WIP: allowing multiple vertex ports on the same location

This commit is contained in:
Matthias Koefferlein 2025-05-04 15:38:45 +02:00
parent 80ad38f81b
commit aca3095efa
10 changed files with 137 additions and 47 deletions

View File

@ -43,47 +43,58 @@ namespace plc
// Vertex implementation
Vertex::Vertex (Graph *graph)
: DPoint (), mp_graph (graph), m_is_precious (false)
: DPoint (), mp_graph (graph), mp_ids (0)
{
// .. nothing yet ..
}
Vertex::Vertex (Graph *graph, const db::DPoint &p)
: DPoint (p), mp_graph (graph), m_is_precious (false)
: DPoint (p), mp_graph (graph), mp_ids (0)
{
// .. nothing yet ..
}
Vertex::Vertex (Graph *graph, const Vertex &v)
: DPoint (), mp_graph (graph), m_is_precious (false), m_id (0)
: DPoint (), mp_graph (graph), mp_ids (0)
{
operator= (v);
}
Vertex::Vertex (Graph *graph, db::DCoord x, db::DCoord y)
: DPoint (x, y), mp_graph (graph), m_is_precious (false), m_id (0)
: DPoint (x, y), mp_graph (graph), mp_ids (0)
{
// .. nothing yet ..
}
Vertex::Vertex (const Vertex &v)
: DPoint (v), mp_graph (v.mp_graph), m_is_precious (v.m_is_precious), m_id (v.m_id)
: DPoint (), mp_graph (v.mp_graph), mp_ids (0)
{
// NOTE: edges are not copied!
operator= (v);
}
Vertex::~Vertex ()
{
// .. nothing yet ..
if (mp_ids) {
delete mp_ids;
mp_ids = 0;
}
}
Vertex &Vertex::operator= (const Vertex &v)
{
if (this != &v) {
// NOTE: edges are not copied!
db::DPoint::operator= (v);
m_is_precious = v.m_is_precious;
m_id = v.m_id;
if (mp_ids) {
delete mp_ids;
mp_ids = 0;
}
if (v.mp_ids) {
mp_ids = new std::set<unsigned int> (*v.mp_ids);
}
}
return *this;
}
@ -99,6 +110,39 @@ Vertex::is_outside () const
return false;
}
void
Vertex::set_is_precious (bool f, unsigned int id)
{
if (f) {
if (! mp_ids) {
mp_ids = new std::set<unsigned int> ();
}
mp_ids->insert (id);
} else {
if (mp_ids) {
delete mp_ids;
mp_ids = 0;
}
}
}
bool
Vertex::is_precious () const
{
return mp_ids != 0;
}
const std::set<unsigned int> &
Vertex::ids () const
{
if (mp_ids != 0) {
return *mp_ids;
} else {
static std::set<unsigned int> empty;
return empty;
}
}
std::vector<Polygon *>
Vertex::polygons () const
{

View File

@ -131,16 +131,12 @@ public:
*
* "precious" vertexes are not removed during triangulation for example.
*/
void set_is_precious (bool f, unsigned int id)
{
m_is_precious = f;
m_id = id;
}
void set_is_precious (bool f, unsigned int id);
/**
* @brief Gets a value indicating whether the vertex is precious
*/
bool is_precious () const { return m_is_precious; }
bool is_precious () const;
/**
* @brief Gets the ID passed to "set_is_precious"
@ -148,7 +144,7 @@ public:
* This ID can be used to identify the vertex in the context it came from (e.g.
* index in point vector).
*/
unsigned int id () const { return m_id; }
const std::set<unsigned int> &ids () const;
/**
* @brief Returns a string representation of the vertex
@ -187,8 +183,7 @@ private:
Graph *mp_graph;
edges_type mp_edges;
bool m_is_precious : 1;
unsigned int m_id : 31;
std::set<unsigned int> *mp_ids;
};
/**

View File

@ -236,10 +236,38 @@ public:
/**
* @brief Refines the triangulation using the given parameters
*
* This method is used internally by the "triangulation" method after creating the basic triangulation.
* This method is used internally by the "triangulate" method after creating the basic triangulation.
*
* This method is provided as a partial solution of a triangulation for special cases.
*/
void refine (const TriangulationParameters &param);
/**
* @brief Given a set of contours with edges, mark outer triangles
*
* The edges must be made from existing vertexes. Edge orientation is
* clockwise.
*
* This will also mark triangles as outside ones.
* This method is used internally by the "triangulate" method after creating the basic triangulation.
*
* This method is provided as a partial solution of a triangulation for special cases.
*/
void constrain (const std::vector<std::vector<Vertex *> > &contours);
/**
* @brief Inserts a contours of a polygon
*
* This method fills the contours of the given polygon by doint an "insert_point"
* on all points and logging the outer edges ("segments") into the "contours"
* array. The latter can be passed to "constrain" to create a constrained
* triangulation.
*
* This method is used internally by the "triangulate" method to create the basic triangulation.
* This method is provided as a partial solution of a triangulation for special cases.
*/
template<class Poly, class Trans> void make_contours (const Poly &poly, const Trans &trans, std::vector<std::vector<Vertex *> > &contours);
protected:
/**
* @brief Checks the polygon graph for consistency
@ -287,16 +315,6 @@ protected:
*/
std::vector<Edge *> ensure_edge (Vertex *from, Vertex *to);
/**
* @brief Given a set of contours with edges, mark outer triangles
*
* The edges must be made from existing vertexes. Edge orientation is
* clockwise.
*
* This will also mark triangles as outside ones.
*/
void constrain (const std::vector<std::vector<Vertex *> > &contours);
/**
* @brief Returns a value indicating whether the edge is "illegal" (violates the Delaunay criterion)
*/
@ -313,8 +331,6 @@ private:
size_t m_id;
mutable size_t m_flips, m_hops;
template<class Poly, class Trans> void make_contours (const Poly &poly, const Trans &trans, std::vector<std::vector<Vertex *> > &contours);
void remove_outside_vertex (Vertex *vertex, std::list<tl::weak_ptr<Polygon> > *new_triangles = 0);
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);

View File

@ -145,7 +145,7 @@ TEST(internal_vertex)
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::to_string (p->internal_vertex (i)->id ()));
ip.push_back (p->internal_vertex (i)->to_string () + "#" + tl::to_string (p->internal_vertex (i)->ids ()));
}
std::sort (ip.begin (), ip.end ());
EXPECT_EQ (tl::join (ip, "/"), "(0, 0)#2/(0, 0.05)#0/(0.2, 0.07)#1");

View File

@ -56,7 +56,12 @@ TEST(basic)
EXPECT_EQ (v1->is_precious (), false);
v1->set_is_precious (true, 17);
EXPECT_EQ (v1->is_precious (), true);
EXPECT_EQ (v1->id (), 17u);
EXPECT_EQ (v1->ids ().size (), 1u);
EXPECT_EQ (*v1->ids ().begin (), 17u);
v1->set_is_precious (true, 1);
EXPECT_EQ (v1->is_precious (), true);
EXPECT_EQ (v1->ids ().size (), 2u);
EXPECT_EQ (*v1->ids ().begin (), 2u);
}
TEST(edge)

View File

@ -468,14 +468,14 @@ RNetExtractor::extract_conductor (const RExtractorTechConductor &cond,
// type 0 objects (vertex ports)
for (auto i = vertex_ports.begin (); i != vertex_ports.end (); ++i) {
// @@@ could be without enlarge?
// TODO: could be without enlarge?
box_heap.push_back (db::Box (*i, *i).enlarged (db::Vector (1, 1)));
scanner.insert2 (&box_heap.back (), make_id (i - vertex_ports.begin (), 0));
}
// type 1 objects (via ports)
for (auto i = via_ports.begin (); i != via_ports.end (); ++i) {
// @@@ could be without enlarge?
// TODO: could be without enlarge?
box_heap.push_back (db::Box (i->position, i->position).enlarged (db::Vector (1, 1)));
scanner.insert2 (&box_heap.back (), make_id (i - via_ports.begin (), 1));
}

View File

@ -269,7 +269,9 @@ SquareCountingRExtractor::extract (const db::Polygon &polygon, const std::vector
for (size_t i = 0; i < plc_poly->internal_vertexes (); ++i) {
auto v = plc_poly->internal_vertex (i);
db::Point loc = inv_trans * *v;
ports.push_back (std::make_pair (PortDefinition (pex::RNode::VertexPort, loc, v->id ()), (pex::RNode *) 0));
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));
}
}
// 3. polygon ports

View File

@ -77,6 +77,14 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector<
tri.clear ();
std::vector<std::vector<db::plc::Vertex *> > edge_contours;
// first step of the triangulation
for (auto p = residual_poly.begin_merged (); ! p.at_end (); ++p) {
tri.make_contours (*p, trans, edge_contours);
}
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++);
@ -91,9 +99,9 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector<
}
}
// perform the triangulation
// constrain and refine the triangulation
tri.create_constrained_delaunay (residual_poly, trans);
tri.constrain (edge_contours);
tri.refine (param);
// identify the vertexes present for the polygon port -> store them inside pp_vertexes
@ -147,11 +155,19 @@ TriangulationRExtractor::extract (const db::Polygon &polygon, const std::vector<
} 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);
for (auto pi = vertex->ids ().begin (); pi != vertex->ids ().end (); ++pi) {
size_t port_index = size_t (*pi);
if (port_index < vertex_ports.size ()) {
RNode *nn = rnetwork.create_node (pex::RNode::VertexPort, port_index);
nn->location = db::DBox (*vertex, *vertex);
if (n) {
// in case of multiple vertexes on the same spot, short them
rnetwork.create_element (RElement::short_value (), n, nn);
} else {
n = nn;
}
vports_present.insert (port_index);
}
}
} else {

View File

@ -215,6 +215,18 @@ TEST(netex_2layer)
rex.extract (tech, geo, vertex_ports, polygon_ports, network);
EXPECT_EQ (network.to_string (true),
""
"R $0(0.3,-5.7;0.5,-5.5) $1(0.3,-5.7;0.5,-5.5) 50\n"
"R $2(9.3,-5.9;9.9,-5.3) $3(9.3,-5.9;9.9,-5.3) 12.5\n"
"R $4(9.3,0.1;9.9,0.3) $5(9.3,0.1;9.9,0.3) 25\n"
"R $6(0.1,0.1;0.7,0.7) $7(0.1,0.1;0.7,0.7) 12.5\n"
"R $0(0.3,-5.7;0.5,-5.5) $2(9.3,-5.9;9.9,-5.3) 5.75\n"
"R $2(9.3,-5.9;9.9,-5.3) P0(12.9,-5.9;13.5,-5.3) 2.25\n"
"R $6(0.1,0.1;0.7,0.7) V0(5.2,0.4;5.2,0.4) 3\n"
"R $4(9.3,0.1;9.9,0.3) V0(5.2,0.4;5.2,0.4) 2.75\n"
"R $5(9.3,0.1;9.9,0.3) $8(10,-3.5;10,-2.7) 1.03125\n"
"R $3(9.3,-5.9;9.9,-5.3) $8(10,-3.5;10,-2.7) 0.78125\n"
"R $8(10,-3.5;10,-2.7) P1(12.9,-3.4;13.5,-2.8) 1\n"
"R $7(0.1,0.1;0.7,0.7) V1(0.4,-5.6;0.4,-5.6) 1.875\n"
"R $1(0.3,-5.7;0.5,-5.5) V1(0.4,-5.6;0.4,-5.6) 0"
);
}

View File

@ -301,7 +301,7 @@ TEST(extraction_analytic_disc)
rex.extract (disc, vertex_ports, polygon_ports, rn);
EXPECT_EQ (rn.to_string (),
"R P0 P1 0.245379" // theoretical: 1/(2*PI)*log(r2/r1) = 0.25615 with r2=10000, r1=2000
"R P0 P1 0.245558" // theoretical: 1/(2*PI)*log(r2/r1) = 0.25615 with r2=10000, r1=2000
)
rex.triangulation_parameters ().max_area = 100000 * dbu * dbu;
@ -309,7 +309,7 @@ TEST(extraction_analytic_disc)
rex.extract (disc, vertex_ports, polygon_ports, rn);
EXPECT_EQ (rn.to_string (),
"R P0 P1 0.255614" // theoretical: 1/(2*PI)*log(r2/r1) = 0.25615 with r2=10000, r1=2000
"R P0 P1 0.255609" // theoretical: 1/(2*PI)*log(r2/r1) = 0.25615 with r2=10000, r1=2000
)
}
@ -357,7 +357,7 @@ TEST(extraction_meander)
rex.extract (poly, vertex_ports, polygon_ports, rn);
EXPECT_EQ (rn.to_string (),
"R V0 V1 8.75751" // what is the "real" value?
"R V0 V1 8.61417" // what is the "real" value?
)
}