Cesium教程(12)态势标绘 钳形攻击箭头(双箭头)标绘与编辑

86 阅读2分钟

本学习系列将以Cesium + Vue3+Typescript+elementplus作为主要技术栈展开,后续会循序渐进,持续探索Cesium的高级功能。 详情请关注原文Cesium+Vue3学习系列(12)---态势标绘 钳形攻击箭头(双箭头)标绘与编辑

上篇介绍攻击箭头与燕尾攻击箭头的标绘与编辑。下面开始继续扩展,本篇介绍钳形攻击箭头(双箭头)标绘与编辑。先看效果

9.gif 新建PincerAttackArrow继承BaseDraw。通过createPincerAttackArrowPoints函数实现计算具体的箭头需要的点。

import { CallbackProperty, Cartesian3, ClassificationType, Color, Entity, PolygonGraphics, Viewer } from "cesium";
import { BaseDraw, GeometryType } from "../BaseDraw";
import EventDispatcher from "@/system/EventDispatcher/EventDispatcher";
import { createPincerAttackArrowPoints } from "@/system/Utils/SituationUtils/SituationUtil";
export default class PincerAttackArrow extends BaseDraw {
    private tempCursor = new Cartesian3();
    constructor(viewer: Viewer, dispatcher: EventDispatcher) {
        super(viewer, dispatcher);
        this.geometryType = GeometryType.PINCER_ATTACK_ARROW;
        this.minPointCount = 4;
    }
    protected buildFinalEntity(): Entity {
        const geometryPoints = createPincerAttackArrowPoints(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 < (this.minPointCount - 1)) return undefined;
        return this.viewer.entities.add({
            polygon: new PolygonGraphics({
                hierarchy: new CallbackProperty(() => ({
                    positions: createPincerAttackArrowPoints([...this.getPositions(), this.tempCursor || new Cartesian3()])
                }), false),
                classificationType: ClassificationType.BOTH,
                material: Color.CYAN.withAlpha(0.3)
            })
        });
    }
    protected updateTempEntity(cursor: Cartesian3) {
        this.tempCursor = cursor;
    }
    protected onLeftClick(e: any) {
        super.onLeftClick(e);
        // 需要 5次点击即可结束
        if (this.getPositions().length == 5) {
            this.finish();
        }
    }
}
export const createPincerAttackArrowPoints = (positions: Cartesian3[],headHeightFactor: number=0.25,headWidthFactor:number=0.3,neckWidthFactor:number=0.15,neckHeightFactor:number=0.85) => {
    const lnglatPoints = positions.map((pnt) => {
      return CoordinatesUtil.Cartesian2Wgs84Lonlat(pnt);
    });
    const [pnt1, pnt2, pnt3] = [lnglatPoints[0], lnglatPoints[1], lnglatPoints[2]];
    const count = lnglatPoints.length;
    let tempPoint4: number[] = [];
    let connPoint: number[] = [];
    if (count === 3) {
      tempPoint4 = getPincerAttackArrowTempPoint4(pnt1, pnt2, pnt3);
      connPoint = CoordinatesUtil.MidPoint(pnt1, pnt2);
    } else if (count === 4) {
      tempPoint4 = lnglatPoints[3];
      connPoint = CoordinatesUtil.MidPoint(pnt1, pnt2);
    } else {
      tempPoint4 = lnglatPoints[3];
      connPoint = lnglatPoints[4];
    }
    let leftArrowPnts: number[][];
    let rightArrowPnts;
    let isCW = isClockWise(pnt1, pnt2, pnt3);
    if (isCW) {
      leftArrowPnts = getPincerAttackArrowPoints(pnt1, connPoint, tempPoint4, false,headHeightFactor,headWidthFactor,neckWidthFactor,neckHeightFactor);
      rightArrowPnts = getPincerAttackArrowPoints(connPoint, pnt2, pnt3, true,headHeightFactor,headWidthFactor,neckWidthFactor,neckHeightFactor);
    } else {
      leftArrowPnts = getPincerAttackArrowPoints(pnt2, connPoint, pnt3, false,headHeightFactor,headWidthFactor,neckWidthFactor,neckHeightFactor);
      rightArrowPnts = getPincerAttackArrowPoints(connPoint, pnt1, tempPoint4, true,headHeightFactor,headWidthFactor,neckWidthFactor,neckHeightFactor);
    }
    const m = leftArrowPnts.length;
    const t = (m - 5) / 2;
    const llBodyPnts = leftArrowPnts.slice(0, t);
    const lArrowPnts = leftArrowPnts.slice(t, t + 5);
    let lrBodyPnts = leftArrowPnts.slice(t + 5, m);
   
    let rlBodyPnts = rightArrowPnts.slice(0, t);
    const rArrowPnts = rightArrowPnts.slice(t, t + 5);
    const rrBodyPnts = rightArrowPnts.slice(t + 5, m);
   
    rlBodyPnts = getBezierPoints(rlBodyPnts);
    const bodyPnts = getBezierPoints(rrBodyPnts.concat(llBodyPnts.slice(1)));
    lrBodyPnts = getBezierPoints(lrBodyPnts);
    const pnts: number[][] = rlBodyPnts.concat(rArrowPnts, bodyPnts, lArrowPnts, lrBodyPnts);
    const temp: number[] = ([] as number[]).concat(...pnts);
    const cartesianPoints = Cartesian3.fromDegreesArray(temp);
    return cartesianPoints;
  }

上述代码封装层级较多,完整源码请关注原文Cesium+Vue3学习系列(12)---态势标绘 钳形攻击箭头(双箭头)标绘与编辑