We are about to switch to a new forum software. Until then we have removed the registration on this forum.
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();
}
}
Answers
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 understandsin(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 :-).
Thanks already for you input!
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.
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
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. :-$
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!
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:
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.
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.
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
At constructor's we can use method set() in order to reassign the values in a PVector:
https://Processing.org/reference/PVector_set_.html
We can even have an extra constructor which receives a direct pair of
int
orfloat
primitive values: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[]:
Here's my tweaked version based on your original: :ar!
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
@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/
Watch it online here: http://p5js.SketchPad.cc/sp/pad/view/ro.RmWK6w2aY9t/latest
"RandomPolygonShape.html":
@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." ?
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... :-(
final
when used on variables prohibits them to be re-assigned more than once.new
1.private
fields, it makes sure the caller won't be able to access the internal PVector.https://GitHub.com/fjenett/javascript-mode-processing/issues/33#issuecomment-146649518
https://Processing.org/reference/createShape_.html
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.
@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...
protected
, along w/private
&public
, controls the access level for class members.http://docs.Oracle.com/javase/tutorial/java/javaOO/nested.html
protected
as a subtle way of saying that those 2 methods weren't supposed to be directly invoked from outside. Rather use rebuildPolygon() instead. ;;)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)
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 :-).
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!!