I am working on a question where I am working within a right-handed coordinate system where the y-axis is straight up. I am supplied a structure that represents a 3-dimensional vector that looks like this:
struct vec{float x; float y; float z; };
I need to write a function that takes in a unit vector representing north and a unit vector represent a player's forward vector, and return if they are facing more north than south. Unfortunatly I have no idea where to go from here, I believe I have to do something like:
PlayerDirection = sqrt((PlayerVector.x *= PlayerVector.x)
+ (PlayerVector.y *= PlayerVector.y)
+ (PlayerVector.z *= PlayerVector.z));
But I do not know where to go from here. Any help/explanation would help, thanks.
apply a dot product to both vectors. The dot product will be positive if the angle between both vectors is smaller than 90 degrees, and negative otherwise.
The formula you include (and which contains an error - the product is "*", not "*=") gives you the entity of the movement - the length of the vector. Which you already know, since it is a unit vector and therefore has length 1.
You need instead to perform the dot product between the two vectors. You get 1 if the two unit vectors are completely aligned (parallel), -1 if they're antiparallel, and zero if they're normal to each other.
"More north than south" means that the scalar product is positive, so:
return if they are facing more north than south
Alignment = ((PlayerVector.x * NorthVector.x)
+ (PlayerVector.y * NorthVector.y)
+ (PlayerVector.z * NorthVector.z));
return (Alignment > 0);
Questions
What if I wanted to tell if it was facing east/west?
The dot product tells you how much two vectors are aligned. It is the same formula shown by Kevin Glasson, without the unit vectors norms since they are 1, and dividing by one doesn't change anything.
So, you can't use it to tell where a vector is facing except in terms of another vector. And that's why you're given the north vector; with the player vector alone you can't run a dot product. To tell whether the player is facing east, you need the east vector (or the west vector, and then take the opposite sign).
So if the number comes back as say 35 it means it is facing more north than south but why?
Why it is so: you can find it explained on the Wikipedia page, the dot product is equal to the product of the two lengths by the cosine of their angle. Since the lengths are both 1, it is just the cosine. The cosine varies between 1 and -1 (so you can't ever get 35). When the cosine is 1, it means that the angle is zero and the vectors are aligned; when it is -1, they're opposite. A cosine of zero means the vectors are normal to each other, i.e. form an angle of 90°, and in this case it means that the player is facing either East, West, or Up, or Down - but it doesn't tell you which.
I think what would work is taking the 'dot product' of the vectors. Using the following form:
Where you would re-arrange for theta. This would give you the angle between the two vectors.
In my mind at least if the angle was 0 then you are pointing exactly north and if the angle were greater than 90 then you were facing more south.
I don't know exactly how you intend to use this, but this should work for being able to tell North from South in 3D space.
Well you can use the dot-product to get the angle between 2 vectors. The formula is the following:
cos(phi) = (a * b) / (|a|*|b|)
Which converts to this:
phi = acos((ax*bx + ay*by + az * bz) / (sqrt(ax^2 + ay^2 + az^2)+sqrt(bx^2 + by^2 + bz^2)))
Now the dot product is symmetric, meaning: (1,1,1)(2,2,2) gives you the same result as (2,2,2)(1,1,1). Hence you have to add a further step. By adding a third vector, whose angle to the first given vector you do know, you can verify the true angle between the two vectors. Optaining this reference vector can be done by turning the first vector arround an axis, now to ensure it is a valid reference it has to be in the same plane as the vectors a and b.
This means that your axis to turn your first vector arround has to be orthogonal to vector 1 and 2, the vectorproduct of 2 vectors gives a vector orthogonal to both, so we will use the so obtained vector as axis.
axis = a x b
This is equal to:
axis = (aybz-azby, azbx-axbz, axby-aybx)
To turn a vector by a given amount arround an axis the following has to be done:
double R[3][3] = {};
Vector axis = Axis.getUnitVector();
double deg = degrees / 180 * M_PI;
R[0][0] = axis.X * axis.X * (1 - cos(deg)) + cos(deg); R[0][1] = axis.X * axis.Y * (1 - cos(deg)) - axis.Z * sin(deg); R[0][2] = axis.X * axis.Z * (1 - cos(deg)) + axis.Y * sin(deg);
R[1][0] = axis.Y * axis.X * (1 - cos(deg)) + axis.Z * sin(deg); R[1][1] = axis.Y * axis.Y * (1 - cos(deg)) + cos(deg); R[1][2] = axis.Y * axis.Z * (1 - cos(deg)) - axis.X * sin(deg);
R[2][0] = axis.Z * axis.X * (1 - cos(deg)) - axis.Y * sin(deg); R[2][1] = axis.Z * axis.Y * (1 - cos(deg)) + axis.X * sin(deg); R[2][2] = axis.Z * axis.Z * (1 - cos(deg)) + cos(deg);
double x = this->X * R[0][0] + this->Y * R[0][1] + this->Z * R[0][2];
double y = this->X * R[1][0] + this->Y * R[1][1] + this->Z * R[1][2];
double z = this->X * R[2][0] + this->Y * R[2][1] + this->Z * R[2][2];
The unitvector is defined as following:
e_a = (ax / sqrt(ax^2+ay^2+az^2),ay / sqrt(ax^2+ay^2+az^2),az / sqrt(ax^2+ay^2+az^2))
Using this new axis we can rotate our first vector a 90°. By calculating the angle between our reference and our second vector we can now evaluate the real angle between the first and second vector. If the angle to the reference is bigger than 90° the 2nd vector is in the 3rd or 4th sector or a cartesian coordinate system, meaning to get the real angle we'll have to substract our aquired angle between the first and the 2nd vector from 360°. If the angle to the reference it is smaller than 90° the calculated angle is the real angle.
Now there is another issue, what/where is north? If we know north we could just calculate the angle between north and the two vectors and the one with the smaller angle would be more north. This means there is no reason to evaluate a reference vector or build and apply the rotation matrix.
In case of a fixed north you could also project your vectors on a plane containing north, and simplify the calculations required.
Provide more information and I will edit this.
edit:/ since you provide the north and a player vector, just calculate the angle between them.
Related
I'm trying to write an algorithm to determine if point is located inside a triangle or on it's edge in 3D coordinate space.
For example, I try to reach such results for different cases
I've figured out how to check if point P inside the triangle, I calculated normal vectors for triangles ABP, BCP, CAP and checked if they are similar.
Can someone explain how to check if a point is on the edge of a triangle (but not outside of a triangle)? You can provide formulas or code as you wish.
Make vectors:
r = p - A (r.x = p.x - A.x, r.y = p.y - A.y, r.z = p.z - A.z)
s = B - A
q = C - A
Calculate normal to ABC plane:
n = s x q (vector product)
Check if p lies in ABC plane using dot product:
dp = n.dot.r
If dp is zero (or has very small value like 1.0e-10 due to the floating point errors, then p is in the plane, and we can continue
Decompose vector p by base vectors s and q. At first check if z-component of normal (n.z) is non-zero. If so, use the next pair of equations (otherwise choose equations for x/z or y/z components):
px = a * sx + b * qx
py = a * sy + b * qy
Solve this system
a = (sy * qx - sx * qy) / (py * qx - px * qy)
b = (px - a * sx) / qx
If resulting coefficients a and b fulfill limits:
a >= 0
b >= 0
a + b <= 1.0
then point p lies in triangle plane inside it.
I'm currently working on a pice of software that interpolates data from existing measurements and makes estimates from this. The data is arranged in a 2D environment where we've got a wind speed on one axis and a wind angle on the other and each point represents a target speed.
For an example I've got three points:
p1: wind speed 6 knots, wind angle 90 degrees => target speed 5
p2: wind speed 6 knots, wind angle 70 degrees => target speed 6
p3: wind speed 8 knots, wind angle 70 degrees => target speed 7
Now I want to interpolate the point of wind speed 6 knots and wind angle 80 degrees. I would like an algorithm that uses all of these points and gives me an average of these three points.
Ages ago I made a 3D renderer and I think I used a technique there to color a polygon and I think this can be useful in this scenario. All the examples that I've found on the internet rely on OpenGL and such and that won't work for me as I want this solution to be pure c/c++ for an embedded environment. Since i run in an embedded environment I've got limited resources mainly in terms of program size.
Do any of you guys have any pointers to help me get past this problem? Thanks!
After diving into my old calculus i found a mathematical answer to this problem.
Given that I've got three points in the space I can form a plane:
P: (Px, Py, Pz)
Q: (Qx, Qy, Qz)
R: (Rx, Ry, Rz)
These points and the math described in here http://tutorial.math.lamar.edu/Classes/CalcIII/EqnsOfPlanes.aspx allowed me to move forward.
Vector(PQ) = (PQx, PQy, PQz)
Vector(PR) = (PRx, PRy, PRz)
Now I apply the cross product to these two vectors and this gives the normal vector of the plane
(Cross product math described here: http://tutorial.math.lamar.edu/Classes/CalcII/CrossProduct.aspx#Vectors_CrossProd_Ex2)
Vector(PQ) x Vector(PR) = Vector(PQy * PRz - PQz * PRy,
PQz * PRx - PQx * PRz,
PQx * PRy - PQy * PRx)
So, this is what I've got as a plane equation, without respect to that it has to pass trough one of the points:
x(PQy * PRz - PQz * PRy) + y(PQz * PRx - PQx * PRz) + z(PQx * PRy - PQy * PRx) = 0
To get the full equation of my plane that passes trough all of the points, I have to apply one point, as described in example 1 in the first link.
x(PQy * PRz - PQz * PRy) + y(PQz * PRx - PQx * PRz) + z(PQx * PRy - PQy * PRx) =
Px(PQy * PRz - PQz * PRy) + Py(PQz * PRx - PQx * PRz) + Pz(PQx * PRy - PQy * PRx)
To apply my example to this formula I get the following equation:
P: (90, 6, 5)
Q: (70, 6, 6)
R: (70, 8, 7)
Vector(PQ) = (20, 0, -1)
Vector(PR) = (20, -2, -2)
Cross product of these gives me this formula:
-2x + 20y - 40z = 0
If I now apply the point P to this I can get the full equatio of my plane:
-2x + 20y - 40z = -2 * 90 + 20 * 6 - 40 * 5
-2x + 20y - 40z = -260
z = (-2x + 20y + 260) / 40
As I seek the z value where x = 6 and y = 80 I put these values into the equation.
x = 80
y = 6
z = (-2 * 80 + 20 * 6 + 260) / 40
z = 5.5
5.5 is the expected answer for this example as it exactly in the middle of P and Q.
The final implementation of this algorithm:
float TargetSpeed::PlaneInterpolation(Point3D p, Point3D q, Point3D r, int x, int y)
{
Point3D pq = Point3D(p.X - q.X, p.Y - q.Y, p.Z - q.Z);
Point3D pr = Point3D(p.X - r.X, p.Y - r.Y, p.Z - r.Z);
Point3D n = Point3D(pq.Y * pr.Z - pq.Z * pr.Y,
pq.Z * pr.X - pq.X * pr.Z,
pq.X * pr.Y - pq.Y * pr.X);
float d = n.X * p.X + n.Y * p.Y + n.Z * p.Z;
float z = (d - n.X * (float)x - n.Y * (float)y) / n.Z;
return z;
}
Is the data on a regular grid? If so, I would just use something like linear interpolation. If not, then look at something like qhull.
I'm currently working on a 3D scene which has to be rotated by dragging the mouse. To do this, I'm utilizing a ArcBall implementation.
The used framework, immediately transformed the resulting quaternion into a rotation matrix. Any subsequent rotations would also be converted into a matrix. These matrices in turn are multiplied.
I wanted to optimize this by simply multiplying the rotation quaternions. Now the scene seems to be spinning uncontrollably while the original version worked okay(ish).
My code for multiplying quaternions:
public static Quat4f mul(Quat4f q1, Quat4f q2) {
float x = q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x;
float y = -q1.x * q2.z + q1.y * q2.w + q1.z * q2.x + q1.w * q2.y;
float z = q1.x * q2.y - q1.y * q2.x + q1.z * q2.w + q1.w * q2.z;
float w = -q1.x * q2.x - q1.y * q2.y - q1.z * q2.z + q1.w * q2.w;
return new Quat4f(x,y,z,w);
}
The multiplication is done as (the result is normalized for good measure):
currentRotation = Quat4f.mul(newRotation, currentRotation);
An finally, the rotation is applied as:
glMultMatrixf(currentRotation.toMatrix());
Does anyone know what I'm doing wrong?
glMultMatrixf (...) multiplies the current matrix by the one you pass it. Now here is where things get kind of funny, you have a Quaternion that also seems to be cumulative (named currentRotation). You are accumulating the rotation in two different places.
Chances are, what you actually want is glLoadMatrixf (...). Rather than multiplying the current matrix by your rotation matrix, that will replace the matrix. You could achieve the same result by calling glLoadIdentity (...) immediately before glMultMatrixf (...); the bottom line is you need to discard any old rotation in your matrix before applying this.
It is not clear whether the behavior you are after is such that GL's matrix is reset every time it is updated or if the quaternion is reset, but you really need to reset one of the two or you will spin endlessly.
I need a method that allows me to find the Y-coordinate on a Cubic Bezier Curve, given an x-coordinate.
I've come across lots of places telling me to treat it as a cubic function then attempt to find the roots, which I understand. HOWEVER the equation for a Cubic Bezier curve is (for x-coords):
X(t) = (1-t)^3 * X0 + 3*(1-t)^2 * t * X1 + 3*(1-t) * t^2 * X2 + t^3 * X3
What confuses me is the addition of the (1-t) values. For instance, if I fill in the X values with some random numbers:
400 = (1-t)^3 * 100 + 3*(1-t)^2 * t * 600 + 3*(1-t) * t^2 * 800 + t^3 * 800
then rearrange it:
800t^3 + 3*(1-t)*800t^2 + 3*(1-t)^2*600t + (1-t)^3*100 -400 = 0
I still don't know the value of the (1-t) coefficients. How I am I supposed to solve the equation when (1-t) is still unknown?
There are three common ways of expressing a cubic bezier curve.
First x as a function of t
x(t) = sum( f_i(t) x_i )
= (1-t)^3 * x0 + 3*(1-t)^2 * t * x1 + 3*(1-t) * t^2 * x2 + t^3 * x3
Secondly y as a function of x
y(x) = sum( f_i(x) a_i )
= (1-x)^3 * y0 + 3*(1-x)^2 * x * y1 + 3*(1-x) * x^2 * y2 + x^3 * y3
These first two are mathematically the same, just using different names for the variables.
Judging by your description "find the Y-coordinate on a Cubic Bezier Curve, given an x-coordinate on it." I'm guessing that you've got a question using the second equation are are trying to rearrange the first equation to help you solve it, where as you should be using the second equation. If thats the case, then no rearranging or solving is required - just plug your x value in and you have the solution.
Its possible that you have an equation of the third kind case, which is the ugly and hard case.
This is both the x and y parameters are cubic Beziers of a third variable t.
x(t) = sum( f_i(t) x_i )
y(t) = sum( f_i(t) y_i )
If this is your case. Let me know and I can detail what you need to do to solve it.
I think this is a fair CS question, so I'm going to attempt to show how I solved this. Note that a given x may have more than 1 y value associated with it. In the case where I needed this, that was guaranteed not to be the case, so you'll have to figure out how to determine which one you want.
I iterated over t generating an array of x and y values. I did it at a fairly high resolution for my purposes. (I was looking to generate an 8-bit look-up table, so I used ~1000 points.) I just plugged t into the bezier equation for the next x and the next y coordinates to store in the array. Once I had the entire thing generated, I scanned through the array to find the 2 nearest x values. (Or if there was an exact match, used that.) I then did a linear interpolation on that very small line segment to get the y-value I needed.
Developing the expression further should get you rid of the (1 - t) factors
If you run:
expand(800*t^3 + 3*(1-t)*800*t^2 + 3*(1-t)^2*600*t + (1-t)^3*100 -400 = 0);
In either wxMaxima or Maple (you have to add the parameter t in this one though), you get:
100*t^3 - 900*t^2 + 1500*t - 300 = 0
Solve the new cubic equation for t (you can use the cubic equation formula for that), after you got t, you can find x doing:
x = (x4 - x0) * t (asuming x4 > x0)
Equation for Bezier curve (getting x value):
Bx = (-t^3 + 3*t^2 - 3*t + 1) * P0x +
(3*t^3 - 6*t^2 + 3*t) * P1x +
(-3*t^3 + 3*t^2) * P2x +
(t^3) * P3x
Rearrange in the form of a cubic of t
0 = (-P0x + 3*P1x - 3*P2x + P3x) * t^3+
(3*P0x - 6*P1x + 3*P2x) * t^2 +
(-3*P0x + 3*P1x) * t +
(P0x) * P3x - Bx
Solve this using the cubic formula to find values for t. There may be multiple real values of t (if your curve crosses the same x point twice). In my case I was dealing with a situation where there was only ever a single y value for any value of x. So I was able to just take the only real root as the value of t.
a = -P0x + 3.0 * P1x - 3.0 * P2x + P3x;
b = 3.0 * P0x - 6.0 * P1x + 3.0 * P2x;
c = -3.0 * P0x + 3.0 * P1x;
d = P0x;
t = CubicFormula(a, b, c, d);
Next put the value of t back into the Bezier curve for y
By = (1-t)^3 * P0x +
3t(1-t)^2 * P1x +
3t^2(1-t) * P2x +
t^3 * P3x
So I've been looking around for some sort of method to allow me to find the Y-coordinate on a Cubic Bezier Curve, given an x-coordinate on it.
Consider a cubic bezier curve between points (0, 0) and (0, 100), with control points at (0, 33) and (0, 66). There are an infinite number of Y's there for a given X. So there's no equation that's going to solve Y given X for an arbitrary cubic bezier.
For a robust solution, you'll likely want to start with De Casteljau's algorithm
Split the curve recursively until individual segments approximate a straight line. You can then detect whether and where these various line segments intercept your x or whether they are vertical line segments whose x corresponds to the x you're looking for (my example above).
I'm working on a (rather) simple 2D project in OpenGL. It's some sort of asteroids clone.
The ship is basically an isosceles triangle of height H, with the base have a length of H/2.
The way I've been doing it so far is simply storing the center point (CP) of the triangle and then calculating the final vertex positions on the fly. The 'point' of the ship is (vectors are x,y) the (CP.x, CP.y + H/2). The other two points are (CP.X - H/4, CP.Y - H/2) and (CP.X + H/4, CP.Y - H/2).
To get the ship facing the right direction, I first call glRotate on the current rotation angle.
This part is working fine however I'm running into issues with collision detection. Currently I'm trying to implement triangle-plane collision detection however to do that, I first need to figure out the actual points of the ship vertices after rotation. I've tried using trigonometry to calculate these points, however I've failed.
The way I've attempted is was to use the cosine rule to find the distance between the unrotated triangle and the triangle after rotation. To give an example, the following is how I've tried to calculate the 'pointy' vertex position after rotation:
//pA is a vector struct holding the position of the pointy vertex of the ship (centerPoint.x, centerPoint.y + height / 2)
//Distance between pA and the rotated pointy vertex - using the cosine rule
float distance = sqrt((2 * pow(size / 2, 2)) * (1 - cosf(rotAngle)));
//The angle to the calculated point
float newPointAngle = (M_PI / 2) - rotAngle;
float xDif = distance * cosf(newPointAngle);
float yDif = distance * sinf(newPointAngle);
//Actually drawing the new point
glVertex2f(pA.x - xDif, pA.y - yDif);
Any idea what I could be doing wrong?
Thanks for the help guys but I think those explanations were a bit too technical for me. Nonetheless you made it clear to me that there's no special case for a triangle (which, in hindsight, I should've known) so I tried my hand at searching and after trying a few methods, found one which worked for me.
The post from estain at the GameDev forums did the trick. To quote his post (sorry for the c&p but may be useful for someone else who runs into a similar issue):
Without getting to heavily into general solutions and maths (as the above posters and lots of articles have covered this already), I could give you an example on how to solve the problem "rotating a point A around point B by C degrees".
Now. First of all, as I described in the previous post, a point that is on the X axis, L distance from origo, is rotated C degrees around origo by
x = L * cos(C)
y = L * sin(C)
Similarly, the formula for a perpendicular vector is x = -y | y = x, which means that a point that is on the Y axis (again, L from origo) would be rotated by C using the formula
x = - L * sin(C)
y = L * cos(C)
As shown in the above image, the final solution is the sum of the rotations of the projected vectors, so we can derive the formula
x' = x * cos(C) - y * sin(C)
y' = y * cos(C) + x * sin(C)
... but you knew that already, right? problem is, this formula only rotates around origo. So what we need to do is move the coordinate system we're rotating around to origo, rotate and then move back. This can be done quickly with complex numbers or in general solutions with matrices, but we're gonna stick to vector math on this one to keep it simple.
first step; move the origin point.
x' = A.x - B.x
y' = A.y - B.y
second step, perform rotation
x'' = x' * cos(C) - y' * sin(C) = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C)
y'' = y' * cos(C) + x' * sin(C) = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C)
third and final step, move back the coordinate frame
x''' = x'' + B.x = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C) + B.x
y''' = y'' + B.y = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C) + B.y
And presto! we have our rotation formula. I'll give it to you without all those >calculations:
Rotating a point A around point B by angle C
A.x' = (A.x-B.x) * cos(C) - (A.y-B.y) * sin(C) + B.x
A.y' = (A.y-B.y) * cos(C) + (A.x-B.x) * sin(C) + B.y
If you've been following me here (and I'm a pretty lousy teacher, so sorry if you haven't), you can se that the ordering in which you perform these operations is very important. Try to mix step 3 and 1 and see the difference in the formulae you get.
Good luck and all!
Rotation calculations need to be centered at the origin, so you may need to first translate the coordinates so the center of rotation is aligned with the origin.
Then use the new points to get the rotated coordinates:
x1 = x cos f - y sin f
y1 = y cos f + x sin f
where f is the angle of rotation.
Then you translate the new coordinates back to where you started (the reverse of the first translation.
Check out this article for some diagrams and clarification.
Calculating the new points is relatively simple. Assume the x and y are the coordinates of a certain point on the triangle (i.e. the vertices) relative to the point of rotation (or center).
You must convert the coords to a square distance and angle component:
float dist, angle;
dist = (x*x) + (y*y);
angle = atan(abs(x)/abs(y));
// a little more code is required for the different quadrants that the angle could be in.
Then rotate:
angle+=rotation_angle;
Then convert back:
new_x = sqrt(dist)*sin(angle*pi/180);
new_y = sqrt(dist)*cos(angle*pi/180);