I'm prototyping a script to plot equally spaced points around a rotating plane and Processing is producing unexpected results?
This is my code:
int WHITE = 255;
int BLACK = 0;
void setup() {
size(500, 500);
}
void draw() {
background(WHITE);
translate(width/2, height/2); // move origin to center of window
// center ellipse
noStroke();
fill(255, 0, 0);
ellipse(0, 0, 10, 10); // center point, red
// satellite ellipses
fill(BLACK);
int points = 4;
for (int i = 0; i < points; i++) {
rotate(i * (TWO_PI / points));
ellipse(0, 100, 10, 10); // after plane rotation, plot point of size(10, 10), 100 points above y axis
}
}
When points = 4 I get the output I would expect, but when points = 5 // also when points = 3 or > 4, I get an output that is missing plotted points but still spaced correctly.
Why is this happening?
You're rotating too much: you don't want to rotate by i * angle at every iteration, because if we do we end up rotating so much that points end up overlapping. For example, with the code as is, with 3 points we want to place them at 0, 120, and 240 degrees (or, 120, 240, 360). But that's not what happens:
when i=0 we rotate by 0 degrees. So far so good.
when i=1 we rotate by 120 degrees on top of 0. Still good.
when i=2 we rotate by 240 degrees on top of 120. That's 120 degrees too far!
That's clearly not what we want, so just rotate by the fixed angle TAU / points and things'll work as expected:
for (int i = 0; i < points; i++) {
rotate(TAU / points);
ellipse(0, 100, 10, 10);
}
Alternatively, keep the incrementing angle, but then place the points without using rotate(), by using trigonometry to compute the placement:
float x = 0, y = 100, nx, ny, angle;
for (int i = 0; i < points; i++) {
angle = i * TAU / points;
nx = x * cos(a) - y * sin(a);
ny = x * sin(a) + y * cos(a);
ellipse(nx, ny, 10, 10);
}
Related
I hope I'm asking this concisely enough. I'm wanting to run a script that will predict where a rectangle will end up when doing a rotation, before the rotation actually starts. So, if you're given a rectangle which is located on coordinates (40, 40) and you want the angle to change by 20 degrees, how would you predict or estimate the x y values of where that rectangle would end up? I'm wanting to do this estimation first, then store it in an array, and then compare it when the real rotation happens. For the prediction, I'd have thought it would be something like this...
void setup(){
size(825, 825);
background(255);
smooth();
PShape Shape = createShape(GROUP);
PShape rectangle = createShape(RECT, 40, 40, 120, 230); // with 40 and 40 being the x and y
// extra point just to show where the x and y of the rectangle are //
strokeWeight(5);
stroke(0, 255, 0);
PShape point = createShape(POINT, 40, 40);
Shape.addChild(rectangle);
Shape.addChild(point);
int rectangleX = 40;
int rectangleY = 40;
int translationModifierX = 200;
int translationModifierY = 200;
// so this here would be the theoretical estimate on what the new x and y coordinates would be for the translation, before moving onto the rotation. This one's easy to predict, of course. //
int newX = rectangleX + translationModifierX;
int newY = rectangleY + translationModifierY;
// And here is where I'd be trying to estimate what the new x and y coordinates would be after rotated. //
float rotatedX = newX*cos(20) - newY*sin(20);
float rotatedY = newX*sin(20) + newY*cos(20);
println("Final X Coordinate Prediction:", rotatedX);
println("Final Y Coordinate Prediction:", rotatedY);
pushMatrix();
Shape.translate(newX, newY);
Shape.rotate(radians(20));
popMatrix();
shape(Shape);
}
This printed prediction, though, is not that close to where the x y actually ends up. It actually ends up around 263, 292, but the print puts the x value as ~-121, and its y value at ~317. What I'm really needing to do is get this prediction's x and y coordinates to be the same as it would be when I run rectangle.rotate(radians(20)). I just want to be able to see where this rectangle would go before it actually goes there. I feel like it's a math problem. I'm obviously new, so I'd appreciate any assistance.
You need to use the relative (rectangleX/rectangleY), not the absolute (newX/newY) coordinates.
float rotatedX = newX + rectangleX*cos(radians(20)) - rectangleY*sin(radians(20));
float rotatedY = newY + rectangleX*sin(radians(20)) + rectangleY*cos(radians(20));
i am trying to make a clock and have all the numbers in the correct place but they are all rotated e.g. 6 is upside down whereas 12 is correct. is there anyway to rotate just the text not the position of the text?
my code is
push();
textSize(48);
for (int i = 1; i < 13; i++) {
int offset = -15;
if (str(i).length() == 2) {
offset -= 14.5;
}
rotate(radians(30));
text(i, offset, -350);
//println(i*30);
}
pop();
Without seeing the code my hunch is you use rotate(), but probably you don't use pushMatrix()/popMatrix(); to isolate the coordinate space to local one that can be temporarily rotated.
I recommend reading the 2D Transformations tutorial
As the tutorial mentions, the order of transformations matters:
size(300, 300);
background(0);
stroke(255);
// center align text
textAlign(CENTER);
// global translation to center
translate(width / 2, height / 2);
int hours = 12;
// an angle section (360/12 = 30 degrees), but in radians
float angleIncrement = TWO_PI / hours;
// distance from center
float radius = 100;
for(int i = 0 ; i < hours; i++){
// calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
// remember this offset: it may come in handy when drawing clock handles ;)
float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
// isolate coordinate space
pushMatrix();
// rotate from global center by each hour angle
rotate(angle);
// translate from locally rotated center based on radius
translate(radius, 0);
// undo local rotation so text is straight
rotate(-angle);
// render text
text(i+1,0,0);
// exit local coordinate system, back to global coordinates after this
popMatrix();
}
Here is the same example with a helper function to help visualise the coordinate systems:
void setup() {
size(300, 300);
background(0);
stroke(255);
// center align text
textAlign(CENTER);
drawCoordinateSystem("1.original cooordinates",60, 255);
// global translation to center
translate(width / 2, height / 2);
drawCoordinateSystem("2.global center",60, 64);
int hours = 12;
// an angle section (360/12 = 30 degrees), but in radians
float angleIncrement = TWO_PI / hours;
// distance from center
float radius = 100;
for (int i = 0; i < hours; i++) {
// calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
// remember this offset: it may come in handy when drawing clock handles ;)
float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
// isolate coordinate space
pushMatrix();
// rotate from global center by each hour angle
rotate(angle);
if(i == 0){
drawCoordinateSystem("3.local+rotation",60, 127);
}
// translate from locally rotated center based on radius
translate(radius, 0);
if(i == 0){
drawCoordinateSystem("4.local+rot.+\ntrans.",60, 192);
}
// undo local rotation so text is straight
rotate(-angle);
if(i == 0){
drawCoordinateSystem("\n5.prev.\n-rot.",60, 255);
}
// render text
text(i+1, 0, 0);
// exit local coordinate system, back to global coordinates after this
popMatrix();
}
}
void drawCoordinateSystem(String label, float size, float alpha){
pushStyle();
textAlign(LEFT);
strokeWeight(3);
// x axis
stroke(192, 0, 0, alpha);
line(0, 0, size, 0);
// y axis
stroke(0, 192, 0, alpha);
line(0, 0, 0, size);
text(label, 10, 15);
popStyle();
}
Note that the indent is not required for pushMatrix()/popMatrix(), it's more of a visual cue to aid when you read code to remember coordinate system nesting.
This is over the top and you won't need the code bellow, but hopefully it's a fun visualisation:
PImage screenshot;
String[] labels = {"1.original cooordinates","2.global center\ntranslate(width / 2, height / 2)",
"3.local+rotation\npushMatrix();\nrotate(angle)",
"4.local+rot.+\ntrans.\ntranslate(radius, 0)","5.previous-rot.\nrotate(-angle)",""};
PMatrix2D[] systems = new PMatrix2D[labels.length];
PMatrix2D lerpMatrix = new PMatrix2D();
void setup() {
size(300, 300);
background(0);
stroke(255);
// center align text
textAlign(CENTER);
// "1.original cooordinates"
systems[0] = new PMatrix2D();
// global translation to center
translate(width / 2, height / 2);
// "2.global center"
systems[1] = systems[0].get();
systems[1].translate(width / 2, height / 2);
int hours = 12;
// an angle section (360/12 = 30 degrees), but in radians
float angleIncrement = TWO_PI / hours;
// distance from center
float radius = 100;
for (int i = 0; i < hours; i++) {
// calculate the angle for each hour, subtracting a bit because angle 0 points to the right, not top (12 o'clock)
// remember this offset: it may come in handy when drawing clock handles ;)
float angle = (angleIncrement * i) - (QUARTER_PI * 4/3);
// isolate coordinate space
pushMatrix();
// rotate from global center by each hour angle
rotate(angle);
if(i == 0){
// "3.local+rotation"
PMatrix2D local = new PMatrix2D();
local.apply(systems[1]);
local.rotate(angle);
systems[2] = local.get();
}
// translate from locally rotated center based on radius
translate(radius, 0);
if(i == 0){
// "4.local+rot.+\ntrans."
systems[3] = systems[2].get();
systems[3].translate(radius,0);
}
// undo local rotation so text is straight
rotate(-angle);
if(i == 0){
// "\n5.prev.\n-rot."
systems[4] = systems[3].get();
systems[4].rotate(-angle);
systems[5] = systems[4];
}
// render text
text(i+1, 0, 0);
// exit local coordinate system, back to global coordinates after this
popMatrix();
}
screenshot = get();
}
void draw(){
image(screenshot,0, 0);
animateCoordinateSystems();
text("mouse mouse on X axis", width / 2, height - 12);
}
void animateCoordinateSystems(){
float mapping = map(constrain(mouseX, 0, width), 0, width, 0.0, 1.0);
float globalT = (float)(labels.length -1) * mapping;
int index = (int)globalT;
float localT = globalT - index;
lerpMatrix(systems[index], systems[index+1], localT, lerpMatrix);
pushMatrix();
applyMatrix(lerpMatrix);
drawCoordinateSystem(labels[index] + (labels[index+1].length() > 0 ? "\ntransitions to\n" + labels[index+1] : ""),60, 255);
popMatrix();
}
void lerpMatrix(PMatrix2D from, PMatrix2D to, float t, PMatrix2D result){
result.m00 = lerp(from.m00, to.m00, t);
result.m01 = lerp(from.m01, to.m01, t);
result.m02 = lerp(from.m02, to.m02, t);
result.m10 = lerp(from.m10, to.m10, t);
result.m11 = lerp(from.m11, to.m11, t);
result.m12 = lerp(from.m12, to.m12, t);
}
void drawCoordinateSystem(String label, float size, float alpha){
pushStyle();
textAlign(LEFT);
strokeWeight(3);
// x axis
stroke(192, 0, 0, alpha);
line(0, 0, size, 0);
// y axis
stroke(0, 192, 0, alpha);
line(0, 0, 0, size);
text(label, 10, 15);
popStyle();
}
I'm trying to create a script that drawls a curve through 'n' vertexes equally spaced around the center of an ellipse.
The reason I'm not just drawling an ellipse around the center ellipse is because I eventually want to connect a micro-controller to Processing where the data points acquired from the 'n' amount of sensors will vary the height ('y') of each vertex, creating constantly changing, irregular curves around the center ellipse such as this possible curve:
Essentially, this is supposed to be a data visualizer, but I cannot figure out why this is not working or how to achieve this effect after going through examples and the documentation on https://processing.org/reference/.
Here is my code:
color WHITE = color(255);
color BLACK = color(0);
void setup() {
size(500, 500);
}
void draw() {
background(WHITE);
translate(width/2, height/2); // move origin to center of window
// center ellipse
noStroke();
fill(color(255, 0, 0));
ellipse(0, 0, 10, 10); // center point, red
fill(BLACK);
int n = 10;
int y = 100;
float angle = TWO_PI / n;
beginShape();
for (int i = 0; i < n; i++) {
rotate(angle);
curveVertex(0, y);
}
endShape();
}
The matrix operations like rotate do not transform the single vertices in a shape. The current matrix is applied to the entire shape when it is draw (at endShape). You've to calculate all the vertex coordinates:
Create a ArrayList of PVector, fill it with points and draw it in a loop:
color WHITE = color(255);
color BLACK = color(0);
ArrayList<PVector> points = new ArrayList<PVector>();
void setup() {
size(500, 500);
int n = 10;
int radius = 100;
for (int i = 0; i <= n; i++) {
float angle = TWO_PI * (float)i/n;
points.add(new PVector(cos(angle)*radius, sin(angle)*radius));
}
}
void draw() {
background(WHITE);
translate(width/2, height/2);
noFill();
stroke(255, 0, 0);
beginShape();
PVector last = points.get(points.size()-1);
curveVertex(last.x, last.y);
for (int i = 0; i < points.size(); i++) {
PVector p = points.get(i);
curveVertex(p.x, p.y);
}
PVector first = points.get(0);
curveVertex(first.x, first.y);
endShape();
}
Processing is an environment that makes use of Java. I am trying to to use the Monte Carlo method to calculate the value of Pi. I am trying to create a dartboard (a circle within a square), and return "Yes" whenever the randomly selected point is selected within the circle.
Processing uses a coordinate system where the top left corner is the origin, rightwards is the positive x-axis, and downwards is the positive y-axis.
Here's my code:
float circleX;
float circleY;
float r;
void setup() {
size(360, 360);
circleX = 50;
circleY = 50;
frameRate(0.5);
}
void draw() {
background(50);
fill(255);
stroke(255);
fill(100);
ellipse(180, 180, 360, 360);
ellipse(circleX, circleY, 10, 10);
circleX = random(360);
circleY = random(360);
r = (circleX-180)*(circleX-180) + (180-circleY)*(180-circleY);
if (r < 32400) {
print("Yes! ");
}
}
However, on many instances, points inside the circle do not return "Yes," and points outside the circle do return "Yes." Any ideas on what is wrong?
You have to swap the lines generating the random coordinates and drawing it:
// Generate new random coordinates
circleX = random(360);
circleY = random(360);
// Draw circle at those coordinates
ellipse(circleX, circleY, 10, 10);
// Check whether the coordinates are withing the big circle
r = (circleX-180)*(circleX-180) + (180-circleY)*(180-circleY);
The way you do it, the circle is drawn before you generate new coordinates, which you then check.
I have task to write program allowing users to draw stars, which can differ in size and amount of arms. When I was dealing with basic stars I was doing it with GeneralPath and tables of points :
int xPoints[] = { 55, 67, 109, 73, 83, 55, 27, 37, 1, 43 };
int yPoints[] = { 0, 36, 36, 54, 96, 72, 96, 54, 36, 36 };
Graphics2D g2d = ( Graphics2D ) g;
GeneralPath star = new GeneralPath();
star.moveTo( xPoints[ 0 ], yPoints[ 0 ] );
for ( int k = 1; k < xPoints.length; k++ )
star.lineTo( xPoints[ k ], yPoints[ k ] );
star.closePath();
g2d.fill( star );
What method should I choose for drawing stars with variable inner and outer radius, as well as different amount of arms ? This is what I should obtain :
alt text http://img228.imageshack.us/img228/6427/lab6c.jpg
Having n arms means you end up with 2n vertices, the even ones are on the outer circle, and the odd ones on the inner circle. Viewed from the center, the vertices are at evenly spaced angles (the angle is 2*PI/2*n = Pi/n). On an unit circle (r=1), the x,y coordinates of the points i=0..n is cos(x),sin(x). Multiply those coordinates with the respective radius (rOuter or rInner, depending of whether i is odd or even), and add that vector to the center of the star to get the coordinates for each vertex in the star path.
Here's the function to create a star shape with given number of arms, center coordinate and outer, inner radius:
public static Shape createStar(int arms, Point center, double rOuter, double rInner) {
double angle = Math.PI / arms;
GeneralPath path = new GeneralPath();
for (int i = 0; i < 2 * arms; i++) {
double r = (i & 1) == 0 ? rOuter : rInner;
Point2D.Double p = new Point2D.Double(
center.x + Math.cos(i * angle) * r,
center.y + Math.sin(i * angle) * r);
if (i == 0) {
path.moveTo(p.getX(), p.getY());
}
else {
path.lineTo(p.getX(), p.getY());
}
}
path.closePath();
return path;
}
I think you should use the same classes (GeneralPath), but here you should focus on how to compute the vertex coordinates.
The first thing that comes to my mind is positioning 2N points on a circle of radius R1, centered at (0,0). Then, "strech" every odd vertex by multiplying its vector by c. The constant c should be equal to R2/R1 (i.e. the proportion of inner and outer radiuses).
But maybe there is a simpler solution...
Here's an example of finding equally spaced points on a circle that may help. Just make the number of points, n, a parameter in the constructor.
private int n;
...
public CircleTest(int n) {
...
this.n = n;
}
...
for (int i = 0; i < n; i++) {
double t = 2 * Math.PI * i / n;
...
}