WIP: attempt to implement negative edge output on width and space

This commit is contained in:
Matthias Koefferlein 2021-01-02 19:34:46 +01:00
parent 8f8d754180
commit 98792c55de
7 changed files with 527 additions and 151 deletions

View File

@ -566,41 +566,16 @@ run_poly_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp op, db:
// TODO: it's more efficient to feed the EP directly for polygon-to-polygon bools
db::Region ra, rb;
init_region (ra, a);
init_region (rb, b);
if (ra.empty ()) {
if (op == CompoundRegionGeometricalBoolOperationNode::And || op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ra);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Or || op == CompoundRegionGeometricalBoolOperationNode::Xor) {
init_region (rb, b);
write_result (layout, res, rb);
}
} else {
init_region (rb, b);
if (rb.empty ()) {
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, rb);
} else {
write_result (layout, res, ra);
}
} else {
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, ra & rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Or) {
write_result (layout, res, ra + rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) {
write_result (layout, res, ra ^ rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ra - rb);
}
}
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, ra & rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Or) {
write_result (layout, res, ra + rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) {
write_result (layout, res, ra ^ rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ra - rb);
}
}
@ -629,21 +604,12 @@ run_poly_vs_edge_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp
init_region (ra, a);
db::Edges eb;
init_edges (eb, b);
if (ra.empty ()) {
if (eb.empty ()) {
write_result (layout, res, eb);
} else {
init_edges (eb, b);
if (eb.empty ()) {
write_result (layout, res, eb);
} else {
write_result (layout, res, eb & ra);
}
write_result (layout, res, eb & ra);
}
}
@ -670,22 +636,14 @@ run_edge_vs_poly_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp
db::Edges ea;
init_edges (ea, a);
if (ea.empty ()) {
write_result (layout, res, ea);
} else {
// TODO: it's more efficient to feed the EP directly for polygon-to-polygon bools
db::Region rb;
init_region (rb, b);
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, ea & rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ea - rb);
}
// TODO: it's more efficient to feed the EP directly for polygon-to-polygon bools
db::Region rb;
init_region (rb, b);
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, ea & rb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ea - rb);
}
}
@ -706,45 +664,30 @@ run_bool (CompoundRegionGeometricalBoolOperationNode::GeometricalOp op, db::Layo
{
db::Edges ea, eb;
init_edges (ea, a);
init_edges (eb, b);
if (ea.empty ()) {
if (op == CompoundRegionGeometricalBoolOperationNode::And || op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ea);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Or || op == CompoundRegionGeometricalBoolOperationNode::Xor) {
init_edges (eb, b);
write_result (layout, res, eb);
}
} else {
init_edges (eb, b);
if (eb.empty ()) {
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, eb);
} else {
write_result (layout, res, ea);
}
} else {
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, ea & eb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Or) {
write_result (layout, res, ea + eb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) {
write_result (layout, res, ea ^ eb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ea - eb);
}
}
if (op == CompoundRegionGeometricalBoolOperationNode::And) {
write_result (layout, res, ea & eb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Or) {
write_result (layout, res, ea + eb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Xor) {
write_result (layout, res, ea ^ eb);
} else if (op == CompoundRegionGeometricalBoolOperationNode::Not) {
write_result (layout, res, ea - eb);
}
}
template <class T>
static void copy_results (std::vector<std::unordered_set<T> > &res, const std::vector<std::unordered_set<T> > &in)
{
res.front ().insert (in.front ().begin (), in.front ().end ());
}
template <class T, class R>
static void copy_results (std::vector<std::unordered_set<R> > &, const std::vector<std::unordered_set<T> > &)
{
// don't copy
}
template <class T, class T1, class T2, class TR>
void
@ -756,13 +699,45 @@ CompoundRegionGeometricalBoolOperationNode::implement_bool (db::Layout *layout,
shape_interactions<T, T> computed_a;
child (0)->compute_local (layout, interactions_for_child (interactions, 0, computed_a), one_a, max_vertex_count, area_ratio);
std::vector<std::unordered_set<T2> > one_b;
one_b.push_back (std::unordered_set<T2> ());
if (one_a.front ().empty ()) {
shape_interactions<T, T> computed_b;
child (1)->compute_local (layout, interactions_for_child (interactions, 1, computed_b), one_b, max_vertex_count, area_ratio);
if (m_op == GeometricalOp::And || m_op == GeometricalOp::Not) {
run_bool (m_op, layout, one_a.front (), one_b.front (), results.front ());
// .. no results ..
} else {
std::vector<std::unordered_set<T2> > one_b;
one_b.push_back (std::unordered_set<T2> ());
shape_interactions<T, T> computed_b;
child (1)->compute_local (layout, interactions_for_child (interactions, 1, computed_b), one_b, max_vertex_count, area_ratio);
copy_results (results, one_b);
}
} else {
std::vector<std::unordered_set<T2> > one_b;
one_b.push_back (std::unordered_set<T2> ());
shape_interactions<T, T> computed_b;
child (1)->compute_local (layout, interactions_for_child (interactions, 1, computed_b), one_b, max_vertex_count, area_ratio);
if (one_b.front ().empty ()) {
if (m_op != GeometricalOp::And) {
copy_results (results, one_a);
}
} else {
run_bool (m_op, layout, one_a.front (), one_b.front (), results.front ());
}
}
}
template <class T, class TR>

View File

@ -245,6 +245,26 @@ struct compound_operation_type_traits<db::EdgePair>
};
class DB_PUBLIC CompoundRegionOperationEmptyNode
: public CompoundRegionOperationNode
{
public:
CompoundRegionOperationEmptyNode (ResultType type)
: CompoundRegionOperationNode (), m_type (type)
{ }
virtual ~CompoundRegionOperationEmptyNode ()
{ }
virtual std::vector<db::Region *> inputs () const { return std::vector<db::Region *> (); }
virtual db::Coord dist () const { return 0; }
virtual ResultType result_type () const { return m_type; }
private:
ResultType m_type;
};
class DB_PUBLIC CompoundRegionOperationPrimaryNode
: public CompoundRegionOperationNode
{

View File

@ -34,7 +34,7 @@ namespace db
Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding)
: mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons),
m_with_shielding (with_shielding), m_has_edge_pair_output (true), m_has_negative_edge_output (false), m_pass (0)
m_first_pseudo (std::numeric_limits<size_t>::max ()), m_with_shielding (with_shielding), m_has_edge_pair_output (true), m_has_negative_edge_output (false), m_pass (0)
{
m_distance = check.distance ();
}
@ -46,13 +46,20 @@ Edge2EdgeCheckBase::prepare_next_pass ()
if (m_pass == 1) {
if ((m_with_shielding || m_has_negative_edge_output) && ! m_ep.empty ()) {
m_first_pseudo = m_ep.size ();
if (m_with_shielding && ! m_ep.empty ()) {
m_ep_discarded.resize (m_ep.size (), false);
// second pass:
return true;
} else if (m_has_negative_edge_output) {
// second pass:
return true;
}
}
@ -61,7 +68,7 @@ Edge2EdgeCheckBase::prepare_next_pass ()
std::vector<bool>::const_iterator d = m_ep_discarded.begin ();
std::vector<db::EdgePair>::const_iterator ep = m_ep.begin ();
while (ep != m_ep.end ()) {
while (ep != m_ep.end () && size_t (ep - m_ep.begin ()) < m_first_pseudo) {
bool use_result = true;
if (d != m_ep_discarded.end ()) {
use_result = ! *d;
@ -96,12 +103,58 @@ static inline bool shields (const db::EdgePair &ep, const db::Edge &q)
void
Edge2EdgeCheckBase::finish (const Edge *o, const size_t &p)
{
if (m_has_negative_edge_output && m_pass == 1) {
if (m_has_negative_edge_output && m_pass == 1 && m_pseudo_edges.find (std::make_pair (*o, p)) == m_pseudo_edges.end ()) {
// no interaction at all: create a single-edged edge pair
int l = int (p & size_t (1));
put_negative (*o, l);
std::pair<db::Edge, size_t> k (*o, p);
std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i0 = m_e2ep.find (k);
bool fully_removed = false;
bool any = false;
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; ! fully_removed && i != m_e2ep.end () && i->first == k; ++i) {
size_t n = i->second / 2;
if (n >= m_ep_discarded.size () || !m_ep_discarded [n]) {
any = true;
fully_removed = (((i->second & 1) == 0 ? m_ep [n].first () : m_ep [n].second ()) == *o);
}
}
if (! any) {
put_negative (*o, p);
} else if (! fully_removed) {
std::set<db::Edge> partial_edges;
db::EdgeBooleanCluster<std::set<db::Edge> > ec (&partial_edges, db::EdgeNot);
ec.add (o, 0);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; i != m_e2ep.end () && i->first == k; ++i) {
size_t n = i->second / 2;
if (n >= m_ep_discarded.size () || !m_ep_discarded [n]) {
ec.add (((i->second & 1) == 0 ? &m_ep [n].first () : &m_ep [n].second ()), 1);
}
}
ec.finish ();
for (std::set<db::Edge>::const_iterator e = partial_edges.begin (); e != partial_edges.end (); ++e) {
put_negative (*e, p);
}
}
}
}
void
Edge2EdgeCheckBase::feed_pseudo_edges (db::box_scanner<db::Edge, size_t> &scanner)
{
if (m_pass == 1) {
for (std::set<std::pair<db::Edge, size_t> >::const_iterator e = m_pseudo_edges.begin (); e != m_pseudo_edges.end (); ++e) {
// @@@printf("@@@ PSEUDO %s[%d]\n", e->first.to_string().c_str(), int(e->second)); fflush(stdout);
scanner.insert (&e->first, e->second);
}
}
}
@ -118,16 +171,26 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
int l1 = int (p1 & size_t (1));
int l2 = int (p2 & size_t (1));
if (l1 > l2) {
std::swap (o1, o2);
std::swap (p1, p2);
}
db::EdgePair ep;
if (mp_check->check (l1 <= l2 ? *o1 : *o2, l1 <= l2 ? *o2 : *o1, &ep)) {
if (mp_check->check (*o1, *o2, &ep)) {
// found a violation: store inside the local buffer for now. In the second
// pass we will eliminate those which are shielded completely (with shielding)
// and/or compute the negative edges.
size_t n = m_ep.size ();
m_ep.push_back (ep);
m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n));
m_e2ep.insert (std::make_pair (std::make_pair (*o2, p2), n));
m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n * 2));
m_e2ep.insert (std::make_pair (std::make_pair (*o2, p2), n * 2 + 1));
if (m_has_negative_edge_output) {
m_pseudo_edges.insert (std::make_pair (db::Edge (ep.first ().p1 (), ep.second ().p2 ()), p1));
m_pseudo_edges.insert (std::make_pair (db::Edge (ep.second ().p1 (), ep.first ().p2 ()), p2));
}
}
@ -152,7 +215,10 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
std::pair<db::Edge, size_t> k (*o1, p1);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = m_e2ep.find (k); i != m_e2ep.end () && i->first == k; ++i) {
n1.push_back (i->second);
size_t n = i->second / 2;
if (n < m_first_pseudo && ! m_ep_discarded [n]) {
n1.push_back (n);
}
}
std::sort (n1.begin (), n1.end ());
@ -169,11 +235,9 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
std::set_difference (n1.begin (), n1.end (), n2.begin (), n2.end (), std::back_inserter (nn));
for (std::vector<size_t>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
if (! m_ep_discarded [*i]) {
db::EdgePair ep = m_ep [*i].normalized ();
if (shields (ep, *o2)) {
m_ep_discarded [*i] = true;
}
db::EdgePair ep = m_ep [*i].normalized ();
if (shields (ep, *o2)) {
m_ep_discarded [*i] = true;
}
}
@ -185,45 +249,34 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
}
// prepare the negative edge output
if (m_has_negative_edge_output) {
// for negative output edges are cancelled by short interactions perpendicular to them
if (m_has_negative_edge_output &&
(m_pseudo_edges.find (std::make_pair (*o1, p1)) != m_pseudo_edges.end () || m_pseudo_edges.find (std::make_pair (*o2, p2)) != m_pseudo_edges.end ()) &&
! (m_pseudo_edges.find (std::make_pair (*o1, p1)) != m_pseudo_edges.end () && m_pseudo_edges.find (std::make_pair (*o2, p2)) != m_pseudo_edges.end ())) {
//printf("@@@ PASS %d -> %s[%d] x %s[%d]\n", m_pass, o1->to_string().c_str(), int(p1), o2->to_string().c_str(), int(p2)); fflush(stdout);
// Overlap or inside checks require input from different layers
if ((! m_different_polygons || p1 != p2) && (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0)) {
for (int p = 0; p < 2; ++p) {
// ensure that the first check argument is of layer 1 and the second of
// layer 2 (unless both are of the same layer)
int l1 = int (p1 & size_t (1));
int l2 = int (p2 & size_t (1));
std::pair<db::Edge, size_t> k (*o1, p1);
std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i0 = m_e2ep.find (k);
if (l1 > l2) {
std::swap (o1, o2);
std::swap (p1, p2);
}
//printf("@@@1\n"); fflush(stdout);
bool fully_removed = false;
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; ! fully_removed && i != m_e2ep.end () && i->first == k; ++i) {
fully_removed = (m_ep [i->second].first () == *o1);
}
db::EdgePair ep;
if (mp_check->check (*o1, *o2, &ep)) {
if (! fully_removed) {
std::set<db::Edge> partial_edges;
db::EdgeBooleanCluster<std::set<db::Edge> > ec (&partial_edges, db::EdgeNot);
ec.add (o1, 0);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; i != m_e2ep.end () && i->first == k; ++i) {
if (i->second >= m_ep_discarded.size () || !m_ep_discarded [i->second]) {
ec.add (&m_ep [i->second].first (), 1);
}
}
ec.finish ();
for (std::set<db::Edge>::const_iterator e = partial_edges.begin (); e != partial_edges.end (); ++e) {
put_negative (*e, p);
}
std::swap (o1, o2);
std::swap (p1, p2);
}
size_t n = m_ep.size ();
m_ep.push_back (ep);
m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n * 2));
m_e2ep.insert (std::make_pair (std::make_pair (*o2, p2), n * 2 + 1));
//printf("@@@ CANCEL %s\n", ep.to_string().c_str()); fflush(stdout);
}
@ -326,6 +379,8 @@ poly2poly_check_base<PolygonType>::enter (const PolygonType &o, size_t p)
m_scanner.insert (& m_edges.back (), p);
}
mp_output->feed_pseudo_edges (m_scanner);
tl_assert (m_edges.size () == vertices (o));
m_scanner.process (*mp_output, mp_output->distance (), db::box_convert<db::Edge> ());
@ -362,6 +417,8 @@ poly2poly_check_base<PolygonType>::enter (const PolygonType &o1, size_t p1, cons
m_scanner.insert (& m_edges.back (), p2);
}
mp_output->feed_pseudo_edges (m_scanner);
tl_assert (m_edges.size () == vertices (o1) + vertices (o2));
// temporarily disable intra-polygon check in that step .. we do that later in finish()

View File

@ -482,6 +482,12 @@ public:
*/
bool prepare_next_pass ();
/**
* @brief Before the scanner is run, this method must be called to feed additional edges into the scanner
* (required for negative edge output - cancellation of perpendicular edges)
*/
void feed_pseudo_edges (db::box_scanner<db::Edge, size_t> &scanner);
/**
* @brief Reimplementation of the box_scanner_receiver interface
*/
@ -551,6 +557,8 @@ private:
EdgeRelationFilter::distance_type m_distance;
std::vector<db::EdgePair> m_ep;
std::multimap<std::pair<db::Edge, size_t>, size_t> m_e2ep;
std::set<std::pair<db::Edge, size_t> > m_pseudo_edges;
size_t m_first_pseudo;
std::vector<bool> m_ep_discarded;
bool m_with_shielding;
bool m_has_edge_pair_output;

View File

@ -28,10 +28,29 @@
#include "dbEdgesUtils.h"
#include "dbRegionLocalOperations.h"
#include "dbShapeCollectionUtils.h"
#include "tlString.h"
namespace gsi
{
template <class P>
static void check_non_null (P *p, const char *arg)
{
if (!p) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Argument %s must not be null")), arg));
}
}
template <class P>
static void check_non_null (const std::vector<P *> &pp, const char *arg)
{
for (typename std::vector<P *>::const_iterator p = pp.begin (); p != pp.end (); ++p) {
if (!*p) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Arguments %s must not be null")), arg));
}
}
}
static db::CompoundRegionOperationNode *new_primary ()
{
return new db::CompoundRegionOperationPrimaryNode ();
@ -39,16 +58,25 @@ static db::CompoundRegionOperationNode *new_primary ()
static db::CompoundRegionOperationNode *new_secondary (db::Region *region)
{
check_non_null (region, "region");
return new db::CompoundRegionOperationSecondaryNode (region);
}
static db::CompoundRegionOperationNode *new_empty (db::CompoundRegionOperationNode::ResultType type)
{
return new db::CompoundRegionOperationEmptyNode (type);
}
static db::CompoundRegionOperationNode *new_logical_boolean (db::CompoundRegionLogicalBoolOperationNode::LogicalOp op, bool invert, const std::vector<db::CompoundRegionOperationNode *> &inputs)
{
check_non_null (inputs, "inputs");
return new db::CompoundRegionLogicalBoolOperationNode (op, invert, inputs);
}
static db::CompoundRegionOperationNode *new_geometrical_boolean (db::CompoundRegionGeometricalBoolOperationNode::GeometricalOp op, db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b)
{
check_non_null (a, "a");
check_non_null (b, "b");
// 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)) {
@ -59,6 +87,8 @@ 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)
{
check_non_null (a, "a");
check_non_null (b, "b");
// 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");
@ -74,6 +104,8 @@ 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)
{
check_non_null (a, "a");
check_non_null (b, "b");
// 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");
@ -87,6 +119,8 @@ static db::CompoundRegionOperationNode *new_overlapping (db::CompoundRegionOpera
static db::CompoundRegionOperationNode *new_enclosing (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count)
{
check_non_null (a, "a");
check_non_null (b, "b");
// 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");
@ -100,6 +134,8 @@ static db::CompoundRegionOperationNode *new_enclosing (db::CompoundRegionOperati
static db::CompoundRegionOperationNode *new_inside (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse)
{
check_non_null (a, "a");
check_non_null (b, "b");
// 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");
@ -113,6 +149,8 @@ static db::CompoundRegionOperationNode *new_inside (db::CompoundRegionOperationN
static db::CompoundRegionOperationNode *new_outside (db::CompoundRegionOperationNode *a, db::CompoundRegionOperationNode *b, bool inverse)
{
check_non_null (a, "a");
check_non_null (b, "b");
// 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");
@ -126,46 +164,55 @@ static db::CompoundRegionOperationNode *new_outside (db::CompoundRegionOperation
static db::CompoundRegionOperationNode *new_hulls (db::CompoundRegionOperationNode *input)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::HullExtractionProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_holes (db::CompoundRegionOperationNode *input)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::HolesExtractionProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_strange_polygons_filter (db::CompoundRegionOperationNode *input)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::StrangePolygonCheckProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_rounded_corners (db::CompoundRegionOperationNode *input, double rinner, double router, unsigned int n)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::RoundedCornersProcessor (rinner, router, n), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_case (const std::vector<db::CompoundRegionOperationNode *> &inputs)
{
check_non_null (inputs, "inputs");
return new db::CompoundRegionLogicalCaseSelectOperationNode (inputs);
}
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, double angle_end, db::Coord dim = 1)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, angle_end, dim), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, double angle_end)
{
check_non_null (input, "input");
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::CornersAsDots (angle_start, angle_end), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_extents (db::CompoundRegionOperationNode *input, db::Coord e)
{
check_non_null (input, "input");
if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) {
return new db::CompoundRegionEdgePairToPolygonProcessingOperationNode (new db::extents_processor<db::EdgePair> (e, e), input, true /*processor is owned*/);
} else if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) {
@ -180,56 +227,67 @@ static db::CompoundRegionOperationNode *new_extents (db::CompoundRegionOperation
static db::CompoundRegionOperationNode *new_relative_extents (db::CompoundRegionOperationNode *input, double fx1, double fy1, double fx2, double fy2, db::Coord dx, db::Coord dy)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::RelativeExtents (fx1, fy1, fx2, fy2, dx, dy), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_relative_extents_as_edges (db::CompoundRegionOperationNode *input, double fx1, double fy1, double fx2, double fy2)
{
check_non_null (input, "input");
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_convex_decomposition (db::CompoundRegionOperationNode *input, db::PreferredOrientation mode)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::ConvexDecomposition (mode), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_trapezoid_decomposition (db::CompoundRegionOperationNode *input, db::TrapezoidDecompositionMode mode)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::TrapezoidDecomposition (mode), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_polygon_breaker (db::CompoundRegionOperationNode *input, size_t max_vertex_count, double max_area_ratio)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::PolygonBreaker (max_vertex_count, max_area_ratio), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_sized (db::CompoundRegionOperationNode *input, db::Coord dx, db::Coord dy, unsigned int mode)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::PolygonSizer (dx, dy, mode), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_minkowsky_sum_node1 (db::CompoundRegionOperationNode *input, const db::Edge &e)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::minkowsky_sum_computation<db::Edge> (e), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_minkowsky_sum_node2 (db::CompoundRegionOperationNode *input, const db::Polygon &p)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::minkowsky_sum_computation<db::Polygon> (p), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_minkowsky_sum_node3 (db::CompoundRegionOperationNode *input, const db::Box &p)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::minkowsky_sum_computation<db::Box> (p), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_minkowsky_sum_node4 (db::CompoundRegionOperationNode *input, const std::vector<db::Point> &p)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::minkowsky_sum_computation<std::vector<db::Point> > (p), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input)
{
check_non_null (input, "input");
if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) {
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToEdgesProcessor (), input, true /*processor is owned*/);
} else if (input->result_type () == db::CompoundRegionOperationNode::Region) {
@ -242,16 +300,19 @@ static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNo
static db::CompoundRegionOperationNode *new_edge_length_filter (db::CompoundRegionOperationNode *input, bool inverse, db::Edge::distance_type lmin, db::Edge::distance_type lmax)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeLengthFilter (lmin, lmax, inverse), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, double amax)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, amax, inverse), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_polygons (db::CompoundRegionOperationNode *input, db::Coord e)
{
check_non_null (input, "input");
if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) {
return new db::CompoundRegionEdgePairToPolygonProcessingOperationNode (new db::EdgePairToPolygonProcessor (e), input, true /*processor is owned*/);
} else if (input->result_type () == db::CompoundRegionOperationNode::Edges) {
@ -264,26 +325,31 @@ static db::CompoundRegionOperationNode *new_polygons (db::CompoundRegionOperatio
static db::CompoundRegionOperationNode *new_extended (db::CompoundRegionOperationNode *input, db::Coord ext_b, db::Coord ext_e, db::Coord ext_o, db::Coord ext_i)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::ExtendedEdgeProcessor (ext_b, ext_e, ext_o, ext_i), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_extended_in (db::CompoundRegionOperationNode *input, db::Coord e)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::ExtendedEdgeProcessor (0, 0, 0, e), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_extended_out (db::CompoundRegionOperationNode *input, db::Coord e)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgeToPolygonProcessingOperationNode (new db::ExtendedEdgeProcessor (0, 0, e, 0), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_pair_to_first_edges (db::CompoundRegionOperationNode *input)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToFirstEdgesProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges (db::CompoundRegionOperationNode *input)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToSecondEdgesProcessor (), input, true /*processor is owned*/);
}
@ -303,6 +369,7 @@ static db::CompoundRegionOperationNode *new_check_node (db::edge_relation_type r
static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperationNode *input, db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type 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)
{
check_non_null (input, "input");
return new db::CompoundRegionCheckOperationNode (input, rel, different_polygons, d,
db::RegionCheckOptions (whole_edges,
metrics,
@ -364,41 +431,49 @@ static db::CompoundRegionOperationNode *new_inside_check (db::CompoundRegionOper
static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits<db::Coord>::perimeter_type pmin, db::coord_traits<db::Coord>::perimeter_type pmax)
{
check_non_null (input, "input");
return new db::CompoundRegionFilterOperationNode (new db::RegionPerimeterFilter (pmin, pmax, inverse), input, true);
}
static db::CompoundRegionOperationNode *new_area_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits<db::Coord>::area_type amin, db::coord_traits<db::Coord>::area_type amax)
{
check_non_null (input, "input");
return new db::CompoundRegionFilterOperationNode (new db::RegionAreaFilter (amin, amax, inverse), input, true);
}
static db::CompoundRegionOperationNode *new_rectilinear_filter (db::CompoundRegionOperationNode *input, bool inverse)
{
check_non_null (input, "input");
return new db::CompoundRegionFilterOperationNode (new db::RectilinearFilter (inverse), input, true);
}
static db::CompoundRegionOperationNode *new_rectangle_filter (db::CompoundRegionOperationNode *input, bool inverse)
{
check_non_null (input, "input");
return new db::CompoundRegionFilterOperationNode (new db::RectangleFilter (inverse), input, true);
}
static db::CompoundRegionOperationNode *new_bbox_filter (db::CompoundRegionOperationNode *input, db::RegionBBoxFilter::parameter_type parameter, bool inverse, db::coord_traits<db::Coord>::distance_type vmin, db::coord_traits<db::Coord>::distance_type vmax)
{
check_non_null (input, "input");
return new db::CompoundRegionFilterOperationNode (new db::RegionBBoxFilter (vmin, vmax, 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");
return new db::CompoundRegionEdgeProcessingOperationNode (new db::EdgeSegmentSelector (-1, length, fraction), input, true);
}
static db::CompoundRegionOperationNode *new_end_segments (db::CompoundRegionOperationNode *input, db::Edges::length_type length, double fraction)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgeProcessingOperationNode (new db::EdgeSegmentSelector (1, length, fraction), input, true);
}
static db::CompoundRegionOperationNode *new_centers (db::CompoundRegionOperationNode *input, db::Edges::length_type length, double fraction)
{
check_non_null (input, "input");
return new db::CompoundRegionEdgeProcessingOperationNode (new db::EdgeSegmentSelector (0, length, fraction), input, true);
}
@ -582,6 +657,9 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
gsi::constructor ("new_extended_out", &new_extended_out, gsi::arg ("input"), gsi::arg ("e"),
"@brief Creates a node delivering a polygonized, inside-extended version of the edges.\n"
) +
gsi::constructor ("new_empty", &new_empty, gsi::arg ("type"),
"@brief Creates a node delivering an empty result of the given type\n"
) +
method ("description=", &db::CompoundRegionOperationNode::set_description, gsi::arg ("d"),
"@brief Sets the description for this node"
) +
@ -613,10 +691,10 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
);
gsi::EnumIn<db::CompoundRegionOperationNode, db::CompoundRegionLogicalBoolOperationNode::LogicalOp> decl_dbCompoundRegionLogicalBoolOperationNode_LogicalOp ("db", "LogicalOp",
gsi::enum_const ("And", db::CompoundRegionLogicalBoolOperationNode::LogicalOp::And,
gsi::enum_const ("LogAnd", db::CompoundRegionLogicalBoolOperationNode::LogicalOp::And,
"@brief Indicates a logical '&&' (and)."
) +
gsi::enum_const ("Or", db::CompoundRegionLogicalBoolOperationNode::LogicalOp::Or,
gsi::enum_const ("LogOr", db::CompoundRegionLogicalBoolOperationNode::LogicalOp::Or,
"@brief Indicates a logical '||' (or)."
),
"@brief This class represents the CompoundRegionOperationNode::LogicalOp enum\n"

View File

@ -0,0 +1,237 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlUnitTest.h"
#include "tlString.h"
#include "dbRegionUtils.h"
namespace tl
{
template <class Iter>
std::string to_string (Iter b, Iter e)
{
std::string res;
for (Iter i = b; i != e; ++i) {
if (i != b) {
res += ",";
}
res += tl::to_string (*i);
}
return res;
}
template <class T>
std::string to_string (const std::vector<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T>
std::string to_string (const std::list<T> &v)
{
return to_string (v.begin (), v.end ());
}
template <class T>
std::string to_string (const std::set<T> &v)
{
return to_string (v.begin (), v.end ());
}
}
TEST(1_SimpleLShape)
{
std::set<db::EdgePair> ep;
std::set<db::Edge> ee1, ee2;
db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 2000),
db::Point (2000, 2000),
db::Point (2000, 1000),
db::Point (1000, 1000),
db::Point (1000, 0)
};
db::Polygon poly;
poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts[0]));
db::poly2poly_check_base<db::Polygon> poly_check (e2e);
do {
// single polygon check
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)/(1000,1000;1000,0),(1000,2000;2000,2000)/(2000,1000;1000,1000)");
EXPECT_EQ (tl::to_string (ee1), "");
EXPECT_EQ (tl::to_string (ee2), "");
}
TEST(2_SimpleLWithBigPart)
{
std::set<db::EdgePair> ep;
std::set<db::Edge> ee1, ee2;
db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 2500),
db::Point (2000, 2500),
db::Point (2000, 1000),
db::Point (1000, 1000),
db::Point (1000, 0)
};
db::Polygon poly;
poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts[0]));
db::poly2poly_check_base<db::Polygon> poly_check (e2e);
do {
// single polygon check
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)/(1000,1000;1000,0)");
EXPECT_EQ (tl::to_string (ee1), "(0,1000;0,2500),(2000,1000;1000,1000),(0,2500;2000,2500),(2000,2500;2000,1000)");
EXPECT_EQ (tl::to_string (ee2), "");
}
TEST(3_SimpleTWithBigPart)
{
std::set<db::EdgePair> ep;
std::set<db::Edge> ee1, ee2;
db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 3500),
db::Point (1000, 3500),
db::Point (1000, 2500),
db::Point (2000, 2500),
db::Point (2000, 1000),
db::Point (1000, 1000),
db::Point (1000, 0)
};
db::Polygon poly;
poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts[0]));
db::poly2poly_check_base<db::Polygon> poly_check (e2e);
do {
// single polygon check
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)/(1000,1000;1000,0),(0,2500;0,3500)/(1000,3500;1000,2500)");
EXPECT_EQ (tl::to_string (ee1), "(0,1000;0,2500),(2000,1000;1000,1000),(1000,2500;2000,2500),(2000,2500;2000,1000)");
EXPECT_EQ (tl::to_string (ee2), "");
}
TEST(4_SimpleNotch)
{
std::set<db::EdgePair> ep;
std::set<db::Edge> ee1, ee2;
db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 3000),
db::Point (2000, 3000),
db::Point (2000, 2000),
db::Point (1000, 2000),
db::Point (1000, 1000),
db::Point (2000, 1000),
db::Point (2000, 0)
};
db::Polygon poly;
poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts[0]));
db::poly2poly_check_base<db::Polygon> poly_check (e2e);
do {
// single polygon check
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(2000,2000;1000,2000)/(1000,1000;2000,1000)");
EXPECT_EQ (tl::to_string (ee1), "(0,0;0,3000),(2000,0;0,0),(2000,1000;2000,0),(0,3000;2000,3000),(2000,3000;2000,2000)");
EXPECT_EQ (tl::to_string (ee2), "");
}
TEST(5_LShapeNotch)
{
std::set<db::EdgePair> ep;
std::set<db::Edge> ee1, ee2;
db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 3000),
db::Point (2000, 3000),
db::Point (2000, 1500),
db::Point (1500, 1500),
db::Point (1500, 2500),
db::Point (500, 2500),
db::Point (500, 500),
db::Point (2000, 500),
db::Point (2000, 0)
};
db::Polygon poly;
poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts[0]));
db::poly2poly_check_base<db::Polygon> poly_check (e2e);
do {
// single polygon check
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(0,0;0,3000),(2000,0;0,0),(2000,500;2000,0),(0,3000;2000,3000),(2000,3000;2000,1500)");
EXPECT_EQ (tl::to_string (ee1), "");
EXPECT_EQ (tl::to_string (ee2), "");
}

View File

@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
dbCompoundOperationTests.cc \
dbRegionUtilsTests.cc \
dbWriterTools.cc \
dbLoadLayoutOptionsTests.cc \
dbSaveLayoutOptionsTests.cc \