| | |
| | | import * as Cesium from 'cesium' |
| | | import { MapTooltip } from '../Tooltip' |
| | | import { ToolBase } from '../ToolBase' |
| | | import { |
| | | getBoundsFromCartesians, |
| | | getCenterFromBounds, |
| | | getMetersBetween, |
| | | buildEllipsePositions, |
| | | } from '../shapeUtils' |
| | | import { buildEllipsePositions } from '../shapeUtils' |
| | | |
| | | const DEFAULT_STYLE = { |
| | | fill: Cesium.Color.fromBytes(45, 140, 240, 99), |
| | | outline: Cesium.Color.fromBytes(45, 140, 240, 255), |
| | | } |
| | | const resolveStyle = style => ({ |
| | | fill: style?.fill || DEFAULT_STYLE.fill, |
| | | outline: style?.outline || DEFAULT_STYLE.outline, |
| | | }) |
| | | |
| | | export class DrawEllipseTool extends ToolBase { |
| | | constructor(viewer) { |
| | | constructor(viewer, options = {}) { |
| | | super(viewer) |
| | | this.tooltip = new MapTooltip(viewer) |
| | | this.dataSource = null |
| | | this.ellipseEntity = null |
| | | this.startPosition = null |
| | | this.endPosition = null |
| | | this.centerCartesian = null |
| | | this.majorPoint = null |
| | | this.minorPoint = null |
| | | this.semiMajor = 0 |
| | | this.semiMinor = 0 |
| | | this.isDrawing = false |
| | | this.drawStep = 0 |
| | | this.isCompleted = false |
| | | this.style = resolveStyle(options?.style) |
| | | } |
| | | |
| | | start() { |
| | |
| | | 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.tooltip.show('单击设置起点', { x: 0, y: 0 }) |
| | | this.drawStep = 0 |
| | | this.isCompleted = false |
| | | this.tooltip.show('单击设置中心点', { x: 0, y: 0 }) |
| | | } |
| | | |
| | | handleLeftClick(click) { |
| | | if (this.isCompleted) return |
| | | const position = this.getPositionFromScreen(click.position) |
| | | if (!position) return |
| | | |
| | | if (!this.startPosition) { |
| | | this.startPosition = position |
| | | this.endPosition = position |
| | | if (this.drawStep === 0) { |
| | | this.centerCartesian = position |
| | | this.semiMajor = 1 |
| | | this.semiMinor = 1 |
| | | this.isDrawing = true |
| | | this.drawStep = 1 |
| | | this.createEntities() |
| | | this.tooltip.show('单击结束绘制', click.position) |
| | | this.tooltip.show('单击设置长轴', click.position) |
| | | return |
| | | } |
| | | |
| | | if (this.isDrawing) { |
| | | this.endPosition = position |
| | | this.updateEllipseByBounds() |
| | | if (this.drawStep === 1) { |
| | | this.majorPoint = position |
| | | this.semiMajor = Math.max(1, this.getSurfaceDistance(this.centerCartesian, this.majorPoint)) |
| | | this.semiMinor = this.semiMajor |
| | | this.drawStep = 2 |
| | | this.tooltip.show('单击设置短轴', click.position) |
| | | return |
| | | } |
| | | if (this.drawStep === 2) { |
| | | this.minorPoint = position |
| | | const minorRadius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, this.minorPoint)) |
| | | this.semiMinor = Math.min(minorRadius, this.semiMajor) |
| | | this.isDrawing = false |
| | | this.drawStep = 0 |
| | | this.isCompleted = true |
| | | const positions = buildEllipsePositions(this.centerCartesian, this.semiMajor, this.semiMinor) |
| | | this.notify('getPolygonPositions', positions) |
| | | this.tooltip.hide() |
| | |
| | | } |
| | | |
| | | handleMouseMove(movement) { |
| | | if (!this.isDrawing) { |
| | | this.tooltip.move(movement.endPosition) |
| | | return |
| | | } |
| | | if (this.isCompleted) return |
| | | this.tooltip.move(movement.endPosition) |
| | | if (!this.isDrawing) return |
| | | const position = this.getPositionFromScreen(movement.endPosition) |
| | | if (!position) return |
| | | this.endPosition = position |
| | | this.updateEllipseByBounds() |
| | | this.tooltip.move(movement.endPosition) |
| | | } |
| | | |
| | | updateEllipseByBounds() { |
| | | const bounds = getBoundsFromCartesians([this.startPosition, this.endPosition]) |
| | | const center = getCenterFromBounds(bounds) |
| | | if (!bounds || !center) return |
| | | this.centerCartesian = Cesium.Cartesian3.fromRadians(center.longitude, center.latitude) |
| | | const eastWest = getMetersBetween( |
| | | new Cesium.Cartographic(bounds.west, center.latitude), |
| | | new Cesium.Cartographic(bounds.east, center.latitude) |
| | | ) |
| | | const northSouth = getMetersBetween( |
| | | new Cesium.Cartographic(center.longitude, bounds.south), |
| | | new Cesium.Cartographic(center.longitude, bounds.north) |
| | | ) |
| | | this.semiMajor = Math.max(1, eastWest / 2) |
| | | this.semiMinor = Math.max(1, northSouth / 2) |
| | | if (this.drawStep === 1) { |
| | | const radius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position)) |
| | | this.semiMajor = radius |
| | | this.semiMinor = radius |
| | | return |
| | | } |
| | | if (this.drawStep === 2) { |
| | | const minorRadius = Math.max(1, this.getSurfaceDistance(this.centerCartesian, position)) |
| | | this.semiMinor = Math.min(minorRadius, this.semiMajor) |
| | | } |
| | | } |
| | | |
| | | createEntities() { |
| | |
| | | ellipse: { |
| | | semiMajorAxis: new Cesium.CallbackProperty(() => this.semiMajor, false), |
| | | semiMinorAxis: new Cesium.CallbackProperty(() => this.semiMinor, false), |
| | | material: Cesium.Color.fromBytes(45, 140, 240, 99), |
| | | material: this.style.fill, |
| | | outline: true, |
| | | outlineColor: Cesium.Color.fromBytes(45, 140, 240, 255), |
| | | outlineColor: this.style.outline, |
| | | outlineWidth: 2, |
| | | heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | 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 |
| | | } |
| | | |
| | | clearPreviewEntities() { |
| | |
| | | const cartesian = scene.pickPosition(screenPosition) |
| | | if (cartesian) return cartesian |
| | | return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid) |
| | | } |
| | | |
| | | setStyle(style) { |
| | | this.style = resolveStyle(style) |
| | | if (this.ellipseEntity?.ellipse) { |
| | | this.ellipseEntity.ellipse.material = this.style.fill |
| | | this.ellipseEntity.ellipse.outlineColor = this.style.outline |
| | | } |
| | | } |
| | | |
| | | destroy() { |
| | |
| | | } |
| | | this.tooltip?.destroy() |
| | | this.tooltip = null |
| | | this.startPosition = null |
| | | this.endPosition = null |
| | | this.centerCartesian = null |
| | | this.majorPoint = null |
| | | this.minorPoint = null |
| | | this.isDrawing = false |
| | | this.drawStep = 0 |
| | | this.isCompleted = false |
| | | } |
| | | } |