pocket-physics
Version:
Verlet physics extracted from pocket-ces demos
78 lines (68 loc) • 2.46 kB
text/typescript
import { distance, dot, normal, set, sub, v2, Vector2 } from "./v2";
export type PointEdgeProjection<V2 extends Vector2> = {
// distance between the point and the projected point on the line
distance: number;
// dot product between edge normal (perp of endpoint1 -> endpoint2) and normal
// from edge to point. If positive, they are pointing in the same direction
// (aka the point is on the side of the segment in the direction of the
// normal). If negative, the point is on the opposite side. The absolute value
// of this will always match the distance.
similarity: number;
// What percentage along the line the projection is. < 0 means behind the
// edge, > 1 means ahead of the edge endpoints.
u: number;
// The point in absolute space of the projection along the edge
projectedPoint: V2;
// The normal of the edge (endpoint1 -> endpoint2): Given v1(0,0) -> v2(10, 0), the normal will be (0, 1)
edgeNormal: V2;
};
/**
* Create a pre-made result object for tests.
*/
export function createPointEdgeProjectionResult<
V extends number
>(): PointEdgeProjection<Vector2<V>> {
return {
distance: Number.MIN_SAFE_INTEGER,
similarity: 0,
u: Number.MIN_SAFE_INTEGER,
projectedPoint: v2(),
edgeNormal: v2(),
};
}
const edgeDelta = v2();
const perp = v2();
export function projectPointEdge(
point: Vector2,
endpoint1: Vector2,
endpoint2: Vector2,
result: PointEdgeProjection<Vector2>
) {
sub(edgeDelta, endpoint2, endpoint1);
if (edgeDelta.x === 0 && edgeDelta.y === 0) {
throw new Error("ZeroLengthEdge");
}
// http://paulbourke.net/geometry/pointlineplane/
// http://paulbourke.net/geometry/pointlineplane/DistancePoint.java
const u =
((point.x - endpoint1.x) * edgeDelta.x +
(point.y - endpoint1.y) * edgeDelta.y) /
(edgeDelta.x * edgeDelta.x + edgeDelta.y * edgeDelta.y);
result.u = u;
const proj = set(
result.projectedPoint,
endpoint1.x + u * edgeDelta.x,
endpoint1.y + u * edgeDelta.y
);
result.distance = distance(proj, point);
// given:
// E1----------------------E2 Proj
// | |
// | EdgeNorm | perp
// | Point
//
// What is the similarity (dot product) between EdgeNorm and Perp?
const edgeNorm = normal(result.edgeNormal, endpoint1, endpoint2);
sub(perp, point, proj);
result.similarity = dot(edgeNorm, perp);
}