The following code tries to demonstrate how to generate a single irregular contour. Mouse click will generate a new contour. Think of a contour made of a circle with “npts” number of points. These are the steps to generate the contour:
- Generate center of contour (in setup)
- Generate contour’s radius (in setup)
- Generate irregular distributed angle sample. This means, if I request 50 points in my circle, this function will generate 50 angles but not evenly spaced
- Generate noise radius at every angle position generated in the prev step
- Draw contour using either points or lines
Further explanation:
r_irr[i] = r + (r*rFraction)*(noise(noiseStep*i)-0.5);
This line shows that every point has a noise radius, where the noise depends on noisestep and rfraction , each being mapped to mouseX and mouseY. So every time one clicks, it generates a new contour based on the position of mouseX and mouseY in the sketch. Finally, I subtract 0.5 as perlin noise returns a value from 0…1, effectively making this value work in a range from -0.5 to 0.5.
This is not a final solution but just an approach. Notice that nPts is set to 50. It would be better if this number was proportional to the radius. For instance, smaller radius would require a smaller nPts and larger radius would required npts to be larger. This is just a thought but not that important.
Kf
'use strict';
const npts=50;
let dataPts=[];
let locx, locy, r;
function setup() {
createCanvas(600, 600);
angleMode(DEGREES);
strokeWeight(3);
//Center of contour
locx=random(width/4.0, 3*width/4.0); //[0.25 .. 0.75]
locy=random(height/4.0, 3*height/4.0); //[0.25 .. 0.75]
//Generate random radius
r=random(width/4.0, width/2.0);
noLoop();
}
function draw() {
background(120);
generateIrregularSteppingAngle();
showCircularCountour(locx, locy, r, 0);
showIrregularCountour(locx, locy, r, 1);
}
function mouseReleased() {
redraw();
}
function generateIrregularSteppingAngle() {
let delta=360.0/npts; //360 degrees / n_points
print("Delta="+delta);
for (let i=0; i<npts; i++) {
let angle = i*delta;
angle = angle + random(-delta/2.0, delta/2.0);
dataPts[i]=angle;
}
}
//Mode: 0=points 1:kines 2:curve
function showCircularCountour(x, y, r, m) {
push();
if (m==0) {
stroke(250);
translate(locx, locy);
for (let i=0; i<dataPts.length; i++) {
let px = r * cos(dataPts[i]);
let py = r * sin(dataPts[i]);
point(px, py);
}
}
pop();
}
//Mode: 0=points 1:kines 2:curve
function showIrregularCountour(x, y, r, m) {
push();
translate(locx, locy);
//GENERATES irregular radius
let r_irr=[];
for (let i=0; i<dataPts.length; i++) { // begins @ 1
let noiseStep=map(mouseX, 0, width, 0.001, 10);
let rFraction=map(mouseY, 0, height, 0.05, 0.5);
r_irr[i] = r + (r*rFraction)*(noise(noiseStep*i)-0.5);
}
if (m==0) {
stroke(0, 255, 0);
for (let i=0; i<dataPts.length-1; i++) {
let px = r_irr[i] * cos(dataPts[i]);
let py = r_irr[i] * sin(dataPts[i]);
point(px, py);
}
}
if (m==1) {
stroke(150, 255, 0);
for (let i=0; i<dataPts.length-1; i++) {
let px0 = r_irr[i] * cos(dataPts[i]);
let py0 = r_irr[i] * sin(dataPts[i]);
let px = r_irr[i+1] * cos(dataPts[i+1]);
let py = r_irr[i+1] * sin(dataPts[i+1]);
line(px0, py0, px, py);
}
let last_idx=dataPts.length-1;
let px0 = r_irr[last_idx] * cos(dataPts[last_idx]);
let py0 = r_irr[last_idx] * sin(dataPts[last_idx]);
let px = r_irr[0] * cos(dataPts[0]);
let py = r_irr[0] * sin(dataPts[0]);
line(px0, py0, px, py);
}
pop();
}
kf_keyword: irregular patterns contours noise noisy perlin concentric