From 048cebe95d8c9163600f82c50876642a6d6a746c Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Sun, 14 Jun 2026 00:50:56 +0530 Subject: [PATCH 1/9] Add component count to disconnected graph error message --- include/planar/makeMaximalPlanar.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/planar/makeMaximalPlanar.hpp b/include/planar/makeMaximalPlanar.hpp index cb0c612a36..96751b1778 100644 --- a/include/planar/makeMaximalPlanar.hpp +++ b/include/planar/makeMaximalPlanar.hpp @@ -122,6 +122,7 @@ class Pgr_makeMaximalPlanar : public pgrouting::Pgr_messages { std::vector component(boost::num_vertices(graph.graph)); auto num_components = boost::connected_components(graph.graph, &component[0]); if (num_components > 1) { + log << "Graph has " << num_components << " connected components\n"; throw std::string("Graph is not connected. Please run pgr_makeConnected first."); } From df611dad2a617c8347ba4ea58b9a36b09849ffe3 Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Sun, 14 Jun 2026 01:00:11 +0530 Subject: [PATCH 2/9] Implement component filtering for makeMaximalPlanar --- include/planar/makeMaximalPlanar.hpp | 7 +--- src/planar/planar_driver.cpp | 50 +++++++++++++++++++++------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/include/planar/makeMaximalPlanar.hpp b/include/planar/makeMaximalPlanar.hpp index 96751b1778..6b5c1aeed0 100644 --- a/include/planar/makeMaximalPlanar.hpp +++ b/include/planar/makeMaximalPlanar.hpp @@ -119,12 +119,7 @@ class Pgr_makeMaximalPlanar : public pgrouting::Pgr_messages { return std::vector(); } - std::vector component(boost::num_vertices(graph.graph)); - auto num_components = boost::connected_components(graph.graph, &component[0]); - if (num_components > 1) { - log << "Graph has " << num_components << " connected components\n"; - throw std::string("Graph is not connected. Please run pgr_makeConnected first."); - } + // Connected components check moved to planar_driver.cpp std::vector results; planar_visitor vis(results, graph); diff --git a/src/planar/planar_driver.cpp b/src/planar/planar_driver.cpp index e0f243d9b8..83075b8dfd 100644 --- a/src/planar/planar_driver.cpp +++ b/src/planar/planar_driver.cpp @@ -47,6 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "planar/makeMaximalPlanar.hpp" #include "cpp_common/base_graph.hpp" +#include namespace pgrouting { namespace drivers { @@ -86,20 +87,45 @@ void do_planar( UndirectedGraph undigraph; undigraph.insert_edges(edges); + std::vector component(boost::num_vertices(undigraph.graph)); + auto num_components = boost::connected_components(undigraph.graph, &component[0]); + std::vector results; - switch (which) { - case MAXIMALPLANAR: - { - pgrouting::functions::Pgr_makeMaximalPlanar - fn_makeMaximalPlanar; - results = fn_makeMaximalPlanar.makeMaximalPlanar(undigraph); - log << fn_makeMaximalPlanar.get_log(); - } - break; - default: - err << "Unknown planar function " << get_name(which); - return; + auto execute_planar = [&](UndirectedGraph& g) { + std::vector sub_results; + switch (which) { + case MAXIMALPLANAR: + { + pgrouting::functions::Pgr_makeMaximalPlanar + fn_makeMaximalPlanar; + sub_results = fn_makeMaximalPlanar.makeMaximalPlanar(g); + log << fn_makeMaximalPlanar.get_log(); + } + break; + default: + throw std::string("Unknown planar function ") + get_name(which); + } + return sub_results; + }; + + if (num_components == 1) { + results = execute_planar(undigraph); + } else { + std::vector> comp_edges(num_components); + for (const auto& edge : edges) { + auto v_desc = undigraph.get_V(edge.source); + size_t c = component[v_desc]; + comp_edges[c].push_back(edge); + } + + for (size_t c = 0; c < num_components; ++c) { + if (comp_edges[c].empty()) continue; + UndirectedGraph sub_graph; + sub_graph.insert_edges(comp_edges[c]); + auto sub_results = execute_planar(sub_graph); + results.insert(results.end(), sub_results.begin(), sub_results.end()); + } } auto count = results.size(); From 814a0c7ec447fecb61ae2de557c5522f693cb500 Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Sun, 14 Jun 2026 01:08:58 +0530 Subject: [PATCH 3/9] Move component filtering into makeMaximalPlanar.hpp, keep driver as clean dispatcher Component splitting logic belongs in the algorithm layer (.hpp), not the shared driver. This ensures future planar algorithms (planarFaces, straightLineDrawing) that join the shared driver are not forced to inherit component-splitting behavior they may not want. Each algorithm decides its own disconnected-graph strategy. --- include/planar/makeMaximalPlanar.hpp | 50 ++++++++++++++++++++++++++-- src/planar/planar_driver.cpp | 50 +++++++--------------------- 2 files changed, 59 insertions(+), 41 deletions(-) diff --git a/include/planar/makeMaximalPlanar.hpp b/include/planar/makeMaximalPlanar.hpp index 6b5c1aeed0..fab19f5f7d 100644 --- a/include/planar/makeMaximalPlanar.hpp +++ b/include/planar/makeMaximalPlanar.hpp @@ -43,6 +43,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include "c_types/ii_t_rt.h" +#include "cpp_common/edge_t.hpp" #include "cpp_common/messages.hpp" #include "cpp_common/base_graph.hpp" #include "cpp_common/interruption.hpp" @@ -58,7 +59,52 @@ class Pgr_makeMaximalPlanar : public pgrouting::Pgr_messages { typedef typename G::E_i E_i; std::vector makeMaximalPlanar(G &graph) { - return generateMakeMaximalPlanar(graph); + /* Find how many connected components this graph has */ + std::vector component(boost::num_vertices(graph.graph)); + auto num_components = boost::connected_components( + graph.graph, &component[0]); + + if (num_components == 1) { + /* Simple case: single connected graph — process directly */ + return generateMakeMaximalPlanar(graph); + } + + /* + * Multi-component case: split the graph into connected sub-graphs + * and process each one independently. This algorithm is defined to + * work per-component. Future algorithms (e.g. straightLineDrawing) + * that need a single connected graph should throw instead. + */ + log << "Graph has " << num_components + << " connected components. Processing each independently.\n"; + + /* Collect edges per component using vertex component labels */ + std::vector> comp_edges(num_components); + E_i ei, ei_end; + for (boost::tie(ei, ei_end) = edges(graph.graph); + ei != ei_end; ++ei) { + V src_v = boost::source(*ei, graph.graph); + size_t c = component[src_v]; + Edge_t e; + e.id = 0; /* synthetic id — not used by the algorithm */ + e.source = graph[src_v].id; + e.target = graph[boost::target(*ei, graph.graph)].id; + e.cost = 1; + e.reverse_cost = -1; + comp_edges[c].push_back(e); + } + + std::vector all_results; + for (size_t c = 0; c < num_components; ++c) { + if (comp_edges[c].empty()) continue; + G sub_graph; + sub_graph.insert_edges(comp_edges[c]); + auto sub_results = generateMakeMaximalPlanar(sub_graph); + all_results.insert( + all_results.end(), + sub_results.begin(), sub_results.end()); + } + return all_results; } private: @@ -119,8 +165,6 @@ class Pgr_makeMaximalPlanar : public pgrouting::Pgr_messages { return std::vector(); } - // Connected components check moved to planar_driver.cpp - std::vector results; planar_visitor vis(results, graph); diff --git a/src/planar/planar_driver.cpp b/src/planar/planar_driver.cpp index 83075b8dfd..e0f243d9b8 100644 --- a/src/planar/planar_driver.cpp +++ b/src/planar/planar_driver.cpp @@ -47,7 +47,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "planar/makeMaximalPlanar.hpp" #include "cpp_common/base_graph.hpp" -#include namespace pgrouting { namespace drivers { @@ -87,45 +86,20 @@ void do_planar( UndirectedGraph undigraph; undigraph.insert_edges(edges); - std::vector component(boost::num_vertices(undigraph.graph)); - auto num_components = boost::connected_components(undigraph.graph, &component[0]); - std::vector results; - auto execute_planar = [&](UndirectedGraph& g) { - std::vector sub_results; - switch (which) { - case MAXIMALPLANAR: - { - pgrouting::functions::Pgr_makeMaximalPlanar - fn_makeMaximalPlanar; - sub_results = fn_makeMaximalPlanar.makeMaximalPlanar(g); - log << fn_makeMaximalPlanar.get_log(); - } - break; - default: - throw std::string("Unknown planar function ") + get_name(which); - } - return sub_results; - }; - - if (num_components == 1) { - results = execute_planar(undigraph); - } else { - std::vector> comp_edges(num_components); - for (const auto& edge : edges) { - auto v_desc = undigraph.get_V(edge.source); - size_t c = component[v_desc]; - comp_edges[c].push_back(edge); - } - - for (size_t c = 0; c < num_components; ++c) { - if (comp_edges[c].empty()) continue; - UndirectedGraph sub_graph; - sub_graph.insert_edges(comp_edges[c]); - auto sub_results = execute_planar(sub_graph); - results.insert(results.end(), sub_results.begin(), sub_results.end()); - } + switch (which) { + case MAXIMALPLANAR: + { + pgrouting::functions::Pgr_makeMaximalPlanar + fn_makeMaximalPlanar; + results = fn_makeMaximalPlanar.makeMaximalPlanar(undigraph); + log << fn_makeMaximalPlanar.get_log(); + } + break; + default: + err << "Unknown planar function " << get_name(which); + return; } auto count = results.size(); From 57c0b608dbe0d87bafa5f4255840f4e3a89948dc Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Mon, 15 Jun 2026 12:47:18 +0530 Subject: [PATCH 4/9] Extract accurate edge id and costs during component split --- include/planar/makeMaximalPlanar.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/planar/makeMaximalPlanar.hpp b/include/planar/makeMaximalPlanar.hpp index fab19f5f7d..f82f964aa5 100644 --- a/include/planar/makeMaximalPlanar.hpp +++ b/include/planar/makeMaximalPlanar.hpp @@ -86,11 +86,11 @@ class Pgr_makeMaximalPlanar : public pgrouting::Pgr_messages { V src_v = boost::source(*ei, graph.graph); size_t c = component[src_v]; Edge_t e; - e.id = 0; /* synthetic id — not used by the algorithm */ - e.source = graph[src_v].id; - e.target = graph[boost::target(*ei, graph.graph)].id; - e.cost = 1; - e.reverse_cost = -1; + e.id = graph[*ei].id; + e.source = graph[src_v].id; + e.target = graph[boost::target(*ei, graph.graph)].id; + e.cost = graph[*ei].cost; + e.reverse_cost = graph[*ei].reverse_cost; comp_edges[c].push_back(e); } From ef98c71d2f0c11662f965b0f5622cd18f2257f75 Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Mon, 15 Jun 2026 13:05:06 +0530 Subject: [PATCH 5/9] Fix reverse_cost compile error by setting to -1 --- include/planar/makeMaximalPlanar.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/planar/makeMaximalPlanar.hpp b/include/planar/makeMaximalPlanar.hpp index f82f964aa5..81fe52fb64 100644 --- a/include/planar/makeMaximalPlanar.hpp +++ b/include/planar/makeMaximalPlanar.hpp @@ -90,7 +90,7 @@ class Pgr_makeMaximalPlanar : public pgrouting::Pgr_messages { e.source = graph[src_v].id; e.target = graph[boost::target(*ei, graph.graph)].id; e.cost = graph[*ei].cost; - e.reverse_cost = graph[*ei].reverse_cost; + e.reverse_cost = -1; comp_edges[c].push_back(e); } From 7054e761bcb14201cc727b77f5f96a895f2a4d86 Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Mon, 15 Jun 2026 17:29:26 +0530 Subject: [PATCH 6/9] Added pgtap tests to maximal planar --- pgtap/planar/makeMaximalPlanar/edge_cases.pg | 138 ++++++++++++++++++ pgtap/planar/makeMaximalPlanar/inner_query.pg | 31 ++++ .../planar/makeMaximalPlanar/no_crash_test.pg | 44 ++++++ pgtap/planar/makeMaximalPlanar/types_check.pg | 41 ++++++ 4 files changed, 254 insertions(+) create mode 100644 pgtap/planar/makeMaximalPlanar/edge_cases.pg create mode 100644 pgtap/planar/makeMaximalPlanar/inner_query.pg create mode 100644 pgtap/planar/makeMaximalPlanar/no_crash_test.pg create mode 100644 pgtap/planar/makeMaximalPlanar/types_check.pg diff --git a/pgtap/planar/makeMaximalPlanar/edge_cases.pg b/pgtap/planar/makeMaximalPlanar/edge_cases.pg new file mode 100644 index 0000000000..fd3078cb62 --- /dev/null +++ b/pgtap/planar/makeMaximalPlanar/edge_cases.pg @@ -0,0 +1,138 @@ +/* :file: This file is part of the pgRouting project. +:copyright: Copyright (c) 2018-2026 pgRouting developers +:license: Creative Commons Attribution-Share Alike 3.0 https://creativecommons.org/licenses/by-sa/3.0 */ + +BEGIN; + +UPDATE edges SET cost = sign(cost), reverse_cost = sign(reverse_cost); +SELECT CASE WHEN min_version('4.1.0') THEN plan (8) ELSE plan(1) END; + +CREATE OR REPLACE FUNCTION edge_cases() +RETURNS SETOF TEXT AS +$BODY$ +BEGIN + +IF NOT min_version('4.1.0') THEN + RETURN QUERY + SELECT skip(1, 'Function is new on 4.1.0'); + RETURN; +END IF; + +-- 0 edge, 0 vertex tests + +PREPARE q1 AS +SELECT id, source, target, cost, reverse_cost +FROM edges +WHERE id > 18; + +-- Graph is empty - it has 0 edge and 0 vertex +RETURN QUERY +SELECT is_empty('q1', 'q1: Graph with 0 edge and 0 vertex'); + +PREPARE zeroEdgeTest2 AS +SELECT * +FROM pgr_makeMaximalPlanar('q1'); + +RETURN QUERY +SELECT is_empty('zeroEdgeTest2', '2: Empty, since graph is empty'); + + +-- 1 vertex test + +PREPARE q5 AS +SELECT id, source, source AS target, cost, reverse_cost +FROM edges +WHERE id = 9; + +PREPARE oneVertexTest6 AS +SELECT * +FROM pgr_makeMaximalPlanar('q5'); + +RETURN QUERY +SELECT is_empty('oneVertexTest6', '6: Empty, since graph has 1 vertex'); + + +-- 2 vertices tests + +PREPARE q9 AS +SELECT id, source, target, cost, reverse_cost +FROM edges +WHERE id = 1; + +PREPARE twoVerticesTest10 AS +SELECT * +FROM pgr_makeMaximalPlanar('q9'); + +RETURN QUERY +SELECT is_empty('twoVerticesTest10', '10: Empty, graph has 2 vertices'); + + +-- 3 vertices test (Path graph: 5-6-10) + +PREPARE q11 AS +SELECT id, source, target, cost, reverse_cost +FROM edges +WHERE id IN (1,2); + +PREPARE threeVerticesTest12 AS +SELECT start_vid, end_vid +FROM pgr_makeMaximalPlanar('q11'); + +-- Path graph 5-6-10 needs edge 5-10 to become maximal planar +RETURN QUERY +SELECT set_eq('threeVerticesTest12', $$VALUES(5::bigint, 10::bigint) $$, '12: P3 graph bridged'); + + +-- 4 vertices test (Cyclic, need 1 more edge to triangulate to maximal planar) + +PREPARE q15 AS +SELECT id, source, target, cost, reverse_cost +FROM edges +WHERE id IN (8, 10, 11, 12); + +PREPARE fourVerticesCyclicTest16 AS +SELECT start_vid, end_vid +FROM pgr_makeMaximalPlanar('q15'); + +RETURN QUERY +SELECT isnt_empty('fourVerticesCyclicTest16', '16: Not empty, cyclic graph needs 1 edge to become maximal planar'); + + +-- Disjoint graphs (P3 + Cyclic) + +PREPARE q17 AS +SELECT id, source, target, cost, reverse_cost +FROM edges +WHERE id IN (1,2, 8,10,11,12); + +PREPARE disjointTest18 AS +SELECT start_vid, end_vid +FROM pgr_makeMaximalPlanar('q17'); + +RETURN QUERY +SELECT isnt_empty('disjointTest18', '18: Disjoint graph processed independently'); + + +-- Non-planar graph (K5) +PREPARE q19 AS +SELECT id, source, target, cost, reverse_cost FROM (VALUES + (1, 1, 2, 1.0, -1.0), (2, 1, 3, 1.0, -1.0), (3, 1, 4, 1.0, -1.0), (4, 1, 5, 1.0, -1.0), + (5, 2, 3, 1.0, -1.0), (6, 2, 4, 1.0, -1.0), (7, 2, 5, 1.0, -1.0), + (8, 3, 4, 1.0, -1.0), (9, 3, 5, 1.0, -1.0), + (10, 4, 5, 1.0, -1.0) +) AS t(id, source, target, cost, reverse_cost); + +PREPARE nonPlanarTest20 AS +SELECT * FROM pgr_makeMaximalPlanar('q19'); + +RETURN QUERY +SELECT is_empty('nonPlanarTest20', '20: Non-planar graph returns empty'); + +END; +$BODY$ +LANGUAGE plpgsql; + +SELECT edge_cases(); + +SELECT * FROM finish(); +ROLLBACK; diff --git a/pgtap/planar/makeMaximalPlanar/inner_query.pg b/pgtap/planar/makeMaximalPlanar/inner_query.pg new file mode 100644 index 0000000000..6d4364e815 --- /dev/null +++ b/pgtap/planar/makeMaximalPlanar/inner_query.pg @@ -0,0 +1,31 @@ +/* :file: This file is part of the pgRouting project. +:copyright: Copyright (c) 2020-2026 pgRouting developers +:license: Creative Commons Attribution-Share Alike 3.0 https://creativecommons.org/licenses/by-sa/3.0 */ + + +BEGIN; + +UPDATE edges SET cost = sign(cost), reverse_cost = sign(reverse_cost); +SELECT CASE WHEN min_version('4.1.0') THEN plan (54) ELSE plan(1) END; + +CREATE OR REPLACE FUNCTION inner_query() +RETURNS SETOF TEXT AS +$BODY$ +BEGIN + +IF NOT min_version('4.1.0') THEN + RETURN QUERY + SELECT skip(1, 'Function is new on 4.1.0'); + RETURN; +END IF; + +RETURN QUERY SELECT style_dijkstra('pgr_makeMaximalPlanar(', ')'); + +END; +$BODY$ +LANGUAGE plpgsql; + +SELECT inner_query(); + +SELECT finish(); +ROLLBACK; diff --git a/pgtap/planar/makeMaximalPlanar/no_crash_test.pg b/pgtap/planar/makeMaximalPlanar/no_crash_test.pg new file mode 100644 index 0000000000..4cd8b022cf --- /dev/null +++ b/pgtap/planar/makeMaximalPlanar/no_crash_test.pg @@ -0,0 +1,44 @@ +/* :file: This file is part of the pgRouting project. +:copyright: Copyright (c) 2018-2026 pgRouting developers +:license: Creative Commons Attribution-Share Alike 3.0 https://creativecommons.org/licenses/by-sa/3.0 */ + +BEGIN; + +UPDATE edges SET cost = sign(cost), reverse_cost = sign(reverse_cost); +SELECT CASE WHEN min_version('4.1.0') THEN plan (5) ELSE plan(1) END; + +PREPARE edges AS +SELECT id, source, target, cost, reverse_cost FROM edges; + +CREATE OR REPLACE FUNCTION test_function() +RETURNS SETOF TEXT AS +$BODY$ +DECLARE +params TEXT[]; +subs TEXT[]; +BEGIN + IF NOT min_version('4.1.0') THEN + RETURN QUERY + SELECT skip(1, 'Function is new on 4.1.0'); + RETURN; + END IF; + + RETURN QUERY + SELECT isnt_empty('edges', 'Should not be empty true to tests be meaningful'); + + params = ARRAY['$$SELECT id, source, target, cost, reverse_cost FROM edges$$']::TEXT[]; + subs = ARRAY[ + 'NULL' + ]::TEXT[]; + + RETURN QUERY + SELECT * FROM no_crash_test('pgr_makemaximalplanar', params, subs); + +END +$BODY$ +LANGUAGE plpgsql VOLATILE; + + +SELECT * FROM test_function(); +SELECT finish(); +ROLLBACK; diff --git a/pgtap/planar/makeMaximalPlanar/types_check.pg b/pgtap/planar/makeMaximalPlanar/types_check.pg new file mode 100644 index 0000000000..45d0848113 --- /dev/null +++ b/pgtap/planar/makeMaximalPlanar/types_check.pg @@ -0,0 +1,41 @@ +/* :file: This file is part of the pgRouting project. +:copyright: Copyright (c) 2018-2026 pgRouting developers +:license: Creative Commons Attribution-Share Alike 3.0 https://creativecommons.org/licenses/by-sa/3.0 */ + +BEGIN; + +SELECT CASE WHEN NOT min_version('4.1.0') THEN plan(1) ELSE plan(4) END; + +CREATE OR REPLACE FUNCTION types_check() +RETURNS SETOF TEXT AS +$BODY$ +BEGIN + + IF NOT min_version('4.1.0') THEN + RETURN QUERY + SELECT skip(1, 'Function is new on 4.1.0'); + RETURN; + END IF; + + RETURN QUERY SELECT has_function('pgr_makemaximalplanar'); + RETURN QUERY SELECT function_returns('pgr_makemaximalplanar', ARRAY['text'], 'setof record'); + + RETURN QUERY + SELECT function_args_eq('pgr_makemaximalplanar', + $$SELECT '{"",seq,start_vid,end_vid}'::TEXT[] $$ + ); + + RETURN QUERY + SELECT function_types_eq('pgr_makemaximalplanar', + $$VALUES + ('{text,int8,int8,int8}'::TEXT[]) + $$ + ); +END; +$BODY$ +LANGUAGE plpgsql; + +SELECT types_check(); + +SELECT * FROM finish(); +ROLLBACK; From 45ffd886b0b9fe1f4683309d067def535309ef39 Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Tue, 16 Jun 2026 12:55:00 +0530 Subject: [PATCH 7/9] Update docs and clean up comments --- doc/planar/pgr_makeMaximalPlanar.rst | 94 ++++++++++++++++++++++++++-- docqueries/planar/test.conf | 1 + include/planar/makeMaximalPlanar.hpp | 7 +-- 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/doc/planar/pgr_makeMaximalPlanar.rst b/doc/planar/pgr_makeMaximalPlanar.rst index 9373dad4ff..e5aeef56f8 100644 --- a/doc/planar/pgr_makeMaximalPlanar.rst +++ b/doc/planar/pgr_makeMaximalPlanar.rst @@ -4,14 +4,14 @@ .. index:: single: Planar Family ; pgr_makeMaximalPlanar - Experimental - single: makeMaximalPlanar - Experimental on v4.2 + single: makeMaximalPlanar - Experimental on v4.1 | ``pgr_makeMaximalPlanar`` - Experimental =============================================================================== -``pgr_makeMaximalPlanar`` — [TBD] +``pgr_makeMaximalPlanar`` — Returns the set of edges needed to make a planar graph maximal planar. .. include:: experimental.rst :start-after: warning-begin @@ -19,7 +19,7 @@ .. rubric:: Availability -.. rubric:: Version 4.2.0 +.. rubric:: Version 4.1.0 * New experimental function. @@ -27,4 +27,90 @@ Description ------------------------------------------------------------------------------- -[TBD] +A graph is planar if it can be drawn in two-dimensional space with no two of its +edges crossing. A planar graph is considered **maximal planar** (or fully triangulated) +if no additional edges can be added to it without violating its planarity. In a +maximal planar graph, every face (including the outer face) is a triangle. + +``pgr_makeMaximalPlanar`` identifies the missing edges that need to be added to an +existing planar graph to make it maximal planar. + +The main characteristics are: + +* Works for **undirected** graphs. +* Returns a list of all new edges which are needed to triangulate the graph and make it maximal planar. +* If the input graph is not planar, it returns an empty set. +* The algorithm does not consider traversal costs in the calculations. +* The algorithm does not consider geometric topology in the calculations. +* Running time: :math:`O(|V| + |E|)` + +|Boost| Boost Graph Inside + +Signatures +------------------------------------------------------------------------------- + +.. admonition:: \ \ + :class: signatures + + | pgr_makeMaximalPlanar(`Edges SQL`_) + + | Returns set of |result-component-make| + | OR EMPTY SET + +:Example: List of edges that are needed to make the graph maximal planar. + +.. literalinclude:: makeMaximalPlanar.queries + :start-after: -- q1 + :end-before: -- q2 + +Parameters +------------------------------------------------------------------------------- + +.. include:: pgRouting-concepts.rst + :start-after: only_edge_param_start + :end-before: only_edge_param_end + +Inner Queries +------------------------------------------------------------------------------- + +Edges SQL +............................................................................... + +.. include:: pgRouting-concepts.rst + :start-after: basic_edges_sql_start + :end-before: basic_edges_sql_end + +Result columns +------------------------------------------------------------------------------- + +Returns set of |result-component-make| + +.. list-table:: + :width: 81 + :widths: auto + :header-rows: 1 + + * - Column + - Type + - Description + * - ``seq`` + - ``BIGINT`` + - Sequential value starting from **1**. + * - ``start_vid`` + - ``BIGINT`` + - Identifier of the first end point vertex of the edge. + * - ``end_vid`` + - ``BIGINT`` + - Identifier of the second end point vertex of the edge. + +See Also +------------------------------------------------------------------------------- + +* `Boost: make_maximal_planar + `__ +* :doc:`sampledata` + +.. rubric:: Indices and tables + +* :ref:`genindex` +* :ref:`search` diff --git a/docqueries/planar/test.conf b/docqueries/planar/test.conf index 3c33912e3d..96e526c790 100644 --- a/docqueries/planar/test.conf +++ b/docqueries/planar/test.conf @@ -7,6 +7,7 @@ 'any' => { 'files' => [qw( isPlanar.pg + makeMaximalPlanar.pg )] }, diff --git a/include/planar/makeMaximalPlanar.hpp b/include/planar/makeMaximalPlanar.hpp index 81fe52fb64..b895027186 100644 --- a/include/planar/makeMaximalPlanar.hpp +++ b/include/planar/makeMaximalPlanar.hpp @@ -69,12 +69,7 @@ class Pgr_makeMaximalPlanar : public pgrouting::Pgr_messages { return generateMakeMaximalPlanar(graph); } - /* - * Multi-component case: split the graph into connected sub-graphs - * and process each one independently. This algorithm is defined to - * work per-component. Future algorithms (e.g. straightLineDrawing) - * that need a single connected graph should throw instead. - */ + /* Multi-component case: split the graph into connected sub-graphs */ log << "Graph has " << num_components << " connected components. Processing each independently.\n"; From 3653165e09d0fcd712883a68112b04b9865b6cad Mon Sep 17 00:00:00 2001 From: Mohit Rawat Date: Tue, 16 Jun 2026 12:55:12 +0530 Subject: [PATCH 8/9] Add makeMaximalPlanar.result --- docqueries/planar/makeMaximalPlanar.result | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docqueries/planar/makeMaximalPlanar.result b/docqueries/planar/makeMaximalPlanar.result index 3767ff8b1b..b20cf64257 100644 --- a/docqueries/planar/makeMaximalPlanar.result +++ b/docqueries/planar/makeMaximalPlanar.result @@ -1,3 +1,35 @@ +BEGIN; +BEGIN +SET client_min_messages TO NOTICE; +SET /* :file: This file is part of the pgRouting project. :copyright: Copyright (c) 2020-2026 pgRouting developers :license: Creative Commons Attribution-Share Alike 3.0 https://creativecommons.org/licenses/by-sa/3.0 */ +/* -- q1 */ +SELECT * FROM pgr_makeMaximalPlanar( + 'SELECT id, source, target, cost, reverse_cost FROM edges' +); + seq | start_vid | end_vid +-----+-----------+--------- + 1 | 7 | 9 + 2 | 10 | 5 + 3 | 3 | 11 + 4 | 1 | 7 + 5 | 1 | 6 + 6 | 1 | 5 + 7 | 1 | 10 + 8 | 1 | 11 + 9 | 17 | 15 + 10 | 17 | 10 + 11 | 17 | 6 + 12 | 17 | 7 + 13 | 17 | 8 + 14 | 15 | 11 + 15 | 9 | 11 + 16 | 9 | 12 + 17 | 16 | 12 +(17 rows) + +/* -- q2 */ +ROLLBACK; +ROLLBACK From ba317085ff3c84d01d8c77b294ade2002c84f072 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 15:22:52 +0000 Subject: [PATCH 9/9] Update locale: commit 3653165e0 --- .../en/LC_MESSAGES/pgrouting_doc_strings.po | 50 +++++++++++++++++-- locale/pot/pgrouting_doc_strings.pot | 36 +++++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/locale/en/LC_MESSAGES/pgrouting_doc_strings.po b/locale/en/LC_MESSAGES/pgrouting_doc_strings.po index a04ece1470..e441b472cb 100644 --- a/locale/en/LC_MESSAGES/pgrouting_doc_strings.po +++ b/locale/en/LC_MESSAGES/pgrouting_doc_strings.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: pgRouting v4.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-05 13:26+0000\n" +"POT-Creation-Date: 2026-06-16 15:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -12897,10 +12897,54 @@ msgid "" msgstr "" #, fuzzy -msgid "pgr_makeMaximalPlanar" +msgid "``pgr_makeMaximalPlanar`` - Experimental" msgstr "pgr_isPlanar" -msgid "(Documentation to be added later)" +msgid "" +"``pgr_makeMaximalPlanar`` — Returns the set of edges needed to make a planar " +"graph maximal planar." +msgstr "" + +msgid "" +"A graph is planar if it can be drawn in two-dimensional space with no two of " +"its edges crossing. A planar graph is considered **maximal planar** (or " +"fully triangulated) if no additional edges can be added to it without " +"violating its planarity. In a maximal planar graph, every face (including " +"the outer face) is a triangle." +msgstr "" + +msgid "" +"``pgr_makeMaximalPlanar`` identifies the missing edges that need to be added " +"to an existing planar graph to make it maximal planar." +msgstr "" + +msgid "" +"Returns a list of all new edges which are needed to triangulate the graph " +"and make it maximal planar." +msgstr "" + +msgid "If the input graph is not planar, it returns an empty set." +msgstr "" + +msgid "The algorithm does not consider traversal costs in the calculations." +msgstr "" + +msgid "The algorithm does not consider geometric topology in the calculations." +msgstr "" + +msgid "Running time: :math:`O(|V| + |E|)`" +msgstr "" + +#, fuzzy +msgid "pgr_makeMaximalPlanar(`Edges SQL`_)" +msgstr "pgr_isPlanar" + +msgid "List of edges that are needed to make the graph maximal planar." +msgstr "" + +msgid "" +"`Boost: make_maximal_planar `__" msgstr "" msgid "``pgr_maxCardinalityMatch``" diff --git a/locale/pot/pgrouting_doc_strings.pot b/locale/pot/pgrouting_doc_strings.pot index 4c3c7e080b..4a9750396c 100644 --- a/locale/pot/pgrouting_doc_strings.pot +++ b/locale/pot/pgrouting_doc_strings.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: pgRouting v4.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-05 13:26+0000\n" +"POT-Creation-Date: 2026-06-16 15:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -10990,10 +10990,40 @@ msgstr "" msgid "`Boost: make connected `__" msgstr "" -msgid "pgr_makeMaximalPlanar" +msgid "``pgr_makeMaximalPlanar`` - Experimental" msgstr "" -msgid "(Documentation to be added later)" +msgid "``pgr_makeMaximalPlanar`` — Returns the set of edges needed to make a planar graph maximal planar." +msgstr "" + +msgid "A graph is planar if it can be drawn in two-dimensional space with no two of its edges crossing. A planar graph is considered **maximal planar** (or fully triangulated) if no additional edges can be added to it without violating its planarity. In a maximal planar graph, every face (including the outer face) is a triangle." +msgstr "" + +msgid "``pgr_makeMaximalPlanar`` identifies the missing edges that need to be added to an existing planar graph to make it maximal planar." +msgstr "" + +msgid "Returns a list of all new edges which are needed to triangulate the graph and make it maximal planar." +msgstr "" + +msgid "If the input graph is not planar, it returns an empty set." +msgstr "" + +msgid "The algorithm does not consider traversal costs in the calculations." +msgstr "" + +msgid "The algorithm does not consider geometric topology in the calculations." +msgstr "" + +msgid "Running time: :math:`O(|V| + |E|)`" +msgstr "" + +msgid "pgr_makeMaximalPlanar(`Edges SQL`_)" +msgstr "" + +msgid "List of edges that are needed to make the graph maximal planar." +msgstr "" + +msgid "`Boost: make_maximal_planar `__" msgstr "" msgid "``pgr_maxCardinalityMatch``"