How to create a random convex polygon?

Hello folks! I have a big question for you:

I am creating a code which when you press keyboard then processing creates a random convex polygon but I am really struggling finding the right way.

thanks

1 Like

Hi @rioma7!
You can generate a random set of points using your preferred random generator ( PVector.random2D, random(), or randomGaussian() ) and apply convex hull algorithm to the points. Check out the wikipedia entry for QuickHull pseudocode.

If you just want a regular polygon function, check the example in processing under Basics > Form > Regular Polygon

Passing parameters to create a regular polygon is one of the examples of creating your own function – polygon() – on the Processing website. You can see it here:

1 Like

In the code linked by @jeremydouglass the angles are evenly spaced, so you get regular polygons. If you would like irregular polygons do randomize the angles. Maybe like this:

  • create an array containing 3 or more floats between 0 and TWO_PI (the angles)
  • sort that array
  • iterate through the array of angles and add a vertex for each angle

If you do this on a frame by frame basis, the polygon will jitter, because you get a new random polygon in each frame. You can avoid the jitter by “storing” the generated polygon in a PShape, probably inside setup, and then drawing that PShape inside draw.

I made a small program to do this, but I better don’t spoil the exercise by posting the code :slight_smile:

4 Likes

@jeremydouglass / @hamoid thanks guys. Now I try to find out a solution otherwise I will ask you again :slight_smile:

thanks also to @WakeMeAtThree

@hamoid I need your help :anguished:

I cannot find a solution, I have tried a lot of stuff but never finding a solution!!!

This is the thing I wrote:

PShape shapes[] = new PShape[64];

void setup() {
  size(600, 600, P2D);
  noStroke();
  fill(70);

  for (int i=0; i<shapes.length; i++) {
    shapes[i] = polygon(30, (int)random(3, 10));
  }
}

void draw() {
  background(255);
  for (int i=0; i<shapes.length; i++) {
    pushMatrix();
    // put the polygons in a grid
    translate(map(i%8, 0, 7, 50, 550), map(i/8, 0, 7, 50, 550));
    // make them rotate at different speeds
    rotate(frameCount / (50.0 + 10 * i));
    shape(shapes[i]);
    popMatrix();
  }
}

PShape polygon(float radius, int npoints) {
  // create a random list of angles
  float angles[] = new float[npoints];
  for(int i=0; i<npoints; i++) {
    angles[i] = random(TWO_PI);
  }
  // sort the list
  angles = sort(angles);
  
  // create a shape with those angles
  PShape s = createShape();
  s.beginShape();
  for (float a : angles) {
    float sx = cos(a) * radius;
    float sy = sin(a) * radius;
    s.vertex(sx, sy);
  }
  s.endShape(CLOSE);
  return s;
}
2 Likes

thanks @hamoid

Now I was trying to create only one shape when I KeyPressed(); but I don’t know how to do it because if I put everything inside

if(keyPressed){
for (int i=0; i<shapes.length; i++) {
    pushMatrix();
    translate(map(i%8, 0, 7, 50, 550), map(i/8, 0, 7, 50, 550));
    shape(shapes[i]);
    popMatrix();
  }

PShape polygon(float radius, int npoints) {
  // create a random list of angles
  float angles[] = new float[npoints];
  for(int i=0; i<npoints; i++) {
    angles[i] = random(TWO_PI);
  }
  // sort the list
  angles = sort(angles);
  
  // create a shape with those angles
  PShape s = createShape();
  s.beginShape();
  for (float a : angles) {
    float sx = cos(a) * radius;
    float sy = sin(a) * radius;
    s.vertex(sx, sy);
  }
  s.endShape(CLOSE);
  return s;
}

it doesn’t work and I also didn’t understand how can I move the polygon in the middle of the screen to export in PDF.

The example above was creating an array of 64 shapes. If you only need one, you don’t need that array, and you don’t need the for loop to iterate 64 times creating and drawing all shapes. You just need one I assume.

You can keep the polygon function, which just returns a shape with a polygon. The following example creates and draws a polygon every time you press a key:

void setup() {
  size(600, 600, P2D);
  background(255);
}

void draw() {
}

void keyPressed() {
  noStroke();
  fill(random(255));
  PShape shp = polygon(200, (int)random(3, 10));
  translate(width * 0.5, height * 0.5); // move to the center of the screen
  rotate(random(TWO_PI)); // random rotation
  shape(shp); // draw the polygon
}

PShape polygon(float radius, int npoints) {
  // create a random list of angles
  float angles[] = new float[npoints];
  for (int i=0; i<npoints; i++) {
    angles[i] = random(TWO_PI);
  }
  // sort the list
  angles = sort(angles);

  // create a shape with those angles
  PShape s = createShape();
  s.beginShape();
  for (float a : angles) {
    float sx = cos(a) * radius;
    float sy = sin(a) * radius;
    s.vertex(sx, sy);
  }
  s.endShape(CLOSE);
  return s;
}

Notice that it assigns a random gray color to each polygon, this way you can notice the overlapping polygons. But of course you can change this.

Also notice that the polygon function takes two arguments: first, the radius of the polygon, and second, the number of points it should have.

1 Like

An image to help understand what this polygon function does:

The polygon function receives two arguments: a radius (to set how large the polygon should be) and a number of points. In the image you see 4 examples with 3, 4, 5 and 5 points.

The polygon function first creates an array of angles, each value in that array being between 0 and TWO_PI.

float angles[] = new float[npoints];
for (int i=0; i<npoints; i++) {
  angles[i] = random(TWO_PI);
}

That range contains all possible angles in a circle, as you can see in this image in the outer ring of values that goes 0 0.1 0.2 0.3 … 6.0 6.1 6.2:

Let’s say we asked for a polygon with 5 points, and our angles[] array contains these random numbers:
4.2 1.3 3.0 0.5 5.9. We will use the angles to find 2D points in a circle, by using sin() and cos(), and then connect those points.

The red shape in the image shows what can happen if you forget to sort the list of random angles: you may get a strange shape. By sorting the angles you make sure the angles are either clockwise or counterclockwise and avoid such strange shapes.

angles = sort(angles);

The second part of the polygon function creates a shape and adds one by one points using the sorted angles. To convert an angle to a 2D point we use cos() and sin(). Those two functions return numbers between -1 and +1, which would be a very small polygon. That’s why we multiply the values by radius, so the polygon can have coordinates between -radius and +radius.

  PShape s = createShape();
  s.beginShape();
  for (float a : angles) {
    float sx = cos(a) * radius;
    float sy = sin(a) * radius;
    s.vertex(sx, sy);
  }
  s.endShape(CLOSE);
  return s;
2 Likes

THANK YOU VERY MUCH! @hamoid

Hallo guys!!! Unfortunately I need more help…
my project is changed a bit and now basically is to create a shape using the data from the audio frequency!

So read the audio frequency (between 20Hz to 20kHz) and if [X is the read frequency by the microphone]

if x >= 9990Hz
draw a random polygon in a random position on the screen
long and narrow
with inside angles =< 90°

if x=<9990Hz
draw a random polygon in a random position on the screen
flat and wide
with angles =>90°

I only need how to draw the polygons…the polygon should be convex or concave

I hope you can help me!

If concave polygons are ok, you can randomize the radius with something like this:

  for (float a : angles) {
    float r = radius * random(0.7, 1.3);
    float sx = cos(a) * r;
    float sy = sin(a) * r;
    s.vertex(sx, sy);
  }

That way they points no longer fall in a circle, some are farther from the center, others are closer.

One way to make long shapes would be to choose the angles in a way that they are near two opposing locations in a circle. 0 and PI are opposed (0 and 180 degrees). So you could randomly choose either 0 or PI, and then add some randomness around that:

angles[i] = int(random(2)) * PI + random(0.8);

int(random(2)) gives either 0 or 1. Multiplied by PI you get either 0 or PI. Then add some randomness so you do NOT only get 0 or PI, but numbers around 0 and numbers around PI.

But there are maaaany ways to create shapes. I suggest you make some drawings and then think how they could be created, or post the drawings and people can suggest how to code them. I find it a very fun challenge :slight_smile:

So basically my code actual is:

import ddf.minim.;
import ddf.minim.analysis.
;
Minim minim;
FFT fft;
AudioInput in;
float amp = 20; // used to make signal stronger/weaker
float ampWave = 20*amp;
float avgAudio; // store avg volume globally

float bass;
float high;

void setup(){
background(255);
size(500, 500);
noStroke();
smooth();

minim = new Minim(this); // initalize in setup
in = minim.getLineIn(Minim.STEREO, 512); // audio in + bufferSize 512 or 1024
fft = new FFT(in.bufferSize(), in.sampleRate());
fft.logAverages(22, 3); // 3 = 30, 4 = 40, slices of frequency
}

void draw(){

if(keyPressed) {
fft.forward(in.mix); // IMPORTANT! -update for FFT anaylsis
bass = fft.calcAvg(20,300)*amp; // fft.calcAvg(minFreq, maxFreq)
high = fft.calcAvg(300,20000)*amp;
}

if(bass > high){
background(255);
fill(0,0,255);
ellipse(width/2, height/2, 50,50);
}

else if(high > bass) {
background(255);
fill(255,0,0);
rect(width/2, height/2, 50,50);
}

println(bass+" / "+high);

}

and instead of the two background I would like to draw two “random” polygons… here on the sketch you can look at it easily:

thanksssss

I think you need to do a lot more drawing to understand your concept – try making a series of images or an animatic.

For example, you suggest that each could have as few as three sides… that’s always a triangle, and it cannot meet the requirement “all angles >= 90”. Similarly, there aren’t closed polygons higher than 4 sides with every angle “<= 90” – for five and up, the average angle must be > 90 … and to create small angles in a closed 5-plus-agon you must pair them with large angles (e.g. starburst).

I was wandering if can I code something like this:

beginShape();
vertex(random(x), random(y));
vertex(random(x),random(y));
vertex(random(x),random(y));
vertex(random(x),random(y));
endShape(CLOSE);

Should I declare randomX and randomY? And can I say draw random vertex between 4 and 10?

thankssss

solved like this

background(255);
noStroke();
fill(255,0,0);

int n_vertex = int(random(3, 7));

beginShape();
for (int i = 0; i < n_vertex; i++) {
  vertex(random(width), random(height));
}
endShape(CLOSE);
1 Like