Data structure to query points which lie inside a triangle - algorithm

I have some 2D data which contains edges which were rasterized into pixels. I want to implement an efficient data structure which returns all edge pixels which lie in a non-axis-aligned 2D triangle.
The image shows a visualization of the problem where white denotes the rasterized edges, and red visualizes the query triangle. The result would be all white pixels which lie on the boundary or inside the red triangle.
When further looking at the image, one notices that we have sparse boolean data, meaning that if we denote black pixels with a 0 and white pixels with a 1, that the number of 1s in the data is much lower than the number of 0s. Therefore, rasterizing the red triangle and checking for each point on it's inside whether it is white or black is not the most efficient approach.
Besides the sparseness of the data; since the white pixels origin from edges, it is in their nature to be connected together. However, at junctions with other lines, they have more than two neighbors. Pixels which are at a junction should only be returned once.
The data must be processed in realtime, but with no GPU assistance. There will be multiple queries for different triangle contents, and after each one, points may be removed from the data structure. However, new points won't be inserted anymore after the initial filling of the data structure.
The query triangles are already known when the rasterized edges arrive.
There are more query triangles than data edges.
There are many spatial data structures available. However I'm wondering, which one is the best one for my problem. I'm willing to implement a highly optimized data structure to solve this problem, as it will be a core element of the project. Therefore, also mixes or abbreviations of data structures are welcome!
R-trees seem to be the best data structure which I found for this problem until now as they provide support for rectangle-based queries. I would check for all white pixels within an AABB of the query triangle, then would check for each returned pixel if it lies within the query rectangle.
However, I'm not sure how well R-trees will behave since edge-based data will not be easily groupable into rectangles, as the points are clumped together on narrow lines and not pread out.
I'm alo not sure if it would make sense to pre-build the structure of the R-tree using information about the query triangles which will be made as soon as the structure is filled (as mentioned before, the query triangles are already known when the data arrives).
Reversing the problem seems also to be a valid solution, where I use a 2-dimensional interval tree to get for each white pixel a list of all triangles which contain it. Then, it can already be stored within all those result sets and be returned instantly when the query arrives. However, I'm not sure how this performs a the number of triangles is higher than the number of edges, but still lower than the number of white pixels (as an edge is mostly split up into ~20-50 pixels).
A data structure which would exploit that white pixels have most often white pixels as neighbors would seem to be most efficient. However, I could not find anything about such a thing until now.

Decompose the query triangle(s) into n*3 lines. For every point under test you can estimate at which side of every line it is. The rest is boolean logic.
EDIT: since your points are rasterised, you could precompute the points on the scanlines where the scanline enters or leaves a particular query triangle (=crosses one of the 3n lines above && is on the "inside" of the other two lines that participate in that particular triangle)
UPDATE: Triggered by another topic ( How can I find out if point is within a triangle in 3D? ) I'll add code to prove that a non-convex case can be expressed en terms of "which side of every line a point is on". Since I am lazy, I'll use an L-shaped form. IMHO other Non-convex shapes can be processed similarly. The lines are parallel to the X- and Y- axes, but that again is laziness.
/*
Y
| +-+
| | |
| | +-+
| | |
| +---+
|
0------ X
the line pieces:
Horizontal:
(x0,y0) - (x2,y0)
(x1,y1) - (x2,y1)
(x0,y2) - (x1,y2)
Vertical:
(x0,y0) - (x0,y2)
(x1,y1) - (x1,y2)
(x2,y0) - (x2,y1)
The lines:
(x==x0)
(x==x1)
(x==x2)
(y==y0)
(y==y1)
(x==y2)
Combine them:
**/
#define x0 2
#define x1 4
#define x2 6
#define y0 2
#define y1 4
#define y2 6
#include <stdio.h>
int inside(int x, int y)
{
switch( (x<x0 ?0:1)
+(x<x1 ?0:2)
+(x<x2 ?0:4)
+(y<y0 ?0:8)
+(y<y1 ?0:16)
+(y<y2 ?0:32) ) {
case 1+8:
case 1+2+8:
case 1+8+16:
return 1;
default: return 0;
}
}
int main(void)
{
int xx,yy,res;
while (1) {
res = scanf("%d %d", &xx, &yy);
if (res < 2) continue;
res = inside(xx, yy);
printf("(%d,%d) := %d\n", xx, yy,res);
}
return 0;
}

There are a couple computational-geometric algorithms that I think in tandem would give good results.
Compute a planar subdivision that contains all of the triangle edges. (This is a little more complicated than computing all intersections of triangle edges.) For each face, make a list of the triangles that contain that face. This is admittedly worst-case cubic, but that's only when the triangles overlap a lot (and I can't help but think that there's a way to compress it to quadratic).
Locate each pixel in the subdivision (i.e., figure out which face it belongs to). The first one in each edge will cost O(log n), but if you have locality thereafter, there may be a way to shortcut the computation to something like O(1) on average. (For example, if you use the trapezoid method and if you store the list of trapezoids that contained the last point, you can traverse up the list until you find a trapezoid that contains the current point and work back down. Compare giving hints to C++ STL set insertion by passing an iterator near the insertion point.)

Related

Efficient line segment-triangle intersection

I have a collection of triangles that compose an arbitrary geometry (read from an OFF file). Each triangle is defined by three vertexes, which are 3D points. I have an observation point, and I want to remove from the object all those vertexes that are not visible, meaning that the segment line that joins the observation point and the vertex does not intersect with any triangle.
It is important to note that the number of vertexes and triangles in a single object is in the other of 10^4. A simple approach will be to follow [1] accepted answer, which uses the signed volumes. I have implemented it, but it includes two nested for loops: for each vertex, I need to check if the line to the observation point intersects with ANY of the triangles. Of course, I break the look when it intersects with one, but it still leads to 192M calls to the signed volume function.
Some efficient algorithms [2] assume an infinite line, not a line segment, which leads to the deletion of the vertex even if the intersection is with a further away triangle.
Any ideas on how to solve this efficiently?
[1] Intersection between line and triangle in 3D
[2] Möller and Trumbore, « Fast, Minimum Storage Ray-Triangle Intersection », Journal of Graphics Tools, vol. 2,‎ 1997, p. 21–28
Your problem statement is literally a ray-tracing problem: find if a bunch of points are occluded by the geometry or not. Therefore you can apply any ray-tracing tricks to make it fast; i.e. build some spacial index over your model and trace the rays using that spacial index. Some of the most common spacial indexes are BVH, BSP trees, or kd-trees.
If an approximate solution is good-enough, you can rasterize the geometry from the vantage point, and then test all your vertices against the generated Z-buffer.
Notice that either of these methods will filter the vertices (which is what you asked for). However, some triangles may be visible even if all their vertices are occluded. Those triangles will be removed too, even though they are visible. The rasterization method is easy to modify to filter triangles instead of vertices.
There are two question in one:
efficiency
segment-triangle intersection instead of ray-triangle intersection
efficiency
You can use a Bounding Volume Hierarchy (BVH)
The idea is to construct a hierarchy of boxes. Each box contains either other boxes or a bunch of triangles. The boxes are organized as a tree, and the root of the tree corresponds to a box that contains everything.
The function that computes an intersection works like that:
Compute the intersection between the ray and the box. If there is an intersection, open the box and recursively compute the intersections between the ray and what's in the box.
In more formal terms:
Intersect_Ray_Node(Ray, node)
if(Intersect_Ray_Box(Ray, node.box)) {
if(node.is_leaf) {
for each triangle t in node
Intersect_Ray_Triangle(Ray, t)
} else {
for each child in children(node)
Intersect_Ray_Node(Ray,child)
}
}
Now, the "boxes" can be different things. The simplest thing to use is an AABB (Axis Aligned Bounding Box), that is, simply the minimum and maximum values of the coordinates of what's in the box.
There are several ways of implementing the tree. The most efficient implementations use no data structure and simply reorder the facets in the mesh, in such a way that facets that are in the same node have contiguous indices. Then you just need a couple of additional arrays, one that stores for each node the bounds of the boxes, and another one that indicate for each node how many triangles there are in the left child (then the number of triangles in the right child is implicit).
An implementation is available here, in my geogram library. Constructing the AABB is just a matter
of sorting the triangles geometrically here and constructing the bouding box recursively.
I made also a ShaderToy implementation here (and a big comment at the end of BufferA contains the C++ source of my "MeshCompiler" that creates the AABB).
Note that if you want to be even more compact in memory, Pierre Terdiman proposed the Zero Byte AABB-tree (see here and here). The idea is to encode everything in the order of the triangles and the order of the vertices, based on the interesting remark that the bounds of the boxes are always coordinates of existing points in the mesh.
line segment versus ray
If what you want to intersect is a segment (with two vertices) instead of a ray (line that starts from a point and that extends towards infinity in a direction), you can do that with a simple modification of my answer here. Replace the last line
of the intersect_triangle() function with:
return (det >= 1e-6 && t >= 0.0 && t <= 1.0 && u >= 0.0 && v >= 0.0 && (u+v) <= 1.0);
(test that t is between 0 and 1, which means that the point is inside the segment)

Algorithm to quickly check amount of intersection in a list of shapes

So I got a list of shapes and already have an algorithm to check if two shapes intersect. Now I'm trying to figure out an efficient algorithm to go through a list and count the number of intersections.
What I have now is simply two for loops that compare the first element of the list to everything that comes after it, then do the same for the second element and etc. That's O(n^2) isn't it? I'm not quite sure how I would go about making it more efficient as I don't think you can sort a list of shapes or use hashtables if that does anything here.
Split your 2D space into a "nice power of 2" number of tiles. For example, you might have 8 rows and 8 columns to get 64 tiles.
For each polygon, add a tileFlags field. This will be 1 bit per tile, which indicates if the polygon does/doesn't overlap with the tile (and is the reason why you want a "nice power of 2" number of tiles).
To determine a polygon's tileFlags field; find the vertex/vertices with the lowest y-coord (and if there's 2 or more find the left-most and right-most vertex). From the starting vertex/vertices; trace the polygon's left and right edges from one vertex to the next, as you set flags corresponding to "tiles between left and right edge" each time you reach a new left/right vertex and each time you cross a "tile top/bottom". Note that this is a minor adaption of the algorithm you'd use for software rendering ("rasterization" for drawing polygons); just with "pixel" replaced with "tile" and "color" replaced with "1-bit flag"; and you should be able to find a better description of it (maybe even with example code). It is somewhat error prone (e.g. you have to take some care when vertices are perfectly on a tile's boundary); and becomes much harder and more expensive if the polygon can be concave (better to disallow concave polygons or maybe detect them and temporarily split them into convex polygons).
Once that's done, you can do if( (polygon1->tileFlags & polygon2->tileFlags) != 0) { /* Polygons might intersect */ } else { /* Polygons can't intersect */ } as a preliminary intersection test to avoid a much more expensive intersection test.

Algorithm for the decomposition of polygons

Does anyone know a relatively fast algorithm for decomposing a set of polygons into their distinct overlapping and non-overlapping regions, i.e. Given a set of n polygons, find all the distinct regions among them?
For instance, the input would be 4 polygons representing circles as shown below
and the output will be all polygons representing the distinct regions shown in the different colours.
I can write my own implementation using polygon operations but the algorithm will probably be slow and time consuming. I'm wondering if there's any optimised algorithm out there for this sort of problem.
Your problem in called the map overlay problem. It can be solved in O(n*log(n)+k*log(k)) time, where n is the number of segments and k is the number of segment intersections.
First you need to represent your polygons as a doubly connected edge list, different faces corresponding to the interiors of different polygons.
Then use the Bentley–Ottmann algorithm to find all segment intersections and rebuild the edge list. See: Computing the Overlay of Two Subdivisions or Subdivision representation and map overlay.
Finally, walk around each cycle in the edge list and collect faces of that cycle's half-edges. Every set of the faces will represent a distinct overlapping region.
See also: Shapefile Overlay Using a Doubly-Connected Edge List.
I don't think it is SO difficult.
I have answered the similar question on the friendly site and it was checked by a smaller community:
https://cs.stackexchange.com/questions/20039/detect-closed-shapes-formed-by-points/20247#20247
Let's look for a more common question - let's take curves instead of polygons. And let's allow them to go out of the picture border, but we'll count only for simple polygons that wholly belong to the picture.
find all intersections by checking all pairs of segments, belonging to different curves. Of course, filter them before real check for intersection.
Number all curves 1..n. Set some order of segments in them.
For every point create a sequence of intersections SOI, so: if it starts from the border end, SOI[1] is null. If not, SOI[1]= (number of the first curve it is intersecting with, the sign of the left movement on the intersecting curve). Go on, writing down into SOI every intersection - number of curve if there is some, or 0 if it is the intersection with the border.
Obviously, you are looking only for simple bordered areas, that have no curves inside.
Pieces of curves between two adjacent non-null intersection points we'll call segments.
Having SOI for each curve:
for segment of the curve 1, starting from the first point of the segment, make 2 attempts to draw a polygon of segments. It is 2 because you can go to 2 sides along the first intersecting curve.
For the right attempt, make only left turns, for the left attempt, make only the right turns.
If you arrive at point with no segment in the correct direction, the attempt fails. If you return to the curve 1, it success. You have a closed area.
Remember all successful attempts
Repeat this for all segments of curve 1
Repeat this for all other curves, checking all found areas against the already found ones. Two same adjacent segments is enough to consider areas equal.
How to find the orientation of the intersection.
When segment p(p1,p2) crosses segment q(q1,q2), we can count the vector multiplication of vectors pXq. We are interested in only sign of its Z coordinate - that is out of our plane. If it is +, q crosses p from left to right. If it is -, the q crosses p from right to left.
The Z coordinate of the vector multiplication is counted here as a determinant of matrix:
0 0 1
p2x-p1x p2y-p1y 0
q2x-q1x q2y-q1y 0
(of course, it could be written more simply, but it is a good memorization trick)
Of course, if you'll change all rights for lefts, nothing really changes in the algorithm as a whole.

How to detect a click on an edge of a multigraph?

I have written a win32 api-based GUI app which uses GDI+ features such as DrawCurve() and DrawLine().
This app draws lines and curves that represent a multigraph.
The data structure for the edge is simply a struct of five int's. (x1, y1, x2, y2, and id)
If there is only one edge between two vertices, a straight line segment is drawn using DrawLine().
If there are more than one edges, curves are drawn using DrawCurve() -- Here, I spread straight-line edges about the midpoint of two vertices, making them curves. A point some unit pixels apart from it is calculated using the normal line equation. If more edges are added then a pixel two unit pixels apart from the midpoint is selected, then next time 3 unit pixels, and so on.
Now I have two questions on detecting the click on edges.
In finding straight-line edges, to minimize the search time, what should I do?
It's quite simple to check if the pixel clicked is on the line segment but comparing all edges would be inefficient if the number of edges large. It seems possible to do it in O(log n), where n is the number of edges.
EDIT: at this point the edges (class Edge) are stored in std::map that maps edge id (int)'s
to Edge objects and I'm considering declaring another container that maps pixels to edge id's.
I'm considering using binary search trees but what can be the key? Or should I use just a 2D pixel array?
Can I get the array of points used by DrawCurve()? If this is impossible, then I should re-calculate the cardinal spline, get the array of points, and check if the point clicked by the user matches any point in that array.
If you have complex shaped lines you can do as follows:
Create an internal bitmap the size of your graph and fill it with black.
When you render your graph also render to this bitmap the edges you want to have click-able, but, render them with a different color. Store these color values in a table together with the corresponding ID. The important thing here is that the colors are different (unique).
When the graph is clicked, transfer the X and Y co-ordinates to your internal bitmap and read the pixel. If non-black, look up the color value in your table and get the associated ID.
This way do don't need to worry about the shape at all, neither is there a need to use your own curve algorithm and so forth. The cost is extra memory, this will a consideration, but unless it is a huge graph (in which case you can buffer the drawing) it is in most cases not an issue. You can render the internal bitmap in a second pass to have main graphics appear faster (as usual).
Hope this helps!
(tip: you can render the "internal" lines with a wider Pen so it gets more sensitive).

Algorithm to find the coordinates of a corner in a simple image

I have a bitmap where two large blocks of colors intersect, and I would like to find the intersection of these two blocks.
Note that I do not know the actual geometry of the two shapes, because this is all just raw pixel data.
Is there any algorithm I could use to do this?
If you have all the pixel data in memory (which I'd assume you do, but this is a major sticking point) and there are only two distinct colours, all you should need to do is run a horizontal scanline to find the point where RGB changes from colour X to colour Y (note that you may need to run this scanline a few times, but in any case it's no worse than O(height)).
A simple graph traversal (BFS or DFS) will then continue to walk you down that line (you should only need 3 points and then you'll be able to form a geometric line with equation a*x + b*y + c = 0 (assuming it's not a curve)).
Repeat this scanline vertically (again, worst case it's O(width)). Find 3 points and you'll then have two lines with d*x + e*y + f = 0. Using a little bit of comp. geom, the intersection of these two lines will give you your point.

Resources