@eturnity/eturnity_3d 8.19.3 → 8.22.0-EPDM-13091.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.19.3",
4
+ "version": "8.22.0-EPDM-13091.0",
5
5
  "files": [
6
6
  "dist",
7
7
  "src"
@@ -16,7 +16,7 @@
16
16
  "merge-remote-master": "node scripts/merge-remote-master.js"
17
17
  },
18
18
  "dependencies": {
19
- "@eturnity/eturnity_maths": "8.19.0",
19
+ "@eturnity/eturnity_maths": "8.19.0-EPDM-13091.1",
20
20
  "@originjs/vite-plugin-commonjs": "1.0.3",
21
21
  "core-js": "3.30.2",
22
22
  "cors": "2.8.5",
package/src/config.js CHANGED
@@ -282,3 +282,14 @@ 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: '#2B3A67',
289
+ brown: '#623A36',
290
+ 'rustic red': '#713229',
291
+ terracotta: '#A76448',
292
+ transparent: 'transparent',
293
+ white: '#ffffff',
294
+ default: '#0068DE',
295
+ }
@@ -3,7 +3,11 @@ import {
3
3
  verticalProjectionOnPlane,
4
4
  intersectOutlines,
5
5
  calculateArea,
6
+ isSelfIntersecting,
7
+ isPolygonInsidePolygon,
8
+ getConcaveOutlines,
6
9
  } from '@eturnity/eturnity_maths'
10
+ import { fittingPanelsColorMap } from '../config'
7
11
  //this function just update the "roof" and "moduleField(s)" properties of panels,moduleFields and roofs
8
12
  export function UpdateRoofModuleFieldRelations(state) {
9
13
  let moduleFields = state.polygons.filter(
@@ -78,3 +82,170 @@ export function removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state) {
78
82
  ]
79
83
  return state
80
84
  }
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,3 +1,5 @@
1
+ import * as THREE from 'three'
2
+
1
3
  export default {
2
4
  methods: {
3
5
  clearThreeObjects(obj) {
@@ -31,18 +33,7 @@ export default {
31
33
  return
32
34
  }
33
35
  scene.remove(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
- }
36
+ this.disposeMesh(mesh)
46
37
  if (
47
38
  mesh.userData.meshId &&
48
39
  this.meshes[mesh.userData.type][mesh.userData.meshId]
@@ -68,19 +59,24 @@ export default {
68
59
  })
69
60
  },
70
61
  clearByType(type) {
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)
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)
79
67
  })
80
68
  this.meshes[type] = {}
81
69
  if (this.renderer) {
82
70
  this.renderer.renderLists.dispose()
83
71
  }
84
72
  },
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
+ },
85
81
  },
86
82
  }
@@ -88,10 +88,9 @@ export default {
88
88
  cylinder.userData.type = 'edgeMeshes'
89
89
  cylinder.userData.layer = edge.layer
90
90
  cylinder.frustumCulled = false
91
- cylinder.renderOrder = 10
92
91
 
93
92
  cylinder.frustumCulled = false
94
- cylinder.renderOrder = 10
93
+ cylinder.renderOrder = 15
95
94
  this.meshes.edgeMeshes[edge.id] = cylinder
96
95
  this.scene.add(cylinder)
97
96
  }
@@ -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 = 10
413
+ const moduleHeight = 20
414
414
  //get lowest verticalProjection
415
415
  const normalVector = roofPolygon.normalVector
416
416
 
@@ -747,3 +747,55 @@ 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,5 +1,9 @@
1
1
  import * as THREE from 'three'
2
- import { getBufferModuleFieldGeometry } from './geometryHandler'
2
+ import {
3
+ getBufferModuleFieldGeometry,
4
+ getFittingPanelsBufferGeometry,
5
+ } from './geometryHandler'
6
+
3
7
  export default {
4
8
  data() {
5
9
  return {
@@ -13,31 +17,89 @@ export default {
13
17
  ['moduleField', 'tmpModuleField'].includes(p.layer)
14
18
  )
15
19
  moduleFieldPolygons.forEach((moduleFieldPolygon) => {
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
- }
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
35
42
  })
36
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,
84
+ })
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
+ },
37
97
  updateModuleFieldsVisibility(isVisible) {
38
98
  this.areModuleFieldsVisible = isVisible
39
99
  Object.values(this.meshes['moduleFieldsMeshes']).forEach(
40
- (mesh) => (mesh.visible = isVisible)
100
+ (mesh) =>
101
+ (mesh.visible =
102
+ this.areModuleFieldsVisible && this.panelOpacity === 1)
41
103
  )
42
104
  },
43
105
  },
@@ -302,6 +302,11 @@ 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
+ })
305
310
  break
306
311
  case 'addPointToPolygon': //params.polygon,index
307
312
  case 'removeObstacle': //params:obstacle
@@ -420,13 +425,6 @@ export default {
420
425
  arg: [],
421
426
  })
422
427
  break
423
- case 'updateIsYearlyShadingHeatmapActive':
424
- methodList.push({
425
- name: 'updateModuleFieldsVisibility',
426
- method: this.updateModuleFieldsVisibility,
427
- arg: [!params.value],
428
- })
429
- break
430
428
  case 'updateModuleFieldsVisibility':
431
429
  methodList.push({
432
430
  name: 'updateModuleFieldsVisibility',
@@ -2,13 +2,18 @@
2
2
  import {
3
3
  Polygon,
4
4
  updateComputedGeometryPolygon,
5
- getRoofMarginOutline,
6
5
  getObstacleMarginOutline,
7
- midPoint,
6
+ multiplyVector,
7
+ addVector,
8
+ Vector,
8
9
  } from '@eturnity/eturnity_maths'
9
10
  import OverlayLayer from '../Overlay/OverlayLayer'
10
11
  import getLayers from '../utils/layers'
11
12
  import { UpdateRoofObstacleRelations } from '../helper/UpdateRoofObstacleRelations'
13
+ import {
14
+ updateModuleFieldFittingPanels,
15
+ UpdateRoofModuleFieldRelations,
16
+ } from '../helper/UpdateRoofModuleFieldRelations'
12
17
  function sanitizedOutline(outline) {
13
18
  return outline.reduce((accumulator, currentValue) => {
14
19
  if (
@@ -24,6 +29,33 @@ function sanitizedOutline(outline) {
24
29
  return accumulator
25
30
  }, [])
26
31
  }
32
+ export function getModuleOutline({ module, grid, offset }) {
33
+ // const convertedOffset =
34
+ // offset == 33 ? 100 / 3 : offset == 66 ? 200 / 3 : offset
35
+
36
+ const rowIndex = module.row_index
37
+ const colIndex = module.col_index
38
+ const gridRowVector = new Vector(grid.grid_row_vector)
39
+ const gridColVector = new Vector(grid.grid_column_vector)
40
+ // const rowOffsetVector = multiplyVector(
41
+ // (convertedOffset * rowIndex) / 100,
42
+ // gridColVector
43
+ // )
44
+ const panelHeightVector = new Vector(grid.panel_height_vector)
45
+ const panelWidthVector = new Vector(grid.panel_width_vector)
46
+ const gridOrigin = new Vector(grid.grid_origin)
47
+ //const offsetOrigin = addVector(gridOrigin, rowOffsetVector)
48
+ const localA = addVector(
49
+ multiplyVector(rowIndex, gridRowVector),
50
+ multiplyVector(colIndex, gridColVector)
51
+ )
52
+ const A = addVector(gridOrigin, localA)
53
+ const B = addVector(A, panelHeightVector)
54
+ const C = addVector(A, addVector(panelHeightVector, panelWidthVector))
55
+ const D = addVector(A, panelWidthVector)
56
+ return [A, B, C, D]
57
+ }
58
+
27
59
  export async function hydratePolygons({
28
60
  roofsResponse = [],
29
61
  obstaclesResponse = [],
@@ -128,6 +160,7 @@ export async function hydratePolygons({
128
160
  moduleField.mountingData = {}
129
161
  moduleField.pvData.module_texture_version_id =
130
162
  moduleFieldResp.module_texture_version_id
163
+ moduleField.pvData.backsheet_color = moduleFieldResp.backsheet_color
131
164
  moduleField.data = {}
132
165
  moduleField.data.texture_img_url = moduleFieldResp.texture_img_url
133
166
  moduleField.data.col_spacing_mm = moduleFieldResp.col_spacing_mm
@@ -138,7 +171,8 @@ export async function hydratePolygons({
138
171
  moduleField.data.row_spacing_valley_mm =
139
172
  moduleFieldResp.row_spacing_valley_mm
140
173
  moduleField.data.offset_percent = moduleFieldResp.offset_percent
141
- moduleField.data.fitting_panel_area_m2 = moduleFieldResp.fitting_panel_area_m2
174
+ moduleField.data.fitting_panel_area_m2 =
175
+ moduleFieldResp.fitting_panel_area_m2
142
176
  moduleField.data.has_fitting_panels = moduleFieldResp.has_fitting_panels
143
177
  moduleField.data.panel_orientation = moduleFieldResp.panel_orientation
144
178
  moduleField.data.panel_direction_degrees =
@@ -166,56 +200,45 @@ export async function hydratePolygons({
166
200
  moduleField.pvModuleId = moduleFieldResp.pv_module_id
167
201
  moduleField.mountingSystemId = moduleFieldResp.mounting_system_id
168
202
 
203
+ moduleField.data.moduleGrids = moduleFieldResp.module_grids
204
+
169
205
  const modules = []
170
- moduleFieldResp.modules.forEach((module) => {
171
- modules.push({
172
- ...module,
173
- status: module.status || 'active',
174
- clipped: module.clipped === undefined ? false : module.clipped,
175
- })
176
- })
177
- if (moduleFieldResp.user_deactivated_modules) {
178
- moduleFieldResp.user_deactivated_modules.forEach((module) => {
206
+ moduleFieldResp.module_grids.forEach((grid, gridIndex) => {
207
+ grid.modules.forEach((module) => {
179
208
  modules.push({
180
209
  ...module,
181
- status: 'user_deactivated',
182
- clipped: module.clipped === undefined ? false : module.clipped,
183
- })
184
- })
185
- }
186
- moduleField.data.modules = modules
187
- modules
188
- .filter((m) => !m.clipped)
189
- .forEach((module) => {
190
- const outline = module.outline.map((p) => {
191
- return { x: p[0], y: p[1], z: p[2] }
210
+ outline: getModuleOutline({
211
+ module,
212
+ grid,
213
+ offset: moduleFieldResp.offset_percent,
214
+ }),
215
+ gridIndex: gridIndex,
192
216
  })
193
- let panel = new Polygon(outline, '')
194
- panel.id = module.module_uuid
195
- panel.row_index = module.row_index
196
- panel.col_index = module.col_index
197
- panel.status = module.status
198
- panel.clipped = module.clipped
199
- panel.moduleField = moduleField
200
- panel.poolGroupUuid = module.project_variant_pool_group_uuid
201
- if (panel.poolGroupUuid) {
202
- panel.poolGroupUuidColor = `#${panel.poolGroupUuid.slice(0, 6)}`
203
- }
204
- panel.available = true
205
- switch (module.status) {
206
- case 'active':
207
- panel.layer = 'panel'
208
- MFpanels.push(panel)
209
- panels.push(panel)
210
- break
211
- case 'user_deactivated':
212
- panel.layer = 'user_deactivated_panel'
213
- MFuserDeactivatedPanels.push(panel)
214
- userDeactivatedPanels.push(panel)
215
- break
216
- }
217
- panel = updateComputedGeometryPolygon(panel)
218
217
  })
218
+ })
219
+
220
+ modules.forEach((module) => {
221
+ const panel = new Polygon(module.outline, '')
222
+ panel.id = module.module_uuid
223
+ panel.row_index = module.row_index
224
+ panel.col_index = module.col_index
225
+ panel.is_active = module.is_active
226
+ panel.moduleField = moduleField
227
+ panel.poolGroupUuid = module.project_variant_pool_group_uuid
228
+ if (panel.poolGroupUuid) {
229
+ panel.poolGroupUuidColor = `#${panel.poolGroupUuid.slice(0, 6)}`
230
+ }
231
+ panel.available = true
232
+ if (module.is_active) {
233
+ panel.layer = 'panel'
234
+ MFpanels.push(panel)
235
+ panels.push(panel)
236
+ } else {
237
+ panel.layer = 'user_deactivated_panel'
238
+ MFuserDeactivatedPanels.push(panel)
239
+ userDeactivatedPanels.push(panel)
240
+ }
241
+ })
219
242
 
220
243
  const roof = roofs.find((r) => r.id == moduleFieldResp.roof_uuid)
221
244
  if (roof) {
@@ -295,4 +318,10 @@ export async function hydrateData({ state, commit }, data) {
295
318
  state.polygons = hydratationResult.polygons
296
319
 
297
320
  state = UpdateRoofObstacleRelations(state)
321
+ state = UpdateRoofModuleFieldRelations(state)
322
+ state.polygons
323
+ .filter((poly) => poly.layer == 'moduleField')
324
+ .forEach((moduleField) => {
325
+ updateModuleFieldFittingPanels(moduleField)
326
+ })
298
327
  }