easy-three-utils 0.0.346 → 0.0.347

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cesium/index.ts CHANGED
@@ -87,7 +87,9 @@ const useCesium = () => {
87
87
  const clipping = hooks.useClipping(viewer)
88
88
  const weather = hooks.useWeather(viewer)
89
89
  const measure = hooks.useMeasure(viewer, {
90
- distanceCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_DISTANCE)
90
+ distanceCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_DISTANCE),
91
+ heightCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_HEIGHT),
92
+ areaCollection: customCollection.addCollection(hooks.dict.ECollectionWhiteListNames.MEASURE_AREA)
91
93
  })
92
94
 
93
95
  if (config.controllerStyle === cesiumConfigDict.EControllerStyle.THREE) {
@@ -5,12 +5,14 @@ enum ECollectionWhiteListNames {
5
5
  POLYGON = 'polygon',
6
6
 
7
7
  MEASURE_DISTANCE = 'measure_distance',
8
+ MEASURE_HEIGHT = 'measure_height',
9
+ MEASURE_AREA = 'measure_area'
8
10
  }
9
11
 
10
12
  const useCustomCollection = (viewer: Cesium.Viewer) => {
11
13
 
12
14
  let collectionNames: string[] = ([])
13
- let whiteList: string[] = ['polygon', 'polygon_node']
15
+ let whiteList: string[] = ['polygon', 'polygon_node', 'measure_distance', 'measure_height', 'measure_area']
14
16
 
15
17
  const addCollection = (name: string) => {
16
18
  const index = collectionNames.findIndex(item => item === name)
@@ -1,17 +1,12 @@
1
1
  import * as Cesium from 'cesium'
2
+ import * as turf from "@turf/turf"
2
3
 
3
4
  const useMeasure = (viewer: Cesium.Viewer, options: {
4
- distanceCollection: Cesium.CustomDataSource
5
+ distanceCollection: Cesium.CustomDataSource,
6
+ heightCollection: Cesium.CustomDataSource,
7
+ areaCollection: Cesium.CustomDataSource
5
8
  }) => {
6
9
 
7
- const point = {
8
- color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
9
- outlineColor: Cesium.Color.WHITE,
10
- outlineWidth: 2,
11
- pixelSize: 10,
12
- heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
13
- }
14
-
15
10
  const angleMeasurement = () => {
16
11
  let anglePoints = []
17
12
  let angleEntities = []
@@ -66,7 +61,7 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
66
61
  }
67
62
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
68
63
 
69
- angleMeasurementHandler.setInputAction(function (movement) {
64
+ angleMeasurementHandler.setInputAction((movement) => {
70
65
  if (anglePoints.length > 0 && anglePoints.length < 3) {
71
66
  const ray = viewer.camera.getPickRay(movement.endPosition)
72
67
  const cartesian = viewer.scene.globe.pick(ray, viewer.scene)
@@ -154,11 +149,20 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
154
149
  const distanceMeasurement = () => {
155
150
  let positions = []
156
151
  let tempPositions = []
152
+ let currentLineEntity: Cesium.Entity
157
153
  let handler = null
158
154
 
155
+ const point = {
156
+ color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
157
+ outlineColor: Cesium.Color.WHITE,
158
+ outlineWidth: 2,
159
+ pixelSize: 10,
160
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
161
+ }
162
+
159
163
  const draw = () => {
160
164
  if (handler) {
161
- console.log('请先右键结束上次测量!');
165
+ console.log('请使用右键结束上次测量!')
162
166
  return
163
167
  }
164
168
  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
@@ -168,6 +172,10 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
168
172
  }
169
173
 
170
174
  const stopDraw = () => {
175
+ if (currentLineEntity) {
176
+ options.distanceCollection.entities.remove(currentLineEntity)
177
+ }
178
+
171
179
  if (handler) {
172
180
  handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
173
181
  handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
@@ -181,11 +189,12 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
181
189
  }
182
190
 
183
191
  const removeAll = () => {
192
+ stopDraw()
184
193
  options.distanceCollection.entities.removeAll()
185
194
  }
186
195
 
187
196
  const createLine = () => {
188
- options.distanceCollection.entities.add({
197
+ currentLineEntity = options.distanceCollection.entities.add({
189
198
  polyline: {
190
199
  positions: new Cesium.CallbackProperty(() => tempPositions, false),
191
200
  material: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
@@ -232,7 +241,14 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
232
241
  }
233
242
 
234
243
  const leftClickEvent = () => {
244
+ let lastClickTime = 0
245
+ const MIN_INTERVAL = 250
246
+
235
247
  handler.setInputAction(event => {
248
+ const now = Date.now()
249
+ if (now - lastClickTime < MIN_INTERVAL) return
250
+ lastClickTime = now
251
+
236
252
  let position = viewer.scene.pickPosition(event.position)
237
253
  if (!position)
238
254
  position = viewer.scene.camera.pickEllipsoid(event.position, viewer.scene.globe.ellipsoid)
@@ -266,7 +282,7 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
266
282
 
267
283
  const rightClickEvent = () => {
268
284
  handler.setInputAction(() => {
269
- if (positions.length < 1) {
285
+ if (positions.length <= 1) {
270
286
  removeAll()
271
287
  stopDraw()
272
288
  } else {
@@ -290,15 +306,447 @@ const useMeasure = (viewer: Cesium.Viewer, options: {
290
306
  }
291
307
 
292
308
  const heightMeasurement = () => {
309
+ let positions = []
310
+ let currentLineEntity: Cesium.Entity
311
+ let currentPointEntities: Cesium.Entity[] = []
312
+ let currentLabelEntity: Cesium.Entity
313
+ let handler = null
314
+
315
+ const cartesian3Point3 = (pos) => {
316
+ const ellipsoid = viewer.scene.globe.ellipsoid
317
+ const cartographic = ellipsoid.cartesianToCartographic(pos)
318
+ return [
319
+ Cesium.Math.toDegrees(cartographic.longitude),
320
+ Cesium.Math.toDegrees(cartographic.latitude),
321
+ cartographic.height
322
+ ]
323
+ }
324
+
325
+ const draw = () => {
326
+ if (handler) {
327
+ console.log('请先结束上次测量!')
328
+ return
329
+ }
330
+ handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
331
+ leftClickEvent()
332
+ mouseMoveEvent()
333
+ }
334
+
335
+ const createLine = () => {
336
+ currentLineEntity = options.heightCollection.entities.add({
337
+ polyline: {
338
+ positions: new Cesium.CallbackProperty(() => positions, false),
339
+ width: 2,
340
+ material: Cesium.Color.fromCssColorString("rgb(249,157,11)")
341
+ }
342
+ })
343
+ }
344
+
345
+ const createPoint = (index) => {
346
+ const entity = options.heightCollection.entities.add({
347
+ position: new Cesium.CallbackProperty(() => positions[index], false) as Cesium.CallbackPositionProperty,
348
+ point: {
349
+ color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
350
+ outlineColor: Cesium.Color.WHITE,
351
+ outlineWidth: 2,
352
+ pixelSize: 10
353
+ }
354
+ })
355
+
356
+ currentPointEntities.push(entity)
357
+ }
358
+
359
+ const createLabel = () => {
360
+ currentLabelEntity = options.heightCollection.entities.add({
361
+ position: new Cesium.CallbackProperty(() => positions[1], false) as Cesium.CallbackPositionProperty,
362
+ label: {
363
+ text: "",
364
+ scale: 0.5,
365
+ font: "normal 28px MicroSoft YaHei",
366
+ style: Cesium.LabelStyle.FILL_AND_OUTLINE,
367
+ pixelOffset: new Cesium.Cartesian2(0, -30),
368
+ outlineWidth: 9,
369
+ outlineColor: Cesium.Color.WHITE
370
+ }
371
+ })
372
+ }
373
+
374
+ const leftClickEvent = () => {
375
+ let lastClickTime = 0
376
+ const MIN_INTERVAL = 250
377
+
378
+ handler.setInputAction(e => {
379
+ const now = Date.now()
380
+ if (now - lastClickTime < MIN_INTERVAL) return
381
+ lastClickTime = now
382
+
383
+ let position = viewer.scene.pickPosition(e.position)
384
+ if (!position) position = viewer.scene.camera.pickEllipsoid(e.position, viewer.scene.globe.ellipsoid)
385
+ if (!position) return
386
+
387
+ if (positions.length === 0) {
388
+ positions.push(position)
389
+ createPoint(0)
390
+ createLine()
391
+ createLabel()
392
+ } else if (positions.length > 2) {
393
+ options.heightCollection.entities.add({
394
+ polyline: {
395
+ positions: positions,
396
+ width: 2,
397
+ material: Cesium.Color.fromCssColorString("rgb(249,157,11)")
398
+ }
399
+ })
400
+
401
+ positions.forEach(pos => {
402
+ options.heightCollection.entities.add({
403
+ position: pos,
404
+ point: {
405
+ color: Cesium.Color.fromCssColorString("rgb(249,157,11)"),
406
+ outlineColor: Cesium.Color.WHITE,
407
+ outlineWidth: 2,
408
+ pixelSize: 10
409
+ }
410
+ })
411
+ })
412
+
413
+ options.heightCollection.entities.add({
414
+ position: positions[1],
415
+ label: {
416
+ text: currentLabelEntity.label.text,
417
+ scale: 0.5,
418
+ font: "normal 28px MicroSoft YaHei",
419
+ style: Cesium.LabelStyle.FILL_AND_OUTLINE,
420
+ pixelOffset: new Cesium.Cartesian2(0, -30),
421
+ outlineWidth: 9,
422
+ outlineColor: Cesium.Color.WHITE
423
+ }
424
+ })
425
+
426
+ stopDraw()
427
+ }
428
+ }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
429
+ }
430
+
431
+ const mouseMoveEvent = () => {
432
+ handler.setInputAction(e => {
433
+ let position = viewer.scene.pickPosition(e.endPosition)
434
+ if (!position) position = viewer.scene.camera.pickEllipsoid(e.startPosition, viewer.scene.globe.ellipsoid)
435
+ if (!position) return
436
+
437
+ handleMove(position)
438
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
439
+ }
440
+
441
+ const handleMove = (position) => {
442
+ if (positions.length < 1) return
443
+ const first = cartesian3Point3(positions[0])
444
+ const move = cartesian3Point3(position)
445
+
446
+ const h = move[2] - first[2]
447
+ first[2] = move[2]
448
+ const twoPos = Cesium.Cartesian3.fromDegrees(first[0], first[1], move[2])
449
+
450
+ if (positions.length < 2) {
451
+ positions.push(twoPos, position)
452
+ createPoint(1)
453
+ createPoint(2)
454
+ } else {
455
+ positions[1] = twoPos
456
+ positions[2] = position
457
+ if (currentLabelEntity) {
458
+ (currentLabelEntity.label.text as any) = `高度:${h.toFixed(3)} 米`
459
+ }
460
+ }
461
+ }
462
+
463
+ const stopDraw = () => {
464
+ if (handler) {
465
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
466
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
467
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
468
+ handler.destroy()
469
+ handler = null
470
+ }
471
+
472
+ if (currentLineEntity) {
473
+ options.heightCollection.entities.remove(currentLineEntity)
474
+ currentLineEntity = null
475
+ }
476
+ if (currentLabelEntity) {
477
+ options.heightCollection.entities.remove(currentLabelEntity)
478
+ currentLabelEntity = null
479
+ }
480
+ if (currentPointEntities.length) {
481
+ currentPointEntities.forEach(entity => options.heightCollection.entities.remove(entity))
482
+ currentPointEntities = []
483
+ }
484
+
485
+ positions = []
486
+ }
487
+
488
+ const removeAll = () => {
489
+ stopDraw()
490
+ options.heightCollection.entities.removeAll()
491
+ }
492
+
493
+ return {
494
+ draw,
495
+ removeAll
496
+ }
497
+ }
498
+
499
+ const areaMeasurement = () => {
500
+ let handler = null
501
+ let currentPolygonEntity = null
502
+ let currentLabelEntity = null
503
+ let positions = []
504
+ let tempPositions = []
505
+ let height = undefined
506
+
507
+ const draw = () => {
508
+ if (handler) {
509
+ console.log('请使用右键结束上次测量!')
510
+ return
511
+ }
512
+ handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
513
+ leftClickEvent()
514
+ mouseMoveEvent()
515
+ rightClickEvent()
516
+ }
517
+
518
+ const stopDraw = () => {
519
+ if (handler) {
520
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
521
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
522
+ handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
523
+ handler.destroy()
524
+ handler = null
525
+ }
526
+
527
+ tempPositions = []
528
+ positions = []
529
+ currentPolygonEntity = null
530
+ currentLabelEntity = null
531
+ height = undefined
532
+ }
533
+
534
+ const removeAll = () => {
535
+ stopDraw()
536
+ options.areaCollection.entities.removeAll()
537
+ }
538
+
539
+ const createPolygon = () => {
540
+ currentPolygonEntity = options.areaCollection.entities.add({
541
+ polygon: {
542
+ hierarchy: new Cesium.CallbackProperty(() => {
543
+ return new Cesium.PolygonHierarchy(tempPositions)
544
+ }, false),
545
+ material: Cesium.Color.fromCssColorString("rgb(249, 157, 11,.6)")
546
+ },
547
+ polyline: {
548
+ clampToGround: true,
549
+ positions: new Cesium.CallbackProperty(() => {
550
+ return tempPositions.concat(tempPositions[0])
551
+ }, false),
552
+ width: 1,
553
+ material: new Cesium.PolylineOutlineMaterialProperty({
554
+ outlineWidth: 2,
555
+ outlineColor: Cesium.Color.WHITE
556
+ })
557
+ }
558
+ })
559
+ }
560
+
561
+ const createPoint = () => {
562
+ options.areaCollection.entities.add({
563
+ position: positions[positions.length - 1],
564
+ point: {
565
+ color: Cesium.Color.fromCssColorString("rgb(249, 157, 11)"),
566
+ outlineColor: Cesium.Color.WHITE,
567
+ outlineWidth: 2,
568
+ pixelSize: 10,
569
+ heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
570
+ }
571
+ })
572
+ }
573
+
574
+ const createLabel = () => {
575
+ currentLabelEntity = options.areaCollection.entities.add({
576
+ position: new Cesium.CallbackProperty(() => getCenterPosition(), false) as Cesium.CallbackPositionProperty,
577
+ label: {
578
+ text: new Cesium.CallbackProperty(() => {
579
+ return "面积 " + computeArea(tempPositions)
580
+ }, false),
581
+ scale: 0.5,
582
+ font: "normal 28px MicroSoft YaHei",
583
+ style: Cesium.LabelStyle.FILL_AND_OUTLINE,
584
+ pixelOffset: new Cesium.Cartesian2(0, -30),
585
+ outlineWidth: 9,
586
+ outlineColor: Cesium.Color.WHITE,
587
+ disableDepthTestDistance: Number.POSITIVE_INFINITY
588
+ }
589
+ })
590
+ }
591
+
592
+ const getCenterPosition = () => {
593
+ if (tempPositions.length < 3) return tempPositions[0]
594
+ const points = tempPositions.map(p => {
595
+ const c = cartesian3ToPoint3D(p)
596
+ return [c.x, c.y]
597
+ })
598
+ const geo = turf.lineString(points)
599
+ const bbox = turf.bbox(geo)
600
+ const bboxPolygon = turf.bboxPolygon(bbox)
601
+ const center = turf.center(bboxPolygon)
602
+ const [lon, lat] = center.geometry.coordinates
603
+ return Cesium.Cartesian3.fromDegrees(lon, lat, height + 0.3)
604
+ }
605
+
606
+ const leftClickEvent = () => {
607
+ let lastClickTime = 0
608
+ const MIN_INTERVAL = 250
609
+
610
+ handler.setInputAction(e => {
611
+ const now = Date.now()
612
+ if (now - lastClickTime < MIN_INTERVAL) return
613
+ lastClickTime = now
614
+
615
+ let position = viewer.scene.pickPosition(e.position)
616
+ if (!position) {
617
+ const ellipsoid = viewer.scene.globe.ellipsoid
618
+ position = viewer.scene.camera.pickEllipsoid(e.position, ellipsoid)
619
+ }
620
+ if (!position) return
621
+
622
+ positions.push(position)
623
+ height = unifiedHeight(positions, height)
624
+ if (positions.length === 1) {
625
+ createPolygon()
626
+ }
627
+ createPoint()
628
+ }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
629
+ }
630
+
631
+ const mouseMoveEvent = () => {
632
+ handler.setInputAction(e => {
633
+ let position = viewer.scene.pickPosition(e.endPosition)
634
+ if (!position)
635
+ position = viewer.scene.camera.pickEllipsoid(
636
+ e.startPosition,
637
+ viewer.scene.globe.ellipsoid
638
+ )
639
+ if (!position) return
640
+ handleMoveEvent(position)
641
+ }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
642
+ }
643
+
644
+ const rightClickEvent = () => {
645
+ handler.setInputAction(e => {
646
+ if (positions.length < 3) {
647
+ stopDraw()
648
+ removeAll()
649
+ } else {
650
+ tempPositions = [...positions]
651
+ currentPolygonEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(tempPositions)
652
+ currentLabelEntity.position = getCenterPosition()
653
+ currentLabelEntity.label.text = "总面积为 " + computeArea(positions)
654
+ stopDraw()
655
+ }
656
+ }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
657
+ }
658
+
659
+ const handleMoveEvent = (position) => {
660
+ if (positions.length < 1) return
661
+ height = unifiedHeight(positions, height)
662
+ tempPositions = positions.concat(position)
663
+ if (tempPositions.length >= 3 && !currentLabelEntity) createLabel()
664
+ }
665
+
666
+ const unifiedHeight = (positions, height) => {
667
+ if (!height) height = getPositionHeight(positions[0])
668
+ for (let i = 0; i < positions.length; i++) {
669
+ const p = cartesian3ToPoint3D(positions[i])
670
+ positions[i] = Cesium.Cartesian3.fromDegrees(p.x, p.y, height)
671
+ }
672
+ return height
673
+ }
674
+
675
+ const computeArea = (points) => {
676
+ let res = 0
677
+ for (let i = 0; i < points.length - 2; i++) {
678
+ const j = (i + 1) % points.length
679
+ const k = (i + 2) % points.length
680
+ const angle = Angle(points[i], points[j], points[k])
681
+ const dis1 = distance(points[j], points[0])
682
+ const dis2 = distance(points[k], points[0])
683
+ res += (dis1 * dis2 * Math.sin(angle)) / 2
684
+ }
685
+ return res < 1000000
686
+ ? Math.abs(res).toFixed(4) + " 平方米"
687
+ : Math.abs(res / 1000000).toFixed(4) + " 平方公里"
688
+ }
689
+
690
+ const Bearing = (from, to) => {
691
+ from = Cesium.Cartographic.fromCartesian(from)
692
+ to = Cesium.Cartographic.fromCartesian(to)
693
+ const lat1 = from.latitude, lon1 = from.longitude
694
+ const lat2 = to.latitude, lon2 = to.longitude
695
+ let angle = -Math.atan2(
696
+ Math.sin(lon1 - lon2) * Math.cos(lat2),
697
+ Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)
698
+ )
699
+ if (angle < 0) angle += Math.PI * 2.0
700
+ return (angle * 180.0) / Math.PI
701
+ }
293
702
 
703
+ const Angle = (p1, p2, p3) => {
704
+ const b21 = Bearing(p2, p1)
705
+ const b23 = Bearing(p2, p3)
706
+ let angle = b21 - b23
707
+ if (angle < 0) angle += 360
708
+ return angle
709
+ }
710
+
711
+ const distance = (p1, p2) => {
712
+ const c1 = Cesium.Cartographic.fromCartesian(p1)
713
+ const c2 = Cesium.Cartographic.fromCartesian(p2)
714
+ const geodesic = new Cesium.EllipsoidGeodesic()
715
+ geodesic.setEndPoints(c1, c2)
716
+ let s = geodesic.surfaceDistance
717
+ return Math.sqrt(s * s + Math.pow(c2.height - c1.height, 2))
718
+ }
719
+
720
+ const getPositionHeight = (p) => {
721
+ const c = Cesium.Cartographic.fromCartesian(p)
722
+ return c.height
723
+ }
724
+
725
+ const cartesian3ToPoint3D = (p) => {
726
+ const c = Cesium.Cartographic.fromCartesian(p)
727
+ return {
728
+ x: Cesium.Math.toDegrees(c.longitude),
729
+ y: Cesium.Math.toDegrees(c.latitude),
730
+ z: c.height
731
+ }
732
+ }
733
+
734
+ return {
735
+ draw,
736
+ removeAll
737
+ }
294
738
  }
295
739
 
296
740
  const angle = angleMeasurement()
297
741
  const distance = distanceMeasurement()
742
+ const height = heightMeasurement()
743
+ const area = areaMeasurement()
298
744
 
299
745
  return {
300
746
  angle,
301
- distance
747
+ distance,
748
+ height,
749
+ area
302
750
  }
303
751
  }
304
752
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "easy-three-utils",
3
- "version": "0.0.346",
3
+ "version": "0.0.347",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"