/*! \brief Writes point Writes GV_POINT to Out at the position of the node in <em>In</em>. \param In pointer to Map_info structure (input vector map) \param[in,out] Out pointer to Map_info structure (output vector map) \param node node id \param Cats pointer to line_cats structures */ void NetA_add_point_on_node(struct Map_info *In, struct Map_info *Out, int node, struct line_cats *Cats) { static struct line_pnts *Points; double x, y, z; Points = Vect_new_line_struct(); Vect_get_node_coor(In, node, &x, &y, &z); Vect_reset_line(Points); Vect_append_point(Points, x, y, z); Vect_write_line(Out, GV_POINT, Points, Cats); Vect_destroy_line_struct(Points); }
void edit_line_phase2(struct edit_line *el, double x, double y) { int node1, node2; double nodex, nodey, nodez, dist; el->phase = 2; el->Points = Vect_new_line_struct(); el->Cats = Vect_new_cats_struct(); el->line_type = Vect_read_line(&Map, el->Points, el->Cats, el->line); el->reversed = 0; /* Find out the node nearest to the line */ Vect_get_line_nodes(&Map, el->line, &node1, &node2); Vect_get_node_coor(&Map, node2, &nodex, &nodey, &nodez); dist = (x - nodex) * (x - nodex) + (y - nodey) * (y - nodey); Vect_get_node_coor(&Map, node1, &nodex, &nodey, &nodez); if ((x - nodex) * (x - nodex) + (y - nodey) * (y - nodey) < dist) { /* The first node is the nearest => reverse the line and remember * doing so. */ Vect_line_reverse(el->Points); el->reversed = 1; } display_node(node1, SYMB_BACKGROUND, 1); display_node(node2, SYMB_BACKGROUND, 1); i_prompt_buttons(_("New Point"), _("Undo Last Point"), _("Close line")); set_location(D_u_to_d_col(el->Points->x[el->Points->n_points - 1]), D_u_to_d_row(el->Points->y[el->Points->n_points - 1]) ); set_mode(MOUSE_LINE); }
/* Snap to node */ int snap(double *x, double *y) { int node; double thresh; G_debug(2, "snap(): x = %f, y = %f", *x, *y); thresh = get_thresh(); node = Vect_find_node(&Map, *x, *y, 0, thresh, 0); if (node > 0) Vect_get_node_coor(&Map, node, x, y, NULL); G_debug(2, "node = %d x = %f, y = %f", node, *x, *y); return node; }
/*! \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); } }
void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, int type ) { unsigned char *wkb; int wkbsize; // TODO int may be 64 bits (memcpy) if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) || mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) /* points or lines */ { if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { double x, y, z; Vect_get_node_coor( mSource->mMap, id, &x, &y, &z ); Vect_reset_line( mPoints ); Vect_append_point( mPoints, x, y, z ); } else { Vect_read_line( mSource->mMap, mPoints, 0, id ); } int npoints = mPoints->n_points; if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { wkbsize = 1 + 4 + 2 * 8; } else if ( type & GV_POINTS ) { wkbsize = 1 + 4 + 2 * 8; } else if ( type & GV_LINES ) { wkbsize = 1 + 4 + 4 + npoints * 2 * 8; } else // GV_FACE { wkbsize = 1 + 4 + 4 + 4 + npoints * 2 * 8; } wkb = new unsigned char[wkbsize]; unsigned char *wkbp = wkb; wkbp[0] = ( unsigned char ) QgsApplication::endian(); wkbp += 1; /* WKB type */ memcpy( wkbp, &mSource->mQgisType, 4 ); wkbp += 4; /* Number of rings */ if ( type & GV_FACE ) { int nrings = 1; memcpy( wkbp, &nrings, 4 ); wkbp += 4; } /* number of points */ if ( type & ( GV_LINES | GV_FACE ) ) { QgsDebugMsg( QString( "set npoints = %1" ).arg( npoints ) ); memcpy( wkbp, &npoints, 4 ); wkbp += 4; } for ( int i = 0; i < npoints; i++ ) { memcpy( wkbp, &( mPoints->x[i] ), 8 ); memcpy( wkbp + 8, &( mPoints->y[i] ), 8 ); wkbp += 16; } } else // GV_AREA { Vect_get_area_points( mSource->mMap, id, mPoints ); int npoints = mPoints->n_points; wkbsize = 1 + 4 + 4 + 4 + npoints * 2 * 8; // size without islands wkb = new unsigned char[wkbsize]; wkb[0] = ( unsigned char ) QgsApplication::endian(); int offset = 1; /* WKB type */ memcpy( wkb + offset, &mSource->mQgisType, 4 ); offset += 4; /* Number of rings */ int nisles = Vect_get_area_num_isles( mSource->mMap, id ); int nrings = 1 + nisles; memcpy( wkb + offset, &nrings, 4 ); offset += 4; /* Outer ring */ memcpy( wkb + offset, &npoints, 4 ); offset += 4; for ( int i = 0; i < npoints; i++ ) { memcpy( wkb + offset, &( mPoints->x[i] ), 8 ); memcpy( wkb + offset + 8, &( mPoints->y[i] ), 8 ); offset += 16; } /* Isles */ for ( int i = 0; i < nisles; i++ ) { Vect_get_isle_points( mSource->mMap, Vect_get_area_isle( mSource->mMap, id, i ), mPoints ); npoints = mPoints->n_points; // add space wkbsize += 4 + npoints * 2 * 8; wkb = ( unsigned char * ) realloc( wkb, wkbsize ); memcpy( wkb + offset, &npoints, 4 ); offset += 4; for ( int i = 0; i < npoints; i++ ) { memcpy( wkb + offset, &( mPoints->x[i] ), 8 ); memcpy( wkb + offset + 8, &( mPoints->y[i] ), 8 ); offset += 16; } } } feature.setGeometryAndOwnership( wkb, wkbsize ); }
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; }
/* Same as path() but get start/stop from the command line (for non-interactive use) Hamish Bowman March 2007 */ int coor_path(struct Map_info *Map, const struct color_rgb *hcolor, int be_bold, double start_x, double start_y, double end_x, double end_y) { int ret; double nx, ny, fx, fy, tx, ty, msize, maxdist; struct line_pnts *Points; int start_node, end_node; double fdist, tdist, cost; Points = Vect_new_line_struct(); msize = 10 * (D_d_to_u_col(2.0) - D_d_to_u_col(1.0)); /* do it better */ G_debug(1, "msize = %f\n", msize); /* x1 = D_d_to_u_col ((double)(screen_x-WDTH)); y1 = D_d_to_u_row ((double)(screen_y-WDTH)); x2 = D_d_to_u_col ((double)(screen_x+WDTH)); y2 = D_d_to_u_row ((double)(screen_y+WDTH)); x1 = fabs ( x2 - x1 ); y1 = fabs ( y2 - y1 ); if ( x1 > y1 ) maxdist = x1; else maxdist = y1; */ /** maxdist = 10 pixels on the display (WDTH*2); ? ** ie related to zoom level ?? just use msize ?? **/ maxdist = msize; G_debug(1, "Maximum distance in map units = %f\n", maxdist); /* Vect_find_node(): find number of nearest node, 0 if not found */ start_node = Vect_find_node(Map, start_x, start_y, 0.0, maxdist, 0); if (start_node > 0) { Vect_get_node_coor(Map, start_node, &nx, &ny, NULL); fprintf(stderr, _("Node %d: %f %f\n"), start_node, nx, ny); } if (start_node > 0) { fx = nx; fy = ny; } else { fx = start_x; fy = start_y; } D_RGB_color(hcolor->r, hcolor->g, hcolor->b); D_plot_icon(fx, fy, G_ICON_BOX, 0.0, msize); end_node = Vect_find_node(Map, end_x, end_y, 0.0, maxdist, 0); if (end_node > 0) { Vect_get_node_coor(Map, end_node, &nx, &ny, NULL); fprintf(stderr, _("Node %d: %f %f\n"), end_node, nx, ny); } if (end_node > 0) { tx = nx; ty = ny; } else { tx = end_x; ty = end_y; } D_RGB_color(hcolor->r, hcolor->g, hcolor->b); D_plot_icon(tx, ty, G_ICON_CROSS, 0.0, msize); G_debug(2, "find path %f %f -> %f %f", fx, fy, tx, ty); ret = Vect_net_shortest_path_coor(Map, fx, fy, 0.0, tx, ty, 0.0, 5 * maxdist, 5 * maxdist, &cost, Points, NULL, NULL, NULL, &fdist, &tdist); if (ret == 0) { fprintf(stdout, _("Destination unreachable\n")); } else { fprintf(stdout, _("Costs on the network = %f\n"), cost); fprintf(stdout, _(" Distance to the network = %f, " "distance from the network = %f\n\n"), fdist, tdist); display(Map, Points, hcolor, 1, 1, be_bold); } return 0; }
/*! \brief Connect lines in given threshold \code \ \ id1 \ -> \ \ id2 --------- -----+--- \endcode If two lines are selected and <i>thresh</i> is -1, no limit is applied. \param Map pointer to Map_info \param List list of selected lines \param thresh threshold value \return number of modified lines \return -1 on error */ int Vedit_connect_lines(struct Map_info *Map, struct ilist *List, double thresh) { int nlines_modified, connected; int i, j, node[2], n_nodes; int line, found; double x, y, z; struct ilist *List_exclude, *List_found; nlines_modified = 0; List_exclude = Vect_new_list(); List_found = Vect_new_list(); n_nodes = 2; /* collect lines to be modified */ for (i = 0; i < List->n_values; i++) { line = List->value[i]; if (!Vect_line_alive(Map, line)) continue; if (Vect_get_line_type(Map, line) & GV_POINTS) continue; node[0] = node[1] = -1; Vect_get_line_nodes(Map, line, &(node[0]), &(node[1])); if (node[0] < 0 || node[1] < 0) continue; connected = 0; Vect_reset_list(List_exclude); Vect_list_append(List_exclude, line); for (j = 0; j < n_nodes && !connected; j++) { /* for each line node find lines in threshold */ Vect_get_node_coor(Map, node[j], &x, &y, &z); do { /* find first nearest line */ found = Vect_find_line_list(Map, x, y, z, GV_LINES, thresh, WITHOUT_Z, List_exclude, List_found); if (found > 0 && Vect_line_alive(Map, found)) { /* try to connect lines (given node) */ G_debug(3, "Vedit_connect_lines(): lines=%d,%d", line, found); if (connect_lines(Map, !j, line, found, thresh, List)) { G_debug(3, "Vedit_connect_lines(): lines=%d,%d -> connected", line, found); nlines_modified += 2; connected = 1; } } Vect_list_append(List_exclude, found); } while(List_found->n_values > 0 && !connected); } } Vect_destroy_list(List_exclude); Vect_destroy_list(List_found); return nlines_modified; }
int display_topo(struct Map_info *Map, int type, LATTR *lattr, double dsize) { int ltype, num, el; double msize; struct line_pnts *Points; struct line_cats *Cats; char text[50]; LATTR lattr2 = *lattr; if (Vect_level(Map) < 2) { G_warning(_("Unable to display topology, not available." "Please try to rebuild topology using " "v.build or v.build.all.")); return 1; } msize = dsize * (D_d_to_u_col(2.0) - D_d_to_u_col(1.0)); /* do it better */ lattr2.xref = lattr->xref == LRIGHT ? LLEFT : LRIGHT; G_debug(1, "display topo:"); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); D_RGB_color(lattr->color.R, lattr->color.G, lattr->color.B); D_text_size(lattr->size, lattr->size); if (lattr->font) D_font(lattr->font); if (lattr->enc) D_encoding(lattr->enc); Vect_rewind(Map); num = Vect_get_num_lines(Map); G_debug(1, "n_lines = %d", num); /* Lines */ for (el = 1; el <= num; el++) { if (!Vect_line_alive(Map, el)) continue; ltype = Vect_read_line(Map, Points, Cats, el); G_debug(3, "ltype = %d", ltype); switch (ltype) { case -1: G_fatal_error(_("Unable to read vector map")); case -2: /* EOF */ return 0; } if (!(type & ltype)) continue; /* used for both lines and labels */ sprintf(text, "%d", el); show_label_line(Points, ltype, lattr, text); } num = Vect_get_num_nodes(Map); G_debug(1, "n_nodes = %d", num); /* Nodes */ for (el = 1; el <= num; el++) { double X, Y; if (!Vect_node_alive(Map, el)) continue; Vect_get_node_coor(Map, el, &X, &Y, NULL); G_debug(3, "node = %d", el); sprintf(text, "n%d", el); show_label(&X, &Y, &lattr2, text); D_plot_icon(X, Y, G_ICON_BOX, 0, msize); } Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); return 0; }
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, 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[]) { struct Map_info In, Out; static struct line_pnts *Points; struct line_cats *Cats; struct GModule *module; /* GRASS module for parsing arguments */ struct Option *map_in, *map_out; struct Option *afield_opt, *nfield_opt, *abcol, *afcol, *ncol, *method_opt; int with_z; int afield, nfield, mask_type; dglGraph_s *graph; int i, bridges, articulations; struct ilist *bridge_list, *articulation_list; /* 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(_("network")); G_add_keyword(_("articulation points")); module->description = _("Computes bridges and articulation points in the network."); /* Define the different options as defined in gis.h */ map_in = G_define_standard_option(G_OPT_V_INPUT); map_out = G_define_standard_option(G_OPT_V_OUTPUT); afield_opt = G_define_standard_option(G_OPT_V_FIELD); afield_opt->key = "alayer"; afield_opt->answer = "1"; afield_opt->description = _("Arc layer"); afield_opt->guisection = _("Cost"); nfield_opt = G_define_standard_option(G_OPT_V_FIELD); nfield_opt->key = "nlayer"; nfield_opt->answer = "2"; nfield_opt->description = _("Node layer"); nfield_opt->guisection = _("Cost"); afcol = G_define_standard_option(G_OPT_DB_COLUMN); afcol->key = "afcolumn"; afcol->required = NO; afcol->description = _("Arc forward/both direction(s) cost column (number)"); afcol->guisection = _("Cost"); abcol = G_define_standard_option(G_OPT_DB_COLUMN); abcol->key = "abcolumn"; abcol->required = NO; abcol->description = _("Arc backward direction cost column (number)"); abcol->guisection = _("Cost"); ncol = G_define_option(); ncol->key = "ncolumn"; ncol->type = TYPE_STRING; ncol->required = NO; ncol->description = _("Node cost column (number)"); ncol->guisection = _("Cost"); 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 = "bridge,articulation"; method_opt->descriptions = _("bridge;Finds bridges;" "articulation;Finds articulation points;"); method_opt->description = _("Feature type"); /* options and flags parser */ if (G_parser(argc, argv)) exit(EXIT_FAILURE); /* TODO: make an option for this */ mask_type = GV_LINE | GV_BOUNDARY; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Vect_check_input_output_name(map_in->answer, map_out->answer, GV_FATAL_EXIT); Vect_set_open_level(2); if (1 > Vect_open_old(&In, map_in->answer, "")) G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer); 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); } /* parse filter option and select appropriate lines */ afield = Vect_get_field_number(&In, afield_opt->answer); nfield = Vect_get_field_number(&In, nfield_opt->answer); Vect_net_build_graph(&In, mask_type, afield, nfield, afcol->answer, abcol->answer, ncol->answer, 0, 0); graph = &(In.graph); Vect_copy_head_data(&In, &Out); Vect_hist_copy(&In, &Out); Vect_hist_command(&Out); if (method_opt->answer[0] == 'b') { bridge_list = Vect_new_list(); bridges = NetA_compute_bridges(graph, bridge_list); G_debug(3, "Bridges: %d", bridges); for (i = 0; i < bridges; i++) { int type = Vect_read_line(&In, Points, Cats, abs(bridge_list->value[i])); Vect_write_line(&Out, type, Points, Cats); } Vect_destroy_list(bridge_list); } else { articulation_list = Vect_new_list(); articulations = NetA_articulation_points(graph, articulation_list); G_debug(3, "Articulation points: %d", articulations); for (i = 0; i < articulations; i++) { double x, y, z; Vect_get_node_coor(&In, articulation_list->value[i], &x, &y, &z); Vect_reset_line(Points); Vect_append_point(Points, x, y, z); Vect_write_line(&Out, GV_POINT, Points, Cats); } Vect_destroy_list(articulation_list); } Vect_build(&Out); Vect_close(&In); 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; }
int Vect_break_lines_list(struct Map_info *Map, struct ilist *List_break, struct ilist *List_ref, int type, struct Map_info *Err) { struct line_pnts *APoints, *BPoints, *Points; struct line_pnts **AXLines, **BXLines; struct line_cats *ACats, *BCats, *Cats; int j, k, l, ret, atype, btype, aline, bline, found, iline, nlines; int naxlines, nbxlines, nx; double *xx = NULL, *yx = NULL, *zx = NULL; struct bound_box ABox, BBox; struct boxlist *List; int nbreaks; int touch1_n = 0, touch1_s = 0, touch1_e = 0, touch1_w = 0; /* other vertices except node1 touching box */ int touch2_n = 0, touch2_s = 0, touch2_e = 0, touch2_w = 0; /* other vertices except node2 touching box */ int is3d; int node, anode1, anode2, bnode1, bnode2; double nodex, nodey; APoints = Vect_new_line_struct(); BPoints = Vect_new_line_struct(); Points = Vect_new_line_struct(); ACats = Vect_new_cats_struct(); BCats = Vect_new_cats_struct(); Cats = Vect_new_cats_struct(); List = Vect_new_boxlist(1); is3d = Vect_is_3d(Map); if (List_break) { nlines = List_break->n_values; } else { nlines = Vect_get_num_lines(Map); } G_debug(3, "nlines = %d", nlines); /* TODO: It seems that lines/boundaries are not broken at intersections * with points/centroids. Check if true, if yes, skip GV_POINTS */ /* To find intersection of two lines (Vect_line_intersection) is quite slow. * Fortunately usual lines/boundaries in GIS often forms a network where lines * are connected by end points, and touch by MBR. This function checks and occasionaly * skips such cases. This is currently done for 2D only */ /* Go through all lines in vector, for each select lines which overlap MBR of * this line exclude those connected by one endpoint (see above) * and try to intersect, if lines intersect write new lines at the end of * the file, and process next line (remaining lines overlapping box are skipped) */ nbreaks = 0; for (iline = 0; iline < nlines; iline++) { G_percent(iline, nlines, 1); if (List_break) { aline = List_break->value[iline]; } else { aline = iline + 1; } if (List_ref && !Vect_val_in_list(List_ref, aline)) continue; G_debug(3, "aline = %d", aline); if (!Vect_line_alive(Map, aline)) continue; atype = Vect_read_line(Map, APoints, ACats, aline); if (!(atype & type)) continue; Vect_line_box(APoints, &ABox); /* Find which sides of the box are touched by intermediate (non-end) points of line */ if (!is3d) { touch1_n = touch1_s = touch1_e = touch1_w = 0; for (j = 1; j < APoints->n_points; j++) { if (APoints->y[j] == ABox.N) touch1_n = 1; if (APoints->y[j] == ABox.S) touch1_s = 1; if (APoints->x[j] == ABox.E) touch1_e = 1; if (APoints->x[j] == ABox.W) touch1_w = 1; } G_debug(3, "touch1: n = %d s = %d e = %d w = %d", touch1_n, touch1_s, touch1_e, touch1_w); touch2_n = touch2_s = touch2_e = touch2_w = 0; for (j = 0; j < APoints->n_points - 1; j++) { if (APoints->y[j] == ABox.N) touch2_n = 1; if (APoints->y[j] == ABox.S) touch2_s = 1; if (APoints->x[j] == ABox.E) touch2_e = 1; if (APoints->x[j] == ABox.W) touch2_w = 1; } G_debug(3, "touch2: n = %d s = %d e = %d w = %d", touch2_n, touch2_s, touch2_e, touch2_w); } Vect_select_lines_by_box(Map, &ABox, type, List); G_debug(3, " %d lines selected by box", List->n_values); for (j = 0; j < List->n_values; j++) { bline = List->id[j]; if (List_break && !Vect_val_in_list(List_break, bline)) { continue; } G_debug(3, " j = %d bline = %d", j, bline); btype = Vect_read_line(Map, BPoints, BCats, bline); /* Check if thouch by end node only */ if (!is3d) { Vect_get_line_nodes(Map, aline, &anode1, &anode2); Vect_get_line_nodes(Map, bline, &bnode1, &bnode2); BBox = List->box[j]; if (anode1 == bnode1 || anode1 == bnode2) node = anode1; else if (anode2 == bnode1 || anode2 == bnode2) node = anode2; else node = 0; if (node) { Vect_get_node_coor(Map, node, &nodex, &nodey, NULL); if ((node == anode1 && nodey == ABox.N && !touch1_n && nodey == BBox.S) || (node == anode2 && nodey == ABox.N && !touch2_n && nodey == BBox.S) || (node == anode1 && nodey == ABox.S && !touch1_s && nodey == BBox.N) || (node == anode2 && nodey == ABox.S && !touch2_s && nodey == BBox.N) || (node == anode1 && nodex == ABox.E && !touch1_e && nodex == BBox.W) || (node == anode2 && nodex == ABox.E && !touch2_e && nodex == BBox.W) || (node == anode1 && nodex == ABox.W && !touch1_w && nodex == BBox.E) || (node == anode2 && nodex == ABox.W && !touch2_w && nodex == BBox.E)) { G_debug(3, "lines %d and %d touching by end nodes only -> no intersection", aline, bline); continue; } } } AXLines = NULL; BXLines = NULL; Vect_line_intersection(APoints, BPoints, &AXLines, &BXLines, &naxlines, &nbxlines, 0); G_debug(3, " naxlines = %d nbxlines = %d", naxlines, nbxlines); /* This part handles a special case when aline == bline, no other intersection was found * and the line is forming collapsed loop, for example 0,0;1,0;0,0 should be broken at 1,0. * ---> */ if (aline == bline && naxlines == 0 && nbxlines == 0 && APoints->n_points >= 3) { int centre; int i; G_debug(3, " Check collapsed loop"); if (APoints->n_points % 2) { /* odd number of vertices */ centre = APoints->n_points / 2; /* index of centre */ if (APoints->x[centre - 1] == APoints->x[centre + 1] && APoints->y[centre - 1] == APoints->y[centre + 1] && APoints->z[centre - 1] == APoints->z[centre + 1]) { /* -> break */ AXLines = (struct line_pnts **)G_malloc(2 * sizeof(struct line_pnts *)); AXLines[0] = Vect_new_line_struct(); AXLines[1] = Vect_new_line_struct(); for (i = 0; i <= centre; i++) Vect_append_point(AXLines[0], APoints->x[i], APoints->y[i], APoints->z[i]); for (i = centre; i < APoints->n_points; i++) Vect_append_point(AXLines[1], APoints->x[i], APoints->y[i], APoints->z[i]); naxlines = 2; } } } /* <--- */ if (Err) { /* array for intersections (more than needed */ xx = (double *)G_malloc((naxlines + nbxlines) * sizeof(double)); yx = (double *)G_malloc((naxlines + nbxlines) * sizeof(double)); zx = (double *)G_malloc((naxlines + nbxlines) * sizeof(double)); } nx = 0; /* number of intersections to be written to Err */ if (naxlines > 0) { /* intersection -> write out */ Vect_delete_line(Map, aline); for (k = 0; k < naxlines; k++) { /* Write new line segments */ /* line may collapse, don't write zero length lines */ Vect_line_prune(AXLines[k]); if ((atype & GV_POINTS) || AXLines[k]->n_points > 1) { ret = Vect_write_line(Map, atype, AXLines[k], ACats); if (List_ref) { Vect_list_append(List_ref, ret); } G_debug(3, "Line %d written, npoints = %d", ret, AXLines[k]->n_points); if (List_break) { Vect_list_append(List_break, ret); } } /* Write intersection points */ if (Err) { if (k > 0) { xx[nx] = AXLines[k]->x[0]; yx[nx] = AXLines[k]->y[0]; zx[nx] = AXLines[k]->z[0]; nx++; } } Vect_destroy_line_struct(AXLines[k]); } nbreaks += naxlines - 1; } if (AXLines) G_free(AXLines); if (nbxlines > 0) { if (aline != bline) { /* Self intersection, do not write twice, TODO: is it OK? */ Vect_delete_line(Map, bline); for (k = 0; k < nbxlines; k++) { /* Write new line segments */ /* line may collapse, don't write zero length lines */ Vect_line_prune(BXLines[k]); if ((btype & GV_POINTS) || BXLines[k]->n_points > 1) { ret = Vect_write_line(Map, btype, BXLines[k], BCats); G_debug(5, "Line %d written", ret); if (List_break) { Vect_list_append(List_break, ret); } } /* Write intersection points */ if (Err) { if (k > 0) { found = 0; for (l = 0; l < nx; l++) { if (xx[l] == BXLines[k]->x[0] && yx[l] == BXLines[k]->y[0] && zx[l] == BXLines[k]->z[0]) { found = 1; break; } } if (!found) { xx[nx] = BXLines[k]->x[0]; yx[nx] = BXLines[k]->y[0]; zx[nx] = BXLines[k]->z[0]; nx++; } } } Vect_destroy_line_struct(BXLines[k]); } nbreaks += nbxlines - 1; } else { for (k = 0; k < nbxlines; k++) Vect_destroy_line_struct(BXLines[k]); } } if (BXLines) G_free(BXLines); if (Err) { for (l = 0; l < nx; l++) { /* Write out errors */ Vect_reset_line(Points); Vect_append_point(Points, xx[l], yx[l], zx[l]); ret = Vect_write_line(Err, GV_POINT, Points, Cats); } G_free(xx); G_free(yx); G_free(zx); } if (naxlines > 0) break; /* first line was broken and deleted -> take the next one */ } if (List_break) { nlines = List_break->n_values; } else { nlines = Vect_get_num_lines(Map); } G_debug(3, "nlines = %d", nlines); } /* for each line */ G_percent(nlines, nlines, 1); /* finish it */ G_verbose_message(_("Intersections: %d"), nbreaks); Vect_destroy_line_struct(APoints); Vect_destroy_line_struct(BPoints); Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(ACats); Vect_destroy_cats_struct(BCats); Vect_destroy_cats_struct(Cats); Vect_destroy_boxlist(List); return nbreaks; }
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; }