Cesium基本图形绘制

之前用openlayers开发二维地图的时候,绘制线矩形椭圆是基本的功能,所以在cesium地图中也可以加入这些功能。将常用的绘制功能进行了封装,绘制线比较简单,创建Entity实例,传入对应的坐标就可以绘制出来,具体的代码将在最后贴出来。下面主要界面下矩形椭圆的绘制思路。平台还在努力开发中,可以先预览下效果。cgis

1.绘制圆

绘制圆需要借助turf.js这个框架,圆绘制的原理其实就是绘制多边形,绘制步骤如下所示:

1.点击地图,记录点击的位置作为圆心,记为A点。
2.移动鼠标,再点击地图,记录该点作为圆弧上的点,记为B点。
3.使用turf.distance计算AB两点的距离,可以求出圆的半径。
4.使用turf.circle绘制一个360份的圆,既可求出360个点。
5.用这360个点绘制一个多边形。

createCirclePoints(point){
        let startPoint = this.points[0];
        let startLon = parseFloat(startPoint.longitude);
        let startLat = parseFloat(startPoint.latitude);
        let endLon = parseFloat(point.longitude);
        let endLat = parseFloat(point.latitude);
        if(startLon === endLon && startLat === endLat)return;
        let clickPoint = [endLon,endLat];
        let distanceOptions = {units: 'kilometers'};
        let distance = turf.distance( [startLon,startLat],clickPoint, distanceOptions);
        let options = {steps: 360, units: 'kilometers', properties: {foo: 'bar'}};
        let circleFeatures = turf.circle([startLon,startLat], distance, options);
        let coordinates = circleFeatures.geometry.coordinates[0];
        let points = [];
        coordinates.forEach(item => {
            points.push({longitude:item[0],latitude:item[1]});
        });
        return points;
    }

2.绘制矩形

绘制矩形比较简单,通过两点就可以绘制一个矩形,绘制步骤如下所示:

1.点击地图,记录点击的位置作为左上角,记为A点。
2.移动鼠标,再点击地图,记录该点作为右下角,记为B点。
3.根据A点和B的经纬度坐标分别求出右上角和左下角的坐标。
4.将4个点绘制成一个多边形。

createRectanglePoints(point){
        let startPoint = this.points[0];
        let points = [startPoint];
        let startLon = startPoint.longitude;
        let startLat = startPoint.latitude;
        let endLon = point.longitude;
        let endLat = point.latitude;
        if(startLon === endLon && startLat === endLat)return;
        points.push({longitude:endLon,latitude:startLat});
        points.push({longitude:endLon,latitude:endLat});
        points.push({longitude:startLon,latitude:endLat});
        return points;
    }

3.绘椭圆

绘制椭圆也需要借助turf.js这个框架,椭圆绘制的原理跟圆类似,只是多了一个Y轴上的半径,绘制步骤如下所示:

1.点击地图,记录点击的位置作为圆心,记为A点。
2.移动鼠标,再点击地图,记录该点作为圆弧上的点,记为B点。
3.使用turf.distance计算AB两点的距离,可以求出圆的半径,做为X轴上的半径。
4.根据X轴的半径计算Y轴的半径,只需将Y轴上的半径设置成小于X轴的半径就行了。
5.使用turf.ellipse绘制一个360份的椭圆,既可求出360个点。
6.用这360个点绘制一个多边形。

createEllipsePoints(point){
        let startPoint = this.points[0];
        let startLon = parseFloat(startPoint.longitude);
        let startLat = parseFloat(startPoint.latitude);
        let endLon = parseFloat(point.longitude);
        let endLat = parseFloat(point.latitude);
        let center = [startLon,startLat];
        if(startLon === endLon && startLat === endLat)return;
        let endPoint = [endLon,endLat];
        let distanceOptions = {units: 'kilometers'};
        let xSemiAxis = turf.distance(center,endPoint, distanceOptions);
        let ySemiAxis = xSemiAxis - xSemiAxis * 0.2;
        let ellipse = turf.ellipse(center, xSemiAxis, ySemiAxis,{
            steps:360
        });
        let coordinates = ellipse.geometry.coordinates[0];
        let points = [];
        coordinates.forEach(item => {
            points.push({longitude:item[0],latitude:item[1]});
        });
        return points;
    }

为了方便使用,将绘制基本图形的代码全部进行了封装:

import  * as Cesium from '@/Cesium/Source/Cesium';
import Cgis3DEvent from '@/cgis3d/core/Event';
import * as turf from '@turf/turf'
class DrawTool {
    constructor(){
        this.entities = [];
        this.tempEntities = [];
        this.commandDict = {
            CLEAR:this.clear,
            POINT:this.drawPoint,
            LINE:this.drawLine,
            POLYGON:this.drawPolygon,
            CIRCLE:this.drawCircle,
            RECTANGLE:this.drawRectangle,
            ELLIPSE:this.drawEllipse
        };
        this.commandDictTemp = {
            LINE:this.drawTempLine,
            POLYGON:this.drawTempPolygon,
            RECTANGLE:this.drawTempRectangle,
            CIRCLE:this.drawTempCircle,
            ELLIPSE:this.drawTempEllipse
        }
        this.type = null;
        this.points = [];
    }
    command(type){
        if(type === 'CLEAR'){
            this.clear();
        }else{
            this.type = type;
            this.addEvent();
            this.startDraw();
        }
    }
    clear(){
        this.entities.forEach(entity => {
            cgis3d.viewer.entities.remove(entity);
        })
    }
    clearTempEntities(){
        this.tempEntities.forEach(entity => {
            cgis3d.viewer.entities.remove(entity);
        })
    }
    drawPoint(position){
        let entity = new Cesium.Entity({
            position:new Cesium.Cartesian3.fromDegrees(parseFloat(position.longitude), parseFloat(position.latitude)),
            point:new Cesium.PointGraphics({
                pixelSize:20,
                heightReference:20,
                color:Cesium.Color.RED,
                outlineColor:Cesium.Color.BLUE
            })
        });
        this.entities.push(entity);
        cgis3d.viewer.entities.add(entity);
        this.endDraw();
    }
    drawLine(point){
        this.clear();
        this.points.push(point);
        if(this.points.length < 2){
            return;
        }
        this.clearTempEntities();
        let line = this.createLine(this.points);
        cgis3d.viewer.entities.add(line);
        this.entities.push(line);
    }
    drawTempLine(point){
        this.clearTempEntities();
        if(this.points.length < 1){
            return;
        }
        let line = this.createLine([this.points[this.points.length -1],point]);
        cgis3d.viewer.entities.add(line);
        this.tempEntities.push(line);

    }
    createLine(points){
        let positions = [];
        points.forEach(item => {
            positions.push(new Cesium.Cartesian3.fromDegrees(parseFloat(item.longitude), parseFloat(item.latitude)));
        });
        let line = new Cesium.Entity({
            polyline:new Cesium.PolylineGraphics({
                positions : positions,
                material:Cesium.Color.RED.withAlpha(0.5),
                width:5,
            })
        });
        return line;
    }
    drawPolygon(point){
        this.clear();
        this.points.push(point);
        if(this.points.length < 3){
            this.drawTempLine(point);
            return;
        }
        this.clearTempEntities();
        let polygon = this.createPolygon(this.points);
        cgis3d.viewer.entities.add(polygon);
        this.entities.push(polygon);
    }
    drawTempPolygon(point){
        this.clearTempEntities();
        if(this.points.length <= 2){
            this.drawTempLine(point);
            return;
        }
        let points = [].concat(this.points);
        points.push(point);
        let polygon = this.createPolygon(points);
        cgis3d.viewer.entities.add(polygon);
        this.tempEntities.push(polygon);
    }

    createPolygon(points){
        points = [].concat(points);
        points.push(points[0]);
        let positions = [];
        points.forEach(item => {
            positions.push(new Cesium.Cartesian3.fromDegrees(parseFloat(item.longitude), parseFloat(item.latitude)));
        });
        let polygon = new Cesium.Entity({
            name:'多边形',
            description:"这是描述信息",
            polygon:new Cesium.PolygonGraphics({
                hierarchy : new Cesium.PolygonHierarchy(positions),
                material:Cesium.Color.RED.withAlpha(0.5),
                outline:true,
                outlineColor:Cesium.Color.BLUE,
                outlineWidth:5,
            })
        });
        return polygon;
    }
    drawCircle(point){
        this.clear();
        if(this.points.length < 1){
            this.points.push(point);
            return;
        }else{
            let points = this.createCirclePoints(point);
            if(!points)return;
            this.points = [].concat(points)
        }
        this.clearTempEntities();
        let polygon = this.createPolygon(this.points);
        cgis3d.viewer.entities.add(polygon);
        this.entities.push(polygon);
        this.endDraw();
    }
    drawTempCircle(point){
        this.clearTempEntities();
        if(this.points.length < 1){
            return;
        }else{
            let points = this.createCirclePoints(point);
            if(!points)return;
            let polygon = this.createPolygon([].concat(points));
            cgis3d.viewer.entities.add(polygon);
            this.tempEntities.push(polygon);
        }
    }
    createCirclePoints(point){
        let startPoint = this.points[0];
        let startLon = parseFloat(startPoint.longitude);
        let startLat = parseFloat(startPoint.latitude);
        let endLon = parseFloat(point.longitude);
        let endLat = parseFloat(point.latitude);
        if(startLon === endLon && startLat === endLat)return;
        let clickPoint = [endLon,endLat];
        let distanceOptions = {units: 'kilometers'};
        let distance = turf.distance( [startLon,startLat],clickPoint, distanceOptions);
        let options = {steps: 360, units: 'kilometers', properties: {foo: 'bar'}};
        let circleFeatures = turf.circle([startLon,startLat], distance, options);
        let coordinates = circleFeatures.geometry.coordinates[0];
        let points = [];
        coordinates.forEach(item => {
            points.push({longitude:item[0],latitude:item[1]});
        });
        return points;
    }
    drawRectangle(point){
        this.clear();
        if(this.points.length < 1){
            this.points.push(point);
            return;
        }else{

            let points = this.createRectanglePoints(point);
            if(!points)return;
            this.points = [].concat(points)
        }
        this.clearTempEntities();
        let polygon = this.createPolygon(this.points);
        cgis3d.viewer.entities.add(polygon);
        this.entities.push(polygon);
        this.endDraw();
    }
    drawTempRectangle(point){
        this.clearTempEntities();
        if(this.points.length < 1){
            return;
        }else{
            let points = this.createRectanglePoints(point);
            if(!points)return;
            let polygon = this.createPolygon([].concat(points));
            cgis3d.viewer.entities.add(polygon);
            this.tempEntities.push(polygon);
        }
    }
    createRectanglePoints(point){
        let startPoint = this.points[0];
        let points = [startPoint];
        let startLon = startPoint.longitude;
        let startLat = startPoint.latitude;
        let endLon = point.longitude;
        let endLat = point.latitude;
        if(startLon === endLon && startLat === endLat)return;
        points.push({longitude:endLon,latitude:startLat});
        points.push({longitude:endLon,latitude:endLat});
        points.push({longitude:startLon,latitude:endLat});
        return points;
    }
    drawEllipse(point){
        this.clear();
        if(this.points.length < 1){
            this.points.push(point);
            return;
        }else{
            let points = this.createEllipsePoints(point);
            if(!points)return;
            this.points = [].concat(points)
        }
        this.clearTempEntities();
        let polygon = this.createPolygon(this.points);
        cgis3d.viewer.entities.add(polygon);
        this.entities.push(polygon);
        this.endDraw();
    }
    drawTempEllipse(point){
        this.clearTempEntities();
        if(this.points.length < 1){
            return;
        }else{
            let points = this.createEllipsePoints(point);
            if(!points)return;
            let polygon = this.createPolygon([].concat(points));
            cgis3d.viewer.entities.add(polygon);
            this.tempEntities.push(polygon);
        }
    }
    createEllipsePoints(point){
        let startPoint = this.points[0];
        let startLon = parseFloat(startPoint.longitude);
        let startLat = parseFloat(startPoint.latitude);
        let endLon = parseFloat(point.longitude);
        let endLat = parseFloat(point.latitude);
        let center = [startLon,startLat];
        if(startLon === endLon && startLat === endLat)return;
        let endPoint = [endLon,endLat];
        let distanceOptions = {units: 'kilometers'};
        let xSemiAxis = turf.distance(center,endPoint, distanceOptions);
        let ySemiAxis = xSemiAxis - xSemiAxis * 0.2;
        let ellipse = turf.ellipse(center, xSemiAxis, ySemiAxis,{
            steps:360
        });
        let coordinates = ellipse.geometry.coordinates[0];
        let points = [];
        coordinates.forEach(item => {
            points.push({longitude:item[0],latitude:item[1]});
        });
        return points;
    }
    addEvent(){
        DrawTool.cgs3dEvent = DrawTool.cgs3dEvent || new Cgis3DEvent(cgis3d.viewer);
        DrawTool.cgs3dEvent.on(Cgis3DEvent.LEFT_CLICK,this.leftClickHandler.bind(this));
        DrawTool.cgs3dEvent.on(Cgis3DEvent.LEFT_DOUBLE_CLICK,this.leftDoubleClickHandler.bind(this));
        DrawTool.cgs3dEvent.on(Cgis3DEvent.MOUSE_MOVE,this.mouseMoveHandler.bind(this));
    }
    removeEvent(){
        DrawTool.cgs3dEvent.off(Cgis3DEvent.LEFT_CLICK,this.leftClickHandler);
        DrawTool.cgs3dEvent.off(Cgis3DEvent.LEFT_DOUBLE_CLICK,this.leftDoubleClickHandler);
        DrawTool.cgs3dEvent.off(Cgis3DEvent.MOUSE_MOVE,this.mouseMoveHandler);

    }

    leftClickHandler(movement){
        movement.endPosition = movement.endPosition || movement.position;
        const result = DrawTool.cgs3dEvent.getLocationInfo(movement);
        if(result){
            let fn = this.commandDict[this.type];
            if(fn instanceof Function){
                fn.call(this,result);
            }
        }
    }

    mouseMoveHandler(movement){
        movement.endPosition = movement.endPosition || movement.position;
        const result = DrawTool.cgs3dEvent.getLocationInfo(movement);
        if(result){
            let fn = this.commandDictTemp[this.type];
            if(fn instanceof Function){
                fn.call(this,result);
            }
        }
    }

    startDraw(){
        this.clear();
        this.points = [];
        window.document.body.style.cursor = 'crosshair'
    }

    endDraw(){
        window.document.body.style.cursor = 'default'
        this.removeEvent();
        this.clearTempEntities()
    }

    leftDoubleClickHandler(){
        this.endDraw();
    }
}

export default new DrawTool();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335