From 6e88705bd5b443a259b24c17c8a299765d059d96 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Thu, 23 Jul 2026 16:50:41 +0800
Subject: [PATCH] Merge branch 'master' of http://139.196.74.78:10010/r/jagzwxm/ja_web
---
applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js | 158 ++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 146 insertions(+), 12 deletions(-)
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js
index bdb7a1a..46da9c5 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/edit/EditPolygonTool.js
@@ -3,6 +3,7 @@
import { ToolBase } from '../ToolBase'
const POINT_ENTITY_NAME = 'edit-polygon-point'
+const MIDPOINT_ENTITY_NAME = 'edit-polygon-midpoint'
const DEFAULT_STYLE = {
fill: Cesium.Color.fromBytes(45, 140, 240, 99),
outline: Cesium.Color.fromBytes(45, 140, 240, 255),
@@ -11,6 +12,69 @@
fill: style?.fill || DEFAULT_STYLE.fill,
outline: style?.outline || DEFAULT_STYLE.outline,
})
+const resolveColorWithAlpha = (baseColor, alphaSource) => {
+ if (!baseColor) return alphaSource
+ const alpha = typeof alphaSource?.alpha === 'number' ? alphaSource.alpha : 1
+ return baseColor.withAlpha(alpha)
+}
+
+const normalizeRing = points => {
+ if (!Array.isArray(points)) return []
+ const ring = points.filter(Boolean)
+ if (ring.length < 2) return ring
+ const first = ring[0]
+ const last = ring[ring.length - 1]
+ if (Cesium.Cartesian3.equals(first, last)) {
+ return ring.slice(0, -1)
+ }
+ return ring
+}
+
+const isSelfIntersecting = positions => {
+ const ring = normalizeRing(positions)
+ if (ring.length < 4) return false
+ const epsilon = 1e-12
+ const toPoint = cartesian => {
+ const carto = Cesium.Cartographic.fromCartesian(cartesian)
+ return { x: carto.longitude, y: carto.latitude }
+ }
+ const pts = ring.map(toPoint)
+ const orientation = (a, b, c) => {
+ const value = (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y)
+ if (Math.abs(value) < epsilon) return 0
+ return value > 0 ? 1 : 2
+ }
+ const onSegment = (a, b, c) =>
+ b.x <= Math.max(a.x, c.x) + epsilon &&
+ b.x + epsilon >= Math.min(a.x, c.x) &&
+ b.y <= Math.max(a.y, c.y) + epsilon &&
+ b.y + epsilon >= Math.min(a.y, c.y)
+ const segmentsIntersect = (p1, q1, p2, q2) => {
+ const o1 = orientation(p1, q1, p2)
+ const o2 = orientation(p1, q1, q2)
+ const o3 = orientation(p2, q2, p1)
+ const o4 = orientation(p2, q2, q1)
+ if (o1 !== o2 && o3 !== o4) return true
+ if (o1 === 0 && onSegment(p1, p2, q1)) return true
+ if (o2 === 0 && onSegment(p1, q2, q1)) return true
+ if (o3 === 0 && onSegment(p2, p1, q2)) return true
+ if (o4 === 0 && onSegment(p2, q1, q2)) return true
+ return false
+ }
+ const count = pts.length
+ for (let i = 0; i < count; i += 1) {
+ const p1 = pts[i]
+ const q1 = pts[(i + 1) % count]
+ for (let j = i + 1; j < count; j += 1) {
+ const isAdjacent = j === i || j === i + 1 || (i === 0 && j === count - 1)
+ if (isAdjacent) continue
+ const p2 = pts[j]
+ const q2 = pts[(j + 1) % count]
+ if (segmentsIntersect(p1, q1, p2, q2)) return true
+ }
+ }
+ return false
+}
const normalizePoints = points =>
(points || []).map(point => ({
@@ -29,6 +93,8 @@
this.positions = []
this.isDragging = false
this.draggedIndex = -1
+ this.dragSnapshot = null
+ this.isIntersecting = false
this.style = resolveStyle(options?.style)
}
@@ -57,11 +123,26 @@
handleLeftDown(click) {
const pickedEntity = this.viewer.scene.pick(click.position)?.id
- if (!pickedEntity || pickedEntity.name !== POINT_ENTITY_NAME) return
+ if (!pickedEntity) return
+ if (pickedEntity.name === MIDPOINT_ENTITY_NAME) {
+ const leftIndex = pickedEntity.customData?.leftIndex
+ const rightIndex = pickedEntity.customData?.rightIndex
+ if (typeof leftIndex !== 'number' || typeof rightIndex !== 'number') return
+ const midpoint = this.getMidpointPosition(leftIndex, rightIndex)
+ this.positions.splice(rightIndex, 0, midpoint)
+ this.rebuildPointEntities()
+ this.isDragging = true
+ this.draggedIndex = rightIndex
+ this.dragSnapshot = this.positions.map(position => Cesium.Cartesian3.clone(position))
+ this.disableMapControl()
+ return
+ }
+ if (pickedEntity.name !== POINT_ENTITY_NAME) return
const index = pickedEntity.customData?.index
if (typeof index !== 'number') return
this.isDragging = true
this.draggedIndex = index
+ this.dragSnapshot = this.positions.map(position => Cesium.Cartesian3.clone(position))
this.disableMapControl()
}
@@ -70,15 +151,30 @@
this.isDragging = false
this.draggedIndex = -1
this.enableMapControl()
+ if (this.isIntersecting && this.dragSnapshot?.length) {
+ this.positions = this.dragSnapshot.map(position => Cesium.Cartesian3.clone(position))
+ this.isIntersecting = false
+ this.rebuildPointEntities()
+ this.dragSnapshot = null
+ return
+ }
+ this.dragSnapshot = null
this.notify('getPolygonPositions', this.positions)
}
handleMouseMove(movement) {
- this.tooltip.show('拖动顶点编辑,右键删除点', movement.endPosition)
+ const tooltipText = '拖动顶点编辑,拖动中点插入新点,右键删除顶点'
+ if (!this.tooltip?.isVisible) {
+ this.tooltip.show(tooltipText, movement.endPosition)
+ } else {
+ this.tooltip.show(tooltipText)
+ this.tooltip.move(movement.endPosition)
+ }
if (!this.isDragging || this.draggedIndex < 0) return
const position = this.getPositionFromScreen(movement.endPosition)
if (!position) return
this.positions[this.draggedIndex] = position
+ this.isIntersecting = isSelfIntersecting(this.positions)
const pointEntity = this.dataSource.entities.values.find(
entity => entity?.name === POINT_ENTITY_NAME && entity.customData?.index === this.draggedIndex
)
@@ -102,7 +198,12 @@
this.polygonEntity = this.dataSource.entities.add({
polygon: {
hierarchy: new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(this.positions), false),
- material: this.style.fill,
+ material: new Cesium.ColorMaterialProperty(
+ new Cesium.CallbackProperty(() => {
+ if (this.isIntersecting) return resolveColorWithAlpha(Cesium.Color.RED, this.style.fill)
+ return this.style.fill
+ }, false)
+ ),
outline: false,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
show: new Cesium.CallbackProperty(() => this.positions.length >= 3, false),
@@ -117,7 +218,12 @@
}, false),
clampToGround: true,
width: 2,
- material: this.style.outline,
+ material: new Cesium.ColorMaterialProperty(
+ new Cesium.CallbackProperty(() => {
+ if (this.isIntersecting) return resolveColorWithAlpha(Cesium.Color.RED, this.style.outline)
+ return this.style.outline
+ }, false)
+ ),
show: new Cesium.CallbackProperty(() => this.positions.length >= 2, false),
},
})
@@ -126,7 +232,7 @@
rebuildPointEntities() {
this.dataSource.entities.values
.slice()
- .filter(entity => entity?.name === POINT_ENTITY_NAME)
+ .filter(entity => entity?.name === POINT_ENTITY_NAME || entity?.name === MIDPOINT_ENTITY_NAME)
.forEach(entity => this.dataSource.entities.remove(entity))
this.positions.forEach((position, index) => {
@@ -146,6 +252,30 @@
},
})
})
+
+ const count = this.positions.length
+ if (count < 2) return
+ const segmentCount = count === 2 ? 1 : count
+ for (let i = 0; i < segmentCount; i += 1) {
+ const leftIndex = i
+ const rightIndex = i + 1 < count ? i + 1 : 0
+ this.dataSource.entities.add({
+ name: MIDPOINT_ENTITY_NAME,
+ position: new Cesium.CallbackProperty(() => this.getMidpointPosition(leftIndex, rightIndex), false),
+ point: {
+ pixelSize: 8,
+ color: Cesium.Color.WHITE.withAlpha(0.6),
+ outlineColor: this.style.outline.withAlpha(0.6),
+ outlineWidth: 2,
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
+ },
+ customData: {
+ leftIndex,
+ rightIndex,
+ },
+ })
+ }
}
getPositions() {
@@ -154,19 +284,21 @@
getPositionFromScreen(screenPosition) {
const scene = this.viewer.scene
- const cartesian = scene.pickPosition(screenPosition)
+ const ray = scene.camera.getPickRay(screenPosition)
+ const cartesian = ray ? scene.globe.pick(ray, scene) : null
if (cartesian) return cartesian
return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
}
+ getMidpointPosition(leftIndex, rightIndex) {
+ const left = this.positions[leftIndex]
+ const right = this.positions[rightIndex]
+ if (!left || !right) return left || right
+ return Cesium.Cartesian3.midpoint(left, right, new Cesium.Cartesian3())
+ }
+
setStyle(style) {
this.style = resolveStyle(style)
- if (this.polygonEntity?.polygon) {
- this.polygonEntity.polygon.material = this.style.fill
- }
- if (this.polylineEntity?.polyline) {
- this.polylineEntity.polyline.material = this.style.outline
- }
if (this.dataSource) {
this.dataSource.entities.values
.filter(entity => entity?.name === POINT_ENTITY_NAME)
@@ -211,5 +343,7 @@
this.positions = []
this.isDragging = false
this.draggedIndex = -1
+ this.dragSnapshot = null
+ this.isIntersecting = false
}
}
--
Gitblit v1.9.3