mirror of https://github.com/KLayout/klayout.git
Compare commits
4 Commits
701bd3b543
...
f80c51bfd2
| Author | SHA1 | Date |
|---|---|---|
|
|
f80c51bfd2 | |
|
|
4ee73b5f86 | |
|
|
853a7d7a13 | |
|
|
eb06679c44 |
|
|
@ -110,6 +110,17 @@ Vertex::is_outside () const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Vertex::is_on_outline () const
|
||||||
|
{
|
||||||
|
for (auto e = mp_edges.begin (); e != mp_edges.end (); ++e) {
|
||||||
|
if ((*e)->is_segment ()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vertex::set_is_precious (bool f, unsigned int id)
|
Vertex::set_is_precious (bool f, unsigned int id)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,11 @@ public:
|
||||||
*/
|
*/
|
||||||
bool is_outside () const;
|
bool is_outside () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a value indicating whether is on the outline - i.e. one edge is a segment
|
||||||
|
*/
|
||||||
|
bool is_on_outline () const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets a list of polygons that are attached to this vertex
|
* @brief Gets a list of polygons that are attached to this vertex
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
// #define DEBUG_DUMP_ESSENTIAL_EDGES
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -286,65 +288,134 @@ ConvexDecomposition::hertel_mehlhorn_decomposition (Triangulation &tris, const C
|
||||||
// them one-by-one, but using them in length order, from the
|
// them one-by-one, but using them in length order, from the
|
||||||
|
|
||||||
std::unordered_set<const Edge *> essential_edges;
|
std::unordered_set<const Edge *> essential_edges;
|
||||||
|
std::unordered_set<const Vertex *> concave_vertexes_seen;
|
||||||
|
|
||||||
typedef std::list<std::pair<double, const Edge *> > angles_and_edges_list;
|
while (! concave_vertexes.empty ()) {
|
||||||
angles_and_edges_list angles_and_edges;
|
|
||||||
std::vector<angles_and_edges_list::iterator> sorted_edges;
|
|
||||||
|
|
||||||
for (auto cc = concave_vertexes.begin (); cc != concave_vertexes.end (); ++cc) {
|
typedef std::list<std::pair<double, const Edge *> > angles_and_edges_list;
|
||||||
|
angles_and_edges_list angles_and_edges;
|
||||||
|
std::vector<angles_and_edges_list::iterator> sorted_edges;
|
||||||
|
|
||||||
angles_and_edges.clear ();
|
std::unordered_set<const Vertex *> new_inner_vertexes;
|
||||||
const Vertex *v0 = cc->corner;
|
|
||||||
|
|
||||||
const Edge *e = cc->incoming;
|
for (auto cc = concave_vertexes.begin (); cc != concave_vertexes.end (); ++cc) {
|
||||||
while (e) {
|
|
||||||
|
|
||||||
const Polygon *t = e->v2 () == v0 ? e->right () : e->left ();
|
angles_and_edges.clear ();
|
||||||
tl_assert (t != 0);
|
const Vertex *v0 = cc->corner;
|
||||||
|
|
||||||
const Edge *en = t->next_edge (e, v0);
|
concave_vertexes_seen.insert (v0);
|
||||||
tl_assert (en != 0);
|
|
||||||
|
|
||||||
db::DVector v1 = e->edge ().d () * (e->v1 () == v0 ? 1.0 : -1.0);
|
const Edge *e = cc->incoming;
|
||||||
db::DVector v2 = en->edge ().d () * (en->v1 () == v0 ? 1.0 : -1.0);
|
while (e) {
|
||||||
|
|
||||||
double angle = atan2 (db::vprod (v1, v2), db::sprod (v1, v2));
|
const Polygon *t = e->v2 () == v0 ? e->right () : e->left ();
|
||||||
|
tl_assert (t != 0);
|
||||||
|
|
||||||
e = (en == cc->outgoing) ? 0 : en;
|
const Edge *en = t->next_edge (e, v0);
|
||||||
angles_and_edges.push_back (std::make_pair (angle, e));
|
tl_assert (en != 0);
|
||||||
|
|
||||||
|
db::DVector v1 = e->edge ().d () * (e->v1 () == v0 ? 1.0 : -1.0);
|
||||||
|
db::DVector v2 = en->edge ().d () * (en->v1 () == v0 ? 1.0 : -1.0);
|
||||||
|
|
||||||
|
double angle = atan2 (db::vprod (v1, v2), db::sprod (v1, v2));
|
||||||
|
|
||||||
|
e = (en == cc->outgoing) ? 0 : en;
|
||||||
|
angles_and_edges.push_back (std::make_pair (angle, e));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted_edges.clear ();
|
||||||
|
|
||||||
|
for (auto i = angles_and_edges.begin (); i != angles_and_edges.end (); ++i) {
|
||||||
|
if (i->second) {
|
||||||
|
sorted_edges.push_back (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort (sorted_edges.begin (), sorted_edges.end (), SortAngleAndEdgesByEdgeLength ());
|
||||||
|
|
||||||
|
for (auto i = sorted_edges.end (); i != sorted_edges.begin (); ) {
|
||||||
|
--i;
|
||||||
|
angles_and_edges_list::iterator ii = *i;
|
||||||
|
angles_and_edges_list::iterator iin = ii;
|
||||||
|
++iin;
|
||||||
|
if (ii->first + iin->first < (split_edges ? M_PI + db::epsilon : M_PI - db::epsilon)) {
|
||||||
|
// not an essential edge -> remove
|
||||||
|
iin->first += ii->first;
|
||||||
|
angles_and_edges.erase (ii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i = angles_and_edges.begin (); i != angles_and_edges.end (); ++i) {
|
||||||
|
if (i->second) {
|
||||||
|
essential_edges.insert (i->second);
|
||||||
|
// record new endpoints of essential edges which are inside the polygon - i.e. they
|
||||||
|
// have a segment attached. Below we will turn them into new concave "corners" and
|
||||||
|
// continue deriving essential edges from there.
|
||||||
|
if (! i->second->v1 ()->is_on_outline () && concave_vertexes_seen.find (i->second->v1 ()) == concave_vertexes_seen.end ()) {
|
||||||
|
new_inner_vertexes.insert (i->second->v1 ());
|
||||||
|
}
|
||||||
|
if (! i->second->v2 ()->is_on_outline () && concave_vertexes_seen.find (i->second->v2 ()) == concave_vertexes_seen.end ()) {
|
||||||
|
new_inner_vertexes.insert (i->second->v2 ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sorted_edges.clear ();
|
// new inner vertexes (i.e. endpoints of essential edges inside the polygon) are treated as new convex vertexes
|
||||||
|
|
||||||
for (auto i = angles_and_edges.begin (); i != angles_and_edges.end (); ++i) {
|
concave_vertexes.clear ();
|
||||||
if (i->second) {
|
|
||||||
sorted_edges.push_back (i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::sort (sorted_edges.begin (), sorted_edges.end (), SortAngleAndEdgesByEdgeLength ());
|
for (auto i = new_inner_vertexes.begin (); i != new_inner_vertexes.end (); ++i) {
|
||||||
|
|
||||||
for (auto i = sorted_edges.end (); i != sorted_edges.begin (); ) {
|
const Vertex *v0 = *i;
|
||||||
--i;
|
auto ie = v0->begin_edges ();
|
||||||
angles_and_edges_list::iterator ii = *i;
|
for ( ; ie != v0->end_edges () && essential_edges.find (*ie) == essential_edges.end (); ++ie)
|
||||||
angles_and_edges_list::iterator iin = ii;
|
;
|
||||||
++iin;
|
tl_assert (ie != v0->end_edges ());
|
||||||
if (ii->first + iin->first < (split_edges ? M_PI + db::epsilon : M_PI - db::epsilon)) {
|
const Edge *e = *ie;
|
||||||
// not an essential edge -> remove
|
|
||||||
iin->first += ii->first;
|
|
||||||
angles_and_edges.erase (ii);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto i = angles_and_edges.begin (); i != angles_and_edges.end (); ++i) {
|
const Edge *en = e;
|
||||||
if (i->second) {
|
|
||||||
essential_edges.insert (i->second);
|
do {
|
||||||
}
|
|
||||||
|
const Edge *enn = en;
|
||||||
|
|
||||||
|
// look for the next edge (clockwise) which is an essential edge
|
||||||
|
do {
|
||||||
|
const Polygon *t = enn->v2 () == v0 ? enn->right () : enn->left ();
|
||||||
|
tl_assert (t != 0);
|
||||||
|
enn = t->next_edge (enn, v0);
|
||||||
|
tl_assert (enn != 0);
|
||||||
|
} while (enn != en && essential_edges.find (enn) == essential_edges.end ());
|
||||||
|
|
||||||
|
db::DEdge e1 (*en->other (v0), *v0);
|
||||||
|
db::DEdge e2 (*v0, *enn->other (v0));
|
||||||
|
|
||||||
|
// vp > 0: concave, vp < 0: convex
|
||||||
|
int vp_sign = db::vprod_sign (e1, e2);
|
||||||
|
if (vp_sign > 0 || en == enn /*folding back*/) {
|
||||||
|
concave_vertexes.push_back (ConcaveCorner (v0, en, enn));
|
||||||
|
}
|
||||||
|
|
||||||
|
en = enn;
|
||||||
|
|
||||||
|
} while (en != e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(DEBUG_DUMP_ESSENTIAL_EDGES)
|
||||||
|
// dump the essential edges for debugging
|
||||||
|
db::Edges edges;
|
||||||
|
for (auto e = essential_edges.begin (); e != essential_edges.end (); ++e) {
|
||||||
|
db::DEdge de = (*e)->edge ();
|
||||||
|
edges.insert (db::VCplxTrans (1000.0) * de);
|
||||||
|
}
|
||||||
|
edges.write ("debug_dump_essential_edges.gds");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Combine triangles, but don't cross essential edges
|
// Combine triangles, but don't cross essential edges
|
||||||
|
|
||||||
std::unordered_set<const Polygon *> left_triangles;
|
std::unordered_set<const Polygon *> left_triangles;
|
||||||
|
|
|
||||||
|
|
@ -136,14 +136,14 @@ private:
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
ConcaveCorner (Vertex *_corner, Edge *_incoming, Edge *_outgoing)
|
ConcaveCorner (const Vertex *_corner, const Edge *_incoming, const Edge *_outgoing)
|
||||||
: corner (_corner), incoming (_incoming), outgoing (_outgoing)
|
: corner (_corner), incoming (_incoming), outgoing (_outgoing)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex *corner;
|
const Vertex *corner;
|
||||||
Edge *incoming, *outgoing;
|
const Edge *incoming, *outgoing;
|
||||||
};
|
};
|
||||||
|
|
||||||
void hertel_mehlhorn_decomposition (Triangulation &tris, const ConvexDecompositionParameters ¶m);
|
void hertel_mehlhorn_decomposition (Triangulation &tris, const ConvexDecompositionParameters ¶m);
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include "dbPLCConvexDecomposition.h"
|
#include "dbPLCConvexDecomposition.h"
|
||||||
#include "dbWriter.h"
|
#include "dbWriter.h"
|
||||||
|
#include "dbReader.h"
|
||||||
|
#include "dbLayout.h"
|
||||||
#include "dbRegionProcessors.h"
|
#include "dbRegionProcessors.h"
|
||||||
#include "dbTestSupport.h"
|
#include "dbTestSupport.h"
|
||||||
#include "tlUnitTest.h"
|
#include "tlUnitTest.h"
|
||||||
|
|
@ -144,3 +146,80 @@ TEST(problematic_polygon)
|
||||||
db::compare_layouts (_this, *ly, tl::testdata () + "/algo/hm_decomposition_au5.gds");
|
db::compare_layouts (_this, *ly, tl::testdata () + "/algo/hm_decomposition_au5.gds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(problematic_polygon2)
|
||||||
|
{
|
||||||
|
db::Point contour[] = {
|
||||||
|
db::Point (-2100, 200),
|
||||||
|
db::Point (-2100, 2000),
|
||||||
|
db::Point (-500, 2000),
|
||||||
|
db::Point (-500, 1700),
|
||||||
|
db::Point (-849, 1700),
|
||||||
|
db::Point (-947, 1690),
|
||||||
|
db::Point (-1043, 1671),
|
||||||
|
db::Point (-1137, 1643),
|
||||||
|
db::Point (-1228, 1605),
|
||||||
|
db::Point (-1315, 1559),
|
||||||
|
db::Point (-1396, 1504),
|
||||||
|
db::Point (-1472, 1442),
|
||||||
|
db::Point (-1542, 1372),
|
||||||
|
db::Point (-1604, 1296),
|
||||||
|
db::Point (-1659, 1215),
|
||||||
|
db::Point (-1705, 1128),
|
||||||
|
db::Point (-1743, 1037),
|
||||||
|
db::Point (-1771, 943),
|
||||||
|
db::Point (-1790, 847),
|
||||||
|
db::Point (-1800, 749),
|
||||||
|
db::Point (-1800, 200)
|
||||||
|
};
|
||||||
|
|
||||||
|
db::Polygon poly;
|
||||||
|
poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0]));
|
||||||
|
|
||||||
|
double dbu = 0.001;
|
||||||
|
|
||||||
|
db::plc::ConvexDecompositionParameters param;
|
||||||
|
param.with_segments = false;
|
||||||
|
param.split_edges = false;
|
||||||
|
param.tri_param.max_area = 1000000;
|
||||||
|
param.tri_param.min_b = 0.5;
|
||||||
|
|
||||||
|
db::plc::Graph plc;
|
||||||
|
TestableConvexDecomposition decomp (&plc);
|
||||||
|
|
||||||
|
decomp.decompose (poly, param, dbu);
|
||||||
|
|
||||||
|
std::unique_ptr<db::Layout> ly (plc.to_layout ());
|
||||||
|
db::compare_layouts (_this, *ly, tl::testdata () + "/algo/hm_decomposition_au6.gds");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(polygon_with_holes)
|
||||||
|
{
|
||||||
|
db::Layout ly;
|
||||||
|
tl::InputStream s (tl::testdata () + "/algo/hm_decomposition_7.gds");
|
||||||
|
db::Reader reader (s);
|
||||||
|
reader.read (ly);
|
||||||
|
|
||||||
|
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||||
|
const db::Cell &top = ly.cell (*ly.begin_top_down ());
|
||||||
|
|
||||||
|
db::Region r (db::RecursiveShapeIterator (ly, top, l1));
|
||||||
|
r.merge ();
|
||||||
|
db::Polygon poly = *r.begin ();
|
||||||
|
|
||||||
|
double dbu = 0.001;
|
||||||
|
|
||||||
|
db::plc::ConvexDecompositionParameters param;
|
||||||
|
param.with_segments = false;
|
||||||
|
param.split_edges = false;
|
||||||
|
param.tri_param.max_area = 1000000;
|
||||||
|
param.tri_param.min_b = 0.5;
|
||||||
|
|
||||||
|
db::plc::Graph plc;
|
||||||
|
TestableConvexDecomposition decomp (&plc);
|
||||||
|
|
||||||
|
decomp.decompose (poly, param, dbu);
|
||||||
|
|
||||||
|
std::unique_ptr<db::Layout> ly_out (plc.to_layout ());
|
||||||
|
db::compare_layouts (_this, *ly_out, tl::testdata () + "/algo/hm_decomposition_au7.gds");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue