We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Is there a way to translate mouse coordinates when the canvas is also translated? In objects where mouse coordinates are used for control, this translation is useful if the object was set at position x,y of a translated canvas.
Answers
Please post some code showing your approach.
Kf
Take the following code for example, a simple "hover-over the square". The non translated object (test2) performs as expected while the translated object (test1) does not become white when the mouse is over it. Is there any way to translate mouse coordinates as well?
Note: I understand why this happens and that it could be avoided by providing the right coordinates to test1 without the use of translation. But it so happens that translating mouse coordinates for GUI applications can be useful.
Since you have your own class, it is better off to do not use the translate operation but to keep record within your class. if you still want to use translate() then you will need to keep track of the mouse and the reference frame:
and in your display() function:
if (mx > x && mx < x+sizeX && my > y && my < y+sizeY) {
Another way to do it below. Reference: https://processing.org/reference/pushMatrix_.html
Kf
@kfrajer All this brings a question, as can be confirmed by @jeremydouglass -
The
getMatrix()
method seemingly only returns the transformations applied after the most recentpushMatrix()
call. How to get the complete current matrix?@kfrajer I have already thought of this but I was hoping for a more elegant solution like translate() instead of manual position offsets. Does something like that exist? Can I manually change the reference point of mouseX & mouseY?
I thought about using getMatrix, but I don't think it will work. You cannot translate the mouse position to the reference frame where the objects were drawn. From what I see, the matrix you get from getMatrix only stores accumulated info of any transformation from the last push. In my next example I suggest a solution. Instead of shifting the mouse position to another reference frame, the point in the reference frame is shifted back to the mouse (un-transformed) reference frame using screenX/screenY. Check the example below.
Reference: https://forum.processing.org/two/discussion/comment/85627/#Comment_85627
https://forum.processing.org/two/discussion/comment/93034/#Comment_93034 (jeremydouglass on March 27/28) https://processing.org/reference/pushMatrix_.html
https://processing.org/reference/applyMatrix_.html
Kf
That obviously exists, but there always are troubles with it :)
@kfrajer -- I believe that this is correct, and is currently the "Processing way" -- in order to do collision detection between the mouse and coordinates inside a transform:
screenX()
etc. then compareAn easy way to project the mouse would be if there was a 2D version of
modelX()
-- but there isn't, and modelX only works in P3D. Also,getMatrix()
doesn't return the full stack, as you mention, and there is no other 2D full stack equivalent.@jeremydouglass
Why?
Because
...and since those things don't exist, doing all of the projection calculations yourself to match the matrix stack is a royal pain. If all you are doing is a single translation, just save that in variables and add it to the mouse. But as soon as you are rotating and scaling or nesting multiple transforms you will really, really wish you had modelX(x,y), but you don't -- you have screenX().
but instead of using mouseX & mouseY, one can write functions mouse_X() & mouse_Y() and for every translate() call, one would also call a translateMouse() function with the same arguments as translate(). The same would apply for other functions like scale() or rotate().
@Alex_Pr -- ...so if in your sketch above you instead position
test3
like this:...what happens? And, in particular, what is happening when you search with the mouse to find the hidden mouseover area for the smallest rectangle (test4)? Even with a "fix" like adding
mouse_totalRotate = 0;
to the bottom ofdraw()
, what happens to test4...?I suspect that we can't simulate matrix transformations using a few fixed variables -- except in very special sequences of transforms using very particular values, and those special cases that work will break the second that we tweak them. Instead, we often need to implement either a stack for each variable or more likely a full transformation matrix.
I'm not saying that this is impossible by any means -- I'm just saying it is non-trivial.
Transformation sets are generally dependent on the order they are applied:
https://www.khanacademy.org/partner-content/pixar/sets/sets1/v/sets-4
While the order of only translations doesn't matter, translation-rotation-scaling does matter. Your approach will not work. You will need to keep track of the transformation (and the order they are applied) using matrix algebra. As @jeremydouglass described it previously, it is a painful exercise and worth of a challenge.
A better way would be to dig into the source code and become familiar with the model function and see if it is possible to design the same version for 2D. Please, keep in mind I am saying this without much experience using these functions.
This question has been brought several times before and the solution is not straight forward unfortunately.
Another way is not to use transformations at all. You use the same reference frame in your program. You apply transformation to actual positions in that reference frame. That means you cannot use translate/rotate/scale functions provided by Processing but you will have to implemented explicitly your own functions in your code. Although this is more work, mouse-object interaction is straight forward as it is in the same reference frame. It is a matter of preference at the end. Notice this is really needed when we are working with the mouse pointer and a set of transformations in the sketch. The reason this has not been address before is because most people don't perform complicated transformations while interacting with the mouse.
Related posts:
https://forum.processing.org/two/discussion/14680/using-modelx-and-screenx-for-3d-picking-but-how#latest
https://forum.processing.org/two/discussion/comment/85129/#Comment_85129
https://forum.processing.org/two/discussion/comment/88384/#Comment_88384
https://forum.processing.org/two/discussion/20235/align-box-with-vector
Kf
@jeremydouglass Thanks for finding out the bug. I revised the code, should work without a problem!
just replace the following function
And add this at the end of draw()
mouse_totalOffsetX = 0; mouse_totalOffsetY = 0; mouse_totalRotate = 0; mouse_totalScale = 1;
What happens if you do this?
To support pushMatrix() & popMatrix() functionality in my code I'd have to store the values of mouse_totalOffsetX, mouse_totalOffsetY, mouse_totalRotate, mouse_totalScale in a stack. It's not difficult, if one understands how those functions work.
Ok! Whether or not pushMatrix/popMatrix is supported, what happens if you do this?
Check all four sides of each of the smallest two shapes carefully with the mouse. What is happening? This kind of thing would also occur in any sketch that was accumulating rotations in a variable
rot=rot+angle
It is the result of the accumulative error of storing PI to a float. If instead of a loop you tried 30000*PI/4 there would be no problem. So, to solve this, we turn
mouse_totalRotate
to a double variable instead of a float, and make the appropriate float conversions in all other functions implementingmouse_totalRotate
.Good! -- a version of your functions with a stack for each variable and high precision would definitely be a better approximation for most common sketches.
Processing sketches may scale to a different aspect ratio, like this:
How would you handle this?
Here is a complete, programmer-friendly solution for mouse coordinates transformations.
and the minimum necessary code for it to run:
Note: for proper function of this code, all calls to functions
pushMatrix(), popMatrix(), translate(), scale(), rotate()
must be followed by calls to functionspushMatrixMouse(), popMatrixMouse(), translateMouse(), scaleMouse(), rotateMouse()
respectively and with the same arguments. To implement, simply replacemouseX
andmouseY
withmouse_X()
andmouse_Y()
I tested your code and it works. I suggest a modification. Instead of calling translate followed by translateMouse, you could call the former inside the latter and the user doesn't need to call both functions in his/her program. Check the code below.
Kf
@Alex_Pr -- Very, very impressive (and fast) -- with a nice use of ArrayDeque<> for the mouse stack!
Two thoughts:
Adding an additional set of wrappers e.g.
rotateM()
,scaleM()
,translateM()
like this:...would really cut down on code clutter of always having to pair calls.
This should be a library! Then it could be a single import statement with no other required lines in the sketch. You could initialize the mouseStack when the library is called, then use
registerMethod("post", this);
to set up a hook that calls yourresetMouse()
after every draw(). https://github.com/processing/processing/wiki/Library-BasicsThe library would probably have some name or description hinting that it is 2D so nobody tries to use
translate(x,y,z)
orrotateX()
with it....Edit: looks like @kfrajer had a very similar suggestion on 1 -- although there might (?) be a situation where you would want to translate the mouse but not the draw frame...? I suppose it could also be handled by multiple signatures, with the default being to pair them, like this:
@kfrajer and @jeremydouglass Thank you both for the feedback! I can't think of a reason why transformations would be applied only to the mouse and not the frame, but for completeness purposes I will add that functionality, removing the need to
as suggester by @kfrajer and at the same time have full control if
as suggester by @jeremydouglass
It will be up to the programmer not to mess the transformations up. I will wrap the whole code into a library (that's a first for me =D ) and provide it here.
Ask me if you need help in making a library/getting it published.
The library has been released! It is listed at https://processing.org/reference/libraries/ under utilities and can be found here:
https://github.com/AlexPoupakis/mouse2DTransformations
Thanks to everyone for their suggestions and help =D
@Alex_Pr -- congratulations! I see that it is also already available in the Add Tool menu -- looking forward to playing with it.