@eturnity/eturnity_3d 9.31.0 → 9.31.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 +2 -2
- package/src/Overlay/ThreeDModelOverlay.js +23 -16
- package/src/components/ThreeCanvasViewer.vue +0 -2
- package/src/config.js +1 -10
- package/src/helper/UpdateRoofModuleFieldRelations.js +75 -36
- package/src/helper/cameraMixin.js +17 -7
- package/src/helper/materialMixin.js +0 -7
- package/src/helper/render/clear.js +7 -1
- package/src/helper/render/edge.js +1 -0
- package/src/helper/render/index.js +2 -0
- package/src/helper/render/moduleField.js +149 -27
- package/src/helper/render/panel.js +21 -11
- package/src/helper/render/pullHandle.js +1000 -0
- package/src/helper/renderMixin.js +40 -1
- package/src/helper/threeMixin.js +2 -1
- package/src/store/hydrateData.js +24 -30
- package/src/store/three-d-module.js +0 -3
- package/dist/assets/images/panels/longiSolarLR4_60HPH_350M.png +0 -0
- package/dist/assets/images/panels/longiSolarLR4_60HPH_370M.png +0 -0
- package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw copy.png +0 -0
- package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
- package/dist/assets/images/panels/uv.png +0 -0
- package/dist/assets/panels/longiSolarLR4_60HPH_350M.png +0 -0
- package/dist/assets/panels/longiSolarLR4_60HPH_370M.png +0 -0
- package/dist/assets/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
- package/dist/assets/panels/uv.png +0 -0
- package/dist/assets/theme.js +0 -43
- package/dist/assets/vue.svg +0 -1
- package/dist/main.es.js +0 -43662
- package/dist/main.umd.js +0 -3542
- package/dist/style.css +0 -1
- package/dist/vite.svg +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eturnity/eturnity_3d",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "9.31.0",
|
|
4
|
+
"version": "9.31.1-9.25-dev-03.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": "9.31.0",
|
|
19
|
+
"@eturnity/eturnity_maths": "9.31.0-9.25-dev-03.0",
|
|
20
20
|
"@originjs/vite-plugin-commonjs": "1.0.3",
|
|
21
21
|
"core-js": "3.30.2",
|
|
22
22
|
"cors": "2.8.5",
|
|
@@ -66,28 +66,31 @@ export default class ThreeDModelOverlay extends Overlay {
|
|
|
66
66
|
threeJSComponent.scene.add(waitingBall)
|
|
67
67
|
}
|
|
68
68
|
threeJSComponent.meshes.overlayMeshes[this.id] = waitingBall
|
|
69
|
-
this.hasPlaceholderMesh = true
|
|
70
69
|
return
|
|
71
70
|
}
|
|
72
|
-
|
|
71
|
+
// Each canvas renders its own clone: an Object3D belongs to a single scene,
|
|
72
|
+
// so sharing this.overlayMesh made one canvas steal (and later dispose) the
|
|
73
|
+
// mesh another canvas was still rendering. this.overlayMesh stays a load
|
|
74
|
+
// cache and is never added to a scene.
|
|
73
75
|
let overlayMesh = threeJSComponent.meshes.overlayMeshes[this.id]
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
+
if (overlayMesh && overlayMesh.name == 'waitingBall') {
|
|
77
|
+
// Placeholder spheres are per-canvas objects, so disposing them is safe.
|
|
78
|
+
threeJSComponent.scene.remove(overlayMesh)
|
|
79
|
+
threeJSComponent.disposeMesh(overlayMesh)
|
|
80
|
+
delete threeJSComponent.meshes.overlayMeshes[this.id]
|
|
76
81
|
overlayMesh = null
|
|
77
|
-
this.hasPlaceholderMesh = false
|
|
78
82
|
}
|
|
79
|
-
if (!overlayMesh
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
if (!overlayMesh) {
|
|
84
|
+
if (!this.overlayMesh) {
|
|
85
|
+
this.overlayMesh = await this.loadFile()
|
|
86
|
+
}
|
|
87
|
+
this.overlayMesh.children.forEach((mesh) => {
|
|
83
88
|
mesh.position.set(-this.boxCenter.x, -this.boxCenter.y, 0)
|
|
84
89
|
})
|
|
90
|
+
overlayMesh = this.overlayMesh.clone(true)
|
|
91
|
+
threeJSComponent.meshes.overlayMeshes[this.id] = overlayMesh
|
|
85
92
|
threeJSComponent.scene.add(overlayMesh)
|
|
86
93
|
}
|
|
87
|
-
if (!overlayMesh) {
|
|
88
|
-
overlayMesh = await this.loadFile()
|
|
89
|
-
threeJSComponent.meshes.overlayMeshes[meshId] = overlayMesh
|
|
90
|
-
}
|
|
91
94
|
const positionOffset = multiplyVector(1 / 1000, this.positionOffset)
|
|
92
95
|
overlayMesh.position.set(0, 0, 0)
|
|
93
96
|
overlayMesh.rotateZ(-overlayMesh.rotation.z)
|
|
@@ -104,9 +107,13 @@ export default class ThreeDModelOverlay extends Overlay {
|
|
|
104
107
|
threeJSComponent.render()
|
|
105
108
|
}
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
this.overlayMesh
|
|
109
|
-
|
|
110
|
+
overlayMesh.frustumCulled = false
|
|
111
|
+
this.set3DObjectMaterialOpacity(overlayMesh)
|
|
112
|
+
// Keep the master aligned with the rendered clones: it is still what
|
|
113
|
+
// getProjectedPlanesOnOverlay raycasts and what bounding-box consumers
|
|
114
|
+
// measure.
|
|
115
|
+
this.overlayMesh.position.copy(overlayMesh.position)
|
|
116
|
+
this.overlayMesh.rotation.copy(overlayMesh.rotation)
|
|
110
117
|
return overlayMesh
|
|
111
118
|
}
|
|
112
119
|
renderOnPaperJS(paperJSComponent) {
|
|
@@ -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
|
@@ -8,6 +8,7 @@ export const mmTolerance = 5
|
|
|
8
8
|
export const mmTolerance3dNode = 50
|
|
9
9
|
export const earthRadius = 6371008
|
|
10
10
|
export const marginAroundBuildingForCameraViewInMeter = 5
|
|
11
|
+
export const DEFAULT_FOV = 50
|
|
11
12
|
export const layerColors = {
|
|
12
13
|
construction: {
|
|
13
14
|
fillColor: 'transparent',
|
|
@@ -49,11 +50,6 @@ export const layerColors = {
|
|
|
49
50
|
strokeColor: '#ffffff',
|
|
50
51
|
strokeWidth: 1,
|
|
51
52
|
},
|
|
52
|
-
user_deactivated_panel: {
|
|
53
|
-
fillColor: 'rgba(115, 115, 229, 0.1)',
|
|
54
|
-
strokeColor: 'white',
|
|
55
|
-
strokeWidth: 2,
|
|
56
|
-
},
|
|
57
53
|
selectedPanel: {
|
|
58
54
|
fillColor: '#0068DE80',
|
|
59
55
|
strokeColor: theme.colors.blue,
|
|
@@ -126,11 +122,6 @@ export const layerColors = {
|
|
|
126
122
|
strokeColor: theme.colors.blueElectric,
|
|
127
123
|
strokeWidth: 5,
|
|
128
124
|
},
|
|
129
|
-
tmpModuleField: {
|
|
130
|
-
fillColor: 'rgba(115, 115, 229, 0.2)',
|
|
131
|
-
strokeColor: theme.colors.blue,
|
|
132
|
-
strokeWidth: 1,
|
|
133
|
-
},
|
|
134
125
|
selectedModuleField: {
|
|
135
126
|
fillColor: '#0068DEA0',
|
|
136
127
|
strokeColor: theme.colors.blue,
|
|
@@ -9,35 +9,51 @@ import {
|
|
|
9
9
|
} from '@eturnity/eturnity_maths'
|
|
10
10
|
import { defaultTextureColorMap, fittingPanelsColorMap } from '../config'
|
|
11
11
|
//this function just update the "roof" and "moduleField(s)" properties of panels,moduleFields and roofs
|
|
12
|
+
// The roof underneath an outline: biggest footprint overlap wins, ties go to
|
|
13
|
+
// the smaller roof. Returns null when no roof intersects the outline.
|
|
14
|
+
export function findRoofWithBiggestOverlap(roofs, outline) {
|
|
15
|
+
const intersections = []
|
|
16
|
+
roofs.forEach((roof) => {
|
|
17
|
+
const intersection = intersectOutlines(roof.outline, outline)
|
|
18
|
+
if (intersection.length) {
|
|
19
|
+
const intersectionArea = intersection.reduce(
|
|
20
|
+
(acc, cur) => acc + calculateArea(cur),
|
|
21
|
+
0
|
|
22
|
+
)
|
|
23
|
+
intersections.push({ roof, intersectionArea })
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
intersections.sort((a, b) => a.roof.area - b.roof.area)
|
|
27
|
+
intersections.sort((a, b) => b.intersectionArea - a.intersectionArea)
|
|
28
|
+
return intersections.length ? intersections[0].roof : null
|
|
29
|
+
}
|
|
30
|
+
|
|
12
31
|
export function UpdateRoofModuleFieldRelations(state) {
|
|
13
32
|
let moduleFields = state.polygons.filter(
|
|
14
33
|
(poly) => poly.layer == 'moduleField'
|
|
15
34
|
)
|
|
16
35
|
let roofs = state.polygons.filter((poly) => poly.layer == 'roof')
|
|
17
36
|
const panels = state.polygons.filter((poly) =>
|
|
18
|
-
['panel'
|
|
37
|
+
['panel'].includes(poly.layer)
|
|
19
38
|
)
|
|
20
|
-
|
|
21
39
|
let roofUnderPerModuleFieldId = {}
|
|
22
40
|
moduleFields.forEach((moduleField) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
roofUnderPerModuleFieldId[moduleField.id] =
|
|
40
|
-
roofModuleFieldIntersections[0].roof
|
|
41
|
+
// A module field keeps its roof for as long as that roof exists (matched
|
|
42
|
+
// by id: polygons are recreated on hydration, so the reference may be
|
|
43
|
+
// stale). It is only reassigned — to the roof it overlaps most — when its
|
|
44
|
+
// previous roof was deleted. Flows that deliberately move a field to
|
|
45
|
+
// another roof (drag replant, MoveModuleFields) set moduleField.roof
|
|
46
|
+
// themselves before the relations update.
|
|
47
|
+
const previousRoof = moduleField.roof
|
|
48
|
+
? roofs.find((roof) => roof.id == moduleField.roof.id)
|
|
49
|
+
: null
|
|
50
|
+
if (previousRoof) {
|
|
51
|
+
roofUnderPerModuleFieldId[moduleField.id] = previousRoof
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
const roofUnder = findRoofWithBiggestOverlap(roofs, moduleField.outline)
|
|
55
|
+
if (roofUnder) {
|
|
56
|
+
roofUnderPerModuleFieldId[moduleField.id] = roofUnder
|
|
41
57
|
}
|
|
42
58
|
})
|
|
43
59
|
roofs.forEach((roof) => (roof.moduleFields = []))
|
|
@@ -47,6 +63,11 @@ export function UpdateRoofModuleFieldRelations(state) {
|
|
|
47
63
|
moduleFields.forEach((moduleField) => {
|
|
48
64
|
let roof = roofUnderPerModuleFieldId[moduleField.id]
|
|
49
65
|
if (roof) {
|
|
66
|
+
if (moduleField.hasError) {
|
|
67
|
+
moduleField.hasError = false
|
|
68
|
+
moduleField.warnings = []
|
|
69
|
+
moduleField.hasWarnings = false
|
|
70
|
+
}
|
|
50
71
|
moduleField.roof = roof
|
|
51
72
|
roof.moduleFields.push(moduleField)
|
|
52
73
|
panels.forEach((panel) => {
|
|
@@ -54,6 +75,13 @@ export function UpdateRoofModuleFieldRelations(state) {
|
|
|
54
75
|
panel.roof = roof
|
|
55
76
|
}
|
|
56
77
|
})
|
|
78
|
+
} else if (moduleField.panels && moduleField.panels.length > 0) {
|
|
79
|
+
moduleField.roof = null
|
|
80
|
+
if (!moduleField.hasError) {
|
|
81
|
+
moduleField.hasError = true
|
|
82
|
+
moduleField.warnings = ['module_field_warning_roof_missing']
|
|
83
|
+
moduleField.hasWarnings = true
|
|
84
|
+
}
|
|
57
85
|
}
|
|
58
86
|
})
|
|
59
87
|
state = removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state)
|
|
@@ -65,36 +93,46 @@ export function removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state) {
|
|
|
65
93
|
['roof', 'obstacle'].includes(polygon.layer)
|
|
66
94
|
)
|
|
67
95
|
const remainingModuleFields = state.polygons.filter(
|
|
68
|
-
(polygon) =>
|
|
96
|
+
(polygon) =>
|
|
97
|
+
polygon.layer == 'moduleField' && (!!polygon.roof || polygon.hasError)
|
|
69
98
|
)
|
|
70
|
-
const
|
|
71
|
-
(
|
|
99
|
+
const retainedModuleFieldIds = new Set(
|
|
100
|
+
remainingModuleFields.map((mf) => mf.id)
|
|
72
101
|
)
|
|
73
|
-
const
|
|
74
|
-
(polygon) =>
|
|
102
|
+
const remainingPanels = state.polygons.filter(
|
|
103
|
+
(polygon) =>
|
|
104
|
+
polygon.layer == 'panel' &&
|
|
105
|
+
(!!polygon.roof || retainedModuleFieldIds.has(polygon.moduleField?.id))
|
|
75
106
|
)
|
|
76
|
-
|
|
77
107
|
state.polygons = [
|
|
78
108
|
...remainingPolygons,
|
|
79
109
|
...remainingModuleFields,
|
|
80
110
|
...remainingPanels,
|
|
81
|
-
...remainingUserDeactivatedPanels,
|
|
82
111
|
]
|
|
83
112
|
return state
|
|
84
113
|
}
|
|
85
114
|
|
|
86
115
|
export function updateModuleFieldFittingPanels(moduleField) {
|
|
116
|
+
const { has_fitting_panels, fitting_panel_area_m2 } = moduleField.data || {}
|
|
117
|
+
if (!(has_fitting_panels && fitting_panel_area_m2 > 0)) {
|
|
118
|
+
delete moduleField.fittingPanels
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
clipModuleFieldFittingPanels(moduleField)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function clipModuleFieldFittingPanels(moduleField) {
|
|
125
|
+
const prevVisible = moduleField?.fittingPanels?.visible
|
|
87
126
|
delete moduleField.fittingPanels
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
127
|
+
if (!moduleField?.panels?.length) return
|
|
128
|
+
if (!moduleField?.roof || !moduleField.data?.has_fitting_panels) return
|
|
129
|
+
const innerOutline = moduleField.roof.margins?.innerOutline
|
|
130
|
+
if (!innerOutline?.length) return
|
|
92
131
|
|
|
93
|
-
const outlines = getModuleFieldRoofIntersections(
|
|
94
|
-
|
|
95
|
-
moduleField.roof.margins.innerOutline
|
|
96
|
-
)
|
|
132
|
+
const outlines = getModuleFieldRoofIntersections(moduleField, innerOutline)
|
|
133
|
+
if (!outlines?.length) return
|
|
97
134
|
const holes = getModuleFieldHoleOutlines(moduleField)
|
|
135
|
+
const polygons = []
|
|
98
136
|
|
|
99
137
|
outlines.forEach((outline) => {
|
|
100
138
|
polygons.push({
|
|
@@ -105,6 +143,7 @@ export function updateModuleFieldFittingPanels(moduleField) {
|
|
|
105
143
|
.filter(Boolean),
|
|
106
144
|
})
|
|
107
145
|
})
|
|
146
|
+
if (!polygons.length) return
|
|
108
147
|
|
|
109
148
|
const hasCustomTexture = !!moduleField.pvData?.texture_img_url
|
|
110
149
|
const defaultTextureIndex = moduleField.pvData?.module_texture_version_id || 0
|
|
@@ -115,7 +154,7 @@ export function updateModuleFieldFittingPanels(moduleField) {
|
|
|
115
154
|
|
|
116
155
|
moduleField.fittingPanels = {
|
|
117
156
|
polygons,
|
|
118
|
-
visible:
|
|
157
|
+
visible: prevVisible !== false,
|
|
119
158
|
color: mappedColor,
|
|
120
159
|
}
|
|
121
160
|
}
|
|
@@ -6,13 +6,21 @@ import {
|
|
|
6
6
|
multiplyVector,
|
|
7
7
|
substractVector,
|
|
8
8
|
} from '@eturnity/eturnity_maths'
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_FOV,
|
|
11
|
+
marginAroundBuildingForCameraViewInMeter,
|
|
12
|
+
} from '../config'
|
|
10
13
|
import OverlayLayer from '../Overlay/OverlayLayer'
|
|
11
14
|
export default {
|
|
12
15
|
data() {
|
|
13
16
|
return {
|
|
14
17
|
animationFrameId: null,
|
|
15
|
-
perspectiveCamera: new THREE.PerspectiveCamera(
|
|
18
|
+
perspectiveCamera: new THREE.PerspectiveCamera(
|
|
19
|
+
DEFAULT_FOV,
|
|
20
|
+
300 / 300,
|
|
21
|
+
1,
|
|
22
|
+
50000
|
|
23
|
+
),
|
|
16
24
|
orthographicCamera: new THREE.OrthographicCamera(
|
|
17
25
|
-50,
|
|
18
26
|
50,
|
|
@@ -398,7 +406,7 @@ export default {
|
|
|
398
406
|
},
|
|
399
407
|
setCameraInitialPosition() {
|
|
400
408
|
if (this.roofs.length == 0) return
|
|
401
|
-
let newFov =
|
|
409
|
+
let newFov = DEFAULT_FOV
|
|
402
410
|
if (
|
|
403
411
|
this.roofsBounds.xMax === Infinity ||
|
|
404
412
|
this.roofsBounds.xMin === -Infinity ||
|
|
@@ -462,7 +470,7 @@ export default {
|
|
|
462
470
|
if (this.camera.isOrthographicCamera) {
|
|
463
471
|
this.setOrthographicCameraGlobalPosition()
|
|
464
472
|
} else {
|
|
465
|
-
let newFov =
|
|
473
|
+
let newFov = DEFAULT_FOV
|
|
466
474
|
let bounds = this.roofsBounds
|
|
467
475
|
if (
|
|
468
476
|
bounds.xMax === Infinity ||
|
|
@@ -618,7 +626,7 @@ export default {
|
|
|
618
626
|
const {
|
|
619
627
|
position,
|
|
620
628
|
target,
|
|
621
|
-
fov =
|
|
629
|
+
fov = DEFAULT_FOV,
|
|
622
630
|
duration = 1500,
|
|
623
631
|
callback = () => {},
|
|
624
632
|
} = payload
|
|
@@ -713,7 +721,9 @@ export default {
|
|
|
713
721
|
callback()
|
|
714
722
|
})
|
|
715
723
|
} else {
|
|
716
|
-
|
|
724
|
+
// must stay a real Vector3: OrbitControls' zoomToCursor calls
|
|
725
|
+
// camera.up.dot() on wheel zoom (a plain object crashes it)
|
|
726
|
+
this.camera.up = new THREE.Vector3(0, 0, 1)
|
|
717
727
|
this.tweenCamera = new TWEEN.Tween(currentTweenVar)
|
|
718
728
|
.to({ t: 1 }, duration)
|
|
719
729
|
.easing(TWEEN.Easing.Sinusoidal.Out)
|
|
@@ -778,7 +788,7 @@ export default {
|
|
|
778
788
|
},
|
|
779
789
|
},
|
|
780
790
|
|
|
781
|
-
|
|
791
|
+
beforeUnmount() {
|
|
782
792
|
TWEEN.removeAll()
|
|
783
793
|
cancelAnimationFrame(this.animationFrameId)
|
|
784
794
|
},
|
|
@@ -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]
|
|
@@ -33,7 +33,13 @@ export default {
|
|
|
33
33
|
return
|
|
34
34
|
}
|
|
35
35
|
scene.remove(mesh)
|
|
36
|
-
|
|
36
|
+
// Overlay meshes are per-canvas clones sharing geometry/material with the
|
|
37
|
+
// overlay's master mesh and with the other canvases' clones: disposing
|
|
38
|
+
// here would blank the overlay on every other canvas. Scene removal plus
|
|
39
|
+
// registry delete only; the master's resources go with the overlay.
|
|
40
|
+
if (mesh.userData.type != 'overlayMeshes') {
|
|
41
|
+
this.disposeMesh(mesh)
|
|
42
|
+
}
|
|
37
43
|
if (
|
|
38
44
|
mesh.userData.meshId &&
|
|
39
45
|
this.meshes[mesh.userData.type][mesh.userData.meshId]
|
|
@@ -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
|
}
|
|
@@ -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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
40
|
-
|
|
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 =
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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)
|