Download src/client/transform-tool.mjs from xlt99/EmboDi: direct link, hf CLI and curl.
- Browser
- Download file 3.08 kB
-
https://huggingface.co/spaces/xlt99/EmboDi/resolve/main/src/client/transform-tool.mjs
- Command line
-
hf download hf://spaces/xlt99/EmboDi/src/client/transform-tool.mjs
-
curl -L -o transform-tool.mjs https://huggingface.co/spaces/xlt99/EmboDi/resolve/main/src/client/transform-tool.mjs
3.08 kB
| import * as THREE from "three"; | |
| import { transformTargets, transformUpdates, wrapYaw } from "../shared/transforms.mjs"; | |
| function createTransformTool({ world, getState, spatialKey, onEvent = () => { | |
| } }) { | |
| let drag = null; | |
| function intersection(ray, y) { | |
| world.updateMatrixWorld(true); | |
| const local = ray.ray.clone().applyMatrix4(world.matrixWorld.clone().invert()); | |
| if (Math.abs(local.direction.y) < 0.06) return null; | |
| const p = local.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 1, 0), -y), new THREE.Vector3()); | |
| return p && p.distanceTo(local.origin) < 50 ? p : null; | |
| } | |
| function begin(ids, pivot, ray) { | |
| if (drag) return false; | |
| const targets = structuredClone(transformTargets(getState().scene, ids)), point = intersection(ray, pivot[1]); | |
| if (!point) throw new Error("Point slightly downward, then hold the trigger to adjust again"); | |
| drag = { revision: getState().revision, key: spatialKey(), targets, point, translation: [0, 0, 0], yaw: 0, pivot: [...pivot], axisHeld: false, changed: false }; | |
| onEvent("transform-begin", { ids: targets.map((o) => o.id), pivot, revision: drag.revision }); | |
| return true; | |
| } | |
| function update(ray, dt, x = 0, y = 0) { | |
| if (!drag) return; | |
| if (drag.revision !== getState().revision || drag.key !== spatialKey()) { | |
| cancel("Scene or alignment changed"); | |
| return; | |
| } | |
| x = Math.abs(x) > 0.2 ? x : 0; | |
| y = Math.abs(y) > 0.2 ? y : 0; | |
| const point = intersection(ray, drag.pivot[1]); | |
| if (x || y) { | |
| drag.yaw = wrapYaw(drag.yaw - x * dt * Math.PI / 3); | |
| drag.translation[1] = THREE.MathUtils.clamp(drag.translation[1] - y * dt * 0.4, -20, 20); | |
| drag.axisHeld = true; | |
| } else if (point) { | |
| if (drag.axisHeld) { | |
| drag.point.copy(point).sub(new THREE.Vector3(drag.translation[0], 0, drag.translation[2])); | |
| drag.axisHeld = false; | |
| } else { | |
| drag.translation[0] = point.x - drag.point.x; | |
| drag.translation[2] = point.z - drag.point.z; | |
| } | |
| } | |
| drag.changed = Math.hypot(...drag.translation) > 5e-3 || Math.abs(drag.yaw) > 2e-3; | |
| } | |
| const operation = () => drag ? { ids: drag.targets.map((o) => o.id), pivot: [...drag.pivot], translation: [...drag.translation], yaw: drag.yaw } : null; | |
| function cancel(reason = "Cancelled by user") { | |
| if (drag) onEvent("transform-cancel", { reason, operation: operation() }); | |
| drag = null; | |
| } | |
| return { begin, update, cancel, active: () => !!drag, operation, revision: () => drag?.revision, changed: () => !!drag?.changed, updates: () => drag ? transformUpdates(drag.targets, operation()) : [], finish() { | |
| const result = drag && { revision: drag.revision, operation: operation(), changed: drag.changed }; | |
| drag = null; | |
| return result; | |
| } }; | |
| } | |
| function createNavigationGate() { | |
| let blocked = false; | |
| return { block() { | |
| blocked = true; | |
| }, sample(axes) { | |
| if (blocked && axes.every((v) => Math.abs(v) < 0.17)) blocked = false; | |
| return !blocked; | |
| }, blocked: () => blocked }; | |
| } | |
| export { | |
| createNavigationGate, | |
| createTransformTool | |
| }; | |