/*! \brief Draw line nodes */ void draw_line_nodes(struct Map_info *Map, int line, int draw_flag, struct robject_list *list) { unsigned int i; int type, nodes[2]; int x, y; double east, north; struct robject *robj; Vect_get_line_nodes(Map, line, &(nodes[0]), &(nodes[1])); for (i = 0; i < sizeof(nodes) / sizeof(int); i++) { type = 0; if (Vect_get_node_n_lines(Map, nodes[i]) == 1) { if (draw_flag & DRAW_NODEONE) { type = TYPE_NODEONE; } } else { if (draw_flag & DRAW_NODETWO) { type = TYPE_NODETWO; } } if (type == 0) continue; Vect_get_node_coor(Map, nodes[i], &east, &north, NULL); robj = robj_alloc(type, 1); en_to_xy(east, north, &x, &y); robj->fid = line; robj->point->x = x; robj->point->y = y; list_append(list, robj); } }
/* find next line for given line and node * return: next line (may be input line if it is loop) * 0 - num of lines <> 2 */ int find_next_line(struct Map_info *map, int line, int node, int ltype) { int n_lines, i, tmp_line, tmp_type, next_line; G_debug(2, " find_next_line() line = %d node = %d", line, node); next_line = 0; n_lines = 0; for (i = 0; i < Vect_get_node_n_lines(map, node); i++) { tmp_line = abs(Vect_get_node_line(map, node, i)); tmp_type = Vect_read_line(map, NULL, NULL, tmp_line); /* The line may be a loop so we want some other line if exists or the same line if loop */ if (tmp_type & ltype) { if (next_line == 0 || tmp_line != line) next_line = tmp_line; n_lines++; } } if (n_lines != 2) next_line = 0; G_debug(2, " -> next line = %d", next_line); return next_line; }
/* merge a given line with all other lines of the same type and * with the same categories */ static int merge_line(struct Map_info *Map, int line, struct line_pnts *MPoints, struct line_cats *MCats) { int nlines, i, first, last, next_line, curr_line; int merged = 0, newl = 0; int next_node, direction, node_n_lines, type, ltype, lines_type; static struct ilist *List = NULL; static struct line_pnts *Points = NULL; static struct line_cats *Cats = NULL; type = GV_LINE; nlines = Vect_get_num_lines(Map); if (!Points) Points = Vect_new_line_struct(); if (!Cats) Cats = Vect_new_cats_struct(); if (!List) List = Vect_new_list(); Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_reset_cats(MCats); Vect_reset_list(List); if (!Vect_line_alive(Map, line)) return 0; ltype = Vect_get_line_type(Map, line); if (!(ltype & type)) return 0; Vect_read_line(Map, MPoints, MCats, line); /* special cases: * - loop back to start boundary via several other boundaries * - one boundary forming closed loop * - node with 3 entries but only 2 boundaries, one of them connecting twice, * the other one must then be topologically incorrect in case of boundary */ /* go backward as long as there is only one other line/boundary at the current node */ G_debug(3, "go backward"); Vect_get_line_nodes(Map, line, &next_node, NULL); first = -line; while (1) { node_n_lines = Vect_get_node_n_lines(Map, next_node); /* count lines/boundaries at this node */ lines_type = 0; next_line = first; for (i = 0; i < node_n_lines; i++) { curr_line = Vect_get_node_line(Map, next_node, i); if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES)) lines_type++; if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) { if (abs(curr_line) != abs(first)) { Vect_read_line(Map, NULL, Cats, abs(curr_line)); /* catgories must be identical */ if (compare_cats(MCats, Cats) == 0) next_line = curr_line; } } } if (lines_type == 2 && abs(next_line) != abs(first) && abs(next_line) != line) { first = next_line; if (first < 0) { Vect_get_line_nodes(Map, -first, &next_node, NULL); } else { Vect_get_line_nodes(Map, first, NULL, &next_node); } } else break; } /* go forward as long as there is only one other line/boundary at the current node */ G_debug(3, "go forward"); /* reverse direction */ last = -first; if (last < 0) { Vect_get_line_nodes(Map, -last, &next_node, NULL); } else { Vect_get_line_nodes(Map, last, NULL, &next_node); } Vect_reset_list(List); while (1) { G_ilist_add(List, last); node_n_lines = Vect_get_node_n_lines(Map, next_node); lines_type = 0; next_line = last; for (i = 0; i < node_n_lines; i++) { curr_line = Vect_get_node_line(Map, next_node, i); if ((Vect_get_line_type(Map, abs(curr_line)) & GV_LINES)) lines_type++; if ((Vect_get_line_type(Map, abs(curr_line)) == ltype)) { if (abs(curr_line) != abs(last)) { Vect_read_line(Map, NULL, Cats, abs(curr_line)); if (compare_cats(MCats, Cats) == 0) next_line = curr_line; } } } if (lines_type == 2 && abs(next_line) != abs(last) && abs(next_line) != abs(first)) { last = next_line; if (last < 0) { Vect_get_line_nodes(Map, -last, &next_node, NULL); } else { Vect_get_line_nodes(Map, last, NULL, &next_node); } } else break; } /* merge lines */ G_debug(3, "merge %d lines", List->n_values); Vect_reset_line(MPoints); for (i = 0; i < List->n_values; i++) { Vect_reset_line(Points); Vect_read_line(Map, Points, Cats, abs(List->value[i])); direction = (List->value[i] < 0 ? GV_BACKWARD : GV_FORWARD); Vect_append_points(MPoints, Points, direction); MPoints->n_points--; Vect_delete_line(Map, abs(List->value[i])); } MPoints->n_points++; merged += List->n_values; newl++; return merged; }
bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature ) { if ( mClosed ) return false; feature.setValid( false ); int cat = -1, type = -1, id = -1; QgsFeatureId featureId = -1; QgsDebugMsgLevel( "entered.", 3 ); /* TODO: handle editing if ( P->isEdited() || P->isFrozen() || !P->mValid ) { close(); return false; } */ // TODO: is this necessary? the same is checked below if ( !QgsGrassProvider::isTopoType( mSource->mLayerType ) && ( mSource->mCidxFieldIndex < 0 || mNextCidx >= mSource->mCidxFieldNumCats ) ) { close(); return false; // No features, no features in this layer } bool filterById = mRequest.filterType() == QgsFeatureRequest::FilterFid; // Get next line/area id int found = 0; while ( true ) { QgsDebugMsgLevel( QString( "mNextTopoId = %1" ).arg( mNextTopoId ), 3 ); if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { if ( mNextTopoId > Vect_get_num_lines( mSource->mMap ) ) break; id = mNextTopoId; type = Vect_read_line( mSource->mMap, 0, 0, mNextTopoId++ ); if ( !( type & mSource->mGrassType ) ) continue; featureId = id; } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { if ( mNextTopoId > Vect_get_num_nodes( mSource->mMap ) ) break; id = mNextTopoId; type = 0; mNextTopoId++; featureId = id; } else { if ( mNextCidx >= mSource->mCidxFieldNumCats ) break; Vect_cidx_get_cat_by_index( mSource->mMap, mSource->mCidxFieldIndex, mNextCidx++, &cat, &type, &id ); // Warning: selection array is only of type line/area of current layer -> check type first if ( !( type & mSource->mGrassType ) ) continue; // The 'id' is a unique id of a GRASS geometry object (point, line, area) // but it cannot be used as QgsFeatureId because one geometry object may // represent more features because it may have more categories. featureId = makeFeatureId( id, cat ); } if ( filterById && featureId != mRequest.filterFid() ) continue; // it is correct to use id with mSelection because mSelection is only used // for geometry selection if ( !mSelection[id] ) continue; found = 1; break; } if ( !found ) { close(); return false; // No more features } QgsDebugMsgLevel( QString( "cat = %1 type = %2 id = %3 fatureId = %4" ).arg( cat ).arg( type ).arg( id ).arg( featureId ), 3 ); feature.setFeatureId( featureId ); feature.initAttributes( mSource->mFields.count() ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups if ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) feature.setGeometry( 0 ); else setFeatureGeometry( feature, id, type ); if ( ! QgsGrassProvider::isTopoType( mSource->mLayerType ) ) { if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) setFeatureAttributes( cat, &feature, mRequest.subsetOfAttributes() ); else setFeatureAttributes( cat, &feature ); } else { feature.setAttribute( 0, id ); #if GRASS_VERSION_MAJOR < 7 if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) #else /* No more topo points in GRASS 7 */ if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) #endif { feature.setAttribute( 1, QgsGrassProvider::primitiveTypeName( type ) ); int node1, node2; Vect_get_line_nodes( mSource->mMap, id, &node1, &node2 ); feature.setAttribute( 2, node1 ); if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { feature.setAttribute( 3, node2 ); } } if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE ) { if ( type == GV_BOUNDARY ) { int left, right; Vect_get_line_areas( mSource->mMap, id, &left, &right ); feature.setAttribute( 4, left ); feature.setAttribute( 5, right ); } } else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { QString lines; int nlines = Vect_get_node_n_lines( mSource->mMap, id ); for ( int i = 0; i < nlines; i++ ) { int line = Vect_get_node_line( mSource->mMap, id, i ); if ( i > 0 ) lines += ","; lines += QString::number( line ); } feature.setAttribute( 1, lines ); } } feature.setValid( true ); return true; }
int main(int argc, char *argv[]) { struct Map_info In, Out, Error; struct line_pnts *Points; struct line_cats *Cats; int i, type, iter; struct GModule *module; /* GRASS module for parsing arguments */ struct Option *map_in, *map_out, *error_out, *thresh_opt, *method_opt, *look_ahead_opt; struct Option *iterations_opt, *cat_opt, *alpha_opt, *beta_opt, *type_opt; struct Option *field_opt, *where_opt, *reduction_opt, *slide_opt; struct Option *angle_thresh_opt, *degree_thresh_opt, *closeness_thresh_opt; struct Option *betweeness_thresh_opt; struct Flag *notab_flag, *loop_support_flag; int with_z; int total_input, total_output; /* Number of points in the input/output map respectively */ double thresh, alpha, beta, reduction, slide, angle_thresh; double degree_thresh, closeness_thresh, betweeness_thresh; int method; int look_ahead, iterations; int loop_support; int layer; int n_lines; int simplification, mask_type; struct cat_list *cat_list = NULL; char *s, *descriptions; /* initialize GIS environment */ G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */ /* initialize module */ module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("generalization")); G_add_keyword(_("simplification")); G_add_keyword(_("smoothing")); G_add_keyword(_("displacement")); G_add_keyword(_("network generalization")); module->description = _("Performs vector based generalization."); /* Define the different options as defined in gis.h */ map_in = G_define_standard_option(G_OPT_V_INPUT); field_opt = G_define_standard_option(G_OPT_V_FIELD_ALL); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->options = "line,boundary,area"; type_opt->answer = "line,boundary,area"; type_opt->guisection = _("Selection"); map_out = G_define_standard_option(G_OPT_V_OUTPUT); error_out = G_define_standard_option(G_OPT_V_OUTPUT); error_out->key = "error"; error_out->required = NO; error_out->description = _("Error map of all lines and boundaries not being generalized due to topology issues or over-simplification"); method_opt = G_define_option(); method_opt->key = "method"; method_opt->type = TYPE_STRING; method_opt->required = YES; method_opt->multiple = NO; method_opt->options = "douglas,douglas_reduction,lang,reduction,reumann,boyle,sliding_averaging,distance_weighting,chaiken,hermite,snakes,network,displacement"; descriptions = NULL; G_asprintf(&descriptions, "douglas;%s;" "douglas_reduction;%s;" "lang;%s;" "reduction;%s;" "reumann;%s;" "boyle;%s;" "sliding_averaging;%s;" "distance_weighting;%s;" "chaiken;%s;" "hermite;%s;" "snakes;%s;" "network;%s;" "displacement;%s;", _("Douglas-Peucker Algorithm"), _("Douglas-Peucker Algorithm with reduction parameter"), _("Lang Simplification Algorithm"), _("Vertex Reduction Algorithm eliminates points close to each other"), _("Reumann-Witkam Algorithm"), _("Boyle's Forward-Looking Algorithm"), _("McMaster's Sliding Averaging Algorithm"), _("McMaster's Distance-Weighting Algorithm"), _("Chaiken's Algorithm"), _("Interpolation by Cubic Hermite Splines"), _("Snakes method for line smoothing"), _("Network generalization"), _("Displacement of lines close to each other")); method_opt->descriptions = G_store(descriptions); method_opt->description = _("Generalization algorithm"); thresh_opt = G_define_option(); thresh_opt->key = "threshold"; thresh_opt->type = TYPE_DOUBLE; thresh_opt->required = YES; thresh_opt->options = "0-1000000000"; thresh_opt->description = _("Maximal tolerance value"); look_ahead_opt = G_define_option(); look_ahead_opt->key = "look_ahead"; look_ahead_opt->type = TYPE_INTEGER; look_ahead_opt->required = NO; look_ahead_opt->answer = "7"; look_ahead_opt->description = _("Look-ahead parameter"); reduction_opt = G_define_option(); reduction_opt->key = "reduction"; reduction_opt->type = TYPE_DOUBLE; reduction_opt->required = NO; reduction_opt->answer = "50"; reduction_opt->options = "0-100"; reduction_opt->description = _("Percentage of the points in the output of 'douglas_reduction' algorithm"); slide_opt = G_define_option(); slide_opt->key = "slide"; slide_opt->type = TYPE_DOUBLE; slide_opt->required = NO; slide_opt->answer = "0.5"; slide_opt->options = "0-1"; slide_opt->description = _("Slide of computed point toward the original point"); angle_thresh_opt = G_define_option(); angle_thresh_opt->key = "angle_thresh"; angle_thresh_opt->type = TYPE_DOUBLE; angle_thresh_opt->required = NO; angle_thresh_opt->answer = "3"; angle_thresh_opt->options = "0-180"; angle_thresh_opt->description = _("Minimum angle between two consecutive segments in Hermite method"); degree_thresh_opt = G_define_option(); degree_thresh_opt->key = "degree_thresh"; degree_thresh_opt->type = TYPE_INTEGER; degree_thresh_opt->required = NO; degree_thresh_opt->answer = "0"; degree_thresh_opt->description = _("Degree threshold in network generalization"); closeness_thresh_opt = G_define_option(); closeness_thresh_opt->key = "closeness_thresh"; closeness_thresh_opt->type = TYPE_DOUBLE; closeness_thresh_opt->required = NO; closeness_thresh_opt->answer = "0"; closeness_thresh_opt->options = "0-1"; closeness_thresh_opt->description = _("Closeness threshold in network generalization"); betweeness_thresh_opt = G_define_option(); betweeness_thresh_opt->key = "betweeness_thresh"; betweeness_thresh_opt->type = TYPE_DOUBLE; betweeness_thresh_opt->required = NO; betweeness_thresh_opt->answer = "0"; betweeness_thresh_opt->description = _("Betweeness threshold in network generalization"); alpha_opt = G_define_option(); alpha_opt->key = "alpha"; alpha_opt->type = TYPE_DOUBLE; alpha_opt->required = NO; alpha_opt->answer = "1.0"; alpha_opt->description = _("Snakes alpha parameter"); beta_opt = G_define_option(); beta_opt->key = "beta"; beta_opt->type = TYPE_DOUBLE; beta_opt->required = NO; beta_opt->answer = "1.0"; beta_opt->description = _("Snakes beta parameter"); iterations_opt = G_define_option(); iterations_opt->key = "iterations"; iterations_opt->type = TYPE_INTEGER; iterations_opt->required = NO; iterations_opt->answer = "1"; iterations_opt->description = _("Number of iterations"); cat_opt = G_define_standard_option(G_OPT_V_CATS); cat_opt->guisection = _("Selection"); where_opt = G_define_standard_option(G_OPT_DB_WHERE); where_opt->guisection = _("Selection"); loop_support_flag = G_define_flag(); loop_support_flag->key = 'l'; loop_support_flag->label = _("Disable loop support"); loop_support_flag->description = _("Do not modify end points of lines forming a closed loop"); notab_flag = G_define_standard_flag(G_FLG_V_TABLE); notab_flag->description = _("Do not copy attributes"); notab_flag->guisection = _("Attributes"); /* options and flags parser */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); thresh = atof(thresh_opt->answer); look_ahead = atoi(look_ahead_opt->answer); alpha = atof(alpha_opt->answer); beta = atof(beta_opt->answer); reduction = atof(reduction_opt->answer); iterations = atoi(iterations_opt->answer); slide = atof(slide_opt->answer); angle_thresh = atof(angle_thresh_opt->answer); degree_thresh = atof(degree_thresh_opt->answer); closeness_thresh = atof(closeness_thresh_opt->answer); betweeness_thresh = atof(betweeness_thresh_opt->answer); mask_type = type_mask(type_opt); G_debug(3, "Method: %s", method_opt->answer); s = method_opt->answer; if (strcmp(s, "douglas") == 0) method = DOUGLAS; else if (strcmp(s, "lang") == 0) method = LANG; else if (strcmp(s, "reduction") == 0) method = VERTEX_REDUCTION; else if (strcmp(s, "reumann") == 0) method = REUMANN; else if (strcmp(s, "boyle") == 0) method = BOYLE; else if (strcmp(s, "distance_weighting") == 0) method = DISTANCE_WEIGHTING; else if (strcmp(s, "chaiken") == 0) method = CHAIKEN; else if (strcmp(s, "hermite") == 0) method = HERMITE; else if (strcmp(s, "snakes") == 0) method = SNAKES; else if (strcmp(s, "douglas_reduction") == 0) method = DOUGLAS_REDUCTION; else if (strcmp(s, "sliding_averaging") == 0) method = SLIDING_AVERAGING; else if (strcmp(s, "network") == 0) method = NETWORK; else if (strcmp(s, "displacement") == 0) { method = DISPLACEMENT; /* we can displace only the lines */ mask_type = GV_LINE; } else { G_fatal_error(_("Unknown method")); exit(EXIT_FAILURE); } /* simplification or smoothing? */ switch (method) { case DOUGLAS: case DOUGLAS_REDUCTION: case LANG: case VERTEX_REDUCTION: case REUMANN: simplification = 1; break; default: simplification = 0; break; } Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Vect_check_input_output_name(map_in->answer, map_out->answer, G_FATAL_EXIT); Vect_set_open_level(2); if (Vect_open_old2(&In, map_in->answer, "", field_opt->answer) < 1) G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer); if (Vect_get_num_primitives(&In, mask_type) == 0) { G_warning(_("No lines found in input map <%s>"), map_in->answer); Vect_close(&In); exit(EXIT_SUCCESS); } with_z = Vect_is_3d(&In); if (0 > Vect_open_new(&Out, map_out->answer, with_z)) { Vect_close(&In); G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer); } if (error_out->answer) { if (0 > Vect_open_new(&Error, error_out->answer, with_z)) { Vect_close(&In); G_fatal_error(_("Unable to create error vector map <%s>"), error_out->answer); } } Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); total_input = total_output = 0; layer = Vect_get_field_number(&In, field_opt->answer); /* parse filter options */ if (layer > 0) cat_list = Vect_cats_set_constraint(&In, layer, where_opt->answer, cat_opt->answer); if (method == DISPLACEMENT) { /* modifies only lines, all other features including boundaries are preserved */ /* options where, cats, and layer are respected */ G_message(_("Displacement...")); snakes_displacement(&In, &Out, thresh, alpha, beta, 1.0, 10.0, iterations, cat_list, layer); } /* TODO: rearrange code below. It's really messy */ if (method == NETWORK) { /* extracts lines of selected type, all other features are discarded */ /* options where, cats, and layer are ignored */ G_message(_("Network generalization...")); total_output = graph_generalization(&In, &Out, mask_type, degree_thresh, closeness_thresh, betweeness_thresh); } /* copy tables here because method == NETWORK is complete and * tables for Out may be needed for parse_filter_options() below */ if (!notab_flag->answer) { if (method == NETWORK) copy_tables_by_cats(&In, &Out); else Vect_copy_tables(&In, &Out, -1); } else if (where_opt->answer && method < NETWORK) { G_warning(_("Attributes are needed for 'where' option, copying table")); Vect_copy_tables(&In, &Out, -1); } /* smoothing/simplification */ if (method < NETWORK) { /* modifies only lines of selected type, all other features are preserved */ int not_modified_boundaries = 0, n_oversimplified = 0; struct line_pnts *APoints; /* original Points */ set_topo_debug(); Vect_copy_map_lines(&In, &Out); Vect_build_partial(&Out, GV_BUILD_CENTROIDS); G_message("-----------------------------------------------------"); G_message(_("Generalization (%s)..."), method_opt->answer); G_message(_("Using threshold: %g %s"), thresh, G_database_unit_name(1)); G_percent_reset(); APoints = Vect_new_line_struct(); n_lines = Vect_get_num_lines(&Out); for (i = 1; i <= n_lines; i++) { int after = 0; G_percent(i, n_lines, 1); type = Vect_read_line(&Out, APoints, Cats, i); if (!(type & GV_LINES) || !(mask_type & type)) continue; if (layer > 0) { if ((type & GV_LINE) && !Vect_cats_in_constraint(Cats, layer, cat_list)) continue; else if ((type & GV_BOUNDARY)) { int do_line = 0; int left, right; do_line = Vect_cats_in_constraint(Cats, layer, cat_list); if (!do_line) { /* check if any of the centroids is selected */ Vect_get_line_areas(&Out, i, &left, &right); if (left < 0) left = Vect_get_isle_area(&Out, abs(left)); if (right < 0) right = Vect_get_isle_area(&Out, abs(right)); if (left > 0) { Vect_get_area_cats(&Out, left, Cats); do_line = Vect_cats_in_constraint(Cats, layer, cat_list); } if (!do_line && right > 0) { Vect_get_area_cats(&Out, right, Cats); do_line = Vect_cats_in_constraint(Cats, layer, cat_list); } } if (!do_line) continue; } } Vect_line_prune(APoints); if (APoints->n_points < 2) /* Line of length zero, delete if boundary ? */ continue; total_input += APoints->n_points; /* copy points */ Vect_reset_line(Points); Vect_append_points(Points, APoints, GV_FORWARD); loop_support = 0; if (!loop_support_flag->answer) { int n1, n2; Vect_get_line_nodes(&Out, i, &n1, &n2); if (n1 == n2) { if (Vect_get_node_n_lines(&Out, n1) == 2) { if (abs(Vect_get_node_line(&Out, n1, 0)) == i && abs(Vect_get_node_line(&Out, n1, 1)) == i) loop_support = 1; } } } for (iter = 0; iter < iterations; iter++) { switch (method) { case DOUGLAS: douglas_peucker(Points, thresh, with_z); break; case DOUGLAS_REDUCTION: douglas_peucker_reduction(Points, thresh, reduction, with_z); break; case LANG: lang(Points, thresh, look_ahead, with_z); break; case VERTEX_REDUCTION: vertex_reduction(Points, thresh, with_z); break; case REUMANN: reumann_witkam(Points, thresh, with_z); break; case BOYLE: boyle(Points, look_ahead, loop_support, with_z); break; case SLIDING_AVERAGING: sliding_averaging(Points, slide, look_ahead, loop_support, with_z); break; case DISTANCE_WEIGHTING: distance_weighting(Points, slide, look_ahead, loop_support, with_z); break; case CHAIKEN: chaiken(Points, thresh, loop_support, with_z); break; case HERMITE: hermite(Points, thresh, angle_thresh, loop_support, with_z); break; case SNAKES: snakes(Points, alpha, beta, loop_support, with_z); break; } } if (loop_support == 0) { /* safety check, BUG in method if not passed */ if (APoints->x[0] != Points->x[0] || APoints->y[0] != Points->y[0] || APoints->z[0] != Points->z[0]) G_fatal_error(_("Method '%s' did not preserve first point"), method_opt->answer); if (APoints->x[APoints->n_points - 1] != Points->x[Points->n_points - 1] || APoints->y[APoints->n_points - 1] != Points->y[Points->n_points - 1] || APoints->z[APoints->n_points - 1] != Points->z[Points->n_points - 1]) G_fatal_error(_("Method '%s' did not preserve last point"), method_opt->answer); } else { /* safety check, BUG in method if not passed */ if (Points->x[0] != Points->x[Points->n_points - 1] || Points->y[0] != Points->y[Points->n_points - 1] || Points->z[0] != Points->z[Points->n_points - 1]) G_fatal_error(_("Method '%s' did not preserve loop"), method_opt->answer); } Vect_line_prune(Points); /* oversimplified line */ if (Points->n_points < 2) { after = APoints->n_points; n_oversimplified++; if (error_out->answer) Vect_write_line(&Error, type, APoints, Cats); } /* check for topology corruption */ else if (type == GV_BOUNDARY) { if (!check_topo(&Out, i, APoints, Points, Cats)) { after = APoints->n_points; not_modified_boundaries++; if (error_out->answer) Vect_write_line(&Error, type, APoints, Cats); } else after = Points->n_points; } else { /* type == GV_LINE */ Vect_rewrite_line(&Out, i, type, Points, Cats); after = Points->n_points; } total_output += after; } if (not_modified_boundaries > 0) G_warning(_("%d boundaries were not modified because modification would damage topology"), not_modified_boundaries); if (n_oversimplified > 0) G_warning(_("%d lines/boundaries were not modified due to over-simplification"), n_oversimplified); G_message("-----------------------------------------------------"); /* make sure that clean topo is built at the end */ Vect_build_partial(&Out, GV_BUILD_NONE); if (error_out->answer) Vect_build_partial(&Error, GV_BUILD_NONE); } Vect_build(&Out); if (error_out->answer) Vect_build(&Error); Vect_close(&In); Vect_close(&Out); if (error_out->answer) Vect_close(&Error); G_message("-----------------------------------------------------"); if (total_input != 0 && total_input != total_output) G_done_msg(_("Number of vertices for selected features %s from %d to %d (%d%% remaining)"), simplification ? _("reduced") : _("changed"), total_input, total_output, (total_output * 100) / total_input); else G_done_msg(" "); exit(EXIT_SUCCESS); }
int report(struct Map_info *In, int afield, int nfield, int action) { int i, j, k, line, ltype, nnodes; int cat_line, cat_node[2]; struct line_cats *Cats, *Cats2; int node; double x, y, z; Cats = Vect_new_cats_struct(); Cats2 = Vect_new_cats_struct(); if (action == TOOL_REPORT) { /* For all lines find categories for points on nodes */ for (i = 1; i <= Vect_get_num_lines(In); i++) { ltype = Vect_read_line(In, NULL, Cats, i); if (ltype != GV_LINE) continue; cat_line = 0; if (!Vect_cat_get(Cats, afield, &cat_line)) G_warning(_("Line %d has no category"), i); cat_node[0] = cat_node[1] = 0; for (j = 0; j < 2; j++) { if (j == 0) Vect_get_line_nodes(In, i, &node, NULL); else Vect_get_line_nodes(In, i, NULL, &node); Vect_get_node_coor(In, node, &x, &y, &z); nnodes = 0; for (k = 0; k < Vect_get_node_n_lines(In, node); k++) { line = abs(Vect_get_node_line(In, node, k)); ltype = Vect_read_line(In, NULL, Cats, line); if (ltype != GV_POINT) continue; Vect_cat_get(Cats, nfield, &(cat_node[j])); nnodes++; } if (nnodes == 0) G_warning(_("Point not found: %.3lf %.3lf %.3lf line category: %d"), x, y, z, cat_line); else if (nnodes > 1) G_warning(_("%d points found: %.3lf %.3lf %.3lf line category: %d"), nnodes, x, y, z, cat_line); } fprintf(stdout, "%d %d %d\n", cat_line, cat_node[0], cat_node[1]); } } else { /* node report */ int nnodes, node; nnodes = Vect_get_num_nodes(In); for (node = 1; node <= nnodes; node++) { int nelem, elem, type, i, j, k, l; nelem = Vect_get_node_n_lines(In, node); /* Loop through all points */ for (i = 0; i < nelem; i++) { elem = abs(Vect_get_node_line(In, node, i)); type = Vect_read_line(In, NULL, Cats, elem); if (type != GV_POINT) continue; /* Loop through all cats of point */ for (j = 0; j < Cats->n_cats; j++) { if (Cats->field[j] == nfield) { int count = 0; fprintf(stdout, "%d ", Cats->cat[j]); /* Loop through all lines */ for (k = 0; k < nelem; k++) { elem = abs(Vect_get_node_line(In, node, k)); type = Vect_read_line(In, NULL, Cats2, elem); if (!(type & GV_LINES)) continue; /* Loop through all cats of line */ for (l = 0; l < Cats2->n_cats; l++) { if (Cats2->field[l] == afield) { if (count > 0) fprintf(stdout, ","); fprintf(stdout, "%d", Cats2->cat[l]); count++; } } } fprintf(stdout, "\n"); } } } } } return 0; }
int report(struct Map_info *In, int afield, int nfield, int action) { int i, j, line, nlines, ltype, node, nnodes; int cat_line, cat_node[2]; struct line_cats *Cats, *Cats2; struct line_pnts *Points; struct bound_box box; double x, y, z; Cats = Vect_new_cats_struct(); Cats2 = Vect_new_cats_struct(); Points = Vect_new_line_struct(); nlines = Vect_get_num_lines(In); if (action == TOOL_REPORT) { struct boxlist *List; List = Vect_new_boxlist(0); /* For all lines find categories for points on nodes */ for (i = 1; i <= nlines; i++) { ltype = Vect_read_line(In, NULL, Cats, i); if (!(ltype & GV_LINES)) continue; cat_line = 0; if (!Vect_cat_get(Cats, afield, &cat_line)) G_warning(_("Line %d has no category"), i); cat_node[0] = cat_node[1] = -1; for (j = 0; j < 2; j++) { if (j == 0) Vect_get_line_nodes(In, i, &node, NULL); else Vect_get_line_nodes(In, i, NULL, &node); Vect_get_node_coor(In, node, &x, &y, &z); box.E = box.W = x; box.N = box.S = y; box.T = box.B = z; Vect_select_lines_by_box(In, &box, GV_POINT, List); nnodes = List->n_values; if (nnodes > 0) { line = List->id[nnodes - 1]; /* last in list */ Vect_read_line(In, NULL, Cats, line); Vect_cat_get(Cats, nfield, &(cat_node[j])); } if (nnodes == 0) { /* this is ok, not every node needs to be * represented by a point */ G_debug(4, "No point here: %g %g %.g line category: %d", x, y, z, cat_line); } else if (nnodes > 1) G_warning(_("%d points found: %g %g %g line category: %d"), nnodes, x, y, z, cat_line); } fprintf(stdout, "%d %d %d\n", cat_line, cat_node[0], cat_node[1]); } } else { /* node report */ int elem, nelem, type, k, l; struct ilist *List; List = Vect_new_list(); for (i = 1; i <= nlines; i++) { if (Vect_get_line_type(In, i) != GV_POINT) continue; Vect_read_line(In, Points, Cats, i); box.E = box.W = Points->x[0]; box.N = box.S = Points->y[0]; box.T = box.B = Points->z[0]; nnodes = Vect_select_nodes_by_box(In, &box, List); if (nnodes > 1) { G_warning(_("Duplicate nodes at x=%g y=%g z=%g "), Points->x[0], Points->y[0], Points->z[0]); } if (nnodes > 0) { node = List->value[0]; nelem = Vect_get_node_n_lines(In, node); /* Loop through all cats of point */ for (j = 0; j < Cats->n_cats; j++) { if (Cats->field[j] == nfield) { int count = 0; fprintf(stdout, "%d ", Cats->cat[j]); /* Loop through all lines */ for (k = 0; k < nelem; k++) { elem = abs(Vect_get_node_line(In, node, k)); type = Vect_read_line(In, NULL, Cats2, elem); if (!(type & GV_LINES)) continue; /* Loop through all cats of line */ for (l = 0; l < Cats2->n_cats; l++) { if (Cats2->field[l] == afield) { if (count > 0) fprintf(stdout, ","); fprintf(stdout, "%d", Cats2->cat[l]); count++; } } } fprintf(stdout, "\n"); } } } } } return 0; }
int main(int argc, char **argv) { int i, j, k, ret; int nlines, type, ltype, afield, tfield, geo, cat; int sp, nsp, nspused, node, line; struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *type_opt, *term_opt, *nsp_opt; struct Flag *geo_f; struct GModule *module; struct Map_info Map, Out; int *testnode; /* array all nodes: 1 - should be tested as Steiner, * 0 - no need to test (unreachable or terminal) */ struct ilist *TList; /* list of terminal nodes */ struct ilist *StArcs; /* list of arcs on Steiner tree */ struct ilist *StNodes; /* list of nodes on Steiner tree */ struct boxlist *pointlist; double cost, tmpcost; struct cat_list *Clist; struct line_cats *Cats; struct line_pnts *Points; /* Initialize the GIS calls */ G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("network")); G_add_keyword(_("steiner tree")); module->label = _("Creates Steiner tree for the network and given terminals."); module->description = _("Note that 'Minimum Steiner Tree' problem is NP-hard " "and heuristic algorithm is used in this module so " "the result may be sub optimal."); map = G_define_standard_option(G_OPT_V_INPUT); output = G_define_standard_option(G_OPT_V_OUTPUT); 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->label = _("Arc type"); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "arc_layer"; afield_opt->answer = "1"; afield_opt->label = _("Arc layer"); tfield_opt = G_define_standard_option(G_OPT_V_FIELD); tfield_opt->key = "node_layer"; tfield_opt->answer = "2"; tfield_opt->label = _("Node layer (used for terminals)"); afcol = G_define_option(); afcol->key = "acolumn"; afcol->type = TYPE_STRING; afcol->required = NO; afcol->description = _("Arcs' cost column (for both directions)"); term_opt = G_define_standard_option(G_OPT_V_CATS); term_opt->key = "terminal_cats"; term_opt->required = YES; term_opt->description = _("Categories of points on terminals (layer is specified by nlayer)"); nsp_opt = G_define_option(); nsp_opt->key = "npoints"; nsp_opt->type = TYPE_INTEGER; nsp_opt->required = NO; nsp_opt->multiple = NO; nsp_opt->answer = "-1"; nsp_opt->description = _("Number of Steiner points (-1 for all possible)"); geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = _("Use geodesic calculation for longitude-latitude locations"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); Cats = Vect_new_cats_struct(); Points = Vect_new_line_struct(); type = Vect_option_to_types(type_opt); afield = atoi(afield_opt->answer); TList = Vect_new_list(); StArcs = Vect_new_list(); StNodes = Vect_new_list(); Clist = Vect_new_cat_list(); tfield = atoi(tfield_opt->answer); Vect_str_to_cat_list(term_opt->answer, Clist); G_debug(1, "Imput categories:\n"); for (i = 0; i < Clist->n_ranges; i++) { G_debug(1, "%d - %d\n", Clist->min[i], Clist->max[i]); } if (geo_f->answer) geo = 1; else geo = 0; Vect_check_input_output_name(map->answer, output->answer, G_FATAL_EXIT); Vect_set_open_level(2); if (Vect_open_old(&Map, map->answer, "") < 0) G_fatal_error(_("Unable to open vector map <%s>"), map->answer); nnodes = Vect_get_num_nodes(&Map); nlines = Vect_get_num_lines(&Map); /* Create list of terminals based on list of categories */ for (i = 1; i <= nlines; i++) { ltype = Vect_get_line_type(&Map, i); if (!(ltype & GV_POINT)) continue; Vect_read_line(&Map, Points, Cats, i); if (!(Vect_cat_get(Cats, tfield, &cat))) continue; 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 (cat=%d)"), cat); continue; } if (Vect_cat_in_cat_list(cat, Clist)) { Vect_list_append(TList, node); } } nterms = TList->n_values; /* GTC Terminal refers to an Steiner tree endpoint */ G_message(_("Number of terminals: %d\n"), nterms); if (nterms < 2) { /* GTC Terminal refers to an Steiner tree endpoint */ G_fatal_error(_("Not enough terminals (< 2)")); } /* Number of steiner points */ nsp = atoi(nsp_opt->answer); if (nsp > nterms - 2) { nsp = nterms - 2; G_warning(_("Requested number of Steiner points > than possible")); } else if (nsp == -1) { nsp = nterms - 2; } G_message(_("Number of Steiner points set to %d\n"), nsp); testnode = (int *)G_malloc((nnodes + 1) * sizeof(int)); for (i = 1; i <= nnodes; i++) testnode[i] = 1; /* Alloc arrays of costs for nodes, first node at 1 (0 not used) */ nodes_costs = (double **)G_malloc((nnodes) * sizeof(double *)); for (i = 0; i < nnodes; i++) { nodes_costs[i] = (double *)G_malloc((nnodes - i) * sizeof(double)); for (j = 0; j < nnodes - i; j++) nodes_costs[i][j] = -1; /* init, i.e. cost was not calculated yet */ } /* alloc memory from each to each other (not directed) terminal */ i = nterms + nterms - 2; /* max number of terms + Steiner points */ comps = (int *)G_malloc(i * sizeof(int)); i = i * (i - 1) / 2; /* number of combinations */ term_costs = (COST *) G_malloc(i * sizeof(COST)); /* alloc memory for costs from Stp to each other terminal */ i = nterms + nterms - 2 - 1; /* max number of terms + Steiner points - 1 */ sp_costs = (COST *) G_malloc(i * sizeof(COST)); terms = (int *)G_malloc((nterms + nterms - 2) * sizeof(int)); /* i.e. +(nterms - 2) St Points */ /* Create initial parts from list of terminals */ G_debug(1, "List of terminal nodes (%d):\n", nterms); for (i = 0; i < nterms; i++) { G_debug(1, "%d\n", TList->value[i]); terms[i] = TList->value[i]; testnode[terms[i]] = 0; /* do not test as Steiner */ } /* Build graph */ Vect_net_build_graph(&Map, type, afield, 0, afcol->answer, NULL, NULL, geo, 0); /* Init costs for all terminals */ for (i = 0; i < nterms; i++) init_node_costs(&Map, terms[i]); /* Test if all terminal may be connected */ for (i = 1; i < nterms; i++) { ret = get_node_costs(terms[0], terms[i], &cost); if (ret == 0) { /* GTC Terminal refers to an Steiner tree endpoint */ G_fatal_error(_("Terminal at node [%d] cannot be connected " "to terminal at node [%d]"), terms[0], terms[i]); } } /* Remove not reachable from list of SP candidates */ j = 0; for (i = 1; i <= nnodes; i++) { ret = get_node_costs(terms[0], i, &cost); if (ret == 0) { testnode[i] = 0; G_debug(2, "node %d removed from list of Steiner point candidates\n", i ); j++; } } G_message(_("[%d] (not reachable) nodes removed from list " "of Steiner point candidates"), j); /* calc costs for terminals MST */ ret = mst(&Map, terms, nterms, &cost, PORT_DOUBLE_MAX, NULL, NULL, 0, 1); /* no StP, rebuild */ G_message(_("MST costs = %f"), cost); /* Go through all nodes and try to use as steiner points -> find that which saves most costs */ nspused = 0; for (j = 0; j < nsp; j++) { sp = 0; G_verbose_message(_("Search for [%d]. Steiner point"), j + 1); for (i = 1; i <= nnodes; i++) { G_percent(i, nnodes, 1); if (testnode[i] == 0) { G_debug(3, "skip test for %d\n", i); continue; } ret = mst(&Map, terms, nterms + j, &tmpcost, cost, NULL, NULL, i, 0); G_debug(2, "cost = %f x %f\n", tmpcost, cost); if (tmpcost < cost) { /* sp candidate */ G_debug(3, " steiner candidate node = %d mst = %f (x last = %f)\n", i, tmpcost, cost); sp = i; cost = tmpcost; } } if (sp > 0) { G_message(_("Steiner point at node [%d] was added " "to terminals (MST costs = %f)"), sp, cost); terms[nterms + j] = sp; init_node_costs(&Map, sp); testnode[sp] = 0; nspused++; /* rebuild for nex cycle */ ret = mst(&Map, terms, nterms + nspused, &tmpcost, PORT_DOUBLE_MAX, NULL, NULL, 0, 1); } else { /* no steiner found */ G_message(_("No Steiner point found -> leaving cycle")); break; } } G_message(_("Number of added Steiner points: %d " "(theoretic max is %d).\n"), nspused, nterms - 2); /* Build lists of arcs and nodes for final version */ ret = mst(&Map, terms, nterms + nspused, &cost, PORT_DOUBLE_MAX, StArcs, StNodes, 0, 0); /* Calculate true costs, which may be lower than MST if steiner points were not used */ if (nsp < nterms - 2) { G_message(_("Spanning tree costs on complet graph = %f\n" "(may be higher than resulting Steiner tree costs!!!)"), cost); } else G_message(_("Steiner tree costs = %f"), cost); /* 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); G_debug(1, "Steiner tree:"); G_debug(1, "Arcs' categories (layer %d, %d arcs):", afield, StArcs->n_values); for (i = 0; i < StArcs->n_values; i++) { line = StArcs->value[i]; ltype = Vect_read_line(&Map, Points, Cats, line); Vect_write_line(&Out, ltype, Points, Cats); Vect_cat_get(Cats, afield, &cat); G_debug(1, "arc cat = %d", cat); } G_debug(1, "Nodes' categories (layer %d, %d nodes):", tfield, StNodes->n_values); k = 0; pointlist = Vect_new_boxlist(0); for (i = 0; i < StNodes->n_values; i++) { double x, y, z; struct bound_box box; node = StNodes->value[i]; Vect_get_node_coor(&Map, node, &x, &y, &z); box.E = box.W = x; box.N = box.S = y; box.T = box.B = z; Vect_select_lines_by_box(&Map, &box, GV_POINT, pointlist); nlines = Vect_get_node_n_lines(&Map, node); for (j = 0; j < pointlist->n_values; j++) { line = pointlist->id[j]; ltype = Vect_read_line(&Map, Points, Cats, line); if (!(ltype & GV_POINT)) continue; if (!(Vect_cat_get(Cats, tfield, &cat))) continue; Vect_write_line(&Out, ltype, Points, Cats); G_debug(1, "node cat = %d", cat); k++; } } Vect_build(&Out); G_message(n_("A Steiner tree with %d arc has been built", "A Steiner tree with %d arcs has been built", StArcs->n_values), StArcs->n_values); /* Free, ... */ Vect_destroy_list(StArcs); Vect_destroy_list(StNodes); Vect_close(&Map); Vect_close(&Out); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int i; int **cats, *ncats, nfields, *fields; struct Flag *line_flag; /* struct Flag *all_flag; */ struct Option *in_opt, *out_opt; struct Flag *table_flag; struct GModule *module; struct line_pnts *Points; struct line_cats *Cats; int node, nnodes; COOR *coor; int ncoor, acoor; int line, nlines, type, ctype, area, nareas; int err_boundaries, err_centr_out, err_centr_dupl, err_nocentr; G_gisinit(argv[0]); module = G_define_module(); G_add_keyword(_("vector")); G_add_keyword(_("geometry")); G_add_keyword(_("triangulation")); module->description = _("Creates a Voronoi diagram from an input vector " "map containing points or centroids."); in_opt = G_define_standard_option(G_OPT_V_INPUT); out_opt = G_define_standard_option(G_OPT_V_OUTPUT); /* all_flag = G_define_flag (); all_flag->key = 'a'; all_flag->description = _("Use all points (do not limit to current region)"); */ line_flag = G_define_flag(); line_flag->key = 'l'; line_flag->description = _("Output tessellation as a graph (lines), not areas"); table_flag = G_define_flag(); table_flag->key = 't'; table_flag->description = _("Do not create attribute table"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); if (line_flag->answer) Type = GV_LINE; else Type = GV_BOUNDARY; All = 0; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* open files */ Vect_set_open_level(2); Vect_open_old(&In, in_opt->answer, ""); if (Vect_open_new(&Out, out_opt->answer, 0) < 0) G_fatal_error(_("Unable to create vector map <%s>"), out_opt->answer); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); /* initialize working region */ G_get_window(&Window); Vect_region_box(&Window, &Box); Box.T = 0.5; Box.B = -0.5; freeinit(&sfl, sizeof(struct Site)); G_message(_("Reading sites...")); readsites(); siteidx = 0; geominit(); triangulate = 0; plot = 0; debug = 0; G_message(_("Voronoi triangulation...")); voronoi(triangulate, nextone); /* Close free ends by current region */ Vect_build_partial(&Out, GV_BUILD_BASE); ncoor = 0; acoor = 100; coor = (COOR *) G_malloc(sizeof(COOR) * acoor); nnodes = Vect_get_num_nodes(&Out); for (node = 1; node <= nnodes; node++) { double x, y; if (Vect_get_node_n_lines(&Out, node) < 2) { /* add coordinates */ Vect_get_node_coor(&Out, node, &x, &y, NULL); if (ncoor == acoor - 5) { /* always space for 5 region corners */ acoor += 100; coor = (COOR *) G_realloc(coor, sizeof(COOR) * acoor); } coor[ncoor].x = x; coor[ncoor].y = y; ncoor++; } } /* Add region corners */ coor[ncoor].x = Box.W; coor[ncoor].y = Box.S; ncoor++; coor[ncoor].x = Box.E; coor[ncoor].y = Box.S; ncoor++; coor[ncoor].x = Box.E; coor[ncoor].y = Box.N; ncoor++; coor[ncoor].x = Box.W; coor[ncoor].y = Box.N; ncoor++; /* Sort */ qsort(coor, ncoor, sizeof(COOR), (void *)cmp); /* add last (first corner) */ coor[ncoor].x = Box.W; coor[ncoor].y = Box.S; ncoor++; for (i = 1; i < ncoor; i++) { if (coor[i].x == coor[i - 1].x && coor[i].y == coor[i - 1].y) continue; /* duplicate */ Vect_reset_line(Points); Vect_append_point(Points, coor[i].x, coor[i].y, 0.0); Vect_append_point(Points, coor[i - 1].x, coor[i - 1].y, 0.0); Vect_write_line(&Out, Type, Points, Cats); } G_free(coor); /* Copy input points as centroids */ nfields = Vect_cidx_get_num_fields(&In); cats = (int **)G_malloc(nfields * sizeof(int *)); ncats = (int *)G_malloc(nfields * sizeof(int)); fields = (int *)G_malloc(nfields * sizeof(int)); for (i = 0; i < nfields; i++) { ncats[i] = 0; cats[i] = (int *)G_malloc(Vect_cidx_get_num_cats_by_index(&In, i) * sizeof(int)); fields[i] = Vect_cidx_get_field_number(&In, i); } if (line_flag->answer) ctype = GV_POINT; else ctype = GV_CENTROID; nlines = Vect_get_num_lines(&In); G_message(_("Writing sites to output...")); for (line = 1; line <= nlines; line++) { G_percent(line, nlines, 2); type = Vect_read_line(&In, Points, Cats, line); if (!(type & GV_POINTS)) continue; if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &Box)) continue; Vect_write_line(&Out, ctype, Points, Cats); for (i = 0; i < Cats->n_cats; i++) { int f, j; f = -1; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == Cats->field[i]) { f = j; break; } } if (f > -1) { cats[f][ncats[f]] = Cats->cat[i]; ncats[f]++; } } } /* Copy tables */ if (!(table_flag->answer)) { int ttype, ntabs = 0; struct field_info *IFi, *OFi; /* Number of output tabs */ for (i = 0; i < Vect_get_num_dblinks(&In); i++) { int f, j; IFi = Vect_get_dblink(&In, i); f = -1; for (j = 0; j < nfields; j++) { /* find field */ if (fields[j] == IFi->number) { f = j; break; } } if (f > -1) { if (ncats[f] > 0) ntabs++; } } if (ntabs > 1) ttype = GV_MTABLE; else ttype = GV_1TABLE; for (i = 0; i < nfields; i++) { int ret; if (fields[i] == 0) continue; G_message(_("Layer %d"), fields[i]); /* Make a list of categories */ IFi = Vect_get_field(&In, fields[i]); if (!IFi) { /* no table */ G_message(_("No table")); continue; } OFi = Vect_default_field_info(&Out, IFi->number, IFi->name, ttype); ret = db_copy_table_by_ints(IFi->driver, IFi->database, IFi->table, OFi->driver, Vect_subst_var(OFi->database, &Out), OFi->table, IFi->key, cats[i], ncats[i]); if (ret == DB_FAILED) { G_warning(_("Cannot copy table")); } else { Vect_map_add_dblink(&Out, OFi->number, OFi->name, OFi->table, IFi->key, OFi->database, OFi->driver); } } } Vect_close(&In); /* cleaning part 1: count errors */ Vect_build_partial(&Out, GV_BUILD_CENTROIDS); err_boundaries = err_centr_out = err_centr_dupl = err_nocentr = 0; nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); if (left == 0 || right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); err_boundaries++; } } if (type == GV_CENTROID) { area = Vect_get_centroid_area(&Out, line); if (area == 0) err_centr_out++; else if (area < 0) err_centr_dupl++; } } err_nocentr = 0; nareas = Vect_get_num_areas(&Out); for (area = 1; area <= nareas; area++) { if (!Vect_area_alive(&Out, area)) continue; line = Vect_get_area_centroid(&Out, area); if (line == 0) err_nocentr++; } /* cleaning part 2: snap */ if (err_nocentr || err_centr_dupl || err_centr_out) { int nmod; G_important_message(_("Output needs topological cleaning")); Vect_snap_lines(&Out, GV_BOUNDARY, 1e-7, NULL); do { Vect_break_lines(&Out, GV_BOUNDARY, NULL); Vect_remove_duplicates(&Out, GV_BOUNDARY, NULL); nmod = Vect_clean_small_angles_at_nodes(&Out, GV_BOUNDARY, NULL); } while (nmod > 0); err_boundaries = 0; nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); if (left == 0 || right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); err_boundaries++; } } } } /* cleaning part 3: remove remaining incorrect boundaries */ if (err_boundaries) { G_important_message(_("Removing incorrect boundaries from output")); nlines = Vect_get_num_lines(&Out); for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(&Out, line)) continue; type = Vect_get_line_type(&Out, line); if (type == GV_BOUNDARY) { int left, right; Vect_get_line_areas(&Out, line, &left, &right); /* &&, not ||, no typo */ if (left == 0 && right == 0) { G_debug(3, "line = %d left = %d right = %d", line, left, right); Vect_delete_line(&Out, line); } } } } /* build clean topology */ Vect_build_partial(&Out, GV_BUILD_NONE); Vect_build(&Out); Vect_close(&Out); G_done_msg(" "); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int i, j, ret, centre, line, centre1, centre2; int nlines, nnodes, type, ltype, afield, nfield, geo, cat; int node, node1, node2; double cost, e1cost, e2cost, n1cost, n2cost, s1cost, s2cost, l, l1, l2; struct Option *map, *output; struct Option *afield_opt, *nfield_opt, *afcol, *abcol, *ncol, *type_opt, *term_opt; struct Flag *geo_f; struct GModule *module; char *mapset; struct Map_info Map, Out; struct cat_list *catlist; CENTER *Centers = NULL; int acentres = 0, ncentres = 0; NODE *Nodes; struct line_cats *Cats; struct line_pnts *Points, *SPoints; G_gisinit(argv[0]); module = G_define_module(); module->keywords = _("vector, network, allocation"); module->label = _("Allocate subnets for nearest centres (direction from centre)."); module->description = _("Centre node must be opened (costs >= 0). " "Costs of centre node are used in calculation"); map = G_define_standard_option(G_OPT_V_INPUT); output = G_define_standard_option(G_OPT_V_OUTPUT); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->options = "line,boundary"; type_opt->answer = "line,boundary"; type_opt->description = _("Arc type"); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "alayer"; afield_opt->answer = "1"; afield_opt->description = _("Arc layer"); nfield_opt = G_define_standard_option(G_OPT_V_FIELD); nfield_opt->key = "nlayer"; nfield_opt->answer = "2"; nfield_opt->description = _("Node layer"); afcol = G_define_option(); afcol->key = "afcolumn"; afcol->type = TYPE_STRING; afcol->required = NO; afcol->description = _("Arc forward/both direction(s) cost column (number)"); abcol = G_define_option(); abcol->key = "abcolumn"; abcol->type = TYPE_STRING; abcol->required = NO; abcol->description = _("Arc backward direction cost column (number)"); ncol = G_define_option(); ncol->key = "ncolumn"; ncol->type = TYPE_STRING; ncol->required = NO; ncol->description = _("Node cost column (number)"); term_opt = G_define_standard_option(G_OPT_V_CATS); term_opt->key = "ccats"; term_opt->required = YES; term_opt->description = _("Categories of centres (points on nodes) to which net " "will be allocated, " "layer for this categories is given by nlayer option"); geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = _("Use geodesic calculation for longitude-latitude locations"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); Vect_check_input_output_name(map->answer, output->answer, GV_FATAL_EXIT); Cats = Vect_new_cats_struct(); Points = Vect_new_line_struct(); SPoints = Vect_new_line_struct(); type = Vect_option_to_types(type_opt); afield = atoi(afield_opt->answer); nfield = atoi(nfield_opt->answer); catlist = Vect_new_cat_list(); Vect_str_to_cat_list(term_opt->answer, catlist); if (geo_f->answer) geo = 1; else geo = 0; mapset = G_find_vector2(map->answer, NULL); if (mapset == NULL) G_fatal_error(_("Vector map <%s> not found"), map->answer); Vect_set_open_level(2); Vect_open_old(&Map, map->answer, mapset); /* Build graph */ Vect_net_build_graph(&Map, type, afield, nfield, afcol->answer, abcol->answer, ncol->answer, geo, 0); nnodes = Vect_get_num_nodes(&Map); /* Create list of centres based on list of categories */ for (node = 1; node <= nnodes; node++) { nlines = Vect_get_node_n_lines(&Map, node); for (j = 0; j < nlines; j++) { line = abs(Vect_get_node_line(&Map, node, j)); ltype = Vect_read_line(&Map, NULL, Cats, line); if (!(ltype & GV_POINT)) 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("Centre at closed node (costs = -1) ignored"); } else { if (acentres == ncentres) { acentres += 1; Centers = (CENTER *) G_realloc(Centers, acentres * sizeof(CENTER)); } Centers[ncentres].cat = cat; Centers[ncentres].node = node; G_debug(2, "centre = %d node = %d cat = %d", ncentres, node, cat); ncentres++; } } } } G_message(_("Number of centres: [%d] (nlayer: [%d])"), ncentres, nfield); if (ncentres == 0) G_warning(_("Not enough centres for selected nlayer. " "Nothing will be allocated.")); /* alloc and reset space for all nodes */ Nodes = (NODE *) G_calloc((nnodes + 1), sizeof(NODE)); for (i = 1; i <= nnodes; i++) { Nodes[i].centre = -1; } /* Fill Nodes by neares centre and costs from that centre */ G_message(_("Calculating costs from centres ...")); for (centre = 0; centre < ncentres; centre++) { G_percent(centre, ncentres, 1); node1 = Centers[centre].node; Vect_net_get_node_cost(&Map, node1, &n1cost); G_debug(2, "centre = %d node = %d cat = %d", centre, node1, Centers[centre].cat); for (node2 = 1; node2 <= nnodes; node2++) { G_debug(5, " node1 = %d node2 = %d", node1, node2); Vect_net_get_node_cost(&Map, node2, &n2cost); if (n2cost == -1) { continue; } /* closed, left it as not attached */ ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &cost); if (ret == -1) { continue; } /* node unreachable */ /* We must add centre node costs (not calculated by Vect_net_shortest_path() ), but * only if centre and node are not identical, because at the end node cost is add later */ if (node1 != node2) cost += n1cost; G_debug(5, "Arc nodes: %d %d cost: %f (x old cent: %d old cost %f", node1, node2, cost, Nodes[node2].centre, Nodes[node2].cost); if (Nodes[node2].centre == -1 || cost < Nodes[node2].cost) { Nodes[node2].cost = cost; Nodes[node2].centre = centre; } } } G_percent(1, 1, 1); /* Write arcs to new map */ Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)); Vect_hist_command(&Out); nlines = Vect_get_num_lines(&Map); for (line = 1; line <= nlines; line++) { ltype = Vect_read_line(&Map, Points, NULL, line); if (!(ltype & type)) { continue; } Vect_get_line_nodes(&Map, line, &node1, &node2); centre1 = Nodes[node1].centre; centre2 = Nodes[node2].centre; s1cost = Nodes[node1].cost; s2cost = Nodes[node2].cost; G_debug(3, "Line %d:", line); G_debug(3, "Arc centres: %d %d (nodes: %d %d)", centre1, centre2, node1, node2); Vect_net_get_node_cost(&Map, node1, &n1cost); Vect_net_get_node_cost(&Map, node2, &n2cost); Vect_net_get_line_cost(&Map, line, GV_FORWARD, &e1cost); Vect_net_get_line_cost(&Map, line, GV_BACKWARD, &e2cost); 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 ((centre1 != -1 && n1cost != -1 && e1cost != -1) || (centre2 != -1 && n2cost != -1 && e2cost != -1)) { /* Line is reachable at least from one side */ G_debug(3, " -> arc is reachable"); if (centre1 == centre2) { /* both nodes in one area -> whole arc in one area */ if (centre1 != -1) cat = Centers[centre1].cat; /* line reachable */ else cat = Centers[centre2].cat; Vect_cat_set(Cats, 1, cat); Vect_write_line(&Out, ltype, Points, Cats); } else { /* each node in different area */ /* Check if direction is reachable */ if (centre1 == -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[centre2].cat; Vect_cat_set(Cats, 1, cat); Vect_write_line(&Out, ltype, Points, Cats); continue; } else if (centre2 == -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[centre1].cat; 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[centre1].cat; 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[centre2].cat; 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 centres 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[centre1].cat; 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[centre2].cat; 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"); Vect_write_line(&Out, ltype, Points, Cats); } } Vect_build(&Out); /* Free, ... */ G_free(Nodes); G_free(Centers); Vect_close(&Map); Vect_close(&Out); exit(EXIT_SUCCESS); }
int main(int argc, char **argv) { int i, j, k, ret, city, city1; int nlines, type, ltype, afield, tfield, geo, cat; int node, node1, node2, line; struct Option *map, *output, *afield_opt, *tfield_opt, *afcol, *type_opt, *term_opt; struct Flag *geo_f; struct GModule *module; char *mapset; struct Map_info Map, Out; struct ilist *TList; /* list of terminal nodes */ struct ilist *List; struct ilist *StArcs; /* list of arcs on Steiner tree */ struct ilist *StNodes; /* list of nodes on Steiner tree */ double cost, tmpcost, tcost; struct cat_list *Clist; struct line_cats *Cats; struct line_pnts *Points; /* Initialize the GIS calls */ G_gisinit(argv[0]); module = G_define_module(); module->keywords = _("vector, network, salesman"); module->label = _("Creates a cycle connecting given nodes (Traveling salesman problem)."); module->description = _("Note that TSP is NP-hard, heuristic algorithm is used by " "this module and created cycle may be sub optimal"); map = G_define_standard_option(G_OPT_V_INPUT); output = G_define_standard_option(G_OPT_V_OUTPUT); type_opt = G_define_standard_option(G_OPT_V_TYPE); type_opt->options = "line,boundary"; type_opt->answer = "line,boundary"; type_opt->description = _("Arc type"); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "alayer"; afield_opt->description = _("Arc layer"); tfield_opt = G_define_standard_option(G_OPT_V_FIELD); tfield_opt->key = "nlayer"; tfield_opt->answer = "2"; tfield_opt->description = _("Node layer (used for cities)"); afcol = G_define_option(); afcol->key = "acolumn"; afcol->type = TYPE_STRING; afcol->required = NO; afcol->description = _("Arcs' cost column (for both directions)"); term_opt = G_define_standard_option(G_OPT_V_CATS); term_opt->key = "ccats"; term_opt->required = YES; term_opt->description = _("Categories of points ('cities') on nodes " "(layer is specified by nlayer)"); geo_f = G_define_flag(); geo_f->key = 'g'; geo_f->description = _("Use geodesic calculation for longitude-latitude locations"); if (G_parser(argc, argv)) exit(EXIT_FAILURE); Cats = Vect_new_cats_struct(); Points = Vect_new_line_struct(); type = Vect_option_to_types(type_opt); afield = atoi(afield_opt->answer); TList = Vect_new_list(); List = Vect_new_list(); StArcs = Vect_new_list(); StNodes = Vect_new_list(); Clist = Vect_new_cat_list(); tfield = atoi(tfield_opt->answer); Vect_str_to_cat_list(term_opt->answer, Clist); G_debug(1, "Imput categories:\n"); for (i = 0; i < Clist->n_ranges; i++) { G_debug(1, "%d - %d\n", Clist->min[i], Clist->max[i]); } if (geo_f->answer) geo = 1; else geo = 0; Vect_check_input_output_name(map->answer, output->answer, GV_FATAL_EXIT); mapset = G_find_vector2(map->answer, NULL); if (mapset == NULL) G_fatal_error(_("Vector map <%s> not found"), map->answer); Vect_set_open_level(2); Vect_open_old(&Map, map->answer, mapset); nnodes = Vect_get_num_nodes(&Map); /* Create list of terminals based on list of categories */ for (i = 1; i <= nnodes; i++) { nlines = Vect_get_node_n_lines(&Map, i); for (j = 0; j < nlines; j++) { line = abs(Vect_get_node_line(&Map, i, j)); ltype = Vect_read_line(&Map, NULL, Cats, line); if (!(ltype & GV_POINT)) continue; if (!(Vect_cat_get(Cats, tfield, &cat))) continue; if (Vect_cat_in_cat_list(cat, Clist)) { Vect_list_append(TList, i); } } } ncities = TList->n_values; G_message(_("Number of cities: [%d]"), ncities); if (ncities < 2) G_fatal_error(_("Not enough cities (< 2)")); /* Alloc memory */ cities = (int *)G_malloc(ncities * sizeof(int)); cused = (int *)G_malloc(ncities * sizeof(int)); for (i = 0; i < ncities; i++) { G_debug(1, "%d\n", TList->value[i]); cities[i] = TList->value[i]; cused[i] = 0; /* not in cycle */ } costs = (COST **) G_malloc(ncities * sizeof(COST *)); for (i = 0; i < ncities; i++) { costs[i] = (COST *) G_malloc(ncities * sizeof(COST)); } cycle = (int *)G_malloc((ncities + 1) * sizeof(int)); /* + 1 is for output cycle */ /* Build graph */ Vect_net_build_graph(&Map, type, afield, 0, afcol->answer, NULL, NULL, geo, 0); /* Create sorted lists of costs */ for (i = 0; i < ncities; i++) { k = 0; for (j = 0; j < ncities; j++) { if (i == j) continue; ret = Vect_net_shortest_path(&Map, cities[i], cities[j], NULL, &cost); if (ret == -1) G_fatal_error(_("Destination node [%d] is unreachable " "from node [%d]"), cities[i], cities[j]); costs[i][k].city = j; costs[i][k].cost = cost; k++; } qsort((void *)costs[i], k, sizeof(COST), cmp); } /* debug: print sorted */ for (i = 0; i < ncities; i++) { for (j = 0; j < ncities - 1; j++) { city = costs[i][j].city; G_debug(2, "%d -> %d = %f\n", cities[i], cities[city], costs[i][j].cost); } } /* find 2 cities with largest distance */ cost = -1; for (i = 0; i < ncities; i++) { tmpcost = costs[i][ncities - 2].cost; if (tmpcost > cost) { cost = tmpcost; city = i; } } G_debug(2, "biggest costs %d - %d\n", city, costs[city][ncities - 2].city); /* add this 2 cities to array */ add_city(city, -1); add_city(costs[city][ncities - 2].city, 0); /* In each step, find not used city, with biggest cost to any used city, and insert * into cycle between 2 nearest nodes */ for (i = 0; i < ncities - 2; i++) { cost = -1; G_debug(2, "---- %d ----\n", i); for (j = 0; j < ncities; j++) { if (cused[j] == 1) continue; tmpcost = 0; for (k = 0; k < ncities - 1; k++) { G_debug(2, "? %d (%d) - %d (%d) \n", j, cnode(j), costs[j][k].city, cnode(costs[j][k].city)); if (!cused[costs[j][k].city]) continue; /* only used */ tmpcost += costs[j][k].cost; break; /* first nearest */ } G_debug(2, " cost = %f x %f\n", tmpcost, cost); if (tmpcost > cost) { cost = tmpcost; city = j; } } G_debug(2, "add %d\n", city); /* add to cycle on lovest costs */ cycle[ncyc] = cycle[0]; /* tmp for cycle */ cost = PORT_DOUBLE_MAX; for (j = 0; j < ncyc; j++) { node1 = cities[cycle[j]]; node2 = cities[cycle[j + 1]]; ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost); tmpcost = -tcost; node1 = cities[cycle[j]]; node2 = cities[city]; ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost); tmpcost += tcost; node1 = cities[cycle[j + 1]]; node2 = cities[city]; ret = Vect_net_shortest_path(&Map, node1, node2, NULL, &tcost); tmpcost += tcost; G_debug(2, "? %d - %d cost = %f x %f\n", node1, node2, tmpcost, cost); if (tmpcost < cost) { city1 = j; cost = tmpcost; } } add_city(city, city1); } /* Print */ G_debug(2, "Cycle:\n"); for (i = 0; i < ncities; i++) { G_debug(2, "%d: %d: %d\n", i, cycle[i], cities[cycle[i]]); } /* Create list of arcs */ cycle[ncities] = cycle[0]; for (i = 0; i < ncities; i++) { node1 = cities[cycle[i]]; node2 = cities[cycle[i + 1]]; G_debug(2, " %d -> %d\n", node1, node2); ret = Vect_net_shortest_path(&Map, node1, node2, List, NULL); for (j = 0; j < List->n_values; j++) { line = abs(List->value[j]); Vect_list_append(StArcs, line); Vect_get_line_nodes(&Map, line, &node1, &node2); Vect_list_append(StNodes, node1); Vect_list_append(StNodes, node2); } } /* Write arcs to new map */ Vect_open_new(&Out, output->answer, Vect_is_3d(&Map)); Vect_hist_command(&Out); fprintf(stdout, "\nCycle:\n"); fprintf(stdout, "Arcs' categories (layer %d, %d arcs):\n", afield, StArcs->n_values); for (i = 0; i < StArcs->n_values; i++) { line = StArcs->value[i]; ltype = Vect_read_line(&Map, Points, Cats, line); Vect_write_line(&Out, ltype, Points, Cats); Vect_cat_get(Cats, afield, &cat); if (i > 0) printf(","); fprintf(stdout, "%d", cat); } fprintf(stdout, "\n\n"); fprintf(stdout, "Nodes' categories (layer %d, %d nodes):\n", tfield, StNodes->n_values); k = 0; for (i = 0; i < StNodes->n_values; i++) { node = StNodes->value[i]; nlines = Vect_get_node_n_lines(&Map, node); for (j = 0; j < nlines; j++) { line = abs(Vect_get_node_line(&Map, node, j)); ltype = Vect_read_line(&Map, Points, Cats, line); if (!(ltype & GV_POINT)) continue; if (!(Vect_cat_get(Cats, tfield, &cat))) continue; Vect_write_line(&Out, ltype, Points, Cats); if (k > 0) fprintf(stdout, ","); fprintf(stdout, "%d", cat); k++; } } fprintf(stdout, "\n\n"); Vect_build(&Out); /* Free, ... */ Vect_destroy_list(StArcs); Vect_destroy_list(StNodes); Vect_close(&Map); Vect_close(&Out); exit(EXIT_SUCCESS); }
int write_triple(struct Site *s1, struct Site *s2, struct Site *s3) { int i; int node; static struct line_pnts *Points = NULL; static struct line_cats *Cats = NULL; struct Site *sa, *sb; if (!Points) { Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); } if (triangulate) { for (i = 0; i < 3; i++) { switch (i) { case 0: sa = s1; sb = s2; break; case 1: sa = s2; sb = s3; break; case 2: sa = s3; sb = s1; break; } /* Look if the line already exists */ node = Vect_find_node(&Out, sa->coord.x, sa->coord.y, 0.0, 0.0, 0); if (node > 0) { /* node found */ int j, nlines; int found = 0; double x, y, z; nlines = Vect_get_node_n_lines(&Out, node); for (j = 0; j < nlines; j++) { int line, node2; line = Vect_get_node_line(&Out, node, j); if (line > 0) Vect_get_line_nodes(&Out, line, NULL, &node2); else Vect_get_line_nodes(&Out, abs(line), &node2, NULL); Vect_get_node_coor(&Out, node2, &x, &y, &z); if (x == sb->coord.x && y == sb->coord.y) { found = 1; break; } } if (found) continue; /* next segment */ } /* Not found, write it */ Vect_reset_line(Points); if (mode3d) { G_debug(3, "sa->coord.z: %f", sa->coord.z); Vect_append_point(Points, sa->coord.x, sa->coord.y, sa->coord.z); Vect_append_point(Points, sb->coord.x, sb->coord.y, sb->coord.z); } else { Vect_append_point(Points, sa->coord.x, sa->coord.y, 0.0); Vect_append_point(Points, sb->coord.x, sb->coord.y, 0.0); } Vect_write_line(&Out, Type, Points, Cats); } } return 0; }
/*! \brief Overlay 2 vector maps with AND. AND supports:point line area point + - + line - - - area + - - \param AMap vector map A \param atype feature type for A \param AList unused ? \param AAList unused ? \param BMap vector map B \param btype feature type for B \param BList unused ? \param BAList unused ? \param operator operator code \return 1 on success \return 0 on error */ int Vect_overlay_and(struct Map_info *AMap, int atype, struct ilist *AList, struct ilist *AAList, struct Map_info *BMap, int btype, struct ilist *BList, struct ilist *BAList, struct Map_info *OMap) { int i, j, k, node, line, altype, bltype, oltype, area, centr; struct line_pnts *Points; struct line_cats *ACats, *BCats, *OCats; struct ilist *AOList, *BOList; /* TODO: support Lists */ Points = Vect_new_line_struct(); ACats = Vect_new_cats_struct(); BCats = Vect_new_cats_struct(); OCats = Vect_new_cats_struct(); AOList = Vect_new_list(); BOList = Vect_new_list(); /* TODO: support all types; at present only point x point, area x point and point x area supported */ if ((atype & GV_LINES) || (btype & GV_LINES)) G_warning(_("Overlay: line/boundary types not supported by AND operator")); if ((atype & GV_AREA) && (btype & GV_AREA)) G_warning(_("Overlay: area x area types not supported by AND operator")); /* TODO: more points in one node in one map */ /* point x point: select all points with identical coordinates in both maps */ if ((atype & GV_POINTS) && (btype & GV_POINTS)) { /* both points and centroids */ G_debug(3, "overlay: AND: point x point"); for (i = 1; i <= Vect_get_num_lines(AMap); i++) { altype = Vect_read_line(AMap, Points, ACats, i); if (!(altype & GV_POINTS)) continue; node = Vect_find_node(BMap, Points->x[0], Points->y[0], Points->z[0], 0, 1); G_debug(3, "overlay: node = %d", node); if (node == 0) continue; Vect_reset_cats(OCats); for (j = 0; j < Vect_get_node_n_lines(BMap, node); j++) { line = Vect_get_node_line(BMap, node, j); bltype = Vect_read_line(BMap, NULL, BCats, line); if (!(bltype & GV_POINTS)) continue; /* Identical points found -> write out */ /* TODO: do something if fields in ACats and BCats are identical */ for (k = 0; k < ACats->n_cats; k++) Vect_cat_set(OCats, ACats->field[k], ACats->cat[k]); for (k = 0; k < BCats->n_cats; k++) Vect_cat_set(OCats, BCats->field[k], BCats->cat[k]); /* TODO: what to do if one type is GV_POINT and second GV_CENTROID */ oltype = altype; Vect_write_line(OMap, oltype, Points, OCats); Vect_list_append(AOList, i); /* add to list of written lines */ Vect_list_append(BOList, line); break; } } } /* TODO: check only labeled areas */ /* point x area: select points from A in areas in B */ if ((atype & GV_POINTS) && (btype & GV_AREA)) { /* both points and centroids */ G_debug(3, "overlay: AND: point x area"); for (i = 1; i <= Vect_get_num_lines(AMap); i++) { altype = Vect_read_line(AMap, Points, ACats, i); if (!(altype & GV_POINTS)) continue; area = Vect_find_area(BMap, Points->x[0], Points->y[0]); if (area == 0) continue; Vect_reset_cats(OCats); /* TODO: do something if fields in ACats and BCats are identical */ for (k = 0; k < ACats->n_cats; k++) Vect_cat_set(OCats, ACats->field[k], ACats->cat[k]); centr = Vect_get_area_centroid(BMap, area); if (centr > 0) { bltype = Vect_read_line(BMap, NULL, BCats, centr); for (k = 0; k < BCats->n_cats; k++) Vect_cat_set(OCats, BCats->field[k], BCats->cat[k]); } /* Check if not yet written */ if (!(Vect_val_in_list(AOList, i))) { Vect_write_line(OMap, altype, Points, OCats); Vect_list_append(AOList, i); } } } /* area x point: select points from B in areas in A */ if ((btype & GV_POINTS) && (atype & GV_AREA)) { /* both points and centroids */ G_debug(3, "overlay: AND: area x point"); for (i = 1; i <= Vect_get_num_lines(BMap); i++) { bltype = Vect_read_line(BMap, Points, BCats, i); if (!(bltype & GV_POINTS)) continue; area = Vect_find_area(AMap, Points->x[0], Points->y[0]); if (area == 0) continue; Vect_reset_cats(OCats); /* TODO: do something if fields in ACats and BCats are identical */ for (k = 0; k < BCats->n_cats; k++) Vect_cat_set(OCats, BCats->field[k], BCats->cat[k]); centr = Vect_get_area_centroid(AMap, area); if (centr > 0) { altype = Vect_read_line(AMap, NULL, ACats, centr); for (k = 0; k < ACats->n_cats; k++) Vect_cat_set(OCats, ACats->field[k], ACats->cat[k]); } /* Check if not yet written */ if (!(Vect_val_in_list(BOList, i))) { Vect_write_line(OMap, bltype, Points, OCats); Vect_list_append(BOList, i); } } } return 0; }
int nodes(struct Map_info *In, struct Map_info *Out, int add_cats, int nfield) { int i, node, nnodes, line, nlines, count, type, add_point; double x, y, z; struct line_pnts *Points, *Pout; struct line_cats *Cats; struct boxlist *List; struct bound_box box; int cat; Points = Vect_new_line_struct(); Pout = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); List = Vect_new_boxlist(0); /* Rewrite all primitives to output file */ cat = 0; while ((type = Vect_read_next_line(In, Points, Cats)) >= 0) { if (type == GV_POINT) { /* Get max cat in input */ int j; for (j = 0; j < Cats->n_cats; j++) { if (Cats->field[j] == nfield && Cats->cat[j] > cat) { cat = Cats->cat[j]; } } } Vect_write_line(Out, type, Points, Cats); } cat++; /* Go through all nodes in old map and write a new point if missing */ nnodes = Vect_get_num_nodes(In); count = 0; for (node = 1; node <= nnodes; node++) { nlines = Vect_get_node_n_lines(In, node); add_point = 0; for (i = 0; i < nlines; i++) { line = abs(Vect_get_node_line(In, node, i)); type = Vect_read_line(In, NULL, NULL, line); if (type & GV_LINES) { add_point = 1; break; } } if (add_point) { Vect_get_node_coor(In, node, &x, &y, &z); box.E = box.W = x; box.N = box.S = y; box.T = box.B = z; Vect_select_lines_by_box(In, &box, GV_POINT, List); add_point = List->n_values == 0; } if (add_point) { /* Write new point */ Vect_reset_line(Pout); Vect_append_point(Pout, x, y, z); Vect_reset_cats(Cats); if (add_cats) { Vect_cat_set(Cats, nfield, cat++); } Vect_write_line(Out, GV_POINT, Pout, Cats); count++; } } Vect_destroy_line_struct(Points); Vect_destroy_line_struct(Pout); Vect_destroy_cats_struct(Cats); Vect_destroy_boxlist(List); return count; }