steve
steve

Reputation: 311

Changing the coordinate system in P5.js

As you know P5 coordinate system doesn't start from the middle of the canvas plus the y axis is flipped My question is how to change the coordinates of p5 so it became the same as the Cartesian coordinate system

Upvotes: 12

Views: 5233

Answers (2)

mike
mike

Reputation: 2106

In addition to translating the origin and flipping the y axis, I came to this question looking to scale for "world coordinates" (coordinates that are for the scene, independent of the pixel dimensions of the canvas).

A few refinements I'd like to add to address my specific needs:

  1. Set up some word coordinate variables:

    let worldWidth = 640
    let worldHeight = 400
    let worldAspect = (worldHeight/worldWidth);
    
  2. In setup() adjust the canvas to the width of the window, but maintain the world aspect ratio:

    function setup() {
      createCanvas(windowWidth, windowWidth * worldAspect);
    }
    
  3. Begin draw() by translating origin to the bottom left. To use world coordinates, one can scale by the canvas height and width, divided by world coordinates (remembering to also flip vertically by using negative height):

    function draw() {
      translate(0, height);
      scale(width / worldWidth, -height / worldHeight);
    
      # ...
    }
    
  4. For un-flipping text, if you need to do this often, write a function which wraps text() to temporarily un-flip:

    function wText(message, x, y, size) {
      push();
      scale(1, -1);
      textSize(size);
      text(message, x, -y);
      pop();
    }
    

    This maintains the world-coordinates scaling because successive calls to scale() are cumulative. It's also why we want to scale by one.

  5. Now we can think in world coordinates, with origin in the bottom left and vertical y axis going up. For instance, this will always draw "hi" the right way up, in the top-right corner, and a medium sized true circle in the center, no matter the size of the window and canvas:

    wText("hi", 580, 350, 50);
    circle(320, 200, 80);
    

    Note the use of world coordinates means we no longer have to calculate pixel position based on width and height: the scale takes care of this.

  6. The mouseX and mouseY variables always contain the mouse's device pixel position: not scaled or translated. To resolve this, define two more functions:

    function wMouseX() {
      return mouseX * (worldWidth / width)
    }
    
    function wMouseY() {
      return worldHeight - (mouseY * (worldHeight / height))
    }
    

    You can test this with the following code, to show the mouse coordinates (pixels) and their world coordinates (scaled and translated points):

    wText(" x:\t" + round(mouseX), 0, 40);
    wText(" y:\t" + round(mouseY), 0, 20);
    
    wText("wX:\t" + wMouseX(), 200, 40);
    wText("wY:\t" + wMouseY(), 200, 20);
    
    fill("red");
    circle(wMouseX(), wMouseY(), 15);
    

Upvotes: 1

Rabbid76
Rabbid76

Reputation: 210889

Use translate() to translate the origin to the center. Use scale to flip the y axis:

function draw() {
    translate(width/2, height/2); 
    scale(1, -1);

    // [...] 
}

Note, width and height is the width and height of the canvas.
translate(width/2, height/2) moves everything by the half width and height. It moves the objects of the scene from the top left to the center of the canvas.


This approach will cause that text to be flipped. To "unflip" the text again, each text must be inserted in a push()/pop() block that reverses the flip::

push();
scale(1, -1); // reverse the global flip
text(...);
pop(); 

Upvotes: 22

Related Questions