Merge pull request #2431 from KLayout/bugfix/issue-2429

Bugfix: Fixing issue #2429 (PEX error)
This commit is contained in:
Matthias Köfferlein
2026-08-23 14:03:58 +02:00
committed by GitHub
16 changed files with 156 additions and 84 deletions
+4 -4
View File
@@ -903,10 +903,10 @@ Graph::bbox () const
}
db::Layout *
Graph::to_layout (bool decompose_by_id) const
Graph::to_layout (bool decompose_by_id, double dbu) const
{
db::Layout *layout = new db::Layout ();
layout->dbu (0.001);
layout->dbu (dbu);
auto dbu_trans = db::CplxTrans (layout->dbu ()).inverted ();
@@ -950,9 +950,9 @@ Graph::to_layout (bool decompose_by_id) const
}
void
Graph::dump (const std::string &path, bool decompose_by_id) const
Graph::dump (const std::string &path, bool decompose_by_id, double dbu) const
{
std::unique_ptr<db::Layout> ly (to_layout (decompose_by_id));
std::unique_ptr<db::Layout> ly (to_layout (decompose_by_id, dbu));
tl::OutputStream stream (path);
+2 -2
View File
@@ -879,13 +879,13 @@ public:
* according to bit 0, 1 and 2 of the ID (useful with the 'mark_polygons'
* flat in TriangulateParameters).
*/
void dump (const std::string &path, bool decompose_by_id = false) const;
void dump (const std::string &path, bool decompose_by_id = false, double dbu = 0.001) const;
/**
* @brief Creates a new layout object representing the polygon graph
* This method is for testing purposes mainly.
*/
db::Layout *to_layout (bool decompose_by_id = false) const;
db::Layout *to_layout (bool decompose_by_id = false, double dbu = 0.001) const;
protected:
Vertex *create_vertex (double x, double y);
+70 -49
View File
@@ -42,11 +42,8 @@ static inline bool is_equal (const db::DPoint &a, const db::DPoint &b)
std::abs (a.y () - b.y ()) < std::max (1.0, (std::abs (a.y ()) + std::abs (b.y ()))) * db::epsilon;
}
// distance of point to vertex to be considered "on edge vertex" relative to edge length involved
const double snap_to_edge_vertex = 1e-5;
// distance of point to edge center to be considered "on edge center" relative to edge length involved
double snap_to_edge_center = 1e-3;
const double snap_to_edge_center = 1e-3;
Triangulation::Triangulation (Graph *graph)
@@ -238,70 +235,67 @@ Triangulation::insert_point (db::DCoord x, db::DCoord y, std::list<tl::weak_ptr<
Vertex *
Triangulation::insert (Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles)
{
std::vector<Polygon *> tris = find_triangle_for_point (*vertex);
Polygon *in_triangle = 0;
Edge *on_edge = 0;
// the new vertex is outside the domain
if (tris.empty ()) {
if (! find_triangle_for_point (*vertex, in_triangle, on_edge)) {
// the new vertex is outside the domain
tl_assert (! m_is_constrained);
insert_new_vertex (vertex, new_triangles);
return vertex;
}
// check, if the new vertex is on an edge (may be edge between triangles or edge on outside)
Edge *on_edge = 0;
std::vector<Edge *> on_vertex;
for (int i = 0; i < 3; ++i) {
Edge *e = tris.front ()->edge (i);
double snap_range = snap_to_edge_vertex * e->length ();
if (std::abs (e->edge ().distance (*vertex)) < snap_range - db::epsilon) {
if (vertex->distance (*e->v1 ()) < snap_range + db::epsilon || vertex->distance (*e->v2 ()) < snap_range + db::epsilon) {
on_vertex.push_back (e);
} else if (! on_edge) {
on_edge = e;
}
}
}
if (on_edge) {
split_triangles_on_edge (vertex, on_edge, new_triangles);
if (is_equal (*vertex, *on_edge->v1 ())) {
return on_edge->v1 ();
} else if (is_equal (*vertex, *on_edge->v2 ())) {
return on_edge->v2 ();
} else {
split_triangles_on_edge (vertex, on_edge, new_triangles);
return vertex;
}
} else if (in_triangle) {
split_triangle (in_triangle, vertex, new_triangles);
return vertex;
} else if (! on_vertex.empty ()) {
} else {
tl_assert (on_vertex.size () == size_t (2));
return on_vertex.front ()->common_vertex (on_vertex [1]);
} else if (tris.size () == size_t (1)) {
// the new vertex is inside one triangle
split_triangle (tris.front (), vertex, new_triangles);
return vertex;
tl_assert (false);
return 0;
}
tl_assert (false);
}
std::vector<Polygon *>
Triangulation::find_triangle_for_point (const db::DPoint &point)
bool Triangulation::find_triangle_for_point (const db::DPoint &point, Polygon *&in_triangle, Edge *&on_edge)
{
Edge *edge = find_closest_edge (point);
std::vector<Polygon *> res;
if (edge) {
for (auto t = edge->begin_polygons (); t != edge->end_polygons (); ++t) {
if (t->contains (point) >= 0) {
res.push_back (t.operator-> ());
if (edge->side_of (point) == 0) {
on_edge = edge;
return true;
} else {
for (auto t = edge->begin_polygons (); t != edge->end_polygons (); ++t) {
if (t->contains (point) >= 0) {
in_triangle = t.operator-> ();
return true;
}
}
}
}
return res;
return false;
}
Edge *
@@ -1140,17 +1134,23 @@ static bool is_touching (const db::DEdge &a, const db::DEdge &b)
std::vector<Edge *>
Triangulation::ensure_edge_inner (Vertex *from, Vertex *to)
{
auto crossed_edges = search_edges_crossing (from, to);
std::vector<Edge *> result;
// check if there is an edge already
Edge *already_there = find_edge_for_points (*from, *to);
if (already_there) {
result.push_back (already_there);
return result;
}
auto crossed_edges = search_edges_crossing (from, to);
db::DEdge dedge (*from , *to);
if (crossed_edges.empty ()) {
// no crossing edge - there should be a edge already
Edge *res = find_edge_for_points (*from, *to);
tl_assert (res != 0);
result.push_back (res);
tl_assert (false);
} else if (crossed_edges.size () == 1 && ! is_touching (dedge, crossed_edges.front ()->edge ())) {
@@ -1171,7 +1171,7 @@ Triangulation::ensure_edge_inner (Vertex *from, Vertex *to)
db::DPoint p = (*e)->intersection_point (dedge);
double dp = fabs ((p - *from).sq_length () - l_half);
if (d < 0.0 || dp < d) {
dp = d;
d = dp;
split_point = p;
split_edge = *e;
}
@@ -1396,6 +1396,9 @@ template DB_PUBLIC void Triangulation::make_contours (const db::DPolygon &, cons
void
Triangulation::create_constrained_delaunay (const db::Region &region, const CplxTrans &trans)
{
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (region.bbox ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
for (auto p = region.begin_merged (); ! p.at_end (); ++p) {
@@ -1408,6 +1411,9 @@ Triangulation::create_constrained_delaunay (const db::Region &region, const Cplx
void
Triangulation::create_constrained_delaunay (const db::Polygon &p, const CplxTrans &trans)
{
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (p.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (p, trans, edge_contours);
@@ -1417,6 +1423,9 @@ Triangulation::create_constrained_delaunay (const db::Polygon &p, const CplxTran
void
Triangulation::create_constrained_delaunay (const db::DPolygon &p, const DCplxTrans &trans)
{
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::DPolygon (p.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (p, trans, edge_contours);
@@ -1485,6 +1494,9 @@ Triangulation::triangulate (const db::Region &region, const std::vector<db::Poin
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (region.bbox ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
for (auto p = region.begin_merged (); ! p.at_end (); ++p) {
make_contours (*p, trans, edge_contours);
@@ -1514,6 +1526,9 @@ Triangulation::triangulate (const db::Polygon &poly, const std::vector<db::Point
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (poly.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (poly, trans, edge_contours);
@@ -1539,6 +1554,9 @@ Triangulation::triangulate (const db::Polygon &poly, const std::vector<db::Point
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::Polygon (poly.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (poly, trans, edge_contours);
@@ -1564,6 +1582,9 @@ Triangulation::triangulate (const db::DPolygon &poly, const std::vector<db::DPoi
clear ();
std::vector<std::vector<Vertex *> > box_contours;
make_contours (db::DPolygon (poly.box ()), trans, box_contours);
std::vector<std::vector<Vertex *> > edge_contours;
make_contours (poly, trans, edge_contours);
+1 -1
View File
@@ -335,7 +335,7 @@ private:
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);
bool find_triangle_for_point (const db::DPoint &point, Polygon *&in_triangle, Edge *&on_edge);
Edge *find_closest_edge (const db::DPoint &p, Vertex *vstart = 0, bool inside_only = false) const;
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);
+68 -19
View File
@@ -896,8 +896,8 @@ TEST(triangulate_geo)
}
EXPECT_LT (n_skinny, size_t (20));
EXPECT_GT (plc.num_polygons (), size_t (29000));
EXPECT_LT (plc.num_polygons (), size_t (30000));
EXPECT_GT (plc.num_polygons (), size_t (30000));
EXPECT_LT (plc.num_polygons (), size_t (30200));
}
TEST(triangulate_analytic)
@@ -951,8 +951,8 @@ TEST(triangulate_analytic)
EXPECT_GE (t->b (), param.min_b);
}
EXPECT_GT (plc.num_polygons (), size_t (1250));
EXPECT_LT (plc.num_polygons (), size_t (1300));
EXPECT_GT (plc.num_polygons (), size_t (1300));
EXPECT_LT (plc.num_polygons (), size_t (1340));
}
TEST(triangulate_problematic)
@@ -1078,7 +1078,7 @@ TEST(triangulate_issue1996)
EXPECT_LT (plc.num_polygons (), size_t (132000));
}
TEST(triangulate_discussion_2883)
TEST(triangulate_issue_2429)
{
db::DPoint contour[] = {
db::DPoint (-13025.428, -33338.541),
@@ -1114,27 +1114,76 @@ TEST(triangulate_discussion_2883)
db::DPolygon poly;
poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0]));
double dbu = 0.001;
double dbu = 1.0;
db::plc::TriangulationParameters param;
param.min_b = 0.3;
{
db::plc::TriangulationParameters param;
param.min_b = 0.3;
param.max_area = 0.0;
db::plc::Graph plc;
TestableTriangulation tri (&plc);
db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ()));
tri.triangulate (trans * poly, param);
db::plc::Graph plc;
TestableTriangulation tri (&plc);
db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ()));
tri.triangulate (trans * poly, param);
EXPECT_EQ (tri.check (false), true);
EXPECT_EQ (tri.check (false), true);
// for debugging:
// tri.dump ("debug.gds");
// for debugging:
// tri.dump ("debug.gds");
for (auto t = plc.begin (); t != plc.end (); ++t) {
EXPECT_GE (t->b (), param.min_b);
for (auto t = plc.begin (); t != plc.end (); ++t) {
EXPECT_GE (t->b (), param.min_b);
}
EXPECT_GE (plc.num_polygons (), size_t (65));
EXPECT_LE (plc.num_polygons (), size_t (67));
}
EXPECT_GE (plc.num_polygons (), size_t (70));
EXPECT_LE (plc.num_polygons (), size_t (72));
{
db::plc::TriangulationParameters param;
param.min_b = 0.3;
param.max_area = 500.0;
db::plc::Graph plc;
TestableTriangulation tri (&plc);
db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ()));
tri.triangulate (trans * poly, param);
EXPECT_EQ (tri.check (false), true);
// for debugging:
// tri.dump ("debug.gds");
for (auto t = plc.begin (); t != plc.end (); ++t) {
EXPECT_GE (t->b (), param.min_b);
}
EXPECT_GE (plc.num_polygons (), size_t (94));
EXPECT_LE (plc.num_polygons (), size_t (96));
}
{
db::plc::TriangulationParameters param;
param.min_b = 0.9;
param.max_area = 50.0;
db::plc::Graph plc;
TestableTriangulation tri (&plc);
db::DCplxTrans trans = db::DCplxTrans (dbu) * db::DCplxTrans (db::DTrans (db::DPoint () - poly.box ().center ()));
tri.triangulate (trans * poly, param);
EXPECT_EQ (tri.check (false), true);
// for debugging:
// tri.dump ("debug.gds");
for (auto t = plc.begin (); t != plc.end (); ++t) {
EXPECT_GE (t->b (), param.min_b);
}
EXPECT_GE (plc.num_polygons (), size_t (670));
EXPECT_LE (plc.num_polygons (), size_t (676));
}
}
TEST(triangulate_with_vertexes)
+2
View File
@@ -339,6 +339,8 @@ private:
case RExtractorTechConductor::Tesselation:
{
pex::TriangulationRExtractor rex (m_dbu);
rex.triangulation_parameters ().max_area = mp_cond->triangulation_max_area;
rex.triangulation_parameters ().min_b = mp_cond->triangulation_min_b;
rex.extract (poly, local_vertex_ports, local_polygon_ports, local_network);
}
break;
@@ -357,7 +357,7 @@ TEST(extraction_meander)
rex.extract (poly, vertex_ports, polygon_ports, rn);
EXPECT_EQ (rn.to_string (),
"R V0 V1 8.61417" // what is the "real" value?
"R V0 V1 8.60459" // what is the "real" value?
)
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4 -4
View File
@@ -1062,15 +1062,15 @@ class DBPolygon_TestClass < TestBase
assert_equal(sorted_polygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_polygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_polygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
p = RBA::DPolygon::new([ [0, 0], [0, 100], [1000, 100], [1000, 1000], [1100, 1000], [1100, 100], [2200, 100], [2200, 0] ])
assert_equal(sorted_dpolygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_dpolygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_dpolygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
end
+4 -4
View File
@@ -452,15 +452,15 @@ class DBSimplePolygon_TestClass < TestBase
assert_equal(sorted_polygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_polygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_polygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
assert_equal(sorted_polygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_polygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
p = RBA::DSimplePolygon::new([ [0, 0], [0, 100], [1000, 100], [1000, 1000], [1100, 1000], [1100, 100], [2200, 100], [2200, 0] ])
assert_equal(sorted_dpolygons(p.hm_decomposition(false, false)), "(0,0;0,100;1000,100);(0,0;1000,100;1100,100);(0,0;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_dpolygons(p.hm_decomposition(true, false)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;1100,0);(1000,100;1000,1000;1100,1000;1100,100);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_dpolygons(p.hm_decomposition(false, true)), "(0,0;0,100;1000,100;1100,100;2200,100;2200,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1000,1000;1100,1000;1100,100;1100,0);(1100,0;1100,100;2200,100;2200,0)")
assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;500,100;1000,100;1100,0;825,0;550,0;275,0);(1000,100;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,325;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
assert_equal(sorted_dpolygons(p.hm_decomposition(true, true)), "(0,0;0,100;1000,100;1000,0);(1000,0;1000,100;1100,100;2200,100;2200,0;1100,0);(1000,100;1000,1000;1100,1000;1100,100)")
assert_equal(sorted_dpolygons(p.hm_decomposition(false, false, 0.0, 0.5)), "(0,0;0,100;250,100;500,100;1000,100;1100,0;825,0;550,0);(1000,100;1000,325;1000,550;1000,775;1000,1000;1100,1000;1100,550;1100,100);(1100,0;1000,100;1100,100);(1100,0;1100,100;1650,100;1925,100;2200,100;2200,0;1650,0;1375,0)")
end
end