From d09cc795254bf62b87861b66b8419b7547062417 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Thu, 17 Jan 2019 02:49:19 +0000 Subject: [PATCH] feat(geom): add clipConvex, scatter, warpPoints --- packages/geom3/package.json | 3 ++- packages/geom3/src/api.ts | 30 ++++++++++++++++++++----- packages/geom3/src/index.ts | 5 +++++ packages/geom3/src/ops/as-polygon.ts | 1 + packages/geom3/src/ops/clip-convex.ts | 31 ++++++++++++++++++++++++++ packages/geom3/src/ops/scatter.ts | 22 ++++++++++++++++++ packages/geom3/src/ops/warp-points.ts | 13 +++++++++++ packages/geom3/src/ops/with-attribs.ts | 7 ++++++ 8 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 packages/geom3/src/ops/clip-convex.ts create mode 100644 packages/geom3/src/ops/scatter.ts create mode 100644 packages/geom3/src/ops/warp-points.ts create mode 100644 packages/geom3/src/ops/with-attribs.ts diff --git a/packages/geom3/package.json b/packages/geom3/package.json index bbc4ffebcc..9dda804af2 100644 --- a/packages/geom3/package.json +++ b/packages/geom3/package.json @@ -16,7 +16,7 @@ "scripts": { "build": "yarn clean && yarn build:es6 && yarn build:bundle", "build:es6": "tsc --declaration", - "build:bundle": "../../scripts/bundle-module geom3 api checks defmulti equiv errors hiccup hiccup-svg math matrices transducers vectors3", + "build:bundle": "../../scripts/bundle-module geom3 api checks defmulti equiv errors hiccup hiccup-svg math matrices random transducers vectors3", "test": "rimraf build && tsc -p test/tsconfig.json && nyc mocha build/test/*.js", "clean": "rimraf *.js *.d.ts .nyc_output build coverage doc lib", "cover": "yarn test && nyc report --reporter=lcov", @@ -41,6 +41,7 @@ "@thi.ng/hiccup-svg": "^2.0.10", "@thi.ng/math": "^0.2.2", "@thi.ng/matrices": "^0.0.1", + "@thi.ng/random": "^0.1.1", "@thi.ng/transducers": "^2.3.2", "@thi.ng/vectors3": "^0.0.1" }, diff --git a/packages/geom3/src/api.ts b/packages/geom3/src/api.ts index f785d6fd20..74185add69 100644 --- a/packages/geom3/src/api.ts +++ b/packages/geom3/src/api.ts @@ -5,6 +5,7 @@ import { illegalState } from "@thi.ng/errors"; import { cossin } from "@thi.ng/math"; import { add2, + add3, maddN2, mul2, ReadonlyVec, @@ -77,6 +78,8 @@ export interface IShape extends export interface AABBLike extends IShape { pos: Vec; size: Vec; + + max(): Vec; } export interface IHiccupShape extends IShape, IToHiccup { } @@ -184,7 +187,7 @@ export abstract class APC implements } export class AABB implements - IShape { + AABBLike { pos: Vec; size: Vec; @@ -203,8 +206,13 @@ export class AABB implements copy() { return new AABB(set([], this.pos), set([], this.size), { ...this.attribs }); } + + max() { + return add3([], this.pos, this.size); + } } + export class Arc implements IHiccupShape, IHiccupPathSegment { @@ -488,7 +496,8 @@ export class Path implements } } -export class Points extends APC { +export class Points extends APC implements + IHiccupShape { get type() { return Type.POINTS; @@ -503,7 +512,8 @@ export class Points extends APC { } } -export class Polygon extends APC { +export class Polygon extends APC implements + IHiccupShape { get type() { return Type.POLYGON; @@ -543,7 +553,8 @@ export class Polyline extends APC implements } } -export class Quad extends APC { +export class Quad extends APC implements + IHiccupShape { get type() { return Type.QUAD; @@ -559,6 +570,7 @@ export class Quad extends APC { } export class Quadratic extends APC implements + IHiccupShape, IHiccupPathSegment { get type() { @@ -611,6 +623,7 @@ export class Ray implements } export class Rect implements + AABBLike, IHiccupShape { pos: Vec; @@ -631,13 +644,17 @@ export class Rect implements return new Rect(set([], this.pos), set([], this.size), { ...this.attribs }); } + max() { + return add2([], this.pos, this.size); + } + toHiccup() { return ["rect", this.attribs, this.pos, this.size]; } } export class Sphere implements - IShape { + IHiccupShape { pos: Vec; r: number; @@ -662,7 +679,8 @@ export class Sphere implements } } -export class Triangle extends APC { +export class Triangle extends APC implements + IHiccupShape { get type() { return Type.TRIANGLE; diff --git a/packages/geom3/src/index.ts b/packages/geom3/src/index.ts index 3e08dc0e39..9161fa5fd0 100644 --- a/packages/geom3/src/index.ts +++ b/packages/geom3/src/index.ts @@ -7,6 +7,7 @@ export * from "./ctors/ellipse"; export * from "./ctors/group"; export * from "./ctors/line"; export * from "./ctors/path"; +export * from "./ctors/points"; export * from "./ctors/polygon"; export * from "./ctors/polyline"; export * from "./ctors/quad"; @@ -23,6 +24,7 @@ export * from "./ops/bounds"; export * from "./ops/center"; export * from "./ops/centroid"; export * from "./ops/classify-point"; +export * from "./ops/clip-convex"; export * from "./ops/closest-point"; export * from "./ops/convex-hull"; export * from "./ops/fit-into-bounds"; @@ -30,6 +32,7 @@ export * from "./ops/map-point"; export * from "./ops/point-at"; export * from "./ops/point-inside"; export * from "./ops/resample"; +export * from "./ops/scatter"; export * from "./ops/simplify"; export * from "./ops/split-at"; export * from "./ops/subdiv-curve"; @@ -39,6 +42,8 @@ export * from "./ops/translate"; export * from "./ops/union"; export * from "./ops/unmap-point"; export * from "./ops/vertices"; +export * from "./ops/warp-points"; +export * from "./ops/with-attribs"; export * from "./internal/bounds"; export * from "./internal/centroid"; diff --git a/packages/geom3/src/ops/as-polygon.ts b/packages/geom3/src/ops/as-polygon.ts index b43dfc9fdd..5a82145e28 100644 --- a/packages/geom3/src/ops/as-polygon.ts +++ b/packages/geom3/src/ops/as-polygon.ts @@ -20,6 +20,7 @@ asPolygon.addAll({ asPolygon.isa(Type.CIRCLE, Type.POINTS); asPolygon.isa(Type.ELLIPSE, Type.POINTS); asPolygon.isa(Type.LINE, Type.POINTS); +asPolygon.isa(Type.PATH, Type.POINTS); asPolygon.isa(Type.POLYGON, Type.POINTS); asPolygon.isa(Type.POLYLINE, Type.POINTS); asPolygon.isa(Type.QUAD, Type.POINTS); diff --git a/packages/geom3/src/ops/clip-convex.ts b/packages/geom3/src/ops/clip-convex.ts new file mode 100644 index 0000000000..cc4da93295 --- /dev/null +++ b/packages/geom3/src/ops/clip-convex.ts @@ -0,0 +1,31 @@ +import { defmulti } from "@thi.ng/defmulti"; +import { IShape, Polygon, Type } from "../api"; +import { dispatch } from "../internal/dispatch"; +import { sutherlandHodgeman } from "../internal/sutherland-hodgeman"; +import { vertices } from "./vertices"; +import { centroid } from "./centroid"; + +export const clipConvex = defmulti(dispatch); + +clipConvex.addAll({ + + [Type.POLYGON]: + ($: Polygon, boundary: IShape) => + new Polygon( + sutherlandHodgeman($.points, vertices(boundary), centroid(boundary)), + { ...$.attribs } + ), + + [Type.RECT]: + ($, boundary: IShape) => + new Polygon( + sutherlandHodgeman(vertices($), vertices(boundary), centroid(boundary)), + { ...$.attribs } + ) +}); + +clipConvex.isa(Type.CIRCLE, Type.RECT); +clipConvex.isa(Type.ELLIPSE, Type.RECT); +clipConvex.isa(Type.PATH, Type.RECT); +clipConvex.isa(Type.QUAD, Type.POLYGON); +clipConvex.isa(Type.TRIANGLE, Type.POLYGON); diff --git a/packages/geom3/src/ops/scatter.ts b/packages/geom3/src/ops/scatter.ts new file mode 100644 index 0000000000..72d9f79d66 --- /dev/null +++ b/packages/geom3/src/ops/scatter.ts @@ -0,0 +1,22 @@ +import { IShape } from "../api"; +import { Vec, randMinMax } from "@thi.ng/vectors3"; +import { SYSTEM } from "@thi.ng/random"; +import { bounds } from "./bounds"; +import { pointInside } from "./point-inside"; + +export const scatter = + (shape: IShape, num: number, rnd = SYSTEM, out: Vec[] = []) => { + const b = bounds(shape); + const mi = b.pos; + const mx = b.max(); + for (; --num >= 0;) { + while (true) { + const p = randMinMax([], mi, mx, rnd); + if (pointInside(shape, p)) { + out.push(p); + break; + } + } + } + return out; + }; diff --git a/packages/geom3/src/ops/warp-points.ts b/packages/geom3/src/ops/warp-points.ts new file mode 100644 index 0000000000..414c5bd3a4 --- /dev/null +++ b/packages/geom3/src/ops/warp-points.ts @@ -0,0 +1,13 @@ +import { ReadonlyVec, Vec } from "@thi.ng/vectors3"; +import { IShape } from "../api"; +import { mapPoint } from "./map-point"; +import { unmapPoint } from "./unmap-point"; + +export const warpPoints = + (pts: ReadonlyVec[], dest: IShape, src: IShape) => { + const res: Vec[] = []; + for (let n = pts.length, i = 0; i < n; i++) { + res.push(unmapPoint(dest, mapPoint(src, pts[i]))); + } + return res; + }; diff --git a/packages/geom3/src/ops/with-attribs.ts b/packages/geom3/src/ops/with-attribs.ts new file mode 100644 index 0000000000..b1000a4c23 --- /dev/null +++ b/packages/geom3/src/ops/with-attribs.ts @@ -0,0 +1,7 @@ +import { Attribs, IShape } from "../api"; + +export const withAttribs = + (shape: IShape, attribs: Attribs, replace = true) => { + shape.attribs = replace ? attribs : { ...shape.attribs, ...attribs }; + return shape; + };