From 0e5b1764e3eb59e5f4aac4d380c6fda3f0c1e2fe Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Thu, 05 Feb 2026 17:23:42 +0800
Subject: [PATCH] feat:多边形绘制及编辑增加交叉判断
---
applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js | 126 ++++++++++++++++++++++++++++++++++++-----
1 files changed, 109 insertions(+), 17 deletions(-)
diff --git a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js
index c932d8b..88674c7 100644
--- a/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js
+++ b/applications/drone-command/src/utils/cesium/shapeTools/draw/DrawPolygonTool.js
@@ -11,6 +11,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
+}
export class DrawPolygonTool extends ToolBase {
constructor(viewer, options = {}) {
@@ -23,6 +86,7 @@
this.floatPosition = null
this.isDrawing = false
this.lastMousePosition = null
+ this.isIntersecting = false
this.style = resolveStyle(options?.style)
}
@@ -50,6 +114,13 @@
const position = this.getPositionFromScreen(click.position)
if (!position) return
+ const preview = [...this.positions, position]
+ if (isSelfIntersecting(preview)) {
+ this.isIntersecting = true
+ this.tooltip.show(this.getTipText(), click.position)
+ return
+ }
+
this.addPoint(position)
this.tooltip.show(this.getTipText(), click.position)
}
@@ -66,15 +137,20 @@
handleMouseMove(movement) {
if (!this.isDrawing) return
- this.tooltip.show(this.getTipText(), movement.endPosition)
if (this.positions.length === 0) return
const position = this.getPositionFromScreen(movement.endPosition)
if (!position) return
this.lastMousePosition = position
this.floatPosition = position
+ this.tooltip.show(this.getTipText(), movement.endPosition)
}
getTipText() {
+ const preview = this.getPreviewPositions()
+ this.isIntersecting = isSelfIntersecting(preview)
+ if (this.isIntersecting) {
+ return '区域存在交叉,请调整位置'
+ }
const count = this.positions.length
if (count === 0) {
return '单击增加点'
@@ -116,27 +192,41 @@
}
}
+ getPreviewPositions() {
+ if (this.positions.length === 0) return []
+ if (!this.isDrawing || !this.floatPosition) return this.positions
+ return [...this.positions, this.floatPosition]
+ }
+
createEntities() {
- const getPreviewPositions = () => {
- if (this.positions.length === 0) return []
- if (!this.isDrawing || !this.floatPosition) return this.positions
- return [...this.positions, this.floatPosition]
+ const getIntersecting = () => {
+ const preview = this.getPreviewPositions()
+ this.isIntersecting = isSelfIntersecting(preview)
+ return this.isIntersecting
}
this.polygonEntity = this.dataSource.entities.add({
polygon: {
- hierarchy: new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(getPreviewPositions()), false),
- material: this.style.fill,
+ hierarchy: new Cesium.CallbackProperty(
+ () => new Cesium.PolygonHierarchy(this.getPreviewPositions()),
+ false
+ ),
+ material: new Cesium.ColorMaterialProperty(
+ new Cesium.CallbackProperty(() => {
+ if (getIntersecting()) 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(() => getPreviewPositions().length >= 3, false),
+ show: new Cesium.CallbackProperty(() => this.getPreviewPositions().length >= 3, false),
},
})
this.polylineEntity = this.dataSource.entities.add({
polyline: {
positions: new Cesium.CallbackProperty(() => {
- const positions = getPreviewPositions()
+ const positions = this.getPreviewPositions()
if (positions.length < 2) return positions
if (positions.length >= 3) {
return [...positions, positions[0]]
@@ -145,8 +235,13 @@
}, false),
clampToGround: true,
width: 2,
- material: this.style.outline,
- show: new Cesium.CallbackProperty(() => getPreviewPositions().length >= 2, false),
+ material: new Cesium.ColorMaterialProperty(
+ new Cesium.CallbackProperty(() => {
+ if (getIntersecting()) return resolveColorWithAlpha(Cesium.Color.RED, this.style.outline)
+ return this.style.outline
+ }, false)
+ ),
+ show: new Cesium.CallbackProperty(() => this.getPreviewPositions().length >= 2, false),
},
})
}
@@ -180,6 +275,7 @@
if (this.positions.length < 3) return
this.isDrawing = false
this.floatPosition = null
+ this.isIntersecting = false
this.notify('getPolygonPositions', this.positions)
this.tooltip.hide()
this.clearPreviewEntities()
@@ -187,12 +283,6 @@
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)
@@ -209,6 +299,7 @@
this.dataSource.entities.removeAll()
this.polygonEntity = null
this.polylineEntity = null
+ this.isIntersecting = false
}
getPositionFromScreen(screenPosition) {
@@ -237,5 +328,6 @@
this.floatPosition = null
this.isDrawing = false
this.lastMousePosition = null
+ this.isIntersecting = false
}
}
--
Gitblit v1.9.3