MATLAB, interpolation of 3D curve crossing xy plane - arrays

In Matlab, I have a 3D-curve (array with 3 coordinates) that crosses the xy-plane in a 3 dimensional coordinate system. The "curve" is just a bunch of x,y,z points and its shape is elliptical that spans across the 3D space and spirals towards the origin. It crosses the xy plane several times and I would like to interpolate the x and y coordinates when the curve intersects the xy plane (i.e. when z=0). How do I do so?

Assuming you have 3 vectors x, y, and z with coordinates,
crossidx = find(diff(sign(z)) ~= 0); % z(zcross) and z(zcross+1) have different signs
z1 = z(crossidx);
z2 = z(crossidx+1);
dz = z2 - z1;
alpha = -z1;
beta = z2;
xcross = (beta*x(crossidx) + alpha*x(crossidx+1))./dz;
ycross = (beta*y(crossidx) + alpha*y(crossidx+1))./dz;
zcross = 0;
hold on; plot3(xcross, ycross, zcross, '*');
It should work for either positive to negative or negative to positive crossing. I wrote the code assuming only 1 zero crossing, but I think it would also work for any number of crossings.

Related

Angle to Quaternion - Making an object facing another object

i have two Objects in a 3D World and want to make the one object facing the other object. I already calculated all the angles and stuff (pitch angle and yaw angle).
The problem is i have no functions to set the yaw or pitch individually which means that i have to do it by a quaternion. As the only function i have is: SetEnetyQuaternion(float x, float y, float z, float w). This is my pseudocode i have yet:
float px, py, pz;
float tx, ty, tz;
float distance;
GetEnetyCoordinates(ObjectMe, &px, &py, &pz);
GetEnetyCoordinates(TargetObject, &tx, &ty, &tz);
float yaw, pitch;
float deltaX, deltaY, deltaZ;
deltaX = tx - px;
deltaY = ty - py;
deltaZ = tz - pz;
float hyp = SQRT((deltaX*deltaX) + (deltaY*deltaY) + (deltaZ*deltaZ));
yaw = (ATAN2(deltaY, deltaX));
if(yaw < 0) { yaw += 360; }
pitch = ATAN2(-deltaZ, hyp);
if (pitch < 0) { pitch += 360; }
//here is the part where i need to do a calculation to convert the angles
SetEnetyQuaternion(ObjectMe, pitch, 0, yaw, 0);
What i tried yet was calculating the sinus from those angles devided with 2 but this didnt work - i think this is for euler angles or something like that but didnt help me. The roll(y axis) and the w argument can be left out i think as i dont want my object to have a roll. Thats why i put 0 in.
If anyone has any idea i would really appreciate help.
Thank you in advance :)
Let's suppose that the quaternion you want describes the attitude of the player relative to some reference attitude. It is then essential to know what the reference attitude is.
Moreover, you need to understand that an object's attitude comprises more than just its facing -- it also comprises the object's orientation around that facing. For example, imagine the player facing directly in the positive x direction of the position coordinate system. This affords many different attitudes, from the one where the player is standing straight up to ones where he is horizontal on either his left or right side, to one where he is standing on his head, and all those in between.
Let's suppose that the appropriate reference attitude is the one facing parallel to the positive x direction, and with "up" parallel to the positive z direction (we'll call this "vertical"). Let's also suppose that among the attitudes in which the player is facing the target, you want the one having "up" most nearly vertical. We can imagine the wanted attitude change being performed in two steps: a rotation about the coordinate y axis followed by a rotation about the coordinate z axis. We can write a unit quaternion for each of these, and the desired quaternion for the overall rotation is the Hamilton product of these quaternions.
The quaternion for a rotation of angle θ around the unit vector described by coordinates (x, y, z) is (cos θ/2, x sin θ/2, y sin θ/2, z sin θ/2). Consider then, the first quaternion you want, corresponding to the pitch. You have
double semiRadius = sqrt(deltaX * deltaX + deltaY * deltaY);
double cosPitch = semiRadius / hyp;
double sinPitch = deltaZ / hyp; // but note that we don't actually need this
. But you need the sine and cosine of half that angle. The half-angle formulae come in handy here:
double sinHalfPitch = sqrt((1 - cosPitch) / 2) * ((deltaZ < 0) ? -1 : 1);
double cosHalfPitch = sqrt((1 + cosPitch) / 2);
The cosine will always be nonnegative because the pitch angle must be in the first or fourth quadrant; the sine will be positive if the object is above the player, or negative if it is below. With all that being done, the first quaternion is
(cosHalfPitch, 0, sinHalfPitch, 0)
Similar analysis applies to the second quaternion. The cosine and sine of the full rotation angle are
double cosYaw = deltaX / semiRadius;
double sinYaw = deltaY / semiRadius; // again, we don't actually need this
We can again apply the half-angle formulae, but now we need to account for the full angle to be in any quadrant. The half angle, however, can be only in quadrant 1 or 2, so its sine is necessarily non-negative:
double sinHalfYaw = sqrt((1 - cosYaw) / 2);
double cosHalfYaw = sqrt((1 + cosYaw) / 2) * ((deltaY < 0) ? -1 : 1);
That gives us an overall second quaternion of
(cosHalfYaw, 0, 0, sinHalfYaw)
The quaternion you want is the Hamilton product of these two, and you must take care to compute it with the correct operand order (qYaw * qPitch), because the Hamilton product is not commutative. All the zeroes in the two factors make the overall expression much simpler than it otherwise would be, however:
(cosHalfYaw * cosHalfPitch,
-sinHalfYaw * sinHalfPitch,
cosHalfYaw * sinHalfPitch,
sinHalfYaw * cosHalfPitch)
At this point I remind you that we started with an assumption about the reference attitude for the quaternion system, and the this result depends on that choice. I also remind you that I made an assumption about the wanted attitude, and that also affects this result.
Finally, I observe that this approach breaks down where the target object is very nearly directly above or directly below the player (corresponding to semiRadius taking a value very near zero) and where the player is very nearly on top of the target (corresponding to hyp taking a value very near zero). There is a non-zero chance of causing a division by zero if you use these formulae exactly as given, so you'll want to think about how to deal with that.)

Texture mapping on a cylinder in C (building a raytracer)

This is my first question here so I hope I'm doing it right.
I'm trying to build a raytracer for a school project, and I'd like to add some texture mapping to my basic shapes. I already did it for the sphere and it worked perfectly, this is the algorithm I used (UV mapping):
d = vector3d_normalize(vector3d_sub(hit->point, object->position));
u = 0.5 + atan2(d.z, d.x) / M_PI * 0.5;
v = 0.5 - asin(d.y) / M_PI;
For the cylinder, I can't find any algorithm so I'm trying different things but I can't make it work. Actually, it works fine for a cylinder when it's fixed at (x: 0, y: 0, z: 0) but from the moment I'm moving it in space, the texture looks stretched.
For the code at this moment, it's the following:
d = vector3d_sub(hit->point, vector3d_mult(object->position, ray->direction));
u = 0.5 + atan2(d.z, d.x) / M_PI * 0.5;
v = d.y / M_PI;
v = v - floor(v);
Cylinder in (0, 0, 0):
With translation:
I'm stuck so if you have any idea, it could help me a lot!
Here's some pseudo-code from Jamis' Buck's The Ray Tracer Challenge (highly recommended):
// Based off of pseudocode from Jamis Buck: http://raytracerchallenge.com/bonus/texture-mapping.html
// Input: point on the cylinder. The cylinder is assumed to be of radius 1, centered at the origin and parallel with the y axis.
// Output: (u,v) with u and v both between 0 and 1.
// u will vary from 0 to 1 with the azimuthal angle, counter-clockwise.
// v will vary from 0 to 1 with whole units of y; note that the cylinder will have to be scaled by PI in the y axis to prevent stretching
map_cylinder_point_to_uv(point: (x: float, y: float, z: float)) -> (float, float) {
// compute the azimuthal angle, -PI < theta <= PI
float theta = arctan2(point.x, point.z);
// convert from radians to units
// -0.5 < rawU <= 0.5
float rawU = theta / (2 * Constants.PI)
// convert to correct scale, and flip it so that u increases with theta counter-clockwise
// 0 <= u < 1
float u = 1 - (rawU + 0.5);
// v will vary from 0 to 1 between whole units of y
// Use whatever modulus method or operator your language has to gauarantee a positive value for v.
// It's different for every programming language: https://en.wikipedia.org/wiki/Modulo_operation#In_programming_languages
float v = point.y % 1
return (u, v)
}
Your problem may have to do with the fact that you are placing a square texture on a cylinder, and the length of the texture applied to the side of a cylinder will be some multiple of 2 PI (the circumference of a circle). You may be able to fix your issue by simply scaling the cylinder in the y axis by PI or 2 PI.
If you don't want to be limited to cylinders of particular dimensions, and you have a texture that can be repeated like a checker pattern, then you can scale v to prevent stretching. Replace the v calculation above with this line, instead:
// let v go from 0 to 1 between 2*pi units of y
let v = point.y % (2 * Constants.PI) * 1 / (2 * Constants.PI);
I'll also note that these days there's also a separate stack exchange for computer graphics that might be of more help than SO: https://computergraphics.stackexchange.com/.

How to render 3D axes given pitch, roll, and yaw?

I'm attempting to render a simple axes display like the following, except using simple 2D lines.
I have angle values for the pitch, yaw, and roll that the axes should display. (e.g. PI/2, PI/4, PI*3/2)
I have a function that can render 2D lines given start and end points in 2D space.
How can I properly render a rotated set of axes given the angles? I don't care about z-indexing (so if sometimes the lines incorrectly show up on top of each other, that is OK as long as they point the correct direction).
What I've tried
I know that the start points for all the lines will just be in the center of the axis, and we'll say the center is at (0, 0) and the length of the axes will be 100. That leaves me to calculate the endpoints for each of the 3 axes.
I have defined the X axis to be left-to-right, the Y axis to be up-and-down and the Z axis to be back-forward (i.e. out of the screen).
Pitch is rotation around the X axis, roll is rotation around Z axis, and yaw is rotation around Y axis.
To calculate the X-axis end point I've done:
x = cos(roll) * cos(yaw) * 100;
y = sin(-roll) * 100;
To calculate the Y-axis end point I've done:
x = cos(roll + PI/2) * 100;
y = sin(-roll - PI/2) * sin(PI/2 - pitch) * 100;
To calculate the Z-axis end point I've done:
x = cos(PI/2 - yaw) * 100;
y = sin(PI - pitch) * 100;
It's probably evident that I don't really know what I'm doing. I feel like I am taking a very naive approach when I should be using something more advanced like matrices. If it makes a difference, I'm using C, but psuedocode is fine. Any help would be appreciated.
First, you need to agree on an order of the rotations. In the following, I assume the order x, y, z (pitch, yaw, roll).
The end points are simply the column vectors of the according rotation matrix. Then, you need to project the 3d points onto the 2d screen. It seems as if you use a simple orthogonal projection (removing the z-coordinate). So here are the results:
x1 = 100 (cos yaw * cos roll)
y1 = 100 (cos pitch * sin roll + cos roll * sin pitch * sin yaw)
x2 = 100 (-cos yaw * sin roll)
y2 = 100 (cos pitch * cos roll - sin pitch * sin yaw * sin roll)
x3 = 100 (sin yaw)
y3 = 100 (-cos yaw * sin pitch)

Finding the angle a vector makes over variable axes

The typical way to find the angle a vector makes from the x axis (assuming the x axis runs left to right, and the y axis runs bottom to top) is:
double vector_angle = atan2( y , x )
However, I want my axes to have their origin at a point on a circle so that the x axis runs from the point on the edge of the circle through the centre of the circle, and the y axis runs tangent to the circle at that point (which would thus be perpendicular to the x axis).
Assumedly the code would still be the same, but now adjusted by a distance k and an angle theta, perhaps:
double y_position = ( y + k ) * theta;
double x_position = ( x + k ) * theta;
double vector_angle = atan2( y_position, x_position );
But I'm not sure about this. This is a generalised problem for a touch-based application where I would like to have a general way to move a sprite (in cocos2d) using swipe motions which is always a constant distance from the center of a circle.
Here, B is the origin of the vector which could be transformed by a rotation theta. For example, if we transformed the circle and point B by 90 degrees, B would be at (4, 0) and the line B->A would be along the axis at 4 (y = 4). I would like to get the angle in node-space of point B, when under transform.
Arctan returns the correct angle for the vector where the "x axis" is the line perpendicular to your tangent.

How to find coordinates of a 2d equilateral triangle in C?

I have the coordinates (x,y) of 2 points. I want to build the third point so that these 3 points make an equilateral triangle.
How can I calculate the third point?
Thank you
After reading the posts (specially vkit's) I produced this simple piece of code which will do the trick for one direction (remember that there are two points). The modification for the other case shold be trivial.
#include<stdio.h>
#include<math.h>
typedef struct{
double x;
double y;
} Point;
Point vertex(Point p1, Point p2){
double s60 = sin(60 * M_PI / 180.0);
double c60 = cos(60 * M_PI / 180.0);
Point v = {
c60 * (p1.x - p2.x) - s60 * (p1.y - p2.y) + p2.x,
s60 * (p1.x - p2.x) + c60 * (p1.y - p2.y) + p2.y
};
return v;
}
You could rotate the second point 60° around first to find the location of the third point.
Something like this:
//find offset from point 1 to 2
dX = x2 - x1;
dY = y2 - y1;
//rotate and add to point 1 to find point 3
x3 = (cos(60°) * dX - sin(60°) * dY) + x1;
y3 = (sin(60°) * dX + cos(60°) * dY) + y1;
Let's call your two points A and B. Bisect AB, call this point C. Find the slope of AB (YA-YB / XA-XB), call it m. Find the perpendicular to that (-1/m) and call it m2. Then compute a segment CD whose length is sin(60) * length(AB), at the slope m2 (there will be two such points, one to each side of AB). ABD is then your equilateral triangle.
That, obviously, is a "constructive" method. You should also be able to do it by solving a set of linear equations. I haven't tried to figure out the right system of equations for this case, but this approach tends to be somewhat more stable numerically, and has fewer special cases (e.g., with the constructive version, a slope of 0 has to be dealt with specially).
For BlueRaja's challenge go to end of post:
Answer using translation and rotation:
Says points are P(x1,y1) and Q(x2,y2).
Since it is graphics, you can use tranforms to get the point.
First translate axes so P is the origin.
Next rotate Q around P by 60 degrees (or -60 to get the other possible point).
This gives you the coordinates of the third point say R, when P is the origin.
Translate back and there you have it.
You can use standard graphics API which take care of precision etc issues for you. No headaches.
Of course you could do the math and actually come up with a formula and use that and that might be faster, but then the question might get closed as off-topic ;-)
To take up BlueRaja's challenge: Here is a method which does not use trigonometry.
Given points P(x1,y1) and Q(x2,y2)
Say the point we need (R) to find is (x3,y3).
Let T be midpoint of PQ.
We know the area of triangle PQR (as it is equilateral and we know the side)
and we know the area of triangle PRT (1/2 the earlier area).
Now area of a triangle can be written as a determinant having the co-ordinates as entries:
2*Area = |D|
where
| 1 x1 y1|
D = | 1 x2 y2|
| 1 x3 y3|
We have two such equations (which are linear), solve for x3 and y3.
pc <- c((x1+x2)/2,(y1+y2)/2) #center point
ov <- c(y2-y1,x1-x2) #orthogonal vector
p3 <- pc+sqrt(3/4)*ov #The 3dr point in equilateral triangle (center point + height of triangle*orthogonal vector)

Resources