Skip to content

Commit

Permalink
feat(geom): avoid recursive application of __samples attrib
Browse files Browse the repository at this point in the history
- add internal __copyAttribsNoSamples() helper
- update implementations for:
  - asPolygon()
  - asPolyline()
  - edges()
  - resample()
  - splitArcLength()
- update Group ctor to make attribs optional
  • Loading branch information
postspectacular committed Mar 24, 2023
1 parent a4b7b18 commit 189446d
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 27 deletions.
2 changes: 1 addition & 1 deletion packages/geom/src/api/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { __copyAttribs } from "../internal/copy.js";

export class Group implements IHiccupShape {
constructor(
public attribs: Attribs,
public attribs?: Attribs,
public children: IHiccupShape[] = []
) {}

Expand Down
7 changes: 5 additions & 2 deletions packages/geom/src/as-polygon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { MultiFn1O } from "@thi.ng/defmulti";
import { defmulti } from "@thi.ng/defmulti/defmulti";
import type { IShape, SamplingOpts } from "@thi.ng/geom-api";
import { Polygon } from "./api/polygon.js";
import { __copyAttribs } from "./internal/copy.js";
import { __copyAttribsNoSamples as __attribs } from "./internal/copy.js";
import { __dispatch } from "./internal/dispatch.js";
import { vertices } from "./vertices.js";

Expand All @@ -12,6 +12,9 @@ import { vertices } from "./vertices.js";
* or number of target vertices.
*
* @remarks
* If the shape has a `__samples` attribute, it will be removed in the result to
* avoid recursive application.
*
* Currently implemented for:
*
* - {@link Circle}
Expand Down Expand Up @@ -45,6 +48,6 @@ export const asPolygon: MultiFn1O<
tri: "points",
},
{
points: ($, opts) => new Polygon(vertices($, opts), __copyAttribs($)),
points: ($, opts) => new Polygon(vertices($, opts), __attribs($)),
}
);
11 changes: 7 additions & 4 deletions packages/geom/src/as-polyline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { IShape, SamplingOpts } from "@thi.ng/geom-api";
import { set } from "@thi.ng/vectors/set";
import type { Path } from "./api/path.js";
import { Polyline } from "./api/polyline.js";
import { __copyAttribs } from "./internal/copy.js";
import { __copyAttribsNoSamples as __attribs } from "./internal/copy.js";
import { __dispatch } from "./internal/dispatch.js";
import { vertices } from "./vertices.js";

Expand All @@ -14,6 +14,9 @@ import { vertices } from "./vertices.js";
* or number of target vertices.
*
* @remarks
* If the shape has a `__samples` attribute, it will be removed in the result to
* avoid recursive application.
*
* Currently implemented for:
*
* - {@link Arc}
Expand Down Expand Up @@ -51,18 +54,18 @@ export const asPolyline: MultiFn1O<
tri: "poly",
},
{
points: ($, opts) => new Polyline(vertices($, opts), __copyAttribs($)),
points: ($, opts) => new Polyline(vertices($, opts), __attribs($)),

path: ($: Path, opts) => {
const pts = vertices($, opts);
$.closed && pts.push(set([], pts[0]));
return new Polyline(pts, __copyAttribs($));
return new Polyline(pts, __attribs($));
},

poly: ($, opts) => {
const pts = vertices($, opts);
pts.push(set([], pts[0]));
return new Polyline(pts, __copyAttribs($));
return new Polyline(pts, __attribs($));
},
}
);
22 changes: 20 additions & 2 deletions packages/geom/src/edges.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { MultiFn1O } from "@thi.ng/defmulti";
import { defmulti } from "@thi.ng/defmulti/defmulti";
import type { IShape, SamplingOpts } from "@thi.ng/geom-api";
import { mapcat } from "@thi.ng/transducers/mapcat";
import type { VecPair } from "@thi.ng/vectors";
import type { AABB } from "./api/aabb.js";
import type { Arc } from "./api/arc.js";
import type { BPatch } from "./api/bpatch.js";
import type { Circle } from "./api/circle.js";
import type { Group } from "./api/group.js";
import type { Path } from "./api/path.js";
import type { Polygon } from "./api/polygon.js";
import type { Polyline } from "./api/polyline.js";
Expand All @@ -18,10 +20,12 @@ import { vertices } from "./vertices.js";

/**
* Extracts the edges of given shape's boundary and returns them as an iterable
* of vector pairs. Some shapes also support
* [`SamplingOpts`](https://docs.thi.ng/umbrella/geom-api/interfaces/SamplingOpts.html).
* of vector pairs.
*
* @remarks
* If the shape has a `__samples` attribute, it will be removed in the result to
* avoid recursive application.
*
* Currently implemented for:
*
* - {@link AABB}
Expand All @@ -30,6 +34,7 @@ import { vertices } from "./vertices.js";
* - {@link Circle}
* - {@link Cubic}
* - {@link Ellipse}
* - {@link Group}
* - {@link Line}
* - {@link Path}
* - {@link Polygon}
Expand All @@ -39,6 +44,17 @@ import { vertices } from "./vertices.js";
* - {@link Rect}
* - {@link Triangle}
*
* The implementations for the following shapes **do not** support
* [`SamplingOpts`](https://docs.thi.ng/umbrella/geom-api/interfaces/SamplingOpts.html)
* (all others do):
*
* - {@link Line}
* - {@link Polygon}
* - {@link Polyline}
* - {@link Quad}
* - {@link Rect}
* - {@link Triangle}
*
* @param shape
* @param opts
*/
Expand Down Expand Up @@ -85,6 +101,8 @@ export const edges: MultiFn1O<

circle: ($: Circle, opts) => __edges(asPolygon($, opts).points, true),

group: ($: Group, opts) => mapcat((c) => edges(c, opts), $.children),

path: ($: Path, opts) => __edges(asPolygon($, opts).points, $.closed),

poly: ($: Polygon) => __edges($.points, true),
Expand Down
27 changes: 24 additions & 3 deletions packages/geom/src/internal/copy.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
// thing:export
import { copyVectors } from "@thi.ng/vectors/copy";
import { withoutKeysObj } from "@thi.ng/associative/without-keys";
import type {
Attribs,
IShape,
PCLike,
PCLikeConstructor,
} from "@thi.ng/geom-api";
import { copyVectors } from "@thi.ng/vectors/copy";

/** @internal */
export const __copyAttribs = ($: IShape) => <Attribs>{ ...$.attribs };
/**
* Creates a shallow copy of shape's attribs. Any `exclude` keys will be removed
* from result attribs.
*
* @internal
*/
export const __copyAttribs = ($: IShape, ...exclude: string[]) => {
if (!$.attribs) return;
const attribs = <Attribs>{ ...$.attribs };
return exclude.length ? <Attribs>withoutKeysObj(attribs, exclude) : attribs;
};

/**
* Syntax sugar for {@link __copyAttribs}, also removing `__samples` key from
* result.
*
* @param x
*
* @internal
*/
export const __copyAttribsNoSamples = (x: IShape) =>
__copyAttribs(x, "__samples");

/** @internal */
export const __copyShape = <T extends PCLike>(
Expand Down
15 changes: 6 additions & 9 deletions packages/geom/src/resample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import { resample as _resample } from "@thi.ng/geom-resample/resample";
import { Polygon } from "./api/polygon.js";
import { Polyline } from "./api/polyline.js";
import { asPolygon } from "./as-polygon.js";
import { __copyAttribs } from "./internal/copy.js";
import { __copyAttribsNoSamples as __attribs } from "./internal/copy.js";
import { __dispatch } from "./internal/dispatch.js";

/**
* Resamples given 2D shape with given options and returns result as polygon (if
* closed) or polyline (if open).
*
* @remarks
* If the shape has a `__samples` attribute, it will be removed in the result to
* avoid recursive application.
*
* Currently implemented for:
*
* - {@link Circle}
Expand Down Expand Up @@ -44,15 +47,9 @@ export const resample: MultiFn2<
circle: ($: IShape, opts) => asPolygon($, opts),

poly: ($: PCLike, opts) =>
new Polygon(
_resample($.points, opts, true, true),
__copyAttribs($)
),
new Polygon(_resample($.points, opts, true, true), __attribs($)),

polyline: ($: PCLike, opts) =>
new Polyline(
_resample($.points, opts, false, true),
__copyAttribs($)
),
new Polyline(_resample($.points, opts, false, true), __attribs($)),
}
);
20 changes: 14 additions & 6 deletions packages/geom/src/split-arclength.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Vec } from "@thi.ng/vectors";
import { Group } from "./api/group.js";
import { Polyline } from "./api/polyline.js";
import { asPolyline } from "./as-polyline.js";
import { __copyAttribs } from "./internal/copy.js";
import { __copyAttribsNoSamples as __attribs } from "./internal/copy.js";
import { __dispatch } from "./internal/dispatch.js";
import { __pointArraysAsShapes } from "./internal/points-as-shape.js";

Expand All @@ -16,6 +16,9 @@ import { __pointArraysAsShapes } from "./internal/points-as-shape.js";
* Returns array of new shapes/polylines.
*
* @remarks
* If the shape has a `__samples` attribute, it will be removed in the result to
* avoid recursive application.
*
* Currently only implemented for:
*
* - {@link Group}
Expand All @@ -24,23 +27,28 @@ import { __pointArraysAsShapes } from "./internal/points-as-shape.js";
* Other shape types will be attempted to be auto-converted via
* {@link asPolyline} first.
*
* Groups will be recursively processed (i.e. by calling {@link splitArcLength}
* for each child). Any nested groups will be retained, but each group might
* have a greater resulting number of children (depending on number of splits
* performed).
*
* @param shape
* @param dist
*/
export const splitArclength: MultiFn2<IShape, number, IShape[]> = defmulti<
export const splitArcLength: MultiFn2<IShape, number, IShape[]> = defmulti<
any,
number,
IShape[]
>(
__dispatch,
{},
{
[DEFAULT]: ($: IShape, d: number) => splitArclength(asPolyline($), d),
[DEFAULT]: ($: IShape, d: number) => splitArcLength(asPolyline($), d),

group: ($, d) => [
new Group(__copyAttribs($.attribs), [
new Group(__attribs($), [
...mapcat(
(c: IShape) => <IHiccupShape[]>splitArclength(c, d),
(c: IShape) => <IHiccupShape[]>splitArcLength(c, d),
$.children
),
]),
Expand All @@ -62,7 +70,7 @@ export const splitArclength: MultiFn2<IShape, number, IShape[]> = defmulti<
break;
}
}
return __pointArraysAsShapes(Polyline, chunks, $.attribs)!;
return __pointArraysAsShapes(Polyline, chunks, __attribs($))!;
},
}
);

0 comments on commit 189446d

Please sign in to comment.