Refactoring of Edges - compiles again.

This commit is contained in:
Matthias Koefferlein 2018-11-09 00:39:00 +01:00
parent 0a9ab32f81
commit ec638c87b4
17 changed files with 4100 additions and 2500 deletions

View File

@ -125,7 +125,12 @@ SOURCES = \
dbFlatRegion.cc \
dbOriginalLayerRegion.cc \
dbRegionDelegate.cc \
dbEdgesDelegate.cc
dbEdgesDelegate.cc \
dbEmptyEdges.cc \
dbAsIfFlatEdges.cc \
dbFlatEdges.cc \
dbEdgeBoolean.cc \
dbOriginalLayerEdges.cc
HEADERS = \
dbArray.h \
@ -220,7 +225,12 @@ HEADERS = \
dbFlatRegion.h \
dbOriginalLayerRegion.h \
dbRegionDelegate.h \
dbEdgesDelegate.h
dbEdgesDelegate.h \
dbEmptyEdges.h \
dbAsIfFlatEdges.h \
dbFlatEdges.h \
dbEdgeBoolean.h \
dbOriginalLayerEdges.h
!equals(HAVE_QT, "0") {

View File

@ -0,0 +1,917 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbAsIfFlatEdges.h"
#include "dbFlatEdges.h"
#include "dbEmptyEdges.h"
#include "dbEdges.h"
#include "dbEdgeBoolean.h"
#include "dbBoxConvert.h"
#include "dbBoxScanner.h"
#include "dbRegion.h"
#include "dbFlatRegion.h"
#include "dbPolygonTools.h"
#include "dbShapeProcessor.h"
#include <sstream>
namespace db
{
// -------------------------------------------------------------------------------------------------------------
// AsIfFlagEdges implementation
AsIfFlatEdges::AsIfFlatEdges ()
: EdgesDelegate (), m_bbox_valid (false)
{
// .. nothing yet ..
}
AsIfFlatEdges::~AsIfFlatEdges ()
{
// .. nothing yet ..
}
std::string
AsIfFlatEdges::to_string (size_t nmax) const
{
std::ostringstream os;
EdgesIterator p (begin ());
bool first = true;
for ( ; ! p.at_end () && nmax != 0; ++p, --nmax) {
if (! first) {
os << ";";
}
first = false;
os << p->to_string ();
}
if (! p.at_end ()) {
os << "...";
}
return os.str ();
}
namespace
{
/**
* @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver
*
* Note: This special scanner uses pointers to two different objects: edges and polygons.
* It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate
* pointers to edges.
*
* There is a special box converter which is able to sort that out as well.
*/
template <class OutputContainer>
class edge_to_region_interaction_filter
: public db::box_scanner_receiver<char, size_t>
{
public:
edge_to_region_interaction_filter (OutputContainer &output)
: mp_output (&output)
{
// .. nothing yet ..
}
void add (const char *o1, size_t p1, const char *o2, size_t p2)
{
const db::Edge *e = 0;
const db::Polygon *p = 0;
// Note: edges have property 0 and have even-valued pointers.
// Polygons have property 1 and odd-valued pointers.
if (p1 == 0 && p2 == 1) {
e = reinterpret_cast<const db::Edge *> (o1);
p = reinterpret_cast<const db::Polygon *> (o2 - 1);
} else if (p1 == 1 && p2 == 0) {
e = reinterpret_cast<const db::Edge *> (o2);
p = reinterpret_cast<const db::Polygon *> (o1 - 1);
}
if (e && p && m_seen.find (e) == m_seen.end ()) {
if (db::interact (*p, *e)) {
m_seen.insert (e);
mp_output->insert (*e);
}
}
}
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
};
/**
* @brief A special box converter that splits the pointers into polygon and edge pointers
*/
struct EdgeOrRegionBoxConverter
{
typedef db::Box box_type;
db::Box operator() (const char &c) const
{
// Note: edges have property 0 and have even-valued pointers.
// Polygons have property 1 and odd-valued pointers.
const char *cp = &c;
if ((size_t (cp) & 1) == 1) {
// it's a polygon
return (reinterpret_cast<const db::Polygon *> (cp - 1))->box ();
} else {
// it's an edge
const db::Edge *e = reinterpret_cast<const db::Edge *> (cp);
return db::Box (e->p1 (), e->p2 ());
}
}
};
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Region &other) const
{
// shortcuts
if (other.empty () || empty ()) {
return new EmptyEdges ();
}
db::box_scanner<char, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert ((char *) e.operator-> (), 0);
}
AddressablePolygonDelivery p = other.addressable_polygons ();
for ( ; ! p.at_end (); ++p) {
scanner.insert ((char *) p.operator-> () + 1, 1);
}
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
edge_to_region_interaction_filter<FlatEdges> filter (*output);
EdgeOrRegionBoxConverter bc;
scanner.process (filter, 1, bc);
return output.release ();
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Region &other) const
{
// shortcuts
if (other.empty () || empty ()) {
return clone ();
}
db::box_scanner<char, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert ((char *) e.operator-> (), 0);
}
AddressablePolygonDelivery p = other.addressable_polygons ();
for ( ; ! p.at_end (); ++p) {
scanner.insert ((char *) p.operator-> () + 1, 1);
}
std::set<db::Edge> interacting;
edge_to_region_interaction_filter<std::set<db::Edge> > filter (interacting);
EdgeOrRegionBoxConverter bc;
scanner.process (filter, 1, bc);
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (interacting.find (*o) == interacting.end ()) {
output->insert (*o);
}
}
return output.release ();
}
namespace
{
template <class OutputContainer>
struct JoinEdgesCluster
: public db::cluster<db::Edge, size_t>,
public db::PolygonSink
{
typedef db::Edge::coord_type coord_type;
JoinEdgesCluster (OutputContainer *output, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i)
: mp_output (output), m_ext_b (ext_b), m_ext_e (ext_e), m_ext_o (ext_o), m_ext_i (ext_i)
{
// .. nothing yet ..
}
void finish ()
{
std::multimap<db::Point, iterator> objects_by_p1;
std::multimap<db::Point, iterator> objects_by_p2;
for (iterator o = begin (); o != end (); ++o) {
if (o->first->p1 () != o->first->p2 ()) {
objects_by_p1.insert (std::make_pair (o->first->p1 (), o));
objects_by_p2.insert (std::make_pair (o->first->p2 (), o));
}
}
while (! objects_by_p2.empty ()) {
tl_assert (! objects_by_p1.empty ());
// Find the beginning of a new sequence
std::multimap<db::Point, iterator>::iterator j0 = objects_by_p1.begin ();
std::multimap<db::Point, iterator>::iterator j = j0;
do {
std::multimap<db::Point, iterator>::iterator jj = objects_by_p2.find (j->first);
if (jj == objects_by_p2.end ()) {
break;
} else {
j = objects_by_p1.find (jj->second->first->p1 ());
tl_assert (j != objects_by_p1.end ());
}
} while (j != j0);
iterator i = j->second;
// determine a sequence
// TODO: this chooses any solution in case of forks. Choose a specific one?
std::vector<db::Point> pts;
pts.push_back (i->first->p1 ());
do {
// record the next point
pts.push_back (i->first->p2 ());
// remove the edge as it's taken
std::multimap<db::Point, iterator>::iterator jj;
for (jj = objects_by_p2.find (i->first->p2 ()); jj != objects_by_p2.end () && jj->first == i->first->p2 (); ++jj) {
if (jj->second == i) {
break;
}
}
tl_assert (jj != objects_by_p2.end () && jj->second == i);
objects_by_p2.erase (jj);
objects_by_p1.erase (j);
// process along the edge to the next one
// TODO: this chooses any solution in case of forks. Choose a specific one?
j = objects_by_p1.find (i->first->p2 ());
if (j != objects_by_p1.end ()) {
i = j->second;
} else {
break;
}
} while (true);
bool cyclic = (pts.back () == pts.front ());
if (! cyclic) {
// non-cyclic sequence
db::Path path (pts.begin (), pts.end (), 0, m_ext_b, m_ext_e, false);
std::vector<db::Point> hull;
path.hull (hull, m_ext_o, m_ext_i);
db::Polygon poly;
poly.assign_hull (hull.begin (), hull.end ());
put (poly);
} else {
// we have a loop: form a contour by using the polygon size functions and a "Not" to form the hole
db::Polygon poly;
poly.assign_hull (pts.begin (), pts.end ());
db::EdgeProcessor ep;
db::PolygonGenerator pg (*this, false, true);
int mode_a = -1, mode_b = -1;
if (m_ext_o == 0) {
ep.insert (poly, 0);
} else {
db::Polygon sized_poly (poly);
sized_poly.size (m_ext_o, m_ext_o, 2 /*sizing mode*/);
ep.insert (sized_poly, 0);
mode_a = 1;
}
if (m_ext_i == 0) {
ep.insert (poly, 1);
} else {
db::Polygon sized_poly (poly);
sized_poly.size (-m_ext_i, -m_ext_i, 2 /*sizing mode*/);
ep.insert (sized_poly, 1);
mode_b = 1;
}
db::BooleanOp2 op (db::BooleanOp::ANotB, mode_a, mode_b);
ep.process (pg, op);
}
}
}
virtual void put (const db::Polygon &polygon)
{
mp_output->insert (polygon);
}
private:
OutputContainer *mp_output;
coord_type m_ext_b, m_ext_e, m_ext_o, m_ext_i;
};
template <class OutputContainer>
struct JoinEdgesClusterCollector
: public db::cluster_collector<db::Edge, size_t, JoinEdgesCluster<OutputContainer> >
{
typedef db::Edge::coord_type coord_type;
JoinEdgesClusterCollector (OutputContainer *output, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i)
: db::cluster_collector<db::Edge, size_t, JoinEdgesCluster<OutputContainer> > (JoinEdgesCluster<OutputContainer> (output, ext_b, ext_e, ext_o, ext_i), true)
{
// .. nothing yet ..
}
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
if (o1->p2 () == o2->p1 () || o1->p1 () == o2->p2 ()) {
db::cluster_collector<db::Edge, size_t, JoinEdgesCluster<OutputContainer> >::add (o1, p1, o2, p2);
}
}
};
}
RegionDelegate *
AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const
{
if (join) {
std::auto_ptr<FlatRegion> output (new FlatRegion ());
JoinEdgesClusterCollector<FlatRegion> cluster_collector (output.get (), ext_b, ext_e, ext_o, ext_i);
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size ());
size_t n = 0;
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
scanner.insert (&*e, n);
++n;
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
return output.release ();
} else {
std::auto_ptr<FlatRegion> output (new FlatRegion ());
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
db::DVector d;
if (e->is_degenerate ()) {
d = db::DVector (1.0, 0.0);
} else {
d = db::DVector (e->d ()) * (1.0 / e->double_length ());
}
db::DVector n (-d.y (), d.x ());
db::Point pts[4] = {
db::Point (db::DPoint (e->p1 ()) - d * double (ext_b) + n * double (ext_o)),
db::Point (db::DPoint (e->p2 ()) + d * double (ext_e) + n * double (ext_o)),
db::Point (db::DPoint (e->p2 ()) + d * double (ext_e) - n * double (ext_i)),
db::Point (db::DPoint (e->p1 ()) - d * double (ext_b) - n * double (ext_i)),
};
db::Polygon poly;
poly.assign_hull (pts + 0, pts + 4);
output->insert (poly);
}
return output.release ();
}
}
EdgesDelegate *
AsIfFlatEdges::start_segments (length_type length, double fraction) const
{
std::auto_ptr<FlatEdges> edges (new FlatEdges ());
edges->reserve (size ());
// zero-length edges would vanish in merged sematics, so we don't set it now
if (length == 0) {
edges->set_merged_semantics (false);
}
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
double l = std::max (e->double_length () * fraction, double (length));
edges->insert (db::Edge (e->p1 (), db::Point (db::DPoint (e->p1 ()) + db::DVector (e->d()) * (l / e->double_length ()))));
}
return edges.release ();
}
EdgesDelegate *
AsIfFlatEdges::end_segments (length_type length, double fraction) const
{
std::auto_ptr<FlatEdges> edges (new FlatEdges ());
edges->reserve (size ());
// zero-length edges would vanish in merged sematics, so we don't set it now
if (length == 0) {
edges->set_merged_semantics (false);
}
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
double l = std::max (e->double_length () * fraction, double (length));
edges->insert (db::Edge (db::Point (db::DPoint (e->p2 ()) - db::DVector (e->d()) * (l / e->double_length ())), e->p2 ()));
}
return edges.release ();
}
EdgesDelegate *
AsIfFlatEdges::centers (length_type length, double fraction) const
{
std::auto_ptr<FlatEdges> edges (new FlatEdges ());
edges->reserve (size ());
// zero-length edges would vanish in merged sematics, so we don't set it now
if (length == 0) {
edges->set_merged_semantics (false);
}
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
double l = std::max (e->double_length () * fraction, double (length));
db::DVector dl = db::DVector (e->d()) * (0.5 * l / e->double_length ());
db::DPoint center = db::DPoint (e->p1 ()) + db::DVector (e->p2 () - e->p1 ()) * 0.5;
edges->insert (db::Edge (db::Point (center - dl), db::Point (center + dl)));
}
return edges.release ();
}
namespace
{
/**
* @brief A helper class for the edge interaction functionality which acts as an edge pair receiver
*/
template <class OutputContainer>
class edge_interaction_filter
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
edge_interaction_filter (OutputContainer &output)
: mp_output (&output)
{
// .. nothing yet ..
}
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
// Select the edges which intersect
if (p1 != p2) {
const db::Edge *o = p1 > p2 ? o2 : o1;
const db::Edge *oo = p1 > p2 ? o1 : o2;
if (o->intersect (*oo)) {
if (m_seen.insert (o).second) {
mp_output->insert (*o);
}
}
}
}
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
};
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Edges &other) const
{
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee = other.addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
edge_interaction_filter<FlatEdges> filter (*output);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
return output.release ();
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Edges &other) const
{
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + other.size ());
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee = other.addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
std::set<db::Edge> interacting;
edge_interaction_filter<std::set<db::Edge> > filter (interacting);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if (interacting.find (*o) == interacting.end ()) {
output->insert (*o);
}
}
return output.release ();
}
EdgesDelegate *
AsIfFlatEdges::in (const Edges &other, bool invert) const
{
std::set <db::Edge> op;
for (EdgesIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
op.insert (*o);
}
std::auto_ptr<FlatEdges> new_region (new FlatEdges (false));
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
if ((op.find (*o) == op.end ()) == invert) {
new_region->insert (*o);
}
}
return new_region.release ();
}
size_t
AsIfFlatEdges::size () const
{
size_t n = 0;
for (EdgesIterator p (begin ()); ! p.at_end (); ++p) {
++n;
}
return n;
}
AsIfFlatEdges::length_type
AsIfFlatEdges::length (const db::Box &box) const
{
distance_type l = 0;
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
if (box.empty () || (box.contains (e->p1 ()) && box.contains (e->p2 ()))) {
l += e->length ();
} else {
std::pair<bool, db::Edge> ce = e->clipped (box);
if (ce.first) {
db::Coord dx = ce.second.dx ();
db::Coord dy = ce.second.dy ();
db::Coord x = ce.second.p1 ().x ();
db::Coord y = ce.second.p1 ().y ();
if ((dx == 0 && x == box.left () && dy < 0) ||
(dx == 0 && x == box.right () && dy > 0) ||
(dy == 0 && y == box.top () && dx < 0) ||
(dy == 0 && y == box.bottom () && dx > 0)) {
// not counted -> box is at outside side of the edge
} else {
l += ce.second.length ();
}
}
}
}
return l;
}
Box AsIfFlatEdges::bbox () const
{
if (! m_bbox_valid) {
m_bbox = compute_bbox ();
m_bbox_valid = true;
}
return m_bbox;
}
Box AsIfFlatEdges::compute_bbox () const
{
db::Box b;
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
b += e->bbox ();
}
return b;
}
void AsIfFlatEdges::update_bbox (const db::Box &b)
{
m_bbox = b;
m_bbox_valid = true;
}
void AsIfFlatEdges::invalidate_bbox ()
{
m_bbox_valid = false;
}
EdgesDelegate *
AsIfFlatEdges::filtered (const EdgeFilterBase &filter) const
{
std::auto_ptr<FlatEdges> new_region (new FlatEdges ());
for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) {
new_region->insert (*p);
}
}
return new_region.release ();
}
namespace
{
/**
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
*
* If will perform a edge by edge check using the provided EdgeRelationFilter
*/
class Edge2EdgeCheck
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
Edge2EdgeCheck (const EdgeRelationFilter &check, EdgePairs &output, bool requires_different_layers)
: mp_check (&check), mp_output (&output)
{
m_requires_different_layers = requires_different_layers;
}
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
// Overlap or inside checks require input from different layers
if (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0) {
// 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));
db::EdgePair ep;
if (mp_check->check (l1 <= l2 ? *o1 : *o2, l1 <= l2 ? *o2 : *o1, &ep)) {
mp_output->insert (ep);
}
}
}
private:
const EdgeRelationFilter *mp_check;
EdgePairs *mp_output;
bool m_requires_different_layers;
};
}
EdgePairs
AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
EdgePairs result;
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + (other ? other->size () : 0));
size_t n = 0;
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
scanner.insert (&*e, n);
n += 2;
}
if (other) {
n = 1;
for (EdgesIterator e (other->begin_merged ()); ! e.at_end (); ++e) {
scanner.insert (&*e, n);
n += 2;
}
}
EdgeRelationFilter check (rel, d, metrics);
check.set_include_zero (other != 0);
check.set_whole_edges (whole_edges);
check.set_ignore_angle (ignore_angle);
check.set_min_projection (min_projection);
check.set_max_projection (max_projection);
Edge2EdgeCheck edge_check (check, result, other != 0);
scanner.process (edge_check, d, db::box_convert<db::Edge> ());
return result;
}
EdgesDelegate *
AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
{
std::auto_ptr<FlatEdges> output (new FlatEdges (true));
EdgeBooleanClusterCollector<FlatEdges> cluster_collector (output.get (), op);
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size () + (other ? other->size () : 0));
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (&*e, 0);
}
}
if (other) {
for (EdgesIterator e (other->begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (&*e, 1);
}
}
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
return output.release ();
}
EdgesDelegate *
AsIfFlatEdges::edge_region_op (const Region &other, bool outside, bool include_borders) const
{
// shortcuts
if (other.empty ()) {
if (! outside) {
return new EmptyEdges ();
} else {
return clone ();
}
} else if (empty ()) {
return new EmptyEdges ();
}
db::EdgeProcessor ep (report_progress (), progress_desc ());
for (db::Region::const_iterator p = other.begin (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, 0);
}
}
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
ep.insert (*e, 1);
}
std::auto_ptr<FlatEdges> output (new FlatEdges (false));
db::EdgeShapeGenerator cc (output->raw_edges (), true /*clear*/);
db::EdgePolygonOp op (outside, include_borders);
ep.process (cc, op);
return output.release ();
}
EdgesDelegate *
AsIfFlatEdges::add (const Edges &other) const
{
FlatEdges *other_flat = dynamic_cast<FlatEdges *> (other.delegate ());
if (other_flat) {
std::auto_ptr<FlatEdges> new_edges (new FlatEdges (*other_flat));
new_edges->set_is_merged (false);
new_edges->invalidate_cache ();
size_t n = new_edges->raw_edges ().size () + size ();
new_edges->reserve (n);
for (EdgesIterator p (begin ()); ! p.at_end (); ++p) {
new_edges->raw_edges ().insert (*p);
}
return new_edges.release ();
} else {
std::auto_ptr<FlatEdges> new_edges (new FlatEdges (false /*not merged*/));
size_t n = size () + other.size ();
new_edges->reserve (n);
for (EdgesIterator p (begin ()); ! p.at_end (); ++p) {
new_edges->raw_edges ().insert (*p);
}
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
new_edges->raw_edges ().insert (*p);
}
return new_edges.release ();
}
}
bool
AsIfFlatEdges::equals (const Edges &other) const
{
if (empty () != other.empty ()) {
return false;
}
if (size () != other.size ()) {
return false;
}
EdgesIterator o1 (begin ());
EdgesIterator o2 (other.begin ());
while (! o1.at_end () && ! o2.at_end ()) {
if (*o1 != *o2) {
return false;
}
++o1;
++o2;
}
return true;
}
bool
AsIfFlatEdges::less (const Edges &other) const
{
if (empty () != other.empty ()) {
return empty () < other.empty ();
}
if (size () != other.size ()) {
return (size () < other.size ());
}
EdgesIterator o1 (begin ());
EdgesIterator o2 (other.begin ());
while (! o1.at_end () && ! o2.at_end ()) {
if (*o1 != *o2) {
return *o1 < *o2;
}
++o1;
++o2;
}
return false;
}
}

176
src/db/db/dbAsIfFlatEdges.h Normal file
View File

@ -0,0 +1,176 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#ifndef HDR_dbAsIfFlatEdges
#define HDR_dbAsIfFlatEdges
#include "dbCommon.h"
#include "dbEdgesDelegate.h"
namespace db {
/**
* @brief Provides default flat implementations
*/
class DB_PUBLIC AsIfFlatEdges
: public EdgesDelegate
{
public:
AsIfFlatEdges ();
virtual ~AsIfFlatEdges ();
virtual size_t size () const;
virtual std::string to_string (size_t) const;
virtual distance_type length (const db::Box &) const;
virtual Box bbox () const;
virtual EdgePairs width_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
return run_check (db::WidthRelation, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
}
virtual EdgePairs space_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
return run_check (db::SpaceRelation, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
}
virtual EdgePairs enclosing_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
return run_check (db::OverlapRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
}
virtual EdgePairs overlap_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
return run_check (db::WidthRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
}
virtual EdgePairs separation_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
return run_check (db::SpaceRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
}
virtual EdgePairs inside_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
return run_check (db::InsideRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
}
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter)
{
return filtered (filter);
}
virtual EdgesDelegate *filtered (const EdgeFilterBase &) const;
virtual EdgesDelegate *merged_in_place ()
{
return merged ();
}
virtual EdgesDelegate *merged () const
{
return boolean (0, EdgeOr);
}
virtual EdgesDelegate *and_with (const Edges &other) const
{
return boolean (&other, EdgeAnd);
}
virtual EdgesDelegate *and_with (const Region &other) const
{
return edge_region_op (other, false /*inside*/, true /*include borders*/);
}
virtual EdgesDelegate *not_with (const Edges &other) const
{
return boolean (&other, EdgeNot);
}
virtual EdgesDelegate *not_with (const Region &other) const
{
return edge_region_op (other, true /*outside*/, true /*include borders*/);
}
virtual EdgesDelegate *xor_with (const Edges &other) const
{
return boolean (&other, EdgeXor);
}
virtual EdgesDelegate *or_with (const Edges &other) const
{
return boolean (&other, EdgeOr);
}
virtual EdgesDelegate *add_in_place (const Edges &other)
{
return add (other);
}
virtual EdgesDelegate *add (const Edges &other) const;
virtual EdgesDelegate *inside_part (const Region &other) const
{
return edge_region_op (other, false /*inside*/, false /*don't include borders*/);
}
virtual EdgesDelegate *outside_part (const Region &other) const
{
return edge_region_op (other, true /*outside*/, false /*don't include borders*/);
}
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const;
virtual EdgesDelegate *start_segments (length_type length, double fraction) const;
virtual EdgesDelegate *end_segments (length_type length, double fraction) const;
virtual EdgesDelegate *centers (length_type length, double fraction) const;
virtual EdgesDelegate *selected_interacting (const Edges &) const;
virtual EdgesDelegate *selected_not_interacting (const Edges &) const;
virtual EdgesDelegate *selected_interacting (const Region &) const;
virtual EdgesDelegate *selected_not_interacting (const Region &) const;
virtual EdgesDelegate *in (const Edges &, bool) const;
virtual bool equals (const Edges &other) const;
virtual bool less (const Edges &other) const;
protected:
void update_bbox (const db::Box &box);
void invalidate_bbox ();
private:
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
mutable bool m_bbox_valid;
mutable db::Box m_bbox;
virtual db::Box compute_bbox () const;
EdgePairs run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
EdgesDelegate *boolean (const Edges *other, EdgeBoolOp op) const;
EdgesDelegate *edge_region_op (const Region &other, bool outside, bool include_borders) const;
};
}
#endif

View File

@ -433,9 +433,10 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse)
scanner.insert ((char *) p.operator-> () + 1, 1);
}
other.ensure_valid_merged_edges ();
for (Edges::const_iterator e = other.begin (); ! e.at_end (); ++e) {
scanner.insert ((char *) &*e, 0);
AddressableEdgeDelivery e (other.addressable_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert ((char *) e.operator-> (), 0);
}
std::auto_ptr<FlatRegion> output (new FlatRegion (false));

View File

@ -0,0 +1,24 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbEdgeBoolean.h"

241
src/db/db/dbEdgeBoolean.h Normal file
View File

@ -0,0 +1,241 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#ifndef HDR_dbEdgeBoolean
#define HDR_dbEdgeBoolean
#include "dbEdge.h"
#include "dbEdgesDelegate.h"
#include "dbBoxScanner.h"
#include "tlIntervalMap.h"
namespace db
{
struct OrJoinOp
{
void operator() (int &v, int n)
{
v += n;
}
};
struct AndJoinOp
{
void operator() (int &v, int n)
{
if (n == 0) {
v = 0;
}
}
};
struct NotJoinOp
{
void operator() (int &v, int n)
{
if (n != 0) {
v = 0;
}
}
};
struct XorJoinOp
{
void operator() (int &v, int n)
{
if (n != 0) {
if (v == 0) {
v = (n > 0 ? 1 : -1);
} else {
v = 0;
}
}
}
};
template <class OutputContainer>
struct EdgeBooleanCluster
: public db::cluster<db::Edge, size_t>
{
typedef db::Edge::coord_type coord_type;
EdgeBooleanCluster (OutputContainer *output, EdgeBoolOp op)
: mp_output (output), m_op (op)
{
// .. nothing yet ..
}
void finish ()
{
// determine base edge (longest overall edge)
// shortcut for single edge
if (begin () + 1 == end ()) {
if (begin ()->second == 0) {
if (m_op != EdgeAnd) {
mp_output->insert (*(begin ()->first));
}
} else {
if (m_op != EdgeAnd && m_op != EdgeNot) {
mp_output->insert (*(begin ()->first));
}
}
return;
}
db::Edge r = *begin ()->first;
double l1 = 0.0, l2 = r.double_length ();
double n = 1.0 / l2;
db::Point p1 = r.p1 (), p2 = r.p2 ();
for (iterator o = begin () + 1; o != end (); ++o) {
double ll1 = db::sprod (db::Vector (o->first->p1 () - r.p1 ()), r.d ()) * n;
double ll2 = db::sprod (db::Vector (o->first->p2 () - r.p1 ()), r.d ()) * n;
if (ll1 < l1) {
p1 = o->first->p1 ();
l1 = ll1;
}
if (ll2 < l1) {
p1 = o->first->p2 ();
l1 = ll2;
}
if (ll1 > l2) {
p2 = o->first->p1 ();
l2 = ll1;
}
if (ll2 > l2) {
p2 = o->first->p2 ();
l2 = ll2;
}
}
db::Vector d = db::Vector (p2 - p1);
n = 1.0 / d.double_length ();
OrJoinOp or_jop;
AndJoinOp and_jop;
NotJoinOp not_jop;
XorJoinOp xor_jop;
tl::interval_map<db::Coord, int> a, b;
a.add (0, db::coord_traits<db::Coord>::rounded (d.double_length ()), 0, or_jop);
b.add (0, db::coord_traits<db::Coord>::rounded (d.double_length ()), 0, or_jop);
for (iterator o = begin (); o != end (); ++o) {
db::Coord l1 = db::coord_traits<db::Coord>::rounded (db::sprod (db::Vector (o->first->p1 () - p1), d) * n);
db::Coord l2 = db::coord_traits<db::Coord>::rounded (db::sprod (db::Vector (o->first->p2 () - p1), d) * n);
if (o->second == 0 || m_op == EdgeOr) {
if (l1 < l2) {
a.add (l1, l2, 1, or_jop);
} else if (l1 > l2) {
a.add (l2, l1, -1, or_jop);
}
} else {
if (l1 < l2) {
b.add (l1, l2, 1, or_jop);
} else {
b.add (l2, l1, -1, or_jop);
}
}
}
tl::interval_map<db::Coord, int> q;
for (tl::interval_map<db::Coord, int>::const_iterator ia = a.begin (); ia != a.end (); ++ia) {
q.add (ia->first.first, ia->first.second, ia->second > 0 ? 1 : (ia->second < 0 ? -1 : 0), or_jop);
}
if (b.begin () == b.end ()) {
// optimize for empty b
if (m_op != EdgeAnd) {
for (tl::interval_map<db::Coord, int>::const_iterator ib = b.begin (); ib != b.end (); ++ib) {
if (ib->second > 0) {
mp_output->insert (db::Edge (p1 + db::Vector (d * (ib->first.first * n)), p1 + db::Vector (d * (ib->first.second * n))));
} else if (ib->second < 0) {
mp_output->insert (db::Edge (p1 + db::Vector (d * (ib->first.second * n)), p1 + db::Vector (d * (ib->first.first * n))));
}
}
}
} else {
if (m_op == EdgeAnd) {
for (tl::interval_map<db::Coord, int>::const_iterator ib = b.begin (); ib != b.end (); ++ib) {
q.add (ib->first.first, ib->first.second, ib->second, and_jop);
}
} else if (m_op == EdgeNot) {
for (tl::interval_map<db::Coord, int>::const_iterator ib = b.begin (); ib != b.end (); ++ib) {
q.add (ib->first.first, ib->first.second, ib->second, not_jop);
}
} else if (m_op == EdgeXor) {
for (tl::interval_map<db::Coord, int>::const_iterator ib = b.begin (); ib != b.end (); ++ib) {
q.add (ib->first.first, ib->first.second, ib->second, xor_jop);
}
}
for (tl::interval_map<db::Coord, int>::const_iterator iq = q.begin (); iq != q.end (); ++iq) {
if (iq->second > 0) {
mp_output->insert (db::Edge (p1 + db::Vector (d * (iq->first.first * n)), p1 + db::Vector (d * (iq->first.second * n))));
} else if (iq->second < 0) {
mp_output->insert (db::Edge (p1 + db::Vector (d * (iq->first.second * n)), p1 + db::Vector (d * (iq->first.first * n))));
}
}
}
}
private:
OutputContainer *mp_output;
db::EdgeBoolOp m_op;
};
template <class OutputContainer>
struct EdgeBooleanClusterCollector
: public db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> >
{
EdgeBooleanClusterCollector (OutputContainer *output, EdgeBoolOp op)
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, op), op != EdgeAnd /*report single*/)
{
// .. nothing yet ..
}
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
// Select edges which are:
// 1.) not degenerate
// 2.) parallel with some tolerance of roughly 1 dbu
// 3.) connected
if (! o1->is_degenerate () && ! o2->is_degenerate ()
&& fabs ((double) db::vprod (*o1, *o2)) < db::coord_traits<db::Coord>::prec_distance () * std::min (o1->double_length (), o2->double_length ())
&& (o1->p1 () == o2->p1 () || o1->p1 () == o2->p2 () || o1->p2 () == o2->p1 () || o1->p2 () == o2->p2 () || o1->coincident (*o2))) {
db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> >::add (o1, p1, o2, p2);
}
}
};
}
#endif

View File

@ -20,6 +20,195 @@
*/
#include "dbEdges.h"
#include "dbOriginalLayerEdges.h"
#include "dbEmptyEdges.h"
#include "dbFlatEdges.h"
#include "dbRegion.h"
namespace db
{
// -------------------------------------------------------------------------------------------------------------
// Edges implementation
Edges::Edges ()
: mp_delegate (new EmptyEdges ())
{
// .. nothing yet ..
}
Edges::Edges (EdgesDelegate *delegate)
: mp_delegate (delegate)
{
// .. nothing yet ..
}
Edges::Edges (const Edges &other)
: mp_delegate (other.mp_delegate->clone ())
{
// .. nothing yet ..
}
Edges::~Edges ()
{
delete mp_delegate;
mp_delegate = 0;
}
Edges &Edges::operator= (const Edges &other)
{
if (this != &other) {
set_delegate (other.mp_delegate->clone ());
}
return *this;
}
Edges::Edges (const RecursiveShapeIterator &si, bool as_edges)
{
if (! as_edges) {
mp_delegate = new OriginalLayerEdges (si);
} else {
FlatEdges *fe = new FlatEdges ();
mp_delegate = fe;
for (RecursiveShapeIterator s = si; ! s.at_end (); ++s) {
fe->insert (s.shape (), s.trans ());
}
}
}
Edges::Edges (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool as_edges, bool merged_semantics)
{
if (! as_edges) {
mp_delegate = new OriginalLayerEdges (si, trans, merged_semantics);
} else {
FlatEdges *fe = new FlatEdges ();
fe->set_merged_semantics (merged_semantics);
mp_delegate = fe;
for (RecursiveShapeIterator s = si; ! s.at_end (); ++s) {
fe->insert (s.shape (), trans * s.trans ());
}
}
}
const db::RecursiveShapeIterator &
Edges::iter () const
{
static db::RecursiveShapeIterator def_iter;
const db::RecursiveShapeIterator *i = mp_delegate->iter ();
return *(i ? i : &def_iter);
}
void
Edges::set_delegate (EdgesDelegate *delegate)
{
if (delegate != mp_delegate) {
delete mp_delegate;
mp_delegate = delegate;
}
}
void
Edges::clear ()
{
set_delegate (new EmptyEdges ());
}
void
Edges::reserve (size_t n)
{
flat_edges ()->reserve (n);
}
void Edges::extended (Region &output, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const
{
output.set_delegate (mp_delegate->extended (ext_b, ext_e, ext_o, ext_i, join));
}
template <class T>
Edges &Edges::transform (const T &trans)
{
flat_edges ()->transform (trans);
return *this;
}
// explicit instantiations
template Edges &Edges::transform (const db::ICplxTrans &);
template Edges &Edges::transform (const db::Trans &);
template <class Sh>
void Edges::insert (const Sh &shape)
{
flat_edges ()->insert (shape);
}
template void Edges::insert (const db::Box &);
template void Edges::insert (const db::SimplePolygon &);
template void Edges::insert (const db::Polygon &);
template void Edges::insert (const db::Path &);
template void Edges::insert (const db::Edge &);
void Edges::insert (const db::Shape &shape)
{
flat_edges ()->insert (shape);
}
template <class T>
void Edges::insert (const db::Shape &shape, const T &trans)
{
flat_edges ()->insert (shape, trans);
}
template void Edges::insert (const db::Shape &, const db::ICplxTrans &);
template void Edges::insert (const db::Shape &, const db::Trans &);
FlatEdges *
Edges::flat_edges ()
{
FlatEdges *edges = dynamic_cast<FlatEdges *> (mp_delegate);
if (! edges) {
edges = new FlatEdges ();
if (mp_delegate) {
edges->EdgesDelegate::operator= (*mp_delegate);
edges->insert_seq (begin ());
}
set_delegate (edges);
}
return edges;
}
}
namespace tl
{
template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Edges &b)
{
db::Edge p;
if (! ex.try_read (p)) {
return false;
}
b.insert (p);
while (ex.test (";")) {
ex.read (p);
b.insert (p);
}
return true;
}
template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Edges &b)
{
if (! test_extractor_impl (ex, b)) {
ex.error (tl::to_string (tr ("Expected an edge set specification")));
}
}
}
#if 0
// @@@@@@@@@@@@@@@@@@@@@@@@@@ ORIGINAL @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@qqq
#include "dbEdges.h"
#include "dbEdgePairs.h"
@ -1371,4 +1560,5 @@ namespace tl
}
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

105
src/db/db/dbEmptyEdges.cc Normal file
View File

@ -0,0 +1,105 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbEmptyEdges.h"
#include "dbEmptyRegion.h"
#include "dbEdges.h"
namespace db
{
// -------------------------------------------------------------------------------------------------------------
// EmptyEdges implementation
EmptyEdges::EmptyEdges ()
{
// .. nothing yet ..
}
EmptyEdges::~EmptyEdges ()
{
// .. nothing yet ..
}
EmptyEdges::EmptyEdges (const EmptyEdges &other)
: EdgesDelegate (other)
{
// .. nothing yet ..
}
EdgesDelegate *
EmptyEdges::clone () const
{
return new EmptyEdges (*this);
}
RegionDelegate *
EmptyEdges::extended (coord_type, coord_type, coord_type, coord_type, bool) const
{
return new EmptyRegion ();
}
EdgesDelegate *
EmptyEdges::add_in_place (const Edges &other)
{
return add (other);
}
EdgesDelegate *
EmptyEdges::add (const Edges &other) const
{
return other.delegate ()->clone ();
}
EdgesDelegate *
EmptyEdges::xor_with (const Edges &other) const
{
return or_with (other);
}
EdgesDelegate *
EmptyEdges::or_with (const Edges &other) const
{
if (other.empty ()) {
return new EmptyEdges ();
} else if (! other.strict_handling ()) {
return other.delegate ()->clone ();
} else {
return other.delegate ()->merged ();
}
}
bool
EmptyEdges::equals (const Edges &other) const
{
return other.empty ();
}
bool
EmptyEdges::less (const Edges &other) const
{
return other.empty () ? false : true;
}
}

111
src/db/db/dbEmptyEdges.h Normal file
View File

@ -0,0 +1,111 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#ifndef HDR_dbEmptyEdges
#define HDR_dbEmptyEdges
#include "dbCommon.h"
#include "dbEdgesDelegate.h"
#include "dbRecursiveShapeIterator.h"
namespace db {
/**
* @brief An empty Edges
*/
class DB_PUBLIC EmptyEdges
: public EdgesDelegate
{
public:
EmptyEdges ();
virtual ~EmptyEdges ();
EmptyEdges (const EmptyEdges &other);
EdgesDelegate *clone () const;
virtual EdgesIteratorDelegate *begin () const { return 0; }
virtual EdgesIteratorDelegate *begin_merged () const { return 0; }
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
virtual bool empty () const { return true; }
virtual size_t size () const { return 0; }
virtual std::string to_string (size_t) const { return std::string (); }
virtual bool is_merged () const { return true; }
virtual distance_type length (const db::Box &) const { return 0; }
virtual Box bbox () const { return db::Box (); }
virtual EdgePairs width_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); }
virtual EdgePairs space_check (db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); }
virtual EdgePairs enclosing_check (const Edges &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); }
virtual EdgePairs overlap_check (const Edges &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); }
virtual EdgePairs separation_check (const Edges &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); }
virtual EdgePairs inside_check (const Edges &, db::Coord, bool, metrics_type, double, distance_type, distance_type) const { return EdgePairs (); }
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &) { return this; }
virtual EdgesDelegate *filtered (const EdgeFilterBase &) const { return new EmptyEdges (); }
virtual EdgesDelegate *merged_in_place () { return this; }
virtual EdgesDelegate *merged () const { return new EmptyEdges (); }
virtual EdgesDelegate *and_with (const Edges &) const { return new EmptyEdges (); }
virtual EdgesDelegate *and_with (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *not_with (const Edges &) const { return new EmptyEdges (); }
virtual EdgesDelegate *not_with (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *xor_with (const Edges &other) const;
virtual EdgesDelegate *or_with (const Edges &other) const;
virtual EdgesDelegate *add_in_place (const Edges &other);
virtual EdgesDelegate *add (const Edges &other) const;
virtual RegionDelegate *extended (coord_type, coord_type, coord_type, coord_type, bool) const;
virtual EdgesDelegate *start_segments (length_type, double) const { return new EmptyEdges (); }
virtual EdgesDelegate *end_segments (length_type, double) const { return new EmptyEdges (); }
virtual EdgesDelegate *centers (length_type, double) const { return new EmptyEdges (); }
virtual EdgesDelegate *inside_part (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *outside_part (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_interacting (const Edges &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Edges &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_interacting (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Region &) const { return new EmptyEdges (); }
virtual EdgesDelegate *in (const Edges &, bool) const { return new EmptyEdges (); }
virtual const db::Edge *nth (size_t) const { tl_assert (false); }
virtual bool has_valid_edges () const { return true; }
virtual bool has_valid_merged_edges () const { return true; }
virtual const db::RecursiveShapeIterator *iter () const { return 0; }
virtual bool equals (const Edges &other) const;
virtual bool less (const Edges &other) const;
private:
EmptyEdges &operator= (const EmptyEdges &other);
};
} // namespace db
#endif

363
src/db/db/dbFlatEdges.cc Normal file
View File

@ -0,0 +1,363 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbFlatEdges.h"
#include "dbEmptyEdges.h"
#include "dbEdgeBoolean.h"
#include "dbEdges.h"
namespace db
{
// -------------------------------------------------------------------------------------------------------------
// FlatEdges implementation
FlatEdges::FlatEdges ()
: AsIfFlatEdges (), m_edges (false), m_merged_edges (false)
{
init ();
}
FlatEdges::~FlatEdges ()
{
// .. nothing yet ..
}
FlatEdges::FlatEdges (const FlatEdges &other)
: AsIfFlatEdges (other), m_edges (false), m_merged_edges (false)
{
init ();
m_is_merged = other.m_is_merged;
m_edges = other.m_edges;
m_merged_edges = other.m_merged_edges;
m_merged_edges_valid = other.m_merged_edges_valid;
}
FlatEdges::FlatEdges (const db::Shapes &edges, bool is_merged)
: AsIfFlatEdges (), m_edges (edges), m_merged_edges (false)
{
init ();
m_is_merged = is_merged;
}
FlatEdges::FlatEdges (bool is_merged)
: AsIfFlatEdges (), m_edges (false), m_merged_edges (false)
{
init ();
m_is_merged = is_merged;
}
void FlatEdges::set_is_merged (bool m)
{
m_is_merged = m;
}
void FlatEdges::invalidate_cache ()
{
invalidate_bbox ();
m_merged_edges.clear ();
m_merged_edges_valid = false;
}
void FlatEdges::init ()
{
m_is_merged = true;
m_merged_edges_valid = false;
}
void FlatEdges::merged_semantics_changed ()
{
m_merged_edges.clear ();
m_merged_edges_valid = false;
}
void FlatEdges::reserve (size_t n)
{
m_edges.reserve (db::Polygon::tag (), n);
}
void
FlatEdges::ensure_merged_edges_valid () const
{
if (! m_merged_edges_valid) {
m_merged_edges.clear ();
db::Shapes tmp;
EdgeBooleanClusterCollector<db::Shapes> cluster_collector (&tmp, EdgeOr);
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (m_edges.size ());
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (&*e, 0);
}
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
m_merged_edges.swap (tmp);
m_merged_edges_valid = true;
}
}
EdgesIteratorDelegate *FlatEdges::begin () const
{
return new FlatEdgesIterator (m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().begin (), m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ());
}
EdgesIteratorDelegate *FlatEdges::begin_merged () const
{
if (! merged_semantics () || m_is_merged) {
return begin ();
} else {
ensure_merged_edges_valid ();
return new FlatEdgesIterator (m_merged_edges.get_layer<db::Edge, db::unstable_layer_tag> ().begin (), m_merged_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ());
}
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatEdges::begin_iter () const
{
return std::make_pair (db::RecursiveShapeIterator (m_edges), db::ICplxTrans ());
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatEdges::begin_merged_iter () const
{
if (! merged_semantics () || m_is_merged) {
return begin_iter ();
} else {
ensure_merged_edges_valid ();
return std::make_pair (db::RecursiveShapeIterator (m_merged_edges), db::ICplxTrans ());
}
}
bool FlatEdges::empty () const
{
return m_edges.empty ();
}
size_t FlatEdges::size () const
{
return m_edges.size ();
}
bool FlatEdges::is_merged () const
{
return m_is_merged;
}
Box FlatEdges::compute_bbox () const
{
m_edges.update_bbox ();
return m_edges.bbox ();
}
EdgesDelegate *
FlatEdges::filter_in_place (const EdgeFilterBase &filter)
{
edge_iterator_type pw = m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().begin ();
for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (filter.selected (*p)) {
if (pw == m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ()) {
m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().insert (*p);
pw = m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ();
} else {
m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().replace (pw++, *p);
}
}
}
m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().erase (pw, m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ());
m_merged_edges.clear ();
m_is_merged = merged_semantics ();
return this;
}
EdgesDelegate *FlatEdges::add (const Edges &other) const
{
std::auto_ptr<FlatEdges> new_region (new FlatEdges (*this));
new_region->invalidate_cache ();
new_region->set_is_merged (false);
FlatEdges *other_flat = dynamic_cast<FlatEdges *> (other.delegate ());
if (other_flat) {
new_region->raw_edges ().insert (other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().end ());
} else {
size_t n = new_region->raw_edges ().size ();
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
++n;
}
new_region->raw_edges ().reserve (db::Edge::tag (), n);
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
new_region->raw_edges ().insert (*p);
}
}
return new_region.release ();
}
EdgesDelegate *FlatEdges::add_in_place (const Edges &other)
{
invalidate_cache ();
m_is_merged = false;
FlatEdges *other_flat = dynamic_cast<FlatEdges *> (other.delegate ());
if (other_flat) {
m_edges.insert (other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().begin (), other_flat->raw_edges ().get_layer<db::Edge, db::unstable_layer_tag> ().end ());
} else {
size_t n = m_edges.size ();
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
++n;
}
m_edges.reserve (db::Edge::tag (), n);
for (EdgesIterator p (other.begin ()); ! p.at_end (); ++p) {
m_edges.insert (*p);
}
}
return this;
}
const db::Edge *FlatEdges::nth (size_t n) const
{
return n < m_edges.size () ? &m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().begin () [n] : 0;
}
bool FlatEdges::has_valid_edges () const
{
return true;
}
bool FlatEdges::has_valid_merged_edges () const
{
return true;
}
const db::RecursiveShapeIterator *FlatEdges::iter () const
{
return 0;
}
void
FlatEdges::insert (const db::Box &box)
{
if (! box.empty () && box.width () > 0 && box.height () > 0) {
bool was_empty = empty ();
m_edges.insert (db::Edge (box.lower_left (), box.upper_left ()));
m_edges.insert (db::Edge (box.upper_left (), box.upper_right ()));
m_edges.insert (db::Edge (box.upper_right (), box.lower_right ()));
m_edges.insert (db::Edge (box.lower_right (), box.lower_left ()));
if (was_empty) {
m_is_merged = true;
update_bbox (box);
} else {
m_is_merged = false;
invalidate_cache ();
}
}
}
void
FlatEdges::insert (const db::Path &path)
{
if (path.points () > 0) {
insert (path.polygon ());
}
}
void
FlatEdges::insert (const db::Polygon &polygon)
{
if (polygon.holes () > 0 || polygon.vertices () > 0) {
for (db::Polygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) {
m_edges.insert (*e);
}
m_is_merged = false;
invalidate_cache ();
}
}
void
FlatEdges::insert (const db::SimplePolygon &polygon)
{
if (polygon.vertices () > 0) {
for (db::SimplePolygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) {
m_edges.insert (*e);
}
m_is_merged = false;
invalidate_cache ();
}
}
void
FlatEdges::insert (const db::Edge &edge)
{
m_edges.insert (edge);
}
void
FlatEdges::insert (const db::Shape &shape)
{
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
db::Polygon poly;
shape.polygon (poly);
insert (poly);
} else if (shape.is_edge ()) {
db::Edge edge;
shape.edge (edge);
insert (edge);
}
}
}

203
src/db/db/dbFlatEdges.h Normal file
View File

@ -0,0 +1,203 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#ifndef HDR_dbFlatEdges
#define HDR_dbFlatEdges
#include "dbCommon.h"
#include "dbAsIfFlatEdges.h"
#include "dbShapes.h"
#include "dbShapes2.h"
namespace db {
/**
* @brief An iterator delegate for the flat region
*/
class DB_PUBLIC FlatEdgesIterator
: public EdgesIteratorDelegate
{
public:
typedef db::layer<db::Edge, db::unstable_layer_tag> edge_layer_type;
typedef edge_layer_type::iterator iterator_type;
FlatEdgesIterator (iterator_type from, iterator_type to)
: m_from (from), m_to (to)
{
// .. nothing yet ..
}
virtual bool at_end () const
{
return m_from == m_to;
}
virtual void increment ()
{
++m_from;
}
virtual const value_type *get () const
{
return m_from.operator-> ();
}
virtual EdgesIteratorDelegate *clone () const
{
return new FlatEdgesIterator (*this);
}
private:
friend class Edges;
iterator_type m_from, m_to;
};
/**
* @brief A flat, edge-set delegate
*/
class DB_PUBLIC FlatEdges
: public AsIfFlatEdges
{
public:
typedef db::layer<db::Edge, db::unstable_layer_tag> edge_layer_type;
typedef edge_layer_type::iterator edge_iterator_type;
FlatEdges ();
FlatEdges (const db::Shapes &edges, bool is_merged);
FlatEdges (bool is_merged);
FlatEdges (const FlatEdges &other);
virtual ~FlatEdges ();
EdgesDelegate *clone () const
{
return new FlatEdges (*this);
}
void reserve (size_t);
virtual EdgesIteratorDelegate *begin () const;
virtual EdgesIteratorDelegate *begin_merged () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const;
virtual bool empty () const;
virtual size_t size () const;
virtual bool is_merged () const;
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter);
virtual EdgesDelegate *add_in_place (const Edges &other);
virtual EdgesDelegate *add (const Edges &other) const;
virtual const db::Edge *nth (size_t n) const;
virtual bool has_valid_edges () const;
virtual bool has_valid_merged_edges () const;
virtual const db::RecursiveShapeIterator *iter () const;
void insert (const db::Box &box);
void insert (const db::Path &path);
void insert (const db::SimplePolygon &polygon);
void insert (const db::Polygon &polygon);
void insert (const db::Edge &edge);
void insert (const db::Shape &shape);
template <class T>
void insert (const db::Shape &shape, const T &trans)
{
if (shape.is_polygon () || shape.is_path () || shape.is_box ()) {
db::Polygon poly;
shape.polygon (poly);
poly.transform (trans);
insert (poly);
} else if (shape.is_edge ()) {
db::Edge edge;
shape.edge (edge);
edge.transform (trans);
insert (edge);
}
}
template <class Iter>
void insert (const Iter &b, const Iter &e)
{
reserve (size () + (e - b));
for (Iter i = b; i != e; ++i) {
insert (*i);
}
}
template <class Iter>
void insert_seq (const Iter &seq)
{
for (Iter i = seq; ! i.at_end (); ++i) {
insert (*i);
}
}
template <class Trans>
void transform (const Trans &trans)
{
if (! trans.is_unity ()) {
for (edge_iterator_type p = m_edges.template get_layer<db::Edge, db::unstable_layer_tag> ().begin (); p != m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end (); ++p) {
m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
}
invalidate_cache ();
}
}
protected:
virtual void merged_semantics_changed ();
virtual Box compute_bbox () const;
void invalidate_cache ();
void set_is_merged (bool m);
private:
friend class AsIfFlatEdges;
db::Shapes &raw_edges () { return m_edges; }
FlatEdges &operator= (const FlatEdges &other);
bool m_is_merged;
mutable db::Shapes m_edges;
mutable db::Shapes m_merged_edges;
mutable bool m_merged_edges_valid;
void init ();
void ensure_merged_edges_valid () const;
};
}
#endif

View File

@ -0,0 +1,268 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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 "dbOriginalLayerEdges.h"
#include "dbFlatEdges.h"
#include "dbEdges.h"
#include "dbEdgeBoolean.h"
namespace db
{
// -------------------------------------------------------------------------------------------------------------
// OriginalLayerEdges implementation
namespace
{
class OriginalLayerEdgesIterator
: public EdgesIteratorDelegate
{
public:
OriginalLayerEdgesIterator (const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans)
: m_rec_iter (iter), m_iter_trans (trans)
{
set ();
}
virtual bool at_end () const
{
return m_rec_iter.at_end ();
}
virtual void increment ()
{
inc ();
set ();
}
virtual const value_type *get () const
{
return &m_edge;
}
virtual EdgesIteratorDelegate *clone () const
{
return new OriginalLayerEdgesIterator (*this);
}
private:
friend class Edges;
db::RecursiveShapeIterator m_rec_iter;
db::ICplxTrans m_iter_trans;
db::Edge m_edge;
void set ()
{
while (! m_rec_iter.at_end () && ! (m_rec_iter.shape ().is_edge () || m_rec_iter.shape ().is_path () || m_rec_iter.shape ().is_box ())) {
++m_rec_iter;
}
if (! m_rec_iter.at_end ()) {
m_rec_iter.shape ().edge (m_edge);
m_edge.transform (m_iter_trans * m_rec_iter.trans ());
}
}
void inc ()
{
if (! m_rec_iter.at_end ()) {
++m_rec_iter;
}
}
};
}
OriginalLayerEdges::OriginalLayerEdges ()
: AsIfFlatEdges (), m_merged_edges (false)
{
init ();
}
OriginalLayerEdges::OriginalLayerEdges (const OriginalLayerEdges &other)
: AsIfFlatEdges (other),
m_is_merged (other.m_is_merged),
m_merged_edges (other.m_merged_edges),
m_merged_edges_valid (other.m_merged_edges_valid),
m_iter (other.m_iter),
m_iter_trans (other.m_iter_trans)
{
// .. nothing yet ..
}
OriginalLayerEdges::OriginalLayerEdges (const RecursiveShapeIterator &si, bool is_merged)
: AsIfFlatEdges (), m_merged_edges (false), m_iter (si)
{
init ();
m_is_merged = is_merged;
}
OriginalLayerEdges::OriginalLayerEdges (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
: AsIfFlatEdges (), m_merged_edges (false), m_iter (si), m_iter_trans (trans)
{
init ();
m_is_merged = is_merged;
set_merged_semantics (merged_semantics);
}
OriginalLayerEdges::~OriginalLayerEdges ()
{
// .. nothing yet ..
}
EdgesDelegate *
OriginalLayerEdges::clone () const
{
return new OriginalLayerEdges (*this);
}
EdgesIteratorDelegate *
OriginalLayerEdges::begin () const
{
return new OriginalLayerEdgesIterator (m_iter, m_iter_trans);
}
EdgesIteratorDelegate *
OriginalLayerEdges::begin_merged () const
{
if (! merged_semantics () || m_is_merged) {
return begin ();
} else {
ensure_merged_edges_valid ();
return new FlatEdgesIterator (m_merged_edges.get_layer<db::Edge, db::unstable_layer_tag> ().begin (), m_merged_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ());
}
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
OriginalLayerEdges::begin_iter () const
{
return std::make_pair (m_iter, m_iter_trans);
}
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
OriginalLayerEdges::begin_merged_iter () const
{
if (! merged_semantics () || m_is_merged) {
return begin_iter ();
} else {
ensure_merged_edges_valid ();
return std::make_pair (db::RecursiveShapeIterator (m_merged_edges), db::ICplxTrans ());
}
}
bool
OriginalLayerEdges::empty () const
{
return m_iter.at_end ();
}
bool
OriginalLayerEdges::is_merged () const
{
return m_is_merged;
}
const db::Edge *
OriginalLayerEdges::nth (size_t) const
{
tl_assert (false);
}
bool
OriginalLayerEdges::has_valid_edges () const
{
return false;
}
bool
OriginalLayerEdges::has_valid_merged_edges () const
{
return merged_semantics () && ! m_is_merged;
}
const db::RecursiveShapeIterator *
OriginalLayerEdges::iter () const
{
return &m_iter;
}
bool
OriginalLayerEdges::equals (const Edges &other) const
{
const OriginalLayerEdges *other_delegate = dynamic_cast<const OriginalLayerEdges *> (other.delegate ());
if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) {
return true;
} else {
return AsIfFlatEdges::equals (other);
}
}
bool
OriginalLayerEdges::less (const Edges &other) const
{
const OriginalLayerEdges *other_delegate = dynamic_cast<const OriginalLayerEdges *> (other.delegate ());
if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) {
return false;
} else {
return AsIfFlatEdges::less (other);
}
}
void
OriginalLayerEdges::init ()
{
m_is_merged = true;
m_merged_edges_valid = false;
}
void
OriginalLayerEdges::ensure_merged_edges_valid () const
{
if (! m_merged_edges_valid) {
m_merged_edges.clear ();
db::Shapes tmp;
EdgeBooleanClusterCollector<db::Shapes> cluster_collector (&tmp, EdgeOr);
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve (size ());
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (&*e, 0);
}
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
m_merged_edges.swap (tmp);
m_merged_edges_valid = true;
}
}
}

View File

@ -0,0 +1,85 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2018 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
*/
#ifndef HDR_dbOriginalLayerEdges
#define HDR_dbOriginalLayerEdges
#include "dbCommon.h"
#include "dbAsIfFlatEdges.h"
#include "dbShapes.h"
#include "dbRecursiveShapeIterator.h"
namespace db {
/**
* @brief An original layerregion based on a RecursiveShapeIterator
*/
class DB_PUBLIC OriginalLayerEdges
: public AsIfFlatEdges
{
public:
OriginalLayerEdges ();
OriginalLayerEdges (const OriginalLayerEdges &other);
OriginalLayerEdges (const RecursiveShapeIterator &si, bool is_merged = false);
OriginalLayerEdges (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false);
virtual ~OriginalLayerEdges ();
EdgesDelegate *clone () const;
virtual EdgesIteratorDelegate *begin () const;
virtual EdgesIteratorDelegate *begin_merged () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_merged_iter () const;
virtual bool empty () const;
virtual bool is_merged () const;
virtual const db::Edge *nth (size_t n) const;
virtual bool has_valid_edges () const;
virtual bool has_valid_merged_edges () const;
virtual const db::RecursiveShapeIterator *iter () const;
virtual bool equals (const Edges &other) const;
virtual bool less (const Edges &other) const;
private:
OriginalLayerEdges &operator= (const OriginalLayerEdges &other);
bool m_is_merged;
mutable db::Shapes m_merged_edges;
mutable bool m_merged_edges_valid;
mutable db::RecursiveShapeIterator m_iter;
db::ICplxTrans m_iter_trans;
void init ();
void ensure_merged_edges_valid () const;
};
}
#endif

View File

@ -1659,6 +1659,8 @@ public:
}
private:
friend class Edges;
RegionDelegate *mp_delegate;
void set_delegate (RegionDelegate *delegate);