@eturnity/eturnity_3d 8.10.1 → 8.16.1

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.
Files changed (32) hide show
  1. package/package.json +2 -2
  2. package/src/Overlay/ImageOverlay.js +16 -139
  3. package/src/Overlay/Overlay.js +115 -14
  4. package/src/Overlay/OverlayFactory.js +3 -0
  5. package/src/Overlay/OverlayLayer.js +6 -0
  6. package/src/Overlay/ThreeDModelOverlay.js +16 -122
  7. package/src/Overlay/YearlySunShadingOverlay.js +368 -0
  8. package/src/helper/render/imageOverlay.js +23 -9
  9. package/src/helper/render/moduleField.js +12 -2
  10. package/src/helper/render/overlay.js +60 -5
  11. package/src/helper/render/projectionMaterial.js +2 -0
  12. package/src/helper/render/roof.js +0 -1
  13. package/src/helper/render/shadingMaterial/ShadingImageGenerator.js +241 -0
  14. package/src/helper/render/shadingMaterial/helper.js +109 -0
  15. package/src/helper/render/shadingMaterial/yearlySunShaderMaterial.js +389 -0
  16. package/src/helper/renderMixin.js +17 -0
  17. package/src/store/hydrateData.js +2 -0
  18. package/dist/assets/images/panels/longiSolarLR4_60HPH_350M.png +0 -0
  19. package/dist/assets/images/panels/longiSolarLR4_60HPH_370M.png +0 -0
  20. package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw copy.png +0 -0
  21. package/dist/assets/images/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
  22. package/dist/assets/images/panels/uv.png +0 -0
  23. package/dist/assets/panels/longiSolarLR4_60HPH_350M.png +0 -0
  24. package/dist/assets/panels/longiSolarLR4_60HPH_370M.png +0 -0
  25. package/dist/assets/panels/reneSola_Virtus_2_JC320S_24_Bbw.png +0 -0
  26. package/dist/assets/panels/uv.png +0 -0
  27. package/dist/assets/theme.js +0 -43
  28. package/dist/assets/vue.svg +0 -1
  29. package/dist/main.es.js +0 -43662
  30. package/dist/main.umd.js +0 -3542
  31. package/dist/style.css +0 -1
  32. package/dist/vite.svg +0 -1
@@ -1,23 +1,14 @@
1
1
  import Overlay from './Overlay'
2
2
  import * as THREE from 'three'
3
- import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
4
- import { layerColors } from '../config'
5
3
  import {
6
- getDistanceBetweenPoints,
7
4
  addVector,
8
5
  multiplyVector,
9
- substractVector,
10
- getAngleInDegFromCanvasVector,
11
- normalize2DVector,
12
6
  isInsidePolygon,
13
7
  calculateBestFittingPlanePolygon,
14
8
  verticalProjectionOnPlane,
15
- vectorLength2D,
16
- deltaLatLngToDistance,
17
9
  rotateTransformation,
18
10
  getStandardDeviation,
19
11
  } from '@eturnity/eturnity_maths'
20
- let Paper
21
12
  export default class ThreeDModelOverlay extends Overlay {
22
13
  constructor(overlay, emit, origin, loader) {
23
14
  super(overlay, emit)
@@ -44,15 +35,6 @@ export default class ThreeDModelOverlay extends Overlay {
44
35
  this.geoLocalisation = this.settings.geoLocalisation
45
36
  }
46
37
  loadFile() {}
47
- onLoad() {
48
- return new Promise((resolve) => {
49
- if (this.isReady) {
50
- resolve(this)
51
- } else {
52
- this.isReadyCallback.push(resolve)
53
- }
54
- })
55
- }
56
38
  set3DObjectMaterialOpacity(obj) {
57
39
  obj.children.forEach((child) => {
58
40
  this.set3DObjectMaterialOpacity(child, this.opacity)
@@ -65,7 +47,6 @@ export default class ThreeDModelOverlay extends Overlay {
65
47
  if (this.overlayMesh && this.overlayMesh.children.length == 0) {
66
48
  this.overlayMesh = await this.loadFile()
67
49
  }
68
-
69
50
  if (!this.isReady) {
70
51
  let waitingBall = threeJSComponent.meshes.overlayMeshes[this.id]
71
52
  if (!waitingBall) {
@@ -126,9 +107,10 @@ export default class ThreeDModelOverlay extends Overlay {
126
107
  this.overlayMesh = overlayMesh
127
108
  this.overlayMesh.frustumCulled = false
128
109
  this.set3DObjectMaterialOpacity(this.overlayMesh)
110
+ return overlayMesh
129
111
  }
130
112
  renderOnPaperJS(paperJSComponent) {
131
- Paper = paperJSComponent.paperScope
113
+ this.Paper = paperJSComponent.paperScope
132
114
  if (!this.isActive) {
133
115
  return
134
116
  }
@@ -139,7 +121,7 @@ export default class ThreeDModelOverlay extends Overlay {
139
121
  if (!paperJSComponent.loadingSpinner) {
140
122
  return
141
123
  }
142
- group = new Paper.Group()
124
+ group = new this.Paper.Group()
143
125
 
144
126
  group.addChild(this.renderImagePlaceHolder(paperJSComponent))
145
127
  group.itemType = 'placeholderOverlays'
@@ -150,7 +132,7 @@ export default class ThreeDModelOverlay extends Overlay {
150
132
  this.placeholderPath = group
151
133
 
152
134
  paperJSComponent.paperLayer['loadingSpinners'].activate()
153
- Paper.view.onFrame = (event) => this.animatePlaceholder(event)
135
+ this.Paper.view.onFrame = (event) => this.animatePlaceholder(event)
154
136
  }
155
137
  paperJSComponent.paths.imageOverlays[this.id] = group
156
138
  this.hasPlaceholderPath = true
@@ -174,7 +156,9 @@ export default class ThreeDModelOverlay extends Overlay {
174
156
  let isRotationHandleVisible =
175
157
  paperJSComponent.selectedTool == 'selectOverlay' && this.isSelected
176
158
 
177
- let corners = this.corners.map((p) => paperJSComponent.toCanvasRef(p))
159
+ const getCorners = () =>
160
+ this.corners.map((p) => paperJSComponent.toCanvasRef(p))
161
+ let corners = getCorners()
178
162
  if (group) {
179
163
  imageOverlayPath = group.children[0]
180
164
  handles = this.renderImageOverlayHandles(
@@ -187,8 +171,8 @@ export default class ThreeDModelOverlay extends Overlay {
187
171
  group.opacity = this.opacity
188
172
  group.transparent = this.opacity != 1
189
173
  } else {
190
- group = new Paper.Group()
191
- imageOverlayPath = this.loadImageOverlay(this.imageUrl, corners)
174
+ group = new this.Paper.Group()
175
+ imageOverlayPath = this.loadImageOverlay(this.imageUrl, getCorners)
192
176
  this.applyRasterToCorners(imageOverlayPath, corners)
193
177
  handles = this.renderImageOverlayHandles(corners, isRotationHandleVisible)
194
178
  group.addChild(imageOverlayPath)
@@ -209,15 +193,15 @@ export default class ThreeDModelOverlay extends Overlay {
209
193
  renderImagePlaceHolder(paperJSComponent) {
210
194
  const toCanvasRef = paperJSComponent.canvasContext.toCanvasRef
211
195
 
212
- const group = new Paper.Group()
213
- const circle = new Paper.Path.Circle({
196
+ const group = new this.Paper.Group()
197
+ const circle = new this.Paper.Path.Circle({
214
198
  center: toCanvasRef({ x: 0, y: 0 }),
215
199
  radius: 50,
216
200
  fillColor: '#ffffff80',
217
201
  })
218
202
  circle.radius = 70
219
203
  circle.itemData = 'circle'
220
- const fillRectangle = new Paper.Path()
204
+ const fillRectangle = new this.Paper.Path()
221
205
  fillRectangle.fillColor = '#ffffff80'
222
206
  fillRectangle.itemType = 'placeholder'
223
207
  fillRectangle.itemData = this
@@ -247,92 +231,16 @@ export default class ThreeDModelOverlay extends Overlay {
247
231
  circle.scale(scale)
248
232
  circle.radius = newRadius
249
233
  }
250
- loadImageOverlay(url, corners) {
251
- let rasterImageOverlay = new Paper.Raster({
252
- source: url,
253
- crossOrigin: 'Anonymous',
254
- })
255
- rasterImageOverlay.visible = false
256
- rasterImageOverlay.onLoad = () => {
257
- this.applyRasterToCorners(rasterImageOverlay, corners)
258
- }
259
- rasterImageOverlay.data.angle = 0
260
- rasterImageOverlay.data.type = 'imageOverlayRaster'
261
- rasterImageOverlay.data.overlayId = this.id
262
- rasterImageOverlay.data.url = url
263
- return rasterImageOverlay
264
- }
265
- applyRasterToCorners(texture, corners = this.corners) {
266
- //remove angle of texture
267
- let textureAngle = texture.angle || 0
268
- texture.rotate(-textureAngle)
269
-
270
- //make texture the same size to fit corners
271
- const textureWidth = texture.bounds.width
272
- const textureHeight = texture.bounds.height
273
- const frameWidth = getDistanceBetweenPoints(corners[1], corners[0])
274
- const frameHeight = getDistanceBetweenPoints(corners[3], corners[0])
275
- const center = multiplyVector(0.5, addVector(corners[0], corners[2]))
276
- if (texture.bounds.width) {
277
- var a = frameWidth / textureWidth
278
- var b = 0
279
- var c = 0
280
- var d = frameHeight / textureHeight
281
- texture.transform(new Paper.Matrix(a, b, c, d, 0, 0))
282
- //translate to fit top left corner
283
- var tx = center.x - texture.bounds.center.x
284
- var ty = center.y - texture.bounds.center.y
285
- texture.transform(new Paper.Matrix(1, 0, 0, 1, tx, ty))
286
- //rotate
287
- let angle = getAngleInDegFromCanvasVector(
288
- substractVector(corners[0], corners[3])
289
- )
290
-
291
- texture.angle = angle
292
- texture.rotate(angle)
293
- }
294
- }
295
- renderImageOverlayHandles(corners, rotateHandleVisible, group = null) {
296
- let circleHandle
297
- let hasPaths = !!group
298
- let handles = group || new Paper.Group()
299
- let u = normalize2DVector(substractVector(corners[1], corners[0]))
300
- let v = normalize2DVector(substractVector(corners[0], corners[3]))
301
-
302
- //rotation handle
303
- let center = multiplyVector(0.5, addVector(corners[0], corners[2]))
304
-
305
- let radius = vectorLength2D(substractVector(center, corners[0])) - 10
306
- if (!hasPaths) {
307
- circleHandle = new Paper.Path.Circle(center, radius)
308
- circleHandle.fillColor = layerColors.imageOverlayHandle.fillColor
309
- circleHandle.strokeWidth = layerColors.imageOverlayHandle.strokeWidth
310
- circleHandle.strokeColor = layerColors.imageOverlayHandle.strokeColor
311
- circleHandle.data.type = 'imageOverlayRotateHandle'
312
- circleHandle.data.overlayId = this.id
313
- circleHandle.radius = radius
314
- handles.addChild(circleHandle)
315
- } else {
316
- circleHandle = handles.children[0]
317
- let ratio = radius / circleHandle.radius
318
- circleHandle.transform(new Paper.Matrix(ratio, 0, 0, ratio, 0, 0))
319
- circleHandle.position = center
320
- circleHandle.radius = radius
321
- }
322
-
323
- circleHandle.visible = rotateHandleVisible
324
- return handles
325
- }
326
234
  initialiseCornersAndProjectionCamera() {
327
235
  const box = new THREE.Box3().setFromObject(this.overlayMesh)
328
236
  const boxSize = box.getSize(new THREE.Vector3())
329
- this.boxSize = boxSize
330
237
  const boxCenter = box.getCenter(new THREE.Vector3())
238
+ this.boxSize = boxSize
239
+ this.boxCenter = boxCenter
331
240
  const left = -boxSize.x / 2
332
241
  const right = +boxSize.x / 2
333
242
  const top = +boxSize.y / 2
334
243
  const bottom = -boxSize.y / 2
335
- this.boxCenter = boxCenter
336
244
  const initialCorners = [
337
245
  {
338
246
  x: 1000 * (boxCenter.x + left),
@@ -374,9 +282,7 @@ export default class ThreeDModelOverlay extends Overlay {
374
282
  1000 // far
375
283
  )
376
284
  }
377
- checkGeoLocDataAndOffset() {
378
- return
379
- }
285
+ checkGeoLocDataAndOffset() {}
380
286
  async initialiseModel() {
381
287
  this.overlayMesh = await this.loadFile()
382
288
  if (!this.geoLocalisation) {
@@ -442,7 +348,7 @@ export default class ThreeDModelOverlay extends Overlay {
442
348
  const imageUrl = canvas.toDataURL()
443
349
  scene.remove(light)
444
350
  scene.remove(ambientLight)
445
- canvas.parentNode.removeChild(canvas)
351
+ canvas.parentNode?.removeChild(canvas)
446
352
  resolve(imageUrl)
447
353
  })
448
354
  }
@@ -526,18 +432,6 @@ export default class ThreeDModelOverlay extends Overlay {
526
432
  })
527
433
  return newOutlines
528
434
  }
529
- createCanvas() {
530
- const canvas = document.createElement('canvas')
531
- canvas.width = this.canvasWidth
532
- canvas.height = this.canvasHeight
533
- canvas.style.position = 'fixed'
534
- canvas.style.top = '100px'
535
- canvas.style.left = '50px'
536
- canvas.style.zIndex = 0
537
- // Add the canvas to the document body
538
- document.body.appendChild(canvas)
539
- return canvas
540
- }
541
435
  serializeSettings() {
542
436
  return {
543
437
  version: this.version,
@@ -0,0 +1,368 @@
1
+ import * as THREE from 'three'
2
+ import Overlay from './Overlay.js'
3
+ import {
4
+ getEdgesForHorizonForShader,
5
+ blurImagePreserveTransparency,
6
+ } from '../helper/render/shadingMaterial/helper.js'
7
+ import yearlySunShaderMaterial from '../helper/render/shadingMaterial/yearlySunShaderMaterial.js'
8
+ import {
9
+ updateBufferRoofGeometry,
10
+ getBufferRoofGeometry,
11
+ } from '../helper/render/geometryHandler.js'
12
+ import {
13
+ intersectOutlines,
14
+ verticalProjectionOnPlane,
15
+ } from '@eturnity/eturnity_maths'
16
+
17
+ export default class YearlySunShadingOverlay extends Overlay {
18
+ constructor(overlay, emit) {
19
+ super(overlay, emit)
20
+ if (!this.constructorValidation(overlay)) {
21
+ return
22
+ }
23
+ this.hasToBeSavedInBE = false
24
+ this.dataGrids = overlay.settings.dataGrids
25
+ this.edges = overlay.settings.edges || []
26
+ this.roofs = overlay.settings.roofs || []
27
+ this.obstacles = overlay.settings.obstacles || []
28
+ this.latitude = overlay.settings.lat
29
+ this.longitude = overlay.settings.lng
30
+ this.isActive = false
31
+ this.opacity = 1
32
+ this.projectionMaterialPriority = 40
33
+ this.colorMap = overlay.settings.colorMap
34
+ const hash = [...this.roofs, ...this.obstacles, ...this.edges].reduce(
35
+ (hash, item) => {
36
+ hash[item.id] = item.version
37
+ return hash
38
+ },
39
+ {}
40
+ )
41
+ // Update the stored hash
42
+ this.previousHash = hash
43
+ this.initialiseScene()
44
+ this.getImage().then((imageUrl) => {
45
+ this.imageUrl = imageUrl
46
+ this.isReady = true
47
+ this.version++
48
+ this.emit('overlay-is-ready', { id: this.id })
49
+ this.isReadyCallback.forEach((callback) => {
50
+ if (typeof callback === 'function') {
51
+ callback()
52
+ }
53
+ })
54
+ this.isReadyCallback = []
55
+ })
56
+ }
57
+ constructorValidation(overlay) {
58
+ if (!overlay.settings.dataGrids) {
59
+ console.error('No dataGrids provided')
60
+ return false
61
+ }
62
+ if (!overlay.settings.lat || !overlay.settings.lng) {
63
+ console.error('No lat long provided')
64
+ return false
65
+ }
66
+ return true
67
+ }
68
+ initialiseScene() {
69
+ this.canvasWidth = 600
70
+ this.canvasHeight = 600
71
+ this.canvas = this.createCanvas()
72
+ this.scene = new THREE.Scene()
73
+ this.renderer = new THREE.WebGLRenderer({
74
+ canvas: this.canvas,
75
+ alpha: true,
76
+ })
77
+ this.renderer.setSize(this.canvasWidth, this.canvasHeight)
78
+ this.renderer.setClearColor(0x000000, 0) // Make background transparent
79
+ this.meshes = { roofMeshes: {}, obstacleMeshes: {} }
80
+ this.renderRoofs()
81
+ this.renderObstacles()
82
+ this.updateBox()
83
+ this.updateCorners()
84
+ this.updateCanvasFromBoxSize()
85
+ this.updateProjectionCamera()
86
+ }
87
+ updateCanvasFromBoxSize() {
88
+ if (!this.boxSize) return
89
+ this.canvasWidth = this.boxSize.x * 100 //(cm resolution)
90
+ this.canvasHeight = this.boxSize.y * 100
91
+ const maxSize = Math.max(this.canvasWidth, this.canvasHeight)
92
+ const CANVAS_MAX_SIZE = 2048
93
+ if (maxSize > CANVAS_MAX_SIZE) {
94
+ this.canvasWidth *= CANVAS_MAX_SIZE / maxSize
95
+ this.canvasHeight *= CANVAS_MAX_SIZE / maxSize
96
+ }
97
+ this.renderer.setSize(this.canvasWidth, this.canvasHeight)
98
+ this.canvas.width = this.canvasWidth
99
+ this.canvas.height = this.canvasHeight
100
+ }
101
+ renderRoofs() {
102
+ const roofsIds = this.roofs.map((r) => r.id)
103
+ Object.values(this.meshes.roofMeshes).forEach((mesh) => {
104
+ if (!roofsIds.includes(mesh.userData.id)) {
105
+ this.scene.remove(mesh)
106
+ delete this.meshes.roofMeshes[mesh.userData.id]
107
+ }
108
+ })
109
+ this.roofs.forEach((roof) => {
110
+ const normalVector = roof.normalVector
111
+ const point = roof.flatOutline[0]
112
+ const plane = { normalVector, point }
113
+ const edgesForHorizon = getEdgesForHorizonForShader(plane, this.edges)
114
+ let mesh = this.meshes.roofMeshes[roof.id]
115
+ let roofOutline = roof.outline
116
+ let cropedHolesOutlines = roof.holes.map((h) => {
117
+ //let's crop obstacle with roof outline
118
+ const cropedHoleOutline =
119
+ intersectOutlines(h.outline, roof.outline)[0] || []
120
+ const outline = cropedHoleOutline.map((p) => {
121
+ return {
122
+ x: p.x,
123
+ y: p.y,
124
+ z: verticalProjectionOnPlane(
125
+ p,
126
+ roof.normalVector,
127
+ roof.flatOutline[0]
128
+ ).z,
129
+ }
130
+ })
131
+ return outline
132
+ })
133
+ cropedHolesOutlines = cropedHolesOutlines.filter((outline) => !!outline)
134
+ if (mesh) {
135
+ let geometry = mesh.geometry
136
+ geometry = updateBufferRoofGeometry(
137
+ roofOutline,
138
+ cropedHolesOutlines,
139
+ geometry
140
+ )
141
+ mesh.material.updateEdges(edgesForHorizon)
142
+ mesh.material.needsUpdate = true
143
+ mesh.geometry = geometry
144
+ mesh.geometry.needsUpdate = true
145
+ mesh.geometry.computeBoundingBox()
146
+ mesh.needsUpdate = true
147
+ } else {
148
+ let material = new yearlySunShaderMaterial({
149
+ dataGrids: this.dataGrids,
150
+ lat: this.latitude,
151
+ lng: this.longitude,
152
+ edges: edgesForHorizon,
153
+ isShadingFactor: true,
154
+ colorMap: this.colorMap,
155
+ })
156
+ let geometry = getBufferRoofGeometry(roof.outline, cropedHolesOutlines)
157
+ mesh = new THREE.Mesh(geometry, material)
158
+ mesh.material.updateEdges(edgesForHorizon)
159
+ mesh.userData.id = roof.id
160
+ mesh.material.needsUpdate = true
161
+ mesh.needsUpdate = true
162
+ this.meshes.roofMeshes[roof.id] = mesh
163
+ this.scene.add(mesh)
164
+ }
165
+ })
166
+ }
167
+ renderObstacles() {
168
+ const obstacleIds = this.obstacles.map((o) => o.id)
169
+ Object.values(this.meshes.obstacleMeshes).forEach((mesh) => {
170
+ if (!obstacleIds.includes(mesh.userData.id)) {
171
+ this.scene.remove(mesh)
172
+ delete this.meshes.obstacleMeshes[mesh.userData.id]
173
+ }
174
+ })
175
+ this.obstacles.forEach((obstacle) => {
176
+ let mesh = this.meshes.obstacleMeshes[obstacle.id]
177
+ let obstacleOutline = obstacle.outline
178
+ if (mesh) {
179
+ let geometry = mesh.geometry
180
+ geometry = updateBufferRoofGeometry(obstacleOutline, [], geometry)
181
+ mesh.geometry = geometry
182
+ mesh.geometry.needsUpdate = true
183
+ mesh.geometry.computeBoundingBox()
184
+ mesh.needsUpdate = true
185
+ } else {
186
+ let material = new THREE.MeshBasicMaterial({
187
+ color: 0x000000,
188
+ })
189
+ let geometry = getBufferRoofGeometry(obstacle.outline, [])
190
+ mesh = new THREE.Mesh(geometry, material)
191
+ mesh.userData.id = obstacle.id
192
+ this.meshes.obstacleMeshes[obstacle.id] = mesh
193
+ this.scene.add(mesh)
194
+ }
195
+ })
196
+ }
197
+ updateMaterial(roofs, obstacles, edges) {
198
+ return new Promise((resolve, reject) => {
199
+ this.roofs = roofs
200
+ this.obstacles = obstacles
201
+ this.edges = edges
202
+ // Create a hash of roof and edge IDs and versions
203
+ const newHash = [...roofs, ...obstacles, ...edges].reduce(
204
+ (hash, item) => {
205
+ hash[item.id] = item.version
206
+ return hash
207
+ },
208
+ {}
209
+ )
210
+
211
+ // Compare with the previous hash
212
+ if (
213
+ this.previousHash &&
214
+ JSON.stringify(this.previousHash) === JSON.stringify(newHash)
215
+ ) {
216
+ resolve(this.imageUrl)
217
+ return
218
+ }
219
+
220
+ // Update the stored hash
221
+ this.previousHash = newHash
222
+ this.renderRoofs()
223
+ this.renderObstacles()
224
+ this.updateBox()
225
+ this.updateCorners()
226
+ this.updateCanvasFromBoxSize()
227
+ this.updateProjectionCamera()
228
+ this.getImage().then((imageUrl) => {
229
+ this.imageUrl = imageUrl
230
+ this.version++
231
+ this.emit('overlay-is-ready', { id: this.id })
232
+ this.isReadyCallback.forEach((callback) => {
233
+ if (typeof callback === 'function') {
234
+ callback()
235
+ }
236
+ })
237
+ resolve(this.imageUrl)
238
+ })
239
+ })
240
+ }
241
+ getImage() {
242
+ return new Promise((resolve, reject) => {
243
+ // Set camera position and look at the center of the model
244
+ this.overlayProjectionCamera.position.set(
245
+ this.boxCenter.x,
246
+ this.boxCenter.y,
247
+ this.boxCenter.z + 100
248
+ )
249
+ this.overlayProjectionCamera.lookAt(this.boxCenter.x, this.boxCenter.y, 0)
250
+ this.overlayProjectionCamera.updateProjectionMatrix()
251
+ // Render the scene
252
+ this.renderer.render(this.scene, this.overlayProjectionCamera)
253
+
254
+ // Generate image from canvas
255
+ const imageUrl = this.canvas.toDataURL()
256
+ blurImagePreserveTransparency(imageUrl, 15)
257
+ .then((blurredImageUrl) => {
258
+ resolve(blurredImageUrl)
259
+ })
260
+ .catch((error) => {
261
+ resolve(imageUrl)
262
+ })
263
+ })
264
+ }
265
+ updateBox() {
266
+ const box = new THREE.Box3().setFromObject(this.scene)
267
+ const boxSize = box.getSize(new THREE.Vector3())
268
+ this.boxSize = boxSize
269
+ this.boxCenter = box.getCenter(new THREE.Vector3())
270
+ }
271
+ updateProjectionCamera() {
272
+ const left = -this.boxSize.x / 2
273
+ const right = +this.boxSize.x / 2
274
+ const top = +this.boxSize.y / 2
275
+ const bottom = -this.boxSize.y / 2
276
+ if (!this.overlayProjectionCamera) {
277
+ this.initialiseProjectionCamera()
278
+ }
279
+ this.overlayProjectionCamera.position.set(
280
+ this.boxCenter.x,
281
+ this.boxCenter.y,
282
+ this.boxCenter.z + 100
283
+ )
284
+ this.overlayProjectionCamera.lookAt(this.boxCenter.x, this.boxCenter.y, 0)
285
+ this.overlayProjectionCamera.left = left
286
+ this.overlayProjectionCamera.right = right
287
+ this.overlayProjectionCamera.top = top
288
+ this.overlayProjectionCamera.bottom = bottom
289
+ this.overlayProjectionCamera.updateProjectionMatrix()
290
+ }
291
+ initialiseProjectionCamera() {
292
+ this.overlayProjectionCamera = new THREE.OrthographicCamera(
293
+ -1,
294
+ 1,
295
+ 1,
296
+ -1,
297
+ 0.1, // near
298
+ 1000 // far
299
+ )
300
+ this.overlayProjectionCamera.lookAt(this.boxCenter.x, this.boxCenter.y, 0)
301
+ this.overlayProjectionCamera.updateProjectionMatrix()
302
+ }
303
+ updateCorners() {
304
+ const left = -this.boxSize.x / 2
305
+ const right = +this.boxSize.x / 2
306
+ const top = +this.boxSize.y / 2
307
+ const bottom = -this.boxSize.y / 2
308
+ this.corners = [
309
+ {
310
+ x: 1000 * (this.boxCenter.x + left),
311
+ y: 1000 * (this.boxCenter.y + top),
312
+ z: 0,
313
+ },
314
+ {
315
+ x: 1000 * (this.boxCenter.x + right),
316
+ y: 1000 * (this.boxCenter.y + top),
317
+ z: 0,
318
+ },
319
+ {
320
+ x: 1000 * (this.boxCenter.x + right),
321
+ y: 1000 * (this.boxCenter.y + bottom),
322
+ z: 0,
323
+ },
324
+ {
325
+ x: 1000 * (this.boxCenter.x + left),
326
+ y: 1000 * (this.boxCenter.y + bottom),
327
+ z: 0,
328
+ },
329
+ ]
330
+ this.updateCanvasFromBoxSize()
331
+ }
332
+ renderOnThreeJS(threeJSComponent) {}
333
+ renderOnPaperJS(paperJSComponent) {
334
+ this.Paper = paperJSComponent.paperScope
335
+ if (!this.isReady || !this.isActive || !this.corners) {
336
+ return
337
+ }
338
+ let group = paperJSComponent.paths.imageOverlays[this.id]
339
+ paperJSComponent.paperLayer['imageOverlays'].activate()
340
+
341
+ let imageOverlayPath
342
+
343
+ const getCorners = () =>
344
+ this.corners.map((p) => paperJSComponent.toCanvasRef(p))
345
+ const corners = getCorners()
346
+ imageOverlayPath = this.loadImageOverlay(this.imageUrl, getCorners)
347
+ this.applyRasterToCorners(imageOverlayPath, corners)
348
+ imageOverlayPath.data.type = 'heatmapShadowRaster'
349
+ imageOverlayPath.visible = true
350
+ if (group) {
351
+ group.removeChildren()
352
+ group.insertChild(0, imageOverlayPath)
353
+ group.version++
354
+ group.visible = true
355
+ } else {
356
+ group = new this.Paper.Group()
357
+ group.addChild(imageOverlayPath)
358
+ group.itemType = 'imageOverlays'
359
+ group.data.url = this.imageUrl
360
+ group.type = 'imageOverlays'
361
+ group.pathId = this.id
362
+ group.overlayId = this.id
363
+ group.visible = true
364
+ paperJSComponent.paths.imageOverlays[this.id] = group
365
+ }
366
+ imageOverlayPath.opacity = this.opacity
367
+ }
368
+ }
@@ -21,14 +21,23 @@ export default {
21
21
  methods: {
22
22
  renderImageOverlayOnBackground() {
23
23
  const overlayGeometries = OverlayLayer.getReadyItems()
24
- .filter((overlay) => overlay.isReady && overlay.corners && overlay.type=='image_overlay')
24
+ .filter(
25
+ (overlay) =>
26
+ overlay.isReady &&
27
+ overlay.isActive &&
28
+ overlay.corners &&
29
+ overlay.type != 'yearly_sun_shading'
30
+ )
25
31
  .map((overlay) => {
26
32
  return overlay.getBackgroundGeometry()
27
33
  })
34
+ const overlayMaterialsToBackground = this.overlayMaterials.filter((m) => {
35
+ return m.userData.overlayType != 'yearly_sun_shading'
36
+ })
28
37
  const newBackgroundMesh = this.updateOrCreateMergedMesh(
29
38
  this.meshes.backgroundMesh,
30
39
  overlayGeometries,
31
- this.overlayMaterials
40
+ overlayMaterialsToBackground
32
41
  )
33
42
  if (!this.meshes.backgroundMesh) {
34
43
  this.meshes.backgroundMesh = newBackgroundMesh
@@ -37,20 +46,25 @@ export default {
37
46
  this.meshes.backgroundMesh = newBackgroundMesh
38
47
  }
39
48
  this.meshes.backgroundMesh.position.z = 0.15
40
- this.applyTextureOnMesh(this.overlayMaterials, this.meshes.backgroundMesh)
49
+ this.applyTextureOnMesh(
50
+ overlayMaterialsToBackground,
51
+ this.meshes.backgroundMesh
52
+ )
41
53
 
42
54
  this.meshes.backgroundMesh.visible = true
43
55
  return
44
56
  },
45
57
  async getOverlaysMaterials() {
46
58
  let overlayMaterialsPromises = []
47
- OverlayLayer.getReadyItems().forEach((overlay) => {
48
- overlayMaterialsPromises.push(overlay.getProjectionMaterial())
49
- })
59
+ OverlayLayer.getReadyItems()
60
+ .filter((o) => o.isActive)
61
+ .forEach((overlay) => {
62
+ overlayMaterialsPromises.push(overlay.getProjectionMaterial())
63
+ })
50
64
  overlayMaterialsPromises = overlayMaterialsPromises.filter((p) => !!p)
51
- const imageOverlayMaterial = await Promise.all(overlayMaterialsPromises)
52
- this.imageOverlayMaterial=imageOverlayMaterial.filter(m=>!!m)
53
- return this.imageOverlayMaterial
65
+ const imageOverlayMaterials = await Promise.all(overlayMaterialsPromises)
66
+ this.imageOverlayMaterials = imageOverlayMaterials.filter((m) => !!m)
67
+ return this.imageOverlayMaterials
54
68
  },
55
69
  },
56
70
  }