@eturnity/eturnity_3d 7.2.3 → 7.2.4-qa-7.6.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/components/ThreeCanvasViewer.vue +4 -12
- package/src/config.js +3 -3
- package/src/helper/UpdateRoofModuleFieldRelations.js +1 -1
- package/src/helper/cameraMixin.js +274 -17
- package/src/helper/materialMixin.js +29 -7
- package/src/helper/render/circle.png +0 -0
- package/src/helper/render/clear.js +0 -8
- package/src/helper/render/edge.js +52 -20
- package/src/helper/render/margin.js +56 -37
- package/src/helper/render/mergedGeometry.js +4 -3
- package/src/helper/render/moduleField.js +9 -5
- package/src/helper/render/node.js +12 -2
- package/src/helper/render/panel.js +61 -31
- package/src/helper/render/roof.js +28 -10
- package/src/helper/renderMixin.js +61 -7
- package/src/helper/threeMixin.js +13 -12
- package/src/store/hydrateData.js +23 -0
- package/src/store/nodesEdgesCreation.js +10 -9
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
|
+
"version": "7.2.4-qa-7.6.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.2.3-qa-7.6.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.
|
|
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.
|
|
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 =
|
|
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.
|
|
143
|
-
export const node3dOpacity = 0.
|
|
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
|
-
|
|
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,135 @@
|
|
|
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
|
+
let altitude =
|
|
93
|
+
(this.orthographicCamera.right - this.orthographicCamera.left) /
|
|
94
|
+
((this.perspectiveCamera.fov * Math.PI) / 180) /
|
|
95
|
+
this.perspectiveCamera.aspect
|
|
96
|
+
|
|
97
|
+
this.camera.position.set(
|
|
98
|
+
this.orthographicCamera.position.x,
|
|
99
|
+
this.orthographicCamera.position.y,
|
|
100
|
+
altitude
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
this.camera.up = new THREE.Vector3(0, 0, 1)
|
|
104
|
+
this.camera.updateProjectionMatrix()
|
|
105
|
+
|
|
106
|
+
this.renderer.camera = this.camera
|
|
107
|
+
this.composer.renderer.camera = this.camera
|
|
108
|
+
this.composer.renderCamera = this.camera
|
|
109
|
+
this.renderPass.camera = this.camera
|
|
110
|
+
this.overlayRenderPass.camera = this.camera
|
|
111
|
+
this.outlinePassHighlight.camera = this.camera
|
|
112
|
+
this.outlinePassHighlight.renderCamera = this.camera
|
|
113
|
+
this.outlinePassSelected.camera = this.camera
|
|
114
|
+
this.outlinePassSelected.renderCamera = this.camera
|
|
115
|
+
this.orbitControl.camera = this.camera
|
|
116
|
+
this.orbitControl.object = this.camera
|
|
117
|
+
this.orbitControl.target.set(
|
|
118
|
+
this.camera.position.x,
|
|
119
|
+
this.camera.position.y,
|
|
120
|
+
0
|
|
121
|
+
)
|
|
122
|
+
this.orbitControl.screenSpacePanning = false
|
|
123
|
+
this.orbitControl.enableRotate = true
|
|
124
|
+
this.orbitControl.mouseButtons = {
|
|
125
|
+
LEFT: THREE.MOUSE.ROTATE,
|
|
126
|
+
MIDDLE: THREE.MOUSE.DOLLY,
|
|
127
|
+
RIGHT: THREE.MOUSE.PAN
|
|
128
|
+
}
|
|
129
|
+
this.orbitControl.update()
|
|
130
|
+
|
|
131
|
+
this.composer.render()
|
|
132
|
+
},
|
|
10
133
|
zoomIn3D() {
|
|
11
134
|
let target = this.orbitControl.target
|
|
12
135
|
let curentPosition = this.camera.position
|
|
@@ -39,6 +162,7 @@ export default {
|
|
|
39
162
|
},
|
|
40
163
|
setCameraGlobalPosition() {
|
|
41
164
|
if (this.roofs.length == 0) return
|
|
165
|
+
let newFov = 50
|
|
42
166
|
let bounds = this.roofsBounds
|
|
43
167
|
let targetVector = {
|
|
44
168
|
x: (bounds.xMax + bounds.xMin) / 2000,
|
|
@@ -50,7 +174,7 @@ export default {
|
|
|
50
174
|
(bounds.yMax - bounds.yMin) / 2000
|
|
51
175
|
)
|
|
52
176
|
let distance =
|
|
53
|
-
5 + objectRadius_m / Math.sin(((
|
|
177
|
+
5 + objectRadius_m / Math.sin(((newFov / 2) * Math.PI) / 180)
|
|
54
178
|
let cameraMoveVector = { x: 0, y: 0, z: distance }
|
|
55
179
|
const positionVector = addVector(targetVector, cameraMoveVector)
|
|
56
180
|
const position = [
|
|
@@ -59,8 +183,39 @@ export default {
|
|
|
59
183
|
positionVector.z
|
|
60
184
|
]
|
|
61
185
|
let target = [targetVector.x, targetVector.y, targetVector.z]
|
|
186
|
+
this.setTweenTo(position, target, newFov)
|
|
187
|
+
},
|
|
188
|
+
setCameraGlobalVerticalPosition() {
|
|
189
|
+
let position, target
|
|
190
|
+
let newFov = 10
|
|
191
|
+
if (this.roofs.length != 0) {
|
|
192
|
+
let bounds = this.roofsBounds
|
|
193
|
+
let targetVector = {
|
|
194
|
+
x: (bounds.xMax + bounds.xMin) / 2000,
|
|
195
|
+
y: (bounds.yMax + bounds.yMin) / 2000,
|
|
196
|
+
z: 0
|
|
197
|
+
}
|
|
198
|
+
let objectRadius_m = Math.max(
|
|
199
|
+
(bounds.xMax - bounds.xMin) / 2000,
|
|
200
|
+
(bounds.yMax - bounds.yMin) / 2000
|
|
201
|
+
)
|
|
62
202
|
|
|
63
|
-
|
|
203
|
+
let distance =
|
|
204
|
+
2 * (objectRadius_m / Math.sin(((newFov / 2) * Math.PI) / 180))
|
|
205
|
+
let cameraMoveVector = { x: 0, y: 0, z: distance }
|
|
206
|
+
const positionVector = addVector(targetVector, cameraMoveVector)
|
|
207
|
+
position = [positionVector.x, positionVector.y, positionVector.z]
|
|
208
|
+
target = [targetVector.x, targetVector.y, targetVector.z]
|
|
209
|
+
} else {
|
|
210
|
+
position = [0, 0, 300]
|
|
211
|
+
target = [0, 0, 0]
|
|
212
|
+
}
|
|
213
|
+
this.setTweenTo(
|
|
214
|
+
position,
|
|
215
|
+
target,
|
|
216
|
+
newFov,
|
|
217
|
+
this.turnPerspectiveCameraToOrthogonal
|
|
218
|
+
)
|
|
64
219
|
},
|
|
65
220
|
setCameraOrthogonalTo(polygon) {
|
|
66
221
|
if (polygon) {
|
|
@@ -109,23 +264,125 @@ export default {
|
|
|
109
264
|
this.setTweenTo(position, target)
|
|
110
265
|
}
|
|
111
266
|
},
|
|
112
|
-
setTweenTo(position, target,
|
|
267
|
+
setTweenTo(position, target, fov = 50, onCompleteCallback = () => {}) {
|
|
113
268
|
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
269
|
if (this.camera) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
270
|
+
const currentTweenVar = {
|
|
271
|
+
t: 0
|
|
272
|
+
}
|
|
273
|
+
const initialTarget = {
|
|
274
|
+
x: this.orbitControl.target.x,
|
|
275
|
+
y: this.orbitControl.target.y,
|
|
276
|
+
z: this.orbitControl.target.z
|
|
277
|
+
}
|
|
278
|
+
const initialFov = this.camera.fov
|
|
279
|
+
const initialCameraPosition = {
|
|
280
|
+
x: this.camera.position.x,
|
|
281
|
+
y: this.camera.position.y,
|
|
282
|
+
z: this.camera.position.z
|
|
283
|
+
}
|
|
284
|
+
const finalCameraPosition = {
|
|
285
|
+
x: position[0],
|
|
286
|
+
y: position[1],
|
|
287
|
+
z: position[2]
|
|
288
|
+
}
|
|
289
|
+
if (position[0] == target[0] && position[1] == target[1]) {
|
|
290
|
+
const distance2D = getDistanceBetweenPoints(
|
|
291
|
+
finalCameraPosition,
|
|
292
|
+
initialCameraPosition
|
|
293
|
+
)
|
|
294
|
+
//angle from south
|
|
295
|
+
const angle2D = Math.atan2(
|
|
296
|
+
initialCameraPosition.y - finalCameraPosition.y,
|
|
297
|
+
initialCameraPosition.x - finalCameraPosition.x
|
|
298
|
+
)
|
|
299
|
+
this.tweenCamera = new TWEEN.Tween(currentTweenVar)
|
|
300
|
+
.to({ t: 1 }, 2000)
|
|
301
|
+
.easing(TWEEN.Easing.Sinusoidal.Out)
|
|
302
|
+
.onUpdate(() => {
|
|
303
|
+
const t = currentTweenVar.t
|
|
304
|
+
this.camera.fov = initialFov + Math.sqrt(t) * (fov - initialFov)
|
|
305
|
+
|
|
306
|
+
const newDistance = distance2D * (1 - t)
|
|
307
|
+
const newAngle = (angle2D + Math.PI / 2) * (1 - t) - Math.PI / 2
|
|
308
|
+
const newAltitude =
|
|
309
|
+
finalCameraPosition.z +
|
|
310
|
+
(1 - t) * (initialCameraPosition.z - finalCameraPosition.z)
|
|
311
|
+
const nextPosition = {
|
|
312
|
+
x: finalCameraPosition.x + newDistance * Math.cos(newAngle),
|
|
313
|
+
y: finalCameraPosition.y + newDistance * Math.sin(newAngle),
|
|
314
|
+
z: newAltitude
|
|
315
|
+
}
|
|
316
|
+
this.camera.position.set(
|
|
317
|
+
nextPosition.x,
|
|
318
|
+
nextPosition.y,
|
|
319
|
+
nextPosition.z
|
|
320
|
+
)
|
|
321
|
+
this.camera.up = new THREE.Vector3(
|
|
322
|
+
0,
|
|
323
|
+
Math.sin((t * Math.PI) / 2),
|
|
324
|
+
Math.cos((t * Math.PI) / 2)
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
this.camera.updateProjectionMatrix()
|
|
328
|
+
const nextTarget = {
|
|
329
|
+
x: initialTarget.x + t * (target[0] - initialTarget.x),
|
|
330
|
+
y: initialTarget.y + t * (target[1] - initialTarget.y),
|
|
331
|
+
z: initialTarget.z + t * (target[2] - initialTarget.z)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
this.orbitControl.target.set(
|
|
335
|
+
nextTarget.x,
|
|
336
|
+
nextTarget.y,
|
|
337
|
+
nextTarget.z
|
|
338
|
+
)
|
|
339
|
+
if (this.orbitControl && this.orbitControl.update)
|
|
340
|
+
this.orbitControl.update()
|
|
341
|
+
})
|
|
342
|
+
.onComplete(() => {
|
|
343
|
+
onCompleteCallback()
|
|
344
|
+
})
|
|
345
|
+
} else {
|
|
346
|
+
this.camera.up = { x: 0, y: 0, z: 1 }
|
|
347
|
+
this.tweenCamera = new TWEEN.Tween(currentTweenVar)
|
|
348
|
+
.to({ t: 1 }, 2000)
|
|
349
|
+
.easing(TWEEN.Easing.Sinusoidal.Out)
|
|
350
|
+
.onUpdate(() => {
|
|
351
|
+
const t = currentTweenVar.t
|
|
352
|
+
this.camera.fov = initialFov + t * t * (fov - initialFov)
|
|
353
|
+
this.camera.updateProjectionMatrix()
|
|
354
|
+
|
|
355
|
+
const nextPosition = {
|
|
356
|
+
x:
|
|
357
|
+
finalCameraPosition.x +
|
|
358
|
+
(1 - t) * (initialCameraPosition.x - finalCameraPosition.x),
|
|
359
|
+
y:
|
|
360
|
+
finalCameraPosition.y +
|
|
361
|
+
(1 - t) * (initialCameraPosition.y - finalCameraPosition.y),
|
|
362
|
+
z:
|
|
363
|
+
finalCameraPosition.z +
|
|
364
|
+
(1 - t) * (initialCameraPosition.z - finalCameraPosition.z)
|
|
365
|
+
}
|
|
366
|
+
this.camera.position.set(
|
|
367
|
+
nextPosition.x,
|
|
368
|
+
nextPosition.y,
|
|
369
|
+
nextPosition.z
|
|
370
|
+
)
|
|
371
|
+
const nextTarget = {
|
|
372
|
+
x: initialTarget.x + t * (target[0] - initialTarget.x),
|
|
373
|
+
y: initialTarget.y + t * (target[1] - initialTarget.y),
|
|
374
|
+
z: initialTarget.z + t * (target[2] - initialTarget.z)
|
|
375
|
+
}
|
|
376
|
+
this.orbitControl.target.set(
|
|
377
|
+
nextTarget.x,
|
|
378
|
+
nextTarget.y,
|
|
379
|
+
nextTarget.z
|
|
380
|
+
)
|
|
381
|
+
if (this.orbitControl && this.orbitControl.update)
|
|
382
|
+
this.orbitControl.update()
|
|
383
|
+
})
|
|
384
|
+
}
|
|
385
|
+
this.tweenCamera.start()
|
|
129
386
|
}
|
|
130
387
|
}
|
|
131
388
|
},
|
|
@@ -32,18 +32,32 @@ export default {
|
|
|
32
32
|
side: THREE.DoubleSide
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
this.material.edge = new THREE.
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
cylinder =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
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
|
-
|
|
60
|
-
|
|
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 (
|
|
10
|
-
|
|
11
|
-
|
|
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 =
|
|
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[
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
panelPolygon.moduleField.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
133
|
+
this.clearRemovedOnes('flatRoofMeshes')
|
|
134
|
+
let geometry
|
|
134
135
|
this.roofs.forEach((roofPolygon) => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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(
|
|
@@ -94,6 +106,7 @@ export default {
|
|
|
94
106
|
const name = geometryEvent.name
|
|
95
107
|
const params = geometryEvent.params
|
|
96
108
|
let methodList = []
|
|
109
|
+
console.log(name)
|
|
97
110
|
switch (name) {
|
|
98
111
|
case 'zoomIn3D':
|
|
99
112
|
methodList.push({
|
|
@@ -118,6 +131,11 @@ export default {
|
|
|
118
131
|
})
|
|
119
132
|
break
|
|
120
133
|
case 'toolChange': //params.toolName
|
|
134
|
+
methodList.push({
|
|
135
|
+
name: 'renderEdges',
|
|
136
|
+
method: this.renderEdges,
|
|
137
|
+
arg: []
|
|
138
|
+
})
|
|
121
139
|
case 'marginIsSameChange': //params.polygon
|
|
122
140
|
case 'marginDifferentChange': //params.polygon,index
|
|
123
141
|
case 'marginSameChange': //params.polygon
|
|
@@ -132,6 +150,13 @@ export default {
|
|
|
132
150
|
case 'removeNodes': //params.nodes
|
|
133
151
|
case 'removeEdges': //params.edges
|
|
134
152
|
case 'translate': //params.edges
|
|
153
|
+
if (this.removeConstructionPolylineMesh) {
|
|
154
|
+
methodList.push({
|
|
155
|
+
name: 'removeConstructionPolyline',
|
|
156
|
+
method: this.removeConstructionPolylineMesh,
|
|
157
|
+
arg: []
|
|
158
|
+
})
|
|
159
|
+
}
|
|
135
160
|
methodList.push({
|
|
136
161
|
name: 'renderGeometry',
|
|
137
162
|
method: this.renderGeometry,
|
|
@@ -187,6 +212,11 @@ export default {
|
|
|
187
212
|
method: this.renderObstacles,
|
|
188
213
|
arg: []
|
|
189
214
|
})
|
|
215
|
+
methodList.push({
|
|
216
|
+
name: 'renderNodes',
|
|
217
|
+
method: this.renderNodes,
|
|
218
|
+
arg: []
|
|
219
|
+
})
|
|
190
220
|
} else if (params.layer == 'obstacle') {
|
|
191
221
|
methodList.push({
|
|
192
222
|
name: 'renderBase',
|
|
@@ -232,11 +262,24 @@ export default {
|
|
|
232
262
|
arg: []
|
|
233
263
|
})
|
|
234
264
|
case 'selectedRoofChange':
|
|
265
|
+
case 'selectedObstacleChange':
|
|
235
266
|
methodList.push({
|
|
236
267
|
name: 'renderFlatRoofs',
|
|
237
268
|
method: this.renderFlatRoofs,
|
|
238
269
|
arg: []
|
|
239
270
|
})
|
|
271
|
+
methodList.push({
|
|
272
|
+
name: 'renderRoofsMargin',
|
|
273
|
+
method: this.renderRoofsMargin,
|
|
274
|
+
arg: []
|
|
275
|
+
})
|
|
276
|
+
break
|
|
277
|
+
case 'selectedModuleFieldChange':
|
|
278
|
+
methodList.push({
|
|
279
|
+
name: 'renderEdges',
|
|
280
|
+
method: this.renderEdges,
|
|
281
|
+
arg: []
|
|
282
|
+
})
|
|
240
283
|
break
|
|
241
284
|
case 'subHandleSelectionChange':
|
|
242
285
|
case 'masterHandleSelectionChange':
|
|
@@ -321,12 +364,28 @@ export default {
|
|
|
321
364
|
arg: [params.roofIds]
|
|
322
365
|
})
|
|
323
366
|
break
|
|
367
|
+
case 'selectedPanelChange':
|
|
368
|
+
methodList.push({
|
|
369
|
+
name: 'renderModuleFields',
|
|
370
|
+
method: this.renderModuleFields,
|
|
371
|
+
arg: []
|
|
372
|
+
})
|
|
373
|
+
break
|
|
374
|
+
case 'removeConstruction':
|
|
375
|
+
methodList.push({
|
|
376
|
+
name: 'removeConstructionPolyline',
|
|
377
|
+
method: this.removeConstructionPolyline,
|
|
378
|
+
arg: []
|
|
379
|
+
})
|
|
380
|
+
break
|
|
324
381
|
}
|
|
325
382
|
return methodList
|
|
326
383
|
},
|
|
327
384
|
async renderMethods(methodList) {
|
|
328
385
|
for (let item of methodList) {
|
|
329
|
-
|
|
386
|
+
if (item.method) {
|
|
387
|
+
await item.method(...item.arg)
|
|
388
|
+
}
|
|
330
389
|
}
|
|
331
390
|
},
|
|
332
391
|
renderGeometry() {
|
|
@@ -406,17 +465,12 @@ export default {
|
|
|
406
465
|
},
|
|
407
466
|
geometryEventsToDo(val) {
|
|
408
467
|
if (val.length > 0) {
|
|
468
|
+
console.log(val)
|
|
409
469
|
this.refreshRendering()
|
|
410
470
|
}
|
|
411
471
|
}
|
|
412
472
|
},
|
|
413
473
|
beforeDestroy() {
|
|
414
|
-
if (this.tweenOrbit) {
|
|
415
|
-
this.tweenOrbit = null
|
|
416
|
-
}
|
|
417
|
-
if (this.tweenCamera) {
|
|
418
|
-
this.tweenCamera = null
|
|
419
|
-
}
|
|
420
474
|
this.clearThreeObjects(this.scene)
|
|
421
475
|
|
|
422
476
|
if (this.three_map) {
|
package/src/helper/threeMixin.js
CHANGED
|
@@ -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 =
|
|
109
|
+
this.orbitControl.maxPolarAngle = Math.PI / 2
|
|
110
|
+
this.orbitControl.mouseButtons = {
|
|
111
|
+
LEFT: THREE.MOUSE.PAN,
|
|
112
|
+
RIGHT: 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
|
-
|
|
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
|
package/src/store/hydrateData.js
CHANGED
|
@@ -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
|
|
@@ -47,6 +68,7 @@ export async function hydratePolygons({
|
|
|
47
68
|
})
|
|
48
69
|
let roof = new Polygon(roof_outline, 'roof')
|
|
49
70
|
roof.id = roofResp.roof_uuid
|
|
71
|
+
roof.version = roofResp.version
|
|
50
72
|
roof.name = roofResp.roof_name
|
|
51
73
|
roof.shadingData = roofResp.shading_data
|
|
52
74
|
roof.systemSolarSizeKWp = roofResp.system_solar_size_kWp
|
|
@@ -67,6 +89,7 @@ export async function hydratePolygons({
|
|
|
67
89
|
})
|
|
68
90
|
let obstacle = new Polygon(obstacle_outline, 'obstacle')
|
|
69
91
|
obstacle.id = obstacleResp.obstacle_uuid
|
|
92
|
+
obstacle.version = obstacleResp.version
|
|
70
93
|
obstacle.height = obstacleResp.obstacle_height_above_ground_mm
|
|
71
94
|
obstacle.isParallel = obstacleResp.obstacle_slope_is_parallel_to_roof
|
|
72
95
|
obstacle = updateComputedGeometryPolygon(obstacle)
|
|
@@ -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
|
-
|
|
119
|
-
|
|
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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|