PVector rotate use for 3D

in the ref find:
https://processing.org/reference/PVector_rotate_.html
only work 2D,
now to rotate a PVector in 3D it still can be used / hacked

try:

// file: sketch_3D_PVector_rotate
// using mouseWheel Plus PLus for rotation

PVector a, atx, aty, atz, at;
int along = 50;
float angbx=0, angby=0, angbz=0;
boolean axprint = true, axline = true;

void setup() {
  size(600, 600, P3D);
  a = new PVector(along, along, along);
  info_print();                                          // Tab ptz
  println("here add: key [x] [y] [z] rotation axis / key [r] reset AND turn MouseWheel");
}

void draw () {
  background(200, 200, 0);
  PTZ();
}

//_____________________________________________________
void draw_object() {                                     // called by / from inside ptz
  axis();
  trans();
  show_vector();
} 


void rotatePVX(float angbx) {
  //______________________________________________   step 1 rotate a ( by x )
  atx = new PVector(a.y, a.z);                    // create a 2D vector
  atx.rotate(angbx);                             // rotate 2D original angle + MWPP angle
  atx.set(a.x, atx.x, atx.y);                     // restore to 3D 
  atx.sub(a);                                     // get the move vector only

  at.add(atx);                                   // by x
}

void rotatePVY(float angby) {
  //______________________________________________   step 2 rotate a ( by y )  
  aty = new PVector(a.x, a.z);
  aty.rotate(angby);
  aty.set(aty.x, a.y, aty.y);
  aty.sub(a);

  at.add(aty);                                   // by y
}

void rotatePVZ(float angbz) {
  //______________________________________________   step 3 rotate a ( by z )
  atz = new PVector(a.x, a.y);
  atz.rotate(angbz);
  atz.set(atz.x, atz.y, a.z);
  atz.sub(a);

  at.add(atz);                                   // by z
}

void trans() {
  at = a.copy();                                 // copy from original
  rotatePVX(angbx);
  rotatePVY(angby);
  rotatePVZ(angbz);
}

void axis() {
  int max = 100;
  stroke(200, 0, 0);
  strokeWeight(1);
  line(0, 0, 0, max, 0, 0);
  strokeWeight(0.3);
  line(0, 0, 0, -max, 0, 0);
  fill(200, 0, 0);
  text("x", max, 0);
  stroke(0, 200, 0);
  strokeWeight(1);
  line(0, 0, 0, 0, max, 0);
  strokeWeight(0.3);
  line(0, 0, 0, 0, -max, 0);
  fill(0, 200, 0);
  text("y", 0, max);
  stroke(0, 0, 200);
  strokeWeight(1);
  line(0, 0, 0, 0, 0, max);
  strokeWeight(0.3);
  line(0, 0, 0, 0, 0, -max);
  fill(0, 0, 200);
  text("z", 0, 0, max);
  fill(100, 100, 0, 10); // transparent not work
  noStroke();
  //max = 20;              // so make it small
  //rect(-max, -max, 2*max, 2*max);   // xy plane
}

void show_vector() {
  fill(200, 0, 200);
  noStroke();
  push();
  translate(a.x, a.y, a.z);
  sphere(3);
  pop();
  stroke(200, 0, 200);
  strokeWeight(3);
  line(a.x, a.y, a.z, 0, 0, 0);

  if ( axline ) {
    //show axis components
    stroke(80);
    strokeWeight(0.5);
    line(a.x, a.y, a.z, a.x, 0, 0);
    line(a.x, a.y, a.z, 0, a.y, 0);
    line(a.x, a.y, a.z, 0, 0, a.z);
  }
  // show rotated vector
  fill(0, 200, 200);
  noStroke();
  push();
  translate(at.x, at.y, at.z);
  sphere(3);
  pop();
  stroke(0, 200, 200);
  strokeWeight(3);
  line(at.x, at.y, at.z, 0, 0, 0);

  if ( axline ) {
    //show axis components
    stroke(80);
    strokeWeight(0.5);
    line(at.x, at.y, at.z, at.x, 0, 0);
    line(at.x, at.y, at.z, 0, at.y, 0);
    line(at.x, at.y, at.z, 0, 0, at.z);

    // show the at_i components
    push();
    stroke(0, 200, 200);
    strokeWeight(0.5);
    translate(a.x, a.y, a.z);
    line(0, 0, 0, atx.x, atx.y, atx.z);
    translate(atx.x, atx.y, atx.z);
    line(0, 0, 0, aty.x, aty.y, aty.z);
    translate(aty.x, aty.y, aty.z);
    line(0, 0, 0, atz.x, atz.y, atz.z);
    pop();
  }
}

void main_keyPressed(float e) {  // called from pts void mouseWheel(MouseEvent event) {
  float speed = 0.056;
  if ( keyPressed && key == 'x' ) { 
    angbx += e * speed;
    if ( abs(angbx) > TAU ) angbx = 0;
    println(" key x: angbx "+int(degrees(angbx)));
  }
  if ( keyPressed && key == 'y' ) { 
    angby += e * speed;
    if ( abs(angby) > TAU ) angby = 0;
    println(" key y: angby "+int(degrees(angby)));
  }
  if ( keyPressed && key == 'z' ) { 
    angbz += e * speed;
    if ( abs(angbz) > TAU ) angbz = 0;
    println(" key z: angbz "+int(degrees(angbz)));
  }
  if (  keyPressed && key == 'r' ) {
    angbx=angby=angbz=0;
    println("reset");
  }
  if ( axprint ) {
    println("a"+a);
    println("atx"+atx);
    println("aty"+aty);
    println("atz"+atz);
    println("at"+at);
  }
}

// tab ptz

int mode = 0;
float Zmag = 2;
int Zaxis=-100;                                                       
float Xmag, Ymag = 0;
float newXmag, newYmag = 0; 
int newZmag = 0;
float newxpos, newypos = 0;       // for PAN
float xposd, yposd = 0;           // for PAN

//_________________________________________________________________ ROTATE / TILDE and MOVE / PAN
void mousePressed() {
  if      (mouseButton == LEFT)   mode=1;  // ORBIT
  else if (mouseButton == RIGHT)  mode=2;  // PAN
  // else if (mouseButton == CENTER) mode=3;  // zoom mouse wheel
}

//_________________________________________________________________ mouse PT end
void mouseReleased() { 
  mode = 0;
}

//_________________________________________________________________ mouseWheel ZOOM
void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  //println(e);
  if ( !keyPressed ) {
    float newZmag = event.getCount()/3.0; 
    Zmag += newZmag;
    //println("mouse event: "+newZmag+" Zmag "+Zmag);
  }
  main_keyPressed(e);                                        // from main
}

//_______________________________________________ OPERATION
void keyPressed() {
  if ( keyCode == UP   )   Ymag -= 0.1 ;
  if ( keyCode == DOWN )   Ymag += 0.1 ; 
  if ( keyCode == RIGHT)   Xmag -= 0.1 ; 
  if ( keyCode == LEFT )   Xmag += 0.1 ;
  if ( keyCode == 16 )     Zmag -= 0.2 ;  // [Page Down]
  if ( keyCode == 11 )     Zmag += 0.2 ;  // [Page Up  ]
  //println("key: "+key); println("keyCode: "+keyCode);
}

//_______________________________________________
void keyReleased() {
}

//________________________________________________ Pan Tilde Zoom
void PTZ() {
  pushMatrix(); 
  translate(width/2, height/2, Zaxis);
  // get new mouse operation  
  if ( mode == 2 ) {                              // PAN ( right mouse button pressed)
    xposd = (mouseX-float(width/2));
    yposd = (mouseY-float(height/2));
  }  
  newxpos = xposd;// xposd=0;
  newypos = yposd;// yposd = 0; 
  translate(newxpos, newypos, 0);          // move object
  if ( mode == 1 ) {  // ORBIT ( left mouse button pressed)
    newXmag = mouseX/float(width) * TWO_PI;
    newYmag = mouseY/float(height) * TWO_PI;

    float diff = Xmag-newXmag;
    if (abs(diff) >  0.01)   Xmag -= diff/4.0;
    diff = Ymag-newYmag;
    if (abs(diff) >  0.01)   Ymag -= diff/4.0;
  }
  rotateX(-Ymag);   
  rotateY(-Xmag);   
  scale(Zmag);
  draw_object();                                // THE OBJECT
  popMatrix();
}

//_______________________________________________ SETUP PRINT INFO
void info_print() {
  println("PTZ info:");
  println("key UP DOWN RIGHT LEFT -> rotate // key PAGE UP DOWN -> zoom");
  println("mouse LEFT press drag up down right left -> rotate");
  println("mouse RIGHT press -> move ");
  println("mouse WHEEL turn -> zoom");
}
//_______________________________________________

yes, the code is lengthy,
but the rotation part not,

  • only the axis / axis components / move vector / part
  • MouseWheel Plus Plus operation ( x y z invisible slider )
  • and the Pan-tilt-zoom (PTZ) operation/show makes it long.

same trick used here Intersection between point and plane in 3D or more already

interesting

PTZ is for “Pan–tilt–zoom camera” ?

2 Likes

Nice that you figured out your own rotate function! :slight_smile: If you need such methods another option is to use Vec3D from toxiclibs (instead of PVector). It implements rotations and much more. https://github.com/postspectacular/toxiclibs/blob/master/src.core/toxi/geom/Vec3D.java

4 Likes