@eturnity/eturnity_3d 6.34.0 → 6.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.editorconfig +5 -0
  2. package/package.json +8 -4
  3. package/src/App.vue +16 -16
  4. package/src/assets/theme.js +4 -4
  5. package/src/components/ThreeCanvasViewer.vue +56 -43
  6. package/src/config.js +139 -65
  7. package/src/helper/MapView.js +214 -241
  8. package/src/helper/UpdateRoofModuleFieldRelations.js +17 -23
  9. package/src/helper/UpdateRoofObstacleRelations.js +48 -41
  10. package/src/helper/cameraMixin.js +97 -93
  11. package/src/helper/customProvider.js +28 -28
  12. package/src/helper/materialMixin.js +86 -70
  13. package/src/helper/materials.js +64 -49
  14. package/src/helper/render/background.js +2 -5
  15. package/src/helper/render/base.js +43 -40
  16. package/src/helper/render/clear.js +96 -84
  17. package/src/helper/render/edge.js +59 -65
  18. package/src/helper/render/geometryHandler.js +166 -128
  19. package/src/helper/render/imageOverlay.js +157 -106
  20. package/src/helper/render/index.js +21 -3
  21. package/src/helper/render/loader.js +34 -34
  22. package/src/helper/render/mapProjection.js +88 -74
  23. package/src/helper/render/margin.js +46 -50
  24. package/src/helper/render/moduleField.js +26 -24
  25. package/src/helper/render/node.js +43 -43
  26. package/src/helper/render/obstacle.js +50 -48
  27. package/src/helper/render/panel.js +85 -79
  28. package/src/helper/render/projectionMaterial.js +58 -50
  29. package/src/helper/render/roof.js +136 -133
  30. package/src/helper/render/texture.js +17 -17
  31. package/src/helper/render/tile.js +291 -0
  32. package/src/helper/renderMixin.js +30 -37
  33. package/src/helper/threeMixin.js +40 -101
  34. package/src/main.js +22 -18
  35. package/src/store/AddMargin.js +87 -83
  36. package/src/store/hydrateData.js +40 -30
  37. package/src/store/nodesEdgesCreation.js +177 -160
  38. package/src/store/three-d-module.js +41 -27
  39. package/src/utils/cancellablePromise.js +23 -0
  40. package/.eslintrc.json +0 -18
  41. package/src/helper/geo-three.module.js +0 -1903
@@ -1,5 +1,5 @@
1
- import {Mesh, MeshBasicMaterial} from 'three';
2
- import {MapNode,LODRaycast,MapPlaneNode} from 'geo-three';
1
+ import { Mesh, MeshBasicMaterial } from 'three'
2
+ import { MapNode, LODRaycast, MapPlaneNode } from 'geo-three'
3
3
  /**
4
4
  * Map viewer is used to read and display map tiles from a server.
5
5
  *
@@ -7,242 +7,215 @@ import {MapNode,LODRaycast,MapPlaneNode} from 'geo-three';
7
7
  *
8
8
  * The map is drawn in plane map nodes using a quad tree that is subdivided as necessary to guaratee good map quality.
9
9
  */
10
- export class MapView extends Mesh
11
- {
12
- /**
13
- * Planar map projection.
14
- */
15
- PLANAR = 200;
16
-
17
-
18
- mapModes = new Map([
19
- [MapView.PLANAR, MapPlaneNode]
20
- ]);
21
-
22
- /**
23
- * LOD control object used to defined how tiles are loaded in and out of memory.
24
- */
25
- lod = null;
26
-
27
- /**
28
- * Map tile color layer provider.
29
- */
30
- provider = null;
31
-
32
- /**
33
- * Map height (terrain elevation) layer provider.
34
- *
35
- * Only used for HEIGHT, HEIGHT_SHADER and MARTINI map modes.
36
- */
37
- heightProvider = null;
38
-
39
- /**
40
- * Define the type of map node in use, defined how the map is presented.
41
- *
42
- * Should only be set on creation.
43
- */
44
- root = null;
45
-
46
- /**
47
- * Indicate if the nodes should cache its children when it is simplified. Nodes that are no longer in use should be kept in memory.
48
- *
49
- * Usefull for fast moving scenarios to prevent reparsing data in fast moving scenes.
50
- *
51
- * Should only be used if the child generation process is time consuming. Should be kept off unless required.
52
- */
53
- cacheTiles= false;
54
-
55
- /**
56
- * Constructor for the map view objects.
57
- *
58
- * @param root - Map view node modes can be SPHERICAL, HEIGHT or PLANAR. PLANAR is used by default. Can also be a custom MapNode instance.
59
- * @param provider - Map color tile provider by default a OSM maps provider is used if none specified.
60
- * @param heightProvider - Map height tile provider, by default no height provider is used.
61
- */
62
- constructor(root = MapView.PLANAR, provider = new OpenStreetMapsProvider(), heightProvider = null)
63
- {
64
- super(undefined, new MeshBasicMaterial({transparent: true, opacity: 0.0}));
65
- this.lod = new LODRaycast();
66
- this.provider = provider;
67
- this.heightProvider = heightProvider;
68
- this.setRoot(root);
69
- this.preSubdivide();
70
- }
71
-
72
- /**
73
- * Ajust node configuration depending on the camera distance.
74
- *
75
- * Called everytime automatically before render by the renderer.
76
- */
77
- onBeforeRender=(renderer, scene, camera) =>
78
- {
79
- this.lod.updateLOD(this, camera, renderer, scene);
80
- };
81
-
82
- /**
83
- * Set the root of the map view.
84
- *
85
- * Is set by the constructor by default, can be changed in runtime.
86
- *
87
- * @param root - Map node to be used as root.
88
- */
89
- setRoot(root)
90
- {
91
-
92
- if (typeof root === 'number')
93
- {
94
- const rootConstructor = MapPlaneNode//MapView.mapModes.get(root);
95
- // @ts-ignore
96
- root = new rootConstructor(null, this);
97
- }
98
-
99
- // Remove old root
100
- if (!!this.root )
101
- {
102
- this.remove(this.root);
103
- this.root = null;
104
- }
105
-
106
- // @ts-ignore
107
- this.root = root;
108
-
109
- // Initialize root node
110
- if (!!this.root )
111
- {
112
- // @ts-ignore
113
- this.geometry = this.root.constructor.baseGeometry;
114
- // // @ts-ignore
115
- this.scale.copy(this.root.constructor.baseScale);
116
-
117
- this.root.mapView = this;
118
- this.add(this.root);
119
- this.root.initialize();
120
- }
121
- }
122
-
123
- /**
124
- * Pre-subdivide map tree to create nodes of levels not available in the provider.
125
- *
126
- * Checks for the minimum zoom level in the providers attached to the map view.
127
- */
128
- preSubdivide()
129
- {
130
- const minZoom = this.provider.minZoom
131
- const maxZoom = this.provider.maxZoom
132
- function subdivide(node, depth)
133
- {
134
- if (depth <= 0)
135
- {
136
- return;
137
- }
138
-
139
-
140
- node.subdivide();
141
-
142
- for (let i = 0; i < node.children.length; i++)
143
- {
144
- if (node.children[i] instanceof MapNode)
145
- {
146
- const child = node.children[i];
147
- subdivide(child, depth - 1);
148
- }
149
- }
150
- }
151
-
152
-
153
- if (minZoom > 0)
154
- {
155
- subdivide(this.root, minZoom);
156
- }
157
- }
158
-
159
- /**
160
- * Change the map provider of this map view.
161
- *
162
- * Will discard all the tiles already loaded using the old provider.
163
- */
164
- setProvider(provider)
165
- {
166
- if (provider !== this.provider)
167
- {
168
- this.provider = provider;
169
- this.clear();
170
- }
171
- }
172
-
173
- /**
174
- * Change the map height provider of this map view.
175
- *
176
- * Will discard all the tiles already loaded using the old provider.
177
- */
178
- setHeightProvider(heightProvider)
179
- {
180
- if (heightProvider !== this.heightProvider)
181
- {
182
- this.heightProvider = heightProvider;
183
- this.clear();
184
- }
185
- }
186
-
187
- /**
188
- * Clears all tiles from memory and reloads data. Used when changing the provider.
189
- *
190
- * Should be called manually if any changed to the provider are made without setting the provider.
191
- */
192
- clear()
193
- {
194
- this.traverse(function(children)
195
- {
196
- // @ts-ignore
197
- if (children.childrenCache)
198
- {
199
- // @ts-ignore
200
- children.childrenCache = null;
201
- }
202
-
203
- // @ts-ignore
204
- if (children.initialize)
205
- {
206
- // @ts-ignore
207
- children.initialize();
208
- }
209
- });
210
-
211
- return this;
212
- }
213
-
214
- /**
215
- * Get the minimum zoom level available in the providers attached to the map view.
216
- *
217
- * @returns Minimum zoom level available.
218
- */
219
- minZoom()
220
- {
221
- return 15
222
- return Math.max(this.provider.minZoom, -Infinity);
223
- }
224
-
225
- /**
226
- * Get the maximum zoom level available in the providers attached to the map view.
227
- *
228
- * @returns Maximum zoom level available.
229
- */
230
- maxZoom()
231
- {
232
- return 18
233
- return Math.min(this.provider.maxZoom, Infinity);
234
- }
235
-
236
- /**
237
- * Get map meta data from server if supported.
238
- */
239
- getMetaData()
240
- {
241
- this.provider.getMetaData();
242
- }
243
-
244
- raycast(raycaster, intersects)
245
- {
246
- return false;
247
- }
248
- }
10
+ export class MapView extends Mesh {
11
+ /**
12
+ * Planar map projection.
13
+ */
14
+ PLANAR = 200
15
+
16
+ mapModes = new Map([[MapView.PLANAR, MapPlaneNode]])
17
+
18
+ /**
19
+ * LOD control object used to defined how tiles are loaded in and out of memory.
20
+ */
21
+ lod = null
22
+
23
+ /**
24
+ * Map tile color layer provider.
25
+ */
26
+ provider = null
27
+
28
+ /**
29
+ * Map height (terrain elevation) layer provider.
30
+ *
31
+ * Only used for HEIGHT, HEIGHT_SHADER and MARTINI map modes.
32
+ */
33
+ heightProvider = null
34
+
35
+ /**
36
+ * Define the type of map node in use, defined how the map is presented.
37
+ *
38
+ * Should only be set on creation.
39
+ */
40
+ root = null
41
+
42
+ /**
43
+ * Indicate if the nodes should cache its children when it is simplified. Nodes that are no longer in use should be kept in memory.
44
+ *
45
+ * Usefull for fast moving scenarios to prevent reparsing data in fast moving scenes.
46
+ *
47
+ * Should only be used if the child generation process is time consuming. Should be kept off unless required.
48
+ */
49
+ cacheTiles = false
50
+
51
+ /**
52
+ * Constructor for the map view objects.
53
+ *
54
+ * @param root - Map view node modes can be SPHERICAL, HEIGHT or PLANAR. PLANAR is used by default. Can also be a custom MapNode instance.
55
+ * @param provider - Map color tile provider by default a OSM maps provider is used if none specified.
56
+ * @param heightProvider - Map height tile provider, by default no height provider is used.
57
+ */
58
+ constructor(
59
+ root = MapView.PLANAR,
60
+ provider = new OpenStreetMapsProvider(),
61
+ heightProvider = null
62
+ ) {
63
+ super(undefined, new MeshBasicMaterial({ transparent: true, opacity: 0.0 }))
64
+ this.lod = new LODRaycast()
65
+ this.provider = provider
66
+ this.heightProvider = heightProvider
67
+ this.setRoot(root)
68
+ this.preSubdivide()
69
+ }
70
+
71
+ /**
72
+ * Ajust node configuration depending on the camera distance.
73
+ *
74
+ * Called everytime automatically before render by the renderer.
75
+ */
76
+ onBeforeRender = (renderer, scene, camera) => {
77
+ this.lod.updateLOD(this, camera, renderer, scene)
78
+ }
79
+
80
+ /**
81
+ * Set the root of the map view.
82
+ *
83
+ * Is set by the constructor by default, can be changed in runtime.
84
+ *
85
+ * @param root - Map node to be used as root.
86
+ */
87
+ setRoot(root) {
88
+ if (typeof root === 'number') {
89
+ const rootConstructor = MapPlaneNode //MapView.mapModes.get(root);
90
+ // @ts-ignore
91
+ root = new rootConstructor(null, this)
92
+ }
93
+
94
+ // Remove old root
95
+ if (!!this.root) {
96
+ this.remove(this.root)
97
+ this.root = null
98
+ }
99
+
100
+ // @ts-ignore
101
+ this.root = root
102
+
103
+ // Initialize root node
104
+ if (!!this.root) {
105
+ // @ts-ignore
106
+ this.geometry = this.root.constructor.baseGeometry
107
+ // // @ts-ignore
108
+ this.scale.copy(this.root.constructor.baseScale)
109
+
110
+ this.root.mapView = this
111
+ this.add(this.root)
112
+ this.root.initialize()
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Pre-subdivide map tree to create nodes of levels not available in the provider.
118
+ *
119
+ * Checks for the minimum zoom level in the providers attached to the map view.
120
+ */
121
+ preSubdivide() {
122
+ const minZoom = this.provider.minZoom
123
+ const maxZoom = this.provider.maxZoom
124
+ function subdivide(node, depth) {
125
+ if (depth <= 0) {
126
+ return
127
+ }
128
+
129
+ node.subdivide()
130
+
131
+ for (let i = 0; i < node.children.length; i++) {
132
+ if (node.children[i] instanceof MapNode) {
133
+ const child = node.children[i]
134
+ subdivide(child, depth - 1)
135
+ }
136
+ }
137
+ }
138
+
139
+ if (minZoom > 0) {
140
+ subdivide(this.root, minZoom)
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Change the map provider of this map view.
146
+ *
147
+ * Will discard all the tiles already loaded using the old provider.
148
+ */
149
+ setProvider(provider) {
150
+ if (provider !== this.provider) {
151
+ this.provider = provider
152
+ this.clear()
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Change the map height provider of this map view.
158
+ *
159
+ * Will discard all the tiles already loaded using the old provider.
160
+ */
161
+ setHeightProvider(heightProvider) {
162
+ if (heightProvider !== this.heightProvider) {
163
+ this.heightProvider = heightProvider
164
+ this.clear()
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Clears all tiles from memory and reloads data. Used when changing the provider.
170
+ *
171
+ * Should be called manually if any changed to the provider are made without setting the provider.
172
+ */
173
+ clear() {
174
+ this.traverse(function (children) {
175
+ // @ts-ignore
176
+ if (children.childrenCache) {
177
+ // @ts-ignore
178
+ children.childrenCache = null
179
+ }
180
+
181
+ // @ts-ignore
182
+ if (children.initialize) {
183
+ // @ts-ignore
184
+ children.initialize()
185
+ }
186
+ })
187
+
188
+ return this
189
+ }
190
+
191
+ /**
192
+ * Get the minimum zoom level available in the providers attached to the map view.
193
+ *
194
+ * @returns Minimum zoom level available.
195
+ */
196
+ minZoom() {
197
+ return 15
198
+ return Math.max(this.provider.minZoom, -Infinity)
199
+ }
200
+
201
+ /**
202
+ * Get the maximum zoom level available in the providers attached to the map view.
203
+ *
204
+ * @returns Maximum zoom level available.
205
+ */
206
+ maxZoom() {
207
+ return 18
208
+ return Math.min(this.provider.maxZoom, Infinity)
209
+ }
210
+
211
+ /**
212
+ * Get map meta data from server if supported.
213
+ */
214
+ getMetaData() {
215
+ this.provider.getMetaData()
216
+ }
217
+
218
+ raycast(raycaster, intersects) {
219
+ return false
220
+ }
221
+ }
@@ -9,7 +9,7 @@ export function UpdateRoofModuleFieldRelations(state) {
9
9
  const roofPolygons = state.polygons.filter((poly) => poly.layer == 'roof')
10
10
  const moduleFieldPolygons = state.polygons.filter(
11
11
  (poly) => poly.layer == 'moduleField'
12
- )
12
+ )
13
13
  const panelPolygons = state.polygons.filter((poly) =>
14
14
  ['panel', 'user_deactivated_panel'].includes(poly.layer)
15
15
  )
@@ -30,20 +30,14 @@ export function UpdateRoofModuleFieldRelations(state) {
30
30
 
31
31
  for (let k in moduleFieldPolygons) {
32
32
  const moduleField = moduleFieldPolygons[k]
33
- const moduleFieldArea=calculateArea(moduleField.outline)
33
+ const moduleFieldArea = calculateArea(moduleField.outline)
34
34
  //check if everypoint is in the same roof and if they are not too far from the flat surface.(at least above)
35
- let roofPolygonCandidates = roofPolygons.filter((roof) =>
36
- {
37
- const intersection=intersectOutlines(
38
- moduleField.outline,
39
- roof.outline
40
- )
41
- if(intersection.length==0) return false
42
- const intersectionArea=calculateArea(intersection[0])
43
- return intersectionArea>0.9*moduleFieldArea
44
-
45
- }
46
- )
35
+ let roofPolygonCandidates = roofPolygons.filter((roof) => {
36
+ const intersection = intersectOutlines(moduleField.outline, roof.outline)
37
+ if (intersection.length == 0) return false
38
+ const intersectionArea = calculateArea(intersection[0])
39
+ return intersectionArea > 0.9 * moduleFieldArea
40
+ })
47
41
  //roofs on roof can lead to multiple roof under a point. moduleField is in the smallest
48
42
  let smallestRoof = null
49
43
  for (let roof of roofPolygonCandidates) {
@@ -56,14 +50,14 @@ export function UpdateRoofModuleFieldRelations(state) {
56
50
  //no roof found under first node of moduleField => moduleField will be deleted
57
51
  continue
58
52
  }
59
- roofPolygon.moduleFields.push(moduleField)
60
- moduleField.roof = roofPolygon
61
- moduleField.panels.forEach((panel) => (panel.roof = roofPolygon))
62
- panelPolygons.forEach((p) => {
63
- if (p.moduleField.id == moduleField.id) {
64
- p.roof = roofPolygon
65
- }
66
- })
53
+ roofPolygon.moduleFields.push(moduleField)
54
+ moduleField.roof = roofPolygon
55
+ moduleField.panels.forEach((panel) => (panel.roof = roofPolygon))
56
+ panelPolygons.forEach((p) => {
57
+ if (p.moduleField.id == moduleField.id) {
58
+ p.roof = roofPolygon
59
+ }
60
+ })
67
61
  //}
68
62
  }
69
63
 
@@ -98,7 +92,7 @@ export function removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state) {
98
92
  const remainingUserDeactivatedPanels = state.polygons.filter(
99
93
  (polygon) => polygon.layer == 'user_deactivated_panel' && !!polygon.roof
100
94
  )
101
-
95
+
102
96
  state.polygons = [
103
97
  ...remainingPolygons,
104
98
  ...remainingModuleFields,
@@ -2,17 +2,15 @@ import {
2
2
  verticalProjectionOnPlane,
3
3
  calculateArea
4
4
  } from '@eturnity/eturnity_maths'
5
- import {
6
- intersectOutlines
7
- } from '@eturnity/eturnity_maths'
5
+ import { intersectOutlines } from '@eturnity/eturnity_maths'
8
6
  //this function just update the "roof" and "holes" properties of roofs and obstacles
9
- export function UpdateRoofObstacleRelations(state,updateVersionEnable=true) {
7
+ export function UpdateRoofObstacleRelations(state, updateVersionEnable = true) {
10
8
  //let's remove all holes from roofs which are not obstacle then check for every obstacle and add them to roofs
11
9
  const roofPolygons = state.polygons.filter((poly) => poly.layer == 'roof')
12
- const initialRelation={}
10
+ const initialRelation = {}
13
11
 
14
12
  roofPolygons.forEach((roofPolygon) => {
15
- initialRelation[roofPolygon.id]=[]
13
+ initialRelation[roofPolygon.id] = []
16
14
  //breaking circular reference for memory management
17
15
  for (let k in roofPolygon.holes) {
18
16
  initialRelation[roofPolygon.id].push(roofPolygon.holes.id)
@@ -21,60 +19,69 @@ export function UpdateRoofObstacleRelations(state,updateVersionEnable=true) {
21
19
  roofPolygon.holes = []
22
20
  })
23
21
  const holePolygons = state.polygons.filter((poly) =>
24
- ['roof','obstacle'].includes(poly.layer)
22
+ ['roof', 'obstacle'].includes(poly.layer)
25
23
  )
26
-
24
+
27
25
  holePolygons.forEach((obstacle) => {
28
26
  //breaking circular reference for memory management
29
27
  for (let k in obstacle.roofs) {
30
28
  obstacle.roofs[k] = null
31
29
  }
32
30
  obstacle.roofs = []
33
-
34
- let roofsWithObstacle=roofPolygons.filter(roof=>{
35
- let intersection=intersectOutlines(obstacle.outline,roof.outline)[0]||[]
36
- if(intersection.length==0)return false
37
- if(obstacle.layer=='obstacle')return true
38
31
 
39
- let deltaArea=calculateArea(roof.outline)-calculateArea(intersection)
40
- if(deltaArea<100)return false
32
+ let roofsWithObstacle = roofPolygons.filter((roof) => {
33
+ let intersection =
34
+ intersectOutlines(obstacle.outline, roof.outline)[0] || []
35
+ if (intersection.length == 0) return false
36
+ if (obstacle.layer == 'obstacle') return true
37
+
38
+ let deltaArea = calculateArea(roof.outline) - calculateArea(intersection)
39
+ if (deltaArea < 100) return false
41
40
  return true
42
41
  })
43
-
44
- let heightReference = 0
45
- for (let roof of roofsWithObstacle) {
46
-
47
- heightReference = obstacle.outline.reduce((acc,cur)=>{
48
- acc=Math.max(
49
- acc,
50
- verticalProjectionOnPlane(cur, roof.normalVector, roof.flatOutline[0])
51
- .z
52
- )
53
- return acc
54
- },0)
55
-
56
- if (!obstacle.roofs.map((r) => r.id).includes(roof.id) && obstacle.id!=roof.id) {
57
- obstacle.roofs.push(roof)
58
- }
59
- if (!roof.holes.map((h) => h.id).includes(obstacle.id) && obstacle.id!=roof.id) {
60
- roof.holes.push(obstacle)
61
- }
42
+
43
+ let heightReference = 0
44
+ for (let roof of roofsWithObstacle) {
45
+ heightReference = obstacle.outline.reduce((acc, cur) => {
46
+ acc = Math.max(
47
+ acc,
48
+ verticalProjectionOnPlane(cur, roof.normalVector, roof.flatOutline[0])
49
+ .z
50
+ )
51
+ return acc
52
+ }, 0)
53
+
54
+ if (
55
+ !obstacle.roofs.map((r) => r.id).includes(roof.id) &&
56
+ obstacle.id != roof.id
57
+ ) {
58
+ obstacle.roofs.push(roof)
59
+ }
60
+ if (
61
+ !roof.holes.map((h) => h.id).includes(obstacle.id) &&
62
+ obstacle.id != roof.id
63
+ ) {
64
+ roof.holes.push(obstacle)
62
65
  }
63
- obstacle.heightReference = heightReference
64
-
65
-
66
+ }
67
+ obstacle.heightReference = heightReference
66
68
  })
67
69
 
68
- roofPolygons.forEach((roof)=>{
69
- if(roof.holes.map(h=>h.id).sort().join()!=initialRelation[roof.id].sort().join()){
70
- if(updateVersionEnable){
70
+ roofPolygons.forEach((roof) => {
71
+ if (
72
+ roof.holes
73
+ .map((h) => h.id)
74
+ .sort()
75
+ .join() != initialRelation[roof.id].sort().join()
76
+ ) {
77
+ if (updateVersionEnable) {
71
78
  roof.version++
72
79
  }
73
80
  }
74
81
  })
75
82
 
76
83
  state = removeStandaloneObstacles(state)
77
-
84
+
78
85
  return state
79
86
  }
80
87