@eturnity/eturnity_3d 9.19.0 → 9.25.1-9.25-dev-03.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,15 +1,22 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_3d",
3
3
  "private": false,
4
- "version": "9.19.0",
4
+ "version": "9.25.1-9.25-dev-03.0",
5
5
  "files": [
6
6
  "dist",
7
7
  "src"
8
8
  ],
9
9
  "main": "./dist/main.umd.js",
10
10
  "module": "./dist/main.es.js",
11
+ "scripts": {
12
+ "dev": "vite",
13
+ "build": "vite build",
14
+ "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src`",
15
+ "prettier": "prettier --write \"**/*.{js,vue}\"",
16
+ "merge-remote-master": "node scripts/merge-remote-master.js"
17
+ },
11
18
  "dependencies": {
12
- "@eturnity/eturnity_maths": "9.19.0",
19
+ "@eturnity/eturnity_maths": "9.25.0-panel-placement.1",
13
20
  "@originjs/vite-plugin-commonjs": "1.0.3",
14
21
  "core-js": "3.30.2",
15
22
  "cors": "2.8.5",
@@ -53,12 +60,5 @@
53
60
  "require": "./dist/main.umd.js"
54
61
  },
55
62
  "./src/*": "./src/*"
56
- },
57
- "scripts": {
58
- "dev": "vite",
59
- "build": "vite build",
60
- "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src`",
61
- "prettier": "prettier --write \"**/*.{js,vue}\"",
62
- "merge-remote-master": "node scripts/merge-remote-master.js"
63
63
  }
64
- }
64
+ }
@@ -26,7 +26,6 @@
26
26
  layers: null,
27
27
  provider: null,
28
28
  pointer: { x: 0, y: 0 },
29
- areUserDeactivatedPanelsVisible: false,
30
29
  animationFrameId: null,
31
30
  intervalId: null,
32
31
  intervalEventId: null,
@@ -55,7 +54,6 @@
55
54
  obstacles: 'getObstacles',
56
55
  moduleFields: 'getModuleFields',
57
56
  panels: 'getPanels',
58
- userDeactivatedPanels: 'getUserDeactivatedPanels',
59
57
  }),
60
58
  },
61
59
  watch: {
package/src/config.js CHANGED
@@ -49,11 +49,6 @@ export const layerColors = {
49
49
  strokeColor: '#ffffff',
50
50
  strokeWidth: 1,
51
51
  },
52
- user_deactivated_panel: {
53
- fillColor: 'rgba(115, 115, 229, 0.1)',
54
- strokeColor: 'white',
55
- strokeWidth: 2,
56
- },
57
52
  selectedPanel: {
58
53
  fillColor: '#0068DE80',
59
54
  strokeColor: theme.colors.blue,
@@ -126,11 +121,6 @@ export const layerColors = {
126
121
  strokeColor: theme.colors.blueElectric,
127
122
  strokeWidth: 5,
128
123
  },
129
- tmpModuleField: {
130
- fillColor: 'rgba(115, 115, 229, 0.2)',
131
- strokeColor: theme.colors.blue,
132
- strokeWidth: 1,
133
- },
134
124
  selectedModuleField: {
135
125
  fillColor: '#0068DEA0',
136
126
  strokeColor: theme.colors.blue,
@@ -15,9 +15,8 @@ export function UpdateRoofModuleFieldRelations(state) {
15
15
  )
16
16
  let roofs = state.polygons.filter((poly) => poly.layer == 'roof')
17
17
  const panels = state.polygons.filter((poly) =>
18
- ['panel', 'user_deactivated_panel'].includes(poly.layer)
18
+ ['panel'].includes(poly.layer)
19
19
  )
20
-
21
20
  let roofUnderPerModuleFieldId = {}
22
21
  moduleFields.forEach((moduleField) => {
23
22
  let roofModuleFieldIntersections = []
@@ -47,6 +46,11 @@ export function UpdateRoofModuleFieldRelations(state) {
47
46
  moduleFields.forEach((moduleField) => {
48
47
  let roof = roofUnderPerModuleFieldId[moduleField.id]
49
48
  if (roof) {
49
+ if (moduleField.hasError) {
50
+ moduleField.hasError = false
51
+ moduleField.warnings = []
52
+ moduleField.hasWarnings = false
53
+ }
50
54
  moduleField.roof = roof
51
55
  roof.moduleFields.push(moduleField)
52
56
  panels.forEach((panel) => {
@@ -54,6 +58,13 @@ export function UpdateRoofModuleFieldRelations(state) {
54
58
  panel.roof = roof
55
59
  }
56
60
  })
61
+ } else if (moduleField.panels && moduleField.panels.length > 0) {
62
+ moduleField.roof = null
63
+ if (!moduleField.hasError) {
64
+ moduleField.hasError = true
65
+ moduleField.warnings = ['module_field_warning_roof_missing']
66
+ moduleField.hasWarnings = true
67
+ }
57
68
  }
58
69
  })
59
70
  state = removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state)
@@ -65,36 +76,46 @@ export function removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state) {
65
76
  ['roof', 'obstacle'].includes(polygon.layer)
66
77
  )
67
78
  const remainingModuleFields = state.polygons.filter(
68
- (polygon) => polygon.layer == 'moduleField' && !!polygon.roof
79
+ (polygon) =>
80
+ polygon.layer == 'moduleField' && (!!polygon.roof || polygon.hasError)
69
81
  )
70
- const remainingPanels = state.polygons.filter(
71
- (polygon) => polygon.layer == 'panel' && !!polygon.roof
82
+ const retainedModuleFieldIds = new Set(
83
+ remainingModuleFields.map((mf) => mf.id)
72
84
  )
73
- const remainingUserDeactivatedPanels = state.polygons.filter(
74
- (polygon) => polygon.layer == 'user_deactivated_panel' && !!polygon.roof
85
+ const remainingPanels = state.polygons.filter(
86
+ (polygon) =>
87
+ polygon.layer == 'panel' &&
88
+ (!!polygon.roof || retainedModuleFieldIds.has(polygon.moduleField?.id))
75
89
  )
76
-
77
90
  state.polygons = [
78
91
  ...remainingPolygons,
79
92
  ...remainingModuleFields,
80
93
  ...remainingPanels,
81
- ...remainingUserDeactivatedPanels,
82
94
  ]
83
95
  return state
84
96
  }
85
97
 
86
98
  export function updateModuleFieldFittingPanels(moduleField) {
99
+ const { has_fitting_panels, fitting_panel_area_m2 } = moduleField.data || {}
100
+ if (!(has_fitting_panels && fitting_panel_area_m2 > 0)) {
101
+ delete moduleField.fittingPanels
102
+ return
103
+ }
104
+ clipModuleFieldFittingPanels(moduleField)
105
+ }
106
+
107
+ export function clipModuleFieldFittingPanels(moduleField) {
108
+ const prevVisible = moduleField?.fittingPanels?.visible
87
109
  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 = []
110
+ if (!moduleField?.panels?.length) return
111
+ if (!moduleField?.roof || !moduleField.data?.has_fitting_panels) return
112
+ const innerOutline = moduleField.roof.margins?.innerOutline
113
+ if (!innerOutline?.length) return
92
114
 
93
- const outlines = getModuleFieldRoofIntersections(
94
- moduleField,
95
- moduleField.roof.margins.innerOutline
96
- )
115
+ const outlines = getModuleFieldRoofIntersections(moduleField, innerOutline)
116
+ if (!outlines?.length) return
97
117
  const holes = getModuleFieldHoleOutlines(moduleField)
118
+ const polygons = []
98
119
 
99
120
  outlines.forEach((outline) => {
100
121
  polygons.push({
@@ -105,6 +126,7 @@ export function updateModuleFieldFittingPanels(moduleField) {
105
126
  .filter(Boolean),
106
127
  })
107
128
  })
129
+ if (!polygons.length) return
108
130
 
109
131
  const hasCustomTexture = !!moduleField.pvData?.texture_img_url
110
132
  const defaultTextureIndex = moduleField.pvData?.module_texture_version_id || 0
@@ -115,7 +137,7 @@ export function updateModuleFieldFittingPanels(moduleField) {
115
137
 
116
138
  moduleField.fittingPanels = {
117
139
  polygons,
118
- visible: true,
140
+ visible: prevVisible !== false,
119
141
  color: mappedColor,
120
142
  }
121
143
  }
@@ -80,13 +80,6 @@ export default {
80
80
  flatShading: true,
81
81
  })
82
82
  }
83
- this.material.panel['userDeactivatedPanel'] = new THREE.MeshBasicMaterial({
84
- color: 0xffffff,
85
- transparent: true,
86
- alphaTest: 0,
87
- opacity: 0.2,
88
- side: THREE.DoubleSide,
89
- })
90
83
  this.material.projectionTiles = []
91
84
 
92
85
  this.material.roof = [this.material.wall]
@@ -48,6 +48,7 @@ export default {
48
48
  if (cylinder) {
49
49
  cylinder.visible = false
50
50
  }
51
+ if (edge.layer === 'moduleField') return
51
52
  if (['obstacle', 'construction'].includes(edge.layer)) return
52
53
  if (
53
54
  ['selectRoof'].includes(this.selectedTool) &&
@@ -18,6 +18,7 @@ import mergedGeometry from './mergedGeometry'
18
18
  import building from './building'
19
19
  import marker from './marker'
20
20
  import scene from './scene'
21
+ import pullHandle from './pullHandle'
21
22
  export default {
22
23
  mixins: [
23
24
  margin,
@@ -40,5 +41,6 @@ export default {
40
41
  building,
41
42
  marker,
42
43
  scene,
44
+ pullHandle,
43
45
  ],
44
46
  }
@@ -4,9 +4,12 @@ export default {
4
4
  methods: {
5
5
  loadTextureAsync(url) {
6
6
  return new Promise((resolve) => {
7
- this.loader.load(url, (texture) => {
8
- resolve(texture)
9
- })
7
+ this.loader.load(
8
+ url,
9
+ (texture) => resolve(texture),
10
+ () => {},
11
+ () => resolve(null)
12
+ )
10
13
  })
11
14
  },
12
15
  async loadNewPanelTextures() {
@@ -42,13 +45,20 @@ export default {
42
45
  const promiseArray = this.moduleFields.map(async (mf) => {
43
46
  const pvId = mf.data.component_id_pv_module
44
47
  if (!this.material.panel[pvId]) {
48
+ const defaultPanelMaterial =
49
+ this.material.panel[
50
+ `default_${mf.pvData.module_texture_version_id || 0}`
51
+ ]
45
52
  if (!mf.pvData.texture_img_url) {
46
- this.material.panel[pvId] =
47
- this.material.panel[`default_${this.moduleTextureVersionId}`]
53
+ this.material.panel[pvId] = defaultPanelMaterial
48
54
  } else {
49
55
  const texture = await this.loadTextureAsync(
50
56
  mf.pvData.texture_img_url
51
57
  )
58
+ if (!texture) {
59
+ this.material.panel[pvId] = defaultPanelMaterial
60
+ return
61
+ }
52
62
  texture.encoding = THREE.sRGBEncoding
53
63
  texture.colorSpace = THREE.SRGBColorSpace
54
64
  this.material.panel[pvId] = new THREE.MeshPhongMaterial({
@@ -3,6 +3,7 @@ import {
3
3
  getBufferModuleFieldGeometry,
4
4
  getFittingPanelsBufferGeometry,
5
5
  } from './geometryHandler'
6
+ import { clipModuleFieldFittingPanels } from '../UpdateRoofModuleFieldRelations'
6
7
 
7
8
  export default {
8
9
  data() {
@@ -11,35 +12,149 @@ export default {
11
12
  }
12
13
  },
13
14
  methods: {
15
+ refreshModuleFieldFittingPanels(moduleFieldId = null) {
16
+ this.polygons
17
+ .filter((p) => p.layer === 'moduleField')
18
+ .forEach((moduleField) => {
19
+ if (
20
+ moduleField.data &&
21
+ (moduleFieldId == null || moduleField.id == moduleFieldId)
22
+ ) {
23
+ clipModuleFieldFittingPanels(moduleField)
24
+ }
25
+ })
26
+ this.renderModuleFields()
27
+ },
14
28
  renderModuleFields() {
15
- this.clearByType('moduleFieldsMeshes')
16
- const moduleFieldPolygons = this.polygons.filter((p) =>
17
- ['moduleField', 'tmpModuleField'].includes(p.layer)
29
+ console.log('renderModuleFields')
30
+ this.clearRemovedModuleFieldGroups()
31
+ const moduleFieldPolygons = this.polygons.filter(
32
+ (p) => p.layer === 'moduleField'
18
33
  )
19
34
  moduleFieldPolygons.forEach((moduleFieldPolygon) => {
20
- const panelOverrideMesh =
21
- this.renderModuleFieldPanelOverride(moduleFieldPolygon)
22
- const fittingPanelsMesh =
23
- this.renderModuleFieldFittingPanels(moduleFieldPolygon)
35
+ let group = this.meshes.moduleFieldsMeshes[moduleFieldPolygon.id]
36
+ if (!group) {
37
+ group = new THREE.Group()
38
+ group.matrixAutoUpdate = false
39
+ group.userData.type = 'moduleFieldsMeshes'
40
+ group.userData.layer = moduleFieldPolygon.layer
41
+ group.userData.meshId = moduleFieldPolygon.id
42
+ group.userData.polygonId = moduleFieldPolygon.id
43
+ this.scene.add(group)
44
+ this.meshes.moduleFieldsMeshes[moduleFieldPolygon.id] = group
45
+ }
24
46
 
25
- if (!panelOverrideMesh && !fittingPanelsMesh) return
47
+ this.updateModuleFieldPanelOverrideMesh(group, moduleFieldPolygon)
48
+ this.updateModuleFieldFittingPanelsMesh(group, moduleFieldPolygon)
26
49
 
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
50
  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
51
  group.visible = this.areModuleFieldsVisible && this.panelOpacity === 1
39
- this.scene.add(group)
40
- this.meshes.moduleFieldsMeshes[moduleFieldPolygon.id] = group
52
+
53
+ if (group.children.length === 0) {
54
+ this.scene.remove(group)
55
+ delete this.meshes.moduleFieldsMeshes[moduleFieldPolygon.id]
56
+ }
57
+ })
58
+ },
59
+ clearRemovedModuleFieldGroups() {
60
+ Object.values(this.meshes.moduleFieldsMeshes).forEach((group) => {
61
+ if (!this.polygonIds.includes(group.userData.polygonId)) {
62
+ this.disposeModuleFieldGroupChildren(group)
63
+ this.scene.remove(group)
64
+ delete this.meshes.moduleFieldsMeshes[group.userData.meshId]
65
+ }
66
+ })
67
+ },
68
+ disposeModuleFieldGroupChildren(group) {
69
+ group.children.forEach((child) => {
70
+ if (child.geometry?.dispose) child.geometry.dispose()
71
+ if (
72
+ child.userData.type === 'moduleFieldsMeshes_fittingPanels' &&
73
+ child.material?.dispose
74
+ ) {
75
+ child.material.dispose()
76
+ }
77
+ })
78
+ },
79
+ updateModuleFieldPanelOverrideMesh(group, moduleFieldPolygon) {
80
+ const type = 'moduleFieldsMeshes_panelOverride'
81
+ let mesh = group.children.find((c) => c.userData.type === type)
82
+ const shouldExist = !!moduleFieldPolygon?.data?.number_of_panels_override
83
+
84
+ if (!shouldExist) {
85
+ if (mesh) {
86
+ group.remove(mesh)
87
+ if (mesh.geometry?.dispose) mesh.geometry.dispose()
88
+ }
89
+ return
90
+ }
91
+
92
+ if (!mesh) {
93
+ mesh = this.renderModuleFieldPanelOverride(moduleFieldPolygon)
94
+ if (mesh) group.add(mesh)
95
+ return
96
+ }
97
+
98
+ if (mesh.userData.version < moduleFieldPolygon.version) {
99
+ const geometry = getBufferModuleFieldGeometry(moduleFieldPolygon)
100
+ if (geometry) {
101
+ if (mesh.geometry?.dispose) mesh.geometry.dispose()
102
+ mesh.geometry = geometry
103
+ mesh.userData.version = moduleFieldPolygon.version
104
+ mesh.updateMatrix()
105
+ }
106
+ }
107
+ },
108
+ updateModuleFieldFittingPanelsMesh(group, moduleFieldPolygon) {
109
+ const type = 'moduleFieldsMeshes_fittingPanels'
110
+ let mesh = group.children.find((c) => c.userData.type === type)
111
+ const fittingPanels = moduleFieldPolygon?.fittingPanels
112
+
113
+ const removeMesh = () => {
114
+ if (mesh) {
115
+ group.remove(mesh)
116
+ if (mesh.geometry?.dispose) mesh.geometry.dispose()
117
+ if (mesh.material?.dispose) mesh.material.dispose()
118
+ }
119
+ }
120
+
121
+ if (!fittingPanels?.polygons?.length) {
122
+ removeMesh()
123
+ return
124
+ }
125
+
126
+ if (!mesh) {
127
+ mesh = this.renderModuleFieldFittingPanels(moduleFieldPolygon)
128
+ if (mesh) group.add(mesh)
41
129
  return
130
+ }
131
+
132
+ const { polygons, visible, color } = fittingPanels
133
+ const geometries = []
134
+ polygons.forEach((polygon) => {
135
+ const geometry = getFittingPanelsBufferGeometry(
136
+ polygon.outline,
137
+ polygon.holes,
138
+ moduleFieldPolygon
139
+ )
140
+ if (geometry) geometries.push(geometry)
42
141
  })
142
+
143
+ if (!geometries.length) {
144
+ removeMesh()
145
+ return
146
+ }
147
+
148
+ mesh.geometry = this.updateMergedGeometry(geometries, mesh.geometry)
149
+ const isTransparent = color === 'transparent'
150
+ mesh.material.color.set(isTransparent ? '#ffffff' : color)
151
+ mesh.material.transparent = true
152
+ mesh.material.opacity = isTransparent ? 0.2 : 0.8
153
+ mesh.material.needsUpdate = true
154
+ mesh.userData.fittingPanelsVisible = visible
155
+ mesh.userData.version = moduleFieldPolygon.version
156
+ mesh.visible =
157
+ visible && this.areModuleFieldsVisible && this.panelOpacity === 1
43
158
  },
44
159
  renderModuleFieldPanelOverride(moduleFieldPolygon) {
45
160
  if (!moduleFieldPolygon?.data?.number_of_panels_override) return
@@ -60,7 +175,6 @@ export default {
60
175
  renderModuleFieldFittingPanels(moduleFieldPolygon) {
61
176
  if (!moduleFieldPolygon?.fittingPanels?.polygons?.length) return
62
177
  const { polygons, visible, color } = moduleFieldPolygon.fittingPanels
63
-
64
178
  const geometries = []
65
179
  polygons.forEach((polygon) => {
66
180
  const { outline, holes } = polygon
@@ -84,8 +198,10 @@ export default {
84
198
  })
85
199
 
86
200
  const mesh = new THREE.Mesh(mergedGeometry, material)
87
- mesh.visible = visible
201
+ mesh.visible =
202
+ visible && this.areModuleFieldsVisible && this.panelOpacity === 1
88
203
  mesh.matrixAutoUpdate = false
204
+ mesh.userData.fittingPanelsVisible = visible
89
205
  mesh.userData.version = moduleFieldPolygon.version
90
206
  mesh.userData.type = 'moduleFieldsMeshes_fittingPanels'
91
207
  mesh.userData.layer = moduleFieldPolygon.layer
@@ -96,11 +212,17 @@ export default {
96
212
  },
97
213
  updateModuleFieldsVisibility(isVisible) {
98
214
  this.areModuleFieldsVisible = isVisible
99
- Object.values(this.meshes['moduleFieldsMeshes']).forEach(
100
- (mesh) =>
101
- (mesh.visible =
102
- this.areModuleFieldsVisible && this.panelOpacity === 1)
103
- )
215
+ const moduleFieldsVisible =
216
+ this.areModuleFieldsVisible && this.panelOpacity === 1
217
+ Object.values(this.meshes['moduleFieldsMeshes']).forEach((group) => {
218
+ group.visible = moduleFieldsVisible
219
+ group.children.forEach((child) => {
220
+ if (child.userData.type === 'moduleFieldsMeshes_fittingPanels') {
221
+ child.visible =
222
+ moduleFieldsVisible && child.userData.fittingPanelsVisible
223
+ }
224
+ })
225
+ })
104
226
  },
105
227
  hideModuleFields() {
106
228
  this.updateModuleFieldsVisibility(false)
@@ -64,9 +64,7 @@ export default {
64
64
  renderPanelsPerModuleField(moduleField) {
65
65
  const panelSideGeometries = []
66
66
  const panelTopGeometries = []
67
- const panels = this.areUserDeactivatedPanelsVisible
68
- ? [...moduleField.panels, ...moduleField.userDeactivatedPanels]
69
- : [...moduleField.panels]
67
+ const panels = [...moduleField.panels]
70
68
 
71
69
  const existingTopMesh = this.mergedPanelTopMeshes[moduleField.id]
72
70
  const isNewerVersion =
@@ -75,7 +73,24 @@ export default {
75
73
  existingTopMesh?.userData.panelOpacity !== this.panelOpacity
76
74
  const skipRender = existingTopMesh && !isNewerVersion && !opacityChanged
77
75
 
78
- if (!panels.length || skipRender) {
76
+ if (!panels.length) {
77
+ if (this.mergedPanelTopMeshes[moduleField.id]) {
78
+ this.clearMeshFromScene(
79
+ this.mergedPanelTopMeshes[moduleField.id],
80
+ this.scene
81
+ )
82
+ delete this.mergedPanelTopMeshes[moduleField.id]
83
+ }
84
+ if (this.mergedPanelSideMesh[moduleField.id]) {
85
+ this.clearMeshFromScene(
86
+ this.mergedPanelSideMesh[moduleField.id],
87
+ this.scene
88
+ )
89
+ delete this.mergedPanelSideMesh[moduleField.id]
90
+ }
91
+ return
92
+ }
93
+ if (skipRender) {
79
94
  return
80
95
  }
81
96
 
@@ -119,8 +134,7 @@ export default {
119
134
  meshSide.userData.polygonId = panel.id
120
135
  meshSide.matrixAutoUpdate = false
121
136
  this.meshes.panelsMeshes[panel.id + '_side'] = meshSide
122
- if (panel.layer != 'user_deactivated_panel')
123
- panelSideGeometries.push(geometrySide)
137
+ panelSideGeometries.push(geometrySide)
124
138
  })
125
139
 
126
140
  // create merged meshes
@@ -148,11 +162,7 @@ export default {
148
162
  getPanelMaterial(panel) {
149
163
  let material
150
164
  let materialId
151
- if (panel.layer == 'user_deactivated_panel') {
152
- materialId = 'userDeactivatedPanel'
153
- material = this.material.panel[materialId]
154
- material.opacity = this.panelOpacity
155
- } else {
165
+ {
156
166
  const moduleTextureId =
157
167
  panel.moduleField?.pvData?.module_texture_version_id || 0
158
168