feat: 新增Polyline的绘制与编辑(待完善)。fix: window下的Cesium,Viewer对象改成cesium,viewer小写

pull/2/head
cbwu 12 months ago
parent 0134c112c0
commit eb3d03220c

@ -19,8 +19,6 @@ commit 提交信息时,必须是 **git commit -m 'fix: xxx'** 符合类型的
'build',//编译相关的修改,例如发布版本、对项目构建或者依赖的改动
```
## 地图库
- 地图采用开源的Cesium.js库版本为1.108.注不要随意升级版本天地图三维地形服务目前只支持1.108实测1.109也能用,更高版本则无法使用。

@ -1,3 +1,10 @@
<!--
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-07 09:19:24
* @LastEditors: cbwu
* @LastEditTime: 2024-04-02 13:19:05
* @Description:
-->
<!doctype html>
<html lang="en">
<head>

@ -1,11 +1,17 @@
<!--
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-07 14:15:35
* @LastEditors: cbwu
* @LastEditTime: 2024-04-02 14:14:36
* @Description:
-->
<template>
<div id="cesium-viewer" ref="viewerDivRef"></div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
// import * as Cesium from 'cesium'
import { Viewer } from 'cesium'
import { Viewer, Ion } from 'cesium'
import 'cesium/Build/Cesium/Widgets/widgets.css'
import {
TDTLayerType,
@ -15,13 +21,13 @@ import {
} from '@/utils/map/TDTProvider'
import { initViewer, perfViewer } from '@/utils/map/sceneViewer'
import { flyToChina } from '@/utils/map/camera'
import CreatePolyline from '@/utils/map/draw/drawPolyline'
const viewerDivRef = ref<HTMLDivElement>()
let viewer: Viewer
window.CESIUM_BASE_URL = 'node_modules/cesium/Build/Cesium/'
// window.CESIUM_BASE_URL = 'libs/cesium/' //
window.Cesium.Ion.defaultAccessToken =
Ion.defaultAccessToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3YjU4MjJlMS0wMWE4LTRhOWQtYjQ1OC04MTgzMzFhMzQ5ZjAiLCJpZCI6MTE1ODUxLCJpYXQiOjE2NjkyMDM1MzN9.8ajEuv3VKYg8wvFiQlUWWY6Ng6JfY4PuVgRyStL1B-E'
//
// window.Cesium.Camera.DEFAULT_VIEW_RECTANGLE =
@ -52,7 +58,11 @@ onMounted(() => {
viewer.terrainProvider = getTDTTerrainProvider()
// window
window.Viewer = viewer
window.viewer = viewer
//
// const drawPolyline = new CreatePolyline(viewer)
// drawPolyline.start()
})
</script>

6
src/global.d.ts vendored

@ -4,11 +4,11 @@ import type { Cesium, Viewer } from 'cesium'
// 扩展全局变量
declare global {
// 定义全局Cesium类型
const Cesium: Cesium
// const Cesium: Cesium
// 允许扩展 Window
interface Window {
Cesium: Cesium
cesium: Cesium
CESIUM_BASE_URL: string
Viewer: Viewer
viewer: Viewer
}
}

@ -1,3 +1,10 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-07 16:04:55
* @LastEditors: cbwu
* @LastEditTime: 2024-04-02 14:01:22
* @Description:
*/
// 天地图影像服务
import {
WebMapTileServiceImageryProvider,
@ -27,7 +34,7 @@ const subdomains = ['0', '1', '2', '3', '4', '5', '6', '7']
/**
*
* @param layerType :
* @param projectionType :WGS84
* @param projectionType :
* @param minimumLevel :
* @param maximumLevel :
* @returns :ImageryProvider
@ -79,7 +86,7 @@ export function getTDTTerrainProvider() {
terrainUrls.push(url)
}
const provider = new Cesium.GeoTerrainProvider({
const provider = new window.cesium.GeoTerrainProvider({
urls: terrainUrls,
})
return provider

@ -2,12 +2,12 @@
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-22 09:11:54
* @LastEditors: cbwu
* @LastEditTime: 2024-03-26 13:33:42
* @LastEditTime: 2024-04-01 09:21:17
* @Description:
*/
import { Cartesian2, Viewer, Math, Cartographic } from 'cesium'
import { Cartesian2, Viewer, Math, Cartographic, Cartesian3 } from 'cesium'
/**
*
*
* @param viewer
* @param windowPosition :
* @returns :
@ -27,11 +27,22 @@ function cartesian2ToCartesian3(viewer: Viewer, windowPosition: Cartesian2) {
function cartesian2ToWGS84(viewer: Viewer, windowPosition: Cartesian2) {
const cartesian3 = cartesian2ToCartesian3(viewer, windowPosition)
if (cartesian3 != undefined) {
const cartographic = Cartographic.fromCartesian(cartesian3)
return cartesian3ToWGS84(cartesian3)
} else return []
}
/**
* WGS84
* @param pos
* @returns
*/
function cartesian3ToWGS84(pos: Cartesian3) {
if (pos) {
const cartographic = Cartographic.fromCartesian(pos)
const lon = Math.toDegrees(cartographic.longitude) // 经度
const lat = Math.toDegrees(cartographic.latitude) // 纬度
const alt = cartographic.height // 高度
return [lon, lat, alt]
} else return []
}
return []
}
export { cartesian2ToCartesian3, cartesian2ToWGS84 }
export { cartesian2ToCartesian3, cartesian2ToWGS84, cartesian3ToWGS84 }

@ -0,0 +1,7 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-27 09:51:04
* @LastEditors: cbwu
* @LastEditTime: 2024-03-27 09:51:07
* @Description:
*/

@ -0,0 +1,197 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-27 08:43:44
* @LastEditors: cbwu
* @LastEditTime: 2024-04-02 13:33:25
* @Description: Polyline
*/
import {
Viewer,
ScreenSpaceEventHandler,
Cartesian3,
Color,
ScreenSpaceEventType,
Entity,
CallbackProperty,
PolylineDashMaterialProperty,
} from 'cesium'
import { cartesian2ToCartesian3 } from '@/utils/map/coordinate'
// import { PointEntity, PolylineEntity } from '@/utils/map/geometry'
import { PolylineEntity } from '../geometry/polylineEntity'
import { PointEntity } from '@/utils/map/geometry/pointEntity'
import EditGeometry from '@/utils/map/draw/editGeometry'
type EntityOptions = {
id?: string
name?: string
show?: boolean
pixelSize?: number
color?: Color
fillColor?: Color
fill?: boolean
width?: number
outlineWidth?: number
}
export default class CreatePolyline {
viewer: Viewer
handler: ScreenSpaceEventHandler
polyline: PolylineEntity | null
dashLine: Entity | null
trackingLine: Entity | null
trackingLinePositions: Cartesian3[] = []
controlPoints: Entity[] | null
modifyPoint: any = null
clickedGeometry: Entity | null = null
moveSelectedPoint: PointEntity | null = null
positions: Cartesian3[] = []
bMove: boolean = false
bLongClick: boolean = false
clickTimeout: any
// layer: CustomDataSource
defaultStyle: EntityOptions = {
// id: 'Polyline' + String(PolylineEntity.id),
// name: 'Polyline' + String(PolylineEntity.id + 1),
show: true,
width: 2,
color: Color.GREEN,
}
constructor(viewer: Viewer, options?: EntityOptions) {
this.viewer = viewer
this.handler = new ScreenSpaceEventHandler(this.viewer.scene.canvas)
this.polyline = null
this.trackingLine = null
this.dashLine = null
this.controlPoints = []
this.defaultStyle = { ...this.defaultStyle, ...options }
}
// 开始绘制
public start() {
// 左单击加点
this.handler.setInputAction(
this.leftClickCallBack,
ScreenSpaceEventType.LEFT_CLICK,
)
// 移动动态绘制
this.handler.setInputAction(
this.moveCallBack,
ScreenSpaceEventType.MOUSE_MOVE,
)
// 左双击结束
this.handler.setInputAction(
this.leftDoubleClickCallBack,
ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
)
// 右击回退上一步
this.handler.setInputAction(
this.rightClickCallBack,
ScreenSpaceEventType.RIGHT_CLICK,
)
}
public end() {
this.handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK)
}
//左单击回调事件
private leftClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
const pickedObject = this.viewer.scene.pick(event.position)
// console.log(pickedObject)
if (pickedObject) {
//点击同一位置,返回
if (
pickedObject.id.id ===
this.polyline?.controlPointsID[this.positions.length - 1]
) {
return
// console.log('********click the same point')
}
}
const cartesian3 = cartesian2ToCartesian3(this.viewer, event.position)
if (cartesian3 != undefined) {
if (!this.polyline) {
this.polyline = new PolylineEntity(this.positions)
this.dashLine = this.createTrackingLine(this.positions)
this.viewer.entities.add(this.dashLine)
this.viewer.dataSources.add(this.polyline)
}
this.polyline.addPoint(cartesian3)
this.trackingLinePositions[0] = cartesian3
this.bMove = true
this.viewer.scene.requestRender() //刷新
}
}
// 移动回调事件
private moveCallBack = (event: ScreenSpaceEventHandler.MotionEvent) => {
if (this.bMove) {
const cartesian3 = cartesian2ToCartesian3(this.viewer, event.endPosition)
if (cartesian3 != undefined) {
//更新追踪线坐标
this.trackingLinePositions[1] = cartesian3
if (!this.trackingLine) {
//创建追踪线对象
this.trackingLine = this.createTrackingLine(
this.trackingLinePositions,
)
this.viewer.entities.add(this.trackingLine)
}
}
this.viewer.scene.requestRender() //刷新
}
}
// 左双击回调事件
private leftDoubleClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
// 清除可能已经设置的单击定时器
// clearTimeout(this.clickTimeout)
if (!this.polyline) return
console.log('**************************** double click')
this.bMove = false
const cartesian3 = cartesian2ToCartesian3(this.viewer, event.position)
if (cartesian3 != undefined) {
// 移除追踪线
if (!this.trackingLine) {
this.viewer.entities.remove(this.trackingLine!)
}
}
this.clearEvent()
console.log('end:' + this.positions.length.toString())
console.log(this.positions)
//结束绘制进入编辑模式
this.polyline.removeControlPoints()
const editTool = new EditGeometry(this.viewer, this.polyline.geometry!)
editTool.start()
}
// 右击回调事件
private rightClickCallBack = () => {
if (!this.controlPoints) return
if (this.controlPoints.length > 1) {
const lastPoint = this.positions.pop()
this.positions[this.positions.length - 1] = lastPoint!
this.viewer.entities.remove(this.controlPoints.pop() as Entity)
}
}
clearEvent() {
this.handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK)
this.handler.removeInputAction(ScreenSpaceEventType.MOUSE_MOVE)
this.handler.removeInputAction(ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
}
createTrackingLine(positions: Cartesian3[]) {
return new Entity({
polyline: {
positions: new CallbackProperty(() => {
return positions
}, false),
width: 2,
material: new PolylineDashMaterialProperty({
color: Color.GREEN,
dashLength: 15, //短划线长度
}),
clampToGround: true,
},
})
}
}

@ -0,0 +1,249 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-27 11:06:45
* @LastEditors: cbwu
* @LastEditTime: 2024-04-02 11:05:20
* @Description:
*/
import {
Viewer,
ScreenSpaceEventHandler,
PointGraphics,
PolylineGraphics,
Cartesian3,
ConstantProperty,
ScreenSpaceEventType,
Entity,
ConstantPositionProperty,
defined,
} from 'cesium'
import { cartesian2ToCartesian3 } from '@/utils/map/coordinate'
import { getClosestPoint, isOnLineSegment } from '@/utils/map/geocomputation'
import { PointEntity } from '@/utils/map/geometry/pointEntity'
export default class EditGeometry {
viewer: Viewer
editHandler: ScreenSpaceEventHandler
geometry: Entity //要编辑的几何对象
oldPositions: Cartesian3[] = [] //存储未修改前的坐标
positions: Cartesian3[] = [] //要编辑的几个对象坐标
controlPointsID: string[] = []
controlPoint: PointEntity | null = null
clickedGeometry: Entity | null = null
clickDownPosition: Cartesian3 | null = null
moveSelectedPoint: PointEntity | null = null
bDrag: boolean = false //拖动标识
bLongClick: boolean = false //长按标识
clickTimeout: any
constructor(viewer: Viewer, editGeometry: Entity) {
this.viewer = viewer
this.editHandler = new ScreenSpaceEventHandler(this.viewer.scene.canvas)
this.geometry = editGeometry
this.positions = editGeometry.polyline?.positions?.getValue(
this.viewer.clock.currentTime,
)
this.oldPositions = this.positions
// 创建控制点
this.positions.forEach((value, index) => {
this.createPoint(value, index)
})
}
public start() {
this.editHandler.setInputAction(
this.leftDownClickCallBack,
ScreenSpaceEventType.LEFT_DOWN,
)
this.editHandler.setInputAction(
this.moveCallBack,
ScreenSpaceEventType.MOUSE_MOVE,
)
this.editHandler.setInputAction(
this.leftUpClickCallBack,
ScreenSpaceEventType.LEFT_UP,
)
}
//左键点击回调
private leftClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
const pickedObject = this.viewer.scene.pick(event.position)
// 点中控制点
if (
defined(pickedObject) &&
defined(pickedObject.id) &&
pickedObject.id.point instanceof PointGraphics
) {
console.log('You clicked a point entity.')
this.controlPoint = pickedObject.id
console.log(this.controlPoint?.subId)
this.bDrag = true
this.forbidDrawWorld(true)
}
}
//左键按下回调
private leftDownClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
// 清除可能已经设置的单击定时器
clearTimeout(this.clickTimeout)
// 判断是不是长按
this.clickTimeout = setTimeout(() => {
this.bLongClick = true
}, 100)
const pickedObject = this.viewer.scene.pick(event.position)
//点中实体对象
if (defined(pickedObject) && defined(pickedObject.id)) {
// 记录点击的几何对象及位置
this.clickedGeometry = pickedObject.id
this.clickDownPosition = this.viewer.scene.pickPosition(event.position)
// // 判断是否同一实体
// if (this.geometry != pickedObject.id) {
// this.geometry = pickedObject.id
// if (
// pickedObject instanceof PolylineGraphics &&
// pickedObject.positions
// ) {
// this.oldPositions = this.geometry!.polyline!.positions?.getValue(
// this.viewer.clock.currentTime,
// )
// }
// }
// 点中控制点
if (pickedObject.id.point instanceof PointGraphics) {
console.log('You clicked a point entity.')
this.controlPoint = pickedObject.id
console.log(this.controlPoint?.subId)
this.bDrag = true
this.forbidDrawWorld(true)
}
}
}
//移动回调
private moveCallBack = (event: ScreenSpaceEventHandler.MotionEvent) => {
const pickedObject = this.viewer.scene.pick(event.endPosition)
// 悬停控制点放大
if (
pickedObject &&
pickedObject.id &&
pickedObject.id.point instanceof PointGraphics
) {
if (pickedObject.id.point instanceof PointGraphics) {
if (
this.moveSelectedPoint == null ||
this.moveSelectedPoint.id !== pickedObject.id.id
) {
this.moveSelectedPoint = pickedObject.id
this.moveSelectedPoint!.point!.pixelSize = new ConstantProperty(
this.moveSelectedPoint!.options.pixelSize! + 2,
)
// console.log(this.moveSelectedPoint)
}
this.viewer.scene.requestRender() //刷新
}
} else {
// 离开控制点恢复原始大小
if (this.moveSelectedPoint) {
this.moveSelectedPoint!.point!.pixelSize = new ConstantProperty(
this.moveSelectedPoint!.options.pixelSize! - 2,
)
this.moveSelectedPoint = null
this.viewer.scene.requestRender() //刷新
}
}
if (!this.controlPoint || !this.bDrag) return
console.log('************************left down')
const cartesian3 = cartesian2ToCartesian3(this.viewer, event.endPosition)
if (cartesian3) {
// 修改节点坐标
this.modifyPoint(cartesian3, this.controlPoint.subId)
// this.geometry?.modifyPoint(cartesian3, this.controlPoint.subId)
this.viewer.scene.requestRender() //刷新
}
}
//左键松开回调
private leftUpClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
clearTimeout(this.clickTimeout)
// 单击添加点
if (
!this.bLongClick &&
this.clickedGeometry?.polyline instanceof PolylineGraphics
) {
console.log('点中线,加点')
this.addPoint()
}
this.bLongClick = false
this.bDrag = false
this.forbidDrawWorld(false)
}
// 左键双击回调
private leftDoubleClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
// this.geometry.
}
// Viewer操作控制
forbidDrawWorld(isForbid: boolean) {
this.viewer.scene.screenSpaceCameraController.enableRotate = !isForbid
this.viewer.scene.screenSpaceCameraController.enableTilt = !isForbid
this.viewer.scene.screenSpaceCameraController.enableTranslate = !isForbid
this.viewer.scene.screenSpaceCameraController.enableInputs = !isForbid
}
// 添加点
addPoint() {
for (let i = 0; i < this.positions.length - 1; ++i) {
if (
isOnLineSegment(
this.positions[i],
this.positions[i + 1],
this.clickDownPosition!,
)
) {
// 修改线坐标
const pt = getClosestPoint(
this.positions[i],
this.positions[i + 1],
this.clickDownPosition!,
)
this.positions.splice(i + 1, 0, pt)
// 新建控制点
this.createPoint(pt, i + 1)
// 修改控制点的subid
for (let index = i + 2; index < this.controlPointsID.length; ++index) {
const point = this.geometry.entityCollection.getById(
this.controlPointsID[index],
) as PointEntity
point!.subId = point!.subId + 1
}
return
}
}
}
/**
*
* @param pos
* @param index
*/
modifyPoint(pos: Cartesian3, index: number) {
// 修改线坐标
this.positions.splice(index, 1, pos)
// 修改控制点坐标
this.controlPoint!.position = new ConstantPositionProperty(pos)
}
/**
*
* @param pos
* @param index ,0
*/
createPoint(pos: Cartesian3, index: number) {
// if (this.geometry) {
const point = new PointEntity(pos)
point.parent = this.geometry
point.subId = index
this.geometry.entityCollection.add(point)
this.controlPointsID.splice(index, 0, point.id)
// }
}
}

@ -0,0 +1,231 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-28 09:14:45
* @LastEditors: cbwu
* @LastEditTime: 2024-03-28 17:40:14
* @Description:
*/
import {
Entity,
EntityCollection,
Cartesian3,
Color,
PrimitiveCollection,
PointPrimitiveCollection,
PolylineGeometry,
PointGraphics,
Property,
PositionProperty,
LabelGraphics,
PolylineGraphics,
PolygonGraphics,
Cartesian2,
ConstantPositionProperty,
CallbackProperty,
} from 'cesium'
type EntityOptions = {
id?: string
name?: string
show?: boolean
pixelSize?: number
outlineColor?: Color
color?: Color
fillColor?: Color
fill?: boolean
width?: number
outlineWidth?: number
text?: string
font?: string
pixelOffset?: Cartesian2
}
// 点
class PointEntity extends Entity {
static ID: number = 0
public subId: number = 0 //用于作为其他几何体的控制点时标记节点号
options: EntityOptions = {
id: 'Point' + String(PointEntity.ID),
name: 'Point' + String(PointEntity.ID + 1),
show: true,
pixelSize: 10,
color: Color.GREEN,
outlineWidth: 0,
}
constructor(
position: PositionProperty | Cartesian3,
options?: EntityOptions,
) {
super({
position: position,
})
this.options = { ...this.options, ...options }
//点对象
this.point = new PointGraphics({
pixelSize: this.options.pixelSize,
color: this.options.color,
outlineColor: this.options.outlineColor,
outlineWidth: this.options.outlineWidth,
})
// 标注对象
this.label = new LabelGraphics({
text: this.options.text,
font: this.options.font,
pixelOffset: this.options.pixelOffset,
})
PointEntity.ID++
}
}
// 线
class PolylineEntity extends EntityCollection {
static ID: number = 0
positions: Cartesian3[] = []
controlPointsID: string[] = []
options: EntityOptions = {
id: 'Polyline' + String(PolylineEntity.ID),
name: 'Polyline' + String(PolylineEntity.ID + 1),
show: true,
width: 2,
color: Color.GREEN,
}
constructor(ptArr: Cartesian3[], options?: EntityOptions) {
super()
this.options = { ...this.options, ...options }
this.positions = ptArr
const polyline = new Entity({
name: this.options.name,
polyline: {
positions: new CallbackProperty(() => {
return this.positions
}, false),
show: this.options.show,
width: this.options.width,
material: this.options.color,
},
})
this.add(polyline)
ptArr.forEach((pt, index) => {
this.createPoint(pt, index)
})
PolylineEntity.ID++
}
/**
* ,
* @param pos
* @param index 0
*/
public addPoint(pos: Cartesian3, index: number = -1) {
if (index === -1) {
//插入尾部
this.positions.push(pos)
this.createPoint(pos, this.positions.length - 1)
} else if (index >= 0 && index < this.positions.length) {
this.positions.splice(index, 0, pos)
this.createPoint(pos, index)
} else {
return
}
}
/**
*
* @param index
* @returns
*/
public removePoint(index: number = -1) {
if (index === -1 || index === this.positions.length - 1) {
//移除尾部元素
this.positions.pop()
} else if (index >= 0 && index < this.positions.length) {
this.positions.splice(index, 1)
this.removeById(this.controlPointsID[index])
this.controlPointsID.splice(index, 1)
} else {
return
}
}
/**
*
* @param pos
* @param index
*/
public modifyPoint(pos: Cartesian3, index: number) {
if (index >= 0 && index < this.positions.length) {
this.positions.splice(index, 1, pos)
//修改控制点坐标
const point = this.getById(this.controlPointsID[index])
if (point) {
point.position = new ConstantPositionProperty(pos)
}
}
}
/**
*
* @param pos
* @param index ,0
*/
createPoint(pos: Cartesian3, index: number) {
const point = new PointEntity(pos)
point.subId = index + 1
this.add(point)
this.controlPointsID.splice(index, 0, point.id)
}
}
// 多边形
class PolygonEntity extends Entity {
static id: number = 0
options: EntityOptions = {
id: 'Polygon' + String(PolygonEntity.id),
name: 'Polygon' + String(PolygonEntity.id + 1),
show: true,
width: 2,
color: Color.RED,
fillColor: Color.RED.withAlpha(0.5),
fill: true,
}
constructor(ptArr: Cartesian3[] | Property, options?: EntityOptions) {
super({
// id: options?.id || String(PolygonEntity.id),
})
this.options = { ...this.options, ...options }
this.name = this.options.name
this.polygon = new PolygonGraphics({
show: this.options.show,
hierarchy: ptArr,
material: this.options.fillColor, //填充颜色
fill: this.options.fill, //是否填充
outlineWidth: this.options.width, //线宽
outlineColor: this.options.color, //线颜色
})
PolygonEntity.id++
}
}
// 线
class Polyline extends PrimitiveCollection {
constructor(ptArr: Cartesian3[]) {
super()
this.add(this.createPoints(ptArr))
this.add(this.createPolyline(ptArr))
// this.id
}
private createPoints(posArr: Cartesian3[]) {
const points = new PointPrimitiveCollection()
for (const pos in posArr) {
points.add({
position: pos,
color: Color.RED,
pixelSize: 10,
})
}
return points
}
private createPolyline(posArr: Cartesian3[]) {
return new PolylineGeometry({
positions: posArr,
width: 2,
colors: new Array(posArr.length).fill(Color.fromCssColorString('green')),
})
}
}
export { PointEntity, Polyline, PolylineEntity, PolygonEntity }

@ -0,0 +1,185 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-15 08:43:26
* @LastEditors: cbwu
* @LastEditTime: 2024-03-26 14:20:32
* @FilePath: \GCSMap\src\utils\drawer.ts
* @Description:
*/
import {
Viewer,
ScreenSpaceEventHandler,
ScreenSpaceEventType,
CustomDataSource,
Cartesian3,
CallbackProperty,
PolygonHierarchy,
Color,
} from 'cesium'
import { cartesian2ToCartesian3 } from '@/utils/map/coordinate'
import {
PointEntity,
PolylineEntity,
PolygonEntity,
} from '@/utils/map/geometry'
class Drawer {
viewer: Viewer
type: string
handler: ScreenSpaceEventHandler
layer: CustomDataSource
polyline: PolylineEntity | null
polygon: PolygonEntity | null
positions: Cartesian3[] = []
n_Points: number
bMove: boolean
clickTimeout: any
constructor(viewer: Viewer, type: string) {
this.viewer = viewer
this.type = type
this.handler = new ScreenSpaceEventHandler(this.viewer.canvas)
this.polyline = null
this.polygon = null
this.n_Points = 0
this.bMove = false
this.positions = []
this.clickTimeout = null
if (viewer.dataSources.getByName(type).length === 0) {
this.layer = new CustomDataSource(type)
viewer.dataSources.add(this.layer)
} else {
this.layer = viewer.dataSources.getByName(type)[0]
}
}
// 开始绘制
public start() {
// 左单击加点
this.handler.setInputAction(
this.leftClickCallBack,
ScreenSpaceEventType.LEFT_CLICK,
)
// 移动动态绘制
this.handler.setInputAction(
this.moveCallBack,
ScreenSpaceEventType.MOUSE_MOVE,
)
// 左双击结束
this.handler.setInputAction(
this.leftDoubleClickCallBack,
ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
)
}
public end() {
this.handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK)
}
//左单击回调事件
private leftClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
// 清除可能已经设置的单击定时器
clearTimeout(this.clickTimeout)
console.log('**************************** click')
// 设置一个新的定时器,用于判断是单击还是双击
this.clickTimeout = setTimeout(() => {
console.log('**************************** run')
const cartesian3 = cartesian2ToCartesian3(this.viewer, event.position)
if (cartesian3 != undefined) {
if (this.bMove) {
this.positions.pop()
this.bMove = false
}
this.positions.push(cartesian3)
this.createGeometry(this.type)
// 创建控制点
const point = new PointEntity(
this.positions[this.positions.length - 1],
{
color: Color.WHITE,
pixelSize: 6,
},
)
point.parent = this.polygon!
this.layer.entities.add(point)
this.viewer.scene.requestRender() //刷新
}
}, 100)
}
// 移动回调事件
private moveCallBack = (event: ScreenSpaceEventHandler.MotionEvent) => {
const cartesian3 = cartesian2ToCartesian3(this.viewer, event.endPosition)
if (cartesian3 != undefined) {
if (this.positions.length >= 1) {
if (!this.bMove) {
this.positions.push(cartesian3)
this.bMove = true
} else {
this.positions[this.positions.length - 1] = cartesian3
}
if (this.type === 'Polygon') {
// 多边形创建临时线
if (this.positions.length === 2) {
this.createGeometry('Polyline')
}
if (this.positions.length > 2) {
this.polyline!.show = false
}
}
}
this.viewer.scene.requestRender() //刷新
}
}
// 左双击回调事件
private leftDoubleClickCallBack = (
event: ScreenSpaceEventHandler.PositionedEvent,
) => {
// 清除可能已经设置的单击定时器
clearTimeout(this.clickTimeout)
console.log('**************************** double click')
const cartesian3 = cartesian2ToCartesian3(this.viewer, event.position)
if (cartesian3 != undefined) {
this.positions.pop()
this.positions.push(cartesian3)
}
this.clearEvent()
console.log('end:' + this.positions.length.toString())
console.log(this.positions)
}
clearEvent() {
this.handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK)
this.handler.removeInputAction(ScreenSpaceEventType.MOUSE_MOVE)
this.handler.removeInputAction(ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
}
// 创建几何体
createGeometry(type: string) {
switch (type) {
case 'Polyline':
if (this.polyline == null) {
this.polyline = new PolylineEntity(
new CallbackProperty(() => {
return this.positions
}, false),
)
this.layer.entities.add(this.polyline)
// this.viewer.entities.add(this.polyline)
}
break
case 'Polygon':
if (this.polygon == null) {
this.polygon = new PolygonEntity(
new CallbackProperty(() => {
return new PolygonHierarchy(this.positions)
}, false),
)
this.layer.entities.add(this.polygon)
// this.viewer.entities.add(this.polygon)
console.log('Polygon created!')
}
break
default:
break
}
}
}
export { Drawer }

@ -2,6 +2,87 @@
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-22 15:42:49
* @LastEditors: cbwu
* @LastEditTime: 2024-03-22 15:43:23
* @LastEditTime: 2024-04-01 14:05:43
* @Description:
*/
import { Cartesian3, Math as Cesium_Math } from 'cesium'
/**
* 线
* @param lineStart 线[longitude1, latitude1, height1]
* @param lineEnd 线:[longitude2, latitude2, height2]
* @param point :[[longitude3, latitude3, height3]]
* @returns
*/
function getClosestPoint(
lineStart: Cartesian3,
lineEnd: Cartesian3,
point: Cartesian3,
): Cartesian3 {
// 计算直线方向向量
const lineDirection = new Cartesian3()
Cartesian3.subtract(lineEnd, lineStart, lineDirection)
Cartesian3.normalize(lineDirection, lineDirection)
// 计算点到直线起点的向量
const pointToStart = new Cartesian3()
Cartesian3.subtract(point, lineStart, pointToStart)
// 计算投影长度,即点到直线的向量在直线方向向量上的分量长度
const projectionLength = Cartesian3.dot(pointToStart, lineDirection)
// 使用标量乘法和向量加法确定交点
const closestPoint = new Cartesian3()
Cartesian3.multiplyByScalar(lineDirection, projectionLength, closestPoint)
Cartesian3.add(lineStart, closestPoint, closestPoint)
return closestPoint
}
/**
* 线
* @param lineStart 线[longitude1, latitude1, height1]
* @param lineEnd 线[longitude2, latitude2, height2]
* @param pointToCheck 线[longitude3, latitude3, height3]
* @param tolerance
* @returns 线
*/
function isOnLineSegment(
lineStart: Cartesian3,
lineEnd: Cartesian3,
pointToCheck: Cartesian3,
tolerance: number = Cesium_Math.EPSILON1,
): boolean {
const dist_AP = Cartesian3.distance(lineStart, pointToCheck)
const dist_BP = Cartesian3.distance(lineEnd, pointToCheck)
const dist_AB = Cartesian3.distance(lineStart, lineEnd)
const isCollinear = Math.abs(dist_AP + dist_BP - dist_AB) < tolerance
return isCollinear
/*
const startToEnd = new Cartesian3()
const startToPoint = new Cartesian3()
const endToPoint = new Cartesian3()
// 计算向量
Cartesian3.subtract(lineEnd, lineStart, startToEnd)
Cartesian3.subtract(pointToCheck, lineStart, startToPoint)
Cartesian3.subtract(pointToCheck, lineEnd, endToPoint)
// 判断共线
const cross = Cartesian3.cross(startToEnd, startToPoint, new Cartesian3())
console.log('cross:' + Cartesian3.magnitude(cross).toString())
// Math.EPSILON6 是一个非常小的值,用来防止浮点数计算的误差
const isCollinear = Cartesian3.magnitude(cross) < tolerance
// 判断点是否在线段之间
let isBetween = false
if (isCollinear) {
const dotProduct1 = Cartesian3.dot(startToEnd, startToPoint)
const dotProduct2 = Cartesian3.dot(startToEnd, endToPoint)
isBetween = dotProduct1 >= 0 && dotProduct2 <= 0
}
return isBetween
*/
}
export { getClosestPoint, isOnLineSegment }

@ -1,134 +0,0 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-20 08:55:59
* @LastEditors: cbwu
* @LastEditTime: 2024-03-26 09:00:46
* @Description:
*/
import {
Entity,
Cartesian3,
Color,
PrimitiveCollection,
PointPrimitiveCollection,
PolylineGeometry,
PointGraphics,
Property,
PolylineGraphics,
PolygonGraphics,
} from 'cesium'
type EntityOptions = {
id?: string
name?: string
show?: boolean
pixelSize?: number
color?: Color
fillColor?: Color
fill?: boolean
width?: number
outlineWidth?: number
}
// 点
class PointEntity extends Entity {
static id: number = 0
options: EntityOptions = {
id: 'Point' + String(PointEntity.id),
name: 'Point' + String(PointEntity.id + 1),
show: true,
pixelSize: 10,
color: Color.GREEN,
outlineWidth: 0,
}
constructor(position: Cartesian3, options?: EntityOptions) {
super({
// id: options?.id || String(PointEntity.id),
position: position,
})
this.options = { ...this.options, ...options }
this.name = this.options.name
this.point = new PointGraphics({ ...this.options })
PointEntity.id++
}
}
// 线
class PolylineEntity extends Entity {
static id: number = 0
options: EntityOptions = {
id: 'Polyline' + String(PolylineEntity.id),
name: 'Polyline' + String(PolylineEntity.id + 1),
show: true,
width: 2,
color: Color.GREEN,
}
constructor(ptArr: Cartesian3[] | Property, options?: EntityOptions) {
super({
// id: options?.id || String(PolylineEntity.id),
})
this.options = { ...this.options, ...options }
this.name = this.options.name
this.polyline = new PolylineGraphics({
positions: ptArr,
show: this.options.show,
width: this.options.width,
material: this.options.color,
})
PolylineEntity.id++
}
}
// 多边形
class PolygonEntity extends Entity {
static id: number = 0
options: EntityOptions = {
id: 'Polygon' + String(PolygonEntity.id),
name: 'Polygon' + String(PolygonEntity.id + 1),
show: true,
width: 2,
color: Color.RED,
fillColor: Color.RED.withAlpha(0.5),
fill: true,
}
constructor(ptArr: Cartesian3[] | Property, options?: EntityOptions) {
super({
// id: options?.id || String(PolygonEntity.id),
})
this.options = { ...this.options, ...options }
this.name = this.options.name
this.polygon = new PolygonGraphics({
show: this.options.show,
hierarchy: ptArr,
material: this.options.fillColor, //填充颜色
fill: this.options.fill, //是否填充
outlineWidth: this.options.width, //线宽
outlineColor: this.options.color, //线颜色
})
PolygonEntity.id++
}
}
// 线
class Polyline extends PrimitiveCollection {
constructor(ptArr: Cartesian3[]) {
super()
this.add(this.createPoints(ptArr))
this.add(this.createPolyline(ptArr))
// this.id
}
private createPoints(posArr: Cartesian3[]) {
const points = new PointPrimitiveCollection()
for (const pos in posArr) {
points.add({
position: pos,
color: Color.RED,
pixelSize: 10,
})
}
return points
}
private createPolyline(posArr: Cartesian3[]) {
return new PolylineGeometry({
positions: posArr,
width: 2,
colors: new Array(posArr.length).fill(Color.fromCssColorString('green')),
})
}
}
export { PointEntity, Polyline, PolylineEntity, PolygonEntity }

@ -0,0 +1,109 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-28 16:22:58
* @LastEditors: cbwu
* @LastEditTime: 2024-04-02 14:09:15
* @Description:
*/
import {
// EntityCollection,
Entity,
Cartesian3,
Color,
ConstantPositionProperty,
CustomDataSource,
} from 'cesium'
import { PointEntity, EntityOptions } from './pointEntity'
export abstract class BaseGeometry extends CustomDataSource {
static ID: number
// abstract subId: number
geometry: Entity | null = null
positions: Cartesian3[] = []
controlPointsID: string[] = [] //存储
options: EntityOptions = {
// id: 'Point' + String(PointEntity.ID),
// name: 'Point' + String(PointEntity.ID + 1),
show: true,
// pixelSize: 10,
width: 2,
color: Color.GREEN,
outlineWidth: 0,
}
constructor() {
super()
}
/**
* ,
* @param pos
* @param index 0
*/
public addPoint(pos: Cartesian3, index: number = -1) {
if (index === -1) {
//插入尾部
this.positions.push(pos)
// console.log(this.positions.length)
this.createPoint(pos, this.positions.length - 1)
} else if (index >= 0 && index < this.positions.length) {
this.positions.splice(index, 0, pos)
this.createPoint(pos, index)
} else {
return
}
}
/**
*
* @param index
* @returns
*/
public removePoint(index: number = -1) {
if (index === -1 || index === this.positions.length - 1) {
//移除尾部元素
this.positions.pop()
} else if (index >= 0 && index < this.positions.length) {
this.positions.splice(index, 1)
this.entities.removeById(this.controlPointsID[index])
this.controlPointsID.splice(index, 1)
} else {
return
}
}
/**
*
* @param pos
* @param index
*/
public modifyPoint(pos: Cartesian3, index: number) {
if (index >= 0 && index < this.positions.length) {
this.positions.splice(index, 1, pos)
//修改控制点坐标
const point = this.entities.getById(this.controlPointsID[index])
if (point) {
point.position = new ConstantPositionProperty(pos)
}
}
}
/**
*
* @param pos
* @param index ,0
*/
createPoint(pos: Cartesian3, index: number) {
// if (this.geometry) {
const point = new PointEntity(pos)
point.parent = this.geometry!
point.subId = index
this.entities.add(point)
this.controlPointsID.splice(index, 0, point.id)
// }
}
/**
*
*/
removeControlPoints() {
this.controlPointsID.forEach((value) => {
this.entities.removeById(value)
})
this.controlPointsID = []
}
}

@ -0,0 +1,69 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-28 16:35:33
* @LastEditors: cbwu
* @LastEditTime: 2024-03-30 22:06:23
* @Description:
*/
import {
Entity,
Cartesian3,
Color,
PointGraphics,
PositionProperty,
LabelGraphics,
Cartesian2,
CallbackProperty,
Property,
} from 'cesium'
type EntityOptions = {
id?: string
name?: string
show?: boolean
pixelSize?: number
outlineColor?: Color
color?: Color
fillColor?: Color
fill?: boolean
width?: number
outlineWidth?: number
text?: string
font?: string
pixelOffset?: Cartesian2
}
// 点
class PointEntity extends Entity {
static ID: number = 0
public subId: number = 0 //用于作为其他几何体的控制点时标记节点号
options: EntityOptions = {
id: 'Point' + String(PointEntity.ID),
name: 'Point' + String(PointEntity.ID + 1),
show: true,
pixelSize: 10,
color: Color.GREEN,
outlineWidth: 0,
}
constructor(position: Cartesian3, options?: EntityOptions) {
super({
position: position,
})
this.options = { ...this.options, ...options }
//点对象
this.point = new PointGraphics({
pixelSize: this.options.pixelSize,
color: this.options.color,
outlineColor: this.options.outlineColor,
outlineWidth: this.options.outlineWidth,
})
// 标注对象
this.label = new LabelGraphics({
text: this.options.text,
font: this.options.font,
pixelOffset: this.options.pixelOffset,
})
PointEntity.ID++
}
}
export { PointEntity, type EntityOptions }

@ -0,0 +1,48 @@
/*
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-28 16:49:02
* @LastEditors: cbwu
* @LastEditTime: 2024-04-01 17:04:55
* @Description: Polyline
*/
import { Entity, Cartesian3, Color, CallbackProperty } from 'cesium'
import { BaseGeometry } from './baseGeometry'
import { type EntityOptions } from './pointEntity'
export class PolylineEntity extends BaseGeometry {
static ID: number = 0
// positions: Cartesian3[] = []
controlPointsID: string[] = []
options: EntityOptions = {
// id: 'Polyline' + String(PolylineEntity.ID),
name: 'Polyline' + String(PolylineEntity.ID + 1),
show: true,
width: 3,
color: Color.GREEN,
}
constructor(ptArr: Cartesian3[], options?: EntityOptions) {
super()
this.options = { ...this.options, ...options }
// console.log(this.options)
this.positions = ptArr
// console.log(this.positions)
// 创建线实体对象
this.geometry = new Entity({
name: this.options.name,
polyline: {
positions: new CallbackProperty(() => {
return this.positions
}, false),
show: this.options.show,
width: this.options.width,
material: this.options.color,
},
})
this.entities.add(this.geometry)
// 添加控制点
ptArr.forEach((pt, index) => {
this.createPoint(pt, index)
})
PolylineEntity.ID++
}
}

@ -2,7 +2,7 @@
* @Author: cbwu 504-wuchengbo@htsdfp.com
* @Date: 2024-03-13 09:32:21
* @LastEditors: cbwu
* @LastEditTime: 2024-03-26 13:27:27
* @LastEditTime: 2024-04-02 13:49:26
* @Description:
*/
// Viewer初始化
@ -13,6 +13,7 @@ import {
RequestScheduler,
SceneMode,
buildModuleUrl,
ScreenSpaceEventType,
} from 'cesium'
//离线地球底图
@ -49,6 +50,8 @@ function initViewer(container: string | Element): Viewer {
//去除cesium logo隐藏版本信息
const creditContainer = viewer.cesiumWidget.creditContainer as HTMLDivElement
creditContainer.style.display = 'none'
// 开启深度检测
viewer.scene.globe.depthTestAgainstTerrain = true
// 水雾特效
viewer.scene.globe.showGroundAtmosphere = true
// 设置更高的缩放惯性以使缩放操作更平滑
@ -58,10 +61,10 @@ function initViewer(container: string | Element): Viewer {
viewer.scene.screenSpaceCameraController.maximumZoomDistance = 20000000 //相机高度的最大值
// 去掉entity的点击事件双击、单击
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
)
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
Cesium.ScreenSpaceEventType.LEFT_CLICK,
ScreenSpaceEventType.LEFT_CLICK,
)
return viewer
}

Loading…
Cancel
Save