Processing - Line in direction of mouse pointer - processing

I am trying to achieve an effect like the image below
In my code, I managed to create this effect but in repeating the effect it seems to multiply inwards on itself. Could anyone help me to make my code achieve the effect in the image above?
void setup(){
size(500,500);
frameRate(60);
ellipseMode(CENTER);
smooth();
loop();
}
void draw() {
background(#ffffff);
//border
strokeWeight(3);
fill(255);
arc(50, 50, 50, 50, -PI, -PI / 2);
fill(255);
arc(450, 450, 50, 50, 0, PI / 2.0);
line(25, 50, 25, 475);
line(25, 475, 450, 475);
line(475, 450, 475, 25);
line(475, 25, 135, 25);
fill(0);
text("MAGNETS", 60, 30);
//Lines
for(int i=0; i<3; i++){
drawMagnet();
}
}
float angle = 0;
int x = 75;
int y = 75;
float tAngle = 0;
float easing = 0.1f;
void drawMagnet(){
int l = 10; //length
angle = atan2( mouseY - y, mouseX - x);
float dir = (angle - tAngle) / TWO_PI;
dir -= round(dir);
dir *= TWO_PI;
tAngle += dir * easing;
stroke(0);
translate(x, y);
rotate(tAngle);
line(-l, 0, l, 0);
}

Your rotations and translations are stacking, which is causing your problem. To fix this, you might do something like this:
pushMatrix();
translate(x, y);
rotate(tAngle);
line(-l, 0, l, 0);
popMatrix();
Here I'm using the pushMatrix() and popMatrix() functions so your rotations and translations don't stack.
But then all of your lines are at the same x,y location. So they'll all have the same angle towards the mouse position.
You're using the translate() function to draw them in different locations, but that doesn't change their underlying "model" position.
Similar to my answer to this question, you need to either base your calculations off the screen position of the lines (using the screenX() and screenY() functions), or you need to stop relying on translate() to move your lines around and calculate their positions directly.

Related

Processing Square Stacking loop

This is my first time writing here so i'll be direct, i've been trying to recreate this image:
and so far all the code i've got is:
void setup() {
size(500, 500);
}
void draw() {
rectMode(CENTER);
recta();
}
void recta() {
noFill();
int a = 10;
int y = 250;
for (int x = 0; x<20; x++) {
pushMatrix();
translate(y, y);
rect(0, 0, a, a);
popMatrix();
rotate(radians(2.0*PI));
stroke(0, 0, 0);
a= a - 20;
}
}
And i have no idea what to do next since this is what i get from it:
So i'd like to ask for help on how to get the same result as the image.
You are so close !
You're absolutely on the right track using pushMatrix()/popMatrix() to isolate coordinate systems, however you might have accidentally placed the rotation after popMatrix() which defeats the purpose. You probably meant to for each square to have an independent rotation from each other and not accumulate 2 * PI to the global rotation.
The other catch is that you're rotating by the same angle (2 * PI) for each iteration in your for loop and that rotation is 360 degrees so even if you fix rotation like this:
pushMatrix();
translate(y, y);
rotate(radians(2.0*PI));
rect(0, 0, a, a);
popMatrix();
you'll get a scaling effect:
(Minor note 2.0 * PI already exists in Processing as the TWO_PI constant)
To get that spiral looking effect is to increment the angle for each iteration (e.g. x = 0, rotation = 0, x = 1, rotation = 5, x = 2, rotation = 10, etc.). The angle increment is totally up to you: depending on how you map the x increment to a rotation angle angle you'll get a tighter or looser spiral.
Speaking of mapping, Processing has a map() function which makes it super easy to map from one range of numbers (let's say x from 0 to 19) to another (let's say 0 radians to PI radians):
for (int x = 0; x < 20; x++) {
pushMatrix();
translate(y, y);
rotate(map(x, 0, 19, 0, PI));
rect(0, 0, a, a);
popMatrix();
a = a - 20;
}
Here's a basic sketch based on your code:
int a = 10;
int y = 250;
void setup() {
size(500, 500);
rectMode(CENTER);
noFill();
background(255);
recta();
}
void recta() {
for (int x = 0; x < 20; x++) {
pushMatrix();
translate(y, y);
rotate(map(x, 0, 19, 0, PI));
rect(0, 0, a, a);
popMatrix();
a = a - 20;
}
}
I've removed draw() because it was rendering the same frame without any change: drawing once in setup() achieves the same visual effect using less CPU/power.
You can use draw(), but might as add some interactivity or animation to explore shapes. Here's a tweaked version of the above with comments:
int y = 250;
void setup() {
size(500, 500);
rectMode(CENTER);
noFill();
}
void draw(){
background(255);
recta();
}
void recta() {
// map mouse X position to -180 to 180 degrees (as radians)
float maxAngle = map(mouseX, 0, width, -PI, PI);
// reset square size
int a = 10;
// for each square
for (int x = 0; x < 20; x++) {
// isolate coordinate space
pushMatrix();
// translate first
translate(y, y);
// then rotate: order matters
// map x value to mouse mapped maximum rotation angle
rotate(map(x, 0, 19, 0, maxAngle));
// render the square
rect(0, 0, a, a);
popMatrix();
// decrease square size
a = a - 20;
}
}
Remember transformation order matters (e.g. translate() then rotate() would produce different effects compared to rotate() then translate()). Have fun!

How to manually apply matrix stack to coordinates in processing

In processing, when you apply a matrix transformation, you can draw on your canvas without worrying of the "true" position of your x y coordinate.
I thought that by the same logic, I could copy a section of the canvas by using ParentApplet.get(x, y, width, height) and that it would automatically shift the x and y, but it does not, it uses the coordinates as raw inputs without applying the matrix stack to it.
So the easiest way I see to deal with the problem would be to manually apply the matrix stack to my x, y, width, height values and using the results as input of get(). But I cannot find such a function, does one exist ?
EDIT : As requested, Here's an example of my problem
So the objective here is to draw a simple shape, copy it and paste it. Without translate, there is no problem:
void settings(){
size(500, 500);
}
void draw() {
background(255);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(0, 0, 101, 101);
image(img, 200, 200);
}
Now if I applied a translate matrix before drawing the shape, I wish that I could use the same get() code to copy the exact same drawing:
void settings(){
size(500, 500);
}
void draw() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(0, 0, 101, 101);
image(img, 200, 200);
popMatrix();
}
But it doesn't work that way, The get(0, 0, ..) doesn't use the current transformation matrix to copy pixels from origin (10, 10):
Can you please provide a few more details.
It is possible to manipulate coordinate systems using pushMatrix()/PopMatrix() and you can go further and manually multiply matrices and vectors.
The part that is confusing is that you're calling get(x,y,width,height) but no showing how you render the PImage section. It's hard to guess the matrix stack you're mentioning. Can you post an example snippet ?
If you render it at the same x,y you call get() with it should render with the same x,y shift:
size(640, 360);
noFill();
strokeWeight(9);
PImage placeholderForPGraphics = loadImage("https://processing.org/examples/moonwalk.jpg");
image(placeholderForPGraphics, 0, 0);
int x = 420;
int y = 120;
int w = 32;
int h = 48;
// visualise region of interest
rect(x, y, w, h);
// grab the section sub PImage
PImage section = placeholderForPGraphics.get(x, y, w, h);
//filter the section to make it really standout
section.filter(THRESHOLD);
// display section at same location
image(section, x, y);
Regarding the matrix stack, you can call getMatrix() which will return a PMatrix2D if you're in 2D mode (otherwise a PMatrix3D). This is a copy of the current matrix stack at the state you've called it (any prior operations will be "baked" into this one).
For example:
PMatrix m = g.getMatrix();
printArray(m.get(new float[]{}));
(g.printMatrix() should be easier to print to console, but you need to call getMatrix() if you need an instance to manipulate)
Where g is your PGraphics instance.
You can then manipulate it as you like:
m.translate(10, 20);
m.rotate(radians(30));
m.scale(1.5);
Remember to call applyMatrix() it when you're done:
g.applyMatrix(m);
Trivial as it may be I hope this modified version of the above example illustrates the idea:
size(640, 360);
noFill();
strokeWeight(9);
// get the current transformation matrix
PMatrix m = g.getMatrix();
// print to console
println("before");
g.printMatrix();
// modify it
m.translate(160, 90);
m.scale(0.5);
// apply it
g.applyMatrix(m);
// print applied matrix
println("after");
g.printMatrix();
PImage placeholderForPGraphics = loadImage("https://processing.org/examples/moonwalk.jpg");
image(placeholderForPGraphics, 0, 0);
int x = 420;
int y = 120;
int w = 32;
int h = 48;
// visualise region of interest
rect(x, y, w, h);
// grab the section sub PImage
PImage section = placeholderForPGraphics.get(x, y, w, h);
//filter the section to make it really standout
section.filter(THRESHOLD);
// display section at same location
image(section, x, y);
Here's another example making a basic into PGraphics using matrix transformations:
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
}
This is overkill: the same effect could have been drawn much simpler, however the focus in on calling get() and using transformation matrices. Here a modified iteration showing the same principle with get(x,y,w,h), then image(section,x,y):
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
// take a section of PGraphics instance
int w = 180;
int h = 180;
int x = (pg.width - w) / 2;
int y = (pg.height - h) / 2;
PImage section = pg.get(x, y, w, h);
// filter section to emphasise
section.filter(INVERT);
// render section at sampled location
image(section, x, y);
popMatrix();
}
void polygon(int sides, float radius, PGraphics pg){
float angleIncrement = TWO_PI / sides;
pg.beginShape();
for(int i = 0 ; i <= sides; i++){
float angle = (angleIncrement * i) + HALF_PI;
pg.vertex(cos(angle) * radius, sin(angle) * radius);
}
pg.endShape();
}
Here's a final iteration re-applying the last transformation matrix in an isolated coordinate space (using push/pop matrix calls):
void setup(){
size(360, 360);
// draw something manipulating the coordinate system
PGraphics pg = createGraphics(360, 360);
pg.beginDraw();
pg.background(0);
pg.noFill();
pg.stroke(255, 128);
pg.strokeWeight(4.5);
pg.rectMode(CENTER);
pg.translate(180,180);
for(int i = 0 ; i < 72; i++){
pg.rotate(radians(5));
pg.scale(0.95);
//pg.rect(0, 0, 320, 320, 32, 32, 32, 32);
polygon(6, 180, pg);
}
pg.endDraw();
// render PGraphics
image(pg, 0, 0);
// take a section of PGraphics instance
int w = 180;
int h = 180;
int x = (pg.width - w) / 2;
int y = (pg.height - h) / 2;
PImage section = pg.get(x, y, w, h);
// filter section to emphasise
section.filter(INVERT);
// print last state of the transformation matrix
pg.printMatrix();
// get the last matrix state
PMatrix m = pg.getMatrix();
// isolate coordinate space
pushMatrix();
//apply last PGraphics matrix
applyMatrix(m);
// render section at sampled location
image(section, x, y);
popMatrix();
save("state3.png");
}
void polygon(int sides, float radius, PGraphics pg){
float angleIncrement = TWO_PI / sides;
pg.beginShape();
for(int i = 0 ; i <= sides; i++){
float angle = (angleIncrement * i) + HALF_PI;
pg.vertex(cos(angle) * radius, sin(angle) * radius);
}
pg.endShape();
}
This is an extreme example, as 0.95 downscale is applied 72 times, hence a very small image is rendered. Also notice the rotation is incremented.
Update Based on your update snippet it seems the confusion is around pushMatrix() and get().
In your scenario, pushMatrix()/translate() will offset the local coordinate sytem: that is where elements are drawn.
get() is called globally and uses absolute coordinates.
If you're only using translation, you can simply store the translation coordinates and re-use them to sample from the same location:
int sampleX = 10;
int sampleY = 10;
void settings(){
size(500, 500);
}
void draw() {
background(255);
pushMatrix();
translate(sampleX, sampleY);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// copy rectangle and paste it elsewhere
PImage img = get(sampleX, sampleY, 101, 101);
image(img, 200, 200);
popMatrix();
}
Update
Here are a couple more examples on how to compute, rather than hard code the translation value:
void settings(){
size(500, 500);
}
void setup() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// local to global coordinate conversion using PMatrix
// g is the global PGraphics instance every PApplet (sketch) uses
PMatrix m = g.getMatrix();
printArray(m.get(null));
// the point in local coordinate system
PVector local = new PVector(0,0);
// multiply local point by transformation matrix to get global point
// we pass in null to get a new PVector instance: you can make this more efficient by allocating a single PVector ad re-using it instead of this basic demo
PVector global = m.mult(local,null);
// copy rectangle and paste it elsewhere
println("local",local,"->global",global);
PImage img = get((int)global.x, (int)global.y, 101, 101);
image(img, 200, 200);
popMatrix();
}
To calculate the position of a vector based on a transformation matrix, simply multiply the vector by that matrix. Very roughly speaking what's what happens with push/pop matrix (a transformation matrix is used for each push/pop stack, which is then multiplied all the way up the global coordinate system). (Notice the comment on efficienty/pre-allocating matrices and vectors as well).
This will be more verbose in terms of code and may need a bit of planning if you're using a lot of nested transformations, however you have finer control of which transformations you choose to use.
A simpler solution may be to switch to the P3D OpenGL renderer which allows you use screenX(), screenY() to do this conversion. (Also checkout modelX()/modelY())
void settings(){
size(500, 500, P3D);
}
void draw() {
background(255);
pushMatrix();
translate(10, 10);
// Fancy rectangle for visibility
fill(255, 0 ,0);
rect(0, 0, 100, 100);
fill(0, 255, 0);
rect(20, 20, 60, 60);
// local to global coordinate conversion using modelX,modelY
float x = screenX(0, 0, 0);
float y = screenY(0, 0, 0);
println(x,y);
PImage img = get((int)x, (int)y, 101, 101);
image(img, 200, 200);
popMatrix();
}
Bare in mind that you want to grab a rectangle which simply has translation applied. Since get() won't take rotation/scale into account, for more complex cases you may want to convert local to global coordinates of not just the top left point, but also the bottom right one with an offset. The idea is to compute the larger bounding box (with no rotation) around the transformed box so when you call get() the whole area of interest is returned (not just a clipped section).

How to draw shapes along a bezier path

I would like to plot a series of ellipses along a bezier path but I am struggling to plot anything more than just the line of the path. I don't need it to move at all. So far I have:
void setup() {
size(150, 150);
background(255);
smooth();
// Don't show where control points are
noFill();
stroke(0);
beginShape();
vertex(50, 75); // first point
bezierVertex(25, 25, 125, 25, 100, 75);
endShape();
}
How do I plot ellipses to follow the bezier path instead of the line?
Why would you expect that code to draw circles? It doesn't contain any calls to the ellipse() function.
Anyway, it sounds like you're looking for the bezierPoint() function:
noFill();
bezier(85, 20, 10, 10, 90, 90, 15, 80);
fill(255);
int steps = 10;
for (int i = 0; i <= steps; i++) {
float t = i / float(steps);
float x = bezierPoint(85, 10, 90, 15, t);
float y = bezierPoint(20, 10, 90, 80, t);
ellipse(x, y, 5, 5);
}
(source: processing.org)
As always, more info can be found in the reference.

I need to figure out how to properly use variables/instance variables?

float x = 100;
float y = 100;
float p = 150;
float l = 10;
int r = 150;
int t = 100;
int s = 100;
int w = 60;
int h = 60;
int z = 11;
int eyeSize = 10;
int pigNose = 30;
int pigBody = 30;
int pigEars = 35;
int pigTail = 20;
int speed = 1;
void setup () {
size (600, 600);
}
void draw () {
background(255);
//Draw legs
fill(255);
rect(x+(2*w), y+h/3.5, z, 2*z);
rect(x+(w), y+h/3, z, 2*z);
rect(x+(1.5*w), y+h/3, z, 2*z);
rect(x+(2.5*w), y+h/3.5, z, 2*z);
////draw body
fill(255);
ellipse(2.1*x,y-pigBody, p, p-(2*l));
//draw tail
fill(0);
line(2.85*x, y-pigTail, (6+l)*pigTail, pigTail*3);
// Draw payer's head
fill(255);
ellipse(x,y-pigNose,t,t);
// Draw player's eyes
fill(0);
ellipse(x-w/3+1,y-h/2,eyeSize,eyeSize);
ellipse(x+w/3-1,y-h/2,eyeSize,eyeSize);
//Draw nose
fill(0);
ellipse(x, y, pigNose, pigNose);
//draw ears
fill(0);
ellipse(x-(w/2),y-h, pigEars, pigEars);
fill(0);
ellipse(x+(w/2),y-h, pigEars, pigEars);
}
void mousePressed(){
x = mouseX;
y = mouseY;
}
I'm not that great at using variables instead of magic numbers and I'm wondering why when I click somewhere on the screen the pig splits apart? I'm also supposed to be using instance variables but I'm not sure how. Can anyone help? This is for Processing.
You've got the right idea by using x and y variables and basing all your shapes off those variables. But you got one thing wrong: you're multiplying those variables by different values to get the positions of your shapes, when you should really be adding to those variables to get the positions of your shapes.
Think about it this way, using a simpler example:
size(200, 100);
float x = 100;
float y = 50;
ellipse(x, y, 20, 20);
ellipse(x*.8, y, 20, 20);
This creates a drawing of two circles next to each other:
That might seem correct, but now what happens if I change my x variable?
size(200, 100);
float x = 50;
float y = 50;
ellipse(x, y, 20, 20);
ellipse(x*.8, y, 20, 20);
Since I'm multiplying my x value by .8, now that I change my x value to 50, the second ellipse will be at 40, which is only 10 pixels away from the first circle. But in the first sketch, the second ellipse was 20 pixels away!
Note that the same thing will happen if I increase x, the space between the circles will increase. This is what's happening in your example.
To fix this, I need to add values to my variables to get the locations of my other shapes:
size(200, 100);
float x = 150;
float y = 50;
ellipse(x, y, 20, 20);
ellipse(x-20, y, 20, 20);
Now the circles will stay next to each other (in this case, 20 pixels apart) no matter what the value of x is.
You have to do something similar, just with two variables instead of one. If it doesn't make sense, try drawing your figure out on a piece of paper, and use a few different example values for x and y. What are the locations of the other shapes?
Also, you're already using instance variables. Those are just the variables at the top of your sketch. (Unless you're supposed to be using classes, but I doubt that's the case here.)

make curtain like behaviour in drawing of lines

I am new to Processing.js and need a little bit support with this issue. I have made a HTML-Canvas animation where I have lines with a curtain like behavior which can be seen here:
Click
this is made with a canvas plugin called Paper.js
I now want to get similar effect on processing but don't really know how to figure it out. My attempt was:
float x;
float y;
void setup() {
size(1024, 768);
strokeWeight(2);
background(0, 0, 0);
}
void mouseMoved() {
x = mouseX;
y = mouseY;
}
void draw() {
background(0);
line(50, 50, x += x - x/5, y += y - y/5);
stroke(255, 255, 255);
line(50, 700, x += x - x/15, y += y - y/15);
stroke(255, 255, 255);
line(75, 50, x += x - x/25, y += y - y/25);
stroke(255, 255, 255);
line(75, 700, x += x - x/35, y += y - y/35);
// and so on, would create it within a loop
}
So what I am trying to do is basically get the same effect which I have done in HTML and adapt it in Processing.js.
Thanks in advance.
I'd strongly recommend ignoring the paper.js and reimplementing this properly. We're seeing a sequence of lines that connect to a historical line of coordinates, based on mouse position, so let's just implement that:
class Point {
float x, y;
Point(float _x, float _y) { x=_x; y=_y; }}
// our list of historical points
ArrayList<Point> points;
// the horizontal spacing of our lines has fixed interval
float interval;
// how many lines do we want to draw?
int steps = 50;
void setup() {
size(500, 500);
// initialise the "history" as just the midpoint
points = new ArrayList<Point>();
for (int i=0; i<steps; i++) {
points.add(new Point(width/2, height/2));
}
// compute the horizontal interval, because it's
// width-dependent. Never hard code dependent values.
interval = width/(float)steps;
// the lower we set this, the slower it animates.
frameRate(60);
}
void draw() {
// white background, black lines
background(255);
stroke(0);
// for each historic point, draw two
// lines. One from height 0 to the point,
// another from height [max] to the point.
Point p;
for (int i=0; i<steps; i++) {
p = points.get(i);
line(interval/2 + i*interval, 0, p.x, p.y);
line(interval/2 + i*interval, height, p.x, p.y);
}
// when we move the mouse, that counts as a new historic point
points.remove(0);
points.add(new Point(mouseX, mouseY));
}
Sketch running in the browser: http://jsfiddle.net/M2LRy/1/
(You could speed this up by using a round-robin array instead of an ArrayList, but ArrayLists are pretty convenient here)

Resources