3dtiles-inspector 0.2.2 → 0.2.3
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/CHANGELOG.md +6 -0
- package/README.md +6 -5
- package/dist/inspector-assets/viewer/app.js +764 -71
- package/package.json +1 -1
- package/src/server/viewerHtml.js +111 -2
- package/src/viewer/app.js +1 -1
- package/src/viewer/screenSelection/cropController.js +418 -6
- package/src/viewer/screenSelection/editOverlay.js +348 -0
- package/src/viewer/screenSelection/geometry.js +66 -52
- package/src/viewer/screenSelection/index.js +61 -0
- package/src/viewer/screenSelection/pointerTracker.js +19 -11
|
@@ -67954,6 +67954,15 @@ function clientPointToNdc(point, domRect) {
|
|
|
67954
67954
|
y: 1 - (point.y - domRect.top) / domRect.height * 2
|
|
67955
67955
|
};
|
|
67956
67956
|
}
|
|
67957
|
+
function getClientSelectionQuad(start, end) {
|
|
67958
|
+
const clientRect = getClientSelectionRect(start, end);
|
|
67959
|
+
return [
|
|
67960
|
+
new Vector2(clientRect.minX, clientRect.minY),
|
|
67961
|
+
new Vector2(clientRect.maxX, clientRect.minY),
|
|
67962
|
+
new Vector2(clientRect.maxX, clientRect.maxY),
|
|
67963
|
+
new Vector2(clientRect.minX, clientRect.maxY)
|
|
67964
|
+
];
|
|
67965
|
+
}
|
|
67957
67966
|
function getNdcSelectionRect(clientRect, domRect) {
|
|
67958
67967
|
const topLeft = clientPointToNdc(
|
|
67959
67968
|
new Vector2(clientRect.minX, clientRect.minY),
|
|
@@ -67970,6 +67979,19 @@ function getNdcSelectionRect(clientRect, domRect) {
|
|
|
67970
67979
|
maxY: Math.max(topLeft.y, bottomRight.y)
|
|
67971
67980
|
};
|
|
67972
67981
|
}
|
|
67982
|
+
function getNdcSelectionQuad(clientPoints, domRect) {
|
|
67983
|
+
return clientPoints.map((point) => clientPointToNdc(point, domRect));
|
|
67984
|
+
}
|
|
67985
|
+
function getNdcBounds(points) {
|
|
67986
|
+
const xs2 = points.map((point) => point.x);
|
|
67987
|
+
const ys2 = points.map((point) => point.y);
|
|
67988
|
+
return {
|
|
67989
|
+
maxX: Math.max(...xs2),
|
|
67990
|
+
maxY: Math.max(...ys2),
|
|
67991
|
+
minX: Math.min(...xs2),
|
|
67992
|
+
minY: Math.min(...ys2)
|
|
67993
|
+
};
|
|
67994
|
+
}
|
|
67973
67995
|
function updateOverlayRect(overlayEl, rectEl, clientRect) {
|
|
67974
67996
|
if (!overlayEl || !rectEl) {
|
|
67975
67997
|
return;
|
|
@@ -68151,10 +68173,10 @@ function createFarPlaneData({
|
|
|
68151
68173
|
width
|
|
68152
68174
|
};
|
|
68153
68175
|
}
|
|
68154
|
-
function
|
|
68176
|
+
function createFrustumDataFromQuad(camera, quad, depthRange) {
|
|
68155
68177
|
const { farDepth, nearDepth } = normalizeDepthRange(camera, depthRange);
|
|
68156
|
-
const centerX = (
|
|
68157
|
-
const centerY = (
|
|
68178
|
+
const centerX = quad.reduce((total, point) => total + point.x, 0) / quad.length;
|
|
68179
|
+
const centerY = quad.reduce((total, point) => total + point.y, 0) / quad.length;
|
|
68158
68180
|
const nearCenter = createPointAtViewDepth(
|
|
68159
68181
|
camera,
|
|
68160
68182
|
centerX,
|
|
@@ -68181,55 +68203,13 @@ function createFrustumData(camera, rect, depthRange) {
|
|
|
68181
68203
|
const insidePoint = selectionForward.clone().multiplyScalar((nearDistance + farDistance) * 0.5).add(camera.position);
|
|
68182
68204
|
plane.setFromNormalAndCoplanarPoint(selectionForward, farCenter);
|
|
68183
68205
|
const farClipPlane = plane.clone();
|
|
68184
|
-
const farTopLeft =
|
|
68185
|
-
camera,
|
|
68186
|
-
rect.minX,
|
|
68187
|
-
rect.maxY,
|
|
68188
|
-
farClipPlane
|
|
68189
|
-
);
|
|
68190
|
-
const farTopRight = createPointOnPlane(
|
|
68191
|
-
camera,
|
|
68192
|
-
rect.maxX,
|
|
68193
|
-
rect.maxY,
|
|
68194
|
-
farClipPlane
|
|
68195
|
-
);
|
|
68196
|
-
const farBottomRight = createPointOnPlane(
|
|
68197
|
-
camera,
|
|
68198
|
-
rect.maxX,
|
|
68199
|
-
rect.minY,
|
|
68200
|
-
farClipPlane
|
|
68201
|
-
);
|
|
68202
|
-
const farBottomLeft = createPointOnPlane(
|
|
68203
|
-
camera,
|
|
68204
|
-
rect.minX,
|
|
68205
|
-
rect.minY,
|
|
68206
|
-
farClipPlane
|
|
68206
|
+
const [farTopLeft, farTopRight, farBottomRight, farBottomLeft] = quad.map(
|
|
68207
|
+
(point) => createPointOnPlane(camera, point.x, point.y, farClipPlane)
|
|
68207
68208
|
);
|
|
68208
68209
|
plane.setFromNormalAndCoplanarPoint(selectionForward, nearCenter);
|
|
68209
68210
|
const nearPlane = plane.clone();
|
|
68210
|
-
const nearTopLeft =
|
|
68211
|
-
camera,
|
|
68212
|
-
rect.minX,
|
|
68213
|
-
rect.maxY,
|
|
68214
|
-
nearPlane
|
|
68215
|
-
);
|
|
68216
|
-
const nearTopRight = createPointOnPlane(
|
|
68217
|
-
camera,
|
|
68218
|
-
rect.maxX,
|
|
68219
|
-
rect.maxY,
|
|
68220
|
-
nearPlane
|
|
68221
|
-
);
|
|
68222
|
-
const nearBottomRight = createPointOnPlane(
|
|
68223
|
-
camera,
|
|
68224
|
-
rect.maxX,
|
|
68225
|
-
rect.minY,
|
|
68226
|
-
nearPlane
|
|
68227
|
-
);
|
|
68228
|
-
const nearBottomLeft = createPointOnPlane(
|
|
68229
|
-
camera,
|
|
68230
|
-
rect.minX,
|
|
68231
|
-
rect.minY,
|
|
68232
|
-
nearPlane
|
|
68211
|
+
const [nearTopLeft, nearTopRight, nearBottomRight, nearBottomLeft] = quad.map(
|
|
68212
|
+
(point) => createPointOnPlane(camera, point.x, point.y, nearPlane)
|
|
68233
68213
|
);
|
|
68234
68214
|
if (!farTopLeft || !farTopRight || !farBottomRight || !farBottomLeft || !nearTopLeft || !nearTopRight || !nearBottomRight || !nearBottomLeft) {
|
|
68235
68215
|
return null;
|
|
@@ -68306,8 +68286,21 @@ function createFrustumData(camera, rect, depthRange) {
|
|
|
68306
68286
|
selectionForward: selectionForward.toArray()
|
|
68307
68287
|
};
|
|
68308
68288
|
}
|
|
68289
|
+
function createFrustumData(camera, rect, depthRange) {
|
|
68290
|
+
return createFrustumDataFromQuad(
|
|
68291
|
+
camera,
|
|
68292
|
+
[
|
|
68293
|
+
{ x: rect.minX, y: rect.maxY },
|
|
68294
|
+
{ x: rect.maxX, y: rect.maxY },
|
|
68295
|
+
{ x: rect.maxX, y: rect.minY },
|
|
68296
|
+
{ x: rect.minX, y: rect.minY }
|
|
68297
|
+
],
|
|
68298
|
+
depthRange
|
|
68299
|
+
);
|
|
68300
|
+
}
|
|
68309
68301
|
function createSelectionData({
|
|
68310
68302
|
camera,
|
|
68303
|
+
clientPoints,
|
|
68311
68304
|
domElement,
|
|
68312
68305
|
end,
|
|
68313
68306
|
getDepthRange,
|
|
@@ -68317,19 +68310,27 @@ function createSelectionData({
|
|
|
68317
68310
|
if (domRect.width <= 0 || domRect.height <= 0) {
|
|
68318
68311
|
return null;
|
|
68319
68312
|
}
|
|
68320
|
-
const
|
|
68313
|
+
const hasClientQuad = Array.isArray(clientPoints) && clientPoints.length === 4;
|
|
68314
|
+
const points = hasClientQuad ? clientPoints : getClientSelectionQuad(start, end);
|
|
68315
|
+
const clientRect = {
|
|
68316
|
+
maxX: Math.max(...points.map((point) => point.x)),
|
|
68317
|
+
maxY: Math.max(...points.map((point) => point.y)),
|
|
68318
|
+
minX: Math.min(...points.map((point) => point.x)),
|
|
68319
|
+
minY: Math.min(...points.map((point) => point.y))
|
|
68320
|
+
};
|
|
68321
68321
|
const width = clientRect.maxX - clientRect.minX;
|
|
68322
68322
|
const height = clientRect.maxY - clientRect.minY;
|
|
68323
68323
|
if (width * width + height * height < SCREEN_SELECTION_MIN_DRAG_DISTANCE_SQ) {
|
|
68324
68324
|
return null;
|
|
68325
68325
|
}
|
|
68326
|
-
const
|
|
68326
|
+
const quad = getNdcSelectionQuad(points, domRect);
|
|
68327
|
+
const rect = hasClientQuad ? getNdcBounds(quad) : getNdcSelectionRect(clientRect, domRect);
|
|
68327
68328
|
camera.updateProjectionMatrix();
|
|
68328
68329
|
camera.updateMatrixWorld(true);
|
|
68329
68330
|
cameraPosition.copy(camera.position);
|
|
68330
68331
|
const depthRange = normalizeDepthRange(camera, getDepthRange());
|
|
68331
68332
|
const viewProjectionMatrix = new Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse).toArray();
|
|
68332
|
-
const frustum = createFrustumData(camera, rect, depthRange);
|
|
68333
|
+
const frustum = hasClientQuad ? createFrustumDataFromQuad(camera, quad, depthRange) : createFrustumData(camera, rect, depthRange);
|
|
68333
68334
|
if (!frustum) {
|
|
68334
68335
|
return null;
|
|
68335
68336
|
}
|
|
@@ -68687,6 +68688,8 @@ function createScreenSelectionPointerTracker({
|
|
|
68687
68688
|
camera,
|
|
68688
68689
|
domElement,
|
|
68689
68690
|
getDepthRange,
|
|
68691
|
+
onOverlayClear,
|
|
68692
|
+
onOverlayUpdate,
|
|
68690
68693
|
onSelectionCreated,
|
|
68691
68694
|
overlayEl,
|
|
68692
68695
|
rectEl
|
|
@@ -68695,8 +68698,18 @@ function createScreenSelectionPointerTracker({
|
|
|
68695
68698
|
let drag = null;
|
|
68696
68699
|
function clearDrag() {
|
|
68697
68700
|
drag = null;
|
|
68701
|
+
onOverlayClear?.();
|
|
68698
68702
|
clearOverlay(overlayEl, rectEl);
|
|
68699
68703
|
}
|
|
68704
|
+
function updateDragOverlay() {
|
|
68705
|
+
const clientRect = {
|
|
68706
|
+
...getClientSelectionRect(drag.start, drag.current)
|
|
68707
|
+
};
|
|
68708
|
+
if (onOverlayUpdate?.(clientRect) === true) {
|
|
68709
|
+
return;
|
|
68710
|
+
}
|
|
68711
|
+
updateOverlayRect(overlayEl, rectEl, clientRect);
|
|
68712
|
+
}
|
|
68700
68713
|
function setActive(nextActive) {
|
|
68701
68714
|
active = !!nextActive;
|
|
68702
68715
|
if (!active) {
|
|
@@ -68715,11 +68728,7 @@ function createScreenSelectionPointerTracker({
|
|
|
68715
68728
|
start: dragStart.clone(),
|
|
68716
68729
|
current: dragCurrent.clone()
|
|
68717
68730
|
};
|
|
68718
|
-
|
|
68719
|
-
overlayEl,
|
|
68720
|
-
rectEl,
|
|
68721
|
-
getClientSelectionRect(drag.start, drag.current)
|
|
68722
|
-
);
|
|
68731
|
+
updateDragOverlay();
|
|
68723
68732
|
domElement.setPointerCapture?.(event.pointerId);
|
|
68724
68733
|
event.preventDefault();
|
|
68725
68734
|
event.stopPropagation();
|
|
@@ -68731,11 +68740,7 @@ function createScreenSelectionPointerTracker({
|
|
|
68731
68740
|
}
|
|
68732
68741
|
const domRect = domElement.getBoundingClientRect();
|
|
68733
68742
|
getClampedClientPoint(event, domRect, drag.current);
|
|
68734
|
-
|
|
68735
|
-
overlayEl,
|
|
68736
|
-
rectEl,
|
|
68737
|
-
getClientSelectionRect(drag.start, drag.current)
|
|
68738
|
-
);
|
|
68743
|
+
updateDragOverlay();
|
|
68739
68744
|
event.preventDefault();
|
|
68740
68745
|
event.stopPropagation();
|
|
68741
68746
|
return true;
|
|
@@ -68744,6 +68749,9 @@ function createScreenSelectionPointerTracker({
|
|
|
68744
68749
|
if (!active || !drag || event.pointerId !== drag.pointerId) {
|
|
68745
68750
|
return false;
|
|
68746
68751
|
}
|
|
68752
|
+
const clientRect = {
|
|
68753
|
+
...getClientSelectionRect(drag.start, drag.current)
|
|
68754
|
+
};
|
|
68747
68755
|
const selection = createSelectionData({
|
|
68748
68756
|
camera,
|
|
68749
68757
|
domElement,
|
|
@@ -68753,7 +68761,7 @@ function createScreenSelectionPointerTracker({
|
|
|
68753
68761
|
});
|
|
68754
68762
|
domElement.releasePointerCapture?.(event.pointerId);
|
|
68755
68763
|
clearDrag();
|
|
68756
|
-
onSelectionCreated(selection);
|
|
68764
|
+
onSelectionCreated(selection, clientRect);
|
|
68757
68765
|
event.preventDefault();
|
|
68758
68766
|
event.stopPropagation();
|
|
68759
68767
|
return true;
|
|
@@ -68832,6 +68840,56 @@ function getScreenSelectionPayload(selection) {
|
|
|
68832
68840
|
viewProjectionMatrix: selection.viewProjectionMatrix.slice()
|
|
68833
68841
|
};
|
|
68834
68842
|
}
|
|
68843
|
+
function setScreenSelectionShape(selection, {
|
|
68844
|
+
cameraPosition: sourceCameraPosition,
|
|
68845
|
+
depthRange,
|
|
68846
|
+
farPlane,
|
|
68847
|
+
planeMatrices,
|
|
68848
|
+
rect,
|
|
68849
|
+
selectionForward: sourceSelectionForward,
|
|
68850
|
+
viewProjectionMatrix
|
|
68851
|
+
}, currentTransformMatrix) {
|
|
68852
|
+
if (!selection) {
|
|
68853
|
+
return;
|
|
68854
|
+
}
|
|
68855
|
+
const previousFarDepth = Number(selection.depthRange?.farDepth);
|
|
68856
|
+
const copiedPlaneMatrices = planeMatrices.map((matrix) => matrix.slice());
|
|
68857
|
+
const referenceTransformMatrix = copyMatrix4Array(currentTransformMatrix);
|
|
68858
|
+
selection.basePlaneMatrices = copiedPlaneMatrices.map(
|
|
68859
|
+
(matrix) => matrix.slice()
|
|
68860
|
+
);
|
|
68861
|
+
selection.cameraPosition = copyVectorArray(sourceCameraPosition);
|
|
68862
|
+
selection.currentTransformMatrix = referenceTransformMatrix.slice();
|
|
68863
|
+
selection.depthRange = copyDepthRange(depthRange);
|
|
68864
|
+
selection.farPlane = copyFarPlane(farPlane);
|
|
68865
|
+
selection.planeMatrices = copiedPlaneMatrices;
|
|
68866
|
+
selection.referenceTransformMatrix = referenceTransformMatrix;
|
|
68867
|
+
selection.rect = copyRect(rect);
|
|
68868
|
+
selection.selectionForward = copyVectorArray(sourceSelectionForward, [
|
|
68869
|
+
0,
|
|
68870
|
+
0,
|
|
68871
|
+
-1
|
|
68872
|
+
]);
|
|
68873
|
+
selection.viewProjectionMatrix = viewProjectionMatrix.slice();
|
|
68874
|
+
updateScreenSelectionWorldState(selection, currentTransformMatrix);
|
|
68875
|
+
if (!Number.isFinite(previousFarDepth)) {
|
|
68876
|
+
return;
|
|
68877
|
+
}
|
|
68878
|
+
const nextFarDepth = Math.min(
|
|
68879
|
+
selection.depthRange.maxFarDepth,
|
|
68880
|
+
Math.max(
|
|
68881
|
+
selection.depthRange.nearDepth + SCREEN_SELECTION_MIN_DEPTH_RANGE,
|
|
68882
|
+
previousFarDepth
|
|
68883
|
+
)
|
|
68884
|
+
);
|
|
68885
|
+
if (Math.abs(nextFarDepth - selection.depthRange.farDepth) > 1e-9) {
|
|
68886
|
+
setScreenSelectionFarDepth(
|
|
68887
|
+
selection,
|
|
68888
|
+
nextFarDepth,
|
|
68889
|
+
currentTransformMatrix
|
|
68890
|
+
);
|
|
68891
|
+
}
|
|
68892
|
+
}
|
|
68835
68893
|
function updateScreenSelectionWorldState(selection, currentTransformMatrix, active = selection?.farHandle?.visible) {
|
|
68836
68894
|
if (!selection) {
|
|
68837
68895
|
return;
|
|
@@ -68876,6 +68934,313 @@ var init_screenSelection = __esm({
|
|
|
68876
68934
|
}
|
|
68877
68935
|
});
|
|
68878
68936
|
|
|
68937
|
+
// src/viewer/screenSelection/editOverlay.js
|
|
68938
|
+
function clampValue(value, min, max) {
|
|
68939
|
+
return Math.min(max, Math.max(min, value));
|
|
68940
|
+
}
|
|
68941
|
+
function copyClientPoint(point) {
|
|
68942
|
+
return {
|
|
68943
|
+
x: Number(point?.x) || 0,
|
|
68944
|
+
y: Number(point?.y) || 0
|
|
68945
|
+
};
|
|
68946
|
+
}
|
|
68947
|
+
function copyClientPoints(points) {
|
|
68948
|
+
return points.map(copyClientPoint);
|
|
68949
|
+
}
|
|
68950
|
+
function getClientPointsBounds(points) {
|
|
68951
|
+
const xs2 = points.map((point) => point.x);
|
|
68952
|
+
const ys2 = points.map((point) => point.y);
|
|
68953
|
+
return {
|
|
68954
|
+
maxX: Math.max(...xs2),
|
|
68955
|
+
maxY: Math.max(...ys2),
|
|
68956
|
+
minX: Math.min(...xs2),
|
|
68957
|
+
minY: Math.min(...ys2)
|
|
68958
|
+
};
|
|
68959
|
+
}
|
|
68960
|
+
function getClientRectPoints(rect) {
|
|
68961
|
+
return [
|
|
68962
|
+
{ x: Number(rect?.minX) || 0, y: Number(rect?.minY) || 0 },
|
|
68963
|
+
{ x: Number(rect?.maxX) || 0, y: Number(rect?.minY) || 0 },
|
|
68964
|
+
{ x: Number(rect?.maxX) || 0, y: Number(rect?.maxY) || 0 },
|
|
68965
|
+
{ x: Number(rect?.minX) || 0, y: Number(rect?.maxY) || 0 }
|
|
68966
|
+
];
|
|
68967
|
+
}
|
|
68968
|
+
function clampClientPoint(point, domRect) {
|
|
68969
|
+
return {
|
|
68970
|
+
x: clampValue(point.x, domRect.left, domRect.right),
|
|
68971
|
+
y: clampValue(point.y, domRect.top, domRect.bottom)
|
|
68972
|
+
};
|
|
68973
|
+
}
|
|
68974
|
+
function clampClientPoints(points, domElement) {
|
|
68975
|
+
const domRect = domElement.getBoundingClientRect();
|
|
68976
|
+
return points.map((point) => clampClientPoint(point, domRect));
|
|
68977
|
+
}
|
|
68978
|
+
function getPointTurnCross(a2, b5, c2) {
|
|
68979
|
+
return (b5.x - a2.x) * (c2.y - b5.y) - (b5.y - a2.y) * (c2.x - b5.x);
|
|
68980
|
+
}
|
|
68981
|
+
function isConvexClientQuad(points) {
|
|
68982
|
+
if (!Array.isArray(points) || points.length !== 4) {
|
|
68983
|
+
return false;
|
|
68984
|
+
}
|
|
68985
|
+
let turnSign = 0;
|
|
68986
|
+
for (let index = 0; index < points.length; index++) {
|
|
68987
|
+
const cross = getPointTurnCross(
|
|
68988
|
+
points[index],
|
|
68989
|
+
points[(index + 1) % points.length],
|
|
68990
|
+
points[(index + 2) % points.length]
|
|
68991
|
+
);
|
|
68992
|
+
if (Math.abs(cross) <= SCREEN_EDIT_MIN_CONVEX_CROSS_ABS) {
|
|
68993
|
+
return false;
|
|
68994
|
+
}
|
|
68995
|
+
const nextSign = Math.sign(cross);
|
|
68996
|
+
if (turnSign === 0) {
|
|
68997
|
+
turnSign = nextSign;
|
|
68998
|
+
} else if (nextSign !== turnSign) {
|
|
68999
|
+
return false;
|
|
69000
|
+
}
|
|
69001
|
+
}
|
|
69002
|
+
return true;
|
|
69003
|
+
}
|
|
69004
|
+
function getPartPoint(points, part) {
|
|
69005
|
+
const indices = SCREEN_EDIT_PART_POINT_INDICES[part] || [];
|
|
69006
|
+
if (indices.length === 0) {
|
|
69007
|
+
return { x: 0, y: 0 };
|
|
69008
|
+
}
|
|
69009
|
+
const x5 = indices.reduce((total, index) => total + points[index].x, 0) / indices.length;
|
|
69010
|
+
const y6 = indices.reduce((total, index) => total + points[index].y, 0) / indices.length;
|
|
69011
|
+
return { x: x5, y: y6 };
|
|
69012
|
+
}
|
|
69013
|
+
function getPartAngle(points, part) {
|
|
69014
|
+
const indices = SCREEN_EDIT_PART_POINT_INDICES[part] || [];
|
|
69015
|
+
if (indices.length !== 2) {
|
|
69016
|
+
return null;
|
|
69017
|
+
}
|
|
69018
|
+
const start = points[indices[0]];
|
|
69019
|
+
const end = points[indices[1]];
|
|
69020
|
+
return Math.atan2(end.y - start.y, end.x - start.x);
|
|
69021
|
+
}
|
|
69022
|
+
function getPartLength(points, part) {
|
|
69023
|
+
const indices = SCREEN_EDIT_PART_POINT_INDICES[part] || [];
|
|
69024
|
+
if (indices.length !== 2) {
|
|
69025
|
+
return null;
|
|
69026
|
+
}
|
|
69027
|
+
const start = points[indices[0]];
|
|
69028
|
+
const end = points[indices[1]];
|
|
69029
|
+
return Math.hypot(end.x - start.x, end.y - start.y);
|
|
69030
|
+
}
|
|
69031
|
+
function interpolatePoint(a2, b5, t2) {
|
|
69032
|
+
return {
|
|
69033
|
+
x: a2.x + (b5.x - a2.x) * t2,
|
|
69034
|
+
y: a2.y + (b5.y - a2.y) * t2
|
|
69035
|
+
};
|
|
69036
|
+
}
|
|
69037
|
+
function updateScreenEditGrid(grid, localPoints, visible) {
|
|
69038
|
+
if (!grid) {
|
|
69039
|
+
return;
|
|
69040
|
+
}
|
|
69041
|
+
grid.replaceChildren();
|
|
69042
|
+
grid.hidden = !visible;
|
|
69043
|
+
if (!visible) {
|
|
69044
|
+
return;
|
|
69045
|
+
}
|
|
69046
|
+
const [topLeft, topRight, bottomRight, bottomLeft] = localPoints;
|
|
69047
|
+
for (let index = 1; index < SCREEN_EDIT_GRID_DIVISIONS; index++) {
|
|
69048
|
+
const t2 = index / SCREEN_EDIT_GRID_DIVISIONS;
|
|
69049
|
+
const top = interpolatePoint(topLeft, topRight, t2);
|
|
69050
|
+
const bottom = interpolatePoint(bottomLeft, bottomRight, t2);
|
|
69051
|
+
const left = interpolatePoint(topLeft, bottomLeft, t2);
|
|
69052
|
+
const right = interpolatePoint(topRight, bottomRight, t2);
|
|
69053
|
+
const verticalLine = document.createElementNS(
|
|
69054
|
+
"http://www.w3.org/2000/svg",
|
|
69055
|
+
"line"
|
|
69056
|
+
);
|
|
69057
|
+
const horizontalLine = document.createElementNS(
|
|
69058
|
+
"http://www.w3.org/2000/svg",
|
|
69059
|
+
"line"
|
|
69060
|
+
);
|
|
69061
|
+
verticalLine.setAttribute("x1", String(top.x));
|
|
69062
|
+
verticalLine.setAttribute("y1", String(top.y));
|
|
69063
|
+
verticalLine.setAttribute("x2", String(bottom.x));
|
|
69064
|
+
verticalLine.setAttribute("y2", String(bottom.y));
|
|
69065
|
+
horizontalLine.setAttribute("x1", String(left.x));
|
|
69066
|
+
horizontalLine.setAttribute("y1", String(left.y));
|
|
69067
|
+
horizontalLine.setAttribute("x2", String(right.x));
|
|
69068
|
+
horizontalLine.setAttribute("y2", String(right.y));
|
|
69069
|
+
grid.append(verticalLine, horizontalLine);
|
|
69070
|
+
}
|
|
69071
|
+
}
|
|
69072
|
+
function ensureEditableRectHandles(rectEl) {
|
|
69073
|
+
if (!rectEl || rectEl.dataset.editHandlesReady === "true") {
|
|
69074
|
+
return;
|
|
69075
|
+
}
|
|
69076
|
+
const svg2 = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
69077
|
+
const polygon = document.createElementNS(
|
|
69078
|
+
"http://www.w3.org/2000/svg",
|
|
69079
|
+
"polygon"
|
|
69080
|
+
);
|
|
69081
|
+
const grid = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
69082
|
+
svg2.classList.add("screen-selection-edit-svg");
|
|
69083
|
+
grid.classList.add("screen-selection-edit-grid");
|
|
69084
|
+
polygon.classList.add("screen-selection-edit-polygon");
|
|
69085
|
+
svg2.append(polygon, grid);
|
|
69086
|
+
rectEl.appendChild(svg2);
|
|
69087
|
+
SCREEN_EDIT_HANDLE_PARTS.forEach((part) => {
|
|
69088
|
+
const handle = document.createElement("span");
|
|
69089
|
+
handle.classList.add(
|
|
69090
|
+
"screen-selection-edit-handle",
|
|
69091
|
+
`screen-selection-edit-${part}`
|
|
69092
|
+
);
|
|
69093
|
+
handle.dataset.editPart = part;
|
|
69094
|
+
rectEl.appendChild(handle);
|
|
69095
|
+
});
|
|
69096
|
+
rectEl.dataset.editHandlesReady = "true";
|
|
69097
|
+
}
|
|
69098
|
+
function pointSegmentDistanceSq(point, start, end) {
|
|
69099
|
+
const dx = end.x - start.x;
|
|
69100
|
+
const dy = end.y - start.y;
|
|
69101
|
+
const lengthSq = dx * dx + dy * dy;
|
|
69102
|
+
if (lengthSq <= 1e-12) {
|
|
69103
|
+
const px2 = point.x - start.x;
|
|
69104
|
+
const py2 = point.y - start.y;
|
|
69105
|
+
return px2 * px2 + py2 * py2;
|
|
69106
|
+
}
|
|
69107
|
+
const t2 = clampValue(
|
|
69108
|
+
((point.x - start.x) * dx + (point.y - start.y) * dy) / lengthSq,
|
|
69109
|
+
0,
|
|
69110
|
+
1
|
|
69111
|
+
);
|
|
69112
|
+
const x5 = start.x + dx * t2;
|
|
69113
|
+
const y6 = start.y + dy * t2;
|
|
69114
|
+
const px = point.x - x5;
|
|
69115
|
+
const py = point.y - y6;
|
|
69116
|
+
return px * px + py * py;
|
|
69117
|
+
}
|
|
69118
|
+
function createScreenEditOverlay({ overlayEl, rectEl }) {
|
|
69119
|
+
let activePart = null;
|
|
69120
|
+
function applyActivePart() {
|
|
69121
|
+
SCREEN_EDIT_HANDLE_PARTS.forEach((part) => {
|
|
69122
|
+
const handle = rectEl?.querySelector(`[data-edit-part="${part}"]`);
|
|
69123
|
+
handle?.classList.toggle("active", part === activePart);
|
|
69124
|
+
});
|
|
69125
|
+
}
|
|
69126
|
+
function render(clientPoints, { showGrid = false } = {}) {
|
|
69127
|
+
ensureEditableRectHandles(rectEl);
|
|
69128
|
+
rectEl?.classList.add("editable");
|
|
69129
|
+
rectEl?.classList.toggle("drawing", showGrid);
|
|
69130
|
+
const bounds = getClientPointsBounds(clientPoints);
|
|
69131
|
+
updateOverlayRect(overlayEl, rectEl, bounds);
|
|
69132
|
+
const width = Math.max(1, bounds.maxX - bounds.minX);
|
|
69133
|
+
const height = Math.max(1, bounds.maxY - bounds.minY);
|
|
69134
|
+
const localPoints = clientPoints.map((point) => ({
|
|
69135
|
+
x: point.x - bounds.minX,
|
|
69136
|
+
y: point.y - bounds.minY
|
|
69137
|
+
}));
|
|
69138
|
+
const svg2 = rectEl?.querySelector(".screen-selection-edit-svg");
|
|
69139
|
+
const polygon = rectEl?.querySelector(".screen-selection-edit-polygon");
|
|
69140
|
+
const grid = rectEl?.querySelector(".screen-selection-edit-grid");
|
|
69141
|
+
svg2?.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
69142
|
+
polygon?.setAttribute(
|
|
69143
|
+
"points",
|
|
69144
|
+
localPoints.map((point) => `${point.x},${point.y}`).join(" ")
|
|
69145
|
+
);
|
|
69146
|
+
updateScreenEditGrid(grid, localPoints, showGrid);
|
|
69147
|
+
SCREEN_EDIT_HANDLE_PARTS.forEach((part) => {
|
|
69148
|
+
const point = getPartPoint(localPoints, part);
|
|
69149
|
+
const handle = rectEl?.querySelector(`[data-edit-part="${part}"]`);
|
|
69150
|
+
if (!handle) {
|
|
69151
|
+
return;
|
|
69152
|
+
}
|
|
69153
|
+
handle.style.left = `${point.x}px`;
|
|
69154
|
+
handle.style.top = `${point.y}px`;
|
|
69155
|
+
const angle = getPartAngle(localPoints, part);
|
|
69156
|
+
const length = getPartLength(localPoints, part);
|
|
69157
|
+
if (length != null) {
|
|
69158
|
+
const maxVisualLength = Math.max(0, length - 2);
|
|
69159
|
+
const visualLength = Math.max(
|
|
69160
|
+
0,
|
|
69161
|
+
Math.min(SCREEN_EDIT_EDGE_HANDLE_MAX_LENGTH, maxVisualLength)
|
|
69162
|
+
);
|
|
69163
|
+
const activeScaleX = visualLength > 0 ? Math.min(
|
|
69164
|
+
SCREEN_EDIT_EDGE_HANDLE_ACTIVE_SCALE_X,
|
|
69165
|
+
Math.max(1, maxVisualLength / visualLength)
|
|
69166
|
+
) : 1;
|
|
69167
|
+
handle.style.width = `${visualLength}px`;
|
|
69168
|
+
handle.style.height = `${length <= SCREEN_EDIT_EDGE_HANDLE_MIN_LENGTH ? 2 : 4}px`;
|
|
69169
|
+
handle.style.setProperty(
|
|
69170
|
+
"--screen-selection-edit-active-scale-x",
|
|
69171
|
+
String(activeScaleX)
|
|
69172
|
+
);
|
|
69173
|
+
handle.style.setProperty(
|
|
69174
|
+
"--screen-selection-edit-active-scale-y",
|
|
69175
|
+
String(SCREEN_EDIT_EDGE_HANDLE_ACTIVE_SCALE_Y)
|
|
69176
|
+
);
|
|
69177
|
+
} else {
|
|
69178
|
+
handle.style.width = "";
|
|
69179
|
+
handle.style.height = "";
|
|
69180
|
+
handle.style.removeProperty("--screen-selection-edit-active-scale-x");
|
|
69181
|
+
handle.style.removeProperty("--screen-selection-edit-active-scale-y");
|
|
69182
|
+
}
|
|
69183
|
+
handle.style.transform = angle == null ? "translate(-50%, -50%)" : `translate(-50%, -50%) rotate(${angle}rad)`;
|
|
69184
|
+
});
|
|
69185
|
+
applyActivePart();
|
|
69186
|
+
}
|
|
69187
|
+
function clear() {
|
|
69188
|
+
activePart = null;
|
|
69189
|
+
rectEl?.classList.remove("drawing", "editable");
|
|
69190
|
+
applyActivePart();
|
|
69191
|
+
}
|
|
69192
|
+
function setActivePart(part) {
|
|
69193
|
+
activePart = SCREEN_EDIT_HANDLE_PARTS.includes(part) ? part : null;
|
|
69194
|
+
applyActivePart();
|
|
69195
|
+
}
|
|
69196
|
+
return {
|
|
69197
|
+
clear,
|
|
69198
|
+
render,
|
|
69199
|
+
setActivePart
|
|
69200
|
+
};
|
|
69201
|
+
}
|
|
69202
|
+
var SCREEN_EDIT_EDGE_HIT_SIZE, SCREEN_EDIT_CORNER_HIT_SIZE, SCREEN_EDIT_EDGE_HANDLE_MAX_LENGTH, SCREEN_EDIT_EDGE_HANDLE_MIN_LENGTH, SCREEN_EDIT_EDGE_HANDLE_ACTIVE_SCALE_X, SCREEN_EDIT_EDGE_HANDLE_ACTIVE_SCALE_Y, SCREEN_EDIT_GRID_DIVISIONS, SCREEN_EDIT_MIN_CONVEX_CROSS_ABS, SCREEN_EDIT_HANDLE_PARTS, SCREEN_EDIT_CORNER_PARTS, SCREEN_EDIT_EDGE_PARTS, SCREEN_EDIT_PART_POINT_INDICES;
|
|
69203
|
+
var init_editOverlay = __esm({
|
|
69204
|
+
"src/viewer/screenSelection/editOverlay.js"() {
|
|
69205
|
+
init_geometry();
|
|
69206
|
+
SCREEN_EDIT_EDGE_HIT_SIZE = 8;
|
|
69207
|
+
SCREEN_EDIT_CORNER_HIT_SIZE = 16;
|
|
69208
|
+
SCREEN_EDIT_EDGE_HANDLE_MAX_LENGTH = 26;
|
|
69209
|
+
SCREEN_EDIT_EDGE_HANDLE_MIN_LENGTH = 6;
|
|
69210
|
+
SCREEN_EDIT_EDGE_HANDLE_ACTIVE_SCALE_X = 1.5;
|
|
69211
|
+
SCREEN_EDIT_EDGE_HANDLE_ACTIVE_SCALE_Y = 1.5;
|
|
69212
|
+
SCREEN_EDIT_GRID_DIVISIONS = 8;
|
|
69213
|
+
SCREEN_EDIT_MIN_CONVEX_CROSS_ABS = 1e-3;
|
|
69214
|
+
SCREEN_EDIT_HANDLE_PARTS = [
|
|
69215
|
+
"top-left",
|
|
69216
|
+
"top",
|
|
69217
|
+
"top-right",
|
|
69218
|
+
"right",
|
|
69219
|
+
"bottom-right",
|
|
69220
|
+
"bottom",
|
|
69221
|
+
"bottom-left",
|
|
69222
|
+
"left"
|
|
69223
|
+
];
|
|
69224
|
+
SCREEN_EDIT_CORNER_PARTS = [
|
|
69225
|
+
"top-left",
|
|
69226
|
+
"top-right",
|
|
69227
|
+
"bottom-right",
|
|
69228
|
+
"bottom-left"
|
|
69229
|
+
];
|
|
69230
|
+
SCREEN_EDIT_EDGE_PARTS = ["top", "right", "bottom", "left"];
|
|
69231
|
+
SCREEN_EDIT_PART_POINT_INDICES = {
|
|
69232
|
+
"bottom-left": [3],
|
|
69233
|
+
"bottom-right": [2],
|
|
69234
|
+
bottom: [2, 3],
|
|
69235
|
+
left: [3, 0],
|
|
69236
|
+
right: [1, 2],
|
|
69237
|
+
top: [0, 1],
|
|
69238
|
+
"top-left": [0],
|
|
69239
|
+
"top-right": [1]
|
|
69240
|
+
};
|
|
69241
|
+
}
|
|
69242
|
+
});
|
|
69243
|
+
|
|
68879
69244
|
// src/viewer/dom/cropUi.js
|
|
68880
69245
|
function updateCropControls({
|
|
68881
69246
|
activeScreenSelectionId,
|
|
@@ -68993,9 +69358,13 @@ function createCropController({
|
|
|
68993
69358
|
let nextSelectionId = 1;
|
|
68994
69359
|
let activeSelectionId = null;
|
|
68995
69360
|
let pendingMode = false;
|
|
69361
|
+
let pendingScreenEdit = null;
|
|
69362
|
+
let pendingEditDrag = null;
|
|
69363
|
+
let editCursor = "";
|
|
68996
69364
|
let hasGaussianSplats = false;
|
|
68997
69365
|
const sphere = new Sphere();
|
|
68998
69366
|
const cameraForward2 = new Vector3();
|
|
69367
|
+
const screenEditOverlay = createScreenEditOverlay({ overlayEl, rectEl });
|
|
68999
69368
|
function getActiveSelection() {
|
|
69000
69369
|
if (activeSelectionId == null) {
|
|
69001
69370
|
return null;
|
|
@@ -69011,6 +69380,115 @@ function createCropController({
|
|
|
69011
69380
|
}))
|
|
69012
69381
|
];
|
|
69013
69382
|
}
|
|
69383
|
+
function setEditCursor(cursor) {
|
|
69384
|
+
const nextCursor = cursor || "";
|
|
69385
|
+
if (editCursor === nextCursor) {
|
|
69386
|
+
return;
|
|
69387
|
+
}
|
|
69388
|
+
domElement.style.cursor = nextCursor;
|
|
69389
|
+
editCursor = nextCursor;
|
|
69390
|
+
}
|
|
69391
|
+
function clearEditCursor() {
|
|
69392
|
+
setEditCursor("");
|
|
69393
|
+
}
|
|
69394
|
+
function getActivePendingEdit() {
|
|
69395
|
+
if (!pendingScreenEdit || activeSelectionId !== pendingScreenEdit.selectionId) {
|
|
69396
|
+
return null;
|
|
69397
|
+
}
|
|
69398
|
+
const match = pendingSelections.find(
|
|
69399
|
+
(selection) => selection.id === pendingScreenEdit.selectionId
|
|
69400
|
+
);
|
|
69401
|
+
return match ? pendingScreenEdit : null;
|
|
69402
|
+
}
|
|
69403
|
+
function clearScreenEditOverlay() {
|
|
69404
|
+
screenEditOverlay.clear();
|
|
69405
|
+
clearEditCursor();
|
|
69406
|
+
}
|
|
69407
|
+
function syncPendingEditOverlay() {
|
|
69408
|
+
const edit = getActivePendingEdit();
|
|
69409
|
+
if (!edit) {
|
|
69410
|
+
clearScreenEditOverlay();
|
|
69411
|
+
if (!pendingMode) {
|
|
69412
|
+
clearOverlay(overlayEl, rectEl);
|
|
69413
|
+
}
|
|
69414
|
+
return;
|
|
69415
|
+
}
|
|
69416
|
+
screenEditOverlay.render(edit.clientPoints, { showGrid: false });
|
|
69417
|
+
}
|
|
69418
|
+
function createCameraPoseSnapshot() {
|
|
69419
|
+
camera.updateMatrixWorld(true);
|
|
69420
|
+
return {
|
|
69421
|
+
position: camera.position.toArray(),
|
|
69422
|
+
projectionMatrix: camera.projectionMatrix.toArray(),
|
|
69423
|
+
quaternion: camera.quaternion.toArray()
|
|
69424
|
+
};
|
|
69425
|
+
}
|
|
69426
|
+
function projectionChanged(source, target) {
|
|
69427
|
+
if (!Array.isArray(source) || !Array.isArray(target)) {
|
|
69428
|
+
return true;
|
|
69429
|
+
}
|
|
69430
|
+
return source.some(
|
|
69431
|
+
(value, index) => Math.abs(value - target[index]) > CAMERA_PROJECTION_EPSILON
|
|
69432
|
+
);
|
|
69433
|
+
}
|
|
69434
|
+
function cameraPoseChanged(cameraPose) {
|
|
69435
|
+
if (!cameraPose) {
|
|
69436
|
+
return true;
|
|
69437
|
+
}
|
|
69438
|
+
camera.updateMatrixWorld(true);
|
|
69439
|
+
const dx = camera.position.x - cameraPose.position[0];
|
|
69440
|
+
const dy = camera.position.y - cameraPose.position[1];
|
|
69441
|
+
const dz = camera.position.z - cameraPose.position[2];
|
|
69442
|
+
if (dx * dx + dy * dy + dz * dz > CAMERA_POSITION_EPSILON_SQ) {
|
|
69443
|
+
return true;
|
|
69444
|
+
}
|
|
69445
|
+
const quaternion = cameraPose.quaternion;
|
|
69446
|
+
const quaternionDot = Math.abs(
|
|
69447
|
+
camera.quaternion.x * quaternion[0] + camera.quaternion.y * quaternion[1] + camera.quaternion.z * quaternion[2] + camera.quaternion.w * quaternion[3]
|
|
69448
|
+
);
|
|
69449
|
+
if (1 - Math.min(1, quaternionDot) > CAMERA_QUATERNION_EPSILON) {
|
|
69450
|
+
return true;
|
|
69451
|
+
}
|
|
69452
|
+
return projectionChanged(
|
|
69453
|
+
camera.projectionMatrix.toArray(),
|
|
69454
|
+
cameraPose.projectionMatrix
|
|
69455
|
+
);
|
|
69456
|
+
}
|
|
69457
|
+
function clearPendingScreenEdit() {
|
|
69458
|
+
pendingScreenEdit = null;
|
|
69459
|
+
pendingEditDrag = null;
|
|
69460
|
+
syncPendingEditOverlay();
|
|
69461
|
+
}
|
|
69462
|
+
function freezePendingScreenEdit(showStatus = false) {
|
|
69463
|
+
const hadEdit = !!pendingScreenEdit;
|
|
69464
|
+
if (!hadEdit) {
|
|
69465
|
+
return false;
|
|
69466
|
+
}
|
|
69467
|
+
clearPendingScreenEdit();
|
|
69468
|
+
if (showStatus) {
|
|
69469
|
+
setStatus(
|
|
69470
|
+
"Screen selection shape fixed after camera movement. Drag the 3D far plane, then Confirm or Cancel."
|
|
69471
|
+
);
|
|
69472
|
+
}
|
|
69473
|
+
return true;
|
|
69474
|
+
}
|
|
69475
|
+
function freezePendingScreenEditIfCameraChanged() {
|
|
69476
|
+
if (!pendingScreenEdit || pendingEditDrag) {
|
|
69477
|
+
return false;
|
|
69478
|
+
}
|
|
69479
|
+
if (!cameraPoseChanged(pendingScreenEdit.cameraPose)) {
|
|
69480
|
+
return false;
|
|
69481
|
+
}
|
|
69482
|
+
return freezePendingScreenEdit(true);
|
|
69483
|
+
}
|
|
69484
|
+
function createPendingScreenEdit(selection, clientRect) {
|
|
69485
|
+
pendingScreenEdit = {
|
|
69486
|
+
cameraPose: createCameraPoseSnapshot(),
|
|
69487
|
+
clientPoints: clampClientPoints(getClientRectPoints(clientRect), domElement),
|
|
69488
|
+
selectionId: selection.id
|
|
69489
|
+
};
|
|
69490
|
+
syncPendingEditOverlay();
|
|
69491
|
+
}
|
|
69014
69492
|
function syncWorldState() {
|
|
69015
69493
|
const transform = getCurrentRootTransformArray();
|
|
69016
69494
|
getEntries().forEach(({ selection }) => {
|
|
@@ -69090,10 +69568,171 @@ function createCropController({
|
|
|
69090
69568
|
camera,
|
|
69091
69569
|
domElement,
|
|
69092
69570
|
getDepthRange,
|
|
69571
|
+
onOverlayClear: clearScreenEditOverlay,
|
|
69572
|
+
onOverlayUpdate: (clientRect) => {
|
|
69573
|
+
screenEditOverlay.render(getClientRectPoints(clientRect), {
|
|
69574
|
+
showGrid: true
|
|
69575
|
+
});
|
|
69576
|
+
return true;
|
|
69577
|
+
},
|
|
69093
69578
|
onSelectionCreated: handleSelectionCreated,
|
|
69094
69579
|
overlayEl,
|
|
69095
69580
|
rectEl
|
|
69096
69581
|
});
|
|
69582
|
+
function createEditHit(part) {
|
|
69583
|
+
return { cursor: "grab", part };
|
|
69584
|
+
}
|
|
69585
|
+
function getPendingEditHit(event) {
|
|
69586
|
+
if (freezePendingScreenEditIfCameraChanged()) {
|
|
69587
|
+
return null;
|
|
69588
|
+
}
|
|
69589
|
+
const edit = getActivePendingEdit();
|
|
69590
|
+
if (!edit) {
|
|
69591
|
+
return null;
|
|
69592
|
+
}
|
|
69593
|
+
const pointer = { x: event.clientX, y: event.clientY };
|
|
69594
|
+
for (const part of SCREEN_EDIT_CORNER_PARTS) {
|
|
69595
|
+
const point = getPartPoint(edit.clientPoints, part);
|
|
69596
|
+
const dx = pointer.x - point.x;
|
|
69597
|
+
const dy = pointer.y - point.y;
|
|
69598
|
+
if (dx * dx + dy * dy <= SCREEN_EDIT_CORNER_HIT_SIZE ** 2) {
|
|
69599
|
+
return createEditHit(part);
|
|
69600
|
+
}
|
|
69601
|
+
}
|
|
69602
|
+
for (const part of SCREEN_EDIT_EDGE_PARTS) {
|
|
69603
|
+
const [startIndex, endIndex] = SCREEN_EDIT_PART_POINT_INDICES[part];
|
|
69604
|
+
if (pointSegmentDistanceSq(
|
|
69605
|
+
pointer,
|
|
69606
|
+
edit.clientPoints[startIndex],
|
|
69607
|
+
edit.clientPoints[endIndex]
|
|
69608
|
+
) <= SCREEN_EDIT_EDGE_HIT_SIZE ** 2) {
|
|
69609
|
+
return createEditHit(part);
|
|
69610
|
+
}
|
|
69611
|
+
}
|
|
69612
|
+
return null;
|
|
69613
|
+
}
|
|
69614
|
+
function getPendingEditDragPoints(event) {
|
|
69615
|
+
const { part, startClientX, startClientY, startPoints } = pendingEditDrag;
|
|
69616
|
+
const domRect = domElement.getBoundingClientRect();
|
|
69617
|
+
const indices = SCREEN_EDIT_PART_POINT_INDICES[part] || [];
|
|
69618
|
+
let dx = event.clientX - startClientX;
|
|
69619
|
+
let dy = event.clientY - startClientY;
|
|
69620
|
+
indices.forEach((index) => {
|
|
69621
|
+
const point = startPoints[index];
|
|
69622
|
+
dx = Math.max(dx, domRect.left - point.x);
|
|
69623
|
+
dx = Math.min(dx, domRect.right - point.x);
|
|
69624
|
+
dy = Math.max(dy, domRect.top - point.y);
|
|
69625
|
+
dy = Math.min(dy, domRect.bottom - point.y);
|
|
69626
|
+
});
|
|
69627
|
+
return startPoints.map(
|
|
69628
|
+
(point, index) => indices.includes(index) ? {
|
|
69629
|
+
x: point.x + dx,
|
|
69630
|
+
y: point.y + dy
|
|
69631
|
+
} : copyClientPoint(point)
|
|
69632
|
+
);
|
|
69633
|
+
}
|
|
69634
|
+
function updatePendingEditSelection(clientPoints) {
|
|
69635
|
+
const edit = getActivePendingEdit();
|
|
69636
|
+
if (!edit) {
|
|
69637
|
+
return false;
|
|
69638
|
+
}
|
|
69639
|
+
const match = findSelection(edit.selectionId);
|
|
69640
|
+
if (!match) {
|
|
69641
|
+
return false;
|
|
69642
|
+
}
|
|
69643
|
+
if (!isConvexClientQuad(clientPoints)) {
|
|
69644
|
+
return false;
|
|
69645
|
+
}
|
|
69646
|
+
const selectionData = createSelectionData({
|
|
69647
|
+
camera,
|
|
69648
|
+
clientPoints,
|
|
69649
|
+
domElement,
|
|
69650
|
+
getDepthRange
|
|
69651
|
+
});
|
|
69652
|
+
if (!selectionData) {
|
|
69653
|
+
return false;
|
|
69654
|
+
}
|
|
69655
|
+
edit.clientPoints = copyClientPoints(clientPoints);
|
|
69656
|
+
setScreenSelectionShape(
|
|
69657
|
+
match.selection,
|
|
69658
|
+
selectionData,
|
|
69659
|
+
getCurrentRootTransformArray()
|
|
69660
|
+
);
|
|
69661
|
+
syncPendingEditOverlay();
|
|
69662
|
+
syncTransformControlsState();
|
|
69663
|
+
return true;
|
|
69664
|
+
}
|
|
69665
|
+
function handlePendingEditPointerDown(event) {
|
|
69666
|
+
if (event.button !== 0) {
|
|
69667
|
+
return false;
|
|
69668
|
+
}
|
|
69669
|
+
const hit = getPendingEditHit(event);
|
|
69670
|
+
if (!hit) {
|
|
69671
|
+
return false;
|
|
69672
|
+
}
|
|
69673
|
+
pendingEditDrag = {
|
|
69674
|
+
part: hit.part,
|
|
69675
|
+
pointerId: event.pointerId,
|
|
69676
|
+
startClientX: event.clientX,
|
|
69677
|
+
startClientY: event.clientY,
|
|
69678
|
+
startPoints: copyClientPoints(pendingScreenEdit.clientPoints),
|
|
69679
|
+
updated: false
|
|
69680
|
+
};
|
|
69681
|
+
domElement.setPointerCapture?.(event.pointerId);
|
|
69682
|
+
screenEditOverlay.setActivePart(hit.part);
|
|
69683
|
+
setEditCursor("grabbing");
|
|
69684
|
+
event.preventDefault();
|
|
69685
|
+
event.stopPropagation();
|
|
69686
|
+
return true;
|
|
69687
|
+
}
|
|
69688
|
+
function handlePendingEditPointerMove(event) {
|
|
69689
|
+
if (pendingEditDrag) {
|
|
69690
|
+
if (event.pointerId !== pendingEditDrag.pointerId) {
|
|
69691
|
+
return false;
|
|
69692
|
+
}
|
|
69693
|
+
pendingEditDrag.updated = updatePendingEditSelection(getPendingEditDragPoints(event)) || pendingEditDrag.updated;
|
|
69694
|
+
event.preventDefault();
|
|
69695
|
+
event.stopPropagation();
|
|
69696
|
+
return true;
|
|
69697
|
+
}
|
|
69698
|
+
if (event.buttons) {
|
|
69699
|
+
return false;
|
|
69700
|
+
}
|
|
69701
|
+
const hit = getPendingEditHit(event);
|
|
69702
|
+
screenEditOverlay.setActivePart(hit?.part);
|
|
69703
|
+
setEditCursor(hit?.cursor || "");
|
|
69704
|
+
return false;
|
|
69705
|
+
}
|
|
69706
|
+
function handlePendingEditPointerUp(event) {
|
|
69707
|
+
if (!pendingEditDrag || event.pointerId !== pendingEditDrag.pointerId) {
|
|
69708
|
+
return false;
|
|
69709
|
+
}
|
|
69710
|
+
domElement.releasePointerCapture?.(event.pointerId);
|
|
69711
|
+
const updated = pendingEditDrag.updated;
|
|
69712
|
+
pendingEditDrag = null;
|
|
69713
|
+
const hit = getPendingEditHit(event);
|
|
69714
|
+
screenEditOverlay.setActivePart(hit?.part);
|
|
69715
|
+
setEditCursor(hit?.cursor || "");
|
|
69716
|
+
setStatus(
|
|
69717
|
+
updated ? "Updated screen selection convex quadrilateral." : "Screen selection must stay convex.",
|
|
69718
|
+
!updated
|
|
69719
|
+
);
|
|
69720
|
+
event.preventDefault();
|
|
69721
|
+
event.stopPropagation();
|
|
69722
|
+
return true;
|
|
69723
|
+
}
|
|
69724
|
+
function handlePendingEditPointerCancel(event) {
|
|
69725
|
+
if (!pendingEditDrag || event.pointerId !== pendingEditDrag.pointerId) {
|
|
69726
|
+
return false;
|
|
69727
|
+
}
|
|
69728
|
+
domElement.releasePointerCapture?.(event.pointerId);
|
|
69729
|
+
pendingEditDrag = null;
|
|
69730
|
+
screenEditOverlay.setActivePart(null);
|
|
69731
|
+
clearEditCursor();
|
|
69732
|
+
event.preventDefault();
|
|
69733
|
+
event.stopPropagation();
|
|
69734
|
+
return true;
|
|
69735
|
+
}
|
|
69097
69736
|
function setMode(active) {
|
|
69098
69737
|
pendingMode = active && hasGaussianSplats && pendingSelections.length === 0;
|
|
69099
69738
|
pointerTracker.setActive(pendingMode);
|
|
@@ -69106,6 +69745,7 @@ function createCropController({
|
|
|
69106
69745
|
}
|
|
69107
69746
|
cameraController.enabled = !transformControls.dragging;
|
|
69108
69747
|
syncTransformControlsState();
|
|
69748
|
+
syncPendingEditOverlay();
|
|
69109
69749
|
refreshUi();
|
|
69110
69750
|
}
|
|
69111
69751
|
function cancelMode() {
|
|
@@ -69114,7 +69754,7 @@ function createCropController({
|
|
|
69114
69754
|
}
|
|
69115
69755
|
setMode(false);
|
|
69116
69756
|
}
|
|
69117
|
-
function handleSelectionCreated(selectionData) {
|
|
69757
|
+
function handleSelectionCreated(selectionData, clientRect) {
|
|
69118
69758
|
if (pendingSelections.length > 0) {
|
|
69119
69759
|
setMode(false);
|
|
69120
69760
|
setStatus(
|
|
@@ -69136,12 +69776,13 @@ function createCropController({
|
|
|
69136
69776
|
pendingSelections.push(selection);
|
|
69137
69777
|
activeSelectionId = selection.id;
|
|
69138
69778
|
setMode(false);
|
|
69779
|
+
createPendingScreenEdit(selection, clientRect);
|
|
69139
69780
|
syncEditSdfs();
|
|
69140
69781
|
syncFarHandles();
|
|
69141
69782
|
syncTransformControlsState();
|
|
69142
69783
|
refreshUi();
|
|
69143
69784
|
setStatus(
|
|
69144
|
-
"Added screen exclude selection. Drag the 3D far plane
|
|
69785
|
+
"Added screen exclude selection. Drag corner points or edges into a convex quadrilateral before moving the camera, then adjust the 3D far plane and Confirm or Cancel."
|
|
69145
69786
|
);
|
|
69146
69787
|
}
|
|
69147
69788
|
function toggle() {
|
|
@@ -69173,6 +69814,7 @@ function createCropController({
|
|
|
69173
69814
|
}
|
|
69174
69815
|
const count = pendingSelections.length;
|
|
69175
69816
|
selections.push(...pendingSelections);
|
|
69817
|
+
clearPendingScreenEdit();
|
|
69176
69818
|
pendingSelections = [];
|
|
69177
69819
|
activeSelectionId = null;
|
|
69178
69820
|
setMode(false);
|
|
@@ -69193,6 +69835,7 @@ function createCropController({
|
|
|
69193
69835
|
)) {
|
|
69194
69836
|
activeSelectionId = null;
|
|
69195
69837
|
}
|
|
69838
|
+
clearPendingScreenEdit();
|
|
69196
69839
|
pendingSelections.forEach(disposeScreenSelection);
|
|
69197
69840
|
pendingSelections = [];
|
|
69198
69841
|
syncEditSdfs();
|
|
@@ -69259,10 +69902,12 @@ function createCropController({
|
|
|
69259
69902
|
setTransformMode(null);
|
|
69260
69903
|
syncEditSdfs();
|
|
69261
69904
|
syncFarHandles();
|
|
69905
|
+
syncPendingEditOverlay();
|
|
69262
69906
|
refreshUi();
|
|
69263
69907
|
syncTransformControlsState();
|
|
69908
|
+
const canEditPendingRect = !wasActive && !!getActivePendingEdit();
|
|
69264
69909
|
setStatus(
|
|
69265
|
-
wasActive ? "Screen selection deactivated." : "Drag the 3D far plane handle to adjust screen selection depth."
|
|
69910
|
+
wasActive ? "Screen selection deactivated." : canEditPendingRect ? "Drag corner points or edges into a convex quadrilateral before moving the camera, or drag the 3D far plane to adjust depth." : "Drag the 3D far plane handle to adjust screen selection depth."
|
|
69266
69911
|
);
|
|
69267
69912
|
}
|
|
69268
69913
|
function removeFromList(list, selectionId) {
|
|
@@ -69283,6 +69928,9 @@ function createCropController({
|
|
|
69283
69928
|
if (Number(selectionId) === activeSelectionId) {
|
|
69284
69929
|
activeSelectionId = null;
|
|
69285
69930
|
}
|
|
69931
|
+
if (Number(selectionId) === pendingScreenEdit?.selectionId) {
|
|
69932
|
+
clearPendingScreenEdit();
|
|
69933
|
+
}
|
|
69286
69934
|
syncEditSdfs();
|
|
69287
69935
|
syncFarHandles();
|
|
69288
69936
|
refreshUi();
|
|
@@ -69300,6 +69948,7 @@ function createCropController({
|
|
|
69300
69948
|
selections = [];
|
|
69301
69949
|
pendingSelections = [];
|
|
69302
69950
|
activeSelectionId = null;
|
|
69951
|
+
clearPendingScreenEdit();
|
|
69303
69952
|
syncEditSdfs();
|
|
69304
69953
|
syncFarHandles();
|
|
69305
69954
|
refreshUi();
|
|
@@ -69313,6 +69962,7 @@ function createCropController({
|
|
|
69313
69962
|
activeSelectionId = null;
|
|
69314
69963
|
syncEditSdfs();
|
|
69315
69964
|
syncFarHandles();
|
|
69965
|
+
syncPendingEditOverlay();
|
|
69316
69966
|
cancelMode();
|
|
69317
69967
|
refreshUi();
|
|
69318
69968
|
}
|
|
@@ -69323,8 +69973,44 @@ function createCropController({
|
|
|
69323
69973
|
activeSelectionId = null;
|
|
69324
69974
|
syncEditSdfs();
|
|
69325
69975
|
syncFarHandles();
|
|
69976
|
+
syncPendingEditOverlay();
|
|
69326
69977
|
refreshUi();
|
|
69327
69978
|
}
|
|
69979
|
+
function shouldCapturePointerDown(event) {
|
|
69980
|
+
return event.button === 0 && (pendingMode || getPendingEditHit(event) !== null);
|
|
69981
|
+
}
|
|
69982
|
+
function handlePointerDown(event) {
|
|
69983
|
+
if (pointerTracker.handlePointerDown(event)) {
|
|
69984
|
+
return true;
|
|
69985
|
+
}
|
|
69986
|
+
return handlePendingEditPointerDown(event);
|
|
69987
|
+
}
|
|
69988
|
+
function handlePointerMove(event) {
|
|
69989
|
+
if (pointerTracker.handlePointerMove(event)) {
|
|
69990
|
+
return true;
|
|
69991
|
+
}
|
|
69992
|
+
return handlePendingEditPointerMove(event);
|
|
69993
|
+
}
|
|
69994
|
+
function handlePointerUp(event) {
|
|
69995
|
+
if (pointerTracker.handlePointerUp(event)) {
|
|
69996
|
+
return true;
|
|
69997
|
+
}
|
|
69998
|
+
return handlePendingEditPointerUp(event);
|
|
69999
|
+
}
|
|
70000
|
+
function handlePointerCancel(event) {
|
|
70001
|
+
if (pointerTracker.handlePointerCancel(event)) {
|
|
70002
|
+
return true;
|
|
70003
|
+
}
|
|
70004
|
+
return handlePendingEditPointerCancel(event);
|
|
70005
|
+
}
|
|
70006
|
+
cameraController.addEventListener(
|
|
70007
|
+
"update",
|
|
70008
|
+
freezePendingScreenEditIfCameraChanged
|
|
70009
|
+
);
|
|
70010
|
+
cameraController.addEventListener(
|
|
70011
|
+
"finish",
|
|
70012
|
+
freezePendingScreenEditIfCameraChanged
|
|
70013
|
+
);
|
|
69328
70014
|
return {
|
|
69329
70015
|
cancel,
|
|
69330
70016
|
cancelMode,
|
|
@@ -69334,25 +70020,32 @@ function createCropController({
|
|
|
69334
70020
|
getActiveSelection,
|
|
69335
70021
|
getPayload,
|
|
69336
70022
|
getPendingMode: () => pendingMode,
|
|
69337
|
-
handlePointerCancel
|
|
69338
|
-
handlePointerDown
|
|
69339
|
-
handlePointerMove
|
|
69340
|
-
handlePointerUp
|
|
70023
|
+
handlePointerCancel,
|
|
70024
|
+
handlePointerDown,
|
|
70025
|
+
handlePointerMove,
|
|
70026
|
+
handlePointerUp,
|
|
69341
70027
|
handleSelectionRemove,
|
|
69342
70028
|
handleSelectionSelect,
|
|
69343
70029
|
handleTransformControlObjectChange,
|
|
69344
70030
|
hasPendingSelections: () => pendingSelections.length > 0,
|
|
69345
70031
|
notifyTransformModeChanged,
|
|
69346
70032
|
setHasGaussianSplats,
|
|
70033
|
+
shouldCapturePointerDown,
|
|
69347
70034
|
syncWorldState,
|
|
69348
70035
|
toggle
|
|
69349
70036
|
};
|
|
69350
70037
|
}
|
|
70038
|
+
var CAMERA_POSITION_EPSILON_SQ, CAMERA_QUATERNION_EPSILON, CAMERA_PROJECTION_EPSILON;
|
|
69351
70039
|
var init_cropController = __esm({
|
|
69352
70040
|
"src/viewer/screenSelection/cropController.js"() {
|
|
69353
70041
|
init_three_module();
|
|
69354
70042
|
init_screenSelection();
|
|
70043
|
+
init_geometry();
|
|
70044
|
+
init_editOverlay();
|
|
69355
70045
|
init_cropUi();
|
|
70046
|
+
CAMERA_POSITION_EPSILON_SQ = 1e-12;
|
|
70047
|
+
CAMERA_QUATERNION_EPSILON = 1e-10;
|
|
70048
|
+
CAMERA_PROJECTION_EPSILON = 1e-10;
|
|
69356
70049
|
}
|
|
69357
70050
|
});
|
|
69358
70051
|
|
|
@@ -69961,7 +70654,7 @@ var require_app = __commonJS({
|
|
|
69961
70654
|
savedControlDisabledStates = null;
|
|
69962
70655
|
}
|
|
69963
70656
|
cameraController.setPointerDownFilter((event) => {
|
|
69964
|
-
return !(cropController?.
|
|
70657
|
+
return !(cropController?.shouldCapturePointerDown(event) ?? false);
|
|
69965
70658
|
});
|
|
69966
70659
|
var { transformControls, transformControlsHelper } = createViewerTransformControls({
|
|
69967
70660
|
camera,
|