Cesium+Vue3学习系列(10)---态势标绘 直箭头、 细直线箭头画法

 本学习系列将以Cesium + Vue3 + Vite +Typescript+elementplus作为主要技术栈展开,后续会循序渐进,持续探索Cesium的高级功能,相关源码全部免费公开。 请关注微信公众号 “webgis学习”或扫描下方二维码,关注后,在公众号里输入“Cesium学习系列源码”,即可看到本系列全部代码。

前两篇介绍如何标绘和编辑普通的点、线、多边形。本篇在之前的基础上扩展到态势标绘中的直箭头、细直线箭头的绘制和编辑。先看效果

1、直箭头画法:新建StraightArrow类继承自BaseDraw,通过createStraightArrowPoints函数进行更新关键点数据。

import { BaseDraw, GeometryType } from "../BaseDraw";
import { CallbackProperty, Cartesian3, ClassificationType, Color, Entity, PolygonGraphics, Viewer } from "cesium";
import { createStraightArrowPoints } from "@/system/Utils/SituationUtil";
import EventDispatcher from "@/system/EventDispatcher/EventDispatcher";
export default class StraightArrow extends BaseDraw {
    
    
    private tempCursor = new Cartesian3();
    constructor(viewer: Viewer, dispatcher: EventDispatcher) {
        super(viewer, dispatcher);
        this.geometryType = GeometryType.STRAIGHT_ARROW;
        this.minPointCount = 2;
    }
    protected buildFinalEntity(): Entity {
        const geometryPoints = createStraightArrowPoints(this.getPositions())
        return this.viewer.entities.add({
            polygon: new PolygonGraphics({
                hierarchy: new CallbackProperty(() => ({
                    positions: geometryPoints
                }), false),
                classificationType: ClassificationType.BOTH,
                material: Color.BLUE.withAlpha(0.4)
            })
        });
    }
    protected buildTempEntity(): Entity | undefined {
      
        if(this.getPositions().length == 0) return undefined;
        return this.viewer.entities.add({
            polygon: new PolygonGraphics({
                hierarchy: new CallbackProperty(() => ({
                    positions: createStraightArrowPoints([...this.getPositions(), this.tempCursor || new Cartesian3()])
                }), false),
                classificationType: ClassificationType.BOTH,
                material: Color.CYAN.withAlpha(0.3)
            })
        });
    }
    protected onLeftClick(e: any) {
        super.onLeftClick(e);
        // 点只需要 2 次点击即可结束
        if (this.getPositions().length == 2) {
            this.finish();
        }
    }
    protected updateTempEntity(cursor: Cartesian3) {
        this.tempCursor = cursor;
    }
}
* 创建一条直箭头
 * @param positions 箭头的起点和终点
 * @param tailWidthFactor 尾端宽度因子
 * @param neckWidthFactor 颈部宽度因子
 * @param headWidthFactor 头端宽度因子
 * @param headAngle 头端角度
 * @param neckAngle 颈部角度
 * @returns 箭头的点数组
 */
export const createStraightArrowPoints = (positions: Cartesian3[], tailWidthFactor: number=0.1, neckWidthFactor: number=0.2, headWidthFactor: number=0.25, headAngle: number=Math.PI/8.5, neckAngle: number=Math.PI/13) => {
    const firstPnt = CoordinatesUtil.Cartesian2Wgs84Lonlat(positions[0]);
    const lastPnt = CoordinatesUtil.Cartesian2Wgs84Lonlat(positions[1]);
    const distance = MathDistance([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]]);
    const tailWidth = distance * tailWidthFactor;
    const neckWidth = distance * neckWidthFactor;
    const headWidth = distance * headWidthFactor;
    const tailLeft = getThirdPoint([lastPnt[0], lastPnt[1]], [firstPnt[0], firstPnt[1]], Math.PI / 2, tailWidth, true);
    const tailRight = getThirdPoint([lastPnt[0], lastPnt[1]], [firstPnt[0], firstPnt[1]], Math.PI / 2, tailWidth, false);
    const headLeft = getThirdPoint([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]], headAngle, headWidth, false);
    const headRight = getThirdPoint([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]], headAngle, headWidth, true);
    const neckLeft = getThirdPoint([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]], neckAngle, neckWidth, false);
    const neckRight = getThirdPoint([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]], neckAngle, neckWidth, true);
    const points = [...tailLeft, ...neckLeft, ...headLeft, ...lastPnt, ...headRight, ...neckRight, ...tailRight, ...firstPnt];
    const cartesianPoints = Cartesian3.fromDegreesArray(points);
    return cartesianPoints;
}

2、细直线箭头画法:新建StraightLineArrow类,继承继承自BaseDraw,通过createStraightLineArrowPoints函数进行更新关键点数据。

import { CallbackProperty, Cartesian3, Color, Entity, PolylineGraphics, Viewer } from "cesium";
import { BaseDraw, GeometryType } from "../BaseDraw";
import EventDispatcher from "@/system/EventDispatcher/EventDispatcher";
import { createStraightLineArrowPoints } from "@/system/Utils/SituationUtil";
export default class StraightLineArrow extends BaseDraw {
    private tempCursor?: Cartesian3;
    constructor(viewer: Viewer, dispatcher: EventDispatcher) {
        super(viewer, dispatcher);
        this.geometryType = GeometryType.STRAIGHT_LINE_ARROW;
        this.minPointCount = 2;
    }
    protected buildFinalEntity(): Entity {
        return this.viewer.entities.add({
            polyline: new PolylineGraphics({
                positions: new CallbackProperty(() => createStraightLineArrowPoints(this.getPositions()), false),
                width: 3,
                material: Color.ORANGE,
                clampToGround: true
            })
        });
    }
    protected buildTempEntity(): Entity | undefined {
        if(this.getPositions().length == 0) return undefined;
        return this.viewer.entities.add({
            polyline: new PolylineGraphics({
                positions: new CallbackProperty(() => createStraightLineArrowPoints([...this.getPositions(), this.tempCursor || new Cartesian3()]), false),
                width: 3,
                material: Color.YELLOW.withAlpha(0.6),
                clampToGround: true
            })
        });
    }
    protected updateTempEntity(cursor: Cartesian3) {
        this.tempCursor = cursor;
    }
    protected onLeftClick(e: any) {
        super.onLeftClick(e);
        // 需要 2 次点击即可结束
        if (this.getPositions().length == 2) {
            this.finish();
        }
    }
}
/**
 * 创建一条直线箭头
 * @param positions 直箭头的起点和终点
 * @param arrowLengthScale 箭头长度缩放因子
 * @param maxArrowLength 最大箭头长度
 * @param minPointsForShape 最小点数以形成形状
 * @returns 直箭头的点数组
 */
 export const createStraightLineArrowPoints = (positions: Cartesian3[],arrowLengthScale:number=5,maxArrowLength: number = 3000000) => {
    const firstPnt = CoordinatesUtil.Cartesian2Wgs84Lonlat(positions[0]);
    const lastPnt = CoordinatesUtil.Cartesian2Wgs84Lonlat(positions[1]);
    const distance = MathDistance([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]]);
    let len = distance / arrowLengthScale;
    len = len > maxArrowLength ? maxArrowLength : len;
    const leftPnt = getThirdPoint([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]], Math.PI / 6, len / 2, false);
    const rightPnt = getThirdPoint([firstPnt[0], firstPnt[1]], [lastPnt[0], lastPnt[1]], Math.PI / 6, len / 2, true);
    const points = [...firstPnt, ...lastPnt, ...leftPnt, ...lastPnt, ...rightPnt];
    const cartesianPoints = Cartesian3.fromDegreesArray(points);
    return cartesianPoints;
  }

3、在EditHelper.ts中修改updateShape函数

    /** 更新被编辑的图形 */
    private updateShape() {
        switch (this.geometryType) {
            case GeometryType.COMMON_POLYGON:
                this.shapeEntity.polygon!.hierarchy = new CallbackProperty(() => new PolygonHierarchy(this.positions), false);
                break;
            case GeometryType.COMMON_LINE:
                this.shapeEntity.polyline!.positions = new CallbackProperty(() => this.positions, false);
                break;
            case GeometryType.COMMON_POINT:
                this.shapeEntity.position = new ConstantPositionProperty(this.positions[this.positions.length - 1]);
                break;
            case GeometryType.STRAIGHT_ARROW:
                this.shapeEntity.polygon!.hierarchy = new CallbackProperty(() => new PolygonHierarchy(createStraightArrowPoints(this.positions)), false);
                break;
            case GeometryType.STRAIGHT_LINE_ARROW:
                this.shapeEntity.polyline!.positions = new CallbackProperty(() => createStraightLineArrowPoints(this.positions), false);
                break;
        }  
        
    }

4、实现效果

图片

5、更多详细代码,请关注微信公众号“webgis学习”,回复“Cesium学习系列源码”,即可看到本系列全部代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值