import * as Cesium from 'cesium'
|
import { MapTooltip } from '@ztzf/utils'
|
import { ToolBase } from '../ToolBase'
|
import {
|
buildEllipsePositions,
|
formatBufferRadius,
|
getBufferRadiusLabelStyle,
|
getBufferRadiusPoint,
|
} from '../shapeUtils'
|
|
export class DrawBufferCircleTool extends ToolBase {
|
constructor(viewer) {
|
super(viewer)
|
this.tooltip = new MapTooltip(viewer)
|
this.dataSource = null
|
this.centerCartesian = null
|
this.radiusLevel1 = 0
|
this.radiusLevel2 = 0
|
this.radiusLevel3 = 0
|
this.circleLevel1Entity = null
|
this.circleLevel2Entity = null
|
this.circleLevel3Entity = null
|
this.circleLevel1OutlineEntity = null
|
this.circleLevel2OutlineEntity = null
|
this.circleLevel3OutlineEntity = null
|
this.radiusPoint1 = null
|
this.radiusPoint2 = null
|
this.radiusPoint3 = null
|
this.radiusLevel1LabelEntity = null
|
this.radiusLevel2LabelEntity = null
|
this.radiusLevel3LabelEntity = null
|
this.isDrawing = false
|
this.drawStep = 0
|
this.isCompleted = false
|
}
|
|
start() {
|
this.dataSource = new Cesium.CustomDataSource('draw-buffer-circle')
|
this.viewer.dataSources.add(this.dataSource)
|
this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
|
this.handler.setInputAction(click => this.handleLeftClick(click), Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
this.handler.setInputAction(movement => this.handleMouseMove(movement), Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
this.drawStep = 0
|
this.isCompleted = false
|
this.tooltip.hide()
|
}
|
|
handleLeftClick(click) {
|
if (this.isCompleted) return
|
const position = this.getPositionFromScreen(click.position)
|
if (!position) return
|
|
if (this.drawStep === 0) {
|
this.centerCartesian = position
|
this.radiusLevel1 = 1
|
this.radiusLevel2 = 1
|
this.radiusLevel3 = 1
|
this.isDrawing = true
|
this.drawStep = 1
|
this.createEntities()
|
this.tooltip.show('单击设置一级缓冲圆', click.position)
|
return
|
}
|
|
if (this.drawStep === 1) {
|
const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
|
this.radiusLevel1 = radius
|
this.radiusLevel2 = radius
|
this.radiusLevel3 = radius
|
this.radiusPoint1 = position
|
this.drawStep = 2
|
this.tooltip.show('单击设置二级缓冲圆', click.position)
|
return
|
}
|
|
if (this.drawStep === 2) {
|
const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
|
this.radiusLevel2 = Math.max(radius, this.radiusLevel1)
|
this.radiusLevel3 = this.radiusLevel2
|
this.radiusPoint2 = position
|
this.drawStep = 3
|
this.tooltip.show('单击设置三级缓冲圆', click.position)
|
return
|
}
|
|
if (this.drawStep === 3) {
|
const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
|
this.radiusLevel3 = Math.max(radius, this.radiusLevel2)
|
this.radiusPoint3 = position
|
this.isDrawing = false
|
this.drawStep = 0
|
this.isCompleted = true
|
const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel3, this.radiusLevel3)
|
this.notify('getPolygonPositions', {
|
positions,
|
meta: {
|
center: this.centerCartesian,
|
bufferRadii: [this.radiusLevel1, this.radiusLevel2, this.radiusLevel3],
|
controlPoints: [this.centerCartesian, this.radiusPoint1, this.radiusPoint2, this.radiusPoint3].filter(
|
Boolean
|
),
|
},
|
})
|
this.tooltip.hide()
|
this.clearPreviewEntities()
|
}
|
}
|
|
handleMouseMove(movement) {
|
if (this.isCompleted) return
|
const tipText = this.drawStep === 0
|
? '单击设置中心点'
|
: this.drawStep === 1
|
? '单击设置一级缓冲圆'
|
: this.drawStep === 2
|
? '单击设置二级缓冲圆'
|
: '单击设置三级缓冲圆'
|
if (!this.tooltip?.isVisible) {
|
this.tooltip.show(tipText, movement.endPosition)
|
} else {
|
this.tooltip.show(tipText)
|
this.tooltip.move(movement.endPosition)
|
}
|
if (!this.isDrawing) return
|
const position = this.getPositionFromScreen(movement.endPosition)
|
if (!position) return
|
if (this.drawStep === 1) {
|
const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
|
this.radiusLevel1 = radius
|
this.radiusLevel2 = radius
|
this.radiusLevel3 = radius
|
return
|
}
|
if (this.drawStep === 2) {
|
const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
|
this.radiusLevel2 = Math.max(radius, this.radiusLevel1)
|
this.radiusLevel3 = this.radiusLevel2
|
return
|
}
|
if (this.drawStep === 3) {
|
const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position))
|
this.radiusLevel3 = Math.max(radius, this.radiusLevel2)
|
}
|
}
|
|
createEntities() {
|
if (this.circleLevel1Entity || this.circleLevel2Entity || this.circleLevel3Entity) return
|
this.circleLevel1Entity = this.dataSource.entities.add({
|
position: new Cesium.CallbackProperty(() => this.centerCartesian, false),
|
ellipse: {
|
semiMajorAxis: new Cesium.CallbackProperty(() => this.radiusLevel1, false),
|
semiMinorAxis: new Cesium.CallbackProperty(() => this.radiusLevel1, false),
|
material: Cesium.Color.fromBytes(247, 20, 20, 128),
|
outline: false,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
})
|
this.circleLevel1OutlineEntity = this.dataSource.entities.add({
|
polyline: {
|
positions: new Cesium.CallbackProperty(() => {
|
if (!this.centerCartesian || this.radiusLevel1 <= 0) return []
|
const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel1, this.radiusLevel1)
|
return positions.length ? [...positions, positions[0]] : positions
|
}, false),
|
clampToGround: true,
|
width: 2,
|
material: Cesium.Color.fromBytes(255, 0, 0, 255),
|
},
|
})
|
|
this.circleLevel2Entity = this.dataSource.entities.add({
|
position: new Cesium.CallbackProperty(() => this.centerCartesian, false),
|
ellipse: {
|
semiMajorAxis: new Cesium.CallbackProperty(() => this.radiusLevel2, false),
|
semiMinorAxis: new Cesium.CallbackProperty(() => this.radiusLevel2, false),
|
material: Cesium.Color.fromBytes(255, 235, 59, 128),
|
outline: false,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
})
|
this.circleLevel2OutlineEntity = this.dataSource.entities.add({
|
polyline: {
|
positions: new Cesium.CallbackProperty(() => {
|
if (!this.centerCartesian || this.radiusLevel2 <= 0) return []
|
const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel2, this.radiusLevel2)
|
return positions.length ? [...positions, positions[0]] : positions
|
}, false),
|
clampToGround: true,
|
width: 2,
|
material: Cesium.Color.fromBytes(255, 235, 59, 255),
|
},
|
})
|
|
this.circleLevel3Entity = this.dataSource.entities.add({
|
position: new Cesium.CallbackProperty(() => this.centerCartesian, false),
|
ellipse: {
|
semiMajorAxis: new Cesium.CallbackProperty(() => this.radiusLevel3, false),
|
semiMinorAxis: new Cesium.CallbackProperty(() => this.radiusLevel3, false),
|
material: Cesium.Color.fromBytes(25, 178, 230, 128),
|
outline: false,
|
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
},
|
})
|
this.circleLevel3OutlineEntity = this.dataSource.entities.add({
|
polyline: {
|
positions: new Cesium.CallbackProperty(() => {
|
if (!this.centerCartesian || this.radiusLevel3 <= 0) return []
|
const positions = buildEllipsePositions(this.centerCartesian, this.radiusLevel3, this.radiusLevel3)
|
return positions.length ? [...positions, positions[0]] : positions
|
}, false),
|
clampToGround: true,
|
width: 2,
|
material: Cesium.Color.fromBytes(0, 251, 255, 255),
|
},
|
})
|
|
this.radiusLevel1LabelEntity = this.createRadiusLabelEntity(() => this.radiusLevel1)
|
this.radiusLevel2LabelEntity = this.createRadiusLabelEntity(() => this.radiusLevel2)
|
this.radiusLevel3LabelEntity = this.createRadiusLabelEntity(() => this.radiusLevel3)
|
}
|
|
clearPreviewEntities() {
|
if (!this.dataSource) return
|
this.dataSource.entities.removeAll()
|
this.circleLevel1Entity = null
|
this.circleLevel2Entity = null
|
this.circleLevel3Entity = null
|
this.circleLevel1OutlineEntity = null
|
this.circleLevel2OutlineEntity = null
|
this.circleLevel3OutlineEntity = null
|
this.radiusLevel1LabelEntity = null
|
this.radiusLevel2LabelEntity = null
|
this.radiusLevel3LabelEntity = null
|
}
|
|
getSurfaceDistance(startCartesian, endCartesian) {
|
const start = Cesium.Cartographic.fromCartesian(startCartesian)
|
const end = Cesium.Cartographic.fromCartesian(endCartesian)
|
const geodesic = new Cesium.EllipsoidGeodesic(start, end)
|
return geodesic.surfaceDistance
|
}
|
|
getPositionFromScreen(screenPosition) {
|
const scene = this.viewer.scene
|
const cartesian = scene.pickPosition(screenPosition)
|
if (cartesian) return cartesian
|
return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid)
|
}
|
|
getRadiusPoint(radius) {
|
return getBufferRadiusPoint(this.centerCartesian, radius)
|
}
|
|
createRadiusLabelEntity(getRadius) {
|
return this.dataSource.entities.add({
|
position: new Cesium.CallbackProperty(
|
() => getBufferRadiusPoint(this.centerCartesian, getRadius()),
|
false
|
),
|
label: {
|
...getBufferRadiusLabelStyle(),
|
text: new Cesium.CallbackProperty(() => formatBufferRadius(getRadius()), false),
|
},
|
})
|
}
|
|
destroy() {
|
if (this.dataSource) {
|
this.dataSource.entities.removeAll()
|
this.viewer.dataSources.remove(this.dataSource)
|
this.dataSource = null
|
}
|
if (this.handler) {
|
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
this.handler.destroy()
|
this.handler = null
|
}
|
this.tooltip?.destroy()
|
this.tooltip = null
|
this.centerCartesian = null
|
this.radiusLevel1 = 0
|
this.radiusLevel2 = 0
|
this.radiusLevel3 = 0
|
this.radiusPoint1 = null
|
this.radiusPoint2 = null
|
this.radiusPoint3 = null
|
this.radiusLevel1LabelEntity = null
|
this.radiusLevel2LabelEntity = null
|
this.radiusLevel3LabelEntity = null
|
this.isDrawing = false
|
this.drawStep = 0
|
this.isCompleted = false
|
}
|
}
|