Closed nkint closed 5 years ago
Hey @nkint - by all means, I'd be totally happy about any more examples - can never have enough :) As for nice graphics: As an interim step prior to having a proper website for this project, I want create screenshots of all existing examples to help better navigate them. Since a lot of them aren't precisely eye candy, any more visual ones would be amazing!
The geom-voronoi
example actually has two examples, they only still need to be added as such. See here:
As for the spline package and other geom-*
packages, these are all just "low level" functions for the main geom
package which combines their functionality. So I'd always recommend using this one first...
Some references:
import * as g from "@thi.ng/geom";
import * as sd from "@thi.ng/geom-subdiv-curve";
import * as tx from "@thi.ng/transducers";
import * as v from "@thi.ng/vectors";
const a = g.polygon([[0, 0], [100, 0], [50, 86]]);
// subdivide polygon (2 iterations)
// btw. there're also other subdiv types than cubic
// https://github.com/thi-ng/umbrella/blob/master/packages/geom-subdiv-curve/src/api.ts#L21
const a2 = g.subdivCurve(a, sd.SUBDIV_CUBIC_CLOSED, 2);
// Polygon {
// points: [
// [ 23.4375, 13.4375 ],
// [ 34.375, 5.375 ],
// [ 50, 2.6875 ],
// [ 65.625, 5.375 ],
// [ 76.5625, 13.4375 ],
// [ 78.125, 26.875 ],
// [ 72.65625, 41.65625 ],
// [ 62.5, 53.75 ],
// [ 50, 59.125 ],
// [ 37.5, 53.75 ],
// [ 27.34375, 41.65625 ],
// [ 21.875, 26.875 ]
// ],
// attribs: {}
// }
// create SVG
console.log(g.asSvg(g.svgDoc({}, a2)))
// <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="56.25" height="56.44" viewBox="21.88 2.69 56.25 56.44"><polygon points="23.44,13.44 34.38,5.38 50.00,2.69 65.63,5.38 76.56,13.44 78.13,26.88 72.66,41.66 62.50,53.75 50.00,59.13 37.50,53.75 27.34,41.66 21.88,26.88"/></svg>
// convert a polygon to a path of cubic spline segments
const polyAsCubicPath = (poly, t = 0.5) => {
// transform each poly edge a->b
// wrap() is needed because we need to connect last seg w/ first later
const segments = tx.wrap(
tx.mapcat(([a,b])=> [v.mixN([], a, b, 0.5), b], g.edges(poly)),
1,
false
);
let first = true;
const path = g.pathBuilder();
// re-org segments such that we get [midEdgeA, origPolyVertex, midEdgeB]
for (let s of tx.partition(3, 2, segments)) {
if (first) {
path.moveTo(s[0]);
first = false;
}
// create cubic spline to midpoint of next edge
// using interpolated control points
path.cubicTo(
v.mixN([], s[0], s[1], t),
v.mixN([], s[1], s[2], 1 - t),
s[2]
);
}
return path.current();
};
// output as SVG
console.log(
g.asSvg(
g.svgDoc(
// there seems to be a bug with computing cubic bounding box
// so need to specify viewBox directly... (I will create another issue)
{viewBox: "0 0 100 100", fill: "none"},
...tx.map(
(t) => g.withAttribs(polyAsCubicPath(a, t), { stroke: [t, t, t, 1] }),
tx.normRange(4, false)
)
)
)
);
This last output will create this below using different t
values to adjust curve tightness. The inner triangle is t=0
, i.e. all control points coincide with the mid points of the original poly. The original poly is enclosing all of these curves...
Btw. I will add the above function to the geom
package soon...
Another thing... This code of yours:
const points = [
...tx.iterator1(
tx.map(index => cartesian2([], [radius, index * TAU + angle], center)),
tx.normRange(10, false),
),
]
Can be simplified with the geom
package like so:
const points = g.vertices(g.circle(center, radius), 10)
@nkint also wanted to point out that you can use any convex polygon as clipping boundary for the voronoi, e.g. use a hexagon:
const bounds = g.vertices(g.circle([width / 2, height / 2], width / 2), 6);
Just added another version of that above polyToCubicPath
function, which creates a curve going through the original polygon vertices (rather than through the edge midpoints as in the other function). To compare, in the image below the blue curves are created with the version from above, the red ones are computed with the new function. Original polygon in black.
The new function computes tangents (and symmetric control points) for each polygon vertex (perpendicular to the corner bisector at each vertex) and in the version shown above, these tangent are scaled relative to the length of their parent poly edge. Alternatively, there's a flag to use uniform scaling only:
Hi! After discussed recently on Discord I've done some test with voronoi and delanuy. The feeling is so good that I'd like to make a PR with a small example (see code below) to replicate the Mike Bostock and Mario visual images:
This could have some interesting feature as learning by example / tutorial:
@thi.ng/geom-voronoi
package has no example right now even if documentation is clear@thi.ng/geom-subdiv-curve
, no example right now even if the documentation or just signature are clear@thi.ng/geom-splines
that lacks both example and documentation (and signature are not so clear imho: at a first look I am in doubt when use which method, and use it with'path'
or can produce polygon points? some more examples can be interesting, let think about images of different curve parameters in d3 documentation).What do you think?
A base skelton should be this (without splines and with only canvas):