123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 |
- /****************************************************************
- *
- * MODULE: v.net.alloc
- *
- * AUTHOR(S): Radim Blazek
- * Stepan Turek <stepan.turek seznam.cz> (turns support)
- * Markus Metz (costs from/to centers; attributes)
- *
- * PURPOSE: Allocate subnets for nearest centers
- *
- * COPYRIGHT: (C) 2001, 2016,2017 by the GRASS Development Team
- *
- * This program is free software under the
- * GNU General Public License (>=v2).
- * Read the file COPYING that comes with GRASS
- * for details.
- *
- ****************************************************************/
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <grass/gis.h>
- #include <grass/vector.h>
- #include <grass/dbmi.h>
- #include <grass/glocale.h>
- #include "alloc.h"
- int main(int argc, char **argv)
- {
- int i, ret, line, center1, center2;
- int nlines, nnodes, type, ltype, afield, nfield, geo, cat;
- int tfield, tucfield;
- int node1, node2;
- double e1cost, e2cost, n1cost, n2cost, s1cost, s2cost, l, l1, l2;
- struct Option *map, *output, *method_opt;
- struct Option *afield_opt, *nfield_opt, *afcol, *abcol, *ncol, *type_opt,
- *term_opt, *tfield_opt, *tucfield_opt;
- struct Flag *geo_f, *turntable_f, *ucat_f;
- struct GModule *module;
- struct Map_info Map, Out;
- struct cat_list *catlist;
- CENTER *Centers = NULL;
- int acenters = 0, ncenters = 0;
- NODE *Nodes;
- struct line_cats *Cats, *ICats, *OCats;
- struct line_pnts *Points, *SPoints;
- int graph_version;
- int from_centers;
- /* Attribute table */
- int unique_cats, ucat, ocat, n;
- char buf[2000];
- dbString sql;
- dbDriver *driver;
- struct field_info *Fi;
- /* initialize GIS environment */
- G_gisinit(argv[0]);
- /* initialize module */
- module = G_define_module();
- G_add_keyword(_("vector"));
- G_add_keyword(_("network"));
- G_add_keyword(_("cost allocation"));
- module->label = _("Allocates subnets for nearest centers.");
- module->description =
- _("Center node must be opened (costs >= 0). "
- "Costs of center node are used in calculation.");
- map = G_define_standard_option(G_OPT_V_INPUT);
- output = G_define_standard_option(G_OPT_V_OUTPUT);
- method_opt = G_define_option();
- method_opt->key = "method";
- method_opt->type = TYPE_STRING;
- method_opt->required = NO;
- method_opt->options = "from,to";
- method_opt->answer = "from";
- method_opt->description = _("Use costs from centers or costs to centers");
- method_opt->guisection = _("Cost");
- term_opt = G_define_standard_option(G_OPT_V_CATS);
- term_opt->key = "center_cats";
- term_opt->required = YES;
- term_opt->description =
- _("Categories of centers (points on nodes) to which net "
- "will be allocated, "
- "layer for this categories is given by nlayer option");
- afield_opt = G_define_standard_option(G_OPT_V_FIELD);
- afield_opt->key = "arc_layer";
- afield_opt->answer = "1";
- afield_opt->required = YES;
- afield_opt->label = _("Arc layer");
- type_opt = G_define_standard_option(G_OPT_V_TYPE);
- type_opt->key = "arc_type";
- type_opt->options = "line,boundary";
- type_opt->answer = "line,boundary";
- type_opt->required = YES;
- type_opt->label = _("Arc type");
- nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
- nfield_opt->key = "node_layer";
- nfield_opt->answer = "2";
- nfield_opt->required = YES;
- nfield_opt->label = _("Node layer");
- afcol = G_define_standard_option(G_OPT_DB_COLUMN);
- afcol->key = "arc_column";
- afcol->description =
- _("Arc forward/both direction(s) cost column (number)");
- afcol->guisection = _("Cost");
- abcol = G_define_standard_option(G_OPT_DB_COLUMN);
- abcol->key = "arc_backward_column";
- abcol->description = _("Arc backward direction cost column (number)");
- abcol->guisection = _("Cost");
- ncol = G_define_standard_option(G_OPT_DB_COLUMN);
- ncol->key = "node_column";
- ncol->description = _("Node cost column (number)");
- ncol->guisection = _("Cost");
- turntable_f = G_define_flag();
- turntable_f->key = 't';
- turntable_f->description = _("Use turntable");
- turntable_f->guisection = _("Turntable");
- tfield_opt = G_define_standard_option(G_OPT_V_FIELD);
- tfield_opt->key = "turn_layer";
- tfield_opt->answer = "3";
- tfield_opt->label = _("Layer with turntable");
- tfield_opt->description =
- _("Relevant only with -t flag");
- tfield_opt->guisection = _("Turntable");
- tucfield_opt = G_define_standard_option(G_OPT_V_FIELD);
- tucfield_opt->key = "turn_cat_layer";
- tucfield_opt->answer = "4";
- tucfield_opt->label = _("Layer with unique categories used in turntable");
- tucfield_opt->description =
- _("Relevant only with -t flag");
- tucfield_opt->guisection = _("Turntable");
- geo_f = G_define_flag();
- geo_f->key = 'g';
- geo_f->description =
- _("Use geodesic calculation for longitude-latitude locations");
- ucat_f = G_define_flag();
- ucat_f->key = 'u';
- ucat_f->label =
- _("Create unique categories and attribute table");
- ucat_f->description =
- _("Default: same category like nearest center");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT);
- Cats = Vect_new_cats_struct();
- ICats = Vect_new_cats_struct();
- OCats = Vect_new_cats_struct();
- Points = Vect_new_line_struct();
- SPoints = Vect_new_line_struct();
- type = Vect_option_to_types(type_opt);
- catlist = Vect_new_cat_list();
- Vect_str_to_cat_list(term_opt->answer, catlist);
- unique_cats = ucat_f->answer;
- if (geo_f->answer)
- geo = 1;
- else
- geo = 0;
- Vect_set_open_level(2);
- if (Vect_open_old(&Map, map->answer, "") < 0)
- G_fatal_error(_("Unable to open vector map <%s>"), map->answer);
- afield = Vect_get_field_number(&Map, afield_opt->answer);
- nfield = Vect_get_field_number(&Map, nfield_opt->answer);
- tfield = Vect_get_field_number(&Map, tfield_opt->answer);
- tucfield = Vect_get_field_number(&Map, tucfield_opt->answer);
- /* Build graph */
- graph_version = 1;
- from_centers = 1;
- if (method_opt->answer[0] == 't') {
- from_centers = 0;
- if (!turntable_f->answer)
- graph_version = 2;
- }
- if (turntable_f->answer)
- Vect_net_ttb_build_graph(&Map, type, afield, nfield, tfield, tucfield,
- afcol->answer, abcol->answer, ncol->answer,
- geo, 0);
- else
- Vect_net_build_graph(&Map, type, afield, nfield, afcol->answer,
- abcol->answer, ncol->answer, geo, graph_version);
- nnodes = Vect_get_num_nodes(&Map);
- nlines = Vect_get_num_lines(&Map);
- /* Create list of centers based on list of categories */
- for (i = 1; i <= nlines; i++) {
- int node;
- ltype = Vect_get_line_type(&Map, i);
- if (!(ltype & GV_POINT))
- continue;
- Vect_read_line(&Map, Points, Cats, i);
- node =
- Vect_find_node(&Map, Points->x[0], Points->y[0], Points->z[0], 0,
- 0);
- if (!node) {
- G_warning(_("Point is not connected to the network"));
- continue;
- }
- if (!(Vect_cat_get(Cats, nfield, &cat)))
- continue;
- if (Vect_cat_in_cat_list(cat, catlist)) {
- Vect_net_get_node_cost(&Map, node, &n1cost);
- if (n1cost == -1) { /* closed */
- G_warning(_("Center at closed node (costs = -1) ignored"));
- }
- else {
- if (acenters == ncenters) {
- acenters += 1;
- Centers =
- (CENTER *) G_realloc(Centers,
- acenters * sizeof(CENTER));
- }
- Centers[ncenters].cat = cat;
- Centers[ncenters].node = node;
- G_debug(2, "center = %d node = %d cat = %d", ncenters,
- node, cat);
- ncenters++;
- }
- }
- }
- G_message(_("Number of centers: %d (nlayer %d)"), ncenters, nfield);
- if (ncenters == 0)
- G_warning(_("Not enough centers for selected nlayer. Nothing will be allocated."));
- /* alloc and reset space for all nodes */
- if (turntable_f->answer) {
- /* if turntable is used we are looking for lines as destinations, instead of the intersections (nodes) */
- Nodes = (NODE *) G_calloc((nlines * 2 + 2), sizeof(NODE));
- for (i = 2; i <= (nlines * 2 + 2); i++) {
- Nodes[i].center = -1;/* NOTE: first two items of Nodes are not used */
- }
- }
- else {
- Nodes = (NODE *) G_calloc((nnodes + 1), sizeof(NODE));
- for (i = 1; i <= nnodes; i++) {
- Nodes[i].center = -1;
- }
- }
- /* Fill Nodes by nearest center and costs from that center */
- if (turntable_f->answer) {
- if (from_centers) {
- G_message(_("Calculating costs from centers ..."));
- alloc_from_centers_loop_tt(&Map, Nodes, Centers, ncenters,
- tucfield);
- }
- else {
- G_message(_("Calculating costs to centers ..."));
- alloc_to_centers_loop_tt(&Map, Nodes, Centers, ncenters,
- tucfield);
- }
- }
- else {
- if (from_centers) {
- G_message(_("Calculating costs from centers ..."));
- alloc_from_centers(Vect_net_get_graph(&Map), Nodes, Centers, ncenters);
- }
- else {
- G_message(_("Calculating costs to centers ..."));
- alloc_to_centers(Vect_net_get_graph(&Map), Nodes, Centers, ncenters);
- }
- }
- /* Write arcs to new map */
- if (Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)) < 0)
- G_fatal_error(_("Unable to create vector map <%s>"), output->answer);
- Vect_hist_command(&Out);
- Fi = NULL;
- driver = NULL;
- if (unique_cats) {
- /* create attribute table:
- * cat: new category
- * ocat: original category in afield
- * center: nearest center
- */
- Fi = Vect_default_field_info(&Out, 1, NULL, GV_MTABLE);
- Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
- Fi->driver);
- driver = db_start_driver_open_database(Fi->driver, Fi->database);
- if (driver == NULL)
- G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
- Fi->database, Fi->driver);
- db_set_error_handler_driver(driver);
- sprintf(buf,
- "create table %s ( %s integer, ocat integer, center integer )",
- Fi->table, GV_KEY_COLUMN);
- db_init_string(&sql);
- db_set_string(&sql, buf);
- G_debug(2, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql));
- }
- if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
- G_warning(_("Cannot create index"));
- if (db_grant_on_table
- (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK)
- G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table);
- db_begin_transaction(driver);
- }
- G_message(_("Allocating subnets..."));
- nlines = Vect_get_num_lines(&Map);
- ucat = 1;
- for (line = 1; line <= nlines; line++) {
- G_percent(line, nlines, 2);
- ltype = Vect_read_line(&Map, Points, ICats, line);
- if (!(ltype & type)) {
- continue;
- }
- if (unique_cats) {
- Vect_reset_cats(OCats);
- for (n = 0; n < ICats->n_cats; n++) {
- if (ICats->field[n] == afield) {
- Vect_cat_set(OCats, 2, ICats->cat[n]);
- }
- }
- }
- if (turntable_f->answer) {
- center1 = Nodes[line * 2].center;
- center2 = Nodes[line * 2 + 1].center;
- s1cost = Nodes[line * 2].cost;
- s2cost = Nodes[line * 2 + 1].cost;
- n1cost = n2cost = 0;
- }
- else {
- Vect_get_line_nodes(&Map, line, &node1, &node2);
- center1 = Nodes[node1].center;
- center2 = Nodes[node2].center;
- s1cost = Nodes[node1].cost;
- s2cost = Nodes[node2].cost;
- if (s1cost > 0)
- s1cost /= Map.dgraph.cost_multip;
- if (s2cost > 0)
- s2cost /= Map.dgraph.cost_multip;
- Vect_net_get_node_cost(&Map, node1, &n1cost);
- Vect_net_get_node_cost(&Map, node2, &n2cost);
- }
- if (from_centers) {
- Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e1cost);
- Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e2cost);
- }
- else {
- /* from node to center */
- Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e2cost);
- Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e1cost);
- }
- G_debug(3, "Line %d:", line);
- G_debug(3, "Arc centers: %d %d (nodes: %d %d)", center1, center2,
- node1, node2);
- G_debug(3, " s1cost = %f n1cost = %f e1cost = %f", s1cost, n1cost,
- e1cost);
- G_debug(3, " s2cost = %f n2cost = %f e2cost = %f", s2cost, n2cost,
- e2cost);
- Vect_reset_cats(Cats);
- /* First check if arc is reachable from at least one side */
- if ((center1 != -1 && n1cost != -1 && e1cost != -1) ||
- (center2 != -1 && n2cost != -1 && e2cost != -1)) {
- /* Line is reachable at least from one side */
- G_debug(3, " -> arc is reachable");
- if (center1 == center2) { /* both nodes in one area -> whole arc in one area */
- if (center1 != -1)
- cat = Centers[center1].cat; /* line reachable */
- else
- cat = Centers[center2].cat;
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, cat);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- else
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, ltype, Points, Cats);
- }
- else { /* each node in different area */
- /* Check if line is reachable from center */
- if (center1 == -1 || n1cost == -1 || e1cost == -1) { /* closed from first node */
- G_debug(3,
- " -> arc is not reachable from 1. node -> alloc to 2. node");
- cat = Centers[center2].cat;
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, cat);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- else
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, ltype, Points, Cats);
- continue;
- }
- else if (center2 == -1 || n2cost == -1 || e2cost == -1) { /* closed from second node */
- G_debug(3,
- " -> arc is not reachable from 2. node -> alloc to 1. node");
- cat = Centers[center1].cat;
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, cat);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- else
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, ltype, Points, Cats);
- continue;
- }
- /* Now we know that arc is reachable from both sides */
- /* Add costs of node to starting costs */
- s1cost += n1cost;
- s2cost += n2cost;
- /* Check if s1cost + e1cost <= s2cost or s2cost + e2cost <= s1cost !
- * Note this check also possibility of (e1cost + e2cost) = 0 */
- if (s1cost + e1cost <= s2cost) { /* whole arc reachable from node1 */
- cat = Centers[center1].cat;
- Vect_reset_cats(Cats);
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, cat);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- else
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, ltype, Points, Cats);
- }
- else if (s2cost + e2cost <= s1cost) { /* whole arc reachable from node2 */
- cat = Centers[center2].cat;
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, cat);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- else
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, ltype, Points, Cats);
- }
- else { /* split */
- /* Calculate relative costs - we expect that costs along the line do not change */
- l = Vect_line_length(Points);
- e1cost /= l;
- e2cost /= l;
- G_debug(3, " -> s1cost = %f e1cost = %f", s1cost,
- e1cost);
- G_debug(3, " -> s2cost = %f e2cost = %f", s2cost,
- e2cost);
- /* Costs from both centers to the splitting point must be equal:
- * s1cost + l1 * e1cost = s2cost + l2 * e2cost */
- l1 = (l * e2cost - s1cost + s2cost) / (e1cost + e2cost);
- l2 = l - l1;
- G_debug(3, "l = %f l1 = %f l2 = %f", l, l1, l2);
- /* First segment */
- ret = Vect_line_segment(Points, 0, l1, SPoints);
- if (ret == 0) {
- G_warning(_
- ("Cannot get line segment, segment out of line"));
- }
- else {
- cat = Centers[center1].cat;
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, cat);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- else
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, ltype, SPoints, Cats);
- }
- /* Second segment */
- ret = Vect_line_segment(Points, l1, l, SPoints);
- if (ret == 0) {
- G_warning(_
- ("Cannot get line segment, segment out of line"));
- }
- else {
- Vect_reset_cats(Cats);
- cat = Centers[center2].cat;
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, cat);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- else
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, ltype, SPoints, Cats);
- }
- }
- }
- }
- else {
- /* arc is not reachable */
- G_debug(3, " -> arc is not reachable");
- if (unique_cats) {
- Vect_cat_set(Cats, 1, ucat);
- for (n = 0; n < OCats->n_cats; n++) {
- Vect_cat_set(Cats, 2, OCats->cat[n]);
- }
- ocat = -1;
- Vect_cat_get(ICats, afield, &ocat);
- sprintf(buf,
- "insert into %s values ( %d, %d, %d )",
- Fi->table, ucat, ocat, -1);
- db_set_string(&sql, buf);
- G_debug(3, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Cannot insert new record: %s"),
- db_get_string(&sql));
- }
- ucat++;
- }
- Vect_write_line(&Out, ltype, Points, Cats);
- }
- }
- if (unique_cats) {
- db_commit_transaction(driver);
- db_close_database_shutdown_driver(driver);
- Vect_copy_table(&Map, &Out, afield, 2, NULL, GV_MTABLE);
- }
- Vect_build(&Out);
- /* Free, ... */
- G_free(Nodes);
- G_free(Centers);
- Vect_close(&Map);
- Vect_close(&Out);
- exit(EXIT_SUCCESS);
- }
|