How to create nested polygon


#1

Hi, I’m new to processing, and this is my first post. I has some problem with a processing assignment in school, so I hope everyone can help me to see how to approach to this problem.
So basically I want to create a nested polygon pattern.!


I created the outer polygon by connecting random vertices around a circle.
Then I need to find the midpoints between every vertices. The problem is that all my x-coordinates are stored in sx, and all my y-coordinates are stored in sy, so I have no idea how to calculate the midpoints.
Here is my code:

int numVertices=int(random(4,10));
float[] sx;
float[] sy;
void setup() {
  size(600, 600);
  background(255);
  noLoop();
}

void draw() {
  stroke(0);
  noFill();
  translate(width/2, height/2); // move to the center of the screen
  float angles[] = new float[numVertices];
  float radius=250;
  for (int i=0; i<numVertices; i++) {
      angles[i] = random(TWO_PI);
  }
       
  angles = sort(angles);

for (int i = 0; i < 1; i++){
  drawPolygon(angles, radius);
 }
}

void drawPolygon(float[] angles, float radius){
  createShape();
  beginShape();
  for (int i = 0; i<numVertices; i++){
    for (float a : angles) {
      float sx = cos(a) * radius;
      float sy= sin(a) * radius;
      vertex(sx, sy);
  }
  endShape(CLOSE);
  }
}

#2

I would suggest you write a function that stores - in two new global arrays - the midpoints of the next iteration, based on the current points in your existing global arrays.

Then you will have FOUR arrays. Two for the current polygon’s points, and two for the NEXT polygon’s points.

After you draw the first polygon, can you run a new function that overwrites the current points with the values from the next polygon’s?

float[] nextX;
float[] nextY;

void gen_next_points(){
  // TODO: Fill nextX and nextY with the right values.
}

void copy_values(){
  // TODO: move the values form nextX and nextY to px and py.
}

#3

Hi TfGuy44,
Thank you for replying so soon! I think for arrays nextX and nextY, I need to shift my original arrays one place to the right. The problem is that I do not know how to do so in processing :frowning_face:


#4

Nope! There’s no need to do any sort of shifting at all!

Consider a simple case: Your polygon has four points. So then the shape made by drawing lines between those points has… four sides. That means there are going to be four midpoints to use for the next iteration! Notice how the number of points/lines/midpoints is always the same and unchanging?

This solves another question: How big do your nextX and nextY arrays need to be? They need to be the same length as your px and py arrays!


#5

Okay I see. But how do I compute the midpoints?


#6

That is like the main issue


#7

Oh! :sweat_smile:

Here’s an example:


float ax, ay, bx, by;

void setup() {
  size(400, 400);
  ax = 200;
  ay = 200;
  fill(0);
  stroke(255);
}

void draw() {
  background(0);
  bx = mouseX;
  by = mouseY;
  line(ax, ay, bx, by);
  ellipse(ax, ay, 5, 5);
  ellipse(bx, by, 5, 5);
  float cx = (ax + bx) / 2.0;
  float cy = (ay + by) / 2.0;
  ellipse(cx, cy, 5, 5);
}

void mousePressed() {
  ax = mouseX;
  ay = mouseY;
}

#8

Okay thank you! I will look into that :grinning:


#9

So now the vertices of my first polygon will be( x1,y1) and the midpoints of my polygon(or the next points) will be(mx, my). I set up in the way that mx=(x1+x2)/2, my=(y1+y2)/2. I don’t know what should I write for x2 and y2 for this to make sense :anguished: And I seriously don’t know what to write to make this recursion.


#10

Here’s the finished, working effect:

int numVertices=int(random(4, 10));
float[] curtX;
float[] curtY;
float[] nextX;
float[] nextY;
float[] angles;

void setup() {
  size(600,600);
  curtX = new float[numVertices];
  curtY = new float[numVertices];
  nextX = new float[numVertices];
  nextY = new float[numVertices];
  angles = new float[numVertices];
  // Pick initial random angles.
  for (int i=0; i<numVertices; i++) {
    angles[i] = random(TWO_PI);
  }
  // Sort the angles.
  angles = sort(angles);
}

void draw() {
  background(0);
  stroke(255);
  noFill();
  translate(width/2, height/2);
  float radius=280;
  ellipse(0,0,2*radius, 2*radius);
  // Convert the random angles to (x,y) positions.
  for (int i = 0; i < numVertices; i++) {
    curtX[i] = cos(angles[i]) * radius;
    curtY[i] = sin(angles[i]) * radius;
  }
  for( int t = 0; t < 20; t++){
    draw_polygon();
    next_gen();
    copy_back();
  }
  noLoop();
}

void draw_polygon() {
  beginShape();
  for (int i = 0; i<numVertices; i++) {
      vertex(curtX[i], curtY[i]);
  }
  endShape(CLOSE);
}

void next_gen(){
  for( int i = 0; i < numVertices; i++){
    nextX[i] = ( curtX[i] + curtX[(i+1)%numVertices] ) / 2.0;
    nextY[i] = ( curtY[i] + curtY[(i+1)%numVertices] ) / 2.0;
  }
}

void copy_back(){
  for( int i = 0; i < numVertices; i++){
    curtX[i] = nextX[i];
    curtY[i] = nextY[i];
  }
}

Make sure you study this - line by line, function by function, one loop at a time - in detail so you understand how it works.


#11

Oh my god…Thank you so much!!!
My school taught us how to do some basic algorithms such as circle packing, but I do not have prior coding experience, and I am kind of confused with the logic of how processing operates…
I will make sure I study this code thoroughly and watch some coding train videos. Again, I cannot thank you enough! :grin::grin::grin:


#12

Asking questions about things is also good.

Wheeee!

int numVertices=120; //int(random(30,60));
float[] curtX;
float[] curtY;
float[] nextX;
float[] nextY;
float[] angles;
float[] da;

void setup() {
  size(600,600);//,P3D);
  curtX = new float[numVertices];
  curtY = new float[numVertices];
  nextX = new float[numVertices];
  nextY = new float[numVertices];
  angles = new float[numVertices];
  da = new float[numVertices];
  // Pick initial random angles.
  for (int i=0; i<numVertices; i++) {
    angles[i] = i*TWO_PI/float(numVertices); //random(TWO_PI);
    da[i] = random(-.05,.05);
  }
  colorMode(HSB, 255);
  
  background(0);
}

void draw() {
  //background(0);
  fill(0,0,0,10);
  noStroke();
  rect(0,0,width,height);
  stroke(255);
  noFill();
  translate(width/2, height/2);
  //rotateY(map(millis()%7000,0,7000,0,TWO_PI));
  float radius=280;
  for (int i=0; i<numVertices; i++) {
    angles[i] += da[i];
  }
  // Convert the random angles to (x,y) positions.
  for (int i = 0; i < numVertices; i++) {
    curtX[i] = cos(angles[i]) * radius;
    curtY[i] = sin(angles[i]) * radius;
  }
  for( int t = 0; t < 20; t++){
    stroke((map(t,0,20,0,128)+map(millis()%7000,0,7000,0,255))%255,255,map(t,3,20,128,255));
    draw_polygon(t);
    next_gen();
    copy_back();
  }
  stroke(255);
  strokeWeight(3);
  ellipse(0,0,2*radius, 2*radius);
  strokeWeight(1);
}

void draw_polygon(int z) {
  beginShape();
  for (int i = 0; i<numVertices; i++) {
      vertex(curtX[i], curtY[i]);//, -20*z);
  }
  endShape(CLOSE);
}

void next_gen(){
  for( int i = 0; i < numVertices; i++){
    nextX[i] = ( curtX[i] + curtX[(i+1)%numVertices] ) / 2.0;
    nextY[i] = ( curtY[i] + curtY[(i+1)%numVertices] ) / 2.0;
  }
}

void copy_back(){
  for( int i = 0; i < numVertices; i++){
    curtX[i] = nextX[i];
    curtY[i] = nextY[i];
  }
}

#13

Woah, that’s something mind-blowing!
Processing does have great potential to generate cool, random patterns (although I can only do squares and circles for now lol)!
Thanks for showing me that :grinning:


#14

BTW. I’m not sure if this would help or make it harder, but there’s this nice thing called PVector that can be used to represent a point. So finding a point between A and B is very easy in that case.

PVector a = new PVector(10, 10);
PVector b = new PVector(100, 30);
PVector c = PVector.lerp(a, b, 0.50);

That gives you a c that is exactly in the middle between a and b. Lerp means linear-interpolation. Then you can access c.x and c.y to get the coordinates.

You don’t need to use 0.50. If you use 0.0, you get a. With 1.0 you get b. With 0.20 you get a point between a and b, that is 1/5 of the the distance from a to b.

The program from above using PVector and not exactly at the middle (0.25):

PVector a, b;

void setup() {
  size(400, 400);
  a = new PVector(200, 200);
  b = new PVector(100, 100);
  fill(0);
  stroke(255);
}

void draw() {
  background(0);
  b.set(mouseX, mouseY);
  line(a.x, a.y, b.x, b.y);
  ellipse(a.x, a.y, 5, 5);
  ellipse(b.x, b.y, 5, 5);
  PVector c = PVector.lerp(a, b, 0.25);
  ellipse(c.x, c.y, 5, 5);
}

void mousePressed() {
  a.set(mouseX, mouseY);
}