Skip to content

Commit 8ea5fc8

Browse files
arjxn-pypre-commit-ci[bot]martinRenougithub-actions[bot]
authored
Undo opencascade positioning and rotation (#580)
* undo opencascade positioning and rotation * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * use Math.PI * Recentering done * Translation is smooth * Apply suggestions from code review Co-authored-by: martinRenou <[email protected]> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add helping comment * Try fixing exploded view * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * create interface `IMeshGroupMetadata` and assign originalPosition in buildShape * refactor exploded view logic * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * only `newGeometryCenter` is not right * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * expand boundingGroup via meshGroup * Refactoring * Merge review suggestions * `getQuaternion` method * fallback not needed * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * rebase issue * more refactoring * Remove originalPosition refactor groupMetadata * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * in theory, this seems correct * rebase issue fixes * Update packages/base/src/3dview/mainview.tsx Co-authored-by: martinRenou <[email protected]> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * prevent default enabling transform controls * Normalize the axis and quaternion * Apply suggestions from code review Co-authored-by: martinRenou <[email protected]> * Local space and local bounding box * Update Playwright Snapshots --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: martinRenou <[email protected]> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 04617de commit 8ea5fc8

File tree

7 files changed

+114
-31
lines changed

7 files changed

+114
-31
lines changed

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

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js';
99
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
1010
import { LineSegments2 } from 'three/examples/jsm/lines/LineSegments2.js';
11+
import { IJCadObject } from '@jupytercad/schema';
1112

1213
import { getCSSVariableColor } from '../tools';
1314

@@ -64,6 +65,12 @@ export interface IMouseDrag {
6465
end: THREE.Vector2;
6566
}
6667

68+
export interface IMeshGroupMetadata {
69+
type: string;
70+
jcObject: IJCadObject;
71+
[key: string]: any;
72+
}
73+
6774
export function projectVector(options: {
6875
vector: THREE.Vector3;
6976
camera: THREE.Camera;
@@ -81,25 +88,56 @@ export function projectVector(options: {
8188
);
8289
}
8390

91+
export function getQuaternion(jcObject: IJCadObject): THREE.Quaternion {
92+
const placement = jcObject?.parameters?.Placement;
93+
94+
const angle = placement.Angle;
95+
const axis = placement.Axis;
96+
const axisVector = new THREE.Vector3(axis[0], axis[1], axis[2]);
97+
axisVector.normalize();
98+
99+
const angleRad = (angle * Math.PI) / 180;
100+
const halfAngle = angleRad / 2;
101+
const sinHalfAngle = Math.sin(halfAngle);
102+
103+
return new THREE.Quaternion(
104+
axisVector.x * sinHalfAngle,
105+
axisVector.y * sinHalfAngle,
106+
axisVector.z * sinHalfAngle,
107+
Math.cos(halfAngle)
108+
).normalize();
109+
}
110+
84111
export function computeExplodedState(options: {
85112
mesh: BasicMesh;
86113
boundingGroup: THREE.Box3;
87114
factor: number;
88115
}) {
89116
const { mesh, boundingGroup, factor } = options;
90117
const center = new THREE.Vector3();
118+
const meshGroup = mesh.parent as THREE.Object3D;
91119
boundingGroup.getCenter(center);
92120

93121
const oldGeometryCenter = new THREE.Vector3();
94122
mesh.geometry.boundingBox?.getCenter(oldGeometryCenter);
95123

124+
const meshGroupQuaternion = getQuaternion(meshGroup.userData.jcObject);
125+
const meshGroupPositionArray =
126+
meshGroup.userData.jcObject.parameters?.Placement.Position;
127+
const meshGroupPosition = new THREE.Vector3(
128+
meshGroupPositionArray[0],
129+
meshGroupPositionArray[1],
130+
meshGroupPositionArray[2]
131+
);
132+
oldGeometryCenter.applyQuaternion(meshGroupQuaternion).add(meshGroupPosition);
133+
96134
const centerToMesh = new THREE.Vector3(
97135
oldGeometryCenter.x - center.x,
98136
oldGeometryCenter.y - center.y,
99137
oldGeometryCenter.z - center.z
100138
);
101-
const distance = centerToMesh.length() * factor;
102139

140+
const distance = centerToMesh.length() * factor;
103141
centerToMesh.normalize();
104142

105143
const newGeometryCenter = new THREE.Vector3(
@@ -112,7 +150,7 @@ export function computeExplodedState(options: {
112150
oldGeometryCenter,
113151
newGeometryCenter,
114152
vector: centerToMesh,
115-
distance
153+
distance: distance
116154
};
117155
}
118156

@@ -134,18 +172,33 @@ export function buildShape(options: {
134172

135173
const vertices: Array<number> = [];
136174
const triangles: Array<number> = [];
175+
const placement = data?.jcObject?.parameters?.Placement;
176+
const objPosition = placement.Position;
177+
178+
const objQuaternion = getQuaternion(jcObject);
179+
const inverseQuaternion = objQuaternion.clone().invert();
137180

138181
let vInd = 0;
139182
if (faceList.length === 0 && edgeList.length === 0) {
140183
return null;
141184
}
142185
for (const face of faceList) {
143-
// Copy Vertices into three.js Vector3 List
144186
const vertexCoorLength = face.vertexCoord.length;
145-
for (let ii = 0; ii < vertexCoorLength; ii++) {
146-
vertices.push(face.vertexCoord[ii]);
187+
for (let ii = 0; ii < vertexCoorLength; ii += 3) {
188+
const vertex = new THREE.Vector3(
189+
face.vertexCoord[ii],
190+
face.vertexCoord[ii + 1],
191+
face.vertexCoord[ii + 2]
192+
);
193+
// Undo placement from the vertices, we want the placement done on the THREE.Object3D (Mesh), not the geometry
194+
vertex.sub(
195+
new THREE.Vector3(objPosition[0], objPosition[1], objPosition[2])
196+
);
197+
vertex.applyQuaternion(inverseQuaternion);
198+
199+
vertices.push(vertex.x, vertex.y, vertex.z);
147200
}
148-
// Sort Triangles into a three.js Face List
201+
149202
const triIndexesLength = face.triIndexes.length;
150203
for (let i = 0; i < triIndexesLength; i += 3) {
151204
triangles.push(
@@ -246,8 +299,25 @@ export function buildShape(options: {
246299
polygonOffsetFactor: -5,
247300
polygonOffsetUnits: -5
248301
});
302+
303+
const transformedVertices: number[] = [];
304+
for (let i = 0; i < edge.vertexCoord.length; i += 3) {
305+
const vertex = new THREE.Vector3(
306+
edge.vertexCoord[i],
307+
edge.vertexCoord[i + 1],
308+
edge.vertexCoord[i + 2]
309+
);
310+
// Undo placement from the vertices, we want the placement done on the THREE.Object3D (Mesh), not the geometry
311+
vertex.sub(
312+
new THREE.Vector3(objPosition[0], objPosition[1], objPosition[2])
313+
);
314+
vertex.applyQuaternion(inverseQuaternion);
315+
316+
transformedVertices.push(vertex.x, vertex.y, vertex.z);
317+
}
318+
249319
const edgeGeometry = new LineGeometry();
250-
edgeGeometry.setPositions(edge.vertexCoord);
320+
edgeGeometry.setPositions(transformedVertices);
251321
const edgesMesh = new LineSegments2(edgeGeometry, edgeMaterial);
252322
edgesMesh.name = `edge-${objName}-${edgeIdx}`;
253323
edgesMesh.userData = {
@@ -261,7 +331,7 @@ export function buildShape(options: {
261331
edgeIdx++;
262332
}
263333

264-
const bbox = new THREE.Box3().setFromObject(mainMesh);
334+
const bbox = new THREE.Box3().setFromObject(meshGroup);
265335
const size = new THREE.Vector3();
266336
bbox.getSize(size);
267337
const center = new THREE.Vector3();
@@ -275,8 +345,14 @@ export function buildShape(options: {
275345
boundingBox.visible = false;
276346
boundingBox.name = SELECTION_BOUNDING_BOX;
277347
meshGroup.add(boundingBox);
348+
meshGroup.userData.type = 'shape';
278349

279350
meshGroup.add(mainMesh);
280351

352+
meshGroup.applyQuaternion(objQuaternion);
353+
meshGroup.position.copy(
354+
new THREE.Vector3(objPosition[0], objPosition[1], objPosition[2])
355+
);
356+
281357
return { meshGroup, mainMesh, edgesMeshes };
282358
}

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

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ import {
4949
buildShape,
5050
computeExplodedState,
5151
projectVector,
52-
IMouseDrag
52+
IMouseDrag,
53+
IMeshGroupMetadata
5354
} from './helpers';
5455
import { MainViewModel } from './mainviewmodel';
5556
import { Spinner } from './spinner';
@@ -426,11 +427,10 @@ export class MainView extends React.Component<IProps, IStates> {
426427
const obj = this._model.sharedModel.getObjectByName(objectName);
427428

428429
if (obj && obj.parameters && obj.parameters.Placement) {
429-
const positionArray = obj?.parameters?.Placement?.Position;
430430
const newPosition = [
431-
positionArray[0] + updatedPosition.x,
432-
positionArray[1] + updatedPosition.y,
433-
positionArray[2] + updatedPosition.z
431+
updatedPosition.x,
432+
updatedPosition.y,
433+
updatedPosition.z
434434
];
435435

436436
this._mainViewModel.maybeUpdateObjectParameters(objectName, {
@@ -444,6 +444,7 @@ export class MainView extends React.Component<IProps, IStates> {
444444
});
445445
this._scene.add(this._transformControls);
446446
this._transformControls.setMode('translate');
447+
this._transformControls.setSpace('local');
447448
this._transformControls.enabled = false;
448449
this._transformControls.visible = false;
449450

@@ -782,7 +783,7 @@ export class MainView extends React.Component<IProps, IStates> {
782783
if (output) {
783784
const { meshGroup, mainMesh, edgesMeshes } = output;
784785
if (meshGroup.userData.jcObject.visible) {
785-
this._boundingGroup.expandByObject(mainMesh);
786+
this._boundingGroup.expandByObject(meshGroup);
786787
}
787788

788789
// Save original color for the main mesh
@@ -1202,18 +1203,6 @@ export class MainView extends React.Component<IProps, IStates> {
12021203
if (matchingChild) {
12031204
this._transformControls.attach(matchingChild as BasicMesh);
12041205

1205-
const obj = this._model.sharedModel.getObjectByName(selectedMeshName);
1206-
const positionArray = obj?.parameters?.Placement?.Position;
1207-
1208-
if (positionArray && positionArray.length === 3) {
1209-
const positionVector = new THREE.Vector3(
1210-
positionArray[0],
1211-
positionArray[1],
1212-
positionArray[2]
1213-
);
1214-
this._transformControls.position.copy(positionVector);
1215-
}
1216-
12171206
this._transformControls.visible = this.state.transform;
12181207
this._transformControls.enabled = this.state.transform;
12191208

@@ -1506,6 +1495,9 @@ export class MainView extends React.Component<IProps, IStates> {
15061495
this._explodedViewLinesHelperGroup = new THREE.Group();
15071496

15081497
for (const group of this._meshGroup?.children as THREE.Group[]) {
1498+
const groupMetadata = group.userData as IMeshGroupMetadata;
1499+
const positionArray =
1500+
groupMetadata.jcObject.parameters?.Placement.Position;
15091501
const explodedState = computeExplodedState({
15101502
mesh: group.getObjectByName(
15111503
group.name.replace('-group', '')
@@ -1514,8 +1506,13 @@ export class MainView extends React.Component<IProps, IStates> {
15141506
factor: this._explodedView.factor
15151507
});
15161508

1517-
group.position.set(0, 0, 0);
1518-
group.translateOnAxis(explodedState.vector, explodedState.distance);
1509+
group.position.copy(
1510+
new THREE.Vector3(
1511+
positionArray[0] + explodedState.vector.x * explodedState.distance,
1512+
positionArray[1] + explodedState.vector.y * explodedState.distance,
1513+
positionArray[2] + explodedState.vector.z * explodedState.distance
1514+
)
1515+
);
15191516

15201517
// Draw lines
15211518
const material = new THREE.LineBasicMaterial({
@@ -1535,10 +1532,20 @@ export class MainView extends React.Component<IProps, IStates> {
15351532

15361533
this._scene.add(this._explodedViewLinesHelperGroup);
15371534
} else {
1538-
// Exploded view is disabled, we reset the initial positions
1539-
for (const mesh of this._meshGroup?.children as BasicMesh[]) {
1540-
mesh.position.set(0, 0, 0);
1535+
// Reset objects to their original positions
1536+
for (const group of this._meshGroup?.children as THREE.Group[]) {
1537+
const groupMetadata = group.userData as IMeshGroupMetadata;
1538+
const positionArray =
1539+
groupMetadata.jcObject.parameters?.Placement.Position;
1540+
group.position.copy(
1541+
new THREE.Vector3(
1542+
positionArray[0],
1543+
positionArray[1],
1544+
positionArray[2]
1545+
)
1546+
);
15411547
}
1548+
15421549
this._explodedViewLinesHelperGroup?.removeFromParent();
15431550
}
15441551
}
386 Bytes
Loading
-2.85 KB
Loading
-6.34 KB
Loading
-3.14 KB
Loading
-2.15 KB
Loading

0 commit comments

Comments
 (0)