@eturnity/eturnity_3d 7.33.1 → 7.35.0-EPDM-10923.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 +7 -7
- package/src/Overlay/GLBOverlay.js +97 -0
- package/src/Overlay/OverlayFactory.js +3 -3
- package/src/Overlay/{AirTeamOverlay.js → ThreeDModelOverlay.js} +129 -186
- package/src/components/ThreeCanvasViewer.vue +1 -1
- package/src/helper/UpdateRoofModuleFieldRelations.js +34 -94
- package/src/helper/UpdateRoofObstacleRelations.js +0 -3
- package/src/helper/render/imageOverlay.js +3 -3
- package/src/helper/render/margin.js +1 -1
- package/src/helper/render/overlay.js +0 -3
- package/src/helper/render/tileProjection.js +0 -10
- package/src/helper/renderMixin.js +10 -0
- package/src/helper/threeMixin.js +4 -2
- package/src/store/hydrateData.js +10 -8
- package/src/store/three-d-module.js +1 -1
- package/src/store/nodesEdgesCreation.js +0 -279
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eturnity/eturnity_3d",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "7.
|
|
4
|
+
"version": "7.35.0-EPDM-10923.0",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"src"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"prettier": "prettier --write \"**/*.{js,vue}\""
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@eturnity/eturnity_maths": "7.
|
|
18
|
+
"@eturnity/eturnity_maths": "7.35.0-EPDM-10923.0",
|
|
19
19
|
"@originjs/vite-plugin-commonjs": "1.0.3",
|
|
20
20
|
"core-js": "2.6.12",
|
|
21
21
|
"cors": "2.8.5",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
"leaflet.gridlayer.googlemutant": "0.14.0",
|
|
27
27
|
"lodash": "4.17.21",
|
|
28
28
|
"svd-js": "1.1.1",
|
|
29
|
-
"three": "0.
|
|
29
|
+
"three": "0.142.0",
|
|
30
30
|
"tween": "0.9.0",
|
|
31
31
|
"uuid": "9.0.0",
|
|
32
|
-
"vite-plugin-require": "1.
|
|
32
|
+
"vite-plugin-require": "1.2.14",
|
|
33
33
|
"vue": "3.3.4",
|
|
34
34
|
"vuex": "4.1.0"
|
|
35
35
|
},
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"eslint-plugin-prettier": "4.2.1",
|
|
43
43
|
"eslint-plugin-vue": "9.14.1",
|
|
44
44
|
"html-webpack-plugin": "3.2.0",
|
|
45
|
-
"prettier": "
|
|
46
|
-
"prettier-plugin-vue": "
|
|
45
|
+
"prettier": "2.8.4",
|
|
46
|
+
"prettier-plugin-vue": "1.1.6",
|
|
47
47
|
"vite": "2.7.2",
|
|
48
|
-
"vite-plugin-env-compatible": "
|
|
48
|
+
"vite-plugin-env-compatible": "2.0.1",
|
|
49
49
|
"webpack": "4.46.0",
|
|
50
50
|
"webpack-cli": "4.10.0"
|
|
51
51
|
},
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import ThreeDModelOverlay from './ThreeDModelOverlay'
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
|
|
4
|
+
import { deltaLatLngToDistance } from '@eturnity/eturnity_maths'
|
|
5
|
+
export default class GLBOverlay extends ThreeDModelOverlay {
|
|
6
|
+
constructor(overlay, emit, origin) {
|
|
7
|
+
super(overlay, emit, origin, new GLTFLoader())
|
|
8
|
+
this.extracted = false
|
|
9
|
+
this.geoLocalisation = this.settings.geoLocalisation
|
|
10
|
+
this.has_plain_roof_simplified = false
|
|
11
|
+
}
|
|
12
|
+
loadFile() {
|
|
13
|
+
this.isReady = false
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
if (this.overlayMesh) {
|
|
16
|
+
resolve(this.overlayMesh)
|
|
17
|
+
}
|
|
18
|
+
let resource = this.resources[0]
|
|
19
|
+
let overlayMesh = new THREE.Group()
|
|
20
|
+
this.loader.load(resource.file_url, (gltf) => {
|
|
21
|
+
const model = gltf.scene
|
|
22
|
+
model.rotateX(Math.PI / 2)
|
|
23
|
+
overlayMesh.userData.meshId = this.id
|
|
24
|
+
overlayMesh.userData.type = 'overlayMeshes'
|
|
25
|
+
overlayMesh.userData.version = this.version
|
|
26
|
+
overlayMesh.attach(model)
|
|
27
|
+
overlayMesh.position.set(0, 0, 0)
|
|
28
|
+
const box = new THREE.Box3().setFromObject(overlayMesh)
|
|
29
|
+
overlayMesh.position.set(0, 0, -box.min.z)
|
|
30
|
+
|
|
31
|
+
if (overlayMesh.getObjectByName('plain_roof_simplified')) {
|
|
32
|
+
this.has_plain_roof_simplified = true
|
|
33
|
+
this.type = 'airteam'
|
|
34
|
+
} else {
|
|
35
|
+
this.type = 'custom_3d_model'
|
|
36
|
+
}
|
|
37
|
+
overlayMesh.traverse((object) => {
|
|
38
|
+
if (object.material) {
|
|
39
|
+
object.material.metalness = 0
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
resolve(overlayMesh)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
checkGeoLocDataAndOffset() {
|
|
47
|
+
const lat0 = this.overlayMesh.children[0].userData.latitude_origin
|
|
48
|
+
const lng0 = this.overlayMesh.children[0].userData.longitude_origin
|
|
49
|
+
if (lat0 && lng0 && this.origin) {
|
|
50
|
+
let { x, y } = deltaLatLngToDistance(
|
|
51
|
+
lat0 - this.origin.lat,
|
|
52
|
+
lng0 - this.origin.lng,
|
|
53
|
+
lat0
|
|
54
|
+
)
|
|
55
|
+
if (Math.hypot(x, y) < 100000) {
|
|
56
|
+
this.positionOffset.x = x
|
|
57
|
+
this.positionOffset.y = y
|
|
58
|
+
this.positionOffset.z = 0
|
|
59
|
+
} else {
|
|
60
|
+
this.positionOffset.x = 0
|
|
61
|
+
this.positionOffset.y = 0
|
|
62
|
+
this.positionOffset.z = 0
|
|
63
|
+
this.emit('overlay-offset-position-error', { id: this.id })
|
|
64
|
+
}
|
|
65
|
+
this.geoLocalisation = { x, y }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
setOverlayVisibilityFor2D() {
|
|
69
|
+
if (
|
|
70
|
+
this.overlayMesh.children[0].children.some(
|
|
71
|
+
(child) => child.name == 'plain_roof_simplified'
|
|
72
|
+
)
|
|
73
|
+
) {
|
|
74
|
+
this.overlayMesh.children[0].children.forEach(
|
|
75
|
+
(child) => (child.visible = child.name != 'plain_roof_simplified')
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
return this.overlayMesh
|
|
79
|
+
}
|
|
80
|
+
set3DObjectMaterialOpacity(obj) {
|
|
81
|
+
obj.children.forEach((child) => {
|
|
82
|
+
this.set3DObjectMaterialOpacity(child, this.opacity)
|
|
83
|
+
})
|
|
84
|
+
if (obj.material && obj.name != 'plain_roof_simplified') {
|
|
85
|
+
obj.visible = this.opacity > 0
|
|
86
|
+
obj.material.opacity = this.opacity
|
|
87
|
+
obj.material.transparent = this.opacity < 1
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
serializeSettings() {
|
|
91
|
+
return {
|
|
92
|
+
version: this.version,
|
|
93
|
+
corners: this.corners,
|
|
94
|
+
geoLocalisation: this.geoLocalisation,
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import Overlay from './Overlay'
|
|
2
|
-
import
|
|
2
|
+
import GLBOverlay from './GLBOverlay'
|
|
3
3
|
import ImageOverlay from './ImageOverlay'
|
|
4
4
|
|
|
5
5
|
const OverlayFactory = {
|
|
6
6
|
createOverlay(serializedOverlay, emit, origin = { lat: null, lng: null }) {
|
|
7
7
|
let overlayInstance
|
|
8
|
-
if (serializedOverlay.type
|
|
9
|
-
overlayInstance = new
|
|
8
|
+
if (['airteam', 'custom_3d_model'].includes(serializedOverlay.type)) {
|
|
9
|
+
overlayInstance = new GLBOverlay(serializedOverlay, emit, origin)
|
|
10
10
|
} else if (serializedOverlay.type == 'image_overlay') {
|
|
11
11
|
overlayInstance = new ImageOverlay(serializedOverlay, emit)
|
|
12
12
|
} else {
|
|
@@ -15,16 +15,17 @@ import {
|
|
|
15
15
|
vectorLength2D,
|
|
16
16
|
deltaLatLngToDistance,
|
|
17
17
|
rotateTransformation,
|
|
18
|
+
getStandardDeviation,
|
|
18
19
|
} from '@eturnity/eturnity_maths'
|
|
19
20
|
let Paper
|
|
20
|
-
export default class
|
|
21
|
-
constructor(overlay, emit, origin) {
|
|
21
|
+
export default class ThreeDModelOverlay extends Overlay {
|
|
22
|
+
constructor(overlay, emit, origin, loader) {
|
|
22
23
|
super(overlay, emit)
|
|
23
|
-
//this.updateVerticalProjectionIfNeeded()
|
|
24
24
|
this.canvasWidth = 400
|
|
25
25
|
this.canvasHeight = 400
|
|
26
26
|
this.origin = origin
|
|
27
27
|
this.imageUrl = null
|
|
28
|
+
this.loader = loader
|
|
28
29
|
this.initialiseModel().then((isReady) => {
|
|
29
30
|
this.isReady = isReady
|
|
30
31
|
this.version++
|
|
@@ -42,6 +43,7 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
42
43
|
this.extracted = false
|
|
43
44
|
this.geoLocalisation = this.settings.geoLocalisation
|
|
44
45
|
}
|
|
46
|
+
loadFile() {}
|
|
45
47
|
onLoad() {
|
|
46
48
|
return new Promise((resolve) => {
|
|
47
49
|
if (this.isReady) {
|
|
@@ -51,65 +53,17 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
51
53
|
}
|
|
52
54
|
})
|
|
53
55
|
}
|
|
54
|
-
setOpacity(opacity) {
|
|
55
|
-
this.opacity = opacity
|
|
56
|
-
this.emit('item-updated', this)
|
|
57
|
-
this.emit('overlay-three-loaded', this)
|
|
58
|
-
}
|
|
59
|
-
hasVerticalProjection() {
|
|
60
|
-
return this.resources.some((resource) => resource.file_type == 'image')
|
|
61
|
-
}
|
|
62
|
-
loadGLBFile() {
|
|
63
|
-
this.isReady = false
|
|
64
|
-
return new Promise((resolve) => {
|
|
65
|
-
if (this.overlayMesh) {
|
|
66
|
-
resolve(this.overlayMesh)
|
|
67
|
-
}
|
|
68
|
-
let resource = this.resources[0]
|
|
69
|
-
let overlayMesh = new THREE.Group()
|
|
70
|
-
const glbLoader = new GLTFLoader()
|
|
71
|
-
glbLoader.load(resource.file_url, (gltf) => {
|
|
72
|
-
const model = gltf.scene
|
|
73
|
-
overlayMesh.attach(model)
|
|
74
|
-
overlayMesh.userData.meshId = this.id
|
|
75
|
-
model.rotateX(Math.PI / 2)
|
|
76
|
-
model.children = model.children.filter((child) =>
|
|
77
|
-
[
|
|
78
|
-
'textured_facade',
|
|
79
|
-
'textured_environment',
|
|
80
|
-
'textured_roof',
|
|
81
|
-
'plain_roof_simplified',
|
|
82
|
-
].includes(child.name)
|
|
83
|
-
)
|
|
84
|
-
model.children.forEach((child) => {
|
|
85
|
-
if (['plain_roof_simplified'].includes(child.name)) {
|
|
86
|
-
child.visible = false
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
overlayMesh.userData.type = 'overlayMeshes'
|
|
91
|
-
overlayMesh.userData.meshId = this.id
|
|
92
|
-
overlayMesh.userData.version = this.version
|
|
93
|
-
overlayMesh.position.set(0, 0, 0)
|
|
94
|
-
const box = new THREE.Box3().setFromObject(overlayMesh)
|
|
95
|
-
overlayMesh.position.set(0, 0, -box.min.z)
|
|
96
|
-
resolve(overlayMesh)
|
|
97
|
-
})
|
|
98
|
-
})
|
|
99
|
-
}
|
|
100
56
|
set3DObjectMaterialOpacity(obj) {
|
|
101
57
|
obj.children.forEach((child) => {
|
|
102
58
|
this.set3DObjectMaterialOpacity(child, this.opacity)
|
|
103
59
|
})
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
obj.material.transparent = this.opacity < 1
|
|
108
|
-
}
|
|
60
|
+
obj.visible = this.opacity > 0
|
|
61
|
+
obj.material.opacity = this.opacity
|
|
62
|
+
obj.material.transparent = this.opacity < 1
|
|
109
63
|
}
|
|
110
64
|
async renderOnThreeJS(threeJSComponent) {
|
|
111
65
|
if (this.overlayMesh && this.overlayMesh.children.length == 0) {
|
|
112
|
-
this.overlayMesh = await this.
|
|
66
|
+
this.overlayMesh = await this.loadFile()
|
|
113
67
|
}
|
|
114
68
|
|
|
115
69
|
if (!this.isReady) {
|
|
@@ -150,7 +104,7 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
150
104
|
threeJSComponent.scene.add(overlayMesh)
|
|
151
105
|
}
|
|
152
106
|
if (!overlayMesh) {
|
|
153
|
-
overlayMesh = await this.
|
|
107
|
+
overlayMesh = await this.loadFile()
|
|
154
108
|
threeJSComponent.meshes.overlayMeshes[meshId] = overlayMesh
|
|
155
109
|
}
|
|
156
110
|
const positionOffset = multiplyVector(1 / 1000, this.positionOffset)
|
|
@@ -168,6 +122,7 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
168
122
|
threeJSComponent.scene.add(overlayMesh)
|
|
169
123
|
threeJSComponent.render()
|
|
170
124
|
}
|
|
125
|
+
|
|
171
126
|
this.overlayMesh = overlayMesh
|
|
172
127
|
this.overlayMesh.frustumCulled = false
|
|
173
128
|
this.set3DObjectMaterialOpacity(this.overlayMesh)
|
|
@@ -231,7 +186,6 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
231
186
|
group.visible = true
|
|
232
187
|
group.opacity = this.opacity
|
|
233
188
|
group.transparent = this.opacity != 1
|
|
234
|
-
// group.children[2].position=new Paper.Point(paperJSComponent.toCanvasRef(this.geoLocalisation))
|
|
235
189
|
} else {
|
|
236
190
|
group = new Paper.Group()
|
|
237
191
|
imageOverlayPath = this.loadImageOverlay(this.imageUrl, corners)
|
|
@@ -239,11 +193,6 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
239
193
|
handles = this.renderImageOverlayHandles(corners, isRotationHandleVisible)
|
|
240
194
|
group.addChild(imageOverlayPath)
|
|
241
195
|
group.addChild(handles)
|
|
242
|
-
// let circle=new Paper.Path.Circle(new Paper.Point(paperJSComponent.toCanvasRef(multiplyVector(1000,this.geoLocalisation))),10)
|
|
243
|
-
// circle.strokeWidth=2
|
|
244
|
-
// circle.strokeColor = 'lime'
|
|
245
|
-
// group.addChild(circle)
|
|
246
|
-
|
|
247
196
|
group.itemType = 'imageOverlays'
|
|
248
197
|
group.data.url = this.url
|
|
249
198
|
group.type = 'imageOverlays'
|
|
@@ -374,11 +323,66 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
374
323
|
circleHandle.visible = rotateHandleVisible
|
|
375
324
|
return handles
|
|
376
325
|
}
|
|
326
|
+
initialiseCornersAndProjectionCamera() {
|
|
327
|
+
const box = new THREE.Box3().setFromObject(this.overlayMesh)
|
|
328
|
+
const boxSize = box.getSize(new THREE.Vector3())
|
|
329
|
+
this.boxSize = boxSize
|
|
330
|
+
const boxCenter = box.getCenter(new THREE.Vector3())
|
|
331
|
+
const left = -boxSize.x / 2
|
|
332
|
+
const right = +boxSize.x / 2
|
|
333
|
+
const top = +boxSize.y / 2
|
|
334
|
+
const bottom = -boxSize.y / 2
|
|
335
|
+
this.boxCenter = boxCenter
|
|
336
|
+
const initialCorners = [
|
|
337
|
+
{
|
|
338
|
+
x: 1000 * (boxCenter.x + left),
|
|
339
|
+
y: 1000 * (boxCenter.y + top),
|
|
340
|
+
z: 0,
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
x: 1000 * (boxCenter.x + right),
|
|
344
|
+
y: 1000 * (boxCenter.y + top),
|
|
345
|
+
z: 0,
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
x: 1000 * (boxCenter.x + right),
|
|
349
|
+
y: 1000 * (boxCenter.y + bottom),
|
|
350
|
+
z: 0,
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
x: 1000 * (boxCenter.x + left),
|
|
354
|
+
y: 1000 * (boxCenter.y + bottom),
|
|
355
|
+
z: 0,
|
|
356
|
+
},
|
|
357
|
+
]
|
|
358
|
+
this.corners = []
|
|
359
|
+
initialCorners.forEach((corner, index) => {
|
|
360
|
+
corner = rotateTransformation(
|
|
361
|
+
corner,
|
|
362
|
+
this.angleOffset,
|
|
363
|
+
multiplyVector(1000, boxCenter)
|
|
364
|
+
)
|
|
365
|
+
corner = addVector(corner, this.positionOffset)
|
|
366
|
+
this.corners[index] = corner
|
|
367
|
+
})
|
|
368
|
+
this.overlayProjectionCamera = new THREE.OrthographicCamera(
|
|
369
|
+
left,
|
|
370
|
+
right,
|
|
371
|
+
top,
|
|
372
|
+
bottom,
|
|
373
|
+
0.1, // near
|
|
374
|
+
1000 // far
|
|
375
|
+
)
|
|
376
|
+
}
|
|
377
|
+
checkGeoLocDataAndOffset() {
|
|
378
|
+
return
|
|
379
|
+
}
|
|
377
380
|
async initialiseModel() {
|
|
378
|
-
this.overlayMesh = await this.
|
|
381
|
+
this.overlayMesh = await this.loadFile()
|
|
379
382
|
if (!this.geoLocalisation) {
|
|
380
383
|
this.checkGeoLocDataAndOffset()
|
|
381
384
|
}
|
|
385
|
+
this.initialiseCornersAndProjectionCamera()
|
|
382
386
|
this.imageUrl = await this.initialiseVerticalProjectionImg()
|
|
383
387
|
this.overlayMesh.position.set(
|
|
384
388
|
this.positionOffset.x / 1000,
|
|
@@ -388,86 +392,24 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
388
392
|
this.overlayMesh.rotateZ(-this.angleOffset)
|
|
389
393
|
return true
|
|
390
394
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const lng0 = this.overlayMesh.children[0].userData.longitude_origin
|
|
394
|
-
if (lat0 && lng0 && this.origin) {
|
|
395
|
-
let { x, y } = deltaLatLngToDistance(
|
|
396
|
-
lat0 - this.origin.lat,
|
|
397
|
-
lng0 - this.origin.lng,
|
|
398
|
-
lat0
|
|
399
|
-
)
|
|
400
|
-
if (Math.hypot(x, y) < 100000) {
|
|
401
|
-
this.positionOffset.x = x
|
|
402
|
-
this.positionOffset.y = y
|
|
403
|
-
this.positionOffset.z = 0
|
|
404
|
-
} else {
|
|
405
|
-
this.positionOffset.x = 0
|
|
406
|
-
this.positionOffset.y = 0
|
|
407
|
-
this.positionOffset.z = 0
|
|
408
|
-
this.emit('overlay-offset-position-error', { id: this.id })
|
|
409
|
-
}
|
|
410
|
-
this.geoLocalisation = { x, y }
|
|
411
|
-
}
|
|
395
|
+
setOverlayVisibilityFor2D() {
|
|
396
|
+
return this.overlayMesh
|
|
412
397
|
}
|
|
413
398
|
initialiseVerticalProjectionImg() {
|
|
414
399
|
return new Promise((resolve, reject) => {
|
|
415
|
-
const box = new THREE.Box3().setFromObject(this.overlayMesh)
|
|
416
|
-
const boxSize = box.getSize(new THREE.Vector3())
|
|
417
|
-
this.boxSize = boxSize
|
|
418
|
-
this.canvasWidth = boxSize.x * 100
|
|
419
|
-
this.canvasHeight = boxSize.y * 100
|
|
420
|
-
const boxCenter = box.getCenter(new THREE.Vector3())
|
|
421
|
-
const left = -boxSize.x / 2
|
|
422
|
-
const right = +boxSize.x / 2
|
|
423
|
-
const top = +boxSize.y / 2
|
|
424
|
-
const bottom = -boxSize.y / 2
|
|
425
|
-
this.boxCenter = boxCenter
|
|
426
|
-
const initialCorners = [
|
|
427
|
-
{
|
|
428
|
-
x: 1000 * (boxCenter.x + left),
|
|
429
|
-
y: 1000 * (boxCenter.y + top),
|
|
430
|
-
z: 0,
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
x: 1000 * (boxCenter.x + right),
|
|
434
|
-
y: 1000 * (boxCenter.y + top),
|
|
435
|
-
z: 0,
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
x: 1000 * (boxCenter.x + right),
|
|
439
|
-
y: 1000 * (boxCenter.y + bottom),
|
|
440
|
-
z: 0,
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
x: 1000 * (boxCenter.x + left),
|
|
444
|
-
y: 1000 * (boxCenter.y + bottom),
|
|
445
|
-
z: 0,
|
|
446
|
-
},
|
|
447
|
-
]
|
|
448
|
-
this.corners = []
|
|
449
|
-
initialCorners.forEach((corner, index) => {
|
|
450
|
-
corner = rotateTransformation(
|
|
451
|
-
corner,
|
|
452
|
-
this.angleOffset,
|
|
453
|
-
multiplyVector(1000, boxCenter)
|
|
454
|
-
)
|
|
455
|
-
corner = addVector(corner, this.positionOffset)
|
|
456
|
-
this.corners[index] = corner
|
|
457
|
-
})
|
|
458
400
|
// Create a canvas element
|
|
401
|
+
this.canvasWidth = this.boxSize.x * 100
|
|
402
|
+
this.canvasHeight = this.boxSize.y * 100
|
|
403
|
+
const maxSize = Math.max(this.canvasWidth, this.canvasHeight)
|
|
404
|
+
const CANVAS_MAX_SIZE = 2048
|
|
405
|
+
if (maxSize > CANVAS_MAX_SIZE) {
|
|
406
|
+
this.canvasWidth *= CANVAS_MAX_SIZE / maxSize
|
|
407
|
+
this.canvasHeight *= CANVAS_MAX_SIZE / maxSize
|
|
408
|
+
}
|
|
459
409
|
const canvas = this.createCanvas()
|
|
460
410
|
|
|
461
411
|
// Initialize Three.js
|
|
462
412
|
const scene = new THREE.Scene()
|
|
463
|
-
this.overlayProjectionCamera = new THREE.OrthographicCamera(
|
|
464
|
-
left,
|
|
465
|
-
right,
|
|
466
|
-
top,
|
|
467
|
-
bottom,
|
|
468
|
-
0.1, // near
|
|
469
|
-
1000 // far
|
|
470
|
-
)
|
|
471
413
|
|
|
472
414
|
const renderer = new THREE.WebGLRenderer({
|
|
473
415
|
canvas: canvas,
|
|
@@ -475,54 +417,40 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
475
417
|
})
|
|
476
418
|
renderer.setSize(this.canvasWidth, this.canvasHeight)
|
|
477
419
|
renderer.setClearColor(0x000000, 0) // Make background transparent
|
|
478
|
-
|
|
420
|
+
this.setOverlayVisibilityFor2D()
|
|
479
421
|
scene.add(this.overlayMesh)
|
|
480
422
|
|
|
423
|
+
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8)
|
|
424
|
+
ambientLight.name = 'overlayAmbientLight'
|
|
425
|
+
scene.add(ambientLight)
|
|
426
|
+
const light = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.8)
|
|
427
|
+
ambientLight.name = 'overlayHemisphereLight'
|
|
428
|
+
scene.add(light)
|
|
429
|
+
|
|
481
430
|
// Set camera position and look at the center of the model
|
|
482
431
|
this.overlayProjectionCamera.position.set(
|
|
483
|
-
boxCenter.x,
|
|
484
|
-
boxCenter.y,
|
|
485
|
-
boxCenter.z + 100
|
|
432
|
+
this.boxCenter.x,
|
|
433
|
+
this.boxCenter.y,
|
|
434
|
+
this.boxCenter.z + 100
|
|
486
435
|
)
|
|
487
|
-
this.overlayProjectionCamera.lookAt(boxCenter.x, boxCenter.y, 0)
|
|
436
|
+
this.overlayProjectionCamera.lookAt(this.boxCenter.x, this.boxCenter.y, 0)
|
|
488
437
|
this.overlayProjectionCamera.updateProjectionMatrix()
|
|
489
|
-
const childrenVisibility = this.overlayMesh.children[0].children.map(
|
|
490
|
-
(child) => child.visible
|
|
491
|
-
)
|
|
492
|
-
this.overlayMesh.children[0].children.forEach(
|
|
493
|
-
(child) => (child.visible = child.name == 'textured_roof')
|
|
494
|
-
)
|
|
495
|
-
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8)
|
|
496
|
-
this.overlayMesh.children[0].add(ambientLight)
|
|
497
|
-
const light = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.8)
|
|
498
|
-
this.overlayMesh.children[0].add(light)
|
|
499
438
|
// Render the scene
|
|
500
439
|
renderer.render(scene, this.overlayProjectionCamera)
|
|
501
440
|
|
|
502
441
|
// Generate image from canvas
|
|
503
442
|
const imageUrl = canvas.toDataURL()
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
this.overlayMesh.children[0].children.forEach((child, index) => {
|
|
507
|
-
child.visible = childrenVisibility[index]
|
|
508
|
-
})
|
|
443
|
+
scene.remove(light)
|
|
444
|
+
scene.remove(ambientLight)
|
|
509
445
|
canvas.parentNode.removeChild(canvas)
|
|
510
446
|
resolve(imageUrl)
|
|
511
447
|
})
|
|
512
448
|
}
|
|
513
|
-
getProjectedPlanesOnOverlay(
|
|
514
|
-
// const scene = new THREE.Scene()
|
|
449
|
+
getProjectedPlanesOnOverlay(polygons) {
|
|
515
450
|
const RayCaster = new THREE.Raycaster()
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
// overlaySimplifiedRoof.visible = true
|
|
520
|
-
// if(overlaySimplifiedRoof){
|
|
521
|
-
// }else{
|
|
522
|
-
let overlaySimplifiedRoof = this.overlayMesh.clone()
|
|
523
|
-
//}
|
|
524
|
-
//scene.add(overlayMesh)
|
|
525
|
-
const cloudsPoints = outlines.map((outline) => {
|
|
451
|
+
const cloudsPoints = polygons.map((polygon) => {
|
|
452
|
+
const outline = polygon.outline
|
|
453
|
+
const holeOutlines = polygon.holes.map((h) => h.outline)
|
|
526
454
|
let outlineBounds = outline.reduce(
|
|
527
455
|
(acc, cur) => {
|
|
528
456
|
acc.xMin = Math.min(acc.xMin, cur.x)
|
|
@@ -535,24 +463,27 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
535
463
|
)
|
|
536
464
|
let { xMin, xMax, yMin, yMax } = outlineBounds
|
|
537
465
|
const cloudPoints = []
|
|
538
|
-
let stepNum =
|
|
539
|
-
for (let i =
|
|
540
|
-
for (let j =
|
|
466
|
+
let stepNum = 8
|
|
467
|
+
for (let i = 1; i < stepNum; i++) {
|
|
468
|
+
for (let j = 1; j < stepNum; j++) {
|
|
541
469
|
const testPoint = {
|
|
542
470
|
x: xMin + (i * (xMax - xMin)) / stepNum,
|
|
543
471
|
y: yMin + (j * (yMax - yMin)) / stepNum,
|
|
544
472
|
}
|
|
545
|
-
if (
|
|
473
|
+
if (
|
|
474
|
+
isInsidePolygon(testPoint, outline) &&
|
|
475
|
+
holeOutlines.every(
|
|
476
|
+
(holeOutline) => !isInsidePolygon(testPoint, holeOutline)
|
|
477
|
+
)
|
|
478
|
+
) {
|
|
546
479
|
RayCaster.set(
|
|
547
|
-
new THREE.Vector3(testPoint.x / 1000, testPoint.y / 1000,
|
|
548
|
-
new THREE.Vector3(0, 0, 1)
|
|
480
|
+
new THREE.Vector3(testPoint.x / 1000, testPoint.y / 1000, 100),
|
|
481
|
+
new THREE.Vector3(0, 0, -1)
|
|
549
482
|
)
|
|
550
|
-
let intersects = RayCaster.intersectObject(
|
|
551
|
-
intersects.
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}
|
|
555
|
-
})
|
|
483
|
+
let intersects = RayCaster.intersectObject(this.overlayMesh)
|
|
484
|
+
if (intersects.length > 0) {
|
|
485
|
+
cloudPoints.push(intersects[0].point)
|
|
486
|
+
}
|
|
556
487
|
}
|
|
557
488
|
}
|
|
558
489
|
}
|
|
@@ -560,19 +491,31 @@ export default class AirTeamOverlay extends Overlay {
|
|
|
560
491
|
})
|
|
561
492
|
const SVDResults = cloudsPoints.map((cloud) => {
|
|
562
493
|
if (cloud.length > 3) {
|
|
563
|
-
|
|
494
|
+
let cloudInMm = cloud.map((p) => {
|
|
495
|
+
return multiplyVector(1000, p)
|
|
496
|
+
})
|
|
497
|
+
let SVDResult = calculateBestFittingPlanePolygon(cloudInMm)
|
|
498
|
+
let gaps = SVDResult.gaps
|
|
499
|
+
let standardDeviation = getStandardDeviation(gaps)
|
|
500
|
+
if (standardDeviation > 10 && cloudInMm.length > 10) {
|
|
501
|
+
let sortedGaps = gaps.map((p) => p)
|
|
502
|
+
sortedGaps = sortedGaps.sort((a, b) => a - b)
|
|
503
|
+
let threshold = sortedGaps[Math.floor(sortedGaps.length * 0.75)]
|
|
504
|
+
cloudInMm = cloudInMm.filter((_, index) => {
|
|
505
|
+
return gaps[index] <= threshold
|
|
506
|
+
})
|
|
507
|
+
SVDResult = calculateBestFittingPlanePolygon(cloudInMm)
|
|
508
|
+
}
|
|
509
|
+
return SVDResult
|
|
564
510
|
} else {
|
|
565
511
|
return null
|
|
566
512
|
}
|
|
567
513
|
})
|
|
568
|
-
const newOutlines =
|
|
514
|
+
const newOutlines = polygons.map((polygon, index) => {
|
|
515
|
+
let outline = polygon.outline
|
|
569
516
|
if (SVDResults[index]) {
|
|
570
517
|
const normalVector = SVDResults[index].normalVector
|
|
571
|
-
const referencePoint =
|
|
572
|
-
1000,
|
|
573
|
-
SVDResults[index].projectedOutline[0]
|
|
574
|
-
)
|
|
575
|
-
|
|
518
|
+
const referencePoint = SVDResults[index].projectedOutline[0]
|
|
576
519
|
const newOutline = outline.map((p) =>
|
|
577
520
|
verticalProjectionOnPlane(p, normalVector, referencePoint)
|
|
578
521
|
)
|
|
@@ -6,113 +6,53 @@ import {
|
|
|
6
6
|
} from '@eturnity/eturnity_maths'
|
|
7
7
|
//this function just update the "roof" and "moduleField(s)" properties of panels,moduleFields and roofs
|
|
8
8
|
export function UpdateRoofModuleFieldRelations(state) {
|
|
9
|
-
|
|
10
|
-
const moduleFieldPolygons = state.polygons.filter(
|
|
9
|
+
let moduleFields = state.polygons.filter(
|
|
11
10
|
(poly) => poly.layer == 'moduleField'
|
|
12
11
|
)
|
|
13
|
-
|
|
12
|
+
let roofs = state.polygons.filter((poly) => poly.layer == 'roof')
|
|
13
|
+
const panels = state.polygons.filter((poly) =>
|
|
14
14
|
['panel', 'user_deactivated_panel'].includes(poly.layer)
|
|
15
15
|
)
|
|
16
|
-
panelPolygons.forEach((panel) => {
|
|
17
|
-
panel.roof = null
|
|
18
|
-
})
|
|
19
|
-
//let's remove all moduleFields from roofs
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
let roofUnderPerModuleFieldId = {}
|
|
18
|
+
moduleFields.forEach((moduleField) => {
|
|
19
|
+
let roofModuleFieldIntersections = []
|
|
20
|
+
roofs.forEach((roof) => {
|
|
21
|
+
let intersection = intersectOutlines(roof.outline, moduleField.outline)
|
|
22
|
+
if (intersection.length) {
|
|
23
|
+
const intersectionArea = intersection.reduce((acc, cur) => {
|
|
24
|
+
acc += calculateArea(cur)
|
|
25
|
+
return acc
|
|
26
|
+
}, 0)
|
|
27
|
+
roofModuleFieldIntersections.push({ roof, intersectionArea })
|
|
28
|
+
}
|
|
27
29
|
})
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
roofModuleFieldIntersections.sort((a, b) => a.roof.area - b.roof.area)
|
|
31
|
+
roofModuleFieldIntersections.sort(
|
|
32
|
+
(a, b) => b.intersectionArea - a.intersectionArea
|
|
33
|
+
)
|
|
34
|
+
if (roofModuleFieldIntersections.length) {
|
|
35
|
+
roofUnderPerModuleFieldId[moduleField.id] =
|
|
36
|
+
roofModuleFieldIntersections[0].roof
|
|
35
37
|
}
|
|
36
38
|
})
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
roof,
|
|
51
|
-
intersectionArea: 0,
|
|
52
|
-
intersectionRatio: 0,
|
|
53
|
-
areaRatio: 0,
|
|
54
|
-
roofBiggerThanModuleField: 1,
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
const intersectionArea_m2 = calculateArea(intersection[0]) / 1e6
|
|
58
|
-
return {
|
|
59
|
-
roof,
|
|
60
|
-
intersectionArea: intersectionArea_m2,
|
|
61
|
-
intersectionRatio: (intersectionArea_m2 / roof.area).toFixed(3),
|
|
62
|
-
areaRatio: (moduleField.area / roof.area).toFixed(3),
|
|
63
|
-
roofBiggerThanModuleField: roof.area >= moduleField.area ? 1 : -1,
|
|
39
|
+
roofs.forEach((roof) => (roof.moduleFields = []))
|
|
40
|
+
panels.forEach((panel) => {
|
|
41
|
+
panel.roof = null
|
|
42
|
+
})
|
|
43
|
+
moduleFields.forEach((moduleField) => {
|
|
44
|
+
let roof = roofUnderPerModuleFieldId[moduleField.id]
|
|
45
|
+
if (roof) {
|
|
46
|
+
moduleField.roof = roof
|
|
47
|
+
roof.moduleFields.push(moduleField)
|
|
48
|
+
panels.forEach((panel) => {
|
|
49
|
+
if (panel.moduleField.id == moduleField.id) {
|
|
50
|
+
panel.roof = roof
|
|
64
51
|
}
|
|
65
52
|
})
|
|
66
|
-
//roofs on roof can lead to multiple roof under a point. moduleField is on the smallest
|
|
67
|
-
|
|
68
|
-
roofPolygonCandidates
|
|
69
|
-
.sort((a, b) => b.roof.area - a.roof.area)
|
|
70
|
-
.sort((a, b) => a.intersectionArea - b.intersectionArea)
|
|
71
|
-
.sort(
|
|
72
|
-
(a, b) => a.roofBiggerThanModuleField - b.roofBiggerThanModuleField
|
|
73
|
-
)
|
|
74
|
-
let polygonCandidate = roofPolygonCandidates.pop()
|
|
75
|
-
if (!polygonCandidate) {
|
|
76
|
-
continue
|
|
77
|
-
}
|
|
78
|
-
roofPolygon = polygonCandidate.roof
|
|
79
|
-
if (!roofPolygon) {
|
|
80
|
-
continue
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
roofPolygon.moduleFields.push(moduleField)
|
|
84
53
|
}
|
|
85
|
-
roofPolygon = roofPolygons.find((r) => r.id == roofPolygon.id)
|
|
86
|
-
roofPolygon.moduleFields = [
|
|
87
|
-
...roofPolygon.moduleFields.filter((mf) => mf.id != moduleField.id),
|
|
88
|
-
moduleField,
|
|
89
|
-
]
|
|
90
|
-
moduleField.roof = roofPolygon
|
|
91
|
-
moduleField.panels.forEach((panel) => (panel.roof = roofPolygon))
|
|
92
|
-
panelPolygons.forEach((p) => {
|
|
93
|
-
if (p.moduleField.id == moduleField.id) {
|
|
94
|
-
p.roof = roofPolygon
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
let newPolygons = state.polygons.map((p) => {
|
|
100
|
-
if (
|
|
101
|
-
!['roof', 'moduleField', 'panel', 'user_deactivated_panel'].includes(
|
|
102
|
-
p.layer
|
|
103
|
-
)
|
|
104
|
-
)
|
|
105
|
-
return p
|
|
106
|
-
if (p.layer == 'roof') return roofPolygons.find((r) => r.id == p.id)
|
|
107
|
-
if (p.layer == 'moduleField')
|
|
108
|
-
return moduleFieldPolygons.find((mf) => mf.id == p.id)
|
|
109
|
-
if (['panel', 'user_deactivated_panel'].includes(p.layer))
|
|
110
|
-
return panelPolygons.find((panel) => panel.id == p.id)
|
|
111
54
|
})
|
|
112
|
-
state = { ...state, polygons: newPolygons }
|
|
113
|
-
|
|
114
55
|
state = removeModuleFieldAndPanelsOnNoOrMultipleRoofs(state)
|
|
115
|
-
|
|
116
56
|
return state
|
|
117
57
|
}
|
|
118
58
|
|
|
@@ -25,9 +25,6 @@ export function UpdateRoofObstacleRelations(state, updateVersionEnable = true) {
|
|
|
25
25
|
|
|
26
26
|
holePolygons.forEach((obstacle) => {
|
|
27
27
|
//breaking circular reference for memory management
|
|
28
|
-
for (let k in obstacle.roofs) {
|
|
29
|
-
obstacle.roofs[k] = null
|
|
30
|
-
}
|
|
31
28
|
obstacle.roofs = []
|
|
32
29
|
|
|
33
30
|
let roofsWithObstacle = roofPolygons.filter((roof) => {
|
|
@@ -21,7 +21,7 @@ export default {
|
|
|
21
21
|
methods: {
|
|
22
22
|
renderImageOverlayOnBackground() {
|
|
23
23
|
const overlayGeometries = OverlayLayer.getReadyItems()
|
|
24
|
-
.filter((overlay) => overlay.isReady && overlay.corners)
|
|
24
|
+
.filter((overlay) => overlay.isReady && overlay.corners && overlay.type=='image_overlay')
|
|
25
25
|
.map((overlay) => {
|
|
26
26
|
return overlay.getBackgroundGeometry()
|
|
27
27
|
})
|
|
@@ -40,7 +40,6 @@ export default {
|
|
|
40
40
|
this.applyTextureOnMesh(this.overlayMaterials, this.meshes.backgroundMesh)
|
|
41
41
|
|
|
42
42
|
this.meshes.backgroundMesh.visible = true
|
|
43
|
-
|
|
44
43
|
return
|
|
45
44
|
},
|
|
46
45
|
async getOverlaysMaterials() {
|
|
@@ -49,7 +48,8 @@ export default {
|
|
|
49
48
|
overlayMaterialsPromises.push(overlay.getProjectionMaterial())
|
|
50
49
|
})
|
|
51
50
|
overlayMaterialsPromises = overlayMaterialsPromises.filter((p) => !!p)
|
|
52
|
-
|
|
51
|
+
const imageOverlayMaterial = await Promise.all(overlayMaterialsPromises)
|
|
52
|
+
this.imageOverlayMaterial=imageOverlayMaterial.filter(m=>!!m)
|
|
53
53
|
return this.imageOverlayMaterial
|
|
54
54
|
},
|
|
55
55
|
},
|
|
@@ -28,7 +28,7 @@ export default {
|
|
|
28
28
|
showableRoofs = this.roofs
|
|
29
29
|
}
|
|
30
30
|
showableRoofs.forEach((roofPolygon) => {
|
|
31
|
-
const geometries = getBufferRoofMarginGeometry(roofPolygon)
|
|
31
|
+
const geometries = getBufferRoofMarginGeometry(roofPolygon, roofPolygon)
|
|
32
32
|
|
|
33
33
|
geometries.forEach((geometry, index) => {
|
|
34
34
|
if (geometry) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as THREE from 'three'
|
|
2
|
-
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
|
|
3
1
|
import { mapState } from 'vuex'
|
|
4
2
|
import OverlayLayer from '../../Overlay/OverlayLayer.js'
|
|
5
3
|
|
|
@@ -8,7 +6,6 @@ export default {
|
|
|
8
6
|
return {}
|
|
9
7
|
},
|
|
10
8
|
created() {
|
|
11
|
-
this.glbLoader = new GLTFLoader()
|
|
12
9
|
},
|
|
13
10
|
computed: {
|
|
14
11
|
...mapState({}),
|
|
@@ -106,16 +106,6 @@ export default {
|
|
|
106
106
|
const latitude = this.layoutSettings.layout_latitude
|
|
107
107
|
const longitude = this.layoutSettings.layout_longitude
|
|
108
108
|
let corners = tileToCorners(x, y, zoom, latitude, longitude)
|
|
109
|
-
let height, width, tileCenter
|
|
110
|
-
let numberOfTiles = Math.pow(2, zoom)
|
|
111
|
-
height =
|
|
112
|
-
(2000 * Math.PI * earthRadius * Math.cos((latitude * Math.PI) / 180)) /
|
|
113
|
-
numberOfTiles
|
|
114
|
-
width = height
|
|
115
|
-
tileCenter = {
|
|
116
|
-
x: (corners[0].x + corners[2].x) / 2,
|
|
117
|
-
y: (corners[0].y + corners[2].y) / 2,
|
|
118
|
-
}
|
|
119
109
|
|
|
120
110
|
camera.left = corners[0].x / 1000
|
|
121
111
|
camera.right = corners[2].x / 1000
|
|
@@ -176,6 +176,11 @@ export default {
|
|
|
176
176
|
method: this.renderOverlays,
|
|
177
177
|
arg: [],
|
|
178
178
|
})
|
|
179
|
+
methodList.push({
|
|
180
|
+
name: 'updateProjectionMaterials',
|
|
181
|
+
method: this.updateProjectionMaterials,
|
|
182
|
+
arg: [],
|
|
183
|
+
})
|
|
179
184
|
case 'removeNodes': //params.nodes
|
|
180
185
|
case 'removeEdges': //params.edges
|
|
181
186
|
case 'translate': //params.edges
|
|
@@ -268,6 +273,11 @@ export default {
|
|
|
268
273
|
method: this.renderRoofsMargin,
|
|
269
274
|
arg: [],
|
|
270
275
|
})
|
|
276
|
+
methodList.push({
|
|
277
|
+
name: 'renderTiles',
|
|
278
|
+
method: this.debouncedRenderTiles,
|
|
279
|
+
arg: [],
|
|
280
|
+
})
|
|
271
281
|
break
|
|
272
282
|
case 'removePanels': //params.panels
|
|
273
283
|
case 'removeModuleField': //params:moduleField
|
package/src/helper/threeMixin.js
CHANGED
|
@@ -105,12 +105,14 @@ export default {
|
|
|
105
105
|
})
|
|
106
106
|
},
|
|
107
107
|
initialiseLights() {
|
|
108
|
-
const ambientLight = new THREE.AmbientLight(
|
|
108
|
+
// const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
|
|
109
|
+
var hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444)
|
|
110
|
+
hemiLight.position.set(0, 0, 300)
|
|
111
|
+
this.scene.add(hemiLight)
|
|
109
112
|
let directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)
|
|
110
113
|
directionalLight.position.set(0, 1000, 500)
|
|
111
114
|
let directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.5)
|
|
112
115
|
directionalLight2.position.set(0, -1000, 500)
|
|
113
|
-
this.scene.add(ambientLight)
|
|
114
116
|
this.scene.add(directionalLight)
|
|
115
117
|
this.scene.add(directionalLight2)
|
|
116
118
|
},
|
package/src/store/hydrateData.js
CHANGED
|
@@ -24,9 +24,9 @@ function sanitizedOutline(outline) {
|
|
|
24
24
|
}, [])
|
|
25
25
|
}
|
|
26
26
|
export async function hydratePolygons({
|
|
27
|
-
roofsResponse,
|
|
28
|
-
obstaclesResponse,
|
|
29
|
-
moduleFieldsResponse,
|
|
27
|
+
roofsResponse = [],
|
|
28
|
+
obstaclesResponse = [],
|
|
29
|
+
moduleFieldsResponse = [],
|
|
30
30
|
}) {
|
|
31
31
|
//removing empty roof,obstacle and modulefield generated by BE on variant creation
|
|
32
32
|
roofsResponse = roofsResponse.reduce((acc, cur) => {
|
|
@@ -124,6 +124,7 @@ export async function hydratePolygons({
|
|
|
124
124
|
moduleField.version = moduleFieldResp.version
|
|
125
125
|
|
|
126
126
|
moduleField.pvData = {}
|
|
127
|
+
moduleField.mountingData = {}
|
|
127
128
|
moduleField.pvData.module_texture_version_id =
|
|
128
129
|
moduleFieldResp.module_texture_version_id
|
|
129
130
|
moduleField.data = {}
|
|
@@ -204,11 +205,13 @@ export async function hydratePolygons({
|
|
|
204
205
|
})
|
|
205
206
|
|
|
206
207
|
const roof = roofs.find((r) => r.id == moduleFieldResp.roof_uuid)
|
|
207
|
-
if (
|
|
208
|
-
roof.moduleFields
|
|
208
|
+
if (roof) {
|
|
209
|
+
if (!roof.moduleFields) {
|
|
210
|
+
roof.moduleFields = []
|
|
211
|
+
}
|
|
212
|
+
roof.moduleFields.push(moduleField)
|
|
213
|
+
moduleField.roof = roof
|
|
209
214
|
}
|
|
210
|
-
roof.moduleFields.push(moduleField)
|
|
211
|
-
moduleField.roof = roof
|
|
212
215
|
moduleField.panels = MFpanels
|
|
213
216
|
moduleField.userDeactivatedPanels = MFuserDeactivatedPanels
|
|
214
217
|
try {
|
|
@@ -244,7 +247,6 @@ export async function hydrateData({ state, commit }, data) {
|
|
|
244
247
|
let layers = getLayers()
|
|
245
248
|
let selectedLayer = layers.find((layer) => layer.key == mapType)
|
|
246
249
|
commit('mutate_selectedMapLayer', selectedLayer)
|
|
247
|
-
|
|
248
250
|
if (overlaysResponse) {
|
|
249
251
|
let origin
|
|
250
252
|
if (layoutSettingResponse) {
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import { Point, Line } from '@eturnity/eturnity_maths'
|
|
2
|
-
import { mmTolerance, mmTolerance3dNode } from '../config'
|
|
3
|
-
import {
|
|
4
|
-
isAlmostSamePoint3D,
|
|
5
|
-
isAlmostSameSegment2D,
|
|
6
|
-
isAlmostSameSegment3D,
|
|
7
|
-
isAlmostSamePoint2D,
|
|
8
|
-
verticalProjectionOnPlane,
|
|
9
|
-
} from '@eturnity/eturnity_maths'
|
|
10
|
-
|
|
11
|
-
export function generateNodes2D(polygons) {
|
|
12
|
-
let nodes2D = []
|
|
13
|
-
polygons
|
|
14
|
-
.filter((poly) =>
|
|
15
|
-
[
|
|
16
|
-
'roof',
|
|
17
|
-
'obstacle',
|
|
18
|
-
'tmpModuleField',
|
|
19
|
-
'moduleField',
|
|
20
|
-
'construction',
|
|
21
|
-
].includes(poly.layer)
|
|
22
|
-
)
|
|
23
|
-
.forEach((polygon) => {
|
|
24
|
-
const outline = polygon.outline
|
|
25
|
-
outline.forEach((point, i) => {
|
|
26
|
-
//check if nodes2D already exist
|
|
27
|
-
let node2D = nodes2D.find(
|
|
28
|
-
(node) =>
|
|
29
|
-
isAlmostSamePoint2D(node, point, mmTolerance) &&
|
|
30
|
-
node.layer == polygon.layer
|
|
31
|
-
)
|
|
32
|
-
if (!node2D) {
|
|
33
|
-
node2D = new Point(point.x, point.y, point.z, polygon.layer)
|
|
34
|
-
node2D.belongsTo = []
|
|
35
|
-
node2D.id = 'node2D'
|
|
36
|
-
node2D.itemType = 'node2D'
|
|
37
|
-
node2D.layer = polygon.layer
|
|
38
|
-
node2D.masterHandle = {
|
|
39
|
-
id: node2D.id,
|
|
40
|
-
itemType: 'masterHandle',
|
|
41
|
-
open: null,
|
|
42
|
-
selected: null,
|
|
43
|
-
}
|
|
44
|
-
nodes2D.push(node2D)
|
|
45
|
-
}
|
|
46
|
-
node2D.belongsTo.push({
|
|
47
|
-
polygonId: polygon.id,
|
|
48
|
-
index: i,
|
|
49
|
-
polygon,
|
|
50
|
-
})
|
|
51
|
-
node2D.id += '_' + polygon.id + '_' + i
|
|
52
|
-
})
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
//all nodes has been created. now lets update open/selected field
|
|
56
|
-
nodes2D.forEach((node2D) => {
|
|
57
|
-
if (node2D.masterHandle) {
|
|
58
|
-
node2D.masterHandle.open = node2D.belongsTo.some(
|
|
59
|
-
(item) => item.index == null || item.polygon.outline[item.index].open
|
|
60
|
-
)
|
|
61
|
-
node2D.masterHandle.selected = node2D.belongsTo.every(
|
|
62
|
-
(item) =>
|
|
63
|
-
item.index == null || item.polygon.outline[item.index].selected
|
|
64
|
-
)
|
|
65
|
-
node2D.masterHandle.locked = node2D.belongsTo.every(
|
|
66
|
-
(item) => item.index == null || item.polygon.outline[item.index].locked
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
return nodes2D
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function generateNodes3D(polygons) {
|
|
74
|
-
let nodes3D = []
|
|
75
|
-
polygons
|
|
76
|
-
.filter((poly) =>
|
|
77
|
-
['roof', 'obstacle', 'tmpModuleField', 'moduleField'].includes(poly.layer)
|
|
78
|
-
)
|
|
79
|
-
.forEach((polygon) => {
|
|
80
|
-
const outline = polygon.outline
|
|
81
|
-
outline.forEach((point, i) => {
|
|
82
|
-
//check if nodes2D already exist
|
|
83
|
-
let node3D = nodes3D.find((node) =>
|
|
84
|
-
isAlmostSamePoint3D(node, point, mmTolerance3dNode)
|
|
85
|
-
)
|
|
86
|
-
if (!node3D) {
|
|
87
|
-
node3D = new Point(point.x, point.y, point.z, polygon.layer)
|
|
88
|
-
node3D.belongsTo = []
|
|
89
|
-
node3D.id = 'node3D'
|
|
90
|
-
node3D.itemType = 'node3D'
|
|
91
|
-
node3D.layer = polygon.layer
|
|
92
|
-
node3D.masterHandle = {
|
|
93
|
-
id: node3D.id,
|
|
94
|
-
itemType: 'masterHandle',
|
|
95
|
-
open: null,
|
|
96
|
-
selected: null,
|
|
97
|
-
}
|
|
98
|
-
nodes3D.push(node3D)
|
|
99
|
-
}
|
|
100
|
-
node3D.belongsTo.push({
|
|
101
|
-
polygonId: polygon.id,
|
|
102
|
-
index: i,
|
|
103
|
-
polygon,
|
|
104
|
-
})
|
|
105
|
-
node3D.id += '_' + polygon.id + '_' + i
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
//all nodes has been created. now lets update open/selected field
|
|
109
|
-
nodes3D.forEach((node3D) => {
|
|
110
|
-
if (node3D.masterHandle) {
|
|
111
|
-
node3D.masterHandle.open = node3D.belongsTo.some(
|
|
112
|
-
(item) => item.polygon.outline[item.index].open
|
|
113
|
-
)
|
|
114
|
-
node3D.masterHandle.selected = node3D.belongsTo.every(
|
|
115
|
-
(item) => item.polygon.outline[item.index].selected
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
})
|
|
119
|
-
return nodes3D
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function generateEdges2D(polygons, splitEdgesIds = []) {
|
|
123
|
-
let edges2D = []
|
|
124
|
-
polygons
|
|
125
|
-
.filter((poly) =>
|
|
126
|
-
['roof', 'obstacle', 'moduleField', 'construction'].includes(poly.layer)
|
|
127
|
-
)
|
|
128
|
-
.forEach((polygon) => {
|
|
129
|
-
const outline = polygon.outline
|
|
130
|
-
outline.forEach((point, i) => {
|
|
131
|
-
const isLastPointOfPolygon = i == outline.length - 1
|
|
132
|
-
if (!polygon.isClosed && isLastPointOfPolygon) {
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
//check if edge2D already exist
|
|
136
|
-
const nextPoint = outline[(i + 1) % outline.length]
|
|
137
|
-
let edge2D = edges2D.find((edge) => {
|
|
138
|
-
return (
|
|
139
|
-
isAlmostSameSegment2D(
|
|
140
|
-
[point, nextPoint],
|
|
141
|
-
edge.outline,
|
|
142
|
-
mmTolerance
|
|
143
|
-
) && edge.layer == polygon.layer
|
|
144
|
-
)
|
|
145
|
-
})
|
|
146
|
-
if (!edge2D) {
|
|
147
|
-
//create an edge at this position
|
|
148
|
-
edge2D = new Line(point, nextPoint, polygon.layer)
|
|
149
|
-
edge2D.id = 'edge2D'
|
|
150
|
-
edge2D.belongsTo = []
|
|
151
|
-
edge2D.layer = polygon.layer
|
|
152
|
-
edge2D.selected = false
|
|
153
|
-
edge2D.itemType = 'edge2D'
|
|
154
|
-
edges2D.push(edge2D)
|
|
155
|
-
}
|
|
156
|
-
//add BelongToPolygon
|
|
157
|
-
edge2D.belongsTo.push({
|
|
158
|
-
polygonId: polygon.id,
|
|
159
|
-
index: i,
|
|
160
|
-
polygon,
|
|
161
|
-
})
|
|
162
|
-
if (polygon.roofs && polygon.roofs.length > 0) {
|
|
163
|
-
polygon.roofs.forEach((supportRoof) => {
|
|
164
|
-
edge2D.belongsTo.push({
|
|
165
|
-
polygonId: supportRoof.id,
|
|
166
|
-
index: null,
|
|
167
|
-
polygon: supportRoof,
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
}
|
|
171
|
-
edge2D.id += '_' + polygon.id + '_' + i
|
|
172
|
-
})
|
|
173
|
-
})
|
|
174
|
-
edges2D.forEach((edge2D) => {
|
|
175
|
-
edge2D.isSplit = splitEdgesIds.includes(edge2D.id)
|
|
176
|
-
if (edge2D.belongsTo.length > 2) {
|
|
177
|
-
edge2D.belongsTo = edge2D.belongsTo.filter((i) => i.index !== null)
|
|
178
|
-
}
|
|
179
|
-
})
|
|
180
|
-
edges2D.forEach((edge2D) => {
|
|
181
|
-
const isNotSplit = edge2D.belongsTo.every((item, index, array) => {
|
|
182
|
-
if (index == 0) {
|
|
183
|
-
return true
|
|
184
|
-
}
|
|
185
|
-
const outline0 = array[0].polygon.outline
|
|
186
|
-
const outline1 = item.polygon.outline
|
|
187
|
-
let point0, point1, nextPoint0, nextPoint1
|
|
188
|
-
let pointNull = []
|
|
189
|
-
if (array[0].index !== null) {
|
|
190
|
-
point0 = outline0[array[0].index]
|
|
191
|
-
nextPoint0 = outline0[(array[0].index + 1) % outline0.length]
|
|
192
|
-
} else {
|
|
193
|
-
pointNull.push(0)
|
|
194
|
-
point0 = verticalProjectionOnPlane(
|
|
195
|
-
outline1[item.index],
|
|
196
|
-
array[0].polygon.normalVector,
|
|
197
|
-
array[0].polygon.flatOutline[0]
|
|
198
|
-
)
|
|
199
|
-
nextPoint0 = verticalProjectionOnPlane(
|
|
200
|
-
outline1[(item.index + 1) % outline1.length],
|
|
201
|
-
array[0].polygon.normalVector,
|
|
202
|
-
array[0].polygon.flatOutline[0]
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
if (item.index !== null) {
|
|
206
|
-
point1 = outline1[item.index]
|
|
207
|
-
nextPoint1 = outline1[(item.index + 1) % outline1.length]
|
|
208
|
-
} else {
|
|
209
|
-
pointNull.push(1)
|
|
210
|
-
point1 = verticalProjectionOnPlane(
|
|
211
|
-
outline0[array[0].index],
|
|
212
|
-
item.polygon.normalVector,
|
|
213
|
-
item.polygon.flatOutline[0]
|
|
214
|
-
)
|
|
215
|
-
nextPoint1 = verticalProjectionOnPlane(
|
|
216
|
-
outline0[(array[0].index + 1) % outline0.length],
|
|
217
|
-
item.polygon.normalVector,
|
|
218
|
-
item.polygon.flatOutline[0]
|
|
219
|
-
)
|
|
220
|
-
}
|
|
221
|
-
const isSameSeg = isAlmostSameSegment3D(
|
|
222
|
-
[point0, nextPoint0],
|
|
223
|
-
[point1, nextPoint1],
|
|
224
|
-
mmTolerance
|
|
225
|
-
)
|
|
226
|
-
return isSameSeg
|
|
227
|
-
})
|
|
228
|
-
if (!isNotSplit && edge2D.belongsTo.length == 2 && edge2D.layer == 'roof') {
|
|
229
|
-
edge2D.isSplit = true
|
|
230
|
-
}
|
|
231
|
-
})
|
|
232
|
-
return edges2D
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
export function generateEdges3D(polygons) {
|
|
236
|
-
let edges3D = []
|
|
237
|
-
polygons
|
|
238
|
-
.filter((poly) =>
|
|
239
|
-
['roof', 'obstacle', 'moduleField', 'construction'].includes(poly.layer)
|
|
240
|
-
)
|
|
241
|
-
.forEach((polygon) => {
|
|
242
|
-
const outline = polygon.outline
|
|
243
|
-
outline.forEach((point, i) => {
|
|
244
|
-
const isLastPointOfPolygon = i == outline.length - 1
|
|
245
|
-
if (!polygon.isClosed && isLastPointOfPolygon) {
|
|
246
|
-
return
|
|
247
|
-
}
|
|
248
|
-
//check if edge2D already exist
|
|
249
|
-
const nextPoint = outline[(i + 1) % outline.length]
|
|
250
|
-
let edge3D = edges3D.find((edge) => {
|
|
251
|
-
return (
|
|
252
|
-
isAlmostSameSegment3D(
|
|
253
|
-
[point, nextPoint],
|
|
254
|
-
edge.outline,
|
|
255
|
-
mmTolerance
|
|
256
|
-
) && edge.layer == polygon.layer
|
|
257
|
-
)
|
|
258
|
-
})
|
|
259
|
-
if (!edge3D) {
|
|
260
|
-
//create an edge at this position
|
|
261
|
-
edge3D = new Line(point, nextPoint, polygon.layer)
|
|
262
|
-
edge3D.id = 'edge3D'
|
|
263
|
-
edge3D.belongsTo = []
|
|
264
|
-
edge3D.layer = polygon.layer
|
|
265
|
-
edge3D.selected = false
|
|
266
|
-
edge3D.itemType = 'edge3D'
|
|
267
|
-
edges3D.push(edge3D)
|
|
268
|
-
}
|
|
269
|
-
//add BelongToPolygon
|
|
270
|
-
edge3D.belongsTo.push({
|
|
271
|
-
polygonId: polygon.id,
|
|
272
|
-
index: i,
|
|
273
|
-
polygon,
|
|
274
|
-
})
|
|
275
|
-
edge3D.id += '_' + polygon.id + '_' + i
|
|
276
|
-
})
|
|
277
|
-
})
|
|
278
|
-
return edges3D
|
|
279
|
-
}
|