Goal
I want to determine if a test point is within a defined quadrilateral. I'm probably going to implement the solution in Matlab so I only need pseudo-code.
Inputs
Corners of quadrilateral : (x1,y1) (x2,y2) (x3,y3) (x4,y4)
Test point : (xt, yt)
Output
1 - If within quadrilateral
0 - Otherwise
Update
It was pointed out that identifying the vertices of the quadrilateral is not enough to uniquely identify it. You can assume that the order of the points determines the sides of the quadrilateral (point 1 connects 2, 2 connects to 3, 3 connects to 4, 4 connects to 1)
You can test the Point with this condition. Also you can treat quadrilateral as 2 triangles to calculate its area.
Use inpolygon. Usage would be inpolygon(xt,yt,[x1 x2 x3 x4],[y1 y2 y3 y4])
Since it's a simple quadrilateral you can test for a point in triangle for each end and a point in rectangle for the middle.
EDIT Here is some pseudo code for point in triangle:
function SameSide(p1,p2, a,b)
cp1 = CrossProduct(b-a, p1-a)
cp2 = CrossProduct(b-a, p2-a)
if DotProduct(cp1, cp2) >= 0 then return true
else return false
function PointInTriangle(p, a,b,c)
if SameSide(p,a, b,c) and SameSide(p,b, a,c)
and SameSide(p,c, a,b) then return true
else return false
Or using Barycentric technique:
A, B, and C are the triangle end points, P is the point under test
// Compute vectors
v0 = C - A
v1 = B - A
v2 = P - A
// Compute dot products
dot00 = dot(v0, v0)
dot01 = dot(v0, v1)
dot02 = dot(v0, v2)
dot11 = dot(v1, v1)
dot12 = dot(v1, v2)
// Compute barycentric coordinates
invDenom = 1 / (dot00 * dot11 - dot01 * dot01)
u = (dot11 * dot02 - dot01 * dot12) * invDenom
v = (dot00 * dot12 - dot01 * dot02) * invDenom
// Check if point is in triangle
return (u > 0) && (v > 0) && (u + v < 1)
If the aim is to code your own test, then pick any classic point in polygon test to implement. Otherwise do what Jacob suggests.
assuming you the given coordinates are arranged s.t.
(x1,y1) = rightmost coordinate
(x2,y2) = uppermost coordinate
(x3,y3) = leftmost coordinate
(x4,y4) = botoom-most coordinate
You can do the following:
1. calculate the 4 lines of the quadrilateral (we'll call these quad lines)
2. calculate 4 lines, from the (xt, yt) to every other coordinate (we'll call these new lines)
3. if any new line intersects any of the quad lines, then the coordinate is outside of the quadrilateral, otherwise it is inside.
Assume A,B,C,D are the vertices of the quadrilateral and P is the point.
If P is inside the quadrilateral then all dot products dot(BP,BA), dot(BP,BC), dot(AP,AB), dot(AP,AD), dot(DP,DC), dot(DP,DA), dot(CP,CB) and dot(CP,CD) will be positive.
If P is outside the quadrilateral at least one of these products will be negative.
The solution I used to solve this problem was to get the angle of P (in the diagrams the OP posted) for each of the 4 triangles it makes with each side of the quadrilateral. Add the angles together. If they equal (or nearly equal, depending on the error tolerance of the code) 360, the point is inside the quadrilateral. If the sum is less than 360, the point is outside. However, this might only work with convex quadrilaterals.
Related
I have drawn a 2D representation of the problem, but I will eventually have to solve this in 3 dimensions.
A line is drawn from an origin point to infinity, in a direction given by pitch and yaw. There is an axis-aligned box "in front of" the point.
I want to get the coordinates of the point on box that is closest to the line, or, if it intersects, closest to the origin point.
I.e., if the line were 'turned' towards the box, which point of the box would intersect with the line first?
Make parametric represenation of the ray with base point P0, direction vector D and parameter t
P = P0 + t * D
Get t for intersections of the ray with rectangle edges like this (similar in 3d):
Rect.Right = X0 + t * D.X
Find what intersection occurs first (smaller t), check coordinates of intersection. If inside edge - point found. If not, analyze intersection parameters with edgr continuations to determine what corner (perhaps edge in 3d) is the closest
Note that in 2d case you need to check only two possible edges - depending on ray direction. For example - left and bottom for your right picture. When you see that intersections are out of edges - check what of two corners is closer. The same for 3d - but intersection is possible for three faces and closest for more edges or corners.
Let the position of the point be (x0,y0,z0) and the box have corners (x1,y1,z1) and (x2,y2,z2) with x1 < x2, y1 < y2, z1 < z2. In terms of yaw ψ and pitch θ a unit vector along the line will be give by
(u,v,w) = (cos ψ sin θ, sin ψ, cos ψ cos θ)
The line is (x0,y0,z0) + t (u,v,w)
Finding intersection with one of the plane containing a face of the box is trivial. Say to find the intersection with the plane x=x1, just requires solving
x0 + u t = x1 so t = (x1-x0)/u. Once found its easy to check if the intersection is contained in the face.
The tricky situation happens if the line does not intersect the faces. Here we have a pair of skew lines, and wish to find the closest pair of points one on each line.
Consider the closest point to the edge from (x1,y1,z1) to (x2,y1,z1).
We want to find the parameter s,t such that that the points
(x0,y0,z0)+s(u,v,w)
(x1,y1,z1)+t(1,0,0)
are the closest. The segment joining these points must be perpendicular to both lines. A vector along that line is the cross product
N = (u,v,w) X (1,0,0) = (0,w,-v)
Now consider the plane through (x1,y1,z1) spanned by (1,0,0) and N, this has normal
N2 = (1,0,0) X N
= (1,0,0) X (0,w,-v)
= (0,v,w)
and the plane is defined by
P . N2 = (x1,y1,z1) . N2
Take a point on our ray
( (x0,y0,z0)+s(u,v,w) ) . N2 = (x1,y1,z1) . N2
(x0,y0,z0) . N2 + s (u,v,w) . N2 = (x1,y1,z1) . N2
s (u,v,w) . N2 = ((x1,y1,z1)-(x0,y0,z0)) . N2
s (v^2+w^2) = (y1-y0) v + (z1-z0) w
so
s = [ (y1-y0) v + (z1-z0) w ] / (v^2+w^2)
We can repeat the above for each edge on the box, find the closest points and select the smallest.
I have:
axis-aligned rectangle R;
non-vertical line A (specified by two points);
vertical line B (specified by x-coordinate).
All objects above is specified by integer coordinates.
I need to check, if result of crossing A and B is in the R. But I can't just calculate result of crossing A and B because it may be unpresentable in integer coordinates. Also I can't convert it to doubles because I need to get absolutely accurate result without any inaccuracy.
So, how can I check it?
If lines are specified by integer coordinates, then their crossing point has rational coordinates, which may be compared with absolutely precision.
Let's A goes through points (ax0, ay0) and (ax1, ay1), and B is at X0 coordinate.
Then crossing point Y-coordinate is (ay0*(ax1-ax0)+(X0-ax0)*(ay1-ay0))/(ax1-ax0) = p/q, where p and q are integer, and q is positive (negate nominator if needed).
Then p may be compared with R.Top*q and R.Bottom*q
[let's ignore not interesting case when B does not intersect R]
R cuts a segment from B, let's call it S. Intersection of B and A lies inside of R if and only if A crosses S.
Finding points of S is trivial.
To check whether a line crosses a segment, you should check that ends of S lie on different sides from A - this can be checked by signed angles.
Let's say that the 2 points on A are (x0, y0) and (x1, y1), with 'x0 < x1'.
The rectangle is determined by a x-coordinate xR and a y-coordinate yR
The B line is determined by the x-coordinate xB
The point you're looking for is (xB, yB), where yB is to be determined somehow, by manipulating integers only :
So first, you need to check
if xB * xR >= 0 (same side of the x-coordinate)
if abs(xB) <= abs(xR) (the B line cuts the rectangle)
If it's ok, then you need to check that this integer (which is equal to (x1-x0)yB)
Y = (y1-y0)(xB-x0)+(x1-x0)y0
verifies
Y * yR >=0 (same side of the y-coord)
abs(Y) <= (x1-x0) * abs(yR) (meaning that your intersection point is in the R area regarding its y-coord)
Your point is inside R if and only if the 4 conditions are true.
Hope it helps.
I have three vertices which make up a plane/polygon in 3D Space, v0, v1 & v2.
To calculate barycentric co-ordinates for a 3D point upon this plane I must first project both the plane and point into 2D space.
After trawling the web I have a good understanding of how to calculate barycentric co-ordinates in 2D space, but I am stuck at finding the best way to project my 3D points into a suitable 2D plane.
It was suggested to me that the best way to achieve this was to "drop the axis with the smallest projection". Without testing the area of the polygon formed when projected on each world axis (xy, yz, xz) how can I determine which projection is best (has the largest area), and therefore is most suitable for calculating the most accurate barycentric co-ordinate?
Example of computation of barycentric coordinates in 3D space as requested by the OP. Given:
3D points v0, v1, v2 that define the triangle
3D point p that lies on the plane defined by v0, v1 and v2 and inside the triangle spanned by the same points.
"x" denotes the cross product between two 3D vectors.
"len" denotes the length of a 3D vector.
"u", "v", "w" are the barycentric coordinates belonging to v0, v1 and v2 respectively.
triArea = len((v1 - v0) x (v2 - v0)) * 0.5
u = ( len((v1 - p ) x (v2 - p )) * 0.5 ) / triArea
v = ( len((v0 - p ) x (v2 - p )) * 0.5 ) / triArea
w = ( len((v0 - p ) x (v1 - p )) * 0.5 ) / triArea
=> p == u * v0 + v * v1 + w * v2
The cross product is defined like this:
v0 x v1 := { v0.y * v1.z - v0.z * v1.y,
v0.z * v1.x - v0.x * v1.z,
v0.x * v1.y - v0.y * v1.x }
WARNING - Almost every thing I know about using barycentric coordinates, and using matrices to solve linear equations, was learned last night because I found this question so interesting. So the following may be wrong, wrong, wrong - but some test values I have put in do seem to work.
Guys and girls, please feel free to rip this apart if I screwed up completely - but here goes.
Finding barycentric coords in 3D space (with a little help from Wikipedia)
Given:
v0 = (x0, y0, z0)
v1 = (x1, y1, z1)
v2 = (x2, y2, z2)
p = (xp, yp, zp)
Find the barycentric coordinates:
b0, b1, b2 of point p relative to the triangle defined by v0, v1 and v2
Knowing that:
xp = b0*x0 + b1*x1 + b2*x2
yp = b0*y0 + b1*y1 + b2*y2
zp = b0*z0 + b1*z1 + b2*z2
Which can be written as
[xp] [x0] [x1] [x2]
[yp] = b0*[y0] + b1*[y1] + b2*[y2]
[zp] [z0] [z1] [z2]
or
[xp] [x0 x1 x2] [b0]
[yp] = [y0 y1 y2] . [b1]
[zp] [z0 z1 z2] [b2]
re-arranged as
-1
[b0] [x0 x1 x2] [xp]
[b1] = [y0 y1 y2] . [yp]
[b2] [z0 z1 z2] [zp]
the determinant of the 3x3 matrix is:
det = x0(y1*z2 - y2*z1) + x1(y2*z0 - z2*y0) + x2(y0*z1 - y1*z0)
its adjoint is
[y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1]
[y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2]
[y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0]
giving:
[b0] [y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1] [xp]
[b1] = ( [y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2] . [yp] ) / det
[b2] [y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0] [zp]
If you need to test a number of points against the triangle, stop here. Calculate the above 3x3 matrix once for the triangle (dividing it by the determinant as well), and then dot product that result to each point to get the barycentric coords for each point.
If you are only doing it once per triangle, then here is the above multiplied out (courtesy of Maxima):
b0 = ((x1*y2-x2*y1)*zp+xp*(y1*z2-y2*z1)+yp*(x2*z1-x1*z2)) / det
b1 = ((x2*y0-x0*y2)*zp+xp*(y2*z0-y0*z2)+yp*(x0*z2-x2*z0)) / det
b2 = ((x0*y1-x1*y0)*zp+xp*(y0*z1-y1*z0)+yp*(x1*z0-x0*z1)) / det
That's quite a few additions, subtractions and multiplications - three divisions - but no sqrts or trig functions. It obviously does take longer than the pure 2D calcs, but depending on the complexity of your projection heuristics and calcs, this might end up being the fastest route.
As I mentioned - I have no idea what I'm talking about - but maybe this will work, or maybe someone else can come along and correct it.
Update: Disregard, this approach does not work in all cases
I think I have found a valid solution to this problem.
NB: I require a projection to 2D space rather than working with 3D Barycentric co-ordinates as I am challenged to make the most efficient algorithm possible. The additional overhead incurred by finding a suitable projection plane should still be smaller than the overhead incurred when using more complex operations such as sqrt or sin() cos() functions (I guess I could use lookup tables for sin/cos but this would increase the memory footprint and defeats the purpose of this assignment).
My first attempts found the delta between the min/max values on each axis of the polygon, then eliminated the axis with the smallest delta. However, as suggested by #PeterTaylor there are cases where dropping the axis with the smallest delta, can yeild a straight line rather than a triangle when projected into 2D space. THIS IS BAD.
Therefore my revised solution is as follows...
Find each sub delta on each axis for the polygon { abs(v1.x-v0.x), abs(v2.x-v1.x), abs(v0.x-v2.x) }, this results in 3 scalar values per axis.
Next, multiply these scaler values to compute a score. Repeat this, calculating a score for each axis. (This way any 0 deltas force the score to 0, automatically eliminating this axis, avoiding triangle degeneration)
Eliminate the axis with the lowest score to form the projection, e.g. If the lowest score is in the x-axis, project onto the y-z plane.
I have not had time to unit test this approach but after preliminary tests it seems to work rather well. I would be eager to know if this is in-fact the best approach?
After much discussion there is actually a pretty simple way to solve the original problem of knowing which axis to drop when projecting to 2D space. The answer is described in 3D Math Primer for Graphics and Game Development as follows...
"A solution to this dilemma is to
choose the plane of projection so as
to maximize the area of the projected
triangle. This can be done by
examining the plane normal; the
coordinate that has the largest
absolute value is the coordinate that
we will discard. For example, if the
normal is [–1, 0, 0], then we would
discard the x values of the vertices
and p, projecting onto the yz plane."
My original solution which involved computing a score per axis (using sub deltas) is flawed as it is possible to generate a zero score for all three axis, in which case the axis to drop remains undetermined.
Using the normal of the collision plane (which can be precomputed for efficiency) to determine which axis to drop when projecting into 2D is therefore the best approach.
To project a point p onto the plane defined by the vertices v0, v1 & v2 you must calculate a rotation matrix. Let us call the projected point pd
e1 = v1-v0
e2 = v2-v0
r = normalise(e1)
n = normalise(cross(e1,e2))
u = normalise(n X r)
temp = p-v0
pd.x = dot(temp, r)
pd.y = dot(temp, u)
pd.z = dot(temp, n)
Now pd can be projected onto the plane by setting pd.z=0
Also pd.z is the distance between the point and the plane defined by the 3 triangles. i.e. if the projected point lies within the triangle, pd.z is the distance to the triangle.
Another point to note above is that after rotation and projection onto this plane, the vertex v0 lies is at the origin and v1 lies along the x axis.
HTH
I'm not sure that the suggestion is actually the best one. It's not too hard to project to the plane containing the triangle. I assume here that p is actually in that plane.
Let d1 = sqrt((v1-v0).(v1-v0)) - i.e. the distance v0-v1.
Similarly let d2 = sqrt((v2-v0).(v2-v0))
v0 -> (0,0)
v1 -> (d1, 0)
What about v2? Well, you know the distance v0-v2 = d2. All you need is the angle v1-v0-v2. (v1-v0).(v2-v0) = d1 d2 cos(theta). Wlog you can take v2 as having positive y.
Then apply a similar process to p, with one exception: you can't necessarily take it as having positive y. Instead you can check whether it has the same sign of y as v2 by taking the sign of (v1-v0)x(v2-v0) . (v1-v0)x(p-v0).
As an alternative solution, you could use a linear algebra solver on the matrix equation for the tetrahedral case, taking as the fourth vertex of the tetrahedron v0 + (v1-v0)x(v2-v0) and normalising if necessary.
You shouldn't need to determine the optimal area to find a decent projection.
It's not strictly necessary to find the "best" projection at all, just one that's good enough, and that doesn't degenerate to a line when projected into 2D.
EDIT - algorithm deleted due to degenerate case I hadn't thought of
I am having two Vectors (X,Y,Z), one above Y=0 and one below Y=0.
I want to find the Vector (X,Y,Z) where the line between the two original vectors intersects with the Y=0 level.
How do I do that?
Example Point A:
X = -43.54235
Y = 95.2679138
Z = -98.2120361
Example Point B:
X = -43.54235
Y = 97.23531
Z = -96.24464
These points read from two UnProjections from a users click and I'm trying to target the unprojection to Y=0.
(I found 3D line plane intersection, with simple plane but didn't understand the accepted answer as it's for 2D)
I suspect that by two vectors, you really mean two points, and want to intersect the line connecting those two points with the plane defined by Y=0.
If that's the case, then you could use the definition of a line between two points:
<A + (D - A)*u, B + (E - B)*u, C + (F - C)*u>
Where <A,B,C> is one of your points and <D,E,F> is the other point. u is an undefined scalar that is used to calculate the points along this line.
Since you're intersecting this line with the plane Y=0, you simply need to find the point on the line where the "Y" segment is 0.
Specifically, solve for u in B + (E - B)*u = 0, and then feed that back into the original line equation to find the X and Z components.
The equation for the line is
(x–x1)/(x2–x1) = (y–y1)/(y2–y1) = (z–z1)/(z2–z1)
So making y=0 yields your coordinates for the intersection.
x = -y1 * (x2-x1)/(y2-y1) + x1
and
z = -y1 * (z2-z1) /(y2-y1) + z1
The problem is straight forward:
1) We have a photon traveling from Point 1 (x,y,z) to Point 2 (x,y,z), both of which could be located anywhere in 3D space.
2) We have a polygon that is both rotated randomly on the x-axis and/or y-axis and also located anywhere in 3D space.
3) We want to find: a) if the photon will collide with the polygon at all and b) if it does where will that be (x,y,z)?
An image of the problem: http://dl.dropbox.com/u/3150177/Programming/3D/Math/Photon%20Path/Photon%20Path.png
The aim of this is to calculate how the photon's path should be altered from an interaction(s) with the polygon(s).
I am reading up on this subject now but I was wondering if anyone could give me a head start. Thanks in advance.
Sounds like you are looking for a ray/polygon intersection test.
I can't remember the details but I imagine you split it into two parts. First you find the point on the polygon's plane that the ray intersects at. This can be got from a simple ray/plane intersection test. Secondly use a co-ordinate system on the polygon's plane to test whether the intersection point lies within the polygon. This can be got from a point-in-polygon test.
General overview:
1) Segment-Plane Intersection: Determine if the line segment connecting points 1 and 2 intersects the plane containing the polygon. If it doesn't, then it will never intersect the polygon, and you're done.
2) Find Point of Intersection: Determine the point at which the line segment and plane intersect. This will provide the information you want in 3-b in your question. Call this point Q
3) Determine if Q is interior to the polygon: One method of determining this is here, but a well crafted Google search will likely result in others. You can optimize for different types of polygons you expect (i.e. convex) or if the plane containing the polygon is axially aligned (i.e. one of the axes for your coordinate system is normal to the plane containing the polygon).
Assumption: All of the polygon's points are co-planar.
You're doing ray tracing. Most efficient is to break the polygon into triangles and use the Moeller ray-triangle test. Or perhaps the Wald test. There are also variants that use extra stored data beyond just the vertex information which can be even faster if you're doing multiple rays against the same triangle. Google provides so many results, I haven't selected a "best" one to put here.
The photon is traveling with vector v = p2 - p1 starting at p1, creating this line:
p1 + v * a
To find out if the photon collides with the polygon you have to find a value for a for:
p1 + v * a = polygon
For example:
p1 is (15, 4, 5)
p2 is (10, 1, 3)
and polygon is a 10x10 square: (-5...5, -5...5, 0)
v = p2 - p1 = (-5, -3, -2)
p1 + v * a = pol makes:
p1.x + v.x * a = pol.x
p1.y + v.y * a = pol.y
p1.z + v.z * a = pol.z
a = (pol.z - p1.z) / v.z = (0 - 15) / -2 = 7.5
pol.x = p1.x + v.x * a = 15 + -5 * 7.5 = -22.5
pol.y = p1.y + v.y * a = 10 + -3 * 7.5 = -12.5
The -22.5 is not between -5 and 5 and -12.5 is not between -5 and 5, so the photon does not collide with the polygon.
It's been a while since I've done this so I may have made some mistakes. I used the fact that pol.z = 0 to calculate a. You may have to rotate the polygon to line up with one axis, as long as you rotate p1 around the polygon's center as well.
Ray / triangle intersections are well understood and quite easy. The rotations are harder, though.
Perhaps you could transform the triangle's vertices using a rotation matrix and then use a simple ray / triangle intersection?