This commit is contained in:
Matthias Koefferlein 2023-08-12 00:46:23 +02:00
parent 7bf23e7471
commit 495da3de23
8 changed files with 923 additions and 0 deletions

View File

@ -95,6 +95,8 @@ SOURCES = \
dbTextWriter.cc \
dbTilingProcessor.cc \
dbTrans.cc \
dbTriangle.cc \
dbTriangles.cc \
dbUserObject.cc \
dbUtils.cc \
dbVector.cc \
@ -319,6 +321,8 @@ HEADERS = \
dbTextWriter.h \
dbTilingProcessor.h \
dbTrans.h \
dbTriangle.h \
dbTriangles.h \
dbTypes.h \
dbUserObject.h \
dbUtils.h \

406
src/db/db/dbTriangle.cc Normal file
View File

@ -0,0 +1,406 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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_level (0)
{
// .. nothing yet ..
}
Vertex::Vertex (const db::DPoint &p)
: DPoint (p), m_level (0)
{
// .. nothing yet ..
}
Vertex::Vertex (db::DCoord x, db::DCoord y)
: DPoint (x, y), m_level (0)
{
// .. nothing yet ..
}
bool
Vertex::is_outside () const
{
for (auto e = m_edges.begin (); e != m_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 = m_edges.begin (); e != m_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;
}
std::string
Vertex::to_string () const
{
return db::DPoint::to_string () + tl::sprintf ("[%p]", (void *)this);
}
// -------------------------------------------------------------------------------------
// TriangleEdge implementation
TriangleEdge::TriangleEdge ()
: mp_v1 (0), mp_v2 (0), mp_left (), mp_right (), m_level (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_is_segment (false)
{
// .. nothing yet ..
}
Triangle *
TriangleEdge::other (const Triangle *t) const
{
if (t == mp_left.get ()) {
return const_cast<Triangle *> (mp_right.get ());
}
if (t == mp_right.get ()) {
return const_cast<Triangle *> (mp_left.get ());
}
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 () const
{
return mp_v1->to_string () + "," + mp_v2->to_string () + tl::sprintf ("[%p]", (void *)this);
}
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), mp_v1 (0), mp_v2 (0), mp_v3 (0)
{
// .. nothing yet ..
}
Triangle::Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3)
: m_is_outside (false), mp_e1 (e1), mp_e2 (e2), mp_e3 (e3)
{
mp_v1 = e1->v1 ();
mp_v2 = e1->other (mp_v1);
if (e2->has_vertex (mp_v2)) {
mp_v3 = e2->other (mp_v2);
tl_assert (e3->other (mp_v3) == mp_v1);
} else {
mp_v3 = e3->other (mp_v2);
tl_assert (e2->other (mp_v3) == mp_v1);
}
// enforce clockwise orientation
if (db::vprod_sign (*mp_v3 - *mp_v1, *mp_v2 - *mp_v1) < 0) {
std::swap (mp_v3, mp_v2);
}
// establish link to edges
for (int i = 0; i < 3; ++i) {
TriangleEdge *e = edge (i);
int side_of = 0;
for (int j = 0; j < 3; ++j) {
side_of += e->side_of (*vertex (j));
}
// NOTE: in the degenerated case, the triangle is not attached to an edge!
if (side_of < 0) {
e->set_left (this);
} else if (side_of > 0) {
e->set_right (this);
}
}
}
std::string
Triangle::to_string () const
{
std::string res;
for (int i = 0; i < 3; ++i) {
if (i > 0) {
res += ", ";
}
if (vertex (i)) {
res += vertex (i)->to_string ();
} else {
res += "(null)";
}
}
return res;
}
Vertex *
Triangle::vertex (int n) const
{
tl_assert (mp_e1 && mp_e2 && mp_e3);
n = (n + 3) % 3;
if (n == 0) {
return mp_v1;
} else if (n == 1) {
return mp_v2;
} else {
return mp_v3;
}
}
TriangleEdge *
Triangle::edge (int n) const
{
n = (n + 3) % 3;
if (n == 0) {
return const_cast<TriangleEdge *> (mp_e1.get ());
} else if (n == 1) {
return const_cast<TriangleEdge *> (mp_e2.get ());
} else {
return const_cast<TriangleEdge *> (mp_e3.get ());
}
}
double
Triangle::area () const
{
return fabs (db::vprod (mp_e1->d (), mp_e2->d ())) * 0.5;
}
std::pair<db::DPoint, double>
Triangle::circumcircle () const
{
db::DVector v1 = *vertex(0) - *vertex(1);
db::DVector v2 = *vertex(0) - *vertex(2);
db::DVector n1 = db::DVector (v1.y (), -v1.x ());
db::DVector n2 = db::DVector (v2.y (), -v2.x ());
double p1s = vertex(0)->sq_distance (db::DPoint ());
double p2s = vertex(1)->sq_distance (db::DPoint ());
double p3s = vertex(2)->sq_distance (db::DPoint ());
double s = db::vprod (v1, v2);
tl_assert (fabs (s) > db::epsilon);
db::DPoint center = db::DPoint () + (n2 * (p1s - p2s) - n1 * (p1s - p3s)) * (0.5 / s);
double radius = (*vertex (0) - center).length ();
return std::make_pair (center, radius);
}
Vertex *
Triangle::opposite (const TriangleEdge *edge) const
{
for (int i = 0; i < 3; ++i) {
Vertex *v = vertex (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 = edge (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 = edge (i);
if (e->has_vertex (v1) && e->has_vertex (v2)) {
return e;
}
}
tl_assert (false);
}
int
Triangle::contains (const db::DPoint &point) const
{
int res = 1;
const Vertex *vl = vertex (-1);
for (int i = 0; i < 3; ++i) {
const Vertex *v = vertex (i);
int s = db::DEdge (*vl, *v).side_of (point);
if (s == 0) {
res = 0;
} else if (s < 0) {
return -1;
}
vl = v;
}
return res;
}
}

388
src/db/db/dbTriangle.h Normal file
View File

@ -0,0 +1,388 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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"
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 Vertex
: public db::DPoint
{
public:
typedef tl::weak_collection<db::TriangleEdge> edges_type;
typedef edges_type::const_iterator edges_iterator;
Vertex ();
Vertex (const DPoint &p);
Vertex (db::DCoord x, db::DCoord y);
bool is_outside () const;
std::vector<db::Triangle *> triangles () const;
edges_iterator begin_edges () const { return m_edges.begin (); }
edges_iterator end_edges () const { return m_edges.end (); }
size_t level () const { return m_level; }
void set_level (size_t l) { m_level = l; }
std::string to_string () const;
private:
edges_type m_edges;
size_t m_level;
};
/**
* @brief A class representing an edge in the Delaunay triangulation graph
*/
class TriangleEdge
: public tl::Object
{
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 mp_edge == other.mp_edge && 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; }
Triangle *left () const { return const_cast<Triangle *> (mp_left.get ()); }
Triangle *right () const { return const_cast<Triangle *> (mp_right.get ()); }
void set_left (Triangle *t) { mp_left = t; }
void set_right (Triangle *t) { mp_right = t; }
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_is_segment (bool is_seg) { m_is_segment = is_seg; }
bool is_segment () const { return m_is_segment; }
std::string to_string () 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 wether 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 wether 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 wether 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 wether 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 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 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"
*/
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;
private:
Vertex *mp_v1, *mp_v2;
tl::weak_ptr<Triangle> mp_left, mp_right;
size_t m_level;
bool m_is_segment;
};
/**
* @brief A class representing a triangle
*/
class Triangle
: public tl::Object
{
public:
Triangle ();
Triangle (TriangleEdge *e1, TriangleEdge *e2, TriangleEdge *e3);
bool is_outside () const { return m_is_outside; }
void set_outside (bool o) { m_is_outside = o; }
std::string to_string () const;
/**
* @brief Gets the nth vertex (n wraps around and can be negative)
* The vertexes are oriented clockwise.
*/
Vertex *vertex (int n) const;
/**
* @brief Gets the nth edge (n wraps around and can be negative)
*/
TriangleEdge *edge (int n) const;
/**
* @brief Gets the area
*/
double area () const;
/**
* @brief Gets the center point and radius of the circumcircle
*/
std::pair<db::DPoint, double> circumcircle () 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 Returns a value indicating whether the point is inside (1), on the triangle (0) or outside (-1)
*/
int contains (const db::DPoint &point) const;
private:
bool m_is_outside;
tl::weak_ptr<TriangleEdge> mp_e1, mp_e2, mp_e3;
db::Vertex *mp_v1, *mp_v2, *mp_v3;
};
}
#endif

24
src/db/db/dbTriangles.cc Normal file
View File

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

39
src/db/db/dbTriangles.h Normal file
View File

@ -0,0 +1,39 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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"
namespace db
{
}
#endif

View File

@ -0,0 +1,30 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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"
TEST(1)
{
}

View File

@ -0,0 +1,30 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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 "dbTriangles.h"
#include "tlUnitTest.h"
TEST(1)
{
}

View File

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