From a8f08bffacf95dbd7430dc358043de9406fae700 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 Jan 2021 02:12:33 +0100 Subject: [PATCH] WIP: new ratio filters, squares for DRC --- src/db/db/gsiDeclDbCompoundOperation.cc | 26 ++++ .../drc/built-in-macros/_drc_complex_ops.rb | 123 +++++++++++++++++- .../built-in-macros/_drc_cop_integration.rb | 36 +++++ src/drc/drc/built-in-macros/_drc_layer.rb | 121 ++++++++++++++++- 4 files changed, 298 insertions(+), 8 deletions(-) diff --git a/src/db/db/gsiDeclDbCompoundOperation.cc b/src/db/db/gsiDeclDbCompoundOperation.cc index 176481fde..f12ac1944 100644 --- a/src/db/db/gsiDeclDbCompoundOperation.cc +++ b/src/db/db/gsiDeclDbCompoundOperation.cc @@ -496,6 +496,12 @@ static db::CompoundRegionOperationNode *new_bbox_filter (db::CompoundRegionOpera return new db::CompoundRegionFilterOperationNode (new db::RegionBBoxFilter (vmin, vmax, inverse, parameter), input, true); } +static db::CompoundRegionOperationNode *new_ratio_filter (db::CompoundRegionOperationNode *input, db::RegionRatioFilter::parameter_type parameter, bool inverse, double vmin, bool vmin_included, double vmax, bool vmax_included) +{ + check_non_null (input, "input"); + return new db::CompoundRegionFilterOperationNode (new db::RegionRatioFilter (vmin, vmin_included, vmax, vmax_included, inverse, parameter), input, true); +} + static db::CompoundRegionOperationNode *new_start_segments (db::CompoundRegionOperationNode *input, db::Edges::length_type length, double fraction) { check_non_null (input, "input"); @@ -663,6 +669,11 @@ Class decl_CompoundRegionOperationNode ("db", " "This node renders the input if the specified bounding box parameter of the input shape is between pmin and pmax (exclusively). If 'inverse' is set to true, the " "input shape is returned if the parameter is less than pmin (exclusively) or larger than pmax (inclusively)." ) + + gsi::constructor ("new_ratio_filter", &new_ratio_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0.0), gsi::arg ("pmin_included"), gsi::arg ("pmax", std::numeric_limits::max (), "max"), gsi::arg ("pmax_included", true), + "@brief Creates a node filtering the input by ratio parameters.\n" + "This node renders the input if the specified ratio parameter of the input shape is between pmin and pmax. If 'pmin_included' is true, the range will include pmin. Same for 'pmax_included' and pmax. " + "If 'inverse' is set to true, the input shape is returned if the parameter is not within the specified range." + ) + 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" ) + @@ -851,5 +862,20 @@ gsi::EnumIn decl_dbRegionRatioFilter_ParameterType ("db", "ParameterType", + gsi::enum_const ("AreaRatio", db::RegionRatioFilter::AreaRatio, + "@brief Measures the area ratio (bounding box area / polygon area)\n" + ) + + gsi::enum_const ("AspectRatio", db::RegionRatioFilter::AspectRatio, + "@brief Measures the aspect ratio of the bounding box (larger / smaller dimension)\n" + ) + + gsi::enum_const ("RelativeHeight", db::RegionRatioFilter::RelativeHeight, + "@brief Measures the relative height (height / width)\n" + ), + "@brief This class represents the parameter type enum used in \\CompoundRegionOperationNode#new_ratio_filter\n" + "\n" + "This enum has been introduced in version 0.27." +); + } diff --git a/src/drc/drc/built-in-macros/_drc_complex_ops.rb b/src/drc/drc/built-in-macros/_drc_complex_ops.rb index 090dd8795..c3df1adf3 100644 --- a/src/drc/drc/built-in-macros/_drc_complex_ops.rb +++ b/src/drc/drc/built-in-macros/_drc_complex_ops.rb @@ -29,6 +29,8 @@ module DRC # @ul # @li \global#angle @/li # @li \global#area @/li +# @li \global#area_ratio @/li +# @li \global#bbox_area_ratio @/li # @li \global#bbox_height @/li # @li \global#bbox_max @/li # @li \global#bbox_min @/li @@ -60,6 +62,7 @@ module DRC # @li \global#primary @/li # @li \global#rectangles @/li # @li \global#rectilinear @/li +# @li \global#relative_height @/li # @li \global#rounded_corners @/li # @li \global#secondary @/li # @li \global#separation @/li @@ -67,6 +70,7 @@ module DRC # @li \global#sized @/li # @li \global#smoothed @/li # @li \global#space @/li +# @li \global#squares @/li # @li \global#width @/li # @/ul # @@ -269,7 +273,7 @@ CODE # %DRC% # @name perimeter - # @brief Selects the primary shape if the perimeter is meeting the condition + # @brief Selects the input polygon if the perimeter is meeting the condition # @synopsis expression.perimeter (in condition) # # This operation is used in conditions to select shapes based on their perimeter. @@ -294,7 +298,7 @@ CODE # %DRC% # @name bbox_min - # @brief Selects the primary shape if its bounding box smaller dimension is meeting the condition + # @brief Selects the input polygon if its bounding box smaller dimension is meeting the condition # @synopsis expression.bbox_min (in condition) # # This operation is used in conditions to select shapes based on smaller dimension of their bounding boxes. @@ -320,7 +324,7 @@ CODE # %DRC% # @name bbox_max - # @brief Selects the primary shape if its bounding box larger dimension is meeting the condition + # @brief Selects the input polygon if its bounding box larger dimension is meeting the condition # @synopsis expression.bbox_max (in condition) # # This operation acts similar to \DRC#bbox_min, but takes the larger dimension of the shape's @@ -335,7 +339,7 @@ CODE # %DRC% # @name bbox_width - # @brief Selects the primary shape if its bounding box width is meeting the condition + # @brief Selects the input polygon if its bounding box width is meeting the condition # @synopsis expression.bbox_width (in condition) # # This operation acts similar to \DRC#bbox_min, but takes the width of the shape's @@ -353,7 +357,7 @@ CODE # %DRC% # @name bbox_height - # @brief Selects the primary shape if its bounding box height is meeting the condition + # @brief Selects the input polygon if its bounding box height is meeting the condition # @synopsis expression.bbox_height (in condition) # # This operation acts similar to \DRC#bbox_min, but takes the height of the shape's @@ -369,6 +373,95 @@ CODE DRCOpNodeBBoxParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::ParameterType::BoxHeight, self) end + # %DRC% + # @name bbox_aspect_ratio + # @brief Selects the input polygon according to the aspect ratio of the bounding box + # @synopsis expression.bbox_aspect_ratio (in condition) + # + # This operation is used in conditions to select shapes based on aspect ratios of their bounding boxes. + # The aspect ratio is computed by dividing the larger of width and height by the smaller of both. + # The aspect ratio is always larger or equal to 1. Square or square-boxed shapes have a + # bounding box aspect ratio of 1. + # + # This filter is applicable on polygon expressions. The result will be the input + # polygon if the bounding box condition is met. + # + # See \Layer#drc for more details about comparison specs. + # + # The following example will select all polygons whose bounding box aspect ratio is larger than 3: + # + # @code + # out = in.drc(bbox_aspect_ratio > 3) + # out = in.drc(primary.bbox_aspect_ratio > 3) # equivalent + # @/code + # + # The "bbox_aspect_ratio" method is available as a plain function or as a method on \DRC## expressions. + # The plain function is equivalent to "primary.bbox_aspect_ratio". + + def bbox_aspect_ratio + DRCOpNodeRatioParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::RegionRatioFilter::AspectRatio, self) + end + + # %DRC% + # @name relative_height + # @brief Selects the input polygon according to the height vs. width of the bounding box + # @synopsis expression.relative_height (in condition) + # + # This operation is used in conditions to select shapes based on the ratio of bounding box + # height vs. width. The taller the shape, the larger the value. Wide polygons have a value + # below 1. A square has a relative height of 1. + # + # This filter is applicable on polygon expressions. The result will be the input + # polygon if the condition is met. + # + # Don't use this method if you can use \bbox_aspect_ratio, because the latter is + # isotropic and can be used hierarchically without generating rotation variants. + # + # See \Layer#drc for more details about comparison specs. + # + # The following example will select all polygons whose relative height is larger than 3: + # + # @code + # out = in.drc(relative_height > 3) + # out = in.drc(primary.relative_height > 3) # equivalent + # @/code + # + # The "relative_height" method is available as a plain function or as a method on \DRC## expressions. + # The plain function is equivalent to "primary.bbox_aspect_ratio". + + def relative_height + DRCOpNodeRatioParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::RegionRatioFilter::RelativeHeight, self) + end + + # %DRC% + # @name area_ratio + # @brief Selects the input polygon according to its area ratio (bounding box area by polygon area) + # @synopsis expression.area_ratio (in condition) + # + # This operation is used in conditions to select shapes based on their area ratio. + # The area ratio is the ratio of bounding box vs. polygon area. It's a measure how + # "sparse" the polygons are and how good an approximation the bounding box is. + # The value is always larger or equal than 1. Boxes have a value of 1. + # + # This filter is applicable on polygon expressions. The result will be the input + # polygon if the condition is met. + # + # See \Layer#drc for more details about comparison specs. + # + # The following example will select all polygons whose area ratio is larger than 3: + # + # @code + # out = in.drc(area_ratio > 3) + # out = in.drc(primary.area_ratio > 3) # equivalent + # @/code + # + # The "area_ratio" method is available as a plain function or as a method on \DRC## expressions. + # The plain function is equivalent to "primary.area_ratio". + + def area_ratio + DRCOpNodeRatioParameterFilter::new(@engine, RBA::CompoundRegionOperationNode::RegionRatioFilter::AreaRatio, self) + end + # %DRC% # @name length # @brief Selects edges based on their length @@ -627,7 +720,25 @@ CODE # @/code def rectangles - return DRCOpNodeFilter::new(@engine, self, :new_rectangle_filter, "rectangle") + return DRCOpNodeFilter::new(@engine, self, :new_rectangle_filter, "rectangle", false) + end + + # %DRC% + # @name squares + # @brief Selects all polygons which are squares + # @synopsis expression.squares + # + # This operation can be used as a plain function in which case it acts on primary + # shapes or can be used as method on another DRC expression. + # The following example selects all squares: + # + # @code + # out = in.drc(squares) + # out = in.drc(primary.squares) # equivalent + # @/code + + def squares + return DRCOpNodeFilter::new(@engine, self, :new_rectangle_filter, "rectangle", true) end # %DRC% diff --git a/src/drc/drc/built-in-macros/_drc_cop_integration.rb b/src/drc/drc/built-in-macros/_drc_cop_integration.rb index 96f95996e..768eb211f 100644 --- a/src/drc/drc/built-in-macros/_drc_cop_integration.rb +++ b/src/drc/drc/built-in-macros/_drc_cop_integration.rb @@ -499,11 +499,35 @@ CODE # # See \Layer#drc, \bbox_min and \DRC#bbox_min for more details. + # %DRC% + # @name bbox_aspect_ratio + # @brief Selects primary shapes based on the aspect ratio of their bounding boxes + # @synopsis bbox_aspect_ratio (in condition) + # + # See \Layer#drc, \bbox_aspect_ratio and \DRC#bbox_aspect_ratio for more details. + + # %DRC% + # @name relative_height + # @brief Selects primary shapes based on the ratio of height and width of their bounding boxes + # @synopsis relative_height (in condition) + # + # See \Layer#drc, \relative_height and \DRC#relative_height for more details. + + # %DRC% + # @name area_ratio + # @brief Selects primary shapes based on the ratio of bounding box and polygon area + # @synopsis area_ratio (in condition) + # + # See \Layer#drc, \area_ratio and \DRC#area_ratio for more details. + %w( bbox_height bbox_max bbox_min bbox_width + bbox_aspect_ratio + area_ratio + relative_height ).each do |f| eval <<"CODE" def #{f} @@ -584,6 +608,17 @@ CODE # argument, "rectangles" represents the rectangles filter for primary shapes in # \DRC# expressions (see \Layer#drc and \DRC#rectangles for more details). + # %DRC% + # @name squares + # @brief Selects all polygons which are squares + # @synopsis squares + # @synopsis squares(layer) + # + # This function can be used with a layer argument in which case it + # is equivalent to "layer.squares" (see \Layer#squares). Without a layer + # argument, "squares" represents the rectangles filter for primary shapes in + # \DRC# expressions (see \Layer#drc and \DRC#squares for more details). + # %DRC% # @name rectilinear # @brief Selects all polygons which are rectilinear @@ -623,6 +658,7 @@ CODE odd_polygons perimeter rectangles + squares rectilinear length angle diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 7ecec71c6..5ef059555 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -517,6 +517,106 @@ CODE end end + # %DRC% + # @name with_bbox_aspect_ratio + # @brief Selects polygons by the aspect ratio of their bounding box + # @synopsis layer.with_bbox_aspect_ratio(min .. max) + # @synopsis layer.with_bbox_aspect_ratio(value) + # @synopsis layer.with_bbox_aspect_ratio(min, max) + # The method selects polygons similar to \with_area or \with_perimeter. + # However, the measured value is the aspect ratio of the bounding + # box. It is the larger dimensions divided by the smaller one. + # The "thinner" the polygon, the larger the aspect ratio. A square + # bounding box gives an aspect ratio of 1. + # + # This method is available for polygon layers only. + + # %DRC% + # @name without_bbox_height + # @brief Selects polygons by the aspect ratio of their bounding box + # @synopsis layer.without_bbox_aspect_ratio(min .. max) + # @synopsis layer.without_bbox_aspect_ratio(value) + # @synopsis layer.without_bbox_aspect_ratio(min, max) + # The method provides the opposite filter for \with_bbox_aspect_ratio. + # + # This method is available for polygon layers only. + + # %DRC% + # @name with_area_ratio + # @brief Selects polygons by the ratio of the bounding box area vs. polygon area + # @synopsis layer.with_area_ratio(min .. max) + # @synopsis layer.with_area_ratio(value) + # @synopsis layer.with_area_ratio(min, max) + # The area ratio is a measure how far a polygon is approximated by it's + # bounding box. The value is always larger or equal to 1. Boxes have a + # area ratio of 1. Larger values mean more empty area inside the bounding box. + # + # This method is available for polygon layers only. + + # %DRC% + # @name without_area_ratio + # @brief Selects polygons by the aspect ratio of their bounding box + # @synopsis layer.without_area_ratio(min .. max) + # @synopsis layer.without_area_ratio(value) + # @synopsis layer.without_area_ratio(min, max) + # The method provides the opposite filter for \with_area_ratio. + # + # This method is available for polygon layers only. + + # %DRC% + # @name with_relative_height + # @brief Selects polygons by the ratio of the height vs. width of it's bounding box + # @synopsis layer.with_relative_height(min .. max) + # @synopsis layer.with_relative_height(value) + # @synopsis layer.with_relative_height(min, max) + # The relative height is a measure how tall a polygon is. Tall polygons + # have values larger than 1, wide polygons have a value smaller than 1. + # Squares have a value of 1. + # + # Don't use this method when you can use \with_area_ratio, which provides a + # similar measure but is isotropic. + # + # This method is available for polygon layers only. + + # %DRC% + # @name without_relative_height + # @brief Selects polygons by the ratio of the height vs. width + # @synopsis layer.without_relative_height(min .. max) + # @synopsis layer.without_relative_height(value) + # @synopsis layer.without_relative_height(min, max) + # The method provides the opposite filter for \with_relative_height. + # + # This method is available for polygon layers only. + + %w(area_ratio bbox_aspect_ratio relative_height).each do |f| + [true, false].each do |inv| + mn = (inv ? "without" : "with") + "_" + f + eval <<"CODE" + def #{mn}(*args) + + @engine._context("#{mn}") do + + requires_region + if args.size == 1 + a = args[0] + if a.is_a?(Range) + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, @engine._prep_value(a.first), @engine._make_numeric_value(a.last), #{inv.inspect})) + else + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, @engine._prep_value(a), #{inv.inspect})) + end + elsif args.size == 2 + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Region, :with_#{f}, @engine._prep_value(args[0]), @engine._make_numeric_value(args[1]), #{inv.inspect})) + else + raise("Invalid number of arguments (1 or 2 expected)") + end + + end + + end +CODE + end + end + # %DRC% # @name with_length # @brief Selects edges by their length @@ -2332,13 +2432,22 @@ CODE # %DRC% # @name rectangles - # @brief Selects all rectangle polygons from the input + # @brief Selects all rectangles from the input # @synopsis layer.rectangles # # This method is available for polygon layers. By default "merged" semantics applies, # i.e. all polygons are merged before rectangles are selected (see \clean and \raw). # \non_rectangles will select all non-rectangles. + # %DRC% + # @name squares + # @brief Selects all squares from the input + # @synopsis layer.squares + # + # This method is available for polygon layers. By default "merged" semantics applies, + # i.e. all polygons are merged before squares are selected (see \clean and \raw). + # \non_squares will select all non-rectangles. + # %DRC% # @name rectilinear # @brief Selects all rectilinear polygons from the input @@ -2348,6 +2457,14 @@ CODE # i.e. all polygons are merged before rectilinear polygons are selected (see \clean and \raw). # \non_rectilinear will select all non-rectangles. + # %DRC% + # @name non_squares + # @brief Selects all polygons from the input which are not squares + # @synopsis layer.non_rectangles + # + # This method is available for polygon layers. By default "merged" semantics applies, + # i.e. all polygons are merged before non-squares are selected (see \clean and \raw). + # %DRC% # @name non_rectangles # @brief Selects all polygons from the input which are not rectangles @@ -2400,7 +2517,7 @@ CODE # @/tr # @/table - %w(rectangles rectilinear non_rectangles non_rectilinear + %w(rectangles rectilinear non_rectangles non_rectilinear squares non_squares holes hulls).each do |f| eval <<"CODE" def #{f}