I wrote a code that should turn a point around another point counterclockwise. But it does not work correctly.
public boolean contains(double x, double y) {
double ox = this.x.get() + (this.width.get()/2);
double oy = this.y.get() + (this.height.get()/2);
double theta = rotate.get() - (rotate.get() * 2);
double px1 = Math.cos(theta) * (x-ox) - Math.sin(theta) * (y-oy) + ox;
double py1 = Math.sin(theta) * (x-ox) + Math.cos(theta) * (y-oy) + oy;
return shape.contains(px1, py1);
}
x, y - are the coordinates of the point to be rotated.
ox,oy - is the coordinates of the point around which you want to rotate.
rotate.get() - angle to rotate
Update: Changes in the code that solved the problem, who can come in handy:
double px1 = Math.cos(Math.toRadians(theta)) * (x-ox) - Math.sin(Math.toRadians(theta)) * (y-oy) + ox;
double py1 = Math.sin(Math.toRadians(theta)) * (x-ox) + Math.cos(Math.toRadians(theta)) * (y-oy) + oy;
Please check, if your rotate.get() will give you a degrees value (e.g. 45°) or a radians value (e.g. 0.5*pi). Math.sin() and Math.cos() will only accept radians.
To convert them you could use something like angle = Math.toRadians(45)
Although this is answered, another simple way to get this done is using the built-in method of Rotate class. This way you dont need to worry about the Math stuff ;)
Rotate r = new Rotate();
r.setPivotX(ox);
r.setPivotY(oy);
r.setAngle(angleInDegrees);
Point2D point = r.transform(new Point2D(x, y));
Related
my math isnt too great but im trying to learn though..
What im trying to do is give my games missiles a helix rocket effect, but i dont know how to work the Sin and Cos to make the helix play out in the right direction..
This is a 3D game by the way:
The problem is, depending on which direction the missile faces, the helix looks warped or flat..
Whats the best way to mathematically calculate a helix based on the missiles X,Y,Z/direction?, ive been trying to figure it out for a long time :/
Thanks alot!
double x = radius * Math.cos(theta);
double y = radius * Math.sin(theta);
double z = radius * Math.cos(theta);
location.add(x,y,z);
missile.shootFlame(location,2);
location.subtract(x,y,z);
Basis vectors
you need the overall direction of missile as 3D vector let call it W. From it you need to get 2 another vectors U,V which are all perpendicular to each other. To get them you can exploit cross product. So:
make W unit vector
Just W = W/|W| so:
l=sqrt(Wx*Wx+Wy*Wy+Wz*Wz);
Wx/=l;
Wy/=l;
Wz/=l;
choose U as any direction non parallel to W
so start with U=(1.0,0.0,0.0) and if U==W choose U=(0.0,1.0,0.0). If you got anything to lock to use that as U direction so the coordinate system will not rotate with time (like Up,North,Sun ...)
U should be unit so if not normalize it just like in #1
compute V
It should be perpendicular to U,W so use cross product:
V = W x U
Cross product of unit vectors is also unit vector so no need to normalize.
recompute U
As we choose the U manually we need to make sure it is also perpendicular to V,W so:
U = V x W
Now we have 3 perpendicular basis vectors where U,V lies in plane of the helix screws and W is the overall movement direction.
If you do not know how to compute the cross product see:
Understanding 4x4 homogenous transform matrices look for [edit2].
Now the Helix is easy:
Defines
so we have U,V,W on top of that we need radius r [units], movement speed v [units/s], angular speed o [rad/s] time t>=0.0 [s] and start position P0.
Helix equation
What we need is equation returning actual position for time so:
ang = o*t;
P(t) = P0 + U*r*cos(ang) + V*r*sin(ang) + W*v*t;
rewritten to scalars:
ang = o*t;
x = P0x + Ux*r*cos(ang) + Vx*r*sin(ang) + Wx*v*t;
y = P0y + Uy*r*cos(ang) + Vy*r*sin(ang) + Wy*v*t;
z = P0z + Uz*r*cos(ang) + Vz*r*sin(ang) + Wz*v*t;
[edit1] as you are incompetent to copy paste and or changing my code correctly...
Vector w = loc.getDirection();
double wX = w.getX();
double wY = w.getY();
double wZ = w.getZ();
double l = Math.sqrt((wX * wX) + (wY * wY) + (wZ * wZ));
wX = wX / l;
wY = wY / l;
wZ = wZ / l;
w = new Vector(wX,wY,wZ); // you forget to change W and use it latter ...
Vector u = new Vector(0, 1.0, 0);
if (Math.abs(wX)<1e-3) // if U and W are the same chose different U
if (Math.abs(wZ)<1e-3)
u = new Vector(1.0, 0.0, 0);
Vector v = w.crossProduct(u);
u = v.crossProduct(w);
double radius = 10; // helix radius [units]
double speed = 2.00; // movement speed [unit/s]
double omega = 0.628; // angular speed [rad/s]
//double omega = 36.0; // angular speed [deg/s]
for (double i = 0; i < 100; i += 1.0) // time [s]
{
double angle = omega * i; // actual screw position [rad] or [deg]
double x = u.getX() * radius * Math.cos(angle) + v.getX() * radius * Math.sin(angle) + wX * speed * i;
double y = u.getY() * radius * Math.cos(angle) + v.getY() * radius * Math.sin(angle) + wY * speed * i;
double z = u.getZ() * radius * Math.cos(angle) + v.getZ() * radius * Math.sin(angle) + wZ * speed * i;
loc.add(x,y,z); // What is this? should not you set the x,y,z instead of adding?
//do work
loc.subtract(x,y,z); // what is this?
}
This should provide you with helix points with traveled linear distance
speed*imax = 2.0*100.0 = 200.0 units
And screws:
omega*imax/(2*Pi) ~= 0.628*100.0/6.28 ~= 10 screws // in case of sin,cos want [rad]
omega*imax/360.0 = 36.0*100.0/360 = 10.0 screws // in case of sin,cos want [deg]
Do not forget to rem in/out the correct omega line (I choose [rad] as that is what I am used that my math libs use). Not sure If I translated to your environment correctly there may be bugs like abs has different name or u = new Vector(1.0, 0.0, 0); can be done on intermediate or declaration of variable only etc which I do not know as I do not code in it.
I know there are lots of questions and answers about this topic or related but i've beenn trying for 2 hours and still haven't benn able to figure it.
I would like to get a function that looks like this:
public static Vector rotateVector(Vector v, Vector axis, double angle){
}
Where the axis is a unit vector that defines the plane of rotation (the vector v rotates towards the vector axis if angle is positive)
I have already taken a look at rotation matrices but haven't been able to implement those to the above function
Rotating (x, y, z) counter clockwise around unit vector (u, v, w) by angle theta produces a vector (xPrime, yPrime, zPrime):
double xPrime = u*(u*x + v*y + w*z)*(1d - Math.cos(theta))
+ x*Math.cos(theta)
+ (-w*y + v*z)*Math.sin(theta);
double yPrime = v*(u*x + v*y + w*z)*(1d - Math.cos(theta))
+ y*Math.cos(theta)
+ (w*x - u*z)*Math.sin(theta);
double zPrime = w*(u*x + v*y + w*z)*(1d - Math.cos(theta))
+ z*Math.cos(theta)
+ (-v*x + u*y)*Math.sin(theta);
Source here.
Got it, thanks #Chris K. Here is the java function:
public static Vector rotateVectorCC(Vector vec, Vector axis, double theta){
double x, y, z;
double u, v, w;
x=vec.getX();y=vec.getY();z=vec.getZ();
u=axis.getX();v=axis.getY();w=axis.getZ();
double xPrime = u*(u*x + v*y + w*z)*(1d - Math.cos(theta))
+ x*Math.cos(theta)
+ (-w*y + v*z)*Math.sin(theta);
double yPrime = v*(u*x + v*y + w*z)*(1d - Math.cos(theta))
+ y*Math.cos(theta)
+ (w*x - u*z)*Math.sin(theta);
double zPrime = w*(u*x + v*y + w*z)*(1d - Math.cos(theta))
+ z*Math.cos(theta)
+ (-v*x + u*y)*Math.sin(theta);
return new Vector(xPrime, yPrime, zPrime);
}
However, I will keep the check on Chris' answer.
This is the correct way to rotate a vector.
private Vector rotateZ(Vector vector,double angle) { // angle in radians
//normalize(vector); // No need to normalize, vector is already ok...
float x1 = (float)(vector.x * Math.cos(angle) - vector.y * Math.sin(angle));
float y1 = (float)(vector.x * Math.sin(angle) + vector.y * Math.cos(angle)) ;
return new Vector(x1, y1);
}
If you want the rotation for x,y and z axis then you should use rotation matrices all at once.
NewVector = [Rotation_X][Rotation_Y][Rotation_Z]*OldVector
Here Rotation_X,Rotation_Y and Rotation_Z are 3x3 matrices. (You can see http://mathworld.wolfram.com/RotationMatrix.html)
The order of multiplication depends on the problem but i guess you want only one-axis rotation (i.e. the other 2 matrices become identity matrices)
So just putting an if-block you can set the correct matrix, and leave the rest as identity matrices.
Hope this helps.
I'm programming a software renderer in Java, and am trying to use Z-buffering for the depth calculation of each pixel. However, it appears to work inconsistently. For example, with the Utah teapot example model, the handle will draw perhaps half depending on how I rotate it.
My z-buffer algorithm:
for(int i = 0; i < m_triangles.size(); i++)
{
if(triangleIsBackfacing(m_triangles.get(i))) continue; //Backface culling
for(int y = minY(m_triangles.get(i)); y < maxY(m_triangles.get(i)); y++)
{
if((y + getHeight()/2 < 0) || (y + getHeight()/2 >= getHeight())) continue; //getHeight/2 and getWidth/2 is for moving the model to the centre of the screen
for(int x = minX(m_triangles.get(i)); x < maxX(m_triangles.get(i)); x++)
{
if((x + getWidth()/2 < 0) || (x + getWidth()/2 >= getWidth())) continue;
rayOrigin = new Point2D(x, y);
if(pointWithinTriangle(m_triangles.get(i), rayOrigin))
{
zDepth = zValueOfPoint(m_triangles.get(i), rayOrigin);
if(zDepth > zbuffer[x + getWidth()/2][y + getHeight()/2])
{
zbuffer[x + getWidth()/2][y + getHeight()/2] = zDepth;
colour[x + getWidth()/2][y + getHeight()/2] = m_triangles.get(i).getColour();
g2.setColor(m_triangles.get(i).getColour());
drawDot(g2, rayOrigin);
}
}
}
}
}
Method for calculating the z value of a point, given a triangle and the ray origin:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double d = -(A * triangle.getV1().x + B * triangle.getV1().y + C * triangle.getV1().z);
double rayZ = -(A * rayOrigin.x + B * rayOrigin.y + d) / C;
return rayZ;
}
Method for calculating if the ray origin is within a projected triangle:
private boolean pointWithinTriangle(Triangle triangle, Point2D rayOrigin)
{
Vector2D v0 = new Vector2D(triangle.getV3().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v1 = new Vector2D(triangle.getV2().projectPoint(modelViewer), triangle.getV1().projectPoint(modelViewer));
Vector2D v2 = new Vector2D(rayOrigin, triangle.getV1().projectPoint(modelViewer));
double d00 = v0.dotProduct(v0);
double d01 = v0.dotProduct(v1);
double d02 = v0.dotProduct(v2);
double d11 = v1.dotProduct(v1);
double d12 = v1.dotProduct(v2);
double invDenom = 1.0 / (d00 * d11 - d01 * d01);
double u = (d11 * d02 - d01 * d12) * invDenom;
double v = (d00 * d12 - d01 * d02) * invDenom;
// Check if point is in triangle
if((u >= 0) && (v >= 0) && ((u + v) <= 1))
{
return true;
}
return false;
}
Method for calculating surface normal of a triangle:
private Vector3D getNormal(Triangle triangle)
{
Vector3D v1 = new Vector3D(triangle.getV1(), triangle.getV2());
Vector3D v2 = new Vector3D(triangle.getV3(), triangle.getV2());
return v1.crossProduct(v2);
}
Example of the incorrectly drawn teapot:
What am I doing wrong? I feel like it must be some small thing. Given that the triangles draw at all, I doubt it's the pointWithinTriangle method. Backface culling also appears to work correctly, so I doubt it's that. The most likely culprit to me is the zValueOfPoint method, but I don't know enough to know what's wrong with it.
My zValueOfPoint method was not working correctly. I'm unsure why :( however, I changed to a slightly different method of calculating the value of a point in a plane, found here: http://forum.devmaster.net/t/interpolation-on-a-3d-triangle-using-normals/20610/5
To make the answer here complete, we have the equation of a plane:
A * x + B * y + C * z + D = 0
Where A, B, and C are the surface normal x/y/z values, and D is -(Ax0 + By0 + Cz0).
x0, y0, and z0 are taken from one of the vertices of the triangle. x, y, and z are the coordinates of the point where the ray intersects the plane. x and y are known values (rayOrigin.x, rayOrigin.y) but z is the depth which we need to calculate. From the above equation we derive:
z = -A / C * x - B / C * y - D
Then, copied from the above link, we do:
"Note that for every step in the x-direction, z increments by -A / C, and likewise it increments by -B / C for every step in the y-direction.
So these are the gradients we're looking for to perform linear interpolation. In the plane equation (A, B, C) is the normal vector of the plane.
It can easily be computed with a cross product.
Now that we have the gradients, let's call them dz/dx (which is -A / C) and dz/dy (which is -B / C), we can easily compute z everywhere on the triangle.
We know the z value in all three vertex positions.
Let's call the one of the first vertex z0, and it's position coordinates (x0, y0). Then a generic z value of a point (x, y) can be computed as:"
z = z0 + dz/dx * (x - x0) + dz/dy * (y - y0)
This found the Z value correctly and fixed my code. The new zValueOfPoint method is:
private double zValueOfPoint(Triangle triangle, Point2D rayOrigin)
{
Vector3D surfaceNormal = getNormal(triangle);
double A = surfaceNormal.x;
double B = surfaceNormal.y;
double C = surfaceNormal.z;
double dzdx = -A / C;
double dzdy = -B / C;
double rayZ = triangle.getV1().z * modelViewer.getModelScale() + dzdx * (rayOrigin.x - triangle.getV1().projectPoint(modelViewer).x) + dzdy * (rayOrigin.y - triangle.getV1().projectPoint(modelViewer).y);
return rayZ;
}
We can optimize this by only calculating most of it once, and then adding dz/dx to get the z value for the next pixel, or dz/dy for the pixel below (with the y-axis going down). This means that we cut down on calculations per polygon significantly.
this must be really slow
so much redundant computations per iteration/pixel just to iterate its coordinates. You should compute the 3 projected vertexes and iterate between them instead look here:
triangle/convex polygon rasterization
I dislike your zValueOfPoint function
can not find any use of x,y coordinates from the main loops in it so how it can compute the Z value correctly ?
Or it just computes the average Z value per whole triangle ? or am I missing something? (not a JAVA coder myself) in anyway it seems that this is your main problem.
if you Z-value is wrongly computed then Z-Buffer can not work properly. To test that look at the depth buffer as image after rendering if it is not shaded teapot but some incoherent or constant mess instead then it is clear ...
Z buffer implementation
That looks OK
[Hints]
You have too much times terms like x + getWidth()/2 why not compute them just once to some variable? I know modern compilers should do it anyway but the code would be also more readable and shorter... at least for me
I asked about this yesterday as well and was told that I needed to be using radians. I had assumed that was the answer but there does appear to be another problem with the code below. I am trying to write a method which will allow my Gladiators to rotate a central point between the two, to circle each other so to speak. Below is my code. Gladiator variable target is of Gladiator type and is set to the second party in the rotation. center[0] is the x location, center[1] is y.
public void rotate(Gladiator a, int angle) {
double x1;
double y1;
double x2;
double y2;
double r;
double midx;
double midy;
int currentAngle;
r = getDistance(a,a.target)/2;
midx = (a.center[0]-a.target.center[0])/2;
midy = (a.center[1]-a.target.center[1])/2;
currentAngle = (int)Math.toDegrees(Math.atan2(a.center[1] - midy, a.center[0] - midx));
x1 = Math.cos(Math.toRadians(currentAngle+angle)) * r;
y1 = Math.sin(Math.toRadians(currentAngle+angle)) * r;
x2 = Math.cos(Math.toRadians(currentAngle+angle)) * -r;
y2 = Math.sin(Math.toRadians(currentAngle+angle)) * -r;
a.move((int)x1,(int)y1);
a.target.move((int)x2,(int)y2);
}
Anyone see anything wrong with this? At the moment they end up meeting towards what I would think would be the middle of my circle, waaay closer than they were. Any thoughts?
Edit: Also, I am currently running this twice... once for each Gladiator involved. I can do that and just have them rotate half the desired amount each time, but it would be better if I could rotate them as a whole then disinclude the second party from the Gladiator list I am iterating through. What would be the most simple implementation of this?
Edit2: I think part of my problem was that I wasn't calling Math.toDegrees on my atan2 equation. I noticed it wasn't getting any new angle value other than 0, now it is. Still, there is something wrong. They rotate from horizontal to vertical but are moving much further from each other on each rotation and once they get to the vertical alignment they end up rotating the other direction just a few degrees (rather than 45, my current input) and then do get much closer together like before.
Edit3: Note that the move method's parameters are the change needed, not the actual coordinates.
I see you are using int a lot, be very careful since you may get stuck depending on angle.
I did a quick rewrite to simplify your repetition and use the radian logic that was recommended. (Untested).
I also converted your locations to double to avoid odd integer arithmetic problems. (Your midx/midy calculations were in int math)
After finishing I realized you were rotating around (0,0) rather than the midpoint, and your mid variables were confusingly named.
//I would do double inline with the initialization, but left here in case you had another reason
double x1,y1, x2,y2, r, midx,midy, newAngle;
x1 = a.center[0];
y1 = a.center[1];
x2 = a.target.center[0];
y1 = a.target.center[1];
r = getDistance(a, a.target)/2;
midx = x1 + (x2 - x1)/2;
midy = y1 + (y2 - y1)/2;
newAngle = Math.toRadians(angle) +
Math.atan2(midy, midx);
x1 = Math.cos(newAngle) * r + midx;
y1 = Math.sin(newAngle) * r + midy;
x2 = Math.cos(newAngle) * -r + midx;
y2 = Math.sin(newAngle) * -r + midy;
a.move((int)x1,(int)y1);
a.target.move((int)x2,(int)y2);
I have this method for rotating points in 3D using quaternions, but it seems not to work properly:
public static ArrayList<Float> rotation3D(ArrayList<Float> points, double angle, int xi, int yi, int zi)
{
ArrayList<Float> newPoints = new ArrayList<>();
for (int i=0;i<points.size();i+=3)
{
float x_old = points.get(i);
float y_old = points.get(i+1);
float z_old = points.get(i+2);
double w = Math.cos(angle/2.0);
double x = xi*Math.sin(angle/2.0);
double y = yi*Math.sin(angle/2.0);
double z = zi*Math.sin(angle/2.0);
float x_new = (float) ((1 - 2*y*y -2*z*z)*x_old + (2*x*y + 2*w*z)*y_old + (2*x*z-2*w*y)*z_old);
float y_new = (float) ((2*x*y - 2*w*z)*x_old + (1 - 2*x*x - 2*z*z)*y_old + (2*y*z + 2*w*x)*z_old);
float z_new = (float) ((2*x*z + 2*w*y)*x_old + (2*y*z - 2*w*x)*y_old + (1 - 2*x*x - 2*y*y)*z_old);
newPoints.add(x_new);
newPoints.add(y_new);
newPoints.add(z_new);
}
return newPoints;
}
If i make this call rotation3D(list, Math.toRadians(90), 0, 1, 0); where points is (0,0,10), the output is (-10.0, 0.0, 2.220446E-15), but it should be (-10,0,0), right? Could someone take a look at my code and tell me if is there somethig wrong?
Here are 4 screens that represent the initial position of my object, and 3 rotations with -90 degrees (the object is not properly painted, that's a GL issue, that i will work on later):
I haven't studied the code but what you get from it is correct: Assuming a left-handed coordinate system, when you rotate the point (0,0,10) 90 degrees around the y-axis (i.e. (0,1,0)) you end up with (-10,0,0).
If your coordinate system is right-handed I think you have to reverse the sign of the angle.