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.postProcessStages.fxaa.enabled = true;
|
||||||
viewer.scene.camera.setView({
|
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;
|
const buttonGroup = document.getElementById('button-group') as HTMLElement;
|
||||||
fineArrow.onclick = () => {
|
buttonGroup.onclick = (evt) => {
|
||||||
new CesiumPlot.FineArrow(Cesium, viewer, {});
|
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;
|
default:
|
||||||
attackArrow.onclick = () => {
|
break;
|
||||||
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, {});
|
|
||||||
};
|
};
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<div id="cesiumContainer"></div>
|
<div id="cesiumContainer"></div>
|
||||||
<div class="button-container">
|
<div class="button-container" id="button-group">
|
||||||
<button id="drawStraightArrow" class="button">细直箭头</button>
|
<button id="drawStraightArrow" class="button">细直箭头</button>
|
||||||
<button id="drawCurvedArrow" class="button">曲线箭头</button>
|
<button id="drawCurvedArrow" class="button">曲线箭头</button>
|
||||||
<button id="drawFineArrow" class="button">直箭头</button>
|
<button id="drawFineArrow" class="button">直箭头</button>
|
||||||
@ -47,6 +47,7 @@
|
|||||||
<button id="drawSquadCombat" class="button">分队战斗方向</button>
|
<button id="drawSquadCombat" class="button">分队战斗方向</button>
|
||||||
<button id="drawSwallowtailSquadCombat" class="button">分队战斗方向(燕尾)</button>
|
<button id="drawSwallowtailSquadCombat" class="button">分队战斗方向(燕尾)</button>
|
||||||
<button id="drawAssaultDirection" class="button">突击方向</button>
|
<button id="drawAssaultDirection" class="button">突击方向</button>
|
||||||
|
<button id="drawDoubleArrow" class="button">双箭头</button>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
window.CESIUM_BASE_URL = './examples/cesium';
|
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 lnglat = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
|
||||||
const lat = this.cesium.Math.toDegrees(lnglat.latitude);
|
const lat = this.cesium.Math.toDegrees(lnglat.latitude);
|
||||||
const lng = this.cesium.Math.toDegrees(lnglat.longitude);
|
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 StraightArrow from './arrow/straight-arrow';
|
||||||
import CurvedArrow from './arrow/curved-arrow';
|
import CurvedArrow from './arrow/curved-arrow';
|
||||||
import AssaultDirection from './arrow/assault-direction';
|
import AssaultDirection from './arrow/assault-direction';
|
||||||
|
import DoubleArrow from './arrow/double-arrow';
|
||||||
|
|
||||||
const CesiumPlot = {
|
const CesiumPlot = {
|
||||||
FineArrow,
|
FineArrow,
|
||||||
@ -16,6 +17,7 @@ const CesiumPlot = {
|
|||||||
StraightArrow,
|
StraightArrow,
|
||||||
CurvedArrow,
|
CurvedArrow,
|
||||||
AssaultDirection,
|
AssaultDirection,
|
||||||
|
DoubleArrow,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CesiumPlot;
|
export default CesiumPlot;
|
||||||
|
@ -40,7 +40,7 @@ export const getBaseLength = (points) => wholeDistance(points) ** 0.99;
|
|||||||
* @returns {[*,*]}
|
* @returns {[*,*]}
|
||||||
* @constructor
|
* @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