views:

83

answers:

2

I am trying to rotate vectors using matrices, but got confused.

I thought all I needed to do is create a rotation matrix and multiply it to a vector to get the rotated vector.

Here you can see a simple test I've done using Processing:

processing text

Use a to increment rotation, and x/y/z to changes the axis.

And here is source:

PVector[] clone,face = {new PVector(50,0,50),new PVector(-50,0,50),new PVector(-50, 0, -50),new PVector(50, 0, -50)};
color faceC = color(255,0,0),cloneC = color(0,255,0);
float angle = 90;
PVector x = new PVector(1,0,0),y = new PVector(0,1,0),z = new PVector(0,0,1), axis = x;
PFont ocr;

void setup(){
  size(400,400,P3D);
  strokeWeight(1.1610855);smooth();
  clone = rotateVerts(face,angle,axis);
  ocr = loadFont("ocr.vlw");
}
void draw(){
  background(255);
  fill(0);textFont(ocr,10);text("a = increment rotation\nx/y/z = change axis\nrotation: " + angle + "\naxis: " + axis,10,10,200,200);fill(255);
  translate(width*.5,height*.5);
  rotateX(map(mouseY,height*.5,-height*.5,0,TWO_PI));
  rotateY(map(mouseX,0,width,0,TWO_PI));
    drawQuad(face,faceC);
    drawQuad(clone,cloneC);
  stroke(128,0,0);line(0,0,0,100,0,0);stroke(0,128,0);line(0,0,0,0,-100,0);stroke(0,0,128);line(0,0,0,0,0,100);
}
void keyPressed(){
  if(key == 'a') angle += 15;
  if(angle > 360) angle -= 360;
  if(key == 'x') axis = x;
  if(key == 'y') axis = y;
  if(key == 'z') axis = z;
  clone = rotateVerts(face,angle,axis);
}
PVector[] rotateVerts(PVector[] verts,float angle,PVector axis){
  int vl = verts.length;
  PVector[] clone = new PVector[vl];
  for(int i = 0; i<vl;i++) clone[i] = PVector.add(verts[i],new PVector());
  //rotate using a matrix
  PMatrix3D rMat = new PMatrix3D();
  rMat.rotate(radians(angle),axis.x,axis.y,axis.z);
  for(int i = 0; i<vl;i++) rMat.mult(clone[i],clone[i]);
  return clone;
}
void drawQuad(PVector[] verts,color c){
  stroke(c);
  beginShape(QUADS);
    for(int i = 0 ; i < 4; i++) vertex(verts[i].x,verts[i].y,verts[i].z);
  endShape();
}

Processing comes with a PVector and PMatrix3D which I've used.

Am I not using PMatrix they it should be used or is this a bug ? Any hints ?

+2  A: 

This is the culprit:

rMat.mult(clone[i],clone[i]);

this is not safe to do, because unlike in C or JAVA, the source is changing as the operation proceeds.

changing the end of the function to:

PVector[] dst = new PVector[vl];
for(int i = 0; i<vl;i++) dst[i] = new PVector();
for(int i = 0; i<vl;i++) rMat.mult(clone[i],dst[i]);
return dst;

will resolve the issue.

Knyphe
That's it! woo hoo! Thanks!
George Profenza
+2  A: 

Instead of PVector, you could also use the toxiclibs geometry classes, which would help to simplify the whole syntax quite a bit:

import toxi.geom.*;

Vec3D[] rotateVerts(Vec3D[] verts, float angle, Vec3D axis){
  Vec3D[] clone = new Vec3D[verts.length];
  for(int i = 0; i<verts.length;i++)
    clone[i] = verts[i].getRotatedAroundAxis(axis,angle);
  return clone;
}

Or using a matrix to do the transform:

Vec3D[] rotateVerts(Vec3D[] verts, float angle, Vec3D axis){
  Matrix4x4 mat=new Matrix4x4();
  mat.rotateAroundAxis(axis,angle);
  Vec3D[] clone = new Vec3D[verts.length];
  for(int i = 0; i<verts.length;i++) clone[i] = mat.applyTo(verts[i]);
  return clone;
}

The latter will be slightly slower for just a simple axis rotation, but makes more sense if you also do other transformations at the same time (e.g. translate etc.). Also, in both cases, the angle is assumed to be in radians...

Hope that helps!

toxi
@toxi Very nice! Thank you! I was looking through the docs(https://dev.postspectacular.com/docs/core/toxi/geom/Vec3D.html#headingXY()) and found headingXY, XZ, YZ which are quite handy. If I've got 4 vertices and a normal, how can I get the rotation on the Z axis ? If I use the heading methods on the normal, Z will always be the same, because I'm dealing with 1 vertex. Any hints ?
George Profenza