i am programming a C++ collision detection in my game and am trying to come up with an algorithm:
I have a capsule defined with two center points (C1, C2), length and a radius. Then i have a ray defined with two points (R1, R2). I already know that they are intersecting. I just need to find inner part of ray that is contained in capsule (H1-H2). Thanks in advance for all the help.
First let's take a look at a diagram for reference:
The procedure for calculating H1 and H2 is as follows:
Compute the intersection, if any, between the ray R and the line
segment P1P2. We're only interested in intersections that lie
within the interior of P1P2. Similarly for P3P4. The points P1 to P4 can be calculated easily from the circle centers, C1 and C2, and some vector math. E.g. P1 = C1 + r*nC, where nC is the normal (CCW) of the unit vector from C1 to C2. This
answer on SO provides the necessary math to determine if an
intersection exists between two line segments and, if so, calculate the parameter h, such
that H=R1+h(R2-R1), where H is an intersection point. This step can produce 0, 1, or 2 valid h values, depending on whether the ray intersects neither, one, or both of P1P2, P3P4.
Compute the intersection points, if any, between the ray and each of the 2
circles. Again, an SO answer provides the necessary math for
ray to circle intersection. Each circle can produce 0, 1, or 2
intersections, again represented parametrically.
If no valid h values were generated from steps 1 & 2 then the ray does not intersect the capsule. Otherwise, calculate hMin and hMax, the min and max parameter values of all valid
intersections identified in steps 1 & 2. Note that it's possible that hMin==hMax, in the case where the ray is tangent to one of the circles and does not intersect P1P2 or P3P4. The required intersection point(s) can now be calculated as H1=R1+hMin(R2-R1) and H2=R1+hMax(R2-R1).
I'm afraid my language of choice is Java rather than C++, but hopefully you'll find the code (IDEOne) I put together helpful as a reference. Please be aware that no effort was put it to handle robustness issues resulting from the rounding of double values during calculations.
Related
I am looking for some assistance on creating an algorithm that is able to calculate a bounding box for an arc. Typically, this would be a simple problem. However, I am required to have one of the edges of the box to be the line that connects the starting point and the ending point of the arc.
I am having difficulty in developing an algorithm that is able to compute the additional two points of the rectangle.
Here is a picture of what I am attempting to calculate:
The two purple dots, I need to develop an algorithm that will determine these two locations. The green dots are the known points that can be inputs. Additionally, I do know the radius and the center of the arc.
I would need the algorithm to handle the different cases for when line AB is vertical, has a + slope, and has a - slope.
I have been considering a few directions. For example, I know that the line through point E is parallel to line AB. Since it is parallel, that means they will have the same slopes and the line from point A to the purple point is perpendicular to this line. I can then consider the intersection point of the line through E and this perpendicular line.
This method seems messy because then I would need to consider the cases for when the slope of line AB is infinite and 0. I am wondering if there is some algorithm that could account for that automatically (or not even consider the slope at all for line AB)
You claim to know points A, B, C, D, E, and that the amplitude of the sustaining angle of the circular arc does not exceed 180° (semi circle).
Let P1, and P2, the two points that complement the bounding box - (in the drawing, P1 is the purple point above A, and P2 the one above B).
Using vectors:
E-C = vector perpendicular to segment AB', i/e subtract C from E; its magnitude is equal to the distance EC.
P1 = A + (E-C)
P2 = B + (E-C)
Bounding Box = Rectangle A, P1, P2, B
If you need a closer fit, you can replace vector (E-C) with vector (D-C) to place the bounding segment P1P2 tangent to D
I am trying to write C++ code to find the intersection points of a segment intersecting a tetrahedron. I reduced the problem like this:
For each face of the tetrahedron (a triangle), find the intersection point of the line segment. Then, I have three cases:
a) The segment doesn't intersect any face - thus either the segment is entirely in the tetrahedron or completely outside.
b) The segment only intersects one face. Then I just need to determine the side of the segment that is in the tetrahedron and I get the two points that are in the tetrahedron.
c) The segment intersects two faces.
I am having trouble implementing this algorithm. Here are the issues:
If the segment and triangle are in the same plane, how do I find the intersection points?
How can I determine if the segment lies on one of the edges of the tetrahedron?
Thanks.
Hint:
You can't avoid a complex case discussion. Here I introduce the planar case of a line segment and a triangle.
The sides of the triangle define three straight lines that partition the plane in 7 regions, one bounded and 6 unbounded. On the figure, they are designated by the signs obtained when you plug the coordinates of a point in the three implicit equations of these lines.
If you need to consider endpoints exactly on a side, you need to add 6 half-lines and 3 segments to the discussion.
Then take all possible combinations of the starting and ending regions.
Many of the cases are straightforward. When the two segment endpoint belong to the same region, the segment is wholly inside or outside; when one of the regions is +++ and the other is different, there is exactly one intersection...
In the case of the figure (--+ to ++-), you are sure to have one intersection with the bottom edge; but which is the other intersected side is unsure: to answer this, you need to tell on what side of the line segment the top vertex lies.
With some courage, you can discuss all 16 x 15 / 2 = 120 cases, many of which are identical to a permutation of the elements.
This is just an appetizer compared to the 3D problem.
"How can I determine if the segment lies on one of the edges of the tetrahedron?"
Write a function that computes the area of the triangle determined by three points in space. This can be computed from a determinant, as explained here and many other sites.
Then write a function that determines if two segments ab and cd are collinear.
They are if and only if the area of abc is zero, and the area of abd is zero.
Finally, write a function that determines if one point c lies on the segment ab. With all this, the remainder is easy.
To answer the general question, i.e. how to find the (up to two) intersections between a segment and a tetrahedron, I'd prefer to avoid the painful case-by-case analysis (mentioned in your problem reduction and in another answer).
I would use a variant of Sutherland-Hogdman's reentrant clipping (explained in 2D in [1]): the idea is to consider the tetrahedron as the intersection between four oriented half-spaces (limited by the support planes of the four faces of the tetrahedron).
Thus to compute the intersection between a segment and a tetrahedron, you can proceed as follows:
S := your segment
for f := 0 to 3 {
H := half_space(tet, f)
S := intersect(S, H)
}
H is just a plane equation (coefficients a,b,c,d of equation ax+by+cz+d=0,
[a,b,c] is the normal to the facet, oriented towards the interior of the tetrahedron. d is obtained by injecting a vertex incident to the facet into the equation).
The function intersect() is simple to implement (just test the sign of ax+by+cz+d at both vertices of the segment, if they differ, there is an intersection, that can be computed by injecting a parametric equation of S
x=x1+t(x2-x1), y=y1+t(y2-y1), z=z1+t(z2-z1) into (ax+by+cz+d=0) and solving for t, where (x1,y1,z1) and (x2,y2,z2) denote the two extremities of S.
In addition, the function intersect() may compute two booleans, to keep track of which vertex of S is a generated intersection.
[1] https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
I want to determine whether a given triangle intersects a tetrahedron. I do not want to compute the solution polygon(if it exists) itself. Is there any library/package/published practical algorithm which can be used to solve this problem directly(unlike my attempt below)?
I think as a last resort I will have to use standard polygon-polygon intersection algorithm implementations to solve this problem indirectly.
My attempt on this problem:
I thought of breaking it into the problem of polygon-polygon intersection. So for each triangular face(say T1) of the tetrahedron and the given triangle T2, I thought of doing the following:
Compute intersection(a line) between planes corresponding to each triangle, say L1.
For each triangle:
For each edge of the triangle say L2, compute point of intersection P between L1 and L2.
Test(maybe using parametric form) of L2, if the point lies on the edge L2.
If for both triangles T1 and T2, there exists at least one edge on which the intersection point P lies, then it implies that the triangles(and hence the given tetrahedron and the triangle T2) do intersect.
Create an orthonormal frame based on the triangle (origin at some vertex, axis X using the direction of some side, axis Y and Z using the direction of another side and Gram-Schmidt formulas).
Transform the coordinates of the 3 + 4 vertices to the new frame.
If all Z of the 4 tetrahedron vertices are of the same sign, there is no intersection. Otherwise, find the 3 or 4 intersection point of the edges into XY, by linear interpolation on Z.
Now you need to check for intersections between a triangle and a triangle or (convex) quadrilateral, in 2D. You can solve that by means of a standard clipping algorithm, made simple by convexity of the polygons.
As an easy optimization, note that it is useless to compute the Z of the triangle vertices (=0), and the XY of the tetrahedron vertices before you know that there is a possible intersection.
You can also speedup the polygon intersection process by first using a bounding box test.
I just found a function in CGAL library CGAL::do_intersect(Type1< Kernel > obj1,Type2< Kernel > obj2 ) for computing intersection between two geometric objects. It permits Type1 and Type2 to be Triangle_3<Kernel> and Tetrahedron_3<Kernel> respectively.
I have a closed contour represented by a list of points and I need to split it into equal parts, knowing the area of the parts.
I think that I can use some subdivision algorithm, like Delanuy subdivision. But with this method I have to give the centroid of the subdivded parts.
Anyone has some hints?
if i understand correctly: given say a rectangle say of area 10, and a target area of 1, you would need to partition rectangle into 10 parts, each having area of 1. So slicing the rectangles into 10 thin rectangles (like guitar frets, or bread slices) would do.
If that's the case, then I would do the following:
Create a function to compute the area of a convex poly. This is fairly trivial (since poly is convex).
Observe, since input poly is convex, any line segment that splits the polygon into two, will intersect the polygon in exactly two places. Specifically, you can triangulate the polygon by picking a vertex of the poly and connecting it to every other vert of the polygon, like a fan.
Triangulating in this fashion would create a partition that would be close to what you need. Assume that the input polygon is given by a vertex list poly = {v1, v2, v3, ..., vn}, where verts are unique and no three are co-linear (convex poly).
Observe that given a triangle of that poly formed by say (v2,v3,v4) we can compute its area, A1. Now if we grow the triangle into a poly by adding one extra vert to the next, say v5, to form (v2, v3, v4, v5) the area increased to A2 (sum of two triangles, (v2,v3,v4) and (v2,v4,v5). Due to linearity if you wanted to grow the original triangle to say A2' where A1 < A2' < A2, you can interpolate on the line segment (v4,v5) to find v4' that will give you the right area A2' that you need.
Since you can compute the total area of initial input poly, and you know the target area of each subdivision, you can cut the input poly into pieces of desired area until you subdivide the entire thing. If you want a nicer partition, you can start from the center of the polygon, i.e. first (seed triangle) would be (center, v1,v2). Then shrink/grow it until desired area, move to the next triangle, repeat.
Hope that makes sense :D
I am trying to determine the distance from a point to a polygon in 2D space. The point can be inside or outside the polygon; The polygon can be convex or concave.
If the point is within the polygon or outside the polygon with a distance smaller than a user-defined constant d, the procedure should return True; False otherwise.
I have found a similar question: Distance from a point to a polyhedron or to a polygon. However, the space is 2D in my case and the polygon can be concave, so it's somehow different from that one.
I suppose there should be a method simpler than offsetting the polygon by d and determining it's inside or outside the polygon.
Any algorithm, code, or hints for me to google around would be appreciated.
Your best bet is to iterate over all the lines and find the minimum distance from a point to a line segment.
To find the distance from a point to a line segment, you first find the distance from a point to a line by picking arbitrary points P1 and P2 on the line (it might be wise to use your endpoints). Then take the vector from P1 to your point P0 and find (P2-P1) . (P0 - P1) where . is the dot product. Divide this value by ||P2-P1||^2 and get a value r.
Now if you picked P1 and P2 as your points, you can simply check if r is between 0 and 1. If r is greater than 1, then P2 is the closest point, so your distance is ||P0-P2||. If r is less than 0, then P1 is the closest point, so your distance is ||P0-P1||.
If 0<r<1, then your distance is sqrt(||P0-P1||^2 - (r * ||P2-P1||)^2)
The pseudocode is as follows:
for p1, p2 in vertices:
var r = dotProduct(vector(p2 - p1), vector(x - p1))
//x is the point you're looking for
r /= (magnitude(vector(p2 - p1)) ** 2)
if r < 0:
var dist = magnitude(vector(x - p1))
else if r > 1:
dist = magnitude(vector(p2 - x))
else:
dist = sqrt(magnitude(vector(x - p1)) ^ 2 - (r * magnitude(vector(p2-p1))) ^ 2)
minDist = min(dist,minDist)
In the event that this helps someone else, I reverse engineered doverbin's answer to understand why it worked showing graphically what the three cases are computing. (doverbin, feel free to incorporate this into your answer if you wish.)
If you have a working point to line segment distance function, you can use it to calculate the distance from the point to each of the edges of the polygon. Of course, you have to check if the point is inside the polygon first.
Do you need fast or simple?
Does it have to be always absolutely correct in edge cases or will good enough most of the time be OK?
Typical solution are to find the distance to each vertex and find the pair with the smallest values ( note that for a point outside a convex polygon these might not be adjacent) and then check point to line intersections for each segment.
For large complex shapes you can also store approx polygon bounding boxes (either rectangular or hexagons) and find the closest side before checking more detail.
You may also need code to handle the special case of exactly on a line.
I can help you with this pointers:
The distance can be calculated using Wikipedia entry, even with an untested snipped of code.
The inside/outside border can be solved with this Stack Post and links
and some remarks:
you should check only the nearest points, as Martin Beckett´s answer point outs, since another segment can "proyected" very near, but in reality don´t be close as need.
I do not know about the difference in performance with respect to the rest of answers, but in boost C++ libraries there is an generic implementation called distance. It has information about complexity in every case and in your problem case it is linear.
I was also looking for solutions to this problem some days ago and I want to share this finding. Hope it helps to someone.