1

I have a rectangular mesh that is represented as a bidimensional array of bidimensional points. Something like this (C#-inspired pseudo-code):

Point2D[,] mesh = CreateSampleMesh();
mesh.Plot();

enter image description here

Important characteristics are:

  1. The mesh is topologically rectangular, but geometrically "irregular" as the image shows;
  2. The X coordinate of each row and Y coordinate of each column is monotonical (that is, it does not "reverse directions");
  3. Every rectangle is convex (a necessary consequence of item 2, I guess);

My question is: given a candidate Point2D, how do I find which " rectangle" it's inside, if any? Here is the method signature I would suggest:

GridPosition position = GetIndexOfBottomLeftRectangleContaining(Point2D candidatePoint);
if (position != null)
{
    int pi = Position.I;
    int pj = Positino.J;
}
heltonbiker
  • 26,657
  • 28
  • 137
  • 252
  • There may be a topological transform -type algorithm which allows you to query the grid as if it were *spatially* regular, i.e. in O(1). Without knowing this you could still reduce the complexity by using a "quadtree"-like data structure; split the grid into 4 parts recursively, and at run-time determine which quarter the point is in. Assuming the grid is topologically square with side length `N`, this would reduce the search complexity from brute-force `O(N^2)` to at least `O(N)`, or even `O(log^2 N)` with a good containment query algorithm. – meowgoesthedog Jan 25 '18 at 23:09
  • You could also build a BSP tree with all of the lines, but that would create extra segments, and finding the optimal tree might not be worth the effort. – meowgoesthedog Jan 25 '18 at 23:23

3 Answers3

1

You may find useful the algorithm for finding whether a point is inside a convex polygon or not. Note that the second answer there suggests a method which costs four dot products in 2D, which assuming that multiplications take constant time, means time complexity of 4 * O(D) = 4 * O(2) = O(1).

Now you could go insane and check in parallel all the polygons you have there, which of course wouldn't be O(N2), but still an overkill probably.

For that reason, you need to partition space, with any data structure you like, where every partition would contain one of your polygons.

A quadtree:

is a tree data structure in which each internal node has exactly four children. Quadtrees are the two-dimensional analog of octrees and are most often used to partition a two-dimensional space by recursively subdividing it into four quadrants or regions.

seems to come in handy in that case, where every leaf would contain one polygon (or few of them, you choose).

Once a query lands on a leaf, then you would go and check if that point is inside the polygon(s) of this leaf and give the answer.

In particular, I would try a Region Quadtree, which "represents a partition of space in two dimensions by decomposing the region into four equal quadrants, subquadrants, and so on with each leaf node containing data corresponding to a specific subregion."

The query time is logarithmic, or linear in worst case scenario, as you can read in these slides.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • That is an interesting approach. I would _love_ to have the time to perform a check on multiple candidate algorithms. Right now I think using an exhaustive parallel double-pass hit testing (checking for bounding box first, and polygon second only if needed) could give a decent performance. If not, I'm going to consider a better algorithm, possibly trying one of your suggested data-structures. Thank you very much for now! – heltonbiker Jan 26 '18 at 12:34
  • Yeah @heltonbiker bbox sounds good, good luck, have fun! You are welcome, – gsamaras Jan 27 '18 at 11:14
  • Well, my exhaustive approach worked correctly but the performance was incredibly poor as I expected. Since I am performing a rectangular scanning, perhaps I get to optimize search based on last find, but I think conceptually the Region Quadtree is the obvious fit for this problem, specially if you need to find arbitrary points. Thanks! – heltonbiker Jan 29 '18 at 12:58
  • @heltonbiker: do you mean that you resample the domain on a regular grid ? If yes, this is a different question, with a different answer. –  Jan 31 '18 at 17:52
  • @YvesDaoust I don't resample in the sense of "moving" the points (that is, altering the X, Y and Z of each Point3D in the array). Actually I _interpolate_ a new Z value for a given X,Y input, based on the X, Y and Z coordinates of each corner of the intercepted ("containing") polygon. Hope I made myself clear... :o) – heltonbiker Jan 31 '18 at 19:28
  • @heltonbiker: this is what I meant by resampling. Are you resampling on a regular grid ? –  Jan 31 '18 at 19:33
  • Yes, I am. If you consider the drawing you made in your answer, I need to obtain a Point3D(x,y,z) from the green Point2D(x,y) used for input, and the four Point3D at the corners of the rectangle containing the green point. That part would involve some sort of bilinear interpolation, or even a simple average for a start. – heltonbiker Jan 31 '18 at 19:40
  • 1
    @heltonbiker: given the regular arrangement of the sampling point, you don't need to redo a full search for every point, there are much more efficient ways. –  Jan 31 '18 at 22:07
1

You are lucky to have monotonic chains (polylines), which are in a way of sorting the plane.

First, design a procedure that will tell if you are left or right of a vertical chain. To achieve this, you find the line segment facing the point vertically, and draw an horizontal line. The intersection point tells you if you are left or right. This takes a dichotomic search among the node ordinates.

enter image description here

Use this procedure to find the two closest chains on either sides, that define a stripe where the point lies. Now a final dichotomic search in this stripe, by comparing to the horizontal edges will tell you the exact tile.

For an array of N² nodes, this will take time proportional to Log²N and require no extra data structure !

  • I am abandoning quadtree search which ended up being quite complex for me (at least my implementation with lots of index operations), and will try your suggestion with one binary search for each dimension, and a final check for actual polygon intersection. Thanks! – heltonbiker Jan 31 '18 at 19:38
0

You could use some kind of 2D binary search.

Example: If you have a point p(px,py) and your mesh is stored in a 5x5 array 'mesh[i,j]', you would start with i=5/2=3 and j=5/2=3. Here is some basic example code for illustration.:

int i = 3;
int j = 3;
int iOld = i
int jOld = j;
do {
    iOld = i
    jOld = j;

    Point m = mesh[i,j]; 
    //Compare p with m: 
    if (p.x > m.x) {
        i = (i+5)/2;
    } else {
        i = (i/2)/2;
    }
    if (p.y > m.y) {
        j = (j+5)/2;
    } else {
        j = (j/2)/2;
    }
} while (i != iOld && j != jOld);

This code is only for illustration! You may have to verify that i and j are calculated correctly when you get close to the node, and that they don't oscillate, otherwise the exit condition may never become true. Otherwise this should find your point in the mesh pretty fast.

Edit: This approach assumes that distortion is 'benign', meaning that nodes are not contorted such that they move into a different square (which requires that the grid lines would intersect). If grid lines can cross, then this approach won't work.

TilmannZ
  • 1,784
  • 11
  • 18