Search code examples
matrix3dgeometryprocessing

Position of a vector in coordinate system (Processing/p5.js)


i am new to processing i had to perform a task and i wanted to know how can i go about it in processing. Down below is the code and i want to find the coordinates of Pvector 'vectorInNewCoordSys' in the original coordinate system which would be the one in which i drew the vector 'originalVector'.(if you are running this code then what i mean is i want to know the coordinates of where the blue vector points.) (the answer one would be expecting is (100,100)) Or maybe can you suggest some other method of performing this task?

PVector originalVector; // The vector in the original coordinate system

void setup() {
  size(400, 400);
  originalVector = new PVector(100, 0); 
}
void draw() {
  background(220);
  translate(width/2, height/2); 
  stroke(255, 0, 0);
  drawVector(originalVector);

  pushMatrix();

  rotate(radians(45));
  PVector vectorInNewCoordSys = originalVector.get(); 
  applyTransformations(vectorInNewCoordSys); 
  stroke(0, 0, 255);
  drawVector(vectorInNewCoordSys);

  popMatrix();

pushMatrix();
//line(0,0,400,0);
//line(0,0,0,400);
PVector v1 = vectorInNewCoordSys.get();

popMatrix();


}

void drawVector(PVector v) {
  line(0, 0, v.x, v.y);
}

void applyTransformations(PVector v) {
}  

Solution

  • You have two options:

    1. using modelX(), modelY(), modelZ() so Processing converts between the local coordinate space (in between push/pop matrix calls) to global coordinates for you: this will require the P3D renderer
    2. using PMatrix2D to do handle the conversion (vector to (transformation) matrix multiplication) from local to global manually.

    There is a catch: you're first translating to the centre. This is one transformation already applied. You need to take that into account when converting between local and global coordinates: the pivot point/transformation centre will be different. You can either undo the translation when converting coordinates or simply translate from centre after doing the coordinate conversion for rendering only:

    PVector originalVector; // The vector in the original coordinate system
    
    void setup() {
      size(400, 400, P3D);
      originalVector = new PVector(100, 0);
    }
    
    void draw() {
      background(220);
      
      pushMatrix();
    
        rotateZ(radians(45));
        PVector vectorInNewCoordSys = originalVector.copy();
        applyTransformations(vectorInNewCoordSys);
      
      popMatrix();
      
      // translate to centre after converting (using the same pivot in the top left corner) 
      translate(width/2, height/2);
      
      stroke(255, 0, 0);
      drawVector(originalVector);
    
      stroke(0, 0, 255);
      drawVector(vectorInNewCoordSys);
    }
    
    void drawVector(PVector v) {
      line(0, 0, v.x, v.y);
    }
    
    void applyTransformations(PVector v) {
      v.set(modelX(v.x,v.y,v.z), 
            modelY(v.x,v.y,v.z), 
            modelZ(v.x,v.y,v.z));
    }
    

    For more details I warmy recommend the 2D transformations tutorial.

    If you want to go a bit deeper/lower level, you can access the current transformation matrix (via getMatrix(yourMatrix)) and use it to transform the vector. (Multiplying a vector with a transformation matrix transforms that vector into the coordinate system the transformation matrix holds).

    PVector originalVector = new PVector(100, 0);
    // transformation matrix
    PMatrix2D currentTransformation = new PMatrix2D();
    
    void setup(){
      size(400, 400);
      currentTransformation.print();
    }
    
    void draw(){
      background(220);
      
      pushMatrix();
        rotate(radians(frameCount % 360));
        // store this local coordinate system transformation matrix
        getMatrix(currentTransformation);
        // debugging only
      popMatrix();
      
      
      PVector vectorInNewCoordSys = originalVector.copy();
      // convert from the global coordinate system: 
      // vectorInNewCoordSys = currentTransformation * originalVector
      // 1st argument = input(original) vector
      // 2nd argument = output(transformed) vector
      currentTransformation.mult(originalVector, vectorInNewCoordSys);
      // render from centre
      translate(width / 2, height / 2);
      
      stroke(255, 0, 0);
      drawVector(originalVector);
      
      stroke(0, 0, 255);
      drawVector(vectorInNewCoordSys);
      
    }
    
    void drawVector(PVector v) {
      line(0, 0, v.x, v.y);
    }
    
    

    You can off course encapsulate the above multiplication in a function, as your original code suggests:

    PVector originalVector = new PVector(100, 0);
    // transformation matrix
    PMatrix2D currentTransformation = new PMatrix2D();
    
    void setup(){
      size(400, 400);
    }
    
    void draw(){
      background(220);
      
      pushMatrix();
        rotate(radians(frameCount % 360));
        // store this local coordinate system transformation matrix
        getMatrix(currentTransformation);
        // debugging only
      popMatrix();
      
      
      PVector vectorInNewCoordSys = originalVector.copy();
      // convert from the global coordinate system: 
      // vectorInNewCoordSys = currentTransformation * originalVector
      // 1st argument = input(original) vector
      // 2nd argument = output(transformed) vector
      applyTransformations(vectorInNewCoordSys, currentTransformation);
      // render from centre
      translate(width / 2, height / 2);
      
      stroke(255, 0, 0);
      drawVector(originalVector);
      
      stroke(0, 0, 255);
      drawVector(vectorInNewCoordSys);
      
    }
    
    void drawVector(PVector v) {
      line(0, 0, v.x, v.y);
    }
    
    
    void applyTransformations(PVector v, PMatrix2D transformations) {
      // make a new pvector to transform from 0, 0
      PVector transformed = new PVector();
      transformations.mult(v, transformed);
      // apply the v transformed (from 0,0) back to v
      v.set(transformed);
    }
    

    Because you're only using one transformation (rotation) and not a set of nested transformations you can also directly use PMatrix2D (instead of push/pop matrix). (In case you're animating, remember to reset the matrix first, otherwise you'd accumulate previous transformations continuously, in this case spinning out of control :) ):

    PVector originalVector = new PVector(100, 0);
    // transformation matrix
    PMatrix2D currentTransformation = new PMatrix2D();
    
    void setup(){
      size(400, 400);
    }
    
    void draw(){
      background(220);
      
      // clear the previous frame's transformation (back to the identity matrix
      currentTransformation.reset();
      currentTransformation.rotate(radians(frameCount % 360));
      
      PVector vectorInNewCoordSys = originalVector.copy();
      // convert from the global coordinate system: 
      // vectorInNewCoordSys = currentTransformation * originalVector
      // 1st argument = input(original) vector
      // 2nd argument = output(transformed) vector
      applyTransformations(vectorInNewCoordSys, currentTransformation);
      // render from centre
      translate(width / 2, height / 2);
      
      stroke(255, 0, 0);
      drawVector(originalVector);
      
      stroke(0, 0, 255);
      drawVector(vectorInNewCoordSys);
      
    }
    
    void drawVector(PVector v) {
      line(0, 0, v.x, v.y);
    }
    
    
    void applyTransformations(PVector v, PMatrix transformations) {
      // make a new pvector to transform from 0, 0
      PVector transformed = new PVector();
      transformations.mult(v, transformed);
      // apply the v transformed (from 0,0) back to v
      v.set(transformed);
    }
    

    (For tons more detail on the actual math I recommed checking out "3D math primer for graphics and game development". It's c++, not Java/Processing, however the concept apply to most 3D libraries))