diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index e489d71db..088dc3971 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -437,6 +437,193 @@ poly2poly_check::enter (const PolygonType &o1, size_t p1, const Pol template class poly2poly_check; template class poly2poly_check; +// ------------------------------------------------------------------------------------- +// 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 diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 0b5af89ce..5e6e54ed7 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -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 * diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index 9ccc49e7f..176481fde 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -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::distance_type vmin, db::coord_traits::distance_type vmax) @@ -666,8 +666,9 @@ Class 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" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 5b23694a2..55b539d4f 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -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 (), min_included, max.is_nil () ? std::numeric_limits ::max () : max.to (), 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 (), min_included, max.is_nil () ? std::numeric_limits ::max () : max.to (), 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 (), min_included, max.is_nil () ? std::numeric_limits ::max () : max.to (), 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 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 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 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 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 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 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 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 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 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 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 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,7 +1001,96 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" ) + - method ("strange_polygon_check", &db::Region::strange_polygon_check, + 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" "\n" @@ -1877,6 +2014,20 @@ Class 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." diff --git a/src/db/unit_tests/dbCompoundOperationTests.cc b/src/db/unit_tests/dbCompoundOperationTests.cc index dde3ea383..f2ab315bf 100644 --- a/src/db/unit_tests/dbCompoundOperationTests.cc +++ b/src/db/unit_tests/dbCompoundOperationTests.cc @@ -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 inputs; inputs.push_back (condition1r); diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 0400da263..576fff5da 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -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")