#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# How to avoid crossing borders in a random polygon?

edited February 2016

Hello, I want to make a generative sketch. I want polygons (with a random number of corners) to grow on each other. I'm busy with step one. One random polygon. The basic idea works, but of course, by using random corners I get borders that cross each other. I don't want that, I want "full" polygons.

Is there a logical solution I don't think about right now?

I wanted to avoid using angles, but maybe that's the way. Or polygons built from overlapping triangles.

This what I have now:

``````Polygon Polygon1;

void setup() {
size(600, 600);
Polygon1 = new Polygon();
background(204, 100, 30);
Polygon1.display();
}

class Polygon {
int numbercorners= int(random(3, 8));
float xpos = 300;
float ypos = 300;

Polygon() {
}

void display() {
println(numbercorners);
beginShape();
float endcornerx=random(-40, +40);
float endcornery=random(-40, +40);
vertex(xpos+endcornerx, ypos+endcornery);
for (int i = 0; i < numbercorners-1; i++) {
vertex(xpos+random(-40, +40), ypos+random(-40, +40));
}
vertex(xpos+endcornerx, ypos+endcornery);
endShape();
}
}
``````
Tagged:

• edited February 2016 Answer ✓

Hi Jonasan,

Unfortunately my solution has a a little angle work but it is pretty simple.

I started by having an array of PVectors[] to store some points. Here is how I created the points: ```int r = int(3, 8); float t = 360/r; for (int i = 0; i < r; i++) { points[i] = new PVector(sin(radians(i*t))*200, cos(radians(i*t))*200); }```

I am not sure whether this makes sense but I will run over it a little and if you need help understanding it just say so. The first variable should make sense. In the sense of making an equilateral polygon, the second variable tells me the size that every internal angle needs to be. Assuming you know how sin and cos, we simply multiply i (as its values are from 1 - r) by our internal angle variable and use that as the angle we need to move to our next point.

Once we have the points stored we draw them like so: ```beginShape(); for (int i = 0; i < points.length; i++) { vertex(points[i].x, points[i].y); } endShape(CLOSE);```

Try implementing this into your code, to make the polygons more random looking, add random values to the shape size, so for example `sin(radians(i*t))*(200*random(-100, 50)`

Let me know if you need any help understanding the code or implementing it.

• The polygon doesn't have to be equilateral, but if that's the easiest solution, it can be.

I understand: r is the random number of corners, t is for the equal distance between the angle of each corner and points[] each x and y position of those corners. `i * t` is the angle of each corner. I had to look up the link between vector and sin/cos, but now I understand `sin(radians(i * t)) * 200, cos(radians(i * t)) * 200`.

I didn't know you could use points.length to use the length of an Array. I guess you can use "r" as wel, since r is the number of corners = the length of the Array? I also didn't know how to use PVector, `(points[i].x, points[i].y)`.

So I already learned a lot :-).

Alas, I tried to implement the whole thing, but the sketch freezes (NullPointerException in `points[i] = new PVector(sin(radians(i*t))*200, cos(radians(i*t))*200);` I don't understand why)

I also have to think about the first and last corner/point being the same location. Something for tomorrow, it's getting late in Belgium :-).

Make sure you declare the points array correctly. `PVector[] points;` Also before you start adding the points in the constructor, you need to create the array like so. `points = new PVector[];`

I don't think you will need to worry about the first and last points as in the draw function I gave you, the line `endShape(CLOSE);` automatically joins the first and last points together. The 'CLOSE' parameter does this trick.

Hope this helps some more. If your still having trouble I can give you my example code.

• Thanks @slambeetle!

I was a little hasty and sloppy yesterday, I corrected the array declaration. I corrected the sketch and made the polygons more irregular. Now for the next step: attaching one polygon to the previous one.

You can follow the sketch here: GrowPolygons.

Before I asked: is it okay to post the link to openprocessing, or better to post the code here; I found the answer myself: better to post the code here for future reference, because the openprocessing sketch can/will change later.

``````Polygon Polygon1;

void setup() {
size(600, 600);
Polygon1 = new Polygon();
background(204, 100, 30);
Polygon1.display();
}

class Polygon {

float xpos = 300;
float ypos = 300;
PVector[] points;

Polygon() {
}

void display() {
int numbercorners= int(random(3, 8));
float t = 360/numbercorners;
points = new PVector[numbercorners];

for (int i = 0; i < numbercorners; i++) {
}

println(numbercorners);

beginShape();
for (int i = 0; i < points.length; i++) {
vertex(xpos+points[i].x, ypos+points[i].y);
}
endShape(CLOSE);
}
}
``````
• I'm trying to use PVector in stead of separate X and Y positions. Is this useful you think, or isn't this something to use PVector for?

• PVectors are just ways of storing 2 numbers. Coordinates are a common use of PVectors as it was some neat functions like distance, magnitude, normalize and much more. https://processing.org/reference/PVector.html

• edited February 2016 Answer ✓

PVectors are just ways of storing 2 numbers.

Actually it's got 3 fields: x, y & z. :-\" Of course we're free to ignore the last z. ;;)
It's better applied when we need to use its methods: https://Processing.org/reference/PVector.html
But it's not that a big deal if we just use them as sorta 2 or 3 values container. :-\$

• edited February 2016

I understood it was meant for coordinates, so I thought: since I'm using coordinates, maybe using PVectors will give me a benefit sooner or later. I was not sure, because we almost ALWAYS use coordinates in Processing, while I don't see PVectors used always.

For the sake of learning possible benefits, I switch to PVector in this sketch, but I noticed I use the separate .x and .y a lot, which is why started doubting the benefits in this case. Hence my question.

I understand: if I'm not using the specific methods for PVector, it's no added value to use PVectors (as soon as you explained that, it seemed too logic to have asked :-) ). I will try a little further with the PVector, because I have the feeling I don't use it at "full power" yet and maybe I have to get used to PVector-thinking.

Thanks @slambeetle and @GoToLoop!

``````    Polygon Polygon1;

void setup() {
size(600, 600);
Polygon1 = new Polygon(new PVector(300, 300));
background(204, 100, 30);
Polygon1.display();
}

class Polygon {
PVector begincorner;
PVector endcorner = new PVector(300, 300);
PVector[] points;

Polygon(PVector tempbegincorner) {
begincorner = tempbegincorner;
}

void display() {
int numbercorners= int(random(3, 8));
float t = 360/numbercorners;
points = new PVector[numbercorners];

for (int i = 0; i < numbercorners; i++) {
}
beginShape();
vertex(begincorner.x, begincorner.y);
for (int i = 0; i < points.length-1; i++) {
endcorner.x = begincorner.x + points[i].x;
endcorner.y = begincorner.y + points[i].y;
vertex(endcorner.x, endcorner.y);
}
endShape(CLOSE);
}

PVector newcorner() {
endcorner=(new PVector(endcorner.x, endcorner.y));
return endcorner;
}
}
``````

the endcorner is because I will start the next polygon connected to the previous polygon, that's the next thing I'll work out.

To use the benefits of PVector, I guess I have to use rotate() in stead of

points[i] = new PVector(sin(radians(i * t)) * (14+random(-8, 10)), cos(radians(i * t)) * (14+random(-8, 10)));

• Is there any reason you aren't using the `draw(){}` function? Also you seem to be assigning your PVector array values inside your display function when conventionally you should be doing this in the constructor.

Your newcorner function doesn't make sense either. If you want the last point of your polygon or any point you simply return points[index]. An example function would be:

```    PVector getPoint(int i){
return points[i];
}
```

To rotate the polygon you would need to use pushMatrix and popMatrix. The formula I gave you must be used to create the polygon.

How new are you to processing? I ask as the code you provided doesn't all make sense to what you are trying to achieve.

• edited February 2016

I'm very new :-)

I read half the book of Daniel Shiffman and did most of the exercises, but then stopped for a few months. Now I picked up again.

I'm not using the draw-function (yet) because I thought: setup is for actions you only want to perform once. I only want to draw the polygon once, so I thought it doesn't have to be in draw (where it should be looped for no reason?).

I want to use the newcorner-function to draw the next polygon, first corner touching previous last corner. That isn't worked out yet, because I don't succeed in passing the PVector to a new Polygon2. When I have time today, I use your tip!

I'm trying PVector for the reason described above. It's totally new for me. I don't want to use de matrix-thing, I think PVector is already too advanced for what I want (polygons growing other polygons in some of their corners).

I keep reading Learning Processing and yesterday I discovered Fun Programming, I'll start checking that out as well.

• edited February 2016 Answer ✓

Some tips for your class Polygon: *-:)

At newCorner() method, since endCorner is already a PVector, we can take advantage of its method get() or copy() in order to clone it:
https://Processing.org/reference/PVector_copy_.html

``````PVector newCorner() {
return endCorner.get();
}
``````

At constructor's we can use method set() in order to reassign the values in a PVector:
https://Processing.org/reference/PVector_set_.html

``````class Polygon {
final PVector beginCorner = new PVector();
final PVector endCorner = new PVector(width*.5, height*.5);

Polygon(PVector startCorner) {
beginCorner.set(startCorner);
}
}
``````

We can even have an extra constructor which receives a direct pair of `int` or `float` primitive values:

``````class Polygon {
final PVector beginCorner = new PVector();
final PVector endCorner = new PVector(width/2, height/2);

Polygon(PVector startCorner) {
beginCorner.set(startCorner);
}

Polygon(float x, float y) {
beginCorner.set(x, y);
}
}
``````

For a tidier organization, we should separate display() from rebuild().
That is, make 1 separate method to build those points[], and keep display() only to show those pre-calculated points[]:

``````class Polygon {
static final int CORNERS_MIN = 3, CORNERS_MAX = 7;
static final int DIAM = 6, DIM_MIN = 6*DIAM, DIM_MAX = 24*DIAM;

final PVector beginCorner = new PVector();
PVector[] corners;

void rebuildCorners() {
final int qty = (int) random(CORNERS_MIN, 1 + CORNERS_MAX);
corners = new PVector[qty];

for (int i = 0; i < qty; ++i) {
final float x = cos(i*rad) * random(DIM_MIN, DIM_MAX);
final float y = sin(i*rad) * random(DIM_MIN, DIM_MAX);
corners[i] = new PVector(x, y);
}
}
}
``````
• edited February 2016 Answer ✓

Here's my tweaked version based on your original: :ar!

``````/**
* Random Polygon Shape (v2.03)
* by Jonasan & GoToLoop (2016-Feb-24)
*
* forum.Processing.org/two/discussion/15064/
* how-to-avoid-crossing-borders-in-a-random-polygon
*/

Polygon poly;

void setup() {
size(300, 300);
smooth(4);
noLoop();
frameRate(5);
shapeMode(CORNER);
poly = new Polygon(width>>1, height>>1);
}

void draw() {
background((color) random(#000000));
poly.display();
frame.setTitle("Corners: " + poly.corners.length);
}

void keyPressed() {
poly.rebuildPolygon();
redraw();
}

void mousePressed() {
keyPressed();
}

class Polygon {
static final int CORNERS_MIN = 3, CORNERS_MAX = 7;
static final int DIM = 6, RAD_MIN = 6*DIM, RAD_MAX = 24*DIM;
static final color FILL = #FFFF00, STROKE = 0;

final PVector beginCorner = new PVector();
PVector[] corners;
PShape s;

Polygon(PVector startCorner) {
this(startCorner.x, startCorner.y);
}

Polygon(float x, float y) {
beginCorner.set(x, y);
rebuildPolygon();
}

void display() {
shape(s);
}

void rebuildPolygon() {
rebuildCorners();
rebuildShape();
}

protected void rebuildCorners() {
final int qty = (int) random(CORNERS_MIN, 1 + CORNERS_MAX);

corners = new PVector[qty];

for (int i = 0; i < qty; ++i) {
corners[i] = new PVector(x, y);
}
}

protected void rebuildShape() {
s = createShape();
s.beginShape();

s.fill(FILL);
s.stroke(STROKE);
s.strokeWeight(1.5);

s.translate(beginCorner.x, beginCorner.y);
for (final PVector v : corners)  s.vertex(v.x, v.y);

s.endShape(CLOSE);
}
}
``````
• PVectors are used to represent, well, vectors...

The first chapter of Dan Shiffman's The Nature of Code is about vectors.

It's a great reference, it explains some of the math with vectors and shows some of the methods of PVectors with processing examples.

http://natureofcode.com/book/chapter-1-vectors/

In lines 30 and 31, you're basically adding vectors, you can replace them by:

`endcorner = PVector.add(begincorner, points[i]);`

• I've made a Python Mode version as well: :D

``````'''
* Random Polygon Shape (v2.03)
* by Jonasan & GoToLoop (2016-Feb-24)
*
* forum.Processing.org/two/discussion/15064/
* how-to-avoid-crossing-borders-in-a-random-polygon
'''

def setup():
size(300, 300)
smooth(4), noLoop(), frameRate(5), shapeMode(CORNER)

global poly
poly = Polygon(width>>1, height>>1)

def draw():
background(int(random(0x1000000)))
poly.display()
frame.setTitle('Corners: %i' % len(poly.corners))

def keyPressed(): poly.rebuildPolygon(), redraw()
def mousePressed(): keyPressed()

class Polygon:
CORNERS_MIN, CORNERS_MAX = 3, 7
DIM = 6
FILL, STROKE = 0xffFFFF00, 0

def __init__(_, v, y=None):
_.beginCorner = PVector(v.x, v.y) if y is None else PVector(v, y)
_.rebuildPolygon()

def display(_): shape(_.s)
def rebuildPolygon(_): _.rebuildCorners(), _.rebuildShape()

def rebuildCorners(_):
qty = int(random(Polygon.CORNERS_MIN, 1 + Polygon.CORNERS_MAX))

for i in range(qty))

def rebuildShape(_):
_.s = createShape()
_.s.beginShape()

_.s.fill(Polygon.FILL), _.s.stroke(Polygon.STROKE), _.s.strokeWeight(1.5)

_.s.translate(_.beginCorner.x, _.beginCorner.y)
for v in _.corners: _.s.vertex(v.x, v.y)

_.s.endShape(CLOSE)
``````
• edited February 2016

@slambeetle:
"Your newcorner function doesn't make sense either. If you want the last point of your polygon or any point you simply return points[index]. An example function would be:"
I don't want to return the index, I want to return the x and y position, the vector.

And "To rotate the polygon you would need to use pushMatrix and popMatrix"

I don't want to rotate the polygon. But each corner is a rotation of the previous point (already, but with cos en sin).

Thanks for thinking with me, anyway ;-) !

• And for completeness' sake, also a p5.js version: \m/

## "RandomPolygonShape.html":

```<script src=http://p5js.org/js/p5.min.js async></script>

<script>

/**
* Random Polygon Shape (v2.03)
* by Jonasan & GoToLoop (2016-Feb-24)
*
* https://forum.Processing.org/two/discussion/15064/
* how-to-avoid-crossing-borders-in-a-random-polygon
*
*/

var poly

function setup() {
createCanvas(300, 300)
smooth().frameRate(5).noLoop()
poly = new Polygon(width>>1, height>>1)
}

function draw() {
background('#' + hex(~~random(0x1000), 3))
poly.display()
document.title = `Corners: \${poly.corners.length}`
}

function keyPressed() {
poly.rebuildPolygon()
redraw()
}

function mousePressed() {
keyPressed()
}

class Polygon {
constructor (v, y) {
this.beginCorner = typeof y === 'number'?
createVector(v, y) : createVector(v.x, v.y)

this.s = createGraphics(width, height)
this.s.fill(this.FILL).stroke(this.STROKE).strokeWeight(1.5)

this.rebuildPolygon()
}

display() {
image(this.s, 0, 0)
}

rebuildPolygon() {
this.rebuildCorners(), this.rebuildShape()
}

rebuildCorners() {
const qty = ~~random(this.CORNERS_MIN, 1 + this.CORNERS_MAX),

this.corners = Array(qty)

for (let i = 0; i < qty; ++i) {
this.corners[i] = createVector(x, y)
}
}

rebuildShape() {
this.s.clear()
this.s.translate(this.beginCorner.x, this.beginCorner.y)

this.s.beginShape()
for (const v of this.corners)  this.s.vertex(v.x, v.y)
this.s.endShape(CLOSE)

this.s.resetMatrix()
}
}

Polygon.prototype.CORNERS_MIN = 3
Polygon.prototype.CORNERS_MAX = 7
Polygon.prototype.DIM = 6
Polygon.prototype.FILL = 'yellow'
Polygon.prototype.STROKE = 0

Object.freeze(Object.freeze(Polygon).prototype)

</script>
```
• edited February 2016

@GoToLoop :-D I think your on an unstoppable coding ride :-) I'm still busy applying your first comment (I go through it line by line, to really get what you explain). Why is the "final"? I guess it's not necessary, the reference says "This keyword is an essential part of Java programming and is not usually used with Processing." ?

``````class Polygon {
PVector beginCorner = new PVector();

Polygon(PVector startCorner) {
beginCorner.set(startCorner);
}
}

class Polygon {
PVector beginCorner;

Polygon(PVector tempbeginCorner) {
beginCorner = tempbeginCorner;
}
}
``````

Those to ways accomplish the same, what's the advantage of the first?

• The JavaScript mode is not compatible with my version of Processing, I can't see it... :-(

• edited February 2016 Answer ✓

Why is the `final`? I guess it's not necessary, ...

• Keyword `final` when used on variables prohibits them to be re-assigned more than once.
• When initializing a field variable w/ a compile-time constant, it behaves as if it were a literal value.
• Indeed it's not that necessary. But as you can see now, it's got some advantages.

Those 2 ways accomplish the same; what's the advantage of the first?

• 1st 1 is more independent from the passed PVector.
• For example, it safeguards against the caller passing the very same PVector over & over rather than instantiating a `new` 1.
• For `private` fields, it makes sure the caller won't be able to access the internal PVector.
• Also, it's a good use of PVector::set() method. 8-X

The JavaScript mode is not compatible with my version of Processing, ...

• edited February 2016

Thanks for introducing me to Multiple Constructors and Redraw. I'm getting good education here, again :-)

• @BarbaraAlmeida thanks for the link, I'll check it out ( The Nature of Code). And I replaced line 30-31 like you said.

I start to "think PVector" a little more each step.

• edited February 2016

@GoToLoop: you use a lot of code that's still to complicated to me, I'll use what I understand ;-). I looked up final, didn't find protected in the reference, I guess you use a lot of Java. The way you use shape s with createShape(), s.beginShape(), s.fill(FILL), s.stroke(STROKE), s.strokeWeight(1.5), s.translate is completely new for me. I'll first learn the basics, before I try to understand those...

• edited February 2016 Answer ✓

I looked up `final`, didn't find `protected` in the reference,

• Processing's reference is far from complete unfortunately. Besides lotsa missinformation! :-&
• Keyword `protected`, along w/ `private` & `public`, controls the access level for class members.
• Find more about it here: http://docs.Oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
• Although access levels are useless to ".pde" files due to the fact all classes there are nested:
http://docs.Oracle.com/javase/tutorial/java/javaOO/nested.html
• So don't bother. I've only used `protected` as a subtle way of saying that those 2 methods weren't supposed to be directly invoked from outside. Rather use rebuildPolygon() instead. ;;)

The way you use `shape(s);` with... is completely new for me.

Well, up to this afternoon, I've never had used those before. I've had to look up for them here: *-:)
https://Processing.org/reference/createShape_.html

Yup, I've learnt a lot doing this as well! ~O)

• edited February 2016

This is the new version, with all the advice I could understand. Now I want to draw a second polygon, with the `PVector newCorner()` as the first vector. How do I pass that return value when I call the next polygon (something like: `Polygon2 = new Polygon(newCorner)`? (Later, I'll make an Array of Polygons).

And I noticed still a fault: the polygon never reaches the bottom left quarter (comment out the noLoop and you will see). I have to use the center coördinates to calculate the other points, so ADD the center to each, or something. So was it before. But that'll make it difficult to start from a corner to draw the next polygon. I'll decipher @GoToLoop s calculations :-).

``````Polygon Polygon1, Polygon2;

void setup() {
size(600, 600);
Polygon1 = new Polygon(new PVector(300, 300));
background(204, 100, 30);
}

void draw() {
Polygon1.build();
Polygon1.display();
noLoop();
}

class Polygon {
PVector beginCorner = new PVector();
PVector endcorner = new PVector();
PVector corner = new PVector();
PVector[] points;

Polygon(PVector startCorner) {
beginCorner.set(startCorner);
}

void build() {
int numbercorners= int(random(3, 8));
float t = 360/numbercorners;
points = new PVector[numbercorners];
corner = new PVector(beginCorner.x, beginCorner.y);

for (int i = 0; i < numbercorners; i++) {
}
}

void display() {
beginShape();
vertex(beginCorner.x, beginCorner.y);
for (int i = 0; i < points.length-1; i++) {
vertex(corner.x, corner.y);
}
endShape(CLOSE);
}

PVector newCorner() {      // This method is ment to pass the last vector
return corner.copy();    // to be the first vector of a new polygon.
}
}
``````
• I think this version is correct and the way I like it. I added random rotation to avoid the first point of the polygon always starting at the same place. I will continue with "growing polygons" from the first one. You can follow the advance at OpenProcessing - GrowPolygons. And presumably, I will return here because I'm stuck.: :-) Thanks a lot people!!

``````Polygon Polygon1;

void setup() {
size(600, 600);
Polygon1 = new Polygon(new PVector(300, 300));
background(204, 100, 30);
}

void draw() {
Polygon1.build();
Polygon1.display();
noLoop();
}

class Polygon {
PVector endCorner = new PVector();
PVector center = new PVector();
PVector[] points;

Polygon(PVector start) {
center.set(start);
}

void build() {
int numbercorners= int(random(3, 8));
float t = 360/numbercorners;
points = new PVector[numbercorners];
float rotation = random(0, 2 * PI);
for (int i = 0; i < numbercorners; i++) {
float xcorner = center.x + sin((radians(i * t)+rotation)) * (20 + random(-8, 10));
float ycorner = center.y + cos((radians(i * t)+rotation)) * (20 + random(-8, 10));
points[i] = new PVector(xcorner, ycorner);
println(numbercorners, points[i].x, points[i].y);
}
}

void display() {
beginShape();
for (int i = 0; i < points.length; i++) {
vertex(points[i].x, points[i].y);
}
endShape(CLOSE);
}

//  PVector endCorner() {      // This method is ment to pass the last vector
//    return points[i].copy();    // to be the first vector of a new polygon.
}
``````