Skip to content

Commit 8485813

Browse files
Transform controls: undo positioning upon failure (#610)
* Undo rotation/translation upon dry-run failure * Undo positioning upon dry run failure * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Linter --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent b5b6029 commit 8485813

File tree

3 files changed

+45
-16
lines changed

3 files changed

+45
-16
lines changed

packages/base/src/3dview/helpers.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export interface IMeshGroupMetadata {
7171
[key: string]: any;
7272
}
7373

74+
export interface IMeshGroup extends THREE.Group {
75+
userData: IMeshGroupMetadata;
76+
}
77+
7478
export function projectVector(options: {
7579
vector: THREE.Vector3;
7680
camera: THREE.Camera;
@@ -162,7 +166,7 @@ export function buildShape(options: {
162166
isWireframe: boolean;
163167
objColor?: THREE.Color | string | number;
164168
}): {
165-
meshGroup: THREE.Group;
169+
meshGroup: IMeshGroup;
166170
mainMesh: THREE.Mesh<THREE.BufferGeometry, THREE.MeshStandardMaterial>;
167171
edgesMeshes: LineSegments2[];
168172
} | null {
@@ -240,11 +244,12 @@ export function buildShape(options: {
240244
geometry.computeBoundsTree();
241245
}
242246

243-
const meshGroup = new THREE.Group();
247+
const meshGroup = new THREE.Group() as IMeshGroup;
244248
meshGroup.name = `${objName}-group`;
245249
meshGroup.visible = visible;
246250
meshGroup.userData = {
247-
jcObject
251+
jcObject,
252+
type: 'shape'
248253
};
249254

250255
// We only build the stencil logic for solid meshes
@@ -345,7 +350,6 @@ export function buildShape(options: {
345350
boundingBox.visible = false;
346351
boundingBox.name = SELECTION_BOUNDING_BOX;
347352
meshGroup.add(boundingBox);
348-
meshGroup.userData.type = 'shape';
349353

350354
meshGroup.add(mainMesh);
351355

packages/base/src/3dview/mainview.tsx

+33-10
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ import {
5050
computeExplodedState,
5151
projectVector,
5252
IMouseDrag,
53-
IMeshGroupMetadata
53+
IMeshGroupMetadata,
54+
getQuaternion
5455
} from './helpers';
5556
import { MainViewModel } from './mainviewmodel';
5657
import { Spinner } from './spinner';
@@ -417,8 +418,9 @@ export class MainView extends React.Component<IProps, IStates> {
417418
this._controls.enabled = !event.value;
418419
});
419420
// Update the currently transformed object in the shared model once finished moving
420-
this._transformControls.addEventListener('mouseUp', () => {
421+
this._transformControls.addEventListener('mouseUp', async () => {
421422
const updatedObject = this._selectedMeshes[0];
423+
422424
const objectName = updatedObject.name;
423425

424426
const updatedPosition = new THREE.Vector3();
@@ -451,15 +453,36 @@ export class MainView extends React.Component<IProps, IStates> {
451453
updatedPosition.z
452454
];
453455

454-
this._mainViewModel.maybeUpdateObjectParameters(objectName, {
455-
...obj.parameters,
456-
Placement: {
457-
...obj.parameters.Placement,
458-
Position: newPosition,
459-
Axis: updatedRotation[0],
460-
Angle: updatedRotation[1]
456+
const done = await this._mainViewModel.maybeUpdateObjectParameters(
457+
objectName,
458+
{
459+
...obj.parameters,
460+
Placement: {
461+
...obj.parameters.Placement,
462+
Position: newPosition,
463+
Axis: updatedRotation[0],
464+
Angle: updatedRotation[1]
465+
}
461466
}
462-
});
467+
);
468+
// If the dry run failed, we bring back the object to its original position
469+
if (!done && updatedObject.parent) {
470+
const origPosition = obj.parameters.Placement.Position;
471+
472+
// Undo positioning
473+
updatedObject.parent.position.copy(new THREE.Vector3(0, 0, 0));
474+
updatedObject.parent.applyQuaternion(updatedQuaternion.invert());
475+
476+
// Redo original positioning
477+
updatedObject.parent.applyQuaternion(getQuaternion(obj));
478+
updatedObject.parent.position.copy(
479+
new THREE.Vector3(
480+
origPosition[0],
481+
origPosition[1],
482+
origPosition[2]
483+
)
484+
);
485+
}
463486
}
464487
});
465488
this._scene.add(this._transformControls);

packages/base/src/3dview/mainviewmodel.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export class MainViewModel implements IDisposable {
178178
async maybeUpdateObjectParameters(
179179
name: string,
180180
properties: { [key: string]: any }
181-
): Promise<void> {
181+
): Promise<boolean> {
182182
// getContent already returns a deep copy of the content, we can change it safely here
183183
const updatedContent = this.jcadModel.getContent();
184184
for (const object of updatedContent.objects) {
@@ -197,7 +197,7 @@ export class MainViewModel implements IDisposable {
197197
'Failed to update the desired shape',
198198
'The tool was unable to update the desired shape due to invalid parameter values. The values you entered may not be compatible with the dimensions of your piece.'
199199
);
200-
return;
200+
return false;
201201
}
202202

203203
// Dry run was successful, ready to apply the update now
@@ -215,6 +215,8 @@ export class MainViewModel implements IDisposable {
215215
meta
216216
});
217217
}
218+
219+
return true;
218220
}
219221

220222
/**

0 commit comments

Comments
 (0)