|
|
import _extends from '@babel/runtime/helpers/esm/extends'; |
|
|
import { useThree, useFrame } from '@react-three/fiber'; |
|
|
import * as React from 'react'; |
|
|
import * as THREE from 'three'; |
|
|
import { AxisArrow } from './AxisArrow.js'; |
|
|
import { AxisRotator } from './AxisRotator.js'; |
|
|
import { PlaneSlider } from './PlaneSlider.js'; |
|
|
import { ScalingSphere } from './ScalingSphere.js'; |
|
|
import { context } from './context.js'; |
|
|
import { calculateScaleFactor } from '../../core/calculateScaleFactor.js'; |
|
|
|
|
|
const mL0 = new THREE.Matrix4(); |
|
|
const mW0 = new THREE.Matrix4(); |
|
|
const mP = new THREE.Matrix4(); |
|
|
const mPInv = new THREE.Matrix4(); |
|
|
const mW = new THREE.Matrix4(); |
|
|
const mL = new THREE.Matrix4(); |
|
|
const mL0Inv = new THREE.Matrix4(); |
|
|
const mdL = new THREE.Matrix4(); |
|
|
const mG = new THREE.Matrix4(); |
|
|
const bb = new THREE.Box3(); |
|
|
const bbObj = new THREE.Box3(); |
|
|
const vCenter = new THREE.Vector3(); |
|
|
const vSize = new THREE.Vector3(); |
|
|
const vAnchorOffset = new THREE.Vector3(); |
|
|
const vPosition = new THREE.Vector3(); |
|
|
const vScale = new THREE.Vector3(); |
|
|
const xDir = new THREE.Vector3(1, 0, 0); |
|
|
const yDir = new THREE.Vector3(0, 1, 0); |
|
|
const zDir = new THREE.Vector3(0, 0, 1); |
|
|
const PivotControls = React.forwardRef(({ |
|
|
enabled = true, |
|
|
matrix, |
|
|
onDragStart, |
|
|
onDrag, |
|
|
onDragEnd, |
|
|
autoTransform = true, |
|
|
anchor, |
|
|
disableAxes = false, |
|
|
disableSliders = false, |
|
|
disableRotations = false, |
|
|
disableScaling = false, |
|
|
activeAxes = [true, true, true], |
|
|
offset = [0, 0, 0], |
|
|
rotation = [0, 0, 0], |
|
|
scale = 1, |
|
|
lineWidth = 4, |
|
|
fixed = false, |
|
|
translationLimits, |
|
|
rotationLimits, |
|
|
scaleLimits, |
|
|
depthTest = true, |
|
|
axisColors = ['#ff2060', '#20df80', '#2080ff'], |
|
|
hoveredColor = '#ffff40', |
|
|
annotations = false, |
|
|
annotationsClass, |
|
|
opacity = 1, |
|
|
visible = true, |
|
|
userData, |
|
|
children, |
|
|
...props |
|
|
}, fRef) => { |
|
|
const invalidate = useThree(state => state.invalidate); |
|
|
const parentRef = React.useRef(null); |
|
|
const ref = React.useRef(null); |
|
|
const gizmoRef = React.useRef(null); |
|
|
const childrenRef = React.useRef(null); |
|
|
const translation = React.useRef([0, 0, 0]); |
|
|
const cameraScale = React.useRef(new THREE.Vector3(1, 1, 1)); |
|
|
const gizmoScale = React.useRef(new THREE.Vector3(1, 1, 1)); |
|
|
React.useLayoutEffect(() => { |
|
|
if (!anchor) return; |
|
|
childrenRef.current.updateWorldMatrix(true, true); |
|
|
mPInv.copy(childrenRef.current.matrixWorld).invert(); |
|
|
bb.makeEmpty(); |
|
|
childrenRef.current.traverse(obj => { |
|
|
if (!obj.geometry) return; |
|
|
if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox(); |
|
|
mL.copy(obj.matrixWorld).premultiply(mPInv); |
|
|
bbObj.copy(obj.geometry.boundingBox); |
|
|
bbObj.applyMatrix4(mL); |
|
|
bb.union(bbObj); |
|
|
}); |
|
|
vCenter.copy(bb.max).add(bb.min).multiplyScalar(0.5); |
|
|
vSize.copy(bb.max).sub(bb.min).multiplyScalar(0.5); |
|
|
vAnchorOffset.copy(vSize).multiply(new THREE.Vector3(...anchor)).add(vCenter); |
|
|
vPosition.set(...offset).add(vAnchorOffset); |
|
|
gizmoRef.current.position.copy(vPosition); |
|
|
invalidate(); |
|
|
}); |
|
|
const config = React.useMemo(() => ({ |
|
|
onDragStart: props => { |
|
|
mL0.copy(ref.current.matrix); |
|
|
mW0.copy(ref.current.matrixWorld); |
|
|
onDragStart && onDragStart(props); |
|
|
invalidate(); |
|
|
}, |
|
|
onDrag: mdW => { |
|
|
mP.copy(parentRef.current.matrixWorld); |
|
|
mPInv.copy(mP).invert(); |
|
|
|
|
|
mW.copy(mW0).premultiply(mdW); |
|
|
mL.copy(mW).premultiply(mPInv); |
|
|
mL0Inv.copy(mL0).invert(); |
|
|
mdL.copy(mL).multiply(mL0Inv); |
|
|
if (autoTransform) { |
|
|
ref.current.matrix.copy(mL); |
|
|
} |
|
|
onDrag && onDrag(mL, mdL, mW, mdW); |
|
|
invalidate(); |
|
|
}, |
|
|
onDragEnd: () => { |
|
|
if (onDragEnd) onDragEnd(); |
|
|
invalidate(); |
|
|
}, |
|
|
translation, |
|
|
translationLimits, |
|
|
rotationLimits, |
|
|
axisColors, |
|
|
hoveredColor, |
|
|
opacity, |
|
|
scale, |
|
|
lineWidth, |
|
|
fixed, |
|
|
depthTest, |
|
|
userData, |
|
|
annotations, |
|
|
annotationsClass |
|
|
}), [onDragStart, onDrag, onDragEnd, translation, translationLimits, rotationLimits, scaleLimits, depthTest, scale, lineWidth, fixed, ...axisColors, hoveredColor, opacity, userData, autoTransform, annotations, annotationsClass]); |
|
|
const vec = new THREE.Vector3(); |
|
|
useFrame(state => { |
|
|
if (fixed) { |
|
|
const sf = calculateScaleFactor(gizmoRef.current.getWorldPosition(vec), scale, state.camera, state.size); |
|
|
cameraScale.current.setScalar(sf); |
|
|
} |
|
|
if (matrix && matrix instanceof THREE.Matrix4) { |
|
|
ref.current.matrix = matrix; |
|
|
} |
|
|
|
|
|
|
|
|
ref.current.updateWorldMatrix(true, true); |
|
|
mG.makeRotationFromEuler(gizmoRef.current.rotation).setPosition(gizmoRef.current.position).premultiply(ref.current.matrixWorld); |
|
|
gizmoScale.current.setFromMatrixScale(mG); |
|
|
vScale.copy(cameraScale.current).divide(gizmoScale.current); |
|
|
if (Math.abs(gizmoRef.current.scale.x - vScale.x) > 1e-4 || Math.abs(gizmoRef.current.scale.y - vScale.y) > 1e-4 || Math.abs(gizmoRef.current.scale.z - vScale.z) > 1e-4) { |
|
|
gizmoRef.current.scale.copy(vScale); |
|
|
state.invalidate(); |
|
|
} |
|
|
}); |
|
|
React.useImperativeHandle(fRef, () => ref.current, []); |
|
|
return React.createElement(context.Provider, { |
|
|
value: config |
|
|
}, React.createElement("group", { |
|
|
ref: parentRef |
|
|
}, React.createElement("group", _extends({ |
|
|
ref: ref, |
|
|
matrix: matrix, |
|
|
matrixAutoUpdate: false |
|
|
}, props), React.createElement("group", { |
|
|
visible: visible, |
|
|
ref: gizmoRef, |
|
|
position: offset, |
|
|
rotation: rotation |
|
|
}, enabled && React.createElement(React.Fragment, null, !disableAxes && activeAxes[0] && React.createElement(AxisArrow, { |
|
|
axis: 0, |
|
|
direction: xDir |
|
|
}), !disableAxes && activeAxes[1] && React.createElement(AxisArrow, { |
|
|
axis: 1, |
|
|
direction: yDir |
|
|
}), !disableAxes && activeAxes[2] && React.createElement(AxisArrow, { |
|
|
axis: 2, |
|
|
direction: zDir |
|
|
}), !disableSliders && activeAxes[0] && activeAxes[1] && React.createElement(PlaneSlider, { |
|
|
axis: 2, |
|
|
dir1: xDir, |
|
|
dir2: yDir |
|
|
}), !disableSliders && activeAxes[0] && activeAxes[2] && React.createElement(PlaneSlider, { |
|
|
axis: 1, |
|
|
dir1: zDir, |
|
|
dir2: xDir |
|
|
}), !disableSliders && activeAxes[2] && activeAxes[1] && React.createElement(PlaneSlider, { |
|
|
axis: 0, |
|
|
dir1: yDir, |
|
|
dir2: zDir |
|
|
}), !disableRotations && activeAxes[0] && activeAxes[1] && React.createElement(AxisRotator, { |
|
|
axis: 2, |
|
|
dir1: xDir, |
|
|
dir2: yDir |
|
|
}), !disableRotations && activeAxes[0] && activeAxes[2] && React.createElement(AxisRotator, { |
|
|
axis: 1, |
|
|
dir1: zDir, |
|
|
dir2: xDir |
|
|
}), !disableRotations && activeAxes[2] && activeAxes[1] && React.createElement(AxisRotator, { |
|
|
axis: 0, |
|
|
dir1: yDir, |
|
|
dir2: zDir |
|
|
}), !disableScaling && activeAxes[0] && React.createElement(ScalingSphere, { |
|
|
axis: 0, |
|
|
direction: xDir |
|
|
}), !disableScaling && activeAxes[1] && React.createElement(ScalingSphere, { |
|
|
axis: 1, |
|
|
direction: yDir |
|
|
}), !disableScaling && activeAxes[2] && React.createElement(ScalingSphere, { |
|
|
axis: 2, |
|
|
direction: zDir |
|
|
}))), React.createElement("group", { |
|
|
ref: childrenRef |
|
|
}, children)))); |
|
|
}); |
|
|
|
|
|
export { PivotControls }; |
|
|
|