@eturnity/eturnity_3d 8.16.2-EPDM-14200.4 → 8.19.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": "8.16.2-EPDM-14200.4",
4
+ "version": "8.19.0",
5
5
  "files": [
6
6
  "dist",
7
7
  "src"
@@ -26,6 +26,7 @@
26
26
  layers: null,
27
27
  provider: null,
28
28
  pointer: { x: 0, y: 0 },
29
+ areModuleFieldsVisible: false,
29
30
  areUserDeactivatedPanelsVisible: false,
30
31
  animationFrameId: null,
31
32
  intervalId: null,
package/src/config.js CHANGED
@@ -282,14 +282,3 @@ export const hitOptionStroke = {
282
282
 
283
283
  export const dragHeightSensitivity = 20
284
284
  export const snapLimit = 100
285
-
286
- export const fittingPanelsColorMap = {
287
- black: '#000000',
288
- blue: '#0068DE',
289
- brown: '#5C4033',
290
- 'rustic red': '#8B0000',
291
- terracotta: '#E35336',
292
- transparent: 'transparent',
293
- white: '#ffffff',
294
- default: '#0068DE',
295
- }
@@ -3,11 +3,7 @@ import {
3
3
  verticalProjectionOnPlane,
4
4
  intersectOutlines,
5
5
  calculateArea,
6
- isSelfIntersecting,
7
- isPolygonInsidePolygon,
8
- getConcaveOutlines,
9
6
  } from '@eturnity/eturnity_maths'
10
- import { fittingPanelsColorMap } from '../config'
11
7
  //this function just update the "roof" and "moduleField(s)" properties of panels,moduleFields and roofs
12
8
  export function UpdateRoofModuleFieldRelations(state) {
13
9
  let moduleFields = state.polygons.filter(
@@ -82,170 +78,3 @@ export function removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state) {
82
78
  ]
83
79
  return state
84
80
  }
85
-
86
- export function updateModuleFieldFittingPanels(moduleField) {
87
- delete moduleField.fittingPanels
88
- const { has_fitting_panels, fitting_panel_area_m2 } = moduleField.data
89
- const hasFittingPanels = has_fitting_panels && fitting_panel_area_m2 > 0
90
- if (!hasFittingPanels) return
91
- const polygons = []
92
-
93
- const outlines = getModuleFieldRoofIntersections(
94
- moduleField,
95
- moduleField.roof.margins.innerOutline
96
- )
97
- const holes = getModuleFieldHoleOutlines(moduleField)
98
-
99
- outlines.forEach((outline) => {
100
- polygons.push({
101
- outline,
102
- // Clean up holes outside of the outline
103
- holes: holes
104
- .flatMap((hole) => intersectOutlines(hole, outline))
105
- .filter(Boolean),
106
- })
107
- })
108
-
109
- // map backsheet color to hex color
110
- const backSheetColor = moduleField.pvData?.backsheet_color || 'default'
111
- const mappedColor = fittingPanelsColorMap[backSheetColor]
112
-
113
- moduleField.fittingPanels = {
114
- polygons,
115
- visible: true,
116
- color: mappedColor,
117
- }
118
- }
119
-
120
- export function getRoofInnerMarginOutline({
121
- roof,
122
- moduleField,
123
- pointer = null,
124
- } = {}) {
125
- let roofInnerMarginOutline = roof.margins.innerOutline
126
- let isOutlineSelfIntersecting = false
127
- let sumAllArea = 0
128
- if (isSelfIntersecting(roofInnerMarginOutline)) {
129
- let selfIntersections = intersectOutlines(
130
- roof.margins.innerOutline,
131
- roof.margins.innerOutline
132
- )
133
- let sumAllArea = selfIntersections.reduce((acc, cur) => {
134
- acc += calculateArea(cur)
135
- return acc
136
- }, 0)
137
- if (moduleField) {
138
- selfIntersections = selfIntersections.filter((i) => {
139
- if (calculateArea(i) < 0.05 * sumAllArea) {
140
- return false
141
- }
142
- let MFintersections = intersectOutlines(moduleField.outline, i)
143
- if (MFintersections.length > 0) {
144
- return true
145
- }
146
- })
147
- } else {
148
- if (pointer && pointer.reality_x && pointer.reality_y) {
149
- let P = {
150
- x: pointer.reality_x,
151
- y: pointer.reality_y,
152
- z: 0,
153
- }
154
- let pointerIntersections = selfIntersections.filter((outline) =>
155
- isInsidePolygon(P, outline)
156
- )
157
- if (pointerIntersections.length) {
158
- selfIntersections = pointerIntersections
159
- }
160
- }
161
- }
162
- let sortedSelfIntersections = selfIntersections.sort(
163
- (a, b) => calculateArea(b) - calculateArea(a)
164
- )
165
- if (sortedSelfIntersections.length) {
166
- roofInnerMarginOutline = sortedSelfIntersections[0]
167
- isOutlineSelfIntersecting = true
168
- }
169
- }
170
- return {
171
- isSelfIntersecting: isOutlineSelfIntersecting,
172
- outline: roofInnerMarginOutline,
173
- totalArea: sumAllArea,
174
- }
175
- }
176
-
177
- export function getModuleFieldRoofIntersections(
178
- moduleField,
179
- roofInnerMarginOutline
180
- ) {
181
- const roof = moduleField.roof
182
- let intersections = intersectOutlines(
183
- roofInnerMarginOutline,
184
- moduleField.outline
185
- )
186
-
187
- intersections = intersections.map((i) =>
188
- i.map((v) => {
189
- return {
190
- ...v,
191
- z: verticalProjectionOnPlane(v, roof.normalVector, roof.flatOutline[0])
192
- .z,
193
- }
194
- })
195
- )
196
-
197
- return intersections
198
- }
199
-
200
- export function getModuleFieldHoleOutlines(moduleField) {
201
- const obstacles = []
202
- const roof = moduleField.roof
203
- if (roof.moduleFields && roof.moduleFields.length > 0) {
204
- obstacles.push(
205
- ...roof.moduleFields.filter((obstacle) => {
206
- return (
207
- obstacle.id != moduleField.id && //obstacle cannot be MF itself
208
- obstacle.panels &&
209
- obstacle.panels.length > 0 && //obstacle cannot be a moduleField without panels on
210
- !isPolygonInsidePolygon(moduleField.outline, obstacle.outline) && //obstacle cannot be a container of the polygon we try to compute
211
- (obstacle.priority >= moduleField.priority ||
212
- isPolygonInsidePolygon(obstacle.outline, moduleField.outline)) //obstacle cannot be a MF with lower prio level (except if fully inside)
213
- )
214
- })
215
- )
216
- }
217
-
218
- let groupedConcavePanelOutlines = []
219
- obstacles.forEach((moduleField) => {
220
- if (moduleField.panels.length) {
221
- let groupedConcavePanelData = getConcaveOutlines(
222
- moduleField.panels,
223
- moduleField.panels[0].outline
224
- )
225
- groupedConcavePanelOutlines.push(...groupedConcavePanelData.outlines)
226
- }
227
- })
228
-
229
- function verticalProjectionOnRoofFlatFace(v) {
230
- const projectedZ = verticalProjectionOnPlane(
231
- v,
232
- roof.normalVector,
233
- roof.flatOutline[0]
234
- ).z
235
- return { ...v, z: projectedZ }
236
- }
237
-
238
- groupedConcavePanelOutlines = groupedConcavePanelOutlines.map((outline) =>
239
- outline.map((v) => verticalProjectionOnRoofFlatFace(v)).reverse()
240
- )
241
-
242
- const roofObstacleOutlines = roof.holes.map((hole) =>
243
- hole.margins.outterOutline.map((v) => verticalProjectionOnRoofFlatFace(v))
244
- )
245
- const obstacleOutLine = [
246
- ...roofObstacleOutlines,
247
- ...groupedConcavePanelOutlines,
248
- ]
249
-
250
- return obstacleOutLine
251
- }
@@ -1,5 +1,3 @@
1
- import * as THREE from 'three'
2
-
3
1
  export default {
4
2
  methods: {
5
3
  clearThreeObjects(obj) {
@@ -33,7 +31,18 @@ export default {
33
31
  return
34
32
  }
35
33
  scene.remove(mesh)
36
- this.disposeMesh(mesh)
34
+ if (mesh.geometry && mesh.geometry.dispose) {
35
+ mesh.geometry.dispose()
36
+ mesh.geometry = null
37
+ }
38
+ if (mesh.texture && mesh.texture.dispose) {
39
+ mesh.texture.dispose()
40
+ mesh.texture = null
41
+ }
42
+ if (mesh.material && mesh.material.dispose) {
43
+ mesh.material.dispose()
44
+ mesh.material = null
45
+ }
37
46
  if (
38
47
  mesh.userData.meshId &&
39
48
  this.meshes[mesh.userData.type][mesh.userData.meshId]
@@ -59,24 +68,19 @@ export default {
59
68
  })
60
69
  },
61
70
  clearByType(type) {
62
- Object.values(this.meshes[type]).forEach((object) => {
63
- object instanceof THREE.Group
64
- ? object.children.forEach((c) => this.disposeMesh(c))
65
- : this.disposeMesh(object)
66
- this.scene.remove(object)
71
+ Object.values(this.meshes[type]).forEach((mesh) => {
72
+ mesh.geometry.dispose()
73
+ mesh.geometry = null
74
+ if (mesh.material && mesh.material.dispose) {
75
+ mesh.material.dispose()
76
+ }
77
+ mesh.material = null
78
+ this.scene.remove(mesh)
67
79
  })
68
80
  this.meshes[type] = {}
69
81
  if (this.renderer) {
70
82
  this.renderer.renderLists.dispose()
71
83
  }
72
84
  },
73
- disposeMesh(mesh) {
74
- if (mesh.geometry && mesh.geometry.dispose) mesh.geometry.dispose()
75
- if (mesh.material && mesh.material.dispose) mesh.material.dispose()
76
- if (mesh.texture && mesh.texture.dispose) mesh.texture.dispose()
77
- mesh.geometry = null
78
- mesh.material = null
79
- mesh.texture = null
80
- },
81
85
  },
82
86
  }
@@ -88,9 +88,10 @@ export default {
88
88
  cylinder.userData.type = 'edgeMeshes'
89
89
  cylinder.userData.layer = edge.layer
90
90
  cylinder.frustumCulled = false
91
+ cylinder.renderOrder = 10
91
92
 
92
93
  cylinder.frustumCulled = false
93
- cylinder.renderOrder = 15
94
+ cylinder.renderOrder = 10
94
95
  this.meshes.edgeMeshes[edge.id] = cylinder
95
96
  this.scene.add(cylinder)
96
97
  }
@@ -410,7 +410,7 @@ export function getBufferObstacleSideGeometry(obstaclePolygon, roofPolygon) {
410
410
 
411
411
  export function getBufferModuleFieldGeometry(moduleFieldPolygon) {
412
412
  const roofPolygon = moduleFieldPolygon.roof
413
- const moduleHeight = 20
413
+ const moduleHeight = 10
414
414
  //get lowest verticalProjection
415
415
  const normalVector = roofPolygon.normalVector
416
416
 
@@ -747,55 +747,3 @@ export function getExtrusionGeometry(
747
747
  const geometry = new THREE.ExtrudeGeometry(shapes, settings)
748
748
  return geometry
749
749
  }
750
-
751
- export function getFittingPanelsBufferGeometry(
752
- outline,
753
- holes = [],
754
- moduleFieldPolygon
755
- ) {
756
- const croppedHolesOutline = holes
757
- .map((hole) => {
758
- const cropedHoleOutline = intersectOutlines(hole, outline)[0] || []
759
- return cropedHoleOutline.map((p) => {
760
- return {
761
- x: p.x,
762
- y: p.y,
763
- z: verticalProjectionOnPlane(
764
- p,
765
- moduleFieldPolygon.normalVector,
766
- moduleFieldPolygon.flatOutline[0]
767
- ).z,
768
- }
769
- })
770
- })
771
- .filter((outline) => !!outline)
772
-
773
- // add offset to vertices for rendering
774
- const FITTING_PANELS_OFFSET = 2
775
- const vectorOffset = multiplyVector(
776
- FITTING_PANELS_OFFSET,
777
- moduleFieldPolygon.normalVector
778
- )
779
-
780
- const offsetOutline = outline.map((point) => addVector(point, vectorOffset))
781
- const offsetHolesOutline = croppedHolesOutline.map((outline) =>
782
- outline.map((point) => addVector(point, vectorOffset))
783
- )
784
-
785
- const geometry = new THREE.BufferGeometry()
786
- const triangleVertices = getTriangleVerticesFromOutline(
787
- offsetOutline,
788
- offsetHolesOutline
789
- )
790
- if (hasNaN(triangleVertices)) {
791
- return null
792
- }
793
- const vertices = new Float32Array(triangleVertices)
794
-
795
- const uvs = new Float32Array([1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0])
796
- geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
797
- geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2))
798
- geometry.computeVertexNormals()
799
- geometry.userData.version = 0
800
- return geometry
801
- }
@@ -1,105 +1,43 @@
1
1
  import * as THREE from 'three'
2
- import {
3
- getBufferModuleFieldGeometry,
4
- getFittingPanelsBufferGeometry,
5
- } from './geometryHandler'
6
-
2
+ import { getBufferModuleFieldGeometry } from './geometryHandler'
7
3
  export default {
8
- data() {
9
- return {
10
- areModuleFieldsVisible: true,
11
- }
12
- },
13
4
  methods: {
5
+ data() {
6
+ return {
7
+ areModuleFieldsVisible: true,
8
+ }
9
+ },
14
10
  renderModuleFields() {
15
11
  this.clearByType('moduleFieldsMeshes')
16
12
  const moduleFieldPolygons = this.polygons.filter((p) =>
17
13
  ['moduleField', 'tmpModuleField'].includes(p.layer)
18
14
  )
19
15
  moduleFieldPolygons.forEach((moduleFieldPolygon) => {
20
- const panelOverrideMesh =
21
- this.renderModuleFieldPanelOverride(moduleFieldPolygon)
22
- const fittingPanelsMesh =
23
- this.renderModuleFieldFittingPanels(moduleFieldPolygon)
24
-
25
- if (!panelOverrideMesh && !fittingPanelsMesh) return
26
-
27
- const meshList = [panelOverrideMesh, fittingPanelsMesh]
28
- const group = new THREE.Group()
29
- meshList.forEach((mesh) => {
30
- if (mesh) group.add(mesh)
31
- })
32
- group.matrixAutoUpdate = false
33
- group.userData.version = moduleFieldPolygon.version
34
- group.userData.type = 'moduleFieldsMeshes'
35
- group.userData.layer = moduleFieldPolygon.layer
36
- group.userData.meshId = moduleFieldPolygon.id
37
- group.userData.polygonId = moduleFieldPolygon.id
38
- group.visible = this.areModuleFieldsVisible && this.panelOpacity === 1
39
- this.scene.add(group)
40
- this.meshes.moduleFieldsMeshes[moduleFieldPolygon.id] = group
41
- return
42
- })
43
- },
44
- renderModuleFieldPanelOverride(moduleFieldPolygon) {
45
- if (!moduleFieldPolygon?.data?.number_of_panels_override) return
46
- const geometry = getBufferModuleFieldGeometry(moduleFieldPolygon)
47
- const material = this.material.moduleFieldWithPanelOveride
48
- if (geometry) {
49
- const mesh = new THREE.Mesh(geometry, material)
50
- mesh.matrixAutoUpdate = false
51
- mesh.userData.version = moduleFieldPolygon.version
52
- mesh.userData.type = 'moduleFieldsMeshes_panelOverride'
53
- mesh.userData.layer = moduleFieldPolygon.layer
54
- mesh.userData.meshId = moduleFieldPolygon.id
55
- mesh.userData.polygonId = moduleFieldPolygon.id
56
- mesh.renderOrder = 5
57
- return mesh
58
- }
59
- },
60
- renderModuleFieldFittingPanels(moduleFieldPolygon) {
61
- if (!moduleFieldPolygon?.fittingPanels?.polygons?.length) return
62
- const { polygons, visible, color } = moduleFieldPolygon.fittingPanels
63
-
64
- const geometries = []
65
- polygons.forEach((polygon) => {
66
- const { outline, holes } = polygon
67
- const geometry = getFittingPanelsBufferGeometry(
68
- outline,
69
- holes,
70
- moduleFieldPolygon
71
- )
72
- geometries.push(geometry)
73
- })
74
-
75
- if (!geometries.length) return
76
-
77
- const mergedGeometry = this.createMergedGeometry(geometries)
78
- const isTransparent = color === 'transparent'
79
- const material = new THREE.MeshBasicMaterial({
80
- color: isTransparent ? '#ffffff' : color,
81
- side: THREE.DoubleSide,
82
- transparent: true,
83
- opacity: isTransparent ? 0.2 : 0.8,
16
+ let material
17
+ if (moduleFieldPolygon.data.number_of_panels_override) {
18
+ material = this.material.moduleFieldWithPanelOveride
19
+ } else {
20
+ return
21
+ }
22
+ const geometry = getBufferModuleFieldGeometry(moduleFieldPolygon)
23
+ if (geometry) {
24
+ const mesh = new THREE.Mesh(geometry, material)
25
+ mesh.matrixAutoUpdate = false
26
+ mesh.userData.version = moduleFieldPolygon.version
27
+ mesh.userData.type = 'moduleFieldsMeshes'
28
+ mesh.userData.layer = moduleFieldPolygon.layer
29
+ mesh.userData.meshId = moduleFieldPolygon.id
30
+ mesh.userData.polygonId = moduleFieldPolygon.id
31
+ mesh.visible = this.areModuleFieldsVisible
32
+ this.scene.add(mesh)
33
+ this.meshes.moduleFieldsMeshes[moduleFieldPolygon.id] = mesh
34
+ }
84
35
  })
85
-
86
- const mesh = new THREE.Mesh(mergedGeometry, material)
87
- mesh.visible = visible
88
- mesh.matrixAutoUpdate = false
89
- mesh.userData.version = moduleFieldPolygon.version
90
- mesh.userData.type = 'moduleFieldsMeshes_fittingPanels'
91
- mesh.userData.layer = moduleFieldPolygon.layer
92
- mesh.userData.meshId = moduleFieldPolygon.id
93
- mesh.userData.polygonId = moduleFieldPolygon.id
94
- mesh.renderOrder = 5
95
- return mesh
96
36
  },
97
- updateModuleFieldsVisibility(isVisible) {
37
+ setModuleFieldsVisibility(isVisible) {
98
38
  this.areModuleFieldsVisible = isVisible
99
39
  Object.values(this.meshes['moduleFieldsMeshes']).forEach(
100
- (mesh) =>
101
- (mesh.visible =
102
- this.areModuleFieldsVisible && this.panelOpacity === 1)
40
+ (mesh) => (mesh.visible = isVisible)
103
41
  )
104
42
  },
105
43
  },
@@ -295,7 +295,7 @@ export default {
295
295
  mesh.castShadow = false
296
296
  mesh.updateMatrix()
297
297
  } else {
298
- material = new THREE.MeshPhongMaterial({
298
+ material = new THREE.MeshPhysicalMaterial({
299
299
  map: texture,
300
300
  color: 0xffffff,
301
301
  side: THREE.FrontSide,
@@ -448,7 +448,7 @@ export default {
448
448
  googleMapType
449
449
  )
450
450
  }
451
- planeMaterial[indexGoogleBackground] = new THREE.MeshPhongMaterial({
451
+ planeMaterial[indexGoogleBackground] = new THREE.MeshPhysicalMaterial({
452
452
  map: planeTexture[indexGoogleBackground],
453
453
  side: THREE.DoubleSide,
454
454
  shininess: 0,
@@ -302,11 +302,6 @@ export default {
302
302
  method: this.renderPanels,
303
303
  arg: [],
304
304
  })
305
- methodList.push({
306
- name: 'updateModuleFieldsVisibility',
307
- method: this.updateModuleFieldsVisibility,
308
- arg: [this.areModuleFieldsVisible],
309
- })
310
305
  break
311
306
  case 'addPointToPolygon': //params.polygon,index
312
307
  case 'removeObstacle': //params:obstacle
@@ -427,18 +422,11 @@ export default {
427
422
  break
428
423
  case 'updateIsYearlyShadingHeatmapActive':
429
424
  methodList.push({
430
- name: 'updateModuleFieldsVisibility',
431
- method: this.updateModuleFieldsVisibility,
425
+ name: 'setModuleFieldsVisibility',
426
+ method: this.setModuleFieldsVisibility,
432
427
  arg: [!params.value],
433
428
  })
434
429
  break
435
- case 'updateModuleFieldsVisibility':
436
- methodList.push({
437
- name: 'updateModuleFieldsVisibility',
438
- method: this.updateModuleFieldsVisibility,
439
- arg: [params.value],
440
- })
441
- break
442
430
  case 'selectedPanelChange':
443
431
  methodList.push({
444
432
  name: 'renderModuleFields',
@@ -2,15 +2,13 @@
2
2
  import {
3
3
  Polygon,
4
4
  updateComputedGeometryPolygon,
5
+ getRoofMarginOutline,
5
6
  getObstacleMarginOutline,
7
+ midPoint,
6
8
  } from '@eturnity/eturnity_maths'
7
9
  import OverlayLayer from '../Overlay/OverlayLayer'
8
10
  import getLayers from '../utils/layers'
9
11
  import { UpdateRoofObstacleRelations } from '../helper/UpdateRoofObstacleRelations'
10
- import {
11
- updateModuleFieldFittingPanels,
12
- UpdateRoofModuleFieldRelations,
13
- } from '../helper/UpdateRoofModuleFieldRelations'
14
12
  function sanitizedOutline(outline) {
15
13
  return outline.reduce((accumulator, currentValue) => {
16
14
  if (
@@ -130,7 +128,6 @@ export async function hydratePolygons({
130
128
  moduleField.mountingData = {}
131
129
  moduleField.pvData.module_texture_version_id =
132
130
  moduleFieldResp.module_texture_version_id
133
- moduleField.pvData.backsheet_color = moduleFieldResp.backsheet_color
134
131
  moduleField.data = {}
135
132
  moduleField.data.texture_img_url = moduleFieldResp.texture_img_url
136
133
  moduleField.data.col_spacing_mm = moduleFieldResp.col_spacing_mm
@@ -141,8 +138,7 @@ export async function hydratePolygons({
141
138
  moduleField.data.row_spacing_valley_mm =
142
139
  moduleFieldResp.row_spacing_valley_mm
143
140
  moduleField.data.offset_percent = moduleFieldResp.offset_percent
144
- moduleField.data.fitting_panel_area_m2 =
145
- moduleFieldResp.fitting_panel_area_m2
141
+ moduleField.data.fitting_panel_area_m2 = moduleFieldResp.fitting_panel_area_m2
146
142
  moduleField.data.has_fitting_panels = moduleFieldResp.has_fitting_panels
147
143
  moduleField.data.panel_orientation = moduleFieldResp.panel_orientation
148
144
  moduleField.data.panel_direction_degrees =
@@ -299,10 +295,4 @@ export async function hydrateData({ state, commit }, data) {
299
295
  state.polygons = hydratationResult.polygons
300
296
 
301
297
  state = UpdateRoofObstacleRelations(state)
302
- state = UpdateRoofModuleFieldRelations(state)
303
- state.polygons
304
- .filter((poly) => poly.layer == 'moduleField')
305
- .forEach((moduleField) => {
306
- updateModuleFieldFittingPanels(moduleField)
307
- })
308
298
  }