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);
}
}
Related
Programming Language: C
I'm currently in the process of implementing a 3D wireframe model represented through isometric projection.
My current understanding of the project is to:
parse a text map containing the x,y,z coordinates of the wireframe model
Transforming the 3D coordinates to 2D using isometric projection
Drawing the line using the Bresenham Line Algo and a few functions out of my graphic library of choice.
I'm done with Step 1 however I've been stuck on Step 2 for the last few days.
I understand that isometric projection is the process of projecting a 2D plane in a angle that it looks like it's 3D even though we are only working with x,y when drawing the lines. That is def. not the best way of describing it and if I'm incorrect please correct me.
Example of a text map:
0 0 0
0 5 0
0 0 0
My data structure of choice (implemented as array of structs)
typedef struct point
{
float x;
float y;
float z;
bool is_last;
int color; // Implemented after mandatory part
} t_point;
I pretty much just read out the rows, column and values of the text map and store them in x,y,z values respectively.
Now that I have to transform them I've tried the following formulas:
const double angle = 30 * M_PI / 180.0;
void isometric(t_dot *dot, double angle)
{
dot->x = (dot->x - dot->y) * cos(angle);
dot->y = (dot->x + dot->y) * sin(angle) - dot->z;
}
static void iso(int x, int y, int z)
{
int previous_x;
int previous_y;
previous_x = x;
previous_y = y;
x = (previous_x - previous_y) * cos(0.523599);
y = -z + (previous_x + previous_y) * sin(0.523599);
}
t_point *calc_isometric(t_point *pts, int max_pts)
{
float x;
float y;
float z;
const double angle = 30 * M_PI / 180.0;
int num_pts;
num_pts = 0;
while (num_pts < max_pts)
{
x = pts[num_pts].x;
y = pts[num_pts].y;
z = pts[num_pts].z;
printf("x: %f y: %f z: %f\n", x, y, z);
pts[num_pts].x = (x - y) * cos(angle);
pts[num_pts].y = (x + y) * sin(angle) - z;
printf("x_iso %f\ty_iso %f\n\n", pts[num_pts].x, pts[num_pts].y);
num_pts++;
}
return (pts);
}
It spits out various things which makes no sense to me. I could just go one and try to implement the Line Algo. from here and hope for the best but I would like to understand what I'm actually doing here.
Next to that I learned through me research that I need to set up my camera in a certain way to create the projection.
All in all I'm just very lost and my question boils down to this.
Please help me understand the concept of isometric projection.
How to transform 3D coordinates (x,y,z) into coordinates using isometric projection.
I see it like this:
// constants:
float deg = M_PI/180.0;
float ax = 30*deg;
float ay =150*deg;
vec2 X = vec2(cos(ax),-sin(ax)); // x axis
vec2 Y = vec2(cos(ay),-sin(ay)); // y axis
vec2 Z = vec2( 0.0,- 1.0); // z axis
vec2 O = vec2(0,0); // position of point (0,0,0) on screen
// conversion:
vec3 p=vec3(?,?,?); // input point
vec2 q=O+(p.x*X)+(p.y*Y)+(p.z*Y); // output point
the coordinatewise version:
float Xx = cos(ax);
float Xy = -sin(ax);
float Yx = cos(ay);
float Yy = -sin(ay);
float Zx = 0.0;
float Zy = - 1.0;
float Ox = 0;
float Oy = 0;
// conversion:
float px=?,py=?,pz=?; // input point
float qx=Ox+(px*Xx)+(py*Yx)+(pz*Yx); // output point
float qy=Oy+(px*Xy)+(py*Yy)+(pz*Yy); // output point
Asuming x axis going to right and y axis going down ... the O is usually set to center of screen instead of (0,0) unless you add pan capabilities of your isometric world.
In case you want to add arbitrary rotations within the "3D" XY plane see this:
How can I warp a shader matrix to match isometric perspective in a 3d scene?
So you just compute the X,Y vectors on the ellipse (beware they will not be unit anymore!!!) So if I see it right it would be:
float ax=?,ay=ax+90*deg;
float Xx = cos(ax) ;
float Xy = -sin(ax)*0.5;
float Yx = cos(ay) ;
float Yy = -sin(ay)*0.5;
where ax is the rotation angle...
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 )
I'm trying to implement an atan2-like function to map two input sinusoidal signals of arbitrary relative phase shift to a single output signal that linearly goes from 0 to 2π. atan2 normally assumes two signals with a 90 deg phase shift.
Given y0(x) = sin(x) and y1 = sin(x + phase), where phase is a fixed non-zero value, how can I implement a way to return x modulo 2π?
atan2 returns the angle of a 2d vector. Your code does not handle such scaling properly. But no worries, it's actually very easy to reduce your problem to an atan2 that would handle everything nicely.
Notice that calculating sin(x) and sin(x + phase) is the same as projecting a point (cos(x), sin(x)) onto the axes (0, 1) and (sin(phase), cos(phase)). This is the same as taking dot products with those axes, or transforming the coordinate system from the standard orthogonal basis into the skewed one. This suggests a simple solution: inverse the transformation to get the coordinates in the orthogonal basis and then use atan2.
Here's a code that does that:
double super_atan2(double x0, double x1, double a0, double a1) {
double det = sin(a0 - a1);
double u = (x1*sin(a0) - x0*sin(a1))/det;
double v = (x0*cos(a1) - x1*cos(a0))/det;
return atan2(v, u);
}
double duper_atan2(double y0, double y1, double phase) {
const double tau = 6.28318530717958647692; // https://tauday.com/
return super_atan2(y0, y1, tau/4, tau/4 - phase);
}
super_atan2 gets the angles of the two projection axes, duper_atan2 solves the problem exactly as you stated.
Also notice that the calculation of det is not strictly necessary. It is possible to replace it by fmod and copysign (we still need the correct sign of u and v).
Derivation:
In code:
// assume phase != k * pi, for any integer k
double f (double y0, double y1, double phase)
{
double u = (- y0 * cos(phase) + y1) / sin(phase);
double v = y0;
double x = atan2 (v, u);
return (x < 0) ? (x + 2 * M_PI) : x;
}
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 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