More complete compound DRC operations.

This commit is contained in:
Matthias Koefferlein 2020-12-05 18:18:27 +01:00
parent 44aef92160
commit 6ac766d68f
4 changed files with 134 additions and 59 deletions

View File

@ -467,7 +467,10 @@ void CompoundRegionLogicalBoolOperationNode::implement_compute_local (db::Layout
}
// @@@ invert is not handled, this is not a boolean return value
if (m_invert) {
ok = ! ok;
}
if (ok) {
tl_assert (! results.empty ());
results.front ().insert (subject_shape);
@ -922,12 +925,20 @@ template void CompoundRegionLogicalCaseSelectOperationNode::implement_compute_lo
// ---------------------------------------------------------------------------------------------
CompoundRegionFilterOperationNode::CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input)
: CompoundRegionMultiInputOperationNode (input), mp_filter (filter)
CompoundRegionFilterOperationNode::CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter)
: CompoundRegionMultiInputOperationNode (input), mp_filter (filter), m_owns_filter (owns_filter)
{
set_description ("filter");
}
CompoundRegionFilterOperationNode::~CompoundRegionFilterOperationNode ()
{
if (m_owns_filter) {
delete mp_filter;
}
mp_filter = 0;
}
void
CompoundRegionFilterOperationNode::do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const
{

View File

@ -733,7 +733,8 @@ class DB_PUBLIC CompoundRegionFilterOperationNode
: public CompoundRegionMultiInputOperationNode
{
public:
CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input);
CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter = false);
~CompoundRegionFilterOperationNode ();
// specifies the result type
virtual ResultType result_type () const { return Region; }
@ -746,6 +747,7 @@ public:
private:
PolygonFilterBase *mp_filter;
bool m_owns_filter;
bool is_selected (const db::Polygon &p) const;
bool is_selected (const db::PolygonRef &p) const;

View File

@ -24,6 +24,7 @@
#include "gsiEnums.h"
#include "dbCompoundOperation.h"
#include "dbRegionUtils.h"
namespace gsi
{
@ -45,7 +46,7 @@ static db::CompoundRegionOperationNode *new_logical_boolean (db::CompoundRegionL
static db::CompoundRegionOperationNode *new_geometrical_boolean (db::CompoundRegionGeometricalBoolOperationNode::GeometricalOp op, db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b)
{
// @@@ is this correct?
// TODO: is this correct?
if ((a->result_type () != db::CompoundRegionOperationNode::Region && a->result_type () != db::CompoundRegionOperationNode::Edges) ||
(b->result_type () != db::CompoundRegionOperationNode::Region && b->result_type () != db::CompoundRegionOperationNode::Edges)) {
throw tl::Exception ("Inputs for geometrical booleans must be either of Region or Edges type");
@ -55,7 +56,7 @@ static db::CompoundRegionOperationNode *new_geometrical_boolean (db::CompoundReg
static db::CompoundRegionOperationNode *new_interacting (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count)
{
// @@@ is this correct?
// TODO: is this correct?
if (a->result_type () != db::CompoundRegionOperationNode::Region) {
throw tl::Exception ("Primary input for interaction compound operation must be of Region type");
}
@ -70,7 +71,7 @@ static db::CompoundRegionOperationNode *new_interacting (db::CompoundRegionOpera
static db::CompoundRegionOperationNode *new_overlapping (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count)
{
// @@@ is this correct?
// TODO: is this correct?
if (a->result_type () != db::CompoundRegionOperationNode::Region) {
throw tl::Exception ("Primary input for interaction compound operation must be of Region type");
}
@ -83,7 +84,7 @@ static db::CompoundRegionOperationNode *new_overlapping (db::CompoundRegionOpera
static db::CompoundRegionOperationNode *new_inside (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse)
{
// @@@ is this correct?
// TODO: is this correct?
if (a->result_type () != db::CompoundRegionOperationNode::Region) {
throw tl::Exception ("Primary input for interaction compound operation must be of Region type");
}
@ -96,7 +97,7 @@ static db::CompoundRegionOperationNode *new_inside (db::CompoundRegionOperationN
static db::CompoundRegionOperationNode *new_outside (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse)
{
// @@@ is this correct?
// TODO: is this correct?
if (a->result_type () != db::CompoundRegionOperationNode::Region) {
throw tl::Exception ("Primary input for interaction compound operation must be of Region type");
}
@ -202,6 +203,31 @@ static db::CompoundRegionOperationNode *new_inside_check_node (db::CompoundRegio
return new db::CompoundRegionCheckOperationNode (input, db::InsideRelation, true, d, whole_edges, metrics, ignore_angle, min_projection, max_projection, shielded);
}
static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegionOperationNode *input, db::coord_traits<db::Coord>::perimeter_type pmin, db::coord_traits<db::Coord>::perimeter_type pmax, bool inverse)
{
return new db::CompoundRegionFilterOperationNode (new db::RegionPerimeterFilter (pmin, pmax, inverse), input, true);
}
static db::CompoundRegionOperationNode *new_area_filter (db::CompoundRegionOperationNode *input, db::coord_traits<db::Coord>::area_type amin, db::coord_traits<db::Coord>::area_type amax, bool inverse)
{
return new db::CompoundRegionFilterOperationNode (new db::RegionAreaFilter (amin, amax, inverse), input, true);
}
static db::CompoundRegionOperationNode *new_rectilinear_filter (db::CompoundRegionOperationNode *input, bool inverse)
{
return new db::CompoundRegionFilterOperationNode (new db::RectilinearFilter (inverse), input, true);
}
static db::CompoundRegionOperationNode *new_rectangle_filter (db::CompoundRegionOperationNode *input, bool inverse)
{
return new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (inverse), input, true);
}
static db::CompoundRegionOperationNode *new_bbox_filter (db::CompoundRegionOperationNode *input, db::RegionBBoxFilter::parameter_type parameter, db::coord_traits<db::Coord>::distance_type vmin, db::coord_traits<db::Coord>::distance_type vmax, bool inverse)
{
return new db::CompoundRegionFilterOperationNode (new db::RegionBBoxFilter (vmin, vmax, inverse, parameter), input, true);
}
Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "CompoundRegionOperationNode",
gsi::constructor ("new_primary", &new_primary,
"@brief Creates a node object representing the primary input"
@ -212,127 +238,108 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
gsi::constructor ("new_logical_boolean", &new_logical_boolean, gsi::arg ("op"), gsi::arg ("invert"), gsi::arg ("inputs"),
"@brief Creates a node representing a logical boolean operation between the inputs.\n"
"\n"
"@@@ TODO.\n"
"A logical AND operation will evaluate the arguments and render the subject shape when all arguments are non-empty. "
"The logical OR operation will evaluate the arguments and render the subject shape when one argument is non-empty. "
"Setting 'inverse' to true will reverse the result and return the subject shape when one argument is empty in the AND case and "
"when all arguments are empty in the OR case."
) +
gsi::constructor ("new_geometrical_boolean", &new_geometrical_boolean, gsi::arg ("op"), gsi::arg ("a"), gsi::arg ("b"),
"@brief Creates a node representing a geometrical boolean operation between the inputs.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_interacting", &new_interacting, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an interacting selection operation between the inputs.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_overlapping", &new_overlapping, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an overlapping selection operation between the inputs.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_inside", &new_inside, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false),
"@brief Creates a node representing an inside selection operation between the inputs.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_outside", &new_outside, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false),
"@brief Creates a node representing an outside selection operation between the inputs.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_case", &new_case, gsi::arg ("inputs"),
"@brief Creates a 'switch ladder' (case statement) compound operation node.\n"
"\n"
"@@@ TODO.\n"
"The inputs are treated as a sequence of condition/result pairs: c1,r1,c2,r2 etc. If there is an odd number of inputs, the last "
"element is taken as the default result. The implementation will evaluate c1 and if not empty, will render r1. Otherwise, c2 will be evaluated and r2 "
"rendered if c2 isn't empty etc. If none of the conditions renders a non-empty set and a default result is present, the default will be "
"returned. Otherwise, the result is empty."
) +
gsi::constructor ("new_corners_as_rectangles", &new_corners_as_rectangles_node, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"), gsi::arg ("dim"),
"@brief Creates a node turning corners into rectangles.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_corners_as_dots", &new_corners_as_dots_node, gsi::arg ("input"), gsi::arg ("angle_start"), gsi::arg ("angle_end"),
"@brief Creates a node turning corners into dots (single-point edges).\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_relative_extents", &new_relative_extents_node, gsi::arg ("input"), gsi::arg ("fx1"), gsi::arg ("fy1"), gsi::arg ("fx2"), gsi::arg ("fy2"), gsi::arg ("dx"), gsi::arg ("dy"),
"@brief Creates a node returning markers at specified locations of the extend (e.g. at the center).\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_relative_extents_as_edges", &new_relative_extents_as_edges_node, gsi::arg ("input"), gsi::arg ("fx1"), gsi::arg ("fy1"), gsi::arg ("fx2"), gsi::arg ("fy2"),
"@brief Creates a node returning edges at specified locations of the extend (e.g. at the center).\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_convex_decomposition", &new_convex_decomposition_node, gsi::arg ("input"), gsi::arg ("mode"),
"@brief Creates a node providing a composition into convex pieces.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_trapezoid_decomposition", &new_trapezoid_decomposition_node, gsi::arg ("input"), gsi::arg ("mode"),
"@brief Creates a node providing a composition into trapezoids.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_polygon_breaker_node", &new_polygon_breaker_node, gsi::arg ("input"), gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"),
"@brief Creates a node providing a composition into parts with less than the given number of points and a smaller area ratio.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_size_node", &new_size_node, gsi::arg ("input"), gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"),
"@brief Creates a node providing sizing.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_minkowsky_sum", &new_minkowsky_sum_node1, gsi::arg ("input"), gsi::arg ("e"),
"@brief Creates a node providing a Minkowsky sum with an edge.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_minkowsky_sum", &new_minkowsky_sum_node2, gsi::arg ("input"), gsi::arg ("p"),
"@brief Creates a node providing a Minkowsky sum with a polygon.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_minkowsky_sum", &new_minkowsky_sum_node3, gsi::arg ("input"), gsi::arg ("p"),
"@brief Creates a node providing a Minkowsky sum with a box.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_minkowsky_sum", &new_minkowsky_sum_node4, gsi::arg ("input"), gsi::arg ("p"),
"@brief Creates a node providing a Minkowsky sum with a point sequence forming a contour.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_width_check", &new_width_check_node, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", 90.0), gsi::arg ("min_projection", db::coord_traits<db::Coord>::distance_type (0)), gsi::arg ("max_projection", std::numeric_limits<db::coord_traits<db::Coord>::distance_type>::max (), "max."), gsi::arg ("shielded", true),
"@brief Creates a node providing a width check.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_space_check", &new_space_check_node, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", 90.0), gsi::arg ("min_projection", db::coord_traits<db::Coord>::distance_type (0)), gsi::arg ("max_projection", std::numeric_limits<db::coord_traits<db::Coord>::distance_type>::max (), "max."), gsi::arg ("shielded", true),
"@brief Creates a node providing a space check.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_notch_check", &new_notch_check_node, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", 90.0), gsi::arg ("min_projection", db::coord_traits<db::Coord>::distance_type (0)), gsi::arg ("max_projection", std::numeric_limits<db::coord_traits<db::Coord>::distance_type>::max (), "max."), gsi::arg ("shielded", true),
"@brief Creates a node providing a space check.\n"
"\n"
"@@@ TODO.\n"
"@brief Creates a node providing a intra-polygon space check.\n"
) +
gsi::constructor ("new_separation_check", &new_separation_check_node, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", 90.0), gsi::arg ("min_projection", db::coord_traits<db::Coord>::distance_type (0)), gsi::arg ("max_projection", std::numeric_limits<db::coord_traits<db::Coord>::distance_type>::max (), "max."), gsi::arg ("shielded", true),
"@brief Creates a node providing a separation check.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_overlap_check", &new_overlap_check_node, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", 90.0), gsi::arg ("min_projection", db::coord_traits<db::Coord>::distance_type (0)), gsi::arg ("max_projection", std::numeric_limits<db::coord_traits<db::Coord>::distance_type>::max (), "max."), gsi::arg ("shielded", true),
"@brief Creates a node providing an overlap check.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_inside_check", &new_inside_check_node, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian), gsi::arg ("ignore_angle", 90.0), gsi::arg ("min_projection", db::coord_traits<db::Coord>::distance_type (0)), gsi::arg ("max_projection", std::numeric_limits<db::coord_traits<db::Coord>::distance_type>::max (), "max."), gsi::arg ("shielded", true),
"@brief Creates a node providing an inside (enclosure) check.\n"
"\n"
"@@@ TODO.\n"
) +
gsi::constructor ("new_perimeter_filter", &new_perimeter_filter, gsi::arg ("input"), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits<db::coord_traits<db::Coord>::perimeter_type>::max (), "max"), gsi::arg ("inverse", false),
"@brief Creates a node filtering the input by perimeter.\n"
"This node renders the input if the perimeter is between pmin and pmax (exclusively). If 'inverse' is set to true, the "
"input shape is returned if the perimeter is less than pmin (exclusively) or larger than pmax (inclusively)."
) +
gsi::constructor ("new_area_filter", &new_area_filter, gsi::arg ("input"), gsi::arg ("amin", 0), gsi::arg ("amax", std::numeric_limits<db::coord_traits<db::Coord>::area_type>::max (), "max"), gsi::arg ("inverse", false),
"@brief Creates a node filtering the input by area.\n"
"This node renders the input if the area is between amin and amax (exclusively). If 'inverse' is set to true, the "
"input shape is returned if the area is less than amin (exclusively) or larger than amax (inclusively)."
) +
gsi::constructor ("new_bbox_filter", &new_bbox_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits<db::coord_traits<db::Coord>::area_type>::max (), "max"), gsi::arg ("inverse", false),
"@brief Creates a node filtering the input by bounding box parameters.\n"
"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_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"
) +
method ("description=", &db::CompoundRegionOperationNode::set_description, gsi::arg ("d"),
"@brief Sets the description for this node"
@ -343,7 +350,21 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
method ("result_type", &db::CompoundRegionOperationNode::result_type,
"@brief Gets the result type of this node"
),
"@brief A base class for compound operations\n"
"@brief A base class for compound DRC operations\n"
"\n"
"This class is not intended to be used directly but rather provide a factory for various incarnations of "
"compound operation nodes. Compound operations are a way to specify complex DRC operations put together "
"by building a tree of operations. This operation tree then is executed with \\Region#complex_op and will act on "
"individual clusters of shapes and their interacting neighbors.\n"
"\n"
"A basic concept to the compound operations is the 'subject' (primary) and 'intruder' (secondary) input. "
"The 'subject' is the Region, 'complex_op' with the operation tree is executed on. 'intruders' are regions inserted into "
"the equation through secondary input nodes created with \\new_secondary_node. The algorithm will execute the "
"operation tree for every subject shape considering intruder shapes from the secondary inputs. The algorithm will "
"only act on subject shapes primarily. As a consequence, 'lonely' intruder shapes without a subject shape are "
"not considered at all. Only subject shapes trigger evaluation of the operation tree.\n"
"\n"
"The search distance for introduder shapes is determined by the operation and computed from the operation's requirements.\n"
"\n"
"This class has been introduced in version 0.27."
);
@ -457,5 +478,26 @@ gsi::Enum<db::metrics_type> decl_dbMetricsType ("db", "MetricsType",
"This enum has been introduced in version 0.27."
);
gsi::EnumIn<db::RegionBBoxFilter, db::RegionBBoxFilter::parameter_type> decl_dbRegionBBoxFilter_ParameterType ("db", "ParameterType",
gsi::enum_const ("BoxWidth", db::RegionBBoxFilter::BoxWidth,
"@brief Measures the width of the bounding box\n"
) +
gsi::enum_const ("BoxHeight", db::RegionBBoxFilter::BoxHeight,
"@brief Measures the height of the bounding box\n"
) +
gsi::enum_const ("BoxMaxDim", db::RegionBBoxFilter::BoxMaxDim,
"@brief Measures the maximum dimension of the bounding box\n"
) +
gsi::enum_const ("BoxMinDim", db::RegionBBoxFilter::BoxMinDim,
"@brief Measures the minimum dimension of the bounding box\n"
) +
gsi::enum_const ("BoxAverageDim", db::RegionBBoxFilter::BoxAverageDim,
"@brief Measures the average of width and height of the bounding box\n"
),
"@brief This class represents the parameter type enum used in \\CompoundRegionOperationNode#new_bbox_filter\n"
"\n"
"This enum has been introduced in version 0.27."
);
}

View File

@ -32,6 +32,7 @@
#include "dbDeepShapeStore.h"
#include "dbRegion.h"
#include "dbRegionProcessors.h"
#include "dbCompoundOperation.h"
#include "tlGlobPattern.h"
#include <memory>
@ -630,6 +631,20 @@ static size_t id (const db::Region *r)
return tl::id_of (r->delegate ());
}
tl::Variant complex_op (db::Region *region, db::CompoundRegionOperationNode *node)
{
if (node->result_type () == db::CompoundRegionOperationNode::Region) {
return tl::Variant (region->cop_to_region (*node));
} else if (node->result_type () == db::CompoundRegionOperationNode::Edges) {
return tl::Variant (region->cop_to_edges (*node));
} else if (node->result_type () == db::CompoundRegionOperationNode::EdgePairs) {
return tl::Variant (region->cop_to_edge_pairs (*node));
} else {
return tl::Variant ();
}
}
// provided by gsiDeclDbPolygon.cc:
int td_simple ();
int po_any ();
@ -847,6 +862,11 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@brief Gets a flag indicating whether minimum coherence is selected\n"
"See \\min_coherence= for a description of this attribute.\n"
) +
method_ext ("complex_op", &complex_op, gsi::arg ("node"),
"@brief Executes a complex operation (see \\CompoundRegionOperationNode for details)\n"
"\n"
"This method has been introduced in version 0.27."
) +
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 "