mirror of https://github.com/KLayout/klayout.git
WIP: attempt to implement negative edge output on width and space
This commit is contained in:
parent
8f8d754180
commit
98792c55de
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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), "");
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
|
|||
|
||||
SOURCES = \
|
||||
dbCompoundOperationTests.cc \
|
||||
dbRegionUtilsTests.cc \
|
||||
dbWriterTools.cc \
|
||||
dbLoadLayoutOptionsTests.cc \
|
||||
dbSaveLayoutOptionsTests.cc \
|
||||
|
|
|
|||
Loading…
Reference in New Issue