最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

algorithm - Sortingclustering mechanism for determining bounding box intersection - Stack Overflow

programmeradmin0浏览0评论

I want to be more efficient in determining intersections between a group of 2D shapes (primitives like lines, arcs). I thought to do this by first checking overlap between their bounding boxes. Is there a means to sort the bounding boxes of all shapes such that I can conlude following:

Whenever box[i] is not intersecting with box[i+1], then this implies box[i] is also not intersecting with box[j] for j > i + 1 ?

Maybe some clustering is needed? Any ideas?

I want to be more efficient in determining intersections between a group of 2D shapes (primitives like lines, arcs). I thought to do this by first checking overlap between their bounding boxes. Is there a means to sort the bounding boxes of all shapes such that I can conlude following:

Whenever box[i] is not intersecting with box[i+1], then this implies box[i] is also not intersecting with box[j] for j > i + 1 ?

Maybe some clustering is needed? Any ideas?

Share Improve this question asked Jan 19 at 21:24 pfp.meijerspfp.meijers 9628 silver badges9 bronze badges 4
  • This is exactly what R-Trees (and their variants) are for! You insert items with their bounding boxes and querying returns items whose bounds intersect the given box. – micycle Commented Jan 22 at 11:14
  • @micycle Post an answer describing how to use R-Trees – ravenspoint Commented Jan 22 at 17:38
  • @ravenspoint R-Tree libraries are readily accessible in most languages. Once you have one they're trivial to interact with, so it's just a matter of letting OP know about them as a solution for a spatial index for bounding boxes. – micycle Commented Jan 22 at 17:51
  • Then it will be easy for you to post a good answer. – ravenspoint Commented Jan 22 at 18:32
Add a comment  | 

3 Answers 3

Reset to default 2

Whenever box[i] is not intersecting with box[i+1], then this implies box[i] is also not intersecting with box[j] for j > i + 1 ?

That is impossible.

Your best bet would be to take a look at quad trees. https://github/JamesBremner/quadtree

Here is an example of how using a quadtree can be applied to a problem, in this case selecting the points that are inside a viewport:

Code to generate the quadtree.

void cViewport::gen()
{
    // viewport located at 250,150 dimensions 100 by 100
    viewport = new quad::cCell( cxy(250,150), 100 );

    // quadtree incuding entire display
    quadtree = new quad::cCell(cxy(300, 300), 600);

    //add randomly placed objects
    const int count = 2000;
    for (int k = 0; k < count; k++) {
        cxy obj(rand() % 500, rand() % 500);
        vObjects.push_back(obj);
        quadtree->insert(obj);
    }
}

Code to detect all the points that are visible in the viewport ( i.e. collide with the viewport ) using the quadtree

void cViewport::draw(wex::shapes &S)
{
    // Draw all the point in white
    S.color(0xFFFFFF);
    for (auto &r : vObjects)
    {
        S.rectangle(r, cxy(1,1));
    }

    // redraw points inside view port in black
    S.color(0x000000);
    for (auto &r : quadtree->find( *viewport ))
    {
        S.rectangle(*r, cxy(1,1));
    }

    // draw viewport in red
    S.color(0x0000FF);
    int dim = viewport->getDim();
    cxy tl( 
        viewport->getCenter().x - dim / 2,
        viewport->getCenter().y - dim / 2);
    S.rectangle(
        tl,
        cxy(dim,dim));
}

Code to generate the sweeplines

void cViewport::genSweep()
{
    vSweep = vObjects;
    std::sort(
        vSweep.begin(), vSweep.end(),
        [](const cxy &a, const cxy &b)
        {
            return a.y < b.y;
        });
}

Code to detect all the points that are visible in the viewport ( i.e. collide with the viewport ) using the sweep lines


std::vector<cxy *> cViewport::sweepFind()
{
    std::vector<cxy *> ret;

    cxy cent = viewport->getCenter();
    double dim = viewport->getDim() / 2;
    double xmin = cent.x - dim;
    double xmax = cent.x + dim;
    double ymin = cent.y - dim;
    double ymax = cent.y + dim;

    for( cxy& o : vSweep )
    {
        if( o.y < ymin )
            continue;
        if( o.y > ymax )
            break;
        if( o.x < xmin)
            continue;
        if( o.x > xmax )
            continue;
        ret.push_back(&o);
    }
    return ret;
}

Output

Complete code for the viewport application at https://codeberg./JamesBremner/viewport You can toggle between using the quadtree or the sweepline algorithm using the menu options.

For your particular problem, replace the 1 by 1 points with the bounding rectangles of your 2D shapes, loop over the rectangles, using quadtree->find( boundingRectangle ) to detect possible overlaps.

Performance

Because of the initial expense of building the quadtree, it only becomes worthwhile to use a quadtree if you have more than 100 objects. More than 1000 and the quadtree performance benefit becomes really significant. Performace details at https://github/JamesBremner/quadtree#performance-test

It's not exactly a sorting/clustering solution, but you can determine all the intersections in O((n log n) + output_size) time using a sweep-line algorithm.

First, separate each box into its top edge and bottom edge. Each edge will include its y coordinate and the interval in x that it spans.

Then, sort the edges by their y coordinates.

Now, iterate through the edges in y order, from top to bottom. If you have top and bottom edges with the same y coordinate, visit the bottom edges first. Now:

  • When you see a top edge, insert its x-interval into an interval tree. At the same time you should check how many other intervals in the tree it overlaps with. There is a collision between the box that has the new top edge, and the boxes for all the overlapping intervals.
  • When you see a bottom edge, remove the corresponding top edge from the interval tree.

When you're done, you will have found all the overlaps.

You can imagine the horizontal "sweep line" moving from top to bottom, and the interval tree always represents all the boxes it intersects. The overlaps that the line intersects can only change at top or bottom edges.

As suggested by 'micycle' the R-Tree is matching my needs. With one call I create the index:

index = Index(generator(shapes))

where generator yields the bboxes of supplied shapes. And then I can do the intersection queries like:

intersections = index.intersection(bbox)

Thats it. Its fast for my needs (maybe because of compiled implementation). Factor 4 compared to brute force. (I don't have too many shapes.)

发布评论

评论列表(0)

  1. 暂无评论