3D Baton Circles move around a Sun - processing

How do I use translate and rotate to position spheres and lines on the canvas and also rotate the entire scene with Java Processing?
I need to be able to do this so that I can:
Create a class for a 3D baton which contains two equal size spheres and a line connecting the centers of the two spheres. The Baton class must have the following field variables:
float x, y, z; // the x, y, z coordinates of the center of one baton sphere
// the other baton sphere should be (-x, -y, -z)
float angle; // rotation angle
float speed; //rotational speed
float radius; //radius of the baton sphere
In the main tab of the sketch I need to create a scene that contains the following:
A yellow sphere with radius 50 at the center of the window. The yellow sphere doesn’t move.
6 batons rotating about the y axis passing through the yellow sphere.
Each baton rotates at a random speed between 0.01 and 0.04.
All batons have different distances from the center of the yellow sphere.
The radius of each baton sphere is a random number between 15 and 30.
3D Batons Picture
This is my code:
Baton[] batons;
void setup() {
size(600, 600);
batons = new Baton[4];
for(int i = 0; i < batons.length; i++)
batons[i] = new Baton(100, 100, 100, 45, 2, 25, 2);
}
void draw() {
background(255);
stroke(0);
translate(width/2, height/2);
fill(255, 200, 50);
sphere(50);
for(int i = 0; i < batons.length; i++) {
batons[i].update();
batons[i].display();
}
}
class Baton {
float x;
float y;
float z;
float angle;
float speed;
float radius;
float theta;
Baton(float x, float y, float z, float angle, float speed, float radius, float theta) {
this.x = x;
this.y = y;
this.z = y;
this.angle = angle;
this.speed = speed;
this.radius = radius;
theta = 0;
}
void update() {
theta = theta + speed;
}
void display() {
pushMatrix();
rotate(theta);
translate(radius/2, 0);
fill(51, 51, 51);
noStroke();
sphere(radius);
popMatrix();
line(x, y, -x, -y);
pushMatrix();
rotate(theta);
translate(radius/2, 0);
fill(51, 51, 51);
noStroke();
sphere(radius);
popMatrix();
}
}
The Baton has to go through the Sun that is in the middle. This means that the two circles and the line that connects it has to rotate around the Sun. To explain easier the line will go through the Sun and rotate with the two Circles. See the picture link above.

The main thing that makes your code render differently than the image you have attached is that the Baton objects are placed at the center of the canvas and end up being hidden by the sphere at the center.
Here I have moved the Baton spheres out away from the center and have slowed down the frameRate and speed so that it is easier to see how they are moving.
Baton[] batons;
void setup() {
size(600, 600, P3D);
batons = new Baton[4];
frameRate(1); // slowed down the frame rate to 1 frame per second
for(int i = 0; i < batons.length; i++){
// changed speed from 2 to 0.1 so that the batons move in smaller increments
batons[i] = new Baton(100, 100, 100, 45, 0.1, 25, 2);
}
}
void draw() {
background(255);
stroke(0);
translate(width/2, height/2);
fill(255, 200, 50);
sphere(50);
for(int i = 0; i < batons.length; i++) {
batons[i].update();
batons[i].display();
}
}
class Baton {
float x;
float y;
float z;
float angle;
float speed;
float radius;
float theta;
Baton(float x, float y, float z, float angle, float speed, float radius, float theta) {
this.x = x;
this.y = y;
this.z = y;
this.angle = angle;
this.speed = speed;
this.radius = radius;
theta = 0;
}
void update() {
theta = theta + speed;
}
void display() {
pushMatrix();
// since we want the entire configuration to rotate we will rotate the entire canvas
rotate(theta);
// for a more interesting rotation we could do this instead:
// rotateX(theta);
// rotateY(theta);
// rotateZ(theta);
float distanceBetweenBatonSpheres = radius + 300;
translate(distanceBetweenBatonSpheres/2, 0);
fill(0, 200, 200);
sphere(radius);
// now we undo the previous translate and also move back out to the other side of the central sphere
translate(distanceBetweenBatonSpheres/-1.0, 0);
sphere(radius);
// and finally.. draw a line to connect the two spheres
line(0,0,distanceBetweenBatonSpheres, 0);
popMatrix();
}
}
Notice how we rotate the entire canvas so that the configuration of spheres rotates as a body along with the line that connects the baton spheres.
Also see the comments about making the sketch more interesting by rotating in the x, y and z directions.

Related

I want to move a square in a circular motion in java processing

This is a school project so i cannot use a lot of functions like translate or rotate. I have to use basic trigonometry to do this. So I have made a square and I need it to move in a circular motion 360 degrees with one of it's point constant and not moving.
float rotX,rotY;
size(500,500);
fill(#B71143);
int rectX=width/4;
int rectY=height/10;
int rectSize=30;
angle=angle+0.1;
//rotX=rectX*cos(angle)-rectY*sin(angle);
//rotY=rectX*cos(angle)+rectY*sin(angle);
square(rotX,rotY,rectSize);
You are so close, at least in terms of the trigonometry part.
In terms of Processing you're only missing setup() and draw() which will draw a single frame (once you uncomment the assignments of rotX, rotY and initialise angle to 0)
Here's your code with above notes applied:
float rotX, rotY;
float angle = 0;
void setup() {
size(500, 500);
fill(#B71143);
}
void draw() {
int rectX=width/4;
int rectY=height/10;
int rectSize=30;
angle=angle+0.1;
rotX = rectX*cos(angle)-rectY*sin(angle);
rotY = rectX*cos(angle)+rectY*sin(angle);
square(rotX, rotY, rectSize);
}
Additionally, if you want to draw from the centre, you can add half the width/height to the square coordinates before rendering (equivalent to translating to centre), and if you want to draw a circle instead of an oval, use the same size for the two radii (named rectX, rectY):
float rotX, rotY;
float angle = 0;
void setup() {
size(500, 500);
fill(#B71143);
rectMode(CENTER);
}
void draw() {
int rectX=width/4;
int rectY=height/4;
int rectSize=30;
angle=angle+0.1;
rotX = rectX*cos(angle)-rectY*sin(angle);
rotY = rectX*cos(angle)+rectY*sin(angle);
// offset to center
rotX += width / 2;
rotY += height / 2;
square(rotX, rotY, rectSize);
}
Personally I'd simplify the code a bit (though your assignment requirements might differ based on your curriculum).
// initialise angle value
float angle = 0;
void setup() {
size(500, 500);
fill(#B71143);
}
void draw() {
// circular motion radius
int radius = width / 4;
// define square size
int rectSize=30;
// increment the angle (rotating around center)
angle=angle+0.1;
// convert polar (angle, radius) to cartesian(x,y) coords
float x = cos(angle) * radius;
float y = sin(angle) * radius;
// offset to center
x += width / 2;
y += height / 2;
// render the square at the rotated position
square(x, y, rectSize);
}
(In case you're after another polar to cartesian coordinates conversion formula explanation you can check out my older answer here which includes an interactive demo)

Tangent to the curve

I’m new at coding and I have a problem, I would like to draw a program where there is a curve and but for now I just have the static drawing but I don’t know how to generate a tangent line on the curve thanks to his derivate, as the mouse move…
This is all I have for now
void draw(){
background(255);
noFill();
stroke(0);
beginShape();
for(float a=0; a < TWO_PI; a+=0.01) {
float r=78;
float x=sin (a);
float y=(pow(cos(a),2)/(2-cos(a)))
my idea was to make a cursor, that moved by the curve, and every tima generated is own tangent.
THANK YOU SO MUCH !!!!!
I recommend to use PVector for the computation.
Create a function which computes a point on the shape:
PVector fSahpe(float a) {
float r = 200;
float x = r * sin(a);
float y = -r *(pow(cos(a),2)/(2-cos(a)));
return new PVector(x, y);
}
You have to find the point on the shape which is closest to the mouse position. Find the nearest point while you draw the shape. Note, since the shape is translated, the mouse position which is used to compare the mouse position to a point on the shape has to be shifted in the opposite direction:
PVector m = new PVector(mouseX-width/2, mouseY-height/2);
dist() can be used to compute the Euclidean distance between 2 points:
float mindist = 1000;
float mina = 0;
for(float a=0; a < TWO_PI; a+=0.01) {
PVector p = fSahpe(a);
// [...]
float dist = PVector.dist(p, m);
if (dist < mindist) {
mindist = dist;
mina = a;
}
}
Define a threshold distance. If the distance of the mouse to the closest point on the curve falls below the distance, the draw the tangent:
if (mindist < 10) {
// [...] draw tangent
}
Compute 2 points on the curve, which are close to each another, where one point is the point which is closest to the mouse cursor:
PVector p0 = fSahpe(mina);
PVector p1 = fSahpe(mina+0.01);
This 2 points ar on the approximated tangent. Compute the vector from on point to the other and scale it to a certain length (the length is the half length of the tangent):
PVector dir = PVector.sub(p1, p0);
dir.normalize().mult(100);
Compute the start point and the end point of the tangent:
PVector l0 = PVector.add(p0, dir);
PVector l1 = PVector.sub(p0, dir);
See the complete example:
void setup() {
size(500, 500);
}
PVector fSahpe(float a) {
float r = 200;
float x = r * sin(a);
float y = -r *(pow(cos(a),2)/(2-cos(a)));
return new PVector(x, y);
}
void draw(){
background(0);
translate(width/2, height/2);
noFill();
strokeWeight(1);
stroke(255);
float mindist = 1000;
float mina = 0;
PVector m = new PVector(mouseX-width/2, mouseY-height/2);
beginShape();
for(float a=0; a < TWO_PI; a+=0.01) {
PVector p = fSahpe(a);
vertex(p.x, p.y);
float dist = PVector.dist(p, m);
if (dist < mindist) {
mindist = dist;
mina = a;
}
}
endShape();
if (mindist < 10) {
PVector p0 = fSahpe(mina);
PVector p1 = fSahpe(mina+0.01);
PVector dir = PVector.sub(p1, p0);
dir.normalize().mult(100);
PVector l0 = PVector.add(p0, dir);
PVector l1 = PVector.sub(p0, dir);
strokeWeight(3);
stroke(255, 0, 0);
line(l0.x, l0.y, l1.x, l1.y);
}
}

How to add a gradient in a Bezier curve?

I have drawn curves that denote the customer country and the country where he is headed for a trip in a map.
But I could not add a gradient so that the lines would denote the said information and gives this random color between two colors at random. Here's what I tried.
int steps = 10;
noFill();
//stroke(#5A38FA, 50);
strokeWeight(1);
for(int i=0; i<steps; i++) {
strokeWeight(1);
noFill();
stroke(lerpColor(#31B5E8, #F0E62E, (float)i/steps));
bezier(locationX, locationY, locationX+random(15, 50), locationY+random(13,50), customerLocationX+random(15, 30), customerLocationY+random(15, 70), customerLocationX, customerLocationY);
}
You can decompose a bezier curve into points using the bezierPoint()method and then draw straight line segments between successive points, specifying the colour for each individual line segment (meanwhile gradually lerping the colour of course).
I've produced a method which can do that in the code example below.
Additionally, with the method, you can specify the curve's magnitude (curve) and the direction of the curve (dir); the method calculates the bezier control point using the point on a line perpendicular to the midpoint between the start point (head) and end point (tail).
void setup() {
size(500, 500);
smooth(4);
noLoop();
redraw();
strokeWeight(5);
noFill();
}
void draw() {
background(35);
drawCurve(new PVector(50, 50), new PVector(456, 490), #31B5E8, #F0E62E, 50, -1);
drawCurve(new PVector(150, 75), new PVector(340, 410), #B9FF00, #FF00C5, 150, 1);
drawCurve(new PVector(200, 480), new PVector(480, 30), #007CFF, #89CA7F, 100, 1);
}
void drawCurve(PVector head, PVector tail, color headCol, color tailCol, float curve, int curveDir) {
final float theta2 = angleBetween(tail, head);
final PVector midPoint = new PVector((head.x + tail.x) / 2,
(head.y + tail.y) / 2);
final PVector bezierCPoint = new PVector(midPoint.x + (sin(-theta2) * (curve * 2 * curveDir)),
midPoint.y + (cos(-theta2) * (curve * 2 * curveDir)));
PVector point = head.copy();
for (float t=0; t<=1; t+=0.025) {
float x1 = bezierPoint(head.x, bezierCPoint.x, bezierCPoint.x, tail.x, t);
float y1 = bezierPoint(head.y, bezierCPoint.y, bezierCPoint.y, tail.y, t);
PVector pointB = new PVector(x1, y1);
stroke(lerpColor(headCol, tailCol, t));
line(point.x, point.y, pointB.x, pointB.y);
point = pointB.copy();
}
}
static float angleBetween(PVector tail, PVector head) {
float a = PApplet.atan2(tail.y - head.y, tail.x - head.x);
if (a < 0) {
a += PConstants.TWO_PI;
}
return a;
}
Result:

Calculate ellipse size in relation to distance from center point

I want to achieve a slow fade in size on every collapse into itself. In other words, when the circle is at its biggest, the ellipses will be at the largest in size and conversely the opposite for the retraction. So far I am trying to achieve this affect by remapping the cSize from the distance of the center point, but somewhere along the way something is going wrong. At the moment I am getting a slow transition from small to large in ellipse size, but the inner ellipses are noticeably larger. I want an equal distribution of size amongst all ellipses in relation to center point distance.
I've simplified the code down to 4 ellipses rather than an array of rows of ellipses in order to hopefully simplify this example. This is done in the for (int x = -50; x <= 50; x+=100).
I've seen one or two examples that slightly does what I want, but is more or less static. This example is kind of similar because the ellipse size gets smaller or larger in relation to the mouse position
Distance2D
Here is an additional diagram of the grid of ellipses I am trying to create, In addition, I am trying to scale that "square grid" of ellipses by a center point.
Multiple ellipses + Scale by center
Any pointers?
float cSize;
float shrinkOrGrow;
void setup() {
size(640, 640);
noStroke();
smooth();
fill(255);
}
void draw() {
background(#202020);
translate(width/2, height/2);
if (cSize > 10) {
shrinkOrGrow = 0;
} else if (cSize < 1 ) {
shrinkOrGrow = 1;
}
if (shrinkOrGrow == 1) {
cSize += .1;
} else if (shrinkOrGrow == 0) {
cSize -= .1;
}
for (int x = -50; x <= 50; x+=100) {
for (int y = -50; y <= 50; y+=100) {
float d = dist(x, y, 0, 0);
float fromCenter = map(cSize, 0, d, 1, 10);
pushMatrix();
translate(x, y);
rotate(radians(d + frameCount));
ellipse(x, y, fromCenter, fromCenter);
popMatrix();
}
}
}
The values you're passing into the map() function don't make a lot of sense to me:
float fromCenter = map(cSize, 0, d, 1, 100);
The cSize variable bounces from 1 to 10 independent of anything else. The d variable is the distance of each ellipse to the center of the circle, but that's going to be static for each one since you're using the rotate() function to "move" the circle, which never actually moves. That's based only on the frameCount variable, which you never use to calculate the size of your ellipses.
In other words, the position of the ellipses and their size are completely unrelated in your code.
You need to refactor your code so that the size is based on the distance. I see two main options for doing this:
Option 1: Right now you're moving the circles on screen using the translate() and rotate() functions. You could think of this as the camera moving, not the ellipses moving. So if you want to base the size of the ellipse on its distance from some point, you have to get the distance of the transformed point, not the original point.
Luckily, Processing gives you the screenX() and screenY() functions for figuring out where a point will be after you transform it.
Here's an example of how you might use it:
for (int x = -50; x <= 50; x+=100) {
for (int y = -50; y <= 50; y+=100) {
pushMatrix();
//transform the point
//in other words, move the camera
translate(x, y);
rotate(radians(frameCount));
//get the position of the transformed point on the screen
float screenX = screenX(x, y);
float screenY = screenY(x, y);
//get the distance of that position from the center
float distanceFromCenter = dist(screenX, screenY, width/2, height/2);
//use that distance to create a diameter
float diameter = 141 - distanceFromCenter;
//draw the ellipse using that diameter
ellipse(x, y, diameter, diameter);
popMatrix();
}
}
Option 2: Stop using translate() and rotate(), and use the positions of the ellipses directly.
You might create a class that encapsulates everything you need to move and draw an ellipse. Then just create instances of that class and iterate over them. You'd need some basic trig to figure out the positions, but you could then use them directly.
Here's a little example of doing it that way:
ArrayList<RotatingEllipse> ellipses = new ArrayList<RotatingEllipse>();
void setup() {
size(500, 500);
ellipses.add(new RotatingEllipse(width*.25, height*.25));
ellipses.add(new RotatingEllipse(width*.75, height*.25));
ellipses.add(new RotatingEllipse(width*.75, height*.75));
ellipses.add(new RotatingEllipse(width*.25, height*.75));
}
void draw() {
background(0);
for (RotatingEllipse e : ellipses) {
e.stepAndDraw();
}
}
void mouseClicked() {
ellipses.add(new RotatingEllipse(mouseX, mouseY));
}
void mouseDragged() {
ellipses.add(new RotatingEllipse(mouseX, mouseY));
}
class RotatingEllipse {
float rotateAroundX;
float rotateAroundY;
float distanceFromRotatingPoint;
float angle;
public RotatingEllipse(float startX, float startY) {
rotateAroundX = (width/2 + startX)/2;
rotateAroundY = (height/2 + startY)/2;
distanceFromRotatingPoint = dist(startX, startY, rotateAroundX, rotateAroundY);
angle = atan2(startY-height/2, startX-width/2);
}
public void stepAndDraw() {
angle += PI/64;
float x = rotateAroundX + cos(angle)*distanceFromRotatingPoint;
float y = rotateAroundY + sin(angle)*distanceFromRotatingPoint;
float distance = dist(x, y, width/2, height/2);
float diameter = 50*(500-distance)/500;
ellipse(x, y, diameter, diameter);
}
}
Try clicking or dragging in this example. User interaction makes more sense to me using this approach, but which option you choose really depends on what fits inside your head the best.

Continuous rotation in Processing

I wrote a program in Procesisng that renders opaque cubes with random colour and rotation on top of each other, but I'm looking to individually continuously spin each cube while the program is running. Here's my code at the moment,
int boxval = 1;
void setup(){
size (640, 320, P3D);
frameRate(60);
}
void draw(){
for (int i = 0; i < boxval; i++){
translate(random(0,640), random(0,320), 0);
rotateY(random(0,360));
rotateX(random(0,360));
rotateZ(random(0,360));
fill(random(0,255),random(0,255),random(0,255),50);
noStroke();
box(64,64,64);
}
}
Here's a screenshot if it helps at all,
This is a great time to use Object Oriented Programming! If I understand the question correctly, you would like each cube to rotate independently of the other cubes. Let's make a Cube class. Think of each cube as an object that we will handle individually.
class Cube {
float x, y, z; // position of the cube
float size; // size of cube
color c; // color of cube
float xAngle, yAngle, zAngle; // current rotation amount of cube's x, y, z axes
float xSpeed, ySpeed, zSpeed; // how quickly the cube is rotated in the x, y, z axes
// Cube constructor - create the cube and all of its parameters
Cube(float x_, float y_, float z_, float size_, color c_, float xSpeed_, float ySpeed_, float zSpeed_) {
x = x_;
y = y_;
z = z_;
size = size_;
c = c_;
xSpeed = xSpeed_;
ySpeed = ySpeed_;
zSpeed = zSpeed_;
xAngle = yAngle = zAngle = 0; // starting position
}
// update the cube
// all we're doing is rotating each axis
void update() {
xAngle += xSpeed;
yAngle += ySpeed;
zAngle += zSpeed;
}
// draw the cube to the screen
void display() {
pushMatrix(); // need this
translate(x, y, z); // position on screen
rotateX(xAngle); // rotation amounts
rotateY(yAngle);
rotateZ(zAngle);
fill(c);
noStroke();
box(size);
popMatrix(); // and this
// push and pop matrix allows for individual cube rotation
// otherwise you would rotate the whole draw window, which isn't what you're looking for
}
}
If you would like each cube to change color and position on screen but still rotate independently, the display() function could be something like this instead:
void display() {
pushMatrix();
translate(random(0, width), random(0, height), random(-100, 100)); // random position on screen
rotateX(xAngle);
rotateY(yAngle);
rotateZ(zAngle);
fill(random(255), random(255), random(255), 50); // random color
noStroke();
box(size);
popMatrix();
}
Understanding rotation and translation of elements in Processing is really key. I highly recommend this tutorial from the Processing website if you have not read it. I incorporated some concepts into the Cube class.
Since you would like to have more than one Cube drawn on the screen, let's make an array of Cubes. I chose 25 as an arbitrary number.
Cube[] cube = new Cube[25];
Now in setup(), we'll need to actually create each Cube and give it certain parameters, like position on screen, color, etc. Here is how that is accomplished.
for (int i = 0; i < cube.length; i++) {
cube[i] = new Cube(random(0, width), random(0, height), 0, // x, y, z position
random(30, 80), color(random(255), random(255), random(255), 50), // size, color
random(0.001, 0.020), random(0.001, 0.020), random(0.001, 0.020)); // xSpeed, ySpeed, zSpeed
}
Now we just need to draw the Cubes to the screen and update the rotation of each one, which simply happens in the draw() loop.
for (int i = 0; i < cube.length; i++) {
cube[i].update();
cube[i].display()
}
Here is whole program. It's important to call background() each time through the draw() loop so the display window will be cleared each frame. Comment it out to see what will happen, but I noticed that was not in the code snippet you provided above. I guess it can be an effect though!
Cube[] cube = new Cube[25];
void setup() {
size(640, 320, P3D);
smooth();
frameRate(60);
for (int i = 0; i < cube.length; i++) {
cube[i] = new Cube(random(0, width), random(0, height), 0,
random(30, 80), color(random(255), random(255), random(255), 50),
random(0.001, 0.020), random(0.001, 0.020), random(0.001, 0.020));
}
}
void draw() {
camera();
lights();
background(50);
for (int i = 0; i < cube.length; i++) {
cube[i].update();
cube[i].display();
}
}
I'm not sure what your programming background is, but getting a hang of Object Oriented Programming is really helpful in Processing (and other OOP languages), so I'd recommend this OOP tutorial from the Processing website if you need a crash course. My programming life changed when OOP finally made sense.

Resources