Skip to content

Commit

Permalink
refactor(geom): add interfaces, split out common.ts into /func folder
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Sep 29, 2018
1 parent 34312d8 commit 9fb2091
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 58 deletions.
2 changes: 1 addition & 1 deletion packages/geom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"license": "Apache-2.0",
"scripts": {
"build": "yarn run clean && tsc --declaration",
"clean": "rm -rf *.js *.d.ts .nyc_output build coverage doc",
"clean": "rm -rf *.js *.d.ts .nyc_output build coverage doc func",
"cover": "yarn test && nyc report --reporter=lcov",
"doc": "node_modules/.bin/typedoc --mode modules --out doc src",
"pub": "yarn run build && yarn publish --access public",
Expand Down
61 changes: 61 additions & 0 deletions packages/geom/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { ICopy } from "@thi.ng/api/api";
import { IDistance, IMix } from "@thi.ng/vectors/api";

export type SampleableVector<T> = ICopy<T> & IDistance<T> & IMix<T>;

export interface IArea {
/**
* Computes and returns area. For types where orientation is taken
* into account, setting `signed` to false will always return the
* absolute area (default is `true`).
*
* @param unsigned
*/
area(signed?: boolean): number;
}

export interface IArcLength {
/**
* Returns arc length, or for closed shapes, circumference.
*/
arcLength(): number;
}

export interface IBounds<T> {
bounds(): T;
/**
* Dimension along x-axis.
*/
width(): number;
/**
* Dimension along y-axis.
*/
height(): number;
/**
* Dimension along z-axis.
*/
depth(): number;
}

export interface ICentroid<T> {
/**
* Computes & returns centroid. If `c` is given it MUST be a zero
* vector and will be used to store result.
*
* @param c
*/
centroid(c?: T): T;
}

export interface IEdges<T> {
edges(): Iterable<T>;
}

export interface IToPolygon2 {
// FIXME return type should be interface
toPolygon2(opts?: any): any;
}

export interface IVertices<T> {
vertices(opts?: any): Iterable<T>;
}
43 changes: 38 additions & 5 deletions packages/geom/src/circle2.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import { IObjectOf } from "@thi.ng/api/api";
import { IObjectOf, IToHiccup } from "@thi.ng/api/api";
import { IToPolygon2, IVertices, IBounds, ICentroid, IArcLength } from "@thi.ng/geom/src/api";
import { normRange } from "@thi.ng/transducers/iter/norm-range";
import { Vec } from "@thi.ng/vectors/api";
import { mix1, PI, TAU } from "@thi.ng/vectors/math";
import { setS2, toCartesian2, Vec2 } from "@thi.ng/vectors/vec2";
import { circumCenter } from "./func/circumcenter";
import { Polygon2 } from "./poly2";

export class Circle2 {
export class Circle2 implements
IArcLength,
IBounds<Vec2[]>,
ICentroid<Vec2>,
IToHiccup,
IToPolygon2,
IVertices<Vec2> {

static from3Points(a: Readonly<Vec2>, b: Readonly<Vec2>, c: Readonly<Vec2>) {
const o = circumCenter(a, b, c);
if (o) {
return new Circle2(o, a.dist(o));
}
}

static DEFAULT_RES = 20;

pos: Vec2;
r: number;
Expand Down Expand Up @@ -42,15 +59,15 @@ export class Circle2 {
return dest;
}

vertices(res = 20) {
vertices(res = Circle2.DEFAULT_RES) {
return Vec2.mapBuffer(this.verticesRaw(0, TAU, res, false), res);
}

area() {
return PI * this.r * this.r;
}

circumference() {
arcLength() {
return TAU * this.r;
}

Expand All @@ -61,7 +78,23 @@ export class Circle2 {
];
}

toPolygon(res = 20) {
width() {
return this.r * 2;
}

height() {
return this.width();
}

depth() {
return 0;
}

centroid(c?: Vec2) {
return c ? c.set(this.pos) : this.pos;
}

toPolygon2(res = Circle2.DEFAULT_RES) {
return new Polygon2(this.vertices(res));
}

Expand Down
17 changes: 6 additions & 11 deletions packages/geom/src/container2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import { IObjectOf } from "@thi.ng/api/api";
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
import { Mat23 } from "@thi.ng/vectors/mat23";
import { Vec2, vec2 } from "@thi.ng/vectors/vec2";
import { IBounds } from "./api";
import { IBounds, ICentroid, IVertices } from "./api";
import { bounds } from "./func/bounds";

export class PointContainer2 implements
IBounds<Vec2[]> {
IBounds<Vec2[]>,
ICentroid<Vec2>,
IVertices<Vec2> {

points: Vec2[];
attribs: IObjectOf<any>;
Expand All @@ -24,15 +27,7 @@ export class PointContainer2 implements
}

bounds() {
const pts = this.points;
const min = Vec2.MAX.copy();
const max = Vec2.MIN.copy();
for (let i = pts.length; --i >= 0;) {
const p = pts[i];
min.min(p);
max.max(p);
}
return [min, max];
return bounds(this.points, Vec2.MAX.copy(), Vec2.MIN.copy());
}

width() {
Expand Down
17 changes: 6 additions & 11 deletions packages/geom/src/container3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import { IObjectOf } from "@thi.ng/api/api";
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
import { Mat44 } from "@thi.ng/vectors/mat44";
import { Vec3, vec3 } from "@thi.ng/vectors/vec3";
import { IBounds } from "./api";
import { IBounds, ICentroid, IVertices } from "./api";
import { bounds } from "./func/bounds";

export class PointContainer3 implements
IBounds<Vec3[]> {
IBounds<Vec3[]>,
ICentroid<Vec3>,
IVertices<Vec3> {

points: Vec3[];
attribs: IObjectOf<any>;
Expand All @@ -24,15 +27,7 @@ export class PointContainer3 implements
}

bounds() {
const pts = this.points;
const min = Vec3.MAX.copy();
const max = Vec3.MIN.copy();
for (let i = pts.length; --i >= 0;) {
const p = pts[i];
min.min(p);
max.max(p);
}
return [min, max];
return bounds(this.points, Vec3.MAX.copy(), Vec3.MIN.copy());
}

width() {
Expand Down
14 changes: 14 additions & 0 deletions packages/geom/src/func/arc-length.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { IDistance } from "@thi.ng/vectors/api";

export const arcLength = <T extends IDistance<T>>(pts: Readonly<T>[], closed = false) => {
const num = pts.length;
if (num < 2) return 0;
let i = pts[0];
let j = pts[1];
let res = 0;
for (let k = 1; k < num; k++ , i = j, j = pts[k]) {
res += i.dist(j);
}
closed && (res += i.dist(pts[0]));
return res;
};
10 changes: 10 additions & 0 deletions packages/geom/src/func/bounds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IMinMax } from "@thi.ng/vectors/api";

export const bounds = <T extends IMinMax<T>>(pts: T[], vmin: T, vmax: T) => {
for (let i = pts.length; --i >= 0;) {
const p = pts[i];
vmin.min(p);
vmax.max(p);
}
return [vmin, vmax];
};
41 changes: 41 additions & 0 deletions packages/geom/src/func/circumcenter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Vec2 } from "@thi.ng/vectors/vec2";

export const circumCenter = (a: Readonly<Vec2>, b: Readonly<Vec2>, c: Readonly<Vec2>) => {
let m1, m2, mx1, mx2, my1, my2, xc, yc;
const deltaAB = Math.abs(a.y - b.y),
deltaBC = Math.abs(b.y - c.y);

if (deltaAB < 1e-6 && deltaBC < 1e-6) {
return null;
}
const ax = a.x, ay = a.y,
bx = b.x, by = b.y,
cx = c.x, cy = c.y;
if (deltaAB < 1e-6) {
m2 = - (cx - bx) / (cy - by);
mx2 = (bx + cx) / 2;
my2 = (by + cy) / 2;
xc = (bx + ax) / 2;
yc = m2 * (xc - mx2) + my2;
} else if (deltaBC < 1e-6) {
m1 = - (bx - ax) / (by - ay);
mx1 = (ax + bx) / 2;
my1 = (ay + by) / 2;
xc = (cx + bx) / 2;
yc = m1 * (xc - mx1) + my1;
} else {
m1 = - (bx - ax) / (by - ay);
m2 = - (cx - bx) / (cy - by);
mx1 = (ax + bx) / 2;
my1 = (ay + by) / 2;
mx2 = (bx + cx) / 2;
my2 = (by + cy) / 2;
xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
if (deltaAB > deltaBC) {
yc = m1 * (xc - mx1) + my1;
} else {
yc = m2 * (xc - mx2) + my2;
}
}
return new Vec2(xc, yc);
}
6 changes: 6 additions & 0 deletions packages/geom/src/func/edges.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { wrap } from "@thi.ng/transducers/iter/wrap";
import { partition } from "@thi.ng/transducers/xform/partition";

export const edges = <T>(vertices: T[], closed = false) => {
return partition(2, 1, closed ? wrap(vertices, 1, false, true) : vertices);
};
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
import { peek } from "@thi.ng/transducers/func/peek";
import { wrap } from "@thi.ng/transducers/iter/wrap";
import { partition } from "@thi.ng/transducers/xform/partition";
import { IDistance } from "@thi.ng/vectors/api";
import { SampleableVector } from "./api";

export const arcLength = <T extends IDistance<T>>(pts: Readonly<T>[], closed = false) => {
const num = pts.length;
if (num < 2) return 0;
let i = pts[0];
let j = pts[1];
let res = 0;
for (let k = 1; k < num; k++ , i = j, j = pts[k]) {
res += i.dist(j);
}
closed && (res += i.dist(pts[0]));
return res;
}
import { SampleableVector } from "../api";

/**
* Re-samples given polyline at given uniform distance. Returns array of
Expand All @@ -39,8 +23,3 @@ export const sampleUniform = <T extends SampleableVector<T>>(pts: T[], step: num
res.push(peek(pts));
return res;
};


export function edges<T>(vertices: T[], closed = false) {
return partition(2, 1, closed ? wrap(vertices, 1, false, true) : vertices);
}
11 changes: 7 additions & 4 deletions packages/geom/src/poly2.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { IObjectOf } from "@thi.ng/api/api";
import { IObjectOf, IToHiccup } from "@thi.ng/api/api";
import { Vec2 } from "@thi.ng/vectors/vec2";
import { IArcLength, IArea } from "./api";
import { arcLength, edges } from "./common";
import { IArcLength, IArea, IEdges } from "./api";
import { PointContainer2 } from "./container2";
import { arcLength } from "./func/arc-length";
import { edges } from "./func/edges";

export class Polygon2 extends PointContainer2 implements
IArcLength,
IArea {
IArea,
IEdges<Vec2[]>,
IToHiccup {

constructor(points: Vec2[], attribs?: IObjectOf<any>) {
super(points, attribs);
Expand Down
15 changes: 11 additions & 4 deletions packages/geom/src/polyline2.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { IObjectOf } from "@thi.ng/api/api";
import { IObjectOf, IToHiccup } from "@thi.ng/api/api";
import { Vec2 } from "@thi.ng/vectors/vec2";
import { arcLength, edges, sampleUniform } from "./common";
import { IArcLength, IArea, IEdges } from "./api";
import { PointContainer2 } from "./container2";

export class Polyline2 extends PointContainer2 {
import { arcLength } from "./func/arc-length";
import { edges } from "./func/edges";
import { sampleUniform } from "./func/sample-uniform";

export class Polyline2 extends PointContainer2 implements
IArcLength,
IArea,
IEdges<Vec2[]>,
IToHiccup {

constructor(points: Vec2[], attribs?: IObjectOf<any>) {
super(points, attribs);
Expand Down

0 comments on commit 9fb2091

Please sign in to comment.