Translate mouse coordinates

edited April 2017 in Questions about Code

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?

    Shape test1, test2;
    
    void setup(){
      size(500,500);
      test1 = new Shape(200,200,100,100);
      test2 = new Shape(100,50,70,70);
    }
    
    void draw(){
      background(255);
      translate(150, 150);
      test1.display();
      translate(-150, -150);
    
      test2.display();
    
      //where mouse should be for test1 to become white
      stroke(180);
      fill(255);
      rect(200,200,100,100);
    }
    
    class Shape{
      int x, y, sizeX, sizeY;
    
      Shape(int x, int y, int sizeX, int sizeY){
        this.x = x;
        this.y = y;
        this.sizeX = sizeX;
        this.sizeY = sizeY;
      }
    
      void display(){
        if (mouseX > x && mouseX < x+sizeX && mouseY > y && mouseY < y+sizeY){
          fill(255);
        }
        else {
          fill(0);
        }
        stroke(255,0,0);
        rectMode(CORNER);
        rect(x, y, sizeX, sizeY);
      }
    }
    

    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:

    void draw() {
      mx=mouseX;
      my=mouseY;
      background(255);  
    
      translate(150, 150);
      mx=mouseX-150;
      my=mouseY-150;
      test1.display();
    
    
      translate(-150, -150);
      mx=mouseX+150;
      my=mouseY+150;
      test2.display();
    
      //where mouse should be for test1 to become white
      stroke(180);
      fill(255);
      rect(200, 200, 100, 100);
    }
    

    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

    void draw() {
      mx=mouseX;
      my=mouseY;
      background(255);  
      pushMatrix();
      translate(150, 150);
      mx=mouseX-150;
      my=mouseY-150;
      test1.display();
      popMatrix();
    
      mx=mouseX;
      my=mouseY;
      test2.display();
    
      //where mouse should be for test1 to become white
      stroke(180);
      fill(255);
      rect(200, 200, 100, 100);
    }
    
  • @kfrajer All this brings a question, as can be confirmed by @jeremydouglass -
    The getMatrix() method seemingly only returns the transformations applied after the most recent pushMatrix() 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?

  • edited April 2017 Answer ✓

    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

    //INSTRUCTIONS: Red circle out of the sketch. Click on the middle circle to
    //     test hover action
    
    //Ellipse position and radius
    final int ex=0;  
    final int ey=0;
    final int er=100;
    
    
    void setup() {
    
      size(600, 600);
      noLoop();
    }
    
    void draw() {
      printInfo("INIT STATE");
    
      pushMatrix();
      rotate(PI/2);
      printMatrix();
      pushMatrix();
      translate(width>>1, height>>1);
      printInfo("Rotate follow by Translate");
      fill(255, 0, 0);
      ellipse(ex, ey, er, er);
      popMatrix();
      popMatrix();
    
    
      pushMatrix();
      translate(width>>1, height>>1);
      printMatrix();
      pushMatrix();
      rotate(PI/2);
      printInfo("Translate follow by rotate");
    
     //Check if click is on figure
      if (dist(mouseX, mouseY, screenX(ex, ey), screenX(ex, ey))<er)
        fill(0, 255, 0);
      else
        fill(0, 0, 255);
    
      ellipse(ex, ey, er/2.0, er/2.0);
      popMatrix();
      popMatrix();
    }
    
    void printInfo(String msg) {
      println("==========================");
      println(msg);
      printMatrix();
      println("****  Position (0,0) at "+screenX(ex, ey)+"  "+screenY(ex, ey));
    }
    
    void mouseReleased() {
      redraw();
    }
    
  • That obviously exists, but there always are troubles with it :)

  • edited April 2017

    @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:

    1. don't try to project the mouse into transform space, then compare
    2. instead, project the transform coordinates into screen space using screenX() etc. then compare

    An 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

    don't try to project the mouse into transform space, then compare

    Why?

  • edited April 2017

    Because

    An 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.

    ...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().

    float mouse_totalOffsetX = 0, mouse_totalOffsetY = 0, mouse_totalRotate = 0, mouse_totalScale = 1;
    
    Shape test1, test2, test3, test4;
    
    void setup(){
      size(700,700);
    
      test1 = new Shape(200,200,100,100);
      test2 = new Shape(350,150,80,80);
      test3 = new Shape(0,0, 50,50);
      test4 = new Shape(100,50,30,30);
    }
    
    void draw(){
      background(255);
    
      translate(150, 150);
      translateMouse(150, 150);
    
      test2.display();
    
      scale(1.5);
      scaleMouse(1.5);
      test1.display();
      scale(1/1.5);
      scaleMouse(1/1.5);
    
      rotate(PI/4);
      rotateMouse(PI/4);
      test3.display();
      rotate(-PI/4);
      rotateMouse(-PI/4);
    
      translate(-150, -150);
      translateMouse(-150, -150);
    
      test4.display();
    }
    
    void translateMouse(float offsetX, float offsetY){
      mouse_totalOffsetX += offsetX;
      mouse_totalOffsetY += offsetY;
    }
    
    void scaleMouse(float scale){
      mouse_totalScale *= scale;
    }
    
    void rotateMouse(float rad){
      mouse_totalRotate += rad;
    }
    
    int mouse_X(){
      return int(cos(mouse_totalRotate)*(1/mouse_totalScale)*(mouseX - int(mouse_totalOffsetX))) + int(sin(mouse_totalRotate)*(1/mouse_totalScale)*(mouseY - int(mouse_totalOffsetY)));
    }
    
    int mouse_Y(){
      return int(cos(mouse_totalRotate)*(1/mouse_totalScale)*(mouseY - int(mouse_totalOffsetY))) - int(sin(mouse_totalRotate)*(1/mouse_totalScale)*(mouseX - int(mouse_totalOffsetX)));
    }
    
    
    class Shape{
      int x, y, sizeX, sizeY;
    
      Shape(int x, int y, int sizeX, int sizeY){
        this.x = x;
        this.y = y;
        this.sizeX = sizeX;
        this.sizeY = sizeY;
      }
    
      void display(){
        if (mouse_X() > x && mouse_X() < x+sizeX && mouse_Y() > y && mouse_Y() < y+sizeY){
          fill(255);
        }
        else {
          fill(0);
        }
        stroke(255,0,0);
        rectMode(CORNER);
        rect(x, y, sizeX, sizeY);
      }
    }
    
  • edited April 2017

    @Alex_Pr -- ...so if in your sketch above you instead position test3 like this:

      for(int i=0; i<3; i++){
        rotate(PI/4);
        rotateMouse(PI/4);
      }
      test3.display();
    

    ...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 of draw(), 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

    void translateMouse(float offsetX, float offsetY){
      mouse_totalOffsetX += cos(mouse_totalRotate)*(mouse_totalScale)*offsetX - sin(mouse_totalRotate)*(mouse_totalScale)*offsetY;
      mouse_totalOffsetY += cos(mouse_totalRotate)*(mouse_totalScale)*offsetY + sin(mouse_totalRotate)*(mouse_totalScale)*offsetX;
    }
    

    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?

      pushMatrix();
      for(int i=0; i<3; i++){
        rotate(PI/4);
        rotateMouse(PI/4);
      }
      test3.display();
      popMatrix();
    
  • 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.

  • edited April 2017

    Ok! Whether or not pushMatrix/popMatrix is supported, what happens if you do this?

      for(int i=0; i<30000; i++){
        rotate(PI/4);
        rotateMouse(PI/4);
      }
      test3.display();
    

    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

    float angle = PI/32;
    float rot;
    
    void draw(){
        rot = rot+angle;
        rotate(rot);
        rotateMouse(rot);
        test3.display();
    }
    
  • 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 implementing mouse_totalRotate.

  • edited April 2017

    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:

    scale(0.5, 1.3);
    

    How would you handle this?

  • Here is a complete, programmer-friendly solution for mouse coordinates transformations.

    import java.util.ArrayDeque;
    
    ArrayDeque<mouseParameters> mouseStack = new ArrayDeque();
    
    class mouseParameters{
      final float initialOffsetX, initialOffsetY, initialScaleX, initialScaleY;
      final double initialRotate;
      float totalOffsetX, totalOffsetY, totalScaleX, totalScaleY;
      double totalRotate;
    
      mouseParameters(float initialOffsetX, float initialOffsetY, double initialRotate, float initialScaleX, float initialScaleY){
        this.initialOffsetX = initialOffsetX;
        this.initialOffsetY = initialOffsetY;
        this.initialRotate = initialRotate;
        this.initialScaleX = initialScaleX;
        this.initialScaleY = initialScaleY;
        reset();
      }
    
      mouseParameters(){
        initialOffsetX = 0;
        initialOffsetY = 0;
        initialRotate = 0;
        initialScaleX = 1;
        initialScaleY = 1;
      }
    
      void reset(){
        totalOffsetX = initialOffsetX;
        totalOffsetY = initialOffsetY;
        totalRotate = initialRotate;
        totalScaleX = initialScaleX;
        totalScaleY = initialScaleY;
      }
    }
    
    
    void pushMatrixMouse(){
      mouseStack.addLast(new mouseParameters(mouseStack.getLast().totalOffsetX, mouseStack.getLast().totalOffsetY, mouseStack.getLast().totalRotate, mouseStack.getLast().totalScaleX, mouseStack.getLast().totalScaleY));
    }
    
    void popMatrixMouse(){
      mouseStack.removeLast();
    }
    
    void translateMouse(float offsetX, float offsetY){
      mouseStack.getLast().totalOffsetX += cos((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleX)*offsetX - sin((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleY)*offsetY;
      mouseStack.getLast().totalOffsetY += cos((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleX)*offsetY + sin((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleY)*offsetX;
    }
    
    void scaleMouse(float scale){
      mouseStack.getLast().totalScaleX *= scale;
      mouseStack.getLast().totalScaleY *= scale;
    }
    
    void scaleMouse(float scaleX, float scaleY){
      mouseStack.getLast().totalScaleX *= scaleX;
      mouseStack.getLast().totalScaleY *= scaleY;
    }
    
    void rotateMouse(double rad){
      mouseStack.getLast().totalRotate += rad;
    }
    
    void resetMouse(){
      mouseStack.getLast().reset();
    }
    
    int mouse_X(){
      return int(cos((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleX)*(mouseX - int(mouseStack.getLast().totalOffsetX))) + int(sin((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleY)*(mouseY - int(mouseStack.getLast().totalOffsetY)));
    }
    
    int mouse_Y(){
      return int(cos((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleY)*(mouseY - int(mouseStack.getLast().totalOffsetY))) - int(sin((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleX)*(mouseX - int(mouseStack.getLast().totalOffsetX)));
    }
    

    and the minimum necessary code for it to run:

    void setup(){
      mouseStack.addLast(new mouseParameters());
    }
    
    void draw(){
      //always at the end of draw()
      resetMouse();
    }
    

    Note: for proper function of this code, all calls to functions pushMatrix(), popMatrix(), translate(), scale(), rotate() must be followed by calls to functions pushMatrixMouse(), popMatrixMouse(), translateMouse(), scaleMouse(), rotateMouse() respectively and with the same arguments. To implement, simply replace mouseX and mouseY with mouse_X() and mouse_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

    import java.util.ArrayDeque;
    
    ArrayDeque<mouseParameters> mouseStack = new ArrayDeque();
    
    
    //INSTRUCTIONS: for proper function of this code, calls to functions  
    //  pushMatrix(), popMatrix(), translate(), scale(), rotate() must be replaced by calls to functions  
    //  pushMatrixMouse(), popMatrixMouse(), translateMouse(), scaleMouse(), rotateMouse() respectively 
    //  To implement, simply replace mouseX and mouseY with mouse_X() and mouse_Y()
    Shape test1, test2, test3, test4;
    
    void setup() {
      size(700, 700);
      textAlign(CENTER);
      mouseStack.addLast(new mouseParameters());
    
      test1 = new Shape("test1", 200, 200, 100, 100);
      test2 = new Shape("test2", 350, 150, 80, 80);
      test3 = new Shape("test3", 0, 0, 50, 50);
      test4 = new Shape("test4", 100, 50, 30, 30);
    }
    
    void draw() {
      background(255);
    
      pushMatrixMouse();
      translateMouse(150, 150);
      test2.display();
    
      scaleMouse(1.5);
      test1.display();
    
      scaleMouse(1/1.5);
      rotateMouse(PI/4);
      test3.name="test3";
      test3.display();
    
      rotateMouse(-PI/4);
      translateMouse(-150, -150);
      test4.display();
    
      popMatrixMouse();
    
      pushMatrixMouse();
      translateMouse(250, 250);
      rotateMouse(PI/4);
      test3.name="t3_TR";
      test3.display();
      popMatrixMouse();
    
    
      pushMatrixMouse();
      rotateMouse(PI/4);
      translateMouse(250, 250);
      test3.name="t3_RT";
      test3.display();
      popMatrixMouse();
    
      //always at the end of draw()
      resetMouse();
    }
    
    
    
    //=======================================
    class Shape {
      int x, y, sizeX, sizeY;
      String name;
    
      Shape(String  nn, int x, int y, int sizeX, int sizeY) {
        this.x = x;
        this.y = y;
        this.sizeX = sizeX;
        this.sizeY = sizeY;
        name=nn;
      }
    
      void display() {
        if (mouse_X() > x && mouse_X() < x+sizeX && mouse_Y() > y && mouse_Y() < y+sizeY) {
          fill(255);
        } else {
          fill(0);
        }
        stroke(255, 0, 0);
        rectMode(CORNER);
        rect(x, y, sizeX, sizeY);
        fill(155);
        text(name, x+sizeX/2, y+sizeY/2);
        fill(155);
        //text(name, mouseX, mouseY);
        fill(0, 0, 255);
        //text(name, mouse_X(), mouse_Y());
      }
    }
    
    
    //=======================================
    class mouseParameters {
      final float initialOffsetX, initialOffsetY, initialScaleX, initialScaleY;
      final double initialRotate;
      float totalOffsetX, totalOffsetY, totalScaleX, totalScaleY;
      double totalRotate;
    
      mouseParameters(float initialOffsetX, float initialOffsetY, double initialRotate, float initialScaleX, float initialScaleY) {
        this.initialOffsetX = initialOffsetX;
        this.initialOffsetY = initialOffsetY;
        this.initialRotate = initialRotate;
        this.initialScaleX = initialScaleX;
        this.initialScaleY = initialScaleY;
        reset();
      }
    
      mouseParameters() {
        initialOffsetX = 0;
        initialOffsetY = 0;
        initialRotate = 0;
        initialScaleX = 1;
        initialScaleY = 1;
      }
    
      void reset() {
        totalOffsetX = initialOffsetX;
        totalOffsetY = initialOffsetY;
        totalRotate = initialRotate;
        totalScaleX = initialScaleX;
        totalScaleY = initialScaleY;
      }
    }
    
    
    void pushMatrixMouse() {
      pushMatrix();
      mouseStack.addLast(new mouseParameters(mouseStack.getLast().totalOffsetX, mouseStack.getLast().totalOffsetY, mouseStack.getLast().totalRotate, mouseStack.getLast().totalScaleX, mouseStack.getLast().totalScaleY));
    }
    
    void popMatrixMouse() {
      popMatrix();
      mouseStack.removeLast();
    }
    
    void translateMouse(float offsetX, float offsetY) {
      translate(offsetX, offsetY);
      mouseStack.getLast().totalOffsetX += cos((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleX)*offsetX - sin((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleY)*offsetY;
      mouseStack.getLast().totalOffsetY += cos((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleX)*offsetY + sin((float)mouseStack.getLast().totalRotate)*(mouseStack.getLast().totalScaleY)*offsetX;
    }
    
    void scaleMouse(float scale) {
      scale(scale);
      mouseStack.getLast().totalScaleX *= scale;
      mouseStack.getLast().totalScaleY *= scale;
    }
    
    void scaleMouse(float scaleX, float scaleY) {
      scale(scaleX, scaleY);
      mouseStack.getLast().totalScaleX *= scaleX;
      mouseStack.getLast().totalScaleY *= scaleY;
    }
    
    void rotateMouse(double rad) {
      rotate((float)rad);
      mouseStack.getLast().totalRotate += rad;
    }
    
    void resetMouse() {
      mouseStack.getLast().reset();
    }
    
    int mouse_X() {
      return int(cos((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleX)*(mouseX - int(mouseStack.getLast().totalOffsetX))) + int(sin((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleY)*(mouseY - int(mouseStack.getLast().totalOffsetY)));
    }
    
    int mouse_Y() {
      return int(cos((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleY)*(mouseY - int(mouseStack.getLast().totalOffsetY))) - int(sin((float)mouseStack.getLast().totalRotate)*(1/mouseStack.getLast().totalScaleX)*(mouseX - int(mouseStack.getLast().totalOffsetX)));
    }
    
  • edited April 2017

    @Alex_Pr -- Very, very impressive (and fast) -- with a nice use of ArrayDeque<> for the mouse stack!

    Two thoughts:

    1. Adding an additional set of wrappers e.g. rotateM(), scaleM(), translateM() like this:

      void rotateM(double rad){
         mouseStack.getLast().totalRotate += rad;
         rotate(rad);
      }
      

      ...would really cut down on code clutter of always having to pair calls.

    2. 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 your resetMouse() after every draw(). https://github.com/processing/processing/wiki/Library-Basics

    The library would probably have some name or description hinting that it is 2D so nobody tries to use translate(x,y,z) or rotateX() 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:

        void rotateMouse(double rad){
           rotateMouse(rad, true);
        }
        void rotateMouse(double rad, boolean rot){
           mouseStack.getLast().totalRotate += rad;
           if(rot){
             rotate(rad);
           }
        }
    
  • edited April 2017

    @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

    call both functions in his/her program

    as suggester by @kfrajer and at the same time have full control if

    you would want to translate the mouse but not the draw frame

    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.

  • edited May 2017

    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.

Sign In or Register to comment.