Fixing issue #2102 (internal error on R extraction)

Problem was a conceptual problem: the triangulation for
Hertel-Mehlhorn decomposition must not contain internal
vertexes. So we need a different solution for including
vertex ports.
This commit is contained in:
Matthias Koefferlein 2025-07-30 23:24:34 +02:00
parent 3c4f80020b
commit b89ff76a84
5 changed files with 113 additions and 101 deletions

View File

@ -429,12 +429,6 @@ ConvexDecomposition::decompose (const db::Polygon &poly, const ConvexDecompositi
decompose (poly, parameters, db::CplxTrans (dbu));
}
void
ConvexDecomposition::decompose (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const ConvexDecompositionParameters &parameters, double dbu)
{
decompose (poly, vertexes, parameters, db::CplxTrans (dbu));
}
void
ConvexDecomposition::decompose (const db::Polygon &poly, const ConvexDecompositionParameters &parameters, const db::CplxTrans &trans)
{
@ -444,15 +438,6 @@ ConvexDecomposition::decompose (const db::Polygon &poly, const ConvexDecompositi
hertel_mehlhorn_decomposition (tri, parameters);
}
void
ConvexDecomposition::decompose (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const ConvexDecompositionParameters &parameters, const db::CplxTrans &trans)
{
Triangulation tri (mp_graph);
tri.triangulate (poly, vertexes, parameters.tri_param, trans);
hertel_mehlhorn_decomposition (tri, parameters);
}
void
ConvexDecomposition::decompose (const db::DPolygon &poly, const ConvexDecompositionParameters &parameters, const db::DCplxTrans &trans)
{
@ -462,15 +447,6 @@ ConvexDecomposition::decompose (const db::DPolygon &poly, const ConvexDecomposit
hertel_mehlhorn_decomposition (tri, parameters);
}
void
ConvexDecomposition::decompose (const db::DPolygon &poly, const std::vector<db::DPoint> &vertexes, const ConvexDecompositionParameters &parameters, const db::DCplxTrans &trans)
{
Triangulation tri (mp_graph);
tri.triangulate (poly, vertexes, parameters.tri_param, trans);
hertel_mehlhorn_decomposition (tri, parameters);
}
void
ConvexDecomposition::decompose (const db::Region &region, const ConvexDecompositionParameters &parameters, double dbu)
{

View File

@ -118,15 +118,12 @@ public:
// more versions
void decompose (const db::Region &region, const ConvexDecompositionParameters &parameters, const db::CplxTrans &trans = db::CplxTrans ());
void decompose (const db::Polygon &poly, const ConvexDecompositionParameters &parameters, double dbu = 1.0);
void decompose (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const ConvexDecompositionParameters &parameters, double dbu = 1.0);
void decompose (const db::Polygon &poly, const ConvexDecompositionParameters &parameters, const db::CplxTrans &trans = db::CplxTrans ());
void decompose (const db::Polygon &poly, const std::vector<db::Point> &vertexes, const ConvexDecompositionParameters &parameters, const db::CplxTrans &trans = db::CplxTrans ());
/**
* @brief Decomposes a floating-point polygon
*/
void decompose (const db::DPolygon &poly, const ConvexDecompositionParameters &parameters, const db::DCplxTrans &trans = db::DCplxTrans ());
void decompose (const db::DPolygon &poly, const std::vector<db::DPoint> &vertexes, const ConvexDecompositionParameters &parameters, const db::DCplxTrans &trans = db::DCplxTrans ());
private:
Graph *mp_graph;

View File

@ -110,49 +110,6 @@ TEST(basic)
db::compare_layouts (_this, *ly, tl::testdata () + "/algo/hm_decomposition_au4.gds");
}
TEST(internal_vertex)
{
db::plc::Graph plc;
TestableConvexDecomposition decomp (&plc);
db::Point contour[] = {
db::Point (0, 0),
db::Point (0, 100),
db::Point (1000, 100),
db::Point (1000, 0)
};
std::vector<db::Point> vertexes;
vertexes.push_back (db::Point (0, 50)); // on edge
vertexes.push_back (db::Point (200, 70));
vertexes.push_back (db::Point (0, 0)); // on vertex
db::Polygon poly;
poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0]));
double dbu = 0.001;
db::plc::ConvexDecompositionParameters param;
decomp.decompose (poly, vertexes, param, dbu);
EXPECT_EQ (plc.begin () == plc.end (), false);
if (plc.begin () == plc.end ()) {
return;
}
auto p = plc.begin ();
EXPECT_EQ (p->polygon ().to_string (), "(0,0;0,0.05;0,0.1;1,0.1;1,0)");
std::vector<std::string> ip;
for (size_t i = 0; i < p->internal_vertexes (); ++i) {
ip.push_back (p->internal_vertex (i)->to_string () + "#" + tl::join (p->internal_vertex (i)->ids ().begin (), p->internal_vertex (i)->ids ().end (), ","));
}
std::sort (ip.begin (), ip.end ());
EXPECT_EQ (tl::join (ip, "/"), "(0, 0)#2/(0, 0.05)#0/(0.2, 0.07)#1");
EXPECT_EQ (++p == plc.end (), true);
}
TEST(problematic_polygon)
{
db::Point contour[] = {

View File

@ -35,17 +35,9 @@ const double infinite_squares = 1e10;
namespace
{
class PolygonPortInteractionReceiver
: public db::box_scanner_receiver2<const db::Polygon, size_t, const db::Polygon, size_t>
class PortInteractionReceiverBase
{
public:
void add (const db::Polygon *obj1, const size_t &index1, const db::Polygon *obj2, const size_t &index2)
{
if (db::interact_pp (*obj1, *obj2)) {
m_interactions[index1].insert (index2);
}
}
const std::set<size_t> &interactions (size_t index) const
{
static std::set<size_t> empty;
@ -57,10 +49,42 @@ public:
}
}
protected:
void insert (size_t index1, size_t index2)
{
m_interactions[index1].insert (index2);
}
private:
std::map<size_t, std::set<size_t> > m_interactions;
};
class PolygonPortInteractionReceiver
: public db::box_scanner_receiver2<const db::Polygon, size_t, const db::Polygon, size_t>,
public PortInteractionReceiverBase
{
public:
void add (const db::Polygon *obj1, const size_t &index1, const db::Polygon *obj2, const size_t &index2)
{
if (db::interact_pp (*obj1, *obj2)) {
insert (index1, index2);
}
}
};
class VertexPortInteractionReceiver
: public db::box_scanner_receiver2<const db::Polygon, size_t, const db::Point, size_t>,
public PortInteractionReceiverBase
{
public:
void add (const db::Polygon *obj1, const size_t &index1, const db::Point *obj2, const size_t &index2)
{
if (obj1->box ().contains (*obj2) && db::inside_poly (obj1->begin_edge (), *obj2) >= 0) {
insert (index1, index2);
}
}
};
struct JoinEdgeSets
{
void operator() (std::set<db::Edge> &a, const std::set<db::Edge> &b) const
@ -188,12 +212,9 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector
db::plc::Graph plc;
db::plc::ConvexDecomposition decomp (&plc);
decomp.decompose (polygon, vertex_ports, m_decomp_param, trans);
decomp.decompose (polygon, m_decomp_param, trans);
// Set up a scanner to detect interactions between polygon ports
// and decomposed polygons
db::box_scanner2<const db::Polygon, size_t, const db::Polygon, size_t> scanner;
// create a heap for the scanners
std::vector<std::pair<db::Polygon, const db::plc::Polygon *> > decomp_polygons;
for (auto p = plc.begin (); p != plc.end (); ++p) {
@ -201,17 +222,50 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector
decomp_polygons.back ().first = inv_trans * p->polygon ();
}
for (auto i = decomp_polygons.begin (); i != decomp_polygons.end (); ++i) {
scanner.insert1 (&i->first, i - decomp_polygons.begin ());
// Set up a scanner to detect interactions between polygon ports
// and decomposed polygons
PolygonPortInteractionReceiver interactions_pp;
if (! decomp_polygons.empty () && ! polygon_ports.empty ()) {
db::box_scanner2<const db::Polygon, size_t, const db::Polygon, size_t> scanner;
for (auto i = decomp_polygons.begin (); i != decomp_polygons.end (); ++i) {
scanner.insert1 (&i->first, i - decomp_polygons.begin ());
}
for (auto i = polygon_ports.begin (); i != polygon_ports.end (); ++i) {
scanner.insert2 (i.operator-> (), i - polygon_ports.begin ());
}
db::box_convert<db::Polygon> bc;
scanner.process (interactions_pp, 1, bc, bc);
}
for (auto i = polygon_ports.begin (); i != polygon_ports.end (); ++i) {
scanner.insert2 (i.operator-> (), i - polygon_ports.begin ());
}
// Set up a scanner to detect interactions between vertex ports
// and decomposed polygons
PolygonPortInteractionReceiver interactions;
db::box_convert<db::Polygon> bc;
scanner.process (interactions, 1, bc, bc);
VertexPortInteractionReceiver interactions_vp;
if (! decomp_polygons.empty () && ! vertex_ports.empty ()) {
db::box_scanner2<const db::Polygon, size_t, const db::Point, size_t> scanner;
for (auto i = decomp_polygons.begin (); i != decomp_polygons.end (); ++i) {
scanner.insert1 (&i->first, i - decomp_polygons.begin ());
}
for (auto i = vertex_ports.begin (); i != vertex_ports.end (); ++i) {
scanner.insert2 (i.operator-> (), i - vertex_ports.begin ());
}
db::box_convert<db::Polygon> bc1;
db::box_convert<db::Point> bc2;
scanner.process (interactions_vp, 1, bc1, bc2);
}
// Generate the internal ports: those are defined by edges connecting two polygons
@ -253,8 +307,8 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector
ports.clear ();
const db::Polygon &db_poly = p->first;
const db::plc::Polygon *plc_poly = p->second;
const std::set<size_t> &pp_indexes = interactions.interactions (p - decomp_polygons.begin ());
const std::set<size_t> &pp_indexes = interactions_pp.interactions (p - decomp_polygons.begin ());
const std::set<size_t> &vp_indexes = interactions_vp.interactions (p - decomp_polygons.begin ());
const std::vector<size_t> &ip_indexes = internal_port_indexes [p - decomp_polygons.begin ()];
// set up the ports:
@ -266,16 +320,12 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector
}
// 2. vertex ports
for (size_t i = 0; i < plc_poly->internal_vertexes (); ++i) {
auto v = plc_poly->internal_vertex (i);
db::Point loc = inv_trans * *v;
for (auto pi = v->ids ().begin (); pi != v->ids ().end (); ++pi) {
ports.push_back (std::make_pair (PortDefinition (pex::RNode::VertexPort, loc, *pi), (pex::RNode *) 0));
}
for (auto i = vp_indexes.begin (); i != vp_indexes.end (); ++i) {
db::Point loc = vertex_ports [*i];
ports.push_back (std::make_pair (PortDefinition (pex::RNode::VertexPort, db::Box (loc, loc), (unsigned int) *i), (pex::RNode *) 0));
}
// 3. polygon ports
// (NOTE: here we only take the center of the bounding box)
for (auto i = pp_indexes.begin (); i != pp_indexes.end (); ++i) {
db::Box loc = polygon_ports [*i].box ();
ports.push_back (std::make_pair (PortDefinition (pex::RNode::PolygonPort, loc, (unsigned int) *i), (pex::RNode *) 0));

View File

@ -213,3 +213,35 @@ TEST(extraction_meander)
"R V0(0.3,0;0.3,0) V1(4.3,1;4.3,1) 10.0543767445" // that is pretty much the length of the center line / width :)
)
}
TEST(issue_2102)
{
db::Point contour[] = {
db::Point (-85, -610),
db::Point (-85, 610),
db::Point (85, 610),
db::Point (85, 440),
db::Point (65, 440),
db::Point (65, -610)
};
db::Polygon poly;
poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0]));
double dbu = 0.001;
pex::RNetwork rn;
pex::SquareCountingRExtractor rex (dbu);
std::vector<db::Point> vertex_ports;
vertex_ports.push_back (db::Point (0, 525));
vertex_ports.push_back (db::Point (-85, -610));
std::vector<db::Polygon> polygon_ports;
rex.extract (poly, vertex_ports, polygon_ports, rn);
EXPECT_EQ (network2s (rn),
"R V0(0,0.525;0,0.525) V1(-0.085,-0.61;-0.085,-0.61) 7.89600487195" // was crashing before
)
}