p5.js Curve Reactor
This example uses a curve as the reactor object. The curve is subdivided into several points, and those points used in the similar way as the previous reactor examples.
var NDIVS = 100; // # of subdivisions, higher is more accurate, but slower, and vice versa
var cps = []; // curve controll points
var gridWidth = 30;
var gridHeight = 30;
var shapeWidth = 19;
var shapeHeight = 19;
var reactorScaler = 0.006;
function setup() {
createCanvas(500,500);
smooth();
for (var i=0; i<4; i++) {
cps[i] = createVector(0,0);
}
cps[0].x = width+300;
cps[0].y = -500;
cps[1].x= 50;
cps[1].y= 50;
cps[2].x= width-50;
cps[2].y= height-50;
cps[3].x= -500;
cps[3].y= height+300;
}
function draw() {
background(255);
drawGeometry();
}
function drawGeometry() {
stroke(255,0,0);
noFill();
curve(cps[0].x,cps[0].y, cps[1].x,cps[1].y, cps[2].x,cps[2].y, cps[3].x,cps[3].y);
// uncomment if you want to manipulate curve (BUT BE CAREFUL, it's heavy!)
/*
for (let pt of cps) {
ellipse(pt.x, pt.y, 20, 20);
}
if (mouseIsPressed) {
for (let pt of cps) {
if (dist(mouseX, mouseY, pt.x, pt.y) < 20) {
pt.x = mouseX;
pt.y = mouseY;
break;
}
}
}
*/
fill(0);
noStroke();
for(var i = 0; i<gridWidth; i++ ) {
for(var j = 0; j<gridHeight; j++ ) {
var myPos = createVector(i*shapeWidth, j*shapeHeight);
var cpt = ClosestPointOnCatmullRom(cps,myPos,NDIVS);
let reactorDistance = dist(cpt.x, cpt.y, myPos.x, myPos.y);
let scaler = reactorDistance*reactorScaler;
ellipse(myPos.x, myPos.y, shapeWidth*scaler, shapeHeight*scaler);
}
}
}
// see http://davebollinger.org/category/code/
/**
* Returns the closest point on a catmull-rom curve relative to a search location.
* This is only an approximation, by subdividing the curve a given number of times.
* More subdivisions gives a better approximation but takes longer, and vice versa.
* No concern is given to handling multiple equidistant points on the curve - the
* first encountered equidistant point on the subdivided curve is returned.
*
* @param cps array of four PVectors that define the control points of the curve
* @param pt the search-from location
* @param ndivs how many segments to subdivide the curve into
* @returns PVector containing closest subdivided point on curve
*/
function ClosestPointOnCatmullRom(cps,pt,steps) {
var result = createVector(0,0);
var bestDistanceSquared = 0;
var bestT = 0;
for (var i=0; i<=steps; i++) {
let t = (float)(i) / (float)(steps);
let x = curvePoint(cps[0].x,cps[1].x,cps[2].x,cps[3].x,t);
let y = curvePoint(cps[0].y,cps[1].y,cps[2].y,cps[3].y,t);
let dissq = dist(pt.x, pt.y, x, y);
if (i==0 || dissq < bestDistanceSquared) {
bestDistanceSquared = dissq;
bestT = t;
result.set(x,y,0);
}
}
return result;
}