I'm stuck on a problem where I'm suppose to create a function to calculate the distance between two points. This is the code we were given in class:
typedef struct Point3D {
double x;
double y;
double z;
} point3d_t;
// Structure for a triangle in 3d
typedef struct Triangle3D {
point3d_t pts[3]; // Lines between points implicit
} triangle3d_t;
// Distance between two points
double distance(point3d_t *p1, point3d_t *p2){
}
Initially I thought that the code in double distance was going to be the following, but I couldn't compile:
distance = (sqrt((p2-p1)*(p2-p1)));
Anyone what should be in double distance?
Getting a distance in 3D space is not much different than in 2D space:
you have 3 vectors, dx, dy, dz. The distance is sqrt(dx^2 + dy^2 + dz^2)
Your code didn't compile because it doesn't balance parenthesis, but it is also incorrect as it only accounts for 2 dimensions and multiplies instead of adds.
For you code, you need to do a simple calculation to get dx, dy, dz:
double distance(point3d_t *p1, point3d_t *p2){
double dx,dy,dz;
dx = p2->x - p1->x;
dy = p2->y - p1->y;
dz = p2->z - p1->z;
return sqrt(dx*dx + dy*dy + dz*dz);
}
Note, sign doesn't matter on our deltas, since they get squared and will always be positive.
For a quick proof of the distance formula, you start with Pythagorean theorem, and then realize that any two vectors (say, dx and dy) form a right triangle, with sqrt(dx^2 + dy^2) as the length of hypotenuse. The hypotenuse forms another right triangle with dz, so applying pythagorean theorem again, we get:
sqrt(sqrt(dx^2 + dy^2) ^ 2 + dz^2)
which simplifies to:
sqrt( dx^2 + dy^2 + dz^2 )
Related
I am in the process of writing a function to test for the intersection of a rectangle with a superellipse.
The rectangle will always be axis-aligned whereas the superellipse may be oriented with an angle of rotation alpha.
In the case of an axis-aligned rectangle intersecting an axis-aligned superellipse I have written these two short functions that work beautifully.
The code is concise, clear and efficient. If possible, I would like to keep a similar structure for the new more general function.
Here is what I have for detecting if an axis-aligned rectangle intersects an axis-aligned superellipse:
double fclamp(double x, double min, double max)
{
if (x <= min) return min;
if (x >= max) return max;
return x;
}
bool rect_intersects_superellipse(const t_rect *rect, double cx, double cy, double rx, double ry, double exponent)
{
t_pt closest;
closest.x = fclamp(cx, rect->x, rect->x + rect->width);
closest.y = fclamp(cy, rect->y, rect->y + rect->height);
return point_inside_superellipse(&closest, cx, cy, rx, ry, exponent);
}
bool point_inside_superellipse(const t_pt *pt, double cx, double cy, double rx, double ry, double exponent)
{
double dx = fabs(pt->x - cx);
double dy = fabs(pt->y - cy);
double dxp = pow(dx, exponent);
double dyp = pow(dy, exponent);
double rxp = pow(rx, exponent);
double ryp = pow(ry, exponent);
return (dxp * ryp + dyp * rxp) <= (rxp * ryp);
}
This works correctly but - as I said - only for an axis-aligned superellipse.
Now I would like to generalize it to an oriented superellipse, keeping the algorithm structure as close to the above as possible.
The obvious expansion of the previous two functions would then become something like:
bool rect_intersects_oriented_superellipse(const t_rect *rect, double cx, double cy, double rx, double ry, double exponent, double radians)
{
t_pt closest;
closest.x = fclamp(cx, rect->x, rect->x + rect->width);
closest.y = fclamp(cy, rect->y, rect->y + rect->height);
return point_inside_oriented_superellipse(&closest, cx, cy, rx, ry, exponent, radians);
}
bool point_inside_oriented_superellipse(const t_pt *pt, double cx, double cy, double rx, double ry, double exponent, double radians)
{
double dx = pt->x - cx;
double dy = pt->y - cy;
if (radians) {
double c = cos(radians);
double s = sin(radians);
double new_x = dx * c - dy * s;
double new_y = dx * s + dy * c;
dx = new_x;
dy = new_y;
}
double dxp = pow(fabs(dx), exponent);
double dyp = pow(fabs(dy), exponent);
double rxp = pow(rx, exponent);
double ryp = pow(ry, exponent);
return (dxp * ryp + dyp * rxp) < (rxp * ryp);
}
For an oriented superellipse, the above doesn’t work correctly, even though point_inside_oriented_superellipse() by itself works as expected. I cannot use the above functions to test for an intersection with an axis-aligned rectangle. I have been researching online for about a week now and I have found some solutions requiring an inverse matrix transform to equalize the superellipse axes and bring its origin at (0, 0). The tradeoff is that now my rectangle won’t be a rectangle anymore and certainly not axis-aligned. I would like to avoid going down that route.
My question is to show how to make the above algorithm work keeping its structure more or less unaltered. If it is not possible to keep the same algorithmic structure, please show the simplest, most efficient algorithm to test for the intersection between an axis-aligned rectangle and an oriented superellipse. I only need to know if the intersection occurred or not (boolean result).
The range of the exponent parameter can vary from 0.25 to 100.0.
Thanks for any assistance.
Take a look at point 2 in this source. In simple terms, you will need to do the following tests:
1. Are there any rectangle vertexes in the ellipse?
2. Is a rectangle edge intersecting the ellipse?
3. Is the center of the ellipse inside the rectangle?
The ellipse and the rectangle intersect each-other if any of the questions above can be answered with a yes, so, your function should return something like this:
return areVertexesInsideEllipse(/*params*/) || areRectangleEdgesIntersectingEllipse(/*params*/) || isEllipseCenterInsideRectangle(/*params*/);
The doc even has an example of implementation, which is reasonably close to yours.
To check whether any of the vertex is inside the ellipse, you can compute their coordinates against the inequality of the ellipse. To check whether an edge overlaps the ellipse, you will need to check whether its line goes through the ellipse or touches it. If so, you will need to check whether the segment where the line goes through the ellipse or touches it intersects the segment defined by the edge. To check whether the center of the ellipse is inside the rectangle you will need to check the center against the inequalities of the rectangle.
Note, that these are very general terms, they do not even assume that your rectangle is axis oriented, yet alone your ellipse.
First you should rule out the obvious non-intersecting cases using the separating axis theorem -- The super-ellipse has possibly two bounding boxes (cases where exponent n>1) and case where n<=1.
In the SAT, all vertices in Bounding Box ABCD are compared against all (directed) edges in the BB(abcd) of super-ellipse; then vice versa. If the signed distances to the separating axis are all positive (i.e. outside), the objects don't collide.
b
a
A------B
| | d
| | c
C------D
The exponent n==1 divides the cases further -- n<=1 makes the super-ellipsoid concave, in which case ABCD intersects abcd only, if one or more points are inside the super-ellipsoid.
When n>1, one must solve the intersection point of the line segment in AABB and the super-ellipsoid, which may have to be approximated by splines or another proxy must be found. After all, the actual intersection point is not of interest, but putting the equations to wolfram alpha failed to produce any results in standard execution time.
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.)
I want to check if a point P(x1,y1) belongs , is inside , a square with center C(x,y) and horizontal diagonal r.
Square with the above characteristics:
Function that calculates the distance between two points
float calculate_distance (float x1,float y1,float x2 ,float y2)
{
float distance;
float distance_x = x1-x2;
float distance_y = y1- y2;
distance = sqrt( (distance_x * distance_x) + (distance_y * distance_y));
return distance;
}
You don't need the Euclidian distance between points here.
Just as for a circle (at the origin) you know that x2+y2 is some constant (r2), here you know that |x|+|y| is some constant (r again), which is even simpler. Actually you can interpolate between these shapes by using exponents between 1 and 2.
So to check whether a point (x,y) is inside the diamond (which without loss of generality can be assumed to be centered on the origin), just test
fabsf(x)+fabsf(y) <= r
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)
Have created a c++ implementation of the Hough transform for detecting lines in images. Found lines are represented using rho, theta, as described on wikipedia:
"The parameter r represents the distance between the line and the origin, while θ is the angle of the vector from the origin to this closest point "
How can i find the intersection point in x, y space for two lines described using r, θ?
For reference here are my current functions for converting in and out of hough space:
//get 'r' (length of a line from pole (corner, 0,0, distance from center) perpendicular to a line intersecting point x,y at a given angle) given the point and the angle (in radians)
inline float point2Hough(int x, int y, float theta) {
return((((float)x)*cosf(theta))+((float)y)*sinf(theta));
}
//get point y for a line at angle theta with a distance from the pole of r intersecting x? bad explanation! >_<
inline float hough2Point(int x, int r, float theta) {
float y;
if(theta!=0) {
y=(-cosf(theta)/sinf(theta))*x+((float)r/sinf(theta));
} else {
y=(float)r; //wth theta may == 0?!
}
return(y);
}
sorry in advance if this is something obvious..
Looking at the Wikipedia page, I see that the equation of a straight line corresponding to a given given r, θ pair is
r = x cosθ + y sinθ
Thus, if I understand, given two pairs r1, θ1 and r2, θ2, to find the intersection you must solve for the unknowns x,y the following linear 2x2 system:
x cos θ1 + y sin θ1 = r1
x cos θ2 + y sin θ2 = r2
that is AX = b, where
A = [cos θ1 sin θ1] b = |r1| X = |x|
[cos θ2 sin θ2] |r2| |y|
Had never encountered matrix maths before, so took a bit of research and experimentation to work out the proceedure for Fredrico's answer. Thanks, needed to learn about matrices anyway. ^^
function to find where two parameterized lines intersect:
//Find point (x,y) where two parameterized lines intersect :p Returns 0 if lines are parallel
int parametricIntersect(float r1, float t1, float r2, float t2, int *x, int *y) {
float ct1=cosf(t1); //matrix element a
float st1=sinf(t1); //b
float ct2=cosf(t2); //c
float st2=sinf(t2); //d
float d=ct1*st2-st1*ct2; //determinative (rearranged matrix for inverse)
if(d!=0.0f) {
*x=(int)((st2*r1-st1*r2)/d);
*y=(int)((-ct2*r1+ct1*r2)/d);
return(1);
} else { //lines are parallel and will NEVER intersect!
return(0);
}
}