@archvisioninc/canvas 3.3.8 → 3.3.10
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/dist/Canvas.js +67 -0
- package/dist/actions/index.js +1 -0
- package/dist/actions/shortcutActions.js +313 -0
- package/dist/constants/constants.js +80 -0
- package/dist/constants/index.js +1 -0
- package/dist/enums/aspectRatios.js +17 -0
- package/dist/enums/dimensions.js +20 -0
- package/dist/enums/downscaling.js +16 -0
- package/dist/enums/exclusions.js +4 -0
- package/dist/enums/formats.js +1 -0
- package/dist/enums/index.js +8 -0
- package/dist/enums/orthoOptions.js +28 -0
- package/dist/enums/scaleUnits.js +25 -0
- package/dist/enums/shortcuts.js +89 -0
- package/dist/helpers/cameraHelpers.js +86 -0
- package/dist/helpers/canvasAddHelpers.js +161 -0
- package/dist/helpers/canvasCommunicationHelpers.js +52 -0
- package/dist/helpers/canvasRemoveHelpers.js +230 -0
- package/dist/helpers/canvasUpdateHelpers.js +1368 -0
- package/dist/helpers/gizmoHelpers.js +156 -0
- package/dist/helpers/guiHelpers.js +46 -0
- package/dist/helpers/index.js +16 -0
- package/dist/helpers/initHelpers.js +514 -0
- package/dist/helpers/lightHelpers.js +17 -0
- package/dist/helpers/loadHelpers.js +269 -0
- package/dist/helpers/materialHelpers.js +34 -0
- package/dist/helpers/meshHelpers.js +169 -0
- package/dist/helpers/rayHelpers.js +11 -0
- package/dist/helpers/shortcutHelpers.js +35 -0
- package/dist/helpers/utilityHelpers.js +710 -0
- package/dist/helpers/viewportHelpers.js +364 -0
- package/dist/styles.js +25 -0
- package/package.json +1 -1
- package/src/package/helpers/canvasUpdateHelpers.js +4 -0
- package/src/package/helpers/initHelpers.js +2 -0
package/dist/Canvas.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import React, { useRef, useEffect, useCallback } from 'react';
|
|
3
|
+
import { initScene, cleanup, createScene, engine, scene, warningChecks, updateItem, getGLTFData, takePreviewScreenshots } from './helpers';
|
|
4
|
+
import { CanvasContainer, RenderCanvas } from './styles';
|
|
5
|
+
export let reactProps;
|
|
6
|
+
const Canvas = props => {
|
|
7
|
+
const {
|
|
8
|
+
file,
|
|
9
|
+
guidURL,
|
|
10
|
+
reinitialize,
|
|
11
|
+
updateData,
|
|
12
|
+
exportModel,
|
|
13
|
+
toDownload,
|
|
14
|
+
exportType
|
|
15
|
+
} = props;
|
|
16
|
+
const canvasRef = useRef();
|
|
17
|
+
const checkForWarnings = useCallback(() => {
|
|
18
|
+
if (scene) {
|
|
19
|
+
const hasPlugin = scene?.loadingPluginName;
|
|
20
|
+
if (hasPlugin) warningChecks();
|
|
21
|
+
}
|
|
22
|
+
}, []);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
return () => {
|
|
25
|
+
cleanup();
|
|
26
|
+
};
|
|
27
|
+
}, []);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
initScene({
|
|
30
|
+
canvasRef
|
|
31
|
+
});
|
|
32
|
+
}, [canvasRef, guidURL]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
reactProps = props;
|
|
35
|
+
}, [props]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const createNewScene = true;
|
|
38
|
+
if (file || guidURL && engine) createScene();
|
|
39
|
+
if (!file && !guidURL && scene) createScene(createNewScene);
|
|
40
|
+
}, [file, guidURL]);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
checkForWarnings();
|
|
43
|
+
}, [checkForWarnings]);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (scene && !_.isEmpty(updateData)) {
|
|
46
|
+
updateItem(updateData);
|
|
47
|
+
}
|
|
48
|
+
}, [updateData]);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (canvasRef && reinitialize) {
|
|
51
|
+
cleanup();
|
|
52
|
+
initScene({
|
|
53
|
+
canvasRef
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}, [canvasRef, reinitialize]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (exportModel && exportType) {
|
|
59
|
+
getGLTFData(exportType, toDownload);
|
|
60
|
+
takePreviewScreenshots();
|
|
61
|
+
}
|
|
62
|
+
}, [exportModel, exportType, toDownload]);
|
|
63
|
+
return /*#__PURE__*/React.createElement(CanvasContainer, props, /*#__PURE__*/React.createElement(RenderCanvas, {
|
|
64
|
+
ref: canvasRef
|
|
65
|
+
}));
|
|
66
|
+
};
|
|
67
|
+
export default Canvas;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './shortcutActions';
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import * as BABYLON from 'babylonjs';
|
|
2
|
+
import * as BABYLONGUI from 'babylonjs-gui';
|
|
3
|
+
import { getUserMeshes, gizmoManager, newFraming, scene, selectedMeshes, theme, $selectedTheme, newColor, toggleCameraMode, getParamOfSelectedMeshes, getUserMaterials, guiTexture, getBoundingMeshData, singleMeshTNode, multiMeshTNode, createBoundingMesh, restoreParents, createSafeFrame, newMetaDataEntry, resetSelectedMeshes, buildMaterialsArray, buildSelectedMaterialArray, addAutoRotation, removeAutoRotation, autoRotation, buildMeshPositionsArray } from '../helpers';
|
|
4
|
+
import { GIZMOS, GUI, MESH_PARAMS } from '../constants';
|
|
5
|
+
import { exclusionMaterials, orthoOptions, dimensions, scaleUnits } from '../enums';
|
|
6
|
+
import _ from 'lodash';
|
|
7
|
+
export let cameraView;
|
|
8
|
+
export const resetManagerGizmos = type => {
|
|
9
|
+
Object.values(GIZMOS).forEach(value => {
|
|
10
|
+
if (value !== type) {
|
|
11
|
+
const propertyName = _.camelCase(`${value}Enabled`);
|
|
12
|
+
gizmoManager[propertyName] = false;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
dimensions.forEach(dimension => {
|
|
16
|
+
guiTexture.getControlByName(dimension.rectangle)?.dispose?.();
|
|
17
|
+
guiTexture.getControlByName(dimension.label)?.dispose?.();
|
|
18
|
+
guiTexture.getControlByName(dimension.container)?.dispose?.();
|
|
19
|
+
});
|
|
20
|
+
switch (selectedMeshes.length) {
|
|
21
|
+
case 1:
|
|
22
|
+
gizmoManager.attachToNode(singleMeshTNode);
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
gizmoManager.attachToNode(multiMeshTNode);
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const toggleTurntable = override => {
|
|
30
|
+
const camera = scene.activeCamera;
|
|
31
|
+
const rotationEnabled = camera.useAutoRotationBehavior;
|
|
32
|
+
if (!autoRotation) addAutoRotation();
|
|
33
|
+
if (override !== undefined) {
|
|
34
|
+
camera.useAutoRotationBehavior = override;
|
|
35
|
+
if (override) {
|
|
36
|
+
autoRotation.attach(camera);
|
|
37
|
+
autoRotation.idleRotationSpeed = -0.1;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
autoRotation.detach(camera);
|
|
41
|
+
removeAutoRotation();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (rotationEnabled) {
|
|
45
|
+
autoRotation.detach(camera);
|
|
46
|
+
camera.useAutoRotationBehavior = false;
|
|
47
|
+
removeAutoRotation();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
autoRotation.attach(camera);
|
|
51
|
+
camera.useAutoRotationBehavior = true;
|
|
52
|
+
autoRotation.idleRotationSpeed = -0.1;
|
|
53
|
+
};
|
|
54
|
+
export const focusCamera = () => {
|
|
55
|
+
const camera = scene.activeCamera;
|
|
56
|
+
const userMeshes = getUserMeshes();
|
|
57
|
+
const framingBehavior = newFraming();
|
|
58
|
+
const babylonOrthographic = BABYLON.Camera.ORTHOGRAPHIC_CAMERA;
|
|
59
|
+
const isOrtho = camera.mode === babylonOrthographic;
|
|
60
|
+
const boundingMesh = scene.getMeshById('boundingMesh');
|
|
61
|
+
const meshCenter = getParamOfSelectedMeshes(MESH_PARAMS.center);
|
|
62
|
+
const framingMeshes = boundingMesh ? [boundingMesh] : userMeshes;
|
|
63
|
+
framingBehavior.framingTime = 0;
|
|
64
|
+
framingBehavior.defaultElevation = 0;
|
|
65
|
+
framingBehavior.attach?.(camera);
|
|
66
|
+
!_.isEmpty(userMeshes) ? framingBehavior.zoomOnMeshesHierarchy(framingMeshes) : camera.setTarget(BABYLON.Vector3.Zero());
|
|
67
|
+
camera.beta = Math.PI / 2;
|
|
68
|
+
if (isOrtho) {
|
|
69
|
+
camera.target = meshCenter;
|
|
70
|
+
camera.alpha = orthoOptions[cameraView].alpha;
|
|
71
|
+
camera.beta = orthoOptions[cameraView].beta;
|
|
72
|
+
}
|
|
73
|
+
framingBehavior.detach?.(camera);
|
|
74
|
+
};
|
|
75
|
+
export const toggleSafeFrame = (e, aspectRatio, override) => {
|
|
76
|
+
let outerFrame = guiTexture.getControlByName(GUI.outerSafeFrame);
|
|
77
|
+
if (aspectRatio) {
|
|
78
|
+
outerFrame?.dispose();
|
|
79
|
+
createSafeFrame(aspectRatio);
|
|
80
|
+
outerFrame = guiTexture.getControlByName(GUI.outerSafeFrame);
|
|
81
|
+
outerFrame.isVisible = override;
|
|
82
|
+
newMetaDataEntry('safeFrameEnabled', outerFrame.isVisible);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (override === undefined && outerFrame) {
|
|
86
|
+
outerFrame.isVisible = !outerFrame.isVisible;
|
|
87
|
+
newMetaDataEntry('safeFrameEnabled', outerFrame.isVisible);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
export const toggleInspector = () => {
|
|
92
|
+
const inspector = scene.debugLayer;
|
|
93
|
+
inspector.isVisible() ? inspector.hide() : inspector.show();
|
|
94
|
+
};
|
|
95
|
+
export const toggleMoveWidget = () => {
|
|
96
|
+
if (!_.isEmpty(selectedMeshes)) {
|
|
97
|
+
resetManagerGizmos(GIZMOS.PositionGizmo);
|
|
98
|
+
gizmoManager.positionGizmoEnabled = !gizmoManager.positionGizmoEnabled;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
export const toggleRotateWidget = () => {
|
|
102
|
+
if (!_.isEmpty(selectedMeshes)) {
|
|
103
|
+
resetManagerGizmos(GIZMOS.RotationGizmo);
|
|
104
|
+
gizmoManager.rotationGizmoEnabled = !gizmoManager.rotationGizmoEnabled;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
export const toggleScaleWidget = () => {
|
|
108
|
+
if (!_.isEmpty(selectedMeshes)) {
|
|
109
|
+
resetManagerGizmos(GIZMOS.ScaleGizmo);
|
|
110
|
+
gizmoManager.scaleGizmoEnabled = !gizmoManager.scaleGizmoEnabled;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
export const toggleBoundingBoxWidget = () => {
|
|
114
|
+
const boundingMesh = scene.getMeshById('boundingMesh');
|
|
115
|
+
const boxColor = newColor(theme.colors[$selectedTheme].accent);
|
|
116
|
+
const isEnabled = gizmoManager.boundingBoxGizmoEnabled;
|
|
117
|
+
const boundingInfo = getBoundingMeshData([boundingMesh]);
|
|
118
|
+
dimensions.forEach(dimension => {
|
|
119
|
+
guiTexture.getControlByName(dimension.rectangle)?.dispose?.();
|
|
120
|
+
guiTexture.getControlByName(dimension.label)?.dispose?.();
|
|
121
|
+
guiTexture.getControlByName(dimension.container)?.dispose?.();
|
|
122
|
+
});
|
|
123
|
+
if (!gizmoManager.boundingBoxGizmoEnabled) {
|
|
124
|
+
resetManagerGizmos(GIZMOS.BoundingBoxGizmo);
|
|
125
|
+
gizmoManager.attachToMesh(boundingMesh);
|
|
126
|
+
}
|
|
127
|
+
gizmoManager.boundingBoxGizmoEnabled = !isEnabled;
|
|
128
|
+
gizmoManager.boundingBoxDragBehavior.rotateDraggedObject = false;
|
|
129
|
+
gizmoManager.boundingBoxDragBehavior.disableMovement = true;
|
|
130
|
+
gizmoManager.gizmos.boundingBoxGizmo.setEnabledScaling(false);
|
|
131
|
+
gizmoManager.gizmos.boundingBoxGizmo.setEnabledRotationAxis('');
|
|
132
|
+
gizmoManager.gizmos.boundingBoxGizmo.setColor(boxColor);
|
|
133
|
+
newMetaDataEntry('boundingBoxEnabled', !isEnabled);
|
|
134
|
+
|
|
135
|
+
// ================ Bounding Box Labels ================
|
|
136
|
+
const buildUnitLabel = dimension => {
|
|
137
|
+
const {
|
|
138
|
+
name,
|
|
139
|
+
color,
|
|
140
|
+
label,
|
|
141
|
+
rectangle,
|
|
142
|
+
container
|
|
143
|
+
} = dimension;
|
|
144
|
+
const {
|
|
145
|
+
center,
|
|
146
|
+
minimum,
|
|
147
|
+
maximumWorld,
|
|
148
|
+
minimumWorld
|
|
149
|
+
} = boundingInfo;
|
|
150
|
+
const displayUnit = scene.metadata?.selectedDisplayUnit || scene.metadata?.selectedSourceUnit;
|
|
151
|
+
const labelHeight = 36;
|
|
152
|
+
let x, y, z, value;
|
|
153
|
+
const buildValue = axis => {
|
|
154
|
+
const workingValue = Math.abs(minimumWorld[axis] - maximumWorld[axis]);
|
|
155
|
+
const meterScaleFactor = scaleUnits.find(unit => unit.abbreviation === 'm').scaleFactor;
|
|
156
|
+
const displayScaleFactor = scaleUnits.find(unit => unit.abbreviation === displayUnit || unit.name === displayUnit)?.scaleFactor || meterScaleFactor;
|
|
157
|
+
return (workingValue / displayScaleFactor).toFixed(6);
|
|
158
|
+
};
|
|
159
|
+
switch (name) {
|
|
160
|
+
case 'length':
|
|
161
|
+
x = center.x + (maximumWorld.x - minimumWorld.x) / 2;
|
|
162
|
+
y = center.y - Math.abs(minimum.y);
|
|
163
|
+
z = center.z;
|
|
164
|
+
value = buildValue('z');
|
|
165
|
+
break;
|
|
166
|
+
case 'width':
|
|
167
|
+
x = center.x;
|
|
168
|
+
y = center.y - Math.abs(minimum.y);
|
|
169
|
+
z = center.z + (maximumWorld.z - minimumWorld.z) / 2;
|
|
170
|
+
value = buildValue('x');
|
|
171
|
+
break;
|
|
172
|
+
default:
|
|
173
|
+
x = center.x + (maximumWorld.x - minimumWorld.x) / 2;
|
|
174
|
+
y = center.y;
|
|
175
|
+
z = center.z + (maximumWorld.z - minimumWorld.z) / 2;
|
|
176
|
+
value = buildValue('y');
|
|
177
|
+
}
|
|
178
|
+
const lengthPosition = new BABYLON.Vector3(x, y, z);
|
|
179
|
+
const labelRectangle = new BABYLONGUI.Rectangle(rectangle);
|
|
180
|
+
labelRectangle.width = displayUnit ? 0.14 : 0.12;
|
|
181
|
+
labelRectangle.heightInPixels = labelHeight;
|
|
182
|
+
labelRectangle.cornerRadius = 3;
|
|
183
|
+
labelRectangle.color = color;
|
|
184
|
+
labelRectangle.thickness = 1;
|
|
185
|
+
labelRectangle.background = color + 20;
|
|
186
|
+
guiTexture.addControl(labelRectangle);
|
|
187
|
+
const lengthLabel = new BABYLONGUI.TextBlock(label);
|
|
188
|
+
lengthLabel.text = `${_.startCase(name)}: ${value}${displayUnit || ''}`;
|
|
189
|
+
labelRectangle.addControl(lengthLabel);
|
|
190
|
+
const labelLinkBox = BABYLON.MeshBuilder.CreateBox(container, scene);
|
|
191
|
+
labelLinkBox.position = lengthPosition;
|
|
192
|
+
labelLinkBox.isPickable = false;
|
|
193
|
+
labelLinkBox.visibility = 0;
|
|
194
|
+
labelLinkBox.setParent(boundingMesh);
|
|
195
|
+
labelRectangle.linkWithMesh(labelLinkBox);
|
|
196
|
+
labelRectangle.linkOffsetX = 30;
|
|
197
|
+
labelRectangle.linkOffsetY = 30;
|
|
198
|
+
};
|
|
199
|
+
if (gizmoManager.boundingBoxGizmoEnabled) {
|
|
200
|
+
dimensions.forEach(dimension => buildUnitLabel(dimension));
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
export const hideSelected = () => {
|
|
204
|
+
selectedMeshes.forEach(mesh => {
|
|
205
|
+
mesh.isVisible = false;
|
|
206
|
+
});
|
|
207
|
+
resetManagerGizmos();
|
|
208
|
+
};
|
|
209
|
+
export const unhideAll = () => {
|
|
210
|
+
scene.meshes.forEach(mesh => {
|
|
211
|
+
if (!mesh.isVisible) {
|
|
212
|
+
mesh.isVisible = true;
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
export const deleteSelected = () => {
|
|
217
|
+
selectedMeshes.forEach(mesh => {
|
|
218
|
+
const material = mesh.material;
|
|
219
|
+
if (material?.getBindedMeshes().length === 1) {
|
|
220
|
+
const subMaterials = material.subMaterials;
|
|
221
|
+
const defaultMaterial = name => exclusionMaterials.includes(name);
|
|
222
|
+
if (subMaterials) {
|
|
223
|
+
subMaterials?.forEach(subMaterial => !defaultMaterial(subMaterial.name) && subMaterial.dispose());
|
|
224
|
+
}
|
|
225
|
+
if (!defaultMaterial(material.name)) material.dispose();
|
|
226
|
+
material.getActiveTextures().forEach(texture => texture.dispose());
|
|
227
|
+
}
|
|
228
|
+
resetManagerGizmos();
|
|
229
|
+
mesh.dispose();
|
|
230
|
+
});
|
|
231
|
+
resetSelectedMeshes();
|
|
232
|
+
};
|
|
233
|
+
export const toggleOrthographicViews = (e, orthoCamera) => {
|
|
234
|
+
const isDifferent = cameraView !== orthoCamera;
|
|
235
|
+
const babylonOrthographic = BABYLON.Camera.ORTHOGRAPHIC_CAMERA;
|
|
236
|
+
const babylonPerspective = BABYLON.Camera.PERSPECTIVE_CAMERA;
|
|
237
|
+
if (scene?.debugLayer.isVisible()) return;
|
|
238
|
+
if (isDifferent) {
|
|
239
|
+
cameraView = orthoCamera;
|
|
240
|
+
toggleCameraMode(orthoCamera, babylonOrthographic);
|
|
241
|
+
newMetaDataEntry('selectedOrthoView', orthoCamera);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
toggleCameraMode(orthoCamera, babylonPerspective);
|
|
245
|
+
newMetaDataEntry('selectedOrthoView', '');
|
|
246
|
+
cameraView = null;
|
|
247
|
+
};
|
|
248
|
+
export const toggleCulling = () => {
|
|
249
|
+
const materials = getUserMaterials();
|
|
250
|
+
materials.forEach(material => {
|
|
251
|
+
const isCullingBackfaces = material.backFaceCulling;
|
|
252
|
+
if (isCullingBackfaces) return material.backFaceCulling = false;
|
|
253
|
+
material.backFaceCulling = !material.backFaceCulling;
|
|
254
|
+
});
|
|
255
|
+
newMetaDataEntry('materials', buildMaterialsArray());
|
|
256
|
+
newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
|
|
257
|
+
};
|
|
258
|
+
export const modelToOrigin = sourceUnitScaleOperation => {
|
|
259
|
+
const boundingBoxEnabled = gizmoManager.boundingBoxGizmoEnabled;
|
|
260
|
+
const meshes = selectedMeshes.length > 0 ? selectedMeshes : getUserMeshes();
|
|
261
|
+
const parentList = [];
|
|
262
|
+
const handleBoundingBox = () => {
|
|
263
|
+
const newBox = createBoundingMesh();
|
|
264
|
+
if (boundingBoxEnabled && !sourceUnitScaleOperation) toggleBoundingBoxWidget();
|
|
265
|
+
if (gizmoManager.boundingBoxGizmoEnabled) gizmoManager.attachToMesh(newBox);
|
|
266
|
+
resetManagerGizmos(GIZMOS.BoundingBoxGizmo);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Single selections or only single mesh in scene.
|
|
270
|
+
if (meshes.length === 1) {
|
|
271
|
+
const mesh = meshes[0];
|
|
272
|
+
const boundingBox = mesh.getBoundingInfo().boundingBox;
|
|
273
|
+
const meshCenter = boundingBox.centerWorld;
|
|
274
|
+
const parent = mesh.parent;
|
|
275
|
+
parentList.push({
|
|
276
|
+
mesh,
|
|
277
|
+
parent
|
|
278
|
+
});
|
|
279
|
+
mesh.setParent(singleMeshTNode);
|
|
280
|
+
singleMeshTNode.position.subtractInPlace(meshCenter);
|
|
281
|
+
singleMeshTNode.position.y += boundingBox.extendSizeWorld.y;
|
|
282
|
+
selectedMeshes.length === 1 ? mesh.setParent(singleMeshTNode) : restoreParents(parentList);
|
|
283
|
+
handleBoundingBox();
|
|
284
|
+
newMetaDataEntry('meshChangeTracking', buildMeshPositionsArray({
|
|
285
|
+
preserveScale: true,
|
|
286
|
+
preserveRotation: true
|
|
287
|
+
}));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Multiple selections or multiple meshes in scene.
|
|
292
|
+
const multiBoundingData = getBoundingMeshData(meshes);
|
|
293
|
+
const boundingCenter = multiBoundingData.center;
|
|
294
|
+
const compensationY = multiBoundingData.maximum.y - boundingCenter.y;
|
|
295
|
+
meshes.forEach(mesh => {
|
|
296
|
+
const parent = mesh.parent;
|
|
297
|
+
parentList.push({
|
|
298
|
+
mesh,
|
|
299
|
+
parent
|
|
300
|
+
});
|
|
301
|
+
mesh.setParent(multiMeshTNode);
|
|
302
|
+
});
|
|
303
|
+
if (!sourceUnitScaleOperation) {
|
|
304
|
+
multiMeshTNode.position.subtractInPlace(boundingCenter);
|
|
305
|
+
multiMeshTNode.position.y += compensationY;
|
|
306
|
+
}
|
|
307
|
+
restoreParents(parentList);
|
|
308
|
+
handleBoundingBox();
|
|
309
|
+
newMetaDataEntry('meshChangeTracking', buildMeshPositionsArray({
|
|
310
|
+
preserveScale: true,
|
|
311
|
+
preserveRotation: true
|
|
312
|
+
}));
|
|
313
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export const TEXTURE_SIZE_THRESHOLD = 4096;
|
|
2
|
+
export const MATERIAL_COUNT_THRESHOLD = 50;
|
|
3
|
+
export const MESH_COUNT_THRESHOLD = 500;
|
|
4
|
+
export const INSPECTOR = {
|
|
5
|
+
root: '__root__'
|
|
6
|
+
};
|
|
7
|
+
export const LISTENERS = {
|
|
8
|
+
resize: 'resize',
|
|
9
|
+
keyup: 'keyup'
|
|
10
|
+
};
|
|
11
|
+
export const LIGHTS = {
|
|
12
|
+
SpotLight: 'SpotLight',
|
|
13
|
+
ShadowGenerator: 'ShadowGenerator',
|
|
14
|
+
PointLight: 'PointLight',
|
|
15
|
+
DirectionalLight: 'DirectionalLight',
|
|
16
|
+
HemisphericLight: 'HemisphericLight',
|
|
17
|
+
GroundLight: 'GroundLight'
|
|
18
|
+
};
|
|
19
|
+
export const CAMERAS = {
|
|
20
|
+
FreeCamera: 'FreeCamera',
|
|
21
|
+
FlyCamera: 'FlyCamera',
|
|
22
|
+
FollowCamera: 'FollowCamera',
|
|
23
|
+
GamepadCamera: 'GamepadCamera',
|
|
24
|
+
TouchCamera: 'TouchCamera',
|
|
25
|
+
UniversalCamera: 'UniversalCamera',
|
|
26
|
+
ArcRotateCamera: 'ArcRotateCamera'
|
|
27
|
+
};
|
|
28
|
+
export const VIEWPORT = {
|
|
29
|
+
shadowMapSize: 4096
|
|
30
|
+
};
|
|
31
|
+
export const GIZMOS = {
|
|
32
|
+
RotationGizmo: 'RotationGizmo',
|
|
33
|
+
PositionGizmo: 'PositionGizmo',
|
|
34
|
+
ScaleGizmo: 'ScaleGizmo',
|
|
35
|
+
BoundingBoxGizmo: 'BoundingBoxGizmo'
|
|
36
|
+
};
|
|
37
|
+
export const ORTHO = {
|
|
38
|
+
left: 'orthoLeft',
|
|
39
|
+
right: 'orthoRight',
|
|
40
|
+
top: 'orthoTop',
|
|
41
|
+
bottom: 'orthoBottom'
|
|
42
|
+
};
|
|
43
|
+
export const GUI = {
|
|
44
|
+
dragSelectBox: 'dragSelectBox',
|
|
45
|
+
innerSafeFrame: 'safeFrame_inner',
|
|
46
|
+
outerSafeFrame: 'safeFrame_outer'
|
|
47
|
+
};
|
|
48
|
+
export const MESH_PARAMS = {
|
|
49
|
+
center: 'center',
|
|
50
|
+
rotation: 'rotation',
|
|
51
|
+
scaling: 'scaling',
|
|
52
|
+
radius: 'radius'
|
|
53
|
+
};
|
|
54
|
+
export const MESSAGE_TYPES = {
|
|
55
|
+
error: 'error',
|
|
56
|
+
warning: 'warning',
|
|
57
|
+
info: 'info',
|
|
58
|
+
success: 'success',
|
|
59
|
+
loading: 'loading'
|
|
60
|
+
};
|
|
61
|
+
export const UPDATABLE_ITEMS = {
|
|
62
|
+
material: 'material',
|
|
63
|
+
mesh: 'mesh',
|
|
64
|
+
camera: 'camera',
|
|
65
|
+
environment: 'environment',
|
|
66
|
+
texture: 'texture',
|
|
67
|
+
viewport: 'viewport',
|
|
68
|
+
publish: 'publish',
|
|
69
|
+
lighting: 'lighting'
|
|
70
|
+
};
|
|
71
|
+
export const TRANSPARENCY_MODES = {
|
|
72
|
+
simple: 'simple',
|
|
73
|
+
complex: 'complex',
|
|
74
|
+
stencil: 'stencil'
|
|
75
|
+
};
|
|
76
|
+
export const AXIS_COLORS = {
|
|
77
|
+
xAxis: '#EA4231',
|
|
78
|
+
yAxis: '#249C4A',
|
|
79
|
+
zAxis: '#0089EA'
|
|
80
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './constants';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AXIS_COLORS } from '../constants';
|
|
2
|
+
export const dimensions = [{
|
|
3
|
+
name: 'length',
|
|
4
|
+
color: AXIS_COLORS.zAxis,
|
|
5
|
+
rectangle: 'lengthRectangle',
|
|
6
|
+
label: 'lengthLabel',
|
|
7
|
+
container: 'lengthContainer'
|
|
8
|
+
}, {
|
|
9
|
+
name: 'height',
|
|
10
|
+
color: AXIS_COLORS.yAxis,
|
|
11
|
+
rectangle: 'heightRectangle',
|
|
12
|
+
label: 'heightLabel',
|
|
13
|
+
container: 'widthContainer'
|
|
14
|
+
}, {
|
|
15
|
+
name: 'width',
|
|
16
|
+
color: AXIS_COLORS.xAxis,
|
|
17
|
+
rectangle: 'widthRectangle',
|
|
18
|
+
label: 'widthLabel',
|
|
19
|
+
container: 'heightContainer'
|
|
20
|
+
}];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export const exclusionMaterials = ['colorShader', 'default material', 'gridMat', 'ground', 'skyBox', 'boundingMaterial', 'voxelization', 'voxelSlabDebug'];
|
|
2
|
+
export const exclusionMeshes = ['xAxisMesh', 'yAxisMesh', 'zAxisMesh', 'mirrorGround', 'ground', 'hdrSkyBox', 'boundingMesh', 'lengthContainer', 'widthContainer', 'heightContainer'];
|
|
3
|
+
export const exclusionGUIs = ['guiDragSelectBox', 'lengthRectangle', 'lengthLabel', 'lengthContainer', 'widthRectangle', 'widthLabel', 'widthContainer', 'heightRectangle', 'heightLabel', 'heightContainer'];
|
|
4
|
+
export const exclusionTNodes = ['xAxis', 'yAxis', 'zAxis', 'multiMeshTransforms', 'singleMeshTransforms'];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DRAG_DROP_FORMATS = ['gltf', 'glb'];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as BABYLON from 'babylonjs';
|
|
2
|
+
const toRadians = value => BABYLON.Tools.ToRadians(value || 0);
|
|
3
|
+
export const orthoOptions = {
|
|
4
|
+
orthoLeft: {
|
|
5
|
+
alpha: 0,
|
|
6
|
+
beta: toRadians(90)
|
|
7
|
+
},
|
|
8
|
+
orthoRight: {
|
|
9
|
+
alpha: toRadians(180),
|
|
10
|
+
beta: toRadians(90)
|
|
11
|
+
},
|
|
12
|
+
orthoFront: {
|
|
13
|
+
alpha: toRadians(90),
|
|
14
|
+
beta: toRadians(90)
|
|
15
|
+
},
|
|
16
|
+
orthoBack: {
|
|
17
|
+
alpha: toRadians(270),
|
|
18
|
+
beta: toRadians(90)
|
|
19
|
+
},
|
|
20
|
+
orthoTop: {
|
|
21
|
+
alpha: toRadians(90),
|
|
22
|
+
beta: 0
|
|
23
|
+
},
|
|
24
|
+
orthoBottom: {
|
|
25
|
+
alpha: toRadians(90),
|
|
26
|
+
beta: toRadians(180)
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const scaleUnits = [{
|
|
2
|
+
name: 'millimeter',
|
|
3
|
+
abbreviation: 'mm',
|
|
4
|
+
scaleFactor: 0.001
|
|
5
|
+
}, {
|
|
6
|
+
name: 'centimeter',
|
|
7
|
+
abbreviation: 'cm',
|
|
8
|
+
scaleFactor: 0.01
|
|
9
|
+
}, {
|
|
10
|
+
name: 'meter',
|
|
11
|
+
abbreviation: 'm',
|
|
12
|
+
scaleFactor: 1
|
|
13
|
+
}, {
|
|
14
|
+
name: 'inch',
|
|
15
|
+
abbreviation: 'in',
|
|
16
|
+
scaleFactor: 0.0254
|
|
17
|
+
}, {
|
|
18
|
+
name: 'foot',
|
|
19
|
+
abbreviation: 'ft',
|
|
20
|
+
scaleFactor: 0.3048
|
|
21
|
+
}, {
|
|
22
|
+
name: 'yard',
|
|
23
|
+
abbreviation: 'yd',
|
|
24
|
+
scaleFactor: 0.9144
|
|
25
|
+
}];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { removeFromViewport } from '../helpers';
|
|
2
|
+
import { toggleInspector, toggleSafeFrame, focusCamera, toggleRotateWidget, toggleMoveWidget, hideSelected, unhideAll, toggleCulling, modelToOrigin, toggleScaleWidget, toggleBoundingBoxWidget, toggleOrthographicViews, toggleTurntable } from '../actions';
|
|
3
|
+
const deletePayload = {
|
|
4
|
+
payload: {
|
|
5
|
+
deleteSelectedMesh: true
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
export const shortcuts = {
|
|
9
|
+
camera: [{
|
|
10
|
+
name: 'focusCamera',
|
|
11
|
+
key: 'C',
|
|
12
|
+
action: () => focusCamera?.()
|
|
13
|
+
}, {
|
|
14
|
+
name: 'toggleSafeFrame',
|
|
15
|
+
key: 'F',
|
|
16
|
+
action: () => toggleSafeFrame?.()
|
|
17
|
+
}, {
|
|
18
|
+
name: 'orthoLeft',
|
|
19
|
+
key: '1',
|
|
20
|
+
action: e => toggleOrthographicViews(e, 'orthoLeft')
|
|
21
|
+
}, {
|
|
22
|
+
name: 'orthoRight',
|
|
23
|
+
key: '2',
|
|
24
|
+
action: e => toggleOrthographicViews(e, 'orthoRight')
|
|
25
|
+
}, {
|
|
26
|
+
name: 'orthoFront',
|
|
27
|
+
key: '3',
|
|
28
|
+
action: e => toggleOrthographicViews(e, 'orthoFront')
|
|
29
|
+
}, {
|
|
30
|
+
name: 'orthoBack',
|
|
31
|
+
key: '4',
|
|
32
|
+
action: e => toggleOrthographicViews(e, 'orthoBack')
|
|
33
|
+
}, {
|
|
34
|
+
name: 'orthoTop',
|
|
35
|
+
key: '5',
|
|
36
|
+
action: e => toggleOrthographicViews(e, 'orthoTop')
|
|
37
|
+
}, {
|
|
38
|
+
name: 'orthoBottom',
|
|
39
|
+
key: '6',
|
|
40
|
+
action: e => toggleOrthographicViews(e, 'orthoBottom')
|
|
41
|
+
}],
|
|
42
|
+
utilities: [{
|
|
43
|
+
name: 'inspector',
|
|
44
|
+
key: 'N',
|
|
45
|
+
action: () => toggleInspector?.()
|
|
46
|
+
}, {
|
|
47
|
+
name: 'turntable',
|
|
48
|
+
key: '/',
|
|
49
|
+
action: (e, override) => toggleTurntable?.(override)
|
|
50
|
+
}],
|
|
51
|
+
viewport: [{
|
|
52
|
+
name: 'moveWidget',
|
|
53
|
+
key: 'M',
|
|
54
|
+
action: () => toggleMoveWidget?.()
|
|
55
|
+
}, {
|
|
56
|
+
name: 'rotateWidget',
|
|
57
|
+
key: 'R',
|
|
58
|
+
action: () => toggleRotateWidget?.()
|
|
59
|
+
}, {
|
|
60
|
+
name: 'scaleWidget',
|
|
61
|
+
key: 'S',
|
|
62
|
+
action: () => toggleScaleWidget?.()
|
|
63
|
+
}, {
|
|
64
|
+
name: 'hideSelected',
|
|
65
|
+
key: 'H',
|
|
66
|
+
action: () => hideSelected?.()
|
|
67
|
+
}, {
|
|
68
|
+
name: 'unhideAll',
|
|
69
|
+
key: 'U',
|
|
70
|
+
action: () => unhideAll?.()
|
|
71
|
+
}, {
|
|
72
|
+
name: 'boundingBox',
|
|
73
|
+
key: 'B',
|
|
74
|
+
action: () => toggleBoundingBoxWidget?.()
|
|
75
|
+
}, {
|
|
76
|
+
name: 'deleteSelected',
|
|
77
|
+
key: 'Delete',
|
|
78
|
+
action: () => removeFromViewport(deletePayload)
|
|
79
|
+
}],
|
|
80
|
+
model: [{
|
|
81
|
+
name: 'toggleCulling',
|
|
82
|
+
key: 'c',
|
|
83
|
+
action: () => toggleCulling?.()
|
|
84
|
+
}, {
|
|
85
|
+
name: 'modelToOrigin',
|
|
86
|
+
key: 'O',
|
|
87
|
+
action: () => modelToOrigin?.()
|
|
88
|
+
}]
|
|
89
|
+
};
|