(active)
| 2391 | if (!mesh) return; |
| 2392 | _raycaster.setFromCamera(_canvasNDC(e), getCamera()); |
| 2393 | const hits = _raycaster.intersectObject(mesh); |
| 2394 | const hit = getFrontFaceHit(hits, mesh); |
| 2395 | if (!hit) return; |
| 2396 | |
| 2397 | // Get the face normal (mesh has identity transform) |
| 2398 | const faceNormal = hit.face.normal.clone().normalize(); |
| 2399 | |
| 2400 | // Compute quaternion that rotates faceNormal to -Z (face down on print bed) |
| 2401 | const targetDir = new THREE.Vector3(0, 0, -1); |
| 2402 | const quat = new THREE.Quaternion().setFromUnitVectors(faceNormal, targetDir); |
| 2403 | |
| 2404 | // Apply rotation to all vertex positions |
| 2405 | const pos = currentGeometry.attributes.position.array; |
| 2406 | const v = new THREE.Vector3(); |
| 2407 | for (let i = 0; i < pos.length; i += 3) { |
| 2408 | v.set(pos[i], pos[i + 1], pos[i + 2]); |
| 2409 | v.applyQuaternion(quat); |
| 2410 | pos[i] = v.x; |
| 2411 | pos[i + 1] = v.y; |
| 2412 | pos[i + 2] = v.z; |
| 2413 | } |
| 2414 | |
| 2415 | // Fold the rotation into the pose transform (undone again on export). |
| 2416 | currentPoseRot.premultiply(quat).normalize(); |
| 2417 | currentPoseTrans.applyQuaternion(quat); |
| 2418 | |
| 2419 | // Re-center geometry |
| 2420 | currentGeometry.computeBoundingBox(); |
| 2421 | const center = new THREE.Vector3(); |
| 2422 | currentGeometry.boundingBox.getCenter(center); |
| 2423 | currentGeometry.translate(-center.x, -center.y, -center.z); |
| 2424 | currentPoseTrans.sub(center); |
no test coverage detected