Skip to content

Commit

Permalink
feat(🧮): New 4x4 matrices functions
Browse files Browse the repository at this point in the history
  • Loading branch information
wcandillon authored May 4, 2020
1 parent f64823b commit 460ab5d
Show file tree
Hide file tree
Showing 11 changed files with 396 additions and 25 deletions.
36 changes: 36 additions & 0 deletions packages/core/src/Gesture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,42 @@ export const panGestureHandler = () => {
};
};

export const pinchGestureHandler = () => {
const focal = vec.create(0, 0);
const rotation = new Value(0);
const state = new Value(State.UNDETERMINED);
const gestureHandler = onGestureEvent({
focalX: focal.x,
focalY: focal.y,
rotation,
state,
});
return {
rotation,
state,
gestureHandler,
focal,
};
};

export const rotationGestureHandler = () => {
const anchor = vec.create(0, 0);
const rotation = new Value(0);
const state = new Value(State.UNDETERMINED);
const gestureHandler = onGestureEvent({
anchorX: anchor.x,
anchorY: anchor.y,
rotation,
state,
});
return {
rotation,
state,
gestureHandler,
anchor,
};
};

export const horizontalPanGestureHandler = () => {
const x = new Value(0);
const translationX = new Value(0);
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/Hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
horizontalPanGestureHandler,
onGestureEvent,
panGestureHandler,
pinchGestureHandler,
rotationGestureHandler,
verticalPanGestureHandler,
} from "./Gesture";
import { vec } from "./Vectors";
Expand All @@ -25,6 +27,10 @@ export const useGestureHandler = (
) => useLazyRef(() => onGestureEvent(nativeEvent));

export const usePanGestureHandler = () => useLazyRef(() => panGestureHandler());
export const useRotationGestureHandler = () =>
useLazyRef(() => rotationGestureHandler());
export const usePinchGestureHandler = () =>
useLazyRef(() => pinchGestureHandler());

export const useVerticalPanGestureHandler = () =>
useLazyRef(() => verticalPanGestureHandler());
Expand Down
11 changes: 10 additions & 1 deletion packages/core/src/Math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,23 @@ export const min = (...args: Animated.Adaptable<number>[]) =>
export const max = (...args: Animated.Adaptable<number>[]) =>
args.reduce((acc, arg) => max2(acc, arg));

export const minus = (x: Animated.Node<number>) => multiply(-1, x);

export const avg = (
...v: [
Animated.Adaptable<number>,
Animated.Adaptable<number>,
...Animated.Adaptable<number>[]
]
) => divide(add(...v), v.length);

export const mix = proc(
(
value: Animated.Adaptable<number>,
x: Animated.Adaptable<number>,
y: Animated.Adaptable<number>
) => add(x, multiply(value, sub(y, x)))
);
// x + (value * (y - x))

export const clamp = proc(
(
Expand Down
83 changes: 77 additions & 6 deletions packages/core/src/Matrix.ts → packages/core/src/Matrix3.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Animated from "react-native-reanimated";
import { atan2 } from "./Math";
import { Vector } from "./Vectors";

const {
add,
Expand All @@ -23,7 +24,7 @@ export type Vec3 = readonly [

export type Matrix3 = readonly [Vec3, Vec3, Vec3];

type TransformName =
type Transform2dName =
| "translateX"
| "translateY"
| "scale"
Expand All @@ -33,8 +34,10 @@ type TransformName =
| "scaleY"
| "rotateZ"
| "rotate";
type Transformations = { [Name in TransformName]: Animated.Adaptable<number> };
export type Transforms = (
type Transformations = {
[Name in Transform2dName]: Animated.Adaptable<number>;
};
export type Transforms2d = (
| Pick<Transformations, "translateX">
| Pick<Transformations, "translateY">
| Pick<Transformations, "scale">
Expand Down Expand Up @@ -109,7 +112,7 @@ export const dot3 = (row: Vec3, col: Vec3) =>
multiply(row[2], col[2])
);

export const matrixVecMul = (m: Matrix3, v: Vec3) =>
export const matrixVecMul3 = (m: Matrix3, v: Vec3) =>
[dot3(m[0], v), dot3(m[1], v), dot3(m[2], v)] as const;

export const multiply3 = (m1: Matrix3, m2: Matrix3) => {
Expand All @@ -123,9 +126,9 @@ export const multiply3 = (m1: Matrix3, m2: Matrix3) => {
] as const;
};

export const processTransform = (transforms: Transforms) =>
export const processTransform2d = (transforms: Transforms2d) =>
transforms.reduce((acc, transform) => {
const key = Object.keys(transform)[0] as TransformName;
const key = Object.keys(transform)[0] as Transform2dName;
const value = (transform as Pick<Transformations, typeof key>)[key];
if (key === "translateX") {
return multiply3(acc, translateXMatrix(value));
Expand Down Expand Up @@ -184,3 +187,71 @@ export const decompose2d = (m: Matrix3) => {
skewX: multiply(-1, theta),
};
};

const adjugate = (m: Matrix3) => {
return [
[
sub(multiply(m[1][1], m[2][2]), multiply(m[1][2], m[2][1])),
sub(multiply(m[0][2], m[2][1]), multiply(m[0][1], m[2][2])),
sub(multiply(m[0][1], m[1][2]), multiply(m[0][2], m[1][1])),
],
[
sub(multiply(m[1][2], m[2][0]), multiply(m[1][0], m[2][2])),
sub(multiply(m[0][0], m[2][2]), multiply(m[0][2], m[2][0])),
sub(multiply(m[0][2], m[1][0]), multiply(m[0][0], m[1][2])),
],
[
sub(multiply(m[1][0], m[2][1]), multiply(m[1][1], m[2][0])),
sub(multiply(m[0][1], m[2][0]), multiply(m[0][0], m[2][1])),
sub(multiply(m[0][0], m[1][1]), multiply(m[0][1], m[1][0])),
],
] as const;
};

interface Quadrilateral {
p1: Vector;
p2: Vector;
p3: Vector;
p4: Vector;
}

interface Parameters {
canvas: Quadrilateral;
projected: Quadrilateral;
}

const basisToPoints = ({ p1, p2, p3, p4 }: Quadrilateral) => {
const m = [
[p1.x, p2.x, p3.x],
[p1.y, p2.y, p3.y],
[1, 1, 1],
] as const;
const v = matrixVecMul3(adjugate(m), [p4.x, p4.y, 1]);
return multiply3(m, [
[v[0], 0, 0],
[0, v[1], 0],
[0, 0, v[2]],
]);
};

// https://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript
// https://franklinta.com/2014/09/08/computing-css-matrix3d-transforms/
// http://jsfiddle.net/dFrHS/1/
export const transform2d = (params: Parameters) => {
const s = basisToPoints(params.canvas);
const d = basisToPoints(params.projected);
const t = multiply3(d, adjugate(s));
return [
[
divide(t[0][0], t[2][2]),
divide(t[0][1], t[2][2]),
divide(t[0][2], t[2][2]),
],
[
divide(t[1][0], t[2][2]),
divide(t[1][1], t[2][2]),
divide(t[1][2], t[2][2]),
],
[divide(t[2][0], t[2][2]), divide(t[2][1], t[2][2]), 1],
] as const;
};
Loading

0 comments on commit 460ab5d

Please sign in to comment.