Optimize drawng pattern on both axes
This commit is contained in:
parent
07ca1a0a63
commit
b71c522096
1 changed files with 49 additions and 57 deletions
100
src/main.ts
100
src/main.ts
|
|
@ -1,9 +1,9 @@
|
||||||
import { line, group, translate, asSvg, svgDoc, scale, flip } from "@thi.ng/geom";
|
import { line, type Line, group, translate, asSvg, svgDoc, scale, flip } from "@thi.ng/geom";
|
||||||
|
import { vec2, type Vec2 } from "@thi.ng/vectors"
|
||||||
import { $canvas } from "@thi.ng/rdom-canvas";
|
import { $canvas } from "@thi.ng/rdom-canvas";
|
||||||
import { reactive, sync } from "@thi.ng/rstream";
|
import { reactive, sync } from "@thi.ng/rstream";
|
||||||
import { $compile, $input } from '@thi.ng/rdom'
|
import { $compile, $input } from '@thi.ng/rdom'
|
||||||
import { cycle, takeWhile, comp, mapIndexed, range, iterator, map, mapcat, reverse } from "@thi.ng/transducers"
|
import { cycle, comp, range, iterator, map, mapcat, reverse, zip } from "@thi.ng/transducers"
|
||||||
import { vec2 } from "@thi.ng/vectors"
|
|
||||||
|
|
||||||
const cellSize_ = "12"
|
const cellSize_ = "12"
|
||||||
const xs_ = "101110100101100"
|
const xs_ = "101110100101100"
|
||||||
|
|
@ -11,8 +11,8 @@ const ys_ = "101001111001110000101"
|
||||||
|
|
||||||
const parsePattern = (pattern: string) => pattern.split('').map(x => Number.parseInt(x, 10))
|
const parsePattern = (pattern: string) => pattern.split('').map(x => Number.parseInt(x, 10))
|
||||||
|
|
||||||
const xs = reactive(xs_).map((pattern) => parsePattern(pattern))
|
const xSeeds = reactive(xs_).map((pattern) => parsePattern(pattern))
|
||||||
const ys = reactive(ys_).map((pattern) => parsePattern(pattern))
|
const ySeeds = reactive(ys_).map((pattern) => parsePattern(pattern))
|
||||||
const cellSize = reactive(cellSize_).map(num => {
|
const cellSize = reactive(cellSize_).map(num => {
|
||||||
const next = Number.parseInt(num, 10)
|
const next = Number.parseInt(num, 10)
|
||||||
return Number.isNaN(next)|| next < 5 ? 5 : next
|
return Number.isNaN(next)|| next < 5 ? 5 : next
|
||||||
|
|
@ -28,36 +28,51 @@ const height = 594
|
||||||
|
|
||||||
const size = [width, height]
|
const size = [width, height]
|
||||||
|
|
||||||
// build a list of start positions in a one-dimensional grid; lines will start
|
// some explanation for what's happening below:
|
||||||
// perpendicular from the first value (cell index) with a given seed (1 or 0)
|
//
|
||||||
|
// - a coord is a position on a single axis
|
||||||
const seededGrid = (pattern: Iterable<number>, maxCells: number) =>
|
// - from this coord, a sequence of stitches will be generate in perpendicular
|
||||||
[...iterator(
|
// direction
|
||||||
comp(
|
// - how this line is generated is decided by a seed, which is either 0 or 1;
|
||||||
mapIndexed((cell, val) => [cell, val] as const),
|
// if a seed is 0, the stitches start right at the axis, if it is one it will
|
||||||
takeWhile(([cell, _]) => cell <= maxCells),
|
// skip exactly one coordinate
|
||||||
),
|
|
||||||
cycle(pattern)
|
|
||||||
)]
|
|
||||||
|
|
||||||
// points from which to which a stitch is showing for a given seed
|
// points from which to which a stitch is showing for a given seed
|
||||||
|
|
||||||
const stitches = (seed: number, maxCells: number) =>
|
const stitches = (seed: number, maxCoord: number) =>
|
||||||
[...iterator(
|
iterator(
|
||||||
comp(
|
|
||||||
mapcat((cell) => (cell + seed) % 2 === 0 // start at the beginning or skip it
|
mapcat((cell) => (cell + seed) % 2 === 0 // start at the beginning or skip it
|
||||||
? [vec2(cell, cell + 1)]
|
? [vec2(cell, cell + 1)]
|
||||||
: null),
|
: null)
|
||||||
takeWhile(([a, _]) => a < maxCells)
|
,
|
||||||
|
range(maxCoord)
|
||||||
|
)
|
||||||
|
|
||||||
|
const xLineGen = (coord: number, [p1, p2]: Vec2) => line([p1, coord], [p2, coord])
|
||||||
|
const yLineGen = (coord: number, [p1, p2]: Vec2) => line([coord, p1], [coord, p2])
|
||||||
|
|
||||||
|
const generateLines = (maxCoordOnAxis: number, maxCoordPerpendicular: number, seeds: Iterable<number>, lineGen: (coord: number, l: Vec2) => Line) =>
|
||||||
|
iterator(
|
||||||
|
mapcat(([coord, seed]) => {
|
||||||
|
// optimization for quicker drawing: when we're in an odd row / col,
|
||||||
|
// reverse drawing direction
|
||||||
|
const onEvenCoord = coord % 2 === 0
|
||||||
|
return iterator(
|
||||||
|
comp(
|
||||||
|
map(l => lineGen(coord, l)),
|
||||||
|
map(l => onEvenCoord ? l : flip(l))
|
||||||
),
|
),
|
||||||
range()
|
onEvenCoord ? stitches(seed, maxCoordPerpendicular) : reverse(stitches(seed, maxCoordPerpendicular))
|
||||||
)]
|
)
|
||||||
|
}),
|
||||||
|
zip(range(maxCoordOnAxis), seeds)
|
||||||
|
)
|
||||||
|
|
||||||
|
// now we can put the functions above together based on the current settings and generate a scene to be drawn
|
||||||
|
|
||||||
const scene = sync({
|
const scene = sync({
|
||||||
src: { cellSize, xs, ys, }
|
src: { cellSize, xSeeds, ySeeds, }
|
||||||
}).map(({ cellSize, xs, ys }) => {
|
}).map(({ cellSize, xSeeds, ySeeds }) => {
|
||||||
// console.log({ cellSize, xs, ys })
|
|
||||||
|
|
||||||
const minPadding = cellSize
|
const minPadding = cellSize
|
||||||
|
|
||||||
// calculate available drawing area
|
// calculate available drawing area
|
||||||
|
|
@ -67,31 +82,8 @@ const scene = sync({
|
||||||
const yCells = Math.floor((height - 2 * minPadding) / cellSize)
|
const yCells = Math.floor((height - 2 * minPadding) / cellSize)
|
||||||
const yPadding = (height - (yCells * cellSize)) / 2
|
const yPadding = (height - (yCells * cellSize)) / 2
|
||||||
|
|
||||||
const xSeeds = seededGrid(xs, xCells)
|
const xLines = [...map(l => scale(l, cellSize), generateLines(yCells, xCells, cycle(ySeeds), xLineGen))]
|
||||||
const ySeeds = seededGrid(ys, yCells)
|
const yLines = [...map(l => scale(l, cellSize), generateLines(xCells, yCells, cycle(xSeeds), yLineGen))]
|
||||||
|
|
||||||
const yLines = iterator(
|
|
||||||
mapcat(([x, seed]) => {
|
|
||||||
// optimization for quicker drawing: when we're in an odd row,
|
|
||||||
// reverse drawing direction
|
|
||||||
const inEvenRow = x % 2 === 0
|
|
||||||
return iterator(
|
|
||||||
comp(
|
|
||||||
map(([y1, y2]) => line([x, y1], [x, y2])),
|
|
||||||
map(l => inEvenRow ? l : flip(l)),
|
|
||||||
map(l => scale(l, cellSize))
|
|
||||||
),
|
|
||||||
inEvenRow ? stitches(seed, yCells) : reverse(stitches(seed, yCells))
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
xSeeds
|
|
||||||
)
|
|
||||||
|
|
||||||
const xLines = iterator(
|
|
||||||
mapcat(([y, seed]) =>
|
|
||||||
map(([x1, x2]) => scale(line([x1, y], [x2, y]), cellSize), stitches(seed, xCells))),
|
|
||||||
ySeeds
|
|
||||||
)
|
|
||||||
|
|
||||||
const scene = translate(
|
const scene = translate(
|
||||||
group(
|
group(
|
||||||
|
|
@ -122,13 +114,13 @@ $compile(
|
||||||
["input", {
|
["input", {
|
||||||
type: "text",
|
type: "text",
|
||||||
value: xs_,
|
value: xs_,
|
||||||
oninput: $input(xs)
|
oninput: $input(xSeeds)
|
||||||
}]]],
|
}]]],
|
||||||
["div", {}, ["label", {}, "Y Pattern: ",
|
["div", {}, ["label", {}, "Y Pattern: ",
|
||||||
["input", {
|
["input", {
|
||||||
type: "text",
|
type: "text",
|
||||||
value: ys_,
|
value: ys_,
|
||||||
oninput: $input(ys)
|
oninput: $input(ySeeds)
|
||||||
}]]],
|
}]]],
|
||||||
["h2", {}, "SVG Export"],
|
["h2", {}, "SVG Export"],
|
||||||
["div", {}, ["textarea", {
|
["div", {}, ["textarea", {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue