I don't think the Segment Tree from the CGAL library can help you to solve this problem, because this tree was designed to perform only two types of queries (window_query
and enclosing_query
). In both cases the search process returns a subset of the original set of D-dimensional intervals, which was used to build the tree - however you are interested in the open space "between" these intervals, which is not represented explicitly by this data structure.
Problems, similar to the problem you're asking about, were studied in Computational Geometry for a long time - the simplest case is finding a largest (by area or by perimeter) empty rectangle among a set of points on the plane. Generalizations of this problem have been studied as well - for more general obstacles (segments, rectangles, polygons) and higher dimensions. Please see this Wikipage for more information (including references).
However, finding the largest rectangle might be overabundant for you - any rectangle with size more or equal than the given size will suffice, and it will save you some time compared to the largest rectangle search. If your set of rectangles is static, but the size of the empty rectangle you wish to find varies, then it makes sense to preprocess this set into some data structure (as you mentioned above). There are some publications where they present algorithms to find all the maximal empty rectangles and save them in a list. Maximal empty rectangle is defined as a rectangle, which can’t be extended in any direction without intersecting with obstacles. Sorry to say, I couldn’t find any such publications, which can be accessed for free.
I’m suggesting a simple recursive algorithm, which can find an empty rectangle with width and height more or equal than the requested size. The idea is to start from the bounding box of the rectangle set and process rectangles from this set one by one. Each such rectangle is subtracted from the current empty rectangle, however result of this subtraction is represented as a set of maximal rectangles, which may overlap. For example, result of subtraction of the rectangle [0,2)x[0,2)
from the rectangle [1,3)x[1,3)
is a set of two rectangles [2,3)x[1,3)
and [1,3)x[2,3)
. The algorithm returns an empty rectangle and a Boolean flag, indicating success or fail.
using RVec = std::vector<Rectangle>;
using Result = std::pair<Rectangle, bool>;
Result find(const RVec& V, double W, double H, const Rectangle& R, unsigned J)
{
if (R.sizeIsLess(W, H))
{
// ------ the empty rectangle R is too small
return {R, false};
}
else if (J < V.size())
{
// ------ process the obstacle rectangle with number J
for (const auto& r: subtract(R, V[J]))
{
const auto res = find(V, W, H, r, J + 1);
if (res.second) return {res.first, true};
}
return {R, false};
}
else
{
// ------ the empty rectangle R is big enough, and all the obstacles are processed
return {R, true};
}
}
auto find(const RVec& V, double W, double H)
{
return find(V, W, H, bbox(V), 0);
}
I can’t prove that this algorithm works correctly for any possible set of rectangular obstacles and for any requested width and height, however it worked well in all my tests. The algorithm is recursive, so the limited stack size might be a problem for really large rectangle sets.
The algorithm can be randomized by shuffling the rectangle set and/or the result of rectangles subtraction – then you’ll possibly get multiple solutions for the given rectangle set and given width and height. The algorithm can be extended to higher dimensions as well – then the function subtract
will need to be modified. If you are interested I’ll add this function (for 2D case) into this answer.