Removing obsolete dbTriangle/dbTriangles

This commit is contained in:
Matthias Koefferlein 2025-04-13 23:06:49 +02:00
parent 802cf99521
commit 76e039bd2a
12 changed files with 26 additions and 5446 deletions

View File

@ -107,8 +107,6 @@ SOURCES = \
dbTextWriter.cc \
dbTilingProcessor.cc \
dbTrans.cc \
dbTriangle.cc \
dbTriangles.cc \
dbUserObject.cc \
dbUtils.cc \
dbVector.cc \
@ -347,8 +345,6 @@ HEADERS = \
dbTextWriter.h \
dbTilingProcessor.h \
dbTrans.h \
dbTriangle.h \
dbTriangles.h \
dbTypes.h \
dbUserObject.h \
dbUtils.h \

View File

@ -24,7 +24,6 @@
#define HDR_dbPLC
#include "dbCommon.h"
#include "dbTriangle.h"
#include "dbBox.h"
#include "dbRegion.h"

View File

@ -453,8 +453,8 @@ TriangulationProcessor::process (const db::Polygon &poly, std::vector<db::Polygo
// NOTE: we center the polygon for better numerical stability
db::CplxTrans trans = db::CplxTrans (triangulation_dbu) * db::ICplxTrans (db::Trans (db::Point () - poly.box ().center ()));
db::Triangles tri;
tri.triangulate (poly, m_param, trans);
db::plc::Graph tri;
db::plc::Triangulation (&tri).triangulate (poly, m_param, trans);
db::Point pts [3];
auto trans_inv = trans.inverted ();
@ -474,8 +474,8 @@ TriangulationProcessor::process (const db::PolygonWithProperties &poly, std::vec
// NOTE: we center the polygon for better numerical stability
db::CplxTrans trans = db::CplxTrans (triangulation_dbu) * db::ICplxTrans (db::Trans (db::Point () - poly.box ().center ()));
db::Triangles tri;
tri.triangulate (poly, m_param, trans);
db::plc::Graph tri;
db::plc::Triangulation (&tri).triangulate (poly, m_param, trans);
db::Point pts [3];
auto trans_inv = trans.inverted ();

View File

@ -28,7 +28,7 @@
#include "dbRegionDelegate.h"
#include "dbPolygonTools.h"
#include "dbEdgesUtils.h"
#include "dbTriangles.h"
#include "dbPLCTriangulation.h"
#include "dbEdgePairRelations.h"
namespace db
@ -497,7 +497,7 @@ public:
virtual bool wants_variants () const { return true; }
private:
db::Triangles::TriangulateParameters m_param;
db::plc::TriangulationParameters m_param;
db::MagnificationReducer m_vars;
};

View File

@ -1,607 +0,0 @@
/*
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
*/
#include "dbTriangle.h"
#include <set>
namespace db
{
// -------------------------------------------------------------------------------------
// Vertex implementation
Vertex::Vertex ()
: DPoint (), m_is_precious (false)
{
// .. nothing yet ..
}
Vertex::Vertex (const db::DPoint &p)
: DPoint (p), m_is_precious (false)
{
// .. nothing yet ..
}
Vertex::Vertex (const Vertex &v)
: DPoint (), m_is_precious (false)
{
operator= (v);
}
Vertex &Vertex::operator= (const Vertex &v)
{
if (this != &v) {
// NOTE: edges are not copied!
db::DPoint::operator= (v);
m_is_precious = v.m_is_precious;
}
return *this;
}
Vertex::Vertex (db::DCoord x, db::DCoord y)
: DPoint (x, y), m_is_precious (false)
{
// .. nothing yet ..
}
bool
Vertex::is_outside () const
{
for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) {
if ((*e)->is_outside ()) {
return true;
}
}
return false;
}
std::vector<db::Triangle *>
Vertex::triangles () const
{
std::set<db::Triangle *> seen;
std::vector<db::Triangle *> res;
for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) {
for (auto t = (*e)->begin_triangles (); t != (*e)->end_triangles (); ++t) {
if (seen.insert (t.operator-> ()).second) {
res.push_back (t.operator-> ());
}
}
}
return res;
}
bool
Vertex::has_edge (const TriangleEdge *edge) const
{
for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) {
if (*e == edge) {
return true;
}
}
return false;
}
size_t
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
return mp_edges.size ();
} else {
size_t n = 0;
for (auto i = mp_edges.begin (); i != mp_edges.end () && --max_count >= 0; ++i) {
++n;
}
return n;
}
}
std::string
Vertex::to_string (bool with_id) const
{
std::string res = tl::sprintf ("(%.12g, %.12g)", x (), y());
if (with_id) {
res += tl::sprintf ("[%x]", (size_t)this);
}
return res;
}
int
Vertex::in_circle (const DPoint &point, const DPoint &center, double radius)
{
double dx = point.x () - center.x ();
double dy = point.y () - center.y ();
double d2 = dx * dx + dy * dy;
double r2 = radius * radius;
double delta = fabs (d2 + r2) * db::epsilon;
if (d2 < r2 - delta) {
return 1;
} else if (d2 < r2 + delta) {
return 0;
} else {
return -1;
}
}
// -------------------------------------------------------------------------------------
// TriangleEdge implementation
TriangleEdge::TriangleEdge ()
: mp_v1 (0), mp_v2 (0), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false)
{
// .. nothing yet ..
}
TriangleEdge::TriangleEdge (Vertex *v1, Vertex *v2)
: mp_v1 (v1), mp_v2 (v2), mp_left (), mp_right (), m_level (0), m_id (0), m_is_segment (false)
{
// .. nothing yet ..
}
void
TriangleEdge::set_left (Triangle *t)
{
mp_left = t;
}
void
TriangleEdge::set_right (Triangle *t)
{
mp_right = t;
}
void
TriangleEdge::link ()
{
mp_v1->mp_edges.push_back (this);
m_ec_v1 = --mp_v1->mp_edges.end ();
mp_v2->mp_edges.push_back (this);
m_ec_v2 = --mp_v2->mp_edges.end ();
}
void
TriangleEdge::unlink ()
{
if (mp_v1) {
mp_v1->remove_edge (m_ec_v1);
}
if (mp_v2) {
mp_v2->remove_edge (m_ec_v2);
}
mp_v1 = mp_v2 = 0;
}
Triangle *
TriangleEdge::other (const Triangle *t) const
{
if (t == mp_left) {
return mp_right;
}
if (t == mp_right) {
return mp_left;
}
tl_assert (false);
return 0;
}
Vertex *
TriangleEdge::other (const Vertex *t) const
{
if (t == mp_v1) {
return mp_v2;
}
if (t == mp_v2) {
return mp_v1;
}
tl_assert (false);
return 0;
}
bool
TriangleEdge::has_vertex (const Vertex *v) const
{
return mp_v1 == v || mp_v2 == v;
}
Vertex *
TriangleEdge::common_vertex (const TriangleEdge *other) const
{
if (has_vertex (other->v1 ())) {
return (other->v1 ());
}
if (has_vertex (other->v2 ())) {
return (other->v2 ());
}
return 0;
}
std::string
TriangleEdge::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) {
res += tl::sprintf ("[%x]", (size_t)this);
}
return res;
}
double
TriangleEdge::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;
if (l <= 0.0) {
pp = e.p1 ();
} else if (l >= 1.0) {
pp = e.p2 ();
} else {
pp = e.p1 () + e.d () * l;
}
return (p - pp).length ();
}
bool
TriangleEdge::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
TriangleEdge::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
TriangleEdge::intersection_point (const db::DEdge &e, const db::DEdge &other)
{
return e.intersect_point (other).second;
}
bool
TriangleEdge::point_on (const db::DEdge &edge, const db::DPoint &point)
{
if (edge.side_of (point) != 0) {
return false;
} else {
return db::sprod_sign (point - edge.p1 (), edge.d ()) * db::sprod_sign(point - edge.p2 (), edge.d ()) < 0;
}
}
bool
TriangleEdge::can_flip () const
{
if (! left () || ! right ()) {
return false;
}
const db::Vertex *v1 = left ()->opposite (this);
const db::Vertex *v2 = right ()->opposite (this);
return crosses (db::DEdge (*v1, *v2));
}
bool
TriangleEdge::can_join_via (const Vertex *vertex) const
{
if (! left () || ! right ()) {
return false;
}
tl_assert (has_vertex (vertex));
const db::Vertex *v1 = left ()->opposite (this);
const db::Vertex *v2 = right ()->opposite (this);
return db::DEdge (*v1, *v2).side_of (*vertex) == 0;
}
bool
TriangleEdge::is_outside () const
{
return left () == 0 || right () == 0;
}
bool
TriangleEdge::is_for_outside_triangles () const
{
return (left () && left ()->is_outside ()) || (right () && right ()->is_outside ());
}
bool
TriangleEdge::has_triangle (const Triangle *t) const
{
return t != 0 && (left () == t || right () == t);
}
// -------------------------------------------------------------------------------------
// Triangle implementation
Triangle::Triangle ()
: m_is_outside (false), m_id (0)
{
for (int i = 0; i < 3; ++i) {
mp_v[i] = 0;
mp_e[i] = 0;
}
}
Triangle::Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3)
: m_is_outside (false), m_id (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) {
TriangleEdge *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);
}
}
}
Triangle::~Triangle ()
{
unlink ();
}
void
Triangle::unlink ()
{
for (int i = 0; i != 3; ++i) {
db::TriangleEdge *e = mp_e[i];
if (e->left () == this) {
e->set_left (0);
}
if (e->right () == this) {
e->set_right (0);
}
}
}
std::string
Triangle::to_string (bool with_id) const
{
std::string res = "(";
for (int i = 0; i < 3; ++i) {
if (i > 0) {
res += ", ";
}
if (vertex (i)) {
res += vertex (i)->to_string (with_id);
} else {
res += "(null)";
}
}
res += ")";
return res;
}
double
Triangle::area () const
{
return fabs (db::vprod (mp_e[0]->d (), mp_e[1]->d ())) * 0.5;
}
db::DBox
Triangle::bbox () const
{
db::DBox box;
for (int i = 0; i < 3; ++i) {
box += *mp_v[i];
}
return box;
}
std::pair<db::DPoint, double>
Triangle::circumcircle (bool *ok) const
{
// 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 *
Triangle::opposite (const TriangleEdge *edge) const
{
for (int i = 0; i < 3; ++i) {
Vertex *v = mp_v[i];
if (! edge->has_vertex (v)) {
return v;
}
}
tl_assert (false);
}
TriangleEdge *
Triangle::opposite (const Vertex *vertex) const
{
for (int i = 0; i < 3; ++i) {
TriangleEdge *e = mp_e[i];
if (! e->has_vertex (vertex)) {
return e;
}
}
tl_assert (false);
}
TriangleEdge *
Triangle::find_edge_with (const Vertex *v1, const Vertex *v2) const
{
for (int i = 0; i < 3; ++i) {
TriangleEdge *e = mp_e[i];
if (e->has_vertex (v1) && e->has_vertex (v2)) {
return e;
}
}
tl_assert (false);
}
TriangleEdge *
Triangle::common_edge (const Triangle *other) const
{
for (int i = 0; i < 3; ++i) {
TriangleEdge *e = mp_e[i];;
if (e->other (this) == other) {
return e;
}
}
return 0;
}
int
Triangle::contains (const db::DPoint &point) const
{
auto c = *mp_v[2] - *mp_v[0];
auto b = *mp_v[1] - *mp_v[0];
int vps = db::vprod_sign (c, b);
if (vps == 0) {
return db::vprod_sign (point - *mp_v[0], b) == 0 && db::vprod_sign (point - *mp_v[0], c) == 0 ? 0 : -1;
}
int res = 1;
const Vertex *vl = mp_v[2];
for (int i = 0; i < 3; ++i) {
const Vertex *v = mp_v[i];
int n = db::vprod_sign (point - *vl, *v - *vl) * vps;
if (n < 0) {
return -1;
} else if (n == 0) {
res = 0;
}
vl = v;
}
return res;
}
double
Triangle::min_edge_length () const
{
double lmin = mp_e[0]->d ().length ();
for (int i = 1; i < 3; ++i) {
lmin = std::min (lmin, mp_e[i]->d ().length ());
}
return lmin;
}
double
Triangle::b () const
{
double lmin = min_edge_length ();
bool ok = false;
auto cr = circumcircle (&ok);
return ok ? lmin / cr.second : 0.0;
}
bool
Triangle::has_segment () const
{
for (int i = 0; i < 3; ++i) {
if (mp_e[i]->is_segment ()) {
return true;
}
}
return false;
}
unsigned int
Triangle::num_segments () const
{
unsigned int n = 0;
for (int i = 0; i < 3; ++i) {
if (mp_e[i]->is_segment ()) {
++n;
}
}
return n;
}
}

View File

@ -1,579 +0,0 @@
/*
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_dbTriangle
#define HDR_dbTriangle
#include "dbCommon.h"
#include "dbPoint.h"
#include "dbEdge.h"
#include "tlObjectCollection.h"
#include "tlList.h"
#include <vector>
#include <string>
#include <list>
#include <algorithm>
namespace db
{
class Triangle;
class TriangleEdge;
/**
* @brief A class representing a vertex in a Delaunay triangulation graph
*
* The vertex carries information about the connected edges and
* an integer value that can be used in traversal algorithms
* ("level")
*/
class DB_PUBLIC Vertex
: public db::DPoint
{
public:
typedef std::list<TriangleEdge *> edges_type;
typedef edges_type::const_iterator edges_iterator;
typedef edges_type::iterator edges_iterator_non_const;
Vertex ();
Vertex (const DPoint &p);
Vertex (const Vertex &v);
Vertex (db::DCoord x, db::DCoord y);
Vertex &operator= (const Vertex &v);
bool is_outside () const;
std::vector<db::Triangle *> triangles () const;
edges_iterator begin_edges () const { return mp_edges.begin (); }
edges_iterator end_edges () const { return mp_edges.end (); }
size_t num_edges (int max_count = -1) const;
bool has_edge (const TriangleEdge *edge) const;
void set_is_precious (bool f) { m_is_precious = f; }
bool is_precious () const { return m_is_precious; }
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 &center, double radius);
/**
* @brief Returns 1 is this point is inside the circle, 0 if on the circle and -1 if outside
*/
int in_circle (const db::DPoint &center, double radius) const
{
return in_circle (*this, center, radius);
}
private:
friend class TriangleEdge;
void remove_edge (const edges_iterator_non_const &ec)
{
mp_edges.erase (ec);
}
edges_type mp_edges;
bool m_is_precious;
};
/**
* @brief A class representing an edge in the Delaunay triangulation graph
*/
class DB_PUBLIC TriangleEdge
{
public:
class TriangleIterator
{
public:
typedef Triangle value_type;
typedef Triangle &reference;
typedef Triangle *pointer;
reference operator*() const
{
return *operator-> ();
}
pointer operator->() const
{
return m_index ? mp_edge->right () : mp_edge->left ();
}
bool operator== (const TriangleIterator &other) const
{
return m_index == other.m_index;
}
bool operator!= (const TriangleIterator &other) const
{
return !operator== (other);
}
TriangleIterator &operator++ ()
{
while (++m_index < 2 && operator-> () == 0)
;
return *this;
}
private:
friend class TriangleEdge;
TriangleIterator (const TriangleEdge *edge)
: mp_edge (edge), m_index (0)
{
if (! edge) {
m_index = 2;
} else {
--m_index;
operator++ ();
}
}
const TriangleEdge *mp_edge;
unsigned int m_index;
};
TriangleEdge ();
TriangleEdge (Vertex *v1, Vertex *v2);
Vertex *v1 () const { return mp_v1; }
Vertex *v2 () const { return mp_v2; }
void reverse ()
{
std::swap (mp_v1, mp_v2);
std::swap (mp_left, mp_right);
}
Triangle *left () const { return mp_left; }
Triangle *right () const { return mp_right; }
TriangleIterator begin_triangles () const
{
return TriangleIterator (this);
}
TriangleIterator end_triangles () const
{
return TriangleIterator (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; }
bool is_segment () const { return m_is_segment; }
std::string to_string (bool with_id = false) const;
/**
* @brief Converts to an db::DEdge
*/
db::DEdge edge () const
{
return db::DEdge (*mp_v1, *mp_v2);
}
/**
* @brief Returns the distance of the given point to the edge
*
* The distance is the minimum distance of the point to one point from the edge.
* TODO: Move to db::DEdge
*/
static double distance (const db::DEdge &e, const db::DPoint &p);
/**
* @brief Returns the distance of the given point to the edge
*
* The distance is the minimum distance of the point to one point from the edge.
*/
double distance (const db::DPoint &p) const
{
return distance (edge (), p);
}
/**
* @brief Returns a value indicating whether this edge crosses the other one
*
* "crosses" is true, if both edges share at least one point which is not an endpoint
* of one of the edges.
* TODO: Move to db::DEdge
*/
static bool crosses (const db::DEdge &e, const db::DEdge &other);
/**
* @brief Returns a value indicating whether this edge crosses the other one
*
* "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::DEdge &other) const
{
return crosses (edge (), other);
}
/**
* @brief Returns a value indicating whether this edge crosses the other one
*
* "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::TriangleEdge &other) const
{
return crosses (edge (), other.edge ());
}
/**
* @brief Returns a value indicating whether this edge crosses the other one
* "crosses" is true, if both edges share at least one point.
* TODO: Move to db::DEdge
*/
static bool crosses_including (const db::DEdge &e, const db::DEdge &other);
/**
* @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::DEdge &other) const
{
return crosses_including (edge (), other);
}
/**
* @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::TriangleEdge &other) const
{
return crosses_including (edge (), other.edge ());
}
/**
* @brief Gets the intersection point
* TODO: Move to db::DEdge
*/
static db::DPoint intersection_point (const db::DEdge &e, const DEdge &other);
/**
* @brief Gets the intersection point
*/
db::DPoint intersection_point (const db::DEdge &other) const
{
return intersection_point (edge (), other);
}
/**
* @brief Gets the intersection point
*/
db::DPoint intersection_point (const TriangleEdge &other) const
{
return intersection_point (edge (), other.edge ());
}
/**
* @brief Returns a value indicating whether the point is on the edge
* TODO: Move to db::DEdge
*/
static bool point_on (const db::DEdge &edge, const db::DPoint &point);
/**
* @brief Returns a value indicating whether the point is on the edge
*/
bool point_on (const db::DPoint &point) const
{
return point_on (edge (), point);
}
/**
* @brief Gets the side the point is on
*
* -1 is for "left", 0 is "on" and +1 is "right"
* TODO: correct to same definition as db::Edge (negative)
*/
static int side_of (const db::DEdge &e, const db::DPoint &point)
{
return -e.side_of (point);
}
/**
* @brief Gets the side the point is on
*
* -1 is for "left", 0 is "on" and +1 is "right"
* TODO: correct to same definition as db::Edge (negative)
*/
int side_of (const db::DPoint &p) const
{
return -edge ().side_of (p);
}
/**
* @brief Gets the distance vector
*/
db::DVector d () const
{
return *mp_v2 - *mp_v1;
}
/**
* @brief Gets the other triangle for the given one
*/
Triangle *other (const Triangle *) const;
/**
* @brief Gets the other vertex for the given one
*/
Vertex *other (const Vertex *) const;
/**
* @brief Gets a value indicating whether the edge has the given vertex
*/
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
*/
Vertex *common_vertex (const TriangleEdge *other) const;
/**
* @brief Returns a value indicating whether this edge can be flipped
*/
bool can_flip () const;
/**
* @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 Vertex *vertex) 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;
/**
* @brief Returns a value indicating whether t is attached to this edge
*/
bool has_triangle (const Triangle *t) const;
protected:
void unlink ();
void link ();
private:
friend class Triangle;
friend class Triangles;
Vertex *mp_v1, *mp_v2;
Triangle *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 (Triangle *t);
void set_right (Triangle *t);
};
/**
* @brief A compare function that compares triangles by ID
*
* The ID acts as a more predicable unique ID for the object in sets and maps.
*/
struct TriangleEdgeLessFunc
{
bool operator () (TriangleEdge *a, TriangleEdge *b) const
{
return a->id () < b->id ();
}
};
/**
* @brief A class representing a triangle
*/
class DB_PUBLIC Triangle
: public tl::list_node<Triangle>, public tl::Object
{
public:
Triangle ();
Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3);
~Triangle ();
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; }
std::string to_string (bool with_id = false) const;
/**
* @brief Gets the nth vertex (n wraps around and can be negative)
* The vertexes are oriented clockwise.
*/
inline Vertex *vertex (int n) const
{
if (n >= 0 && n < 3) {
return mp_v[n];
} else {
return mp_v[(n + 3) % 3];
}
}
/**
* @brief Gets the nth edge (n wraps around and can be negative)
*/
inline TriangleEdge *edge (int n) const
{
if (n >= 0 && n < 3) {
return mp_e[n];
} else {
return mp_e[(n + 3) % 3];
}
}
/**
* @brief Gets the area
*/
double area () const;
/**
* @brief Returns the bounding box of the triangle
*/
db::DBox bbox () const;
/**
* @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).
*/
std::pair<db::DPoint, double> circumcircle (bool *ok = 0) const;
/**
* @brief Gets the vertex opposite of the given edge
*/
Vertex *opposite (const TriangleEdge *edge) const;
/**
* @brief Gets the edge opposite of the given vertex
*/
TriangleEdge *opposite (const Vertex *vertex) const;
/**
* @brief Gets the edge with the given vertexes
*/
TriangleEdge *find_edge_with (const Vertex *v1, const Vertex *v2) const;
/**
* @brief Finds the common edge for both triangles
*/
TriangleEdge *common_edge (const Triangle *other) const;
/**
* @brief Returns a value indicating whether the point is inside (1), on the triangle (0) or outside (-1)
*/
int contains (const db::DPoint &point) const;
/**
* @brief Gets a value indicating whether the triangle has the given vertex
*/
inline bool has_vertex (const db::Vertex *v) const
{
return mp_v[0] == v || mp_v[1] == v || mp_v[2] == v;
}
/**
* @brief Gets a value indicating whether the triangle has the given edge
*/
inline bool has_edge (const db::TriangleEdge *e) const
{
return mp_e[0] == e || mp_e[1] == e || mp_e[2] == e;
}
/**
* @brief Returns the minimum edge length
*/
double min_edge_length () const;
/**
* @brief Returns the min edge length to circumcircle radius ratio
*/
double b () const;
/**
* @brief Returns a value indicating whether the triangle borders to a segment
*/
bool has_segment () const;
/**
* @brief Returns the number of segments the triangle borders to
*/
unsigned int num_segments () const;
private:
bool m_is_outside;
TriangleEdge *mp_e[3];
db::Vertex *mp_v[3];
size_t m_id;
// no copying
Triangle &operator= (const Triangle &);
Triangle (const Triangle &);
};
/**
* @brief A compare function that compares triangles by ID
*
* The ID acts as a more predicable unique ID for the object in sets and maps.
*/
struct TriangleLessFunc
{
bool operator () (Triangle *a, Triangle *b) const
{
return a->id () < b->id ();
}
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,360 +0,0 @@
/*
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_dbTriangles
#define HDR_dbTriangles
#include "dbCommon.h"
#include "dbTriangle.h"
#include "dbBox.h"
#include "dbRegion.h"
#include "tlObjectCollection.h"
#include "tlStableVector.h"
#include <limits>
#include <list>
#include <vector>
#include <algorithm>
namespace db
{
class Layout;
class DB_PUBLIC Triangles
{
public:
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;
};
typedef tl::list<db::Triangle> triangles_type;
typedef triangles_type::const_iterator triangle_iterator;
Triangles ();
~Triangles ();
/**
* @brief Initializes the triangle collection with a box
* Two triangles will be created.
*/
void init_box (const db::DBox &box);
/**
* @brief Returns a string representation of the triangle graph.
*/
std::string to_string ();
/**
* @brief Returns the bounding box of the triangle graph.
*/
db::DBox bbox () const;
/**
* @brief Iterates the triangles in the graph (begin iterator)
*/
triangle_iterator begin () const { return mp_triangles.begin (); }
/**
* @brief Iterates the triangles in the graph (end iterator)
*/
triangle_iterator end () const { return mp_triangles.end (); }
/**
* @brief Returns the number of triangles in the graph
*/
size_t num_triangles () const { return mp_triangles.size (); }
/**
* @brief Clears the triangle set
*/
void clear ();
/**
* @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 &region, const TriangulateParameters &parameters, double dbu = 1.0);
// more versions
void triangulate (const db::Region &region, const TriangulateParameters &parameters, const db::CplxTrans &trans = db::CplxTrans ());
void triangulate (const db::Polygon &poly, const TriangulateParameters &parameters, double dbu = 1.0);
void triangulate (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const TriangulateParameters &parameters, double dbu = 1.0);
void triangulate (const db::Polygon &poly, const TriangulateParameters &parameters, const db::CplxTrans &trans = db::CplxTrans ());
void triangulate (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const TriangulateParameters &parameters, const db::CplxTrans &trans = db::CplxTrans ());
/**
* @brief Triangulates a floating-point polygon
*/
void triangulate (const db::DPolygon &poly, const TriangulateParameters &parameters, const db::DCplxTrans &trans = db::DCplxTrans ());
void triangulate (const db::DPolygon &poly, const std::vector<db::DPoint> &vertexes, const TriangulateParameters &parameters, 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.
*/
db::Vertex *insert_point (const db::DPoint &point, std::list<tl::weak_ptr<db::Triangle> > *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 triangle graph for consistency
* This method is for testing purposes mainly.
*/
bool check (bool check_delaunay = true) const;
/**
* @brief Dumps the triangle graph to a GDS file at the given path
* This method is for testing purposes mainly.
*
* "decompose_id" will map triangles to layer 20, 21 and 22.
* according to bit 0, 1 and 2 of the ID (useful with the 'mark_triangles'
* flat in TriangulateParameters).
*/
void dump (const std::string &path, bool decompose_by_id = false) const;
/**
* @brief Creates a new layout object representing the triangle graph
* This method is for testing purposes mainly.
*/
db::Layout *to_layout (bool decompose_by_id = false) const;
/**
* @brief Finds the points within (not "on") a circle of radius "radius" around the given vertex.
*/
std::vector<db::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.
*/
db::Vertex *insert_point (db::DCoord x, db::DCoord y, std::list<tl::weak_ptr<db::Triangle> > *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 (db::Vertex *vertex, std::list<tl::weak_ptr<db::Triangle> > *new_triangles = 0);
/**
* @brief Flips the given edge
*/
std::pair<std::pair<db::Triangle *, db::Triangle *>, db::TriangleEdge *> flip (TriangleEdge *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<db::TriangleEdge *> search_edges_crossing (db::Vertex *from, db::Vertex *to);
/**
* @brief Finds the edge for two given points
*/
db::TriangleEdge *find_edge_for_points (const db::DPoint &p1, const db::DPoint &p2);
/**
* @brief Finds the vertex for a point
*/
db::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<db::TriangleEdge *> ensure_edge (db::Vertex *from, db::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 &region, 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 (db::TriangleEdge *edge);
// NOTE: these functions are SLOW and intended to test purposes only
std::vector<db::Vertex *> find_touching (const db::DBox &box) const;
std::vector<db::Vertex *> find_inside_circle (const db::DPoint &center, double radius) const;
private:
struct TriangleBoxConvert
{
typedef db::DBox box_type;
box_type operator() (db::Triangle *t) const
{
return t ? t->bbox () : box_type ();
}
};
tl::list<db::Triangle> mp_triangles;
tl::stable_vector<db::TriangleEdge> m_edges_heap;
std::vector<db::TriangleEdge *> m_returned_edges;
tl::stable_vector<db::Vertex> m_vertex_heap;
bool m_is_constrained;
size_t m_level;
size_t m_id;
size_t m_flips, m_hops;
db::Vertex *create_vertex (double x, double y);
db::Vertex *create_vertex (const db::DPoint &pt);
db::TriangleEdge *create_edge (db::Vertex *v1, db::Vertex *v2);
db::Triangle *create_triangle (db::TriangleEdge *e1, db::TriangleEdge *e2, db::TriangleEdge *e3);
void remove_triangle (db::Triangle *tri);
void remove_outside_vertex (db::Vertex *vertex, std::list<tl::weak_ptr<db::Triangle> > *new_triangles = 0);
void remove_inside_vertex (db::Vertex *vertex, std::list<tl::weak_ptr<db::Triangle> > *new_triangles_out = 0);
std::vector<db::Triangle *> fill_concave_corners (const std::vector<TriangleEdge *> &edges);
void fix_triangles (const std::vector<db::Triangle *> &tris, const std::vector<db::TriangleEdge *> &fixed_edges, std::list<tl::weak_ptr<db::Triangle> > *new_triangles);
std::vector<db::Triangle *> find_triangle_for_point (const db::DPoint &point);
db::TriangleEdge *find_closest_edge (const db::DPoint &p, db::Vertex *vstart = 0, bool inside_only = false);
db::Vertex *insert (db::Vertex *vertex, std::list<tl::weak_ptr<db::Triangle> > *new_triangles = 0);
void split_triangle (db::Triangle *t, db::Vertex *vertex, std::list<tl::weak_ptr<db::Triangle> > *new_triangles_out);
void split_triangles_on_edge (db::Vertex *vertex, db::TriangleEdge *split_edge, std::list<tl::weak_ptr<db::Triangle> > *new_triangles_out);
void add_more_triangles (std::vector<Triangle *> &new_triangles,
db::TriangleEdge *incoming_edge,
db::Vertex *from_vertex, db::Vertex *to_vertex,
db::TriangleEdge *conn_edge);
void insert_new_vertex(db::Vertex *vertex, std::list<tl::weak_ptr<Triangle> > *new_triangles_out);
std::vector<db::TriangleEdge *> ensure_edge_inner (db::Vertex *from, db::Vertex *to);
void join_edges (std::vector<TriangleEdge *> &edges);
void refine (const TriangulateParameters &param);
template<class Poly, class Trans> void make_contours (const Poly &poly, const Trans &trans, std::vector<std::vector<db::Vertex *> > &contours);
};
}
#endif

View File

@ -28,13 +28,13 @@
#include "dbPolygonTools.h"
#include "dbPolygonGenerators.h"
#include "dbHash.h"
#include "dbTriangles.h"
#include "dbPLCTriangulation.h"
namespace gsi
{
template <class T>
static db::Region region_from_triangles (const db::Triangles &tri, const T &trans)
static db::Region region_from_triangles (const db::plc::Graph &tri, const T &trans)
{
db::Region result;
@ -53,10 +53,10 @@ static db::Region region_from_triangles (const db::Triangles &tri, const T &tran
}
template <class P, class T>
static std::vector<P> polygons_from_triangles (const db::Triangles &tri, const T &trans)
static std::vector<P> polygons_from_triangles (const db::plc::Graph &tri, const T &trans)
{
std::vector<P> result;
result.reserve (tri.num_triangles ());
result.reserve (tri.num_polygons ());
typename P::point_type pts [3];
@ -89,14 +89,15 @@ static db::polygon<C> to_polygon (const db::polygon<C> &p)
template <class P>
static db::Region triangulate_ipolygon (const P *p, double max_area = 0.0, double min_b = 0.0, double dbu = 0.001)
{
db::Triangles tris;
db::Triangles::TriangulateParameters param;
db::plc::Graph tris;
db::plc::Triangulation triangulation (&tris);
db::plc::TriangulationParameters param;
param.min_b = min_b;
param.max_area = max_area * dbu * dbu;
db::CplxTrans trans = db::CplxTrans (dbu) * db::ICplxTrans (db::Trans (db::Point () - p->box ().center ()));
tris.triangulate (to_polygon (*p), param, trans);
triangulation.triangulate (to_polygon (*p), param, trans);
return region_from_triangles (tris, trans.inverted ());
}
@ -104,14 +105,15 @@ static db::Region triangulate_ipolygon (const P *p, double max_area = 0.0, doubl
template <class P>
static db::Region triangulate_ipolygon_v (const P *p, const std::vector<db::Point> &vertexes, double max_area = 0.0, double min_b = 0.0, double dbu = 0.001)
{
db::Triangles tris;
db::Triangles::TriangulateParameters param;
db::plc::Graph tris;
db::plc::Triangulation triangulation (&tris);
db::plc::TriangulationParameters param;
param.min_b = min_b;
param.max_area = max_area * dbu * dbu;
db::CplxTrans trans = db::CplxTrans (dbu) * db::ICplxTrans (db::Trans (db::Point () - p->box ().center ()));
tris.triangulate (to_polygon (*p), vertexes, param, trans);
triangulation.triangulate (to_polygon (*p), vertexes, param, trans);
return region_from_triangles (tris, trans.inverted ());
}
@ -119,14 +121,15 @@ static db::Region triangulate_ipolygon_v (const P *p, const std::vector<db::Poin
template <class P>
static std::vector<P> triangulate_dpolygon (const P *p, double max_area = 0.0, double min_b = 0.0)
{
db::Triangles tris;
db::Triangles::TriangulateParameters param;
db::plc::Graph tris;
db::plc::Triangulation triangulation (&tris);
db::plc::TriangulationParameters param;
param.min_b = min_b;
param.max_area = max_area;
db::DCplxTrans trans = db::DCplxTrans (db::DTrans (db::DPoint () - p->box ().center ()));
tris.triangulate (to_polygon (*p), param, trans);
triangulation.triangulate (to_polygon (*p), param, trans);
return polygons_from_triangles<P, db::DCplxTrans> (tris, trans.inverted ());
}
@ -134,14 +137,15 @@ static std::vector<P> triangulate_dpolygon (const P *p, double max_area = 0.0, d
template <class P>
static std::vector<P> triangulate_dpolygon_v (const P *p, const std::vector<db::DPoint> &vertexes, double max_area = 0.0, double min_b = 0.0)
{
db::Triangles tris;
db::Triangles::TriangulateParameters param;
db::plc::Graph tris;
db::plc::Triangulation triangulation (&tris);
db::plc::TriangulationParameters param;
param.min_b = min_b;
param.max_area = max_area;
db::DCplxTrans trans = db::DCplxTrans (db::DTrans (db::DPoint () - p->box ().center ()));
tris.triangulate (to_polygon (*p), vertexes, param, trans);
triangulation.triangulate (to_polygon (*p), vertexes, param, trans);
return polygons_from_triangles<P, db::DCplxTrans> (tris, trans.inverted ());
}

View File

@ -1,549 +0,0 @@
/*
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
*/
#include "dbTriangle.h"
#include "tlUnitTest.h"
#include <list>
#include <memory>
class TestableEdge
: public db::TriangleEdge
{
public:
using db::TriangleEdge::TriangleEdge;
using db::TriangleEdge::link;
using db::TriangleEdge::unlink;
TestableEdge (db::Vertex *v1, db::Vertex *v2)
: db::TriangleEdge (v1, v2)
{ }
};
// Tests for Vertex class
TEST(Vertex_basic)
{
db::Vertex v;
v.set_x (1.5);
v.set_y (0.5);
EXPECT_EQ (v.to_string (), "(1.5, 0.5)");
EXPECT_EQ (v.x (), 1.5);
EXPECT_EQ (v.y (), 0.5);
v = db::Vertex (db::DPoint (2, 3));
EXPECT_EQ (v.to_string (), "(2, 3)");
}
static std::string edges_from_vertex (const db::Vertex &v)
{
std::string res;
for (auto e = v.begin_edges (); e != v.end_edges (); ++e) {
if (! res.empty ()) {
res += ", ";
}
res += (*e)->to_string ();
}
return res;
}
static std::string triangles_from_vertex (const db::Vertex &v)
{
auto tri = v.triangles ();
std::string res;
for (auto t = tri.begin (); t != tri.end (); ++t) {
if (! res.empty ()) {
res += ", ";
}
res += (*t)->to_string ();
}
return res;
}
TEST(Vertex_edge_registration)
{
db::Vertex v1 (0, 0);
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
std::unique_ptr<TestableEdge> e1 (new TestableEdge (&v1, &v2));
e1->link ();
EXPECT_EQ (edges_from_vertex (v1), "((0, 0), (1, 2))");
EXPECT_EQ (edges_from_vertex (v2), "((0, 0), (1, 2))");
EXPECT_EQ (edges_from_vertex (v3), "");
std::unique_ptr<TestableEdge> e2 (new TestableEdge (&v2, &v3));
e2->link ();
EXPECT_EQ (edges_from_vertex (v1), "((0, 0), (1, 2))");
EXPECT_EQ (edges_from_vertex (v2), "((0, 0), (1, 2)), ((1, 2), (2, 1))");
EXPECT_EQ (edges_from_vertex (v3), "((1, 2), (2, 1))");
e2->unlink ();
e2.reset (0);
EXPECT_EQ (edges_from_vertex (v1), "((0, 0), (1, 2))");
EXPECT_EQ (edges_from_vertex (v2), "((0, 0), (1, 2))");
EXPECT_EQ (edges_from_vertex (v3), "");
e1->unlink ();
e1.reset (0);
EXPECT_EQ (edges_from_vertex (v1), "");
EXPECT_EQ (edges_from_vertex (v2), "");
EXPECT_EQ (edges_from_vertex (v3), "");
}
TEST(Vertex_triangles)
{
db::Vertex v1 (0, 0);
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
db::Vertex v4 (-1, 2);
EXPECT_EQ (triangles_from_vertex (v1), "");
std::unique_ptr<TestableEdge> e1 (new TestableEdge (&v1, &v2));
e1->link ();
std::unique_ptr<TestableEdge> e2 (new TestableEdge (&v2, &v3));
e2->link ();
std::unique_ptr<TestableEdge> e3 (new TestableEdge (&v3, &v1));
e3->link ();
std::unique_ptr<db::Triangle> tri (new db::Triangle (e1.get (), e2.get (), e3.get ()));
EXPECT_EQ (triangles_from_vertex (v1), "((0, 0), (1, 2), (2, 1))");
EXPECT_EQ (triangles_from_vertex (v2), "((0, 0), (1, 2), (2, 1))");
EXPECT_EQ (triangles_from_vertex (v3), "((0, 0), (1, 2), (2, 1))");
std::unique_ptr<TestableEdge> e4 (new TestableEdge (&v1, &v4));
e4->link ();
std::unique_ptr<TestableEdge> e5 (new TestableEdge (&v2, &v4));
e5->link ();
std::unique_ptr<db::Triangle> tri2 (new db::Triangle (e1.get (), e4.get (), e5.get ()));
EXPECT_EQ (triangles_from_vertex (v1), "((0, 0), (-1, 2), (1, 2)), ((0, 0), (1, 2), (2, 1))");
EXPECT_EQ (triangles_from_vertex (v2), "((0, 0), (-1, 2), (1, 2)), ((0, 0), (1, 2), (2, 1))");
EXPECT_EQ (triangles_from_vertex (v3), "((0, 0), (1, 2), (2, 1))");
EXPECT_EQ (triangles_from_vertex (v4), "((0, 0), (-1, 2), (1, 2))");
tri->unlink ();
EXPECT_EQ (triangles_from_vertex (v1), "((0, 0), (-1, 2), (1, 2))");
tri2->unlink ();
EXPECT_EQ (triangles_from_vertex (v1), "");
}
// Tests for Triangle class
TEST(Triangle_basic)
{
db::Vertex v1;
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
EXPECT_EQ (s1.v1 () == &v1, true);
EXPECT_EQ (s2.v2 () == &v3, true);
db::Triangle tri (&s1, &s2, &s3);
EXPECT_EQ (tri.to_string (), "((0, 0), (1, 2), (2, 1))");
EXPECT_EQ (tri.edge (-1) == &s3, true);
EXPECT_EQ (tri.edge (0) == &s1, true);
EXPECT_EQ (tri.edge (1) == &s2, true);
EXPECT_EQ (tri.edge (3) == &s1, true);
// ordering
TestableEdge s11 (&v1, &v2);
TestableEdge s12 (&v3, &v2);
TestableEdge s13 (&v1, &v3);
db::Triangle tri2 (&s11, &s12, &s13);
EXPECT_EQ (tri2.to_string (), "((0, 0), (1, 2), (2, 1))");
// triangle registration
EXPECT_EQ (s11.right () == &tri2, true);
EXPECT_EQ (s11.left () == 0, true);
EXPECT_EQ (s12.left () == &tri2, true);
EXPECT_EQ (s12.right () == 0, true);
EXPECT_EQ (s13.left () == &tri2, true);
EXPECT_EQ (s13.right () == 0, true);
EXPECT_EQ (s13.to_string (), "((0, 0), (2, 1))");
s13.reverse ();
EXPECT_EQ (s13.to_string (), "((2, 1), (0, 0))");
EXPECT_EQ (s13.right () == &tri2, true);
EXPECT_EQ (s13.left () == 0, true);
// flags
EXPECT_EQ (tri.is_outside (), false);
tri.set_outside (true);
EXPECT_EQ (tri.is_outside (), true);
}
TEST(Triangle_find_segment_with)
{
db::Vertex v1;
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
db::Triangle tri (&s1, &s2, &s3);
EXPECT_EQ (tri.find_edge_with (&v1, &v2)->to_string (), "((0, 0), (1, 2))");
EXPECT_EQ (tri.find_edge_with (&v2, &v1)->to_string (), "((0, 0), (1, 2))");
}
TEST(Triangle_ext_vertex)
{
db::Vertex v1;
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
db::Triangle tri (&s1, &s2, &s3);
EXPECT_EQ (tri.opposite (&s1)->to_string (), "(2, 1)");
EXPECT_EQ (tri.opposite (&s3)->to_string (), "(1, 2)");
}
TEST(Triangle_opposite_vertex)
{
db::Vertex v1;
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
db::Triangle tri (&s1, &s2, &s3);
EXPECT_EQ (tri.opposite (&s1)->to_string (), "(2, 1)");
EXPECT_EQ (tri.opposite (&s3)->to_string (), "(1, 2)");
}
TEST(Triangle_opposite_edge)
{
db::Vertex v1;
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
db::Triangle tri (&s1, &s2, &s3);
EXPECT_EQ (tri.opposite (&v1)->to_string (), "((1, 2), (2, 1))");
EXPECT_EQ (tri.opposite (&v3)->to_string (), "((0, 0), (1, 2))");
}
TEST(Triangle_contains)
{
db::Vertex v1;
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
{
db::Triangle tri (&s1, &s2, &s3);
EXPECT_EQ (tri.contains (db::DPoint (0, 0)), 0);
EXPECT_EQ (tri.contains (db::DPoint (-1, -2)), -1);
EXPECT_EQ (tri.contains (db::DPoint (0.5, 1)), 0);
EXPECT_EQ (tri.contains (db::DPoint (0.5, 2)), -1);
EXPECT_EQ (tri.contains (db::DPoint (2.5, 1)), -1);
EXPECT_EQ (tri.contains (db::DPoint (1, -1)), -1);
EXPECT_EQ (tri.contains (db::DPoint (1, 1)), 1);
}
s1.reverse ();
s2.reverse ();
s3.reverse ();
{
db::Triangle tri2 (&s3, &s2, &s1);
EXPECT_EQ (tri2.contains(db::DPoint(0, 0)), 0);
EXPECT_EQ (tri2.contains(db::DPoint(0.5, 1)), 0);
EXPECT_EQ (tri2.contains(db::DPoint(0.5, 2)), -1);
EXPECT_EQ (tri2.contains(db::DPoint(2.5, 1)), -1);
EXPECT_EQ (tri2.contains(db::DPoint(1, -1)), -1);
EXPECT_EQ (tri2.contains(db::DPoint(1, 1)), 1);
}
}
TEST(Triangle_contains_small)
{
db::Vertex v1;
db::Vertex v2 (0.001, 0.002);
db::Vertex v3 (0.002, 0.001);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
{
db::Triangle tri (&s1, &s2, &s3);
EXPECT_EQ (tri.contains (db::DPoint (0, 0)), 0);
EXPECT_EQ (tri.contains (db::DPoint (-0.001, -0.002)), -1);
EXPECT_EQ (tri.contains (db::DPoint (0.0005, 0.001)), 0);
EXPECT_EQ (tri.contains (db::DPoint (0.0005, 0.002)), -1);
EXPECT_EQ (tri.contains (db::DPoint (0.0025, 0.001)), -1);
EXPECT_EQ (tri.contains (db::DPoint (0.001, -0.001)), -1);
EXPECT_EQ (tri.contains (db::DPoint (0.001, 0.001)), 1);
}
s1.reverse ();
s2.reverse ();
s3.reverse ();
{
db::Triangle tri2 (&s3, &s2, &s1);
EXPECT_EQ (tri2.contains(db::DPoint(0, 0)), 0);
EXPECT_EQ (tri2.contains(db::DPoint(0.0005, 0.001)), 0);
EXPECT_EQ (tri2.contains(db::DPoint(0.0005, 0.002)), -1);
EXPECT_EQ (tri2.contains(db::DPoint(0.0025, 0.001)), -1);
EXPECT_EQ (tri2.contains(db::DPoint(0.001, -0.001)), -1);
EXPECT_EQ (tri2.contains(db::DPoint(0.001, 0.001)), 1);
}
}
TEST(Triangle_circumcircle)
{
db::Vertex v1;
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v2, &v3);
TestableEdge s3 (&v3, &v1);
db::Triangle tri (&s1, &s2, &s3);
auto cc = tri.circumcircle ();
auto center = cc.first;
auto radius = cc.second;
EXPECT_EQ (tl::to_string (center), "0.833333333333,0.833333333333");
EXPECT_EQ (tl::to_string (radius), "1.17851130198");
EXPECT_EQ (db::Vertex::in_circle (center, center, radius), 1);
EXPECT_EQ (db::Vertex::in_circle (db::DPoint (-1, -1), center, radius), -1);
EXPECT_EQ (v1.in_circle (center, radius), 0);
EXPECT_EQ (v2.in_circle (center, radius), 0);
EXPECT_EQ (v3.in_circle (center, radius), 0);
}
// Tests for TriangleEdge class
TEST(TriangleEdge_basic)
{
db::Vertex v1;
db::Vertex v2 (1, 0.5);
TestableEdge edge (&v1, &v2);
EXPECT_EQ (edge.to_string (), "((0, 0), (1, 0.5))");
EXPECT_EQ (edge.is_segment (), false);
edge.set_is_segment (true);
EXPECT_EQ (edge.is_segment (), true);
EXPECT_EQ (edge.level (), size_t (0));
edge.set_level (42);
EXPECT_EQ (edge.level (), size_t (42));
EXPECT_EQ (edge.other (&v1) == &v2, true);
EXPECT_EQ (edge.other (&v2) == &v1, true);
}
TEST(TriangleEdge_triangles)
{
db::Vertex v1 (0, 0);
db::Vertex v2 (1, 2);
db::Vertex v3 (2, 1);
db::Vertex v4 (-1, 2);
std::unique_ptr<TestableEdge> e1 (new TestableEdge (&v1, &v2));
std::unique_ptr<TestableEdge> e2 (new TestableEdge (&v2, &v3));
std::unique_ptr<TestableEdge> e3 (new TestableEdge (&v3, &v1));
std::unique_ptr<db::Triangle> tri (new db::Triangle (e1.get (), e2.get (), e3.get ()));
std::unique_ptr<TestableEdge> e4 (new TestableEdge (&v1, &v4));
std::unique_ptr<TestableEdge> e5 (new TestableEdge (&v2, &v4));
std::unique_ptr<db::Triangle> tri2 (new db::Triangle (e1.get (), e4.get (), e5.get ()));
EXPECT_EQ (e1->is_outside (), false);
EXPECT_EQ (e2->is_outside (), true);
EXPECT_EQ (e4->is_outside (), true);
EXPECT_EQ (e1->is_for_outside_triangles (), false);
tri->set_outside (true);
EXPECT_EQ (e1->is_for_outside_triangles (), true);
EXPECT_EQ (e1->has_triangle (tri.get ()), true);
EXPECT_EQ (e1->has_triangle (tri2.get ()), true);
EXPECT_EQ (e4->has_triangle (tri.get ()), false);
EXPECT_EQ (e4->has_triangle (tri2.get ()), true);
EXPECT_EQ (e1->other (tri.get ()) == tri2.get (), true);
EXPECT_EQ (e1->other (tri2.get ()) == tri.get (), true);
EXPECT_EQ (e1->common_vertex (e2.get ()) == &v2, true);
EXPECT_EQ (e2->common_vertex (e4.get ()) == 0, true);
tri->unlink ();
EXPECT_EQ (e1->has_triangle (tri.get ()), false);
EXPECT_EQ (e1->has_triangle (tri2.get ()), true);
}
TEST(TriangleEdge_side_of)
{
db::Vertex v1;
db::Vertex v2 (1, 0.5);
TestableEdge edge (&v1, &v2);
EXPECT_EQ (edge.to_string (), "((0, 0), (1, 0.5))");
EXPECT_EQ (edge.side_of (db::Vertex (0, 0)), 0)
EXPECT_EQ (edge.side_of (db::Vertex (0.5, 0.25)), 0)
EXPECT_EQ (edge.side_of (db::Vertex (0, 1)), -1)
EXPECT_EQ (edge.side_of (db::Vertex (0, -1)), 1)
EXPECT_EQ (edge.side_of (db::Vertex (0.5, 0.5)), -1)
EXPECT_EQ (edge.side_of (db::Vertex (0.5, 0)), 1)
db::Vertex v3 (1, 0);
db::Vertex v4 (0, 1);
TestableEdge edge2 (&v3, &v4);
EXPECT_EQ (edge2.side_of (db::Vertex(0.2, 0.2)), -1);
}
namespace {
class VertexHeap
{
public:
db::Vertex *make_vertex (double x, double y)
{
m_heap.push_back (db::Vertex (x, y));
return &m_heap.back ();
}
private:
std::list<db::Vertex> m_heap;
};
}
TEST(TriangleEdge_crosses)
{
VertexHeap heap;
TestableEdge s1 (heap.make_vertex (0, 0), heap.make_vertex (1, 0.5));
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, -0.5), heap.make_vertex(1, -0.5))), false);
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, 0), heap.make_vertex(1, 0))), false); // only cuts
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, 0.5), heap.make_vertex(1, 0.5))), false);
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, 0.5), heap.make_vertex(2, 0.5))), false);
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, 0.25), heap.make_vertex(2, 0.25))), true);
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, 0.5), heap.make_vertex(-0.1, 0.5))), false);
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, 0.6), heap.make_vertex(0, 0.6))), false);
EXPECT_EQ (s1.crosses (TestableEdge (heap.make_vertex (-1, 1), heap.make_vertex(1, 1))), false);
EXPECT_EQ (s1.crosses_including (TestableEdge (heap.make_vertex (-1, -0.5), heap.make_vertex(1, -0.5))), false);
EXPECT_EQ (s1.crosses_including (TestableEdge (heap.make_vertex (-1, 0), heap.make_vertex(1, 0))), true); // only cuts
EXPECT_EQ (s1.crosses_including (TestableEdge (heap.make_vertex (-1, 0.25), heap.make_vertex(2, 0.25))), true);
}
TEST(TriangleEdge_point_on)
{
VertexHeap heap;
TestableEdge s1 (heap.make_vertex (0, 0), heap.make_vertex (1, 0.5));
EXPECT_EQ (s1.point_on (db::DPoint (0, 0)), false); // endpoints are not "on"
EXPECT_EQ (s1.point_on (db::DPoint (0, -0.5)), false);
EXPECT_EQ (s1.point_on (db::DPoint (0.5, 0)), false);
EXPECT_EQ (s1.point_on (db::DPoint (0.5, 0.25)), true);
EXPECT_EQ (s1.point_on (db::DPoint (1, 0.5)), false); // endpoints are not "on"
EXPECT_EQ (s1.point_on (db::DPoint (1, 1)), false);
EXPECT_EQ (s1.point_on (db::DPoint (2, 1)), false);
}
TEST(TriangleEdge_intersection_point)
{
VertexHeap heap;
TestableEdge s1 (heap.make_vertex (0, 0), heap.make_vertex (1, 0.5));
EXPECT_EQ (s1.intersection_point (TestableEdge (heap.make_vertex (-1, 0.25), heap.make_vertex (2, 0.25))).to_string (), "0.5,0.25");
}
TEST(TriangleEdge_can_flip)
{
db::Vertex v1 (2, -1);
db::Vertex v2 (0, 0);
db::Vertex v3 (1, 0);
db::Vertex v4 (0.5, 1);
TestableEdge s1 (&v1, &v2);
TestableEdge s2 (&v1, &v3);
TestableEdge s3 (&v2, &v3);
TestableEdge s4 (&v2, &v4);
TestableEdge s5 (&v3, &v4);
db::Triangle t1 (&s1, &s2, &s3);
db::Triangle t2 (&s3, &s4, &s5);
EXPECT_EQ (s3.left () == &t2, true);
EXPECT_EQ (s3.right () == &t1, true);
EXPECT_EQ (s3.can_flip(), false);
v1.set_x (0.5);
EXPECT_EQ (s3.can_flip(), true);
v1.set_x (-0.25);
EXPECT_EQ (s3.can_flip(), true);
v1.set_x (-0.5);
EXPECT_EQ (s3.can_flip(), false);
v1.set_x (-1.0);
EXPECT_EQ (s3.can_flip(), false);
}
TEST(TriangleEdge_distance)
{
db::Vertex v1 (0, 0);
db::Vertex v2 (1, 0);
TestableEdge seg (&v1, &v2);
EXPECT_EQ (seg.distance (db::DPoint (0, 0)), 0);
EXPECT_EQ (seg.distance (db::DPoint (0, 1)), 1);
EXPECT_EQ (seg.distance (db::DPoint (1, 2)), 2);
EXPECT_EQ (seg.distance (db::DPoint (1, -1)), 1);
EXPECT_EQ (seg.distance (db::DPoint (2, 0)), 1);
EXPECT_EQ (seg.distance (db::DPoint (-2, 0)), 2);
seg.reverse ();
EXPECT_EQ (seg.distance (db::DPoint (0, 0)), 0);
EXPECT_EQ (seg.distance (db::DPoint (0, 1)), 1);
EXPECT_EQ (seg.distance (db::DPoint (1, 2)), 2);
EXPECT_EQ (seg.distance (db::DPoint (1, -1)), 1);
EXPECT_EQ (seg.distance (db::DPoint (2, 0)), 1);
EXPECT_EQ (seg.distance (db::DPoint (-2, 0)), 2);
}

File diff suppressed because it is too large Load Diff

View File

@ -20,8 +20,6 @@ SOURCES = \
dbQuadTreeTests.cc \
dbRecursiveInstanceIteratorTests.cc \
dbRegionCheckUtilsTests.cc \
dbTriangleTests.cc \
dbTrianglesTests.cc \
dbUtilsTests.cc \
dbWriterTools.cc \
dbLoadLayoutOptionsTests.cc \