T get_minimum_coordinate(unsigned i) const { return min_pt[i]; }
const LinAl::Vector<T, D> &get_maximum_point() const { return max_pt; }
T get_maximum_coordinate(unsigned i) const { return max_pt[i]; }
+ LinAl::Vector<T, D> get_dimensions() const { return max_pt-min_pt; }
+ T get_dimension(unsigned i) const { return max_pt[i]-min_pt[i]; }
+
bool is_empty() const { return empty && !negated; }
bool is_space() const { return empty && negated; }
bool is_negated() const { return negated; }
for(typename ShapeArray::const_iterator i=shapes.begin(); i!=shapes.end(); ++i)
{
Coverage c = (*i)->get_coverage(bbox);
- if(i==shapes.begin() || Ops::shortcircuit(c>coverage))
+ if(i==shapes.begin())
coverage = c;
+ else
+ coverage = Ops::combine_coverage(coverage, c);
- if(coverage!=PARTIAL_COVERAGE && Ops::shortcircuit(coverage==FULL_COVERAGE))
+ if((coverage==NO_COVERAGE && Ops::shortcircuit(false)) || (coverage==FULL_COVERAGE && Ops::shortcircuit(true)))
break;
}
struct IntersectionOps
{
static BoundingBox<T, D> combine_aabb(const BoundingBox<T, D> &a, const BoundingBox<T, D> &b) { return a&b; }
+ static Coverage combine_coverage(Coverage a, Coverage b) { return ((a==PARTIAL_COVERAGE && b==a) ? UNCERTAIN_COVERAGE : std::min(a, b)); }
static bool shortcircuit(bool c) { return !c; }
};
else if(coverage==NO_COVERAGE)
return FULL_COVERAGE;
else
- return PARTIAL_COVERAGE;
+ return coverage;
}
} // namespace Geometry
enum Coverage
{
NO_COVERAGE,
+ UNCERTAIN_COVERAGE,
PARTIAL_COVERAGE,
FULL_COVERAGE
};
const LinAl::Vector<T, D> &min_pt = cell.bounding_box.get_minimum_point();
const LinAl::Vector<T, D> &max_pt = cell.bounding_box.get_maximum_point();
+
+ // Skip cells that are already fully inside the established bounds.
+ bool internal = true;
+ for(unsigned i=0; (i<D && internal); ++i)
+ internal = (min_pt[i]>=tight_min_pt[i] && max_pt[i]<=tight_max_pt[i]);
+ if(internal)
+ {
+ queue.pop_front();
+ continue;
+ }
+
LinAl::Vector<T, D> center = (min_pt+max_pt)/T(2);
// Bisect each dimension.
child.coverage = get_coverage(child.bounding_box);
if(child.coverage==FULL_COVERAGE || (child.level==detail && child.coverage!=NO_COVERAGE))
{
- /* Adjust the bounds when we are certain that it's covered by at
- least part of the shape. Also adjust for uncertain results if
- we're on the last level. */
+ /* Immediately merge cells with full coverage. Also merge cells
+ at the last level. */
for(unsigned j=0; j<D; ++j)
{
tight_min_pt[j] = std::min(tight_min_pt[j], child_min_pt[j]);
}
}
else if(child.coverage==PARTIAL_COVERAGE)
+ {
+ /* Merge cells with confirmed partial coverage so the cell is
+ left just outside the bounding box. */
+ for(unsigned j=0; j<D; ++j)
+ {
+ tight_min_pt[j] = std::min(tight_min_pt[j], child_max_pt[j]);
+ tight_max_pt[j] = std::max(tight_max_pt[j], child_min_pt[j]);
+ }
+ }
+
+ if(child.level<detail && child.coverage!=NO_COVERAGE && child.coverage!=FULL_COVERAGE)
queue.push_back(child);
}
template<typename T, unsigned D>
inline Coverage TransformedShape<T, D>::get_coverage(const BoundingBox<T, D> &bbox) const
{
- return shape->get_coverage(inverse_trans.transform(bbox));
+ BoundingBox<T, D> local_bbox = inverse_trans.transform(bbox);
+ Coverage coverage = shape->get_coverage(local_bbox);
+ if(coverage==PARTIAL_COVERAGE)
+ {
+ BoundingBox<T, D> outer_bbox = transformation.transform(local_bbox);
+ LinAl::Vector<T, D> min_pt = local_bbox.get_minimum_point();
+ LinAl::Vector<T, D> max_pt = local_bbox.get_maximum_point();
+ for(unsigned i=0; i<D; ++i)
+ {
+ T scale_ratio = (1-bbox.get_dimension(i)/outer_bbox.get_dimension(i))*local_bbox.get_dimension(i);
+ T low_gap = bbox.get_minimum_coordinate(i)-outer_bbox.get_minimum_coordinate(i);
+ T high_gap = outer_bbox.get_maximum_coordinate(i)-bbox.get_maximum_coordinate(i);
+ min_pt[i] += low_gap*scale_ratio;
+ max_pt[i] -= high_gap-scale_ratio;
+ }
+
+ local_bbox = BoundingBox<T, D>(min_pt, max_pt);
+ if(shape->get_coverage(local_bbox)>=PARTIAL_COVERAGE)
+ return PARTIAL_COVERAGE;
+ else
+ return UNCERTAIN_COVERAGE;
+ }
+ else
+ return coverage;
}
} // namespace Geometry
struct UnionOps
{
static BoundingBox<T, D> combine_aabb(const BoundingBox<T, D> &a, const BoundingBox<T, D> &b) { return a|b; }
+ static Coverage combine_coverage(Coverage a, Coverage b) { return std::max(a, b); }
static bool shortcircuit(bool c) { return c; }
};