# Help needed to create irregular circles

I intend to create irregular circles like this

but unsure how to get smooth noisy lines in circular manner.

``````function setup() {
createCanvas(600, 600);
background(255);
angleMode(DEGREES);
}

function draw() {
circ()
}

function circ(){
let xoff = 0;
beginShape();
translate(300,300);
for (i=0;i<90;i++) {
x=sin(4*i);
y=cos(4*i);
}
xoff+=0.05;
endShape(CLOSE);
noLoop()
}
``````

Any help appreciated. Thanks!

1 Like

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:

1. Generate center of contour (in setup)
2. Generate contourâ€™s radius (in setup)
3. 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
4. Generate noise radius at every angle position generated in the prev step
5. 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]

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);

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

2 Likes

Yes! and I think specifically if it was directly proportional to the circumference. So, to calculate the number of points you should have, calculate the circumference for your current radius: 2 * PI * radius.

A contour map rule for topographic maps is that the lines cannot cross â€“ they can only touch, which signifies a sheer drop, but a point can never have two elevations. This may be harder to enforce if the points are not aligned across rings â€“ you donâ€™t know the position of the inner ring, so you have to either discover it or to simply set the noise ranges such that crossing is impossible â€“ but that gives your contours a very specific distribution and makes close lines quite rare (as they only arise as a combination of 2 extremes).

Thank you both for the inputs. This is what I got so far, I can make multiple concentric irregular circle, but they have the exact same shape, because i declared random noise within the object. What changes is needed to make each object different? And afterwards how can I animate by frame as itâ€™s static now? Thanks a lot.

``````//shapes that resemble the cross-section of cut crystal
//dense blue rings interspersed by white rings

let cross=[];
let cross_num=2;
let w=1200, h=600;

function setup() {
createCanvas(w, h);
noiseSeed(99);
background(255);
angleMode(DEGREES);
colorMode(RGB);
//start n stop of color range

for (let i=0; i<cross_num; i++){
// x           , y             ,rad,
cross[i] = new CrossSec(random(80, 500),
200,
random(160,30),
random(2,5));
}
}

function draw() {
for (let i=0; i<cross_num; i++){
cross[i].display();
}

}

class CrossSec{
//isolines
constructor(tempX, tempY, tempR,tempN) {
this.x=tempX;
this.y=tempY;
this.r=tempR;
this.n=tempN;

}

display() {
for (let j=0;j<this.n; j++){
//repeat light to dark color gradation
beginShape();
push()
translate(this.x, this.y);
for (let i=0;i<90;i++) {
let radius=this.r+ map(noise(i/5),0,1,6,60) - 20 * j;
let x=sin(4*i);
let y=cos(4*i);
}
endShape(CLOSE);
pop();

}
}
}

``````
1 Like

Try this. If you click in the canvas, you will get a new pattern.
Notice the small change in the noise function.

Kf

``````//shapes that resemble the cross-section of cut crystal
//dense blue rings interspersed by white rings

let cross=[];
let cross_num=2;
let w=1200, h=600;

function setup() {
createCanvas(w, h);
noiseSeed(99);
background(255);
angleMode(DEGREES);
colorMode(RGB);
noLoop();
//start n stop of color range

for (let i=0; i<cross_num; i++) {
// x           , y             ,rad,
cross[i] = new CrossSec(random(80, 500),
200,
random(160, 30),
random(2, 5));
}
}

function draw() {
for (let i=0; i<cross_num; i++) {
cross[i].display();
}
}

function mouseReleased() {
redraw();
}

class CrossSec {
//isolines
constructor(tempX, tempY, tempR, tempN) {
this.x=tempX;
this.y=tempY;
this.r=tempR;
this.n=tempN;
}

display() {
for (let j=0; j<this.n; j++) {
//repeat light to dark color gradation
beginShape();
push();
translate(this.x, this.y);
let mynoiseseed=random(1000);
for (let i=0; i<90; i++) {
let radius=this.r+ map(noise(mynoiseseed+i/5.0), 0, 1, 6, 60) - 20 * j;
let x=sin(4*i);
let y=cos(4*i);