GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
net_build.c
Go to the documentation of this file.
1/*!
2 * \file lib/vector/Vlib/net_build.c
3 *
4 * \brief Vector library - related fns for vector network building
5 *
6 * Higher level functions for reading/writing/manipulating vectors.
7 *
8 * SPDX-FileCopyrightText: 2001-2009, 2014 GRASS Development Team
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 *
11 * \author Radim Blazek
12 * \author Stepan Turek stepan.turek seznam.cz (turns support)
13 */
14
15#include <grass/dbmi.h>
16#include <grass/vector.h>
17#include <grass/glocale.h>
18
19/*!
20 \brief Build network graph with turntable.
21
22 Internal format for edge costs is integer, costs are multiplied
23 before conversion to int by 1000 and for lengths LL without geo flag by
24 1000000. The same multiplication factor is used for nodes. Costs in database
25 column may be 'integer' or 'double precision' number >= 0 or -1 for infinity
26 i.e. arc or node is closed and cannot be traversed If record in table is not
27 found for arcs, costs for arc are set to 0. If record in table is not found
28 for node, costs for node are set to 0.
29
30 \param Map vector map
31 \param ltype line type for arcs
32 \param afield arc costs field (if 0, use length)
33 \param nfield node costs field (if 0, do not use node costs)
34 \param tfield field where turntable is attached
35 \param tucfield field with unique categories used in the turntable
36 \param afcol column with forward costs for arc
37 \param abcol column with backward costs for arc (if NULL, back costs =
38 forward costs)
39 \param ncol column with costs for nodes (if NULL, do not use
40 node costs)
41 \param geo use geodesic calculation for length (LL)
42 \param algorithm not used (in future code for algorithm)
43
44 \return 0 on success, 1 on error
45 */
47 int nfield, int tfield, int tucfield,
48 const char *afcol, const char *abcol,
49 const char *ncol, int geo, int algorithm G_UNUSED)
50{
51 /* TODO very long function, split into smaller ones */
52 int i, j, from, to, line, nlines, nnodes, ret, type, cat, skipped, cfound;
53 struct line_pnts *Points;
54 struct line_cats *Cats;
55 double dcost, bdcost, ll;
56 int cost, bcost;
58 dglInt32_t opaqueset[16] = {360000, 0, 0, 0, 0, 0, 0, 0,
59 0, 0, 0, 0, 0, 0, 0, 0};
60 struct field_info *Fi = NULL;
63 dbHandle handle;
64 dbString stmt;
67 int fctype = 0, bctype = 0, nrec, nturns;
68
70 struct line_cats *ln_Cats;
71 double x, y, z;
72 struct bound_box box;
73 struct boxlist *List;
74
76
77 /*TODO attributes of turntable should be stored in one place */
78 const char *tcols[] = {"cat", "ln_from", "ln_to", "cost", "isec", NULL};
80 int tctype[5] = {0};
81 int tucfield_idx;
82
83 int t, f;
85 int isec;
86
87 /* TODO int costs -> double (waiting for dglib) */
88 G_debug(1,
89 "Vect_net_ttb_build_graph(): "
90 "ltype = %d, afield = %d, nfield = %d, tfield = %d, tucfield = %d ",
92 G_debug(1, " afcol = %s, abcol = %s, ncol = %s", afcol, abcol, ncol);
93
94 G_message(_("Building graph..."));
95
96 Map->dgraph.line_type = ltype;
97
98 Points = Vect_new_line_struct();
100
101 ll = 0;
102 if (G_projection() == 3)
103 ll = 1; /* LL */
104
105 if (afcol == NULL && ll && !geo)
106 Map->dgraph.cost_multip = 1000000;
107 else
108 Map->dgraph.cost_multip = 1000;
109
110 nlines = Vect_get_num_lines(Map);
112
113 gr = &(Map->dgraph.graph_s);
114
115 /* Allocate space for costs, later replace by functions reading costs from
116 * graph */
117 Map->dgraph.edge_fcosts = (double *)G_malloc((nlines + 1) * sizeof(double));
118 Map->dgraph.edge_bcosts = (double *)G_malloc((nlines + 1) * sizeof(double));
119 Map->dgraph.node_costs = (double *)G_malloc((nnodes + 1) * sizeof(double));
120
121 /* Set to -1 initially */
122 for (i = 1; i <= nlines; i++) {
123 Map->dgraph.edge_fcosts[i] = -1; /* forward */
124 Map->dgraph.edge_bcosts[i] = -1; /* backward */
125 }
126 for (i = 1; i <= nnodes; i++) {
127 Map->dgraph.node_costs[i] = 0;
128 }
129
131 opaqueset);
132
133 if (gr == NULL)
134 G_fatal_error(_("Unable to build network graph"));
135
136 db_init_handle(&handle);
137 db_init_string(&stmt);
138
139 if (abcol != NULL && afcol == NULL)
140 G_fatal_error(_("Forward costs column not specified"));
141
142 /* --- Add arcs --- */
143 /* Open db connection */
144
145 /* Get field info */
146 if (tfield < 1)
147 G_fatal_error(_("Turntable field < 1"));
149 if (Fi == NULL)
150 G_fatal_error(_("Database connection not defined for layer %d"),
151 tfield);
152
153 /* Open database */
154 ttbdriver = db_start_driver_open_database(Fi->driver, Fi->database);
155 if (ttbdriver == NULL)
156 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
157 Fi->database, Fi->driver);
158
159 i = 0;
160 while (tcols[i]) {
161 /* Load costs to array */
162 if (db_get_column(ttbdriver, Fi->table, tcols[i], &Column) != DB_OK)
163 G_fatal_error(_("Turntable column <%s> not found in table <%s>"),
164 tcols[i], Fi->table);
165
168
169 if ((tctype[i] == DB_C_TYPE_INT || tctype[i] == DB_C_TYPE_DOUBLE) &&
170 !strcmp(tcols[i], "cost"))
171 ;
172 else if (tctype[i] == DB_C_TYPE_INT)
173 ;
174 else
176 _("Data type of column <%s> not supported (must be numeric)"),
177 tcols[i]);
178
180 nturns = db_select_CatValArray(ttbdriver, Fi->table, Fi->key, tcols[i],
181 NULL, &tvarrs[i]);
182 ++i;
183 }
184
186
187 G_debug(1, "forward costs: nrec = %d", nturns);
188
189 /* Set node attributes */
190 G_message("Register nodes");
191 if (ncol != NULL) {
192
193 G_debug(2, "Set nodes' costs");
194 if (nfield < 1)
195 G_fatal_error("Node field < 1");
196
197 G_message(_("Setting node costs..."));
198
200 if (Fi == NULL)
201 G_fatal_error(_("Database connection not defined for layer %d"),
202 nfield);
203
204 driver = db_start_driver_open_database(Fi->driver, Fi->database);
205 if (driver == NULL)
206 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
207 Fi->database, Fi->driver);
208
209 /* Load costs to array */
210 if (db_get_column(driver, Fi->table, ncol, &Column) != DB_OK)
211 G_fatal_error(_("Column <%s> not found in table <%s>"), ncol,
212 Fi->table);
213
216
219 _("Data type of column <%s> not supported (must be numeric)"),
220 ncol);
221
223
224 nrec = db_select_CatValArray(driver, Fi->table, Fi->key, ncol, NULL,
225 &fvarr);
226 G_debug(1, "node costs: nrec = %d", nrec);
228
230 }
231
234
235 G_message("Building turns graph...");
236
237 i_virt_edge = -1;
238 for (i = 1; i <= nnodes; i++) {
239 /* TODO: what happens if we set attributes of non existing node (skipped
240 * lines, nodes without lines) */
241
242 /* select points at node */
243 Vect_get_node_coor(Map, i, &x, &y, &z);
244 box.E = box.W = x;
245 box.N = box.S = y;
246 box.T = box.B = z;
248
249 G_debug(2, " node = %d nlines = %d", i, List->n_values);
250 cfound = 0;
251 dcost = 0;
252 tucfound = 0;
253
254 for (j = 0; j < List->n_values; j++) {
255 line = List->id[j];
256 G_debug(2, " line (%d) = %d", j, line);
257 type = Vect_read_line(Map, NULL, Cats, line);
258 if (!(type & GV_POINT))
259 continue;
260 /* get node column costs */
261 if (ncol != NULL && !cfound &&
263 &cat)) { /* point with category of field found */
264 /* Set costs */
265 if (fctype == DB_C_TYPE_INT) {
266 ret = db_CatValArray_get_value_int(&fvarr, cat, &cost);
267 dcost = cost;
268 }
269 else { /* DB_C_TYPE_DOUBLE */
271 }
272 if (ret != DB_OK) {
273 G_warning(
274 _("Database record for node %d (cat = %d) not found "
275 "(cost set to 0)"),
276 i, cat);
277 }
278 cfound = 1;
279 Map->dgraph.node_costs[i] = dcost;
280 }
281
282 /* add virtual nodes and lines, which represents the intersections
283 there are added two nodes for every intersection, which are
284 linked with the nodes (edges in primal graph). the positive node
285 - when we are going from the intersection the negative node -
286 when we are going to the intersection
287
288 TODO There are more possible approaches in virtual nodes
289 management. We can also add and remove them dynamically as they
290 are needed for analysis when Vect_net_ttb_shortest_path is called
291 (problem of flattening graph).
292 Currently this static solution was chosen, because it cost
293 time only when graph is build. However it costs more memory
294 space. For Dijkstra algorithm this expansion should not be
295 serious problem because we can only get into positive node or go
296 from the negative node.
297
298 */
299
300 ret = Vect_cat_get(Cats, tucfield, &cat);
301 if (!tucfound && ret) { /* point with category of field found */
302 /* find lines which belongs to the intersection */
304
305 for (i_line = 0; i_line < nnode_lns; i_line++) {
306
310
311 if (line_id < 0)
312 ln_cat *= -1;
313 f = cat * 2;
314
315 if (ln_cat < 0)
316 t = ln_cat * -2 + 1;
317 else
318 t = ln_cat * 2;
319
320 G_debug(
321 5,
322 "Add arc %d for virtual node from %d to %d cost = %d",
323 i_virt_edge, f, t, 0);
324
325 /* positive, start virtual node */
328 if (ret < 0)
329 G_fatal_error(_("Cannot add network arc for virtual "
330 "node connection."));
331
332 t = cat * 2 + 1;
333 i_virt_edge--;
334
335 if (-ln_cat < 0)
336 f = ln_cat * 2 + 1;
337 else
338 f = ln_cat * -2;
339
340 G_debug(
341 5,
342 "Add arc %d for virtual node from %d to %d cost = %d",
343 i_virt_edge, f, t, 0);
344
345 /* negative, destination virtual node */
348 if (ret < 0)
349 G_fatal_error(_("Cannot add network arc for virtual "
350 "node connection."));
351
352 i_virt_edge--;
353 }
354 tucfound++;
355 }
356 else if (ret)
357 tucfound++;
358 }
359
360 if (tucfound > 1)
361 G_warning(_("There exists more than one point of node <%d> with "
362 "unique category field <%d>.\n"
363 "The unique categories layer is not valid therefore "
364 "you will probably get incorrect results."),
365 tucfield, i);
366
367 if (ncol != NULL && !cfound)
368 G_debug(
369 2,
370 "Category of field %d is not attached to any points in node %d"
371 "(costs set to 0)",
372 nfield, i);
373 }
374
376
377 for (i = 1; i <= nturns; i++) {
378 /* select points at node */
379
380 /* TODO use cursors */
382
385
387 dcost = 0.0;
388 if (ncol != NULL) {
389 /* TODO optimization do not do it for every turn in intersection
390 * again */
392 &node_pt_id) == -1) {
393 G_warning(
394 _("Unable to find point representing intersection <%d> in "
395 "unique categories field <%d>.\n"
396 "Cost for the intersection was set to 0.\n"
397 "The unique categories layer is not valid therefore you "
398 "will probably get incorrect results."),
399 isec, tucfield);
400 }
401 else {
403
404 node_pt_id = Vect_find_node(Map, *Points->x, *Points->y,
405 *Points->z, 0.0, WITHOUT_Z);
406
407 if (node_pt_id == 0) {
408 G_warning(
409 _("Unable to find node for point representing "
410 "intersection <%d> in unique categories field <%d>.\n"
411 "Cost for the intersection was set to 0.\n"
412 "The unique categories layer is not valid therefore "
413 "you will probably get incorrect results."),
414 isec, tucfield);
415 }
416 else {
417 G_debug(2, " node = %d", node_pt_id);
418 dcost = Map->dgraph.node_costs[node_pt_id];
419 }
420 }
421 }
422
423 G_debug(2, "Set node's cost to %f", dcost);
424
425 if (dcost >= 0) {
426 /* Set costs from turntable */
427 if (tctype[3] == DB_C_TYPE_INT) {
428 ret = db_CatValArray_get_value_int(&tvarrs[3], i, &cost);
429 dcost = cost;
430 }
431 else /* DB_C_TYPE_DOUBLE */
433
434 if (ret != DB_OK) {
435 G_warning(
436 _("Database record for turn with cat = %d is not found. "
437 "(The turn was skipped."),
438 i);
439 continue;
440 }
441
442 if (dcost >= 0) {
443
444 if (ncol != NULL)
445 cost = (Map->dgraph.node_costs[node_pt_id] + dcost) *
446 (dglInt32_t)Map->dgraph.cost_multip;
447 else
448 cost = dcost * (dglInt32_t)Map->dgraph.cost_multip;
449
450 /* dglib does not like negative id's of nodes */
451 if (from < 0)
452 f = from * -2 + 1;
453 else
454 f = from * 2;
455
456 if (to < 0)
457 t = to * -2 + 1;
458 else
459 t = to * 2;
460
461 G_debug(5, "Add arc/turn %d for turn from %d to %d cost = %d",
462 turn_cat, f, t, cost);
463
465 (dglInt32_t)cost, (dglInt32_t)(turn_cat));
466
467 if (ret < 0)
469 _("Cannot add network arc representing turn."));
470 }
471 }
472 }
473
475
476 i = 0;
477 while (tcols[i]) {
479 ++i;
480 }
481
482 if (ncol != NULL) {
485 }
486
487 /* Open db connection */
488 if (afcol != NULL) {
489 /* Get field info */
490 if (afield < 1)
491 G_fatal_error(_("Arc field < 1"));
493 if (Fi == NULL)
494 G_fatal_error(_("Database connection not defined for layer %d"),
495 afield);
496
497 /* Open database */
498 driver = db_start_driver_open_database(Fi->driver, Fi->database);
499 if (driver == NULL)
500 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
501 Fi->database, Fi->driver);
502
503 /* Load costs to array */
504 if (db_get_column(driver, Fi->table, afcol, &Column) != DB_OK)
505 G_fatal_error(_("Column <%s> not found in table <%s>"), afcol,
506 Fi->table);
507
510
513 _("Data type of column <%s> not supported (must be numeric)"),
514 afcol);
515
517 nrec = db_select_CatValArray(driver, Fi->table, Fi->key, afcol, NULL,
518 &fvarr);
519 G_debug(1, "forward costs: nrec = %d", nrec);
520
521 if (abcol != NULL) {
522 if (db_get_column(driver, Fi->table, abcol, &Column) != DB_OK)
523 G_fatal_error(_("Column <%s> not found in table <%s>"), abcol,
524 Fi->table);
525
528
530 G_fatal_error(_("Data type of column <%s> not supported (must "
531 "be numeric)"),
532 abcol);
533
535 nrec = db_select_CatValArray(driver, Fi->table, Fi->key, abcol,
536 NULL, &bvarr);
537 G_debug(1, "backward costs: nrec = %d", nrec);
538 }
540 }
541
542 skipped = 0;
543
544 G_message(_("Registering arcs..."));
545
546 for (i = 1; i <= nlines; i++) {
547 G_percent(i, nlines, 1); /* must be before any continue */
548
549 type = Vect_read_line(Map, Points, Cats, i);
550 if (!(type & ltype & (GV_LINE | GV_BOUNDARY)))
551 continue;
552
553 Vect_get_line_nodes(Map, i, &from, &to);
554
555 dcost = bdcost = 0;
556
558 if (!cfound)
559 continue;
560
561 if (cfound > 1)
562 G_warning(_("Line with id <%d> has more unique categories defined "
563 "in field <%d>.\n"
564 "The unique categories layer is not valid therefore "
565 "you will probably get incorrect results."),
566 i, tucfield);
567
568 if (afcol != NULL) {
569 if (!(Vect_cat_get(Cats, afield, &cat))) {
570 G_debug(2,
571 "Category of field %d not attached to the line %d -> "
572 "cost was set to 0",
573 afield, i);
574 skipped += 2; /* Both directions */
575 }
576 else {
577 if (fctype == DB_C_TYPE_INT) {
578 ret = db_CatValArray_get_value_int(&fvarr, cat, &cost);
579 dcost = cost;
580 }
581 else { /* DB_C_TYPE_DOUBLE */
583 }
584 if (ret != DB_OK) {
585 G_warning(_("Database record for line %d (cat = %d, "
586 "forward/both direction(s)) not found "
587 "(cost was set to 0)"),
588 i, cat);
589 }
590
591 if (abcol != NULL) {
592 if (bctype == DB_C_TYPE_INT) {
594 bdcost = bcost;
595 }
596 else { /* DB_C_TYPE_DOUBLE */
598 &bdcost);
599 }
600 if (ret != DB_OK) {
601 G_warning(_("Database record for line %d (cat = %d, "
602 "backward direction) not found"
603 "(cost was set to 0)"),
604 i, cat);
605 }
606 }
607 else
608 bdcost = dcost;
609
610 Vect_cat_get(Cats, tucfield, &cat);
611 }
612 }
613 else {
614 if (ll) {
615 if (geo)
617 else
618 dcost = Vect_line_length(Points);
619 }
620 else
621 dcost = Vect_line_length(Points);
622
623 bdcost = dcost;
624 }
625
626 cost = (dglInt32_t)Map->dgraph.cost_multip * dcost;
627 dgl_cost = cost;
628
629 cat = cat * 2;
630
631 G_debug(5, "Setinng node %d cost: %d", cat, cost);
633
634 Map->dgraph.edge_fcosts[i] = dcost;
635
636 cost = (dglInt32_t)Map->dgraph.cost_multip * bdcost;
637 dgl_cost = cost;
638
639 ++cat;
640
641 G_debug(5, "Setinng node %d cost: %d", cat, cost);
643
644 Map->dgraph.edge_bcosts[i] = bdcost;
645 }
646
647 if (afcol != NULL && skipped > 0)
648 G_debug(2, "%d lines missing category of field %d skipped", skipped,
649 afield);
650
651 if (afcol != NULL) {
654
655 if (abcol != NULL) {
657 }
658 }
660
663
664 G_message(_("Flattening the graph..."));
665 ret = dglFlatten(gr);
666 if (ret < 0)
667 G_fatal_error(_("GngFlatten error"));
668
669 /* init SP cache */
670 /* disable to debug dglib cache */
671 dglInitializeSPCache(gr, &(Map->dgraph.spCache));
672
673 G_message(_("Graph was built"));
674
675 return 0;
676}
677
678/*!
679 \brief Build network graph.
680
681 Internal format for edge costs is integer, costs are multiplied
682 before conversion to int by 1000 and for lengths LL without geo flag by
683 1000000. The same multiplication factor is used for nodes. Costs in database
684 column may be 'integer' or 'double precision' number >= 0 or -1 for infinity
685 i.e. arc or node is closed and cannot be traversed If record in table is not
686 found for arcs, arc is skip. If record in table is not found for node, costs
687 for node are set to 0.
688
689 \param Map vector map
690 \param ltype line type for arcs
691 \param afield arc costs field (if 0, use length)
692 \param nfield node costs field (if 0, do not use node costs)
693 \param afcol column with forward costs for arc
694 \param abcol column with backward costs for arc (if NULL, back costs =
695 forward costs), \param ncol column with costs for nodes (if NULL, do not use
696 node costs), \param geo use geodesic calculation for length (LL), \param
697 version graph version to create (1, 2, 3)
698
699 \return 0 on success, 1 on error
700 */
702 int nfield, const char *afcol, const char *abcol,
703 const char *ncol, int geo, int version)
704{
705 /* TODO long function, split into smaller ones */
706 int i, j, from, to, line, nlines, nnodes, ret, type, cat, skipped, cfound;
707 int dofw, dobw;
708 struct line_pnts *Points;
709 struct line_cats *Cats;
710 double dcost, bdcost, ll;
711 int cost, bcost;
712 dglGraph_s *gr;
714 dglInt32_t opaqueset[16] = {360000, 0, 0, 0, 0, 0, 0, 0,
715 0, 0, 0, 0, 0, 0, 0, 0};
716 struct field_info *Fi = NULL;
718 dbHandle handle;
719 dbString stmt;
722 int fctype = 0, bctype = 0, nrec;
723
724 /* TODO int costs -> double (waiting for dglib) */
725 G_debug(1, "Vect_net_build_graph(): ltype = %d, afield = %d, nfield = %d",
727 G_debug(1, " afcol = %s, abcol = %s, ncol = %s", afcol, abcol, ncol);
728
729 G_message(_("Building graph..."));
730
731 Map->dgraph.line_type = ltype;
732
733 Points = Vect_new_line_struct();
735
736 ll = 0;
737 if (G_projection() == 3)
738 ll = 1; /* LL */
739
740 if (afcol == NULL && ll && !geo)
741 Map->dgraph.cost_multip = 1000000;
742 else
743 Map->dgraph.cost_multip = 1000;
744
745 nlines = Vect_get_num_lines(Map);
747
748 gr = &(Map->dgraph.graph_s);
749
750 /* Allocate space for costs, later replace by functions reading costs from
751 * graph */
752 Map->dgraph.edge_fcosts = (double *)G_malloc((nlines + 1) * sizeof(double));
753 Map->dgraph.edge_bcosts = (double *)G_malloc((nlines + 1) * sizeof(double));
754 Map->dgraph.node_costs = (double *)G_malloc((nnodes + 1) * sizeof(double));
755 /* Set to -1 initially */
756 for (i = 1; i <= nlines; i++) {
757 Map->dgraph.edge_fcosts[i] = -1; /* forward */
758 Map->dgraph.edge_bcosts[i] = -1; /* backward */
759 }
760 for (i = 1; i <= nnodes; i++) {
761 Map->dgraph.node_costs[i] = 0;
762 }
763
765 version = 1;
766
767 if (ncol != NULL)
768 dglInitialize(gr, (dglByte_t)version, sizeof(dglInt32_t), (dglInt32_t)0,
769 opaqueset);
770 else
772 opaqueset);
773
774 if (gr == NULL)
775 G_fatal_error(_("Unable to build network graph"));
776
777 db_init_handle(&handle);
778 db_init_string(&stmt);
779
780 if (abcol != NULL && afcol == NULL)
781 G_fatal_error(_("Forward costs column not specified"));
782
783 /* --- Add arcs --- */
784 /* Open db connection */
785 if (afcol != NULL) {
786 /* Get field info */
787 if (afield < 1)
788 G_fatal_error(_("Arc field < 1"));
790 if (Fi == NULL)
791 G_fatal_error(_("Database connection not defined for layer %d"),
792 afield);
793
794 /* Open database */
795 driver = db_start_driver_open_database(Fi->driver, Fi->database);
796 if (driver == NULL)
797 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
798 Fi->database, Fi->driver);
799
800 /* Load costs to array */
801 if (db_get_column(driver, Fi->table, afcol, &Column) != DB_OK)
802 G_fatal_error(_("Column <%s> not found in table <%s>"), afcol,
803 Fi->table);
804
807
810 _("Data type of column <%s> not supported (must be numeric)"),
811 afcol);
812
814 nrec = db_select_CatValArray(driver, Fi->table, Fi->key, afcol, NULL,
815 &fvarr);
816 G_debug(1, "forward costs: nrec = %d", nrec);
817
818 if (abcol != NULL) {
819 if (db_get_column(driver, Fi->table, abcol, &Column) != DB_OK)
820 G_fatal_error(_("Column <%s> not found in table <%s>"), abcol,
821 Fi->table);
822
825
827 G_fatal_error(_("Data type of column <%s> not supported (must "
828 "be numeric)"),
829 abcol);
830
832 nrec = db_select_CatValArray(driver, Fi->table, Fi->key, abcol,
833 NULL, &bvarr);
834 G_debug(1, "backward costs: nrec = %d", nrec);
835 }
837 }
838
839 skipped = 0;
840
841 G_message(_("Registering arcs..."));
842
843 for (i = 1; i <= nlines; i++) {
844 G_percent(i, nlines, 1); /* must be before any continue */
845 dofw = dobw = 1;
846 type = Vect_read_line(Map, Points, Cats, i);
847 if (!(type & ltype & (GV_LINE | GV_BOUNDARY)))
848 continue;
849
850 Vect_get_line_nodes(Map, i, &from, &to);
851
852 if (afcol != NULL) {
853 if (!(Vect_cat_get(Cats, afield, &cat))) {
854 G_debug(2,
855 "Category of field %d not attached to the line %d -> "
856 "line skipped",
857 afield, i);
858 skipped += 2; /* Both directions */
859 continue;
860 }
861 else {
862 if (fctype == DB_C_TYPE_INT) {
863 ret = db_CatValArray_get_value_int(&fvarr, cat, &cost);
864 dcost = cost;
865 }
866 else { /* DB_C_TYPE_DOUBLE */
868 }
869 if (ret != DB_OK) {
870 G_warning(_("Database record for line %d (cat = %d, "
871 "forward/both direction(s)) not found "
872 "(forward/both direction(s) of line skipped)"),
873 i, cat);
874 dofw = 0;
875 }
876
877 if (abcol != NULL) {
878 if (bctype == DB_C_TYPE_INT) {
880 bdcost = bcost;
881 }
882 else { /* DB_C_TYPE_DOUBLE */
884 &bdcost);
885 }
886 if (ret != DB_OK) {
887 G_warning(_("Database record for line %d (cat = %d, "
888 "backward direction) not found"
889 "(direction of line skipped)"),
890 i, cat);
891 dobw = 0;
892 }
893 }
894 else {
895 if (dofw)
896 bdcost = dcost;
897 else
898 dobw = 0;
899 }
900 }
901 }
902 else {
903 if (ll) {
904 if (geo)
906 else
907 dcost = Vect_line_length(Points);
908 }
909 else
910 dcost = Vect_line_length(Points);
911
912 bdcost = dcost;
913 }
914 if (dofw && dcost != -1) {
915 cost = (dglInt32_t)Map->dgraph.cost_multip * dcost;
916 G_debug(5, "Add arc %d from %d to %d cost = %d", i, from, to, cost);
917 ret = dglAddEdge(gr, (dglInt32_t)from, (dglInt32_t)to,
918 (dglInt32_t)cost, (dglInt32_t)i);
919 Map->dgraph.edge_fcosts[i] = dcost;
920 if (ret < 0)
921 G_fatal_error("Cannot add network arc");
922 }
923
924 G_debug(5, "bdcost = %f edge_bcosts = %f", bdcost,
925 Map->dgraph.edge_bcosts[i]);
926 if (dobw && bdcost != -1) {
927 bcost = (dglInt32_t)Map->dgraph.cost_multip * bdcost;
928 G_debug(5, "Add arc %d from %d to %d bcost = %d", -i, to, from,
929 bcost);
930 ret = dglAddEdge(gr, (dglInt32_t)to, (dglInt32_t)from,
932 Map->dgraph.edge_bcosts[i] = bdcost;
933 if (ret < 0)
934 G_fatal_error(_("Cannot add network arc"));
935 }
936 }
937
938 if (afcol != NULL && skipped > 0)
939 G_debug(2, "%d lines missing category of field %d skipped", skipped,
940 afield);
941
942 if (afcol != NULL) {
945
946 if (abcol != NULL) {
948 }
949 }
950
951 /* Set node attributes */
952 G_debug(2, "Register nodes");
953 if (ncol != NULL) {
954 double x, y, z;
955 struct bound_box box;
956 struct boxlist *List;
957
959
960 G_debug(2, "Set nodes' costs");
961 if (nfield < 1)
962 G_fatal_error("Node field < 1");
963
964 G_message(_("Setting node costs..."));
965
967 if (Fi == NULL)
968 G_fatal_error(_("Database connection not defined for layer %d"),
969 nfield);
970
971 driver = db_start_driver_open_database(Fi->driver, Fi->database);
972 if (driver == NULL)
973 G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
974 Fi->database, Fi->driver);
975
976 /* Load costs to array */
977 if (db_get_column(driver, Fi->table, ncol, &Column) != DB_OK)
978 G_fatal_error(_("Column <%s> not found in table <%s>"), ncol,
979 Fi->table);
980
983
986 _("Data type of column <%s> not supported (must be numeric)"),
987 ncol);
988
990 nrec = db_select_CatValArray(driver, Fi->table, Fi->key, ncol, NULL,
991 &fvarr);
992 G_debug(1, "node costs: nrec = %d", nrec);
994
995 for (i = 1; i <= nnodes; i++) {
996 /* TODO: what happens if we set attributes of not existing node
997 * (skipped lines, nodes without lines) */
998
999 /* select points at node */
1000 Vect_get_node_coor(Map, i, &x, &y, &z);
1001 box.E = box.W = x;
1002 box.N = box.S = y;
1003 box.T = box.B = z;
1005
1006 G_debug(2, " node = %d nlines = %d", i, List->n_values);
1007 cfound = 0;
1008 dcost = 0;
1009
1010 for (j = 0; j < List->n_values; j++) {
1011 line = List->id[j];
1012 G_debug(2, " line (%d) = %d", j, line);
1013 type = Vect_read_line(Map, NULL, Cats, line);
1014 if (!(type & GV_POINT))
1015 continue;
1016 if (Vect_cat_get(
1017 Cats, nfield,
1018 &cat)) { /* point with category of field found */
1019 /* Set costs */
1020 if (fctype == DB_C_TYPE_INT) {
1021 ret = db_CatValArray_get_value_int(&fvarr, cat, &cost);
1022 dcost = cost;
1023 }
1024 else { /* DB_C_TYPE_DOUBLE */
1026 &dcost);
1027 }
1028 if (ret != DB_OK) {
1029 G_warning(_("Database record for node %d (cat = %d) "
1030 "not found "
1031 "(cost set to 0)"),
1032 i, cat);
1033 }
1034 cfound = 1;
1035 break;
1036 }
1037 }
1038 if (!cfound) {
1039 G_debug(
1040 2,
1041 "Category of field %d not attached to any points in node %d"
1042 "(costs set to 0)",
1043 nfield, i);
1044 }
1045 if (dcost == -1) { /* closed */
1046 cost = -1;
1047 }
1048 else {
1049 cost = (dglInt32_t)Map->dgraph.cost_multip * dcost;
1050 }
1051
1052 dgl_cost = cost;
1053 G_debug(3, "Set node's cost to %d", cost);
1054
1056
1057 Map->dgraph.node_costs[i] = dcost;
1058 }
1061
1063 }
1064
1065 G_message(_("Flattening the graph..."));
1066 ret = dglFlatten(gr);
1067 if (ret < 0)
1068 G_fatal_error(_("GngFlatten error"));
1069
1070 /* init SP cache */
1071 /* disable to debug dglib cache */
1072 dglInitializeSPCache(gr, &(Map->dgraph.spCache));
1073
1074 G_message(_("Graph was built"));
1075
1076 return 0;
1077}
#define NULL
Definition ccmath.h:32
Main header of GRASS DataBase Management Interface.
#define DB_C_TYPE_INT
Definition dbmi.h:106
#define DB_C_TYPE_DOUBLE
Definition dbmi.h:107
#define DB_OK
Definition dbmi.h:69
void db_CatValArray_free(dbCatValArray *)
Free allocated dbCatValArray.
Definition value.c:371
int db_CatValArray_get_value_int(dbCatValArray *, int, int *)
Find value (integer) by key.
void db_CatValArray_init(dbCatValArray *)
Initialize dbCatValArray.
Definition value.c:359
int db_get_column(dbDriver *, const char *, const char *, dbColumn **)
Get column structure by table and column name.
int db_sqltype_to_Ctype(int)
Get C data type based on given SQL data type.
Definition sqlCtype.c:22
int db_get_column_sqltype(dbColumn *)
Returns column sqltype for column.
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition db.c:58
int db_select_CatValArray(dbDriver *, const char *, const char *, const char *, const char *, dbCatValArray *)
Select pairs key/value to array, values are sorted by key (must be integer)
void db_free_column(dbColumn *)
Frees column structure.
void db_init_handle(dbHandle *)
Initialize handle (i.e database/schema)
Definition handle.c:20
void db_init_string(dbString *)
Initialize dbString.
Definition string.c:23
dbDriver * db_start_driver_open_database(const char *, const char *)
Open driver/database connection.
Definition db.c:25
int db_CatValArray_get_value_double(dbCatValArray *, int, double *)
Find value (double) by key.
void G_percent(long, long, int)
Print percent complete messages.
Definition percent.c:59
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition defs/gis.h:136
void G_message(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
int G_projection(void)
Query cartographic projection.
Definition proj1.c:30
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition line.c:75
int Vect_get_line_nodes(struct Map_info *, int, int *, int *)
Get line nodes.
Definition level_two.c:302
int Vect_get_node_coor(struct Map_info *, int, double *, double *, double *)
Get node coordinates.
Definition level_two.c:272
plus_t Vect_get_num_lines(struct Map_info *)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition level_two.c:73
double Vect_line_length(const struct line_pnts *)
Calculate line length, 3D-length in case of 3D vector line.
Definition line.c:573
int Vect_cidx_get_field_index(struct Map_info *, int)
Get layer index for given layer number.
double Vect_line_geodesic_length(const struct line_pnts *)
Calculate line length.
Definition line.c:600
int Vect_cidx_find_next(struct Map_info *, int, int, int, int, int *, int *)
Find next line/area id for given category, start_index and type_mask.
struct boxlist * Vect_new_boxlist(int)
Creates and initializes a struct boxlist.
int Vect_cat_get(const struct line_cats *, int, int *)
Get first found category of given field.
void Vect_destroy_boxlist(struct boxlist *)
Frees all memory associated with a struct boxlist, including the struct itself.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
struct field_info * Vect_get_field(struct Map_info *, int)
Get information about link to database (by layer number)
Definition field.c:508
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
void Vect_destroy_field_info(struct field_info *)
Free a struct field_info and all memory associated with it.
Definition field.c:626
int Vect_select_lines_by_box(struct Map_info *, const struct bound_box *, int, struct boxlist *)
Select lines with bounding boxes by box.
Definition sindex.c:30
int Vect_get_node_n_lines(struct Map_info *, int)
Get number of lines for node.
Definition level_two.c:379
plus_t Vect_get_num_nodes(struct Map_info *)
Get number of nodes in vector map.
Definition level_two.c:32
int Vect_find_node(struct Map_info *, double, double, double, double, int)
Find the nearest node.
int Vect_get_node_line(struct Map_info *, int, int)
Get line id for node line index.
Definition level_two.c:395
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition line.c:43
#define GV_LINE
#define GV_POINT
Feature types used in memory on run time (may change)
#define GV_BOUNDARY
#define WITHOUT_Z
2D/3D vector data
#define G_UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition gis.h:43
#define _(str)
Definition glocale.h:10
int Vect_net_build_graph(struct Map_info *Map, int ltype, int afield, int nfield, const char *afcol, const char *abcol, const char *ncol, int geo, int version)
Build network graph.
Definition net_build.c:701
int Vect_net_ttb_build_graph(struct Map_info *Map, int ltype, int afield, int nfield, int tfield, int tucfield, const char *afcol, const char *abcol, const char *ncol, int geo, int algorithm)
Build network graph with turntable.
Definition net_build.c:46
double t
Definition r_raster.c:37
Vector map info.
Bounding box.
Definition dig_structs.h:62
List of bounding boxes with id.
struct bound_box * box
Array of bounding boxes.
Layer (old: field) information.
Feature category info.
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
double * z
Array of Z coordinates.
unsigned char dglByte_t
Definition type.h:23
long dglInt32_t
Definition type.h:24
dglInt32_t * dglGetNode(dglGraph_s *pGraph, dglInt32_t nNodeId)
int dglAddEdge(dglGraph_s *pGraph, dglInt32_t nHead, dglInt32_t nTail, dglInt32_t nCost, dglInt32_t nEdge)
void dglNodeSet_Attr(dglGraph_s *pGraph, dglInt32_t *pnNode, dglInt32_t *pnAttr)
int dglInitialize(dglGraph_s *pGraph, dglByte_t Version, dglInt32_t NodeAttrSize, dglInt32_t EdgeAttrSize, dglInt32_t *pOpaqueSet)
int dglInitializeSPCache(dglGraph_s *pGraph, dglSPCache_s *pCache)
int dglFlatten(dglGraph_s *pGraph)
#define x