@eturnity/eturnity_3d 7.2.4 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_3d",
3
3
  "private": false,
4
- "version": "7.2.4",
4
+ "version": "7.4.0",
5
5
  "main": "dist/main.js",
6
6
  "scripts": {
7
7
  "dev": "vue-cli-service serve --skip-plugins @vue/cli-plugin-eslint",
@@ -10,7 +10,7 @@
10
10
  "prettier": "prettier --write \"**/*.{js,vue}\""
11
11
  },
12
12
  "dependencies": {
13
- "@eturnity/eturnity_maths": "7.2.3",
13
+ "@eturnity/eturnity_maths": "7.4.0",
14
14
  "core-js": "^2.6.12",
15
15
  "cors": "^2.8.5",
16
16
  "earcut": "^2.2.4",
@@ -25,15 +25,6 @@ export default {
25
25
  data() {
26
26
  return {
27
27
  scene: new THREE.Scene(),
28
- camera: new THREE.PerspectiveCamera(50, 300 / 300, 0.1, 100000),
29
- orthographicCamera: new THREE.OrthographicCamera(
30
- 10 / -2,
31
- 10 / 2,
32
- 10 / 2,
33
- 10 / -2,
34
- 1,
35
- 1000
36
- ),
37
28
  layers: null,
38
29
  provider: null,
39
30
  cameraProjection: null,
@@ -61,13 +52,14 @@ export default {
61
52
  },
62
53
  screenshotable: false,
63
54
  areModuleFieldsVisible: false,
55
+ areUserDeactivatedPanelsVisible: false,
56
+ animationFrameId: null,
64
57
  intervalId: null,
65
- requestAnimationFrameId: null,
66
58
  }
67
59
  },
68
60
  beforeDestroy() {
69
61
  clearInterval(this.intervalId)
70
- cancelAnimationFrame(this.requestAnimationFrameId)
62
+ cancelAnimationFrame(this.animationFrameId)
71
63
  },
72
64
  mixins: [renderMixin, threeMixin, materialMixin],
73
65
  async mounted() {
@@ -288,7 +280,7 @@ export default {
288
280
  },
289
281
  animate() {
290
282
  this.render()
291
- this.requestAnimationFrameId = requestAnimationFrame(this.animate)
283
+ this.animationFrameId = requestAnimationFrame(this.animate)
292
284
  },
293
285
  render() {
294
286
  this.renderer.clear()
package/src/config.js CHANGED
@@ -4,7 +4,7 @@ export const snapToPointTolerance = 15
4
4
  export const snapToIntersectionPointTolerance = 15
5
5
  export const snapToLineTolerance = 10
6
6
  export const distanceToCloseNode = 70
7
- export const mmTolerance = 50
7
+ export const mmTolerance = 1
8
8
  export const earthRadius = 6371008
9
9
 
10
10
  export const layerColors = {
@@ -139,8 +139,8 @@ export const maxMargin = 2500
139
139
  export const node3DRadius = 0.05
140
140
  export const beamColor = '#ffffff'
141
141
  export const node3DColor = 'white'
142
- export const beamOpacity = 0.4
143
- export const node3dOpacity = 0.3
142
+ export const beamOpacity = 0.1
143
+ export const node3dOpacity = 0.1
144
144
  export const dimMarginColor = '#ff000020'
145
145
  export const defaultTextureUrl = require('./assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw.png')
146
146
  const textureImageDomain = 'https://public-data.eturnity.io/'
@@ -33,7 +33,7 @@ export function UpdateRoofModuleFieldRelations(state) {
33
33
  //check if everypoint is in the same roof and if they are not too far from the flat surface.(at least above)
34
34
  let roofPolygonCandidates = roofPolygons.filter((roof) => {
35
35
  const intersection = intersectOutlines(moduleField.outline, roof.outline)
36
- if (intersection.length == 0) return false
36
+ if (intersection.length == 0) return false
37
37
  const intersectionArea = calculateArea(intersection[0])
38
38
  return intersectionArea > 100 && moduleField.area <= roof.area
39
39
  })
@@ -1,12 +1,136 @@
1
1
  import TWEEN from 'tween'
2
+ import * as THREE from 'three'
3
+ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
2
4
  import {
3
5
  addVector,
6
+ getDistanceBetweenPoints,
4
7
  multiplyVector,
5
8
  substractVector
6
9
  } from '@eturnity/eturnity_maths'
7
10
 
8
11
  export default {
12
+ data() {
13
+ return {
14
+ camera: null,
15
+ perspectiveCamera: new THREE.PerspectiveCamera(50, 300 / 300, 1, 50000),
16
+ orthographicCamera: new THREE.OrthographicCamera(10, 10, 10, 10, 1, 1000)
17
+ }
18
+ },
9
19
  methods: {
20
+ turnPerspectiveCameraToOrthogonal() {
21
+ const cameraPosition = new THREE.Vector3(
22
+ this.camera.position.x,
23
+ this.camera.position.y,
24
+ this.camera.position.z
25
+ )
26
+ var halfHeightDistance =
27
+ (this.camera.position.z * this.camera.fov * Math.PI) / 180
28
+
29
+ // Create an orthographic camera aligned to look down
30
+ this.orthographicCamera.left =
31
+ (-this.camera.aspect * halfHeightDistance) / 2
32
+ this.orthographicCamera.right =
33
+ (this.camera.aspect * halfHeightDistance) / 2
34
+ this.orthographicCamera.top = halfHeightDistance / 2
35
+ this.orthographicCamera.bottom = -halfHeightDistance / 2
36
+ this.orthographicCamera.near = 1
37
+ this.orthographicCamera.far = 1000
38
+ this.orthographicCamera.up = new THREE.Vector3(0, 1, 0)
39
+ this.orthographicCamera.position.set(
40
+ cameraPosition.x,
41
+ cameraPosition.y,
42
+ 100
43
+ )
44
+ this.camera = this.orthographicCamera
45
+ this.camera.position.set(
46
+ cameraPosition.x,
47
+ cameraPosition.y,
48
+ cameraPosition.z
49
+ )
50
+ this.camera.position.set(
51
+ cameraPosition.x,
52
+ cameraPosition.y,
53
+ cameraPosition.z
54
+ )
55
+ this.camera.updateProjectionMatrix()
56
+ this.renderer.camera = this.camera
57
+ this.composer.renderCamera = this.camera
58
+
59
+ this.renderPass.camera = this.camera
60
+ this.overlayRenderPass.camera = this.camera
61
+ this.outlinePassHighlight.renderCamera = this.camera
62
+ this.outlinePassSelected.renderCamera = this.camera
63
+
64
+ this.orbitControl.screenSpacePanning = true
65
+ this.orbitControl.object = this.camera
66
+ this.orbitControl.target.set(cameraPosition.x, cameraPosition.y, 0)
67
+ this.orbitControl.mouseButtons = {
68
+ LEFT: THREE.MOUSE.PAN,
69
+ MIDDLE: THREE.MOUSE.DOLLY,
70
+ RIGHT: THREE.MOUSE.ROTATE
71
+ }
72
+ this.orbitControl.enableRotate = false
73
+ this.orbitControl.addEventListener('change', () => {
74
+ this.orbitControlChange()
75
+ })
76
+ this.orbitControl.update()
77
+ this.camera.position.set(
78
+ cameraPosition.x,
79
+ cameraPosition.y,
80
+ cameraPosition.z
81
+ )
82
+ this.camera.lookAt(
83
+ new THREE.Vector3(cameraPosition.x, cameraPosition.y, 0)
84
+ ) // Set look at coordinate like this
85
+ this.camera.updateProjectionMatrix()
86
+ this.nodesVisible = true
87
+ this.renderNodes()
88
+ this.composer.render()
89
+ },
90
+ turnOrthogonalCameraToPerspective() {
91
+ this.camera = this.perspectiveCamera
92
+ console.log(this.orthographicCamera)
93
+ let altitude =
94
+ (this.orthographicCamera.right - this.orthographicCamera.left) /
95
+ ((this.perspectiveCamera.fov * Math.PI) / 180) /
96
+ this.perspectiveCamera.aspect
97
+
98
+ this.camera.position.set(
99
+ this.orthographicCamera.position.x,
100
+ this.orthographicCamera.position.y,
101
+ altitude
102
+ )
103
+
104
+ this.camera.up = new THREE.Vector3(0, 0, 1)
105
+ this.camera.updateProjectionMatrix()
106
+
107
+ this.renderer.camera = this.camera
108
+ this.composer.renderer.camera = this.camera
109
+ this.composer.renderCamera = this.camera
110
+ this.renderPass.camera = this.camera
111
+ this.overlayRenderPass.camera = this.camera
112
+ this.outlinePassHighlight.camera = this.camera
113
+ this.outlinePassHighlight.renderCamera = this.camera
114
+ this.outlinePassSelected.camera = this.camera
115
+ this.outlinePassSelected.renderCamera = this.camera
116
+ this.orbitControl.camera = this.camera
117
+ this.orbitControl.object = this.camera
118
+ this.orbitControl.target.set(
119
+ this.camera.position.x,
120
+ this.camera.position.y,
121
+ 0
122
+ )
123
+ this.orbitControl.screenSpacePanning = false
124
+ this.orbitControl.enableRotate = true
125
+ this.orbitControl.mouseButtons = {
126
+ LEFT: THREE.MOUSE.ROTATE,
127
+ MIDDLE: THREE.MOUSE.DOLLY,
128
+ RIGHT: THREE.MOUSE.PAN
129
+ }
130
+ this.orbitControl.update()
131
+
132
+ this.composer.render()
133
+ },
10
134
  zoomIn3D() {
11
135
  let target = this.orbitControl.target
12
136
  let curentPosition = this.camera.position
@@ -39,6 +163,7 @@ export default {
39
163
  },
40
164
  setCameraGlobalPosition() {
41
165
  if (this.roofs.length == 0) return
166
+ let newFov = 50
42
167
  let bounds = this.roofsBounds
43
168
  let targetVector = {
44
169
  x: (bounds.xMax + bounds.xMin) / 2000,
@@ -50,7 +175,7 @@ export default {
50
175
  (bounds.yMax - bounds.yMin) / 2000
51
176
  )
52
177
  let distance =
53
- 5 + objectRadius_m / Math.sin(((this.camera.fov / 2) * Math.PI) / 180)
178
+ 5 + objectRadius_m / Math.sin(((newFov / 2) * Math.PI) / 180)
54
179
  let cameraMoveVector = { x: 0, y: 0, z: distance }
55
180
  const positionVector = addVector(targetVector, cameraMoveVector)
56
181
  const position = [
@@ -59,8 +184,39 @@ export default {
59
184
  positionVector.z
60
185
  ]
61
186
  let target = [targetVector.x, targetVector.y, targetVector.z]
187
+ this.setTweenTo(position, target, newFov)
188
+ },
189
+ setCameraGlobalVerticalPosition() {
190
+ let position, target
191
+ let newFov = 10
192
+ if (this.roofs.length != 0) {
193
+ let bounds = this.roofsBounds
194
+ let targetVector = {
195
+ x: (bounds.xMax + bounds.xMin) / 2000,
196
+ y: (bounds.yMax + bounds.yMin) / 2000,
197
+ z: 0
198
+ }
199
+ let objectRadius_m = Math.max(
200
+ (bounds.xMax - bounds.xMin) / 2000,
201
+ (bounds.yMax - bounds.yMin) / 2000
202
+ )
62
203
 
63
- this.setTweenTo(position, target)
204
+ let distance =
205
+ 2 * (objectRadius_m / Math.sin(((newFov / 2) * Math.PI) / 180))
206
+ let cameraMoveVector = { x: 0, y: 0, z: distance }
207
+ const positionVector = addVector(targetVector, cameraMoveVector)
208
+ position = [positionVector.x, positionVector.y, positionVector.z]
209
+ target = [targetVector.x, targetVector.y, targetVector.z]
210
+ } else {
211
+ position = [0, 0, 300]
212
+ target = [0, 0, 0]
213
+ }
214
+ this.setTweenTo(
215
+ position,
216
+ target,
217
+ newFov,
218
+ this.turnPerspectiveCameraToOrthogonal
219
+ )
64
220
  },
65
221
  setCameraOrthogonalTo(polygon) {
66
222
  if (polygon) {
@@ -109,23 +265,126 @@ export default {
109
265
  this.setTweenTo(position, target)
110
266
  }
111
267
  },
112
- setTweenTo(position, target, speed = 2000) {
268
+ setTweenTo(position, target, fov = 50, onCompleteCallback = () => {}) {
113
269
  TWEEN.removeAll()
114
- if (this.orbitControl) {
115
- this.tweenOrbit = new TWEEN.Tween(this.orbitControl.target)
116
- .to({ x: target[0], y: target[1], z: target[2] }, speed)
117
- .easing(TWEEN.Easing.Sinusoidal.Out)
118
- .start()
119
- }
120
270
  if (this.camera) {
121
- this.tweenCamera = new TWEEN.Tween(this.camera.position)
122
- .to({ x: position[0], y: position[1], z: position[2] }, speed)
123
- .easing(TWEEN.Easing.Sinusoidal.Out)
124
- .onUpdate(() => {
125
- if (this.orbitControl && this.orbitControl.update)
126
- this.orbitControl.update()
127
- })
128
- .start()
271
+ const currentTweenVar = {
272
+ t: 0
273
+ }
274
+ const initialTarget = {
275
+ x: this.orbitControl.target.x,
276
+ y: this.orbitControl.target.y,
277
+ z: this.orbitControl.target.z
278
+ }
279
+ const initialFov = this.camera.fov
280
+ const initialCameraPosition = {
281
+ x: this.camera.position.x,
282
+ y: this.camera.position.y,
283
+ z: this.camera.position.z
284
+ }
285
+ const finalCameraPosition = {
286
+ x: position[0],
287
+ y: position[1],
288
+ z: position[2]
289
+ }
290
+ if (position[0] == target[0] && position[1] == target[1]) {
291
+ const distance2D = getDistanceBetweenPoints(
292
+ finalCameraPosition,
293
+ initialCameraPosition
294
+ )
295
+ //angle from south
296
+ const angle2D = Math.atan2(
297
+ initialCameraPosition.y - finalCameraPosition.y,
298
+ initialCameraPosition.x - finalCameraPosition.x
299
+ )
300
+ this.tweenCamera = new TWEEN.Tween(currentTweenVar)
301
+ .to({ t: 1 }, 2000)
302
+ .easing(TWEEN.Easing.Sinusoidal.Out)
303
+ .onUpdate(() => {
304
+ const t = currentTweenVar.t
305
+ this.camera.fov = initialFov + Math.sqrt(t) * (fov - initialFov)
306
+
307
+ const newDistance = distance2D * (1 - t)
308
+ const newAngle = (angle2D + Math.PI / 2) * (1 - t) - Math.PI / 2
309
+ const newAltitude =
310
+ finalCameraPosition.z +
311
+ (1 - t) * (initialCameraPosition.z - finalCameraPosition.z)
312
+ const nextPosition = {
313
+ x: finalCameraPosition.x + newDistance * Math.cos(newAngle),
314
+ y: finalCameraPosition.y + newDistance * Math.sin(newAngle),
315
+ z: newAltitude
316
+ }
317
+ this.camera.position.set(
318
+ nextPosition.x,
319
+ nextPosition.y,
320
+ nextPosition.z
321
+ )
322
+ this.camera.up = new THREE.Vector3(
323
+ 0,
324
+ Math.sin((t * Math.PI) / 2),
325
+ Math.cos((t * Math.PI) / 2)
326
+ )
327
+
328
+ this.camera.updateProjectionMatrix()
329
+ const nextTarget = {
330
+ x: initialTarget.x + t * (target[0] - initialTarget.x),
331
+ y: initialTarget.y + t * (target[1] - initialTarget.y),
332
+ z: initialTarget.z + t * (target[2] - initialTarget.z)
333
+ }
334
+
335
+ this.orbitControl.target.set(
336
+ nextTarget.x,
337
+ nextTarget.y,
338
+ nextTarget.z
339
+ )
340
+ if (this.orbitControl && this.orbitControl.update)
341
+ this.orbitControl.update()
342
+ })
343
+ .onComplete(() => {
344
+ onCompleteCallback()
345
+ })
346
+ } else {
347
+ console.log('setTween Camera not Vertical')
348
+ this.camera.up = { x: 0, y: 0, z: 1 }
349
+ this.tweenCamera = new TWEEN.Tween(currentTweenVar)
350
+ .to({ t: 1 }, 2000)
351
+ .easing(TWEEN.Easing.Sinusoidal.Out)
352
+ .onUpdate(() => {
353
+ const t = currentTweenVar.t
354
+ this.camera.fov = initialFov + t * t * (fov - initialFov)
355
+ this.camera.updateProjectionMatrix()
356
+
357
+ const nextPosition = {
358
+ x:
359
+ finalCameraPosition.x +
360
+ (1 - t) * (initialCameraPosition.x - finalCameraPosition.x),
361
+ y:
362
+ finalCameraPosition.y +
363
+ (1 - t) * (initialCameraPosition.y - finalCameraPosition.y),
364
+ z:
365
+ finalCameraPosition.z +
366
+ (1 - t) * (initialCameraPosition.z - finalCameraPosition.z)
367
+ }
368
+ this.camera.position.set(
369
+ nextPosition.x,
370
+ nextPosition.y,
371
+ nextPosition.z
372
+ )
373
+ const nextTarget = {
374
+ x: initialTarget.x + t * (target[0] - initialTarget.x),
375
+ y: initialTarget.y + t * (target[1] - initialTarget.y),
376
+ z: initialTarget.z + t * (target[2] - initialTarget.z)
377
+ }
378
+ this.orbitControl.target.set(
379
+ nextTarget.x,
380
+ nextTarget.y,
381
+ nextTarget.z
382
+ )
383
+ if (this.orbitControl && this.orbitControl.update)
384
+ this.orbitControl.update()
385
+ })
386
+ }
387
+ this.tweenCamera.start()
129
388
  }
130
389
  }
131
390
  },
@@ -32,18 +32,32 @@ export default {
32
32
  side: THREE.DoubleSide
33
33
  })
34
34
 
35
- this.material.edge = new THREE.MeshPhongMaterial({
35
+ this.material.edge = new THREE.MeshBasicMaterial({
36
36
  color: beamColor,
37
37
  transparent: true,
38
38
  opacity: beamOpacity
39
39
  })
40
+ //Creating dot alpha texture for nodes
41
+ const canvas = document.createElement('canvas'),
42
+ ctx = canvas.getContext('2d');
43
+ canvas.width = 64
44
+ canvas.height = 64
45
+ ctx.fillStyle = 'black'
46
+ ctx.fillRect(0, 0, 64, 64)
47
+ ctx.strokeStyle = 'white'
48
+ ctx.beginPath()
49
+ ctx.lineWidth = 10
50
+ ctx.arc(32, 32, 16, 0, Math.PI * 2)
51
+ ctx.stroke()
52
+ const texture = new THREE.CanvasTexture(canvas)
40
53
 
41
54
  this.material.node = new THREE.PointsMaterial({
42
- size: 0.05,
43
- sizeAttenuation: true,
44
- color: node3DColor,
45
- opacity: node3dOpacity,
46
- transparent: true
55
+ alphaMap: texture,
56
+ size: 25,
57
+ sizeAttenuation: false,
58
+ transparent: true,
59
+ color: "0xffffff",
60
+ opacity: 1,
47
61
  })
48
62
 
49
63
  this.material.panel = {}
@@ -58,6 +72,13 @@ export default {
58
72
  side: THREE.DoubleSide
59
73
  })
60
74
  }
75
+ this.material.panel['userDeactivatedPanel'] = new THREE.MeshBasicMaterial({
76
+ color: 0xffffff,
77
+ transparent: true,
78
+ alphaTest: 0,
79
+ opacity: 0.2,
80
+ side: THREE.DoubleSide
81
+ })
61
82
  this.material.roof = [this.material.wall]
62
83
 
63
84
  this.material.flatRoof = new THREE.MeshPhongMaterial({
@@ -94,7 +115,8 @@ export default {
94
115
  color: 0xffffff,
95
116
  transparent: true,
96
117
  alphaTest: 1,
97
- opacity: 0
118
+ opacity: 0.2,
119
+ side: THREE.DoubleSide
98
120
  })
99
121
  this.material.moduleField = new THREE.MeshBasicMaterial({
100
122
  color: 0xe0e0ff,
Binary file
@@ -43,7 +43,6 @@ export default {
43
43
  )
44
44
  },
45
45
  clearMesh(mesh) {
46
-
47
46
  if (!mesh || !this.scene) {
48
47
  return
49
48
  }
@@ -77,13 +76,6 @@ export default {
77
76
  }
78
77
  })
79
78
  },
80
- clearNodesRemovedOnes() {
81
- Object.values(this.meshes['nodeMeshes']).forEach((mesh) => {
82
- if (!this.nodeIds.includes(mesh.userData.nodeId)) {
83
- this.clearMesh(mesh)
84
- }
85
- })
86
- },
87
79
  clearRemovedOnes(type) {
88
80
  Object.values(this.meshes[type]).forEach((mesh) => {
89
81
  if (!this.polygonIds.includes(mesh.userData.polygonId)) {
@@ -36,30 +36,62 @@ export default {
36
36
  },
37
37
  renderEdges() {
38
38
  this.clearEdgesRemovedOnes('edgeMeshes')
39
+ if(this.renderLineEdges){
40
+ this.renderLineEdges()
41
+ }
39
42
  let cylinder
40
- //this.clearByType('edgeMeshes')
41
- // const material = new THREE.LineBasicMaterial( { color: beamColor,transparent:true,opacity:beamOpacity ,sizeAttenuation: true} );
42
- // material.linewidth=5
43
43
  const material = this.material.edge
44
- this.edges
45
- .filter((edge) => edge.layer == 'roof')
46
- .forEach((edge) => {
47
- cylinder = this.meshes.edgeMeshes[edge.id]
48
- if (cylinder) {
49
- //update
50
- this.setCylinderPosition(cylinder, edge)
51
- //change cylinder length
52
- } else {
53
- const geometry = new THREE.CylinderGeometry(0.1, 0.1, 1, 6)
54
- cylinder = new THREE.Mesh(geometry, material)
55
- cylinder = this.setCylinderPosition(cylinder, edge)
44
+ this.edges.forEach((edge) => {
45
+ cylinder = this.meshes.edgeMeshes[edge.id]
46
+ if (cylinder) {
47
+ cylinder.visible = false
48
+ }
49
+ if (['obstacle', 'construction'].includes(edge.layer)) return
50
+ if (
51
+ ['selectRoof'].includes(this.selectedTool) &&
52
+ edge.layer != 'roof'
53
+ ) {
54
+ return
55
+ }
56
+ if (
57
+ ['selectModuleField'].includes(this.selectedTool) &&
58
+ (edge.layer != 'moduleField' ||
59
+ !this.selectedModuleField ||
60
+ !edge.belongsTo
61
+ .map((i) => i.polygonId)
62
+ .includes(this.selectedModuleField.id))
63
+ ) {
64
+ return
65
+ }
66
+ cylinder = this.meshes.edgeMeshes[edge.id]
67
+ if (cylinder) {
68
+ //update
69
+ cylinder.visible = true
70
+ this.setCylinderPosition(cylinder, edge)
71
+ //change cylinder length
72
+ } else {
73
+ const edgeRadius = this.edgeRadius || 0.1
74
+ const geometry = new THREE.CylinderGeometry(
75
+ edgeRadius,
76
+ edgeRadius,
77
+ 1,
78
+ 6
79
+ )
80
+ if (this.edgeOpacity != undefined) {
81
+ material.opacity = this.edgeOpacity
82
+ }
83
+ cylinder = new THREE.Mesh(geometry, material.clone())
84
+ cylinder = this.setCylinderPosition(cylinder, edge)
56
85
 
57
- cylinder.userData.edgeId = edge.id
86
+ cylinder.userData.meshId = edge.id
87
+ cylinder.userData.edgeId = edge.id
88
+ cylinder.userData.type = 'edgeMeshes'
89
+ cylinder.userData.layer = edge.layer
58
90
 
59
- this.meshes.edgeMeshes[edge.id] = cylinder
60
- this.scene.add(cylinder)
61
- }
62
- })
91
+ this.meshes.edgeMeshes[edge.id] = cylinder
92
+ this.scene.add(cylinder)
93
+ }
94
+ })
63
95
  }
64
96
  }
65
97
  }
@@ -6,13 +6,58 @@ export default {
6
6
  renderRoofsMargin() {
7
7
  this.clearByType('roofMarginMeshes')
8
8
 
9
- if (this.selectedTool == 'selectMargin') {
10
- this.roofs.forEach((roofPolygon) => {
11
- const geometries = getBufferRoofMarginGeometry(roofPolygon)
9
+ if (
10
+ ![
11
+ 'selectMargin',
12
+ 'selectModuleField',
13
+ 'drawRoof',
14
+ 'drawObstacle'
15
+ ].includes(this.selectedTool)
16
+ ) {
17
+ return
18
+ }
19
+ let showableRoofs = []
20
+ if (['drawRoof', 'drawObstacle'].includes(this.selectedTool)) {
21
+ if (this.selectedRoof) {
22
+ showableRoofs = [this.selectedRoof]
23
+ }
24
+ if (this.selectedObstacle) {
25
+ showableRoofs = this.selectedObstacle.roofs
26
+ }
27
+ } else {
28
+ showableRoofs = this.roofs
29
+ }
30
+ showableRoofs.forEach((roofPolygon) => {
31
+ const geometries = getBufferRoofMarginGeometry(roofPolygon)
12
32
 
33
+ geometries.forEach((geometry, index) => {
34
+ if (geometry) {
35
+ const marginColor = roofPolygon.margins.isSameMargin
36
+ ? colorArrayBase[0]
37
+ : colorArrayBase[index % colorArrayBase.length]
38
+ let material = new THREE.MeshPhongMaterial({
39
+ color: marginColor,
40
+ specular: 0x009900,
41
+ shininess: 0,
42
+ flatShading: true,
43
+ side: THREE.DoubleSide,
44
+ transparent: true,
45
+ opacity: 0.8
46
+ })
47
+ const mesh = new THREE.Mesh(geometry, material)
48
+ geometry.dispose()
49
+ this.scene.add(mesh)
50
+ this.meshes.roofMarginMeshes[roofPolygon.id + '_' + index] = mesh
51
+ }
52
+ })
53
+ roofPolygon.holes.forEach((obstaclePolygon) => {
54
+ const geometries = getBufferRoofMarginGeometry(
55
+ obstaclePolygon,
56
+ roofPolygon
57
+ )
13
58
  geometries.forEach((geometry, index) => {
14
59
  if (geometry) {
15
- const marginColor = roofPolygon.margins.isSameMargin
60
+ const marginColor = obstaclePolygon.margins.isSameMargin
16
61
  ? colorArrayBase[0]
17
62
  : colorArrayBase[index % colorArrayBase.length]
18
63
  let material = new THREE.MeshPhongMaterial({
@@ -26,43 +71,17 @@ export default {
26
71
  })
27
72
  const mesh = new THREE.Mesh(geometry, material)
28
73
  geometry.dispose()
74
+ geometry = null
75
+ material.dispose()
76
+ material = null
29
77
  this.scene.add(mesh)
30
- this.meshes.roofMarginMeshes[roofPolygon.id + '_' + index] = mesh
78
+ this.meshes.roofMarginMeshes[
79
+ obstaclePolygon.id + '_' + roofPolygon.id + '_' + index
80
+ ] = mesh
31
81
  }
32
82
  })
33
- roofPolygon.holes.forEach((obstaclePolygon) => {
34
- const geometries = getBufferRoofMarginGeometry(
35
- obstaclePolygon,
36
- roofPolygon
37
- )
38
- geometries.forEach((geometry, index) => {
39
- if (geometry) {
40
- const marginColor = obstaclePolygon.margins.isSameMargin
41
- ? colorArrayBase[0]
42
- : colorArrayBase[index % colorArrayBase.length]
43
- let material = new THREE.MeshPhongMaterial({
44
- color: marginColor,
45
- specular: 0x009900,
46
- shininess: 0,
47
- flatShading: true,
48
- side: THREE.DoubleSide,
49
- transparent: true,
50
- opacity: 0.8
51
- })
52
- const mesh = new THREE.Mesh(geometry, material)
53
- geometry.dispose()
54
- geometry = null
55
- material.dispose()
56
- material = null
57
- this.scene.add(mesh)
58
- this.meshes.roofMarginMeshes[
59
- obstaclePolygon.id + '_' + roofPolygon.id + '_' + index
60
- ] = mesh
61
- }
62
- })
63
- })
64
83
  })
65
- }
84
+ })
66
85
  }
67
86
  }
68
87
  }
@@ -10,9 +10,9 @@ export default {
10
10
  geometries.forEach((geometry) => {
11
11
  const positions = geometry.attributes.position.array
12
12
  const normals = geometry.attributes.normal.array
13
+ mergedVertices.push(...positions.slice(0, 3 * geometry.drawRange.count))
14
+ mergedNormals.push(...normals.slice(0, 3 * geometry.drawRange.count))
13
15
 
14
- mergedVertices.push(...positions.slice(0, geometry.drawRange.count * 3))
15
- mergedNormals.push(...normals.slice(0, geometry.drawRange.count * 3))
16
16
  if (geometry.attributes.uv) {
17
17
  const uvs = geometry.attributes.uv.array
18
18
  mergedUvs.push(...uvs)
@@ -41,12 +41,12 @@ export default {
41
41
  for (let k in mergedNormals) {
42
42
  normals[k] = mergedNormals[k]
43
43
  }
44
+ mergedGeometry.setDrawRange(0, mergedVertices.length / 3)
44
45
  } else {
45
46
  mergedGeometry.dispose()
46
47
  mergedGeometry = null
47
48
  mergedGeometry = this.createMergedGeometry(geometries)
48
49
  }
49
- mergedGeometry.setDrawRange(0, mergedVertices.length / 3)
50
50
  mergedGeometry.attributes.position.needsUpdate = true
51
51
  mergedGeometry.attributes.normal.needsUpdate = true
52
52
  mergedGeometry.needsUpdate = true
@@ -100,6 +100,7 @@ export default {
100
100
  )
101
101
  mesh.geometry = mergedGeometry
102
102
  }
103
+ mesh.frustumCulled = false
103
104
  return mesh
104
105
  }
105
106
  }
@@ -7,19 +7,23 @@ export default {
7
7
  if (!this.areModuleFieldsVisible) {
8
8
  return
9
9
  }
10
- this.moduleFields.forEach((moduleFieldPolygon) => {
10
+ const moduleFieldPolygons = this.polygons.filter((p) =>
11
+ ['moduleField', 'tmpModuleField'].includes(p.layer)
12
+ )
13
+ moduleFieldPolygons.forEach((moduleFieldPolygon) => {
11
14
  const geometry = getBufferModuleFieldGeometry(moduleFieldPolygon)
12
15
  if (geometry) {
13
16
  let material
14
- if(moduleFieldPolygon.data.number_of_panels_override){
15
- material=this.material.moduleFieldWithPanelOveride
16
- }else{
17
- material=this.material.moduleField
17
+ if (moduleFieldPolygon.data.number_of_panels_override) {
18
+ material = this.material.moduleFieldWithPanelOveride
19
+ } else {
20
+ material = this.material.moduleField
18
21
  }
19
22
  const mesh = new THREE.Mesh(geometry, this.material.moduleField)
20
23
  mesh.matrixAutoUpdate = false
21
24
  mesh.userData.version = moduleFieldPolygon.version
22
25
  mesh.userData.type = 'moduleFieldsMeshes'
26
+ mesh.userData.layer = moduleFieldPolygon.layer
23
27
  mesh.userData.meshId = moduleFieldPolygon.id
24
28
  mesh.userData.polygonId = moduleFieldPolygon.id
25
29
  this.scene.add(mesh)
@@ -1,10 +1,17 @@
1
1
  import * as THREE from 'three'
2
-
3
2
  export default {
4
3
  methods: {
5
4
  renderNodes() {
5
+ if (!this.nodesVisible) {
6
+ if (this.meshes.nodeMeshes) {
7
+ this.meshes.nodeMeshes.visible = false
8
+ }
9
+ return
10
+ }
11
+
6
12
  let geometry
7
13
  if (this.meshes.nodeMeshes) {
14
+ this.meshes.nodeMeshes.visible = true
8
15
  geometry = this.meshes.nodeMeshes.geometry
9
16
  geometry.attributes.position.needsUpdate = true
10
17
  } else {
@@ -40,8 +47,11 @@ export default {
40
47
  nodeMeshes.userData.meshId = null
41
48
  nodeMeshes.userData.polygonId = null
42
49
  nodeMeshes.matrixAutoUpdate = false
50
+ nodeMeshes.renderOrder = 10
43
51
  this.meshes.nodeMeshes = nodeMeshes
44
- this.scene.add(nodeMeshes)
52
+ if (this.overlayScene) {
53
+ this.overlayScene.add(nodeMeshes)
54
+ }
45
55
  }
46
56
  }
47
57
  }
@@ -35,9 +35,10 @@ export default {
35
35
  },
36
36
  renderPanels() {
37
37
  this.clearRemovedOnes('panelsMeshes')
38
+ //clear mesh of userDeactivated panels && panels with overriden # of panels
38
39
  Object.values(this.meshes.panelsMeshes).forEach((mesh) => {
39
- //clear UserDeactivatedModules
40
40
  if (
41
+ !this.areUserDeactivatedPanelsVisible &&
41
42
  this.polygons.find(
42
43
  (poly) =>
43
44
  poly.id == mesh.userData.polygonId &&
@@ -54,53 +55,80 @@ export default {
54
55
  this.clearMesh(mesh)
55
56
  }
56
57
  })
58
+
57
59
  let panelSideGeometries = []
58
60
  let panelTopGeometries = {}
59
- this.panels.forEach((panelPolygon) => {
61
+ let panels = this.panels
62
+ if (this.areUserDeactivatedPanelsVisible) {
63
+ panels = this.polygons.filter((polygon) => {
64
+ return ['panel', 'user_deactivated_panel'].includes(polygon.layer)
65
+ })
66
+ }
67
+ panels.forEach((panelPolygon) => {
68
+ //for each visible panels
69
+ //1. define materialId and material
70
+ //2. create or update individual meshes
71
+ // 2a. Fill in panelTopGeometries & panelSideGeometries
60
72
  if (!panelPolygon.visible) {
61
73
  return
62
74
  }
63
- //definition of the material
64
75
  if (panelPolygon.moduleField.data.number_of_panels_override) {
65
76
  return
66
77
  }
67
- const moduleTextureId = panelPolygon.moduleField.pvData.hasOwnProperty(
68
- 'module_texture_version_id'
69
- ) && panelPolygon.moduleField.pvData.module_texture_version_id
70
- ? panelPolygon.moduleField.pvData.module_texture_version_id
71
- : 0
72
- let materialId = 'default_' + moduleTextureId
73
- let material = this.material.panel[materialId]
74
- material.transparent = true
75
- material.opacity = this.panelOpacity
76
- if (panelPolygon.moduleField.data) {
77
- if (
78
- this.material.panel[
79
- panelPolygon.moduleField.data.component_id_pv_module
80
- ]
81
- ) {
82
- materialId = panelPolygon.moduleField.data.component_id_pv_module
83
- material = this.material.panel[materialId]
84
- }
85
- } else if (panelPolygon.moduleField.pvData) {
86
- if (this.material.panel[panelPolygon.moduleField.pvData.id]) {
87
- materialId = panelPolygon.moduleField.pvData.id
88
- material = this.material.panel[materialId]
78
+ //1.define materialId and material
79
+ let material
80
+ let materialId
81
+ if (panelPolygon.layer == 'user_deactivated_panel') {
82
+ materialId = 'userDeactivatedPanel'
83
+ material = this.material.panel[materialId]
84
+ material.opacity = this.panelOpacity
85
+ } else {
86
+ const moduleTextureId =
87
+ panelPolygon.moduleField.pvData.hasOwnProperty(
88
+ 'module_texture_version_id'
89
+ ) && panelPolygon.moduleField.pvData.module_texture_version_id
90
+ ? panelPolygon.moduleField.pvData.module_texture_version_id
91
+ : 0
92
+
93
+ materialId = 'default_' + moduleTextureId
94
+ material = this.material.panel[materialId]
95
+ material.transparent = true
96
+ material.opacity = this.panelOpacity
97
+ if (panelPolygon.moduleField.data) {
98
+ if (
99
+ this.material.panel[
100
+ panelPolygon.moduleField.data.component_id_pv_module
101
+ ]
102
+ ) {
103
+ materialId = panelPolygon.moduleField.data.component_id_pv_module
104
+ material = this.material.panel[materialId]
105
+ }
106
+ } else if (panelPolygon.moduleField.pvData) {
107
+ if (this.material.panel[panelPolygon.moduleField.pvData.id]) {
108
+ materialId = panelPolygon.moduleField.pvData.id
109
+ material = this.material.panel[materialId]
110
+ }
89
111
  }
90
112
  }
113
+ //2. create or update individual meshes
91
114
  if (
92
115
  !this.meshes.panelsMeshes[panelPolygon.id + '_top'] ||
93
116
  !this.meshes.panelsMeshes[panelPolygon.id + '_side']
94
117
  ) {
118
+ //mesh creation
95
119
  const geometry = getBufferPanelGeometry(panelPolygon)
96
120
  const geometrySide = getBufferPanelSideGeometry(panelPolygon)
121
+ //2a.Fill in panelTopGeometries & panelSideGeometries
122
+ //gather all geometry with similar material together to merge them for faster rendering
97
123
  if (!panelTopGeometries[materialId]) {
98
124
  panelTopGeometries[materialId] = []
99
125
  }
100
126
  panelTopGeometries[materialId].push(geometry)
101
- panelSideGeometries.push(geometrySide)
127
+ if (panelPolygon.layer != 'user_deactivated_panel') {
128
+ panelSideGeometries.push(geometrySide)
129
+ }
102
130
  if (geometry && geometrySide) {
103
- const mesh = new THREE.Mesh(geometry, material)
131
+ const mesh = new THREE.Mesh(geometry, this.material.hidden)
104
132
  const meshSide = new THREE.Mesh(
105
133
  geometrySide,
106
134
  this.material.panelSide
@@ -109,18 +137,18 @@ export default {
109
137
  mesh.userData.type = 'panelsMeshes'
110
138
  mesh.userData.meshId = panelPolygon.id + '_top'
111
139
  mesh.userData.polygonId = panelPolygon.id
140
+ this.scene.add(mesh)
112
141
  meshSide.userData.version = panelPolygon.version
113
142
  meshSide.userData.type = 'panelsMeshes'
114
143
  meshSide.userData.meshId = panelPolygon.id + '_side'
115
144
  meshSide.userData.polygonId = panelPolygon.id
116
- geometry.dispose()
117
- geometrySide.dispose()
118
145
  mesh.matrixAutoUpdate = false
119
146
  meshSide.matrixAutoUpdate = false
120
147
  this.meshes.panelsMeshes[panelPolygon.id + '_top'] = mesh
121
148
  this.meshes.panelsMeshes[panelPolygon.id + '_side'] = meshSide
122
149
  }
123
150
  } else {
151
+ //update existing geometry
124
152
  const topMesh = this.meshes.panelsMeshes[panelPolygon.id + '_top']
125
153
  const sideMesh = this.meshes.panelsMeshes[panelPolygon.id + '_side']
126
154
  if (panelPolygon.version > topMesh.userData.version) {
@@ -136,7 +164,9 @@ export default {
136
164
  topMesh.geometry = topGeometry
137
165
  sideMesh.geometry = sideGeometry
138
166
  }
139
- panelSideGeometries.push(sideMesh.geometry)
167
+ if (panelPolygon.layer != 'user_deactivated_panel') {
168
+ panelSideGeometries.push(sideMesh.geometry)
169
+ }
140
170
  if (!panelTopGeometries[materialId]) {
141
171
  panelTopGeometries[materialId] = []
142
172
  }
@@ -145,7 +175,7 @@ export default {
145
175
  }
146
176
  })
147
177
 
148
- //removing unused mesh
178
+ //removing unused mergedmesh
149
179
  const materialIds = Object.keys(panelTopGeometries)
150
180
  const materialIdsToRemove = Object.keys(this.mergedPanelTopMeshes).filter(
151
181
  (key) => !materialIds.includes(key)
@@ -130,17 +130,35 @@ export default {
130
130
  this.applyTextureOnMesh(this.material.roof, this.mergedRoofMesh)
131
131
  },
132
132
  renderFlatRoofs() {
133
- this.clearByType('flatRoofMeshes')
133
+ this.clearRemovedOnes('flatRoofMeshes')
134
+ let geometry
134
135
  this.roofs.forEach((roofPolygon) => {
135
- if (roofPolygon.maximumGap < maximumGapLimit) return
136
- let geometry = getBufferRoofGeometry(roofPolygon.flatOutline)
137
- if (geometry) {
138
- const material = this.material.curvedRoof
139
- const mesh = new THREE.Mesh(geometry, material)
140
- mesh.itemData = roofPolygon
141
- mesh.frustumCulled = false
142
- this.scene.add(mesh)
143
- this.meshes.flatRoofMeshes[roofPolygon.id] = mesh
136
+ let mesh = this.meshes.flatRoofMeshes[roofPolygon.id]
137
+ if (mesh) {
138
+ if (mesh.userData.version < roofPolygon.version) {
139
+ geometry = updateBufferRoofGeometry(
140
+ roofPolygon.flatOutline,
141
+ [],
142
+ mesh.geometry
143
+ )
144
+ mesh.geometry = geometry
145
+ mesh.userData.version = roofPolygon.version
146
+ }
147
+ mesh.visible = roofPolygon.maximumGap > maximumGapLimit
148
+ } else {
149
+ geometry = getBufferRoofGeometry(roofPolygon.flatOutline)
150
+ if (geometry) {
151
+ const material = this.material.curvedRoof
152
+ mesh = new THREE.Mesh(geometry, material)
153
+ mesh.userData.polygonId = roofPolygon.id
154
+ mesh.userData.version = roofPolygon.version
155
+ mesh.userData.type = 'flatRoofMeshes'
156
+ mesh.userData.meshId = roofPolygon.id
157
+
158
+ mesh.visible = roofPolygon.maximumGap > maximumGapLimit
159
+ this.scene.add(mesh)
160
+ this.meshes.flatRoofMeshes[roofPolygon.id] = mesh
161
+ }
144
162
  }
145
163
  })
146
164
  }
@@ -56,6 +56,13 @@ export default {
56
56
  nodeIds() {
57
57
  return this.nodes.map((p) => p.id)
58
58
  },
59
+ setGlobalPositionRenderNeeded() {
60
+ return !!this.geometryEvents.find(
61
+ (e) =>
62
+ e.id > this.lastGeometryEventIdDone &&
63
+ e.name == 'setCameraGlobalPosition'
64
+ )
65
+ },
59
66
  fullRenderNeeded() {
60
67
  return !!this.geometryEvents.find(
61
68
  (e) => e.id > this.lastGeometryEventIdDone && e.name == 'full'
@@ -72,6 +79,11 @@ export default {
72
79
  let methodList = []
73
80
  if (this.fullRenderNeeded) {
74
81
  methodList = this.renderingMethodsByEvent({ name: 'full' })
82
+ if (this.setGlobalPositionRenderNeeded) {
83
+ methodList.push(
84
+ ...this.renderingMethodsByEvent({ name: 'setCameraGlobalPosition' })
85
+ )
86
+ }
75
87
  } else {
76
88
  for (let geometryEvent of this.geometryEventsToDo) {
77
89
  for (let renderingMethod of this.renderingMethodsByEvent(
@@ -118,6 +130,11 @@ export default {
118
130
  })
119
131
  break
120
132
  case 'toolChange': //params.toolName
133
+ methodList.push({
134
+ name: 'renderEdges',
135
+ method: this.renderEdges,
136
+ arg: []
137
+ })
121
138
  case 'marginIsSameChange': //params.polygon
122
139
  case 'marginDifferentChange': //params.polygon,index
123
140
  case 'marginSameChange': //params.polygon
@@ -132,6 +149,13 @@ export default {
132
149
  case 'removeNodes': //params.nodes
133
150
  case 'removeEdges': //params.edges
134
151
  case 'translate': //params.edges
152
+ if (this.removeConstructionPolylineMesh) {
153
+ methodList.push({
154
+ name: 'removeConstructionPolyline',
155
+ method: this.removeConstructionPolylineMesh,
156
+ arg: []
157
+ })
158
+ }
135
159
  methodList.push({
136
160
  name: 'renderGeometry',
137
161
  method: this.renderGeometry,
@@ -204,6 +228,11 @@ export default {
204
228
  arg: []
205
229
  })
206
230
  }
231
+ methodList.push({
232
+ name: 'renderRoofsMargin',
233
+ method: this.renderRoofsMargin,
234
+ arg: []
235
+ })
207
236
  break
208
237
  case 'removePanels': //params.panels
209
238
  case 'removeModuleField': //params:moduleField
@@ -232,11 +261,24 @@ export default {
232
261
  arg: []
233
262
  })
234
263
  case 'selectedRoofChange':
264
+ case 'selectedObstacleChange':
235
265
  methodList.push({
236
266
  name: 'renderFlatRoofs',
237
267
  method: this.renderFlatRoofs,
238
268
  arg: []
239
269
  })
270
+ methodList.push({
271
+ name: 'renderRoofsMargin',
272
+ method: this.renderRoofsMargin,
273
+ arg: []
274
+ })
275
+ break
276
+ case 'selectedModuleFieldChange':
277
+ methodList.push({
278
+ name: 'renderEdges',
279
+ method: this.renderEdges,
280
+ arg: []
281
+ })
240
282
  break
241
283
  case 'subHandleSelectionChange':
242
284
  case 'masterHandleSelectionChange':
@@ -321,12 +363,28 @@ export default {
321
363
  arg: [params.roofIds]
322
364
  })
323
365
  break
366
+ case 'selectedPanelChange':
367
+ methodList.push({
368
+ name: 'renderModuleFields',
369
+ method: this.renderModuleFields,
370
+ arg: []
371
+ })
372
+ break
373
+ case 'removeConstruction':
374
+ methodList.push({
375
+ name: 'removeConstructionPolyline',
376
+ method: this.removeConstructionPolyline,
377
+ arg: []
378
+ })
379
+ break
324
380
  }
325
381
  return methodList
326
382
  },
327
383
  async renderMethods(methodList) {
328
384
  for (let item of methodList) {
329
- await item.method(...item.arg)
385
+ if (item.method) {
386
+ await item.method(...item.arg)
387
+ }
330
388
  }
331
389
  },
332
390
  renderGeometry() {
@@ -411,12 +469,6 @@ export default {
411
469
  }
412
470
  },
413
471
  beforeDestroy() {
414
- if (this.tweenOrbit) {
415
- this.tweenOrbit = null
416
- }
417
- if (this.tweenCamera) {
418
- this.tweenCamera = null
419
- }
420
472
  this.clearThreeObjects(this.scene)
421
473
 
422
474
  if (this.three_map) {
@@ -62,7 +62,7 @@ export default {
62
62
  },
63
63
  initialiseThree(isInteractive = true) {
64
64
  this.scene.background = new THREE.Color(0xb0b0b0)
65
-
65
+ this.camera = this.perspectiveCamera
66
66
  this.camera.position.set(0, -100, 50)
67
67
  this.camera.up.set(0, 0, 1)
68
68
 
@@ -80,6 +80,10 @@ export default {
80
80
 
81
81
  // const axesHelper = new THREE.AxesHelper( 20 );
82
82
  // this.scene.add( axesHelper );
83
+
84
+ this.scene.add(this.perspectiveCamera)
85
+ this.scene.add(this.orthographicCamera)
86
+
83
87
  //Light
84
88
  const ambientLight = new THREE.AmbientLight(0xf0f0f0, 0.5)
85
89
  this.scene.add(ambientLight)
@@ -102,7 +106,13 @@ export default {
102
106
  this.camera,
103
107
  this.renderer.domElement
104
108
  )
105
- this.orbitControl.maxPolarAngle = (Math.PI / 2) * (87 / 90)
109
+ this.orbitControl.maxPolarAngle = (0.95 * Math.PI) / 2
110
+ this.orbitControl.mouseButtons = {
111
+ RIGHT: THREE.MOUSE.PAN,
112
+ LEFT: THREE.MOUSE.ROTATE,
113
+ MIDDLE: THREE.MOUSE.DOLLY
114
+ }
115
+ this.orbitControl.screenSpacePanning = false
106
116
  this.orbitControl.addEventListener('change', () => {
107
117
  this.orbitControlChange()
108
118
  })
@@ -114,16 +124,7 @@ export default {
114
124
  directionalLight2.dispose()
115
125
  },
116
126
  orbitControlChange() {
117
- if (this.orbitControl.target.z != 0) {
118
- this.orbitControl.target.set(
119
- this.orbitControl.target.x,
120
- this.orbitControl.target.y,
121
- 0
122
- )
123
- this.orbitControl.update()
124
- } else {
125
- this.render()
126
- }
127
+ this.render()
127
128
  },
128
129
  onWindowResize() {
129
130
  this.camera.aspect = window.innerWidth / window.innerHeight
@@ -7,6 +7,21 @@ import {
7
7
  } from '@eturnity/eturnity_maths'
8
8
  import getLayers from '../utils/layers'
9
9
  import { UpdateRoofObstacleRelations } from '../helper/UpdateRoofObstacleRelations'
10
+ function sanitizedOutline(outline) {
11
+ return outline.reduce((accumulator, currentValue) => {
12
+ if (
13
+ !accumulator.find(
14
+ (p) =>
15
+ p[0] == currentValue[0] &&
16
+ p[1] == currentValue[1] &&
17
+ p[2] == currentValue[2]
18
+ )
19
+ ) {
20
+ accumulator.push(currentValue)
21
+ }
22
+ return accumulator
23
+ }, [])
24
+ }
10
25
  export async function hydratePolygons({
11
26
  roofsResponse,
12
27
  obstaclesResponse,
@@ -17,18 +32,24 @@ export async function hydratePolygons({
17
32
  //removing empty roof,obstacle and modulefield generated by BE on variant creation
18
33
  roofsResponse = roofsResponse.reduce((acc, cur) => {
19
34
  if (cur.roof_outline.length > 0) {
35
+ let outline = sanitizedOutline(cur.roof_outline)
36
+ cur.roof_outline = outline
20
37
  acc.push(cur)
21
38
  }
22
39
  return acc
23
40
  }, [])
24
41
  obstaclesResponse = obstaclesResponse.reduce((acc, cur) => {
25
42
  if (cur.obstacle_outline.length > 0) {
43
+ let outline = sanitizedOutline(cur.obstacle_outline)
44
+ cur.obstacle_outline = outline
26
45
  acc.push(cur)
27
46
  }
28
47
  return acc
29
48
  }, [])
30
49
  moduleFieldsResponse = moduleFieldsResponse.reduce((acc, cur) => {
31
50
  if (cur.module_field_outline.length > 0) {
51
+ let outline = sanitizedOutline(cur.module_field_outline)
52
+ cur.module_field_outline = outline
32
53
  acc.push(cur)
33
54
  }
34
55
  return acc
@@ -114,10 +114,9 @@ export function generateNodes3D(polygons) {
114
114
  node3D.masterHandle.open =
115
115
  node3D.belongsTo.filter((item) => item.polygon.outline[item.index].open)
116
116
  .length > 0
117
- node3D.masterHandle.selected =
118
- node3D.belongsTo.filter(
119
- (item) => item.polygon.outline[item.index].selected
120
- ).length > node3D.belongsTo.length
117
+ node3D.masterHandle.selected = node3D.belongsTo.every(
118
+ (item) => item.polygon.outline[item.index].selected
119
+ )
121
120
  }
122
121
  })
123
122
  return nodes3D
@@ -180,11 +179,13 @@ export function generateEdges3D(polygons) {
180
179
  //check if edge2D already exist
181
180
  const nextPoint = outline[(i + 1) % outline.length]
182
181
  let edge3D = edges3D.find((edge) => {
183
- isAlmostSameSegment3D(
184
- [point, nextPoint],
185
- edge.outline,
186
- mmTolerance
187
- ) && edge.layer == polygon.layer
182
+ return (
183
+ isAlmostSameSegment3D(
184
+ [point, nextPoint],
185
+ edge.outline,
186
+ mmTolerance
187
+ ) && edge.layer == polygon.layer
188
+ )
188
189
  })
189
190
  if (!edge3D) {
190
191
  //create an edge at this position