Skip to content

Commit

Permalink
feat(geom): add/update edges(), pointInside() & classifyPoint() impls
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Jan 18, 2019
1 parent f5a53ca commit e834597
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 38 deletions.
4 changes: 4 additions & 0 deletions packages/geom3/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export * from "./ops/classify-point";
export * from "./ops/clip-convex";
export * from "./ops/closest-point";
export * from "./ops/convex-hull";
export * from "./ops/edges";
export * from "./ops/fit-into-bounds";
export * from "./ops/intersects";
export * from "./ops/map-point";
Expand All @@ -51,10 +52,12 @@ export * from "./ops/with-attribs";
export * from "./internal/bounds";
export * from "./internal/centroid";
export * from "./internal/circumcenter";
export * from "./internal/clockwise";
export * from "./internal/closest-point";
export * from "./internal/copy-points";
export * from "./internal/corner";
export * from "./internal/douglas–peucker";
export * from "./internal/edges";
export * from "./internal/graham-scan";
export * from "./internal/liang-barsky";
export * from "./internal/poly-arc-length";
Expand All @@ -65,6 +68,7 @@ export * from "./internal/sampler";
export * from "./internal/subdiv-curve";
export * from "./internal/sutherland-hodgeman";
export * from "./internal/transform-points";
export * from "./internal/triangle-point-inside";
export * from "./internal/union-bounds";

export * from "./isec/circle-circle";
Expand Down
5 changes: 5 additions & 0 deletions packages/geom3/src/internal/clockwise.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ReadonlyVec, signedArea2 } from "@thi.ng/vectors3";

export const clockwise2 =
(a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec) =>
signedArea2(a, b, c) < 0;
28 changes: 2 additions & 26 deletions packages/geom3/src/internal/corner.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,6 @@
import { EPS, sign } from "@thi.ng/math";
import { ReadonlyVec, signedArea2 } from "@thi.ng/vectors3";

export const classify =
export const corner =
(a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec, eps = EPS) =>
sign(signedArea2(a, b, c), eps);

export const clockwise2 =
(a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec) =>
signedArea2(a, b, c) < 0;

export const classifyPointInTriangle2 =
(p: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec) => {
const s = clockwise2(a, b, c) ? 1 : -1;
return sign(
Math.min(
s * signedArea2(a, c, p),
s * signedArea2(b, a, p),
s * signedArea2(c, b, p)
)
);
};

export const pointInTriangle2 =
(p: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec) => {
const s = clockwise2(a, b, c) ? 1 : -1;
return s * signedArea2(a, c, p) >= 0 &&
s * signedArea2(b, a, p) >= 0 &&
s * signedArea2(c, b, p) >= 0;
};
sign(signedArea2(a, b, c), eps);
12 changes: 12 additions & 0 deletions packages/geom3/src/internal/edges.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { partition, wrap } from "@thi.ng/transducers";
import { ReadonlyVec } from "@thi.ng/vectors3";
import { VecPair } from "../api";

export const edgeIterator =
(vertices: Iterable<ReadonlyVec>, closed = false) =>
<IterableIterator<VecPair>>partition(
2, 1,
closed ?
wrap(vertices, 1, false, true) :
vertices
);
12 changes: 12 additions & 0 deletions packages/geom3/src/internal/point-in-array.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { EPS } from "@thi.ng/math";
import { eqDelta, ReadonlyVec } from "@thi.ng/vectors3";

export const pointInArray =
(points: ReadonlyVec[], p: ReadonlyVec, eps = EPS) => {
for (let i = points.length; --i >= 0;) {
if (eqDelta(p, points[i], eps)) {
return true;
}
}
return false;
};
8 changes: 4 additions & 4 deletions packages/geom3/src/internal/sutherland-hodgeman.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ReadonlyVec } from "@thi.ng/vectors3";
import { classify } from "./corner";
import { corner } from "./corner";
import { intersectLineLine } from "../isec/line-line";

/**
Expand All @@ -20,12 +20,12 @@ export const sutherlandHodgeman =
const clipped = [];
const ca = bounds[j];
const cb = bounds[i];
const sign = classify(ca, cb, bc, eps);
const sign = corner(ca, cb, bc, eps);
for (let np = pts.length, k = np - 1, l = 0; l < np; k = l, l++) {
const p = pts[k];
const q = pts[l];
const cqsign = classify(ca, cb, q, eps);
if (classify(ca, cb, p, eps) === sign) {
const cqsign = corner(ca, cb, q, eps);
if (corner(ca, cb, p, eps) === sign) {
clipped.push(
cqsign !== sign ?
intersectLineLine(ca, cb, p, q).isec :
Expand Down
24 changes: 24 additions & 0 deletions packages/geom3/src/internal/triangle-point-inside.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { EPS, sign } from "@thi.ng/math";
import { ReadonlyVec, signedArea2 } from "@thi.ng/vectors3";
import { clockwise2 } from "./clockwise";

export const classifyPointInTriangle2 =
(p: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec, eps = EPS) => {
const s = clockwise2(a, b, c) ? 1 : -1;
return sign(
Math.min(
s * signedArea2(a, c, p),
s * signedArea2(b, a, p),
s * signedArea2(c, b, p)
),
eps
);
};

export const pointInTriangle2 =
(p: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec) => {
const s = clockwise2(a, b, c) ? 1 : -1;
return s * signedArea2(a, c, p) >= 0 &&
s * signedArea2(b, a, p) >= 0 &&
s * signedArea2(c, b, p) >= 0;
};
11 changes: 8 additions & 3 deletions packages/geom3/src/ops/classify-point.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { defmulti } from "@thi.ng/defmulti";
import { defmulti, MultiFn2O } from "@thi.ng/defmulti";
import { EPS, sign } from "@thi.ng/math";
import { dist, ReadonlyVec } from "@thi.ng/vectors3";
import { Circle, IShape, Type } from "../api";
import { Circle, IShape, Type, Triangle } from "../api";
import { dispatch } from "../internal/dispatch";
import { classifyPointInTriangle2 } from "../internal/triangle-point-inside";

export const classifyPoint = defmulti<IShape, ReadonlyVec, number>(dispatch);
export const classifyPoint: MultiFn2O<IShape, ReadonlyVec, number, number> = defmulti(dispatch);

classifyPoint.addAll({

[Type.CIRCLE]:
($: Circle, p: ReadonlyVec, eps = EPS) =>
sign($.r - dist($.pos, p), eps),

[Type.TRIANGLE]:
({ points }: Triangle, p: ReadonlyVec, eps = EPS) =>
classifyPointInTriangle2(p, points[0], points[1], points[2], eps),

});
35 changes: 35 additions & 0 deletions packages/geom3/src/ops/edges.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { defmulti, MultiFn1O } from "@thi.ng/defmulti";
import {
IShape,
Polygon,
Polyline,
SamplingOpts,
Type,
VecPair,
Rect
} from "../api";
import { dispatch } from "../internal/dispatch";
import { edgeIterator } from "../internal/edges";
import { vertices } from "./vertices";

export const edges: MultiFn1O<IShape, number | Partial<SamplingOpts>, Iterable<VecPair>> = defmulti(dispatch);

edges.addAll({

[Type.POLYGON]:
($: Polygon) =>
edgeIterator($.points, true),

[Type.POLYLINE]:
($: Polyline) =>
edgeIterator($.points),

[Type.RECT]:
($: Rect) =>
edgeIterator(vertices($), true),

});

edges.isa(Type.LINE, Type.POLYLINE);
edges.isa(Type.QUAD, Type.POLYGON);
edges.isa(Type.TRIANGLE, Type.POLYGON);
19 changes: 15 additions & 4 deletions packages/geom3/src/ops/point-inside.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { defmulti } from "@thi.ng/defmulti";
import { distSq, ReadonlyVec } from "@thi.ng/vectors3";
import { distSq, ReadonlyVec, Vec } from "@thi.ng/vectors3";
import {
AABB,
Circle,
IShape,
Rect,
Type,
Points,
Polygon,
AABB
Rect,
Triangle,
Type
} from "../api";
import { dispatch } from "../internal/dispatch";
import { pointInArray } from "../internal/point-in-array";
import { polyPointInside } from "../internal/poly-point-inside";
import { pointInTriangle2 } from "../internal/triangle-point-inside";

export const pointInside = defmulti<IShape, ReadonlyVec, boolean>(dispatch);

Expand All @@ -25,6 +29,10 @@ pointInside.addAll({
($: Circle, p) =>
distSq($.pos, p) <= $.r * $.r,

[Type.POINTS]:
({ points }: Points, p) =>
pointInArray(points, p),

[Type.POLYGON]:
($: Polygon, p) =>
polyPointInside($.points, p) > 0,
Expand All @@ -34,6 +42,9 @@ pointInside.addAll({
x >= pos[0] && x <= pos[0] + size[0] &&
y >= pos[1] && y <= pos[1] + size[1],

[Type.TRIANGLE]:
(tri: Triangle, p: ReadonlyVec) =>
pointInTriangle2(p, ...<[Vec, Vec, Vec]>tri.points),
});

pointInside.isa(Type.SPHERE, Type.CIRCLE);
Expand Down
2 changes: 1 addition & 1 deletion packages/geom3/src/ops/tessellate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from "@thi.ng/vectors3";
import { Tessellator } from "../api";
import { centroidRaw } from "../internal/centroid";
import { pointInTriangle2 } from "../internal/corner";
import { pointInTriangle2 } from "../internal/triangle-point-inside";
import { polyArea } from "../internal/poly-area";

const snip = (
Expand Down

0 comments on commit e834597

Please sign in to comment.