WIP: debugging, test case for compound booleans

This commit is contained in:
Matthias Koefferlein 2020-12-26 00:06:49 +01:00
parent 80509c64e5
commit 9c6e0129d9
10 changed files with 201 additions and 106 deletions

View File

@ -170,14 +170,14 @@ std::vector<db::Region *> CompoundRegionOperationPrimaryNode::inputs () const
void CompoundRegionOperationPrimaryNode::do_compute_local (db::Layout *, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t, double) const
{
for (shape_interactions<db::Polygon, db::Polygon>::subject_iterator i = interactions.begin_subjects (); i != interactions.begin_subjects (); ++i) {
for (shape_interactions<db::Polygon, db::Polygon>::subject_iterator i = interactions.begin_subjects (); i != interactions.end_subjects (); ++i) {
results.front ().insert (i->second);
}
}
void CompoundRegionOperationPrimaryNode::do_compute_local (db::Layout *, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t, double) const
{
for (shape_interactions<db::PolygonRef, db::PolygonRef>::subject_iterator i = interactions.begin_subjects (); i != interactions.begin_subjects (); ++i) {
for (shape_interactions<db::PolygonRef, db::PolygonRef>::subject_iterator i = interactions.begin_subjects (); i != interactions.end_subjects (); ++i) {
results.front ().insert (i->second);
}
}
@ -320,11 +320,11 @@ CompoundRegionMultiInputOperationNode::init ()
{
std::map<db::Region *, unsigned int> input_index;
for (tl::shared_collection<CompoundRegionOperationNode>::iterator i = m_children.begin (); i != m_children.end (); ++i) {
unsigned int child_index = 0;
for (tl::shared_collection<CompoundRegionOperationNode>::iterator i = m_children.begin (); i != m_children.end (); ++i, ++child_index) {
std::vector<db::Region *> child_inputs = i->inputs ();
unsigned int child_index = 0;
for (std::vector<db::Region *>::const_iterator ii = child_inputs.begin (); ii != child_inputs.end (); ++ii, ++child_index) {
for (std::vector<db::Region *>::const_iterator ii = child_inputs.begin (); ii != child_inputs.end (); ++ii) {
std::map<db::Region *, unsigned int>::const_iterator im = input_index.find (*ii);
unsigned int li = (unsigned int) m_inputs.size ();
@ -335,7 +335,7 @@ CompoundRegionMultiInputOperationNode::init ()
input_index.insert (std::make_pair (*ii, li));
}
m_map_layer_to_child [std::make_pair (child_index, (unsigned int) (ii - child_inputs.begin ()))] = li;
m_map_layer_to_child [std::make_pair (child_index, li)] = (unsigned int) (ii - child_inputs.begin ());
}

View File

@ -726,17 +726,19 @@ public:
void add (const TS *ref1, unsigned int id1, const TI *ref2, unsigned int id2)
{
mp_result->add_subject_shape (id1, *ref1);
if (!mp_result->has_subject_shape_id (id1)) {
mp_result->add_subject_shape (id1, *ref1);
}
if (mp_layout) {
// In order to guarantee the refs come from the subject layout, we'd need to
// rewrite them
if (!mp_result->has_intruder_shape_id (id2)) {
if (!mp_result->has_intruder_shape_id (id2)) {
if (mp_layout) {
// In order to guarantee the refs come from the subject layout, we'd need to
// rewrite them
db::shape_reference_translator<TI> rt (mp_layout);
mp_result->add_intruder_shape (id2, m_intruder_layer, rt (*ref2));
} else {
mp_result->add_intruder_shape (id2, m_intruder_layer, *ref2);
}
} else {
mp_result->add_intruder_shape (id2, m_intruder_layer, *ref2);
}
mp_result->add_interaction (id1, id2);
@ -761,8 +763,12 @@ public:
void add (const TS *ref1, unsigned int id1, const TI *ref2, unsigned int id2)
{
mp_result->add_subject_shape (id1, *ref1);
mp_result->add_intruder_shape (id2, m_intruder_layer, *ref2);
if (!mp_result->has_subject_shape_id (id1)) {
mp_result->add_subject_shape (id1, *ref1);
}
if (!mp_result->has_intruder_shape_id (id2)) {
mp_result->add_intruder_shape (id2, m_intruder_layer, *ref2);
}
mp_result->add_interaction (id1, id2);
}
@ -784,8 +790,12 @@ public:
void add (const T *ref1, unsigned int id1, const T *ref2, unsigned int id2)
{
mp_result->add_subject_shape (id1, *ref1);
mp_result->add_intruder_shape (id2, m_intruder_layer, *ref2);
if (!mp_result->has_subject_shape_id (id1)) {
mp_result->add_subject_shape (id1, *ref1);
}
if (!mp_result->has_intruder_shape_id (id2)) {
mp_result->add_intruder_shape (id2, m_intruder_layer, *ref2);
}
mp_result->add_interaction (id1, id2);
}
@ -1900,7 +1910,7 @@ template <class TS, class TI>
struct scan_shape2shape_same_layer_flat
{
void
operator () (const generic_shape_iterator<TS> &, bool, unsigned int, shape_interactions<TS, TI> &, db::Coord) const
operator () (unsigned int, shape_interactions<TS, TI> &, db::Coord) const
{
// cannot have different types on the same layer
tl_assert (false);
@ -1911,106 +1921,30 @@ template <class T>
struct scan_shape2shape_same_layer_flat<T, T>
{
void
operator () (const generic_shape_iterator<T> &subjects, bool needs_isolated_subjects, unsigned int intruder_layer, shape_interactions<T, T> &interactions, db::Coord dist) const
operator () (unsigned int intruder_layer, shape_interactions<T, T> &interactions, db::Coord dist) const
{
db::box_scanner<T, int> scanner;
interaction_registration_shape1<T, T> rec (&interactions, intruder_layer);
addressable_shape_delivery<T> is (subjects);
for ( ; !is.at_end (); ++is) {
unsigned int id = interactions.next_id ();
const T *shape = is.operator-> ();
scanner.insert (shape, id);
// create subject for subject vs. nothing interactions
if (needs_isolated_subjects) {
interactions.add_subject (id, *shape);
}
for (typename shape_interactions<T, T>::subject_iterator s = interactions.begin_subjects (); s != interactions.end_subjects (); ++s) {
scanner.insert (&s->second, s->first);
}
scanner.process (rec, dist, db::box_convert<T> ());
}
};
template <class TS, class TI>
struct add_subjects_vs_nothing_flat
{
void
operator () (const generic_shape_iterator<TS> &subjects, shape_interactions<TS, TI> &interactions) const
{
addressable_shape_delivery<TS> is (subjects);
for ( ; !is.at_end (); ++is) {
unsigned int id = interactions.next_id ();
const TS *shape = is.operator-> ();
interactions.add_subject (id, *shape);
}
}
};
template <class TS, class TI>
struct scan_shape2shape_different_layers_flat
{
void
operator () (const generic_shape_iterator<TS> &subjects, const generic_shape_iterator<TI> &intruders, bool needs_isolated_subjects, unsigned int intruder_layer, shape_interactions<TS, TI> &interactions, db::Coord dist) const
operator () (const generic_shape_iterator<TI> &intruders, const db::Box &common_box, unsigned int intruder_layer, shape_interactions<TS, TI> &interactions, db::Coord dist) const
{
db::box_scanner2<TS, int, TI, int> scanner;
interaction_registration_shape2shape<TS, TI> rec (0 /*layout*/, &interactions, intruder_layer);
db::Box subjects_box = subjects.bbox ();
if (subjects_box != db::Box::world ()) {
subjects_box.enlarge (db::Vector (dist, dist));
}
db::Box intruders_box = intruders.bbox ();
if (intruders_box != db::Box::world ()) {
intruders_box.enlarge (db::Vector (dist, dist));
}
db::Box common_box = intruders_box & subjects_box;
if (common_box.empty ()) {
if (needs_isolated_subjects) {
for (generic_shape_iterator<TS> is = subjects; ! is.at_end (); ++is) {
// create subject for subject vs. nothing interactions
interactions.add_subject (interactions.next_id (), *is);
}
}
return;
}
addressable_shape_delivery<TS> is;
if (needs_isolated_subjects) {
box_convert<TS> bcs;
is = addressable_shape_delivery<TS> (subjects);
for ( ; !is.at_end (); ++is) {
unsigned int id = interactions.next_id ();
const TS *shape = is.operator-> ();
if (bcs (*shape).overlaps (common_box)) {
scanner.insert1 (shape, id);
}
// create subject for subject vs. nothing interactions
interactions.add_subject (id, *shape);
}
} else {
is = addressable_shape_delivery<TS> (subjects.confined (common_box, true));
for ( ; !is.at_end (); ++is) {
scanner.insert1 (is.operator-> (), interactions.next_id ());
}
for (typename shape_interactions<TS, TI>::subject_iterator s = interactions.begin_subjects (); s != interactions.end_subjects (); ++s) {
scanner.insert1 (&s->second, s->first);
}
addressable_shape_delivery<TI> ii (intruders.confined (common_box, true));
@ -2039,16 +1973,55 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
shape_interactions<TS, TI> interactions;
bool needs_isolated_subjects = (op->on_empty_intruder_hint () != OnEmptyIntruderHint::Drop);
if (intruders.empty () && needs_isolated_subjects) {
add_subjects_vs_nothing_flat<TS, TI> () (subjects, interactions);
// build the subjects in the intruders list
db::Coord dist = op->dist ();
db::Box subjects_box = subjects.bbox ();
if (subjects_box != db::Box::world ()) {
subjects_box.enlarge (db::Vector (dist, dist));
}
db::Box intruders_box;
for (typename std::vector<generic_shape_iterator<TI> >::const_iterator il = intruders.begin (); il != intruders.end (); ++il) {
if (*il == subjects) {
scan_shape2shape_same_layer_flat<TS, TI> () (subjects, needs_isolated_subjects, (unsigned int) (il - intruders.begin ()), interactions, op->dist ());
} else {
scan_shape2shape_different_layers_flat<TS, TI> () (subjects, *il, needs_isolated_subjects, (unsigned int) (il - intruders.begin ()), interactions, op->dist ());
intruders_box += il->bbox ();
}
if (intruders_box != db::Box::world ()) {
intruders_box.enlarge (db::Vector (dist, dist));
}
db::Box common_box = intruders_box & subjects_box;
if (common_box.empty ()) {
if (needs_isolated_subjects) {
for (generic_shape_iterator<TS> is = subjects; ! is.at_end (); ++is) {
// create subject for subject vs. nothing interactions
interactions.add_subject (interactions.next_id (), *is);
}
}
} else {
box_convert<TS> bcs;
addressable_shape_delivery<TS> is (subjects);
for ( ; !is.at_end (); ++is) {
const TS *shape = is.operator-> ();
if (needs_isolated_subjects || bcs (*shape).overlaps (common_box)) {
unsigned int id = interactions.next_id ();
interactions.add_subject (id, *shape);
}
}
for (typename std::vector<generic_shape_iterator<TI> >::const_iterator il = intruders.begin (); il != intruders.end (); ++il) {
if (*il == subjects) {
scan_shape2shape_same_layer_flat<TS, TI> () ((unsigned int) (il - intruders.begin ()), interactions, op->dist ());
} else {
scan_shape2shape_different_layers_flat<TS, TI> () (*il, common_box, (unsigned int) (il - intruders.begin ()), interactions, op->dist ());
}
}
}
if (interactions.begin () != interactions.end ()) {

View File

@ -138,6 +138,16 @@ bool RelativeExtentsAsEdges::result_must_not_be_merged () const
return (fabs (m_fx1 - m_fx2) < db::epsilon && fabs (m_fy1 - m_fy2) < db::epsilon);
}
// -----------------------------------------------------------------------------------
// PolygonToEdgeProcessor implementation
void PolygonToEdgeProcessor::process (const db::Polygon &poly, std::vector<db::Edge> &result) const
{
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
result.push_back (*e);
}
}
// -----------------------------------------------------------------------------------
// ConvexDecomposition implementation

View File

@ -218,6 +218,21 @@ private:
db::MagnificationAndOrientationReducer m_anisotropic_reducer;
};
/**
* @brief A processor that delivers all edges for a polygon
*/
class DB_PUBLIC PolygonToEdgeProcessor
: public db::PolygonToEdgeProcessorBase
{
public:
PolygonToEdgeProcessor ()
{
// .. nothing yet ..
}
void process (const db::Polygon &poly, std::vector<db::Edge> &result) const;
};
/**
* @brief A decomposition processor to deliver convex-only polygons
*/

View File

@ -25,6 +25,7 @@
#include "dbCompoundOperation.h"
#include "dbRegionUtils.h"
#include "dbEdgesUtils.h"
#include "dbRegionLocalOperations.h"
namespace gsi
@ -187,6 +188,41 @@ static db::CompoundRegionOperationNode *new_minkowsky_sum_node4 (db::CompoundReg
return new db::CompoundRegionProcessingOperationNode (new db::minkowsky_sum_computation<std::vector<db::Point> > (p), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edges_node (db::CompoundRegionOperationNode *input)
{
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_length_filter_node (db::CompoundRegionOperationNode *input, db::Edge::distance_type lmin, db::Edge::distance_type lmax, bool inverse)
{
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeLengthFilter (lmin, lmax, inverse), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_orientation_filter_node (db::CompoundRegionOperationNode *input, double amin, double amax, bool inverse)
{
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, amax, inverse), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_pair_to_polygon_node (db::CompoundRegionOperationNode *input, db::Coord e)
{
return new db::CompoundRegionEdgePairToPolygonProcessingOperationNode (new db::EdgePairToPolygonProcessor (e), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_pair_to_edges_node (db::CompoundRegionOperationNode *input)
{
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToEdgesProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_pair_to_first_edges_node (db::CompoundRegionOperationNode *input)
{
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToFirstEdgesProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges_node (db::CompoundRegionOperationNode *input)
{
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToSecondEdgesProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_check_node (db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, const tl::Variant &metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter)
{
return new db::CompoundRegionCheckOperationNode (rel, different_polygons, d,
@ -386,6 +422,27 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
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_edges", &new_edges_node, gsi::arg ("input"),
"@brief Creates a node converting polygons into it's edges.\n"
) +
gsi::constructor ("new_edge_length_filter", &new_edge_length_filter_node, gsi::arg ("input"), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits<db::Edge::distance_type>::max (), "max"), gsi::arg ("inverse", false),
"@brief Creates a node filtering edges by their length.\n"
) +
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter_node, gsi::arg ("input"), gsi::arg ("amin"), gsi::arg ("amax"), gsi::arg ("inverse", false),
"@brief Creates a node filtering edges by their orientation.\n"
) +
gsi::constructor ("new_edge_pair_to_polygon", &new_edge_pair_to_polygon_node, gsi::arg ("input"), gsi::arg ("e", 0),
"@brief Creates a node converting edge pairs to polygons.\n"
) +
gsi::constructor ("new_edge_pair_to_edges", &new_edge_pair_to_edges_node, gsi::arg ("input"),
"@brief Creates a node converting edge pairs to two edges each.\n"
) +
gsi::constructor ("new_edge_pair_to_first_edges", &new_edge_pair_to_first_edges_node, gsi::arg ("input"),
"@brief Creates a node delivering the first edge of each edges pair.\n"
) +
gsi::constructor ("new_edge_pair_to_second_edges", &new_edge_pair_to_second_edges_node, gsi::arg ("input"),
"@brief Creates a node delivering the second edge of each edges pair.\n"
) +
method ("description=", &db::CompoundRegionOperationNode::set_description, gsi::arg ("d"),
"@brief Sets the description for this node"
) +

View File

@ -126,3 +126,43 @@ TEST(2_ChainedOperations)
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/drc/compound_au2.gds");
}
TEST(3_BooleanOperations)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/drc/compound_3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::RegionCheckOptions check_options;
check_options.metrics = db::Projection;
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
db::Region r (db::RecursiveShapeIterator (ly, ly.cell (*ly.begin_top_down ()), l1));
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
db::Region r2 (db::RecursiveShapeIterator (ly, ly.cell (*ly.begin_top_down ()), l2));
db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode ();
db::CompoundRegionOperationSecondaryNode *secondary = new db::CompoundRegionOperationSecondaryNode (&r2);
db::CompoundRegionGeometricalBoolOperationNode geo_bool (db::CompoundRegionGeometricalBoolOperationNode::And, primary, secondary);
db::Region res = r.cop_to_region (geo_bool);
unsigned int l1000 = ly.get_layer (db::LayerProperties (1000, 0));
res.insert_into (&ly, *ly.begin_top_down (), l1000);
db::CompoundRegionGeometricalBoolOperationNode geo_bool2 (db::CompoundRegionGeometricalBoolOperationNode::Not, primary, secondary);
res = r.cop_to_region (geo_bool2);
unsigned int l1001 = ly.get_layer (db::LayerProperties (1001, 0));
res.insert_into (&ly, *ly.begin_top_down (), l1001);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/drc/compound_au3.gds");
}

BIN
testdata/drc/compound_2.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/compound_3.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/compound_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/compound_au3.gds vendored Normal file

Binary file not shown.