Intuition for Separating Axis Test - graphics

The SAT theorem is intuitive at a high level, but two details are not obvious to me.
To test if two convex polygons collide, the 2D SAT theorem states that we need to check if any of the 1D "shadows" of the polygons on various axes overlap. If none of those shadow pairs overlap, then the polygons must be non-colliding. Makes sense so far.
However, the SAT theorem also says that we only need to look at the axes that are parallel to the polygon edges. Since there could be an infinite number of separating lines, why is it sufficient to check only those particular axes?
The 3D extension for polyhedra is similar; it checks for separating planes that are parallel to the faces. However it also checks for planes formed by cross products of various edge combinations. Why are these additional planes necessary in 3D, if they weren't necessary in 2D?

Related

Expanding Convex Hull to Reduce Sides

We have sets of labeled points whose convex hulls do not overlap. There is some empty space between the convex hulls.
Given an unlabeled point that is not in our data we want to approximately determine which convex hull it lies within.
To make the computation faster, we want to reduce the number of sides on the convex hull (thus expanding the convex hull a bit, but not too much).
What algorithms could I use?
Update: Ideally I want to do the expansion under the constraint that it not intersect a given nearby polygon. (The motivation for this constraint is that I have several disjoint hulls and want to reduce the number of sides of all of them while still keeping them disjoint. But treat this as a parenthetical because I do not want to do a joint modification. I am happy to modify one hull while keeping the others constant. I am happy to hack this simple case to do a joint modification iteratively.)
Perhaps this is worth trying.
Find the convex hull A' of A union x, and the convex hull B' of B union x.
Select whichever increases the hull area the least.
In the example below, A' is the winner.
Added in response to comment:
One route is via "minimal enclosing k-gons":
Mictchell et al.: "Minimum-Perimeter Enclosing k-gon" 2006 (CiteSeer link)
Aggarwal et al.: "Minimum Area Circumscribing Polygons" 1985 (CiteSeer link)
O'Rourke et al.: "An optimal algorithm for fnding minimal enclosing triangles" 1986, Algorithmica (ACM link)
These algorithms are, however, quite intricate and unlikely to help much.
The "point in convex polygon" test is not so expensive, as it can be performed in Lg(N) comparisons by dichotomy (split the polygon in two with a straight line, recursively until you have a single triangle left). N is the number of sides. Actually, a polygon of 27 (resp. 130) sides will cost you the double (triple) of a triangle.
If you have many hulls, exhaustive comparisons of the point against every hull is a waste. There are better approaches such as using monotone subdivisions, which could lower the search time to O(Log(M)) query time for a total of M sides, after preprocessing.
I wouldn't be surprised if the saving of processing one less edge in your rough-phase contains check is outweighed by the increased false-positive rate of the inflated hull. Indeed, you might even be making more work for yourself - every point that passes the rough-phase check will have to also be checked against the true hull anyway.
Instead of trying to reduce the n in your O(n) contains check, I'd be tempted to go straight to something amortised O(1) for the rough passes:
1st pass - check against the axis-aligned bounding box (AABB). This gives quick rejection for the vast majority of points outside the polygon.
2nd pass - divide the AABB into a grid, where each grid quad is in one of three states: fully outside the hull, intersecting the hull edge or fully inside the hull. If your point lies in an "in" or "out" quad, you can stop here.
3rd pass - any point that lies in a grid quad that intersects the polygon is checked against the hull as normal.
The state of the grid can be computed ahead of time:
Initialise each grid quad to be outside of the hull
Use the algorithm linked in this answer to trace the edges of the hull over the grid and set all intersecting quads.
The grid now contains the outline of the hull, so use a simple floodfill or scanline approach to find and set all quads on the interior of the hull.
The resolution of the grid can be varied to give a tradeoff between memory cost (2 bits per quad) and false-positive rate (low-resolution grids will lead to more O(n) conventional hull checks).
It looks like your ultimate goal is not really about convex hulls, it is about solving the point location problem (https://en.wikipedia.org/wiki/Point_location). And you seem to be determined to solve it by simply iteratively checking your point against a number of convex hulls. While I understand where convex hulls come from (they actually represent sets of points), it is still not a reason to directly use them in the algorithm. Point location problem can be solved by a number of more efficent algorithms (like search tree based on trapezoidal decomposition), which are much less sensitive to the number of edges in your hulls.

Separating axis test in 4D and higher dimensions for simplex faces

I am trying to determine if two simplices in a simplicial complex intersect in an appropriate manner, i.e. they intersect in a single vertex, edge or face-to-face.
In order to achieve that I try to see if faces of two simplices intersect appropriately. I try to use the separating axis test to check if faces, i.e., (n-1)-simplices, of the n-simplex are separable by a hyperplane in n-D space. For example, I want to check if two tetrahedra (3-simplices) intersect in 4D.
I tried to generalize an explanation in "Intersection of Convex Objects: The Method of Separating Axes" by David Eberly, section "Separation of Convex Polygons in 3D" , as this deals with separation of (n-1) simplices in n-D space. I could not understand how to construct all potential separating axis directions, suggested there.
Choices for potential axes are:
Normal to a face;
Direction perpendicular to both the face normal and "edge" (in 4D we could call a triange face of a tetrahedron such an "edge");
Cross product of a pair edges from different faces should be computed.
I could not understand how to generalize cross products of edges to 4 dimensions. One need at least 3 vectors (not a pair of them) to simulate cross product computation in 4D, as presented here.
Could anyone suggest how it would be best to choose potential separating axis directions in 4D and higher?
Also, if I am pursuing a wrong line of thinking about the correct positioning of simplices, please advise how better to check this.

Given an irregular polygon's vertex list, how to create internal triangles to build a flat 3D mesh efficiently?

I'm using Unity, but the solution should be generic.
I will get user input from mouse clicks, which define the vertex list of a closed irregular polygon.
That vertices will define the outer edges of a flat 3D mesh.
To procedurally generate a mesh in Unity, I have to specify all the vertices and how they are connected to form triangles.
So, for convex polygons it's trivial, I'd just make triangles with vertices 1,2,3 then 1,3,4 etc. forming something like a Peacock tail.
But for concave polygons it's not so simple.
Is there an efficient algorithm to find the internal triangles?
You could make use of a constrained Delaunay triangulation (which is not trivial to implement!). Good library implementations are available within Triangle and CGAL, providing efficient O(n*log(n)) implementations.
If the vertex set is small, the ear-clipping algorithm is also a possibility, although it wont necessarily give you a Delaunay triangulation (it will typically produce sub-optimal triangles) and runs in O(n^2). It is pretty easy to implement yourself though.
Since the input vertices exist on a flat plane in 3d space, you could obtain a 2d problem by projecting onto the plane, computing the triangulation in 2d and then applying the same mesh topology to your 3d vertex set.
I've implemented the ear clipping algorithm as follows:
Iterate over the vertices until a convex vertex, v is found
Check whether any point on the polygon lies within the triangle (v-1,v,v+1). If there are, then you need to partition the polygon along the vertices v, and the point which is farthest away from the line (v-1, v+1). Recursively evaluate both partitions.
If the triangle around vertex v contains no other vertices, add the triangle to your output list and remove vertex v, repeat until done.
Notes:
This is inherently a 2D operation even when working on 3D faces. To consider the problem in 2D, simply ignore the vector coordinate of the face's normal which has the largest absolute value. (This is how you "project" the 3D face into 2D coordinates). For example, if the face had normal (0,1,0), you would ignore the y coordinate and work in the x,z plane.
To determine which vertices are convex, you first need to know the polygon's winding. You can determine this by finding the leftmost (smallest x coordinate) vertex in the polygon (break ties by finding the smallest y). Such a vertex is always convex, so the winding of this vertex gives you the winding of the polygon.
You determine winding and/or convexity with the signed triangle area equation. See: http://softsurfer.com/Archive/algorithm_0101/algorithm_0101.htm. Depending on your polygon's winding, all convex triangles with either have positive area (counterclockwise winding), or negative area (clockwise winding).
The point-in-triangle formula is constructed from the signed-triangle-area formula. See: How to determine if a point is in a 2D triangle?.
In step 2 where you need to determine which vertex (v) is farthest away from the line, you can do so by forming the triangles (L0, v, L1), and checking which one has the largest area (absolute value, unless you're assuming a specific winding direction)
This algorithm is not well defined for self-intersecting polygons, and due to the nature of floating point precision, you will likely encounter such a case. Some safeguards can be implemented for stability: - A point should not be considered to be inside your triangle unless it is a concave point. (Such a case indicates self-intersection and you should not partition your set along this vertex). You may encounter a situation where a partition is entirely concave (i.e. it's wound differently to the original polygon's winding). This partition should be discarded.
Because the algorithm is cyclic and involves partitioning the sets, it is highly efficient to use a bidirectional link list structure with an array for storage. You can then partition the sets in 0(1), however the algorithm still has an average O(n^2) runtime. The best case running time is actually a set where you need to partition many times, as this rapidly reduces the number of comparisons.
There is a community script for triangulating concave polygons but I've not personally used it. The author claims it works on 3D points as well as 2D.
One hack I've used in the past if I want to constrain the problem to 2D is to use principal component analysis to find the 2 axes of greatest change in my 3D data and making these my "X" and "Y".

find orthonormal basis for a planar 3D ( possibly degenerate) polygon

Given a general planar 3D polygon, is there a general way to find the orthonormal basis for that planar polygon?
The most straight forward way to do it is to assume to take the first 3 points of the polygon, and form two vectors each, and these are the two orthonormal basis vectors that we are looking for. But the problem for this approach is that these 3 points may line on the same line in the polygon, and hence instead of getting two orthonormal vectors, we get only one.
Another approach to find the second orthonormal vector is to loop through the polygon and find another point that forms a different orthonormal vector than the first one, but this approach is susceptible to numerical errors (e.g, what if the second vector is almost the same with the first vector? The numerical errors can be significant).
Is there any other better approach?
You can use the cross product of any two lines connected by any two vertices. If the cross product is too low then you're in degenerate territory.
You can also take the centroid (the avg of the points, which is guaranteed to lie on the same plane) and do pick the largest of any two cross products of the vectors from the centroid to any vertex. This will be the most accurate normal. Please note that if the largest cross product is small, you may have an inaccurate normal.
If you can't find any cross product that isn't close to 0, your original poly is degenerate and a normal will be hard to find. You could use arbitrary precision or adaptive precision algebra in this case, but, of course, the round-off error is already significant in the source data, so this may not help. If possible, remove degenerate polys first, and if you have to, sew the mesh back up :).
It's a bit ott but one way would be to compute the covariance matrix of the points, and then diagonalise that. If the points are indeed planar then one of the eigenvalues of the covariance matrix will be zero (or rather very small, due to finite precision arithmetic) and the corresponding eigenvector will be a normal to the plane; the other two eigenvectors will span the plane of the polygon.
If you have N points, and the i'th coordinate of the k'th point is p[k,i], then the mean (vector) and (3x3) covariance matrix can be computed by
m[i] = Sum{ k | p[k,i]}/N (i=1..3)
C[i,j] = Sum{ k | (p[k,i]-m[i])*(p[k,j]-m[j]) }/N (i,j=1..3)
Note that C is symmetric, so that to find how to diagonalise it you might want to look up the "symmetric eigenvalue problem"

Detecting arbitrary shapes

Greetings,
We have a set of points which represent an intersection of a 3d body and a horizontal plane. We would like to detect the 2D shapes that represent the cross sections of the body. There can be one or more such shapes. We found articles that discuss how to operate on images using Hough Transform, but we may have thousands of such points, so converting to an image is very wasteful. Is there a simpler way to do this?
Thank you
In converting your 3D model to a set of points, you have thrown away the information required to find the intersection shapes. Walk the edge-face connectivity graph of your 3D model to find the edge-plane intersection points in order.
Assuming you have, or can construct, the 3d model topography (some number of vertices, edges between vertices, faces bound by edges):
Iterate through the edge list until you find one that intersects the test plane, add it to a list
Pick one of the faces that share this edge
Iterate through the other edges of that face to find the next intersection, add it to the list
Repeat for the other face that shares that edge until you arrive back at the starting edge
You've built an ordered list of edges that intersect the plane - it's trivial to linearly interpolate each edge to find the intersection points, in order, that form the intersection shape. Note that this process assumes that the face polygons are convex, which in your case they are.
If your volume is concave you'll have multiple discrete intersection shapes, and so you need to repeat this process until all edges have been examined.
There's some java code that does this here
The algorithm / code from the accepted answer does not work for complex special cases, when the plane intersects some vertices of a concave surface. In this case "walking" the edge-face connectivity graph greedily could close some of the polygons before time.
What happens is, that because the plane intersects a vertex, at one point when walking the graph there are two possibilities for the next edge, and it does matter which one is chosen.
A possible solution is to implement a graph traversal algorithm (for instance depth-first search), and choose the longest loop which contains the starting edge.
It looks like you wanted to combine intersection points back into connected figures using some detection or Hough Transform.
Much simpler and more robust way is to immediately get not just intersection points, but contours of 3D body, where the plane cuts it.
To construct contours on the body given by triangular mesh, define the value in each mesh vertex equal to signed distance from the plane (positive on one side of the plane and negative on the other side). The marching squares algorithm for isovalue=0 can be then applied to extract the segments of the contours:
This algorithm works well even when the plane passes through a vertex or an edge of the mesh.
To better understand what is the result of plane section, please take a look at this short video. Following the links there, one can find the implementation as well.

Resources