After a long time, I try to use JAVA again. I'm using the vectmath package, with which I'd like to rotate a 3d vector with a rotation matrix. So I wrote that:
double x=2, y=0.12;
Matrix3d rotMat = new Matrix3d(1,0,0, 0,1,0, 0,0,1); //identity matrix
rotMat.rotX(x); //rotation on X axis
rotMat.rotY(y); // rotation on Y axis
System.out.println("rot :\n" + rotMat); // diagonal shouldn't have 1 value on it
result:
rot :
0.9928086358538663, 0.0, 0.11971220728891936
0.0, 1.0, 0.0
-0.11971220728891936, 0.0, 0.9928086358538663
Unfortunately, it doesn't give me what I expected. It is like he ignored the first rotation (around X) and only take the second one (around Y).
If I comment the rotMat.rotX(x); it gives me the same result.
I suspect either a mistake with the print, or with variable management.
Thanks
Methods rotX and rotY set/overwrite the matrix elements, so your subsequent call to rotY(y) cancels the call to rotX(x). Something like this should work:
Vector3d vector = ... //a vector to be transformed
double x=2, y=0.12;
Matrix3d rotMat = new Matrix3d(1,0,0, 0,1,0, 0,0,1); //identity matrix
rotMat.rotX(x); //rotation on X axis
rotMat.transform(vector);
rotMat.rotY(y); // rotation on Y axis
rotMat.transform(vector);
// the vector should now have both x and y rotation
// transformations applied
System.out.println("Rotated vector :\n" + vector);
Related
I am currently playing around with Opengl and I'm trying to create a class that can automatically calculate the vertex buffer data and element buffer data for a polygon.
Here is the code for creating the vertex data:
float centerangle = (float)(2*Math.PI / sides);
ArrayList verticies = new ArrayList<Float>();
for (int i=0; i<sides; i++) {
float angle = (i*centerangle);
float x = (float)Math.round(Math.cos(ang))/2f;
float y = (float)Math.round(Math.sin(ang))/2f;
float z = 0.0f;
verticies.add(x);
verticies.add(y);
verticies.add(z);
}
return verticies;
Given that sides == 5 this method creates the following values:
float[] {
0.5, 0.0, 0.0,
0.0, 0.5, 0.0,
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.0, -0.5, 0.0
}
I'm trying to create a method that will now generate the element buffer data. As of right now i have it hard coded. As an example, for the pentagon the element buffer data looks like this:
new int[] {
1,2,3,
3,1,4,
0,1,4
};
This creates 3 triangles like so
So my question is is there a way i can calculate the element buffer data for any polygon that my method creates? What would that look like?
For convex polygon you can use simple method - choose three top vertices, make triangle, then at every step make new triangle geting the topmost unused vertex (strip triangles up to down). Also fan triangulation.
If polygon might be concave, you need more sophisticated approaches for polygon triangulation (note this is not the same as point cloud triangulation). Wiki page describes some algorithms in short.
Arbitrary found examples of Java implementation of ear-clipping: one, two
how to calculate distance betweeen smartphone camera and artoolkit marker.
i tried to get it from transformation matrix of marker but the vector value are all zero.
float [] pMatrix = ARToolKit.getInstance().getProjectionMatrix();
float x = pMatrix[3];
float y = pMatrix[7];
float z = pMatrix[11];
x, y , z are all zero.
I think you are looking at the wrong positions in the matrix. The camera x,y,z is inside the last column of the transformation matrix:
queryMarkerTransformation(int markerId);
Returns float array with 16 values. The values represent an OpenGL style transformation matrix.
The first 4 values represent the first column of the matrix.
i.e:
float[16] = [0.24218401, 0.9598883, 0.14125957, 0.0, -0.8614648, 0.2801126, -0.42357886, 0.0, -0.44614935, -0.019116696, 0.8947546, 0.0, 23.678268, -6.4265084, -298.65326, 1.0]
The matrix looks like:
0.24218401 -0.8614648 -0.44614935 23.678268
0.9598883 0.2801126 -0.019116696 -6.4265084
0.14125957 -0.42357886 0.8947546 -298.65326
0.0 0.0 0.0 1.0
The last column represents x,y,z in the camera coordinate system.
The source for that is here: https://www.hitl.washington.edu/artoolkit/documentation/tutorialcamera.htm I believe. (But somehow I cannot reach the url right now)
Now you are also reading the projection matrix, not the transformation matrix.
(https://github.com/artoolkit/artoolkit5/blob/master/AndroidStudioProjects/ARSimpleProj/aRSimple/src/main/java/org/artoolkit/ar/samples/ARSimple/SimpleRenderer.java#L98)
If I tracked that down correctly value [14] should give you the distance to the marker.
Update:
I just wrote down a more detailed explanation here:
http://augmentmy.world/artoolkit-distance-between-camera-and-marker
I want to use the heading() function in the PVector class, but I am using P3D and have an x,y,and z for my PVector. How would I re-write this function to allow it to work for 3D space? My goal is to do something like:
size(100, 100, P3D);
PVector v = new PVector(.2, .11, .54);
rotate( v.heading() ); //set rotation from PVector named v
line(0, 0, 10, 0); //draw line that will be rotated in correct direction
The above code doesn't display the correct rotation in 3D space since v.heading() is only suited for 2D coordinate space. How can I achieve this using rotateX(), rotateY(), rotateZ()? I'd like to avoid using a quaternion if possible and use the rotate functions.
Thanks in advance!!
Using the heading() function in 2D is transforming 2D Cartesian coordinates (x,y) into 2D polar coordinates (radius, angle). A 3D version of polar coordinates is spherical coordinates:
The 3D point P can be represented as three linear coordinates (x,y,z) or one linear coordinate and two angles (rho, theta, phi). Rho is the length of the vector, theta is the angle in the x-y plane, and phi is the angle in the angle into the z plane. These equations describe the conversion:
rho = sqrt(x^2 + y^2 + z^2)
phi = arccos(z/rho)
theta = arctan(y/x)
You should be able to use the rotateX(), etc functions using these angles. Note that this uses the mathematics convention for the angle names theta and phi; in physics, these labels are reversed from what's shown above.
What kevinsa5 said, except use the inverse sine function to get the elevation. Use the atan2 function for the azimuth (or better, simply use the vector's 2D heading method). And use the vector's mag method for its magnitude.
rho = v.mag();
phi = asin(v.z/rho);
theta = atan2(v.y, v.x);
Working backwards, think "X - Y - Z" and try:
PVector p = new PVector(v.mag(), 0, 0); // X
rotateY3D(p, phi); // Y
rotateZ3D(p, theta); // Z
Then compare p with the original v.
it seems that there is a problem with my custom Quaternion implementation.
Download My quaternion implementation in Java.
When I lauch this snippet, in order to see quaternion angle evolutions, in a Main() method :
Quaternion currentRotation = Quaternion.buildIdentityQuaternion();
Quaternion constantRotation = Quaternion.buildFromAxisAngle(10, 0,1,0);
while(true){
float angle = currentRotation.toAxisAngle()[0];
System.out.println(angle);
currentRotation = constantRotation.mulInLeftOf(currentRotation);
}
I've got the following results :
0.0
9.99997
19.999975
29.999979
39.99998
49.999977
59.999977
69.99998
79.99997
89.99997
99.99997
109.99997
119.99997
129.99997
139.99997
149.99997
159.99997
169.99997
179.99997
189.99998
199.99998
209.99998
219.99998
230.0
240.0
250.00002
260.00003
270.00003
280.00003
290.00006
300.0001
310.00012
320.00015
330.00024
340.00037
350.00082
360.0
350.00012
340.0001
330.0001
320.0001
310.00006
300.00006
290.00006
So why does the angle value first goes to 360 degrees then decreases toward 0 ? Though I've computed the angle with the formula 2*Acos(Quaternion.w) in Quaternion#toAxisAngle() method ? Maybe the implementation is not bad, so how can I compute the angle so that it returns 0, 10, ...,350, 360, 0, 10, ..., 350, 360, 0, 10 and so on ?
And finally, is there a way to compute the real angle ? SO that angle goes across values : 0,10,20,30,...,360,0,10,20... ?
However I managed to use it in a JOGL program to make a Simple 6-color cube rotate regularly, simply by computing a quaternion multiplication each time and by calling toMatrix() method on the result quaternion. What worked (do not pay attention to JOGL specific implementation details) :
// The OpenGL functionnalities of my program
MyJOGLEventListener implements GLEventListener {
Quaternion myCurrentRotation = Quaternion.buildIdentityQuaternion() // w=1, x=0, y=0, z=0
Quaternion constantRotation = Quaternion.buildFromAxisAngle(0.02f, 0,1,0) // angle = 0.02 degrees, x=0, y=1, z=0
GLUgl2 glu = new GLUgl2();
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
gl.glClear(/* OMITTED : color buffer and depth buffer*/);
gl.glLoadIdentiy();
glu.gluLookAt(/* OMITTED */);
/// the three most relevent lines ///////////////////////////////////
gl.glMultMatrix(myCurrentRotation.toMatrix(), 0);
MyCubeDrawer.drawCube(gl);
myCurrentRotation = constantRotation.mulInLeftOf(myCurrentRotation);
//////////////////////////////////////////////////////////////////////
}
// OMITED : in init(GLAutoDrawable) method, I set up depth buffer
// OMITED : the reshape(GLAutoDrawable drawable, int x, int y, int width, int height) sets the viewport and projection
}
Regards
I suspect that your quaternion implementation is fine. When you pass 360 degrees with a quaternion, it inverts the axis of rotation. So at first, your quaternion represents positive rotations around the positive y axis; however, once you cross 360 degrees, it begins to represent a positive rotation around the negative y axis.
So the angles you are getting are still correct. A rotation of zero is usually represented as [1 0 0 0]. A rotation of 180 degrees around the y axis will be represented as [0 0 1 0]. And then a rotation of 360 degrees (obviously equivalent to a rotation of 0) comes out to be [-1 0 0 0]. Rotating by another 180 degrees will give you [0 0 -1 0] This is a general property of quaternions. They're 2x redundant. If you negate all the components of the quaternion, it's equivalent to rotating the opposite direction around a flipped axis to get the same result.
To get what you wanted, you could just check the y component of your quaternion. If it's less-than-zero, then subtract your computed rotation from 360 in order to flip the axis back to positive.
I have matrix. This matrix represents array x and y coordinates. For example
float[] src = {7,1,7,2,7,3,7,4};
I need to rotate this coordinates to 90 degrees.
I use android.graphics.Matrix like this:
float[] src = {7,1,7,2,7,3,7,4};
float[] dist = new float[8];
Matrix matrix = new Matrix();
matrix.preRotate(90.0f);
matrix.mapPoints(dist,src);
after operation rotate I have array with next values
-1.0 7.0 -2.0 7.0 -3.0 7.0 -4.0 7.0
Its is good for area with 360 degrees.
And how do rotate in area from 0 to 90? I need set up center of circle in this area but how ?
Thanks.
Use setRotate, not preRotate:
setRotate initializes the matrix as a rotation matrix.
preRotate multiplies the current matrix by a rotation matrix M' =
M x R
Since you called the default constructor your starting with the identity matrix.
Remember matrix multiplication is not commutative.
I'm not familiar with android, but if you translate after you rotate you can get a rotation around a specific point. Find where your center point would be rotated to, then translate it back to it's original position.
Use the Matrix preRotate(float degrees, float px, float py) method (preRotate documenation)
This preRoate(degrees) is equivalent to preRotate(degrees, 0, 0).