xzw 3 gadi atpakaļ
vecāks
revīzija
03c46f8bb5
50 mainītis faili ar 2795 papildinājumiem un 3906 dzēšanām
  1. 0 472
      data/t-SNZRfWt/filter.json
  2. 0 41
      data/t-iksBApb/datasets.json
  3. 0 613
      data/t-iksBApb/filter - 副本.json
  4. 0 192
      data/t-iksBApb/filter.json
  5. 0 472
      data/t-iksBApb/filter1.json
  6. 0 30
      data/t-vZkqRV8/cloud.js
  7. 5 4
      examples/4dkk.html
  8. 3 1
      gulpfile.js
  9. 170 6
      libs/three.js/lines/LineMaterial.js
  10. 8 0
      note.txt
  11. 11 0
      src/EventDispatcher.js
  12. 7 6
      src/PointCloudOctree.js
  13. 18 3
      src/Potree.js
  14. 9 1
      src/PotreeRenderer.js
  15. 30 16
      src/Potree_update_visibility.js
  16. 88 75
      src/TextSprite.js
  17. 3 0
      src/materials/EyeDomeLightingMaterial.js
  18. 11 2
      src/materials/PointCloudMaterial.js
  19. 28 19
      src/materials/shaders/edl.fs
  20. 18 4
      src/materials/shaders/pointcloud.fs
  21. 106 96
      src/materials/shaders/pointcloud.vs
  22. 163 136
      src/modules/Images360/Images360.js
  23. 419 47
      src/modules/Images360/Panorama.js
  24. 0 398
      src/modules/Images360/Panorama2.js
  25. 17 100
      src/modules/datasetAlignment/Alignment.js
  26. 92 44
      src/navigation/FirstPersonControls.js
  27. 194 165
      src/navigation/InputHandler.js
  28. 18 7
      src/navigation/OrbitControls.js
  29. 26 37
      src/navigation/Reticule.js
  30. 2 2
      src/navigation/VRControls.js
  31. 39 9
      src/settings.js
  32. 111 19
      src/utils.js
  33. 66 19
      src/utils/Common.js
  34. 10 7
      src/utils/DrawUtil.js
  35. 61 24
      src/utils/Magnifier.js
  36. 228 145
      src/utils/Measure.js
  37. 129 109
      src/utils/MeasuringTool.js
  38. 1 1
      src/utils/TransformationTool.js
  39. 6 34
      src/utils/Volume.js
  40. 4 23
      src/utils/VolumeTool.js
  41. 9 4
      src/utils/math.js
  42. 1 1
      src/utils/transitions.js
  43. 151 231
      src/viewer/EDLRenderer.js
  44. 6 4
      src/viewer/PropertyPanels/PropertiesPanel.js
  45. 14 5
      src/viewer/Scene.js
  46. 2 2
      src/viewer/View.js
  47. 9 1
      src/viewer/potree.css
  48. 9 7
      src/viewer/sidebar.html
  49. 70 17
      src/viewer/sidebar.js
  50. 423 255
      src/viewer/viewer.js

+ 0 - 472
data/t-SNZRfWt/filter.json

@@ -1,472 +0,0 @@
-[
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            1.59676,
-            -1.858297,
-            -1.424995
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            1.59676,
-            -1.858297,
-            0.075004
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00000",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59501418166995,
-            22.367311492079243,
-            -1.424995
-        ],
-        "hidden": false,
-        "id": 0,
-        "location": [
-            113.59501418166995,
-            22.367311492079243,
-            0.075004
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            1.524764,
-            0.321297,
-            -1.448787
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            1.524764,
-            0.321297,
-            0.051212
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00001",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.5950171680593,
-            22.367330988876998,
-            -1.448787
-        ],
-        "hidden": false,
-        "id": 1,
-        "location": [
-            113.5950171680593,
-            22.367330988876998,
-            0.051212
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            1.452417,
-            2.323778,
-            -1.469296
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            1.452417,
-            2.323778,
-            0.030703
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00002",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.5950198524803,
-            22.367348911096724,
-            -1.469296
-        ],
-        "hidden": false,
-        "id": 2,
-        "location": [
-            113.5950198524803,
-            22.367348911096724,
-            0.030703
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -0.465674,
-            2.651643,
-            -1.443204
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -0.465674,
-            2.651643,
-            0.056795
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00003",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59500206487914,
-            22.367354834748246,
-            -1.443204
-        ],
-        "hidden": false,
-        "id": 3,
-        "location": [
-            113.59500206487914,
-            22.367354834748246,
-            0.056795
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -0.304909,
-            0.378079,
-            -1.423422
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -0.304909,
-            0.378079,
-            0.076577
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00004",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59499976884827,
-            22.367334363039878,
-            -1.423422
-        ],
-        "hidden": false,
-        "id": 4,
-        "location": [
-            113.59499976884827,
-            22.367334363039878,
-            0.076577
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -0.180324,
-            -1.626438,
-            -1.400534
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -0.180324,
-            -1.626438,
-            0.099465
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00005",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59499758048605,
-            22.367316340796547,
-            -1.400534
-        ],
-        "hidden": false,
-        "id": 5,
-        "location": [
-            113.59499758048605,
-            22.367316340796547,
-            0.099465
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -2.183048,
-            -1.826385,
-            -1.363442
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -2.183048,
-            -1.826385,
-            0.136557
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00006",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59497809375449,
-            22.367317703143319,
-            -1.363442
-        ],
-        "hidden": false,
-        "id": 6,
-        "location": [
-            113.59497809375449,
-            22.367317703143319,
-            0.136557
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -2.317107,
-            0.144839,
-            -1.385291
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -2.317107,
-            0.144839,
-            0.114708
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00007",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59498013539384,
-            22.36733544415704,
-            -1.385291
-        ],
-        "hidden": false,
-        "id": 7,
-        "location": [
-            113.59498013539384,
-            22.36733544415704,
-            0.114708
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -2.359503,
-            2.410406,
-            -1.412787
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -2.359503,
-            2.410406,
-            0.087212
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00008",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59498354975846,
-            22.367355659126745,
-            -1.412787
-        ],
-        "hidden": false,
-        "id": 8,
-        "location": [
-            113.59498354975846,
-            22.367355659126745,
-            0.087212
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            3.119361,
-            -2.78974,
-            -1.43909
-        ],
-        "dataset_floor_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            3.119361,
-            -2.78974,
-            0.060909
-        ],
-        "dataset_orientation": [
-            0.7071067811865475,
-            0.0,
-            0.0,
-            0.7071067811865476
-        ],
-        "file_id": "00009",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.5950271700403,
-            22.36730082077799,
-            -1.43909
-        ],
-        "hidden": false,
-        "id": 9,
-        "location": [
-            113.5950271700403,
-            22.36730082077799,
-            0.060909
-        ],
-        "orientation": [
-            0.7660444430548815,
-            0.0,
-            0.0,
-            0.6427876097629267
-        ],
-        "site_model_entity_id": 11
-    }
-]

+ 0 - 41
data/t-iksBApb/datasets.json

@@ -1,41 +0,0 @@
-[
-    {
-        "bounding_box_max": [
-            10.309,
-            4.804,
-            2.687
-        ],
-        "bounding_box_min": [
-            -8.202,
-            -11.714,
-            -1.53
-        ],
-        "bundle_id": null,
-        "color": "#c51162",
-        "has_depth_images": true,
-        "has_images": null,
-        "has_webmesh": false,
-        "id": 1,
-        "location": [
-            113.59577794856219,
-            22.36659069637355,
-            -0.3
-        ],
-        "name": "chunk1",
-        "orientation": -2.2689280250000007,
-        "point_cloud_type": "POTREE",
-        "security": {
-            "can_write": false,
-            "group_read": 0,
-            "group_write": 1
-        },
-        "site_model_entity_ids": [
-            10,
-            11,
-            12
-        ],
-        "title": "chunk1",
-        "type": "4dage",
-        "visible": null
-    }
-]

+ 0 - 613
data/t-iksBApb/filter - 副本.json

@@ -1,613 +0,0 @@
-[
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -1.284484,
-            0.186807,
-            -1.433107
-        ],
-        "dataset_floor_orientation": [
-            0.9982455,
-            -0.0070710033,
-            -0.0028280015,
-            -0.058719028
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -1.284484,
-            0.186807,
-            0.066892
-        ],
-        "dataset_orientation": [
-            0.9982455,
-            -0.0070710033,
-            -0.0028280015,
-            -0.058719028
-        ],
-        "file_id": "00003",
-        "file_path": "data/t-vZkqRV8",
-        "floor_location": [
-            113.59572660218173,
-            22.366601126399745,
-            -1.433107
-        ],
-        "hidden": false,
-        "id": 3,
-        "location": [
-            113.59572660218173,
-            22.366601126399745,
-            0.066892
-        ],
-        "orientation": [
-            0.9982455,
-            -0.0070710033,
-            -0.0028280015,
-            -0.058719028
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            1.527454,
-            1.098485,
-            -1.431433
-        ],
-        "dataset_floor_orientation": [
-            0.010460002,
-            0.0009780002,
-            0.0011080002,
-            0.9999442
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            1.527454,
-            1.098485,
-            0.068566
-        ],
-        "dataset_orientation": [
-            0.010460002,
-            0.0009780002,
-            0.0011080002,
-            0.9999442
-        ],
-        "file_id": "00001",
-        "file_path": "data/t-vZkqRV8",
-        "floor_location": [
-            113.59575387967989,
-            22.366609426882,
-            -1.431433
-        ],
-        "hidden": false,
-        "id": 1,
-        "location": [
-            113.59575387967989,
-            22.366609426882,
-            0.068566
-        ],
-        "orientation": [
-            0.010460002,
-            0.0009780002,
-            0.0011080002,
-            0.9999442
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            1.55657,
-            -1.286162,
-            -1.412995
-        ],
-        "dataset_floor_orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            1.55657,
-            -1.286162,
-            0.087004
-        ],
-        "dataset_orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "file_id": "00000",
-        "file_path": "data/t-vZkqRV8",
-        "floor_location": [
-            113.59575422412529,
-            22.36658789345206,
-            -1.412995
-        ],
-        "hidden": false,
-        "id": 0,
-        "location": [
-            113.59575422412529,
-            22.36658789345206,
-            0.087004
-        ],
-        "orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            1.937006,
-            -0.952866,
-            -1.324683
-        ],
-        "dataset_floor_orientation": [
-            0.9385529,
-            -0.011282011,
-            0.0006120006,
-            0.34495035
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            1.937006,
-            -0.952866,
-            0.175316
-        ],
-        "dataset_orientation": [
-            0.9385529,
-            -0.011282011,
-            0.0006120006,
-            0.34495035
-        ],
-        "file_id": "00004",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59575790914679,
-            22.366590912386255,
-            -1.324683
-        ],
-        "hidden": false,
-        "id": 9,
-        "location": [
-            113.59575790914679,
-            22.366590912386255,
-            0.175316
-        ],
-        "orientation": [
-            0.9385529,
-            -0.011282011,
-            0.0006120006,
-            0.34495035
-        ],
-        "site_model_entity_id": 13
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -2.21308,
-            -0.290076,
-            -1.348181
-        ],
-        "dataset_floor_orientation": [
-            0.9852171,
-            -0.009604011,
-            -0.002794003,
-            -0.1710182
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            -2.21308,
-            -0.290076,
-            0.151818
-        ],
-        "dataset_orientation": [
-            0.9852171,
-            -0.009604011,
-            -0.002794003,
-            -0.1710182
-        ],
-        "file_id": "00003",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59571759879374,
-            22.36659679762282,
-            -1.348181
-        ],
-        "hidden": false,
-        "id": 8,
-        "location": [
-            113.59571759879374,
-            22.36659679762282,
-            0.151818
-        ],
-        "orientation": [
-            0.9852171,
-            -0.009604011,
-            -0.002794003,
-            -0.1710182
-        ],
-        "site_model_entity_id": 13
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -0.392763,
-            2.304785,
-            -1.448249
-        ],
-        "dataset_floor_orientation": [
-            -0.7007945,
-            0.005179004,
-            0.0028850022,
-            0.71333855
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -0.392763,
-            2.304785,
-            0.05175
-        ],
-        "dataset_orientation": [
-            -0.7007945,
-            0.005179004,
-            0.0028850022,
-            0.71333855
-        ],
-        "file_id": "00002",
-        "file_path": "data/t-vZkqRV8",
-        "floor_location": [
-            113.59573520504739,
-            22.36662027390481,
-            -1.448249
-        ],
-        "hidden": false,
-        "id": 2,
-        "location": [
-            113.59573520504739,
-            22.36662027390481,
-            0.05175
-        ],
-        "orientation": [
-            -0.7007945,
-            0.005179004,
-            0.0028850022,
-            0.71333855
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -1.366048,
-            -2.241861,
-            -1.412849
-        ],
-        "dataset_floor_orientation": [
-            0.72623765,
-            -0.009041009,
-            -0.005575005,
-            -0.68736166
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -1.366048,
-            -2.241861,
-            0.08715
-        ],
-        "dataset_orientation": [
-            0.72623765,
-            -0.009041009,
-            -0.005575005,
-            -0.68736166
-        ],
-        "file_id": "00004",
-        "file_path": "data/t-vZkqRV8",
-        "floor_location": [
-            113.59572587317935,
-            22.36657919277985,
-            -1.412849
-        ],
-        "hidden": false,
-        "id": 4,
-        "location": [
-            113.59572587317935,
-            22.36657919277985,
-            0.08715
-        ],
-        "orientation": [
-            0.72623765,
-            -0.009041009,
-            -0.005575005,
-            -0.68736166
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -1.781149,
-            2.918267,
-            -1.548546
-        ],
-        "dataset_floor_orientation": [
-            0.9568614,
-            -0.009778004,
-            -0.0047690016,
-            -0.2903411
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            -1.781149,
-            2.918267,
-            -0.048546
-        ],
-        "dataset_orientation": [
-            0.9568614,
-            -0.009778004,
-            -0.0047690016,
-            -0.2903411
-        ],
-        "file_id": "00002",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59572170931502,
-            22.366625780399596,
-            -1.548546
-        ],
-        "hidden": false,
-        "id": 7,
-        "location": [
-            113.59572170931502,
-            22.366625780399596,
-            -0.048546
-        ],
-        "orientation": [
-            0.9568614,
-            -0.009778004,
-            -0.0047690016,
-            -0.2903411
-        ],
-        "site_model_entity_id": 13
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -1.164905,
-            -3.702089,
-            -1.273781
-        ],
-        "dataset_floor_orientation": [
-            -0.59479016,
-            0.010062003,
-            0.0051960014,
-            0.80380124
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            -1.164905,
-            -3.702089,
-            0.226218
-        ],
-        "dataset_orientation": [
-            -0.59479016,
-            0.010062003,
-            0.0051960014,
-            0.80380124
-        ],
-        "file_id": "00007",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59572786389636,
-            22.366566011295626,
-            -1.273781
-        ],
-        "hidden": false,
-        "id": 12,
-        "location": [
-            113.59572786389636,
-            22.366566011295626,
-            0.226218
-        ],
-        "orientation": [
-            -0.59479016,
-            0.010062003,
-            0.0051960014,
-            0.80380124
-        ],
-        "site_model_entity_id": 13
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            2.888978,
-            -3.817622,
-            -1.26312
-        ],
-        "dataset_floor_orientation": [
-            0.6726246,
-            -0.008923007,
-            0.004631004,
-            0.7399156
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            2.888978,
-            -3.817622,
-            0.236879
-        ],
-        "dataset_orientation": [
-            0.6726246,
-            -0.008923007,
-            0.004631004,
-            0.7399156
-        ],
-        "file_id": "00005",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59576722603289,
-            22.366565065646296,
-            -1.26312
-        ],
-        "hidden": false,
-        "id": 10,
-        "location": [
-            113.59576722603289,
-            22.366565065646296,
-            0.236879
-        ],
-        "orientation": [
-            0.6726246,
-            -0.008923007,
-            0.004631004,
-            0.7399156
-        ],
-        "site_model_entity_id": 13
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -0.694302,
-            5.670915,
-            -1.585799
-        ],
-        "dataset_floor_orientation": [
-            0.07594304,
-            -0.00026000012,
-            0.0036470017,
-            0.9971055
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            -0.694302,
-            5.670915,
-            -0.085799
-        ],
-        "dataset_orientation": [
-            0.07594304,
-            -0.00026000012,
-            0.0036470017,
-            0.9971055
-        ],
-        "file_id": "00001",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59573219022284,
-            22.366650663880017,
-            -1.585799
-        ],
-        "hidden": false,
-        "id": 6,
-        "location": [
-            113.59573219022284,
-            22.366650663880017,
-            -0.085799
-        ],
-        "orientation": [
-            0.07594304,
-            -0.00026000012,
-            0.0036470017,
-            0.9971055
-        ],
-        "site_model_entity_id": 13
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            2.891525,
-            -6.820863,
-            -1.352726
-        ],
-        "dataset_floor_orientation": [
-            0.99671096,
-            -0.012863012,
-            -0.0011530011,
-            0.080003075
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            2.891525,
-            -6.820863,
-            0.147273
-        ],
-        "dataset_orientation": [
-            0.99671096,
-            -0.012863012,
-            -0.0011530011,
-            0.080003075
-        ],
-        "file_id": "00006",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59576732853758,
-            22.36653794547289,
-            -1.352726
-        ],
-        "hidden": false,
-        "id": 11,
-        "location": [
-            113.59576732853758,
-            22.36653794547289,
-            0.147273
-        ],
-        "orientation": [
-            0.99671096,
-            -0.012863012,
-            -0.0011530011,
-            0.080003075
-        ],
-        "site_model_entity_id": 13
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -2.104879,
-            7.428907,
-            -1.608292
-        ],
-        "dataset_floor_orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "dataset_id": 2,
-        "dataset_location": [
-            -2.104879,
-            7.428907,
-            -0.108292
-        ],
-        "dataset_orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "file_id": "00000",
-        "file_path": "data/t-DxTiYo6",
-        "floor_location": [
-            113.59571844939139,
-            22.366666505134086,
-            -1.608292
-        ],
-        "hidden": false,
-        "id": 5,
-        "location": [
-            113.59571844939139,
-            22.366666505134086,
-            -0.108292
-        ],
-        "orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "site_model_entity_id": 13
-    }
-]

+ 0 - 192
data/t-iksBApb/filter.json

@@ -1,192 +0,0 @@
-[
-    {
-        "id": "0",
-        "dataset_location": [
-            -5.307045936584473,
-            0.008580000139772892,
-            1.2997100353240967
-        ],
-        "dataset_orientation": [
-            0,
-            0.7071067811865476,
-            0,
-            -0.7071067811865475
-        ],
-        "dataset_floor_location": [
-            -5.307045936584473,
-            -1.4914189577102662,
-            1.2997100353240967
-        ]
-    },
-    {
-        "id": "1",
-        "dataset_location": [
-            -5.355366230010986,
-            0.024910999462008477,
-            -0.7463200092315674
-        ],
-        "dataset_orientation": [
-            -0.0014127994463727738,
-            0.6804602317373005,
-            -0.002597910462992094,
-            -0.7327790640856168
-        ],
-        "dataset_floor_location": [
-            -5.355366230010986,
-            -1.4750880002975464,
-            -0.7463200092315674
-        ]
-    },
-    {
-        "id": "2",
-        "dataset_location": [
-            -3.4088330268859865,
-            0.019850999116897584,
-            -1.0629359483718873
-        ],
-        "dataset_orientation": [
-            -0.004965304747272489,
-            0.9987779350131556,
-            -0.00022768847091248498,
-            0.04917293889190266
-        ],
-        "dataset_floor_location": [
-            -3.4088330268859865,
-            -1.4801479578018189,
-            -1.0629359483718873
-        ]
-    },
-    {
-        "id": "3",
-        "dataset_location": [
-            -3.4127719402313234,
-            0.009693999774754048,
-            1.330907940864563
-        ],
-        "dataset_orientation": [
-            -0.001453811746173509,
-            0.6865858441631616,
-            -0.004658419713830001,
-            0.7270323518278686
-        ],
-        "dataset_floor_location": [
-            -3.4127719402313234,
-            -1.490304946899414,
-            1.330907940864563
-        ]
-    },
-    {
-        "id": "4",
-        "dataset_location": [
-            -0.8715130090713501,
-            0.006692999973893166,
-            1.9747610092163087
-        ],
-        "dataset_orientation": [
-            0.00048224736874806224,
-            0.999734921355444,
-            -0.0018653498740104507,
-            0.02294352207072403
-        ],
-        "dataset_floor_location": [
-            -0.8715130090713501,
-            -1.493306040763855,
-            1.9747610092163087
-        ]
-    },
-    {
-        "id": "5",
-        "dataset_location": [
-            1.859151005744934,
-            0.16297100484371186,
-            1.959488034248352
-        ],
-        "dataset_orientation": [
-            0.001005506214116225,
-            0.8122559400367085,
-            0.002214659208996851,
-            -0.5832960936338238
-        ],
-        "dataset_floor_location": [
-            1.859151005744934,
-            -1.3370280265808106,
-            1.959488034248352
-        ]
-    },
-    {
-        "id": "6",
-        "dataset_location": [
-            3.094014883041382,
-            0.1760769933462143,
-            0.0783189982175827
-        ],
-        "dataset_orientation": [
-            -0.0030462169725763825,
-            0.7409774558870658,
-            -0.0031791530924430669,
-            -0.6715155035424205
-        ],
-        "dataset_floor_location": [
-            3.094014883041382,
-            -1.323922038078308,
-            0.0783189982175827
-        ]
-    },
-    {
-        "id": "7",
-        "dataset_location": [
-            3.2593019008636476,
-            0.19146600365638734,
-            -2.420233964920044
-        ],
-        "dataset_orientation": [
-            -0.003656450665743247,
-            0.7042786380894135,
-            -0.002831963807733264,
-            -0.7099086246502108
-        ],
-        "dataset_floor_location": [
-            3.2593019008636476,
-            -1.308532953262329,
-            -2.420233964920044
-        ]
-    },
-    {
-        "id": "8",
-        "dataset_location": [
-            5.281027793884277,
-            0.2006630003452301,
-            -2.4906139373779299
-        ],
-        "dataset_orientation": [
-            0.00010677311380177844,
-            0.9996876325914147,
-            0.002882876048281535,
-            0.02482580032522047
-        ],
-        "dataset_floor_location": [
-            5.281027793884277,
-            -1.2993359565734864,
-            -2.4906139373779299
-        ]
-    },
-    {
-        "id": "9",
-        "dataset_location": [
-            5.347447872161865,
-            0.189519003033638,
-            -0.25694000720977785
-        ],
-        "dataset_orientation": [
-            0.0015733137021339582,
-            0.724921390041708,
-            0.0052983545771977638,
-            0.6888094223285434
-        ],
-        "dataset_floor_location": [
-            5.347447872161865,
-            -1.310479998588562,
-            -0.25694000720977785
-        ]
-    }
-]

+ 0 - 472
data/t-iksBApb/filter1.json

@@ -1,472 +0,0 @@
-[
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -0.871513,
-            -1.974761,
-            -1.493306
-        ],
-        "dataset_floor_orientation": [
-            0.72314286,
-            -0.0009780011999999997,
-            0.0016600019,
-            0.6906958
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -0.871513,
-            -1.974761,
-            0.006693
-        ],
-        "dataset_orientation": [
-            0.72314286,
-            -0.0009780011999999997,
-            0.0016600019,
-            0.6906958
-        ],
-        "file_id": "00004",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59576869995449,
-            22.36660818826991,
-            -1.793306
-        ],
-        "hidden": false,
-        "id": 4,
-        "location": [
-            113.59576869995449,
-            22.36660818826991,
-            -0.293307
-        ],
-        "orientation": [
-            -0.9315963627701758,
-            -0.0010911514772546083,
-            -0.0015879172192152735,
-            0.3634893461722615
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            1.859151,
-            -1.959488,
-            -1.337028
-        ],
-        "dataset_floor_orientation": [
-            0.16189906000000005,
-            0.0022770007999999999,
-            -0.0008550003,
-            0.9868043
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            1.859151,
-            -1.959488,
-            0.162971
-        ],
-        "dataset_orientation": [
-            0.16189906000000005,
-            0.0022770007999999999,
-            -0.0008550003,
-            0.9868043
-        ],
-        "file_id": "00005",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59575177153018,
-            22.366589209422263,
-            -1.6370280000000002
-        ],
-        "hidden": false,
-        "id": 5,
-        "location": [
-            113.59575177153018,
-            22.366589209422263,
-            -0.13702899999999999
-        ],
-        "orientation": [
-            0.9627699520971074,
-            0.00018740871859766512,
-            -0.0024250023080281629,
-            0.2703111236719827
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            3.094015,
-            -0.078319,
-            -1.323922
-        ],
-        "dataset_floor_orientation": [
-            0.04911701800000007,
-            -0.0044020014,
-            0.00009400003000000021,
-            0.9987833500000001
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            3.094015,
-            -0.078319,
-            0.176077
-        ],
-        "dataset_orientation": [
-            0.04911701800000007,
-            -0.0044020014,
-            0.00009400003000000021,
-            0.9987833500000001
-        ],
-        "file_id": "00006",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59575805636246,
-            22.366569747212304,
-            -1.623922
-        ],
-        "hidden": false,
-        "id": 6,
-        "location": [
-            113.59575805636246,
-            22.366569747212304,
-            -0.12392299999999998
-        ],
-        "orientation": [
-            0.9259628446096352,
-            -0.0017751731754019223,
-            0.0040292942594665728,
-            0.3775889616370673
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -3.408833,
-            1.062936,
-            -1.480148
-        ],
-        "dataset_floor_orientation": [
-            0.74101317,
-            -0.0036720007,
-            -0.0033500006,
-            0.6714721300000001
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -3.408833,
-            1.062936,
-            0.019851
-        ],
-        "dataset_orientation": [
-            0.74101317,
-            -0.0036720007,
-            -0.0033500006,
-            0.6714721300000001
-        ],
-        "file_id": "00002",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59580712883882,
-            22.36660810794898,
-            -1.780148
-        ],
-        "hidden": false,
-        "id": 2,
-        "location": [
-            113.59580712883882,
-            22.36660810794898,
-            -0.280149
-        ],
-        "orientation": [
-            -0.9217260966600163,
-            0.004587986285713982,
-            -0.0019121914334726542,
-            0.3878096139107564
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -3.412772,
-            -1.330908,
-            -1.490305
-        ],
-        "dataset_floor_orientation": [
-            0.9995790000000001,
-            -0.0043220003,
-            0.002266000000000001,
-            -0.02859999999999996
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -3.412772,
-            -1.330908,
-            0.009694
-        ],
-        "dataset_orientation": [
-            0.9995790000000001,
-            -0.0043220003,
-            0.002266000000000001,
-            -0.02859999999999996
-        ],
-        "file_id": "00003",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59578934869998,
-            22.366622030804757,
-            -1.790305
-        ],
-        "hidden": false,
-        "id": 3,
-        "location": [
-            113.59578934869998,
-            22.366622030804757,
-            -0.290306
-        ],
-        "orientation": [
-            -0.3965199696549162,
-            -0.00022713713383227044,
-            -0.004874715471256385,
-            0.9180131258440774
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            3.259302,
-            2.420234,
-            -1.308533
-        ],
-        "dataset_floor_orientation": [
-            -0.003981001699999986,
-            -0.004588002,
-            -0.00058300025,
-            0.9999814
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            3.259302,
-            2.420234,
-            0.191466
-        ],
-        "dataset_orientation": [
-            -0.003981001699999986,
-            -0.004588002,
-            -0.00058300025,
-            0.9999814
-        ],
-        "file_id": "00007",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.5957756083234,
-            22.366554100379628,
-            -1.608533
-        ],
-        "hidden": true,
-        "id": 7,
-        "location": [
-            113.5957756083234,
-            22.366554100379628,
-            -0.10853399999999999
-        ],
-        "orientation": [
-            0.904608459607412,
-            -0.0024673510570067615,
-            0.003911755373666604,
-            0.4262184242324293
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            5.347448,
-            0.25694,
-            -1.31048
-        ],
-        "dataset_floor_orientation": [
-            0.99965864,
-            0.0048590032,
-            -0.0026340017,
-            0.025535016999999994
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            5.347448,
-            0.25694,
-            0.189519
-        ],
-        "dataset_orientation": [
-            0.99965864,
-            0.0048590032,
-            -0.0026340017,
-            0.025535016999999994
-        ],
-        "file_id": "00009",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59574648629548,
-            22.366552212323197,
-            -1.6104800000000002
-        ],
-        "hidden": false,
-        "id": 9,
-        "location": [
-            113.59574648629548,
-            22.366552212323197,
-            -0.110481
-        ],
-        "orientation": [
-            -0.4456165950749855,
-            0.0003337127410200382,
-            0.005516929638989736,
-            0.8952068488995667
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -5.355366,
-            0.74632,
-            -1.475088
-        ],
-        "dataset_floor_orientation": [
-            -0.036995,
-            -0.0028360002,
-            0.0008380000399999998,
-            0.9993111
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -5.355366,
-            0.74632,
-            0.024911
-        ],
-        "dataset_orientation": [
-            -0.036995,
-            -0.0028360002,
-            0.0008380000399999998,
-            0.9993111
-        ],
-        "file_id": "00001",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59581692222116,
-            22.366623411543466,
-            -1.775088
-        ],
-        "hidden": false,
-        "id": 1,
-        "location": [
-            113.59581692222116,
-            22.366623411543466,
-            -0.275089
-        ],
-        "orientation": [
-            0.8900486349700012,
-            -0.0004390594872982186,
-            0.002924443159972475,
-            0.45585598849517908
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            -5.307046,
-            -1.29971,
-            -1.491419
-        ],
-        "dataset_floor_orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            -5.307046,
-            -1.29971,
-            0.00858
-        ],
-        "dataset_orientation": [
-            0.0,
-            0.0,
-            0.0,
-            1.0
-        ],
-        "file_id": "00000",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59580140287446,
-            22.366634953918266,
-            -1.791419
-        ],
-        "hidden": false,
-        "id": 0,
-        "location": [
-            113.59580140287446,
-            22.366634953918266,
-            -0.29142
-        ],
-        "orientation": [
-            0.9063077864888041,
-            0.0,
-            0.0,
-            0.42261826291555895
-        ],
-        "site_model_entity_id": 12
-    },
-    {
-        "camera_head_id": 12,
-        "dataset_floor_location": [
-            5.281028,
-            2.490614,
-            -1.299336
-        ],
-        "dataset_floor_orientation": [
-            0.7244404,
-            0.0021140011999999997,
-            -0.0019630012,
-            0.6893314
-        ],
-        "dataset_id": 1,
-        "dataset_location": [
-            5.281028,
-            2.490614,
-            0.200663
-        ],
-        "dataset_orientation": [
-            0.7244404,
-            0.0021140011999999997,
-            -0.0019630012,
-            0.6893314
-        ],
-        "file_id": "00008",
-        "file_path": "data/chunk1",
-        "floor_location": [
-            113.59576351424079,
-            22.3665397059442,
-            -1.599336
-        ],
-        "hidden": false,
-        "id": 8,
-        "location": [
-            113.59576351424079,
-            22.3665397059442,
-            -0.09933699999999998
-        ],
-        "orientation": [
-            -0.9309081613098724,
-            0.0008856677551485972,
-            0.002745535898144257,
-            0.3652419373948358
-        ],
-        "site_model_entity_id": 12
-    }
-]

+ 0 - 30
data/t-vZkqRV8/cloud.js

@@ -1,30 +0,0 @@
-{
-    "version": "1.8",
-    "octreeDir": "data",
-    "projection": "",
-    "points": 3029543,
-    "boundingBox": {
-        "lx": -11.039,
-        "ly": -12.589,
-        "lz": -2.11,
-        "ux": 10.306,
-        "uy": 8.756,
-        "uz": 19.235
-    },
-    "tightBoundingBox": {
-        "lx": -11.039,
-        "ly": -12.589,
-        "lz": -2.11,
-        "ux": 7.519,
-        "uy": 8.756,
-        "uz": 2.587
-    },
-    "pointAttributes": [
-        "POSITION_CARTESIAN",
-        "COLOR_PACKED",
-        "NORMAL_OCT16"
-    ],
-    "spacing": 0.18485312,
-    "scale": 0.001,
-    "hierarchyStepSize": 5
-}

+ 5 - 4
examples/4dkk.html

@@ -41,17 +41,18 @@
 	<script type="module">
 
 	import * as THREE from "../libs/three.js/build/three.module.js";
+    import browser from '../src/utils/browser.js' //这里必须加.js
      
-    
-        var number = window.location.href.substring(window.location.href.indexOf("=") + 1);
+        /*var number = window.location.href.substring(window.location.href.indexOf("=") + 1);
         if (number.indexOf("&") != -1) {
             number = number.substring(0, number.indexOf("&"));
         }
         if (number.indexOf("#") != -1) {
             number = number.substring(0, number.indexOf("#"));
-        }
+        }*/
         
-        Potree.settings.number = number || 't-o5YMR13'// 't-iksBApb'
+        var number = browser.urlHasValue('m',true);
+        console.log(number)
         Potree.start(document.getElementById("potree_render_area"), number);
         
           

+ 3 - 1
gulpfile.js

@@ -72,7 +72,9 @@ let shaders = [
 	"src/materials/shaders/edl.fs",
 	"src/materials/shaders/blur.vs",
 	"src/materials/shaders/blur.fs",
-    
+    //add:
+	"src/materials/shaders/depthBasic.vs", 
+	"src/materials/shaders/depthBasic.fs",
     "src/materials/shaders/copyCubeMap.vs",
 	"src/materials/shaders/copyCubeMap.fs",
 	"src/materials/shaders/basicTextured.vs",

+ 170 - 6
libs/three.js/lines/LineMaterial.js

@@ -20,15 +20,19 @@ import {
  */
 
 UniformsLib.line = {
-
+  
 	linewidth: { value: 1 },
 	resolution: { value: new Vector2( 1, 1 ) },
+    viewportOffset: { value: new Vector2(0, 0 ) }, //left, top    
 	dashScale: { value: 1 },
 	dashSize: { value: 1 },
 	dashOffset: { value: 0 },
 	gapSize: { value: 1 }, // todo FIX - maybe change to totalSize
-	opacity: { value: 1 }
-
+	opacity: { value: 1 },
+    
+    depthTexture:{ value: null },
+    nearPlane:{value: 0.1},
+    farPlane:{value: 100000},
 };
 
 ShaderLib[ 'line' ] = {
@@ -95,6 +99,8 @@ ShaderLib[ 'line' ] = {
 				vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd;
 
 			#endif
+            
+             
 
 			float aspect = resolution.x / resolution.y;
 
@@ -198,7 +204,17 @@ ShaderLib[ 'line' ] = {
 			uniform float gapSize;
 
 		#endif
-
+        
+        //加
+        #if defined(GL_EXT_frag_depth) && defined(useDepth)    
+            uniform sampler2D depthTexture;
+            uniform float nearPlane;
+            uniform float farPlane; 
+            uniform vec2 resolution;
+            uniform vec2 viewportOffset;
+        #endif
+        
+        
 		varying float vLineDistance;
 
 		#include <common>
@@ -209,6 +225,20 @@ ShaderLib[ 'line' ] = {
 
 		varying vec2 vUv;
 
+
+
+        #if defined(GL_EXT_frag_depth) && defined(useDepth)  
+            float convertToLinear(float zValue)
+            {
+                float z = zValue * 2.0 - 1.0;
+                return (2.0 * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane));
+            }
+        #endif
+
+
+
+
+
 		void main() {
 
 			#include <clipping_planes_fragment>
@@ -231,7 +261,58 @@ ShaderLib[ 'line' ] = {
 
 			}
 
-			vec4 diffuseColor = vec4( diffuse, opacity );
+
+            //加
+            #if defined(GL_EXT_frag_depth) && defined(useDepth)    
+                // mixFactor and clipFactor define the color mixing proportion between the states of
+                // full visibility and occluded visibility
+                // and
+                // full visibility and total invisibility
+                float mixFactor = 0.0;
+                float clipFactor = 0.0;
+
+                // The linear depth value of the current fragment
+                float fragDepth = convertToLinear(gl_FragCoord.z);
+
+                // The coordinates of the current fragment in the depth texture
+                vec2 depthTxtCoords = vec2(gl_FragCoord.x - viewportOffset.x,  gl_FragCoord.y) / resolution;
+
+                // The linear depth value of the pixel occupied by this fragment in the depth buffer
+                float textureDepth = convertToLinear(texture2D(depthTexture, depthTxtCoords).r);
+
+                // The difference between the two depths
+                float delta = textureDepth - fragDepth;
+
+                if (delta < 0.0)
+                {
+                    // occlusionDistance and clipDistance define the width of the respective zones and
+                    // mixFactor and clipFactor express the interpolation between the two colors depending on the position
+                    // of the current fragment withing those zones.
+                    
+                    float occlusionDistance = - 1.0;
+                    float clipDistance = - 4.0;
+                    mixFactor = clamp(delta / occlusionDistance, 0.0, 1.0);
+                    clipFactor = clamp(delta / clipDistance, 0.0, 1.0);
+                }
+                // If the fragment is totally transparent, don't bother drawing it
+                if (clipFactor == 1.0)
+                {
+                    discard;
+                }
+                
+                vec3 backColor = vec3(0.8,0.8,0.8);
+                 
+                
+                // Mix between the solid and the dahsed versions of the line according to the mixFactor
+                vec4 diffuseColor = vec4(mix(diffuse, backColor, mixFactor), opacity*(1.0 - clipFactor));
+               
+            #else
+                vec4 diffuseColor = vec4( diffuse, opacity );
+            #endif
+ 
+
+
+			//vec4 diffuseColor = vec4( diffuse, opacity );
 
 			#include <logdepthbuf_fragment>
 			#include <color_fragment>
@@ -263,9 +344,85 @@ var LineMaterial = function ( parameters ) {
 	} );
 
 	this.dashed = false;
+    
+    //add
+    this.updateDepthParams()
+    
+    viewer.addEventListener('camera_changed', (e)=>{
+        if(e.viewport.name != 'mapViewport') this.updateDepthParams(e) 
+    })   
+
+    let setSize = (e)=>{
+        let viewportOffset = e.viewportOffset || new THREE.Vector2()
+        this.uniforms.resolution.value.set(e.resolution.x, e.resolution.y);
+        this.uniforms.viewportOffset.value.set(viewportOffset.x, viewportOffset.y);
+    }
+    
+    let viewport = viewer.mainViewport;
+    let viewportOffset = new Vector2(viewport.left, viewport.bottom) 
+    let resolution = viewport.resolution  
+    setSize({viewportOffset, resolution} )
+    
+    
+    viewer.addEventListener('resize',(e)=>{
+        //if(!e.viewport || e.viewport.name != 'mapViewport'){
+            setSize(e)
+            //console.log(this.name +  viewportOffset.toArray())     
+        //} 
+    })  
+    
+    
+    /* viewer.addEventListener("render.begin", (e)=>{//before render  如果有大于两个viewport的话可能要
+        if(e.viewport.name != 'mapViewport') this.updateDepthParams({camera:e.viewport.camera})
+    }) */
+
+
+
+
 
 	Object.defineProperties( this, {
+        dashed:{//add
+            enumerable: true,
 
+			get: function () {
+
+				return 'USE_DASH' in this.defines 
+
+			},
+
+			set: function ( value ) {
+                if(value){
+                    this.defines.USE_DASH = ''
+                }else{
+                    delete this.defines.USE_DASH
+                }
+                this.needsUpdate = true
+			}  
+        },
+        
+        useDepth:{//add
+            enumerable: true,
+
+			get: function () {
+
+				return 'useDepth' in this.defines 
+
+			},
+
+			set: function ( value ) {
+                if(value != this.useDepth){ 
+                    if(value){
+                        this.defines.useDepth = ''
+                        this.updateDepthParams()
+                    }else{
+                        delete this.defines.useDepth
+                    }
+                    this.needsUpdate = true
+                }
+			}  
+        },
+        
+        
 		color: {
 
 			enumerable: true,
@@ -420,5 +577,12 @@ LineMaterial.prototype = Object.create( ShaderMaterial.prototype );
 LineMaterial.prototype.constructor = LineMaterial;
 
 LineMaterial.prototype.isLineMaterial = true;
-
+LineMaterial.prototype.updateDepthParams = function(e={}){   
+    if(this.useDepth){
+        var camera = e.camera || viewer.scene.getActiveCamera()
+        this.uniforms.depthTexture.value = viewer.getPRenderer().rtEDL.depthTexture  
+        this.uniforms.nearPlane.value = camera.near;
+        this.uniforms.farPlane.value = camera.far; 
+    }
+}
 export { LineMaterial };

+ 8 - 0
note.txt

@@ -16,6 +16,14 @@ http://indoor.popsmart.cn:8094/zdoblh-yz/
 地图贴图
 https://hq.iv.navvis.com/?fov=100.0&site=1493761991057195&hsCtaTracking=8ca25304-e9e7-49a2-8543-fcd4d6cb6df2%7C1108fea0-c576-4606-adbd-64471b0f92a6&vlon=5.90&vlat=-0.30&image=16830
 
+
+========
+场景:
+
+t-ia44BhY 机场(两个数据集。点量大 )
+t-iksBApb 一楼 一个数据集 十个点左右
+t-Zvd3w0m 室内 4dkk的场景 三个点
+t-CwfhfqJ 大佛 有平面图
 =============================
 地图lib:ol  全局变量    viewer.mapView
 

+ 11 - 0
src/EventDispatcher.js

@@ -105,5 +105,16 @@ export class EventDispatcher{
         this.addEventListener(type,(ev)=>{
             fun.apply(this, ev.arguments)
         })
+    }  
+    once(type, fun) {
+        function callback() {
+            this.removeEventListener(type, callback),
+            n || (n = !0, fun.apply(this, arguments))
+        }
+        var n = !1;
+        return callback.listener = fun,
+            this.on(type, callback),
+            this
     }
+     
 }

+ 7 - 6
src/PointCloudOctree.js

@@ -314,7 +314,7 @@ export class PointCloudOctree extends PointCloudTree {
 
 			this.visibleBounds.expandByPoint(node.getBoundingBox().min);
 			this.visibleBounds.expandByPoint(node.getBoundingBox().max);
-		}
+		} 
 	}
 
 	updateMaterial (material, visibleNodes, camera, renderer) {
@@ -861,12 +861,13 @@ export class PointCloudOctree extends PointCloudTree {
 
 		let x = parseInt(clamp(pixelPos.x - (pickWindowSize - 1) / 2, 0, width));
 		let y = parseInt(clamp(pixelPos.y - (pickWindowSize - 1) / 2, 0, height));
-		let w = parseInt(Math.min(x + pickWindowSize, width) - x);
-		let h = parseInt(Math.min(y + pickWindowSize, height) - y);
-
-		let pixelCount = w * h;
+		/* let w = parseInt(Math.min(x + pickWindowSize, width) - x);
+		let h = parseInt(Math.min(y + pickWindowSize, height) - y); */
+        
+		let pixelCount = pickWindowSize * pickWindowSize//w * h;
 		let buffer = new Uint8Array(4 * pixelCount);
-
+        //w<pickWindowSize会报错
+        
 		gl.readPixels(x, y, pickWindowSize, pickWindowSize, gl.RGBA, gl.UNSIGNED_BYTE, buffer);
 
 		renderer.setRenderTarget(null);

+ 18 - 3
src/Potree.js

@@ -142,16 +142,31 @@ export {scriptPath, resourcePath};
 
 //add: 
 
-export async function loadDatasets(path, callback){
+
+
+export async function loadFile(path, callback){
     let response = await fetch(path); 
     let text = await response.text();
     var data = JSON.parse(text)
-    callback(data) 
+    callback && callback(data) 
+    return data
 }
 
+export async function loadDatasets(path, callback){//之后直接把path写进来
+    return loadFile(path, callback) 
+    
+}
+export async function loadMapEntity(path, callback){
+    return loadFile(path, callback) 
+}
+ 
 
 
-
+export function Log(value, color, fontSize){
+    color = color || '#13f'
+    fontSize = fontSize || 14
+    console.log(`%c${value}`, `color:${color};font-size:${fontSize}px`) 
+}
 
  
 

+ 9 - 1
src/PotreeRenderer.js

@@ -1108,7 +1108,15 @@ export class Renderer {
                 //add:-----------
                 if(material.usePanoMap){
                     defines.push("#define usePanoMap");
-                } 
+                }
+                
+                if(material.useFilterByNormal){
+                    defines.push("#define use_filter_by_normal");
+                    defines.push("#define attenuated_opacity");
+                    
+                }
+
+                
                 //---------------
                 
                 

+ 30 - 16
src/Potree_update_visibility.js

@@ -3,8 +3,8 @@ import * as THREE from "../libs/three.js/build/three.module.js";
 import {ClipTask, ClipMethod} from "./defines.js";
 import {Box3Helper} from "./utils/Box3Helper.js";
 
-export function updatePointClouds(pointclouds, camera, renderer){
-
+export function updatePointClouds(pointclouds,camera, areaSize /* renderer */){
+ 
 	for (let pointcloud of pointclouds) {
 		let start = performance.now();
 
@@ -19,11 +19,12 @@ export function updatePointClouds(pointclouds, camera, renderer){
 
 		let duration = performance.now() - start;
 	}
+    
+    
+	let result = updateVisibility(pointclouds, camera, areaSize  );
 
-	let result = updateVisibility(pointclouds, camera, renderer);
-
-	for (let pointcloud of pointclouds) {
-		pointcloud.updateMaterial(pointcloud.material, pointcloud.visibleNodes, camera, renderer);
+	for (let pointcloud of pointclouds) { 
+		//pointcloud.updateMaterial(pointcloud.material, pointcloud.visibleNodes, camera, renderer);//转移到渲染时
 		pointcloud.updateVisibleBounds();
 	}
 
@@ -34,7 +35,7 @@ export function updatePointClouds(pointclouds, camera, renderer){
 
 
 
-export function updateVisibilityStructures(pointclouds, camera, renderer) {
+export function updateVisibilityStructures(pointclouds, camera, areaSize) {
 	let frustums = [];
 	let camObjPositions = [];
 	let priorityQueue = new BinaryHeap(function (x) { return 1 / x.weight; });
@@ -100,7 +101,7 @@ export function updateVisibilityStructures(pointclouds, camera, renderer) {
 };
 
 
-export function updateVisibility(pointclouds, camera, renderer){
+export function updateVisibility(pointclouds, camera, areaSize){
 
 	let numVisibleNodes = 0;
 	let numVisiblePoints = 0;
@@ -114,15 +115,15 @@ export function updateVisibility(pointclouds, camera, renderer){
 	let lowestSpacing = Infinity;
 
 	// calculate object space frustum and cam pos and setup priority queue
-	let s = updateVisibilityStructures(pointclouds, camera, renderer);//得到相机可见范围
+	let s = updateVisibilityStructures(pointclouds, camera, areaSize);//得到相机可见范围
 	let frustums = s.frustums;
 	let camObjPositions = s.camObjPositions;
 	let priorityQueue = s.priorityQueue;
 
 	let loadedToGPUThisFrame = 0;
 	
-	let domWidth = renderer.domElement.clientWidth;
-	let domHeight = renderer.domElement.clientHeight;
+	let domWidth = areaSize.x; //renderer.domElement.clientWidth;
+	let domHeight = areaSize.y;//renderer.domElement.clientHeight;
 
 	// check if pointcloud has been transformed
 	// some code will only be executed if changes have been detected
@@ -173,13 +174,13 @@ export function updateVisibility(pointclouds, camera, renderer){
 		let camObjPos = camObjPositions[element.pointcloud];
 
 		let insideFrustum = frustum.intersectsBox(box);
-		let maxLevel = pointcloud.maxLevel || Infinity;
+		let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
 		let level = node.getLevel();
 		let visible = insideFrustum;
 		visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
 		visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget);
-		visible = visible && level < maxLevel;
-		visible = visible || node.getLevel() <= 2;
+		visible = visible && level <= maxLevel; //< 改为 <=
+		//visible = visible || node.getLevel() <= 2;
 
 		let clipBoxes = pointcloud.material.clipBoxes;
 		if(true && clipBoxes.length > 0){
@@ -395,8 +396,7 @@ export function updateVisibility(pointclouds, camera, renderer){
 
 	{ // update DEM
 		let maxDEMLevel = 4;
-		let candidates = pointclouds
-			.filter(p => (p.generateDEM && p.dem instanceof Potree.DEM));
+		let candidates = pointclouds.filter(p => (p.generateDEM && p.dem instanceof Potree.DEM));
 		for (let pointcloud of candidates) {
 			let updatingNodes = pointcloud.visibleNodes.filter(n => n.getLevel() <= maxDEMLevel);
 			pointcloud.dem.update(updatingNodes);
@@ -414,3 +414,17 @@ export function updateVisibility(pointclouds, camera, renderer){
 	};
 };
 
+
+//console
+//viewer.scene.pointclouds[0].visibleNodes.map(e=> e && e.name )
+//viewer.scene.pointclouds[0].visibleNodes.map(e=>e.children.map(e=>e && e.name))
+
+
+
+
+
+
+
+
+
+

+ 88 - 75
src/TextSprite.js

@@ -5,127 +5,139 @@
 //  */
 
 import * as THREE from "../libs/three.js/build/three.module.js";
-
+import Sprite from './viewer/Sprite' 
 
 
 //可能还是要用html写,因为要加按钮和图片
 
 export class TextSprite extends THREE.Object3D{
 	
-	constructor(text, options={}){
-		super();
-
-		let texture = new THREE.Texture();
-		texture.minFilter = THREE.LinearFilter;
-		texture.magFilter = THREE.LinearFilter;
-		let spriteMaterial = new THREE.SpriteMaterial({
-			map: texture,
-			depthTest: false,
-			depthWrite: false});
-
-		this.texture = texture;
-
-		this.material = spriteMaterial;
-		//this.material = getRawMaterial(texture);
-		this.sprite = new THREE.Sprite(this.material);
-		this.add(this.sprite);
-
-		this.borderThickness = 4;
+	constructor( options={}){ 
+        super()
+		let map = new THREE.Texture();
+		map.minFilter = THREE.LinearFilter;
+		map.magFilter = THREE.LinearFilter;
+        
+        this.sprite = new Sprite({
+            sizeInfo:options.sizeInfo, 
+            renderOrder:options.renderOrder,
+            useDepth: options.useDepth,
+            map,
+            root: this     
+          
+        })
+        this.add(this.sprite)
+        
+        
+		this.rectBorderThick = options.rectBorderThick || 0
+		this.textBorderThick = options.textBorderThick || 0
 		this.fontface = 'Arial';
-		this.fontsize = options.fontsize ||  28;
-		this.borderColor = options.borderColor || { r: 0, g: 0, b: 0, a: 1.0 };
+		this.fontsize = options.fontsize ||  16; 
+        this.textBorderColor = options.textBorderColor || { r: 0, g: 0, b: 0, a: 0.0 };
 		this.backgroundColor = options.backgroundColor || { r: 255, g: 255, b: 255, a: 1.0 };
-		this.textColor = options.textColor || {r: 255, g: 255, b: 255, a: 1.0};
-		this.text = '';
-
-		this.setText(text);
+		this.textColor = options.textColor || {r: 0, g: 0, b: 0, a: 1.0};
+        this.borderColor = options.borderColor || { r: 0, g: 0, b: 0, a: 0.0 };
+		this.borderRadius = options.borderRadius || 6;
+        if(options.text != void 0)this.setText(options.text)
+        this.name = options.name
+        
+		//this.setText(text);
 	}
 
 	setText(text){
 		if (this.text !== text){
-			this.text = text;
+			this.text = text + '';
 
-			this.update();
+			this.updateTexture();
 		}
 	}
 
 	setTextColor(color){
 		this.textColor = color;
 
-		this.update();
+		this.updateTexture();
 	}
 
 	setBorderColor(color){
 		this.borderColor = color;
 
-		this.update();
+		this.updateTexture();
 	}
 
 	setBackgroundColor(color){
 		this.backgroundColor = color;
 
-		this.update();
+		this.updateTexture();
 	}
-
-	update(){
+    setPos(pos){
+        this.position.copy(pos)
+        this.sprite.update()
+    }
+    update(){
+        this.sprite.update()
+    }
+    setVisible(v){
+        this.visible = v
+    }
+    setUniforms(name,value){
+        this.sprite.setUniforms(name,value)
+    }
+	updateTexture(){
 		let canvas = document.createElement('canvas');
 		let context = canvas.getContext('2d');
-		context.font = 'Bold ' + this.fontsize + 'px ' + this.fontface;
-
+		context.font = 'Bold ' + this.fontsize + 'px ' + this.fontface; 
+       
+        context["font-weight"] = 100; //语法与 CSS font 属性相同。
 		// get size data (height depends only on font size)
-		let metrics = context.measureText(this.text);
+        
+        //this.text = '啊啊啊啊啊啊fag'
+        
+		let metrics = context.measureText(this.text );
 		let textWidth = metrics.width;
-		let margin = 5;
-		let spriteWidth = 2 * margin + textWidth + 2 * this.borderThickness;
-		let spriteHeight = this.fontsize * 1.4 + 2 * this.borderThickness;
-
+		let margin = new THREE.Vector2(this.fontsize, this.fontsize*0.4);
+		let spriteWidth = 2 * margin.x + textWidth + 2 * this.rectBorderThick;
+		let spriteHeight = 2 * margin.y + this.fontsize + 2 * this.rectBorderThick; 
 		context.canvas.width = spriteWidth;
 		context.canvas.height = spriteHeight;
 		context.font = 'Bold ' + this.fontsize + 'px ' + this.fontface;
 
+         
+        let diff = 2//针对英文大部分在baseLine之上所以降低一点(metrics.fontBoundingBoxAscent - metrics.fontBoundingBoxDescent) / 2
+
+        context.textBaseline = "middle"
+        
+        // border color
+        context.strokeStyle = 'rgba(' + this.borderColor.r + ',' + this.borderColor.g + ',' +
+            this.borderColor.b + ',' + this.borderColor.a + ')';
+  
+        context.lineWidth = this.rectBorderThick;
 		// background color
 		context.fillStyle = 'rgba(' + this.backgroundColor.r + ',' + this.backgroundColor.g + ',' +
 			this.backgroundColor.b + ',' + this.backgroundColor.a + ')';
-		// border color
-		context.strokeStyle = 'rgba(' + this.borderColor.r + ',' + this.borderColor.g + ',' +
-			this.borderColor.b + ',' + this.borderColor.a + ')';
-
-		context.lineWidth = this.borderThickness;
-		this.roundRect(context, this.borderThickness / 2, this.borderThickness / 2,
-			textWidth + this.borderThickness + 2 * margin, this.fontsize * 1.4 + this.borderThickness, 6);
-
+        this.roundRect(context, this.rectBorderThick / 2, this.rectBorderThick / 2,
+            spriteWidth - this.rectBorderThick, spriteHeight - this.rectBorderThick, this.borderRadius);
+        
 		// text color
-		context.strokeStyle = 'rgba(0, 0, 0, 1.0)';
-		context.strokeText(this.text, this.borderThickness + margin, this.fontsize + this.borderThickness);
-
+        if(this.textBorderThick){
+            context.strokeStyle = 'rgba(' + this.textBorderColor.r + ',' + this.textBorderColor.g + ',' +
+                this.textBorderColor.b + ',' + this.textBorderColor.a + ')';
+            context.lineWidth = this.textBorderThick;
+            context.strokeText(this.text , this.rectBorderThick + margin.x,spriteHeight/2  + diff );
+        }
+        
 		context.fillStyle = 'rgba(' + this.textColor.r + ',' + this.textColor.g + ',' +
 			this.textColor.b + ',' + this.textColor.a + ')';
-		context.fillText(this.text, this.borderThickness + margin, this.fontsize + this.borderThickness);
+		context.fillText(this.text , this.rectBorderThick + margin.x, spriteHeight/2  + diff );//x,y
 
 		let texture = new THREE.Texture(canvas);
 		texture.minFilter = THREE.LinearFilter;
 		texture.magFilter = THREE.LinearFilter;
 		texture.needsUpdate = true;
-		//this.material.needsUpdate = true;
-
-		// { // screen-space sprite
-		// 	let [screenWidth, screenHeight] = [1620, 937];
-
-		// 	let uniforms = this.sprite.material.uniforms;
-		// 	let aspect = spriteHeight / spriteWidth;
-		// 	let factor = 0.5;
-
-		// 	let w = spriteWidth / screenWidth;
-		// 	let h = spriteHeight / screenHeight;
-
-		// 	uniforms.uScale.value = [2 * w, 2 * h];
-		// 	//uniforms.uScale.value = [factor * 1, factor * aspect];
-		//	this.sprite.material.uniforms.map.value = texture;
-		// }
-
+		//this.material.needsUpdate = true; 
 		this.sprite.material.map = texture;
-		this.texture = texture;
-
+		 
+        
+        
 		this.sprite.scale.set(spriteWidth * 0.01, spriteHeight * 0.01, 1.0);
 	}
 
@@ -133,13 +145,14 @@ export class TextSprite extends THREE.Object3D{
 		ctx.beginPath();
 		ctx.moveTo(x + r, y);
 		ctx.lineTo(x + w - r, y);
-		ctx.quadraticCurveTo(x + w, y, x + w, y + r);
+        ctx.arcTo(x + w, y, x + w, y + r, r );//圆弧。前四个参数同quadraticCurveTo
+		//ctx.quadraticCurveTo(x + w, y, x + w, y + r); //二次贝塞尔曲线需要两个点。第一个点是用于二次贝塞尔计算中的控制点,第二个点是曲线的结束点。
 		ctx.lineTo(x + w, y + h - r);
-		ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
+		ctx.arcTo(x + w, y + h, x + w - r, y + h, r );
 		ctx.lineTo(x + r, y + h);
-		ctx.quadraticCurveTo(x, y + h, x, y + h - r);
+		ctx.arcTo(x, y + h, x, y + h - r, r );
 		ctx.lineTo(x, y + r);
-		ctx.quadraticCurveTo(x, y, x + r, y);
+		ctx.arcTo(x, y, x + r, y, r );
 		ctx.closePath();
 		ctx.fill();
 		ctx.stroke();

+ 3 - 0
src/materials/EyeDomeLightingMaterial.js

@@ -29,6 +29,9 @@ export class EyeDomeLightingMaterial extends THREE.RawShaderMaterial{
 			uEDLDepth:      { type: 't', 	value: null },
 			opacity:        { type: 'f',	value: 1.0 },
 			uProj:          { type: "Matrix4fv", value: [] },
+            
+            
+            useEDL:         { type: 'i', 	value: 1 }//add
 		};
 
 		this.setValues({

+ 11 - 2
src/materials/PointCloudMaterial.js

@@ -285,7 +285,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 			defines.push('#define paraboloid_point_shape');
 		}
 
-		if (this._useEDL) {
+		if (this._useEDL || this.fakeEDL) {
 			defines.push('#define use_edl');
 		}
 
@@ -642,7 +642,16 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 			this.updateShaderSource();
 		}
 	}
-
+    
+    get fakeEDL(){
+		return this._fakeEDL;
+	}
+    set fakeEDL (value) {//add
+		if (this._fakeEDL !== value) {
+			this._fakeEDL = value;
+			this.updateShaderSource();
+		}
+	}
 	get color () {
 		return this.uniforms.uColor.value;
 	}

+ 28 - 19
src/materials/shaders/edl.fs

@@ -16,8 +16,8 @@ uniform float edlStrength;
 uniform float radius;
 uniform float opacity;
 
-uniform float uNear;
-uniform float uFar;
+//uniform float uNear;
+//uniform float uFar;
 
 uniform mat4 uProj;
 
@@ -26,6 +26,8 @@ uniform sampler2D uEDLDepth;
 
 varying vec2 vUv;
 
+uniform int useEDL;
+
 float response(float depth){
 	vec2 uvRadius = radius / vec2(screenWidth, screenHeight);
 	
@@ -54,23 +56,30 @@ void main(){
 	
 	float depth = cEDL.a;
 	depth = (depth == 1.0) ? 0.0 : depth;
-	float res = response(depth);
-	float shade = exp(-res * 300.0 * edlStrength);
-
-	gl_FragColor = vec4(cEDL.rgb * shade, opacity);
-
-	{ // write regular hyperbolic depth values to depth buffer
-		float dl = pow(2.0, depth);
-
-		vec4 dp = uProj * vec4(0.0, 0.0, -dl, 1.0);
-		float pz = dp.z / dp.w;
-		float fragDepth = (pz + 1.0) / 2.0;
-
-		gl_FragDepthEXT = fragDepth;
-	}
-
-	if(depth == 0.0){
+    
+    if(depth == 0.0){
 		discard;
 	}
-
+    
+    
+    if(useEDL == 1){
+        float res = response(depth);
+        float shade = exp(-res * 300.0 * edlStrength);
+
+        gl_FragColor = vec4(cEDL.rgb * shade, opacity); 
+    }else{//加  不改颜色的情况
+        gl_FragColor = vec4(cEDL.rgb, opacity);
+    } 
+    
+    
+    { // write regular hyperbolic depth values to depth buffer  修改深度
+        float dl = pow(2.0, depth);
+
+        vec4 dp = uProj * vec4(0.0, 0.0, -dl, 1.0);
+        float pz = dp.z / dp.w;
+        float fragDepth = (pz + 1.0) / 2.0;
+
+        gl_FragDepthEXT = fragDepth;
+    }
+	
 }

+ 18 - 4
src/materials/shaders/pointcloud.fs

@@ -34,7 +34,8 @@ uniform vec3 cameraPosition;
 
 
 uniform mat4 projectionMatrix;
-uniform float uOpacity;
+//uniform float uOpacity;
+varying float vOpacity; //add
 
 uniform float blendHardness;
 uniform float blendDepthSupplement;
@@ -109,12 +110,25 @@ void main() {
 			discard;
 		}
 	#endif
-		
-	#if defined color_type_indices
+	
+
+ 
+
+	
+ 
+    #if defined color_type_indices    //pick point 识别
 		gl_FragColor = vec4(color, uPCIndex / 255.0);
 	#else
-		gl_FragColor = vec4(color, uOpacity);
+		gl_FragColor = vec4(color, vOpacity);
 	#endif
+    
+    
+    
+    
+    
+    
+    
+    
 
 	#if defined paraboloid_point_shape
 		float wi = 0.0 - ( u*u + v*v);

+ 106 - 96
src/materials/shaders/pointcloud.vs

@@ -113,7 +113,10 @@ uniform float uVNStart;
 uniform bool uIsLeafNode;
 
 uniform vec3 uColor;
-uniform float uOpacity;
+uniform float uOpacity; 
+varying float vOpacity; //add
+
+
 
 uniform vec2 elevationRange;
 uniform vec2 intensityRange;
@@ -122,6 +125,8 @@ uniform vec2 uFilterReturnNumberRange;
 uniform vec2 uFilterNumberOfReturnsRange;
 uniform vec2 uFilterPointSourceIDClipRange;
 uniform vec2 uFilterGPSTimeClipRange;
+//uniform float ufilterByNormalThreshold;    
+
 uniform float uGpsScale;
 uniform float uGpsOffset;
 
@@ -718,7 +723,9 @@ float getPointSize(){
 	projFactor = projFactor * scale;
 	
 	float r = uOctreeSpacing * 1.7;
-	vRadius = r;
+	//vRadius = r;
+     
+    
 	#if defined fixed_point_size
 		pointSize = size;
 	#elif defined attenuated_point_size
@@ -922,16 +929,24 @@ vec3 transformAxis( vec3 direction ) //navvis->4dkk
 }
 
 void main() {
-	vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
-	vViewPosition = mvPosition.xyz;
-	gl_Position = projectionMatrix * mvPosition;
-	vLogDepth = log2(-mvPosition.z);
+    
+    #ifdef use_filter_by_normal
+        if(abs(getNormal().z) > 0.3) { //ufilterByNormalThreshold 暂定0.3
+			// Move point outside clip space space to discard it.
+			gl_Position = vec4(0.0, 0.0, 2.0, 1.0);
+            return;
+		}
+    #endif
+     
+    vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
+    vViewPosition = mvPosition.xyz;
+    gl_Position = projectionMatrix * mvPosition;
+    vLogDepth = log2(-mvPosition.z);
 
 
-    //加-------------------
      
     // COLOR
-	 
+    //加-------------------
     #if defined(usePanoMap)
         vec4 worldPosition = modelMatrix * vec4(position, 1.0);
          
@@ -980,125 +995,120 @@ void main() {
    
     //-------------------        
 
+     
+    #ifdef attenuated_opacity //数据集校准时,相机拉远后随着点云密集需降低透明度
+        vOpacity = uOpacity * exp(-length(-mvPosition.xyz) / 1000.0);  //opacityAttenuation = 1000
+    #else
+        vOpacity = uOpacity;
+    #endif
+	 
 
-    
-
-	//gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-	//gl_PointSize = 5.0;
-
-	// POINT SIZE
-	float pointSize = getPointSize();
-	//float pointSize = 2.0;
-	gl_PointSize = pointSize;
-	vPointSize = pointSize;
+    // POINT SIZE
+    float pointSize = getPointSize();
+     
+    gl_PointSize = pointSize;
+    vPointSize = pointSize;
 
-	
     
     
     
-	// vColor = vec3(1.0, 0.0, 0.0);
+     
 
-	//gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-	//gl_Position = vec4(position.xzy / 1000.0, 1.0 );
+    // only for "replacing" approaches
+    // if(getLOD() != uLevel){
+    // 	gl_Position = vec4(10.0, 10.0, 10.0, 1.0);
+    // }
 
-	//gl_PointSize = 5.0;
-	//vColor = vec3(1.0, 1.0, 1.0);
 
-	// only for "replacing" approaches
-	// if(getLOD() != uLevel){
-	// 	gl_Position = vec4(10.0, 10.0, 10.0, 1.0);
-	// }
+    #if defined hq_depth_pass
+        float originalDepth = gl_Position.w;
+        float adjustedDepth = originalDepth + 2.0 * vRadius;
+        float adjust = adjustedDepth / originalDepth;
 
+        mvPosition.xyz = mvPosition.xyz * adjust;
+        gl_Position = projectionMatrix * mvPosition;
+    #endif
 
-	#if defined hq_depth_pass
-		float originalDepth = gl_Position.w;
-		float adjustedDepth = originalDepth + 2.0 * vRadius;
-		float adjust = adjustedDepth / originalDepth;
-
-		mvPosition.xyz = mvPosition.xyz * adjust;
-		gl_Position = projectionMatrix * mvPosition;
-	#endif
 
+    // CLIPPING
+    doClipping();
 
-	// CLIPPING
-	doClipping();
+    #if defined(num_clipspheres) && num_clipspheres > 0
+        for(int i = 0; i < num_clipspheres; i++){
+            vec4 sphereLocal = uClipSpheres[i] * mvPosition;
 
-	#if defined(num_clipspheres) && num_clipspheres > 0
-		for(int i = 0; i < num_clipspheres; i++){
-			vec4 sphereLocal = uClipSpheres[i] * mvPosition;
+            float distance = length(sphereLocal.xyz);
 
-			float distance = length(sphereLocal.xyz);
+            if(distance < 1.0){
+                float w = distance;
+                vec3 cGradient = texture2D(gradient, vec2(w, 1.0 - w)).rgb;
+                
+                vColor = cGradient;
+                //vColor = cGradient * 0.7 + vColor * 0.3;
+            }
+        }
+    #endif
 
-			if(distance < 1.0){
-				float w = distance;
-				vec3 cGradient = texture2D(gradient, vec2(w, 1.0 - w)).rgb;
-				
-				vColor = cGradient;
-				//vColor = cGradient * 0.7 + vColor * 0.3;
-			}
-		}
-	#endif
+    #if defined(num_shadowmaps) && num_shadowmaps > 0
 
-	#if defined(num_shadowmaps) && num_shadowmaps > 0
+        const float sm_near = 0.1;
+        const float sm_far = 10000.0;
 
-		const float sm_near = 0.1;
-		const float sm_far = 10000.0;
+        for(int i = 0; i < num_shadowmaps; i++){
+            vec3 viewPos = (uShadowWorldView[i] * vec4(position, 1.0)).xyz;
+            float distanceToLight = abs(viewPos.z);
+            
+            vec4 projPos = uShadowProj[i] * uShadowWorldView[i] * vec4(position, 1);
+            vec3 nc = projPos.xyz / projPos.w;
+            
+            float u = nc.x * 0.5 + 0.5;
+            float v = nc.y * 0.5 + 0.5;
 
-		for(int i = 0; i < num_shadowmaps; i++){
-			vec3 viewPos = (uShadowWorldView[i] * vec4(position, 1.0)).xyz;
-			float distanceToLight = abs(viewPos.z);
-			
-			vec4 projPos = uShadowProj[i] * uShadowWorldView[i] * vec4(position, 1);
-			vec3 nc = projPos.xyz / projPos.w;
-			
-			float u = nc.x * 0.5 + 0.5;
-			float v = nc.y * 0.5 + 0.5;
+            vec2 sampleStep = vec2(1.0 / (2.0*1024.0), 1.0 / (2.0*1024.0)) * 1.5;
+            vec2 sampleLocations[9];
+            sampleLocations[0] = vec2(0.0, 0.0);
+            sampleLocations[1] = sampleStep;
+            sampleLocations[2] = -sampleStep;
+            sampleLocations[3] = vec2(sampleStep.x, -sampleStep.y);
+            sampleLocations[4] = vec2(-sampleStep.x, sampleStep.y);
 
-			vec2 sampleStep = vec2(1.0 / (2.0*1024.0), 1.0 / (2.0*1024.0)) * 1.5;
-			vec2 sampleLocations[9];
-			sampleLocations[0] = vec2(0.0, 0.0);
-			sampleLocations[1] = sampleStep;
-			sampleLocations[2] = -sampleStep;
-			sampleLocations[3] = vec2(sampleStep.x, -sampleStep.y);
-			sampleLocations[4] = vec2(-sampleStep.x, sampleStep.y);
+            sampleLocations[5] = vec2(0.0, sampleStep.y);
+            sampleLocations[6] = vec2(0.0, -sampleStep.y);
+            sampleLocations[7] = vec2(sampleStep.x, 0.0);
+            sampleLocations[8] = vec2(-sampleStep.x, 0.0);
 
-			sampleLocations[5] = vec2(0.0, sampleStep.y);
-			sampleLocations[6] = vec2(0.0, -sampleStep.y);
-			sampleLocations[7] = vec2(sampleStep.x, 0.0);
-			sampleLocations[8] = vec2(-sampleStep.x, 0.0);
+            float visibleSamples = 0.0;
+            float numSamples = 0.0;
 
-			float visibleSamples = 0.0;
-			float numSamples = 0.0;
+            float bias = vRadius * 2.0;
 
-			float bias = vRadius * 2.0;
+            for(int j = 0; j < 9; j++){
+                vec4 depthMapValue = texture2D(uShadowMap[i], vec2(u, v) + sampleLocations[j]);
 
-			for(int j = 0; j < 9; j++){
-				vec4 depthMapValue = texture2D(uShadowMap[i], vec2(u, v) + sampleLocations[j]);
+                float linearDepthFromSM = depthMapValue.x + bias;
+                float linearDepthFromViewer = distanceToLight;
 
-				float linearDepthFromSM = depthMapValue.x + bias;
-				float linearDepthFromViewer = distanceToLight;
+                if(linearDepthFromSM > linearDepthFromViewer){
+                    visibleSamples += 1.0;
+                }
 
-				if(linearDepthFromSM > linearDepthFromViewer){
-					visibleSamples += 1.0;
-				}
+                numSamples += 1.0;
+            }
 
-				numSamples += 1.0;
-			}
+            float visibility = visibleSamples / numSamples;
 
-			float visibility = visibleSamples / numSamples;
+            if(u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0 || nc.x < -1.0 || nc.x > 1.0 || nc.y < -1.0 || nc.y > 1.0 || nc.z < -1.0 || nc.z > 1.0){
+                //vColor = vec3(0.0, 0.0, 0.2);
+            }else{
+                //vColor = vec3(1.0, 1.0, 1.0) * visibility + vec3(1.0, 1.0, 1.0) * vec3(0.5, 0.0, 0.0) * (1.0 - visibility);
+                vColor = vColor * visibility + vColor * uShadowColor * (1.0 - visibility);
+            }
 
-			if(u < 0.0 || u > 1.0 || v < 0.0 || v > 1.0 || nc.x < -1.0 || nc.x > 1.0 || nc.y < -1.0 || nc.y > 1.0 || nc.z < -1.0 || nc.z > 1.0){
-				//vColor = vec3(0.0, 0.0, 0.2);
-			}else{
-				//vColor = vec3(1.0, 1.0, 1.0) * visibility + vec3(1.0, 1.0, 1.0) * vec3(0.5, 0.0, 0.0) * (1.0 - visibility);
-				vColor = vColor * visibility + vColor * uShadowColor * (1.0 - visibility);
-			}
 
+        }
 
-		}
+    #endif
 
-	#endif
-    
     
     
 }

+ 163 - 136
src/modules/Images360/Images360.js

@@ -7,7 +7,7 @@ import Common from "../../utils/Common.js";
 import math from "../../utils/math.js";
 import cameraLight from "../../utils/cameraLight.js";
  
-import Panorama2 from "./Panorama2.js";
+import Panorama from "./Panorama.js";
 
 import QualityManager from './tile/QualityManager' 
 import TileDownloader from './tile/TileDownloader'
@@ -18,12 +18,11 @@ import { PanoSizeClass,Vectors} from '../../defines'
 
 //import Axis from '../../viewer/Axis'
 let raycaster = new THREE.Raycaster();
-let currentlyHovered = null;
+//let currentlyHovered = null;
 
 var texLoader = new THREE.TextureLoader()
 let cm = new ModelTextureMaterial()
 
-let smHovered = new THREE.MeshBasicMaterial({side: THREE.BackSide, color: 0xff0000});
 
 
 let previousView = {
@@ -47,7 +46,7 @@ export class Images360 extends EventDispatcher{
 
 		this.panos = [];
 		this.node = new THREE.Object3D();
-        this.node2 = new THREE.Object3D();
+        //this.node2 = new THREE.Object3D();
         
      
          
@@ -55,10 +54,13 @@ export class Images360 extends EventDispatcher{
         let size = params.boundSize 
         this.cube = new THREE.Mesh(new THREE.BoxBufferGeometry(  size.x, size.y, size.z ), cm);
         this.cube.position.copy(params.center) 
-        this.cube.visible = false;
-        this.node2.add(this.cube);
+        this.cube.visible = false; 
+        this.cube.layers.set(Potree.config.renderLayers.skybox)
         this.cube.name = 'skybox'
-      
+        viewer.scene.scene.add(this.cube)
+        
+        
+        
         /* this.axisArrow = new Axis(params.center);
         this.node.add(this.axisArrow) */
         
@@ -82,94 +84,81 @@ export class Images360 extends EventDispatcher{
         this.tileDownloader.processPriorityQueue = !1;
         this.tileDownloader.tilePrioritizer = new TilePrioritizer(this.qualityManager, this.basePanoSize, this.standardPanoSize, this.highPanoSize, this.ultraHighPanoSize);    
     
-    
-    
-    
-		
         
-   
-		this.addEventListener("mousedown", (e) => { 
-        
-		});
         
-        this.addEventListener("drop", (e) => {//不用"mouseup" 是因为 mouseup有drag object时也会触发
-            if(this.flying || e.pressDistance > 2 )return //
+        viewer.addEventListener('global_click'/* "global_drop" */, (e) => {//不用"mouseup" 是因为 mouseup有drag object时也会触发
+            if(this.flying  || e.button != THREE.MOUSE.LEFT  )return //
             
-            if(currentlyHovered && currentlyHovered.pano){
+            /* if(currentlyHovered && currentlyHovered.pano){
 				this.focusPano(currentlyHovered.pano);
-			}else{//add
+			}else{//add */
                 if(this.currentPano){
                     this.flyToPanoClosestToMouse() 
                 } 
-            }  
+            //}  
         })
         
-        this.addEventListener("mousemove", (e) => { 
+        viewer.addEventListener("global_mousemove", (e) => { 
             e.intersectPoint && this.updateClosestPano(e.intersectPoint)
 		});
 
-
-
-		let elUnfocus = document.createElement("input");
-		elUnfocus.type = "button";
-		elUnfocus.value = "unfocus";
-		elUnfocus.style.position = "absolute";
-		elUnfocus.style.right = "10px";
-		elUnfocus.style.bottom = "200px";
-		elUnfocus.style.zIndex = "10000";
-		elUnfocus.style.fontSize = "2em";
-		elUnfocus.addEventListener("click", () => this.unfocus());
-		this.elUnfocus = elUnfocus;
-
-		this.domRoot = viewer.renderer.domElement.parentElement;
-		this.domRoot.appendChild(elUnfocus);
-		this.elUnfocus.style.display = "none";
- 
- 
- 
- 
- 
- 
- 
- 
-        let elHide = document.createElement("input");
-		elHide.type = "button"; 
-        elHide.value = "隐藏点云";
-		elHide.style.position = "absolute";
-		elHide.style.right = "160px";
-        elHide.style.width = '110px'
-		elHide.style.bottom = "100px";
-		elHide.style.zIndex = "10000";
-		elHide.style.fontSize = "1em";
-		elHide.addEventListener("click", (e) => { 
-            viewer.scene.pointclouds.forEach(e=>{
-                e.visible = !e.visible 
+        if(Potree.settings.isTest){
+            this.domRoot = viewer.renderer.domElement.parentElement;
+            let elUnfocus = $("<input type='button' value='unfocus'></input>");
+            elUnfocus.css({
+                position : "absolute",
+                right : '25%',
+                bottom: '20px',
+                zIndex: "10000",
+                fontSize:'1em', color:"black",
+                display:'none',
+                background:'rgba(255,255,255,0.8)',
+            })
+            elUnfocus.on("click", () => this.unfocus());
+            this.elUnfocus = elUnfocus;
+            this.domRoot.appendChild(elUnfocus[0]);
+            
+            
+            
+            let elHide = $("<input type='button' value='隐藏点云'></input>")
+            elHide.css({
+                position : "absolute",
+                right : '40%',
+                bottom: '20px',
+                zIndex: "10000",
+                fontSize:'1em'  ,color:"black",
+                width : '100px',
+                background:'rgba(255,255,255,0.8)',
+            }) 
+            this.domRoot.appendChild(elHide[0]);
+            elHide.on("click", (e) => { 
+                viewer.scene.pointclouds.forEach(e=>{
+                    e.visible = !e.visible 
+                })
+                elHide.val(viewer.scene.pointclouds[0].visible ? "隐藏点云" : "显示点云")  
+            });
+            
+            
+            
+            let elDisplayModel = $("<input type='button' value='>>全景'></input>")
+            elDisplayModel.css({
+                position : "absolute",
+                right : '65%',
+                bottom: '20px',
+                zIndex: "10000",
+                fontSize:'1em',color:"black",
+                width : '100px',
+                background:'rgba(255,255,255,0.8)',                
             })
-            elHide.value = viewer.scene.pointclouds[0].visible ? "隐藏点云" : "显示点云"
-        });
-	  
-		this.domRoot.appendChild(elHide); 
-        
-        
-        
-       
- 
-        
-
-		let elDisplayModel = document.createElement("input");
-		elDisplayModel.type = "button"; 
-        elDisplayModel.value = "点云";
-		elDisplayModel.style.position = "absolute";
-		elDisplayModel.style.right = "6px";
-        elDisplayModel.style.bottom = "100px";
-        elDisplayModel.style.width = '100px' 
-		elDisplayModel.style.zIndex = "10000";
-		elDisplayModel.style.fontSize = "1em";
-        this.domRoot.appendChild(elDisplayModel);
-        elDisplayModel.addEventListener("click", (e) => {
-            Potree.settings.displayMode =  Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud'
             
-        });
+            this.domRoot.appendChild(elDisplayModel[0]);
+            elDisplayModel.on("click", (e) => { 
+                Potree.settings.displayMode =  Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud'
+            });
+ 
+            this.elDisplayModel = elDisplayModel
+        }
+         
         
         
         {//切换模式
@@ -190,10 +179,9 @@ export class Images360 extends EventDispatcher{
                         }else{
                             config2 = config.atPano 
                             if(mode == 'showPanos'){//自动飞入一个pano
-                                //要改成飞进最近的。。。
-                                //this.flyToPanoClosestToMouse()  //?
+                                //要改成飞进最近的。。。 
                                 this.flyToPano({
-                                    pano: this.currentPano || this.panos[0], 
+                                    pano: /* this.currentPano ||  */Common.sortByScore(this.panos,null,[e=>-e.position.distanceTo(this.position)])[0].item,   
                                     callback: ()=>{
                                         Potree.settings.displayMode = mode 
                                     }
@@ -255,11 +243,13 @@ export class Images360 extends EventDispatcher{
                             canLeavePano :  config.canLeavePano 
                         })
                         displayMode = mode
-                        elDisplayModel.value = mode == 'showPointCloud' ? "点云" : '全景'
+                        if(Potree.settings.isTest){
+                            this.elDisplayModel.value = mode == 'showPointCloud' ? ">>全景" : '>>点云'
+                        }
                     }                        
                 }
             }) 
-            Potree.settings.displayMode = elDisplayModel.value == "点云" ? 'showPointCloud' : 'showPanos' 
+            Potree.settings.displayMode =  'showPointCloud'  
         }// 切换模式 end
         
         {//
@@ -284,7 +274,7 @@ export class Images360 extends EventDispatcher{
         viewer.addEventListener("update", () => {
 			this.update(viewer);
 		});
-		viewer.inputHandler.addInputListener(this);
+		//viewer.inputHandler.addInputListener(this);
         
         
         
@@ -324,7 +314,8 @@ export class Images360 extends EventDispatcher{
         
 		 
   
-	};
+	}; 
+    
     flyLocalDirection(dir) {
         var direction = this.getDirection(dir),
             option1 = 1 === dir.y ? .4 : .75,
@@ -340,7 +331,9 @@ export class Images360 extends EventDispatcher{
         }
        
     }
-    
+    get position(){
+        return this.viewer.scene.view.position.clone()
+    }
     
     
     get visible(){
@@ -378,7 +371,22 @@ export class Images360 extends EventDispatcher{
  
 
 
-
+    setView(o={}){
+        let callback = ()=>{
+            if(o.displayMode){
+                Potree.settings.displayMode = o.displayMode
+            }
+            o.callback && o.callback()
+        } 
+        
+        if(o.pano != void 0){//pano 权重高于 position
+            flyToPano(o)
+        }else{
+            viewer.scene.view.setView(o.position, o.target, o.duration, callback)
+        }
+        
+        
+    }
 
 
 
@@ -386,12 +394,12 @@ export class Images360 extends EventDispatcher{
 
 
     flyToPano(toPano) {
-        if(toPano instanceof Panorama2){
+        if(toPano instanceof Panorama){
             toPano = {pano: toPano}
         }
         
         if(!this.currentPano){
-            return this.focusPano(toPano.pano) 
+            return this.focusPano(toPano) 
         }
         
         if(this.currentPano == pano && this.isAtPano() ){
@@ -402,6 +410,9 @@ export class Images360 extends EventDispatcher{
             return
         }
         
+        let target = toPano.target 
+        
+        
         let config = Potree.config.displayMode[Potree.settings.displayMode]
         var pointcloudVisi = config.atPano.showPoint  //viewer.scene.pointclouds[0].visible
         
@@ -446,7 +457,7 @@ export class Images360 extends EventDispatcher{
             
             const endPosition = pano.position.clone() 
             this.flying = true
-            viewer.scene.view.setView(endPosition,null/* endTarget */,duration,  ()=>{//done
+            viewer.scene.view.setView(endPosition, target ,duration,  ()=>{//done
                 
                 if(!config.atPano.pointUsePanoTex){ 
                     viewer.scene.pointclouds.forEach(e=>{
@@ -481,7 +492,7 @@ export class Images360 extends EventDispatcher{
 		if(this.currentPano !== null){
 			return this.flyToPano(toPano); 
 		}
-        if(toPano instanceof Panorama2){
+        if(toPano instanceof Panorama){
             toPano = {pano: toPano}
         }
         
@@ -489,7 +500,7 @@ export class Images360 extends EventDispatcher{
         let config = Potree.config.displayMode[Potree.settings.displayMode]
 		previousView = {
 			//controls: this.viewer.controls, 
-			position: this.viewer.scene.view.position.clone(),
+			position: this.position,
 			target: viewer.scene.view.getPivot(),
 		};
 
@@ -517,7 +528,7 @@ export class Images360 extends EventDispatcher{
         }
 		//this.load(pano).then( () => {
             
-			this.panos.forEach(e=>e.marker.material.depthTest = false) 
+			//this.panos.forEach(e=>e.marker.material.depthTest = false) 
             
              
             
@@ -556,19 +567,19 @@ export class Images360 extends EventDispatcher{
 
 		
 
-		this.elUnfocus.style.display = "";
+		this.elUnfocus[0].style.display = "";
 	}
 
 
-	unfocus(){
+	unfocus(o={}){
 		this.selectingEnabled = true;
         Potree.settings.displayMode = 'showPointCloud' 
         
         
         
-		let pano = this.currentPano;
+		 
 
-		if(pano === null){
+		if(!this.currentPano && !o.position){
 			return;
 		}
           
@@ -579,20 +590,22 @@ export class Images360 extends EventDispatcher{
 		 
 
 		viewer.scene.view.setView(
-			previousView.position, 
-			previousView.target,
-			500,()=>{ //done
+			o.position || previousView.position, 
+			o.target || previousView.target,
+			o.duration || 500,
+            ()=>{ //done
                 for(let pano of this.panos){
                     pano.mesh.visible = true;
-                    pano.marker.material.depthTest = true
-                } 
+                    //pano.marker.material.depthTest = true
+                }
+                o.callback && o.callback()            
             }
 		);
 
         //this.currentPano.exit()
 		this.currentPano = null;
 
-		this.elUnfocus.style.display = "none";
+		this.elUnfocus[0].style.display = "none";
 	}
 
 	load(pano, ){ 
@@ -651,29 +664,29 @@ export class Images360 extends EventDispatcher{
     rankedPanoInDirection(t, direction, option1, option2){
         var panoSet = {
             pano: null,
-            candidates: []
+            candidates: [] //缓存顺序--如果需要打印的话
         };
         t || (t = 0);
         option1 = void 0 !== option1 ? option1 : .75;
         var o = option2 ? "angle" : "direction";
         var request = [//必要条件 
-            Images360.filters.inPanoDirection( viewer.scene.view.getPivot(), direction, option1), 
+            Images360.filters.inPanoDirection( this.position, direction, option1), 
             //Images360.filters.isNeighbourPanoTo(this.currentPano), 
             Images360.filters.not(this.currentPano)
         ] 
         var list = [//决胜项目
             Images360.scoreFunctions.distanceSquared(this.currentPano),
-            Images360.scoreFunctions[o]( viewer.scene.view.getPivot(), direction)
+            Images360.scoreFunctions[o]( this.position, direction)
         ]; 
          
         this.findRankedByScore(t,request,list,panoSet);
-        //this.cachedPanoCandidates = panoSet.candidates;
+        
         return panoSet.pano;
 		
     }
 
     updateClosestPano(intersect) {
-        
+        intersect = intersect && (intersect.location || intersect)
         var filterFuncs = [];
         //if (this.mode === ViewMode.PANORAMA) {
             if (!this.currentPano) {
@@ -683,7 +696,7 @@ export class Images360 extends EventDispatcher{
             filterFuncs.push(Images360.filters.not(this.currentPano));
  			filterFuncs.push(Images360.filters.inFloorDirection(this.currentPano, viewer.scene.view.direction, .25)),//许钟文改
 			//filterFuncs.push(Images360.filters.isNeighbourPanoTo(this.currentPano));
-            filterFuncs.push(Images360.filters.isCloseEnoughTo(intersect.location, 0.35));
+            filterFuncs.push(Images360.filters.isCloseEnoughTo(intersect, 0.35));
        /*  } else {
 			if(!this.linkEditor.noPanoHasNeighbor){//xzw add  如果不是全孤立点的话,就要避开孤立点
 				filterFuncs.push((pano)=>{return this.linkEditor.checkHasNeighbor(pano)})
@@ -693,7 +706,7 @@ export class Images360 extends EventDispatcher{
         } */
          
         
-        var pano = Common.find(this.panos,  filterFuncs, [Images360.sortFunctions.floorDistanceToPoint(intersect.location)]);
+        var pano = Common.find(this.panos,  filterFuncs, [Images360.sortFunctions.floorDistanceToPoint(intersect)]);
         if (pano != this.closestPano) {
             pano && (this.isPanoHover = !0);
             //触发事件,导致地面的marker变清晰
@@ -719,7 +732,7 @@ export class Images360 extends EventDispatcher{
 
 
 
-	handleHovering(){
+	/* handleHovering(){
 		let pointer = viewer.inputHandler.pointer;
 		let camera = viewer.scene.getActiveCamera();
 		let domElement = viewer.renderer.domElement;
@@ -744,19 +757,21 @@ export class Images360 extends EventDispatcher{
 		//label.setText(currentlyHovered.pano.file);
 		//currentlyHovered.getWorldPosition(label.position);
 	}
-
+    */
+    
+    
 	update(){
 
 		let {viewer} = this;
 
-		if(currentlyHovered){
+		/* if(currentlyHovered){
 			currentlyHovered.material = sm;
 			currentlyHovered = null;
-		}
+		}  
 
 		if(this.selectingEnabled){
 			this.handleHovering();
-		}
+		} */
 
 
         if(this.tileDownloader.started){
@@ -775,7 +790,7 @@ export class Images360 extends EventDispatcher{
     
     
     findRankedByScore(e, t, i, n) {
-        n && (n.candidates = null,
+        n && (n.candidates = null,  //candidates 缓存顺序--如果需要打印的话
         n.pano = null),
         e || (e = 0);
         var r = Common.sortByScore(this.panos, t, i);
@@ -911,13 +926,11 @@ Images360.prototype.checkAndWaitForPanoLoad = function() {
 
 
 
-Images360.filters = {
-    
-    inPanoDirection : function(e, t, i) {  
+Images360.filters = { 
+    inPanoDirection : function(e, t, i) { 
         return function(n) {
-            n = n.position.clone()
-            var r = n.clone().sub(e).setZ(0).normalize()    //忽略上下角度,这样即使看得很低也能走
-			  , o = n.clone().sub(e).normalize(); 
+            var r = n.floorPosition.clone().sub(e).setZ(0).normalize()    //忽略上下角度,这样即使看得很低也能走
+			  , o = n.position.clone().sub(e).normalize(); 
 			return r.dot(t.clone().setZ(0).normalize()) > i || o.dot(t) > i
         }
     },
@@ -936,8 +949,8 @@ Images360.filters = {
         }
     },
     isCloseEnoughTo: function(e, t) {
-        return function(i) {
-            return e.distanceTo(i.floorPositionFish || i.floorPosition) < t //许钟文
+        return function(i) {//因为marker可能比地面高,所以识别范围要比marker看起来更近一些。(因为投影到地板的位置比marker更近)
+            return e.distanceTo(i.floorPosition) < t //许钟文
         }
     },
     
@@ -973,7 +986,7 @@ Images360.scoreFunctions = {
     },   
 }
 
-Images360.sortFunctions =  {
+Images360.sortFunctions =  {//排序函数,涉及到两个item相减
     floorDistanceToPoint: function(e) {
         return function(t, i) {
             return t.floorPosition.distanceTo(e) - i.floorPosition.distanceTo(e)
@@ -994,25 +1007,39 @@ export class Images360Loader{
 		}
 		
 		 
-        let response = await fetch(url); 
-        let text = await response.text();
-        var data = JSON.parse(text)
+        var data = await Potree.loadFile(url)
+              
         let images360 = new Images360(viewer, params);
         
         data = data.sort(function(a,b){return a.id-b.id})
        
         data.forEach(info=>{ 
-			let pano = new Panorama2( info,  params.transform, images360   );
-
-			images360.node.add(pano.mesh); 
-            images360.node2.add(pano.marker);
+			let pano = new Panorama( info,  params.transform, images360   );
+            
+            pano.mesh.layers.set(Potree.config.renderLayers.marker)
+            pano.marker.layers.set(Potree.config.renderLayers.marker) 
+		 
 			images360.panos.push(pano);
 
         })
 
         console.log(data)
         viewer.images360 = window.images360 = images360//add
-        images360.tileDownloader.setPanoData(images360.panos, [], Potree.settings.number);
+        images360.tileDownloader.setPanoData(images360.panos, [] /* , Potree.settings.number */);
+
+        {
+            var panosBound = new THREE.Box3
+            images360.panos.forEach(pano=>{
+                panosBound.expandByPoint(pano.position)
+            }) 
+            images360.bound = {
+                bounding:panosBound,
+                size: panosBound.getSize(new THREE.Vector3),
+                center: panosBound.getCenter(new THREE.Vector3)
+            }
+        }
+
+
 
 		return images360;
 	}

+ 419 - 47
src/modules/Images360/Panorama.js

@@ -1,87 +1,459 @@
 import * as THREE from "../../../libs/three.js/build/three.module.js";
-
+import {transitions, easing, lerp} from '../../utils/transitions.js'
+import TileUtils from './tile/TileUtils'
+import { PanoRendererEvents, PanoramaEvents, PanoSizeClass} from '../../defines'
+import math from '../../utils/math'
+import { EventDispatcher } from "../../EventDispatcher.js";
+import {TextSprite} from '../../TextSprite'
 
 var texLoader = new THREE.TextureLoader()
 
+const labelProp = {
+    sizeInfo: {minSize : 120 ,  maxSize : 200,   nearBound : 0.8, farBound : 10},
+    backgroundColor:{r: 255, g: 255, b: 255, a: 0.2 },
+    borderRadius: 15,
+}
 
+  
 
-let standardMarkerMat = new THREE.MeshBasicMaterial({side: THREE.DoubleSide , map:texLoader.load('../resources/textures/marker.png') ,transparent:true})
-let panoHeight = 2.3;
-let planeGeo = new THREE.PlaneBufferGeometry(1,1);
-
+let standardMarkerMat = new THREE.MeshBasicMaterial({opacity:0.5, side: THREE.DoubleSide , map:texLoader.load('../resources/textures/marker.png') ,transparent:true})
+//显示全景图时marker没有被遮挡,如果需要,要换成depthBasicMaterial  或者直接把skybox的深度修改(拿到深度贴图后更如此)
+let planeGeo = new THREE.PlaneBufferGeometry(0.1,0.1);
 
 
-let sg = new THREE.SphereGeometry(1, 8, 8);
 
+let sg = new THREE.SphereGeometry(0.1, 8, 8);
+let smHovered = new THREE.MeshBasicMaterial({/* side: THREE.BackSide,  */color: 0xff0000});
 
-let sm = new THREE.MeshBasicMaterial({side: THREE.BackSide});
-var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0), Math.PI/2); //这里旋转还是基于原先的坐标轴,因为是先有图片的旋转后有skybox整体的旋转。但是角度不是负的是正的。
-
+let sm = new THREE.MeshBasicMaterial({/* side: THREE.BackSide */});
 
 
 
+var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1),  Math.PI/2 ); //使用的是刚好适合全景图的,给cube贴图需要转90°
+//var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0),  -Math.PI/2 ); //4dkk->navvis
+//var rot901 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0), -Math.PI/2 ); //整张球幕图要旋转下
+//rot90 = new THREE.Quaternion().multiplyQuaternions(  rot901, rot90)   
+var old = null;
+/* 
+转成四维看看的axis:
+var a = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90))  因为四维的要绕y转90
+这里的quaternion.multiply(a);
+ 
+先乘再换顺序 w : q.w,  x:q.x , y:-q.z, z:q.y
 
+ */
 
+//暂时直接用4dkkconsole输出的数据 
+class Panorama extends EventDispatcher{
 
+	constructor(o, transform, images360){//file, time, longitude, latitude, altitude, course, pitch, roll
+        super()
+        this.id = o.id;
+        this.images360 = images360
+        this.transform =  transform
+        //this.position.set(this.position.x, -this.position.z, this.position.y) //4dkk的坐标绕x旋转90°
 
+        /* this.longitude = o.location[0]
+        this.latitude = o.location[1]
+        this.altitude = o.location[2]  */
+        this.originPosition = new THREE.Vector3().fromArray(o.dataset_location) 
+        this.originFloorPosition = new THREE.Vector3().fromArray(o.dataset_floor_location)
+        
+        this.originID = parseInt(o.file_id)//"file_id":"00022"对应是原本的4dkk的id  
+        
+        
+        this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0]
+        this.pointcloud.panos.push(this)
+        
+        //全景图和Cube的水平采样起始坐标相差90度 
+        
 
-class Panorama{
+        /* if(from4dkk){
+            var qua = o.dataset_orientation 
+            
+            var quaternion = new THREE.Quaternion().fromArray(qua)
+                quaternion = new THREE.Quaternion().multiplyQuaternions(quaternion,  rot901);//整张球幕图要旋转下  因为在4dkk里转过,还原。如果是tiles的不用
+            this.quaternion = new THREE.Quaternion(quaternion.x, -quaternion.z, quaternion.y, quaternion.w) //转化坐标
+                
+        }else{ */
+        
+            
+            var qua = o.dataset_orientation 
+            qua = [qua[1], qua[2], qua[3], qua[0]] 
+            this.quaternion = new THREE.Quaternion().fromArray(qua)
+            this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion 
+            this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion,  rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
+         //}
+         
+         
+            //this.quaternion1 = Potree.Utils.QuaternionFactory.fromArray(o.dataset_orientation)
+            //同quaternion
 
-	constructor(o){//file, time, longitude, latitude, altitude, course, pitch, roll
-		this.file = o.file;
-		this.time = o.time;
-		this.longitude = o.long;
-		this.latitude = o.lat;
-		this.altitude = o.alt;
-		this.course = o.course;
-		this.pitch = o.pitch;
-		this.roll = o.roll;
-        this.transform = o.transform
-		this.mesh = null;
+      
+        //let xy = this.transform.forward([this.longitude, this.latitude]);  
+        this.file = `https://4dkk.4dage.com/images/images${Potree.settings.number}/pan/high/${this.id}.jpg`
+        this.build()
+        this.transformByPointcloud() //初始化位移
+         
         
         
-        let xy = this.transform.forward([this.longitude, this.latitude]);  
-        this.position = new THREE.Vector3(xy[0], xy[1], o.alt) 
-        this.build()
+        {//tile
+            this.minimumTiledPanoLoaded = !1;
+            this.highestPartialTileRenderOpCompleted = 0;
+            this.highestFullTileRenderOpCompleted = 0;
+            this.shouldRedrawOnBaseLoaded = !1;
+            this.resolutionPromise = {}
+            this.tiledPanoRenderTarget = null;
+            this.zoomed = !1;
+            
+            
+            
+           
+            images360.panoRenderer.on(PanoRendererEvents.TileRenderSuccess, this.onTileRendered.bind(this));
+            images360.panoRenderer.on(PanoRendererEvents.PanoRenderComplete, this.onPanoRendered.bind(this));
+            images360.panoRenderer.on(PanoRendererEvents.TileRenderFailure, this.onTileRenderFail.bind(this));
+            images360.panoRenderer.on(PanoRendererEvents.UploadAttemptedForAllTiles, this.onUploadAttemptedForAllTiles.bind(this));
+            
+        }
+        
+        
+        
+        this.on('hoverOn', (e)=>{//from Map
+            if(!e.byMainView){ 
+                this.hoverOn(e) 
+            } 
+        })
+        
+        this.on('hoverOff', (e)=>{
+            if(!e.byMainView){
+                this.hoverOff(e) 
+            } 
+        })
 	}
     
+
+
+
+
+
+
+
     
     build(){
-         
-
-        let mesh = new THREE.Mesh(sg, sm);
-        mesh.position.copy(this.position)
+          
+        let mesh = new THREE.Mesh(sg, sm); 
         mesh.scale.set(1, 1, 1);
         mesh.material.transparent = true;
         mesh.material.opacity = 0.75;
         mesh.pano = this;
-
+        mesh.name = 'panoSphere'
+        mesh.addEventListener('mouseover',(e)=>{
+            mesh.material = smHovered
+        })
+        mesh.addEventListener('mouseleave',(e)=>{
+            mesh.material = sm
+        })
+        mesh.addEventListener('click',(e)=>{
+            this.images360.focusPano(this)
+        })
         { // orientation
-            var {course, pitch, roll} = this;
-            mesh.rotation.set(
-                THREE.Math.degToRad(+roll + 90),
-                THREE.Math.degToRad(-pitch),
-                THREE.Math.degToRad(-course + 90),
-                "ZYX"
-            );
+            //var {course, pitch, roll} = this;
+            //mesh.quaternion.copy(this.quaternion) 
+             
             //add 
-            var quaternion = new THREE.Quaternion().multiplyQuaternions(mesh.quaternion,  rot90);//改  为球目全
-            this.panoMatrix = new THREE.Matrix4().makeRotationFromQuaternion(quaternion) 
-        
+            //var quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion,  rot901);//改  为球目全
+            //quaternion.premultiply(rot90)
+            this.panoMatrix = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion) 
+            this.oriPanoMatrix = this.panoMatrix.clone()
+            //console.log(this.quaternion)
+            //this.quaternion = quaternion
         } 
         this.mesh = mesh;
-        
-        
          
-        let marker = new THREE.Mesh(planeGeo, standardMarkerMat)
-            
-            marker.position.copy(mesh.position);
-              
-            marker.position.z -= panoHeight
+         
+        let marker = new THREE.Mesh(planeGeo, standardMarkerMat.clone()) 
+            marker.up.set(0,0,1)
+            marker.lookAt(marker.up) 
             marker.scale.set(2,2,2) 
             
-        this.marker = marker    
+             
+        this.marker = marker 
+        
+        this.images360.node.add(mesh)
+        this.images360.node.add(marker)
+        //this.createTextLabel()
+        
+    }
+    
+    
+    
+    
+    transformByPointcloud(){
+        /* pointcloud.orientationUser = 0  
+                    pointcloud.translateUser = new THREE.Vector3; */
+                    
+        /* this.position.        
+        this.position.addVectors(this.originPosition,  pointcloud.translateUser)  */
+        let position = this.originPosition.clone().applyMatrix4(this.pointcloud.matrixForPano);
+        let floorPosition = this.originFloorPosition.clone().applyMatrix4(this.pointcloud.matrixForPano);
+        this.setPosition(position, floorPosition) 
+        this.panoMatrix = new THREE.Matrix4().multiplyMatrices(this.oriPanoMatrix, this.pointcloud.rotateMatrix) 
+    }
+    
+    setPosition(position, floorPosition){
+        this.position = position
+        this.floorPosition = floorPosition
+        this.mesh.position.copy(this.position)
+        this.marker.position.copy(this.floorPosition) 
+        //this.marker.position.z+=0.1
+        this.label && (this.label.position.copy(this.floorPosition), this.label.position.z+=0.2)
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    hoverOn(e={}) { 
+        //console.log("hoverOn  " + this.id  )
+        transitions.start(lerp.property(this.marker.material, "opacity", 1), 250)  
+		if(!e.byMap) this.emit('hoverOn', {byMainView:true})
+    }
+
+ 
+
+
+    hoverOff(e={}){
+        //console.log("hoverOff  " + this.id  )
+        transitions.start(lerp.property(this.marker.material, "opacity", 0.5), 250) 
+        if(!e.byMap) this.emit('hoverOff', {byMainView:true})
+    }
+    
+    enter(){ 
+        this.setZoomed(!1),
+        this.dispatchEvent({type:PanoramaEvents.Enter, oldPano:old, newPano:this  }  ),
+        old = this 
+        //this.model.setHighMap(this)//add
+        
+        //console.log("enter pano "+ this.id)
+    } 
+
+    exit(){
+        /* if(this.tiled)
+        { */
+            this.clearWaitDeferreds();
+            this.minimumTiledPanoLoaded = !1;
+            this.tiledPanoRenderTarget = null;
+            this.setZoomed(!1);
+            this.images360.panoRenderer.deactivateTiledPano(this);
+            this.highestPartialTileRenderOpCompleted = 0;
+            this.highestFullTileRenderOpCompleted = 0;
+        /*}
+         else
+        {
+            this.solidSkybox.dispose();
+            this.solidSkybox.loaded = !1;
+            this.solidSkybox.version = 0;
+        } */
+        
+        //console.log("exit pano "+ this.id)
+        
+        this.emit(PanoramaEvents.Exit, this); 
+    }
+
+    
+    getSkyboxTexture(){
+        /* if(this.tiled)
+        { */
+            if(this.minimumTiledPanoLoaded)
+            {
+                if(this.zoomed && this.images360.qualityManager.maxRenderTargetSize > this.images360.qualityManager.maxNavPanoSize)//change 如果放大后和不放大都是2k就不用这个
+                {
+                    return this.images360.panoRenderer.zoomRenderTarget.texture;   
+                }
+                else
+                {
+                    
+                    this.tiledPanoRenderTarget.texture.mapping = THREE.UVMapping//add
+                    return this.tiledPanoRenderTarget.texture;
+                }
+            }
+            else
+            {
+                return null;
+            }
+        /* }
+        else
+        { 
+            return this.solidSkybox;
+        }*/
+    }
+    
+    setZoomed(e){
+        this.zoomed = e;
+        //this.updateSkyboxForZoomLevel();
+        //e ? this.model.showHighMap() : this.model.hideHighMap() //add
+    }
+    
+    isLoaded(e){
+        //if (this.tiled) {
+            if (e && "string" == typeof e)
+                console.error("Wrong panoSize given to Panorama.isLoaded(); a tiled pano uses PanoSizeClass");
+            return !!this.minimumTiledPanoLoaded && (!e || this.highestPartialTileRenderOpCompleted >= e)
+        //}
+        /* if (e && "number" == typeof e)
+            throw new BasicException("Wrong panoSize given to Panorama.isLoaded(); a non-tiled pano uses high/low.");
+        return !!this.solidSkybox.high || e in this.solidSkybox */
+    }
+
+    getWaitDeferred(size){//获取不同size的tile贴图的promiss 
+        var t = this.resolutionPromise[this.id];
+        t || (t = {}, this.resolutionPromise[this.id] = t);
+        var i = t[size];
+        return i || (i = {
+            deferred: $.Deferred(),
+            active: !1
+        },
+        t[size] = i),
+        i
+    }
+    
+    clearWaitDeferreds(){
+        var e = this.resolutionPromise[this.id];
+        e || (e = {},
+        this.resolutionPromise[this.id] = e);
+        for (var t in e)
+            if (e.hasOwnProperty(t)) {
+                var i = e[t];
+                i.active = !1,
+                i.deferred = $.Deferred()
+            }
+    }
+    resetWaitDeferred(e){
+        var t = this.getWaitDeferred(e);
+        t.active = !1;
+        t.deferred = $.Deferred();
+    }
+    onTileRendered(e, t, i, n){
+        e === this.id && this.dispatchEvent({type:PanoramaEvents.TileLoaded,  size:t, index:i, count:n});
+    }
+
+    onPanoRendered(e, t, i, n) {
+        if(e === this.id)
+        {
+            this.minimumTiledPanoLoaded = !0;
+            //this.updateSkyboxForZoomLevel();//更新贴图 setProjected
+            t > this.highestPartialTileRenderOpCompleted && (this.highestPartialTileRenderOpCompleted = t);//应该是更新最高获取到的Partial size
+            !n && t > this.highestFullTileRenderOpCompleted && (this.highestFullTileRenderOpCompleted = t); //应该是更新最高获取到的Full size
+            //this.emit("load", t);
+            //this.model.emit("load", this);
+            this.dispatchEvent({type:PanoramaEvents.LoadComplete, size:t, count:i});
+        }
+    }
+ 
+    onTileRenderFail(e, t, i) {
+        e === this.id && this.dispatchEvent({type:PanoramaEvents.LoadFailed, t});
+    }
+    onUploadAttemptedForAllTiles(e, t, i) {
+        if (e === this.id) {
+            var n = this.images360.qualityManager.getPanoSize(PanoSizeClass.BASE);
+            if(t === n && this.shouldRedrawOnBaseLoaded)
+            {
+                this.shouldRedrawOnBaseLoaded = !1;
+                this.panoRenderer.resetRenderStatus(this.id, !0, !1);
+                this.panoRenderer.renderPanoTiles(this.id, null, !0, !0);
+            }
+        }
+    }
+
+    
+    
+    createTextLabel(){
+        this.removeTextLabel()
+        this.label = new TextSprite($.extend(
+           labelProp, {text: this.id}) 
+        );
+        this.images360.node.add(this.label);
+        this.floorPosition && this.label.position.copy(this.floorPosition)
+    }
+    
+    removeTextLabel(){
+        if(this.label){
+            
+            this.label.parent.remove(this.label);
+        }
     }
+    
+    
+    
 };
 
+
+
+
+Panorama.prototype.loadTiledPano = function() {
+    var downloads = []  , t = [];
+    
+    return function(size, dir, fov, o, a, download) {
+        null !== o && void 0 !== o || (o = !0),
+        null !== a && void 0 !== a || (a = !0);
+        var l = this.getWaitDeferred(size)
+          , c = l.deferred
+          , h = null
+          , u = null;
+        fov && ("number" == typeof fov ? h = fov : (h = fov.hFov, u = fov.vFov))  
+        if (!this.isLoaded(size)) {
+            if (!l.active) {
+                l.active = !0 
+                if (fov) {
+                    var d = TileUtils.matchingTilesInDirection(this, size, dir, h, u);
+                    downloads[this.id + ":" + size] = {
+                        tileCount: 0,
+                        targetTileCount: d
+                    } 
+                    //console.log("Loading partial pano: " + this.id + " with " + d + " tiles")
+                }
+                if(!t[this.id]) {
+                    t[this.id] = !0 
+                    
+                    this.addEventListener(PanoramaEvents.LoadComplete, function(ev/* e, t */) {//本次任务全部加载完毕 
+                        var i = this.getWaitDeferred(ev.size).deferred;//"pending"为还未完成
+                        i && "pending" === i.state() && this.highestPartialTileRenderOpCompleted >= ev.size && (i.resolve(ev.size, ev.count),
+                        this.resetWaitDeferred(ev.size))//恢复active为false
+                    }.bind(this)) 
+                    
+                    this.addEventListener(PanoramaEvents.LoadFailed, function(ev) {
+                        var t = this.getWaitDeferred(e).deferred;
+                        t && "pending" === t.state() && this.highestPartialTileRenderOpCompleted >= ev.t && (t.reject(ev.t),
+                        this.resetWaitDeferred(ev.t))//恢复active为false
+                    }.bind(this)) 
+                    
+                    this.addEventListener(PanoramaEvents.TileLoaded, function(ev/* t, i, n */) {//每张加载完时
+                        var r = this.getWaitDeferred(ev.size).deferred;
+                        if (r && "pending" === r.state()) {
+                            r.notify(ev.size, ev.index, ev.count);
+                            var o = downloads[this.id + ":" + ev.size];
+                            if(o){//如果有规定下载哪些tile,只需要下载这些tile则LoadComplete
+                                o.tileCount++ 
+                                if(o.tileCount === o.targetTileCount){//达到下载目标数
+                                    this.onPanoRendered(this.id, ev.size, ev.count, !0);
+                                    r.resolve(ev.size, ev.count);
+                                    this.resetWaitDeferred(ev.size)
+                                }
+                            }
+                        }
+                    }.bind(this))
+                }
+            }
+            this.images360.tileDownloader.clearForceQueue(),
+            this.images360.tileDownloader.forceQueueTilesForPano(this, size, dir, h, u, download),
+            this.tiledPanoRenderTarget = this.images360.panoRenderer.activateTiledPano(this, this.images360.qualityManager.getMaxNavPanoSize(), o),
+            this.images360.panoRenderer.renderPanoTiles(this.id, dir, a)
+        }
+        return c.promise()
+    }
+}()
+
 export default Panorama

+ 0 - 398
src/modules/Images360/Panorama2.js

@@ -1,398 +0,0 @@
-import * as THREE from "../../../libs/three.js/build/three.module.js";
-import {transitions, esing, lerp} from '../../utils/transitions.js'
-import TileUtils from './tile/TileUtils'
-import { PanoRendererEvents, PanoramaEvents, PanoSizeClass} from '../../defines'
-import math from '../../utils/math'
-import { EventDispatcher } from "../../EventDispatcher.js";
-
-
-var texLoader = new THREE.TextureLoader()
-
-
-
-let standardMarkerMat = new THREE.MeshBasicMaterial({opacity:0.5, side: THREE.DoubleSide , map:texLoader.load('../resources/textures/marker.png') ,transparent:true})
- 
-let planeGeo = new THREE.PlaneBufferGeometry(0.1,0.1);
-
-
-
-let sg = new THREE.SphereGeometry(0.1, 8, 8);
-
-
-let sm = new THREE.MeshBasicMaterial({side: THREE.BackSide});
-
-
-
-var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1),  Math.PI/2 ); //使用的是刚好适合全景图的,给cube贴图需要转90°
-//var rot90 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0),  -Math.PI/2 ); //4dkk->navvis
-//var rot901 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0), -Math.PI/2 ); //整张球幕图要旋转下
-//rot90 = new THREE.Quaternion().multiplyQuaternions(  rot901, rot90)   
-var old = null;
-/* 
-转成四维看看的axis:
-var a = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90))  因为四维的要绕y转90
-这里的quaternion.multiply(a);
- 
-先乘再换顺序 w : q.w,  x:q.x , y:-q.z, z:q.y
-
- */
-
-//暂时直接用4dkkconsole输出的数据 
-class Panorama2 extends EventDispatcher{
-
-	constructor(o, transform, images360){//file, time, longitude, latitude, altitude, course, pitch, roll
-        super()
-        this.id = o.id;
-        this.position = new THREE.Vector3().fromArray(o.dataset_location) 
-        //this.position.set(this.position.x, -this.position.z, this.position.y) //4dkk的坐标绕x旋转90°
-        this.originPosition = this.position.clone()
-
-        /* this.longitude = o.location[0]
-        this.latitude = o.location[1]
-        this.altitude = o.location[2]  */
-        this.transform =  transform
-		this.mesh = null;
-        this.floorPosition = new THREE.Vector3().fromArray(o.dataset_floor_location)
-        //this.floorPosition.set( this.floorPosition.x, -this.floorPosition.z, this.floorPosition.y)
-        this.originFloorPosition = this.floorPosition.clone()
-        
-        
-        this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0]
-        this.pointcloud.panos.push(this)
-        
-        //全景图和Cube的水平采样起始坐标相差90度 
-        
-
-        /* if(from4dkk){
-            var qua = o.dataset_orientation 
-            
-            var quaternion = new THREE.Quaternion().fromArray(qua)
-                quaternion = new THREE.Quaternion().multiplyQuaternions(quaternion,  rot901);//整张球幕图要旋转下  因为在4dkk里转过,还原。如果是tiles的不用
-            this.quaternion = new THREE.Quaternion(quaternion.x, -quaternion.z, quaternion.y, quaternion.w) //转化坐标
-                
-        }else{ */
-            var qua = o.dataset_orientation 
-            qua = [qua[1], qua[2], qua[3], qua[0]]
-            this.quaternion = new THREE.Quaternion().fromArray(qua)
-            this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion 
-            this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion,  rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
-         //}
-
-      
-        //let xy = this.transform.forward([this.longitude, this.latitude]);  
-        this.file = `https://4dkk.4dage.com/images/images${Potree.settings.number}/pan/high/${this.id}.jpg`
-        this.build()
-        this.transformByPointcloud()
-        
-        
-        
-        {//tile
-            this.minimumTiledPanoLoaded = !1;
-            this.highestPartialTileRenderOpCompleted = 0;
-            this.highestFullTileRenderOpCompleted = 0;
-            this.shouldRedrawOnBaseLoaded = !1;
-            this.resolutionPromise = {}
-            this.tiledPanoRenderTarget = null;
-            this.zoomed = !1;
-            
-            
-            this.images360 = images360
-           
-            images360.panoRenderer.on(PanoRendererEvents.TileRenderSuccess, this.onTileRendered.bind(this));
-            images360.panoRenderer.on(PanoRendererEvents.PanoRenderComplete, this.onPanoRendered.bind(this));
-            images360.panoRenderer.on(PanoRendererEvents.TileRenderFailure, this.onTileRenderFail.bind(this));
-            images360.panoRenderer.on(PanoRendererEvents.UploadAttemptedForAllTiles, this.onUploadAttemptedForAllTiles.bind(this));
-            
-        }
-	}
-    
-
-
-
-
-
-
-
-    transformByPointcloud(){
-        /* pointcloud.orientationUser = 0  
-                    pointcloud.translateUser = new THREE.Vector3; */
-                    
-        /* this.position.        
-        this.position.addVectors(this.originPosition,  pointcloud.translateUser)  */
-        this.position = this.originPosition.clone().applyMatrix4(this.pointcloud.matrixForPano);
-        this.floorPosition = this.originFloorPosition.clone().applyMatrix4(this.pointcloud.matrixForPano);
-        
-        this.mesh.position.copy(this.position)
-        this.marker.position.copy(this.floorPosition)
-        
-        
-        this.panoMatrix = new THREE.Matrix4().multiplyMatrices(this.oriPanoMatrix, this.pointcloud.rotateMatrix) 
-    }
-    
-    
-    build(){
-          
-        let mesh = new THREE.Mesh(sg, sm);
-        mesh.position.copy(this.position)
-        mesh.scale.set(1, 1, 1);
-        mesh.material.transparent = true;
-        mesh.material.opacity = 0.75;
-        mesh.pano = this;
-
-        { // orientation
-            //var {course, pitch, roll} = this;
-            //mesh.quaternion.copy(this.quaternion) 
-             
-            //add 
-            //var quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion,  rot901);//改  为球目全
-            //quaternion.premultiply(rot90)
-            this.panoMatrix = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion) 
-            this.oriPanoMatrix = this.panoMatrix.clone()
-            //console.log(this.quaternion)
-            //this.quaternion = quaternion
-        } 
-        this.mesh = mesh;
-         
-         
-        let marker = new THREE.Mesh(planeGeo, standardMarkerMat.clone())
-            
-            marker.position.copy(this.floorPosition); 
-            //marker.position.z += 0.1;
-            marker.up.set(0,0,1)
-            marker.lookAt(this.position) 
-            marker.scale.set(2,2,2) 
-             
-        this.marker = marker 
-    }
-    
-    
-    hoverOn() { 
-        //console.log("hoverOn  " + this.id  )
-        transitions.start(lerp.property(this.marker.material, "opacity", 1), 250)  
-		
-    }
-
- 
-
-
-    hoverOff(){
-        //console.log("hoverOff  " + this.id  )
-        transitions.start(lerp.property(this.marker.material, "opacity", 0.5), 250) 
-
-    }
-    
-    enter(){ 
-        this.setZoomed(!1),
-        this.dispatchEvent({type:PanoramaEvents.Enter, oldPano:old, newPano:this  }  ),
-        old = this 
-        //this.model.setHighMap(this)//add
-        
-        //console.log("enter pano "+ this.id)
-    } 
-
-    exit(){
-        /* if(this.tiled)
-        { */
-            this.clearWaitDeferreds();
-            this.minimumTiledPanoLoaded = !1;
-            this.tiledPanoRenderTarget = null;
-            this.setZoomed(!1);
-            this.images360.panoRenderer.deactivateTiledPano(this);
-            this.highestPartialTileRenderOpCompleted = 0;
-            this.highestFullTileRenderOpCompleted = 0;
-        /*}
-         else
-        {
-            this.solidSkybox.dispose();
-            this.solidSkybox.loaded = !1;
-            this.solidSkybox.version = 0;
-        } */
-        
-        //console.log("exit pano "+ this.id)
-        
-        this.emit(PanoramaEvents.Exit, this); 
-    }
-
-    
-    getSkyboxTexture(){
-        /* if(this.tiled)
-        { */
-            if(this.minimumTiledPanoLoaded)
-            {
-                if(this.zoomed && this.images360.qualityManager.maxRenderTargetSize > this.images360.qualityManager.maxNavPanoSize)//change 如果放大后和不放大都是2k就不用这个
-                {
-                    return this.images360.panoRenderer.zoomRenderTarget.texture;   
-                }
-                else
-                {
-                    
-                    this.tiledPanoRenderTarget.texture.mapping = THREE.UVMapping//add
-                    return this.tiledPanoRenderTarget.texture;
-                }
-            }
-            else
-            {
-                return null;
-            }
-        /* }
-        else
-        { 
-            return this.solidSkybox;
-        }*/
-    }
-    
-    setZoomed(e){
-        this.zoomed = e;
-        //this.updateSkyboxForZoomLevel();
-        //e ? this.model.showHighMap() : this.model.hideHighMap() //add
-    }
-    
-    isLoaded(e){
-        //if (this.tiled) {
-            if (e && "string" == typeof e)
-                console.error("Wrong panoSize given to Panorama.isLoaded(); a tiled pano uses PanoSizeClass");
-            return !!this.minimumTiledPanoLoaded && (!e || this.highestPartialTileRenderOpCompleted >= e)
-        //}
-        /* if (e && "number" == typeof e)
-            throw new BasicException("Wrong panoSize given to Panorama.isLoaded(); a non-tiled pano uses high/low.");
-        return !!this.solidSkybox.high || e in this.solidSkybox */
-    }
-
-    getWaitDeferred(size){//获取不同size的tile贴图的promiss 
-        var t = this.resolutionPromise[this.id];
-        t || (t = {}, this.resolutionPromise[this.id] = t);
-        var i = t[size];
-        return i || (i = {
-            deferred: $.Deferred(),
-            active: !1
-        },
-        t[size] = i),
-        i
-    }
-    
-    clearWaitDeferreds(){
-        var e = this.resolutionPromise[this.id];
-        e || (e = {},
-        this.resolutionPromise[this.id] = e);
-        for (var t in e)
-            if (e.hasOwnProperty(t)) {
-                var i = e[t];
-                i.active = !1,
-                i.deferred = $.Deferred()
-            }
-    }
-    resetWaitDeferred(e){
-        var t = this.getWaitDeferred(e);
-        t.active = !1;
-        t.deferred = $.Deferred();
-    }
-    onTileRendered(e, t, i, n){
-        e === this.id && this.dispatchEvent({type:PanoramaEvents.TileLoaded,  size:t, index:i, count:n});
-    }
-
-    onPanoRendered(e, t, i, n) {
-        if(e === this.id)
-        {
-            this.minimumTiledPanoLoaded = !0;
-            //this.updateSkyboxForZoomLevel();//更新贴图 setProjected
-            t > this.highestPartialTileRenderOpCompleted && (this.highestPartialTileRenderOpCompleted = t);//应该是更新最高获取到的Partial size
-            !n && t > this.highestFullTileRenderOpCompleted && (this.highestFullTileRenderOpCompleted = t); //应该是更新最高获取到的Full size
-            //this.emit("load", t);
-            //this.model.emit("load", this);
-            this.dispatchEvent({type:PanoramaEvents.LoadComplete, size:t, count:i});
-        }
-    }
- 
-    onTileRenderFail(e, t, i) {
-        e === this.id && this.dispatchEvent({type:PanoramaEvents.LoadFailed, t});
-    }
-    onUploadAttemptedForAllTiles(e, t, i) {
-        if (e === this.id) {
-            var n = this.images360.qualityManager.getPanoSize(PanoSizeClass.BASE);
-            if(t === n && this.shouldRedrawOnBaseLoaded)
-            {
-                this.shouldRedrawOnBaseLoaded = !1;
-                this.panoRenderer.resetRenderStatus(this.id, !0, !1);
-                this.panoRenderer.renderPanoTiles(this.id, null, !0, !0);
-            }
-        }
-    }
-
-    
-    
-    
-    
-    
-    
-    
-    
-    
-};
-
-
-
-
-Panorama2.prototype.loadTiledPano = function() {
-    var downloads = []  , t = [];
-    
-    return function(size, dir, fov, o, a, download) {
-        null !== o && void 0 !== o || (o = !0),
-        null !== a && void 0 !== a || (a = !0);
-        var l = this.getWaitDeferred(size)
-          , c = l.deferred
-          , h = null
-          , u = null;
-        fov && ("number" == typeof fov ? h = fov : (h = fov.hFov, u = fov.vFov))  
-        if (!this.isLoaded(size)) {
-            if (!l.active) {
-                l.active = !0 
-                if (fov) {
-                    var d = TileUtils.matchingTilesInDirection(this, size, dir, h, u);
-                    downloads[this.id + ":" + size] = {
-                        tileCount: 0,
-                        targetTileCount: d
-                    } 
-                    //console.log("Loading partial pano: " + this.id + " with " + d + " tiles")
-                }
-                if(!t[this.id]) {
-                    t[this.id] = !0 
-                    
-                    this.addEventListener(PanoramaEvents.LoadComplete, function(ev/* e, t */) {//本次任务全部加载完毕 
-                        var i = this.getWaitDeferred(ev.size).deferred;//"pending"为还未完成
-                        i && "pending" === i.state() && this.highestPartialTileRenderOpCompleted >= ev.size && (i.resolve(ev.size, ev.count),
-                        this.resetWaitDeferred(ev.size))//恢复active为false
-                    }.bind(this)) 
-                    
-                    this.addEventListener(PanoramaEvents.LoadFailed, function(ev) {
-                        var t = this.getWaitDeferred(e).deferred;
-                        t && "pending" === t.state() && this.highestPartialTileRenderOpCompleted >= ev.t && (t.reject(ev.t),
-                        this.resetWaitDeferred(ev.t))//恢复active为false
-                    }.bind(this)) 
-                    
-                    this.addEventListener(PanoramaEvents.TileLoaded, function(ev/* t, i, n */) {//每张加载完时
-                        var r = this.getWaitDeferred(ev.size).deferred;
-                        if (r && "pending" === r.state()) {
-                            r.notify(ev.size, ev.index, ev.count);
-                            var o = downloads[this.id + ":" + ev.size];
-                            if(o){//如果有规定下载哪些tile,只需要下载这些tile则LoadComplete
-                                o.tileCount++ 
-                                if(o.tileCount === o.targetTileCount){//达到下载目标数
-                                    this.onPanoRendered(this.id, ev.size, ev.count, !0);
-                                    r.resolve(ev.size, ev.count);
-                                    this.resetWaitDeferred(ev.size)
-                                }
-                            }
-                        }
-                    }.bind(this))
-                }
-            }
-            this.images360.tileDownloader.clearForceQueue(),
-            this.images360.tileDownloader.forceQueueTilesForPano(this, size, dir, h, u, download),
-            this.tiledPanoRenderTarget = this.images360.panoRenderer.activateTiledPano(this, this.images360.qualityManager.getMaxNavPanoSize(), o),
-            this.images360.panoRenderer.renderPanoTiles(this.id, dir, a)
-        }
-        return c.promise()
-    }
-}()
-
-export default Panorama2

+ 17 - 100
src/modules/datasetAlignment/Alignment.js

@@ -1,9 +1,12 @@
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
-import {View} from "../../viewer/View.js";
+import SplitScreen from "../../utils/SplitScreen"
+
+
+
 
 var Alignment = {
-    
+     
     setMatrix :  function(pointcloud){
         var vec1 = pointcloud.position
         var vec2 = pointcloud.translateUser
@@ -26,8 +29,8 @@ var Alignment = {
         
         
         pointcloud.matrix = matrix;
-        pointcloud.matrixWorldNeedsUpdate = true //更新matrixWorld (非计算,直接赋值)
-         
+        //pointcloud.matrixWorldNeedsUpdate = true //更新matrixWorld (非计算,直接赋值)
+        pointcloud.updateMatrixWorld(true)
         
     },
     rotate:function(pointcloud, deg, angle){//假设点云位移position后0,0,0就是它的中心了(根据navvis观察这样做是绕同一个点旋转的)
@@ -41,111 +44,25 @@ var Alignment = {
     },
     
     
-    
-    
-    
-    splitScreen : function(){
-        var defaultCamera = viewer.scene.getActiveCamera()
-        /* var pointclouds = viewer.scene.pointclouds//[viewer.scene.pointclouds[0]] //
-        var boundingBox = new THREE.Box3();
-        pointclouds.forEach(pointcloud=>{
-            var boundingBox_ = pointcloud.pcoGeometry.tightBoundingBox.clone().applyMatrix4(pointcloud.matrixWorld)
-            boundingBox.union(boundingBox_)
-        })
-        var boundSize = boundingBox.getSize()
-        var center = boundingBox.getCenter()
-        console.log(boundSize)
-        console.log(center) */
-        let {boundSize, center} = viewer.bound
-          
-        var getOrthographicCamera = function(widthRatio, heightRatio, axis){
-            var widthPX = viewer.renderArea.clientWidth * widthRatio;
-            var heightPX = viewer.renderArea.clientHeight * heightRatio;
-            var aspect = widthPX/heightPX
-            var width = Math.max(boundSize[axis[0]],  boundSize[axis[0]] * aspect)
-            var orthographicCamera = new THREE.OrthographicCamera(-width/2, width/2, -width/2/aspect, width/2/aspect, 0.01, 10000);
-            var moveAtAxis = ['x','y','z'].find(e=>!(axis.includes(e)))
-            orthographicCamera.up.set(0,0,1)
-            orthographicCamera.position.copy(center)
-            orthographicCamera.position[moveAtAxis] += 1000;//偏移一些 在模型外即可
-            
-         
-            //console.log(width )
-            
-            return orthographicCamera
-        }
-
+    enter:function(){
         
-        var viewports = [
-            {
-                left:0.5,
-                bottom:0.5,
-                width: 0.5,height:0.5,
-                name : 'default', 
-                camera : defaultCamera,
-                view: viewer.scene.view,
-                active: true,
-            },
-            {
-                left:0,
-                bottom:0.5,
-                width: 0.5,height:0.5,
-                name : 'Top',   
-                axis:["x","y"],
-                axisSign:[1,1],
-                active: true,
-            },
-            {
-                left:0.5,
-                bottom:0,
-                width: 0.5,height:0.5,
-                name : 'Right', 
-                axis:["y","z"],
-                axisSign:[1,1],
-                active: true,
-            },
-            {
-                left:0,
-                bottom:0,
-                width: 0.5,height:0.5, 
-                name : 'Back', 
-                axis:["x","z"],
-                axisSign:[-1,1],    // 从镜头方向看  x向左 所以取负 
-                active: true,
-            },
-        ]
-        viewer.viewports = viewports;
-        for(let i=1;i<4;i++){
-            let viewport = viewports[i];
-            viewport.camera = getOrthographicCamera(viewport.width, viewport.height, viewport.axis)
-            viewport.view = new View()
-            //viewer.setView(viewport.viewCode, viewport.view )
-            viewport.view.setCubeView(viewport.name)
-            viewport.view.position.copy(viewport.camera.position)
-        }
+        SplitScreen.splitScreen4Views({alignment:true})
         
-        viewer.dispatchEvent({'type': 'beginSplitView' }) 
         
+    },
+    leave:function(){
         
-    }
+        SplitScreen.recoverFrom4Views()
+        viewer.updateModelBound();
+    } 
+    
     ,
     
-    focusOnViewport : function(index){
-        viewer.viewports.forEach((viewport, i )=>{
-            if(i == index){
-                viewport.left = 0;  viewport.bottom = 0;   viewport.height = 1;  viewport.width = 1
-            }else{
-                viewport.active = false
-            }
-        })
-        viewer.viewports[index]
-        
-        
-    }
+    
     
 }
 
 
-window.Alignment = Alignment
+ 
 
 export {Alignment} 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 92 - 44
src/navigation/FirstPersonControls.js


+ 194 - 165
src/navigation/InputHandler.js

@@ -9,19 +9,18 @@ import {KeyCodes} from "../KeyCodes.js";
 import {Utils} from "../utils.js";
 import {MOUSE} from "../defines.js"; 
 import {EventDispatcher} from "../EventDispatcher.js";
-import Magnifier from "../utils/Magnifier.js";
-import Reticule from "./Reticule.js";
+
 
 export class InputHandler extends EventDispatcher {
-	constructor (viewer) {
+	constructor (viewer,scene) {
 		super();
 
-		this.viewer = viewer;
+		this.viewer = viewer; 
 		this.renderer = viewer.renderer;
 		this.domElement = this.renderer.domElement;
 		this.enabled = true;
 		
-		this.scene = null;
+		this.scene = scene;
 		this.interactiveScenes = [];
 		this.interactiveObjects = new Set();
 		this.inputListeners = [];
@@ -31,13 +30,13 @@ export class InputHandler extends EventDispatcher {
 		this.mouse = new THREE.Vector2(0, 0);
         //add:
         this.pointer = new THREE.Vector2(0, 0); //交互点的屏幕坐标,有别于DOM坐标,在此存放NDC坐标。(NDC,三维常用坐标系,二维坐标,整个屏幕映射范围(-1,1),屏幕中心为原点,+Y朝上,+X朝右)
-		
+		this.mouseDownMouse = new THREE.Vector2(0, 0);
         
         this.selection = [];
 
 		this.hoveredElements = [];
 		this.pressedKeys = {};
-
+        
 		this.wheelDelta = 0;
 
 		this.speed = 1;
@@ -49,12 +48,10 @@ export class InputHandler extends EventDispatcher {
 		}
         
         
-        this.magnifier = new Magnifier(viewer, this);//add
-        //this.viewer.scene.sceneOverlay.add(this.magnifier) 
-        this.viewer.overlay.add(this.magnifier) //不和sceneOverlay放一处,因为透明冲突
-        this.reticule = new Reticule(this)
-        this.viewer.scene.sceneOverlay.add(this.reticule) 
-        this.mouseDownMouse;
+     
+
+
+        
         
         
         
@@ -79,7 +76,7 @@ export class InputHandler extends EventDispatcher {
 		this.domElement.addEventListener('touchmove', this.onTouchMove.bind(this));
 	}
 
-	addInputListener (listener) {
+	/* addInputListener (listener) {
 		this.inputListeners.push(listener);
 	}
 
@@ -94,7 +91,7 @@ export class InputHandler extends EventDispatcher {
 
 			return ib - ia;
 		});
-	}
+	} */
 
 	onTouchStart (e) {
 		if (this.logMessages) console.log(this.constructor.name + ': onTouchStart');
@@ -111,13 +108,13 @@ export class InputHandler extends EventDispatcher {
 		}
 
 		
-		for (let inputListener of this.getSortedListeners()) {
-			inputListener.dispatchEvent({
-				type: e.type,
+		/* for (let inputListener of this.getSortedListeners()) {
+			inputListener */this.viewer.dispatchEvent({
+				type: /* "global_"+ */e.type, // global_ 是否加上
 				touches: e.touches,
 				changedTouches: e.changedTouches
 			});
-		}
+		//}
         
         //add
         this.mouseDownMouse = this.mouse.clone()
@@ -128,23 +125,23 @@ export class InputHandler extends EventDispatcher {
 
 		e.preventDefault();
 
-		for (let inputListener of this.getSortedListeners()) {
-			inputListener.dispatchEvent({
-				type: 'drop',
+		/* for (let inputListener of this.getSortedListeners()) {
+			inputListener. */this.viewer.dispatchEvent({
+				type: 'global_drop',
 				drag: this.drag,
 				viewer: this.viewer
 			});
-		}
+		//}
 
 		this.drag = null;
 
-		for (let inputListener of this.getSortedListeners()) {
-			inputListener.dispatchEvent({
-				type: e.type,
+		/* for (let inputListener of this.getSortedListeners()) {
+			inputListener */this.viewer.dispatchEvent({
+				type: 'global_' + e.type,
 				touches: e.touches,
 				changedTouches: e.changedTouches
 			});
-		}
+		//}
 	}
 
 	onTouchMove (e) {
@@ -167,23 +164,23 @@ export class InputHandler extends EventDispatcher {
 				this.drag.end.set(x, y);
 
 				if (this.logMessages) console.log(this.constructor.name + ': drag: ');
-				for (let inputListener of this.getSortedListeners()) {
-					inputListener.dispatchEvent({
-						type: 'drag',
+				/* for (let inputListener of this.getSortedListeners()) {
+					inputListener */this.viewer.dispatchEvent({
+						type: 'global_drag',
 						drag: this.drag,
 						viewer: this.viewer
 					});
-				}
+				//}
 			}
 		}
 
-		for (let inputListener of this.getSortedListeners()) {
-			inputListener.dispatchEvent({
+		/* for (let inputListener of this.getSortedListeners()) {
+			inputListener. */this.viewer.dispatchEvent({
 				type: e.type,
 				touches: e.touches,
 				changedTouches: e.changedTouches
 			});
-		}
+		//}
 
 		// DEBUG CODE
 		// let debugTouches = [...e.touches, {
@@ -255,13 +252,13 @@ export class InputHandler extends EventDispatcher {
 		}
 
 		if (!consumed) {
-			for (let inputListener of this.getSortedListeners()) {
-				inputListener.dispatchEvent({
-					type: 'dblclick',
+			/* for (let inputListener of this.getSortedListeners()) {
+				inputListener. */this.viewer.dispatchEvent({
+					type: 'global_dblclick',
 					mouse: this.mouse,
 					object: null
 				});
-			}
+			//}
 		}
 
 		e.preventDefault();
@@ -280,18 +277,18 @@ export class InputHandler extends EventDispatcher {
     
 		e.preventDefault(); 
         
-        this.onMouseMove(e)//add 重新获取一下mouse, 因在此前canvas可能失去侦听
+        //this.onMouseMove(e)//add 重新获取一下mouse, 因在此前canvas可能失去侦听(不记得是什么了。如果一定要的话再写个加侦听的函数,但是直接调用mousemove的话会发送drag,导致magnifier停止渲染)
         
 		let consumed = false;
 		let consume = () => { return consumed = true; };
 		if (this.hoveredElements.length === 0) {
-			for (let inputListener of this.getSortedListeners()) {
-				inputListener.dispatchEvent({
-					type: 'mousedown',
+			/* for (let inputListener of this.getSortedListeners()) {
+				inputListener */this.viewer.dispatchEvent({
+					type: 'global_mousedown',
 					viewer: this.viewer,
 					mouse: this.mouse
 				});
-			}
+			//}
 		}else{
 			for(let hovered of this.hoveredElements){
 				let object = hovered.object;
@@ -324,10 +321,8 @@ export class InputHandler extends EventDispatcher {
         this.drag.pointerDragStart = this.pointer.clone()
         this.drag.intersectStart = this.intersectPoint;
         this.mouseDownMouse = this.mouse.clone()
-        
-		if (this.scene) {
-			this.viewStart = this.scene.view.clone();
-		}
+        this.dragViewport = this.hoverViewport;
+		 
 	}
 
 	onMouseUp (e) {
@@ -339,14 +334,14 @@ export class InputHandler extends EventDispatcher {
 		e.preventDefault();
         
         let pressDistance = this.mouseDownMouse.distanceTo(this.mouse);
-		let noMovement = this.getNormalizedDrag().length() === 0;
+		let noMovement = this.drag.pointerDelta.length() == 0//this.getNormalizedDrag().length() === 0;
         
 		let consumed = false;
 		let consume = () => { return consumed = true; };
 		if (this.hoveredElements.length === 0) {
-			for (let inputListener of this.getSortedListeners()) {
-				inputListener.dispatchEvent({
-					type: 'mouseup',
+			/* for (let inputListener of this.getSortedListeners()) {
+				inputListener */this.viewer.dispatchEvent({
+					type: 'global_mouseup',
 					viewer: this.viewer,
 					mouse: this.mouse,
 					consume: consume,
@@ -354,10 +349,10 @@ export class InputHandler extends EventDispatcher {
                     pressDistance 
 				});
 
-				if(consumed){
+				/* if(consumed){//??
 					break;
-				}
-			}
+				} */
+			//}
 		}else{
 			let hovered = this.hoveredElements
 				.map(e => e.object)
@@ -371,30 +366,59 @@ export class InputHandler extends EventDispatcher {
 			}
 		}
 
-		if (this.drag) {
-            //只有左键才能拖拽物体:
+		if (this.drag) { 
 			if (this.drag.object/*  && e.button == THREE.MOUSE.LEFT */) {//add LEFT
 				if (this.logMessages) console.log(`${this.constructor.name}: drop ${this.drag.object.name}`);
 				this.drag.object.dispatchEvent({
 					type: 'drop',
 					drag: this.drag, 
 					viewer: this.viewer,
-                    pressDistance
+                    pressDistance,
+                    button : e.button//add 放开的鼠标按键
 
 				});
 			} else {
-				for (let inputListener of this.getSortedListeners()) {
-					inputListener.dispatchEvent({
-						type: 'drop',
+				/* for (let inputListener of this.getSortedListeners()) {
+					inputListener. */this.viewer.dispatchEvent({
+						type: 'global_drop',
 						drag: this.drag,
 						viewer: this.viewer,
-                        pressDistance
+                        pressDistance,
+                        button: e.button //add
 					});
-				}
+				//}
+                
+                
+                // check for a click 
+                if(pressDistance < 2){
+                    if(this.hoveredElements && this.hoveredElements[0]){
+                        if (this.logMessages) console.log(`${this.constructor.name}: click ${clicked.name}`);
+                        this.hoveredElements[0].object.dispatchEvent({
+                            type: 'click',
+                            viewer: this.viewer,
+                            consume: consume,
+                            viewport: this.hoverViewport,
+                            button: e.button //add
+                        });
+                    }else{
+                        /* for (let inputListener of this.getSortedListeners()) {
+                            inputListener. */this.viewer.dispatchEvent({
+                                type: 'global_click',
+                                drag: this.drag,
+                                viewer: this.viewer,
+                                pressDistance,
+                                button: e.button //add
+                            });
+                        //}
+                    }
+                     
+                }
+                
 			}
 
-			// check for a click
-			let clicked = this.hoveredElements.map(h => h.object).find(v => v === this.drag.object) !== undefined;
+			
+            
+			/* let clicked = this.hoveredElements.map(h => h.object).find(v => v === this.drag.object) !== undefined;
 			if(clicked){
 				if (this.logMessages) console.log(`${this.constructor.name}: click ${this.drag.object.name}`);
 				this.drag.object.dispatchEvent({
@@ -402,12 +426,14 @@ export class InputHandler extends EventDispatcher {
 					viewer: this.viewer,
 					consume: consume,
 				});
-			}
+			} */
             this.drag = null;
             
 		}
 
-		if(!consumed){
+        this.dragViewport = null
+
+		if(!consumed && !this.fixSelection){
 			if (e.button === THREE.MOUSE.LEFT) {
 				if (noMovement) {
 					let selectable = this.hoveredElements
@@ -443,7 +469,7 @@ export class InputHandler extends EventDispatcher {
         let camera 
         let viewport 
         
-        if(this.viewer.viewports || viewForceAt){
+        //if(this.viewer.viewports || viewForceAt){
             var getDimension = (view)=>{
                 var left = Math.floor(this.domElement.clientWidth * view.left)
                  , bottom = this.domElement.clientHeight * view.bottom
@@ -481,37 +507,36 @@ export class InputHandler extends EventDispatcher {
                     } 
                     
                 }
-                /* if(!getif){
-                    console.log('no get')
-                } */   
+                  
                 
             } 
-        }else{
+        /*} else{
             camera = this.viewer.scene.getActiveCamera()
             this.mouse.set(x , y )
             Utils.convertScreenPositionToNDC(this.pointer, this.mouse, this.domElement.clientWidth, this.domElement.clientHeight);
-        } 
+        }  */
         return { 
             camera, viewport 
         }
     }
 
 	onMouseMove (e) {
+         
 		e.preventDefault();
-        var defaultCamera = this.viewer.scene.getActiveCamera()
-        var  {  camera, viewport  } = this.getPointerInViewport(e.clientX, e.clientY, this.drag && this.hoverViewport) 
+       
+        var  {  camera, viewport  } = this.getPointerInViewport(e.clientX, e.clientY,  this.dragViewport) 
 		this.hoverViewport = viewport
-         
+        if(!viewport)return//刚变化viewport时会找不到
         
         
-		let hoveredElements = this.getHoveredElements();
+		let hoveredElements = this.getHoveredElements(); 
 		if(hoveredElements.length > 0){
 			let names = hoveredElements.map(h => h.object.name).join(", ");
 			if (this.logMessages) console.log(`${this.constructor.name}: onMouseMove; hovered: '${names}'`);
 		}
-
+ 
         //add
-        let intersectPoint = Utils.getMousePointCloudIntersection(
+        let intersectPoint = viewport.noPointcloud ? null : Utils.getMousePointCloudIntersection(
             viewport,
             this.mouse,
             this.pointer, 
@@ -519,18 +544,24 @@ export class InputHandler extends EventDispatcher {
             this.viewer, 
             this.viewer.scene.pointclouds,
             {pickClipped: true});
-
-
+            
+            
+        if(viewport.name == 'mapViewport'){ 
+            let pos3d = new THREE.Vector3(this.pointer.x,this.pointer.y,-1).unproject(viewport.camera); //z:-1朝外   
+            intersectPoint = pos3d.clone().setZ(0);//z初始默认为0
+             
+        }    
+ 
 		if (this.drag) {//有按下鼠标拖拽(不一定拖拽了物体)
 			this.drag.mouse = e.buttons; 
-
-			this.drag.mouseDelta.x = this.mouse.x - this.drag.end.x;
-			this.drag.mouseDelta.y = this.mouse.y - this.drag.end.y;
-
-			this.drag.end.set(this.mouse.x, this.mouse.y);
+            this.drag.hoverViewport = this.hoverViewport
+			/* this.drag.mouseDelta.x = this.mouse.x - this.drag.end.x;
+			this.drag.mouseDelta.y = this.mouse.y - this.drag.end.y; */
+            this.drag.pointerDelta.set(this.pointer.x - this.drag.end.x, this.pointer.y - this.drag.end.y  )
+			this.drag.end.set(this.pointer.x, this.pointer.y);
             
-            //如果按下右键或中建,就暂停拖拽:
-			if (this.drag.object && (e.buttons == MOUSE.LEFT || e.buttons == MOUSE.NONE)) {//add LEFT
+            
+			if (this.drag.object && (e.buttons == MOUSE.LEFT || e.buttons == MOUSE.NONE)) {//add LEFT  如果按下右键或中建,就暂停拖拽:
 				if (this.logMessages) console.log(this.constructor.name + ': drag: ' + this.drag.object.name);
 				this.drag.object.dispatchEvent({
 					type: 'drag',
@@ -545,19 +576,19 @@ export class InputHandler extends EventDispatcher {
                 
 				if (this.logMessages) console.log(this.constructor.name + ': drag: ');
 
-				let dragConsumed = false;
-				for (let inputListener of this.getSortedListeners()) {
-					inputListener.dispatchEvent({
-						type: 'drag',
+				let dragConsumed = false; 
+				/* for (let inputListener of this.getSortedListeners()) {
+					inputListener. */this.viewer.dispatchEvent({
+						type: 'global_drag',
 						drag: this.drag,
 						viewer: this.viewer,
 						consume: () => {dragConsumed = true;}
 					});
 
-					if(dragConsumed){
+					/* if(dragConsumed){
 						break;
-					}
-				}
+					} */
+				//}
 			}
 		}else{
 			let curr = hoveredElements.map(a => a.object).find(a => true);
@@ -595,74 +626,56 @@ export class InputHandler extends EventDispatcher {
 
             //仅在鼠标不按下时更新:
             
-            if(intersectPoint && viewport && viewport.name != 'default'){
+            if(intersectPoint &&  viewport.alignment ){
                 viewer.dispatchEvent({
                     type : "CursorChange", action : "add",  name:"movePointcloud"
                 })
-            }else{
+            }else{ 
                 viewer.dispatchEvent({
-                    type : "CursorChange", action : "remove",  name:"movePointcloud"
+                    type : "CursorChange", action : "remove",  name:"movePointcloud" 
                 })
-            }
-            
-            
-            
-
-            
-            if (intersectPoint) { 
-                this.magnifier.update( intersectPoint.location) 
-                
-                if(viewer.showCoordType){ //显示坐标位置时
-                    let pos = intersectPoint.point.position.toArray()
-                    if(viewer.showCoordType == "local"){
-                         
-                    }else if(viewer.showCoordType == "lonlat"){
-                        pos = viewer.transform.lonlatToLocal.inverse(pos)
-                    }else{
-                        pos = viewer.transform.lonlatToLocal.inverse(pos)
-                        pos = viewer.transform.lonlatTo4550.forward(pos)
-                        
-                    }
-                     
-                    viewer.dispatchEvent({
-                        type : "coordinateChange", pos
-                    })
-                }
-                
-                //viewer.images360.updateClosestPano(intersectPoint)
-                
-            }
-            
-            
-             
-            
+            } 
             
             
 		}
         
-        this.reticule.updatePosition(intersectPoint, defaultCamera.position)   
-        //add 放大镜
-        
+         
         
+		if (intersectPoint) { 
             
-           
-        this.intersectPoint = intersectPoint        
-        
-		
-        
+            
+            if(viewer.showCoordType){ //显示坐标位置时
+                let pos = intersectPoint.point.position.toArray()
+                if(viewer.showCoordType == "local"){
+                     
+                }else if(viewer.showCoordType == "lonlat"){
+                    pos = viewer.transform.lonlatToLocal.inverse(pos)
+                }else{
+                    pos = viewer.transform.lonlatToLocal.inverse(pos)
+                    pos = viewer.transform.lonlatTo4550.forward(pos)
+                    
+                }
+                 
+                viewer.dispatchEvent({
+                    type : "coordinateChange", pos
+                })
+            }  
+        }
         
         
+        this.intersectPoint = intersectPoint 
         
         
         
         
-		 for (let inputListener of this.getSortedListeners()) {
-		 	inputListener.dispatchEvent({
-		 		type: 'mousemove',
+        /* for (let inputListener of this.getSortedListeners()) {
+            inputListener. */this.viewer.dispatchEvent({
+                type: 'global_mousemove',
                 intersectPoint,
-		 		object: null
-		 	});
-		 }
+                hoverViewport:this.hoverViewport,
+                object: null
+            });
+        //}
 		
 
 		this.hoveredElements = hoveredElements;
@@ -693,14 +706,15 @@ export class InputHandler extends EventDispatcher {
 				object: this.hoveredElement.object
 			});
 		} else {
-			for (let inputListener of this.getSortedListeners()) {
-				inputListener.dispatchEvent({
-					type: 'mousewheel',
+			/* for (let inputListener of this.getSortedListeners()) {
+				inputListener. */this.viewer.dispatchEvent({
+					type: 'global_mousewheel',
 					delta: ndelta,
 					object: null,
                     hoverViewport: this.hoverViewport
+                    
 				});
-			}
+			//}
 		}
 	}
 
@@ -710,18 +724,18 @@ export class InputHandler extends EventDispatcher {
 		if (this.logMessages) console.log(`${this.constructor.name}: startDragging: '${name}'`);
 
 		this.drag = {
-			start: this.mouse.clone(),
-			end: this.mouse.clone(),
-			mouseDelta: new THREE.Vector2(0, 0),
-			startView: this.scene.view.clone(), 
+			start: this.pointer.clone(),
+			end: this.pointer.clone(),
+			pointerDelta: new THREE.Vector2(0, 0), 
 			object: object, 
-            dragViewport :  this.hoverViewport, 
+            dragViewport :  this.hoverViewport, //开始之后就不会变了
+            hoverViewport: this.hoverViewport   //会变化
 		};
         
         
         this.viewer.dispatchEvent({
             type: "startDragging",
-            viewport :  this.hoverViewport, 
+            hoverViewport: this.hoverViewport
         })
         /* console.log('startDragging')
         console.log(this.drag.end) */
@@ -844,12 +858,12 @@ export class InputHandler extends EventDispatcher {
 	}
 
 	getHoveredElements () {
-		let scenes = this.interactiveScenes.concat(this.scene.scene);
+		let scenes = this.hoverViewport.interactiveScenes || this.interactiveScenes.concat(this.scene);
 
 		let interactableListeners = ['mouseup', 'mousemove', 'mouseover', 'mouseleave', 'drag', 'drop', 'click', 'select', 'deselect'];
 		let interactables = [];
 		for (let scene of scenes) {
-			scene.traverseVisible(node => {
+			scene.traverseVisible(node => {//检测加了侦听的object
 				if (node._listeners && node.visible && !this.blacklist.has(node)) {
 					let hasInteractableListener = interactableListeners.filter((e) => {
 						return node._listeners[e] !== undefined;
@@ -862,8 +876,8 @@ export class InputHandler extends EventDispatcher {
 			});
 		}
 		
-		let camera = this.scene.getActiveCamera();
-        let ray = Utils.mouseToRay(this.pointer, camera, this.domElement.clientWidth, this.domElement.clientHeight);
+		let camera = this.hoverViewport.camera
+        let ray = Utils.mouseToRay(this.pointer, camera  );
 		
 		let raycaster = new THREE.Raycaster();
 		raycaster.ray.set(ray.origin, ray.direction);  
@@ -875,9 +889,24 @@ export class InputHandler extends EventDispatcher {
         
         
 		raycaster.params.Line.threshold = 0.2;
-
-		let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), false);
+        raycaster.layers.enableAll()//add
         
+        this.viewer.emit('raycaster', {viewport: this.hoverViewport})//add
+		let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), true); //原本是false 检测不到children
+         
+        intersections = intersections.map(e=>{//add 转化为interactables
+            var object = e.object; 
+            do{ 
+               if(interactables.includes(object)) {
+                   e.oriObject = e.object;
+                   e.object = object; 
+                   break
+               } 
+               object = object.parent
+            }while(object)
+       
+            return e
+        })
         
         //add for测量线,在检测到sphere时优先选中sphere而非线
         intersections = intersections.sort(function(a,b){return b.object.renderOrder-a.object.renderOrder}) // 降序
@@ -886,17 +915,17 @@ export class InputHandler extends EventDispatcher {
 		return intersections;
 	}
 
-	setScene (scene) {
+	/* setScene (scene) {
 		this.deselectAll();
 
 		this.scene = scene;
-	}
+	} */
 
 	update (delta) {
 
 	}
 
-	getNormalizedDrag () {
+	/*getNormalizedDrag () {
 		if (!this.drag) {
 			return new THREE.Vector2(0, 0);
 		}
@@ -920,10 +949,10 @@ export class InputHandler extends EventDispatcher {
 		mouseDelta.y = mouseDelta.y / this.domElement.clientHeight;
 
 		return mouseDelta;
-	}
+	} */
     
     getMouseDirection() {//add 
-		let camera = this.scene.getActiveCamera();
+		let camera = this.hoverViewport.camera
         var t = new THREE.Vector3(this.pointer.x, this.pointer.y, -1).unproject(camera),
             i = new THREE.Vector3(this.pointer.x, this.pointer.y, 1).unproject(camera);
             

+ 18 - 7
src/navigation/OrbitControls.js

@@ -43,6 +43,7 @@ export class OrbitControls extends EventDispatcher{
 		this.tweens = [];
 
 		let drag = (e) => {
+            if(!this.enabled)return
 			if (e.drag.object !== null) {
 				return;
 			}
@@ -53,10 +54,12 @@ export class OrbitControls extends EventDispatcher{
 				this.dispatchEvent({type: 'start'});
 			}
 
-			let ndrag = {
+			/* let ndrag = {
 				x: e.drag.mouseDelta.x / this.renderer.domElement.clientWidth,
 				y: e.drag.mouseDelta.y / this.renderer.domElement.clientHeight
-			};
+			}; */
+            let ndrag = e.drag.pointerDelta.clone()//.add(new THREE.Vector2(1,1)).multiplyScalar(0.5)
+            ndrag.y *= -1
 
 			if (e.drag.mouse === MOUSE.LEFT) {
 				this.yawDelta += ndrag.x * this.rotationSpeed;
@@ -72,10 +75,12 @@ export class OrbitControls extends EventDispatcher{
 		};
 
 		let drop = e => {
+            if(!this.enabled)return
 			this.dispatchEvent({type: 'end'});
 		};
 
 		let scroll = (e) => {
+            if(!this.enabled)return
 			let resolvedRadius = this.scene.view.radius + this.radiusDelta;
 
 			this.radiusDelta += -e.delta * resolvedRadius * 0.1;
@@ -84,6 +89,7 @@ export class OrbitControls extends EventDispatcher{
 		};
 
 		let dblclick = (e) => {
+            if(!this.enabled)return
 			if(this.doubleClockZoomEnabled){
 				this.zoomToLocation(e.mouse);
 			}
@@ -99,6 +105,7 @@ export class OrbitControls extends EventDispatcher{
 		};
 
 		let touchMove = e => {
+            if(!this.enabled)return
 			if (e.touches.length === 2 && previousTouch.touches.length === 2){
 				let prev = previousTouch;
 				let curr = e;
@@ -144,16 +151,18 @@ export class OrbitControls extends EventDispatcher{
 		this.addEventListener('touchstart', touchStart);
 		this.addEventListener('touchend', touchEnd);
 		this.addEventListener('touchmove', touchMove);
-		this.addEventListener('drag', drag);
-		this.addEventListener('drop', drop);
-		this.addEventListener('mousewheel', scroll);
-		this.addEventListener('dblclick', dblclick);
+		this.viewer.addEventListener('global_drag', drag);
+		this.viewer.addEventListener('global_drop', drop);
+		this.viewer.addEventListener('global_mousewheel', scroll);
+		this.viewer.addEventListener('global_dblclick', dblclick);
 	}
 
 	setScene (scene) {
 		this.scene = scene;
 	}
-
+    setEnable(enabled){
+        this.enabled = enabled
+    }
 	stop(){
 		this.yawDelta = 0;
 		this.pitchDelta = 0;
@@ -162,6 +171,7 @@ export class OrbitControls extends EventDispatcher{
 	}
 	
 	zoomToLocation(mouse){
+        if(!this.enabled)return
 		let camera = this.scene.getActiveCamera();
 		
 		let I = Utils.getMousePointCloudIntersection(
@@ -231,6 +241,7 @@ export class OrbitControls extends EventDispatcher{
 	}
 
 	update (delta) {
+        if(!this.enabled)return
 		let view = this.scene.view;
 
 		{ // apply rotation

+ 26 - 37
src/navigation/Reticule.js

@@ -1,6 +1,6 @@
 import * as THREE from "../../libs/three.js/build/three.module.js";
 
-import {transitions, esing, lerp} from '../utils/transitions.js'
+import {transitions, easing, lerp} from '../utils/transitions.js'
 
 
 
@@ -8,9 +8,9 @@ let texLoader = new THREE.TextureLoader()
 let defaultOpacity =  0.7
 //鼠标指示小圆片 
 export default class Reticule extends THREE.Mesh{
-    constructor(inputHandler){
-        var defaultTex = texLoader.load(Potree.config.urls.localTextures+'whiteCircle.png'/* reticule-256x256.png'  */)  
-        var crosshairTex = texLoader.load(Potree.config.urls.localTextures+'reticule_cross_hair.png') 
+    constructor(viewer){
+        var defaultTex = texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png'/* reticule-256x256.png'  */)  
+        var crosshairTex = texLoader.load(Potree.resourcePath+'/textures/reticule_cross_hair.png') 
         
         super(new THREE.PlaneBufferGeometry(0.15,0.15,1,1),new THREE.MeshBasicMaterial({
             side: THREE.DoubleSide , 
@@ -19,51 +19,36 @@ export default class Reticule extends THREE.Mesh{
             depthTest: !1,
             opacity: defaultOpacity,
             //depthWrite: !1,
-        }))
-        
-        
-        
-        
-        /*  new THREE.RawShaderMaterial({
-            side: THREE.DoubleSide,
-            depthWrite: !1,
-            depthTest: !1,
-            transparent: !0,
-            vertexShader: shaders.waypoint.vertexShader,
-            fragmentShader: shaders.waypoint.fragmentShader,
-            uniforms: uniform,
-            name: "waypoint",
-            opacity: 0
-        })); */
-        
-        
-        
-        
+        })) 
         
         //this.layers.set(0/* RenderLayers.RETICULE */);
         this.renderOrder = 0
-       
+        this.layers.set(Potree.config.renderLayers.marker);
+        
+        
         this.direction = new THREE.Vector3;
         this.hidden = !0;
         this.mouseLastMoveTime = Date.now();
 
 
-        inputHandler.addInputListener(this);
-        this.addEventListener('mousemove',this.move.bind(this))
+        //viewer.inputHandler.addInputListener(this);
+        viewer.addEventListener('global_mousemove',this.move.bind(this))
         
-        this.addEventListener('measureMovePoint',()=>{
+        viewer.addEventListener('measureMovePoint',()=>{
             this.material.map = crosshairTex
         }) 
-        this.addEventListener('endMeasureMove',()=>{
+        viewer.addEventListener('endMeasureMove',()=>{
             this.material.map = defaultTex 
         }) 
          
     
     }
 
-    move(){
+    move(e){
         this.hidden = false,
         this.mouseLastMoveTime = Date.now()
+        
+        this.updatePosition(e.intersectPoint, viewer.scene.getActiveCamera().position)
     }
 
     hide(){
@@ -83,21 +68,25 @@ export default class Reticule extends THREE.Mesh{
         Date.now() - this.mouseLastMoveTime > 1500 && !this.hidden && this.hide()
     }
 
-    updatePosition(intersectPoint, cameraPos ){
+    updatePosition(intersectPoint, cameraPos ){ //在地图(当地图融合到viewer时)和场景里都显示且完全相同(大小可能不同)
         if (!this.hidden) {
-            if (!intersectPoint || !intersectPoint.point.normal)
+            if (!intersectPoint /* || !intersectPoint.point.normal */)
                 return //this.hide();
-            var i = intersectPoint.location
-                , n = cameraPos.distanceTo(i)
-                , r = 1 + .01 * n;
+             
+            let normal = intersectPoint.point ? new THREE.Vector3().fromArray(intersectPoint.point.normal ) : new THREE.Vector3(0,0,1)//地图无normal
+             
+            let location = intersectPoint.location || intersectPoint
+                , n = cameraPos.distanceTo(location)
+                , r = 1 + .01 * n; 
+                
             n < 1 && (r -= 1 - n)
             
-            let normal = new THREE.Vector3().fromArray(intersectPoint.point.normal)
+            
             this.show();
             this.scale.set(r, r, r);
             this.direction = this.direction.multiplyScalar(.8); 
             this.direction.add(normal.clone().multiplyScalar(.2));
-            this.position.copy(i).add(normal.clone().multiplyScalar(.01));
+            this.position.copy(location).add(normal.clone().multiplyScalar(.01));
             this.lookAt(this.position.clone().add(this.direction));
         }
     }

+ 2 - 2
src/navigation/VRControls.js

@@ -74,10 +74,10 @@ class FlyMode{
 
 	start(vrControls){
 		if(!this.dbgLabel){
-			this.dbgLabel = new Potree.TextSprite("abc");
+			/* this.dbgLabel = new Potree.TextSprite("abc");
 			this.dbgLabel.name = "debug label";
 			vrControls.viewer.sceneVR.add(this.dbgLabel);
-			this.dbgLabel.visible = false;
+			this.dbgLabel.visible = false; */
 		}
 	}
 	

+ 39 - 9
src/settings.js

@@ -62,6 +62,13 @@ const config = {//配置参数   不可修改
 
 	},
     
+    
+    
+    urls:{
+        //localTextures:'../resources/textures/',
+        prefix: 'laser-oss.4dkankan.com',//oss
+        prefix2: 'testlaser.4dkankan.com'
+    },
      
     transitionsTime:{
         panoToPano: 1000,
@@ -69,17 +76,37 @@ const config = {//配置参数   不可修改
         flyOut:1000,
     }
     ,
+    view:{
+        fov:50,  //navvis:50
+    },
     
+    pointQuality:{
+        low:{//highPerformance
+            maxLevel: 4, //最小为0
+            pointBudget :1*1000*1000,
+        },
+        middle:{//balanced
+            maxLevel: 5,
+            pointBudget:4*1000*1000,
+        },
+        high:{//highQuality
+            maxLevel: 8,
+            pointBudget:8*1000*1000,
+        }
+        //minNodeSize?
+    },
     measure:{
         lineColor:"#00c7b2",
+        highLightColor:'#FFFFFF',//'#02e4cc', //hover时线条和mainLabel颜色
+        backColor:'#333333',
         guideLineColor:"#FFFFFF",
         lineWidth: 4,
-        labelOpacity:0.7,
+        labelOpacity:0.6,
         textColor: "#FFFFFF"
         
     },
     material:{//初始化
-        pointSize:0.4,//1.6,
+        pointSize:0.75,//0.4,
         minSize: 0.1,
         pointSizeType: 'ADAPTIVE'// 
         //ADAPTIVE : 字会失真扭曲
@@ -87,12 +114,15 @@ const config = {//配置参数   不可修改
         //navvis的shader在哪里 为什么不会抖动
     }
     ,
+     
     
-    
-    urls:{
-        localTextures:'../resources/textures/',
-        
-        
+    renderLayers:{//渲染层,方便分批渲染管理,替代scene的创建。数字不代表顺序。
+        bg: 1,
+        skybox: 2,
+        pointcloud: 0,
+        marker: 0,
+        measure:0, //其实本来顺序是3,但是用depthTexture单独渲染了,无所谓layer,就用默认的0
+        magnifier:0//其实本来顺序是4,但是clearDepth了无所谓了
     },
     
     tiling: {
@@ -159,8 +189,8 @@ const config = {//配置参数   不可修改
 
 var settings = {//设置   可修改
     number: '', //场景序号
-    displayMode:''
-    
+    displayMode:'',
+    isTest :browser.urlHasValue('test')
     
 }
 

+ 111 - 19
src/utils.js

@@ -456,7 +456,7 @@ export class Utils {
 		}
 	}
 
-	static pixelsArrayToImage (pixels, width, height) {
+	/* static pixelsArrayToImage (pixels, width, height) {
 		let canvas = document.createElement('canvas');
 		canvas.width = width;
 		canvas.height = height;
@@ -478,9 +478,9 @@ export class Utils {
 		// img.style.transform = "scaleY(-1)";
 
 		return img;
-	}
+	} */
 
-	static pixelsArrayToDataUrl(pixels, width, height) {
+	static pixelsArrayToDataUrl(pixels, width, height, compressRatio = 0.7) {
 		let canvas = document.createElement('canvas');
 		canvas.width = width;
 		canvas.height = height;
@@ -489,20 +489,32 @@ export class Utils {
 
 		pixels = new pixels.constructor(pixels);
 
-		for (let i = 0; i < pixels.length; i++) {
+		/* for (let i = 0; i < pixels.length; i++) {
 			pixels[i * 4 + 3] = 255;
-		}
+		} */
+        // flip vertically
+		let bytesPerLine = width * 4;
+		for(let i = 0; i < parseInt(height / 2); i++){
+			let j = height - i - 1;
 
+			let lineI = pixels.slice(i * bytesPerLine, i * bytesPerLine + bytesPerLine);
+			let lineJ = pixels.slice(j * bytesPerLine, j * bytesPerLine + bytesPerLine);
+			pixels.set(lineJ, i * bytesPerLine);
+			pixels.set(lineI, j * bytesPerLine);
+		}
+        
+        
+        
 		let imageData = context.createImageData(width, height);
 		imageData.data.set(pixels);
 		context.putImageData(imageData, 0, 0);
 
-		let dataURL = canvas.toDataURL();
+		let dataURL = canvas.toDataURL(compressRatio);
 
 		return dataURL;
 	}
 
-	static pixelsArrayToCanvas(pixels, width, height){
+	/* static pixelsArrayToCanvas(pixels, width, height){
 		let canvas = document.createElement('canvas');
 		canvas.width = width;
 		canvas.height = height;
@@ -531,7 +543,7 @@ export class Utils {
 		context.putImageData(imageData, 0, 0);
 
 		return canvas;
-	}
+	} */
 
 	static removeListeners(dispatcher, type){
 		if (dispatcher._listeners === undefined) {
@@ -559,11 +571,12 @@ export class Utils {
 
 		return ray;
 	} */
-    static mouseToRay(pointer, camera, width, height){
+    static mouseToRay(pointer, camera  ){
  
-		let vector = new THREE.Vector3(pointer.x, pointer.y, 0.5);
-		let origin = camera.position.clone();
+		let vector = new THREE.Vector3(pointer.x, pointer.y, 1); 
+        let origin = new THREE.Vector3(pointer.x, pointer.y, -1); //不能用camera.position,在orbitCamera时不准
 		vector.unproject(camera);
+        origin.unproject(camera);
 		let direction = new THREE.Vector3().subVectors(vector, origin).normalize();
 
 		let ray = new THREE.Ray(origin, direction);
@@ -571,23 +584,27 @@ export class Utils {
 		return ray;
 	}
     
-    static getPos2d(point, camera, dom){//获取一个三维坐标对应屏幕中的二维坐标
+    static getPos2d(point, camera, dom, viewport){//获取一个三维坐标对应屏幕中的二维坐标
 		 
 		var pos = point.clone().project(camera)	//比之前hotspot的计算方式写得简单  project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
 		
-		var x,y;
-		x = (pos.x + 1) / 2 * dom.clientWidth;
-		y = (1 - (pos.y + 1) / 2) * dom.clientHeight; 
+		var x,y,left,top;
+		x = (pos.x + 1) / 2 * dom.clientWidth * viewport.width;
+		y = (1 - (pos.y + 1) / 2) * dom.clientHeight * viewport.height; 
+        left = viewport.left * dom.clientWidth;
+        top = (1- viewport.bottom - viewport.height) * dom.clientHeight;
+         
   
-		var inSight = x <= dom.clientWidth &&  x >= 0    //是否在屏幕中   
-					&& y <= dom.clientHeight &&  y >= 0 
+		var inSight = pos.x <= 1 &&  pos.x >= -1    //是否在屏幕中   
+					&& pos.x <= 1 &&  pos.y >= -1 
 	 
 	
 		return {
-			pos: new THREE.Vector2(x,y),  // 屏幕像素坐标
+			pos:  new THREE.Vector2(left+x,top+y) ,// 屏幕像素坐标
 			vector:  pos,   //(范围 -1 ~ 1)
 			trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点   参见Tag.update
-			inSight : inSight	//在屏幕范围内可见
+			inSight : inSight,	//在屏幕范围内可见,
+            posInViewport: new THREE.Vector2(x,y)
 		};
 	} 
 
@@ -1140,6 +1157,7 @@ Utils.computePointcloudsBound = function(pointclouds){
     var boundingBox = new THREE.Box3();
     pointclouds.forEach(pointcloud=>{
         var boundingBox_ = pointcloud.pcoGeometry.tightBoundingBox.clone().applyMatrix4(pointcloud.matrixWorld)
+        pointcloud.bound = boundingBox_
         boundingBox.union(boundingBox_)
     })
     var boundSize = boundingBox.getSize()
@@ -1155,4 +1173,78 @@ Utils.convertScreenPositionToNDC = function(pointer, mouse, width, height) {
         pointer 
 }
 
+Utils.getOrthoCameraMoveVec = function(pointerDelta, camera ){//获取当camera为Ortho型时 屏幕点1 到 屏幕点2 的三维距离
+     
+    let cameraViewWidth = camera.right  
+    let cameraViewHeight = camera.top ; 
+    let moveVec = new THREE.Vector3; 
+    moveVec.set( pointerDelta.x * cameraViewWidth  , pointerDelta.y * cameraViewHeight  , 0).applyQuaternion(camera.quaternion)  
+    return moveVec              
+}
+
 
+Utils.VectorFactory = {
+    fromArray : function(t) {
+        if (t) {
+            if (t.length < 2 || t.length > 3)
+                console.error("Wrong number of ordinates for a point!");
+            return 3 === t.length ? (new THREE.Vector3).fromArray(t) : (new THREE.Vector2).fromArray(t)
+        }
+    },
+    fromArray3 : function(t) {
+        if (t) {
+            if (3 !== t.length)
+                console.error("Wrong number of ordinates for a point!");
+            return (new THREE.Vector3).fromArray(t)
+        }
+    },
+    fromArray2 : function(t) {
+        if (t) {
+            if (2 !== t.length)
+                console.error("Wrong number of ordinates for a point!");
+            return (new THREE.Vector2).fromArray(t)
+        }
+    },
+    toString : function(t) {
+        return t.x.toFixed(8) + "," + t.y.toFixed(8) + "," + t.z.toFixed(3)
+    }
+
+}
+ 
+Utils.QuaternionFactory = {
+    rot90 : (new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90)),
+    fromArray : function(t) {
+        if (t) {
+            if (4 !== t.length)
+                console.error("Wrong number of ordinates for a quaternion!");
+            return new THREE.Quaternion(t[1],t[2],t[3],t[0]).multiply(this.rot90)
+        }
+    }
+    ,
+    toArray : function(t) {
+        if (t) {
+            var e = t.clone().multiply(a).toArray();
+            return [e[3], e[0], e[1], e[2]]
+        }
+    }
+    ,
+    fromLonLat : function(t) {
+        if (t)
+            return (new THREE.Quaternion).setFromEuler(new THREE.Euler(t.lon,t.lat,0))
+    }
+    ,
+    toLonLat : function(t) {
+        if (t) {
+            var e = (new THREE.Euler).setFromQuaternion(t);
+            return {
+                lon: e.x,
+                lat: e.y
+            }
+        }
+    }
+    
+    
+}
+ 
+ 
+ 

+ 66 - 19
src/utils/Common.js

@@ -1,6 +1,6 @@
 var Common = {
     sortByScore: function(list, request, rank){
-        var i = Common.filterAll(list, request);
+        var i = request ? Common.filterAll(list, request) : list
         return 0 === i.length ? null : i = i.map(function(e) {
             return {
                 item: e,
@@ -13,16 +13,7 @@ var Common = {
         })
     } 
     ,
-    
-    find : function(list, request, rank) {
-        var i = Common.filterAll(list, request);
-        return 0 === i.length ? null : (rank && rank.forEach(function(e) {
-            i = Common.stableSort(i, e)
-        }),
-        i[0])
-    }
-    
-    ,
+      
     filterAll: function(e, t) {
         return e.filter(function (e) {
             return t.every(function (t) {
@@ -32,19 +23,60 @@ var Common = {
     },
     
     
-    stableSort: function(e, t) {
-        return e.map(function(e, t) {
+    
+    //---------------
+    find : function(list, request, rank) {
+        var i = request ? Common.filterAll(list, request) : list
+        return 0 === i.length ? null : (rank && rank.forEach(function(e) {
+            i = Common.stableSort(i, e)
+        }),
+        i[0])
+    }
+    
+    ,
+    stableSort: function(e, f) {//用到排序函数,涉及到两个item相减
+        return e.map(function(e, i) {
             return {
                 value: e,
-                index: t
+                index: i
             }
-        }).sort(function(e, i) { 
-            var n = t(e.value, i.value);
-            return 0 !== n ? n : e.index - i.index  //似乎就是加多了这一步:如果结果为0,按照原顺序
+        }).sort(function(e, u) { 
+            var n = f(e.value, u.value);
+            return 0 !== n ? n : e.index - u.index  //似乎就是加多了这一步:若差距为0,按照原顺序
         }).map(function(e) {
             return e.value
         })
     },
+    //---------------------------
+    
+    
+    getMixedSet : function(arr1, arr2){//交集
+        return arr1.filter(item=>arr2.includes(item));
+    },
+    getUnionSet : function(arr1, arr2){//并集
+        return arr1.concat(arr2.filter(item=>!arr1.includes(item)))
+    },
+    getDifferenceSet : function(arr1, arr2){//差集  不能识别重复的,如getDifferenceSet([1,2,2],[1,1,2]) 为空
+        var arr11 = arr1.filter(item=>!arr2.includes(item));
+        var arr22 = arr2.filter(item=>!arr1.includes(item));
+        return arr11.concat(arr22)
+    },
+    getDifferenceSetMuti : function(arr){//收集绝对没有重复的元素,也就是判断出现次数=1的
+        var set = [];
+        arr.forEach(arr1=>{
+            arr1.forEach(item=>{
+                var index = set.indexOf(item)
+                if(index>-1){
+                    set.splice(index, 1)
+                }else{
+                    set.push(item)
+                }
+            })
+        })
+        return set;
+    }
+    ,
+     
     CloneObject : function(copyObj, result, isSimpleCopy, extraReplace) {
         //isSimpleCopy只复制最外层
         //复制json		result的可能:普通数字或字符串、普通数组、复杂对象
@@ -120,7 +152,22 @@ var Common = {
         } 
         
     }
-
-
+    ,
+    replaceAll : function (str, f, e) {
+        //f全部替换成e
+        var reg = new RegExp(f, "g"); //创建正则RegExp对象  
+        return str.replace(reg, e);
+    } 
+    ,
+    downloadFile : function(data, filename, cb) {
+        var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
+        save_link.href = data;
+        save_link.download = filename;
+        var event = document.createEvent('MouseEvents');
+        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+        save_link.dispatchEvent(event);
+        cb && cb();
+    }, 
+    
 }    
 export default Common 

+ 10 - 7
src/utils/DrawUtil.js

@@ -28,7 +28,7 @@ var LineDraw = {
 			p[i * 3 + 2] = posArr[i].z;
 		}
 		var mat = o.mat || new THREE[o.deshed ? "LineDashedMaterial" : "LineBasicMaterial"]({
-			linewidth: o.width || 1,
+			linewidth: o.linewidth || 1,
 			//windows无效。 似乎mac/ios上粗细有效 ? 
 			color: o.color || defaultColor,
 			transparent: o.dontAlwaysSeen ? false : true,
@@ -124,15 +124,18 @@ var LineDraw = {
 	createFatLineMat : function(o){ 
 		var mat = new LineMaterial( { 
 			color: o.color || 0xffffff,
-			linewidth: o.width || 5, // in pixels
+			linewidth: o.linewidth || 5, // in pixels
 			//vertexColors: THREE.VertexColors,//THREE.VertexColors,
-			resolution:  new THREE.Vector2(viewer.renderer.domElement.width,viewer.renderer.domElement.height ),// to be set by renderer, eventually
-			 
+			resolution:  o.resolution,// to be set by renderer, eventually
+			//viewportOffset:  o.viewportOffset,
 			transparent:true, //o.dontAlwaysSeen ? false : true,
-			/* depthTest:   false,//  o.alwaysShow ? false : true,//o.dontAlwaysSeen ? true : false
-            depthWrite:false, */
+			depthTest:   false,//  o.alwaysShow ? false : true,//o.dontAlwaysSeen ? true : false
+            depthWrite:false,
             dashSize : o.dashSize || 0.1,
             gapSize: o.gapSize || 0.1,
+            
+            useDepth: o.useDepth,  
+            dashed :o.dashed
            /*  transparent:o.dontAlwaysSeen ? false : true,
 			depthTest:o.dontAlwaysSeen ? true : false
              */
@@ -142,7 +145,7 @@ var LineDraw = {
              
 		} ); 
         
-        if(o.dashed)(mat.defines.USE_DASH = "") 
+        //if(o.dashed)(mat.defines.USE_DASH = "") 
         
         var opa = 0
         Object.defineProperty( mat, "opacity", {

+ 61 - 24
src/utils/Magnifier.js

@@ -1,37 +1,38 @@
 
 import * as THREE from "../../libs/three.js/build/three.module.js";
+import math from './math'
+ 
  
  
 let texLoader = new THREE.TextureLoader() 
-let circleGeo = new THREE.CircleGeometry(1.2,100);
+let circleGeo = new THREE.CircleGeometry(1.45,100);
  
  
  
-const magDistance_ = 4;//相机离目标位置的距离的分界线,当离得远时要缩小fov以使看到的视野固定(望远镜效果)
+const magDistance_ = 2;//相机离目标位置的距离的分界线,当离得远时要缩小fov以使看到的视野固定(望远镜效果)
 const radius_ = 0.2; //当相机离目标位置的距离>magDistance_时,希望看到的视野的半径
 const maxFov = THREE.Math.radToDeg(Math.atan(radius_ / magDistance_ )) * 2//提前计算出当相机离目标位置的距离<magDistance_时的fov,均使用=magDistance_时的fov。只要保证该fov大于主相机的fov就会有放大效果 
-
+const width2dPX = 200/1.4;//px
+ 
 
 
 export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
-	constructor (viewer, inputHandler) {
+	constructor (viewer) {
 		super()
-        
+        this.width = this.height = 256;
         this.camera = new THREE.PerspectiveCamera(50, 1, 0.1, 10000);  //fov aspect near far
         this.camera.up = new THREE.Vector3(0,0,1) 
-        this.renderTarget = new THREE.WebGLRenderTarget(256,256, { 
+         
+        this.renderTarget = new THREE.WebGLRenderTarget(this.width,this.height, { 
             minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter,
             format: THREE.RGBAFormat ,
             /* type: THREE.FloatType,
             minFilter: THREE.NearestFilter,
 			magFilter: THREE.NearestFilter, 
-			  */
-			 
-		 
-            
+			  */ 
         } )
         
-		this.rtEDL = new THREE.WebGLRenderTarget(256, 256, {
+		this.rtEDL = new THREE.WebGLRenderTarget(this.width, this.height, {
 			minFilter: THREE.NearestFilter,
 			magFilter: THREE.NearestFilter,
 			format: THREE.RGBAFormat,
@@ -50,7 +51,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         }))
         this.overlayMesh = new THREE.Mesh(circleGeo, new THREE.MeshBasicMaterial({
             side: THREE.DoubleSide , 
-            map:texLoader.load(Potree.config.urls.localTextures+'crosshair.png') ,
+            map:texLoader.load(Potree.resourcePath+'/textures/crosshair.png') ,
             transparent:true,
             depthTest: !1,
             //depthWrite: !1,
@@ -62,29 +63,54 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         this.overlayMesh.renderOrder = 11;
         this.aimPos
 
-        inputHandler.addInputListener(this)
-        
-        viewer.addEventListener('camera_changed',this.update.bind(this)) // 平移、滚轮时更新
+        //viewer.inputHandler.addInputListener(this)
         
+        viewer.addEventListener('camera_changed',(e)=>{ // 平移、滚轮时更新
+            if(e.viewport == viewer.mainViewport) this.update()
+        })
+            
 
         this.unvisibleReasons = []; //如果length>0代表不可见
         
-    
-        
+        this.mesh.layers.set(Potree.config.renderLayers.magnifier);
+        this.overlayMesh.layers.set(Potree.config.renderLayers.magnifier);
+        //this.layers.set(Potree.config.renderLayers.magnifier);//这句在外层写没用
         
-        this.dontRender = false
-        this.addEventListener('drag', ()=>{//拖拽时不渲染。主要是右键平移时渲染延迟了,会闪烁。
+        this.dontRender = false 
+        viewer.addEventListener('global_drag', (e)=>{//拖拽时不渲染。主要是右键平移时渲染延迟了,会闪烁。 
             this.dontRender = true
         })
-        this.addEventListener('drop', ()=>{
+        viewer.addEventListener('global_drop', (e)=>{
             this.dontRender = false
         })
-        viewer.addEventListener("beginSplitView",()=>{
+        
+        viewer.addEventListener('global_mousemove', (e)=>{
+            if(e.hoverViewport == viewer.mainViewport){
+                this.updateVisible("atViewport", true)
+                this.update(e.intersectPoint && e.intersectPoint.location)
+            }else{
+                this.updateVisible("atViewport", false)
+            }
+        })
+        
+        
+        
+        
+        /* viewer.addEventListener("beginSplitView",()=>{
             this.updateVisible("splitView", false) 
         })
         viewer.addEventListener("finishSplitView",()=>{
             this.updateVisible("splitView", true) 
-        })  
+        })  */
+        
+        viewer.addEventListener("measureMovePoint",()=>{
+            this.updateVisible("measure", true) 
+        })
+        viewer.addEventListener("endMeasureMove",()=>{
+            this.updateVisible("measure", false) 
+        })
+        
+        this.updateVisible("measure", false) 
     }
     
     
@@ -128,8 +154,10 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
 
         //mesh位置
         let screenPos = viewer.inputHandler.mouse.clone();
-        screenPos.x = screenPos.x / viewer.inputHandler.domElement.clientWidth * 2 - 1;
-        screenPos.y = -((screenPos.y  < 300 ? 200 : -200) + screenPos.y) / viewer.inputHandler.domElement.clientHeight *2 + 1;
+        let clientWidth = viewer.inputHandler.domElement.clientWidth * viewer.mainViewport.width;
+        let clientHeight = viewer.inputHandler.domElement.clientHeight * viewer.mainViewport.height;
+        screenPos.x = screenPos.x / clientWidth * 2 - 1;
+        screenPos.y = -((screenPos.y  < 300 ? 200 : -200) + screenPos.y) / clientHeight * 2 + 1;
     
                 
         let newPos = new THREE.Vector3(screenPos.x,screenPos.y,0.8).unproject(playerCamera); //z:-1朝外       
@@ -140,6 +168,13 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
 
         this.aimPos =  aimPos
  
+        var scale = math.getScaleForConstantSize({// 
+            width2d : width2dPX,
+            camera:viewer.scene.getActiveCamera(),  position: this.getWorldPosition(new THREE.Vector3()),
+            resulution: viewer.mainViewport.resolution
+        })
+        this.scale.set(scale, scale, scale); 
+ 
         if(!this.dontRender){
             this.waitRender = true
         }
@@ -149,10 +184,12 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
     }//位置需要计算,不仅仅是点云,所以需要深度图
     
     render(){ 
+ 
         if(!this.waitRender)return
         //this.visible = false;//防止放大镜里有自己
         viewer.render({
             target : this.renderTarget,
+            viewport : viewer.mainViewport,
             camera : this.camera,
             magnifier : true,
             rtEDL: this.rtEDL,

+ 228 - 145
src/utils/Measure.js

@@ -6,14 +6,41 @@ import  Label  from "./Label.js";
 import {LineDraw,MeshDraw} from "../utils/DrawUtil";
 import math from "./math.js";
 import {MOUSE} from "../defines.js"; 
+import DepthBasicMaterial from "../materials/DepthBasicMaterial.js";
+import Sprite from '../viewer/Sprite'
+import {config} from '../settings'
 
 let texLoader = new THREE.TextureLoader() 
 const defaultNormal = new THREE.Vector2(0,1)
- 
+let color = new THREE.Color(config.measure.lineColor)
+let textColor = new THREE.Color(config.measure.textColor)
+let highLightColor = new THREE.Color(config.measure.highLightColor)
 var sphereMats;  
 var lineMats;  
 var planeMats 
 
+const sphereSizeInfo = {
+    minSize : 15 ,  maxSize : 55,   nearBound : 0.2, farBound : 8,
+}
+const labelSizeInfo = {width2d:200}
+const mainLabelProp = { 
+    backgroundColor: {r: color.r*255, g: color.g*255, b: color.b*255, a:config.measure.labelOpacity},
+    textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
+    fontsize:16, 
+    useDepth : true ,
+    renderOrder : 5 
+}
+const subLabelProp = { 
+    backgroundColor: {r: 255, g: 255, b: 255, a:1},
+    textColor: {r: 0, g: 0, b:0, a: 1.0},
+    fontsize:14, 
+    renderOrder : 4
+}
+
+const verticalLine = new THREE.Line3()
+
+    
+ 
 
 export class Measure extends THREE.Object3D {
 	constructor (prop) {
@@ -40,7 +67,7 @@ export class Measure extends THREE.Object3D {
 		this._showAzimuth = false;
 
 		this.sphereGeometry = new THREE.SphereGeometry(0.4, 10, 10);
-		this.color = new THREE.Color(Potree.config.measure.lineColor)//new THREE.Color(0xff0000);
+		this.color = new THREE.Color(config.measure.lineColor)//new THREE.Color(0xff0000);
 
 		this.spheres = [];
 		this.edges = [];
@@ -56,6 +83,7 @@ export class Measure extends THREE.Object3D {
             this.areaLabel = this.createAreaLabel();
             this.areaPlane = createAreaPlane(); 
             this.add(this.areaPlane)
+            this.add(this.areaLabel)
         }
         
         if(this.showCircle){ 
@@ -79,7 +107,7 @@ export class Measure extends THREE.Object3D {
 		this.add(this.heightLabel); */
 		 
         //add:
-        if(this.maxMarkers > 2 || this.direction){
+        if(this.maxMarkers > 2 || this.faceDirection){
             this.guideLine = this.createGuideLine();
             this.add(this.guideLine) 
         }
@@ -118,8 +146,8 @@ export class Measure extends THREE.Object3D {
                     let msg = pos.map(a=> 
                          a.map(p => Utils.addCommas(p.toFixed(10))).join(", ") 
                     ).join("<br>") 
-                    coordinateLabel.changeText(msg);
-                    coordinateLabel.changePos(position)
+                    coordinateLabel.setText(msg);
+                    coordinateLabel.setPos(position)
                     coordinateLabel.setVisible(true)//this.showCoordinates;
                 }
                 return;
@@ -157,7 +185,7 @@ export class Measure extends THREE.Object3D {
                     center = center.multiplyScalar(0.5);
                     let distance = point.position.distanceTo(nextPoint.position);
 
-                    edgeLabel.changePos(center) 
+                    edgeLabel.setPos(center) 
 
                     /* let suffix = "";
                     if(this.lengthUnit != null && this.lengthUnitDisplay != null){
@@ -166,10 +194,10 @@ export class Measure extends THREE.Object3D {
                     } */
                     let suffix = "m";
                     let txtLength = Utils.addCommas(distance.toFixed(2));
-                    edgeLabel.changeText(`${txtLength} ${suffix}`);
+                    edgeLabel.setText(`${txtLength} ${suffix}`);
                     edgeLabel.shouldVisi = (index < lastIndex || this.closed && this.points.length > 2) && distance>0 
                     /* this.closed || */ edgeLabel.setVisible(edgeLabel.shouldVisi)  
-                
+                     
                 }
                 
                 if(this.showAngles)
@@ -213,14 +241,14 @@ export class Measure extends THREE.Object3D {
                 this.center = center
                 
                 //label
-                this.areaLabel.changePos(center); 
+                this.areaLabel.setPos(center); 
                 let area = Math.abs(math.getArea(this.point2dInfo.points2d))//this.getArea();
 
                 let suffix = "m";
                 this.area = area
                 let txtArea = Utils.addCommas(area.toFixed(2));
                 let msg =  `${this.measureType} ${txtArea} ${suffix}\u00B2`;
-                this.areaLabel.changeText(msg);
+                this.areaLabel.setText(msg);
                 this.areaLabel.setVisible(true)
             }
 
@@ -281,7 +309,7 @@ export class Measure extends THREE.Object3D {
 
              
         }
-		 
+		viewer.mapViewer.emit('content_changed')  
 	};
 
  
@@ -297,26 +325,12 @@ export class Measure extends THREE.Object3D {
 			point = {position: new THREE.Vector3(...point)};
 		}
 		this.points.push(point);
+         
         
-        
-        
-        
-        
-        let color = new THREE.Color(Potree.config.measure.lineColor)
-        let textColor = Potree.config.measure.textColor
-        /* let labelProps = {
-            text:'',
-            borderColor: {r: color.r*255, g: color.g*255, b: color.b*255, a:Potree.config.measure.labelOpacity},
-            backgroundColor: {r: color.r*255, g: color.g*255, b: color.b*255, a:Potree.config.measure.labelOpacity},
-            textColor: {r: textColor.r*255, g: textColor.g*255, b: textColor.b*255, a: 1.0},
-            fontsize:16, 
-        } */
-        
-        
-		// sphere
-		//let sphere = new THREE.Mesh(this.sphereGeometry, this.createSphereMaterial());
-        let sphere = new THREE.Sprite(this.getSphereMaterial('default')  );
-        //sphere.scale.set(1/16,1/16,1/16)
+		// sphere 
+        //let sphere = new THREE.Sprite(this.getSphereMaterial('default')  );
+       
+        let sphere = new Sprite({mat:this.getSphereMaterial('default'), sizeInfo: sphereSizeInfo, name:"measure_point"} )
         sphere.renderOrder = 3
         sphere.sphereSelectStates = {}
 		this.add(sphere);
@@ -356,7 +370,7 @@ export class Measure extends THREE.Object3D {
             if(this.closed){
                 className += ' sub'
             }
-            let edgeLabel = new Label({
+            /* let edgeLabel = new Label({
                 className , 
             })
             edgeLabel.setVisible(false)
@@ -367,20 +381,27 @@ export class Measure extends THREE.Object3D {
                 edgeLabel.elem.on('mouseout',()=>{
                     this.setSelected(false, 'edgeLabel')
                 })
+            } */
+            
+            const edgeLabel = new TextSprite(
+                $.extend(this.closed ? subLabelProp : mainLabelProp,{sizeInfo: labelSizeInfo,  name:'edgeLabel'})
+            )
+            if(!this.closed){
+                edgeLabel.addEventListener('mouseover',()=>{
+                    this.setSelected(true, 'edgeLabel')
+                }) 
+                edgeLabel.addEventListener('mouseleave',()=>{
+                    this.setSelected(false, 'edgeLabel')
+                })  
             }
-	 
+             
+            
 			this.edgeLabels.push(edgeLabel);
-			//this.add(edgeLabel);
+			this.add(edgeLabel);
 		}
 
 		if(this.showAngles){ // angle labels
-			/* let angleLabel = new TextSprite(labelProps); 
 			 
-			angleLabel.material.depthTest = false;
-			angleLabel.material.opacity = 1;
-			angleLabel.visible = false;
-			this.angleLabels.push(angleLabel);
-			this.add(angleLabel); */
 		}
 
 		if(this.showCoordinates){ // coordinate labels 
@@ -394,12 +415,19 @@ export class Measure extends THREE.Object3D {
 		}
         
         
-        this.editStateChange(true)
+        
         
 		{ // Event Listeners 
 			let drag = (e) => {
-				 
-                var I = e.intersectPoint 
+                
+                var I, atMap 
+                
+                
+                atMap = e.drag.dragViewport.name == 'mapViewport'
+                I = e.intersectPoint && (e.intersectPoint.location ? e.intersectPoint.location : e.intersectPoint)
+                
+                //在三维中脱离点云(在map中拉到周围都没有点云的地方)的顶点,无法拖拽怎么办
+                
                 
 				if (I) {
 					let i = this.spheres.indexOf(e.drag.object);
@@ -418,7 +446,7 @@ export class Measure extends THREE.Object3D {
 							point[key] = I.point[key];
 						} */
                         
-                        this.dragChange(I.location, i)
+                        this.dragChange(I, i, atMap)
 						
 					}
 				}
@@ -452,8 +480,8 @@ export class Measure extends THREE.Object3D {
 			};
 
             
-			let mouseover = (e) => {this.setSphereSelected(e.object, true, 'single') };
-			let mouseleave = (e) => {this.setSphereSelected(e.object, false, 'single') }
+			let mouseover = (e) => {this.setSphereSelected(e.object, true, 'single');/* console.log('hover')  */};
+			let mouseleave = (e) => {this.setSphereSelected(e.object, false, 'single');/* console.log('hoveroff')  */}
 
 			sphere.addEventListener('drag', drag);
 			sphere.addEventListener('drop', drop);
@@ -477,14 +505,21 @@ export class Measure extends THREE.Object3D {
 
        
 
-    dragChange(intersectPos,i){ 
+    dragChange(intersectPos,i, atMap){ 
         var len = this.spheres.length
         var location = intersectPos.clone()
 
-        if(this.direction && len > 1){//add 固定方向的点不直接拖拽
+        if(this.faceDirection && this.maxMarkers == 2 && len == 2){//add 固定方向的点不直接拖拽
             var p1 = this.spheres[0].position
-            var p2 = p1.clone().add(this.direction)
-            var projectPos = math.getFootPoint(location, p1, p2)
+            if(this.faceDirection == 'horizontal'){
+                var projectPos = location.clone().setZ(p1.z)
+            }else{
+                var projectPos = p1.clone().setZ(location.z)
+            }
+            //var p2 = p1.clone().add(this.direction)
+            //var projectPos = math.getFootPoint(location, p1, p2)
+            
+            
             this.updateLine(this.guideLine, location, projectPos)
             this.setPosition(i, projectPos);
             this.guideLine.visible = true
@@ -506,14 +541,29 @@ export class Measure extends THREE.Object3D {
                     let vec = points[0].clone().sub(location) 
                     if(Math.sqrt(vec.x*vec.x+vec.y*vec.y) > Math.abs(vec.z) ){//水平(高度差小于水平距离时)
                         location.setZ(this.points[0].position.z) 
-                        this.cannotConfirmNormal = false;//能确定面为水平方向
+                        //this.cannotConfirmNormal = false;//能确定面为水平方向
                     }else{//垂直 (当两点一样时也属于这种)
                         location.setX(points[0].x);
                         location.setY(points[0].y);
-                        this.cannotConfirmNormal = true; //不能确定面,因第三点可绕着纵轴线自由移动
+                        //this.cannotConfirmNormal = true; //不能确定面,因第三点可绕着纵轴线自由移动
                     }
-                }else{
+                }else{ 
+                    {//判断cannotConfirmNormal
+                        this.cannotConfirmNormal = true
+                        let max = this.isRect ? 1 : len-2
+                        for(let i=0;i<max;i++){
+                            let p1 = points[i].clone()
+                            let p2 = points[i+1].clone()
+                            let vec = p1.sub(p2);
+                            if(vec.x != 0 || vec.y != 0){
+                                this.cannotConfirmNormal = false
+                                break;
+                            } 
+                        } 
+                    }
+                    
                     if(!this.facePlane || this.cannotConfirmNormal){//三个点且为水平方向时,计算面
+                          
                         var points_ = points.map(e=>new THREE.Vector2(e.x,e.y))
                         var points2 = getDifferentPoint(points_, 2); 
                         if(points2){
@@ -538,9 +588,17 @@ export class Measure extends THREE.Object3D {
                 }
                 
                 if( this.facePlane && !this.cannotConfirmNormal  ){//之后加的点一定要在面上  
-                    location = this.facePlane.projectPoint(intersectPos, new THREE.Vector3() )
-                }
-                  
+                    if(atMap){ 
+                        //地图上用垂直线,得到和面的交点。
+                        verticalLine.set(location.clone().setZ(100000), location.clone().setZ(-100000))//确保长度范围覆盖所有测量面 
+                        location = this.facePlane.intersectLine(verticalLine, new THREE.Vector3() )
+                        if(!location) return; 
+                    }else{ 
+                        location = this.facePlane.projectPoint(intersectPos, new THREE.Vector3() )
+                    }
+                }  
+                
+                
                 points[i].copy(location)//再copy确认一次
                 
                 if(this.isRect){ //是矩形 (即使没有faceDirection也能执行)
@@ -620,13 +678,13 @@ export class Measure extends THREE.Object3D {
         if(!state){
             this.editStateTimer = setTimeout(()=>{
                 if(!this.isEditing){
-                    viewer.inputHandler.reticule.dispatchEvent({type:"endMeasureMove"})
+                    viewer.dispatchEvent({type:"endMeasureMove"})
                     this.closed && this.edgeLabels.forEach(e=>e.setVisible(false) )
                 }
             },100)
         }else{
             if(!this.isEditing){
-                viewer.inputHandler.reticule.dispatchEvent({type:"measureMovePoint"})
+                viewer.dispatchEvent({type:"measureMovePoint"})
                 this.closed && this.edgeLabels.forEach(e=>e.setVisible(e.shouldVisi)  )
                 clearTimeout(this.editStateTimer)
             } 
@@ -659,6 +717,8 @@ export class Measure extends THREE.Object3D {
         }
         
         sphere.selected = absoluteState
+        
+        viewer.mapViewer.emit('content_changed') 
     }
     setSelected(state, hoverObject){//add
         
@@ -679,18 +739,30 @@ export class Measure extends THREE.Object3D {
 			this.areaPlane && (this.areaPlane.material = planeMats.selected)
              
             this.closed && this.edgeLabels.forEach(e=>e.setVisible(e.shouldVisi)  )
-            this.areaLabel && this.areaLabel.elem.addClass('highLight')
-            this.closed || this.edgeLabels.forEach(e=>e.elem.addClass('highLight')  )
+            //this.areaLabel && this.areaLabel.elem.addClass('highLight')
+            //this.closed || this.edgeLabels.forEach(e=>e.elem.addClass('highLight')  )
+            
+            
+            this.areaLabel && setLabelHightState(this.areaLabel, true) 
+            this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, true)  )
+             
+             
+            
+            
         }else{
             this.spheres.forEach(e=>this.setSphereSelected(e,false,'selectAll' ))
             this.edges.forEach(e=>e.material = this.getLineMat('edgeDefault')  )
             this.areaPlane && (this.areaPlane.material = planeMats.default)
             this.closed && this.edgeLabels.forEach(e=>e.setVisible( false))
-            this.areaLabel && this.areaLabel.elem.removeClass('highLight')
-            this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight')  )
+            //this.areaLabel && this.areaLabel.elem.removeClass('highLight')
+            //this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight')  )
+            this.areaLabel && setLabelHightState(this.areaLabel, false) 
+            this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, false)  )
+            
         }
           
         this.selected = absoluteState
+        viewer.mapViewer.emit('content_changed')
     }
     
 	removeMarker (index) {
@@ -706,7 +778,8 @@ export class Measure extends THREE.Object3D {
 
 
         if(this.edgeLabels[edgeIndex]){
-            this.edgeLabels[edgeIndex].remove()
+            //this.edgeLabels[edgeIndex].remove();
+            this.edgeLabels[edgeIndex].parent.remove(this.edgeLabels[edgeIndex])
             this.edgeLabels.splice(edgeIndex, 1);
         }
 
@@ -727,7 +800,7 @@ export class Measure extends THREE.Object3D {
 		this.dispatchEvent({type: 'marker_removed', measurement: this});
 	};
 
-	setMarker (index, point) {
+	/* setMarker (index, point) {
 		this.points[index] = point;
 
 		let event = {
@@ -739,7 +812,7 @@ export class Measure extends THREE.Object3D {
 		this.dispatchEvent(event);
 
 		this.update();
-	}
+	} */
     
     
     dispose(){//add
@@ -883,7 +956,7 @@ export class Measure extends THREE.Object3D {
     
     
     createAreaLabel(){ 
-        const areaLabel = new Label({
+        /* const areaLabel = new Label({
             className:'measure_area', 
             
         })
@@ -892,7 +965,19 @@ export class Measure extends THREE.Object3D {
         })
         areaLabel.elem.on('mouseout',()=>{
             this.setSelected(false, 'areaLabel')
+        }) */
+        
+        
+        const areaLabel = new TextSprite(
+            $.extend(mainLabelProp,{sizeInfo: labelSizeInfo, name:'areaLabel_'} )
+        )
+        
+        areaLabel.addEventListener('mouseover',()=>{
+            this.setSelected(true, 'areaLabel')
         })
+        areaLabel.addEventListener('mouseleave',()=>{
+            this.setSelected(false, 'areaLabel')
+        })  
         return areaLabel;
         
         
@@ -901,23 +986,21 @@ export class Measure extends THREE.Object3D {
     
     getSphereMaterial(type) {
         if(!sphereMats){
-            sphereMats = { 
-                default:    new THREE.SpriteMaterial({  
+            sphereMats = {  
+                default:    new DepthBasicMaterial({  
                     transparent: !0,
                     opacity: 1,
-                    map: texLoader.load(Potree.config.urls.localTextures+'img_dot_normal@2x.png' ), 
-                    depthTest:false,
-                    depthWrite:false  
+                    map: texLoader.load(Potree.resourcePath+'/textures/pic_point32.png' ), 
+                    useDepth:true 
                 }),
-                select:    new THREE.SpriteMaterial({   
+                select:    new DepthBasicMaterial({   
                     transparent: !0,
                     opacity: 1,
-                    map: texLoader.load(Potree.config.urls.localTextures+'img_dot_focus@2x.png'/* , null, null, { antialias: false } */), 
-                    depthTest:false,
-                    depthWrite:false 
-                }),    
-                    
+                    map: texLoader.load(Potree.resourcePath+'/textures/pic_point_s32.png'/* , null, null, { antialias: false } */), 
+                     
+                }),   
             }
+            Measure.sphereMats = sphereMats
         }
         return sphereMats[type]
         
@@ -926,27 +1009,28 @@ export class Measure extends THREE.Object3D {
     
     
     
-    getLineMat(type) {
+    getLineMat(type) { 
         if(!Measure.lineMats){
             Measure.lineMats = { 
                 edgeDefault:  LineDraw.createFatLineMat({
-                    color: Potree.config.measure.lineColor,
+                    color: color,
                     dashSize: 0.5, 
                     gapSize: 0.2, 
-                    linewidth: Potree.config.measure.lineWidth  
+                    linewidth: config.measure.lineWidth,
+                    useDepth :true                   
                 }),
                 edgeSelect:  LineDraw.createFatLineMat({
-                    color: '#f0ff00',
+                    color: highLightColor,//'#f0ff00',
                     dashSize: 0.5, 
                     gapSize: 0.2, 
-                    linewidth: Potree.config.measure.lineWidth  
+                    linewidth: config.measure.lineWidth  
                 }),
                 guide:   LineDraw.createFatLineMat({
-                    color:Potree.config.measure.guideLineColor, 
+                    color:config.measure.guideLineColor, 
                     dashSize: 0.1, 
                     gapSize: 0.02,
                     dashed: true,
-                    linewidth: Potree.config.measure.lineWidth  
+                    linewidth: config.measure.lineWidth  
                 }) 
                     
             }
@@ -982,20 +1066,9 @@ export class Measure extends THREE.Object3D {
 
     updateSphere(sphere, pos){
         sphere.position.copy(pos);
-        this.updateSphereSize(sphere)
+        sphere.update();
     }
-    updateSphereSize(sphere){    
-        var scale = math.getScaleForConstantSize({//规定下最小最大像素
-            minSize : 15 ,  maxSize : 55,   nearBound : 0.2, farBound : 8, dom:viewer.renderArea,
-            camera:viewer.scene.getActiveCamera(), position: sphere.getWorldPosition(new THREE.Vector3()) 
-        })
-         
-        sphere.scale.set(scale, scale, scale); 
-        
-    }
-
-
-
+    
     transformData(prop){
         if(prop.measureType == 'Point'){ 
             prop.showCoordinates = true, 
@@ -1008,25 +1081,49 @@ export class Measure extends THREE.Object3D {
             prop.showEdges = true,
             prop.maxMarkers = 2,
             prop.minMarkers = 2 
-        }else if(prop.measureType == 'Height'){
+        }else if(prop.measureType == 'Ver Distance'){
+            prop.showDistances = true,  
+            prop.closed = false,
+            prop.showEdges = true,
+            prop.maxMarkers = 2,
+            prop.minMarkers = 2,
+            prop.faceDirection = "vertical" 
+        }else if(prop.measureType == 'Hor Distance'){
             prop.showDistances = true,  
             prop.closed = false,
             prop.showEdges = true,
             prop.maxMarkers = 2,
             prop.minMarkers = 2,
-            prop.direction = new THREE.Vector3(0,0,1) 
+            prop.faceDirection = "horizontal"   
         }else if(prop.measureType == 'Area'){
+            prop.showDistances = true,  
+            prop.showArea = true,  
+            prop.showEdges = true,
+            prop.closed = true, 
+            prop.minMarkers = 3  
+        }else if(prop.measureType == 'Hor Area'){
+            prop.showDistances = true,  
             prop.showArea = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 3  
+            prop.faceDirection = "horizontal"
+        }else if(prop.measureType == 'Ver Area'){
+            prop.showDistances = true,  
+            prop.showArea = true,  
+            prop.showEdges = true,
+            prop.closed = true, 
+            prop.minMarkers = 3 
+            prop.faceDirection = "vertical"            
         }else if(prop.measureType == 'Rect Area'){
+            prop.showDistances = true,  
             prop.showArea = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 4 
             prop.maxMarkers = 4            
         }else if(prop.measureType == 'Hor Rect Area'){
+            prop.showDistances = true,  
             prop.showArea = true,  
             prop.showEdges = true,
             prop.closed = true, 
@@ -1035,6 +1132,7 @@ export class Measure extends THREE.Object3D {
             prop.isRect = true 
             prop.faceDirection = "horizontal"  
         }else if(prop.measureType == 'Ver Rect Area'){
+            prop.showDistances = true,  
             prop.showArea = true,  
             prop.showEdges = true,
             prop.closed = true, 
@@ -1153,25 +1251,41 @@ function getDifferentPoint(points, count){//for facePlane
 
 function createAreaPlane(){
     planeMats || (planeMats = { 
-        default: new THREE.MeshBasicMaterial({
-            color:Potree.config.measure.lineColor,
+        default: new DepthBasicMaterial({
+            color:color,
             side:THREE.DoubleSide,
             opacity:0.2,
-            transparent:true
-        }),
-        selected: new THREE.MeshBasicMaterial({
-            color:Potree.config.measure.lineColor,
+            transparent:true,
+            useDepth:true 
+        }), 
+        selected: new DepthBasicMaterial({
+            color:color,
             side:THREE.DoubleSide,
-            opacity:0.5,
+            opacity:0.3,
             transparent:true
         }) 
-    })
+    },Measure.planeMats = planeMats)
     var geometry = new THREE.Geometry();
     var mesh = new THREE.Mesh(geometry, planeMats.default)
     return mesh
 }
 
- 
+function setLabelHightState(label, state){
+    if(state){
+        //label.backgroundColor =  {r: highLightColor.r*255, g: highLightColor.g*255, b: highLightColor.b*255, a:1},
+        label.backgroundColor.a = 1
+        label.sprite.material.useDepth = false;
+        
+    }else{
+        //label.backgroundColor = mainLabelProp.backgroundColor
+        label.backgroundColor.a = config.measure.labelOpacity
+        label.sprite.material.useDepth = true
+        
+    } 
+    label.updateTexture() 
+    //label.sprite.material.needsUpdate = true 
+}
+
 
 
 function createCircleRadiusLabel(){
@@ -1215,7 +1329,7 @@ function createCircleRadiusLine(){
         color:0xff0000,   
         dashSize: 0.5, 
 		gapSize: 0.2, 
-		linewidth: Potree.config.measure.lineWidth  
+		linewidth: config.measure.lineWidth  
     })
     circleRadiusLine.visible = false; 
 	return circleRadiusLine;
@@ -1268,7 +1382,7 @@ function createCircleLine(){
         color: 0xff0000,
         dashSize: 0.5, 
 		gapSize: 0.2, 
-		linewidth: Potree.config.measure.lineWidth  
+		linewidth: config.measure.lineWidth  
     })
 
 
@@ -1286,24 +1400,7 @@ function createCircleCenter(){
 }
 
 function createLine(){
-	/* const geometry = new LineGeometry();
-
-	geometry.setPositions([
-		0, 0, 0,
-		0, 0, 0,
-	]);
-
-	const material = new LineMaterial({ 
-		color: 0xff0000, 
-		linewidth: 2, 
-		resolution:  new THREE.Vector2(1000, 1000),
-		gapSize: 1,
-		dashed: true,
-	});
-
-	material.depthTest = false;
-
-	const line = new Line2(geometry, material); */
+	 
     const line = LineDraw.createFatLine([
 		0, 0, 0,
 		0, 0, 0,
@@ -1311,7 +1408,7 @@ function createLine(){
         color: 0xff0000,
         dashSize: 0.5, 
 		gapSize: 0.2, 
-		linewidth: Potree.config.measure.lineWidth  
+		linewidth: config.measure.lineWidth  
     })
     
     
@@ -1346,26 +1443,12 @@ function createCircle(){
 		);
 	}
 
-	/* const geometry = new LineGeometry();
-	geometry.setPositions(coordinates);
-
-	const material = new LineMaterial({ 
-		color: 0xff0000, 
-		dashSize: 5, 
-		gapSize: 2,
-		linewidth: 2, 
-		resolution:  new THREE.Vector2(1000, 1000),
-	});
-
-	material.depthTest = false;
-
-	const line = new Line2(geometry, material);
-	line.computeLineDistances(); */
+ 
     var line = LineDraw.createFatLine(coordinates,{
         color: 0xff0000,
         dashSize: 0.5, 
 		gapSize: 0.2, 
-		linewidth: Potree.config.measure.lineWidth  
+		linewidth: config.measure.lineWidth  
     })
 	return line;
 
@@ -1437,6 +1520,6 @@ function createAzimuth(){
 
 
 /* 
-    hover 标签要选中
+     
 
  */

+ 129 - 109
src/utils/MeasuringTool.js

@@ -57,7 +57,7 @@ function updateAzimuth(viewer, measure){
 		azimuth.target.scale.set(scale, scale, scale);
 	}
 
-
+ 
 	azimuth.circle.position.copy(p0.position);
 	azimuth.circle.scale.set(r, r, r);
 	azimuth.circle.material.resolution.set(width, height);
@@ -128,7 +128,7 @@ export class MeasuringTool extends EventDispatcher{
 		this.viewer = viewer;
 		this.renderer = viewer.renderer;
 
-		this.addEventListener('start_inserting_measurement', e => {
+		this.viewer.addEventListener('start_inserting_measurement', e => {
 			this.viewer.dispatchEvent({
 				type: 'cancel_insertions'
 			});
@@ -140,6 +140,8 @@ export class MeasuringTool extends EventDispatcher{
 		//this.light = new THREE.PointLight(0xffffff, 1.0);
 		//this.scene.add(this.light);  
 		this.viewer.inputHandler.registerInteractiveScene(this.scene);
+		  
+        
         //this.scene = viewer.overlay//
         
         
@@ -149,7 +151,12 @@ export class MeasuringTool extends EventDispatcher{
 		for(let measurement of viewer.scene.measurements){
 			this.onAdd({measurement: measurement});
 		}
-		viewer.addEventListener("camera_changed", this.update.bind(this));
+		 
+        viewer.addEventListener('camera_changed',(e)=>{ 
+            if(e.viewport == viewer.mainViewport ) this.update()
+        })
+        
+        
 		//viewer.addEventListener("update", this.update.bind(this));
 		viewer.addEventListener("render.pass.perspective_overlay", this.render.bind(this));
 		viewer.addEventListener("scene_changed", this.onSceneChange.bind(this));
@@ -202,54 +209,62 @@ export class MeasuringTool extends EventDispatcher{
         args.showGuideLine = pick(args.showGuideLine, false);  
         args.isRect = pick(args.isRect, false);
         
-
-
-
+ 
         let measure = new Measure(args);
-        /* if(this.editingMeasure){
-            this.editingMeasure.dispatchEvent({type:"endEdit"}) 
-        }
-        this.editingMeasure = measure */
-        
+        this.scene.add(measure);
         
-		this.dispatchEvent({
+		this.viewer.dispatchEvent({
 			type: 'start_inserting_measurement',
 			measure: measure
 		});
-
-    
-		this.scene.add(measure);
          
-		 
+        
+        measure.editStateChange(true)
+        let timer;
 
 		let endDragFun = (e) => {
            
-			if (e.drag.mouse == MOUSE.LEFT) {
+			if (e.button == THREE.MOUSE.LEFT /* e.drag.mouse == MOUSE.LEFT */) {
 				if (measure.points.length >= measure.maxMarkers) {
                     end({complete:true});
 				}else{
+                    if(measure.points.length == 1){//点击第一下,恢复可见
+                        measure.spheres[0].visible = true;
+                        /* if(e.drag.hoverViewport.name == 'mapViewport'){//如果在地图点击,直接使用地图上的
+                            let pos2d = e.drag.hoverViewport.end;
+                            let newPos = new THREE.Vector3(pos2d.x,pos2d.y,-1).unproject(e.drag.hoverViewport.camera); //z:-1朝外   
+                            
+                        } */
+                        
+                        
+                    }
+                    
                     var marker = measure.addMarker(measure.points[measure.points.length - 1].position.clone())
+                     
                     if(args.isRect && measure.spheres.length == 3){
                         measure.addMarker(measure.points[0].position.clone())
                     }
-                    setTimeout(()=>{//等 drag=null之后
+                    measure.editStateChange(true) //重新激活reticule状态
+                    timer = setTimeout(()=>{//等 drag=null之后
                         this.viewer.inputHandler.startDragging(marker,
                             {endDragFun} 
                         ); 
                     },1)    
                 } 
 				 
-			} else if (e.drag.mouse === MOUSE.RIGHT) {
+			} else if (e.button === THREE.MOUSE.RIGHT /* e.drag.mouse === MOUSE.RIGHT */) {
 				if(e.pressDistance < 2 )end();//非拖拽的话
-                else setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag
-                    this.viewer.inputHandler.startDragging(e.drag.object,
-                        {endDragFun} 
-                    ); 
-                },1) 
+                else {
+                    timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag
+                        this.viewer.inputHandler.startDragging(e.drag.object,
+                            {endDragFun} 
+                        ); 
+                    },1) 
+                }
 			}
 		};
 
-		let end = (o={}) => {
+		let end = (o={}) => {//确定、结束
             if(args.minMarkers != void 0){
                 if(!o.complete && measure.spheres.length<=args.minMarkers){
                     this.viewer.scene.removeMeasurement(measure)
@@ -258,75 +273,66 @@ export class MeasuringTool extends EventDispatcher{
             if (!o.complete && measure.spheres.length > 3) {
 				measure.removeMarker(measure.points.length - 1);
 			}
-            
-            //this.editingMeasure = null
-			//domElement.removeEventListener('mouseup', insertionCallback, false);
-			this.viewer.removeEventListener('cancel_insertions', end);
+            clearTimeout(timer) 
+			this.viewer.removeEventListener('cancel_insertions', Exit);
+            this.viewer.inputHandler.removeEventListener('keydown', pressExit);
+            /* this.viewer.dispatchEvent({
+                type: 'finish_inserting_measurement',
+                measure: measure
+            }); */
 		};
 
-        //measure.addEventListener("endEdit", end)
-
-
-		//if (measure.maxMarkers > 1) {
-			this.viewer.addEventListener('cancel_insertions', end);
-			//domElement.addEventListener('mouseup', insertionCallback, false);
-		//}
-
-		/* measure.addMarker(new THREE.Vector3(0, 0, 0));
-		this.viewer.inputHandler.startDragging(
-			measure.spheres[measure.spheres.length - 1]); */
-            
-        //改写:    
         
-        this.viewer.inputHandler.startDragging( measure.addMarker(new THREE.Vector3(0, 0, 0)), {
-            endDragFun 
-        });
-         
+        let Exit = (e)=>{//模拟右键点击 
+            if(this.viewer.inputHandler.drag){//还未触发drop的话
+                this.viewer.inputHandler.drag.object.dispatchEvent({
+                    type: 'drop',
+                    drag: this.viewer.inputHandler.drag, 
+                    viewer: this.viewer,
+                    pressDistance:0,
+                    button : THREE.MOUSE.RIGHT  
+                });
+                this.viewer.inputHandler.drag = null 
+            }else{
+                end()  //未结束时添加新的measure时会触发
+            }
+        }
+        let pressExit = (e)=>{ 
+            if(e.keyCode == 27){//Esc
+                Exit()
+            }
+        }
+        viewer.inputHandler.addEventListener('keydown', pressExit) 
+        this.viewer.addEventListener('cancel_insertions', Exit);
+		  
+          
+        var marker = measure.addMarker(new THREE.Vector3(0, 0, 0))
+        this.viewer.inputHandler.startDragging(marker , {endDragFun}); 
+             
+        if(measure.maxMarkers > 1){
+            marker.visible = false
+        }            
+             
         
-
 		this.viewer.scene.addMeasurement(measure);
         
 		return measure;
 	}
 	
     
-    updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高
-        
-        group.forEach((e,i)=>{
-            e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0
-         
-            var labels = e.labels.sort((a,b)=>{
-                return b.pos2d.z - a.pos2d.z
-            }) 
-            labels.forEach((label,index)=>{
-                $(label.elem).css('z-index', e.base+index) 
-            }) 
-        }) 
-        
-    }
     
-    setSize(e){ 
-        if(Measure.lineMats){
-            for(var m in Measure.lineMats){
-                Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight);
-            }  
-        } 
-    }
+    
     
 	update(){
 		let camera = this.viewer.scene.getActiveCamera();
 		let domElement = this.renderer.domElement;
 		let measurements = this.viewer.scene.measurements;
 
-		const renderAreaSize = this.renderer.getSize(new THREE.Vector2());
-		let clientWidth = renderAreaSize.width;
-		let clientHeight = renderAreaSize.height;
-
-		//this.light.position.copy(camera.position);
-
+	 
 		// make size independant of distance
         let mainLabels = [], subLabels = [];
         
+      
         
 		for (let measure of measurements) {
 			measure.lengthUnit = this.viewer.lengthUnit;
@@ -335,20 +341,19 @@ export class MeasuringTool extends EventDispatcher{
 
 			updateAzimuth(this.viewer, measure);
 
-			// spheres
-            
-            for(let sphere of measure.spheres){
-                measure.updateSphereSize(sphere)
-            }
-			
+			 
+            /*  [...measure.spheres, ...measure.edgeLabels, measure.areaLabel].forEach(e=>{
+                e && e.update() 
+            }); */
+             
 
 			// labels
-			let labels = measure.edgeLabels.concat(measure.angleLabels);
+			/* let labels = measure.edgeLabels.concat(measure.angleLabels);
 			for(let label of labels){ 
                 label.update()
                 if(label.elem.hasClass('sub')){
                     subLabels.push(label)
-                }else{
+                }else{ 
                     mainLabels.push(label)
                 }
 			}
@@ -365,7 +370,9 @@ export class MeasuringTool extends EventDispatcher{
 				let label = measure.areaLabel; 
                 label.update()
                 mainLabels.push(label)
-			}
+			} */
+             
+            
 
 			/* if(measure.showCircle){ // radius label
 				let label = measure.circleRadiusLabel;
@@ -374,44 +381,57 @@ export class MeasuringTool extends EventDispatcher{
 
 				let scale = (70 / pr);
 				label.scale.set(scale, scale, scale);
-			} */
-
-			{ // edges
-				/* const materials = [
-					measure.circleRadiusLine.material,
-					...measure.edges.map( (e) => e.material),
-					//measure.heightEdge.material,
-                    measure.guideLine.material,
-					measure.circleLine.material,
-				]; 
-
-				for(const material of materials){
-					material.resolution.set(clientWidth, clientHeight);
-				}*/
-                
-                
-                
-                
-			}
-
-			if(!this.showLabels){
-
+			} */ 
+			if(!this.showLabels){ 
 				const labels = [
 					...measure.sphereLabels,  
 					...measure.angleLabels,  
 					measure.circleRadiusLabel,
-				];
-
+				]; 
 				for(const label of labels){
 					label.visible = false;
 				}
 			}
 		}
-        this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}])
+        //this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}])
         
 	}
-
+    setSize(e){ //e.resolution
+        /* if(Measure.lineMats){
+            for(var m in Measure.lineMats){
+                Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight);
+            }  
+        }  
+        if(Measure.sphereMats){
+            for(var s in Measure.sphereMats){
+                Measure.sphereMats[s].uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
+            }
+        }
+        for (let measure of this.viewer.scene.measurements) { 
+            measure.edgeLabels.concat(measure.areaLabel).forEach(label=>{ 
+                label.sprite.material.uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
+            })
+        } */
+    }
+    
+    updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高
+        
+        group.forEach((e,i)=>{
+            e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0
+         
+            var labels = e.labels.sort((a,b)=>{
+                return b.pos2d.z - a.pos2d.z
+            }) 
+            labels.forEach((label,index)=>{
+                $(label.elem).css('z-index', e.base+index) 
+            }) 
+        }) 
+        
+    }
+    
+    
 	render(o={}){
+        o.camera.layers.set(Potree.config.renderLayers.measure)
 		this.viewer.renderer.render(this.scene, o.camera/* this.viewer.scene.getActiveCamera() */);
 	}
 };

+ 1 - 1
src/utils/TransformationTool.js

@@ -263,7 +263,7 @@ export class TransformationTool {
 				t.start();
 			};
 
-			pickSphere.addEventListener("drag", e => {});
+			//pickSphere.addEventListener("drag", e => {});
 
 			pickSphere.addEventListener("mouseup", e => {
 				e.consume();

+ 6 - 34
src/utils/Volume.js

@@ -16,30 +16,9 @@ export class Volume extends THREE.Object3D {
 
 		this._clip = args.clip || false;
 		this._visible = true;
-		this.showVolumeLabel = true;
+	 
 		this._modifiable = args.modifiable || true;
-
-		this.label = new TextSprite('0');
-		this.label.setBorderColor({r: 0, g: 255, b: 0, a: 0.0});
-		this.label.setBackgroundColor({r: 0, g: 255, b: 0, a: 0.0});
-		this.label.material.depthTest = false;
-		this.label.material.depthWrite = false;
-		this.label.material.transparent = true;
-		this.label.position.y -= 0.5;
-		this.add(this.label);
-
-		this.label.updateMatrixWorld = () => {
-			let volumeWorldPos = new THREE.Vector3();
-			volumeWorldPos.setFromMatrixPosition(this.matrixWorld);
-			this.label.position.copy(volumeWorldPos);
-			this.label.updateMatrix();
-			this.label.matrixWorld.copy(this.label.matrix);
-			this.label.matrixWorldNeedsUpdate = false;
-
-			for (let i = 0, l = this.label.children.length; i < l; i++) {
-				this.label.children[ i ].updateMatrixWorld(true);
-			}
-		};
+ 
 
 		{ // event listeners
 			this.addEventListener('select', e => {});
@@ -176,10 +155,10 @@ export class BoxVolume extends Volume{
 
 		if (this._clip) {
 			this.box.visible = false;
-			this.label.visible = false;
+			 
 		} else {
 			this.box.visible = true;
-			this.label.visible = this.showVolumeLabel;
+			 
 		}
 	}
 
@@ -226,8 +205,7 @@ export class SphereVolume extends Volume{
 		this.boundingBox = this.sphere.geometry.boundingBox;
 		this.add(this.sphere);
 
-		this.label.visible = false;
-
+		 
 
 		let frameGeometry = new THREE.Geometry();
 		{
@@ -309,13 +287,7 @@ export class SphereVolume extends Volume{
 		this.boundingBox = this.sphere.geometry.boundingBox;
 		this.boundingSphere = this.boundingBox.getBoundingSphere(new THREE.Sphere());
 
-		//if (this._clip) {
-		//	this.sphere.visible = false;
-		//	this.label.visible = false;
-		//} else {
-		//	this.sphere.visible = true;
-		//	this.label.visible = this.showVolumeLabel;
-		//}
+		 
 	}
 
 	raycast (raycaster, intersects) {

+ 4 - 23
src/utils/VolumeTool.js

@@ -74,7 +74,7 @@ export class VolumeTool extends EventDispatcher{
 		});
 
 		this.viewer.scene.addVolume(volume);
-		this.scene.add(volume);
+		//this.scene.add(volume);
 
 		let cancel = {
 			callback: null
@@ -83,13 +83,8 @@ export class VolumeTool extends EventDispatcher{
 		let drag = e => {
 			let camera = this.viewer.scene.getActiveCamera();
 			
-			/* let I = Utils.getMousePointCloudIntersection(
-				e.drag.end, 
-				this.viewer.scene.getActiveCamera(), 
-				this.viewer, 
-				this.viewer.scene.pointclouds, 
-				{pickClipped: false}); */
-            var I = this.viewer.inputHandler.intersectPoint
+			
+            var I = e.intersectPoint 
 			if (I) {
 				volume.position.copy(I.location);
 
@@ -134,21 +129,7 @@ export class VolumeTool extends EventDispatcher{
 
 		let volumes = this.viewer.scene.volumes;
 		for (let volume of volumes) {
-			let label = volume.label;
-			
-			{
-
-				let distance = label.position.distanceTo(camera.position);
-				let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight);
-
-				let scale = (70 / pr);
-				label.scale.set(scale, scale, scale);
-			}
-
-			let calculatedVolume = volume.getVolume();
-			calculatedVolume = calculatedVolume / Math.pow(this.viewer.lengthUnit.unitspermeter, 3) * Math.pow(this.viewer.lengthUnitDisplay.unitspermeter, 3);  //convert to cubic meters then to the cubic display unit
-			let text = Utils.addCommas(calculatedVolume.toFixed(3)) + ' ' + this.viewer.lengthUnitDisplay.code + '\u00B3';
-			label.setText(text);
+			 
 		}
 	}
 

+ 9 - 4
src/utils/math.js

@@ -368,14 +368,19 @@ var math = {
         return function(op={}){
             if(op.width2d) w = op.width2d //如果恒定二维宽度
             else{//否则考虑上距离,加一丢丢近大远小的效果
-                var dis = op.position.distanceTo(op.camera.position);
-                w = op.maxSize - ( op.maxSize -  op.minSize) * THREE.Math.smoothstep(dis,  op.nearBound,  op.farBound);
+                var currentDis, nearBound, farBound
+                if(op.camera.type == "OrthographicCamera"){
+                    currentDis = op.camera.right - op.camera.left
+                }else{
+                    currentDis = op.position.distanceTo(op.camera.position);
+                } 
+                w = op.maxSize - ( op.maxSize -  op.minSize) * THREE.Math.smoothstep(currentDis,  op.nearBound,  op.farBound);
                 //maxSize : mesh要表现的最大像素宽度;   nearBound: 最近距离,若比nearBound近,则使用maxSize
             }
             i.copy(op.position).project(op.camera),  //tag中心在屏幕上的二维坐标
-            o.set(op.dom.clientWidth / 2, op.dom.clientHeight / 2, 1).multiply(i), //转化成px   -w/2 到 w/2的范围
+            o.set(op.resulution.x / 2, op.resulution.y / 2, 1).multiply(i), //转化成px   -w/2 到 w/2的范围
             l.set(w / 2, 0, 0).add(o),  //加上tag宽度的一半
-            c.set(2 / op.dom.clientWidth, 2 / op.dom.clientHeight, 1).multiply(l), //再转回  -1 到 1的范围
+            c.set(2 / op.resulution.x, 2 / op.resulution.y, 1).multiply(l), //再转回  -1 到 1的范围
             h.copy(c).unproject(op.camera);//再转成三维坐标,求得tag边缘的位置
             var g = h.distanceTo(op.position)//就能得到tag的三维半径
         

+ 1 - 1
src/utils/transitions.js

@@ -372,7 +372,7 @@ var transitions = {
     getUniqueId: function() {
         return this.uniqueID -= 1,
         this.uniqueID
-    }
+    } 
 };
 
 export    {transitions, lerp, easing}

+ 151 - 231
src/viewer/EDLRenderer.js

@@ -4,6 +4,8 @@ import {PointCloudSM} from "../utils/PointCloudSM.js";
 import {EyeDomeLightingMaterial} from "../materials/EyeDomeLightingMaterial.js";
 import {SphereVolume} from "../utils/Volume.js";
 import {Utils} from "../utils.js";
+import {copyShader} from '../materials/shaders/otherShaders'
+
 
 export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 	constructor(viewer){
@@ -19,7 +21,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 		this.shadowMap = new PointCloudSM(this.viewer.pRenderer);
         
         viewer.addEventListener('resize',this.resize.bind(this))
-         
+        this.initEDL()
 	}
 
 	initEDL(){
@@ -46,6 +48,24 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 			format: THREE.RGBAFormat,
 			depthTexture: new THREE.DepthTexture(undefined, undefined, THREE.UnsignedIntType)
 		});
+        
+        
+        
+        
+        
+        let copyUniforms = THREE.UniformsUtils.clone( copyShader.uniforms );
+          
+        this.copyMaterial = new THREE.ShaderMaterial(	{
+            uniforms: copyUniforms,
+            vertexShader: copyShader.vertexShader,
+            fragmentShader: copyShader.fragmentShader,
+            //premultipliedAlpha: true,
+            transparent: true,
+            //blending: THREE.AdditiveBlending,
+            depthTest: false,
+            depthWrite: false
+        });
+        
 	};
 
 	resize(e){
@@ -55,68 +75,12 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 			height = this.screenshot.target.height;
 		} */
 
-		this.rtEDL.setSize(e.canvasWidth, e.canvasHeight);
-		this.rtRegular.setSize(e.canvasWidth, e.canvasHeight);
+		this.rtEDL.setSize(e.resolution.x, e.resolution.y);
+		this.rtRegular.setSize(e.resolution.x, e.resolution.y);
         
 	}
 
-	makeScreenshot(camera, size, callback){
-
-		if(camera === undefined || camera === null){
-			camera = this.viewer.scene.getActiveCamera();
-		}
-
-		if(size === undefined || size === null){
-			size = this.viewer.renderer.getSize(new THREE.Vector2());
-		}
-
-		let {width, height} = size;
-
-		//let maxTextureSize = viewer.renderer.capabilities.maxTextureSize;
-		//if(width * 4 < 
-		width = 2 * width;
-		height = 2 * height;
-
-		let target = new THREE.WebGLRenderTarget(width, height, {
-			format: THREE.RGBAFormat,
-		});
-
-		this.screenshot = {
-			target: target
-		};
-
-		// HACK? removed because of error, was this important?
-		//this.viewer.renderer.clearTarget(target, true, true, true);
-
-		this.render();
-
-		let pixelCount = width * height;
-		let buffer = new Uint8Array(4 * pixelCount);
-
-		this.viewer.renderer.readRenderTargetPixels(target, 0, 0, width, height, buffer);
-
-		// flip vertically
-		let bytesPerLine = width * 4;
-		for(let i = 0; i < parseInt(height / 2); i++){
-			let j = height - i - 1;
-
-			let lineI = buffer.slice(i * bytesPerLine, i * bytesPerLine + bytesPerLine);
-			let lineJ = buffer.slice(j * bytesPerLine, j * bytesPerLine + bytesPerLine);
-			buffer.set(lineJ, i * bytesPerLine);
-			buffer.set(lineI, j * bytesPerLine);
-		}
-        
-        
-        callback && callback(this.screenshot.target)//add
-		this.screenshot.target.dispose();
-		delete this.screenshot;
-
-		return {
-			width: width,
-			height: height,
-			buffer: buffer
-		};
-	}
+	
 
 	clearTargets(params){
 		const viewer = this.viewer;
@@ -143,7 +107,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 	}
 
 	clear(params={}){
-		this.initEDL();
+		//this.initEDL();
 		const viewer = this.viewer;
 
 		const {renderer, background} = viewer;
@@ -201,31 +165,35 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 	}
 
 	render(params={}){
-        const viewer = this.viewer;
-		viewer.useEDL &&  this.initEDL();
-
-		
-		let camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
         
+        /* 
+            渲染顺序:
+                底层:背景 -> skybox(也可中间)
+                中间层(含有深度信息):1 点云、marker等mesh,
+                                        2 测量线(现在被做成借用depthTex
+                顶层:maginifier 
+            magnifier的贴图渲染不需要顶层、中间层只需要点云。
+         */
         
+        const viewer = this.viewer; 
+		let camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
 		const {width, height} = params.width ? params : this.viewer.renderer.getSize(new THREE.Vector2());
-
-
-		viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
+		
+        
+        //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
 	
-		//params.target || this.resize(width, height);//因为resize WebGLRenderTarget会清屏,所以一般不要resize。  但为何navvis不会?
-                                                    //所以最好为放大镜准备一个rtEDL
-		const visiblePointClouds = viewer.scene.pointclouds.filter(pc => pc.visible);
-
-		if(this.screenshot){
-			let oldBudget = Potree.pointBudget;
-			Potree.pointBudget = Math.max(10 * 1000 * 1000, 2 * oldBudget);
-			let result = Potree.updatePointClouds(
-				viewer.scene.pointclouds, 
-				camera, 
-				viewer.renderer);
-			Potree.pointBudget = oldBudget;
-		}
+		                                           
+		const visiblePointClouds = viewer.scene.pointclouds.filter(pc =>  pc.visible );
+		const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => pc.isVisible  );
+		const showPointClouds = viewer.scene.pointclouds.some(e=>e.visible)
+         
+        viewer.scene.pointclouds.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下。且放大镜需要绘制点云)
+            e.oldVisi = e.visible
+            if(e.isVisible)e.visible = true; 
+        }) 
+        
+        
+        
  
 		let lights = [];
 		viewer.scene.scene.traverse(node => {
@@ -234,175 +202,127 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 			}
 		});
 
-		if(viewer.background === "skybox"){
-			viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
-			viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
-			viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
-
-			viewer.skybox.parent.rotation.x = 0;
-			viewer.skybox.parent.updateMatrixWorld();
-
-			viewer.skybox.camera.updateProjectionMatrix();
-			viewer.renderer.render(viewer.skybox.scene, viewer.skybox.camera);
-		} else if (viewer.background === 'gradient') {
-            if(params.target){//add
-                viewer.renderer.setRenderTarget(params.target)
-                viewer.renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG);
-                viewer.renderer.setRenderTarget(null)                
-            }else{
-                viewer.renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG); 
-            }
-			
-		} 
 
-		//TODO adapt to multiple lights
-		this.renderShadowMap(visiblePointClouds, camera, lights);
+        viewer.renderer.setRenderTarget(params.target || null);
+        
+        {//绘制背景
+            if(viewer.background === "skybox"){
+                viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
+                viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
+                viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
+
+                viewer.skybox.parent.rotation.x = 0;
+                viewer.skybox.parent.updateMatrixWorld();
+
+                viewer.skybox.camera.updateProjectionMatrix();
+            }else if (viewer.background === 'gradient') { 
+           
+            }         
+            viewer.renderer.render(viewer.scene.scene, viewer.scene.cameraBG);
+        }
+        
+        //skybox
+        camera.layers.set(Potree.config.renderLayers.skybox);
+        viewer.renderer.render(viewer.scene.scene, camera);
+        
+        
+        //pointcloud
+        camera.layers.set(Potree.config.renderLayers.pointcloud);
+		
+        //TODO adapt to multiple lights
+		this.renderShadowMap(visiblePointClouds2, camera, lights);  //???????
 
-		{ // COLOR & DEPTH PASS
-			for (let pointcloud of visiblePointClouds) {
+		{ //scenePointCloud   COLOR & DEPTH PASS
+			for (let pointcloud of visiblePointClouds2) {
                 
-                let material = pointcloud.material;
-                 
-                if(viewer.useEDL){
-                    let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
- 
-                    material.weighted = false;
-                    material.useLogarithmicDepthBuffer = false;
+                let material = pointcloud.material; 
+                let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
+                material.fov = THREE.Math.degToRad(camera.fov) 
+                material.screenWidth = width;
+                material.screenHeight = height;
+                material.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z);
+                material.near = camera.near;
+                material.far = camera.far;
+                material.uniforms.octreeSize.value = octreeSize
+	
+                if(viewer.useEDL){ 
+                    /* material.weighted = false;
+                    material.useLogarithmicDepthBuffer = false;  */ 
                     material.useEDL = true;
-
-                    material.screenWidth = width;
-                    material.screenHeight = height;
-                    material.uniforms.visibleNodes.value = pointcloud.material.visibleNodesTexture;
-                    material.uniforms.octreeSize.value = octreeSize;
-                    material.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(pointcloud.scale.x, pointcloud.scale.y, pointcloud.scale.z);
+                    //material.fakeEDL = false; //add
                 }else{
-                    material.useEDL = false
-                }
+                    material.useEDL = false;
+                    //material.fakeEDL = true; //add 使也输出深度
+                }  
                 
 			}
 			
-			// TODO adapt to multiple lights
-            if(viewer.useEDL) {
-                viewer.renderer.setRenderTarget(params.rtEDL || this.rtEDL);
-			 
-                
-                if(lights.length > 0){
-                    viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, params.rtEDL || this.rtEDL, {
-                        clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
-                        shadowMaps: [this.shadowMap],
-                        transparent: false,
-                    });
-                }else{
-
-                    
-                    // let test = camera.clone();
-                    // test.matrixAutoUpdate = false;
-
-                    // //test.updateMatrixWorld = () => {};
-
-                    // let mat = new THREE.Matrix4().set(
-                    // 	1, 0, 0, 0,
-                    // 	0, 0, 1, 0,
-                    // 	0, -1, 0, 0,
-                    // 	0, 0, 0, 1,
-                    // );
-                    // mat.invert()
-
-                    // test.matrix.multiplyMatrices(mat, test.matrix);
-                    // test.updateMatrixWorld();
-
-                    //test.matrixWorld.multiplyMatrices(mat, test.matrixWorld);
-                    //test.matrixWorld.multiply(mat);
-                    //test.matrixWorldInverse.invert(test.matrixWorld);
-                    //test.matrixWorldInverse.multiplyMatrices(test.matrixWorldInverse, mat);
-                    
-
-                    viewer.pRenderer.render(viewer.scene.scenePointCloud, camera,  params.rtEDL || this.rtEDL, {
-                        clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
-                        transparent: false,
-                    });
-                }
-            }else{
-                viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, params.target || null, {
-                    clipSpheres: viewer.scene.volumes.filter(v => (v instanceof Potree.SphereVolume)),
-                });
-		
-            }
-			
+            
+            //借用rtEDL存储深度信息 
+            viewer.renderer.setRenderTarget(params.rtEDL || this.rtEDL);
+         
+            
+            //渲染scenePointCloud到rtEDL
+            viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, params.rtEDL || this.rtEDL, {
+                shadowMaps:  lights.length > 0 ? [this.shadowMap] : null,
+                clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
+                transparent: false,
+            });
+             
 		}
-
+        
+        
+        
+         
+        //渲染到rtEDL完毕
 		viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer, renderTarget: this.rtRegular});
-		viewer.renderer.setRenderTarget(params.target ? params.target : null);
-		viewer.renderer.render(viewer.scene.scene, camera);
+		viewer.renderer.setRenderTarget(params.target || null);
+        
+        viewer.scene.pointclouds.forEach(e=>{
+            e.visible = e.oldVisi
+        })
         
+         
+         
         
-        if(viewer.useEDL) {
+       //设置edlMaterial
+        if(viewer.useEDL && showPointClouds  /* || params.magnifier */) {
             // EDL PASS
 
 			const uniforms = this.edlMaterial.uniforms;
-
-			uniforms.screenWidth.value = width;
-			uniforms.screenHeight.value = height;
-
-			let proj = camera.projectionMatrix;
-			let projArray = new Float32Array(16);
-			projArray.set(proj.elements);
-
-			uniforms.uNear.value = camera.near;
-			uniforms.uFar.value = camera.far;
+            //if(viewer.useEDL){
+                uniforms.screenWidth.value = width;
+                uniforms.screenHeight.value = height;
+                
+                uniforms.edlStrength.value = viewer.edlStrength;
+                uniforms.radius.value = viewer.edlRadius;
+                uniforms.useEDL.value = 1;//add
+            /* }else{
+                uniforms.useEDL.value = 0;//add
+            } */
+            
+            let proj = camera.projectionMatrix;
+            let projArray = new Float32Array(16);
+            projArray.set(proj.elements);
+            uniforms.uProj.value = projArray;
+		 
 			uniforms.uEDLColor.value = (params.rtEDL || this.rtEDL).texture;
-			uniforms.uEDLDepth.value = (params.rtEDL || this.rtEDL).depthTexture;
-			uniforms.uProj.value = projArray;
-
-			uniforms.edlStrength.value = viewer.edlStrength;
-			uniforms.radius.value = viewer.edlRadius;
+			//uniforms.uEDLDepth.value = (params.rtEDL || this.rtEDL).depthTexture; //其实没用到
+			 
 			uniforms.opacity.value = viewer.edlOpacity; // HACK
 			 
-			if(this.screenshot){
-				Utils.screenPass.render(viewer.renderer, this.edlMaterial, this.screenshot.target);
-			}else if(params.target){
-				Utils.screenPass.render(viewer.renderer, this.edlMaterial, params.target);
-            }else{
-                Utils.screenPass.render(viewer.renderer, this.edlMaterial);
-            }
-
+			
+            Utils.screenPass.render(viewer.renderer, this.edlMaterial, params.target);
 		}else{
-             
-            
-        }
-        
-        
-        
-        viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer});
-        
-        
+            //渲染点云 (直接用rtEDL上的会失去抗锯齿)
+            viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, null , {
+                shadowMaps:  lights.length > 0 ? [this.shadowMap] : null,
+                clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume))
+            });  
+        }   
+          
+		//viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
         
-        if(!params.target){
-            viewer.renderer.render(viewer.scene.sceneOverlay, camera);// add   透明贴图层  reticule marker 不能遮住测量线
-        }
-
-
-		viewer.renderer.clearDepth();
-
-		viewer.transformationTool.update();
-        
-       
-         
-        
-        if(!params.target){ 
-            //测量线
-            viewer.dispatchEvent({type: "render.pass.perspective_overlay", viewer: viewer, camera});
-            viewer.renderer.render(viewer.overlay, camera); //magnifier 遮住测量线
-            
-        } 
-        
-        
-		 
-		viewer.renderer.render(viewer.controls.sceneControls, camera);
-		viewer.renderer.render(viewer.clippingTool.sceneVolume, camera);
-		viewer.renderer.render(viewer.transformationTool.scene, camera);
-		
-		viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
         
 	}
 }

+ 6 - 4
src/viewer/PropertyPanels/PropertiesPanel.js

@@ -249,7 +249,7 @@ export class PropertiesPanel{
 			sldPointSize.slider({
 				value: material.size,
 				min: 0,
-				max: 30,//3,
+				max: 3,
 				step: 0.01,
 				slide: function (event, ui) { material.size = ui.value; }
 			});
@@ -270,7 +270,7 @@ export class PropertiesPanel{
 			sldMinPointSize.slider({
 				value: material.size,
 				min: 0,
-				max: 30,//3,
+				max: 3,
 				step: 0.01,
 				slide: function (event, ui) { material.minSize = ui.value; }
 			});
@@ -440,8 +440,8 @@ export class PropertiesPanel{
 						}
 					});
 				} else if(attribute){
-					const [min, max] = attribute.range;
-
+					let [min, max] = attribute.range;
+        
 					let selectedRange = material.getRange(attribute.name);
 
 					if(!selectedRange){
@@ -449,6 +449,8 @@ export class PropertiesPanel{
 					}
 
 					let minMaxAreNumbers = typeof min === "number" && typeof max === "number";
+                    /* min = 0 ;max =  50
+                    selectedRange[0] =min; selectedRange[1] = max;  */
 
 					if(minMaxAreNumbers){
 						panel.find('#sldExtraRange').slider({

+ 14 - 5
src/viewer/Scene.js

@@ -15,8 +15,8 @@ export class Scene extends EventDispatcher{
 		this.annotations = new Annotation();
 		
 		this.scene = new THREE.Scene();
-		this.sceneBG = new THREE.Scene();
-        this.sceneOverlay = new THREE.Scene(); //add  放最后渲染的(透明)东西,如marker,防止冲突
+        //this.sceneBG = new THREE.Scene(); //用来放skybox
+        //this.sceneOverlay = new THREE.Scene();  
 		this.scenePointCloud = new THREE.Scene();
 
 		this.cameraP = new THREE.PerspectiveCamera(this.fov, 1, 0.1, 1000*1000);
@@ -50,9 +50,14 @@ export class Scene extends EventDispatcher{
 
 		this.initialize();
         
-        this.axisArrow = new Axis( );
+        this.axisArrow = new Axis();
         this.scene.add(this.axisArrow)
         this.axisArrow.visible = false
+        
+        
+        
+        
+
 	}
 
 	estimateHeightAt (position) {
@@ -171,7 +176,7 @@ export class Scene extends EventDispatcher{
 	add360Images(images){
 		this.images360.push(images);
 		this.scene.add(images.node);
-        this.sceneOverlay.add(images.node2);//add
+        //this.sceneOverlay.add(images.node);//add
         
         
 		this.dispatchEvent({
@@ -404,7 +409,11 @@ export class Scene extends EventDispatcher{
 			);
 			bg.material.depthTest = false;
 			bg.material.depthWrite = false;
-			this.sceneBG.add(bg);
+            bg.name = 'bg'
+			//this.sceneBG.add(bg);
+            this.scene.add(bg)
+            bg.layers.set(Potree.config.renderLayers.bg)
+            this.cameraBG.layers.set(Potree.config.renderLayers.bg);
 		}
 
 		// { // lights

+ 2 - 2
src/viewer/View.js

@@ -6,8 +6,8 @@ export class View{
 	constructor () {
 		this.position = new THREE.Vector3(0, 0, 0);
 
-		this.yaw = Math.PI / 4; // =  4dkk lon + 90  
-		this._pitch = -Math.PI / 4; //上下旋转 = 4dkk lat
+		this.yaw = 0//Math.PI / 4; // =  4dkk lon + 90  
+		this._pitch = 0//-Math.PI / 4; //上下旋转 = 4dkk lat
 		this.radius = 1;
 
 		this.maxPitch = Math.PI / 2;

+ 9 - 1
src/viewer/potree.css

@@ -862,7 +862,15 @@ body{
 #potree_labels >div.measure_length{
     
 }
- 
+#mapGaode{
+    position: absolute;
+    z-index: 100; 
+    box-sizing: border-box;
+    width:300px; height:200px;
+    right:0px;
+    top:0px;
+    background:#fff;
+}
 
 .hide{
     display:none !important; 

+ 9 - 7
src/viewer/sidebar.html

@@ -258,8 +258,8 @@ Thanks to all the companies and institutions funding Potree:
 
         <h3 class="accordion-header ui-widget"><span>数据集校准</span></h3>
         <div id="alignment"  class="accordion-content ui-widget pv-menu-list">
-            <li name='function'><button id='splitView'>分屏</button></li>
-            
+            <li name='function'><button id='startAlignment'>开始</button></li>
+            <li name='function'><button id='exitAlignment'>退出</button></li>
             <li name = 'selectPointCloud'> 
                 <span>选择数据集</span>
                 <div> </div>   
@@ -270,13 +270,15 @@ Thanks to all the companies and institutions funding Potree:
                 <span>平移</span>
                 <div><button>-x</button><button>+x</button><span class='gap'></span> <button>-y</button><button>+y</button> <span class='gap'> <button>-z</button><button>+z</button></div>
             </li>
-            
-        
-        
+             
         </div>
 
-
-
+        <h3 class="accordion-header ui-widget"><span>点云下载</span></h3>
+        <div id="clipModel"  class="accordion-content ui-widget pv-menu-list">
+            <button>开始</button>
+            <button>下载</button>
+            <button>退出</button>
+        </div>
 
 
 

+ 70 - 17
src/viewer/sidebar.js

@@ -16,8 +16,11 @@ import {CameraAnimation} from "../modules/CameraAnimation/CameraAnimation.js"
 import {HierarchicalSlider} from "./HierarchicalSlider.js"
 import {OrientedImage} from "../modules/OrientedImages/OrientedImages.js";
 import {Images360} from "../modules/Images360/Images360.js";
-import {Alignment} from "../modules/datasetAlignment/Alignment.js";
+ 
 import JSON5 from "../../libs/json5-2.1.3/json5.mjs";
+ 
+
+
 
 export class Sidebar{
 
@@ -54,15 +57,17 @@ export class Sidebar{
 		this.initFilters();
 		this.initClippingTool();
 		this.initSettings();
-		this.initAlignment();//add
+        //add
+		this.initAlignment();
+        this.initClipModel();
 		$('#potree_version_number').html(Potree.version.major + "." + Potree.version.minor + Potree.version.suffix);
 	}
 
     
     initAlignment(){
+        let Alignment = viewer.modules.Alignment
         var pannel = $('#alignment');
-        var buttons = pannel.find('[name="transform"] button') 
-        var splitScreenBtn = pannel.find('#splitView') 
+        var buttons = pannel.find('[name="transform"] button')   
         var applyToPointcloud = (fun, value)=>{
             return function(){
                 var selected = $('#alignment li[name="selectPointCloud"] input:checked' )
@@ -93,32 +98,38 @@ export class Sidebar{
         buttons.eq(9).on('click', applyToPointcloud(Alignment.translate, new THREE.Vector3(0,1,0)))
         buttons.eq(10).on('click', applyToPointcloud(Alignment.translate, new THREE.Vector3(0,0,-1)))
         buttons.eq(11).on('click', applyToPointcloud(Alignment.translate, new THREE.Vector3(0,0,1)))
-        splitScreenBtn.on('click', ()=>{
-            Alignment.splitScreen()
+        pannel.find('#startAlignment').on('click', ()=>{
+            Alignment.enter()
+        })
+        pannel.find('#exitAlignment').on('click', ()=>{
+            Alignment.leave()
         })
-        
         this.viewer.addEventListener("translatePointcloud",(e)=>{
             applyToPointcloud(Alignment.translate, e.vec)()
         })
     }
     
-    
     addAlignmentButton(pointcloud){
         var pannel = $('#alignment li[name="selectPointCloud"]>div');
         var option = $(` <input name="${pointcloud.name}" class="editCheckbox" type="checkbox" >
                           
                          <label for="showingLabels">${pointcloud.name}</label>`) 
                          
-        pannel.append(option) 
-
-
-        /* option.find("input").on('change',function(){
-             
-            
+        pannel.append(option)  
+        /* option.find("input").on('change',function(){ 
         })
          */
     }
-
+    initClipModel(){
+        let Clip = viewer.modules.Clip
+        var pannel = $('#clipModel');
+        var buttons = pannel.find('button')
+        buttons.eq(0).on('click', Clip.enter.bind(Clip))
+        buttons.eq(1).on('click', Clip.download.bind(Clip))
+        buttons.eq(2).on('click', Clip.leave.bind(Clip))
+    }
+    
+    
 
 	initToolbar(){
 
@@ -204,9 +215,8 @@ export class Sidebar{
 					closed: false,
 					maxMarkers: 2,
                     minMarkers:2, 
-                    direction: new THREE.Vector3(0,0,1),//add
                     //showGuideLine: true: true
-                    measureType: 'Height',
+                    measureType: 'Ver Distance',
                 });
 
 				let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
@@ -286,6 +296,49 @@ export class Sidebar{
 				$.jstree.reference(jsonNode.id).select_node(jsonNode.id);
 			}
 		));
+        
+        
+        // AREA
+		elToolbar.append(this.createToolIcon(
+			Potree.resourcePath + '/icons/area.svg',
+			'[title]tt.area_measurement',
+			() => {
+				$('#menu_measurements').next().slideDown();
+				let measurement = this.measuringTool.startInsertion({
+					showDistances: true,
+					showArea: true,
+					closed: true,
+                    minMarkers:3, 
+					measureType: 'Hor Area'});
+
+				let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
+				let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
+				$.jstree.reference(jsonNode.id).deselect_all();
+				$.jstree.reference(jsonNode.id).select_node(jsonNode.id);
+			}
+		));
+        
+        
+        // AREA
+		elToolbar.append(this.createToolIcon(
+			Potree.resourcePath + '/icons/area.svg',
+			'[title]tt.area_measurement',
+			() => {
+				$('#menu_measurements').next().slideDown();
+				let measurement = this.measuringTool.startInsertion({
+					showDistances: true,
+					showArea: true,
+					closed: true,
+                    minMarkers:3, 
+					measureType: 'Ver Area'});
+
+				let measurementsRoot = $("#jstree_scene").jstree().get_json("measurements");
+				let jsonNode = measurementsRoot.children.find(child => child.data.uuid === measurement.uuid);
+				$.jstree.reference(jsonNode.id).deselect_all();
+				$.jstree.reference(jsonNode.id).select_node(jsonNode.id);
+			}
+		));
+        
         // rect area freedom direction
         elToolbar.append(this.createToolIcon(
 			Potree.resourcePath + '/icons/area.svg',

+ 423 - 255
src/viewer/viewer.js

@@ -10,6 +10,7 @@ import {ClippingTool} from "../utils/ClippingTool.js";
 import {TransformationTool} from "../utils/TransformationTool.js";
 import {Utils} from "../utils.js";
 import {MapView} from "./map.js";
+import {MapViewer} from "./map/MapViewer.js";
 import {ProfileWindow, ProfileWindowController} from "./profile.js";
 import {BoxVolume} from "../utils/Volume.js";
 import {Features} from "../Features.js";
@@ -29,35 +30,54 @@ import {FirstPersonControls} from "../navigation/FirstPersonControls.js";
 import {EarthControls} from "../navigation/EarthControls.js";
 import {DeviceOrientationControls} from "../navigation/DeviceOrientationControls.js";
 import {VRControls} from "../navigation/VRControls.js";
-import { EventDispatcher } from "../EventDispatcher.js";
+
 import { ClassificationScheme } from "../materials/ClassificationScheme.js";
 import { VRButton } from '../../libs/three.js/extra/VRButton.js';
-import {transitions, esing, lerp} from '../utils/transitions.js'
+import {transitions, easing, lerp} from '../utils/transitions.js'
 import JSON5 from "../../libs/json5-2.1.3/json5.mjs";
 import CursorDeal from '../utils/CursorDeal'
+import Common from '../utils/Common'
 
+import {Clip} from '../modules/clipModel/Clip'
+import {Alignment} from "../modules/datasetAlignment/Alignment.js";
 
+import Magnifier from "../utils/Magnifier.js";
+import Reticule from "../navigation/Reticule.js";
+import Viewport from "./Viewport.js"
+import {ViewerBase} from "./viewerBase.js"
+ 
+import SplitScreen from '../utils/SplitScreen'
 
 
-var W, H, pixelRatio;
-
  
 
-export class Viewer extends EventDispatcher{
+export class Viewer extends ViewerBase{
 	
 	constructor(domElement, args = {}){
-		super();
+		super(domElement,args);
+        window.viewer = this
+        this.modules = { //add
+            Clip : Clip,
+            Alignment : Alignment
+            
+        }
+        
+        
+        
+        //add --------
         this.navigateMode = 'free' // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点, 
         this.isEdit = true
+        CursorDeal.attachToViewer(this)//ADD
+        
+		//-------------
+        
+        
         
-		this.renderArea = domElement;
 		this.guiLoaded = false;
 		this.guiLoadTasks = [];
 
 		this.onVrListeners = [];
         
-        CursorDeal.attachToViewer(this)//ADD
-        
 		this.messages = [];
 		this.elMessages = $(`
 		<div id="message_listing" 
@@ -132,6 +152,12 @@ export class Viewer extends EventDispatcher{
             //add
             {
                 $(domElement).append($("<div id='potree_labels'></div>"))
+                
+                let mapArea = $("<div id='mapGaode'></div>")
+                $(domElement).append(mapArea)
+                
+                
+                
             }
              
             
@@ -180,8 +206,7 @@ export class Viewer extends EventDispatcher{
 		this.filterPointSourceIDRange = [0, 65535];
 
 		this.potreeRenderer = null;
-		this.edlRenderer = null;
-		this.renderer = null;
+		this.edlRenderer = null; 
 		this.pRenderer = null;
 
 		this.scene = null;
@@ -201,8 +226,9 @@ export class Viewer extends EventDispatcher{
 		this.clock = new THREE.Clock();
 		this.background = null;
 
-		this.initThree();
+		 
 
+        
   
 		if(args.noDragAndDrop){
 			
@@ -271,16 +297,35 @@ export class Viewer extends EventDispatcher{
 		this.setScene(scene);
 
 		{
-			this.inputHandler = new InputHandler(this);
-			this.inputHandler.setScene(this.scene);
-
+			this.inputHandler = new InputHandler(this, this.scene.scene);
+			//this.inputHandler.setScene(this.scene);
+            //this.inputHandler.addInputListener(this);//add
+            
+            
+            
 			this.clippingTool = new ClippingTool(this);
 			this.transformationTool = new TransformationTool(this);
 			this.navigationCube = new NavigationCube(this);
 			this.navigationCube.visible = false;
 
 			this.compass = new Compass(this);
-			
+            
+            
+			//add----------
+            this.magnifier = new Magnifier(this);
+            this.reticule = new Reticule(this) 
+            this.scene.scene.add(this.magnifier) 
+            this.scene.scene.add(this.reticule)
+            this.mainViewport = new Viewport(this.renderer, this.scene.view, this.scene.cameraP, {
+                left:0, bottom:0, width:1, height: 1, name:'MainView' 
+            }) 
+            this.viewports = [this.mainViewport]
+            
+            
+            this.mapViewer = new MapViewer($('#mapGaode')[0])
+            //-----------
+            
+            
 			this.createControls();
 
 			this.clippingTool.setScene(this.scene);
@@ -446,16 +491,19 @@ export class Viewer extends EventDispatcher{
 		}
 	};
 
-	setControls(controls){
+	setControls(controls/* , setSpeed */){ 
 		if (controls !== this.controls) {
 			if (this.controls) {
-				this.controls.enabled = false;
-				this.inputHandler.removeInputListener(this.controls);
-			}
-
+                this.controls.setEnable(false) 
+				//this.inputHandler.removeInputListener(this.controls);
+                this.controls.moveSpeed = this.moveSpeed;  //记录   (因为orbit的radius很大,转为firstPerson时要缩小)
+			} 
 			this.controls = controls;
-			this.controls.enabled = true;
-			this.inputHandler.addInputListener(this.controls);
+            controls.moveSpeed && this.setMoveSpeed(controls.moveSpeed) //add
+            
+            this.controls.setEnable(true) 
+			 
+			//this.inputHandler.addInputListener(this.controls);
 		}
 	}
 
@@ -672,6 +720,8 @@ export class Viewer extends EventDispatcher{
 	setFOV (value) {
 		if (this.fov !== value) {
 			this.fov = value;
+            this.scene.cameraP.fov = this.fov;
+            this.scene.cameraP.updateProjectionMatrix()
 			this.dispatchEvent({'type': 'fov_changed', 'viewer': this});
 		}
 	};
@@ -889,11 +939,7 @@ export class Viewer extends EventDispatcher{
 		});
 	};
 
-	getBoundingBox (pointclouds) {
-        //可以直接返回viewer.bound
-		return this.scene.getBoundingBox(pointclouds);
-	};
-
+	
 	getGpsTimeExtent(){
 		const range = [Infinity, -Infinity];
 
@@ -1021,16 +1067,19 @@ export class Viewer extends EventDispatcher{
 	async loadProject(url){
 
 		const response = await fetch(url);
-	
-		const text = await response.text();
-		const json = JSON5.parse(text);
-		// const json = JSON.parse(text);
-
-		if(json.type === "Potree"){
-			Potree.loadProject(viewer, json);
-		}
+        if(response.ok){
+            const text = await response.text();
+            const json = JSON5.parse(text);
+            // const json = JSON.parse(text);
 
-		//Potree.loadProject(this, url);
+            if(json.type === "Potree"){
+                Potree.loadProject(viewer, json);
+            }
+            
+        }else{
+            console.warn("未能加载:"+url )
+        }
+            
 	}
 
 	saveProject(){
@@ -1136,10 +1185,18 @@ export class Viewer extends EventDispatcher{
 
 	createControls () {
 		{ // create FIRST PERSON CONTROLS
-			this.fpControls = new FirstPersonControls(this);
+			this.fpControls = new FirstPersonControls(this, this.scene.view);
 			this.fpControls.enabled = false;
 			this.fpControls.addEventListener('start', this.disableAnnotations.bind(this));
 			this.fpControls.addEventListener('end', this.enableAnnotations.bind(this));
+            this.addEventListener("loadPointCloudDone",  ()=>{
+                let boundPlane = new THREE.Box3()
+                boundPlane.expandByPoint(this.bound.boundingBox.min.clone())//最低高度为bound的最低
+                boundPlane.expandByPoint(this.bound.boundingBox.max.clone().setZ(this.bound.center.z))//最高高度为bound的中心高度
+                FirstPersonControls.boundPlane = boundPlane
+                FirstPersonControls.standardSpeed = THREE.Math.clamp( Math.sqrt(this.bound.boundSize.length() )/ 100 ,   0.02,0.5); //在这个boundPlane中的速度
+            })
+        
 		}
 
 		// { // create GEO CONTROLS
@@ -1424,74 +1481,9 @@ export class Viewer extends EventDispatcher{
 		$("body")[0].addEventListener("drop", dropHandler);
 	}
 
-	initThree () {
-
-		console.log(`initializing three.js ${THREE.REVISION}`);
-
-		let width = this.renderArea.clientWidth;
-		let height = this.renderArea.clientHeight;
-
-		let contextAttributes = {
-			alpha: true,
-			depth: true,
-			stencil: false,
-			antialias: true,
-			//premultipliedAlpha: _premultipliedAlpha,
-			preserveDrawingBuffer: true,
-			powerPreference: "high-performance",
-		};
-
-		// let contextAttributes = {
-		// 	alpha: false,
-		// 	preserveDrawingBuffer: true,
-		// };
-
-		// let contextAttributes = {
-		// 	alpha: false,
-		// 	preserveDrawingBuffer: true,
-		// };
-
-		let canvas = document.createElement("canvas");
-
-		let context = canvas.getContext('webgl', contextAttributes );
-
-		this.renderer = new THREE.WebGLRenderer({
-			alpha: true, 
-			premultipliedAlpha: false,
-			canvas: canvas,
-			context: context,
-            
-        });     
-		this.renderer.sortObjects = true; //原先false 打开了renderOrder才奏效
-		//this.renderer.setSize(width, height);
-		this.renderer.autoClear = false;
-		this.renderArea.appendChild(this.renderer.domElement);
-		this.renderer.domElement.tabIndex = '2222';
-		this.renderer.domElement.style.position = 'absolute';
-		this.renderer.domElement.addEventListener('mousedown', () => {
-			this.renderer.domElement.focus();
-		});
-		//this.renderer.domElement.focus();
-
-		// NOTE: If extension errors occur, pass the string into this.renderer.extensions.get(x) before enabling
-		// enable frag_depth extension for the interpolation shader, if available
-		let gl = this.renderer.getContext();
-		gl.getExtension('EXT_frag_depth');
-		gl.getExtension('WEBGL_depth_texture');
-		gl.getExtension('WEBGL_color_buffer_float'); 	// Enable explicitly for more portability, EXT_color_buffer_float is the proper name in WebGL 2
-		
-		if(gl.createVertexArray == null){
-			let extVAO = gl.getExtension('OES_vertex_array_object');
-
-			if(!extVAO){
-				throw new Error("OES_vertex_array_object extension not supported");
-			}
-
-			gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
-			gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
-		}
+	 
 		
-	}
+	 
 
 	updateAnnotations () {
 
@@ -1646,7 +1638,10 @@ export class Viewer extends EventDispatcher{
 			type: 'update_start',
 			delta: delta,
 			timestamp: timestamp});
-
+            
+        
+        this.updateScreenSize() //判断是否改变canvas大小
+         
 		
 		const scene = this.scene;
 		const camera = scene.getActiveCamera();
@@ -1657,7 +1652,7 @@ export class Viewer extends EventDispatcher{
 		const lTarget = camera.position.clone().add(camera.getWorldDirection(new THREE.Vector3()).multiplyScalar(1000));
 		this.scene.directionalLight.position.copy(camera.position);
 		this.scene.directionalLight.lookAt(lTarget);
-
+        
 
 		for (let pointcloud of visiblePointClouds) {
 
@@ -1700,8 +1695,27 @@ export class Viewer extends EventDispatcher{
 			}
 		}
 
+
+
 		if (!this.freeze) {
-			let result = Potree.updatePointClouds(scene.pointclouds, camera, this.renderer);
+            
+            /*let cameraGroup = []
+            let size = this.renderer.getSize(new THREE.Vector2())
+             if(this.viewports){
+                this.viewports.forEach(viewport=>{
+                    if(!viewport.active)return
+                    cameraGroup.push({camera:viewport.camera, areaSize:new THREE.Vector2(Math.floor(size.x * viewport.width), Math.floor(size.y * viewport.height))})  
+                }) 
+            }else{
+                cameraGroup.push({camera,  areaSize:size})
+            }
+			let result = Potree.updatePointClouds(scene.pointclouds,  cameraGroup );
+            */
+
+
+
+
+
 
 
 			// DEBUG - ONLY DISPLAY NODES THAT INTERSECT MOUSE
@@ -1760,8 +1774,8 @@ export class Viewer extends EventDispatcher{
 			// Potree.debug.numNodes = numNodes;
 
 			//console.log(lowestDistance.toString(2), duration);
-
-			const tStart = performance.now();
+        //搬走
+			/* const tStart = performance.now();
 			const campos = camera.position;
 			let closestImage = Infinity;
 			for(const images of this.scene.orientedImages){
@@ -1794,8 +1808,17 @@ export class Viewer extends EventDispatcher{
 
 			if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {
 				camera.near = -camera.far;
-			}
-		} 
+			}*/
+		}  
+        
+        
+        
+        
+        
+        
+        
+        
+        
 		
 		this.scene.cameraP.fov = this.fov;
 		
@@ -1809,31 +1832,30 @@ export class Viewer extends EventDispatcher{
 		} else if (controls !== null) {
 			controls.setScene(scene);
 			controls.update(delta);
-
+        
             //更新camera
-
-            if(this.viewports){
-                this.viewports.forEach(viewport=>{
-                    if(!viewport.active)return
-                    viewport.view.applyToCamera(viewport.camera)  
+            this.viewports.forEach(viewport=>{
+                if(!viewport.active)return
+                viewport.view.applyToCamera(viewport.camera)  
+                viewport.camera.updateMatrix();
+                viewport.camera.updateMatrixWorld();
+                viewport.camera.matrixWorldInverse.copy(viewport.camera.matrixWorld).invert();
+                 
+            }) 
+		}
+		 
+        this.viewports.forEach(e=>{//判断camera画面是否改变
+            if(e.hasChanged()){
+                this.dispatchEvent({
+                    type: "camera_changed", 
+                    camera: e.camera,
+                    viewport : e
                 })
-                
-            }else{
-                if(typeof debugDisabled === "undefined" ){
-                    scene.view.applyToCamera(this.scene.cameraP)
                  
-                }
-                scene.view.applyToCamera(this.scene.cameraO) 
-                
-            } 
-			 
-		}
-		
-		camera.updateMatrix();
-		camera.updateMatrixWorld();
-		camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
+            }
+        })
          
-		{//判断camera画面是否改变
+        /* {//判断camera画面是否改变
 			if(this._previousCamera === undefined){
 				this._previousCamera = this.scene.getActiveCamera().clone();
 				this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
@@ -1852,11 +1874,8 @@ export class Viewer extends EventDispatcher{
 			this._previousCamera = this.scene.getActiveCamera().clone();
 			this._previousCamera.rotation.copy(this.scene.getActiveCamera().rotation);
 
-		}
+		} */
         
-        {//判断是否改变canvas大小
-            this.updateScreenSize()
-        }
 
 		{ // update clip boxes
 			let boxes = [];
@@ -1927,59 +1946,67 @@ export class Viewer extends EventDispatcher{
 			performance.mark("update-end");
 			performance.measure("update", "update-start", "update-end");
 		}
+        
+        
+        //add ------
+        this.reticule.updateVisible() 
+        this.mapViewer.update(delta)
 
-        this.inputHandler.reticule.updateVisible()//add  
+	}
 
 
-	}
 
+    updateViewPointcloud(camera, areaSize, isViewport){
+        
+ 
+        let result = Potree.updatePointClouds(this.scene.pointclouds,  camera, areaSize );
 
+ 
 
-    updateScreenSize(o={}) { //add 
-          
-        var render = false, ratio, w, h;
-        //记录应当render的大小
-        if (!o.resize && o.width != void 0 && o.height != void 0) {
-            w = o.width
-            h = o.height
-            render = true
-            ratio = 1
-        }else {
-            w = this.renderArea.clientWidth;
-            h = this.renderArea.clientHeight
-            if(o.resize){
-                W = this.renderWidth, H = this.renderHeight 
+        if(isViewport)return
+        const tStart = performance.now();
+        const campos = camera.position;
+        let closestImage = Infinity;
+        for(const images of this.scene.orientedImages){
+            for(const image of images.images){
+                const distance = image.mesh.position.distanceTo(campos);
+
+                closestImage = Math.min(closestImage, distance);
             }
-           
-            if(w !== W || h !== H || this.forceUpdateSize || pixelRatio != window.devicePixelRatio){
-                W = w 
-                H = h 
-                render = true 
-                pixelRatio = window.devicePixelRatio  //如果player放在小窗口了,也要监测devicePixelRatio,因为缩放时client宽高不会改变
-                //config.isMobile ? (ratio = Math.min(window.devicePixelRatio, 2)) : (ratio = window.devicePixelRatio)
-                ratio = window.devicePixelRatio
-            }    
         }
-        if (render) {
-            this.setSize(w, h, ratio);
-            this.forceUpdateSize = !1  
-        } 
-    } 
-    
-    
-    setSize(width, height, devicePixelRatio){//add
+        const tEnd = performance.now();
+
+        if(result.lowestSpacing !== Infinity){
+            let near = result.lowestSpacing * 10.0;
+            let far = -this.getBoundingBox().applyMatrix4(camera.matrixWorldInverse).min.z;
+
+            far = Math.max(far * 1.5, 10000);
+            near = Math.min(100.0, Math.max(0.01, near));
+            near = Math.min(near, closestImage);
+            far = Math.max(far, near + 10000);
+
+            if(near === Infinity){
+                near = 0.1;
+            }
+            
+            camera.near = near;
+            camera.far = far;
+        }else{
+            // don't change near and far in this case
+        }
+
+        if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {
+            camera.near = -camera.far;
+        }
         
-        this.renderer.setSize(width, height, null, devicePixelRatio); //改  为了防止给canvas设置宽高
-        //this.composer.setSize(width, height);
-         
-        this.dispatchEvent({
-            type: 'resize',
-            clientWidth:width, clientHeight:height, devicePixelRatio,
-            canvasWidth:this.renderer.domElement.width,
-            canvasHeight:this.renderer.domElement.height,
-        });
     }
 
+
+
+    
+    
+     
+
 	getPRenderer(){
 		if(this.useHQ){
 			if (!this.hqRenderer) {
@@ -2172,96 +2199,139 @@ export class Viewer extends EventDispatcher{
 
 	}
 
-	renderDefault(params={}){
+	renderDefault(params_={}){
 		let pRenderer = this.getPRenderer();
-        
-        
-        
-		if(!params.target){ // resize
-            const width = params.width || this.scaleFactor * this.renderArea.clientWidth;
-            const height = params.height || this.scaleFactor * this.renderArea.clientHeight;
          
-
-            //this.renderer.setSize(width, height);
         
+        let renderSize = this.renderer.getSize(new THREE.Vector2());
+        let needSResize = this.viewports.length > 1 || params_.resize
         
-            if(this.viewports){
-                this.viewports.forEach(view=>{
-                    if(!view.active)return
-                    var aspect = (this.renderArea.clientWidth * view.width) / (this.renderArea.clientHeight * view.height)
-                    if(view.name == 'default'){
-                        view.camera.aspect = aspect;
-                        view.camera.updateProjectionMatrix();
-                    }else{
-                        view.camera.aspect = aspect;
-                        //不改宽度 同4dkk
-                        var heightHalf = view.camera.right / aspect 
-                        view.camera.top = heightHalf 
-                        view.camera.bottom = -heightHalf 
-                        view.camera.updateProjectionMatrix()
-                    }
-                })
-            }else{
-                const pixelRatio = this.renderer.getPixelRatio();
-                const aspect = width / height;
-
-                const scene = this.scene;
-
-                scene.cameraP.aspect = aspect;
-                scene.cameraP.updateProjectionMatrix();
-
-                let frustumScale = this.scene.view.radius;
-                scene.cameraO.left = -frustumScale;
-                scene.cameraO.right = frustumScale;
-                scene.cameraO.top = frustumScale * 1 / aspect;
-                scene.cameraO.bottom = -frustumScale * 1 / aspect;
-                scene.cameraO.updateProjectionMatrix();
-
-                scene.cameraScreenSpace.top = 1/aspect;
-                scene.cameraScreenSpace.bottom = -1/aspect;
-                scene.cameraScreenSpace.updateProjectionMatrix();
-            }
-           
-		}
-         
-        
+          
         
-        if(this.viewports && !params.target){
-            this.viewports.forEach(view=>{
-                if(!view.active)return
-                var left = Math.floor(this.renderArea.clientWidth * view.left)
-                 , bottom = Math.floor(this.renderArea.clientHeight * view.bottom)
-                 , width = Math.floor(this.renderArea.clientWidth * view.width)
-                 , height = Math.floor(this.renderArea.clientHeight * view.height);
+        this.viewports.forEach(view=>{
+            let params = $.extend({},params_);
+            if(!params.target){
+                params.camera = params.camera || view.camera;
+            }
+            
+            if(!view.active || params.viewport && params.viewport != view)return
+            var left,bottom,width,height
+            if(!params_.target){
+                left = Math.floor(renderSize.x * view.left)
+                 , bottom = Math.floor(renderSize.y * view.bottom)
+                 , width = view.resolution.x
+                 , height = view.resolution.y
                 this.renderer.setViewport(left, bottom, width, height) //规定视口,影响图形变换 
-                this.renderer.setScissor( left, bottom, width, height );//规定渲染范围
-                this.renderer.setScissorTest( view.width<1 || view.height<1 );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
-                params.camera = view.camera;
-                params.width = width; params.height = height;
+                
+                let scissorTest = view.width<1 || view.height<1 
+                scissorTest && this.renderer.setScissor( left, bottom, width, height );//规定渲染范围 
+                this.renderer.setScissorTest( scissorTest );//开启WebGL剪裁测试功能,如果不开启,.setScissor方法设置的范围不起作用 | width==1且height==1时开启会只有鼠标的地方刷新,很奇怪
+             
+            }
+            
+            /* needSResize && this.emitResizeMsg({ //resize everything  such as lines  targets 
+                resolution: new THREE.Vector2(width,height), 
+            }); */
+            needSResize && this.emitResizeMsg(new THREE.Vector2(width,height), new THREE.Vector2(left, bottom/* renderSize.y-bottom-height */),view)
+            
+            viewer.dispatchEvent({type: "render.begin",  viewer: viewer, viewport:view, params });
+            
+            if(view.render){
+               view.render({renderer:this.renderer, renderOverlay: this.renderOverlay.bind(this) })
+            } 
+            
+            
+            
+            
+            if(!view.noPointcloud ){
+                
+                if(!params.target){ 
+                    params.width = width; params.height = height;
+                }
+                
+                
+                
+                this.scene.pointclouds.forEach(e=>{
+                    if(view.differentPointMat){
+                        if(view.name == "MainView"){ 
+                            e.material.activeAttributeName = viewer.matBeforeSplitscreen.colorType 
+                            e.material.color.copy(viewer.matBeforeSplitscreen.color)
+                            e.material.useFilterByNormal = false
+                            e.material.opacity = viewer.matBeforeSplitscreen.opacity 
+                        }else{ 
+                            e.material.activeAttributeName = "color"
+                            e.material.color.set(e.color)
+                            e.material.useFilterByNormal = true
+                            e.material.opacity = 0.09
+                        }
+                    }                 
+                })
+                
+                
+                this.updateViewPointcloud(params.camera, new THREE.Vector2(params.width,params.height), true)
                 pRenderer.clear(params); 
                 pRenderer.render(params);
                 this.renderer.setRenderTarget(null)
-            })
-        }else{
-            pRenderer.clear(params);
-            
-            pRenderer.render(params.target ? params : this.renderer);
-            
-            /* if(!params.target){
-                this.renderer.render(this.overlay,  this.scene.getActiveCamera() );
-            } */
+                
+                 
+            } 
             
-            this.renderer.setRenderTarget(null)//add
-        }
-		
+             
+            if(!view.render){
+                this.renderOverlay(params)
+            }
+            this.dispatchEvent({type: "render.end",  viewer: this, viewport:view  });
+        })
+        
+         
         
         
 	}
 	
+    
+    renderOverlay(params){
+        let camera = params.camera ? params.camera : this.scene.getActiveCamera();
+        
+        if(!params.magnifier){//为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖 
+            camera.layers.set(Potree.config.renderLayers.marker);//透明贴图层 skybox 、reticule marker 不能遮住测量线
+            this.renderer.render(this.scene.scene, camera); 
+        } 
+        this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
+    
+        //清除深度 !!!!
+        this.renderer.clearDepth(); 
+
+        this.transformationTool.update();
+         
+         
+         
+        if(!params.magnifier){ 
+            //测量线
+            this.dispatchEvent({type: "render.pass.perspective_overlay", viewer:this, camera});
+            
+            if(!params.screenshot){
+                camera.layers.set(Potree.config.renderLayers.magnifier);//magnifier 遮住测量线
+                this.renderer.render(this.scene.scene, camera);
+            }
+        } 
+        
+         
+          
+        this.renderer.render(this.clippingTool.sceneVolume, camera);
+        this.renderer.render(this.transformationTool.scene, camera);
+         
+        
+        
+        
+    }
+    
+    
+    
+    
 	render(params){//add params
 		if(Potree.measureTimings) performance.mark("render-start");
 
-		try{
+		//try{
 
 			const vrActive = this.renderer.xr.isPresenting;
 
@@ -2271,9 +2341,9 @@ export class Viewer extends EventDispatcher{
 				this.renderDefault(params);
 			}
 
-		}catch(e){
+		/* }catch(e){
 			this.onCrash(e);
-		}
+		} */
 		
 		if(Potree.measureTimings){
 			performance.mark("render-end");
@@ -2392,7 +2462,7 @@ export class Viewer extends EventDispatcher{
 		}
 
 		this.update(this.clock.getDelta(), timestamp);
-        this.inputHandler.magnifier.render();
+        this.magnifier.render();
 		this.render();
         
         
@@ -2466,16 +2536,114 @@ export class Viewer extends EventDispatcher{
 	}
     
     
+    /* makeScreenshot(camera, size, callback){
+
+		if(camera === undefined || camera === null){
+			camera = this.scene.getActiveCamera();
+		}
+
+		if(size === undefined || size === null){
+			size = this.renderer.getSize(new THREE.Vector2());
+		}
+        let {width, height} = size;
+        const aspect = width / height; 
+        camera.aspect = aspect
+        camera.updateProjectionMatrix() 
+        
+        
+        
+        let oldBudget = Potree.pointBudget;
+        Potree.pointBudget = Math.max(10 * 1000 * 1000, 2 * oldBudget);
+        let result = Potree.updatePointClouds(this.scene.pointclouds, camera, size );
+        Potree.pointBudget = oldBudget;
+        
+         
+		this.dispatchEvent({ //resize everything  such as lines  targets
+            type: 'resize', 
+            resolution: new THREE.Vector2(width,height), 
+        });
+       
+		let target = new THREE.WebGLRenderTarget(width, height, {
+			format: THREE.RGBAFormat,
+		});
+ 
+		// HACK? removed because of error, was this important?
+		  
+		this.renderDefault({
+            target ,
+            camera ,
+            screenshot : true, 
+            width ,
+            height, 
+        });
+
+		let pixelCount = width * height;
+		let buffer = new Uint8Array(4 * pixelCount);
+
+		this.renderer.readRenderTargetPixels(target, 0, 0, width, height, buffer);
+
+        callback && callback(buffer) 
+		target.dispose();
+        
+        //resize back 
+        this.updateScreenSize({forceUpdateSize:true})   
+        
+		return {
+			width: width,
+			height: height,
+			buffer: buffer
+		};
+	} */
+    
+    Screenshot(type, width=800, height=400, compressRatio){//add
+        let viewport,camera
+        if(type == 'mainView'){
+            viewport = this.mainViewport
+        }else if(type == 'map'){
+            viewport = this.mapViewer.viewports[0]
+        }
+         
+        
+        
+        var { buffer  } = this.makeScreenshot(camera, new THREE.Vector2(width,height), viewport);
+        
+        var dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
+        
+        Common.downloadFile(dataUrl, 'screenshot.jpg')
+        
+        
+    }
     
     
+    getBoundingBox (pointclouds) {
+        //可以直接返回viewer.bound
+        if(!this.bound){
+            this.updateModelBound()
+        }
+		return this.bound.boundingBox.clone()//this.scene.getBoundingBox(pointclouds);
+	};
+
+    updateModelBound(){
+        this.bound = Utils.computePointcloudsBound(this.scene.pointclouds)
+             
+    }
     
     
     
     
+    /* attachMapToViewer(state){
+        state ? viewer.mapViewer.attachToMainViewer(state);  
+        
+    } */
     
 };
 
 
+
+
+
+
+
 /* t.prototype.getTransformationMatrix = function(t) {//点云截取   所有点在乘上这个矩阵后, 还能落在 1 * 1 * 1的box内的点就是所裁剪的
             var e = this.ViewService.mainView.getVolumeClippingLayer().getBoxFrame()
               , n = (new o.Matrix4).getInverse(e.matrixWorld)