Skip to content

Commit

Permalink
feat(geom-closest-point): add fns for more shape types
Browse files Browse the repository at this point in the history
- closestPointLine
- distToLine
- closestPointPlane
- closestPointCircle/Sphere
- closestPointAABB/Rect
  • Loading branch information
postspectacular committed Apr 14, 2019
1 parent b1db275 commit 5ae2887
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 1 deletion.
14 changes: 14 additions & 0 deletions packages/geom-closest-point/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ This project is part of the

Closest point / proximity helpers.

- `closestPointAABB`
- `closestPointArray`
- `closestPointCircle`
- `closestPointLine`
- `closestPointPlane`
- `closestPointPolyline`
- `closestPointRect`
- `closestPointSphere`
- `closestPointSegment`

- `closestT`
- `distToLine`
- `distToSegment`

## Installation

```bash
Expand Down
1 change: 1 addition & 0 deletions packages/geom-closest-point/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"typescript": "^3.4.1"
},
"dependencies": {
"@thi.ng/math": "^1.2.2",
"@thi.ng/vectors": "^2.5.2"
},
"keywords": [
Expand Down
126 changes: 125 additions & 1 deletion packages/geom-closest-point/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { clamp } from "@thi.ng/math";
import {
add,
dist,
distSq,
dot,
empty,
magSq,
mixN,
normalize,
ReadonlyVec,
set,
setC2,
setC3,
sub,
Vec
} from "@thi.ng/vectors";
Expand All @@ -24,6 +29,9 @@ import {
* projected point lies outside the line segment. Returns `undefined` if
* `a` and `b` are coincident.
*
* @see closestPointLine
* @see closestPointSegment
*
* @param p
* @param a
* @param b
Expand All @@ -34,6 +42,37 @@ export const closestT = (p: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec) => {
return l > 1e-6 ? dot(sub([], p, a), d) / l : undefined;
};

/**
* Returns closest point to `p` on infinite line defined by points `a`
* and `b`. Use `closestPointSegment` to only consider the actual line
* segment between these two points.
*
* @see closestPointSegment
*
* @param p
* @param a
* @param b
*/
export const closestPointLine = (
p: ReadonlyVec,
a: ReadonlyVec,
b: ReadonlyVec
) => mixN([], a, b, closestT(p, a, b));

/**
* Returns distance from `p` to closest point to infinite line `a` ->
* `b`. Use `distToSegment` to only consider the actual line segment
* between these two points.
*
* @see distToSegment
*
* @param p
* @param a
* @param b
*/
export const distToLine = (p: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec) =>
dist(p, closestPointLine(p, a, b) || a);

/**
* Returns closest point to `p` on line segment `a` -> `b`. By default,
* if the result point lies outside the segment, returns a copy of the
Expand Down Expand Up @@ -73,7 +112,8 @@ export const closestPointSegment = (
};

/**
* Returns distance from `p` to closest point on line `a` -> `b`.
* Returns distance from `p` to closest point on line segment `a` ->
* `b`.
*
* @param p
* @param a
Expand Down Expand Up @@ -157,3 +197,87 @@ export const closestPointArray = (p: ReadonlyVec, pts: Vec[]) => {
}
return closest;
};

export const closestPointPlane = (
p: ReadonlyVec,
normal: ReadonlyVec,
w: number,
out: Vec = []
) => {
out = normalize(out, normal, dot(p, normal) + w);
return sub(out, p, out);
};

export const closestPointCircle = (
p: ReadonlyVec,
c: ReadonlyVec,
r: number,
out: Vec = []
) => add(out, c, normalize(out, sub(out, p, c), r));

export const closestPointSphere = closestPointCircle;

export const closestPointRect = (
p: ReadonlyVec,
bmin: ReadonlyVec,
bmax: ReadonlyVec,
out: Vec = []
) => {
let minD = Infinity;
let minID: number;
let minW: number;
for (let i = 0; i < 4; i++) {
const j = i >> 1;
const w = (i & 1 ? bmax : bmin)[j];
const d = Math.abs(p[j] - w);
if (d < minD) {
minD = d;
minID = j;
minW = w;
}
}
return minID === 0
? setC2(out, minW, clamp(p[1], bmin[1], bmax[1]))
: setC2(out, clamp(p[0], bmin[0], bmax[0]), minW);
};

export const closestPointAABB = (
p: ReadonlyVec,
bmin: ReadonlyVec,
bmax: ReadonlyVec,
out: Vec = []
) => {
let minD = Infinity;
let minID: number;
let minW: number;
for (let i = 0; i < 6; i++) {
const j = i >> 1;
const w = (i & 1 ? bmax : bmin)[j];
const d = Math.abs(p[j] - w);
if (d < minD) {
minD = d;
minID = j;
minW = w;
}
}
return minID === 0
? setC3(
out,
minW,
clamp(p[1], bmin[1], bmax[1]),
clamp(p[2], bmin[2], bmax[2])
)
: minID === 1
? setC3(
out,
clamp(p[0], bmin[0], bmax[0]),
minW,
clamp(p[2], bmin[2], bmax[2])
)
: setC3(
out,
clamp(p[0], bmin[0], bmax[0]),
clamp(p[1], bmin[1], bmax[1]),
minW
);
};

0 comments on commit 5ae2887

Please sign in to comment.