@pmndrs/handle
Advanced tools
Comparing version 6.4.12-alpha.31 to 6.4.12-alpha.33
@@ -9,2 +9,3 @@ import { Euler, Matrix4, Quaternion, Vector3 } from 'three'; | ||
pointerWorldPoint: Vector3; | ||
pointerWorldOrigin: Vector3; | ||
pointerWorldDirection: Vector3 | undefined; | ||
@@ -11,0 +12,0 @@ pointerWorldQuaternion: Quaternion; |
@@ -31,3 +31,3 @@ import { Matrix4, Quaternion, Vector3 } from 'three'; | ||
//matrixHelper2 = initialPointerToTargetParentOffset | ||
projectOntoSpace(spaceHelper, pointerData.initialPointerWorldPoint, vectorHelper1.copy(pointerData.pointerWorldPoint), pointerData.pointerWorldDirection); | ||
projectOntoSpace(spaceHelper, pointerData.initialPointerWorldPoint, pointerData.pointerWorldOrigin, vectorHelper1.copy(pointerData.pointerWorldPoint), pointerData.pointerWorldDirection); | ||
quaternionHelper.copy(pointerData.pointerWorldQuaternion); | ||
@@ -34,0 +34,0 @@ if ((options.rotate ?? true) === false) { |
@@ -9,2 +9,3 @@ import { Matrix4, Quaternion, Vector3 } from 'three'; | ||
pointerWorldQuaternion: Quaternion; | ||
pointerWorldOrigin: Vector3; | ||
prevPointerWorldQuaternion: Quaternion; | ||
@@ -11,0 +12,0 @@ initialPointerWorldPoint: Vector3; |
@@ -35,8 +35,8 @@ import { Matrix4, Quaternion, Vector3 } from 'three'; | ||
deltaHelper1.setFromMatrixPosition(matrixHelper); | ||
projectOntoSpace(space, pointerData.initialPointerWorldPoint, deltaHelper1, undefined); | ||
projectOntoSpace(space, pointerData.initialPointerWorldPoint, pointerData.pointerWorldOrigin, deltaHelper1, undefined); | ||
deltaHelper1.negate().add(pointerData.initialPointerWorldPoint); | ||
//compute current delta between point and target projected on space | ||
deltaHelper2.setFromMatrixPosition(targetWorldMatrix); | ||
projectOntoSpace(space, pointerData.initialPointerWorldPoint, deltaHelper2, undefined); | ||
projectOntoSpace(space, pointerData.initialPointerWorldPoint, vectorHelper2.copy(pointerData.pointerWorldPoint), pointerData.pointerWorldDirection); | ||
projectOntoSpace(space, pointerData.initialPointerWorldPoint, pointerData.pointerWorldOrigin, deltaHelper2, undefined); | ||
projectOntoSpace(space, pointerData.initialPointerWorldPoint, pointerData.pointerWorldOrigin, vectorHelper2.copy(pointerData.pointerWorldPoint), pointerData.pointerWorldDirection); | ||
deltaHelper2.negate().add(vectorHelper2); | ||
@@ -43,0 +43,0 @@ //compute delta rotation |
@@ -9,2 +9,3 @@ import { Euler, Matrix4, Quaternion, Vector3 } from 'three'; | ||
pointerWorldPoint: Vector3; | ||
pointerWorldOrigin: Vector3; | ||
pointerWorldDirection: Vector3 | undefined; | ||
@@ -11,0 +12,0 @@ pointerWorldQuaternion: Quaternion; |
@@ -30,4 +30,4 @@ import { Matrix4, Quaternion, Vector3 } from 'three'; | ||
//project pointers into that space | ||
projectOntoSpace(space, pointer1Data.initialPointerWorldPoint, vectorHelper1.copy(pointer1Data.pointerWorldPoint), pointer1Data.pointerWorldDirection); | ||
projectOntoSpace(space, pointer2Data.initialPointerWorldPoint, vectorHelper2.copy(pointer2Data.pointerWorldPoint), pointer2Data.pointerWorldDirection); | ||
projectOntoSpace(space, pointer1Data.initialPointerWorldPoint, pointer1Data.pointerWorldOrigin, vectorHelper1.copy(pointer1Data.pointerWorldPoint), pointer1Data.pointerWorldDirection); | ||
projectOntoSpace(space, pointer2Data.initialPointerWorldPoint, pointer2Data.pointerWorldOrigin, vectorHelper2.copy(pointer2Data.pointerWorldPoint), pointer2Data.pointerWorldDirection); | ||
//compute delta of pointers | ||
@@ -34,0 +34,0 @@ deltaHelper1.copy(pointer2Data.initialPointerWorldPoint).sub(pointer1Data.initialPointerWorldPoint); |
@@ -1,3 +0,3 @@ | ||
import { Euler, Matrix4, Quaternion, Vector3 } from 'three'; | ||
import { HandleTransformState } from '../state.js'; | ||
import { Euler, Matrix4, Quaternion, Vector3, Vector3Tuple } from 'three'; | ||
import { Axis, HandleTransformState } from '../state.js'; | ||
import { HandleOptions, HandleTransformOptions } from '../store.js'; | ||
@@ -14,4 +14,4 @@ export type BaseHandleStoreData = { | ||
export declare function getDeltaQuaternionOnAxis(normalizedAxis: Vector3, from: Quaternion, to: Quaternion): number; | ||
export declare function applyTransformOptionsToRotation(currentRotation: Quaternion, initialRotation: Euler, options: HandleTransformOptions): Euler; | ||
export declare function projectOntoSpace(space: Array<Vector3>, initialWorldPoint: Vector3, worldPoint: Vector3, worldDirection: Vector3 | undefined): void; | ||
export declare function applyTransformOptionsToRotation(currentRotation: Quaternion, initialRotation: Euler, options: Exclude<HandleTransformOptions, boolean | Array<Vector3Tuple> | Axis>): Euler; | ||
export declare function projectOntoSpace(space: Array<Vector3>, initialWorldPoint: Vector3, worldPointerOrigin: Vector3, worldPoint: Vector3, worldDirection: Vector3 | undefined): void; | ||
export declare function addSpaceFromTransformOptions(target: Array<Vector3>, parentWorldQuaternion: Quaternion, initialLocalRotation: Euler, options: HandleTransformOptions, type: 'translate' | 'rotate' | 'scale'): void; | ||
@@ -21,3 +21,4 @@ /** | ||
*/ | ||
export declare function projectOntoAxis(initialWorldPoint: Vector3, axis: Vector3, worldPoint: Vector3, worldDirection: Vector3 | undefined): void; | ||
export declare function projectOntoAxis(initialWorldPoint: Vector3, axis: Vector3, worldPointerOrigin: Vector3, worldPoint: Vector3, worldDirection: Vector3 | undefined): void; | ||
export declare function projectPointOntoAxis(target: Vector3, axisOrigin: Vector3, axisNormal: Vector3): void; | ||
export declare function projectPointOntoNormal(point: Vector3, normal: Vector3): void; |
@@ -5,2 +5,7 @@ import { Euler, Matrix4, Plane, Quaternion, Vector3 } from 'three'; | ||
const matrixHelper2 = new Matrix4(); | ||
const axisFirstOrder = { | ||
x: 'XYZ', | ||
y: 'YXZ', | ||
z: 'ZXY', | ||
}; | ||
export function computeHandleTransformState(time, pointerAmount, targetWorldMatrix, storeData, targetParentWorldMatrix, options) { | ||
@@ -28,3 +33,4 @@ matrixHelper1.copy(targetWorldMatrix); | ||
} | ||
else if (rotateOptions === true || | ||
else if (Array.isArray(rotateOptions) || | ||
rotateOptions === true || | ||
(typeof rotateOptions != 'string' && | ||
@@ -37,2 +43,15 @@ !Array.isArray(rotateOptions) && | ||
} | ||
else if (typeof rotateOptions === 'string') { | ||
const order = axisFirstOrder[rotateOptions]; | ||
rotation = new Euler().setFromQuaternion(quaternion); | ||
for (const orderElement of order) { | ||
const axis = orderElement.toLowerCase(); | ||
if (axis === rotateOptions) { | ||
continue; | ||
} | ||
rotation[axis] = 0; | ||
} | ||
rotation.order = storeData.initialTargetRotation.order; | ||
quaternion.setFromEuler(rotation); | ||
} | ||
else { | ||
@@ -82,26 +101,21 @@ rotation = applyTransformOptionsToRotation(quaternion, storeData.initialTargetRotation, rotateOptions); | ||
} | ||
const quaternionHelper = new Quaternion(); | ||
const eulerHelper = new Euler(); | ||
export function applyTransformOptionsToRotation(currentRotation, initialRotation, options) { | ||
const result = new Euler(0, 0, 0, initialRotation.order); | ||
let inverted = false; | ||
for (const axisElement of initialRotation.order) { | ||
const axis = axisElement.toLowerCase(); | ||
const axisAngle = eulerHelper.setFromQuaternion(currentRotation, initialRotation.order)[axis] + (inverted ? Math.PI : 0); | ||
const transformedAxisAngle = Array.isArray(options) | ||
? axisAngle | ||
: applyTransformOptionsToAxis(axis, axisAngle, initialRotation[axis], options); | ||
if (Math.abs(axisAngle - transformedAxisAngle) > Math.PI / 2) { | ||
inverted = !inverted; | ||
let orderEnabledAxis = ''; | ||
let orderDisabledAxis = ''; | ||
for (const orderElement of initialRotation.order) { | ||
if (options[orderElement.toLowerCase()] === false) { | ||
orderDisabledAxis += orderElement; | ||
} | ||
if (axisAngle != transformedAxisAngle) { | ||
//currentRotation = currentRotation * result-1 * delta * result | ||
currentRotation.multiply(quaternionHelper.setFromEuler(result).invert()); | ||
const delta = axisAngle - transformedAxisAngle; | ||
result[axis] = delta; | ||
currentRotation.multiply(quaternionHelper.setFromEuler(result)); | ||
else { | ||
orderEnabledAxis += orderElement; | ||
} | ||
result[axis] = transformedAxisAngle; | ||
} | ||
const order = (orderEnabledAxis + orderDisabledAxis); | ||
const result = new Euler().setFromQuaternion(currentRotation, order); | ||
for (const orderElement of order) { | ||
const axis = orderElement.toLowerCase(); | ||
result[axis] = applyTransformOptionsToAxis(axis, result[axis], initialRotation[axis], options); | ||
} | ||
currentRotation.setFromEuler(result); | ||
result.setFromQuaternion(currentRotation, initialRotation.order); | ||
return result; | ||
@@ -127,4 +141,3 @@ } | ||
applyTransformPlane.setFromNormalAndCoplanarPoint(applyTransformNormal, initialVector); | ||
const distanceToPlane = planeHelper.distanceToPoint(target); | ||
target.addScaledVector(applyTransformNormal, -distanceToPlane); | ||
applyTransformPlane.projectPoint(target, target); | ||
return; | ||
@@ -158,3 +171,3 @@ } | ||
} | ||
export function projectOntoSpace(space, initialWorldPoint, worldPoint, worldDirection) { | ||
export function projectOntoSpace(space, initialWorldPoint, worldPointerOrigin, worldPoint, worldDirection) { | ||
switch (space.length) { | ||
@@ -165,6 +178,6 @@ case 0: | ||
case 1: | ||
projectOntoAxis(initialWorldPoint, ...space, worldPoint, worldDirection); | ||
projectOntoAxis(initialWorldPoint, ...space, worldPointerOrigin, worldPoint, worldDirection); | ||
return; | ||
case 2: | ||
projectOntoPlane(initialWorldPoint, ...space, worldPoint, worldDirection); | ||
projectOntoPlane(...space, initialWorldPoint, worldPointerOrigin, worldPoint, worldDirection); | ||
return; | ||
@@ -291,25 +304,42 @@ } | ||
const normalHelper = new Vector3(); | ||
function projectOntoPlane(initialWorldPoint, _axis1, _axis2, worldPoint, worldDirection) { | ||
const vectorHelper = new Vector3(); | ||
const _3Degree = (3 / 180) * Math.PI; | ||
const _6Degree = (6 / 180) * Math.PI; | ||
function projectOntoPlane(_axis1, _axis2, initialWorldPoint, worldPointerOrigin, worldPoint, worldDirection) { | ||
normalHelper.crossVectors(_axis1, _axis2).normalize(); | ||
planeHelper.setFromNormalAndCoplanarPoint(normalHelper, initialWorldPoint); | ||
if (worldDirection == null || Math.abs(normalHelper.dot(worldDirection)) < 0.001) { | ||
const angleDifference = worldDirection == null ? 0 : Math.abs(normalHelper.dot(worldDirection)); | ||
if (worldDirection == null || angleDifference < _3Degree) { | ||
//project point onto plane | ||
planeHelper.projectPoint(worldPoint, worldPoint); | ||
return; | ||
} | ||
const distanceToPlane = planeHelper.distanceToPoint(worldPoint); | ||
let distanceAlongDirection = distanceToPlane / worldDirection.dot(planeHelper.normal); | ||
worldPoint.addScaledVector(worldDirection, -distanceAlongDirection); | ||
//project ray onto plane | ||
const distanceToPlane = planeHelper.distanceToPoint(worldPointerOrigin); | ||
const distanceAlongDirection = -distanceToPlane / worldDirection.dot(planeHelper.normal); | ||
if (distanceAlongDirection < 0) { | ||
//project point onto plane | ||
planeHelper.projectPoint(worldPoint, worldPoint); | ||
return; | ||
} | ||
vectorHelper.copy(worldPoint); | ||
worldPoint.copy(worldPointerOrigin).addScaledVector(worldDirection, distanceAlongDirection); | ||
if (angleDifference < _6Degree) { | ||
//angleDifference is between 3° and 6° | ||
//factor = 1 means that we want 100% from worldPoint and 0 from project point | ||
const factor = (angleDifference - _3Degree) / _3Degree; | ||
planeHelper.projectPoint(vectorHelper, vectorHelper); | ||
worldPoint.multiplyScalar(factor).addScaledVector(vectorHelper, 1 - factor); | ||
} | ||
} | ||
const vectorHelper = new Vector3(); | ||
/** | ||
* finds the intersection between the given axis (infinite line) and another infinite line provided with point and direction | ||
*/ | ||
export function projectOntoAxis(initialWorldPoint, axis, worldPoint, worldDirection) { | ||
if (worldDirection == null || Math.abs(axis.dot(worldDirection)) > 0.999) { | ||
worldPoint.sub(initialWorldPoint); | ||
projectPointOntoNormal(worldPoint, axis); | ||
worldPoint.add(initialWorldPoint); | ||
export function projectOntoAxis(initialWorldPoint, axis, worldPointerOrigin, worldPoint, worldDirection) { | ||
const angleDifference = worldDirection == null ? 0 : 1 - Math.abs(axis.dot(worldDirection)); | ||
if (worldDirection == null || angleDifference < _3Degree) { | ||
projectPointOntoAxis(worldPoint, initialWorldPoint, axis); | ||
return; | ||
} | ||
vectorHelper.subVectors(worldPoint, initialWorldPoint); | ||
vectorHelper.subVectors(worldPointerOrigin, initialWorldPoint); | ||
// 2. Calculate the dot products needed | ||
@@ -322,5 +352,23 @@ const d1d2 = axis.dot(worldDirection); | ||
const t = (d1p1p2 - d1d2 * d2p1p2) / denominator; | ||
const s = (d1d2 * d1p1p2 - d2p1p2) / denominator; | ||
if (s < 0) { | ||
projectPointOntoAxis(worldPoint, initialWorldPoint, axis); | ||
return; | ||
} | ||
vectorHelper.copy(worldPoint); | ||
// 4. Calculate the nearest point on the first line | ||
worldPoint.copy(initialWorldPoint).addScaledVector(axis, t); | ||
if (angleDifference < _6Degree) { | ||
//angleDifference is between 3° and 6° | ||
//factor = 1 means that we want 100% from worldPoint and 0 from project point | ||
const factor = (angleDifference - _3Degree) / _3Degree; | ||
projectPointOntoAxis(vectorHelper, initialWorldPoint, axis); | ||
worldPoint.multiplyScalar(factor).addScaledVector(vectorHelper, 1 - factor); | ||
} | ||
} | ||
export function projectPointOntoAxis(target, axisOrigin, axisNormal) { | ||
target.sub(axisOrigin); | ||
projectPointOntoNormal(target, axisNormal); | ||
target.add(axisOrigin); | ||
} | ||
export function projectPointOntoNormal(point, normal) { | ||
@@ -327,0 +375,0 @@ const dot = point.dot(normal); |
@@ -48,2 +48,3 @@ import { Euler, Object3D, Quaternion, Vector3 } from 'three'; | ||
pointerWorldPoint: event.point, | ||
pointerWorldOrigin: event.pointerPosition, | ||
pointerWorldQuaternion: event.pointerQuaternion, | ||
@@ -89,2 +90,3 @@ initialPointerWorldPoint: event.point.clone(), | ||
entry.pointerWorldQuaternion = event.pointerQuaternion; | ||
entry.pointerWorldOrigin = event.pointerPosition; | ||
if (entry.pointerWorldDirection != null) { | ||
@@ -91,0 +93,0 @@ getWorldDirection(event, entry.pointerWorldDirection); |
@@ -7,3 +7,3 @@ { | ||
"homepage": "https://github.com/pmndrs/xr", | ||
"version": "6.4.12-alpha.31", | ||
"version": "6.4.12-alpha.33", | ||
"keywords": [ | ||
@@ -24,3 +24,3 @@ "r3f", | ||
"dependencies": { | ||
"@pmndrs/pointer-events": "^6.4.12-alpha.31" | ||
"@pmndrs/pointer-events": "^6.4.12-alpha.33" | ||
}, | ||
@@ -27,0 +27,0 @@ "files": [ |
63310
1465