@eturnity/eturnity_3d 0.0.4

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 (78) hide show
  1. package/.babelrc +3 -0
  2. package/.env +0 -0
  3. package/.eslintrc +18 -0
  4. package/.eslintrc.json +18 -0
  5. package/.prettierrc +7 -0
  6. package/Dockerfile +17 -0
  7. package/README.md +18 -0
  8. package/bitbucket-pipelines.yml +681 -0
  9. package/dist/assets/images/panels/longiSolarLR4_60HPH_350M.png +0 -0
  10. package/dist/assets/images/panels/longiSolarLR4_60HPH_370M.png +0 -0
  11. package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw copy.png +0 -0
  12. package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
  13. package/dist/assets/images/panels/uv.png +0 -0
  14. package/dist/assets/panels/longiSolarLR4_60HPH_350M.png +0 -0
  15. package/dist/assets/panels/longiSolarLR4_60HPH_370M.png +0 -0
  16. package/dist/assets/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
  17. package/dist/assets/panels/uv.png +0 -0
  18. package/dist/assets/theme.js +43 -0
  19. package/dist/assets/vue.svg +1 -0
  20. package/dist/css/main.1f8fe45d.css +1 -0
  21. package/dist/img/longiSolarLR4_60HPH_350M.85a84b2e.png +0 -0
  22. package/dist/img/longiSolarLR4_60HPH_370M.bf6b1f4e.png +0 -0
  23. package/dist/img/reneSola_Virtus_2_JC320S_24_Bbw.8b1892e0.png +0 -0
  24. package/dist/index.html +26 -0
  25. package/dist/main.js +60230 -0
  26. package/dist/main.js.map +1 -0
  27. package/dist/vite.svg +1 -0
  28. package/docker_conf/nginx/nginx.conf +16 -0
  29. package/index.html +26 -0
  30. package/package.json +71 -0
  31. package/postcss.config.js +1 -0
  32. package/preview.html +55 -0
  33. package/public/assets/images/panels/longiSolarLR4_60HPH_350M.png +0 -0
  34. package/public/assets/images/panels/longiSolarLR4_60HPH_370M.png +0 -0
  35. package/public/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw copy.png +0 -0
  36. package/public/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
  37. package/public/assets/images/panels/uv.png +0 -0
  38. package/public/assets/panels/longiSolarLR4_60HPH_350M.png +0 -0
  39. package/public/assets/panels/longiSolarLR4_60HPH_370M.png +0 -0
  40. package/public/assets/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
  41. package/public/assets/panels/uv.png +0 -0
  42. package/public/assets/theme.js +43 -0
  43. package/public/assets/vue.svg +1 -0
  44. package/public/vite.svg +1 -0
  45. package/server.js +17 -0
  46. package/src/App.vue +28 -0
  47. package/src/assets/images/panels/longiSolarLR4_60HPH_350M.png +0 -0
  48. package/src/assets/images/panels/longiSolarLR4_60HPH_370M.png +0 -0
  49. package/src/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw copy.png +0 -0
  50. package/src/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
  51. package/src/assets/images/panels/uv.png +0 -0
  52. package/src/assets/images/white_tile.png +0 -0
  53. package/src/assets/theme.js +43 -0
  54. package/src/components/ThreeCanvasViewer.vue +247 -0
  55. package/src/config.js +104 -0
  56. package/src/functions.js +2 -0
  57. package/src/helper/DFS.js +80 -0
  58. package/src/helper/MapView.js +253 -0
  59. package/src/helper/UpdateRoofModuleFieldRelations.js +119 -0
  60. package/src/helper/UpdateRoofObstacleRelations.js +86 -0
  61. package/src/helper/clearThreeObjects.js +21 -0
  62. package/src/helper/customProvider.js +57 -0
  63. package/src/helper/geometryHandler.js +606 -0
  64. package/src/helper/graphCreation.js +43 -0
  65. package/src/helper/materials.js +55 -0
  66. package/src/helper/projectedMaterial.js +502 -0
  67. package/src/helper/renderMixin.js +1132 -0
  68. package/src/helper/threeMixin.js +171 -0
  69. package/src/main.js +28 -0
  70. package/src/store/AddMargin.js +107 -0
  71. package/src/store/hydrateData.js +209 -0
  72. package/src/store/nodesEdgesCreation.js +216 -0
  73. package/src/store/store.js +10 -0
  74. package/src/store/three-d-module.js +142 -0
  75. package/src/style.css +96 -0
  76. package/src/utils/layers.js +265 -0
  77. package/src/utils/leaflet-config.service.js +67 -0
  78. package/vue.config.js +46 -0
@@ -0,0 +1,253 @@
1
+ import {Mesh, MeshBasicMaterial} from 'three';
2
+ import {MapNode,LODRaycast,MapPlaneNode} from 'geo-three';
3
+ /**
4
+ * Map viewer is used to read and display map tiles from a server.
5
+ *
6
+ * It was designed to work with a OpenMapTiles but can also be used with another map tiles.
7
+ *
8
+ * The map is drawn in plane map nodes using a quad tree that is subdivided as necessary to guaratee good map quality.
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
+ console.log('root',root)
92
+
93
+ if (typeof root === 'number')
94
+ {
95
+ const rootConstructor = MapPlaneNode//MapView.mapModes.get(root);
96
+ console.log('rootConstructor',rootConstructor)
97
+ // @ts-ignore
98
+ root = new rootConstructor(null, this);
99
+ }
100
+ console.log(root)
101
+
102
+ // Remove old root
103
+ if (!!this.root )
104
+ {
105
+ this.remove(this.root);
106
+ this.root = null;
107
+ }
108
+
109
+ // @ts-ignore
110
+ this.root = root;
111
+
112
+ // Initialize root node
113
+ if (!!this.root )
114
+ {
115
+ // @ts-ignore
116
+ this.geometry = this.root.constructor.baseGeometry;
117
+ // // @ts-ignore
118
+ this.scale.copy(this.root.constructor.baseScale);
119
+
120
+ this.root.mapView = this;
121
+ this.add(this.root);
122
+ this.root.initialize();
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Pre-subdivide map tree to create nodes of levels not available in the provider.
128
+ *
129
+ * Checks for the minimum zoom level in the providers attached to the map view.
130
+ */
131
+ preSubdivide()
132
+ {
133
+ console.log('preSbdivide')
134
+ const minZoom = this.provider.minZoom
135
+ const maxZoom = this.provider.maxZoom
136
+ function subdivide(node, depth)
137
+ {
138
+ if (depth <= 0)
139
+ {
140
+ return;
141
+ }
142
+
143
+
144
+ node.subdivide();
145
+
146
+ for (let i = 0; i < node.children.length; i++)
147
+ {
148
+ if (node.children[i] instanceof MapNode)
149
+ {
150
+ const child = node.children[i];
151
+ subdivide(child, depth - 1);
152
+ }
153
+ }
154
+ }
155
+
156
+
157
+ console.log("minmax zoom",minZoom,maxZoom)
158
+ if (minZoom > 0)
159
+ {
160
+ subdivide(this.root, minZoom);
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Change the map provider of this map view.
166
+ *
167
+ * Will discard all the tiles already loaded using the old provider.
168
+ */
169
+ setProvider(provider)
170
+ {
171
+ if (provider !== this.provider)
172
+ {
173
+ this.provider = provider;
174
+ this.clear();
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Change the map height provider of this map view.
180
+ *
181
+ * Will discard all the tiles already loaded using the old provider.
182
+ */
183
+ setHeightProvider(heightProvider)
184
+ {
185
+ if (heightProvider !== this.heightProvider)
186
+ {
187
+ this.heightProvider = heightProvider;
188
+ this.clear();
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Clears all tiles from memory and reloads data. Used when changing the provider.
194
+ *
195
+ * Should be called manually if any changed to the provider are made without setting the provider.
196
+ */
197
+ clear()
198
+ {
199
+ this.traverse(function(children)
200
+ {
201
+ // @ts-ignore
202
+ if (children.childrenCache)
203
+ {
204
+ // @ts-ignore
205
+ children.childrenCache = null;
206
+ }
207
+
208
+ // @ts-ignore
209
+ if (children.initialize)
210
+ {
211
+ // @ts-ignore
212
+ children.initialize();
213
+ }
214
+ });
215
+
216
+ return this;
217
+ }
218
+
219
+ /**
220
+ * Get the minimum zoom level available in the providers attached to the map view.
221
+ *
222
+ * @returns Minimum zoom level available.
223
+ */
224
+ minZoom()
225
+ {
226
+ return 15
227
+ return Math.max(this.provider.minZoom, -Infinity);
228
+ }
229
+
230
+ /**
231
+ * Get the maximum zoom level available in the providers attached to the map view.
232
+ *
233
+ * @returns Maximum zoom level available.
234
+ */
235
+ maxZoom()
236
+ {
237
+ return 18
238
+ return Math.min(this.provider.maxZoom, Infinity);
239
+ }
240
+
241
+ /**
242
+ * Get map meta data from server if supported.
243
+ */
244
+ getMetaData()
245
+ {
246
+ this.provider.getMetaData();
247
+ }
248
+
249
+ raycast(raycaster, intersects)
250
+ {
251
+ return false;
252
+ }
253
+ }
@@ -0,0 +1,119 @@
1
+ import {
2
+ isInsidePolygon,
3
+ verticalProjectionOnPlane,
4
+ } from '@eturnity/eturnity_maths'
5
+ //this function just update the "roof" and "moduleField(s)" properties of panels,moduleFields and roofs
6
+ export function UpdateRoofModuleFieldRelations(state) {
7
+ const roofPolygons = state.polygons.filter((poly) => poly.layer == 'roof')
8
+ const moduleFieldPolygons = state.polygons.filter(
9
+ (poly) => poly.layer == 'moduleField'
10
+ )
11
+ const panelPolygons = state.polygons.filter((poly) =>
12
+ ['panel', 'user_deactivated_panel'].includes(poly.layer)
13
+ )
14
+ //let's remove all moduleFields from roofs
15
+ roofPolygons.forEach((roofPolygon) => {
16
+ //breaking circular reference for memory management
17
+ for (let k in roofPolygon.moduleFields) {
18
+ roofPolygon.moduleFields[k] = null
19
+ }
20
+ roofPolygon.moduleFields = []
21
+ })
22
+ moduleFieldPolygons.forEach((moduleFieldPolygon) => {
23
+ moduleFieldPolygon.roof = null
24
+ })
25
+ panelPolygons.forEach((panelPolygon) => {
26
+ panelPolygon.roof = null
27
+ })
28
+
29
+ for (let k in moduleFieldPolygons) {
30
+ const moduleField = moduleFieldPolygons[k]
31
+ //check if everypoint is in the same roof and if they are not too far from the flat surface.(at least above)
32
+ const roofPolygonCandidates = roofPolygons.filter((roof) =>
33
+ {
34
+ return moduleField.outline.every(p=>isInsidePolygon(p, roof.margins.innerOutline))
35
+ }
36
+ )
37
+ //roofs on roof can lead to multiple roof under a point. moduleField is in the smallest
38
+ let smallestRoof = null
39
+ for (let roof of roofPolygonCandidates) {
40
+ if (!smallestRoof || smallestRoof.area > roof.area) {
41
+ smallestRoof = roof
42
+ }
43
+ }
44
+ let roofPolygon = smallestRoof
45
+
46
+ if (!roofPolygon) {
47
+ //no roof found under first node of moduleField => moduleField will be deleted
48
+ continue
49
+ }
50
+ let moduleFieldBelongsToRoof = true
51
+ moduleField.outline.forEach((p) => {
52
+ const distanceToFlatRoof =
53
+ p.z -
54
+ verticalProjectionOnPlane(
55
+ p,
56
+ roofPolygon.normalVector,
57
+ roofPolygon.flatOutline[0]
58
+ ).z
59
+ if (
60
+ !isInsidePolygon(p, roofPolygon.margins.innerOutline) ||
61
+ distanceToFlatRoof < -1 ||
62
+ distanceToFlatRoof > 50
63
+ ) {
64
+ // one point from moduleField is not inside the roof or too far from it's flat surface => moduleField will be deleted
65
+ moduleFieldBelongsToRoof = false
66
+ }
67
+ })
68
+ if (moduleFieldBelongsToRoof) {
69
+ roofPolygon.moduleFields.push(moduleField)
70
+ moduleField.roof = roofPolygon
71
+ moduleField.panels.forEach((panel) => (panel.roof = roofPolygon))
72
+ panelPolygons.forEach((p) => {
73
+ if (p.moduleField.id == moduleField.id) {
74
+ p.roof = roofPolygon
75
+ }
76
+ })
77
+ }
78
+ }
79
+
80
+ let newPolygons = state.polygons.map((p) => {
81
+ if (
82
+ !['roof', 'moduleField', 'panel', 'user_deactivated_panel'].includes(
83
+ p.layer
84
+ )
85
+ )
86
+ return p
87
+ if (p.layer == 'roof') return roofPolygons.find((r) => r.id == p.id)
88
+ if (p.layer == 'moduleField')
89
+ return moduleFieldPolygons.find((mf) => mf.id == p.id)
90
+ if (['panel', 'user_deactivated_panel'].includes(p.layer))
91
+ return panelPolygons.find((panel) => panel.id == p.id)
92
+ })
93
+ state = { ...state, polygons: newPolygons }
94
+ state = removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state)
95
+ return state
96
+ }
97
+
98
+ export function removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state) {
99
+ const remainingPolygons = state.polygons.filter((polygon) =>
100
+ ['roof', 'obstacle'].includes(polygon.layer)
101
+ )
102
+ const remainingModuleFields = state.polygons.filter(
103
+ (polygon) => polygon.layer == 'moduleField' && !!polygon.roof
104
+ )
105
+ const remainingPanels = state.polygons.filter(
106
+ (polygon) => polygon.layer == 'panel' && !!polygon.roof
107
+ )
108
+ const remainingUserDeactivatedPanels = state.polygons.filter(
109
+ (polygon) => polygon.layer == 'user_deactivated_panel' && !!polygon.roof
110
+ )
111
+
112
+ state.polygons = [
113
+ ...remainingPolygons,
114
+ ...remainingModuleFields,
115
+ ...remainingPanels,
116
+ ...remainingUserDeactivatedPanels
117
+ ]
118
+ return state
119
+ }
@@ -0,0 +1,86 @@
1
+ import {
2
+ verticalProjectionOnPlane,
3
+ calculateArea
4
+ } from '@eturnity/eturnity_maths'
5
+ import {
6
+ intersectOutlines
7
+ } from '@eturnity/eturnity_maths'
8
+ //this function just update the "roof" and "holes" properties of roofs and obstacles
9
+ export function UpdateRoofObstacleRelations(state,updateVersionEnable=true) {
10
+ //let's remove all holes from roofs which are not obstacle then check for every obstacle and add them to roofs
11
+ const roofPolygons = state.polygons.filter((poly) => poly.layer == 'roof')
12
+ const initialRelation={}
13
+
14
+ roofPolygons.forEach((roofPolygon) => {
15
+ initialRelation[roofPolygon.id]=[]
16
+ //breaking circular reference for memory management
17
+ for (let k in roofPolygon.holes) {
18
+ initialRelation[roofPolygon.id].push(roofPolygon.holes.id)
19
+ roofPolygon.holes[k] = null
20
+ }
21
+ roofPolygon.holes = []
22
+ })
23
+ const holePolygons = state.polygons.filter((poly) =>
24
+ ['roof','obstacle'].includes(poly.layer)
25
+ )
26
+
27
+ holePolygons.forEach((obstacle) => {
28
+ //breaking circular reference for memory management
29
+ for (let k in obstacle.roofs) {
30
+ obstacle.roofs[k] = null
31
+ }
32
+ 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
+
39
+ let deltaArea=calculateArea(roof.outline)-calculateArea(intersection)
40
+ if(deltaArea<100)return false
41
+ return true
42
+ })
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
+ }
62
+ }
63
+ obstacle.heightReference = heightReference
64
+
65
+
66
+ })
67
+
68
+ roofPolygons.forEach((roof)=>{
69
+ if(roof.holes.map(h=>h.id).sort().join()!=initialRelation[roof.id].sort().join()){
70
+ if(updateVersionEnable){
71
+ roof.version++
72
+ }
73
+ }
74
+ })
75
+
76
+ state = removeStandaloneObstacles(state)
77
+
78
+ return state
79
+ }
80
+
81
+ export function removeStandaloneObstacles(state) {
82
+ state.polygons = state.polygons.filter(
83
+ (polygon) => polygon.layer != 'obstacle' || polygon.roofs.length > 0
84
+ )
85
+ return state
86
+ }
@@ -0,0 +1,21 @@
1
+ export default function clearThreeObject(obj) {
2
+ while (obj.children.length > 0) {
3
+ clearThreeObject(obj.children[0])
4
+ obj.remove(obj.children[0])
5
+ }
6
+ if (obj.geometry) obj.geometry.dispose()
7
+ if (obj.texture) obj.texture.dispose()
8
+
9
+ if (obj.material) {
10
+ //in case of map, bumpMap, normalMap, envMap ...
11
+ Object.keys(obj.material).forEach((prop) => {
12
+ if (!obj.material[prop]) return
13
+ if (
14
+ obj.material[prop] !== null &&
15
+ typeof obj.material[prop].dispose === 'function'
16
+ )
17
+ obj.material[prop].dispose()
18
+ })
19
+ obj.material.dispose()
20
+ }
21
+ }
@@ -0,0 +1,57 @@
1
+ import {
2
+ MapProvider,
3
+ } from 'geo-three'
4
+ import getLayers from '../utils/layers'
5
+ export class CustomProvider extends MapProvider {
6
+ constructor(address, map_layer) {
7
+ super()
8
+
9
+ const layer = getLayers().find((layer) => layer.key == map_layer)
10
+ this.layer = layer
11
+ // if (layer && layer.layerData && layer.layerData.options) {
12
+ // this.minZoom = layer.layerData.options.minZoom || 9
13
+ // this.maxZoom = layer.layerData.options.maxNativeZoom || 21
14
+ // } else {
15
+ // this.minZoom = 9
16
+ // this.maxZoom = 21
17
+ // }
18
+ this.defaultImage = document.createElement('img')
19
+ this.defaultImage.src=require('../assets/images/white_tile.png')
20
+ this.defaultImage.crossOrigin = 'Anonymous'
21
+ this.url = layer
22
+ ? layer.layerData._url
23
+ : 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'
24
+ this.address = address
25
+ }
26
+
27
+ fetchTile(zoom, x, y) {
28
+ const minZoomLayer = this.layer.layerData.options.minZoom || 9
29
+ const maxZoomLayer = this.layer.layerData.options.maxNativeZoom || 20
30
+ return new Promise((resolve, reject) => {
31
+
32
+ if (zoom < minZoomLayer) {
33
+ resolve(this.defaultImage)
34
+ } else if(zoom > maxZoomLayer){
35
+
36
+ }
37
+ else {
38
+ var image = document.createElement('img')
39
+ image.onload = function () {
40
+ resolve(image)
41
+ }
42
+ image.onerror = function () {
43
+ resolve(this.defaultImage)
44
+ }
45
+ image.crossOrigin = 'Anonymous'
46
+ let imageSrc = this.url
47
+ imageSrc = imageSrc.replace('{x}', x)
48
+ imageSrc = imageSrc.replace('{y}', y)
49
+ imageSrc = imageSrc.replace('{z}', zoom)
50
+ imageSrc = imageSrc.replace('{s}', 'a')
51
+ imageSrc = imageSrc.replace('{format}', 'image/png')
52
+ imageSrc = imageSrc.replace('{tileMatrixSet}', 'PM')
53
+ image.src = imageSrc
54
+ }
55
+ })
56
+ }
57
+ }