diff --git a/src/db/db/dbPLC.cc b/src/db/db/dbPLC.cc index c44a96760..7a8be1455 100644 --- a/src/db/db/dbPLC.cc +++ b/src/db/db/dbPLC.cc @@ -300,8 +300,14 @@ Edge::crosses (const db::DEdge &e, const db::DEdge &other) bool Edge::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; + int sa = e.side_of (other.p1 ()); + int sb = e.side_of (other.p2 ()); + int s1 = sa * sb; + + int s2 = other.side_of (e.p1 ()) * other.side_of (e.p2 ()); + + // e can end on other and so can other end on e, but both may not be coincident + return s1 <= 0 && s2 <= 0 && ! (sa == 0 && sb == 0); } db::DPoint diff --git a/src/db/db/dbPLCTriangulation.cc b/src/db/db/dbPLCTriangulation.cc index 07688f0c3..f8f4fdcc9 100644 --- a/src/db/db/dbPLCTriangulation.cc +++ b/src/db/db/dbPLCTriangulation.cc @@ -1099,14 +1099,19 @@ Triangulation::find_vertexes_along_line (const db::DPoint &p1, const db::DPoint } std::vector result; + result.push_back (v); while (v) { Vertex *vn = 0; for (auto e = v->begin_edges (); e != v->end_edges (); ++e) { Vertex *vv = (*e)->other (v); - if (db::vprod_sign (e12.d (), *vv - *v) == 0 && db::sprod_sign (e12.d (), *vv - *v) > 0 && db::sprod_sign (e12.d (), *vv - e12.p2 ()) < 0) { + int cs = 0; + if (db::vprod_sign (e12.d (), *vv - *v) == 0 && db::sprod_sign (e12.d (), *vv - *v) > 0 && (cs = db::sprod_sign (e12.d (), *vv - e12.p2 ())) <= 0) { result.push_back (vv); - vn = vv; + if (cs < 0) { + // continue searching + vn = vv; + } break; } } @@ -1377,8 +1382,6 @@ Triangulation::make_contours (const Poly &poly, const Trans &trans, std::vector< void Triangulation::create_constrained_delaunay (const db::Region ®ion, const CplxTrans &trans) { - clear (); - std::vector > edge_contours; for (auto p = region.begin_merged (); ! p.at_end (); ++p) { @@ -1389,15 +1392,8 @@ Triangulation::create_constrained_delaunay (const db::Region ®ion, const Cplx } void -Triangulation::create_constrained_delaunay (const db::Polygon &p, const std::vector &vertexes, const CplxTrans &trans) +Triangulation::create_constrained_delaunay (const db::Polygon &p, const CplxTrans &trans) { - clear (); - - unsigned int id = 0; - for (auto v = vertexes.begin (); v != vertexes.end (); ++v) { - insert_point (trans * *v)->set_is_precious (true, id++); - } - std::vector > edge_contours; make_contours (p, trans, edge_contours); @@ -1405,15 +1401,8 @@ Triangulation::create_constrained_delaunay (const db::Polygon &p, const std::vec } void -Triangulation::create_constrained_delaunay (const db::DPolygon &p, const std::vector &vertexes, const DCplxTrans &trans) +Triangulation::create_constrained_delaunay (const db::DPolygon &p, const DCplxTrans &trans) { - clear (); - - unsigned int id = 0; - for (auto v = vertexes.begin (); v != vertexes.end (); ++v) { - insert_point (trans * *v)->set_is_precious (true, id++); - } - std::vector > edge_contours; make_contours (p, trans, edge_contours); @@ -1458,6 +1447,8 @@ Triangulation::triangulate (const db::Region ®ion, const TriangulationParamet { tl::SelfTimer timer (tl::verbosity () > parameters.base_verbosity, "Triangles::triangulate"); + clear (); + create_constrained_delaunay (region, db::CplxTrans (dbu)); refine (parameters); } @@ -1467,6 +1458,24 @@ Triangulation::triangulate (const db::Region ®ion, const TriangulationParamet { tl::SelfTimer timer (tl::verbosity () > parameters.base_verbosity, "Triangles::triangulate"); + clear (); + + create_constrained_delaunay (region, trans); + refine (parameters); +} + +void +Triangulation::triangulate (const db::Region ®ion, const std::vector &vertexes, const TriangulationParameters ¶meters, const db::CplxTrans &trans) +{ + tl::SelfTimer timer (tl::verbosity () > parameters.base_verbosity, "Triangles::triangulate"); + + clear (); + + unsigned int id = 0; + for (auto v = vertexes.begin (); v != vertexes.end (); ++v) { + insert_point (trans * *v)->set_is_precious (true, id++); + } + create_constrained_delaunay (region, trans); refine (parameters); } @@ -1482,7 +1491,16 @@ Triangulation::triangulate (const db::Polygon &poly, const std::vector parameters.base_verbosity, "Triangles::triangulate"); - create_constrained_delaunay (poly, vertexes, db::CplxTrans (dbu)); + db::CplxTrans trans (dbu); + + clear (); + + unsigned int id = 0; + for (auto v = vertexes.begin (); v != vertexes.end (); ++v) { + insert_point (trans * *v)->set_is_precious (true, id++); + } + + create_constrained_delaunay (poly, trans); refine (parameters); } @@ -1497,7 +1515,14 @@ Triangulation::triangulate (const db::Polygon &poly, const std::vector parameters.base_verbosity, "Triangles::triangulate"); - create_constrained_delaunay (poly, vertexes, trans); + clear (); + + unsigned int id = 0; + for (auto v = vertexes.begin (); v != vertexes.end (); ++v) { + insert_point (trans * *v)->set_is_precious (true, id++); + } + + create_constrained_delaunay (poly, trans); refine (parameters); } @@ -1512,7 +1537,14 @@ Triangulation::triangulate (const db::DPolygon &poly, const std::vector parameters.base_verbosity, "Triangles::triangulate"); - create_constrained_delaunay (poly, vertexes, trans); + clear (); + + unsigned int id = 0; + for (auto v = vertexes.begin (); v != vertexes.end (); ++v) { + insert_point (trans * *v)->set_is_precious (true, id++); + } + + create_constrained_delaunay (poly, trans); refine (parameters); } diff --git a/src/db/db/dbPLCTriangulation.h b/src/db/db/dbPLCTriangulation.h index ea0830b00..db97f9651 100644 --- a/src/db/db/dbPLCTriangulation.h +++ b/src/db/db/dbPLCTriangulation.h @@ -142,6 +142,7 @@ public: // more versions void triangulate (const db::Region ®ion, const TriangulationParameters ¶meters, const db::CplxTrans &trans = db::CplxTrans ()); + void triangulate (const db::Region ®ion, const std::vector &vertexes, const TriangulationParameters ¶meters, const db::CplxTrans &trans = db::CplxTrans ()); void triangulate (const db::Polygon &poly, const TriangulationParameters ¶meters, double dbu = 1.0); void triangulate (const db::Polygon &poly, const std::vector &vertexes, const TriangulationParameters ¶meters, double dbu = 1.0); void triangulate (const db::Polygon &poly, const TriangulationParameters ¶meters, const db::CplxTrans &trans = db::CplxTrans ()); @@ -181,6 +182,17 @@ public: */ std::vector find_vertexes_along_line (const db::DPoint &p1, const db::DPoint &p2) const; + /** + * @brief Removes the outside triangles. + * + * This method is useful in combination with the "remove_outside_triangles = false" triangulation + * parameter. In this mode, outside triangles are not removed after triangulation (the + * triangulated area is convex). This enables use of the "find" functions. + * + * This method can be used to finally remove the outside triangles if no longer needed. + */ + void remove_outside_triangles (); + /** * @brief Statistics: number of flips (fixing) */ @@ -197,6 +209,37 @@ public: return m_hops; } + /** + * @brief Creates a constrained Delaunay triangulation from the given Region + * + * This method is used internally by the "triangulation" method to create the basic triangulation, + * followed by a "refine" step. + */ + void create_constrained_delaunay (const db::Region ®ion, const db::CplxTrans &trans = db::CplxTrans ()); + + /** + * @brief Creates a constrained Delaunay triangulation from the given Polygon + * + * This method is used internally by the "triangulation" method to create the basic triangulation, + * followed by a "refine" step. + */ + void create_constrained_delaunay (const db::Polygon &poly, const db::CplxTrans &trans = db::CplxTrans ()); + + /** + * @brief Creates a constrained Delaunay triangulation from the given DPolygon + * + * This method is used internally by the "triangulation" method to create the basic triangulation, + * followed by a "refine" step. + */ + void create_constrained_delaunay (const db::DPolygon &poly, const DCplxTrans &trans = db::DCplxTrans ()); + + /** + * @brief Refines the triangulation using the given parameters + * + * This method is used internally by the "triangulation" method after creating the basic triangulation. + */ + void refine (const TriangulationParameters ¶m); + protected: /** * @brief Checks the polygon graph for consistency @@ -254,26 +297,6 @@ protected: */ void constrain (const std::vector > &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 ®ion, 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 &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 &vertexes, const DCplxTrans &trans); - /** * @brief Returns a value indicating whether the edge is "illegal" (violates the Delaunay criterion) */ @@ -308,7 +331,6 @@ private: void insert_new_vertex(Vertex *vertex, std::list > *new_triangles_out); std::vector ensure_edge_inner (Vertex *from, Vertex *to); void join_edges (std::vector &edges); - void refine (const TriangulationParameters ¶m); }; } // namespace plc diff --git a/src/db/unit_tests/dbPLCTriangulationTests.cc b/src/db/unit_tests/dbPLCTriangulationTests.cc index 9253eb0ce..f31a049b2 100644 --- a/src/db/unit_tests/dbPLCTriangulationTests.cc +++ b/src/db/unit_tests/dbPLCTriangulationTests.cc @@ -155,24 +155,28 @@ TEST(collect_vertexes) tris.insert_point (0.5, 0.5); std::vector vertexes = tris.find_vertexes_along_line (db::DPoint (0, 0), db::DPoint (1.5, 1.5)); - EXPECT_EQ (vertexes.size (), size_t (3)); - if (vertexes.size () >= size_t (3)) { - EXPECT_EQ (vertexes [0]->to_string (), "(0.2, 0.2)"); - EXPECT_EQ (vertexes [1]->to_string (), "(0.5, 0.5)"); - EXPECT_EQ (vertexes [2]->to_string (), "(1, 1)"); + EXPECT_EQ (vertexes.size (), size_t (4)); + if (vertexes.size () >= size_t (4)) { + EXPECT_EQ (vertexes [0]->to_string (), "(0, 0)"); + EXPECT_EQ (vertexes [1]->to_string (), "(0.2, 0.2)"); + EXPECT_EQ (vertexes [2]->to_string (), "(0.5, 0.5)"); + EXPECT_EQ (vertexes [3]->to_string (), "(1, 1)"); } vertexes = tris.find_vertexes_along_line (db::DPoint (0, 0), db::DPoint (1.0, 1.0)); - EXPECT_EQ (vertexes.size (), size_t (2)); - if (vertexes.size () >= size_t (2)) { - EXPECT_EQ (vertexes [0]->to_string (), "(0.2, 0.2)"); - EXPECT_EQ (vertexes [1]->to_string (), "(0.5, 0.5)"); + EXPECT_EQ (vertexes.size (), size_t (4)); + if (vertexes.size () >= size_t (4)) { + EXPECT_EQ (vertexes [0]->to_string (), "(0, 0)"); + EXPECT_EQ (vertexes [1]->to_string (), "(0.2, 0.2)"); + EXPECT_EQ (vertexes [2]->to_string (), "(0.5, 0.5)"); + EXPECT_EQ (vertexes [3]->to_string (), "(1, 1)"); } vertexes = tris.find_vertexes_along_line (db::DPoint (1, 1), db::DPoint (0.25, 0.25)); - EXPECT_EQ (vertexes.size (), size_t (1)); - if (vertexes.size () >= size_t (1)) { - EXPECT_EQ (vertexes [0]->to_string (), "(0.5, 0.5)"); + EXPECT_EQ (vertexes.size (), size_t (2)); + if (vertexes.size () >= size_t (2)) { + EXPECT_EQ (vertexes [0]->to_string (), "(1, 1)"); + EXPECT_EQ (vertexes [1]->to_string (), "(0.5, 0.5)"); } } diff --git a/src/pex/pex/pexTriangulationRExtractor.cc b/src/pex/pex/pexTriangulationRExtractor.cc index d464e8fdb..cce1e4150 100644 --- a/src/pex/pex/pexTriangulationRExtractor.cc +++ b/src/pex/pex/pexTriangulationRExtractor.cc @@ -43,24 +43,74 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector< rnetwork.clear (); db::CplxTrans trans = db::CplxTrans (m_dbu) * db::ICplxTrans (db::Trans (db::Point () - polygon.box ().center ())); - auto inv_trans = trans.inverted (); - - // NOTE: currently we treat polygon ports and points where the location is the center of the bounding box - std::vector vp = vertex_ports; - vp.reserve (vertex_ports.size () + polygon_ports.size ()); - for (auto pp = polygon_ports.begin (); pp != polygon_ports.end (); ++pp) { - vp.push_back (pp->box ().center ()); - } - db::plc::Graph plc; db::plc::Triangulation tri (&plc); - tri.triangulate (polygon, vp, m_tri_param, trans); + std::unordered_map pp_vertexes; - // create a network node for each triangle node + if (polygon_ports.empty ()) { + + tri.triangulate (polygon, vertex_ports, m_tri_param, trans); + + } else { + + // Subtract the polygon ports from the original polygon and compute the intersection. + // Hence we have coincident edges that we can use to identify the nodes that are + // connected for the polygon ports + + db::Region org (polygon); + db::Region pp (polygon_ports.begin (), polygon_ports.end ()); + + db::Region residual_poly = org - pp; + + // We must not remove outside triangles yet, as we need them for "find_vertexes_along_line" + db::plc::TriangulationParameters param = m_tri_param; + param.remove_outside_triangles = false; + + tri.clear (); + + unsigned int id = 0; + for (auto v = vertex_ports.begin (); v != vertex_ports.end (); ++v) { + tri.insert_point (trans * *v)->set_is_precious (true, id++); + } + + for (auto p = polygon_ports.begin (); p != polygon_ports.end (); ++p) { + // create vertexes for the port polygon vertexes - this ensures we will find vertexes + // on the edges of the polygons - yet, they may be outside of the original polygon. + // In that case they will not be considered + for (auto e = p->begin_edge (); !e.at_end (); ++e) { + tri.insert_point (trans * (*e).p1 ())->set_is_precious (true, id); + } + } + + // perform the triangulation + + tri.create_constrained_delaunay (residual_poly, trans); + tri.refine (param); + + // identify the vertexes present for the polygon port -> store them inside pp_vertexes + + for (auto p = polygon_ports.begin (); p != polygon_ports.end (); ++p) { + for (auto e = p->begin_edge (); !e.at_end (); ++e) { + // NOTE: this currently only works if one of the end points is an actual + // vertex. + auto vport = tri.find_vertexes_along_line (trans * (*e).p1 (), trans * (*e).p2 ()); + for (auto v = vport.begin (); v != vport.end (); ++v) { + pp_vertexes.insert (std::make_pair (*v, p - polygon_ports.begin ())); + } + } + } + + tri.remove_outside_triangles (); + + } + + // Create a network node for each triangle node. std::unordered_map vertex2node; + std::unordered_set vports_present; + std::map pport_nodes; size_t internal_node_id = 0; @@ -73,28 +123,71 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector< continue; } - pex::RNode::node_type type = pex::RNode::Internal; - size_t port_index = 0; + pex::RNode *n = 0; - if (vertex->is_precious ()) { - size_t idx = vertex->id (); - if (idx >= vertex_ports.size ()) { - type = pex::RNode::PolygonPort; - port_index = size_t (idx) - vertex_ports.size (); + auto ipp = pp_vertexes.find (vertex); + if (ipp != pp_vertexes.end ()) { + + size_t port_index = ipp->second; + auto pn = pport_nodes.find (port_index); + if (pn != pport_nodes.end ()) { + n = pn->second; } else { - type = pex::RNode::VertexPort; - port_index = size_t (idx); + n = rnetwork.create_node (pex::RNode::PolygonPort, port_index); + pport_nodes.insert (std::make_pair (port_index, n)); + n->location = trans * polygon_ports [port_index].box (); } + + } else if (vertex->is_precious ()) { + + size_t port_index = size_t (vertex->id ()); + if (port_index < vertex_ports.size ()) { + n = rnetwork.create_node (pex::RNode::VertexPort, port_index); + n->location = db::DBox (*vertex, *vertex); + vports_present.insert (port_index); + } + } else { - port_index = internal_node_id++; + + n = rnetwork.create_node (pex::RNode::Internal, internal_node_id++); + n->location = db::DBox (*vertex, *vertex); + } - pex::RNode *n = rnetwork.create_node (type, port_index); - db::DPoint loc = *vertex; - n->location = db::DBox (loc, loc); + if (n) { + vertex2node.insert (std::make_pair (vertex, n)); + } - vertex2node.insert (std::make_pair (vertex, n)); + } + } + + // check for vertex ports not assigned to a node + // -> this may be an indication for a vertex port inside a polygon port + + for (size_t iv = 0; iv < vertex_ports.size (); ++iv) { + + if (vports_present.find (iv) != vports_present.end ()) { + continue; + } + + db::Point vp = vertex_ports [iv]; + + for (auto p = polygon_ports.begin (); p != polygon_ports.end (); ++p) { + + if (p->box ().contains (vp) && db::inside_poly_test (*p) (vp) >= 0) { + + auto ip = pport_nodes.find (p - polygon_ports.begin ()); + if (ip != pport_nodes.end ()) { + + // create a new vertex port and short it to the polygon port + auto n = rnetwork.create_node (pex::RNode::VertexPort, iv); + n->location = db::DBox (trans * vp, trans * vp); + rnetwork.create_element (pex::RElement::short_value (), n, ip->second); + + } + + } } } @@ -121,17 +214,22 @@ TriangulationRExtractor::create_conductances (const db::plc::Polygon &tri, const const db::plc::Vertex *p0 = tri.vertex (i + 1); const db::plc::Vertex *p1 = tri.vertex (i + 2); - double a = fabs (db::vprod (*pm1 - *p0, *p1 - *p0) * 0.5); - - double lm1 = (*p0 - *pm1).sq_length (); - double l0 = (*p1 - *p0).sq_length (); - double l1 = (*pm1 - *p1).sq_length (); - - double s = (l0 + l1 - lm1) / (8.0 * a); - auto i0 = vertex2node.find (p0); auto im1 = vertex2node.find (pm1); - rnetwork.create_element (s, i0->second, im1->second); + + if (i0->second != im1->second) { + + double a = fabs (db::vprod (*pm1 - *p0, *p1 - *p0) * 0.5); + + double lm1 = (*p0 - *pm1).sq_length (); + double l0 = (*p1 - *p0).sq_length (); + double l1 = (*pm1 - *p1).sq_length (); + + double s = (l0 + l1 - lm1) / (8.0 * a); + + rnetwork.create_element (s, i0->second, im1->second); + + } } } diff --git a/src/pex/unit_tests/pexTriangulationRExtractorTests.cc b/src/pex/unit_tests/pexTriangulationRExtractorTests.cc index 46609d1ec..de2074322 100644 --- a/src/pex/unit_tests/pexTriangulationRExtractorTests.cc +++ b/src/pex/unit_tests/pexTriangulationRExtractorTests.cc @@ -67,3 +67,191 @@ TEST(extraction) "R V1 V0 10.0938" ) } + +TEST(extraction_with_polygon_ports) +{ + db::Point contour[] = { + db::Point (0, 0), + db::Point (0, 100), + db::Point (1000, 100), + db::Point (1000, 0) + }; + + db::Polygon poly; + poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0])); + + double dbu = 0.001; + + pex::RNetwork rn; + pex::TriangulationRExtractor rex (dbu); + + std::vector vertex_ports; + + std::vector polygon_ports; + polygon_ports.push_back (db::Polygon (db::Box (-100, 0, 0, 100))); + polygon_ports.push_back (db::Polygon (db::Box (1000, 0, 1100, 100))); + + rex.extract (poly, vertex_ports, polygon_ports, rn); + + EXPECT_EQ (rn.to_string (), + "R P1 P0 10" + ) +} + +TEST(extraction_with_polygon_ports_inside) +{ + db::Point contour[] = { + db::Point (-100, 0), + db::Point (-100, 100), + db::Point (1100, 100), + db::Point (1100, 0) + }; + + db::Polygon poly; + poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0])); + + double dbu = 0.001; + + pex::RNetwork rn; + pex::TriangulationRExtractor rex (dbu); + + std::vector vertex_ports; + + std::vector polygon_ports; + polygon_ports.push_back (db::Polygon (db::Box (-100, 0, 0, 100))); + polygon_ports.push_back (db::Polygon (db::Box (1000, 0, 1100, 100))); + + rex.extract (poly, vertex_ports, polygon_ports, rn); + + EXPECT_EQ (rn.to_string (), + "R P1 P0 10" + ) +} + +TEST(extraction_split_by_ports) +{ + db::Point contour[] = { + db::Point (-100, 0), + db::Point (-100, 100), + db::Point (1100, 100), + db::Point (1100, 0) + }; + + db::Polygon poly; + poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0])); + + double dbu = 0.001; + + pex::RNetwork rn; + pex::TriangulationRExtractor rex (dbu); + + std::vector vertex_ports; + + std::vector polygon_ports; + polygon_ports.push_back (db::Polygon (db::Box (-100, 0, 0, 100))); + polygon_ports.push_back (db::Polygon (db::Box (1100, 0, 1200, 100))); + polygon_ports.push_back (db::Polygon (db::Box (500, 0, 600, 100))); + + rex.extract (poly, vertex_ports, polygon_ports, rn); + + EXPECT_EQ (rn.to_string (), + "R P2 P0 5\n" + "R P1 P2 5" + ) +} + +TEST(extraction_split_by_butting_port) +{ + db::Point contour[] = { + db::Point (-100, 0), + db::Point (-100, 100), + db::Point (1100, 100), + db::Point (1100, 0) + }; + + db::Polygon poly; + poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0])); + + double dbu = 0.001; + + pex::RNetwork rn; + pex::TriangulationRExtractor rex (dbu); + + std::vector vertex_ports; + + std::vector polygon_ports; + polygon_ports.push_back (db::Polygon (db::Box (-100, 0, 0, 100))); + polygon_ports.push_back (db::Polygon (db::Box (1100, 0, 1200, 100))); + polygon_ports.push_back (db::Polygon (db::Box (500, 100, 600, 200))); + + rex.extract (poly, vertex_ports, polygon_ports, rn); + + EXPECT_EQ (rn.to_string (), + "R P2 P0 4.84211\n" + "R P1 P2 4.84211\n" + "R P0 P1 281.111" + ) +} + +TEST(extraction_with_outside_polygon_port) +{ + db::Point contour[] = { + db::Point (-100, 0), + db::Point (-100, 100), + db::Point (1100, 100), + db::Point (1100, 0) + }; + + db::Polygon poly; + poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0])); + + double dbu = 0.001; + + pex::RNetwork rn; + pex::TriangulationRExtractor rex (dbu); + + std::vector vertex_ports; + + std::vector polygon_ports; + polygon_ports.push_back (db::Polygon (db::Box (-100, 0, 0, 100))); + polygon_ports.push_back (db::Polygon (db::Box (1100, 0, 1200, 100))); + polygon_ports.push_back (db::Polygon (db::Box (500, 200, 600, 300))); + + rex.extract (poly, vertex_ports, polygon_ports, rn); + + EXPECT_EQ (rn.to_string (), + "R P1 P0 11" + ) +} + +TEST(extraction_with_polygon_ports_and_vertex_port_inside) +{ + db::Point contour[] = { + db::Point (-100, 0), + db::Point (-100, 100), + db::Point (1100, 100), + db::Point (1100, 0) + }; + + db::Polygon poly; + poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0])); + + double dbu = 0.001; + + pex::RNetwork rn; + pex::TriangulationRExtractor rex (dbu); + + std::vector vertex_ports; + vertex_ports.push_back (db::Point (-50, 50)); + + std::vector polygon_ports; + polygon_ports.push_back (db::Polygon (db::Box (-100, 0, 0, 100))); + polygon_ports.push_back (db::Polygon (db::Box (1000, 0, 1100, 100))); + + rex.extract (poly, vertex_ports, polygon_ports, rn); + + EXPECT_EQ (rn.to_string (), + "R V0 P0 0\n" // shorted because V0 is inside P0 + "R P1 P0 10" + ) +}