New region filters (square, area ratio, relative height)

This commit is contained in:
Matthias Koefferlein 2021-01-13 01:08:42 +01:00
parent ae29c75326
commit dce22fee37
6 changed files with 490 additions and 120 deletions

View File

@ -437,6 +437,193 @@ poly2poly_check<PolygonType>::enter (const PolygonType &o1, size_t p1, const Pol
template class poly2poly_check<db::Polygon>;
template class poly2poly_check<db::PolygonRef>;
// -------------------------------------------------------------------------------------
// RegionPerimeterFilter implementation
RegionPerimeterFilter::RegionPerimeterFilter (perimeter_type pmin, perimeter_type pmax, bool inverse)
: m_pmin (pmin), m_pmax (pmax), m_inverse (inverse)
{
// .. nothing yet ..
}
bool RegionPerimeterFilter::selected (const db::Polygon &poly) const
{
perimeter_type p = 0;
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end () && p < m_pmax; ++e) {
p += (*e).length ();
}
if (! m_inverse) {
return p >= m_pmin && p < m_pmax;
} else {
return ! (p >= m_pmin && p < m_pmax);
}
}
const TransformationReducer *RegionPerimeterFilter::vars () const
{
return &m_vars;
}
// -------------------------------------------------------------------------------------
// RegionAreaFilter implementation
RegionAreaFilter::RegionAreaFilter (area_type amin, area_type amax, bool inverse)
: m_amin (amin), m_amax (amax), m_inverse (inverse)
{
// .. nothing yet ..
}
bool
RegionAreaFilter::selected (const db::Polygon &poly) const
{
area_type a = poly.area ();
if (! m_inverse) {
return a >= m_amin && a < m_amax;
} else {
return ! (a >= m_amin && a < m_amax);
}
}
const TransformationReducer *
RegionAreaFilter::vars () const
{
return &m_vars;
}
// -------------------------------------------------------------------------------------
// RectilinearFilter implementation
RectilinearFilter::RectilinearFilter (bool inverse)
: m_inverse (inverse)
{
// .. nothing yet ..
}
bool
RectilinearFilter::selected (const db::Polygon &poly) const
{
return poly.is_rectilinear () != m_inverse;
}
const TransformationReducer *
RectilinearFilter::vars () const
{
return 0;
}
// -------------------------------------------------------------------------------------
// RectilinearFilter implementation
RectangleFilter::RectangleFilter (bool is_square, bool inverse)
: m_is_square (is_square), m_inverse (inverse)
{
// .. nothing yet ..
}
bool
RectangleFilter::selected (const db::Polygon &poly) const
{
bool ok = poly.is_box ();
if (ok && m_is_square) {
db::Box box = poly.box ();
ok = box.width () == box.height ();
}
return ok != m_inverse;
}
const TransformationReducer *RectangleFilter::vars () const
{
return 0;
}
// -------------------------------------------------------------------------------------
// RectilinearFilter implementation
RegionBBoxFilter::RegionBBoxFilter (value_type vmin, value_type vmax, bool inverse, parameter_type parameter)
: m_vmin (vmin), m_vmax (vmax), m_inverse (inverse), m_parameter (parameter)
{
// .. nothing yet ..
}
bool
RegionBBoxFilter::selected (const db::Polygon &poly) const
{
value_type v = 0;
db::Box box = poly.box ();
if (m_parameter == BoxWidth) {
v = box.width ();
} else if (m_parameter == BoxHeight) {
v = box.height ();
} else if (m_parameter == BoxMinDim) {
v = std::min (box.width (), box.height ());
} else if (m_parameter == BoxMaxDim) {
v = std::max (box.width (), box.height ());
} else if (m_parameter == BoxAverageDim) {
v = (box.width () + box.height ()) / 2;
}
if (! m_inverse) {
return v >= m_vmin && v < m_vmax;
} else {
return ! (v >= m_vmin && v < m_vmax);
}
}
const TransformationReducer *
RegionBBoxFilter::vars () const
{
if (m_parameter != BoxWidth && m_parameter != BoxHeight) {
return &m_isotropic_vars;
} else {
return &m_anisotropic_vars;
}
}
// -------------------------------------------------------------------------------------
// RectilinearFilter implementation
RegionRatioFilter::RegionRatioFilter (double vmin, bool min_included, double vmax, bool max_included, bool inverse, parameter_type parameter)
: m_vmin (vmin), m_vmax (vmax), m_vmin_included (min_included), m_vmax_included (max_included), m_inverse (inverse), m_parameter (parameter)
{
// .. nothing yet ..
}
bool RegionRatioFilter::selected (const db::Polygon &poly) const
{
double v = 0.0;
if (m_parameter == AreaRatio) {
v = poly.area_ratio ();
} else if (m_parameter == AspectRatio) {
db::Box box = poly.box ();
double f = std::max (box.height (), box.width ());
double d = std::min (box.height (), box.width ());
if (d < 1) {
return false;
}
v = f / d;
} else if (m_parameter == RelativeHeight) {
db::Box box = poly.box ();
double f = box.height ();
double d = box.width ();
if (d < 1) {
return false;
}
v = f / d;
}
bool ok = (v - (m_vmin_included ? -db::epsilon : db::epsilon) > m_vmin && v - (m_vmax_included ? db::epsilon : -db::epsilon) < m_vmax);
return ok != m_inverse;
}
const TransformationReducer *RegionRatioFilter::vars () const
{
if (m_parameter != RelativeHeight) {
return &m_isotropic_vars;
} else {
return &m_anisotropic_vars;
}
}
// -------------------------------------------------------------------------------------
// SinglePolygonCheck implementation

View File

@ -52,36 +52,17 @@ struct DB_PUBLIC RegionPerimeterFilter
* @param amax The maximum perimeter (only polygons with a perimeter below this value are filtered)
* @param inverse If set to true, only polygons not matching this criterion will be filtered
*/
RegionPerimeterFilter (perimeter_type pmin, perimeter_type pmax, bool inverse)
: m_pmin (pmin), m_pmax (pmax), m_inverse (inverse)
{
// .. nothing yet ..
}
RegionPerimeterFilter (perimeter_type pmin, perimeter_type pmax, bool inverse);
/**
* @brief Returns true if the polygon's perimeter matches the criterion
*/
virtual bool selected (const db::Polygon &poly) const
{
perimeter_type p = 0;
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end () && p < m_pmax; ++e) {
p += (*e).length ();
}
if (! m_inverse) {
return p >= m_pmin && p < m_pmax;
} else {
return ! (p >= m_pmin && p < m_pmax);
}
}
virtual bool selected (const db::Polygon &poly) const;
/**
* @brief This filter is isotropic
*/
virtual const TransformationReducer *vars () const
{
return &m_vars;
}
virtual const TransformationReducer *vars () const;
/**
* @brief This filter prefers producing variants
@ -120,32 +101,17 @@ struct DB_PUBLIC RegionAreaFilter
* @param amax The maximum area (only polygons with an area below this value are filtered)
* @param inverse If set to true, only polygons not matching this criterion will be filtered
*/
RegionAreaFilter (area_type amin, area_type amax, bool inverse)
: m_amin (amin), m_amax (amax), m_inverse (inverse)
{
// .. nothing yet ..
}
RegionAreaFilter (area_type amin, area_type amax, bool inverse);
/**
* @brief Returns true if the polygon's area matches the criterion
*/
virtual bool selected (const db::Polygon &poly) const
{
area_type a = poly.area ();
if (! m_inverse) {
return a >= m_amin && a < m_amax;
} else {
return ! (a >= m_amin && a < m_amax);
}
}
virtual bool selected (const db::Polygon &poly) const;
/**
* @brief This filter is isotropic
*/
virtual const TransformationReducer *vars () const
{
return &m_vars;
}
virtual const TransformationReducer *vars () const;
/**
* @brief This filter prefers producing variants
@ -176,27 +142,17 @@ struct DB_PUBLIC RectilinearFilter
* @brief Constructor
* @param inverse If set to true, only polygons not matching this criterion will be filtered
*/
RectilinearFilter (bool inverse)
: m_inverse (inverse)
{
// .. nothing yet ..
}
RectilinearFilter (bool inverse);
/**
* @brief Returns true if the polygon's area matches the criterion
*/
virtual bool selected (const db::Polygon &poly) const
{
return poly.is_rectilinear () != m_inverse;
}
virtual bool selected (const db::Polygon &poly) const;
/**
* @brief This filter does not need variants
*/
virtual const TransformationReducer *vars () const
{
return 0;
}
virtual const TransformationReducer *vars () const;
/**
* @brief This filter prefers producing variants
@ -225,27 +181,17 @@ struct DB_PUBLIC RectangleFilter
* @brief Constructor
* @param inverse If set to true, only polygons not matching this criterion will be filtered
*/
RectangleFilter (bool inverse)
: m_inverse (inverse)
{
// .. nothing yet ..
}
RectangleFilter (bool is_square, bool inverse);
/**
* @brief Returns true if the polygon's area matches the criterion
*/
virtual bool selected (const db::Polygon &poly) const
{
return poly.is_box () != m_inverse;
}
virtual bool selected (const db::Polygon &poly) const;
/**
* @brief This filter does not need variants
*/
virtual const TransformationReducer *vars () const
{
return 0;
}
virtual const TransformationReducer *vars () const;
/**
* @brief This filter prefers producing variants
@ -258,6 +204,7 @@ struct DB_PUBLIC RectangleFilter
virtual bool requires_raw_input () const { return false; }
private:
bool m_is_square;
bool m_inverse;
};
@ -300,48 +247,17 @@ struct DB_PUBLIC RegionBBoxFilter
* @param vmax The max value (only polygons with bounding box parameters below this value are filtered)
* @param inverse If set to true, only polygons not matching this criterion will be filtered
*/
RegionBBoxFilter (value_type vmin, value_type vmax, bool inverse, parameter_type parameter)
: m_vmin (vmin), m_vmax (vmax), m_inverse (inverse), m_parameter (parameter)
{
// .. nothing yet ..
}
RegionBBoxFilter (value_type vmin, value_type vmax, bool inverse, parameter_type parameter);
/**
* @brief Returns true if the polygon's area matches the criterion
*/
virtual bool selected (const db::Polygon &poly) const
{
value_type v = 0;
db::Box box = poly.box ();
if (m_parameter == BoxWidth) {
v = box.width ();
} else if (m_parameter == BoxHeight) {
v = box.height ();
} else if (m_parameter == BoxMinDim) {
v = std::min (box.width (), box.height ());
} else if (m_parameter == BoxMaxDim) {
v = std::max (box.width (), box.height ());
} else if (m_parameter == BoxAverageDim) {
v = (box.width () + box.height ()) / 2;
}
if (! m_inverse) {
return v >= m_vmin && v < m_vmax;
} else {
return ! (v >= m_vmin && v < m_vmax);
}
}
virtual bool selected (const db::Polygon &poly) const;
/**
* @brief This filter is isotropic unless the parameter is width or height
*/
virtual const TransformationReducer *vars () const
{
if (m_parameter != BoxWidth && m_parameter != BoxHeight) {
return &m_isotropic_vars;
} else {
return &m_anisotropic_vars;
}
}
virtual const TransformationReducer *vars () const;
/**
* @brief This filter prefers producing variants
@ -361,6 +277,69 @@ private:
db::MagnificationAndOrientationReducer m_anisotropic_vars;
};
/**
* @brief A ratio filter for use with Region::filter or Region::filtered
*
* This filter can select polygons based on certain ratio values.
* "ratio values" are typically in the order of 1 and floating point
* values. Ratio values are always >= 0.
*
* Available ratio values are:
* - (AreaRatio) area ratio (bounding box area vs. polygon area)
* - (AspectRatio) bounding box aspect ratio (max / min)
* - (RelativeHeight) bounding box height to width (tallness)
*/
struct DB_PUBLIC RegionRatioFilter
: public PolygonFilterBase
{
/**
* @brief The parameters available
*/
enum parameter_type {
AreaRatio,
AspectRatio,
RelativeHeight
};
/**
* @brief Constructor
*
* @param vmin The min value (only polygons with bounding box parameters above this value are filtered)
* @param vmax The max value (only polygons with bounding box parameters below this value are filtered)
* @param inverse If set to true, only polygons not matching this criterion will be filtered
*/
RegionRatioFilter (double vmin, bool min_included, double vmax, bool max_included, bool inverse, parameter_type parameter);
/**
* @brief Returns true if the polygon's area matches the criterion
*/
virtual bool selected (const db::Polygon &poly) const;
/**
* @brief This filter is isotropic unless the parameter is width or height
*/
virtual const TransformationReducer *vars () const;
/**
* @brief This filter prefers producing variants
*/
virtual bool wants_variants () const { return true; }
/**
* @brief This filter wants merged input
*/
virtual bool requires_raw_input () const { return false; }
private:
double m_vmin, m_vmax;
bool m_vmin_included, m_vmax_included;
bool m_inverse;
parameter_type m_parameter;
db::MagnificationReducer m_isotropic_vars;
db::MagnificationAndOrientationReducer m_anisotropic_vars;
};
/**
* @brief A polygon processor filtering strange polygons
*

View File

@ -484,10 +484,10 @@ static db::CompoundRegionOperationNode *new_rectilinear_filter (db::CompoundRegi
return new db::CompoundRegionFilterOperationNode (new db::RectilinearFilter (inverse), input, true);
}
static db::CompoundRegionOperationNode *new_rectangle_filter (db::CompoundRegionOperationNode *input, bool inverse)
static db::CompoundRegionOperationNode *new_rectangle_filter (db::CompoundRegionOperationNode *input, bool square, bool inverse)
{
check_non_null (input, "input");
return new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (inverse), input, true);
return new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (square, inverse), input, true);
}
static db::CompoundRegionOperationNode *new_bbox_filter (db::CompoundRegionOperationNode *input, db::RegionBBoxFilter::parameter_type parameter, bool inverse, db::coord_traits<db::Coord>::distance_type vmin, db::coord_traits<db::Coord>::distance_type vmax)
@ -666,8 +666,9 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
gsi::constructor ("new_rectilinear_filter", &new_rectilinear_filter, gsi::arg ("input"), gsi::arg ("inverse", false),
"@brief Creates a node filtering the input for rectilinear shapes (or non-rectilinear ones with 'inverse' set to 'true').\n"
) +
gsi::constructor ("new_rectangle_filter", &new_rectangle_filter, gsi::arg ("input"), gsi::arg ("inverse", false),
"@brief Creates a node filtering the input for rectangular shapes (or non-rectangular ones with 'inverse' set to 'true').\n"
gsi::constructor ("new_rectangle_filter", &new_rectangle_filter, gsi::arg ("input"), gsi::arg ("is_square", false), gsi::arg ("inverse", false),
"@brief Creates a node filtering the input for rectangular or square shapes.\n"
"If 'is_square' is true, only squares will be selected. If 'inverse' is true, the non-rectangle/non-square shapes are returned.\n"
) +
gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"),
"@brief Creates a node converting polygons into it's edges.\n"

View File

@ -366,6 +366,42 @@ static db::EdgePairs angle_check2 (const db::Region *r, double amin, double amax
return r->angle_check (amin, amax, inverse);
}
static db::Region with_bbox_aspect_ratio1 (const db::Region *r, double v, bool inverse)
{
db::RegionRatioFilter f (v, true, v, true, inverse, db::RegionRatioFilter::AspectRatio);
return r->filtered (f);
}
static db::Region with_bbox_aspect_ratio2 (const db::Region *r, const tl::Variant &min, const tl::Variant &max, bool inverse, bool min_included, bool max_included)
{
db::RegionRatioFilter f (min.is_nil () ? 0.0 : min.to<double> (), min_included, max.is_nil () ? std::numeric_limits <double>::max () : max.to<double> (), max_included, inverse, db::RegionRatioFilter::AspectRatio);
return r->filtered (f);
}
static db::Region with_area_ratio1 (const db::Region *r, double v, bool inverse)
{
db::RegionRatioFilter f (v, true, v, true, inverse, db::RegionRatioFilter::AreaRatio);
return r->filtered (f);
}
static db::Region with_area_ratio2 (const db::Region *r, const tl::Variant &min, const tl::Variant &max, bool inverse, bool min_included, bool max_included)
{
db::RegionRatioFilter f (min.is_nil () ? 0.0 : min.to<double> (), min_included, max.is_nil () ? std::numeric_limits <double>::max () : max.to<double> (), max_included, inverse, db::RegionRatioFilter::AreaRatio);
return r->filtered (f);
}
static db::Region with_relative_height1 (const db::Region *r, double v, bool inverse)
{
db::RegionRatioFilter f (v, true, v, true, inverse, db::RegionRatioFilter::RelativeHeight);
return r->filtered (f);
}
static db::Region with_relative_height2 (const db::Region *r, const tl::Variant &min, const tl::Variant &max, bool inverse, bool min_included, bool max_included)
{
db::RegionRatioFilter f (min.is_nil () ? 0.0 : min.to<double> (), min_included, max.is_nil () ? std::numeric_limits <double>::max () : max.to<double> (), max_included, inverse, db::RegionRatioFilter::RelativeHeight);
return r->filtered (f);
}
static db::Region in (const db::Region *r, const db::Region &other)
{
return r->in (other, false);
@ -378,13 +414,25 @@ static db::Region not_in (const db::Region *r, const db::Region &other)
static db::Region rectangles (const db::Region *r)
{
db::RectangleFilter f (false);
db::RectangleFilter f (false, false);
return r->filtered (f);
}
static db::Region non_rectangles (const db::Region *r)
{
db::RectangleFilter f (true);
db::RectangleFilter f (false, true);
return r->filtered (f);
}
static db::Region squares (const db::Region *r)
{
db::RectangleFilter f (true, false);
return r->filtered (f);
}
static db::Region non_squares (const db::Region *r)
{
db::RectangleFilter f (true, true);
return r->filtered (f);
}
@ -839,7 +887,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_perimeter", with_perimeter1, gsi::arg ("perimeter"), gsi::arg ("inverse"),
"@brief Filter the polygons by perimeter\n"
"Filters the polygons inside the region by perimeter. If \"inverse\" is false, only "
"Filters the polygons of the region by perimeter. If \"inverse\" is false, only "
"polygons which have the given perimeter are returned. If \"inverse\" is true, "
"polygons not having the given perimeter are returned.\n"
"\n"
@ -847,7 +895,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_perimeter", with_perimeter2, gsi::arg ("min_perimeter"), gsi::arg ("max_perimeter"), gsi::arg ("inverse"),
"@brief Filter the polygons by perimeter\n"
"Filters the polygons inside the region by perimeter. If \"inverse\" is false, only "
"Filters the polygons of the region by perimeter. If \"inverse\" is false, only "
"polygons which have a perimeter larger or equal to \"min_perimeter\" and less than \"max_perimeter\" are "
"returned. If \"inverse\" is true, "
"polygons having a perimeter less than \"min_perimeter\" or larger or equal than \"max_perimeter\" are "
@ -859,7 +907,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"),
"@brief Filter the polygons by area\n"
"Filters the polygons inside the region by area. If \"inverse\" is false, only "
"Filters the polygons of the region by area. If \"inverse\" is false, only "
"polygons which have the given area are returned. If \"inverse\" is true, "
"polygons not having the given area are returned.\n"
"\n"
@ -867,7 +915,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_area", with_area2, gsi::arg ("min_area"), gsi::arg ("max_area"), gsi::arg ("inverse"),
"@brief Filter the polygons by area\n"
"Filters the polygons inside the region by area. If \"inverse\" is false, only "
"Filters the polygons of the region by area. If \"inverse\" is false, only "
"polygons which have an area larger or equal to \"min_area\" and less than \"max_area\" are "
"returned. If \"inverse\" is true, "
"polygons having an area less than \"min_area\" or larger or equal than \"max_area\" are "
@ -879,7 +927,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_bbox_width", with_bbox_width1, gsi::arg ("width"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width\n"
"Filters the polygons inside the region by the width of their bounding box. If \"inverse\" is false, only "
"Filters the polygons of the region by the width of their bounding box. If \"inverse\" is false, only "
"polygons whose bounding box has the given width are returned. If \"inverse\" is true, "
"polygons whose bounding box does not have the given width are returned.\n"
"\n"
@ -887,7 +935,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_bbox_width", with_bbox_width2, gsi::arg ("min_width"), gsi::arg ("max_width"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width\n"
"Filters the polygons inside the region by the width of their bounding box. If \"inverse\" is false, only "
"Filters the polygons of the region by the width of their bounding box. If \"inverse\" is false, only "
"polygons whose bounding box has a width larger or equal to \"min_width\" and less than \"max_width\" are "
"returned. If \"inverse\" is true, all polygons not matching this criterion are returned."
"\n"
@ -897,7 +945,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_bbox_height", with_bbox_height1, gsi::arg ("height"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box height\n"
"Filters the polygons inside the region by the height of their bounding box. If \"inverse\" is false, only "
"Filters the polygons of the region by the height of their bounding box. If \"inverse\" is false, only "
"polygons whose bounding box has the given height are returned. If \"inverse\" is true, "
"polygons whose bounding box does not have the given height are returned.\n"
"\n"
@ -905,7 +953,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_bbox_height", with_bbox_height2, gsi::arg ("min_height"), gsi::arg ("max_height"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box height\n"
"Filters the polygons inside the region by the height of their bounding box. If \"inverse\" is false, only "
"Filters the polygons of the region by the height of their bounding box. If \"inverse\" is false, only "
"polygons whose bounding box has a height larger or equal to \"min_height\" and less than \"max_height\" are "
"returned. If \"inverse\" is true, all polygons not matching this criterion are returned."
"\n"
@ -924,7 +972,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_bbox_min", with_bbox_min2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width or height, whichever is smaller\n"
"Filters the polygons inside the region by the minimum dimension of their bounding box. "
"Filters the polygons of the region by the minimum dimension of their bounding box. "
"If \"inverse\" is false, only polygons whose bounding box's smaller dimension is larger or equal to \"min_dim\" "
"and less than \"max_dim\" are returned. "
"If \"inverse\" is true, all polygons not matching this criterion are returned."
@ -935,7 +983,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_bbox_max", with_bbox_max1, gsi::arg ("dim"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width or height, whichever is larger\n"
"Filters the polygons inside the region by the maximum dimension of their bounding box. "
"Filters the polygons of the region by the maximum dimension of their bounding box. "
"If \"inverse\" is false, only polygons whose bounding box's larger dimension is equal to the given value "
"are returned. "
"If \"inverse\" is true, all polygons not matching this criterion are returned."
@ -944,7 +992,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
) +
method_ext ("with_bbox_max", with_bbox_max2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width or height, whichever is larger\n"
"Filters the polygons inside the region by the minimum dimension of their bounding box. "
"Filters the polygons of the region by the minimum dimension of their bounding box. "
"If \"inverse\" is false, only polygons whose bounding box's larger dimension is larger or equal to \"min_dim\" "
"and less than \"max_dim\" are returned. "
"If \"inverse\" is true, all polygons not matching this criterion are returned."
@ -953,6 +1001,95 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method_ext ("with_bbox_aspect_ratio", with_bbox_aspect_ratio1, gsi::arg ("ratio"), gsi::arg ("inverse"),
"@brief Filters the polygons by the aspect ratio of their bounding boxes\n"
"Filters the polygons of the region by the apspect ratio of their bounding boxes. "
"The aspect ratio is the ratio of larger to smaller dimension of the bounding box. "
"A square has an aspect ratio of 1.\n"
"\n"
"With 'inverse' set to false, this version filters polygons which have a bounding box aspect ratio equal to the given value. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("with_bbox_aspect_ratio", with_bbox_aspect_ratio2, gsi::arg ("min_ratio"), gsi::arg ("max_ratio"), gsi::arg ("inverse"), gsi::arg ("min_included", true), gsi::arg ("max_included", true),
"@brief Filters the polygons by the aspect ratio of their bounding boxes\n"
"Filters the polygons of the region by the apspect ratio of their bounding boxes. "
"The aspect ratio is the ratio of larger to smaller dimension of the bounding box. "
"A square has an aspect ratio of 1.\n"
"\n"
"With 'inverse' set to false, this version filters polygons which have a bounding box aspect ratio between 'min_ratio' and 'max_ratio'. "
"With 'min_included' set to true, the 'min_ratio' value is included in the range, otherwise it's excluded. Same for 'max_included' and 'max_ratio'. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("with_area_ratio", with_area_ratio1, gsi::arg ("ratio"), gsi::arg ("inverse"),
"@brief Filters the polygons by the bounding box area to polygon area ratio\n"
"The area ratio is defined by the ratio of bounding box area to polygon area. It's a measure "
"how much the bounding box is approximating the polygon. 'Thin polygons' have a large area ratio, boxes has an area ratio of 1.\n"
"The area ratio is always larger or equal to 1. "
"\n"
"With 'inverse' set to false, this version filters polygons which have an area ratio equal to the given value. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("with_area_ratio", with_area_ratio2, gsi::arg ("min_ratio"), gsi::arg ("max_ratio"), gsi::arg ("inverse"), gsi::arg ("min_included", true), gsi::arg ("max_included", true),
"@brief Filters the polygons by the aspect ratio of their bounding boxes\n"
"The area ratio is defined by the ratio of bounding box area to polygon area. It's a measure "
"how much the bounding box is approximating the polygon. 'Thin polygons' have a large area ratio, boxes has an area ratio of 1.\n"
"The area ratio is always larger or equal to 1. "
"\n"
"With 'inverse' set to false, this version filters polygons which have an area ratio between 'min_ratio' and 'max_ratio'. "
"With 'min_included' set to true, the 'min_ratio' value is included in the range, otherwise it's excluded. Same for 'max_included' and 'max_ratio'. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("with_relative_height", with_relative_height1, gsi::arg ("ratio"), gsi::arg ("inverse"),
"@brief Filters the polygons by the ratio of heigth to width\n"
"This method filters the polygons of the region by the ratio of height vs. width of their bounding boxes. "
"'Tall' polygons have a large value while 'flat' polygons have a small value. A square has a relative height of 1.\n"
"\n"
"An alternative method is 'with_area_ratio' which can be more efficient because it's isotropic.\n"
"\n"
"With 'inverse' set to false, this version filters polygons which have a relative height equal to the given value. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("with_relative_height", with_relative_height2, gsi::arg ("min_ratio"), gsi::arg ("max_ratio"), gsi::arg ("inverse"), gsi::arg ("min_included", true), gsi::arg ("max_included", true),
"@brief Filters the polygons by the bounding box height to width ratio\n"
"This method filters the polygons of the region by the ratio of height vs. width of their bounding boxes. "
"'Tall' polygons have a large value while 'flat' polygons have a small value. A square has a relative height of 1.\n"
"\n"
"An alternative method is 'with_area_ratio' which can be more efficient because it's isotropic.\n"
"\n"
"With 'inverse' set to false, this version filters polygons which have a relative height between 'min_ratio' and 'max_ratio'. "
"With 'min_included' set to true, the 'min_ratio' value is included in the range, otherwise it's excluded. Same for 'max_included' and 'max_ratio'. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method ("strange_polygon_check", &db::Region::strange_polygon_check,
"@brief Returns a region containing those parts of polygons which are \"strange\"\n"
"Strange parts of polygons are self-overlapping parts or non-orientable parts (i.e. in the \"8\" configuration).\n"
@ -1877,6 +2014,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method returns all polygons in self which are not rectangles."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
) +
method_ext ("squares", &squares,
"@brief Returns all polygons which are squares\n"
"This method returns all polygons in self which are squares."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("non_squares", &non_squares,
"@brief Returns all polygons which are not squares\n"
"This method returns all polygons in self which are not squares."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("rectilinear", &rectilinear,
"@brief Returns all polygons which are rectilinear\n"
"This method returns all polygons in self which are rectilinear."

View File

@ -481,7 +481,7 @@ void run_test9 (tl::TestBase *_this, bool deep)
db::CompoundRegionSizeOperationNode *result1 = new db::CompoundRegionSizeOperationNode (50, 50, 2, primary);
inputs.push_back (result1);
db::CompoundRegionFilterOperationNode *condition2 = new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (false), primary, true);
db::CompoundRegionFilterOperationNode *condition2 = new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (false, false), primary, true);
inputs.push_back (condition2);
db::CompoundRegionSizeOperationNode *result2 = new db::CompoundRegionSizeOperationNode (-50, -50, 2, primary);
@ -536,7 +536,7 @@ void run_test10 (tl::TestBase *_this, bool deep)
db::CompoundRegionFilterOperationNode *condition1 = new db::CompoundRegionFilterOperationNode (new db::RegionAreaFilter (0, 10000000, true), primary, true);
db::CompoundRegionFilterOperationNode *condition1r = new db::CompoundRegionFilterOperationNode (new db::RegionAreaFilter (0, 10000000, false), primary, true);
db::CompoundRegionFilterOperationNode *condition2 = new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (false), primary, true);
db::CompoundRegionFilterOperationNode *condition2 = new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (false, false), primary, true);
std::vector<db::CompoundRegionOperationNode *> inputs;
inputs.push_back (condition1r);

View File

@ -985,6 +985,58 @@ class DBRegion_TestClass < TestBase
end
# Some filters
def test_boxfilters1
r = RBA::Region::new
r.insert(RBA::Box::new(0, 0, 1000, 5000))
r.insert(RBA::Box::new(3000, 0, 7000, 1000))
r.insert(RBA::Box::new(0, 10000, 2000, 12000))
assert_equal(r.with_bbox_width(1000, false).to_s, "(0,0;0,5000;1000,5000;1000,0)")
assert_equal(r.with_bbox_width(1000, true).to_s, "(3000,0;3000,1000;7000,1000;7000,0);(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_width(1000, 2001, false).to_s, "(0,0;0,5000;1000,5000;1000,0);(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_width(1000, 2000, false).to_s, "(0,0;0,5000;1000,5000;1000,0)")
assert_equal(r.with_bbox_width(1000, 2001, true).to_s, "(3000,0;3000,1000;7000,1000;7000,0)")
assert_equal(r.with_bbox_height(5000, false).to_s, "(0,0;0,5000;1000,5000;1000,0)")
assert_equal(r.with_bbox_height(5000, true).to_s, "(3000,0;3000,1000;7000,1000;7000,0);(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_height(1000, 2001, false).to_s, "(3000,0;3000,1000;7000,1000;7000,0);(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_height(1000, 1001, false).to_s, "(3000,0;3000,1000;7000,1000;7000,0)")
assert_equal(r.with_bbox_height(1000, 1001, true).to_s, "(0,0;0,5000;1000,5000;1000,0);(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_aspect_ratio(1.0, false).to_s, "(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_aspect_ratio(1.0, true).to_s, "(3000,0;3000,1000;7000,1000;7000,0);(0,0;0,5000;1000,5000;1000,0)")
assert_equal(r.with_bbox_aspect_ratio(0.9, 1.0, false).to_s, "(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_aspect_ratio(1.0, 1.1, false).to_s, "(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_bbox_aspect_ratio(0.9, 0.95, false).to_s, "")
assert_equal(r.with_bbox_aspect_ratio(0.9, 1.0, false, true, false).to_s, "")
assert_equal(r.with_bbox_aspect_ratio(1.0, 1.1, false, false, true).to_s, "")
assert_equal(r.with_relative_height(1.0, false).to_s, "(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_relative_height(1.0, true).to_s, "(3000,0;3000,1000;7000,1000;7000,0);(0,0;0,5000;1000,5000;1000,0)")
assert_equal(r.with_relative_height(0.9, 1.0, false).to_s, "(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_relative_height(1.0, 1.1, false).to_s, "(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_relative_height(0.9, 0.95, false).to_s, "")
assert_equal(r.with_relative_height(0.9, 1.0, false, true, false).to_s, "")
assert_equal(r.with_relative_height(1.0, 1.1, false, false, true).to_s, "")
r = RBA::Region::new
r.insert(RBA::Box::new(0, 0, 1000, 2000))
r.insert(RBA::Box::new(0, 0, 2000, 1000))
r.insert(RBA::Box::new(0, 10000, 2000, 12000))
assert_equal(r.with_area_ratio(1.0, false).to_s, "(0,10000;0,12000;2000,12000;2000,10000)")
assert_equal(r.with_area_ratio(1.0, true).to_s, "(0,0;0,2000;1000,2000;1000,1000;2000,1000;2000,0)")
assert_equal(r.with_area_ratio(4.0 / 3.0, false).to_s, "(0,0;0,2000;1000,2000;1000,1000;2000,1000;2000,0)")
assert_equal(r.with_area_ratio(1.3, 1.4, false).to_s, "(0,0;0,2000;1000,2000;1000,1000;2000,1000;2000,0)")
assert_equal(r.with_area_ratio(1.3, 4.0 / 3.0, false, false, true).to_s, "(0,0;0,2000;1000,2000;1000,1000;2000,1000;2000,0)")
assert_equal(r.with_area_ratio(1.3, 4.0 / 3.0, false, false, false).to_s, "")
assert_equal(r.with_area_ratio(4.0 / 3.0, 1.4, false, true, false).to_s, "(0,0;0,2000;1000,2000;1000,1000;2000,1000;2000,0)")
assert_equal(r.with_area_ratio(4.0 / 3.0, 1.4, false, false, false).to_s, "")
end
end
load("test_epilogue.rb")