I need to create a list of XYZ positions given a starting point and an offset between the positions based on a plane. On just a flat plane this is easy. Let's say the offset I need is to move down 3 then right 2 from position 0,0,0
The output would be:
0,0,0 (starting position)
0,-3,0 (move down 3)
2,-3,0 (then move right 2)
The same goes for a different start position, let's say 5,5,1:
5,5,1 (starting position)
5,2,1 (move down 3)
7,2,1 (then move right 2)
The problem comes when the plane is no longer on this flat grid.
I'm able to calculate the equation of the plane and the normal vector given 3 points.
But now what can I do to create this dataset of XYZ locations given this equation?
I know I can solve for XYZ given two values. Say I know x=1 and y=1, I can solve for Z. But moving down 2 is no longer just y-2. I believe I need to find a linear equation on both the x and y axis to increment the positions and move parallel to the x and y of this new plane, then just solve for Z. I'm not sure how to accomplish this.
The other issue is that I need to calculate the angle, tilt and rotation of this plane in relation to the base plane.
For example:
P1=0,0,0 and P2=1,1,0 the tilt=0deg angle=0deg rotation=45deg.
P1=0,0,0 and P2=0,1,1 the tilt=0deg angle=45deg rotation=0deg.
P1=0,0,0 and P2=1,0,1 the tilt=45deg angle=0deg rotation=0deg.
P1=0,0,0 and P2=1,1,1 the tilt=0deg angle=45deg rotation=45deg.
I've searched for hours on both these problems and I've always come to a stop at the equation of the plane. Manipulating the x,y correctly to follow parallel to the plane, and then taking that information to find these angles. This is a lot of geometry to be solved, and I can't find any further information on how to calculate this list of points, let alone calculating the 3 angles to the base plane.
I would appericate any help or insight on this. Just plain old math or a reference to C++ would be perfect to sheding some light onto this issue I'm facing here.
Thank you,
Matt
You can think of your plane as being defined by a point and a pair of orthonormal basis vectors (which just means two vectors of length 1, 90 degrees from one another). Your most basic plane can be defined as:
p0 = (0, 0, 0) #Origin point
vx = (1, 0, 0) #X basis vector
vy = (0, 1, 0) #Y basis vector
To find point p1 that's offset by dx in the X direction and dy in the Y direction, you use this formula:
p1 = p0 + dx * vx + dy * vy
This formula will always work if your offsets are along the given axes (which it sounds like they are). This is still true if the vectors have been rotated - that's the property you're going to be using.
So to find a point that's been offset along a rotated plane:
Take the default basis vectors (vx and vy, above).
Rotate them until they define the plane you want (you may or may not need to rotate the origin point as well, depending on how the problem is defined).
Apply the formula, and get your answer.
Now there are some quirks when you're doing rotation (Order matters!), but that's the the basic idea, and should be enough to put you on the right track. Good luck!
Related
I need to make a function that will calculate the degrees necessary to make an NPC look at the center of the player. However, I have not been able to find any results regarding 3 dimensions which is what I need. Only 2 dimensional equations. I'm programming in C++.
Info:
Data Type: Float.
Vertical-Axis: 90 is looking straight up, -90 is looking straight down and 0 is looking straight ahead.
Horizontal-Axis: Positive value between 0 and 360, North is 0, East is 90, South 180, West 270.
See these transformation equations from Wikipedia. But note since you want "elevation" or "vertical-axis" to be zero on the xy-plane, you need to make the changes noted after "if theta measures elevation from the reference plane instead of inclination from the zenith".
First, find a vector from the NPC to the player to get the values x, y, z, where x is positive to the East, y is positive to the North, and z is positive upward.
Then you have:
float r = sqrtf(x*x+y*y+z*z);
float theta = asinf(z/r);
float phi = atan2f(x,y);
Or you might get better precision from replacing the first declaration with
float r = hypotf(hypotf(x,y), z);
Note acosf and atan2f return radians, not degrees. If you need degrees, start with:
theta *= 180./M_PI;
and theta is now your "vertical axis" angle.
Also, Wikipedia's phi = arctan(y/x) assumes an azimuth of zero at the positive x-axis and pi/2 at the positive y-axis. Since you want an azimuth of zero at the North direction and 90 at the East direction, I've switched to atan2f(x,y) (instead of the more common atan2f(y,x)). Also, atan2f returns a value from -pi to pi inclusive, but you want strictly positive values. So:
if (phi < 0) {
phi += 2*M_PI;
}
phi *= 180./M_PI;
and now phi is your desired "horizontal-axis" angle.
I'm not too familiar with math which involves rotation and 3d envionments, but couldn't you draw a line from your coordinates to the NPC's coordinates or vise versa and have a function approximate the proper rotation to that line until within a range of accepted +/-? This way it does this is by just increasing and decreasing the vertical and horizontal values until it falls into the range, it's just a matter of what causes to increase or decrease first and you could determine that based on the position state of the NPC. But I feel like this is the really lame way to go about it.
use 4x4 homogenous transform matrices instead of Euler angles for this. You create the matrix anyway so why not use it ...
create/use NPC transform matrix M
my bet is you got it somewhere near your mesh and you are using it for rendering. In case you use Euler angles you are doing a set of rotations and translation and the result is the M.
convert players GCS Cartesian position to NPC LCS Cartesian position
GCS means global coordinate system and LCS means local coordinate system. So is the position is 3D vector xyz = (x,y,z,1) the transformed position would be one of these (depending on conventions you use)
xyz'=M*xyz
xyz'=Inverse(M)*xyz
xyz'=Transpose(xyz*M)
xyz'=Transpose(xyz*Inverse(M))
either rotate by angle or construct new NPC matrix
You know your NPC's old coordinate system so you can extract X,Y,Z,O vectors from it. And now you just set the axis that is your viewing direction (usually -Z) to direction to player. That is easy
-Z = normalize( xyz' - (0,0,0) )
Z = -xyz' / |xyz'|
Now just exploit cross product and make the other axises perpendicular to Z again so:
X = cross(Y,Z)
Y = cross(Z,X)
And feed the vectors back to your NPC's matrix. This way is also much much easier to move the objects. Also to lock the side rotation you can set one of the vectors to Up prior to this.
If you still want to compute the rotation then it is:
ang = acos(dot(Z,-xyz')/(|Z|*|xyz'|))
axis = cross(Z,-xyz')
but to convert that into Euler angles is another story ...
With transform matrices you can easily make cool stuff like camera follow, easy computation between objects coordinate systems, easy physics motion simulations and much more.
I am using OpenTK(OpenGL) and a general hint will be helpful.
I have a 3d terrain. I have one point on this terrain O(x,y,z) and two perpendicular lines passing through this point that will serve as my X and Y axes.
Now I have a set of 2d points with are in polar coordinates (range,theta). I need to find which points on the terrain correspond to these points. I am not sure what is the best way to do it. I can think of two ideas:
Lets say I am drawing A(x1,y1).
Find the intersection of plane passing through O and A which is perpendicular to the XY plane. This will give me a polyline (semantics may be off). Now on this line, I find a point that is visible from O and is at a distance of the range.
Create a circle which is perpendicular to the XY plane with radius "range", find intersection points on the terrain, find which ones are visible from O and drop rest.
I understand I can find several points which satisfy the conditions, so I will do further check based on topography, but for now I need to get a smaller set which satisfy this condition.
I am new to opengl, but I get geometry pretty well. I am wondering if something like this exists in opengl since it is a standard problem with ground measuring systems.
As you say, both of the options you present will give you more than the one point you need. As I understand your problem, you need only to perform a change of bases from polar coordinates (r, angle) to cartesian coordinates (x,y).
This is fairly straight forward to do. Assuming that the two coordinate spaces share the origin O and that the angle is measured from the x-axis, then point (r_i, angle_i) maps to x_i = r_i*cos(angle_i) and y_i = r_i*sin(angle_i). If those assumptions aren't correct (i.e. if the origins aren't coincident or the angle is not measured from a radii parallel to the x-axis), then the transformation is a bit more complicated but can still be done.
If your terrain is represented as a height map, or 2D array of heights (e.g. Terrain[x][y] = z), once you have the point in cartesian coordinates (x_i,y_i) you can find the height at that point. Of course (x_i, y_i) might not be exactly one of the [x] or [y] indices of the height map.
In that case, I think you have a few options:
Choose the closest (x,y) point and take that height; or
Interpolate the height at (x_i,y_i) based on the surrounding points in the height map.
Unfortunately I am also learning OpenGL and can not provide any specific insights there, but I hope this helps solve your problem.
Reading your description I see a bit of confusion... maybe.
You have defined point O(x,y,z). Fine, this is your pole for the 3D coordinate system. Then you want to find a point defined by polar coordinates. That's fine also - it gives you 2D location. Basically all you need to do is to pinpoint the location in 3D A'(x,y,0), because we are assuming you know the elevation of the A at (r,t), which you of course do from the terrain there.
Angle (t) can be measured only from one axis. Choose which axis will be your polar north and stick to. Then you measure r you have and - voila! - you have your location. What's the point of having 2D coordinate set if you don't use it? Instead, you're adding visibility to the mix - I assume it is important, but highest terrain point on azimuth (t) NOT NECESSARILY will be in the range (r).
You have specific coordinates. Just like RonL suggest, convert to (x,y), find (z) from actual terrain and be done with it.
Unless that's not what you need. But in that case a different question is in order: what do you look for?
I currently have several ellipses. These are defined by a centre point, and then two vectors, one point to the minimum axis and other to the maximum axis.
However, for the program I'm creating I need to be able to deal with these shapes as a polyline. I'm fairly sure there must be formula for generating a set of points from the available data that I have, but I'm unsure how to go about doing it.
Does anyone have any ideas of how to go about this?
Thanks.
(Under assumption that both vectors that represent ellipse axes are parllel to coordinate axes)
If you have a radial ray emanating from the centre of ellipsis at angle angle, then that ray intersects the ellipse at point
x = x_half_axis * cos(angle);
y = y_half_axis * sin(angle);
where x_half_axis and y_half_axis age just the lengths (magnitudes) of your half-axis vectors.
So, just choose some sufficiently small angle step delta. Sweep around your centre point through the entire [0...2*Pi] range with that step, beginning with 0 angle, then delta angle, then 2 * delta angle and so on. For each angle value the coordinates of the ellipse point will be given by the above formulas. That way you will generate your polygonal representation of the ellipse.
If your delta is relatively large (few points on the ellipse) then it should be chosen carefully to make sure your "elliptical polygon" closes nicely: 2*Pi should split into a whole number of delta steps. Albeit for small delta values it does not matter as much.
If your minimum-maximum axis vectors are not parallel to coordinate axes, your can still use the above approach and then transform the resultant points to the proper final position by applying the corresponding rotation transformation.
Fixed-delta angle stepping has some disadvantages though. It generates a denser sequence of polygonal points near the miminum axis of the ellipse (where the curvature is smaller) and a sparser sequence of points near the maximum axis (where the curvature is greater). This is actually the opposite of the desirable behavior: it is better to have higher point density in the regions of higher curvature.
If that is an issue for you, then you can update the algorithm to make it use variadic stepping. The angle delta should gradually decrease as we approach the maximum axis and increase as we approach the minimum axis.
Assuming the center at (Xc,Yc) and the axis vectors (Xm,Ym), (XM,YM) (these two should be orthogonal), the formula is
X = XM cos(t) + Xm sin(t) + Xc
Y = YM cos(t) + Ym sin(t) + Yc
with t in [0,2Pi].
To get a efficient distribution of the endpoints on the outline, I recommend to use the maximum deviation criterion applied recursively: to draw the arc corresponding to the range [t0,t2], try the midpoint value t1=(t0+t2)/2. If the corresponding points are such that the distance of P1 to the line P0P2 is below a constant threshold (such as one pixel), you can approximate the arc by the segment P0P1. Otherwise, repeat the operation for the arcs [t0,t1] and [t1,t2].
Preorder recursion allows you to emit the polyline vertexes in sequence.
I'm trying to export (3D) bezier curves from Blender to my C++ program. I asked a related question a while back, where I was successfully directed to use De Casteljau's Algorithm to evaluate points (and tangents to these points) along a bezier curve. This works well. In fact, perfectly. I can export the curves and evaluate points along the curve, as well as the tangent to these points, all within my program using De Casteljau's Algorithm.
However, in 3D space a point along a bezier curve and the tangent to this point is not enough to define a "frame" that a camera can lock into, if that makes sense. To put it another way, there is no "up vector" which is required for a camera's orientation to be properly specified at any point along the curve. Mathematically speaking, there are an infinite amount of normal vectors at any point along a 3D bezier curve.
I've noticed when constructing curves in Blender that they aren't merely infinitely thin lines, they actually appear to have a proper 3D orientation defined at any point along them (as shown by the offshooting "arrow lines" in the screenshot below). I'd like to replicate what blender does here as closely as possible in my program. That is, I'd like to be able to form a matrix that represents an orientation at any point along a 3D bezier curve (almost exactly as it would in Blender itself).
Can anyone lend further guidance here, perhaps someone with an intimate knowledge of Blender's source code? (But any advice is welcome, Blender background or not.) I know it's open source, but I'm having a lot of troubles isolating the code responsible for these curve calculations due to the vastness of the program.
Some weeks ago, I have found a solution to this problem. I post it here, in case someone else would need it :
1) For a given point P0, calculate the tangent vector T0.
One simple, easy way, is to take next point on the curve, subtract current point, then normalize result :
T0 = normalize(P1 - P0)
Another, more precise way, to get tangent is to calculate the derivative of your bezier curve function.
Then, pick an arbitrary vector V (for example, you can use (0, 0, 1))
Make N0 = crossproduct(T0, V) and B0 = crossproduct(T0, N0) (dont forget to normalize result vectors after each operation)
You now have a starting set of coordinates ( P0, B0, T0, N0)
This is the initial camera orientation.
2) Then, to calculate next points and their orientation :
Calculate T1 using same method as T0
Here is the trick, new reference frame is calculated from previous frame :
N1 = crossproduct(B0, T1)
B1 = crossproduct(T1, N1)
Proceed using same method for other points. It will results of having camera slightly rotating around tangent vector depending on how curve change its direction. Loopings will be handled correctly (camera wont twist like in my previous answer)
You can watch a live example here (not from me) : http://jabtunes.com/labs/3d/webgl_geometry_extrude_splines.html
Primarily, we know, that the normal vector you're searching for lies on the plane "locally perpendicular" to the curve on the specific point. So the real problem is to choose a single vector on this plane.
I've made an empty object to track the curve and noticed, that it behave similarly to the cart of a rollercoaster: its "up" vector was correlated to the centrifugal force while it was moving along the curve. This one can be uniquely evaluated from the local shape of the curve.
I'm not very good at physics, but I would try to estimate that vector by evaluating two planes: the first is previously mentioned perpendicular plane and the second is a plane made of three neighboring points of a curve segment (if the curve is not straight, these will form a triangle, which describes exactly one plane). Intersection of these two planes will give you an axis and you'll only have to choose a direction of such calculated normal vector.
If I understand you question correcly, what you want is to get 3 orientation vectors (left, front, up) for any point of the curve.
Here is a simple method ( there is a limitation, (*) see below ) :
1) Front vector :
Calculate a 3d point on bezier curve for a given position (t). This is the point for which we will calculate front, left, up vectors. We will call it current_point.
Calculate another 3d point on the curve, next to first one (t + 0.01), let's call it next_point.
Note : i don't write formula here, because i believe you already how to
do that.
Then, to calculate front vector, just substract the two points calculated previously :
vector front = next_point - current_point
Don't forget to normalize the result.
2) Left vector
Define a temporary "up" vector
vector up = vector(0.0f, 1.0f, 0.0f);
Now you can calculate left easily, using front and up :
vector left = CrossProduct(front, up);
3) Up vector
vector up = CrossProduct(left, front);
Using this method you can always calculate a front, left, up for any point along the curve.
(*) NOTE : this wont work in all cases. Imagine you have a loop in you curve, just like a rollercoaster loop. On the top of the loop your calculated up vector will be (0, 1, 0), while you maybe want it to be (0, -1, 0). Only way to solve that is to have two curves : one for points and one for up vectors (from which left and front can be calculated easily).
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Finding whether a point lies inside a rectangle or not
There is an interview question that is, "How to determine whether a point lies inside a rectangle"
Note that the rectangle could be rotated as well. So the simple solution of checking point inside the rectangle doesn't stands valid here...
Please share your thoughts on this question..
I found a link on internet, and was trying to understand it, but failed.... Please if any body out here can give complete solution with bit of computer graphics logic, because i have forgotten all the basics....
How to determine if a point is inside rectangle.
Pick a point that's definitely outside the rectangle. Then create a segment from that point to the point in question. Solve the linear equations for intersections between that segment and the segments that make up the rectangle. If you get exactly one intersection, the point is inside the rectangle. Otherwise (0 or 2 intersections), it's outside.
This is trivial to extend to essentially any polygon -- an odd number of intersections means the point is inside the polygon, and an even number means it's outside.
Edit: It may not be immediately obvious, so I'll emphasize that the point we pick outside the rectangle (polygon) is entirely arbitrary. We can pick whatever point we want as long as we're sure it's outside the polygon. To keep our computations easy, what we'll typically do is pick (Px, infinity) (where Px is the x coordinate of the point P that we're testing) -- that is, what we're creating is essentially a vertical ray. That simplifies testing a bit, because we only have to test against one end-point to find an intersection. It also simplifies solving the linear equations to the point that it's barely recognizable as solving linear equations anymore. We really just need to compute the Y coordinate for the line at the Px, and see if it's greater than Py. As such, solving the linear equation breaks down to:
checking whether that X value is within the range of X values for the segment
if it is, plugging the X value into the equation of the line
testing whether the resulting Y value is greater than Py
If those pass, we have an intersection. Also note that the tests can be carried out in parallel (handy if we're doing this on parallel hardware like a GPU).
Simple solution that works in N dimensions for convex polyhedra, of which a 2-dimensional rectangle is a special case:
Represent the polyhedron as the intersection of half-spaces, each defined by a unit normal vector and the distance of the surface hyperplane from the origin along the normal.
For each of these half-spaces, take the dot product of point in question with the defining normal vector. The point is in the half-space if and only if the dot product is less than [or equal to] the defining distance.
The point is inside the polyhedron if and only if it's in every one of the half-spaces.
For a rectangle defined as a counter-clockwise sequence of edges, step 1 amounts to rotating the edges each by 90 degrees clockwise to get the normals, then intersecting the normal line with the line containing the edge to find the distance to the origin.
Assuming step 1 is complete, testing a point takes at most 8 multiplications, 4 additions, and 4 comparisons.
If you want to, you can optimize the process a bit since you have rectangles (and thus opposite sides have opposite normals). Now you're only looking at 2 normals rather than 4, and a range of dot product values which indicate points that lie between the opposite sides. So now you're down to 4 multiplications, 2 additions, and 4 comparisons.
You can also get lucky if the first test you make shows that the point is outside the rectangle, in which case it's just 2 multiplications, 1 addition, and 1-2 comparisons.
This is far from the best solution... But if you have the points in consecutive order, call them a, b, c, and d with an x and a y field, you can use the cross product of the vectors between your point p and each of the consecutive pairs.
If you always get the same sign for the result (i.e., all are positive or all are negative) then you're inside the rectangle; otherwise, you're outside.
Define a new coordinate system with two rectangle sides as unit vectors and transform the coordinate of the point into the new coordinate system. If both coordinates are between 0 and 1, it's inside.
In equations (assuming A,B,C,D are corners of the rectangle, P is the point, _x and _y are the x and y components):
P_x = A_x + x * (B_x - A_x) + y * (D_x - A_x)
P_y = A_y + x * (B_y - A_y) + y * (D_y - A_y)
Solve for x and y and check if they are between 0 and 1
Written as linear equation system (A,B,C,D,P are vectors of length 2):
[ | ] [x] [ ]
[B-A | D-A] * [ ] = [P-A]
[ | ] [y] [ ]
Solving is easy as it has only two dimensions and you can be sure that you are not singular.
You can rotate and move your reference system so it matches position and rotation of the rectangle. Now it is just a matter of simple comparisons between coordinates. This is more a mathematical way, so not the fastest (bellieve #Platinum Azure's one is)
Since the rectangle could be rotated, you might want to consider an algorithm that is used to determine whether a point is interior to a convex polygon.
You could also compute the rotation angle of the rectangle, then transform both the rectangle and the point to axially align the rectangle. Then check to see if the transformed point is inside the axially aligned rectangle.
Finding whether a point lies within a bounded region like rectangle is part of the classic clipping algorithms. Refer to the wikipedia articles on Clipping and Line Clipping to know more about it.
Following the spirit of #Jerry Coffin: create segments from rectangle corners to the point in question. Solve the linear equations. Slope is tan(a). Sum up all seq arctangents diff, if it is 2*PI and each diff < PI - point is inside the rectangle.
Edit Probably enough just check for each sequential difference < Pi...