diff --git a/docqueries/withPoints/test.conf b/docqueries/withPoints/test.conf index 0ab6ca151b..54d0e5b1c7 100644 --- a/docqueries/withPoints/test.conf +++ b/docqueries/withPoints/test.conf @@ -11,6 +11,7 @@ doc-pgr_withPointsDD withPointsVia withPointsKSP + doc-pgr_withPointsKSP )], 'documentation' => [qw( doc-pgr_withPoints @@ -18,6 +19,7 @@ doc-pgr_withPointsCostMatrix doc-pgr_withPointsDD withPointsKSP + doc-pgr_withPointsKSP withPointsVia )], }, diff --git a/include/drivers/yen/withPoints_ksp_driver.h b/include/drivers/yen/withPoints_ksp_driver.h index 16986e2195..b11551a2c8 100644 --- a/include/drivers/yen/withPoints_ksp_driver.h +++ b/include/drivers/yen/withPoints_ksp_driver.h @@ -69,6 +69,25 @@ extern "C" { Path_rt**, size_t*, char**, char**, char**); + +/*TODO remove on v4*/ + int do_pgr_withPointsKsp( + Edge_t *edges, size_t total_edges, + Point_on_edge_t *points, size_t total_points, + Edge_t *edges_of_points, size_t total_edges_of_points, + int64_t start_pid, + int64_t end_pid, + size_t k, + bool directed, + bool heap_paths, + char driving_side, + bool details, + + Path_rt **return_tuples, + size_t *return_count, + char ** log_msg, + char ** notice_msg, + char ** err_msg); #ifdef __cplusplus diff --git a/sql/ksp/_withPointsKSP.sql b/sql/ksp/_withPointsKSP.sql index defe195aa0..47baed64db 100644 --- a/sql/ksp/_withPointsKSP.sql +++ b/sql/ksp/_withPointsKSP.sql @@ -83,6 +83,7 @@ IS 'pgRouting internal function'; COMMENT ON FUNCTION _pgr_v4withPointsKSP(TEXT, TEXT, TEXT, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) IS 'pgRouting internal function'; +/*TODO remove on v4*/ --v3.0 CREATE FUNCTION _pgr_withPointsKSP( edges_sql TEXT, diff --git a/sql/ksp/withPointsKSP.sql b/sql/ksp/withPointsKSP.sql index c1cea53611..df2962cb39 100644 --- a/sql/ksp/withPointsKSP.sql +++ b/sql/ksp/withPointsKSP.sql @@ -186,7 +186,7 @@ ROWS 1000; -- COMMENTS -COMMENT ON FUNCTION pgr_v4withPointsKSP(TEXT, TEXT, BIGINT, BIGINT, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) +COMMENT ON FUNCTION pgr_withPointsKSP(TEXT, TEXT, BIGINT, BIGINT, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) IS 'pgr_withPointsKSP - PROPOSED - Parameters: @@ -203,7 +203,7 @@ IS 'pgr_withPointsKSP - Documentation: - ${PROJECT_DOC_LINK}/pgr_withPointsKSP.html'; -COMMENT ON FUNCTION pgr_v4withPointsKSP(TEXT, TEXT, BIGINT, ANYARRAY, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) +COMMENT ON FUNCTION pgr_withPointsKSP(TEXT, TEXT, BIGINT, ANYARRAY, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) IS 'pgr_withPointsKSP - PROPOSED - Parameters: @@ -220,7 +220,7 @@ IS 'pgr_withPointsKSP - Documentation: - ${PROJECT_DOC_LINK}/pgr_withPointsKSP.html'; -COMMENT ON FUNCTION pgr_v4withPointsKSP(TEXT, TEXT, ANYARRAY, BIGINT, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) +COMMENT ON FUNCTION pgr_withPointsKSP(TEXT, TEXT, ANYARRAY, BIGINT, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) IS 'pgr_withPointsKSP - PROPOSED - Parameters: @@ -237,7 +237,7 @@ IS 'pgr_withPointsKSP - Documentation: - ${PROJECT_DOC_LINK}/pgr_withPointsKSP.html'; -COMMENT ON FUNCTION pgr_v4withPointsKSP(TEXT, TEXT, ANYARRAY, ANYARRAY, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) +COMMENT ON FUNCTION pgr_withPointsKSP(TEXT, TEXT, ANYARRAY, ANYARRAY, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) IS 'pgr_withPointsKSP - PROPOSED - Parameters: @@ -254,7 +254,7 @@ IS 'pgr_withPointsKSP - Documentation: - ${PROJECT_DOC_LINK}/pgr_withPointsKSP.html'; -COMMENT ON FUNCTION pgr_v4withPointsKSP(TEXT, TEXT, TEXT, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) +COMMENT ON FUNCTION pgr_withPointsKSP(TEXT, TEXT, TEXT, INTEGER, CHAR, BOOLEAN, BOOLEAN, BOOLEAN) IS 'pgr_withPointsKSP - PROPOSED - Parameters: diff --git a/src/ksp/withPoints_ksp.c b/src/ksp/withPoints_ksp.c index 8c7810b941..9442e9eb25 100644 --- a/src/ksp/withPoints_ksp.c +++ b/src/ksp/withPoints_ksp.c @@ -46,10 +46,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. PGDLLEXPORT Datum _pgr_withpointsksp(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(_pgr_withpointsksp); +PGDLLEXPORT Datum _pgr_v4withpointsksp(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(_pgr_v4withpointsksp); static void -process( +processv4( char* edges_sql, char* points_sql, char* combinations_sql, @@ -200,7 +202,7 @@ process( -PGDLLEXPORT Datum _pgr_withpointsksp(PG_FUNCTION_ARGS) { +PGDLLEXPORT Datum _pgr_v4withpointsksp(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; @@ -213,7 +215,7 @@ PGDLLEXPORT Datum _pgr_withpointsksp(PG_FUNCTION_ARGS) { oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); if(PG_NARGS() == 9){ - process( + processv4( text_to_cstring(PG_GETARG_TEXT_P(0)), text_to_cstring(PG_GETARG_TEXT_P(1)), NULL, @@ -227,7 +229,7 @@ PGDLLEXPORT Datum _pgr_withpointsksp(PG_FUNCTION_ARGS) { &result_tuples, &result_count); } else/* (PG_NARGS() == 8) */{ - process( + processv4( text_to_cstring(PG_GETARG_TEXT_P(0)), text_to_cstring(PG_GETARG_TEXT_P(1)), text_to_cstring(PG_GETARG_TEXT_P(2)), @@ -274,18 +276,6 @@ PGDLLEXPORT Datum _pgr_withpointsksp(PG_FUNCTION_ARGS) { nulls[i] = false; } - /* - OUT seq INTEGER, - OUT path_id INTEGER, - OUT path_seq INTEGER, - OUT start_vid BIGINT, - OUT end_vid BIGINT, - OUT node BIGINT, - OUT edge BIGINT, - OUT cost FLOAT, - OUT agg_cost FLOAT - */ - int64_t path_id = 1; if (funcctx->call_cntr != 0) { if (result_tuples[funcctx->call_cntr - 1].edge == -1) { @@ -315,3 +305,222 @@ PGDLLEXPORT Datum _pgr_withpointsksp(PG_FUNCTION_ARGS) { } } + +/*TODO remove on v4*/ +static +void +process( + char* edges_sql, + char* points_sql, + int64_t start_pid, + int64_t end_pid, + int p_k, + + bool directed, + bool heap_paths, + char *driving_side, + bool details, + + Path_rt **result_tuples, + size_t *result_count) { + if (p_k < 0) { + return; + } + + size_t k = (size_t)p_k; + + driving_side[0] = (char) tolower(driving_side[0]); + PGR_DBG("driving side:%c", driving_side[0]); + if (!((driving_side[0] == 'r') + || (driving_side[0] == 'l'))) { + driving_side[0] = 'b'; + } + + pgr_SPI_connect(); + char* log_msg = NULL; + char* notice_msg = NULL; + char* err_msg = NULL; + + Point_on_edge_t *points = NULL; + size_t total_points = 0; + pgr_get_points(points_sql, &points, &total_points, &err_msg); + throw_error(err_msg, points_sql); + + char *edges_of_points_query = NULL; + char *edges_no_points_query = NULL; + get_new_queries( + edges_sql, points_sql, + &edges_of_points_query, + &edges_no_points_query); + + + Edge_t *edges_of_points = NULL; + size_t total_edges_of_points = 0; + pgr_get_edges(edges_of_points_query, &edges_of_points, &total_edges_of_points, true, false, &err_msg); + throw_error(err_msg, edges_of_points_query); + + Edge_t *edges = NULL; + size_t total_edges = 0; + pgr_get_edges(edges_no_points_query, &edges, &total_edges, true, false, &err_msg); + throw_error(err_msg, edges_no_points_query); + + PGR_DBG("freeing allocated memory not used anymore"); + pfree(edges_of_points_query); + pfree(edges_no_points_query); + + if ((total_edges + total_edges_of_points) == 0) { + PGR_DBG("No edges found"); + (*result_count) = 0; + (*result_tuples) = NULL; + pgr_SPI_finish(); + return; + } + + PGR_DBG("Starting processing"); + clock_t start_t = clock(); + + do_pgr_withPointsKsp( + edges, + total_edges, + points, + total_points, + edges_of_points, + total_edges_of_points, + start_pid, + end_pid, + k, + + directed, + heap_paths, + driving_side[0], + details, + + result_tuples, + result_count, + + &log_msg, + ¬ice_msg, + &err_msg); + time_msg(" processing withPointsKSP", start_t, clock()); + + if (err_msg && (*result_tuples)) { + pfree(*result_tuples); + (*result_tuples) = NULL; + (*result_count) = 0; + } + + pgr_global_report(log_msg, notice_msg, err_msg); + + if (log_msg) pfree(log_msg); + if (notice_msg) pfree(notice_msg); + if (err_msg) pfree(err_msg); + + pfree(edges); + pfree(edges_of_points); + pfree(points); + + pgr_SPI_finish(); +} + + + + +PGDLLEXPORT Datum _pgr_withpointsksp(PG_FUNCTION_ARGS) { + FuncCallContext *funcctx; + TupleDesc tuple_desc; + + Path_rt *result_tuples = 0; + size_t result_count = 0; + + if (SRF_IS_FIRSTCALL()) { + MemoryContext oldcontext; + funcctx = SRF_FIRSTCALL_INIT(); + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + + /* + CREATE OR REPLACE FUNCTION pgr_withPoint( + edges_sql TEXT, + points_sql TEXT, + start_pid INTEGER, + end_pid BIGINT, + k BIGINT, + directed BOOLEAN -- DEFAULT true, + heap_paths BOOLEAN -- DEFAULT false, + driving_side CHAR -- DEFAULT 'b', + details BOOLEAN -- DEFAULT false + */ + + PGR_DBG("Calling process"); + PGR_DBG("initial driving side:%s", + text_to_cstring(PG_GETARG_TEXT_P(7))); + process( + text_to_cstring(PG_GETARG_TEXT_P(0)), + text_to_cstring(PG_GETARG_TEXT_P(1)), + PG_GETARG_INT64(2), + PG_GETARG_INT64(3), + PG_GETARG_INT32(4), + PG_GETARG_BOOL(5), + PG_GETARG_BOOL(6), + text_to_cstring(PG_GETARG_TEXT_P(7)), + PG_GETARG_BOOL(8), + &result_tuples, + &result_count); + + + funcctx->max_calls = result_count; + + funcctx->user_fctx = result_tuples; + if (get_call_result_type(fcinfo, NULL, &tuple_desc) + != TYPEFUNC_COMPOSITE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("function returning record called in context " + "that cannot accept type record"))); + + funcctx->tuple_desc = tuple_desc; + MemoryContextSwitchTo(oldcontext); + } + + funcctx = SRF_PERCALL_SETUP(); + tuple_desc = funcctx->tuple_desc; + result_tuples = (Path_rt*) funcctx->user_fctx; + + if (funcctx->call_cntr < funcctx->max_calls) { + HeapTuple tuple; + Datum result; + Datum *values; + bool* nulls; + + values = palloc(7 * sizeof(Datum)); + nulls = palloc(7 * sizeof(bool)); + + size_t i; + for (i = 0; i < 7; ++i) { + nulls[i] = false; + } + + /* + OUT seq INTEGER, OUT path_id INTEGER, OUT path_seq INTEGER, + OUT node BIGINT, OUT edge BIGINT, + OUT cost FLOAT, OUT agg_cost FLOAT) + */ + + + // postgres starts counting from 1 + values[0] = Int32GetDatum(funcctx->call_cntr + 1); + values[1] = Int32GetDatum((int) + (result_tuples[funcctx->call_cntr].start_id + 1)); + values[2] = Int32GetDatum(result_tuples[funcctx->call_cntr].seq); + values[3] = Int64GetDatum(result_tuples[funcctx->call_cntr].node); + values[4] = Int64GetDatum(result_tuples[funcctx->call_cntr].edge); + values[5] = Float8GetDatum(result_tuples[funcctx->call_cntr].cost); + values[6] = Float8GetDatum(result_tuples[funcctx->call_cntr].agg_cost); + + tuple = heap_form_tuple(tuple_desc, values, nulls); + result = HeapTupleGetDatum(tuple); + SRF_RETURN_NEXT(funcctx, result); + } else { + SRF_RETURN_DONE(funcctx); + } +} \ No newline at end of file diff --git a/src/ksp/withPoints_ksp_driver.cpp b/src/ksp/withPoints_ksp_driver.cpp index 9bc2d7c246..08a0cdf1ee 100644 --- a/src/ksp/withPoints_ksp_driver.cpp +++ b/src/ksp/withPoints_ksp_driver.cpp @@ -49,14 +49,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. using pgrouting::yen::Pgr_ksp; -// CREATE OR REPLACE FUNCTION pgr_withPointsKSP( -// edges_sql TEXT, -// points_sql TEXT, -// start_pid BIGINT, -// end_pid BIGINT, -// directed BOOLEAN DEFAULT true - - int pgr_do_withPointsKsp( Edge_t *edges, size_t total_edges, @@ -198,3 +190,162 @@ pgr_do_withPointsKsp( } return 1000; } + + +/*TODO remove on v4*/ +int +do_pgr_withPointsKsp( + Edge_t *edges, size_t total_edges, + Point_on_edge_t *points_p, size_t total_points, + Edge_t *edges_of_points, size_t total_edges_of_points, + int64_t start_pid, + int64_t end_pid, + size_t k, + bool directed, + bool heap_paths, + char driving_side, + bool details, + Path_rt **return_tuples, + size_t *return_count, + char ** log_msg, + char ** notice_msg, + char ** err_msg) { + using pgrouting::Path; + using pgrouting::pgr_alloc; + using pgrouting::pgr_msg; + using pgrouting::pgr_free; + + std::ostringstream log; + std::ostringstream err; + std::ostringstream notice; + try { + pgassert(!(*log_msg)); + pgassert(!(*notice_msg)); + pgassert(!(*err_msg)); + pgassert(!(*return_tuples)); + pgassert(*return_count == 0); + pgassert(total_edges != 0); + + pgrouting::Pg_points_graph pg_graph( + std::vector( + points_p, + points_p + total_points), + std::vector< Edge_t >( + edges_of_points, + edges_of_points + total_edges_of_points), + true, + driving_side, + directed); + + if (pg_graph.has_error()) { + log << pg_graph.get_log(); + err << pg_graph.get_error(); + *log_msg = pgr_msg(log.str().c_str()); + *err_msg = pgr_msg(err.str().c_str()); + return -1; + } + + + int64_t start_vid(start_pid); + int64_t end_vid(end_pid); + + log << "start_pid" << start_pid << "\n"; + log << "end_pid" << end_pid << "\n"; + log << "driving_side" << driving_side << "\n"; + log << "start_vid" << start_vid << "\n"; + log << "end_vid" << end_vid << "\n"; + graphType gType = directed? DIRECTED: UNDIRECTED; + + std::deque< Path > paths; + + auto vertices(pgrouting::extract_vertices(edges, total_edges)); + vertices = pgrouting::extract_vertices(vertices, pg_graph.new_edges()); + + log << "extracted vertices: "; + for (const auto& v : vertices) { + log << v.id << ", "; + } + log << "\n"; + + if (directed) { + log << "Working with directed Graph\n"; + pgrouting::DirectedGraph digraph(vertices, gType); + digraph.insert_edges(edges, total_edges); + log << "graph after inserting edges\n"; + log << digraph << "\n"; + + digraph.insert_edges(pg_graph.new_edges()); + log << "graph after inserting new edges\n"; + log << digraph << "\n"; + + Pgr_ksp< pgrouting::DirectedGraph > fn_yen; + paths = fn_yen.Yen(digraph, start_vid, end_vid, k, heap_paths); + // pgassert(true==false); + } else { + log << "Working with undirected Graph\n"; + pgrouting::UndirectedGraph undigraph(gType); + undigraph.insert_edges(edges, total_edges); + undigraph.insert_edges(pg_graph.new_edges()); + + Pgr_ksp< pgrouting::UndirectedGraph > fn_yen; + paths = fn_yen.Yen(undigraph, start_vid, end_vid, k, heap_paths); + } + + + if (!details) { + for (auto &path : paths) { + path = pg_graph.eliminate_details(path); + } + } + + auto count(count_tuples(paths)); + + if (count == 0) { + return 0; + } + + + *return_tuples = NULL; + *return_tuples = pgr_alloc(count, (*return_tuples)); + + size_t sequence = 0; + int route_id = 0; + for (const auto &path : paths) { + if (path.size() > 0) + path.get_pg_ksp_path(return_tuples, sequence, route_id); + ++route_id; + } + + if (count != sequence) { + return 2; + } + (*return_count) = sequence; + + *log_msg = log.str().empty()? + *log_msg : + pgr_msg(log.str().c_str()); + *notice_msg = notice.str().empty()? + *notice_msg : + pgr_msg(notice.str().c_str()); + return 0; + } catch (AssertFailedException &except) { + (*return_tuples) = pgr_free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = pgr_msg(err.str().c_str()); + *log_msg = pgr_msg(log.str().c_str()); + } catch (std::exception &except) { + (*return_tuples) = pgr_free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = pgr_msg(err.str().c_str()); + *log_msg = pgr_msg(log.str().c_str()); + } catch(...) { + (*return_tuples) = pgr_free(*return_tuples); + (*return_count) = 0; + err << "Caught unknown exception!"; + *err_msg = pgr_msg(err.str().c_str()); + *log_msg = pgr_msg(log.str().c_str()); + } + return 1000; +} \ No newline at end of file