mirror of
https://github.com/ethan-zf/cesium-plot-js.git
synced 2025-06-24 03:27:29 +00:00
add DoubleArrow
This commit is contained in:
parent
af081a043b
commit
cd80e1dc82
@ -32,45 +32,42 @@ const viewer = new Cesium.Viewer('cesiumContainer', {
|
||||
|
||||
viewer.scene.postProcessStages.fxaa.enabled = true;
|
||||
viewer.scene.camera.setView({
|
||||
destination: Cesium.Cartesian3.fromDegrees(107.857, 35.594498, 8000000),
|
||||
destination: Cesium.Cartesian3.fromDegrees(107.857, 35.594498, 7000000),
|
||||
});
|
||||
|
||||
const fineArrow = document.getElementById('drawFineArrow') as HTMLElement;
|
||||
fineArrow.onclick = () => {
|
||||
new CesiumPlot.FineArrow(Cesium, viewer, {});
|
||||
};
|
||||
const buttonGroup = document.getElementById('button-group') as HTMLElement;
|
||||
buttonGroup.onclick = (evt) => {
|
||||
const targetElement = evt.target as HTMLElement;
|
||||
switch (targetElement.id) {
|
||||
case 'drawFineArrow':
|
||||
new CesiumPlot.FineArrow(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawAttackArrow':
|
||||
new CesiumPlot.AttackArrow(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawSwallowtailAttackArrow':
|
||||
new CesiumPlot.SwallowtailAttackArrow(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawSquadCombat':
|
||||
new CesiumPlot.SquadCombat(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawSwallowtailSquadCombat':
|
||||
new CesiumPlot.SwallowtailSquadCombat(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawStraightArrow':
|
||||
new CesiumPlot.StraightArrow(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawAssaultDirection':
|
||||
new CesiumPlot.AssaultDirection(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawCurvedArrow':
|
||||
new CesiumPlot.CurvedArrow(Cesium, viewer, {});
|
||||
break;
|
||||
case 'drawDoubleArrow':
|
||||
new CesiumPlot.DoubleArrow(Cesium, viewer, {});
|
||||
break;
|
||||
|
||||
const attackArrow = document.getElementById('drawAttackArrow') as HTMLElement;
|
||||
attackArrow.onclick = () => {
|
||||
new CesiumPlot.AttackArrow(Cesium, viewer, {});
|
||||
};
|
||||
|
||||
const swallowtailAttackArrow = document.getElementById('drawSwallowtailAttackArrow') as HTMLElement;
|
||||
swallowtailAttackArrow.onclick = () => {
|
||||
new CesiumPlot.SwallowtailAttackArrow(Cesium, viewer, {});
|
||||
};
|
||||
|
||||
const squadCombat = document.getElementById('drawSquadCombat') as HTMLElement;
|
||||
squadCombat.onclick = () => {
|
||||
new CesiumPlot.SquadCombat(Cesium, viewer, {});
|
||||
};
|
||||
|
||||
const swallowtailSquadCombat = document.getElementById('drawSwallowtailSquadCombat') as HTMLElement;
|
||||
swallowtailSquadCombat.onclick = () => {
|
||||
new CesiumPlot.SwallowtailSquadCombat(Cesium, viewer, {});
|
||||
};
|
||||
|
||||
const straightArrow = document.getElementById('drawStraightArrow') as HTMLElement;
|
||||
straightArrow.onclick = () => {
|
||||
new CesiumPlot.StraightArrow(Cesium, viewer, {});
|
||||
};
|
||||
|
||||
const assaultDirection = document.getElementById('drawAssaultDirection') as HTMLElement;
|
||||
assaultDirection.onclick = () => {
|
||||
new CesiumPlot.AssaultDirection(Cesium, viewer, {});
|
||||
};
|
||||
|
||||
const curvedArrow = document.getElementById('drawCurvedArrow') as HTMLElement;
|
||||
curvedArrow.onclick = () => {
|
||||
new CesiumPlot.CurvedArrow(Cesium, viewer, {});
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
@ -38,7 +38,7 @@
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="cesiumContainer"></div>
|
||||
<div class="button-container">
|
||||
<div class="button-container" id="button-group">
|
||||
<button id="drawStraightArrow" class="button">细直箭头</button>
|
||||
<button id="drawCurvedArrow" class="button">曲线箭头</button>
|
||||
<button id="drawFineArrow" class="button">直箭头</button>
|
||||
@ -47,6 +47,7 @@
|
||||
<button id="drawSquadCombat" class="button">分队战斗方向</button>
|
||||
<button id="drawSwallowtailSquadCombat" class="button">分队战斗方向(燕尾)</button>
|
||||
<button id="drawAssaultDirection" class="button">突击方向</button>
|
||||
<button id="drawDoubleArrow" class="button">双箭头</button>
|
||||
</div>
|
||||
<script>
|
||||
window.CESIUM_BASE_URL = './examples/cesium';
|
||||
|
221
src/arrow/double-arrow.ts
Normal file
221
src/arrow/double-arrow.ts
Normal file
@ -0,0 +1,221 @@
|
||||
import Draw from '../draw';
|
||||
import * as Utils from '../utils';
|
||||
import { Cartesian3 } from '@examples/cesium';
|
||||
type Position = [number, number];
|
||||
|
||||
export default class DoubleArrow extends Draw {
|
||||
points: Cartesian3[] = [];
|
||||
arrowLengthScale: number = 5;
|
||||
maxArrowLength: number = 2;
|
||||
neckWidthFactor: number;
|
||||
headWidthFactor: number;
|
||||
type: 'polygon' | 'line';
|
||||
headHeightFactor: number;
|
||||
neckHeightFactor: number;
|
||||
connPoint: Position;
|
||||
tempPoint4: Position;
|
||||
|
||||
constructor(cesium: any, viewer: any, style: any) {
|
||||
super(cesium, viewer);
|
||||
this.cesium = cesium;
|
||||
this.type = 'polygon';
|
||||
this.headHeightFactor = 0.25;
|
||||
this.headWidthFactor = 0.3;
|
||||
this.neckHeightFactor = 0.85;
|
||||
this.neckWidthFactor = 0.15;
|
||||
this.connPoint = [0, 0];
|
||||
this.tempPoint4 = [0, 0];
|
||||
this.setState('drawing');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add points only on click events
|
||||
*/
|
||||
addPoint(cartesian: Cartesian3) {
|
||||
this.points.push(cartesian);
|
||||
if (this.points.length < 2) {
|
||||
this.onMouseMove();
|
||||
} else if (this.points.length === 2) {
|
||||
this.setGeometryPoints(this.points);
|
||||
this.drawPolygon();
|
||||
} else if (this.points.length === 3) {
|
||||
this.lineEntity && this.viewer.entities.remove(this.lineEntity);
|
||||
} else {
|
||||
this.finishDrawing();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Draw a shape based on mouse movement points during the initial drawing.
|
||||
*/
|
||||
updateMovingPoint(cartesian: Cartesian3) {
|
||||
const tempPoints = [...this.points, cartesian];
|
||||
this.setGeometryPoints(tempPoints);
|
||||
if (tempPoints.length === 2) {
|
||||
this.drawLine();
|
||||
} else if (tempPoints.length > 2) {
|
||||
const geometryPoints = this.createPolygon(tempPoints);
|
||||
this.setGeometryPoints(geometryPoints);
|
||||
this.drawPolygon();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In edit mode, drag key points to update corresponding key point data.
|
||||
*/
|
||||
updateDraggingPoint(cartesian: Cartesian3, index: number) {
|
||||
this.points[index] = cartesian;
|
||||
const geometryPoints = this.createPolygon(this.points);
|
||||
this.setGeometryPoints(geometryPoints);
|
||||
this.drawPolygon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate geometric shapes based on key points.
|
||||
*/
|
||||
createPolygon(positions: Cartesian3[]) {
|
||||
const lnglatPoints = positions.map((pnt) => {
|
||||
return this.cartesianToLnglat(pnt);
|
||||
});
|
||||
const [pnt1, pnt2, pnt3] = [lnglatPoints[0], lnglatPoints[1], lnglatPoints[2]];
|
||||
const count = lnglatPoints.length;
|
||||
if (count === 3) {
|
||||
this.tempPoint4 = this.getTempPoint4(pnt1, pnt2, pnt3);
|
||||
this.connPoint = Utils.Mid(pnt1, pnt2);
|
||||
} else if (count === 4) {
|
||||
this.tempPoint4 = lnglatPoints[3];
|
||||
this.connPoint = Utils.Mid(pnt1, pnt2);
|
||||
} else {
|
||||
this.tempPoint4 = lnglatPoints[3];
|
||||
this.connPoint = lnglatPoints[4];
|
||||
}
|
||||
let leftArrowPnts: Position[];
|
||||
let rightArrowPnts;
|
||||
if (Utils.isClockWise(pnt1, pnt2, pnt3)) {
|
||||
leftArrowPnts = this.getArrowPoints(pnt1, this.connPoint, this.tempPoint4, false);
|
||||
rightArrowPnts = this.getArrowPoints(this.connPoint, pnt2, pnt3, true);
|
||||
} else {
|
||||
leftArrowPnts = this.getArrowPoints(pnt2, this.connPoint, pnt3, false);
|
||||
rightArrowPnts = this.getArrowPoints(this.connPoint, pnt1, this.tempPoint4, true);
|
||||
}
|
||||
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 = Utils.getBezierPoints(rlBodyPnts);
|
||||
const bodyPnts = Utils.getBezierPoints(rrBodyPnts.concat(llBodyPnts.slice(1)));
|
||||
lrBodyPnts = Utils.getBezierPoints(lrBodyPnts);
|
||||
const pnts = rlBodyPnts.concat(rArrowPnts, bodyPnts, lArrowPnts, lrBodyPnts);
|
||||
const temp = [].concat(...pnts);
|
||||
const cartesianPoints = this.cesium.Cartesian3.fromDegreesArray(temp);
|
||||
return cartesianPoints;
|
||||
}
|
||||
|
||||
getTempPoint4(linePnt1: Position, linePnt2: Position, point: Position): Position {
|
||||
const midPnt = Utils.Mid(linePnt1, linePnt2);
|
||||
const len = Utils.MathDistance(midPnt, point);
|
||||
const angle = Utils.getAngleOfThreePoints(linePnt1, midPnt, point);
|
||||
let symPnt = [0, 0] as Position;
|
||||
let distance1;
|
||||
let distance2;
|
||||
let mid;
|
||||
if (angle < Math.PI / 2) {
|
||||
distance1 = len * Math.sin(angle);
|
||||
distance2 = len * Math.cos(angle);
|
||||
mid = Utils.getThirdPoint(linePnt1, midPnt, Math.PI / 2, distance1, false);
|
||||
symPnt = Utils.getThirdPoint(midPnt, mid, Math.PI / 2, distance2, true);
|
||||
} else if (angle >= Math.PI / 2 && angle < Math.PI) {
|
||||
distance1 = len * Math.sin(Math.PI - angle);
|
||||
distance2 = len * Math.cos(Math.PI - angle);
|
||||
mid = Utils.getThirdPoint(linePnt1, midPnt, Math.PI / 2, distance1, false);
|
||||
symPnt = Utils.getThirdPoint(midPnt, mid, Math.PI / 2, distance2, false);
|
||||
} else if (angle >= Math.PI && angle < Math.PI * 1.5) {
|
||||
distance1 = len * Math.sin(angle - Math.PI);
|
||||
distance2 = len * Math.cos(angle - Math.PI);
|
||||
mid = Utils.getThirdPoint(linePnt1, midPnt, Math.PI / 2, distance1, true);
|
||||
symPnt = Utils.getThirdPoint(midPnt, mid, Math.PI / 2, distance2, true);
|
||||
} else {
|
||||
distance1 = len * Math.sin(Math.PI * 2 - angle);
|
||||
distance2 = len * Math.cos(Math.PI * 2 - angle);
|
||||
mid = Utils.getThirdPoint(linePnt1, midPnt, Math.PI / 2, distance1, true);
|
||||
symPnt = Utils.getThirdPoint(midPnt, mid, Math.PI / 2, distance2, false);
|
||||
}
|
||||
return symPnt;
|
||||
}
|
||||
|
||||
getArrowPoints(pnt1: Position, pnt2: Position, pnt3: Position, clockWise: boolean): Position[] {
|
||||
const midPnt = Utils.Mid(pnt1, pnt2);
|
||||
const len = Utils.MathDistance(midPnt, pnt3);
|
||||
let midPnt1 = Utils.getThirdPoint(pnt3, midPnt, 0, len * 0.3, true);
|
||||
let midPnt2 = Utils.getThirdPoint(pnt3, midPnt, 0, len * 0.5, true);
|
||||
midPnt1 = Utils.getThirdPoint(midPnt, midPnt1, Math.PI / 2, len / 5, clockWise);
|
||||
|
||||
midPnt2 = Utils.getThirdPoint(midPnt, midPnt2, Math.PI / 2, len / 4, clockWise);
|
||||
const points = [midPnt, midPnt1, midPnt2, pnt3];
|
||||
const arrowPnts = this.getArrowHeadPoints(points);
|
||||
if (arrowPnts && Array.isArray(arrowPnts) && arrowPnts.length > 0) {
|
||||
const neckLeftPoint: Position = arrowPnts[0];
|
||||
const neckRightPoint: Position = arrowPnts[4];
|
||||
const tailWidthFactor = Utils.MathDistance(pnt1, pnt2) / Utils.getBaseLength(points) / 2;
|
||||
const bodyPnts = this.getArrowBodyPoints(points, neckLeftPoint, neckRightPoint, tailWidthFactor);
|
||||
if (bodyPnts) {
|
||||
const n = bodyPnts.length;
|
||||
let lPoints = bodyPnts.slice(0, n / 2);
|
||||
let rPoints = bodyPnts.slice(n / 2, n);
|
||||
lPoints.push(neckLeftPoint);
|
||||
rPoints.push(neckRightPoint);
|
||||
lPoints = lPoints.reverse();
|
||||
lPoints.push(pnt2);
|
||||
rPoints = rPoints.reverse();
|
||||
rPoints.push(pnt1);
|
||||
return lPoints.reverse().concat(arrowPnts, rPoints);
|
||||
}
|
||||
} else {
|
||||
throw new Error('Interpolation Error');
|
||||
}
|
||||
}
|
||||
|
||||
getArrowBodyPoints(points: Position[], neckLeft: Position, neckRight: Position, tailWidthFactor: number): Position[] {
|
||||
const allLen = Utils.wholeDistance(points);
|
||||
const len = Utils.getBaseLength(points);
|
||||
const tailWidth = len * tailWidthFactor;
|
||||
const neckWidth = Utils.MathDistance(neckLeft, neckRight);
|
||||
const widthDif = (tailWidth - neckWidth) / 2;
|
||||
let tempLen: number = 0;
|
||||
let leftBodyPnts: Position[] = [];
|
||||
let rightBodyPnts: Position[] = [];
|
||||
for (let i = 1; i < points.length - 1; i++) {
|
||||
const angle = Utils.getAngleOfThreePoints(points[i - 1], points[i], points[i + 1]) / 2;
|
||||
tempLen += Utils.MathDistance(points[i - 1], points[i]);
|
||||
const w = (tailWidth / 2 - (tempLen / allLen) * widthDif) / Math.sin(angle);
|
||||
const left = Utils.getThirdPoint(points[i - 1], points[i], Math.PI - angle, w, true);
|
||||
const right = Utils.getThirdPoint(points[i - 1], points[i], angle, w, false);
|
||||
leftBodyPnts.push(left);
|
||||
rightBodyPnts.push(right);
|
||||
}
|
||||
return leftBodyPnts.concat(rightBodyPnts);
|
||||
}
|
||||
|
||||
getArrowHeadPoints(points: Position[]): Position[] {
|
||||
const len = Utils.getBaseLength(points);
|
||||
const headHeight = len * this.headHeightFactor;
|
||||
const headPnt = points[points.length - 1];
|
||||
const headWidth = headHeight * this.headWidthFactor;
|
||||
const neckWidth = headHeight * this.neckWidthFactor;
|
||||
const neckHeight = headHeight * this.neckHeightFactor;
|
||||
const headEndPnt = Utils.getThirdPoint(points[points.length - 2], headPnt, 0, headHeight, true);
|
||||
const neckEndPnt = Utils.getThirdPoint(points[points.length - 2], headPnt, 0, neckHeight, true);
|
||||
const headLeft = Utils.getThirdPoint(headPnt, headEndPnt, Math.PI / 2, headWidth, false);
|
||||
const headRight = Utils.getThirdPoint(headPnt, headEndPnt, Math.PI / 2, headWidth, true);
|
||||
const neckLeft = Utils.getThirdPoint(headPnt, neckEndPnt, Math.PI / 2, neckWidth, false);
|
||||
const neckRight = Utils.getThirdPoint(headPnt, neckEndPnt, Math.PI / 2, neckWidth, true);
|
||||
return [neckLeft, headLeft, headPnt, headRight, neckRight];
|
||||
}
|
||||
|
||||
getPoints() {
|
||||
return this.points;
|
||||
}
|
||||
}
|
@ -159,7 +159,7 @@ export default class Draw {
|
||||
}
|
||||
}
|
||||
|
||||
cartesianToLnglat(cartesian: CesiumTypeOnly.Cartesian3): number[] {
|
||||
cartesianToLnglat(cartesian: CesiumTypeOnly.Cartesian3): [number, number] {
|
||||
const lnglat = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
|
||||
const lat = this.cesium.Math.toDegrees(lnglat.latitude);
|
||||
const lng = this.cesium.Math.toDegrees(lnglat.longitude);
|
||||
|
@ -6,6 +6,7 @@ import SwallowtailSquadCombat from './arrow/swallowtail-squad-combat';
|
||||
import StraightArrow from './arrow/straight-arrow';
|
||||
import CurvedArrow from './arrow/curved-arrow';
|
||||
import AssaultDirection from './arrow/assault-direction';
|
||||
import DoubleArrow from './arrow/double-arrow';
|
||||
|
||||
const CesiumPlot = {
|
||||
FineArrow,
|
||||
@ -16,6 +17,7 @@ const CesiumPlot = {
|
||||
StraightArrow,
|
||||
CurvedArrow,
|
||||
AssaultDirection,
|
||||
DoubleArrow,
|
||||
};
|
||||
|
||||
export default CesiumPlot;
|
||||
|
@ -40,7 +40,7 @@ export const getBaseLength = (points) => wholeDistance(points) ** 0.99;
|
||||
* @returns {[*,*]}
|
||||
* @constructor
|
||||
*/
|
||||
export const Mid = (point1, point2) => [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2];
|
||||
export const Mid = (point1, point2): [number, number] => [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2];
|
||||
|
||||
/**
|
||||
* 通过三个点确定一个圆的中心点
|
||||
|
Loading…
Reference in New Issue
Block a user