confused about duplicate() and repeating transducers etc. #393
Replies: 3 comments 3 replies
-
Hey & Welcome @pixelpusher 👋 - first off, I don't have an p5js account, so here's an updated/refactored/simplified version and some more comments/explanations below: /**
* Demo of integrating p5js as a module and thi.ng grid iterators
* with a forward/reverse and warp pipeline
*
* by Evan Raskob -- https://post.lurk.org/@BITPRINT
*
* Might be buggy, but hey!
*/
import { zigzagColumns2d } from 'https://cdn.skypack.dev/@thi.ng/grid-iterators';
import { comp, concat, cycle, map, mapIndexed, partition, push, reverse, transduce } from 'https://cdn.skypack.dev/@thi.ng/transducers';
import 'https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js';
const NB = 30; // grid points -- 45 is nice too
let grid; // 2D grid from thi.ng
window.setup = function() {
createCanvas(600, 600);
background(220);
const BW = ceil(width / (NB+1));
const BH = ceil(height / (NB+1));
const forwardgrid = transduce(
// compose processing pipeline of 3 steps:
comp(
// 1) modulate raw grid coordinates
mapIndexed((i, v) => {
let [x, y] = v;
//x = x+0.33*cos((1 + sin(PI*i/NB))*NB*PI*i/10);
x = x+0.33*cos(5*NB*PI*i/10);
y = y+0.5*cos(6*PI*i/NB);
return [x,y];
}),
// 2) project into screen space (pixel coords)
map(([x, y]) => [(x+1)*(BW-1), (y+1)*(BH-1)]),
// 3) repartition into overlapping (point) pairs
// more generally: [1, 2, 3, 4] => [1,2], [2,3], [3,4]
partition(2, 1)
),
// collect results as array
push(),
// grid iterator as data source
zigzagColumns2d({ cols: NB })
);
// grid in reverse
const reversegrid = reverse(forwardgrid);
// or alternatively...
// const reversegrid = forwardgrid.slice().reverse();
// create infinite repetition of the combined fwd & reverse sequence
grid = cycle(concat(forwardgrid, reversegrid));
frameRate(30);
};
window.draw = function() {
try {
// read next point pair (aka line segment) from (endless) iterator
let [[x1,y1], [x2,y2]] = grid.next().value;
strokeWeight(2);
stroke(`hsla(${floor(frameCount/10) % 360}, 80%, 80%, 0.8)`);
line(x1, y1, x2, y2);
ellipse(x1,y1,4,4);
ellipse(x2,y2,4,4);
} catch (err) {
console.error(`DRAW(next):${err.message}`);
}
}; As for the complications and resulting confusions in your OG code:
Anyhow, hope these comments are helpful and make the whole thing a bit less confusing! I'd still be interested about your thought patterns leading to points 2 & 3. With the latter, I guess one issue is that |
Beta Was this translation helpful? Give feedback.
-
I highly subscribe every word that Karsten wrote ☝️, and I wasn't sure what you want to achieve as well. In my opinion the most important is the point 3., As a general (and very personal) note, for me the smell in your code was this line: const reversegrid = iterate([...forwardgrid].reverse()); because when you "materialise" an iterator into an array (by Said that, this is a version of your script with less change and less refactor, hope I go what you want to achieve, but please use Karsten's version as a reference 🙂 import "https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js";
import {
cycle,
iterate,
mapIndexed,
push,
transduce,
duplicate,
reverse,
repeat,
concat,
take,
comp,
} from "https://cdn.skypack.dev/@thi.ng/transducers";
import { zigzagColumns2d } from "https://cdn.skypack.dev/@thi.ng/grid-iterators";
const NB = 9;
let grid; // 2D grid from thi.ng
let lastPoints = [0, 0];
window.setup = function () {
createCanvas(150, 150);
background(220);
const forwardgrid = transduce(
comp(
mapIndexed((i, v) => {
let [x, y] = v;
x = x + 0.33 * cos((5 * NB * PI * i) / 10);
y = y + 0.5 * cos((6 * PI * i) / NB);
return [x, y];
})
),
push(),
zigzagColumns2d({ cols: NB })
);
const reversegrid = reverse(forwardgrid);
grid = cycle(concat(forwardgrid, reversegrid));
lastPoints = [width / (NB + 1), height / (NB + 1)];
frameRate(30);
};
window.draw = function () {
fill(220, 100);
rect(0, 0, width, height);
const BW = ceil(width / (NB + 1));
const BH = ceil(height / (NB + 1));
try {
let b = grid.next();
let [x, y] = [(b.value[0] + 1) * (BW - 1), (b.value[1] + 1) * (BH - 1)];
stroke(10, 10, 10);
line(lastPoints[0], lastPoints[1], x, y);
ellipse(x, y, 4, 4);
ellipse(lastPoints[0], lastPoints[1], 4, 4);
lastPoints = [x, y];
} catch (err) {
console.error(`DRAW(next):${err.message}`);
}
}; just my two cents. |
Beta Was this translation helpful? Give feedback.
-
Thanks, @nkint - I like your version (also with the bg fade) and your comments are spot on! Here're a few more points to know/mention re: iterators vs. arrays: It's good to think about iterators as generalized, lazy data sources, but we always have to consider how they're being used and be aware of their stateful nature (in most cases). Knowing about their finiteness is very important too! Here's an example which might seem counter-intuitive at first: // generator function creating sequence 1,2,3
function* a() { yield 1; yield 2; yield 3; }
// instantiate
const b = a(); If we now try to use this like in Evan's example to create a concatenation of [...concat(b, reverse(b))]
// [1,2,3] Even worse, if we do the same one more time: [...concat(b, reverse(b))]
// [] The reason for this is that This is maybe a contrived example, but hopefully shows why it's sometimes important to cache iterables (as an array or otherwise), e.g. by changing it to the following, the above issues all disappear:
q.e.d. 😄 The flipside of this is ignoring the infinite nature of some iterators (e.g. |
Beta Was this translation helpful? Give feedback.
-
Hi, I'm fuzzy on some basic things. I'm trying to traverse a grid using the grid iterators forwards then backwards in this example: https://editor.p5js.org/eraskgold/sketches/SV_7YjRnX
Forwards is not a problem but trying to add the backwards to the forwards and cycle through them infinitely is a problem. After the forwards part it gets undefined when it jumps to the next value.
Additionally, I thoguht it would be easier to draw lines between the points if I duplicated all the points in the array so I would have pairs of 2 points to use in the line() function, but the comp( duplicate (1) ... etc) on line 29 produces unexpected results. Is that because comp() applied functions from right to left wheras transduce() does it from right to left? I'm a little stuck.
Thanks!
Beta Was this translation helpful? Give feedback.
All reactions