mirror of https://github.com/KLayout/klayout.git
Refactoring: generalization of Triangles into db::plc::Graph in dbPLC.h
This commit is contained in:
parent
291c91fcaa
commit
627e244443
|
|
@ -70,13 +70,14 @@ SOURCES = \
|
|||
dbNetlistSpiceReaderExpressionParser.cc \
|
||||
dbObject.cc \
|
||||
dbObjectWithProperties.cc \
|
||||
dbPLC.cc \
|
||||
dbPLCTriangulation.cc \
|
||||
dbPath.cc \
|
||||
dbPCellDeclaration.cc \
|
||||
dbPCellHeader.cc \
|
||||
dbPCellVariant.cc \
|
||||
dbPoint.cc \
|
||||
dbPolygon.cc \
|
||||
dbPolygonGraph.cc \
|
||||
dbPolygonNeighborhood.cc \
|
||||
dbPolygonTools.cc \
|
||||
dbPolygonGenerators.cc \
|
||||
|
|
@ -309,13 +310,14 @@ HEADERS = \
|
|||
dbObject.h \
|
||||
dbObjectTag.h \
|
||||
dbObjectWithProperties.h \
|
||||
dbPLC.h \
|
||||
dbPLCTriangulation.h \
|
||||
dbPath.h \
|
||||
dbPCellDeclaration.h \
|
||||
dbPCellHeader.h \
|
||||
dbPCellVariant.h \
|
||||
dbPoint.h \
|
||||
dbPolygon.h \
|
||||
dbPolygonGraph.h \
|
||||
dbPolygonNeighborhood.h \
|
||||
dbPolygonTools.h \
|
||||
dbPolygonGenerators.h \
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "dbPolygonGraph.h"
|
||||
#include "dbPLC.h"
|
||||
#include "dbLayout.h"
|
||||
#include "dbWriter.h"
|
||||
#include "tlStream.h"
|
||||
|
|
@ -36,28 +36,43 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
namespace plc
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// GVertex implementation
|
||||
// Vertex implementation
|
||||
|
||||
GVertex::GVertex ()
|
||||
: DPoint (), m_is_precious (false)
|
||||
Vertex::Vertex (Graph *graph)
|
||||
: DPoint (), mp_graph (graph), m_is_precious (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
GVertex::GVertex (const db::DPoint &p)
|
||||
: DPoint (p), m_is_precious (false)
|
||||
Vertex::Vertex (Graph *graph, const db::DPoint &p)
|
||||
: DPoint (p), mp_graph (graph), m_is_precious (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
GVertex::GVertex (const GVertex &v)
|
||||
: DPoint (), m_is_precious (false)
|
||||
Vertex::Vertex (Graph *graph, const Vertex &v)
|
||||
: DPoint (), mp_graph (graph), m_is_precious (false)
|
||||
{
|
||||
operator= (v);
|
||||
}
|
||||
|
||||
GVertex &GVertex::operator= (const GVertex &v)
|
||||
Vertex::Vertex (Graph *graph, db::DCoord x, db::DCoord y)
|
||||
: DPoint (x, y), mp_graph (graph), m_is_precious (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Vertex::Vertex (const Vertex &v)
|
||||
: DPoint (v), mp_graph (v.mp_graph), m_is_precious (v.m_is_precious)
|
||||
{
|
||||
// NOTE: edges are not copied!
|
||||
}
|
||||
|
||||
Vertex &Vertex::operator= (const Vertex &v)
|
||||
{
|
||||
if (this != &v) {
|
||||
// NOTE: edges are not copied!
|
||||
|
|
@ -67,15 +82,8 @@ GVertex &GVertex::operator= (const GVertex &v)
|
|||
return *this;
|
||||
}
|
||||
|
||||
GVertex::GVertex (db::DCoord x, db::DCoord y)
|
||||
: DPoint (x, y), m_is_precious (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
#if 0 // @@@
|
||||
bool
|
||||
GVertex::is_outside () const
|
||||
Vertex::is_outside () const
|
||||
{
|
||||
for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) {
|
||||
if ((*e)->is_outside ()) {
|
||||
|
|
@ -84,13 +92,12 @@ GVertex::is_outside () const
|
|||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<db::GPolygon *>
|
||||
GVertex::polygons () const
|
||||
std::vector<Polygon *>
|
||||
Vertex::polygons () const
|
||||
{
|
||||
std::set<db::GPolygon *> seen;
|
||||
std::vector<db::GPolygon *> res;
|
||||
std::set<Polygon *> seen;
|
||||
std::vector<Polygon *> res;
|
||||
for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) {
|
||||
for (auto t = (*e)->begin_polygons (); t != (*e)->end_polygons (); ++t) {
|
||||
if (seen.insert (t.operator-> ()).second) {
|
||||
|
|
@ -102,7 +109,7 @@ GVertex::polygons () const
|
|||
}
|
||||
|
||||
bool
|
||||
GVertex::has_edge (const GPolygonEdge *edge) const
|
||||
Vertex::has_edge (const Edge *edge) const
|
||||
{
|
||||
for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) {
|
||||
if (*e == edge) {
|
||||
|
|
@ -113,7 +120,7 @@ GVertex::has_edge (const GPolygonEdge *edge) const
|
|||
}
|
||||
|
||||
size_t
|
||||
GVertex::num_edges (int max_count) const
|
||||
Vertex::num_edges (int max_count) const
|
||||
{
|
||||
if (max_count < 0) {
|
||||
// NOTE: this can be slow for a std::list, so we have max_count to limit this effort
|
||||
|
|
@ -128,7 +135,7 @@ GVertex::num_edges (int max_count) const
|
|||
}
|
||||
|
||||
std::string
|
||||
GVertex::to_string (bool with_id) const
|
||||
Vertex::to_string (bool with_id) const
|
||||
{
|
||||
std::string res = tl::sprintf ("(%.12g, %.12g)", x (), y());
|
||||
if (with_id) {
|
||||
|
|
@ -138,7 +145,7 @@ GVertex::to_string (bool with_id) const
|
|||
}
|
||||
|
||||
int
|
||||
GVertex::in_circle (const DPoint &point, const DPoint ¢er, double radius)
|
||||
Vertex::in_circle (const DPoint &point, const DPoint ¢er, double radius)
|
||||
{
|
||||
double dx = point.x () - center.x ();
|
||||
double dy = point.y () - center.y ();
|
||||
|
|
@ -155,34 +162,34 @@ GVertex::in_circle (const DPoint &point, const DPoint ¢er, double radius)
|
|||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// GPolygonEdge implementation
|
||||
// Edge implementation
|
||||
|
||||
GPolygonEdge::GPolygonEdge ()
|
||||
: mp_v1 (0), mp_v2 (0), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false)
|
||||
Edge::Edge (Graph *graph)
|
||||
: mp_graph (graph), mp_v1 (0), mp_v2 (0), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
GPolygonEdge::GPolygonEdge (GVertex *v1, GVertex *v2)
|
||||
: mp_v1 (v1), mp_v2 (v2), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false)
|
||||
Edge::Edge (Graph *graph, Vertex *v1, Vertex *v2)
|
||||
: mp_graph (graph), mp_v1 (v1), mp_v2 (v2), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
GPolygonEdge::set_left (GPolygon *t)
|
||||
Edge::set_left (Polygon *t)
|
||||
{
|
||||
mp_left = t;
|
||||
}
|
||||
|
||||
void
|
||||
GPolygonEdge::set_right (GPolygon *t)
|
||||
Edge::set_right (Polygon *t)
|
||||
{
|
||||
mp_right = t;
|
||||
}
|
||||
|
||||
void
|
||||
GPolygonEdge::link ()
|
||||
Edge::link ()
|
||||
{
|
||||
mp_v1->mp_edges.push_back (this);
|
||||
m_ec_v1 = --mp_v1->mp_edges.end ();
|
||||
|
|
@ -192,7 +199,7 @@ GPolygonEdge::link ()
|
|||
}
|
||||
|
||||
void
|
||||
GPolygonEdge::unlink ()
|
||||
Edge::unlink ()
|
||||
{
|
||||
if (mp_v1) {
|
||||
mp_v1->remove_edge (m_ec_v1);
|
||||
|
|
@ -203,8 +210,8 @@ GPolygonEdge::unlink ()
|
|||
mp_v1 = mp_v2 = 0;
|
||||
}
|
||||
|
||||
GPolygon *
|
||||
GPolygonEdge::other (const GPolygon *t) const
|
||||
Polygon *
|
||||
Edge::other (const Polygon *t) const
|
||||
{
|
||||
if (t == mp_left) {
|
||||
return mp_right;
|
||||
|
|
@ -216,8 +223,8 @@ GPolygonEdge::other (const GPolygon *t) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
GVertex *
|
||||
GPolygonEdge::other (const GVertex *t) const
|
||||
Vertex *
|
||||
Edge::other (const Vertex *t) const
|
||||
{
|
||||
if (t == mp_v1) {
|
||||
return mp_v2;
|
||||
|
|
@ -230,13 +237,13 @@ GPolygonEdge::other (const GVertex *t) const
|
|||
}
|
||||
|
||||
bool
|
||||
GPolygonEdge::has_vertex (const GVertex *v) const
|
||||
Edge::has_vertex (const Vertex *v) const
|
||||
{
|
||||
return mp_v1 == v || mp_v2 == v;
|
||||
}
|
||||
|
||||
GVertex *
|
||||
GPolygonEdge::common_vertex (const GPolygonEdge *other) const
|
||||
Vertex *
|
||||
Edge::common_vertex (const Edge *other) const
|
||||
{
|
||||
if (has_vertex (other->v1 ())) {
|
||||
return (other->v1 ());
|
||||
|
|
@ -248,7 +255,7 @@ GPolygonEdge::common_vertex (const GPolygonEdge *other) const
|
|||
}
|
||||
|
||||
std::string
|
||||
GPolygonEdge::to_string (bool with_id) const
|
||||
Edge::to_string (bool with_id) const
|
||||
{
|
||||
std::string res = std::string ("(") + mp_v1->to_string (with_id) + ", " + mp_v2->to_string (with_id) + ")";
|
||||
if (with_id) {
|
||||
|
|
@ -258,7 +265,7 @@ GPolygonEdge::to_string (bool with_id) const
|
|||
}
|
||||
|
||||
double
|
||||
GPolygonEdge::distance (const db::DEdge &e, const db::DPoint &p)
|
||||
Edge::distance (const db::DEdge &e, const db::DPoint &p)
|
||||
{
|
||||
double l = db::sprod (p - e.p1 (), e.d ()) / e.d ().sq_length ();
|
||||
db::DPoint pp;
|
||||
|
|
@ -273,27 +280,27 @@ GPolygonEdge::distance (const db::DEdge &e, const db::DPoint &p)
|
|||
}
|
||||
|
||||
bool
|
||||
GPolygonEdge::crosses (const db::DEdge &e, const db::DEdge &other)
|
||||
Edge::crosses (const db::DEdge &e, const db::DEdge &other)
|
||||
{
|
||||
return e.side_of (other.p1 ()) * e.side_of (other.p2 ()) < 0 &&
|
||||
other.side_of (e.p1 ()) * other.side_of (e.p2 ()) < 0;
|
||||
}
|
||||
|
||||
bool
|
||||
GPolygonEdge::crosses_including (const db::DEdge &e, const db::DEdge &other)
|
||||
Edge::crosses_including (const db::DEdge &e, const db::DEdge &other)
|
||||
{
|
||||
return e.side_of (other.p1 ()) * e.side_of (other.p2 ()) <= 0 &&
|
||||
other.side_of (e.p1 ()) * other.side_of (e.p2 ()) <= 0;
|
||||
}
|
||||
|
||||
db::DPoint
|
||||
GPolygonEdge::intersection_point (const db::DEdge &e, const db::DEdge &other)
|
||||
Edge::intersection_point (const db::DEdge &e, const db::DEdge &other)
|
||||
{
|
||||
return e.intersect_point (other).second;
|
||||
}
|
||||
|
||||
bool
|
||||
GPolygonEdge::point_on (const db::DEdge &edge, const db::DPoint &point)
|
||||
Edge::point_on (const db::DEdge &edge, const db::DPoint &point)
|
||||
{
|
||||
if (edge.side_of (point) != 0) {
|
||||
return false;
|
||||
|
|
@ -302,42 +309,72 @@ GPolygonEdge::point_on (const db::DEdge &edge, const db::DPoint &point)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0 // @@@
|
||||
bool
|
||||
GPolygonEdge::is_for_outside_polygons () const
|
||||
Edge::can_flip () const
|
||||
{
|
||||
if (! left () || ! right ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Vertex *v1 = left ()->opposite (this);
|
||||
const Vertex *v2 = right ()->opposite (this);
|
||||
return crosses (db::DEdge (*v1, *v2));
|
||||
}
|
||||
|
||||
bool
|
||||
Edge::can_join_via (const Vertex *vertex) const
|
||||
{
|
||||
if (! left () || ! right ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tl_assert (has_vertex (vertex));
|
||||
const Vertex *v1 = left ()->opposite (this);
|
||||
const Vertex *v2 = right ()->opposite (this);
|
||||
return db::DEdge (*v1, *v2).side_of (*vertex) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Edge::is_outside () const
|
||||
{
|
||||
return left () == 0 || right () == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Edge::is_for_outside_triangles () const
|
||||
{
|
||||
return (left () && left ()->is_outside ()) || (right () && right ()->is_outside ());
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
GPolygonEdge::has_polygon (const GPolygon *t) const
|
||||
Edge::has_polygon (const Polygon *t) const
|
||||
{
|
||||
return t != 0 && (left () == t || right () == t);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// GPolygon implementation
|
||||
// Polygon implementation
|
||||
|
||||
GPolygon::GPolygon ()
|
||||
: m_id (0)
|
||||
Polygon::Polygon (Graph *graph)
|
||||
: mp_graph (graph), m_is_outside (false), m_id (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
GPolygon::init ()
|
||||
Polygon::init ()
|
||||
{
|
||||
m_id = 0;
|
||||
m_is_outside = false;
|
||||
|
||||
if (mp_e.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<GPolygonEdge *> e;
|
||||
std::vector<Edge *> e;
|
||||
e.swap (mp_e);
|
||||
|
||||
std::multimap<db::GVertex *, GPolygonEdge *> v2e;
|
||||
std::multimap<Vertex *, Edge *> v2e;
|
||||
|
||||
for (auto i = e.begin (); i != e.end (); ++i) {
|
||||
if (i != e.begin ()) {
|
||||
|
|
@ -379,7 +416,7 @@ GPolygon::init ()
|
|||
// establish clockwise order of the vertexes
|
||||
|
||||
double area = 0.0;
|
||||
const db::GVertex *vm1 = vertex (-1), *v0;
|
||||
const Vertex *vm1 = vertex (-1), *v0;
|
||||
for (auto i = mp_v.begin (); i != mp_v.end (); ++i) {
|
||||
v0 = *i;
|
||||
area += db::vprod (*vm1 - db::DPoint (), *v0 - *vm1);
|
||||
|
|
@ -394,8 +431,8 @@ GPolygon::init ()
|
|||
// link the polygon to the edges
|
||||
|
||||
for (size_t i = 0; i < size (); ++i) {
|
||||
db::GVertex *v = mp_v[i];
|
||||
db::GPolygonEdge *e = mp_e[i];
|
||||
Vertex *v = mp_v[i];
|
||||
Edge *e = mp_e[i];
|
||||
if (e->v1 () == v) {
|
||||
e->set_right (this);
|
||||
} else {
|
||||
|
|
@ -404,13 +441,62 @@ GPolygon::init ()
|
|||
}
|
||||
}
|
||||
|
||||
GPolygon::~GPolygon ()
|
||||
Polygon::Polygon (Graph *graph, Edge *e1, Edge *e2, Edge *e3)
|
||||
: mp_graph (graph), m_is_outside (false), m_id (0)
|
||||
{
|
||||
mp_e.resize (3, 0);
|
||||
mp_v.resize (3, 0);
|
||||
|
||||
mp_e[0] = e1;
|
||||
mp_v[0] = e1->v1 ();
|
||||
mp_v[1] = e1->v2 ();
|
||||
|
||||
if (e2->has_vertex (mp_v[1])) {
|
||||
mp_e[1] = e2;
|
||||
mp_e[2] = e3;
|
||||
} else {
|
||||
mp_e[1] = e3;
|
||||
mp_e[2] = e2;
|
||||
}
|
||||
mp_v[2] = mp_e[1]->other (mp_v[1]);
|
||||
|
||||
// enforce clockwise orientation
|
||||
int s = db::vprod_sign (*mp_v[2] - *mp_v[0], *mp_v[1] - *mp_v[0]);
|
||||
if (s < 0) {
|
||||
std::swap (mp_v[2], mp_v[1]);
|
||||
} else if (s == 0) {
|
||||
// Triangle is not orientable
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
// establish link to edges
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
|
||||
Edge *e = mp_e[i];
|
||||
|
||||
unsigned int i1 = 0;
|
||||
for ( ; e->v1 () != mp_v[i1] && i1 < 3; ++i1)
|
||||
;
|
||||
unsigned int i2 = 0;
|
||||
for ( ; e->v2 () != mp_v[i2] && i2 < 3; ++i2)
|
||||
;
|
||||
|
||||
if ((i1 + 1) % 3 == i2) {
|
||||
e->set_right (this);
|
||||
} else {
|
||||
e->set_left (this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Polygon::~Polygon ()
|
||||
{
|
||||
unlink ();
|
||||
}
|
||||
|
||||
void
|
||||
GPolygon::unlink ()
|
||||
Polygon::unlink ()
|
||||
{
|
||||
for (auto e = mp_e.begin (); e != mp_e.end (); ++e) {
|
||||
if ((*e)->left () == this) {
|
||||
|
|
@ -423,7 +509,7 @@ GPolygon::unlink ()
|
|||
}
|
||||
|
||||
std::string
|
||||
GPolygon::to_string (bool with_id) const
|
||||
Polygon::to_string (bool with_id) const
|
||||
{
|
||||
std::string res = "(";
|
||||
for (int i = 0; i < int (size ()); ++i) {
|
||||
|
|
@ -441,13 +527,13 @@ GPolygon::to_string (bool with_id) const
|
|||
}
|
||||
|
||||
double
|
||||
GPolygon::area () const
|
||||
Polygon::area () const
|
||||
{
|
||||
return fabs (db::vprod (mp_e[0]->d (), mp_e[1]->d ())) * 0.5;
|
||||
}
|
||||
|
||||
db::DBox
|
||||
GPolygon::bbox () const
|
||||
Polygon::bbox () const
|
||||
{
|
||||
db::DBox box;
|
||||
for (auto i = mp_v.begin (); i != mp_v.end (); ++i) {
|
||||
|
|
@ -456,8 +542,77 @@ GPolygon::bbox () const
|
|||
return box;
|
||||
}
|
||||
|
||||
GPolygonEdge *
|
||||
GPolygon::find_edge_with (const GVertex *v1, const GVertex *v2) const
|
||||
std::pair<db::DPoint, double>
|
||||
Polygon::circumcircle (bool *ok) const
|
||||
{
|
||||
tl_assert (mp_v.size () == 3);
|
||||
|
||||
// see https://en.wikipedia.org/wiki/Circumcircle
|
||||
// we set A=(0,0), so the formulas simplify
|
||||
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
|
||||
db::DVector b = *mp_v[1] - *mp_v[0];
|
||||
db::DVector c = *mp_v[2] - *mp_v[0];
|
||||
|
||||
double b2 = b.sq_length ();
|
||||
double c2 = c.sq_length ();
|
||||
|
||||
double sx = 0.5 * (b2 * c.y () - c2 * b.y ());
|
||||
double sy = 0.5 * (b.x () * c2 - c.x() * b2);
|
||||
|
||||
double a1 = b.x() * c.y();
|
||||
double a2 = c.x() * b.y();
|
||||
double a = a1 - a2;
|
||||
double a_abs = std::abs (a);
|
||||
|
||||
if (a_abs < (std::abs (a1) + std::abs (a2)) * db::epsilon) {
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
return std::make_pair (db::DPoint (), 0.0);
|
||||
} else {
|
||||
tl_assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
double radius = sqrt (sx * sx + sy * sy) / a_abs;
|
||||
db::DPoint center = *mp_v[0] + db::DVector (sx / a, sy / a);
|
||||
|
||||
return std::make_pair (center, radius);
|
||||
}
|
||||
|
||||
Vertex *
|
||||
Polygon::opposite (const Edge *edge) const
|
||||
{
|
||||
tl_assert (mp_v.size () == 3);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
Vertex *v = mp_v[i];
|
||||
if (! edge->has_vertex (v)) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
Edge *
|
||||
Polygon::opposite (const Vertex *vertex) const
|
||||
{
|
||||
tl_assert (mp_v.size () == 3);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
Edge *e = mp_e[i];
|
||||
if (! e->has_vertex (vertex)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
Edge *
|
||||
Polygon::find_edge_with (const Vertex *v1, const Vertex *v2) const
|
||||
{
|
||||
for (auto e = mp_e.begin (); e != mp_e.end (); ++e) {
|
||||
if ((*e)->has_vertex (v1) && (*e)->has_vertex (v2)) {
|
||||
|
|
@ -467,8 +622,8 @@ GPolygon::find_edge_with (const GVertex *v1, const GVertex *v2) const
|
|||
tl_assert (false);
|
||||
}
|
||||
|
||||
GPolygonEdge *
|
||||
GPolygon::common_edge (const GPolygon *other) const
|
||||
Edge *
|
||||
Polygon::common_edge (const Polygon *other) const
|
||||
{
|
||||
for (auto e = mp_e.begin (); e != mp_e.end (); ++e) {
|
||||
if ((*e)->other (this) == other) {
|
||||
|
|
@ -478,10 +633,11 @@ GPolygon::common_edge (const GPolygon *other) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if 0 // @@@
|
||||
int
|
||||
GPolygon::contains (const db::DPoint &point) const
|
||||
Polygon::contains (const db::DPoint &point) const
|
||||
{
|
||||
tl_assert (mp_v.size () == 3);
|
||||
|
||||
auto c = *mp_v[2] - *mp_v[0];
|
||||
auto b = *mp_v[1] - *mp_v[0];
|
||||
|
||||
|
|
@ -492,9 +648,9 @@ GPolygon::contains (const db::DPoint &point) const
|
|||
|
||||
int res = 1;
|
||||
|
||||
const GVertex *vl = mp_v[2];
|
||||
const Vertex *vl = mp_v[2];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const GVertex *v = mp_v[i];
|
||||
const Vertex *v = mp_v[i];
|
||||
int n = db::vprod_sign (point - *vl, *v - *vl) * vps;
|
||||
if (n < 0) {
|
||||
return -1;
|
||||
|
|
@ -506,10 +662,9 @@ GPolygon::contains (const db::DPoint &point) const
|
|||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
double
|
||||
GPolygon::min_edge_length () const
|
||||
Polygon::min_edge_length () const
|
||||
{
|
||||
double lmin = mp_e[0]->d ().length ();
|
||||
for (auto e = mp_e.begin (); e != mp_e.end (); ++e) {
|
||||
|
|
@ -518,19 +673,17 @@ GPolygon::min_edge_length () const
|
|||
return lmin;
|
||||
}
|
||||
|
||||
#if 0 // @@@
|
||||
double
|
||||
GPolygon::b () const
|
||||
Polygon::b () const
|
||||
{
|
||||
double lmin = min_edge_length ();
|
||||
bool ok = false;
|
||||
auto cr = circumcircle (&ok);
|
||||
return ok ? lmin / cr.second : 0.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
GPolygon::has_segment () const
|
||||
Polygon::has_segment () const
|
||||
{
|
||||
for (auto e = mp_e.begin (); e != mp_e.end (); ++e) {
|
||||
if ((*e)->is_segment ()) {
|
||||
|
|
@ -541,7 +694,7 @@ GPolygon::has_segment () const
|
|||
}
|
||||
|
||||
unsigned int
|
||||
GPolygon::num_segments () const
|
||||
Polygon::num_segments () const
|
||||
{
|
||||
unsigned int n = 0;
|
||||
for (auto e = mp_e.begin (); e != mp_e.end (); ++e) {
|
||||
|
|
@ -554,49 +707,42 @@ GPolygon::num_segments () const
|
|||
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
||||
static inline bool is_equal (const db::DPoint &a, const db::DPoint &b)
|
||||
{
|
||||
return std::abs (a.x () - b.x ()) < std::max (1.0, (std::abs (a.x ()) + std::abs (b.x ()))) * db::epsilon &&
|
||||
std::abs (a.y () - b.y ()) < std::max (1.0, (std::abs (a.y ()) + std::abs (b.y ()))) * db::epsilon;
|
||||
}
|
||||
|
||||
PolygonGraph::PolygonGraph ()
|
||||
Graph::Graph ()
|
||||
: m_id (0)
|
||||
// @@@: m_is_constrained (false), m_level (0), m_id (0), m_flips (0), m_hops (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
PolygonGraph::~PolygonGraph ()
|
||||
Graph::~Graph ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
db::GVertex *
|
||||
PolygonGraph::create_vertex (double x, double y)
|
||||
Vertex *
|
||||
Graph::create_vertex (double x, double y)
|
||||
{
|
||||
m_vertex_heap.push_back (db::GVertex (x, y));
|
||||
m_vertex_heap.push_back (Vertex (this, x, y));
|
||||
return &m_vertex_heap.back ();
|
||||
}
|
||||
|
||||
db::GVertex *
|
||||
PolygonGraph::create_vertex (const db::DPoint &pt)
|
||||
Vertex *
|
||||
Graph::create_vertex (const db::DPoint &pt)
|
||||
{
|
||||
m_vertex_heap.push_back (pt);
|
||||
m_vertex_heap.push_back (Vertex (this, pt));
|
||||
return &m_vertex_heap.back ();
|
||||
}
|
||||
|
||||
db::GPolygonEdge *
|
||||
PolygonGraph::create_edge (db::GVertex *v1, db::GVertex *v2)
|
||||
Edge *
|
||||
Graph::create_edge (Vertex *v1, Vertex *v2)
|
||||
{
|
||||
db::GPolygonEdge *edge = 0;
|
||||
Edge *edge = 0;
|
||||
|
||||
if (! m_returned_edges.empty ()) {
|
||||
edge = m_returned_edges.back ();
|
||||
m_returned_edges.pop_back ();
|
||||
*edge = db::GPolygonEdge (v1, v2);
|
||||
*edge = Edge (this, v1, v2);
|
||||
} else {
|
||||
m_edges_heap.push_back (db::GPolygonEdge (v1, v2));
|
||||
m_edges_heap.push_back (Edge (this, v1, v2));
|
||||
edge = &m_edges_heap.back ();
|
||||
}
|
||||
|
||||
|
|
@ -605,11 +751,21 @@ PolygonGraph::create_edge (db::GVertex *v1, db::GVertex *v2)
|
|||
return edge;
|
||||
}
|
||||
|
||||
void
|
||||
PolygonGraph::remove_polygon (db::GPolygon *poly)
|
||||
Polygon *
|
||||
Graph::create_triangle (Edge *e1, Edge *e2, Edge *e3)
|
||||
{
|
||||
std::vector<db::GPolygonEdge *> edges;
|
||||
edges.reserve (poly->size ());
|
||||
Polygon *res = new Polygon (this, e1, e2, e3);
|
||||
res->set_id (++m_id);
|
||||
mp_polygons.push_back (res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
Graph::remove_polygon (Polygon *poly)
|
||||
{
|
||||
std::vector<Edge *> edges;
|
||||
edges.resize (poly->size (), 0);
|
||||
for (int i = 0; i < int (poly->size ()); ++i) {
|
||||
edges [i] = poly->edge (i);
|
||||
}
|
||||
|
|
@ -625,63 +781,8 @@ PolygonGraph::remove_polygon (db::GPolygon *poly)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0 // @@@
|
||||
void
|
||||
PolygonGraph::convex_decompose (const db::DPolygon &polygon)
|
||||
{
|
||||
clear ();
|
||||
|
||||
if (polygon.begin_edge ().at_end ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<db::GPolygonEdge *> edges;
|
||||
|
||||
for (unsigned int c = 0; c < polygon.holes () + 1; ++c) {
|
||||
|
||||
const db::DSimplePolygon::contour_type &ctr = polygon.contour (c);
|
||||
|
||||
db::GVertex *v0 = 0, *vv, *v;
|
||||
size_t n = ctr.size ();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
|
||||
db::DPoint pm1 = ctr [i > 0 ? i - 1 : n - 1];
|
||||
db::DPoint pp1 = ctr [i + 1 < n ? i + 1 : 0];
|
||||
db::DPoint p = ctr [i];
|
||||
|
||||
bool is_convex = db::vprod_sign (p - pm1, pp1 - p);
|
||||
// @@@
|
||||
|
||||
v = create_vertex (p.x (), p.y ());
|
||||
if (! v0) {
|
||||
v0 = v;
|
||||
} else {
|
||||
edges.push_back (create_edge (vv, v));
|
||||
}
|
||||
|
||||
vv = v;
|
||||
|
||||
}
|
||||
|
||||
if (v0 && v0 != v) {
|
||||
edges.push_back (create_edge (v, v0));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
PolygonGraph::convex_decompose (const db::DPolygon &poly)
|
||||
{
|
||||
|
||||
// @@@
|
||||
|
||||
|
||||
}
|
||||
|
||||
std::string
|
||||
PolygonGraph::to_string ()
|
||||
Graph::to_string ()
|
||||
{
|
||||
std::string res;
|
||||
for (auto t = mp_polygons.begin (); t != mp_polygons.end (); ++t) {
|
||||
|
|
@ -694,7 +795,7 @@ PolygonGraph::to_string ()
|
|||
}
|
||||
|
||||
db::DBox
|
||||
PolygonGraph::bbox () const
|
||||
Graph::bbox () const
|
||||
{
|
||||
db::DBox box;
|
||||
for (auto t = mp_polygons.begin (); t != mp_polygons.end (); ++t) {
|
||||
|
|
@ -705,7 +806,7 @@ PolygonGraph::bbox () const
|
|||
|
||||
#if 0 // @@@
|
||||
bool
|
||||
PolygonGraph::check (bool check_delaunay) const
|
||||
Graph::check (bool check_delaunay) const
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
|
|
@ -759,7 +860,7 @@ PolygonGraph::check (bool check_delaunay) const
|
|||
tl::error << "(check error) edges " << e->to_string (true) << " vertex 2 not found in adjacent polygon " << t->to_string (true);
|
||||
res = false;
|
||||
}
|
||||
db::GVertex *vopp = t->opposite (e.operator-> ());
|
||||
Vertex *vopp = t->opposite (e.operator-> ());
|
||||
double sgn = (e->left () == t.operator-> ()) ? 1.0 : -1.0;
|
||||
double vp = db::vprod (e->d(), *vopp - *e->v1 ()); // positive if on left side
|
||||
if (vp * sgn <= 0.0) {
|
||||
|
|
@ -803,7 +904,7 @@ PolygonGraph::check (bool check_delaunay) const
|
|||
#endif
|
||||
|
||||
db::Layout *
|
||||
PolygonGraph::to_layout (bool decompose_by_id) const
|
||||
Graph::to_layout (bool decompose_by_id) const
|
||||
{
|
||||
db::Layout *layout = new db::Layout ();
|
||||
layout->dbu (0.001);
|
||||
|
|
@ -850,7 +951,7 @@ PolygonGraph::to_layout (bool decompose_by_id) const
|
|||
}
|
||||
|
||||
void
|
||||
PolygonGraph::dump (const std::string &path, bool decompose_by_id) const
|
||||
Graph::dump (const std::string &path, bool decompose_by_id) const
|
||||
{
|
||||
std::unique_ptr<db::Layout> ly (to_layout (decompose_by_id));
|
||||
|
||||
|
|
@ -860,36 +961,19 @@ PolygonGraph::dump (const std::string &path, bool decompose_by_id) const
|
|||
db::Writer writer (opt);
|
||||
writer.write (*ly, stream);
|
||||
|
||||
tl::info << "PolygonGraph written to " << path;
|
||||
tl::info << "Graph written to " << path;
|
||||
}
|
||||
|
||||
void
|
||||
PolygonGraph::clear ()
|
||||
Graph::clear ()
|
||||
{
|
||||
mp_polygons.clear ();
|
||||
m_edges_heap.clear ();
|
||||
m_vertex_heap.clear ();
|
||||
m_returned_edges.clear ();
|
||||
// @@@m_is_constrained = false;
|
||||
// @@@m_level = 0;
|
||||
m_id = 0;
|
||||
}
|
||||
|
||||
template<class Poly, class Trans>
|
||||
void
|
||||
PolygonGraph::make_contours (const Poly &poly, const Trans &trans, std::vector<std::vector<db::GVertex *> > &edge_contours)
|
||||
{
|
||||
edge_contours.push_back (std::vector<db::GVertex *> ());
|
||||
for (auto pt = poly.begin_hull (); pt != poly.end_hull (); ++pt) {
|
||||
edge_contours.back ().push_back (insert_point (trans * *pt));
|
||||
}
|
||||
} // namespace plc
|
||||
|
||||
for (unsigned int h = 0; h < poly.holes (); ++h) {
|
||||
edge_contours.push_back (std::vector<db::GVertex *> ());
|
||||
for (auto pt = poly.begin_hole (h); pt != poly.end_hole (h); ++pt) {
|
||||
edge_contours.back ().push_back (insert_point (trans * *pt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace db
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
|
||||
*/
|
||||
|
||||
#ifndef HDR_dbPolygonGraph
|
||||
#define HDR_dbPolygonGraph
|
||||
#ifndef HDR_dbPLC
|
||||
#define HDR_dbPLC
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbTriangle.h"
|
||||
|
|
@ -41,8 +41,38 @@ namespace db
|
|||
|
||||
class Layout;
|
||||
|
||||
class GPolygon;
|
||||
class GPolygonEdge;
|
||||
namespace plc
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A framework for piecewise linear curves
|
||||
*
|
||||
* This framework implements classes for dealing with piecewise linear
|
||||
* curves. It is the basis for triangulation and polygon decomposition
|
||||
* algorithms.
|
||||
*
|
||||
* The core class is the PLCGraph which is a collection of vertices,
|
||||
* edges and edge loops (polygons). Vertices, edges and polygons form
|
||||
* graphs.
|
||||
*
|
||||
* A "vertex" (db::plc::Vertex) is a point. A point connects two or
|
||||
* more edges.
|
||||
* A vertex has some attributes:
|
||||
* * 'precious': if set, the vertex is not removed during triangulation
|
||||
* for example.
|
||||
*
|
||||
* An "edge" (db::plc::Edge) is a line connecting two vertexes. The
|
||||
* edge runs from vertex v1 to vertex v2. An edge separates two
|
||||
* polygons (left and right, as seen in the run direction).
|
||||
*
|
||||
* A "segment" as an edge that is part of an original polygon outline.
|
||||
*
|
||||
* A "polygon" (db::plc::Polygon) is a loop of edges.
|
||||
*/
|
||||
|
||||
class Polygon;
|
||||
class Edge;
|
||||
class Graph;
|
||||
|
||||
/**
|
||||
* @brief A class representing a vertex in a Delaunay triangulation graph
|
||||
|
|
@ -51,40 +81,71 @@ class GPolygonEdge;
|
|||
* an integer value that can be used in traversal algorithms
|
||||
* ("level")
|
||||
*/
|
||||
class DB_PUBLIC GVertex
|
||||
class DB_PUBLIC Vertex
|
||||
: public db::DPoint
|
||||
{
|
||||
public:
|
||||
typedef std::list<GPolygonEdge *> edges_type;
|
||||
typedef std::list<Edge *> edges_type;
|
||||
typedef edges_type::const_iterator edges_iterator;
|
||||
typedef edges_type::iterator edges_iterator_non_const;
|
||||
|
||||
GVertex ();
|
||||
GVertex (const DPoint &p);
|
||||
GVertex (const GVertex &v);
|
||||
GVertex (db::DCoord x, db::DCoord y);
|
||||
Vertex (const Vertex &v);
|
||||
Vertex &operator= (const Vertex &v);
|
||||
|
||||
GVertex &operator= (const GVertex &v);
|
||||
|
||||
#if 0 // @@@
|
||||
/**
|
||||
* @brief Gets a value indicating whether any of the attached edges is "outside"
|
||||
*/
|
||||
bool is_outside () const;
|
||||
#endif
|
||||
std::vector<db::GPolygon *> polygons () const;
|
||||
|
||||
/**
|
||||
* @brief Gets a list of polygons that are attached to this vertex
|
||||
*/
|
||||
std::vector<Polygon *> polygons() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the graph object this vertex belongs to
|
||||
*/
|
||||
Graph *graph () const { return mp_graph; }
|
||||
|
||||
/**
|
||||
* @brief Iterates the edges on this vertex (begin)
|
||||
*/
|
||||
edges_iterator begin_edges () const { return mp_edges.begin (); }
|
||||
|
||||
/**
|
||||
* @brief Iterates the edges on this vertex (end)
|
||||
*/
|
||||
edges_iterator end_edges () const { return mp_edges.end (); }
|
||||
|
||||
/**
|
||||
* @brief Returns the number of edges attached to this vertex
|
||||
*/
|
||||
size_t num_edges (int max_count = -1) const;
|
||||
|
||||
bool has_edge (const GPolygonEdge *edge) const;
|
||||
/**
|
||||
* @brief Returns a value indicating whether the given edge is attached to this vertex
|
||||
*/
|
||||
bool has_edge (const Edge *edge) const;
|
||||
|
||||
/**
|
||||
* @brief Sets a valid indicating whether the vertex is precious
|
||||
*
|
||||
* "precious" vertexes are not removed during triangulation for example.
|
||||
*/
|
||||
void set_is_precious (bool f) { m_is_precious = f; }
|
||||
|
||||
/**
|
||||
* @brief Gets a valid indicating whether the vertex is precious
|
||||
*/
|
||||
bool is_precious () const { return m_is_precious; }
|
||||
|
||||
/**
|
||||
* @brief Returns a string representation of the vertex
|
||||
*/
|
||||
std::string to_string (bool with_id = false) const;
|
||||
|
||||
/**
|
||||
* @brief Returns 1 is the point is inside the circle, 0 if on the circle and -1 if outside
|
||||
* TODO: Move to db::DPoint
|
||||
*/
|
||||
static int in_circle (const db::DPoint &point, const db::DPoint ¢er, double radius);
|
||||
|
||||
|
|
@ -97,13 +158,20 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
friend class GPolygonEdge;
|
||||
friend class Edge;
|
||||
friend class Graph;
|
||||
|
||||
Vertex (Graph *graph);
|
||||
Vertex (Graph *graph, const DPoint &p);
|
||||
Vertex (Graph *graph, const Vertex &v);
|
||||
Vertex (Graph *graph, db::DCoord x, db::DCoord y);
|
||||
|
||||
void remove_edge (const edges_iterator_non_const &ec)
|
||||
{
|
||||
mp_edges.erase (ec);
|
||||
}
|
||||
|
||||
Graph *mp_graph;
|
||||
edges_type mp_edges;
|
||||
bool m_is_precious;
|
||||
};
|
||||
|
|
@ -111,15 +179,15 @@ private:
|
|||
/**
|
||||
* @brief A class representing an edge in the Delaunay triangulation graph
|
||||
*/
|
||||
class DB_PUBLIC GPolygonEdge
|
||||
class DB_PUBLIC Edge
|
||||
{
|
||||
public:
|
||||
class GPolygonIterator
|
||||
class PolygonIterator
|
||||
{
|
||||
public:
|
||||
typedef GPolygon value_type;
|
||||
typedef GPolygon &reference;
|
||||
typedef GPolygon *pointer;
|
||||
typedef Polygon value_type;
|
||||
typedef Polygon &reference;
|
||||
typedef Polygon *pointer;
|
||||
|
||||
reference operator*() const
|
||||
{
|
||||
|
|
@ -131,17 +199,17 @@ public:
|
|||
return m_index ? mp_edge->right () : mp_edge->left ();
|
||||
}
|
||||
|
||||
bool operator== (const GPolygonIterator &other) const
|
||||
bool operator== (const PolygonIterator &other) const
|
||||
{
|
||||
return m_index == other.m_index;
|
||||
}
|
||||
|
||||
bool operator!= (const GPolygonIterator &other) const
|
||||
bool operator!= (const PolygonIterator &other) const
|
||||
{
|
||||
return !operator== (other);
|
||||
}
|
||||
|
||||
GPolygonIterator &operator++ ()
|
||||
PolygonIterator &operator++ ()
|
||||
{
|
||||
while (++m_index < 2 && operator-> () == 0)
|
||||
;
|
||||
|
|
@ -149,9 +217,9 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
friend class GPolygonEdge;
|
||||
friend class Edge;
|
||||
|
||||
GPolygonIterator (const GPolygonEdge *edge)
|
||||
PolygonIterator (const Edge *edge)
|
||||
: mp_edge (edge), m_index (0)
|
||||
{
|
||||
if (! edge) {
|
||||
|
|
@ -162,48 +230,72 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const GPolygonEdge *mp_edge;
|
||||
const Edge *mp_edge;
|
||||
unsigned int m_index;
|
||||
};
|
||||
|
||||
GPolygonEdge ();
|
||||
GPolygonEdge (GVertex *v1, GVertex *v2);
|
||||
/**
|
||||
* @brief Gets the first vertex ("from")
|
||||
*/
|
||||
Vertex *v1 () const { return mp_v1; }
|
||||
|
||||
GVertex *v1 () const { return mp_v1; }
|
||||
GVertex *v2 () const { return mp_v2; }
|
||||
/**
|
||||
* @brief Gets the first vertex ("to")
|
||||
*/
|
||||
Vertex *v2 () const { return mp_v2; }
|
||||
|
||||
/**
|
||||
* @brief Reverses the edge
|
||||
*/
|
||||
void reverse ()
|
||||
{
|
||||
std::swap (mp_v1, mp_v2);
|
||||
std::swap (mp_left, mp_right);
|
||||
}
|
||||
|
||||
GPolygon *left () const { return mp_left; }
|
||||
GPolygon *right () const { return mp_right; }
|
||||
/**
|
||||
* @brief Gets the polygon on the left side (can be null)
|
||||
*/
|
||||
Polygon *left () const { return mp_left; }
|
||||
|
||||
GPolygonIterator begin_polygons () const
|
||||
/**
|
||||
* @brief Gets the polygon on the right side (can be null)
|
||||
*/
|
||||
Polygon *right () const { return mp_right; }
|
||||
|
||||
/**
|
||||
* @brief Iterates the polygons (one or two, begin iterator)
|
||||
*/
|
||||
PolygonIterator begin_polygons () const
|
||||
{
|
||||
return GPolygonIterator (this);
|
||||
return PolygonIterator (this);
|
||||
}
|
||||
|
||||
GPolygonIterator end_polygons () const
|
||||
/**
|
||||
* @brief Iterates the polygons (end iterator)
|
||||
*/
|
||||
PolygonIterator end_polygons () const
|
||||
{
|
||||
return GPolygonIterator (0);
|
||||
return PolygonIterator (0);
|
||||
}
|
||||
|
||||
void set_level (size_t l) { m_level = l; }
|
||||
size_t level () const { return m_level; }
|
||||
|
||||
void set_id (size_t id) { m_id = id; }
|
||||
size_t id () const { return m_id; }
|
||||
|
||||
void set_is_segment (bool is_seg) { m_is_segment = is_seg; }
|
||||
/**
|
||||
* @brief Gets a value indicating whether the edge is a segment
|
||||
*/
|
||||
bool is_segment () const { return m_is_segment; }
|
||||
|
||||
/**
|
||||
* @brief Gets the edge ID (a unique identifier)
|
||||
*/
|
||||
size_t id () const { return m_id; }
|
||||
|
||||
/**
|
||||
* @brief Gets a string representation of the edge
|
||||
*/
|
||||
std::string to_string (bool with_id = false) const;
|
||||
|
||||
/**
|
||||
* @brief Converts to an db::DEdge
|
||||
* @brief Converts to a db::DEdge
|
||||
*/
|
||||
db::DEdge edge () const
|
||||
{
|
||||
|
|
@ -254,7 +346,7 @@ public:
|
|||
* "crosses" is true, if both edges share at least one point which is not an endpoint
|
||||
* of one of the edges.
|
||||
*/
|
||||
bool crosses (const db::GPolygonEdge &other) const
|
||||
bool crosses (const Edge &other) const
|
||||
{
|
||||
return crosses (edge (), other.edge ());
|
||||
}
|
||||
|
|
@ -279,7 +371,7 @@ public:
|
|||
* @brief Returns a value indicating whether this edge crosses the other one
|
||||
* "crosses" is true, if both edges share at least one point.
|
||||
*/
|
||||
bool crosses_including (const db::GPolygonEdge &other) const
|
||||
bool crosses_including (const Edge &other) const
|
||||
{
|
||||
return crosses_including (edge (), other.edge ());
|
||||
}
|
||||
|
|
@ -301,7 +393,7 @@ public:
|
|||
/**
|
||||
* @brief Gets the intersection point
|
||||
*/
|
||||
db::DPoint intersection_point (const GPolygonEdge &other) const
|
||||
db::DPoint intersection_point (const Edge &other) const
|
||||
{
|
||||
return intersection_point (edge (), other.edge ());
|
||||
}
|
||||
|
|
@ -353,24 +445,23 @@ public:
|
|||
/**
|
||||
* @brief Gets the other triangle for the given one
|
||||
*/
|
||||
GPolygon *other (const GPolygon *) const;
|
||||
Polygon *other (const Polygon *) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the other vertex for the given one
|
||||
*/
|
||||
GVertex *other (const GVertex *) const;
|
||||
Vertex *other (const Vertex *) const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the edge has the given vertex
|
||||
*/
|
||||
bool has_vertex (const GVertex *) const;
|
||||
bool has_vertex (const Vertex *) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the common vertex of the other edge and this edge or null if there is no common vertex
|
||||
*/
|
||||
GVertex *common_vertex (const GPolygonEdge *other) const;
|
||||
Vertex *common_vertex (const Edge *other) const;
|
||||
|
||||
#if 0 // @@@
|
||||
/**
|
||||
* @brief Returns a value indicating whether this edge can be flipped
|
||||
*/
|
||||
|
|
@ -379,81 +470,93 @@ public:
|
|||
/**
|
||||
* @brief Returns a value indicating whether the edge separates two triangles that can be joined into one (via the given vertex)
|
||||
*/
|
||||
bool can_join_via (const GVertex *vertex) const;
|
||||
bool can_join_via (const Vertex *vertex) const;
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether this edge belongs to outside triangles
|
||||
*/
|
||||
bool is_for_outside_triangles () const;
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether this edge is an outside edge (no other triangles)
|
||||
*/
|
||||
bool is_outside () const;
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether this edge belongs to outside triangles
|
||||
*/
|
||||
bool is_for_outside_triangles () const;
|
||||
#endif // @@@
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether t is attached to this edge
|
||||
*/
|
||||
bool has_polygon (const GPolygon *t) const;
|
||||
bool has_polygon (const Polygon *t) const;
|
||||
|
||||
protected:
|
||||
void unlink ();
|
||||
void link ();
|
||||
|
||||
private:
|
||||
friend class GPolygon;
|
||||
friend class PolygonGraph;
|
||||
friend class Polygon;
|
||||
friend class Graph;
|
||||
friend class Triangulation;
|
||||
|
||||
GVertex *mp_v1, *mp_v2;
|
||||
GPolygon *mp_left, *mp_right;
|
||||
GVertex::edges_iterator_non_const m_ec_v1, m_ec_v2;
|
||||
void set_level (size_t l) { m_level = l; }
|
||||
size_t level () const { return m_level; }
|
||||
|
||||
void set_id (size_t id) { m_id = id; }
|
||||
|
||||
void set_is_segment (bool is_seg) { m_is_segment = is_seg; }
|
||||
|
||||
Edge (Graph *graph);
|
||||
Edge (Graph *graph, Vertex *v1, Vertex *v2);
|
||||
|
||||
Graph *mp_graph;
|
||||
Vertex *mp_v1, *mp_v2;
|
||||
Polygon *mp_left, *mp_right;
|
||||
Vertex::edges_iterator_non_const m_ec_v1, m_ec_v2;
|
||||
size_t m_level;
|
||||
size_t m_id;
|
||||
bool m_is_segment;
|
||||
|
||||
void set_left (GPolygon *t);
|
||||
void set_right (GPolygon *t);
|
||||
void set_left (Polygon *t);
|
||||
void set_right (Polygon *t);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A compare function that compares triangles by ID
|
||||
* @brief A compare function that compares edges by ID
|
||||
*
|
||||
* The ID acts as a more predicable unique ID for the object in sets and maps.
|
||||
*/
|
||||
struct GPolygonEdgeLessFunc
|
||||
struct EdgeLessFunc
|
||||
{
|
||||
bool operator () (GPolygonEdge *a, GPolygonEdge *b) const
|
||||
bool operator () (Edge *a, Edge *b) const
|
||||
{
|
||||
return a->id () < b->id ();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class representing a triangle
|
||||
* @brief A class representing a polygon
|
||||
*/
|
||||
class DB_PUBLIC GPolygon
|
||||
: public tl::list_node<GPolygon>, public tl::Object
|
||||
class DB_PUBLIC Polygon
|
||||
: public tl::list_node<Polygon>, public tl::Object
|
||||
{
|
||||
public:
|
||||
GPolygon ();
|
||||
Polygon (Graph *graph);
|
||||
Polygon (Graph *graph, Edge *e1, Edge *e2, Edge *e3);
|
||||
|
||||
template<class Iter>
|
||||
GPolygon (Iter from, Iter to)
|
||||
: mp_e (from, to)
|
||||
Polygon (Graph *graph, Iter from, Iter to)
|
||||
: mp_graph (graph), mp_e (from, to)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
~GPolygon ();
|
||||
~Polygon ();
|
||||
|
||||
void unlink ();
|
||||
|
||||
void set_id (size_t id) { m_id = id; }
|
||||
size_t id () const { return m_id; }
|
||||
|
||||
// @@@bool is_outside () const { return m_is_outside; }
|
||||
// @@@void set_outside (bool o) { m_is_outside = o; }
|
||||
bool is_outside () const { return m_is_outside; }
|
||||
void set_outside (bool o) { m_is_outside = o; }
|
||||
|
||||
std::string to_string (bool with_id = false) const;
|
||||
|
||||
|
|
@ -469,7 +572,7 @@ public:
|
|||
* @brief Gets the nth vertex (n wraps around and can be negative)
|
||||
* The vertexes are oriented clockwise.
|
||||
*/
|
||||
inline GVertex *vertex (int n) const
|
||||
inline Vertex *vertex (int n) const
|
||||
{
|
||||
size_t sz = size ();
|
||||
tl_assert (sz > 0);
|
||||
|
|
@ -483,7 +586,7 @@ public:
|
|||
/**
|
||||
* @brief Gets the nth edge (n wraps around and can be negative)
|
||||
*/
|
||||
inline GPolygonEdge *edge (int n) const
|
||||
inline Edge *edge (int n) const
|
||||
{
|
||||
size_t sz = size ();
|
||||
tl_assert (sz > 0);
|
||||
|
|
@ -504,46 +607,50 @@ public:
|
|||
*/
|
||||
db::DBox bbox () const;
|
||||
|
||||
#if 0 // @@@
|
||||
/**
|
||||
* @brief Gets the center point and radius of the circumcircle
|
||||
* If ok is non-null, it will receive a boolean value indicating whether the circumcircle is valid.
|
||||
* An invalid circumcircle is an indicator for a degenerated triangle with area 0 (or close to).
|
||||
*
|
||||
* This method only applies to triangles.
|
||||
*/
|
||||
std::pair<db::DPoint, double> circumcircle (bool *ok = 0) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the vertex opposite of the given edge
|
||||
*
|
||||
* This method only applies to triangles.
|
||||
*/
|
||||
GVertex *opposite (const GPolygonEdge *edge) const;
|
||||
Vertex *opposite (const Edge *edge) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the edge opposite of the given vertex
|
||||
*
|
||||
* This method only applies to triangles.
|
||||
*/
|
||||
GPolygonEdge *opposite (const GVertex *vertex) const;
|
||||
#endif
|
||||
Edge *opposite (const Vertex *vertex) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the edge with the given vertexes
|
||||
*/
|
||||
GPolygonEdge *find_edge_with (const GVertex *v1, const GVertex *v2) const;
|
||||
Edge *find_edge_with (const Vertex *v1, const Vertex *v2) const;
|
||||
|
||||
/**
|
||||
* @brief Finds the common edge for both polygons
|
||||
*/
|
||||
GPolygonEdge *common_edge (const GPolygon *other) const;
|
||||
Edge *common_edge (const Polygon *other) const;
|
||||
|
||||
#if 0 // @@@
|
||||
/**
|
||||
* @brief Returns a value indicating whether the point is inside (1), on the polygon (0) or outside (-1)
|
||||
*
|
||||
* This method only applies to triangles currently.
|
||||
*/
|
||||
int contains (const db::DPoint &point) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the triangle has the given vertex
|
||||
*/
|
||||
inline bool has_vertex (const db::GVertex *v) const
|
||||
inline bool has_vertex (const Vertex *v) const
|
||||
{
|
||||
for (auto i = mp_v.begin (); i != mp_v.end (); ++i) {
|
||||
if (*i == v) {
|
||||
|
|
@ -556,7 +663,7 @@ public:
|
|||
/**
|
||||
* @brief Gets a value indicating whether the triangle has the given edge
|
||||
*/
|
||||
inline bool has_edge (const db::GPolygonEdge *e) const
|
||||
inline bool has_edge (const Edge *e) const
|
||||
{
|
||||
for (auto i = mp_e.begin (); i != mp_e.end (); ++i) {
|
||||
if (*i == e) {
|
||||
|
|
@ -571,12 +678,12 @@ public:
|
|||
*/
|
||||
double min_edge_length () const;
|
||||
|
||||
#if 0 // @@@
|
||||
/**
|
||||
* @brief Returns the min edge length to circumcircle radius ratio
|
||||
*
|
||||
* This method only applies to triangles currently.
|
||||
*/
|
||||
double b () const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the polygon borders to a segment
|
||||
|
|
@ -589,16 +696,17 @@ public:
|
|||
unsigned int num_segments () const;
|
||||
|
||||
private:
|
||||
// @@@ bool m_is_outside;
|
||||
std::vector<GPolygonEdge *> mp_e;
|
||||
std::vector<db::GVertex *> mp_v;
|
||||
Graph *mp_graph;
|
||||
bool m_is_outside;
|
||||
std::vector<Edge *> mp_e;
|
||||
std::vector<Vertex *> mp_v;
|
||||
size_t m_id;
|
||||
|
||||
void init ();
|
||||
|
||||
// no copying
|
||||
GPolygon &operator= (const GPolygon &);
|
||||
GPolygon (const GPolygon &);
|
||||
Polygon &operator= (const Polygon &);
|
||||
Polygon (const Polygon &);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -606,87 +714,29 @@ private:
|
|||
*
|
||||
* The ID acts as a more predicable unique ID for the object in sets and maps.
|
||||
*/
|
||||
struct GPolygonLessFunc
|
||||
struct PolygonLessFunc
|
||||
{
|
||||
bool operator () (GPolygon *a, GPolygon *b) const
|
||||
bool operator () (Polygon *a, Polygon *b) const
|
||||
{
|
||||
return a->id () < b->id ();
|
||||
}
|
||||
};
|
||||
|
||||
class DB_PUBLIC PolygonGraph
|
||||
/**
|
||||
* @brief A class representing the polygon graph
|
||||
*
|
||||
* A polygon graph is the main container, holding vertexes, edges and polygons.
|
||||
* The graph can be of "triangles" type, in which case it is guaranteed to only
|
||||
* hold triangles (polygons with 3 vertexes).
|
||||
*/
|
||||
class DB_PUBLIC Graph
|
||||
{
|
||||
public:
|
||||
#if 0 // @@@
|
||||
struct TriangulateParameters
|
||||
{
|
||||
TriangulateParameters ()
|
||||
: min_b (1.0),
|
||||
min_length (0.0),
|
||||
max_area (0.0),
|
||||
max_area_border (0.0),
|
||||
max_iterations (std::numeric_limits<size_t>::max ()),
|
||||
base_verbosity (30),
|
||||
mark_triangles (false)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* @brief Min. readius-to-shortest edge ratio
|
||||
*/
|
||||
double min_b;
|
||||
|
||||
/**
|
||||
* @brief Min. edge length
|
||||
*
|
||||
* This parameter does not provide a guarantee about a minimume edge length, but
|
||||
* helps avoiding ever-reducing triangle splits in acute corners of the input polygon.
|
||||
* Splitting of edges stops when the edge is less than the min length.
|
||||
*/
|
||||
double min_length;
|
||||
|
||||
/**
|
||||
* @brief Max area or zero for "no constraint"
|
||||
*/
|
||||
double max_area;
|
||||
|
||||
/**
|
||||
* @brief Max area for border triangles or zero for "use max_area"
|
||||
*/
|
||||
double max_area_border;
|
||||
|
||||
/**
|
||||
* @brief Max number of iterations
|
||||
*/
|
||||
size_t max_iterations;
|
||||
|
||||
/**
|
||||
* @brief The verbosity level above which triangulation reports details
|
||||
*/
|
||||
int base_verbosity;
|
||||
|
||||
/**
|
||||
* @brief If true, final triangles are marked using the "id" integer as a bit field
|
||||
*
|
||||
* This provides information about the result quality.
|
||||
*
|
||||
* Bit 0: skinny triangle
|
||||
* Bit 1: bad-quality (skinny or area too large)
|
||||
* Bit 2: non-Delaunay (in the strict sense)
|
||||
*/
|
||||
bool mark_triangles;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef tl::list<db::GPolygon> polygons_type;
|
||||
typedef tl::list<Polygon> polygons_type;
|
||||
typedef polygons_type::const_iterator polygon_iterator;
|
||||
|
||||
PolygonGraph ();
|
||||
~PolygonGraph ();
|
||||
|
||||
/**
|
||||
* @brief Creates a convex decomposition for the given polygon
|
||||
*/
|
||||
void convex_decompose (const DPolygon &poly);
|
||||
Graph ();
|
||||
~Graph ();
|
||||
|
||||
/**
|
||||
* @brief Returns a string representation of the polygon graph.
|
||||
|
|
@ -718,15 +768,6 @@ public:
|
|||
*/
|
||||
void clear ();
|
||||
|
||||
protected:
|
||||
#if 0 // @@@
|
||||
/**
|
||||
* @brief Checks the polygon graph for consistency
|
||||
* This method is for testing purposes mainly.
|
||||
*/
|
||||
bool check (bool check_delaunay = true) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Dumps the polygon graph to a GDS file at the given path
|
||||
* This method is for testing purposes mainly.
|
||||
|
|
@ -743,35 +784,43 @@ protected:
|
|||
*/
|
||||
db::Layout *to_layout (bool decompose_by_id = false) const;
|
||||
|
||||
private:
|
||||
tl::list<db::GPolygon> mp_polygons;
|
||||
tl::stable_vector<db::GPolygonEdge> m_edges_heap;
|
||||
std::vector<db::GPolygonEdge *> m_returned_edges;
|
||||
tl::stable_vector<db::GVertex> m_vertex_heap;
|
||||
// @@@ bool m_is_constrained;
|
||||
// @@@ size_t m_level;
|
||||
size_t m_id;
|
||||
// @@@ size_t m_flips, m_hops;
|
||||
|
||||
db::GVertex *create_vertex (double x, double y);
|
||||
db::GVertex *create_vertex (const db::DPoint &pt);
|
||||
db::GPolygonEdge *create_edge (db::GVertex *v1, db::GVertex *v2);
|
||||
protected:
|
||||
Vertex *create_vertex (double x, double y);
|
||||
Vertex *create_vertex (const db::DPoint &pt);
|
||||
Edge *create_edge (Vertex *v1, Vertex *v2);
|
||||
|
||||
template <class Iter>
|
||||
db::GPolygon *
|
||||
Polygon *
|
||||
create_polygon (Iter from, Iter to)
|
||||
{
|
||||
db::GPolygon *res = new db::GPolygon (from ,to);
|
||||
Polygon *res = new Polygon (this, from ,to);
|
||||
res->set_id (++m_id);
|
||||
mp_polygons.push_back (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void remove_polygon (db::GPolygon *tri);
|
||||
template<class Poly, class Trans> void make_contours (const Poly &poly, const Trans &trans, std::vector<std::vector<db::GVertex *> > &contours);
|
||||
Polygon *create_triangle (Edge *e1, Edge *e2, Edge *e3);
|
||||
|
||||
void remove_polygon (Polygon *p);
|
||||
|
||||
private:
|
||||
friend class Triangulation;
|
||||
friend class ConvexDecomposition;
|
||||
|
||||
tl::list<Polygon> mp_polygons;
|
||||
tl::stable_vector<Edge> m_edges_heap;
|
||||
std::vector<Edge *> m_returned_edges;
|
||||
tl::stable_vector<Vertex> m_vertex_heap;
|
||||
size_t m_id;
|
||||
|
||||
tl::list<Polygon> &polygons () { return mp_polygons; }
|
||||
tl::stable_vector<Edge> &edges () { return m_edges_heap; }
|
||||
tl::stable_vector<Vertex> &vertexes () { return m_vertex_heap; }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace plc
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,306 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 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_dbPLCTriangulation
|
||||
#define HDR_dbPLCTriangulation
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbPLC.h"
|
||||
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
namespace plc
|
||||
{
|
||||
|
||||
struct DB_PUBLIC TriangulationParameters
|
||||
{
|
||||
TriangulationParameters ()
|
||||
: min_b (1.0),
|
||||
min_length (0.0),
|
||||
max_area (0.0),
|
||||
max_area_border (0.0),
|
||||
max_iterations (std::numeric_limits<size_t>::max ()),
|
||||
base_verbosity (30),
|
||||
mark_triangles (false)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* @brief Min. readius-to-shortest edge ratio
|
||||
*/
|
||||
double min_b;
|
||||
|
||||
/**
|
||||
* @brief Min. edge length
|
||||
*
|
||||
* This parameter does not provide a guarantee about a minimume edge length, but
|
||||
* helps avoiding ever-reducing triangle splits in acute corners of the input polygon.
|
||||
* Splitting of edges stops when the edge is less than the min length.
|
||||
*/
|
||||
double min_length;
|
||||
|
||||
/**
|
||||
* @brief Max area or zero for "no constraint"
|
||||
*/
|
||||
double max_area;
|
||||
|
||||
/**
|
||||
* @brief Max area for border triangles or zero for "use max_area"
|
||||
*/
|
||||
double max_area_border;
|
||||
|
||||
/**
|
||||
* @brief Max number of iterations
|
||||
*/
|
||||
size_t max_iterations;
|
||||
|
||||
/**
|
||||
* @brief The verbosity level above which triangulation reports details
|
||||
*/
|
||||
int base_verbosity;
|
||||
|
||||
/**
|
||||
* @brief If true, final triangles are marked using the "id" integer as a bit field
|
||||
*
|
||||
* This provides information about the result quality.
|
||||
*
|
||||
* Bit 0: skinny triangle
|
||||
* Bit 1: bad-quality (skinny or area too large)
|
||||
* Bit 2: non-Delaunay (in the strict sense)
|
||||
*/
|
||||
bool mark_triangles;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A Triangulation algorithm
|
||||
*
|
||||
* This class implements a constrained refined Delaunay triangulation using Chew's algorithm.
|
||||
*/
|
||||
class DB_PUBLIC Triangulation
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor
|
||||
*
|
||||
* The graph will be one filled by the triangulation.
|
||||
*/
|
||||
Triangulation (Graph *graph);
|
||||
|
||||
/**
|
||||
* @brief Clears the triangulation
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Initializes the triangle collection with a box
|
||||
* Two triangles will be created.
|
||||
*/
|
||||
void init_box (const db::DBox &box);
|
||||
|
||||
/**
|
||||
* @brief Creates a refined Delaunay triangulation for the given region
|
||||
*
|
||||
* The database unit should be chosen in a way that target area values are "in the order of 1".
|
||||
* For inputs featuring acute angles (angles < ~25 degree), the parameters should defined a min
|
||||
* edge length ("min_length").
|
||||
* "min_length" should be at least 1e-4. If a min edge length is given, the max area constaints
|
||||
* may not be satisfied.
|
||||
*
|
||||
* Edges in the input should not be shorter than 1e-4.
|
||||
*/
|
||||
void triangulate (const db::Region ®ion, const TriangulationParameters ¶meters, double dbu = 1.0);
|
||||
|
||||
// more versions
|
||||
void triangulate (const db::Region ®ion, const TriangulationParameters ¶meters, const db::CplxTrans &trans = db::CplxTrans ());
|
||||
void triangulate (const db::Polygon &poly, const TriangulationParameters ¶meters, double dbu = 1.0);
|
||||
void triangulate (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const TriangulationParameters ¶meters, double dbu = 1.0);
|
||||
void triangulate (const db::Polygon &poly, const TriangulationParameters ¶meters, const db::CplxTrans &trans = db::CplxTrans ());
|
||||
void triangulate (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const TriangulationParameters ¶meters, const db::CplxTrans &trans = db::CplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Triangulates a floating-point polygon
|
||||
*/
|
||||
void triangulate (const db::DPolygon &poly, const TriangulationParameters ¶meters, const db::DCplxTrans &trans = db::DCplxTrans ());
|
||||
void triangulate (const db::DPolygon &poly, const std::vector<db::DPoint> &vertexes, const TriangulationParameters ¶meters, const db::DCplxTrans &trans = db::DCplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Inserts a new vertex as the given point
|
||||
*
|
||||
* If "new_triangles" is not null, it will receive the list of new triangles created during
|
||||
* the remove step.
|
||||
*
|
||||
* This method can be called after "triangulate" to add new points and adjust the triangulation.
|
||||
* Inserting new points will maintain the (constrained) Delaunay condition.
|
||||
*/
|
||||
Vertex *insert_point (const db::DPoint &point, std::list<tl::weak_ptr<Polygon> > *new_triangles = 0);
|
||||
|
||||
/**
|
||||
* @brief Statistics: number of flips (fixing)
|
||||
*/
|
||||
size_t flips () const
|
||||
{
|
||||
return m_flips;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Statistics: number of hops (searching)
|
||||
*/
|
||||
size_t hops () const
|
||||
{
|
||||
return m_hops;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Checks the polygon graph for consistency
|
||||
* This method is for testing purposes mainly.
|
||||
*/
|
||||
bool check (bool check_delaunay = true) const;
|
||||
|
||||
/**
|
||||
* @brief Finds the points within (not "on") a circle of radius "radius" around the given vertex.
|
||||
*/
|
||||
std::vector<Vertex *> find_points_around (Vertex *vertex, double radius);
|
||||
|
||||
/**
|
||||
* @brief Inserts a new vertex as the given point
|
||||
*
|
||||
* If "new_triangles" is not null, it will receive the list of new triangles created during
|
||||
* the remove step.
|
||||
*/
|
||||
Vertex *insert_point (db::DCoord x, db::DCoord y, std::list<tl::weak_ptr<Polygon> > *new_triangles = 0);
|
||||
|
||||
/**
|
||||
* @brief Removes the given vertex
|
||||
*
|
||||
* If "new_triangles" is not null, it will receive the list of new triangles created during
|
||||
* the remove step.
|
||||
*/
|
||||
void remove (Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles = 0);
|
||||
|
||||
/**
|
||||
* @brief Flips the given edge
|
||||
*/
|
||||
std::pair<std::pair<Polygon *, Polygon *>, Edge *> flip (Edge *edge);
|
||||
|
||||
/**
|
||||
* @brief Finds all edges that cross the given one for a convex triangulation
|
||||
*
|
||||
* Requirements:
|
||||
* * self must be a convex triangulation
|
||||
* * edge must not contain another vertex from the triangulation except p1 and p2
|
||||
*/
|
||||
std::vector<Edge *> search_edges_crossing (Vertex *from, Vertex *to);
|
||||
|
||||
/**
|
||||
* @brief Finds the edge for two given points
|
||||
*/
|
||||
Edge *find_edge_for_points (const db::DPoint &p1, const db::DPoint &p2);
|
||||
|
||||
/**
|
||||
* @brief Finds the vertex for a point
|
||||
*/
|
||||
Vertex *find_vertex_for_point (const db::DPoint &pt);
|
||||
|
||||
/**
|
||||
* @brief Ensures all points between from an to are connected by edges and makes these segments
|
||||
*/
|
||||
std::vector<Edge *> ensure_edge (Vertex *from, Vertex *to);
|
||||
|
||||
/**
|
||||
* @brief Given a set of contours with edges, mark outer triangles
|
||||
*
|
||||
* The edges must be made from existing vertexes. Edge orientation is
|
||||
* clockwise.
|
||||
*
|
||||
* This will also mark triangles as outside ones.
|
||||
*/
|
||||
void constrain (const std::vector<std::vector<Vertex *> > &contours);
|
||||
|
||||
/**
|
||||
* @brief Removes the outside triangles.
|
||||
*/
|
||||
void remove_outside_triangles ();
|
||||
|
||||
/**
|
||||
* @brief Creates a constrained Delaunay triangulation from the given Region
|
||||
*/
|
||||
void create_constrained_delaunay (const db::Region ®ion, const db::CplxTrans &trans = db::CplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Creates a constrained Delaunay triangulation from the given Polygon
|
||||
*/
|
||||
void create_constrained_delaunay (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const db::CplxTrans &trans = db::CplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Creates a constrained Delaunay triangulation from the given DPolygon
|
||||
*/
|
||||
void create_constrained_delaunay (const db::DPolygon &poly, const std::vector<DPoint> &vertexes, const DCplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the edge is "illegal" (violates the Delaunay criterion)
|
||||
*/
|
||||
static bool is_illegal_edge (Edge *edge);
|
||||
|
||||
// NOTE: these functions are SLOW and intended to test purposes only
|
||||
std::vector<Vertex *> find_touching (const db::DBox &box) const;
|
||||
std::vector<Vertex *> find_inside_circle (const db::DPoint ¢er, double radius) const;
|
||||
|
||||
private:
|
||||
Graph *mp_graph;
|
||||
bool m_is_constrained;
|
||||
size_t m_level;
|
||||
size_t m_id;
|
||||
size_t m_flips, m_hops;
|
||||
|
||||
template<class Poly, class Trans> void make_contours (const Poly &poly, const Trans &trans, std::vector<std::vector<Vertex *> > &contours);
|
||||
|
||||
void remove_outside_vertex (Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles = 0);
|
||||
void remove_inside_vertex (Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles_out = 0);
|
||||
std::vector<Polygon *> fill_concave_corners (const std::vector<Edge *> &edges);
|
||||
void fix_triangles (const std::vector<Polygon *> &tris, const std::vector<Edge *> &fixed_edges, std::list<tl::weak_ptr<Polygon> > *new_triangles);
|
||||
std::vector<Polygon *> find_triangle_for_point (const db::DPoint &point);
|
||||
Edge *find_closest_edge (const db::DPoint &p, Vertex *vstart = 0, bool inside_only = false);
|
||||
Vertex *insert (Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles = 0);
|
||||
void split_triangle (Polygon *t, Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles_out);
|
||||
void split_triangles_on_edge (Vertex *vertex, Edge *split_edge, std::list<tl::weak_ptr<Polygon> > *new_triangles_out);
|
||||
void add_more_triangles (std::vector<Polygon *> &new_triangles,
|
||||
Edge *incoming_edge,
|
||||
Vertex *from_vertex, Vertex *to_vertex,
|
||||
Edge *conn_edge);
|
||||
void insert_new_vertex(Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles_out);
|
||||
std::vector<Edge *> ensure_edge_inner (Vertex *from, Vertex *to);
|
||||
void join_edges (std::vector<Edge *> &edges);
|
||||
void refine (const TriangulationParameters ¶m);
|
||||
};
|
||||
|
||||
} // namespace plc
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -21,31 +21,21 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "dbPolygonGraph.h"
|
||||
#include "dbPLC.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
class TestablePolygonGraph
|
||||
: public db::PolygonGraph
|
||||
{
|
||||
public:
|
||||
using db::PolygonGraph::PolygonGraph;
|
||||
// @@@ using db::PolygonGraph::check;
|
||||
using db::PolygonGraph::dump;
|
||||
};
|
||||
|
||||
|
||||
TEST(basic)
|
||||
{
|
||||
db::DBox box (0, 0, 100.0, 200.0);
|
||||
|
||||
TestablePolygonGraph pg;
|
||||
db::plc::Graph plc;
|
||||
// @@@ pg.insert_polygon (db::DSimplePolygon (box));
|
||||
|
||||
// @@@
|
||||
tl::info << pg.to_string ();
|
||||
pg.dump ("debug.gds"); // @@@
|
||||
tl::info << plc.to_string ();
|
||||
plc.dump ("debug.gds"); // @@@
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -461,7 +461,7 @@ TEST(ensure_edge)
|
|||
EXPECT_EQ (tl::to_string (area_in), "0.25");
|
||||
}
|
||||
|
||||
bool safe_inside (const db::DBox &b1, const db::DBox &b2)
|
||||
static bool safe_inside (const db::DBox &b1, const db::DBox &b2)
|
||||
{
|
||||
typedef db::coord_traits<db::DBox::coord_type> ct;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ SOURCES = \
|
|||
dbFillToolTests.cc \
|
||||
dbLogTests.cc \
|
||||
dbObjectWithPropertiesTests.cc \
|
||||
dbPolygonGraphTests.cc \
|
||||
dbPLCGraphTest.cc \
|
||||
dbPLCTriangulationTests.cc \
|
||||
dbPolygonNeighborhoodTests.cc \
|
||||
dbPropertiesFilterTests.cc \
|
||||
dbQuadTreeTests.cc \
|
||||
|
|
|
|||
Loading…
Reference in New Issue