@xeokit/xeokit-sdk 2.6.28 → 2.6.30
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/README.md +1 -0
- package/dist/xeokit-sdk.cjs.js +1425 -649
- package/dist/xeokit-sdk.es.js +1420 -650
- package/dist/xeokit-sdk.es5.js +629 -552
- package/dist/xeokit-sdk.min.cjs.js +5 -5
- package/dist/xeokit-sdk.min.es.js +5 -5
- package/dist/xeokit-sdk.min.es5.js +4 -4
- package/package.json +1 -1
- package/src/extras/PointerCircle/PointerCircle.js +1 -1
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.js +22 -41
- package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.js +3 -18
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.js +20 -41
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.js +4 -20
- package/src/plugins/DistanceMeasurementsPlugin/index.js +1 -1
- package/src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js +2 -110
- package/src/plugins/GLTFLoaderPlugin/GLTFSceneModelLoader.js +252 -222
- package/src/plugins/StoreyViewsPlugin/StoreyViewsPlugin.js +31 -1
- package/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js +20 -8
- package/src/plugins/ZonesPlugin/ZonesPlugin.js +1939 -0
- package/src/plugins/ZonesPlugin/index.js +1 -1875
- package/src/viewer/Viewer.js +2 -2
- package/src/viewer/metadata/MetaScene.js +0 -2
- package/src/viewer/scene/math/MeshSurfaceArea.js +90 -0
- package/src/viewer/scene/math/MeshVolume.js +102 -0
- package/src/viewer/scene/math/index.js +3 -0
- package/src/viewer/scene/math/isTriangleMeshSolid.js +162 -0
- package/src/viewer/scene/math/math.js +8 -0
- package/src/viewer/scene/model/SceneModel.js +73 -34
- package/src/viewer/scene/model/SceneModelEntity.js +46 -1
- package/src/viewer/scene/model/SceneModelMesh.js +74 -1
- package/src/viewer/scene/model/SceneModelTextureSet.js +5 -0
- package/src/viewer/scene/model/dtx/lines/DTXLinesLayer.js +7 -1
- package/src/viewer/scene/model/dtx/triangles/DTXTrianglesLayer.js +77 -1
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapInitRenderer.js +8 -0
- package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapRenderer.js +8 -0
- package/src/viewer/scene/model/vbo/VBORenderer.js +10 -1
- package/src/viewer/scene/model/vbo/batching/lines/VBOBatchingLinesLayer.js +6 -1
- package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapRenderer.js +1 -1
- package/src/viewer/scene/model/vbo/batching/points/VBOBatchingPointsLayer.js +6 -1
- package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesLayer.js +59 -18
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/Renderers.js +40 -12
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesBatchingRenderer.js +2 -3
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesColorTextureRenderer.js +25 -7
- package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapRenderer.js +1 -1
- package/src/viewer/scene/model/vbo/instancing/lines/VBOInstancingLinesLayer.js +6 -1
- package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapRenderer.js +1 -1
- package/src/viewer/scene/model/vbo/instancing/points/VBOInstancingPointsLayer.js +6 -1
- package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +48 -14
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/Renderers.js +74 -47
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesColorTextureRenderer.js +29 -14
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesInstancingRenderer.js +5 -4
- package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapRenderer.js +1 -1
- package/src/viewer/scene/scene/Scene.js +16 -5
- package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +1 -1
- package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +1 -5
- package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.d.ts +7 -0
- package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsPlugin.d.ts +26 -1
- package/types/plugins/DistanceMeasurementsPlugin/index.d.ts +3 -1
|
@@ -1,1875 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import {Component} from "../../viewer/scene/Component.js";
|
|
3
|
-
import {buildBoxGeometry} from "../../viewer/scene/geometry/builders/buildBoxGeometry.js";
|
|
4
|
-
import {ReadableGeometry} from "../../viewer/scene/geometry/ReadableGeometry.js";
|
|
5
|
-
import {Marker} from "../../viewer/scene/marker/Marker.js";
|
|
6
|
-
import {PhongMaterial} from "../../viewer/scene/materials/PhongMaterial.js";
|
|
7
|
-
import {math} from "../../viewer/scene/math/math.js";
|
|
8
|
-
import {Mesh} from "../../viewer/scene/mesh/Mesh.js";
|
|
9
|
-
import {Dot} from "../lib/html/Dot.js";
|
|
10
|
-
import {activateDraggableDots, Dot3D, transformToNode} from "../../../src/plugins/lib/ui/index.js";
|
|
11
|
-
|
|
12
|
-
const hex2rgb = function(color) {
|
|
13
|
-
const rgb = idx => parseInt(color.substr(idx + 1, 2), 16) / 255;
|
|
14
|
-
return [ rgb(0), rgb(2), rgb(4) ];
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const triangulateEarClipping = function(planeCoords) {
|
|
18
|
-
|
|
19
|
-
const polygonVertices = [ ];
|
|
20
|
-
for (let i = 0; i < planeCoords.length; ++i)
|
|
21
|
-
polygonVertices.push(i);
|
|
22
|
-
|
|
23
|
-
const isCCW = (function() {
|
|
24
|
-
const ba = math.vec2();
|
|
25
|
-
const bc = math.vec2();
|
|
26
|
-
|
|
27
|
-
let anglesSum = 0;
|
|
28
|
-
const angles = [ ];
|
|
29
|
-
|
|
30
|
-
for (let i = 0; i < polygonVertices.length; ++i)
|
|
31
|
-
{
|
|
32
|
-
const a = planeCoords[polygonVertices[i]];
|
|
33
|
-
const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
|
|
34
|
-
const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];
|
|
35
|
-
|
|
36
|
-
math.subVec2(a, b, ba);
|
|
37
|
-
math.subVec2(c, b, bc);
|
|
38
|
-
|
|
39
|
-
const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
|
|
40
|
-
const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
|
|
41
|
-
const convex = (ba[0] * bc[1] - ba[1] * bc[0]) >= 0;
|
|
42
|
-
anglesSum += convex ? angle : (2 * Math.PI - angle);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return anglesSum < (polygonVertices.length * Math.PI);
|
|
46
|
-
})();
|
|
47
|
-
|
|
48
|
-
const pointInTriangle = (function() {
|
|
49
|
-
const sign = (p1, p2, p3) => {
|
|
50
|
-
return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
return (pt, v1, v2, v3) => {
|
|
54
|
-
const d1 = sign(pt, v1, v2);
|
|
55
|
-
const d2 = sign(pt, v2, v3);
|
|
56
|
-
const d3 = sign(pt, v3, v1);
|
|
57
|
-
|
|
58
|
-
const has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
|
|
59
|
-
const has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
|
|
60
|
-
|
|
61
|
-
return !(has_neg && has_pos);
|
|
62
|
-
};
|
|
63
|
-
})();
|
|
64
|
-
|
|
65
|
-
const baseTriangles = [ ];
|
|
66
|
-
|
|
67
|
-
const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i => ({ idx: i }));
|
|
68
|
-
vertices.forEach((v, i) => {
|
|
69
|
-
v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
|
|
70
|
-
v.next = vertices[(i + 1) % vertices.length];
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const ba = math.vec2();
|
|
74
|
-
const bc = math.vec2();
|
|
75
|
-
|
|
76
|
-
while (vertices.length > 2) {
|
|
77
|
-
let earIdx = 0;
|
|
78
|
-
while (true) {
|
|
79
|
-
if (earIdx >= vertices.length)
|
|
80
|
-
{
|
|
81
|
-
throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
|
|
82
|
-
}
|
|
83
|
-
const v = vertices[earIdx];
|
|
84
|
-
|
|
85
|
-
const a = planeCoords[v.prev.idx];
|
|
86
|
-
const b = planeCoords[v.idx];
|
|
87
|
-
const c = planeCoords[v.next.idx];
|
|
88
|
-
|
|
89
|
-
math.subVec2(a, b, ba);
|
|
90
|
-
math.subVec2(c, b, bc);
|
|
91
|
-
|
|
92
|
-
if (((ba[0] * bc[1] - ba[1] * bc[0]) >= 0) // a convex vertex
|
|
93
|
-
&&
|
|
94
|
-
vertices.every( // no other vertices inside
|
|
95
|
-
vv => ((vv === v)
|
|
96
|
-
||
|
|
97
|
-
(vv === v.prev)
|
|
98
|
-
||
|
|
99
|
-
(vv === v.next)
|
|
100
|
-
||
|
|
101
|
-
!pointInTriangle(planeCoords[vv.idx], a, b, c))))
|
|
102
|
-
break;
|
|
103
|
-
++earIdx;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const ear = vertices[earIdx];
|
|
107
|
-
vertices.splice(earIdx, 1);
|
|
108
|
-
|
|
109
|
-
baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);
|
|
110
|
-
|
|
111
|
-
const prev = ear.prev;
|
|
112
|
-
prev.next = ear.next;
|
|
113
|
-
const next = ear.next;
|
|
114
|
-
next.prev = ear.prev;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return [ planeCoords, baseTriangles ];
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const marker3D = function(scene, color) {
|
|
121
|
-
const canvas = scene.canvas.canvas;
|
|
122
|
-
|
|
123
|
-
const markerParent = canvas.parentNode;
|
|
124
|
-
const markerDiv = document.createElement("div");
|
|
125
|
-
markerParent.insertBefore(markerDiv, canvas);
|
|
126
|
-
|
|
127
|
-
let size = 5;
|
|
128
|
-
markerDiv.style.background = color;
|
|
129
|
-
markerDiv.style.border = "2px solid white";
|
|
130
|
-
markerDiv.style.margin = "0 0";
|
|
131
|
-
markerDiv.style.zIndex = "100";
|
|
132
|
-
markerDiv.style.position = "absolute";
|
|
133
|
-
markerDiv.style.pointerEvents = "none";
|
|
134
|
-
markerDiv.style.display = "none";
|
|
135
|
-
|
|
136
|
-
const marker = new Marker(scene, {});
|
|
137
|
-
|
|
138
|
-
const px = x => x + "px";
|
|
139
|
-
const update = function() {
|
|
140
|
-
const pos = marker.canvasPos.slice();
|
|
141
|
-
transformToNode(canvas, markerParent, pos);
|
|
142
|
-
markerDiv.style.left = px(pos[0] - 3 - size / 2);
|
|
143
|
-
markerDiv.style.top = px(pos[1] - 3 - size / 2);
|
|
144
|
-
markerDiv.style.borderRadius = px(size * 2);
|
|
145
|
-
markerDiv.style.width = px(size);
|
|
146
|
-
markerDiv.style.height = px(size);
|
|
147
|
-
};
|
|
148
|
-
const onViewMatrix = scene.camera.on("viewMatrix", update);
|
|
149
|
-
const onProjMatrix = scene.camera.on("projMatrix", update);
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
update: function(worldPos) {
|
|
153
|
-
if (worldPos)
|
|
154
|
-
{
|
|
155
|
-
marker.worldPos = worldPos;
|
|
156
|
-
update();
|
|
157
|
-
}
|
|
158
|
-
markerDiv.style.display = worldPos ? "" : "none";
|
|
159
|
-
},
|
|
160
|
-
|
|
161
|
-
setHighlighted: function(h) {
|
|
162
|
-
size = h ? 10 : 5;
|
|
163
|
-
update();
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
getCanvasPos: () => marker.canvasPos,
|
|
167
|
-
|
|
168
|
-
getWorldPos: () => marker.worldPos,
|
|
169
|
-
|
|
170
|
-
destroy: function() {
|
|
171
|
-
markerDiv.parentNode.removeChild(markerDiv);
|
|
172
|
-
scene.camera.off(onViewMatrix);
|
|
173
|
-
scene.camera.off(onProjMatrix);
|
|
174
|
-
marker.destroy();
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
import {Wire} from "../lib/html/Wire.js";
|
|
180
|
-
|
|
181
|
-
const wire3D = function(scene, color, startWorldPos) {
|
|
182
|
-
const canvas = scene.canvas.canvas;
|
|
183
|
-
|
|
184
|
-
const startMarker = new Marker(scene, {});
|
|
185
|
-
startMarker.worldPos = startWorldPos;
|
|
186
|
-
const endMarker = new Marker(scene, {});
|
|
187
|
-
const wireParent = canvas.ownerDocument.body;
|
|
188
|
-
const wire = new Wire(wireParent, {
|
|
189
|
-
color: color,
|
|
190
|
-
thickness: 1,
|
|
191
|
-
thicknessClickable: 6
|
|
192
|
-
});
|
|
193
|
-
wire.setVisible(false);
|
|
194
|
-
|
|
195
|
-
const updatePos = function() {
|
|
196
|
-
const p0 = startMarker.canvasPos.slice();
|
|
197
|
-
const p1 = endMarker.canvasPos.slice();
|
|
198
|
-
transformToNode(canvas, wireParent, p0);
|
|
199
|
-
transformToNode(canvas, wireParent, p1);
|
|
200
|
-
wire.setStartAndEnd(p0[0], p0[1], p1[0], p1[1]);
|
|
201
|
-
};
|
|
202
|
-
const onViewMatrix = scene.camera.on("viewMatrix", updatePos);
|
|
203
|
-
const onProjMatrix = scene.camera.on("projMatrix", updatePos);
|
|
204
|
-
|
|
205
|
-
return {
|
|
206
|
-
update: function(endWorldPos) {
|
|
207
|
-
if (endWorldPos)
|
|
208
|
-
{
|
|
209
|
-
endMarker.worldPos = endWorldPos;
|
|
210
|
-
updatePos();
|
|
211
|
-
}
|
|
212
|
-
wire.setVisible(!!endWorldPos);
|
|
213
|
-
},
|
|
214
|
-
|
|
215
|
-
destroy: function() {
|
|
216
|
-
scene.camera.off(onViewMatrix);
|
|
217
|
-
scene.camera.off(onProjMatrix);
|
|
218
|
-
startMarker.destroy();
|
|
219
|
-
endMarker.destroy();
|
|
220
|
-
wire.destroy();
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const basePolygon3D = function(scene, color, alpha) {
|
|
226
|
-
let mesh = null;
|
|
227
|
-
|
|
228
|
-
const updateBase = points => {
|
|
229
|
-
if (points)
|
|
230
|
-
{
|
|
231
|
-
if (mesh)
|
|
232
|
-
{
|
|
233
|
-
mesh.destroy();
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
try {
|
|
237
|
-
const [ baseVertices, baseTriangles ] = triangulateEarClipping(points.map(p => [ p[0], p[2] ]));
|
|
238
|
-
|
|
239
|
-
const positions = [ ].concat(...baseVertices.map(p => [p[0], points[0][1], p[1]])); // To convert from Float64Array into an Array
|
|
240
|
-
const ind = [ ].concat(...baseTriangles);
|
|
241
|
-
mesh = new Mesh(scene, {
|
|
242
|
-
pickable: false, // otherwise there's a WebGL error inside PickMeshRenderer.prototype.drawMesh
|
|
243
|
-
geometry: new ReadableGeometry(
|
|
244
|
-
scene,
|
|
245
|
-
{
|
|
246
|
-
positions: positions,
|
|
247
|
-
indices: ind,
|
|
248
|
-
normals: math.buildNormals(positions, ind)
|
|
249
|
-
}),
|
|
250
|
-
material: new PhongMaterial(scene, {
|
|
251
|
-
alpha: (alpha !== undefined) ? alpha : 0.5,
|
|
252
|
-
backfaces: true,
|
|
253
|
-
diffuse: hex2rgb(color)
|
|
254
|
-
})
|
|
255
|
-
});
|
|
256
|
-
} catch (e) {
|
|
257
|
-
mesh = null;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (mesh)
|
|
262
|
-
{
|
|
263
|
-
mesh.visible = !!points;
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
updateBase(null);
|
|
267
|
-
|
|
268
|
-
return {
|
|
269
|
-
updateBase: updateBase,
|
|
270
|
-
destroy: () => mesh && mesh.destroy()
|
|
271
|
-
};
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
const startAAZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
275
|
-
const marker1 = marker3D(scene, zoneColor);
|
|
276
|
-
const marker2 = marker3D(scene, zoneColor);
|
|
277
|
-
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
278
|
-
|
|
279
|
-
const updatePointerLens = (pointerLens
|
|
280
|
-
? function(canvasPos) {
|
|
281
|
-
pointerLens.visible = !! canvasPos;
|
|
282
|
-
if (canvasPos)
|
|
283
|
-
{
|
|
284
|
-
pointerLens.canvasPos = canvasPos;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
: () => { });
|
|
288
|
-
|
|
289
|
-
let deactivatePointSelection = select3dPoint(
|
|
290
|
-
() => {
|
|
291
|
-
updatePointerLens(null);
|
|
292
|
-
marker1.update(null);
|
|
293
|
-
},
|
|
294
|
-
(canvasPos, worldPos) => {
|
|
295
|
-
updatePointerLens(canvasPos);
|
|
296
|
-
marker1.update(worldPos);
|
|
297
|
-
},
|
|
298
|
-
function(point1CanvasPos, point1WorldPos) {
|
|
299
|
-
marker1.update(point1WorldPos);
|
|
300
|
-
|
|
301
|
-
deactivatePointSelection = select3dPoint(
|
|
302
|
-
function() {
|
|
303
|
-
updatePointerLens(null);
|
|
304
|
-
marker2.update(null);
|
|
305
|
-
basePolygon.updateBase(null);
|
|
306
|
-
},
|
|
307
|
-
function(canvasPos, point2WorldPos) {
|
|
308
|
-
updatePointerLens(canvasPos);
|
|
309
|
-
marker2.update(point2WorldPos);
|
|
310
|
-
|
|
311
|
-
if (math.distVec3(point1WorldPos, point2WorldPos) > 0.01)
|
|
312
|
-
{
|
|
313
|
-
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
314
|
-
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
315
|
-
|
|
316
|
-
const xmin = min(0);
|
|
317
|
-
const ymin = min(1);
|
|
318
|
-
const zmin = min(2);
|
|
319
|
-
const xmax = max(0);
|
|
320
|
-
const ymax = max(1);
|
|
321
|
-
const zmax = max(2);
|
|
322
|
-
|
|
323
|
-
basePolygon.updateBase([ [ xmin, ymin, zmax ], [ xmax, ymin, zmax ],
|
|
324
|
-
[ xmax, ymin, zmin ], [ xmin, ymin, zmin ] ]);
|
|
325
|
-
}
|
|
326
|
-
else
|
|
327
|
-
basePolygon.updateBase(null);
|
|
328
|
-
},
|
|
329
|
-
function(point2CanvasPos, point2WorldPos) {
|
|
330
|
-
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
331
|
-
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
332
|
-
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
333
|
-
marker2.update(point2WorldPos);
|
|
334
|
-
|
|
335
|
-
marker1.destroy();
|
|
336
|
-
marker2.destroy();
|
|
337
|
-
basePolygon.destroy();
|
|
338
|
-
updatePointerLens(null);
|
|
339
|
-
|
|
340
|
-
const min = (idx) => Math.min(point1WorldPos[idx], point2WorldPos[idx]);
|
|
341
|
-
const max = (idx) => Math.max(point1WorldPos[idx], point2WorldPos[idx]);
|
|
342
|
-
|
|
343
|
-
const xmin = min(0);
|
|
344
|
-
const zmin = min(2);
|
|
345
|
-
const xmax = max(0);
|
|
346
|
-
const zmax = max(2);
|
|
347
|
-
|
|
348
|
-
const zone = zonesPlugin.createZone(
|
|
349
|
-
{
|
|
350
|
-
id: math.createUUID(),
|
|
351
|
-
geometry: {
|
|
352
|
-
planeCoordinates: [
|
|
353
|
-
[ xmin, zmax ],
|
|
354
|
-
[ xmax, zmax ],
|
|
355
|
-
[ xmax, zmin ],
|
|
356
|
-
[ xmin, zmin ]
|
|
357
|
-
],
|
|
358
|
-
altitude: zoneAltitude,
|
|
359
|
-
height: zoneHeight
|
|
360
|
-
},
|
|
361
|
-
alpha: zoneAlpha,
|
|
362
|
-
color: zoneColor
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
onZoneCreated(zone);
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
return {
|
|
370
|
-
deactivate: function() {
|
|
371
|
-
deactivatePointSelection();
|
|
372
|
-
marker1.destroy();
|
|
373
|
-
marker2.destroy();
|
|
374
|
-
basePolygon.destroy();
|
|
375
|
-
updatePointerLens(null);
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const mousePointSelector = function(viewer, ray2WorldPos) {
|
|
381
|
-
return function(onCancel, onChange, onCommit) {
|
|
382
|
-
const scene = viewer.scene;
|
|
383
|
-
const canvas = scene.canvas.canvas;
|
|
384
|
-
const moveTolerance = 20;
|
|
385
|
-
|
|
386
|
-
const copyCanvasPos = (event, vec2) => {
|
|
387
|
-
vec2[0] = event.clientX;
|
|
388
|
-
vec2[1] = event.clientY;
|
|
389
|
-
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
390
|
-
return vec2;
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
const pickWorldPos = canvasPos => {
|
|
394
|
-
const origin = math.vec3();
|
|
395
|
-
const direction = math.vec3();
|
|
396
|
-
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, origin, direction);
|
|
397
|
-
return ray2WorldPos(origin, direction);
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
let buttonDown = false;
|
|
401
|
-
const resetAction = function() {
|
|
402
|
-
buttonDown = false;
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
const cleanup = function() {
|
|
406
|
-
resetAction();
|
|
407
|
-
canvas.removeEventListener("mousedown", onMouseDown);
|
|
408
|
-
canvas.removeEventListener("mousemove", onMouseMove);
|
|
409
|
-
viewer.cameraControl.off(onCameraControlRayMove);
|
|
410
|
-
canvas.removeEventListener("mouseup", onMouseUp);
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
const startCanvasPos = math.vec2();
|
|
414
|
-
const onMouseDown = function(event) {
|
|
415
|
-
if (event.which === 1)
|
|
416
|
-
{
|
|
417
|
-
copyCanvasPos(event, startCanvasPos);
|
|
418
|
-
buttonDown = true;
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
canvas.addEventListener("mousedown", onMouseDown);
|
|
422
|
-
|
|
423
|
-
const onMouseMove = function(event) {
|
|
424
|
-
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
425
|
-
if (buttonDown && math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
426
|
-
{
|
|
427
|
-
resetAction();
|
|
428
|
-
onCancel();
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
canvas.addEventListener("mousemove", onMouseMove);
|
|
432
|
-
|
|
433
|
-
const onCameraControlRayMove = viewer.cameraControl.on(
|
|
434
|
-
"rayMove",
|
|
435
|
-
event => {
|
|
436
|
-
const canvasPos = event.canvasPos;
|
|
437
|
-
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
const onMouseUp = function(event) {
|
|
441
|
-
if ((event.which === 1) && buttonDown)
|
|
442
|
-
{
|
|
443
|
-
cleanup();
|
|
444
|
-
const canvasPos = copyCanvasPos(event, math.vec2());
|
|
445
|
-
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
446
|
-
}
|
|
447
|
-
};
|
|
448
|
-
canvas.addEventListener("mouseup", onMouseUp);
|
|
449
|
-
|
|
450
|
-
return cleanup;
|
|
451
|
-
};
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
455
|
-
return function(onCancel, onChange, onCommit) {
|
|
456
|
-
const scene = viewer.scene;
|
|
457
|
-
const canvas = scene.canvas.canvas;
|
|
458
|
-
const longTouchTimeoutMs = 300;
|
|
459
|
-
const moveTolerance = 20;
|
|
460
|
-
|
|
461
|
-
const copyCanvasPos = (event, vec2) => {
|
|
462
|
-
vec2[0] = event.clientX;
|
|
463
|
-
vec2[1] = event.clientY;
|
|
464
|
-
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
465
|
-
return vec2;
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
const pickWorldPos = canvasPos => {
|
|
469
|
-
const origin = math.vec3();
|
|
470
|
-
const direction = math.vec3();
|
|
471
|
-
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, origin, direction);
|
|
472
|
-
return ray2WorldPos(origin, direction);
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
let longTouchTimeout = null;
|
|
476
|
-
const nop = () => { };
|
|
477
|
-
let onSingleTouchMove = nop;
|
|
478
|
-
let startTouchIdentifier;
|
|
479
|
-
|
|
480
|
-
const resetAction = function() {
|
|
481
|
-
pointerCircle.stop();
|
|
482
|
-
clearTimeout(longTouchTimeout);
|
|
483
|
-
viewer.cameraControl.active = true;
|
|
484
|
-
onSingleTouchMove = nop;
|
|
485
|
-
startTouchIdentifier = null;
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
const cleanup = function() {
|
|
489
|
-
resetAction();
|
|
490
|
-
canvas.removeEventListener("touchstart", onCanvasTouchStart);
|
|
491
|
-
canvas.removeEventListener("touchmove", onCanvasTouchMove);
|
|
492
|
-
canvas.removeEventListener("touchend", onCanvasTouchEnd);
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
const onCanvasTouchStart = function(event) {
|
|
496
|
-
const touches = event.touches;
|
|
497
|
-
|
|
498
|
-
if (touches.length !== 1)
|
|
499
|
-
{
|
|
500
|
-
resetAction();
|
|
501
|
-
onCancel();
|
|
502
|
-
}
|
|
503
|
-
else
|
|
504
|
-
{
|
|
505
|
-
const startTouch = touches[0];
|
|
506
|
-
const startCanvasPos = copyCanvasPos(startTouch, math.vec2());
|
|
507
|
-
|
|
508
|
-
const startWorldPos = pickWorldPos(startCanvasPos);
|
|
509
|
-
if (startWorldPos)
|
|
510
|
-
{
|
|
511
|
-
startTouchIdentifier = startTouch.identifier;
|
|
512
|
-
|
|
513
|
-
onSingleTouchMove = canvasPos => {
|
|
514
|
-
if (math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
515
|
-
{
|
|
516
|
-
resetAction();
|
|
517
|
-
}
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
longTouchTimeout = setTimeout(
|
|
521
|
-
function() {
|
|
522
|
-
pointerCircle.start(startCanvasPos);
|
|
523
|
-
|
|
524
|
-
longTouchTimeout = setTimeout(
|
|
525
|
-
function() {
|
|
526
|
-
pointerCircle.stop();
|
|
527
|
-
|
|
528
|
-
viewer.cameraControl.active = false;
|
|
529
|
-
|
|
530
|
-
onSingleTouchMove = canvasPos => {
|
|
531
|
-
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
532
|
-
};
|
|
533
|
-
|
|
534
|
-
onSingleTouchMove(startCanvasPos);
|
|
535
|
-
},
|
|
536
|
-
longTouchTimeoutMs);
|
|
537
|
-
},
|
|
538
|
-
250);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
};
|
|
542
|
-
canvas.addEventListener("touchstart", onCanvasTouchStart, {passive: true});
|
|
543
|
-
|
|
544
|
-
// canvas.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
545
|
-
|
|
546
|
-
const onCanvasTouchMove = function(event) {
|
|
547
|
-
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
548
|
-
if (touch)
|
|
549
|
-
{
|
|
550
|
-
onSingleTouchMove(copyCanvasPos(touch, math.vec2()));
|
|
551
|
-
}
|
|
552
|
-
};
|
|
553
|
-
canvas.addEventListener("touchmove", onCanvasTouchMove, {passive: true});
|
|
554
|
-
|
|
555
|
-
const onCanvasTouchEnd = function(event) {
|
|
556
|
-
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
557
|
-
if (touch)
|
|
558
|
-
{
|
|
559
|
-
cleanup();
|
|
560
|
-
const canvasPos = copyCanvasPos(touch, math.vec2());
|
|
561
|
-
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
562
|
-
}
|
|
563
|
-
};
|
|
564
|
-
canvas.addEventListener("touchend", onCanvasTouchEnd, {passive: true});
|
|
565
|
-
|
|
566
|
-
return cleanup;
|
|
567
|
-
};
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
const planeIntersect = function(p0, n, origin, direction) {
|
|
571
|
-
const t = - (math.dotVec3(origin, n) - p0) / math.dotVec3(direction, n);
|
|
572
|
-
if (false) // (t < 0)
|
|
573
|
-
{
|
|
574
|
-
return false;
|
|
575
|
-
}
|
|
576
|
-
else
|
|
577
|
-
{
|
|
578
|
-
const worldPos = math.vec3();
|
|
579
|
-
math.mulVec3Scalar(direction, t, worldPos);
|
|
580
|
-
math.addVec3(origin, worldPos, worldPos);
|
|
581
|
-
return worldPos;
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
/**
|
|
586
|
-
* @desc Renders a transparent box between two 3D points.
|
|
587
|
-
*
|
|
588
|
-
* See {@link ZonesPlugin} for more info.
|
|
589
|
-
*/
|
|
590
|
-
|
|
591
|
-
class Zone extends Component {
|
|
592
|
-
|
|
593
|
-
/**
|
|
594
|
-
* @private
|
|
595
|
-
*/
|
|
596
|
-
constructor(plugin, cfg = {}) {
|
|
597
|
-
|
|
598
|
-
super(plugin.viewer.scene, cfg);
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* The {@link ZonesPlugin} that owns this Zone.
|
|
602
|
-
* @type {ZonesPlugin}
|
|
603
|
-
*/
|
|
604
|
-
this.plugin = plugin;
|
|
605
|
-
|
|
606
|
-
this._container = cfg.container;
|
|
607
|
-
if (!this._container) {
|
|
608
|
-
throw "config missing: container";
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
this._eventSubs = {};
|
|
612
|
-
|
|
613
|
-
const scene = this.plugin.viewer.scene;
|
|
614
|
-
|
|
615
|
-
this._geometry = cfg.geometry;
|
|
616
|
-
|
|
617
|
-
const onMouseOver = cfg.onMouseOver ? (event) => {
|
|
618
|
-
cfg.onMouseOver(event, this);
|
|
619
|
-
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseover', event));
|
|
620
|
-
} : null;
|
|
621
|
-
|
|
622
|
-
const onMouseLeave = cfg.onMouseLeave ? (event) => {
|
|
623
|
-
cfg.onMouseLeave(event, this);
|
|
624
|
-
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseleave', event));
|
|
625
|
-
} : null;
|
|
626
|
-
|
|
627
|
-
const onMouseDown = (event) => {
|
|
628
|
-
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousedown', event));
|
|
629
|
-
} ;
|
|
630
|
-
|
|
631
|
-
const onMouseUp = (event) => {
|
|
632
|
-
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mouseup', event));
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
const onMouseMove = (event) => {
|
|
636
|
-
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new MouseEvent('mousemove', event));
|
|
637
|
-
};
|
|
638
|
-
|
|
639
|
-
const onContextMenu = cfg.onContextMenu ? (event) => {
|
|
640
|
-
cfg.onContextMenu(event, this);
|
|
641
|
-
} : null;
|
|
642
|
-
|
|
643
|
-
const onMouseWheel = (event) => {
|
|
644
|
-
this.plugin.viewer.scene.canvas.canvas.dispatchEvent(new WheelEvent('wheel', event));
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
this._alpha = (("alpha" in cfg) && (cfg.alpha !== undefined)) ? cfg.alpha : 0.5;
|
|
648
|
-
this.color = cfg.color;
|
|
649
|
-
|
|
650
|
-
this._visible = true;
|
|
651
|
-
|
|
652
|
-
this._rebuildMesh();
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
_rebuildMesh() {
|
|
656
|
-
const scene = this.plugin.viewer.scene;
|
|
657
|
-
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
658
|
-
const downward = this._geometry.height < 0;
|
|
659
|
-
const altitude = this._geometry.altitude + (downward ? this._geometry.height : 0);
|
|
660
|
-
const height = this._geometry.height * (downward ? -1 : 1);
|
|
661
|
-
|
|
662
|
-
const [ baseVertices, baseTriangles ] = triangulateEarClipping(planeCoords); // TODO: prevent crossing edges
|
|
663
|
-
|
|
664
|
-
const pos = [ ];
|
|
665
|
-
const ind = [ ];
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const addPlane = (isCeiling) => {
|
|
669
|
-
const baseIdx = pos.length;
|
|
670
|
-
|
|
671
|
-
for (let c of baseVertices) {
|
|
672
|
-
pos.push([ c[0], altitude + (isCeiling ? height : 0), c[1] ]);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
for (let t of baseTriangles) {
|
|
676
|
-
ind.push(...(isCeiling ? t : t.slice(0).reverse()).map(i => i + baseIdx));
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
addPlane(false); // floor
|
|
680
|
-
addPlane(true); // ceiling
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
// sides
|
|
684
|
-
for (let i = 0; i < baseVertices.length; ++i) {
|
|
685
|
-
const a = baseVertices[i];
|
|
686
|
-
const b = baseVertices[(i+1) % baseVertices.length];
|
|
687
|
-
const f = altitude;
|
|
688
|
-
const c = altitude + height;
|
|
689
|
-
|
|
690
|
-
const baseIdx = pos.length;
|
|
691
|
-
|
|
692
|
-
pos.push(
|
|
693
|
-
[ a[0], f, a[1] ],
|
|
694
|
-
[ b[0], f, b[1] ],
|
|
695
|
-
[ b[0], c, b[1] ],
|
|
696
|
-
[ a[0], c, a[1] ]
|
|
697
|
-
);
|
|
698
|
-
|
|
699
|
-
ind.push(...[ 0, 1, 2, 0, 2, 3 ].map(i => i + baseIdx));
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
if (this._zoneMesh) {
|
|
704
|
-
this._zoneMesh.destroy();
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
const positions = [].concat(...pos);
|
|
709
|
-
this._zoneMesh = new Mesh(scene, {
|
|
710
|
-
edges: this._edges,
|
|
711
|
-
geometry: new ReadableGeometry(
|
|
712
|
-
scene,
|
|
713
|
-
{
|
|
714
|
-
positions: positions,
|
|
715
|
-
indices: ind,
|
|
716
|
-
normals: math.buildNormals(positions, ind)
|
|
717
|
-
}),
|
|
718
|
-
material: new PhongMaterial(scene, {
|
|
719
|
-
alpha: this._alpha,
|
|
720
|
-
backfaces: true,
|
|
721
|
-
diffuse: hex2rgb(this._color)
|
|
722
|
-
}),
|
|
723
|
-
visible: this._visible
|
|
724
|
-
});
|
|
725
|
-
this._zoneMesh.highlighted = this._highlighted;
|
|
726
|
-
|
|
727
|
-
this._zoneMesh.zone = this;
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
const min = idx => Math.min(...pos.map(p => p[idx]));
|
|
731
|
-
const max = idx => Math.max(...pos.map(p => p[idx]));
|
|
732
|
-
|
|
733
|
-
const xmin = min(0);
|
|
734
|
-
const ymin = min(1);
|
|
735
|
-
const zmin = min(2);
|
|
736
|
-
const xmax = max(0);
|
|
737
|
-
const ymax = max(1);
|
|
738
|
-
const zmax = max(2);
|
|
739
|
-
|
|
740
|
-
this._center = math.vec3([ (xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2 ]);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
sectionedAverage(sectionPlanes) {
|
|
744
|
-
const planeCoords = this._geometry.planeCoordinates.slice();
|
|
745
|
-
|
|
746
|
-
let faces = [ ];
|
|
747
|
-
{
|
|
748
|
-
const h = this._geometry.height;
|
|
749
|
-
const a = this._geometry.altitude;
|
|
750
|
-
const c = a + Math.max(0, h);
|
|
751
|
-
const f = a + Math.min(0, h);
|
|
752
|
-
|
|
753
|
-
const addPlane = (isCeiling) => {
|
|
754
|
-
const face = planeCoords.map(p => [ p[0], isCeiling ? c : f, p[1] ]);
|
|
755
|
-
faces.push(isCeiling ? face : face.slice(0).reverse());
|
|
756
|
-
};
|
|
757
|
-
addPlane(true); // ceiling
|
|
758
|
-
addPlane(false); // floor
|
|
759
|
-
|
|
760
|
-
// sides
|
|
761
|
-
const p = (idx, y) => [ planeCoords[idx][0], y, planeCoords[idx][1] ];
|
|
762
|
-
for (let i = 0; i < planeCoords.length; ++i)
|
|
763
|
-
{
|
|
764
|
-
const j = (i + 1) % planeCoords.length;
|
|
765
|
-
faces.push([ p(i, f), p(j, f), p(j, c), p(i, c) ]);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
for (const s of sectionPlanes)
|
|
770
|
-
{
|
|
771
|
-
const dir = s.dir;
|
|
772
|
-
const dist = s.dist;
|
|
773
|
-
const newFaces = [ ];
|
|
774
|
-
|
|
775
|
-
for (const face of faces)
|
|
776
|
-
{
|
|
777
|
-
const EPSILON = 1e-5;
|
|
778
|
-
const COPLANAR = 0;
|
|
779
|
-
const FRONT = 1;
|
|
780
|
-
const BACK = 2;
|
|
781
|
-
const SPANNING = 3;
|
|
782
|
-
|
|
783
|
-
// Classify each point as well as the entire polygon into one of the above four classes.
|
|
784
|
-
let polygonType = 0;
|
|
785
|
-
const types = [ ];
|
|
786
|
-
for (let i = 0; i < face.length; i++) {
|
|
787
|
-
const t = math.dotVec3(dir, face[i]) + dist;
|
|
788
|
-
const type = (t < -EPSILON) ? BACK : (t > EPSILON) ? FRONT : COPLANAR;
|
|
789
|
-
polygonType |= type;
|
|
790
|
-
types.push(type);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// Put the polygon in the correct list, splitting it when necessary.
|
|
794
|
-
switch (polygonType) {
|
|
795
|
-
case COPLANAR:
|
|
796
|
-
newFaces.push(face);
|
|
797
|
-
break;
|
|
798
|
-
case FRONT:
|
|
799
|
-
newFaces.push(face);
|
|
800
|
-
break;
|
|
801
|
-
case BACK:
|
|
802
|
-
break;
|
|
803
|
-
case SPANNING:
|
|
804
|
-
const f = [ ];
|
|
805
|
-
for (let i = 0; i < face.length; i++)
|
|
806
|
-
{
|
|
807
|
-
var j = (i + 1) % face.length;
|
|
808
|
-
const ti = types[i];
|
|
809
|
-
const tj = types[j];
|
|
810
|
-
const vi = face[i];
|
|
811
|
-
const vj = face[j];
|
|
812
|
-
if (ti !== BACK)
|
|
813
|
-
{
|
|
814
|
-
f.push(vi);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
if ((ti | tj) === SPANNING)
|
|
818
|
-
{
|
|
819
|
-
const diff = math.vec3();
|
|
820
|
-
math.subVec3(vj, vi, diff);
|
|
821
|
-
const t = - (dist + math.dotVec3(dir, vi)) / math.dotVec3(dir, diff);
|
|
822
|
-
const v = [0,0,0];
|
|
823
|
-
math.lerpVec3(t, 0, 1, vi, vj, v);
|
|
824
|
-
f.push(v);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
if (f.length >= 3)
|
|
828
|
-
{
|
|
829
|
-
newFaces.push(f);
|
|
830
|
-
}
|
|
831
|
-
break;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
faces = newFaces;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
if (faces.length === 0)
|
|
839
|
-
{
|
|
840
|
-
return null;
|
|
841
|
-
}
|
|
842
|
-
else
|
|
843
|
-
{
|
|
844
|
-
const avg = math.vec3([ 0, 0, 0 ]);
|
|
845
|
-
const unique = new Set();
|
|
846
|
-
|
|
847
|
-
for (const f of faces)
|
|
848
|
-
{
|
|
849
|
-
for (const p of f)
|
|
850
|
-
{
|
|
851
|
-
const id = p.map(x => x.toFixed(3)).join(":");
|
|
852
|
-
if (! (unique.has(id)))
|
|
853
|
-
{
|
|
854
|
-
unique.add(id);
|
|
855
|
-
math.addVec3(avg, p, avg);
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
math.mulVec3Scalar(avg, 1 / unique.size, avg);
|
|
861
|
-
|
|
862
|
-
return avg;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
get center() {
|
|
867
|
-
return this._center;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
get altitude() {
|
|
871
|
-
return this._geometry.altitude;
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
set altitude(value) {
|
|
875
|
-
this._geometry.altitude = value;
|
|
876
|
-
this._rebuildMesh();
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
get height() {
|
|
880
|
-
return this._geometry.height;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
set height(value) {
|
|
884
|
-
this._geometry.height = value;
|
|
885
|
-
this._rebuildMesh();
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
get highlighted() {
|
|
889
|
-
return this._highlighted;
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
set highlighted(value)
|
|
893
|
-
{
|
|
894
|
-
this._highlighted = value;
|
|
895
|
-
if (this._zoneMesh) {
|
|
896
|
-
this._zoneMesh.highlighted = value;
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
set color(value) {
|
|
901
|
-
this._color = value;
|
|
902
|
-
if (this._zoneMesh) {
|
|
903
|
-
this._zoneMesh.material.diffuse = hex2rgb(this._color);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
get color() {
|
|
908
|
-
return this._color;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
set alpha(value) {
|
|
912
|
-
this._alpha = value;
|
|
913
|
-
if (this._zoneMesh) {
|
|
914
|
-
this._zoneMesh.material.alpha = this._alpha;
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
get alpha() {
|
|
919
|
-
return this._alpha;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
get edges() {
|
|
923
|
-
return this._edges;
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
set edges(edges) {
|
|
927
|
-
this._edges = edges;
|
|
928
|
-
if (this._zoneMesh) {
|
|
929
|
-
this._zoneMesh.edges = this._edges;
|
|
930
|
-
}
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
/**
|
|
934
|
-
* Sets whether this Zone is visible or not.
|
|
935
|
-
*
|
|
936
|
-
* @type {Boolean}
|
|
937
|
-
*/
|
|
938
|
-
set visible(value) {
|
|
939
|
-
this._visible = !!value;
|
|
940
|
-
this._zoneMesh.visible = this._visible;
|
|
941
|
-
this._needUpdate();
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
/**
|
|
945
|
-
* Gets whether this Zone is visible or not.
|
|
946
|
-
*
|
|
947
|
-
* @type {Boolean}
|
|
948
|
-
*/
|
|
949
|
-
get visible() {
|
|
950
|
-
return this._visible;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
/**
|
|
954
|
-
* Gets this Zone as JSON.
|
|
955
|
-
*
|
|
956
|
-
* @returns {JSON}
|
|
957
|
-
*/
|
|
958
|
-
|
|
959
|
-
getJSON() {
|
|
960
|
-
return {
|
|
961
|
-
id: this.id,
|
|
962
|
-
geometry: this._geometry,
|
|
963
|
-
alpha: this._alpha,
|
|
964
|
-
color: this._color
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
duplicate() {
|
|
969
|
-
return this.plugin.createZone(
|
|
970
|
-
{
|
|
971
|
-
id: math.createUUID(),
|
|
972
|
-
geometry: {
|
|
973
|
-
planeCoordinates: this._geometry.planeCoordinates.map(c => c.slice()),
|
|
974
|
-
altitude: this._geometry.altitude,
|
|
975
|
-
height: this._geometry.height
|
|
976
|
-
},
|
|
977
|
-
alpha: this._alpha,
|
|
978
|
-
color: this._color
|
|
979
|
-
});
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
/**
|
|
983
|
-
* @private
|
|
984
|
-
*/
|
|
985
|
-
destroy() {
|
|
986
|
-
this._zoneMesh.destroy();
|
|
987
|
-
super.destroy();
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
/**
|
|
992
|
-
* Creates {@link Zone}s in a {@link ZonesPlugin} from mouse input.
|
|
993
|
-
*
|
|
994
|
-
* ## Usage
|
|
995
|
-
*
|
|
996
|
-
* [[Run example](/examples/measurement/#distance_createWithMouse_snapping)]
|
|
997
|
-
*
|
|
998
|
-
* ````javascript
|
|
999
|
-
* import {Viewer, XKTLoaderPlugin, ZonesPlugin, ZonesMouseControl} from "xeokit-sdk.es.js";
|
|
1000
|
-
*
|
|
1001
|
-
* const viewer = new Viewer({
|
|
1002
|
-
* canvasId: "myCanvas",
|
|
1003
|
-
* });
|
|
1004
|
-
*
|
|
1005
|
-
* viewer.camera.eye = [-3.93, 2.85, 27.01];
|
|
1006
|
-
* viewer.camera.look = [4.40, 3.72, 8.89];
|
|
1007
|
-
* viewer.camera.up = [-0.01, 0.99, 0.039];
|
|
1008
|
-
*
|
|
1009
|
-
* const xktLoader = new XKTLoaderPlugin(viewer);
|
|
1010
|
-
*
|
|
1011
|
-
* const sceneModel = xktLoader.load({
|
|
1012
|
-
* id: "myModel",
|
|
1013
|
-
* src: "Duplex.xkt"
|
|
1014
|
-
* });
|
|
1015
|
-
*
|
|
1016
|
-
* const zones = new ZonesPlugin(viewer);
|
|
1017
|
-
*
|
|
1018
|
-
* const zonesControl = new ZonesMouseControl(Zones)
|
|
1019
|
-
* ````
|
|
1020
|
-
*/
|
|
1021
|
-
class ZonesMouseControl extends Component {
|
|
1022
|
-
|
|
1023
|
-
/**
|
|
1024
|
-
* Creates a ZonesMouseControl bound to the given ZonesPlugin.
|
|
1025
|
-
*
|
|
1026
|
-
* @param {ZonesPlugin} zonesPlugin The ZonesPlugin to control.
|
|
1027
|
-
* @param [cfg] Configuration
|
|
1028
|
-
* @param {PointerLens} [cfg.pointerLens] A PointerLens to use to provide a magnified view of the cursor when snapping is enabled.
|
|
1029
|
-
*/
|
|
1030
|
-
constructor(zonesPlugin, cfg = {}) {
|
|
1031
|
-
super(zonesPlugin.viewer.scene);
|
|
1032
|
-
|
|
1033
|
-
this.zonesPlugin = zonesPlugin;
|
|
1034
|
-
this.pointerLens = cfg.pointerLens;
|
|
1035
|
-
this._deactivate = null;
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
get active() {
|
|
1039
|
-
return !! this._deactivate;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
1043
|
-
|
|
1044
|
-
if (this._deactivate) {
|
|
1045
|
-
return;
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
1049
|
-
const params = zoneAltitude;
|
|
1050
|
-
const param = (name, defaultValue) => {
|
|
1051
|
-
if (name in params) {
|
|
1052
|
-
return params[name];
|
|
1053
|
-
} else if (defaultValue !== undefined) {
|
|
1054
|
-
return defaultValue;
|
|
1055
|
-
} else {
|
|
1056
|
-
throw "config missing: " + name;
|
|
1057
|
-
}
|
|
1058
|
-
};
|
|
1059
|
-
|
|
1060
|
-
zoneAltitude = param("altitude");
|
|
1061
|
-
zoneHeight = param("height");
|
|
1062
|
-
zoneColor = param("color", "#008000");
|
|
1063
|
-
zoneAlpha = param("alpha", 0.5);
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
const zonesPlugin = this.zonesPlugin;
|
|
1067
|
-
const viewer = zonesPlugin.viewer;
|
|
1068
|
-
const scene = viewer.scene;
|
|
1069
|
-
const self = this;
|
|
1070
|
-
|
|
1071
|
-
const select3dPoint = mousePointSelector(
|
|
1072
|
-
viewer,
|
|
1073
|
-
function(origin, direction) {
|
|
1074
|
-
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
1075
|
-
});
|
|
1076
|
-
|
|
1077
|
-
(function rec() {
|
|
1078
|
-
self._deactivate = startAAZoneCreateUI(
|
|
1079
|
-
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
1080
|
-
zone => {
|
|
1081
|
-
let reactivate = true;
|
|
1082
|
-
self._deactivate = () => { reactivate = false; };
|
|
1083
|
-
self.fire("zoneEnd", zone);
|
|
1084
|
-
if (reactivate)
|
|
1085
|
-
{
|
|
1086
|
-
rec();
|
|
1087
|
-
}
|
|
1088
|
-
}).deactivate;
|
|
1089
|
-
})();
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
deactivate() {
|
|
1093
|
-
if (this._deactivate)
|
|
1094
|
-
{
|
|
1095
|
-
this._deactivate();
|
|
1096
|
-
this._deactivate = null;
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
/**
|
|
1101
|
-
* Destroys this ZonesMouseControl.
|
|
1102
|
-
*
|
|
1103
|
-
* Destroys any {@link Zone} under construction by this ZonesMouseControl.
|
|
1104
|
-
*/
|
|
1105
|
-
destroy() {
|
|
1106
|
-
this.deactivate();
|
|
1107
|
-
super.destroy();
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
/**
|
|
1112
|
-
* ZonesPlugin documentation to be added, mostly compatible with DistanceMeasurementsPlugin.
|
|
1113
|
-
*/
|
|
1114
|
-
class ZonesPlugin extends Plugin {
|
|
1115
|
-
|
|
1116
|
-
/**
|
|
1117
|
-
* @constructor
|
|
1118
|
-
* @param {Viewer} viewer The Viewer.
|
|
1119
|
-
* @param {Object} [cfg] Plugin configuration.
|
|
1120
|
-
* @param {String} [cfg.id="Zones"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
|
|
1121
|
-
* @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````.
|
|
1122
|
-
* @param {string} [cfg.defaultColor=#00BBFF] The default color of the length dots, wire and label.
|
|
1123
|
-
* @param {number} [cfg.zIndex] If set, the wires, dots and labels will have this zIndex (+1 for dots and +2 for labels).
|
|
1124
|
-
* @param {PointerCircle} [cfg.pointerLens] A PointerLens to help the user position the pointer. This can be shared with other plugins.
|
|
1125
|
-
*/
|
|
1126
|
-
constructor(viewer, cfg = {}) {
|
|
1127
|
-
|
|
1128
|
-
super("Zones", viewer);
|
|
1129
|
-
|
|
1130
|
-
this._pointerLens = cfg.pointerLens;
|
|
1131
|
-
|
|
1132
|
-
this._container = cfg.container || document.body;
|
|
1133
|
-
|
|
1134
|
-
this._zones = [ ];
|
|
1135
|
-
|
|
1136
|
-
this.defaultColor = cfg.defaultColor !== undefined ? cfg.defaultColor : "#00BBFF";
|
|
1137
|
-
this.zIndex = cfg.zIndex || 10000;
|
|
1138
|
-
|
|
1139
|
-
this._onMouseOver = (event, zone) => {
|
|
1140
|
-
this.fire("mouseOver", {
|
|
1141
|
-
plugin: this,
|
|
1142
|
-
zone,
|
|
1143
|
-
event
|
|
1144
|
-
});
|
|
1145
|
-
};
|
|
1146
|
-
|
|
1147
|
-
this._onMouseLeave = (event, zone) => {
|
|
1148
|
-
this.fire("mouseLeave", {
|
|
1149
|
-
plugin: this,
|
|
1150
|
-
zone,
|
|
1151
|
-
event
|
|
1152
|
-
});
|
|
1153
|
-
};
|
|
1154
|
-
|
|
1155
|
-
this._onContextMenu = (event, zone) => {
|
|
1156
|
-
this.fire("contextMenu", {
|
|
1157
|
-
plugin: this,
|
|
1158
|
-
zone,
|
|
1159
|
-
event
|
|
1160
|
-
});
|
|
1161
|
-
};
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
/**
|
|
1165
|
-
* Creates a {@link Zone}.
|
|
1166
|
-
*
|
|
1167
|
-
* The Zone is then registered by {@link Zone#id} in {@link ZonesPlugin#zones}.
|
|
1168
|
-
*
|
|
1169
|
-
* @param {Object} params {@link Zone} configuration.
|
|
1170
|
-
* @param {String} params.id Unique ID to assign to {@link Zone#id}. The Zone will be registered by this in {@link ZonesPlugin#zones} and {@link Scene.components}. Must be unique among all components in the {@link Viewer}.
|
|
1171
|
-
* @param {Number[]} params.origin.worldPos Origin World-space 3D position.
|
|
1172
|
-
* @param {Entity} params.origin.entity Origin Entity.
|
|
1173
|
-
* @param {Number[]} params.target.worldPos Target World-space 3D position.
|
|
1174
|
-
* @param {Entity} params.target.entity Target Entity.
|
|
1175
|
-
* @param {string} [params.color] The color of the length dot, wire and label.
|
|
1176
|
-
* @returns {Zone} The new {@link Zone}.
|
|
1177
|
-
*/
|
|
1178
|
-
createZone(params = {}) {
|
|
1179
|
-
if (this.viewer.scene.components[params.id]) {
|
|
1180
|
-
this.error("Viewer scene component with this ID already exists: " + params.id);
|
|
1181
|
-
delete params.id;
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
const zone = new Zone(this, {
|
|
1185
|
-
id: params.id,
|
|
1186
|
-
plugin: this,
|
|
1187
|
-
container: this._container,
|
|
1188
|
-
geometry: params.geometry,
|
|
1189
|
-
alpha: params.alpha,
|
|
1190
|
-
color: params.color,
|
|
1191
|
-
onMouseOver: this._onMouseOver,
|
|
1192
|
-
onMouseLeave: this._onMouseLeave,
|
|
1193
|
-
onContextMenu: this._onContextMenu
|
|
1194
|
-
});
|
|
1195
|
-
this._zones.push(zone);
|
|
1196
|
-
zone.on("destroyed", () => {
|
|
1197
|
-
const idx = this._zones.indexOf(zone);
|
|
1198
|
-
if (idx >= 0) {
|
|
1199
|
-
this._zones.splice(idx, 1);
|
|
1200
|
-
}
|
|
1201
|
-
});
|
|
1202
|
-
this.fire("zoneCreated", zone);
|
|
1203
|
-
return zone;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
/**
|
|
1207
|
-
* Gets the existing {@link Zone}s, each mapped to its {@link Zone#id}.
|
|
1208
|
-
*
|
|
1209
|
-
* @type {{String:Zone}}
|
|
1210
|
-
*/
|
|
1211
|
-
get zones() {
|
|
1212
|
-
return this._zones;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
/**
|
|
1216
|
-
* Destroys this ZonesPlugin.
|
|
1217
|
-
*
|
|
1218
|
-
* Destroys all {@link Zone}s first.
|
|
1219
|
-
*/
|
|
1220
|
-
destroy() {
|
|
1221
|
-
super.destroy();
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
import {PointerCircle} from "../../extras/PointerCircle/PointerCircle.js";
|
|
1226
|
-
|
|
1227
|
-
export class ZonesTouchControl extends Component {
|
|
1228
|
-
|
|
1229
|
-
constructor(zonesPlugin, cfg = {}) {
|
|
1230
|
-
super(zonesPlugin.viewer.scene);
|
|
1231
|
-
|
|
1232
|
-
this.zonesPlugin = zonesPlugin;
|
|
1233
|
-
this.pointerLens = cfg.pointerLens;
|
|
1234
|
-
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
1235
|
-
this._deactivate = null;
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
get active() {
|
|
1239
|
-
return !! this._deactivate;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
1243
|
-
|
|
1244
|
-
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
1245
|
-
const params = zoneAltitude;
|
|
1246
|
-
const param = (name, defaultValue) => {
|
|
1247
|
-
if (name in params) {
|
|
1248
|
-
return params[name];
|
|
1249
|
-
} else if (defaultValue !== undefined) {
|
|
1250
|
-
return defaultValue;
|
|
1251
|
-
} else {
|
|
1252
|
-
throw "config missing: " + name;
|
|
1253
|
-
}
|
|
1254
|
-
};
|
|
1255
|
-
|
|
1256
|
-
zoneAltitude = param("altitude");
|
|
1257
|
-
zoneHeight = param("height");
|
|
1258
|
-
zoneColor = param("color", "#008000");
|
|
1259
|
-
zoneAlpha = param("alpha", 0.5);
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
if (this._deactivate) {
|
|
1263
|
-
return;
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
const zonesPlugin = this.zonesPlugin;
|
|
1267
|
-
const viewer = zonesPlugin.viewer;
|
|
1268
|
-
const scene = viewer.scene;
|
|
1269
|
-
const self = this;
|
|
1270
|
-
|
|
1271
|
-
const select3dPoint = touchPointSelector(
|
|
1272
|
-
viewer,
|
|
1273
|
-
this.pointerCircle,
|
|
1274
|
-
function(origin, direction) {
|
|
1275
|
-
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
1276
|
-
});
|
|
1277
|
-
|
|
1278
|
-
(function rec() {
|
|
1279
|
-
self._deactivate = startAAZoneCreateUI(
|
|
1280
|
-
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
1281
|
-
zone => {
|
|
1282
|
-
let reactivate = true;
|
|
1283
|
-
self._deactivate = () => { reactivate = false; };
|
|
1284
|
-
self.fire("zoneEnd", zone);
|
|
1285
|
-
if (reactivate)
|
|
1286
|
-
{
|
|
1287
|
-
rec();
|
|
1288
|
-
}
|
|
1289
|
-
}).deactivate;
|
|
1290
|
-
})();
|
|
1291
|
-
}
|
|
1292
|
-
|
|
1293
|
-
deactivate() {
|
|
1294
|
-
if (this._deactivate)
|
|
1295
|
-
{
|
|
1296
|
-
this._deactivate();
|
|
1297
|
-
this._deactivate = null;
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
destroy() {
|
|
1302
|
-
this.deactivate();
|
|
1303
|
-
super.destroy();
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
const startPolysurfaceZoneCreateUI = function(scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, pointerLens, zonesPlugin, select3dPoint, onZoneCreated) {
|
|
1308
|
-
const updatePointerLens = (pointerLens
|
|
1309
|
-
? function(canvasPos) {
|
|
1310
|
-
pointerLens.visible = !! canvasPos;
|
|
1311
|
-
if (canvasPos)
|
|
1312
|
-
{
|
|
1313
|
-
pointerLens.canvasPos = canvasPos;
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
: () => { });
|
|
1317
|
-
|
|
1318
|
-
let deactivatePointSelection;
|
|
1319
|
-
const cleanups = [ () => updatePointerLens(null) ];
|
|
1320
|
-
|
|
1321
|
-
const basePolygon = basePolygon3D(scene, zoneColor, zoneAlpha);
|
|
1322
|
-
cleanups.push(() => basePolygon.destroy());
|
|
1323
|
-
|
|
1324
|
-
(function selectNextPoint(markers) {
|
|
1325
|
-
const marker = marker3D(scene, zoneColor);
|
|
1326
|
-
const wire = (markers.length > 0) && wire3D(scene, zoneColor, markers[markers.length - 1].getWorldPos());
|
|
1327
|
-
|
|
1328
|
-
cleanups.push(() => {
|
|
1329
|
-
marker.destroy();
|
|
1330
|
-
wire && wire.destroy();
|
|
1331
|
-
});
|
|
1332
|
-
|
|
1333
|
-
const firstMarker = (markers.length > 0) && markers[0];
|
|
1334
|
-
const getSnappedFirst = function(canvasPos) {
|
|
1335
|
-
const firstCanvasPos = firstMarker && firstMarker.getCanvasPos();
|
|
1336
|
-
const snapToFirst = firstCanvasPos && (math.distVec2(firstCanvasPos, canvasPos) < 10);
|
|
1337
|
-
return snapToFirst && { canvasPos: firstCanvasPos, worldPos: firstMarker.getWorldPos() };
|
|
1338
|
-
};
|
|
1339
|
-
|
|
1340
|
-
const lastSegmentIntersects = (function() {
|
|
1341
|
-
const onSegment = (p, q, r) => ((q[0] <= Math.max(p[0], r[0])) &&
|
|
1342
|
-
(q[0] >= Math.min(p[0], r[0])) &&
|
|
1343
|
-
(q[1] <= Math.max(p[1], r[1])) &&
|
|
1344
|
-
(q[1] >= Math.min(p[1], r[1])));
|
|
1345
|
-
|
|
1346
|
-
const orient = (p, q, r) => {
|
|
1347
|
-
const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
|
1348
|
-
// collinear
|
|
1349
|
-
// clockwise
|
|
1350
|
-
// counterclockwise
|
|
1351
|
-
return ((val === 0) ? 0 : ((val > 0) ? 1 : 2));
|
|
1352
|
-
};
|
|
1353
|
-
|
|
1354
|
-
return function(pos2D, excludeFirstSegment) {
|
|
1355
|
-
const a = pos2D[pos2D.length - 2];
|
|
1356
|
-
const b = pos2D[pos2D.length - 1];
|
|
1357
|
-
|
|
1358
|
-
for (let i = excludeFirstSegment ? 1 : 0; i < pos2D.length - 2 - 1; ++i)
|
|
1359
|
-
{
|
|
1360
|
-
const c = pos2D[i];
|
|
1361
|
-
const d = pos2D[i + 1];
|
|
1362
|
-
|
|
1363
|
-
const o1 = orient(a, b, c);
|
|
1364
|
-
const o2 = orient(a, b, d);
|
|
1365
|
-
const o3 = orient(c, d, a);
|
|
1366
|
-
const o4 = orient(c, d, b);
|
|
1367
|
-
|
|
1368
|
-
if (((o1 !== o2) && (o3 !== o4)) || // General case
|
|
1369
|
-
((o1 === 0) && onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
|
|
1370
|
-
((o2 === 0) && onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
|
|
1371
|
-
((o3 === 0) && onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
|
|
1372
|
-
((o4 === 0) && onSegment(c, b, d))) // c, d and b are collinear and b lies on segment cd
|
|
1373
|
-
{
|
|
1374
|
-
return true;
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
|
-
return false;
|
|
1379
|
-
};
|
|
1380
|
-
})();
|
|
1381
|
-
|
|
1382
|
-
deactivatePointSelection = select3dPoint(
|
|
1383
|
-
() => {
|
|
1384
|
-
updatePointerLens(null);
|
|
1385
|
-
marker.update(null);
|
|
1386
|
-
wire && wire.update(null);
|
|
1387
|
-
basePolygon.updateBase((markers.length > 2) ? markers.map(m => m.getWorldPos()) : null);
|
|
1388
|
-
},
|
|
1389
|
-
(canvasPos, worldPos) => {
|
|
1390
|
-
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
1391
|
-
firstMarker && firstMarker.setHighlighted(!! snappedFirst);
|
|
1392
|
-
updatePointerLens(snappedFirst ? snappedFirst.canvasPos : canvasPos);
|
|
1393
|
-
marker.update((! snappedFirst) && worldPos);
|
|
1394
|
-
wire && wire.update(snappedFirst ? snappedFirst.worldPos : worldPos);
|
|
1395
|
-
if ((markers.length >= 2))
|
|
1396
|
-
{
|
|
1397
|
-
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
1398
|
-
const inter = lastSegmentIntersects(pos.map(p => [ p[0], p[2] ]), snappedFirst);
|
|
1399
|
-
basePolygon.updateBase(inter ? null : pos);
|
|
1400
|
-
}
|
|
1401
|
-
else
|
|
1402
|
-
basePolygon.updateBase(null);
|
|
1403
|
-
},
|
|
1404
|
-
function(canvasPos, worldPos) {
|
|
1405
|
-
const snappedFirst = (markers.length > 2) && getSnappedFirst(canvasPos);
|
|
1406
|
-
const pos = markers.map(m => m.getWorldPos()).concat(snappedFirst ? [] : [worldPos]);
|
|
1407
|
-
basePolygon.updateBase(pos);
|
|
1408
|
-
const pos2D = pos.map(p => [ p[0], p[2] ]);
|
|
1409
|
-
if ((markers.length > 2) && lastSegmentIntersects(pos2D, snappedFirst))
|
|
1410
|
-
{
|
|
1411
|
-
cleanups.pop()();
|
|
1412
|
-
selectNextPoint(markers);
|
|
1413
|
-
}
|
|
1414
|
-
else if (snappedFirst)
|
|
1415
|
-
{
|
|
1416
|
-
// `marker2.update' makes sure marker's position has been updated from its default [0,0,0]
|
|
1417
|
-
// This works around an unidentified bug somewhere around OcclusionLayer, that causes error
|
|
1418
|
-
// [.WebGL-0x13400c47e00] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call
|
|
1419
|
-
marker.update(worldPos);
|
|
1420
|
-
|
|
1421
|
-
cleanups.forEach(c => c());
|
|
1422
|
-
onZoneCreated(
|
|
1423
|
-
zonesPlugin.createZone(
|
|
1424
|
-
{
|
|
1425
|
-
id: math.createUUID(),
|
|
1426
|
-
geometry: {
|
|
1427
|
-
planeCoordinates: pos2D,
|
|
1428
|
-
altitude: zoneAltitude,
|
|
1429
|
-
height: zoneHeight
|
|
1430
|
-
},
|
|
1431
|
-
alpha: zoneAlpha,
|
|
1432
|
-
color: zoneColor
|
|
1433
|
-
}));
|
|
1434
|
-
}
|
|
1435
|
-
else
|
|
1436
|
-
{
|
|
1437
|
-
marker.update(worldPos);
|
|
1438
|
-
wire && wire.update(worldPos);
|
|
1439
|
-
selectNextPoint(markers.concat(marker));
|
|
1440
|
-
}
|
|
1441
|
-
});
|
|
1442
|
-
})([ ], null);
|
|
1443
|
-
|
|
1444
|
-
return {
|
|
1445
|
-
closeSurface: function() {
|
|
1446
|
-
throw "TODO";
|
|
1447
|
-
},
|
|
1448
|
-
deactivate: function() {
|
|
1449
|
-
deactivatePointSelection();
|
|
1450
|
-
cleanups.forEach(c => c());
|
|
1451
|
-
}
|
|
1452
|
-
};
|
|
1453
|
-
};
|
|
1454
|
-
|
|
1455
|
-
export class ZonesPolysurfaceMouseControl extends Component {
|
|
1456
|
-
|
|
1457
|
-
constructor(zonesPlugin, cfg = {}) {
|
|
1458
|
-
super(zonesPlugin.viewer.scene);
|
|
1459
|
-
|
|
1460
|
-
this.zonesPlugin = zonesPlugin;
|
|
1461
|
-
this.pointerLens = cfg.pointerLens;
|
|
1462
|
-
this._action = null;
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
get active() {
|
|
1466
|
-
return !! this._action;
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
1470
|
-
|
|
1471
|
-
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
1472
|
-
const params = zoneAltitude;
|
|
1473
|
-
const param = (name, defaultValue) => {
|
|
1474
|
-
if (name in params) {
|
|
1475
|
-
return params[name];
|
|
1476
|
-
} else if (defaultValue !== undefined) {
|
|
1477
|
-
return defaultValue;
|
|
1478
|
-
} else {
|
|
1479
|
-
throw "config missing: " + name;
|
|
1480
|
-
}
|
|
1481
|
-
};
|
|
1482
|
-
|
|
1483
|
-
zoneAltitude = param("altitude");
|
|
1484
|
-
zoneHeight = param("height");
|
|
1485
|
-
zoneColor = param("color", "#008000");
|
|
1486
|
-
zoneAlpha = param("alpha", 0.5);
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
if (this._action) {
|
|
1490
|
-
return;
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
const zonesPlugin = this.zonesPlugin;
|
|
1494
|
-
const viewer = zonesPlugin.viewer;
|
|
1495
|
-
const scene = viewer.scene;
|
|
1496
|
-
const self = this;
|
|
1497
|
-
|
|
1498
|
-
const select3dPoint = mousePointSelector(
|
|
1499
|
-
viewer,
|
|
1500
|
-
function(origin, direction) {
|
|
1501
|
-
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
1502
|
-
});
|
|
1503
|
-
|
|
1504
|
-
(function rec() {
|
|
1505
|
-
self._action = startPolysurfaceZoneCreateUI(
|
|
1506
|
-
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
1507
|
-
zone => {
|
|
1508
|
-
let reactivate = true;
|
|
1509
|
-
self._action = { deactivate: () => { reactivate = false; } };
|
|
1510
|
-
self.fire("zoneEnd", zone);
|
|
1511
|
-
if (reactivate)
|
|
1512
|
-
{
|
|
1513
|
-
rec();
|
|
1514
|
-
}
|
|
1515
|
-
});
|
|
1516
|
-
})();
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
deactivate() {
|
|
1520
|
-
if (this._action)
|
|
1521
|
-
{
|
|
1522
|
-
this._action.deactivate();
|
|
1523
|
-
this._action = null;
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
destroy() {
|
|
1528
|
-
this.deactivate();
|
|
1529
|
-
super.destroy();
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
export class ZonesPolysurfaceTouchControl extends Component {
|
|
1534
|
-
|
|
1535
|
-
constructor(zonesPlugin, cfg = {}) {
|
|
1536
|
-
super(zonesPlugin.viewer.scene);
|
|
1537
|
-
|
|
1538
|
-
this.zonesPlugin = zonesPlugin;
|
|
1539
|
-
this.pointerLens = cfg.pointerLens;
|
|
1540
|
-
this.pointerCircle = new PointerCircle(zonesPlugin.viewer);
|
|
1541
|
-
this._action = null;
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
|
-
get active() {
|
|
1545
|
-
return !! this._action;
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
activate(zoneAltitude, zoneHeight, zoneColor, zoneAlpha) {
|
|
1549
|
-
|
|
1550
|
-
if (typeof(zoneAltitude) === "object" && (zoneAltitude !== null)) {
|
|
1551
|
-
const params = zoneAltitude;
|
|
1552
|
-
const param = (name, defaultValue) => {
|
|
1553
|
-
if (name in params) {
|
|
1554
|
-
return params[name];
|
|
1555
|
-
} else if (defaultValue !== undefined) {
|
|
1556
|
-
return defaultValue;
|
|
1557
|
-
} else {
|
|
1558
|
-
throw "config missing: " + name;
|
|
1559
|
-
}
|
|
1560
|
-
};
|
|
1561
|
-
|
|
1562
|
-
zoneAltitude = param("altitude");
|
|
1563
|
-
zoneHeight = param("height");
|
|
1564
|
-
zoneColor = param("color", "#008000");
|
|
1565
|
-
zoneAlpha = param("alpha", 0.5);
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
if (this._action) {
|
|
1569
|
-
return;
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
const zonesPlugin = this.zonesPlugin;
|
|
1573
|
-
const viewer = zonesPlugin.viewer;
|
|
1574
|
-
const scene = viewer.scene;
|
|
1575
|
-
const self = this;
|
|
1576
|
-
|
|
1577
|
-
const select3dPoint = touchPointSelector(
|
|
1578
|
-
viewer,
|
|
1579
|
-
this.pointerCircle,
|
|
1580
|
-
function(origin, direction) {
|
|
1581
|
-
return planeIntersect(zoneAltitude, math.vec3([ 0, 1, 0 ]), origin, direction);
|
|
1582
|
-
});
|
|
1583
|
-
|
|
1584
|
-
(function rec() {
|
|
1585
|
-
self._action = startPolysurfaceZoneCreateUI(
|
|
1586
|
-
scene, zoneAltitude, zoneHeight, zoneColor, zoneAlpha, self.pointerLens, zonesPlugin, select3dPoint,
|
|
1587
|
-
zone => {
|
|
1588
|
-
let reactivate = true;
|
|
1589
|
-
self._action = { deactivate: () => { reactivate = false; } };
|
|
1590
|
-
self.fire("zoneEnd", zone);
|
|
1591
|
-
if (reactivate)
|
|
1592
|
-
{
|
|
1593
|
-
rec();
|
|
1594
|
-
}
|
|
1595
|
-
});
|
|
1596
|
-
})();
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
deactivate() {
|
|
1600
|
-
if (this._action)
|
|
1601
|
-
{
|
|
1602
|
-
this._action.deactivate();
|
|
1603
|
-
this._action = null;
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
destroy() {
|
|
1608
|
-
this.deactivate();
|
|
1609
|
-
super.destroy();
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
|
-
export class ZoneEditControl extends Component {
|
|
1614
|
-
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
1615
|
-
const viewer = zone.plugin.viewer;
|
|
1616
|
-
const scene = viewer.scene;
|
|
1617
|
-
super(scene);
|
|
1618
|
-
|
|
1619
|
-
const altitude = zone._geometry.altitude;
|
|
1620
|
-
|
|
1621
|
-
const dots = zone._geometry.planeCoordinates.map(planeCoord => {
|
|
1622
|
-
const dotParent = scene.canvas.canvas.ownerDocument.body;
|
|
1623
|
-
const dot = new Dot3D(scene, {}, dotParent, { fillColor: zone._color });
|
|
1624
|
-
dot.worldPos = math.vec3([ planeCoord[0], altitude, planeCoord[1] ]);
|
|
1625
|
-
dot.on("worldPos", function() {
|
|
1626
|
-
planeCoord[0] = dot.worldPos[0];
|
|
1627
|
-
planeCoord[1] = dot.worldPos[2];
|
|
1628
|
-
try {
|
|
1629
|
-
zone._rebuildMesh();
|
|
1630
|
-
} catch (e) {
|
|
1631
|
-
if (zone._zoneMesh) {
|
|
1632
|
-
zone._zoneMesh.destroy();
|
|
1633
|
-
zone._zoneMesh = null;
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
});
|
|
1637
|
-
return dot;
|
|
1638
|
-
});
|
|
1639
|
-
|
|
1640
|
-
const cleanupDrag = activateDraggableDots({
|
|
1641
|
-
viewer: viewer,
|
|
1642
|
-
handleMouseEvents: handleMouseEvents,
|
|
1643
|
-
handleTouchEvents: handleTouchEvents,
|
|
1644
|
-
pointerLens: cfg && cfg.pointerLens,
|
|
1645
|
-
dots: dots,
|
|
1646
|
-
ray2WorldPos: (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir),
|
|
1647
|
-
onEnd: (initPos, dot) => {
|
|
1648
|
-
if (zone._zoneMesh)
|
|
1649
|
-
{
|
|
1650
|
-
this.fire("edited");
|
|
1651
|
-
}
|
|
1652
|
-
return !! zone._zoneMesh;
|
|
1653
|
-
}
|
|
1654
|
-
});
|
|
1655
|
-
|
|
1656
|
-
const cleanup = function() {
|
|
1657
|
-
cleanupDrag();
|
|
1658
|
-
dots.forEach(d => d.destroy());
|
|
1659
|
-
};
|
|
1660
|
-
|
|
1661
|
-
const destroyCb = zone.on("destroyed", cleanup);
|
|
1662
|
-
|
|
1663
|
-
this._deactivate = function() {
|
|
1664
|
-
zone.off("destroyed", destroyCb);
|
|
1665
|
-
cleanup();
|
|
1666
|
-
};
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
deactivate() {
|
|
1670
|
-
this._deactivate();
|
|
1671
|
-
super.destroy();
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
export class ZoneEditMouseControl extends ZoneEditControl {
|
|
1676
|
-
constructor(zone, cfg) {
|
|
1677
|
-
super(zone, cfg, true, false);
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
export class ZoneEditTouchControl extends ZoneEditControl {
|
|
1682
|
-
constructor(zone, cfg) {
|
|
1683
|
-
super(zone, cfg, false, true);
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
export class ZoneTranslateControl extends Component {
|
|
1689
|
-
constructor(zone, cfg, handleMouseEvents, handleTouchEvents) {
|
|
1690
|
-
const viewer = zone.plugin.viewer;
|
|
1691
|
-
const scene = viewer.scene;
|
|
1692
|
-
const canvas = scene.canvas.canvas;
|
|
1693
|
-
|
|
1694
|
-
super(scene);
|
|
1695
|
-
const self = this;
|
|
1696
|
-
|
|
1697
|
-
const altitude = zone._geometry.altitude;
|
|
1698
|
-
const pointerLens = cfg && cfg.pointerLens;
|
|
1699
|
-
const updatePointerLens = (pointerLens
|
|
1700
|
-
? function(canvasPos) {
|
|
1701
|
-
pointerLens.visible = !! canvasPos;
|
|
1702
|
-
if (canvasPos)
|
|
1703
|
-
{
|
|
1704
|
-
pointerLens.canvasPos = canvasPos;
|
|
1705
|
-
}
|
|
1706
|
-
}
|
|
1707
|
-
: () => { });
|
|
1708
|
-
|
|
1709
|
-
const ray2WorldPos = (orig, dir) => planeIntersect(altitude, math.vec3([ 0, 1, 0 ]), orig, dir);
|
|
1710
|
-
|
|
1711
|
-
const pickWorldPos = canvasPos => {
|
|
1712
|
-
const origin = math.vec3();
|
|
1713
|
-
const direction = math.vec3();
|
|
1714
|
-
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, origin, direction);
|
|
1715
|
-
return ray2WorldPos(origin, direction);
|
|
1716
|
-
};
|
|
1717
|
-
|
|
1718
|
-
const copyCanvasPos = (event, vec2) => {
|
|
1719
|
-
vec2[0] = event.clientX;
|
|
1720
|
-
vec2[1] = event.clientY;
|
|
1721
|
-
transformToNode(canvas.ownerDocument.body, canvas, vec2);
|
|
1722
|
-
return vec2;
|
|
1723
|
-
};
|
|
1724
|
-
|
|
1725
|
-
const canvasHandle = function(type, cb) {
|
|
1726
|
-
const callback = event => {
|
|
1727
|
-
event.preventDefault();
|
|
1728
|
-
cb(event);
|
|
1729
|
-
};
|
|
1730
|
-
canvas.addEventListener(type, callback);
|
|
1731
|
-
return () => canvas.removeEventListener(type, callback);
|
|
1732
|
-
};
|
|
1733
|
-
|
|
1734
|
-
let cleanupCurrentDrag = () => { };
|
|
1735
|
-
|
|
1736
|
-
const startDrag = function(event, onMoveType, onEndType, matchesEvent) {
|
|
1737
|
-
const e = matchesEvent(event);
|
|
1738
|
-
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
1739
|
-
const pickRecord = viewer.scene.pick({ canvasPos: canvasPos, includeEntities: [ zone._zoneMesh.id ] });
|
|
1740
|
-
const pickZone = pickRecord && pickRecord.entity && pickRecord.entity.zone;
|
|
1741
|
-
|
|
1742
|
-
if (pickZone === zone)
|
|
1743
|
-
{
|
|
1744
|
-
cleanupCurrentDrag();
|
|
1745
|
-
|
|
1746
|
-
canvas.style.cursor = "move";
|
|
1747
|
-
viewer.cameraControl.active = false;
|
|
1748
|
-
|
|
1749
|
-
const onChange = (function() {
|
|
1750
|
-
const initCoords = zone._geometry.planeCoordinates.map(c => c.slice());
|
|
1751
|
-
const initWorldPos = pickWorldPos(canvasPos);
|
|
1752
|
-
const initDragCoord = math.vec2([ initWorldPos[0], initWorldPos[2] ]);
|
|
1753
|
-
const dPos = math.vec2();
|
|
1754
|
-
|
|
1755
|
-
return function(canvasPos) {
|
|
1756
|
-
const worldPos = pickWorldPos(canvasPos);
|
|
1757
|
-
dPos[0] = worldPos[0];
|
|
1758
|
-
dPos[1] = worldPos[2];
|
|
1759
|
-
math.subVec2(initDragCoord, dPos, dPos);
|
|
1760
|
-
|
|
1761
|
-
zone._geometry.planeCoordinates.forEach((planeCoord, idx) => {
|
|
1762
|
-
math.subVec2(initCoords[idx], dPos, planeCoord);
|
|
1763
|
-
});
|
|
1764
|
-
|
|
1765
|
-
try {
|
|
1766
|
-
zone._rebuildMesh();
|
|
1767
|
-
} catch (e) {
|
|
1768
|
-
if (zone._zoneMesh) {
|
|
1769
|
-
zone._zoneMesh.destroy();
|
|
1770
|
-
zone._zoneMesh = null;
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
};
|
|
1774
|
-
})();
|
|
1775
|
-
|
|
1776
|
-
const cleanupMove = canvasHandle(
|
|
1777
|
-
onMoveType,
|
|
1778
|
-
function(event) {
|
|
1779
|
-
const e = matchesEvent(event);
|
|
1780
|
-
if (e)
|
|
1781
|
-
{
|
|
1782
|
-
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
1783
|
-
onChange(canvasPos);
|
|
1784
|
-
updatePointerLens(canvasPos);
|
|
1785
|
-
}
|
|
1786
|
-
});
|
|
1787
|
-
|
|
1788
|
-
const cleanupEnd = canvasHandle(
|
|
1789
|
-
onEndType,
|
|
1790
|
-
function(event) {
|
|
1791
|
-
const e = matchesEvent(event);
|
|
1792
|
-
if (e)
|
|
1793
|
-
{
|
|
1794
|
-
const canvasPos = copyCanvasPos(e, math.vec2());
|
|
1795
|
-
onChange(canvasPos);
|
|
1796
|
-
updatePointerLens(null);
|
|
1797
|
-
cleanupCurrentDrag();
|
|
1798
|
-
self.fire("translated");
|
|
1799
|
-
}
|
|
1800
|
-
});
|
|
1801
|
-
|
|
1802
|
-
cleanupCurrentDrag = function() {
|
|
1803
|
-
cleanupCurrentDrag = () => { };
|
|
1804
|
-
canvas.style.cursor = "default";
|
|
1805
|
-
viewer.cameraControl.active = true;
|
|
1806
|
-
cleanupMove();
|
|
1807
|
-
cleanupEnd();
|
|
1808
|
-
};
|
|
1809
|
-
}
|
|
1810
|
-
};
|
|
1811
|
-
|
|
1812
|
-
const startDragCbs = [ ];
|
|
1813
|
-
|
|
1814
|
-
if (handleMouseEvents) {
|
|
1815
|
-
startDragCbs.push(
|
|
1816
|
-
canvasHandle("mousedown", event => {
|
|
1817
|
-
if (event.which === 1) {
|
|
1818
|
-
startDrag(
|
|
1819
|
-
event,
|
|
1820
|
-
"mousemove",
|
|
1821
|
-
"mouseup",
|
|
1822
|
-
event => (event.which === 1) && event);
|
|
1823
|
-
}
|
|
1824
|
-
}));
|
|
1825
|
-
}
|
|
1826
|
-
|
|
1827
|
-
if (handleTouchEvents) {
|
|
1828
|
-
startDragCbs.push(
|
|
1829
|
-
canvasHandle("touchstart", event => {
|
|
1830
|
-
if (event.touches.length === 1) {
|
|
1831
|
-
const touchStartId = event.touches[0].identifier;
|
|
1832
|
-
startDrag(
|
|
1833
|
-
event,
|
|
1834
|
-
"touchmove",
|
|
1835
|
-
"touchend",
|
|
1836
|
-
event => [...event.changedTouches].find(e => e.identifier === touchStartId));
|
|
1837
|
-
}
|
|
1838
|
-
}));
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
const cleanup = function() {
|
|
1842
|
-
cleanupCurrentDrag();
|
|
1843
|
-
startDragCbs.forEach(cb => cb());
|
|
1844
|
-
updatePointerLens(null);
|
|
1845
|
-
};
|
|
1846
|
-
|
|
1847
|
-
const destroyCb = zone.on("destroyed", cleanup);
|
|
1848
|
-
|
|
1849
|
-
this._deactivate = function() {
|
|
1850
|
-
zone.off("destroyed", destroyCb);
|
|
1851
|
-
cleanup();
|
|
1852
|
-
};
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
deactivate() {
|
|
1856
|
-
this._deactivate();
|
|
1857
|
-
super.destroy();
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
export class ZoneTranslateMouseControl extends ZoneTranslateControl {
|
|
1862
|
-
constructor(zone, cfg) {
|
|
1863
|
-
super(zone, cfg, true, false);
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
export class ZoneTranslateTouchControl extends ZoneTranslateControl {
|
|
1868
|
-
constructor(zone, cfg) {
|
|
1869
|
-
super(zone, cfg, false, true);
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
export {ZonesMouseControl}
|
|
1875
|
-
export {ZonesPlugin}
|
|
1
|
+
export * from "./ZonesPlugin.js";
|