Calculating a line from a starting point and angle in 3d - c++

I have a point in 3D space and two angles, I want to calculate the resulting line from this information. I have found how to do this with 2D lines, but not 3D. How can this be calculated?
If it helps: I'm using C++ & OpenGL and have the location of the user's mouse click and the angle of the camera, I want to trace this line for intersections.

In trig terms two angles and a point are required to define a line in 3d space. Converting that to (x,y,z) is just polar coordinates to cartesian coordinates the equations are:
x = r sin(q) cos(f)
y = r sin(q) sin(f)
z = r cos(q)
Where r is the distance from the point P to the origin; the angle q (zenith) between the line OP and the positive polar axis (can be thought of as the z-axis); and the angle f (azimuth) between the initial ray and the projection of OP onto the equatorial plane(usually measured from the x-axis).
Edit:
Okay that was the first part of what you ask. The rest of it, the real question after the updates to the question, is much more complicated than just creating a line from 2 angles and a point in 3d space. This involves using a camera-to-world transformation matrix and was covered in other SO questions. For convenience here's one: How does one convert world coordinates to camera coordinates? The answers cover converting from world-to-camera and camera-to-world.

The line can be fathomed as a point in "time". The equation must be vectorized, or have a direction to make sense, so time is a natural way to think of it. So an equation of a line in 3 dimensions could really be three two dimensional equations of x,y,z related to time, such as:
x = ax*t + cx
y = ay*t + cy
z = az*t + cz
To find that set of equations, assuming the camera is at origin, (0,0,0), and your point is (x1,y1,z1) then
ax = x1 - 0
ay = y1 - 0
az = z1 - 0
cx = cy = cz = 0
so
x = x1*t
y = y1*t
z = z1*t
Note: this also assumes that the "speed" of the line or vector is such that it is at your point (x1,y1,z1) after 1 second.
So to draw that line just fill in the points as fine as you like for as long as required, such as every 1/1000 of a second for 10 seconds or something, might draw a "line", really a series of points that when seen from a distance appear as a line, over 10 seconds worth of distance, determined by the "speed" you choose.

Related

C++ Move 2D Point Along Angle

So I am writing a game in C++, currently I am working on a 'Compass', but I am having some problems with the vector math..
Here is a little image I created to possibly help explain my question better
Ok, so as you can see the 2D position of A begins at (4, 4), but then I want to move A along the 45 degree angle until the 2D position reaches (16, 16), so basically there is a 12 distance between where A starts and where it ends. And my qustion is how would I calculate this?
the simplest way in 2D is to take angle 'ang', and distance 'd', and your starting point 'x' and 'y':
x1 = x + cos(ang) * distance;
y1 = y + sin(ang) * distance;
In 2D the rotation for any object can be just stored as a single value, ang.
using cos for x and sin for y is the "standard" way that almost everyone does it. cos(ang) and sin(ang) trace a circle out as ang increases. ang = 0 points right along the x-axis here, and as angle increases it spins counter-clockwise (i.e at 90 degrees it's pointing straight up). If you swap the cos and sin terms for x and y, you get ang = 0 pointing up along the y axis and clockwise rotation with increasing ang (since it's a mirror image), which could in fact be more convenient for making game, since y-axis is often the "forward" direction and you might like that increasing ang spins to the right.
x1 = x + sin(ang) * distance;
y1 = y + cos(ang) * distance;
Later you can get into vectors and matricies that do the same thing but in a more flexible manner, but cos/sin are fine to get started with in a 2D game. In a 3D game, using cos and sin for rotations starts to break down in certain circumstances, and you start really benefiting from learning the matrix-based approaches.
The distance between (4,4) and (16,16) isn't actually 12. Using pythagorean theorem, the distance is actually sqrt(12^2 + 12^2) which is 16.97. To get points along the line you want to use sine and cosine. E.g. If you want to calculate the point halfway along the line the x coordinate would be cos(45)(16.97/2) and the y would be sin(45)(16.97/2). This will work with other angles besides 45 degrees.

Find a longitude given a pair of (lat,long) and an offset latitude

In a geodetic coordinate system (wgs84), i have a pair of (latitude,longitude) say (45,50) and (60,20). Also i am said that a new pair of latitude,longitude lies along the line joining these two and at an offset of say 0.1 deg lat from (45,50) i.e. (45.1, x). How do i find this new point? What i tried was to apply the straight line equation
y = mx+c
m = (lat1 - lat2)/ long1-long2)
c = lat1 - m * long1
but that seemed to give wrong results.
Your problem is the calculation of m. You have turned it around!
The normal formula is:
a = (y1 - y2) / (x1 - x2)
so in your case it is:
m = (long2 -long1) / (lat1 - lat2)
so you'll get m = -2
And you also turned the calculation of c around.
Normal is:
b = y1 - a * x1
so you should do:
c = long1 - m * lat1
So you'll get c = 140.
The formula is:
long = -2 * lat + 140
Another way to think about it is given below. The result is the same, of cause.
The surface-line between two coordinates is not a straight line. It is a line drawn on the surface of a round object, i.e. earth. It will be a circle around the earth.
However all coordinates on that line will still go through a straight line.
That is because the coordinate represents the angles of a vector from center of earth to the point you are looking at. The two angles are compared to Equator (latitude) and compared to Greenwich (longitude).
So you need to setup a formula describing all coordinates for that line.
In your case the latitude goes from 45 to 60, i.e. increases by 15.
Your longitude goes from 50 to 20, i.e. decreses by 30.
So your formula will be:
(lat(t), long(t)) = (45, 50) + (15*t, -30*t) for t in [0:1]
Now you can calculate the value of t that will hit (45.1, x) and afterwards you can calculate x.
The equations you use describe a straight line in an 2D cartesian coordinate system.
Longitude and latitude describe a point in a spherical coordinate system.
A spherical coordinate system is not cartesian.
A similar question was answered here.

Find a 2D point in space based on angle and distance

Ok.... so I made a quick diagram to sorta explain what I'm hoping to accomplish. Sadly math is not my forte and I'm hoping one of you wizards can give me the correct formulas :) This is for a c++ program, but really I'm looking for the formulas rather than c++ code.
Ok, now basically, the red circle is our 0,0 point, where I'm standing. The blue circle is 300 units above us and at what I would assume is a 0 degree's angle. I want to know, how I can find a find the x,y for a point in this chart using the angle of my choice as well as a certain distance of my choice.
I would want to know how to find the x,y of the green circle which is lets say 225 degrees and 500 units away.
So I assume I have to figure out a way to transpose a circle that is 500 units away from 0,0 at all points than pick a place on that circle based on the angle I want? But yeah no idea where to go from there.
A point on a plane can be expressed in two main mathematical representations, cartesian (thus x,y) and polar : using a distance from the center and an angle. Typically r and a greek letter, but let's use w.
Definitions
Under common conventions, r is the distance from the center (0,0) to your point, and
angles are measured going counterclockwise (for positive values, clockwise for negative), with the 0 being the horizontal on the right hand side.
Remarks
Note a few things about angles in polar representations :
angles can be expressed with radians as well, with π being the same angle as 180°, thus π/2 90° and so on. π=3.14 (approx.) is defined by 2π=the perimeter of a circle of radius 1.
angles can be represented modulo a full circle. A full circle is either 2π or 360°, thus +90° is the same as -270°, and +180° and -180° are the same, as well as 3π/4 and -5π/4, 2π and 0, 360° and 0°, etc. You can consider angles between [-π,π] (that is [-180,180]) or [0,2π] (i.e. [0,360]), or not restrain them at all, it doesn't matter.
when your point is in the center (r=0) then the angle w is not really defined.
r is by definition always positive. If r is negative, you can change its sign and add half a turn (π or 180°) to get coordinates for the same point.
Points on your graph
red : x=0, y=0 or r=0 w= any value
blue : x=0, y=300 or r=300 and w=90°
green : x=-400, y=-400 or r=-565 and w=225° (approximate values, I didn't do the actual measurements)
Note that for the blue point you can have w=-270°, and for the green w=-135°, etc.
Going from one representation to the other
Finally, you need trigonometry formulas to go back and forth between representations. The easier transformation is from polar to cartesian :
x=r*cos(w)
y=r*sin(w)
Since cos²+sin²=1, pythagoras, and so on, you can see that x² + y² = r²cos²(w) + r²sin²(w) = r², thus to get r, use :
r=sqrt(x²+y²)
And finally to get the angle, we use cos/sin = tan where tan is another trigonometry function. From y/x = r sin(w) / (r cos(w)) = tan(w), you get :
w = arctan(y/x) [mod π]
tan is a function modulo π, instead of 2π. arctan simply means the inverse of the function tan, and is sometimes written tan^-1 or atan.
By inverting the tangent, you get a result betweeen -π/2 and π/2 (or -90° and 90°) : you need to eventually add π to your result. This is done for angles between [π/2,π] and [-π,π/2] ([90,180] and [-180,-90]). These values are caracterized by the sign of the cos : since x = r cos(w) you know x is negative on all these angles. Try looking where these angles are on your graph, it's really straightforward. Thus :
w = arctan(y/x) + (π if x < 0)
Finally, you can not divide by x if it is 0. In that corner case, you have
if y > 0, w = π/2
if y < 0, w = -π/2
What is seems is that given polar coordinates, you want to obtain Cartesian coordinates from this. It's some simple mathematics and should be easy to do.
to convert polar(r, O) coordinates to cartesian(x, y) coordinates
x = r * cos(O)
y = r * sin(O)
where O is theta, not zero
reference: http://www.mathsisfun.com/polar-cartesian-coordinates.html

Perspective projection - how to convert coordinates

I'm studying perspective projections and I stumbled upon this concept:
Basically it says that if I have a point (x,y,z) I can project it into my perspective screen (camera space) by doing
x' = x/z
y' = y/z
z' = f(z-n) / z(f-n)
I can't understand why x' = x/z or y' = y/z
Geometrically, it is a matter of similar triangles.
In your diagram, because (x,y,x) is on the same dotted line as (x',y',z'):
triangle [(0,0,0), (0,0,z), (x,y,z)]
is similar to
triangle [(0,0,0), (0,0,z'), (x',y',z')]
This means that the corresponding sides have a fixed ratio. And, further, the original vector is proportional to the projected vector. Finally, note that the notional projection plane is at z' = 1:
(x,y,z) / z = (x',y',z') / z'
-> so, since z' = 1:
x'/z' = x' = x/z
y'/z' = y' = y/z
[Warning: note that the z' in my answer is different from its occurrence in the question. The question's z' = f(z-n) / z(f-n) doesn't correspond directly to a physical point: it is a "depth value", which is used to do things like hidden surface removal.]
One way to look at this, is that what you are trying to do, is intersect a line which passes through both the viewer position (assumed to be at the origin: 0,0,0), and the point in space you wish to project (P).
So you take the equation of the line, which is P' = P * a, where a is simply a scalar value and solve for P'.Z = 1 (which is where your projection plane is). This is trivially true when the scalar multiple is 1 / P.Z, so the projected point is (P.X, P.Y, P.Z) * (1 / P.Z)
Homogenous coordinates give us the power to represent a point/line at infinity.
we add 1 to the vector representation. The more the distance of a point in 3d space, It tends to move toward the optical centre.
cartesian to homogenous
p=(x,y)to(x,y,1)
homogenous to cartesian
(X, Y, Z)to(X/Z, Y/Z)
For instance,
1. you are travelling in an aeroplane and when you look down, it doesn't seem like points move faster from one instant to another. This is distance is very large, Distance =1/Disparity(drift of the same point in two frames).
2. Try with substituting Infinity in the disparity, it means distance is 0.

Rotate a 3D- Point around another one

I have a function in my program which rotates a point (x_p, y_p, z_p) around another point (x_m, y_m, z_m) by the angles w_nx and w_ny.
The new coordinates are stored in global variables x_n, y_n, and z_n. Rotation around the y-axis (so changing value of w_nx - so that the y - values are not harmed) is working correctly, but as soon as I do a rotation around the x- or z- axis (changing the value of w_ny) the coordinates aren't accurate any more. I commented on the line I think my fault is in, but I can't figure out what's wrong with that code.
void rotate(float x_m, float y_m, float z_m, float x_p, float y_p, float z_p, float w_nx ,float w_ny)
{
float z_b = z_p - z_m;
float x_b = x_p - x_m;
float y_b = y_p - y_m;
float length_ = sqrt((z_b*z_b)+(x_b*x_b)+(y_b*y_b));
float w_bx = asin(z_b/sqrt((x_b*x_b)+(z_b*z_b))) + w_nx;
float w_by = asin(x_b/sqrt((x_b*x_b)+(y_b*y_b))) + w_ny; //<- there must be that fault
x_n = cos(w_bx)*sin(w_by)*length_+x_m;
z_n = sin(w_bx)*sin(w_by)*length_+z_m;
y_n = cos(w_by)*length_+y_m;
}
What the code almost does:
compute difference vector
convert vector into spherical coordinates
add w_nx and wn_y to the inclination and azimuth angle (see link for terminology)
convert modified spherical coordinates back into Cartesian coordinates
There are two problems:
the conversion is not correct, the computation you do is for two inclination vectors (one along the x axis, the other along the y axis)
even if computation were correct, transformation in spherical coordinates is not the same as rotating around two axis
Therefore in this case using matrix and vector math will help:
b = p - m
b = RotationMatrixAroundX(wn_x) * b
b = RotationMatrixAroundY(wn_y) * b
n = m + b
basic rotation matrices.
Try to use vector math. Decide in which order you rotate, first along x, then along y perhaps.
If you rotate along z-axis, [z' = z]
x' = x*cos a - y*sin a;
y' = x*sin a + y*cos a;
The same repeated for y-axis: [y'' = y']
x'' = x'*cos b - z' * sin b;
z'' = x'*sin b + z' * cos b;
Again rotating along x-axis: [x''' = x'']
y''' = y'' * cos c - z'' * sin c
z''' = y'' * sin c + z'' * cos c
And finally the question of rotating around some specific "point":
First, subtract the point from the coordinates, then apply the rotations and finally add the point back to the result.
The problem, as far as I see, is a close relative to "gimbal lock". The angle w_ny can't be measured relative to the fixed xyz -coordinate system, but to the coordinate system that is rotated by applying the angle w_nx.
As kakTuZ observed, your code converts point to spherical coordinates. There's nothing inherently wrong with that -- with longitude and latitude, one can reach all the places on Earth. And if one doesn't care about tilting the Earth's equatorial plane relative to its trajectory around the Sun, it's ok with me.
The result of not rotating the next reference axis along the first w_ny is that two points that are 1 km a part of each other at the equator, move closer to each other at the poles and at the latitude of 90 degrees, they touch. Even though the apparent purpose is to keep them 1 km apart where ever they are rotated.
if you want to transform coordinate systems rather than only points you need 3 angles. But you are right - for transforming points 2 angles are enough. For details ask Wikipedia ...
But when you work with opengl you really should use opengl functions like glRotatef. These functions will be calculated on the GPU - not on the CPU as your function. The doc is here.
Like many others have said, you should use glRotatef to rotate it for rendering. For collision handling, you can obtain its world-space position by multiplying its position vector by the OpenGL ModelView matrix on top of the stack at the point of its rendering. Obtain that matrix with glGetFloatv, and then multiply it with either your own vector-matrix multiplication function, or use one of the many ones you can obtain easily online.
But, that would be a pain! Instead, look into using the GL feedback buffer. This buffer will simply store the points where the primitive would have been drawn instead of actually drawing the primitive, and then you can access them from there.
This is a good starting point.