What is, and is there, a fast way to check where in the plane my line will intersect, if i know the plane is always in the same z-axis (so it cannot be rotated), and its width/height is infinite? Also, my "line" isn't actually a line, but a 3d vector, so the "line" can go to infinite distance.
Here is the code that relies on two points:
(p1 and p2 are start and end points of the line. plane_z = where the plane is)
k1 = -p2.z/(p1.z-p2.z-plane_z);
k2 = 1.0f-k1;
ix = k1*p1.x + k2*p2.x;
iy = k1*p1.y + k2*p2.y;
iz = plane_z; // where my plane lays
Another solution which works with a vector (i made it use two points as the first example did too, "p2.x-p1.x" etc. is the vector calculation):
a = (plane_z-p1.z)/(p2.z-p1.z);
ix = p1.x + a*(p2.x-p1.x);
iy = p1.y + a*(p2.y-p1.y);
iz = plane_z;
Edit3: added Orbling's solution which is slightly faster, and doesnt rely on two points necessarily.
You can implement a strait-forward solution like there http://paulbourke.net/geometry/planeline/, then apply your simplifications. In the algebraic solution (#2) A and B are zeros in your case (if i understand correctly this statement)
plane is always in the same z-axis (so it cannot be rotated)
Note: your line should be a point and a direction, or two points right?
Related
After reading several posts about getting the 2D transformation of 2D points from one image to another, estimateRigidTransform() seems to be the recommendation. I'm trying to use it. I modified the source code (to change the RANSAC parameters, because its hardcoded, and the hardcoded parameters are not very good)(the source code for this function is in lkpyramid.cpp). I have read up on how RANSAC works, and am trying to understand the steps in estimateRigidTransform().
// choose random 3 non-complanar points from A & B
...
// additional check for non-complanar vectors
a[0] = pA[idx[0]];
a[1] = pA[idx[1]];
a[2] = pA[idx[2]];
b[0] = pB[idx[0]];
b[1] = pB[idx[1]];
b[2] = pB[idx[2]];
double dax1 = a[1].x - a[0].x, day1 = a[1].y - a[0].y;
double dax2 = a[2].x - a[0].x, day2 = a[2].y - a[0].y;
double dbx1 = b[1].x - b[0].x, dby1 = b[1].y - b[0].y;
double dbx2 = b[2].x - b[0].x, dby2 = b[2].y - b[0].y;
const double eps = 0.01;
if( fabs(dax1*day2 - day1*dax2) < eps*std::sqrt(dax1*dax1+day1*day1)*std::sqrt(dax2*dax2+day2*day2) ||
fabs(dbx1*dby2 - dby1*dbx2) < eps*std::sqrt(dbx1*dbx1+dby1*dby1)*std::sqrt(dbx2*dbx2+dby2*dby2) )
continue;
Is it a typo that it uses non-coplanar vectors? I mean the 2D points are all on the same plane right?
My second question is what is that if condition doing? I know that the left hand side (gives the area of triangle times 2) would be zero or near zero if the points are collinear, and the right hand side is the multiplication of the lengths of 2 sides of the triangle.
Collinearity is preserved in affine transformations (such as the one you are probably estimating), but this transformations also calculate also changes in rotations in point of view (as if you rotated the object in a 3d world). However, these points will be collinear as well, so for the algorithm it may have not a unique solution. Look at the pictures:
imagine selecting 3 center points of each black square in the first row in the first image. Then map it to the same centers in the next image. It may generate a mapping to that solution, but also a mapping to a zoom version of the first one. The same may happen with the third one, just that this time may map to a zoom out version of the first one (without any other change). However if the points are not collinear, for example, 3 corner squares centers, it will find a unique mapping.
I hope this helps you to clarify your doubts. If not, leave a comment
Im trying to calculate the angle between two edges in a graph, in order to do that I transfer both edges to origin and then used dot product to calculate the angle. my problem is that for some edges like e1 and e2 the output of angle(e1,e2) is -1.#INDOO.
what is this output? is it an error?
Here is my code:
double angle(Edge e1, Edge e2){
Edge t1 = e1, t2 = e2;
Point tail1 = t1.getTail(), head1 = t1.getHead();
Point u(head1.getX() - tail1.getX(), head1.getY() - tail1.getY());
Point tail2 = t2.getTail(), head2 = t2.getHead();
Point v(head2.getX() - tail2.getX(), head2.getY() - tail2.getY());
double dotProduct = u.getX()*v.getX() + u.getY()*v.getY();
double cosAlpha = dotProduct / (e1.getLength()*e2.getLength());
return acos(cosAlpha);
}
Edge is a class that holds two Points, and Point is a class that holds two double numbers as x and y.
Im using angle(e1,e2) to calculate the orthogonal projection length of a vector like b on to a vector like a :
double orthogonalProjectionLength(Edge b, Edge a){
return (b.getLength()*sin(angle(b, a) * (PI / 180)));
}
and this function also sometimes gives me -1.#INDOO. you can see the implementation of Point and Edge here.
My input is a set S of n Points in 2D space. Iv constructed all edges between p and q (p,q are in S) and then tried to calculate the angle like this:
for (int i = 0; i < E.size(); i++)
for (int j = 0; j < E.size(); j++){
if (i == j)
cerr << fixed << angle(E[i], E[j]) << endl; //E : set of all edges
}
If the problem comes from cos() and sin() functions, how can I fix it? is here other libraries that calculate sin and cos in more efficient way?
look at this example.
the inputs in this example are two distinct points(like p and q), and there are two Edges between them (pq and qp). shouldnt the angle(pq , qp) always be 180 ? and angle(pq,pq) and angle(qp,qp) should be 0. my programm shows two different kinds of behavior, sometimes angle(qp,qp) == angle(pq,pq) ==0 and angle(pq , qp) == angle(pq , qp) == 180.0, and sometimes the answer is -1.#INDOO for all four edges.
Here is a code example.
run it for several times and you will see the error.
You want the projection and you go via all this trig? You just need to dot b with the unit vector in the direction of a. So the final answer is
(Xa.Xb + Ya.Yb) / square_root(Xa^2 + Ya^2)
Did you check that cosAlpha doesn't reach 1.000000000000000000000001? That would explain the results, and provide another reason not to go all around the houses like this.
It seems like dividing by zero. Make sure that your vectors always have 0< length.
Answer moved from mine comment
check if your dot product is in <-1,+1> range ...
due to float rounding it can be for example 1.000002045 which will cause acos to fail.
so add two ifs and clamp to this range.
or use faster way: acos(0.99999*dot)
but that lowers the precision for all angles
and also if 0.9999 constant is too big then the error is still present
A recommended way to compute angles is by means of the atan2 function, taking two arguments. It returns the angle on four quadrants.
You can use it in two ways:
compute the angles of u and v separately and subtract: atan2(Vy, Vx) - atan2(Uy, Ux).
compute the cross- and dot-products: atan2(Ux.Vy - Uy.Vx, Ux.Uy + Vx.Vy).
The only case of failure is (0, 0).
I have a set of points in 3d. I form a line by joining these points. I have to obtain another line which is a shifted version of this line, such that the resultant shift is always to the right of the original line. What would be an approach to solve this problem? How to get the up vectors in the right direction each time?
Assume these points to lie on a sphere. Looking at the top view of the sphere i would want something like this
/\/\/\/\
/\/\/\/\
The first line is the original set of points and the second one the shifted set
Ok i am adding the code
std::vector<osg::Vec3> vertArray; // The array containig the 3d points
std::vector<osg::Vec3> shiftVec; // The array to store the shifted vectors
osg::Vec3 line1, line2, result, upVec, p1, p2, cross1, cross2;
result = vertArray[1] - vertArray[0];
result.normalise();
result = result X upVec; // i am not sure how to get this upvec for general set of points
shiftVec.push_back(result);
for(unsigned int i = 1; i < vertArray.size() - 1; i++)
{
line 1 = vertArray[i-1] - vertArray[i];
line 2 = vertArray[i+1] - vertArray[i];
line1.normalise();
line2.normalise();
upVec = line1 X line2;
line 1 = line1 X upVec;
p1 = vertArray[i-1] + line1;
line 2 = line2 X upVec;
p2 = vertArray[i+1] + line2;
cross1 = upVec;
cross2 = (p2-p1)X line2
float factor = cross2.lenght()/cross1.length();
result = p1+line1*factor;
result = result - vertArray[i];
shiftVec.push_back(result);
}
result = vertArray[i] - vertArray[i-1];
result.normalise();
result = result X upVec; // i am not sure how to get this upvec for general set of points
shiftVec.push_back(result);
look here: ECEF <-> ENU coordinates this might help
I rather use NEH local North,East,Height(or altitude) coordinate system
it is similar to compass + altimeter
if you are not looking in rotation axis direction (ECEF Z-axis) ... on poles
then North vector is just (0,0,6356754.7)-viewer_position (all in ECEF)
East,West vectors can be obtained as North x (0,0,6356754.7)
don`t remember if it is east or west (depends on your coordinate system and cross multiplicants order)
just check it visually and if wrong reverse the order or negate result
Up vector (Height or Altitude) is easy from this just Up=North x East or Up=North x West
again if wrong direction reverse order or negate result ...
[Notes]
6356754.7 [m] is earths polar radius
if you viewing from poles (ECEF Z-axis)
then North vector and Up vector lies on the same axis (in opposite direction)
which means there is no east or west (singularity)
on south hemisphere is usually used South instead of North
in that case South = (0,0,-6356754.7)-viewer_position
If you three points are A, B and C. Then the three point define a plane. In general the points will not lie on a (straight) line. If they do then it becomes ambiguous what "right" means. If everything is on a sphere, then the three points will define a curve formed by the intersection of the sphere and the plane. You could form another line my finding the intersection of the sphere with a parallel plane.
I'm not quite sure what you want but I'm guessing you want the second line to lie in a parallel plane. You can find the normal to the plane by taking the cross product N=(A-B) X (C-B). It looks like you are doing something like this but you need the ^ operator. See https://www8.cs.umu.se/kurser/TDBD12/VT04/lab/osg/html/doc++/osg/Vec3.html#DOC.2.224.21
upVec = line1 ^ line2;
I have a ground set up of various points, some of which are flat and others are at an angle, I'm trying to check if there is a collision between the angled points (non-axis aligned).
I have a vector array consisting of two floats at each point - This is each of the points of the ground.
Here's an image representation of what the ground looks like.
http://i.imgur.com/cgEMqUv.png?1?4597
At the moment I want to check collisions between points 1 and 2 and then go onto the others.
I shall use points 1 and 2 as an example.
g1x = 150; g2x = 980;
g2x = 500; g2y = 780;
The dxdy of this is dx = 350 and dy = -200
The normal x of this is dy and the normal y is -dx
nx = -200;
ny = -350;
normalized it is the length between points 1 and 2 which is 403.11
nx/normalized = -0.496
ny/normalized = -0.868
//get position of object - Don't know if its supposed to be velocity or not
float vix = object->getPosition().x;
float viy = object->getPosition().y;
//calculate dot product - unsure if vix/viy are supposed to be minused
float dot = ((-vix * nrmx) + (-viy * nrmy)) * nrmx; //= -131.692
Is this information correct to calculate the normal and dot product between the two points.
How can I check if there is a collision with this line and then reflect according to the normal.
Thanks :) any and all changes are welcome.
Say you have a particle at position x travelling at velocity v and a boundary defined by the line between a and b.
We can find how far along the boundary (as a fraction) the particle collides by projecting c-a onto b-a and dividing by the length ||b-a||. That is,
u = ((c-a).((b-a)/||b-a||))/||b-a|| == (c-a).(b-a) / ||b-a||2.
If u > 1 then the particle travels past the boundary on the b side, if u < 0 then the particle travels past the boundary on the a side. The point of collision would be
c = a + u b.
The time to collision could be found by solving
x + t v = a + s (b-a)
for t. The reflection matrix can be found here. But it will need to be rotated by 90 deg (or pi/2) so that you're reflecting orthogonal to the line, not across it.
In terms of multiple boundaries, calculate the time to collision for each of them, sort by that time (discarding negative times) and check for collisions through the list. Once you've found the one that you will collide with then you can move your particle to the point of collision, reflect it's velocity, change the delta t and redo the whole thing again (ignoring the one you just collided with) as you may collide with more than one boundary in a corner case (get it? It's a maths pun).
Linear algebra can be fun, and you can do so much more with it, getting to grips with linear algebra allows you to do some powerful things. Good luck!
I can't find this answer anywhere, I hope somebody could help me.
I have an image (all black) with a white generic quadrilateral polygon inside it, and the correspondent 4 corners coordinates of such polygon.
I need to find the corners of a slightly enlarged quadrilateral and the same for a slightly reduced one (the shape must be the same, just a resize of the quadrilateral inside the image).
Is there a function which allows me to do that, or should I compute manually some geometry?
Thank you for your help.
Consider a vertex p of the polygon, with its predecessor p1 and successor p2.
The vectors between these points are
v1 = p1 - p
v2 = p2 - p
(The computation is componentwise for the x and y coordinates respectively).
In the shrunk polygon the vertex p is moved to p' along the line
which halves the angle a between the vectors v1 and v2.
The vector w in this direction is
w = v1 + v2
and the unit vector v in this direction is
v = w / |w| = (w_x, w_y) / sqrt(w_x*w_x + w_y*w_y)
The new point p' is
p' = p + k * v , i.e. :
p_x' = p_x + k * v_x
p_y' = p_y + k * v_y
where k is the shifting distance (a scalar).
If the vertex p is convex (as in the figure), then k >= 0 means
shrinking and k <= 0 means expanding.
If the vertex p is concave, then k >= 0 means
expanding and k <= 0 means shrinking.
What you want is polygon offset. If you want to use an existing library. Consider using Clipper
void OffsetPolygons(const Polygons &in_polys,
Polygons &out_polys,
double delta,
JoinType jointype = jtSquare, double MiterLimit = 2.0);
This function offsets the 'polys' polygons parameter by the 'delta' amount. Positive delta values expand outer polygons and contract inner 'hole' polygons. Negative deltas do the reverse.
Although I must add for a simple geometry like a Quadrilateral it is easy to do it from scratch.
Identity all four infinite lines that form the Quadrilateral
Offset the lines parallel to themselves
Compute intersection of these new lines
Just be careful of corner cases. When you offset a quadrilateral which has one very small edge. It will become a triangle on offset.
I agree with the answer of parapura rajkumar. I wanted to add that the solution of Jiri is not 100% correct because the vertex centroid of a quadrilateral is different to the area centroid of a quadrilateral, as it is written here. For the enlargement one would have to use the area centroid - or the much more elegant solution with the parallel lines mentioned by parapura rajkumar. I just want to add the following to this answer:
You can simply determine the outer points of the enlarged quadrilateral by computing the normal vectors of the vectors between the points of the original quadrilateral. Afterwards, normalize the normal vectors, multiply them with the offset and add them to the points of the original quadrilateral. Given these outer points you can now compute the intersection of the parallel lines with this formula.