mirror of https://github.com/KLayout/klayout.git
Refactoring of Edges - compiles again.
This commit is contained in:
parent
0a9ab32f81
commit
ec638c87b4
|
|
@ -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") {
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
1265
src/db/db/dbEdges.h
1265
src/db/db/dbEdges.h
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
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -1659,6 +1659,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
friend class Edges;
|
||||
|
||||
RegionDelegate *mp_delegate;
|
||||
|
||||
void set_delegate (RegionDelegate *delegate);
|
||||
|
|
|
|||
Loading…
Reference in New Issue