Skip to content

Commit a7cfbf4

Browse files
committed
fix applying options to rotation
1 parent 5b32f6c commit a7cfbf4

File tree

2 files changed

+49
-40
lines changed

2 files changed

+49
-40
lines changed

examples/handle/door.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,20 @@ export function Door(props: JSX.IntrinsicElements['group']) {
4141
material={materials.Door}
4242
position={[0.852, 0.017, 0.782]}
4343
/>
44-
<group position={[0.81, 0.043, 0.803]}>
45-
<HandleTarget>
46-
<Handle
47-
stopPropagation={false}
48-
translate={false}
49-
scale={false}
50-
rotate={{ x: false, y: true, z: false }}
51-
>
52-
<mesh geometry={nodes.Circle002_Glossy_0.geometry} material={materials.Glossy} />
53-
</Handle>
54-
</HandleTarget>
55-
</group>
44+
<Handle translate="as-rotate" rotate={{ x: false, y: false, z: [-Math.PI, 0] }}>
45+
<group position={[0.81, 0.043, 0.803]}>
46+
<HandleTarget>
47+
<Handle
48+
stopPropagation={false}
49+
translate={false}
50+
scale={false}
51+
rotate={{ x: false, y: [-Math.PI / 2, 0], z: false }}
52+
>
53+
<mesh geometry={nodes.Circle002_Glossy_0.geometry} material={materials.Glossy} />
54+
</Handle>
55+
</HandleTarget>
56+
</group>
57+
</Handle>
5658
</HandleTarget>
5759
</group>
5860
<mesh geometry={nodes.Plane002_Glossy_0.geometry} material={materials.Glossy} />

packages/handle/src/computations/utils.ts

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Euler, Matrix4, Plane, Quaternion, Vector3, Vector3Tuple } from 'three'
1+
import { Euler, EulerOrder, Matrix4, Plane, Quaternion, Vector3, Vector3Tuple } from 'three'
22
import { Axis, HandleTransformState } from '../state.js'
33
import { HandleOptions, HandleTransformOptions } from '../store.js'
44
import { clamp } from 'three/src/math/MathUtils.js'
@@ -13,6 +13,12 @@ export type BaseHandleStoreData = {
1313
initialTargetScale: Vector3
1414
}
1515

16+
const axisFirstOrder = {
17+
x: 'XYZ',
18+
y: 'YXZ',
19+
z: 'ZXY',
20+
}
21+
1622
export function computeHandleTransformState(
1723
time: number,
1824
pointerAmount: number,
@@ -47,6 +53,7 @@ export function computeHandleTransformState(
4753
quaternion.copy(storeData.initialTargetQuaternion)
4854
rotation = storeData.initialTargetRotation.clone()
4955
} else if (
56+
Array.isArray(rotateOptions) ||
5057
rotateOptions === true ||
5158
(typeof rotateOptions != 'string' &&
5259
!Array.isArray(rotateOptions) &&
@@ -55,6 +62,18 @@ export function computeHandleTransformState(
5562
rotateOptions.z === true)
5663
) {
5764
rotation = new Euler().setFromQuaternion(quaternion, storeData.initialTargetRotation.order)
65+
} else if (typeof rotateOptions === 'string') {
66+
const order = axisFirstOrder[rotateOptions]
67+
rotation = new Euler().setFromQuaternion(quaternion)
68+
for (const orderElement of order) {
69+
const axis = orderElement.toLowerCase() as Axis
70+
if (axis === rotateOptions) {
71+
continue
72+
}
73+
rotation[axis] = 0
74+
}
75+
rotation.order = storeData.initialTargetRotation.order
76+
quaternion.setFromEuler(rotation)
5877
} else {
5978
rotation = applyTransformOptionsToRotation(quaternion, storeData.initialTargetRotation, rotateOptions)
6079
}
@@ -105,39 +124,28 @@ function getPerpendicular(target: Vector3, from: Vector3): void {
105124
target.set(-from.y, from.x, 0)
106125
}
107126

108-
const quaternionHelper = new Quaternion()
109-
const eulerHelper = new Euler()
110-
111127
export function applyTransformOptionsToRotation(
112128
currentRotation: Quaternion,
113129
initialRotation: Euler,
114-
options: HandleTransformOptions,
130+
options: Exclude<HandleTransformOptions, boolean | Array<Vector3Tuple> | Axis>,
115131
): Euler {
116-
const result = new Euler(0, 0, 0, initialRotation.order)
117-
let inverted = false
118-
for (const axisElement of initialRotation.order) {
119-
const axis = axisElement.toLowerCase() as Axis
120-
const axisAngle =
121-
eulerHelper.setFromQuaternion(currentRotation, initialRotation.order)[axis] + (inverted ? Math.PI : 0)
122-
const transformedAxisAngle = Array.isArray(options)
123-
? axisAngle
124-
: applyTransformOptionsToAxis(axis, axisAngle, initialRotation[axis], options)
125-
126-
if (Math.abs(axisAngle - transformedAxisAngle) > Math.PI / 2) {
127-
inverted = !inverted
128-
}
129-
130-
if (axisAngle != transformedAxisAngle) {
131-
//currentRotation = currentRotation * result-1 * delta * result
132-
currentRotation.multiply(quaternionHelper.setFromEuler(result).invert())
133-
const delta = axisAngle - transformedAxisAngle
134-
result[axis] = delta
135-
currentRotation.multiply(quaternionHelper.setFromEuler(result))
132+
let orderEnabledAxis = ''
133+
let orderDisabledAxis = ''
134+
for (const orderElement of initialRotation.order) {
135+
if (options[orderElement.toLowerCase() as Axis] === false) {
136+
orderDisabledAxis += orderElement
137+
} else {
138+
orderEnabledAxis += orderElement
136139
}
137-
138-
result[axis] = transformedAxisAngle
140+
}
141+
const order = (orderEnabledAxis + orderDisabledAxis) as EulerOrder
142+
const result = new Euler().setFromQuaternion(currentRotation, order)
143+
for (const orderElement of order) {
144+
const axis = orderElement.toLowerCase() as Axis
145+
result[axis] = applyTransformOptionsToAxis(axis, result[axis], initialRotation[axis], options)
139146
}
140147
currentRotation.setFromEuler(result)
148+
result.setFromQuaternion(currentRotation, initialRotation.order)
141149
return result
142150
}
143151

@@ -453,7 +461,6 @@ export function projectOntoAxis(
453461
//angleDifference is between 3° and 6°
454462
//factor = 1 means that we want 100% from worldPoint and 0 from project point
455463
const factor = (angleDifference - _3Degree) / _3Degree
456-
console.log(factor)
457464
projectPointOntoAxis(vectorHelper, initialWorldPoint, axis)
458465
worldPoint.multiplyScalar(factor).addScaledVector(vectorHelper, 1 - factor)
459466
}

0 commit comments

Comments
 (0)