We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Good day dear Processing folks!
I'm pretty new to Processing and need some assistance on a small project I'm currently working on. In this project I want to position some ellipses on the canvas. These ellipses should be zoomable via mouse wheel and it should be possible to translate the canvas coordinate system (and all ellipses with it) via mouse drag. Those things kinda work but I've got one more requirement which sadly cost me plenty of time already without working results: I need mouseovers for the ellipses which stop working correctly after scaling and translating. Take a look at the following example:
color bg; color fg; boolean pressed; float pressedX; float pressedY; float transPressedX; float transPressedY; float sval; float radius; float transX; float transY; float maxZoom = 7.0; float minZoom = 0.1; float coords[][]; void setup() { size(1600, 900); bg = color(0,0,0); fg = color(#55ACEE); background(bg); pressed = false; transX = width/2; transY = height/2; sval = 1.0; radius = 10; coords = new float[50][2]; int counter = 0; outerLoop: while (counter < coords.length) { float x = random(0, width); float y = random(0, width); for(int i = 0; i < counter; i++) { if(dist(coords[i][0], coords[i][1], x, y) < (radius * 5)) { continue outerLoop; } } coords[counter][0] = x; coords[counter][1] = y; counter++; } } void draw() { background(bg); fill(fg); translate(-transX, -transY); scale(sval); translate(transX, transY); for(int i = 0; i < coords.length; i++ ) { drawEllipse(coords[i][0], coords[i][1], radius); } } void drawEllipse(float x, float y, float radius) { if(dist(mouseX/sval, mouseY/sval, x, y) < radius) { ellipse(x, y, radius * 2.5, radius * 2.5); } else { ellipse(x, y, radius * 2, radius * 2); } } void mousePressed() { if(!pressed) { pressedX = mouseX; pressedY = mouseY; transPressedX = transX; transPressedY = transY; } pressed = true; } void mouseReleased() { pressed = false; } void mouseDragged() { if(pressed) { float diffX = (max(mouseX, pressedX) - min(mouseX, pressedX)); float diffY = (max(mouseY, pressedY) - min(mouseY, pressedY)); if(sval<1) { diffX *= -((1/minZoom)/2); diffY *= -((1/minZoom)/2); } else { diffX *= ((maxZoom/sval)/2); diffY *= ((maxZoom/sval)/2); } if(mouseX < pressedX) { transX = (transPressedX - diffX); } else { transX = (transPressedX + diffX); } if(mouseY < pressedY) { transY = (transPressedY - diffY); } else { transY = (transPressedY + diffY); } } } void zoomIn(float step) { sval = constrain(sval + step, minZoom, maxZoom); } void zoomOut(float step) { sval = constrain(sval - step, minZoom, maxZoom); } void mouseWheel(MouseEvent event) { float e = event.getAmount(); if(e < 0) { zoomOut(sval*0.075); } else if(e > 0) { zoomIn(sval*0.075); } }
The project is build with Processing.js 1.4.1 but I have stripped it down to the problematic chunks and put it inside Processing 2.1.1. It should run fine there and the only real difference is the handling of mouse wheel since Processing.js uses a different way to do that.
When you run the sketch you can see 25 ellipses randomly distributed on the canvas. Zooming in and out works fine but translation is weird: when scale factor is 1 it doesn't work at all and when the factor shrinks or expands the translation gets faster the farther away the factor gets from 0. That's awkward but not a deal breaker for now, but if you've got any suggestions to fix that, I'd appreciate it!
But back to the main topic: as long as scale factor is 1 everything is okay, but as soon as it shrinks/expands the mouse overs stop working. My problem here is that I don't really get how to achieve that in Processing. Is there any way to transform single points as usually possible in CG? If anyone can help me I would be very grateful!
Best regards, eldahar
Answers
Got an example of using mouseWheel() in this thread:
http://forum.processing.org/two/discussion/598/mousewheel-syntax-question-solved
Perhaps it might help while you wait for specific answers! :D
Matrix transformation settings like translate(), scale(), rotate(), etc. are really cool!
However, finding out an object's coordinates after they're transformed isn't elementary math for sure! X_X
Rather than using scale(), you may try render the ellipses w/
radius * scale
.And rather than translate(), change the ellipses' coordinates themselves!
This way, it's much easier to match mouseX & mouseY, which aren't affected by transformations, to the ellipses' coords.! :-B
Thanks for the input, GoToLoop!
Seems like a viable solution to me. Will see what I can do and post back the results.
Thanks for the help! It now works fine for the test sketch including the fixed awkward behaviour of translation. In case anyone wonders here's how to do it for that case (should work for other cases as well):
Now I'll try to bring it back into my project.
It is obvious that you are trying to zoom in/out about the centre of the screen and that is not working properly.
The trick here is to move the screen origin from the top-left corner to the centre of the display before drawing the ellipses. It means that the 'world' origin (0,0) is now at the centre of the display and ellipse x/y coordinates should be calculated from this new origin.
The trick then is to simply convert the mouse coordinates to 'world' coordinates and compare these to the ellipse coordinates.
Anyway the code below does zooms in and out of the display centre and the ellipses enlarge when the mouse is over them. I have not touched the mousePressed/Released/Dragged methods I leave that to you but think in terms of worldX and worldY rather than mouseX and mouseY.
Thanks, quark!
That was exactly the answer I was looking for!