@eturnity/eturnity_3d 7.20.1 → 7.24.0-EPDM-10926.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.
Files changed (42) hide show
  1. package/package.json +2 -2
  2. package/src/EventManager/EventManager.js +48 -0
  3. package/src/Item/Item.js +12 -0
  4. package/src/Layer/Layer.js +119 -0
  5. package/src/Overlay/GLBOverlay.js +91 -0
  6. package/src/Overlay/ImageOverlay.js +309 -0
  7. package/src/Overlay/Overlay.js +255 -0
  8. package/src/Overlay/OverlayFactory.js +19 -0
  9. package/src/Overlay/OverlayLayer.js +36 -0
  10. package/src/Overlay/ThreeDModelOverlay.js +518 -0
  11. package/src/components/ThreeCanvasViewer.vue +17 -6
  12. package/src/config.js +120 -17
  13. package/src/helper/UpdateRoofModuleFieldRelations.js +65 -25
  14. package/src/helper/cameraMixin.js +25 -0
  15. package/src/helper/materialMixin.js +14 -1
  16. package/src/helper/projectedMaterial.js +662 -0
  17. package/src/helper/render/base.js +5 -5
  18. package/src/helper/render/clear.js +0 -17
  19. package/src/helper/render/edge.js +2 -0
  20. package/src/helper/render/geometryHandler.js +60 -31
  21. package/src/helper/render/imageOverlay.js +26 -145
  22. package/src/helper/render/index.js +2 -0
  23. package/src/helper/render/mergedGeometry.js +11 -2
  24. package/src/helper/render/obstacle.js +2 -1
  25. package/src/helper/render/overlay.js +38 -0
  26. package/src/helper/render/projectionMaterial.js +17 -19
  27. package/src/helper/render/roof.js +49 -52
  28. package/src/helper/render/texture.js +25 -0
  29. package/src/helper/render/tile.js +84 -24
  30. package/src/helper/render/tileProjection.js +23 -14
  31. package/src/helper/renderMixin.js +22 -8
  32. package/src/helper/threeMixin.js +5 -2
  33. package/src/store/hydrateData.js +23 -11
  34. package/src/store/nodesEdgesCreation.js +78 -4
  35. package/src/store/three-d-module.js +1 -1
  36. package/dist/css/app.58568098.css +0 -1
  37. package/dist/img/reneSola_Virtus_2_JC320S_24_Bbw.85a0cb6d.png +0 -0
  38. package/dist/index.html +0 -15
  39. package/dist/js/app-legacy.aa792c98.js +0 -2
  40. package/dist/js/app-legacy.aa792c98.js.map +0 -1
  41. package/dist/js/chunk-vendors-legacy.9bb3863d.js +0 -41
  42. package/dist/js/chunk-vendors-legacy.9bb3863d.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_3d",
3
3
  "private": false,
4
- "version": "7.20.1",
4
+ "version": "7.24.0-EPDM-10926.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.20.0",
18
+ "@eturnity/eturnity_maths": "7.24.0",
19
19
  "@originjs/vite-plugin-commonjs": "1.0.3",
20
20
  "core-js": "2.6.12",
21
21
  "cors": "2.8.5",
@@ -0,0 +1,48 @@
1
+ export default class EventManager {
2
+ constructor() {
3
+ this.listeners = {}
4
+ this.availableEvents = []
5
+ }
6
+
7
+ // Add an event listener
8
+ addEventListener(events, callback) {
9
+ let eventList = events.split(' ')
10
+ eventList.forEach((event) => {
11
+ if (!this.listeners[event]) {
12
+ this.listeners[event] = []
13
+ }
14
+ this.listeners[event].push(callback)
15
+ })
16
+ }
17
+
18
+ // Remove an event listener
19
+ removeEventListener(events, callback) {
20
+ let eventList = events.split(' ')
21
+ eventList.forEach((event) => {
22
+ if (this.listeners[event]) {
23
+ this.listeners[event] = this.listeners[event].filter(
24
+ (listener) => listener !== callback
25
+ )
26
+ }
27
+ })
28
+ }
29
+
30
+ // Dispatch an event and bubble it up to parent components
31
+ emit(event, eventData) {
32
+ //Check if event is available
33
+ if (!this.availableEvents.includes(event)) {
34
+ console.error(
35
+ event,
36
+ ' not available. Available events:',
37
+ this.availableEvents
38
+ )
39
+ }
40
+ // Check if the event has listeners
41
+ if (this.listeners[event]) {
42
+ // Execute each listener callback
43
+ this.listeners[event].forEach((callback) => {
44
+ callback(eventData)
45
+ })
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,12 @@
1
+ import { v4 as uuidv4 } from 'uuid'
2
+
3
+ export default class Item {
4
+ constructor(emit) {
5
+ this.id = uuidv4()
6
+ this.version = 0
7
+ this.emit = emit
8
+ this.actionsAvailable = []
9
+ this.isSelected = false
10
+ }
11
+ serialize() {}
12
+ }
@@ -0,0 +1,119 @@
1
+ import EventManager from '../EventManager/EventManager'
2
+
3
+ export default class LayerManager extends EventManager {
4
+ constructor() {
5
+ super()
6
+ this.items = []
7
+ this.selectedItemsIds = []
8
+ this.itemsIds = []
9
+ this.availableEvents.push(
10
+ 'selected-items-updated',
11
+ 'items-updated',
12
+ 'item-updated',
13
+ 'item-added',
14
+ 'item-removed',
15
+ 'item-selected'
16
+ )
17
+ }
18
+ findById(id) {
19
+ return this.items.find((item) => item.id == id)
20
+ }
21
+ getItems() {
22
+ return this.items
23
+ }
24
+ getReadyItems() {
25
+ return this.items.filter((item) => item.isReady)
26
+ }
27
+ getItemsIds() {
28
+ return this.itemsIds
29
+ }
30
+ getSelectedItemsIds() {
31
+ return this.selectedItemsIds
32
+ }
33
+ getSelectedItems() {
34
+ return this.items.filter((item) => this.selectedItemsIds.includes(item.id))
35
+ }
36
+ setItems(items) {
37
+ this.items = items
38
+ this.itemsIds = items.map((i) => i.id)
39
+ const newSelectedItemsIds = this.selectedItemsIds.filter((id) =>
40
+ this.itemsIds.includes(id)
41
+ )
42
+ this.selectItemsIds(newSelectedItemsIds)
43
+ this.emit('items-updated', [...this.items])
44
+ }
45
+ selectItemsIds(ids) {
46
+ this.selectedItemsIds = ids
47
+ this.items.forEach(
48
+ (item) => (item.isSelected = this.selectedItemsIds.includes(item.id))
49
+ )
50
+ this.emit('selected-items-updated', this.selectedItemsIds)
51
+ }
52
+ selectItems(items) {
53
+ const selectedItemsIds = items.map((item) => item.id)
54
+ this.selectItemsIds(selectedItemsIds)
55
+ }
56
+ deselectItems() {
57
+ this.selectItems([])
58
+ }
59
+ toggleSelectionById(id) {
60
+ let newSelectedItems = this.getSelectedItems()
61
+ if (this.selectedItemsIds.includes(id)) {
62
+ newSelectedItems = newSelectedItems.filter((item) => item.id != id)
63
+ } else {
64
+ let item = this.findById(id)
65
+ if (item) {
66
+ newSelectedItems.push(item)
67
+ }
68
+ }
69
+ this.selectItems(newSelectedItems)
70
+ }
71
+ addOrUpdateItem(item) {
72
+ const id = item.id
73
+ const existingItemWithSameId = this.items.find((i) => i.id == id)
74
+ if (existingItemWithSameId) {
75
+ if (item.version > existingItemWithSameId.version) {
76
+ this.removeItemById(id)
77
+ } else {
78
+ return existingItemWithSameId
79
+ }
80
+ }
81
+ let newItems = [...this.items]
82
+ newItems.push(item)
83
+ this.setItems(newItems)
84
+ this.emit('item-added', item)
85
+ return item
86
+ }
87
+ removeItemById(id) {
88
+ this.setItems(this.items.filter((item) => item.id != id))
89
+ this.emit('item-removed')
90
+ }
91
+ removeSelectedItems() {
92
+ this.setItems(this.items.filter((item) => !item.isSelected))
93
+ this.emit('item-removed')
94
+ }
95
+ removeAllItems() {
96
+ this.setItems([])
97
+ this.emit('item-removed')
98
+ }
99
+ dispatchActionToAllItems(actionName, params) {
100
+ return this.getItems().map((item) => {
101
+ if (
102
+ typeof item[actionName] === 'function' &&
103
+ item.actionsAvailable.includes(actionName)
104
+ ) {
105
+ return item[actionName](params)
106
+ }
107
+ })
108
+ }
109
+ dispatchActionToItemById(id, actionName, params) {
110
+ const item = this.findById(id)
111
+ if (
112
+ typeof item[actionName] === 'function' &&
113
+ item.actionsAvailable.includes(actionName)
114
+ ) {
115
+ return item[actionName](params)
116
+ }
117
+ return
118
+ }
119
+ }
@@ -0,0 +1,91 @@
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
+ if (overlayMesh.getObjectByName('plain_roof_simplified')) {
31
+ this.has_plain_roof_simplified = true
32
+ this.type = 'airteam'
33
+ } else {
34
+ this.type = 'custom_3d_model'
35
+ }
36
+ resolve(overlayMesh)
37
+ })
38
+ })
39
+ }
40
+ checkGeoLocDataAndOffset() {
41
+ const lat0 = this.overlayMesh.children[0].userData.latitude_origin
42
+ const lng0 = this.overlayMesh.children[0].userData.longitude_origin
43
+ if (lat0 && lng0 && this.origin) {
44
+ let { x, y } = deltaLatLngToDistance(
45
+ lat0 - this.origin.lat,
46
+ lng0 - this.origin.lng,
47
+ lat0
48
+ )
49
+ if (Math.hypot(x, y) < 100000) {
50
+ this.positionOffset.x = x
51
+ this.positionOffset.y = y
52
+ this.positionOffset.z = 0
53
+ } else {
54
+ this.positionOffset.x = 0
55
+ this.positionOffset.y = 0
56
+ this.positionOffset.z = 0
57
+ this.emit('overlay-offset-position-error', { id: this.id })
58
+ }
59
+ this.geoLocalisation = { x, y }
60
+ }
61
+ }
62
+ setOverlayVisibilityFor2D() {
63
+ if (
64
+ this.overlayMesh.children[0].children.some(
65
+ (child) => child.name == 'textured_roof'
66
+ )
67
+ ) {
68
+ this.overlayMesh.children[0].children.forEach(
69
+ (child) => (child.visible = child.name == 'textured_roof')
70
+ )
71
+ }
72
+ return this.overlayMesh
73
+ }
74
+ set3DObjectMaterialOpacity(obj) {
75
+ obj.children.forEach((child) => {
76
+ this.set3DObjectMaterialOpacity(child, this.opacity)
77
+ })
78
+ if (obj.material && obj.name != 'plain_roof_simplified') {
79
+ obj.visible = this.opacity > 0
80
+ obj.material.opacity = this.opacity
81
+ obj.material.transparent = this.opacity < 1
82
+ }
83
+ }
84
+ serializeSettings() {
85
+ return {
86
+ version: this.version,
87
+ corners: this.corners,
88
+ geoLocalisation: this.geoLocalisation
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,309 @@
1
+ import Overlay from './Overlay'
2
+ import { layerColors } from '../config'
3
+ import {
4
+ getDistanceBetweenPoints,
5
+ addVector,
6
+ multiplyVector,
7
+ substractVector,
8
+ getAngleInDegFromCanvasVector,
9
+ normalize2DVector,
10
+ vectorLength2D
11
+ } from '@eturnity/eturnity_maths'
12
+ let Paper
13
+ export default class ImageOverlay extends Overlay {
14
+ constructor(overlay, emit) {
15
+ super(overlay, emit)
16
+ this.url = this.resources[0].file_url
17
+ this.opacity = 1
18
+ this.imageUrl = this.resources[0].file_url
19
+ this.corners = overlay.settings.corners
20
+ this.hasScale = overlay.settings.hasScale
21
+ this.points =
22
+ overlay.settings.scaleParams && overlay.settings.scaleParams.points
23
+ ? overlay.settings.scaleParams.points
24
+ : []
25
+ this.mmPerPx =
26
+ overlay.settings.scaleParams && overlay.settings.scaleParams.mmPerPx
27
+ ? overlay.settings.scaleParams.mmPerPx
28
+ : null
29
+ this.distance =
30
+ overlay.settings.scaleParams && overlay.settings.scaleParams.distance
31
+ ? overlay.settings.scaleParams.distance
32
+ : 10000
33
+ this.initialiseImage(this.url).then((isReady) => {
34
+ this.isReady = isReady
35
+ this.version++
36
+ this.emit('overlay-is-ready', { id: this.id })
37
+ this.isReadyCallback.forEach((callback) => {
38
+ if (typeof callback === 'function') {
39
+ callback()
40
+ }
41
+ })
42
+ this.isReadyCallback = []
43
+ })
44
+ }
45
+ onLoad() {
46
+ return new Promise((resolve) => {
47
+ if (this.isReady) {
48
+ resolve(this)
49
+ } else {
50
+ this.isReadyCallback.push(resolve)
51
+ }
52
+ })
53
+ }
54
+ async initialiseImage(url) {
55
+ const img = new Image()
56
+ const _this = this
57
+ const promise = new Promise((resolve, reject) => {
58
+ img.onload = function () {
59
+ _this.width = this.width
60
+ _this.height = this.height
61
+ resolve(true)
62
+ }
63
+ img.onerror = reject
64
+ this.img = img
65
+ })
66
+ img.src = url
67
+ return promise
68
+ }
69
+ async getInitial2DCorners(mmPerPx) {
70
+ const initialWidthMm = this.width * mmPerPx
71
+ const ratio = this.height / this.width
72
+ const initialHeightMm = ratio * initialWidthMm
73
+ const cornersTopLeft = {
74
+ x: -initialWidthMm / 2,
75
+ y: initialHeightMm / 2
76
+ }
77
+ const cornersTopRight = {
78
+ x: initialWidthMm / 2,
79
+ y: initialHeightMm / 2
80
+ }
81
+ const cornersBottomLeft = {
82
+ x: -initialWidthMm / 2,
83
+ y: -initialHeightMm / 2
84
+ }
85
+ const cornersBottomRight = {
86
+ x: initialWidthMm / 2,
87
+ y: -initialHeightMm / 2
88
+ }
89
+ const corners = [
90
+ cornersTopLeft,
91
+ cornersTopRight,
92
+ cornersBottomRight,
93
+ cornersBottomLeft
94
+ ]
95
+ return corners
96
+ }
97
+ async setScale(scaleParams) {
98
+ if (!scaleParams) {
99
+ this.hasScale = false
100
+ this.version++
101
+ this.emit('overlay-scale-updated', { id: this.id })
102
+ return
103
+ }
104
+ let { points, distance, mmPerPx } = scaleParams
105
+
106
+ if (points.length < 2 || !distance) {
107
+ this.hasScale = false
108
+ this.version++
109
+ this.emit('overlay-scale-updated', { id: this.id })
110
+ return
111
+ }
112
+ this.mmPerPx = mmPerPx
113
+ this.points = points
114
+ this.distance = distance
115
+ this.hasScale = true
116
+ this.points = [{ ...this.points[0] }, { ...this.points[1] }]
117
+ this.version++
118
+ this.corners = await this.getInitial2DCorners(mmPerPx)
119
+ this.emit('overlay-scale-updated', { id: this.id })
120
+ }
121
+ renderOnPaperJS(paperJSComponent) {
122
+ Paper = paperJSComponent.paperScope
123
+ if (!this.isReady || !this.isActive || !this.corners) {
124
+ return
125
+ }
126
+ let group = paperJSComponent.paths.imageOverlays[this.id]
127
+ paperJSComponent.paperLayer['imageOverlays'].activate()
128
+
129
+ let imageOverlayPath
130
+ let handles
131
+ let isRotationHandleVisible =
132
+ paperJSComponent.selectedTool == 'selectOverlay' && this.isSelected
133
+ let corners = this.corners.map((p) => paperJSComponent.toCanvasRef(p))
134
+ if (group) {
135
+ if (group.data.url == this.url) {
136
+ imageOverlayPath = group.children[0]
137
+ } else {
138
+ imageOverlayPath = this.loadImageOverlay(this.url, corners)
139
+ paperJSComponent.clearPath(group.children[0])
140
+ group.insertChild(0, imageOverlayPath)
141
+ }
142
+ handles = this.renderImageOverlayHandles(
143
+ corners,
144
+ isRotationHandleVisible,
145
+ group.children[1]
146
+ )
147
+ this.applyRasterToCorners(imageOverlayPath, corners)
148
+ group.visible = true
149
+ } else {
150
+ group = new Paper.Group()
151
+ imageOverlayPath = this.loadImageOverlay(this.url, corners)
152
+
153
+ handles = this.renderImageOverlayHandles(corners, isRotationHandleVisible)
154
+
155
+ group.addChild(imageOverlayPath)
156
+ group.addChild(handles)
157
+ group.itemType = 'imageOverlays'
158
+ group.data.url = this.url
159
+ group.type = 'imageOverlays'
160
+ group.pathId = this.id
161
+ group.overlayId = this.id
162
+ group.visible = true
163
+ paperJSComponent.paths.imageOverlays[this.id] = group
164
+ }
165
+ imageOverlayPath.opacity = this.opacity
166
+ handles.visible = isRotationHandleVisible
167
+ }
168
+ loadImageOverlay(url, corners) {
169
+ let rasterImageOverlay = new Paper.Raster({
170
+ source: url,
171
+ crossOrigin: 'Anonymous'
172
+ })
173
+ rasterImageOverlay.onLoad = () => {
174
+ this.applyRasterToCorners(rasterImageOverlay, corners)
175
+ }
176
+ rasterImageOverlay.data.angle = 0
177
+ rasterImageOverlay.data.type = 'imageOverlayRaster'
178
+ rasterImageOverlay.data.overlayId = this.id
179
+ rasterImageOverlay.data.url = url
180
+ return rasterImageOverlay
181
+ }
182
+ applyRasterToCorners(texture, corners = this.corners) {
183
+ //remove angle of texture
184
+ let textureAngle = texture.angle || 0
185
+ texture.rotate(-textureAngle)
186
+
187
+ //make texture the same size to fit corners
188
+ const textureWidth = texture.bounds.width
189
+ const textureHeight = texture.bounds.height
190
+ const frameWidth = getDistanceBetweenPoints(corners[1], corners[0])
191
+ const frameHeight = getDistanceBetweenPoints(corners[3], corners[0])
192
+ const center = multiplyVector(0.5, addVector(corners[0], corners[2]))
193
+ if (texture.bounds.width) {
194
+ var a = frameWidth / textureWidth
195
+ var b = 0
196
+ var c = 0
197
+ var d = frameHeight / textureHeight
198
+ texture.transform(new Paper.Matrix(a, b, c, d, 0, 0))
199
+ //translate to fit top left corner
200
+ var tx = center.x - texture.bounds.center.x
201
+ var ty = center.y - texture.bounds.center.y
202
+ texture.transform(new Paper.Matrix(1, 0, 0, 1, tx, ty))
203
+ //rotate
204
+ let angle = getAngleInDegFromCanvasVector(
205
+ substractVector(corners[0], corners[3])
206
+ )
207
+
208
+ texture.angle = angle
209
+ texture.rotate(angle)
210
+ }
211
+ }
212
+ renderImageOverlayHandles(corners, rotateHandleVisible, group = null) {
213
+ let circleHandle
214
+ let hasPaths = !!group
215
+ let handles = group || new Paper.Group()
216
+ let u = normalize2DVector(substractVector(corners[1], corners[0]))
217
+ let v = normalize2DVector(substractVector(corners[0], corners[3]))
218
+
219
+ //rotation handle
220
+ let center = multiplyVector(0.5, addVector(corners[0], corners[2]))
221
+
222
+ let radius = vectorLength2D(substractVector(center, corners[0])) - 10
223
+ if (!hasPaths) {
224
+ circleHandle = new Paper.Path.Circle(center, radius)
225
+ circleHandle.fillColor = layerColors.imageOverlayHandle.fillColor
226
+ circleHandle.strokeWidth = layerColors.imageOverlayHandle.strokeWidth
227
+ circleHandle.strokeColor = layerColors.imageOverlayHandle.strokeColor
228
+ circleHandle.data.type = 'imageOverlayRotateHandle'
229
+ circleHandle.data.overlayId = this.id
230
+ circleHandle.radius = radius
231
+ handles.addChild(circleHandle)
232
+ } else {
233
+ circleHandle = handles.children[0]
234
+ let ratio = radius / circleHandle.radius
235
+ circleHandle.transform(new Paper.Matrix(ratio, 0, 0, ratio, 0, 0))
236
+ circleHandle.position = center
237
+ circleHandle.radius = radius
238
+ }
239
+
240
+ circleHandle.visible = rotateHandleVisible
241
+
242
+ //scale handle
243
+ for (let k = 0; k < 4; k++) {
244
+ let squareSize = 10
245
+ let squareHandleVertices = [
246
+ addVector(
247
+ addVector(corners[k], multiplyVector(squareSize / 2, u)),
248
+ multiplyVector(squareSize / 2, v)
249
+ ),
250
+ addVector(
251
+ addVector(corners[k], multiplyVector(-squareSize / 2, u)),
252
+ multiplyVector(squareSize / 2, v)
253
+ ),
254
+ addVector(
255
+ addVector(corners[k], multiplyVector(-squareSize / 2, u)),
256
+ multiplyVector(-squareSize / 2, v)
257
+ ),
258
+ addVector(
259
+ addVector(corners[k], multiplyVector(squareSize / 2, u)),
260
+ multiplyVector(-squareSize / 2, v)
261
+ ),
262
+ addVector(
263
+ addVector(corners[k], multiplyVector(squareSize / 2, u)),
264
+ multiplyVector(squareSize / 2, v)
265
+ )
266
+ ]
267
+ let squareHandle
268
+
269
+ if (hasPaths) {
270
+ squareHandle = handles.children[k + 1]
271
+ squareHandle.position = corners[k]
272
+ //squareHandle.rotate()
273
+ for (let index in squareHandleVertices) {
274
+ let vertex = squareHandleVertices[index]
275
+ squareHandle.segments[index].point = vertex
276
+ }
277
+ } else {
278
+ squareHandle = new Paper.Path()
279
+
280
+ for (let vertex of squareHandleVertices) {
281
+ squareHandle.add(vertex)
282
+ }
283
+
284
+ squareHandle.fillColor = layerColors.imageOverlayHandle.fillColor
285
+ squareHandle.strokeWidth = layerColors.imageOverlayHandle.strokeWidth
286
+ squareHandle.strokeColor = layerColors.imageOverlayHandle.strokeColor
287
+ squareHandle.data.type = 'handle'
288
+ squareHandle.data.index = k
289
+
290
+ handles.addChild(squareHandle)
291
+ }
292
+ squareHandle.visible = false
293
+ }
294
+ return handles
295
+ }
296
+ renderOnThreeJS(threeJSComponent) {}
297
+ serializeSettings() {
298
+ return {
299
+ hasScale: this.hasScale,
300
+ scaleParams: {
301
+ points: this.points,
302
+ distance: this.distance,
303
+ mmPerPx: this.mmPerPx
304
+ },
305
+ corners: this.corners,
306
+ version: this.version
307
+ }
308
+ }
309
+ }