/** \brief Select features by bbox \param[in] Map vector map \param[in] type feature type \param[in] bbox_opt bounding boxes \param[in,out] List list of selected features \return number of selected lines */ int sel_by_bbox(struct Map_info *Map, int type, double x1, double y1, double x2, double y2, struct ilist *List) { struct bound_box bbox; struct boxlist *List_tmp; List_tmp = Vect_new_boxlist(0); /* bounding box */ bbox.N = y1 < y2 ? y2 : y1; bbox.S = y1 < y2 ? y1 : y2; bbox.W = x1 < x2 ? x1 : x2; bbox.E = x1 < x2 ? x2 : x1; bbox.T = PORT_DOUBLE_MAX; bbox.B = -PORT_DOUBLE_MAX; Vect_select_lines_by_box(Map, &bbox, type, List_tmp); G_debug(1, " %d lines selected (by bbox)", List_tmp->n_values); /* merge lists (only duplicate items) */ merge_lists2(List, List_tmp); Vect_destroy_boxlist(List_tmp); return List->n_values; }
void copy_boxlist_and_destroy( struct boxlist *blist, struct ilist * list ) { Vect_reset_list( list ); for ( int i = 0; i < blist->n_values; i++ ) { Vect_list_append( list, blist->id[i] ); } Vect_destroy_boxlist( blist ); }
int display_label(struct Map_info *Map, int type, struct cat_list *Clist, LATTR *lattr, int chcat) { int ltype; struct line_pnts *Points; struct line_cats *Cats; int ogr_centroids; const struct Format_info *finfo; Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); Vect_rewind(Map); ogr_centroids = FALSE; finfo = Vect_get_finfo(Map); if (Vect_maptype(Map) == GV_FORMAT_OGR || (Vect_maptype(Map) == GV_FORMAT_POSTGIS && finfo->pg.toposchema_name == NULL)) { if (Vect_level(Map) < 2) G_warning(_("Topology level required for drawing centroids " "for OGR layers")); else if (Vect_get_num_primitives(Map, GV_CENTROID) > 0 && type & GV_CENTROID) /* label centroids from topo, don't label boundaries */ ogr_centroids = TRUE; } while (TRUE) { ltype = Vect_read_next_line(Map, Points, Cats); if (ltype == -1) G_fatal_error(_("Unable to read vector map")); else if (ltype == -2) /* EOF */ break; if (!(type & ltype) && !((type & GV_AREA) && (ltype & GV_CENTROID))) continue; /* used for both lines and labels */ if (ogr_centroids && ltype == GV_BOUNDARY) /* do not label boundaries */ continue; process_line(ltype, Points, Cats, lattr, chcat, Clist); } if (ogr_centroids) { /* show label for centroids stored in topo (for OGR layers only) */ int line, nlines; struct bound_box box; struct boxlist *list; list = Vect_new_boxlist(FALSE); /* bboxes not needed */ Vect_get_constraint_box(Map, &box); nlines = Vect_select_lines_by_box(Map, &box, GV_CENTROID, list); G_debug(3, "ncentroids (ogr) = %d", nlines); for (line = 0; line < nlines; line++) { ltype = Vect_read_line(Map, Points, Cats, list->id[line]); process_line(ltype, Points, Cats, lattr, chcat, Clist); } Vect_destroy_boxlist(list); } Vect_destroy_line_struct(Points); Vect_destroy_cats_struct(Cats); return 0; }
int area_area(struct Map_info *In, int *field, struct Map_info *Tmp, struct Map_info *Out, struct field_info *Fi, dbDriver * driver, int operator, int *ofield, ATTRIBUTES * attr, struct ilist *BList, double snap) { int ret, input, line, nlines, area, nareas; int in_area, in_centr, out_cat; struct line_pnts *Points; struct line_cats *Cats; CENTR *Centr; char buf[1000]; dbString stmt; int nmodif; int verbose; verbose = G_verbose(); Points = Vect_new_line_struct(); Cats = Vect_new_cats_struct(); /* optional snap */ if (snap > 0) { int i, j, snapped_lines = 0; struct bound_box box; struct boxlist *boxlist = Vect_new_boxlist(0); struct ilist *reflist = Vect_new_list(); G_message(_("Snapping boundaries with %g ..."), snap); /* snap boundaries in B to boundaries in A, * not modifying boundaries in A */ if (BList->n_values > 1) qsort(BList->value, BList->n_values, sizeof(int), cmp_int); snapped_lines = 0; nlines = BList->n_values; for (i = 0; i < nlines; i++) { line = BList->value[i]; Vect_read_line(Tmp, Points, Cats, line); /* select lines by box */ Vect_get_line_box(Tmp, line, &box); box.E += snap; box.W -= snap; box.N += snap; box.S -= snap; box.T = 0.0; box.B = 0.0; Vect_select_lines_by_box(Tmp, &box, GV_BOUNDARY, boxlist); if (boxlist->n_values > 0) { Vect_reset_list(reflist); for (j = 0; j < boxlist->n_values; j++) { int aline = boxlist->id[j]; if (!bsearch(&aline, BList->value, BList->n_values, sizeof(int), cmp_int)) { G_ilist_add(reflist, aline); } } /* snap bline to alines */ if (Vect_snap_line(Tmp, reflist, Points, snap, 0, NULL, NULL)) { /* rewrite bline*/ Vect_delete_line(Tmp, line); ret = Vect_write_line(Tmp, GV_BOUNDARY, Points, Cats); G_ilist_add(BList, ret); snapped_lines++; G_debug(3, "line %d snapped", line); } } } Vect_destroy_boxlist(boxlist); Vect_destroy_list(reflist); G_verbose_message(n_("%d boundary snapped", "%d boundaries snapped", snapped_lines), snapped_lines); } /* same procedure like for v.in.ogr: * Vect_clean_small_angles_at_nodes() can change the geometry so that new intersections * are created. We must call Vect_break_lines(), Vect_remove_duplicates() * and Vect_clean_small_angles_at_nodes() until no more small dangles are found */ do { G_message(_("Breaking lines...")); Vect_break_lines_list(Tmp, NULL, BList, GV_BOUNDARY, NULL); /* Probably not necessary for LINE x AREA */ G_message(_("Removing duplicates...")); Vect_remove_duplicates(Tmp, GV_BOUNDARY, NULL); G_message(_("Cleaning boundaries at nodes...")); nmodif = Vect_clean_small_angles_at_nodes(Tmp, GV_BOUNDARY, NULL); } while (nmodif > 0); /* ?: May be result of Vect_break_lines() + Vect_remove_duplicates() any dangle or bridge? * In that case, calls to Vect_remove_dangles() and Vect_remove_bridges() would be also necessary */ G_set_verbose(0); /* should be fast, be silent */ Vect_build_partial(Tmp, GV_BUILD_AREAS); G_set_verbose(verbose); nlines = Vect_get_num_lines(Tmp); ret = 0; for (line = 1; line <= nlines; line++) { if (!Vect_line_alive(Tmp, line)) continue; if (Vect_get_line_type(Tmp, line) == GV_BOUNDARY) { int left, rite; Vect_get_line_areas(Tmp, line, &left, &rite); if (left == 0 || rite == 0) { /* invalid boundary */ ret = 1; break; } } } if (ret) { Vect_remove_dangles(Tmp, GV_BOUNDARY, -1, NULL); Vect_remove_bridges(Tmp, NULL, NULL, NULL); } G_set_verbose(0); Vect_build_partial(Tmp, GV_BUILD_NONE); Vect_build_partial(Tmp, GV_BUILD_BASE); G_set_verbose(verbose); G_message(_("Merging lines...")); Vect_merge_lines(Tmp, GV_BOUNDARY, NULL, NULL); /* Attach islands */ G_message(_("Attaching islands...")); /* can take some time, show messages */ Vect_build_partial(Tmp, GV_BUILD_ATTACH_ISLES); /* Calculate new centroids for all areas */ nareas = Vect_get_num_areas(Tmp); Centr = (CENTR *) G_malloc((nareas + 1) * sizeof(CENTR)); /* index from 1 ! */ for (area = 1; area <= nareas; area++) { ret = Vect_get_point_in_area(Tmp, area, &(Centr[area].x), &(Centr[area].y)); if (ret < 0) { G_warning(_("Cannot calculate area centroid")); Centr[area].valid = 0; } else { Centr[area].valid = 1; } } /* Query input maps */ for (input = 0; input < 2; input++) { G_message(_("Querying vector map <%s>..."), Vect_get_full_name(&(In[input]))); for (area = 1; area <= nareas; area++) { Centr[area].cat[input] = Vect_new_cats_struct(); G_percent(area, nareas, 1); in_area = Vect_find_area(&(In[input]), Centr[area].x, Centr[area].y); if (in_area > 0) { in_centr = Vect_get_area_centroid(&(In[input]), in_area); if (in_centr > 0) { int i; Vect_read_line(&(In[input]), NULL, Cats, in_centr); /* Add all cats with original field number */ for (i = 0; i < Cats->n_cats; i++) { if (Cats->field[i] == field[input]) { ATTR *at; Vect_cat_set(Centr[area].cat[input], ofield[input + 1], Cats->cat[i]); /* Mark as used */ at = find_attr(&(attr[input]), Cats->cat[i]); if (!at) G_fatal_error(_("Attribute not found")); at->used = 1; } } } } } } G_message(_("Writing centroids...")); db_init_string(&stmt); out_cat = 1; for (area = 1; area <= nareas; area++) { int i; G_percent(area, nareas, 1); /* check the condition */ switch (operator) { case OP_AND: if (! (Centr[area].cat[0]->n_cats > 0 && Centr[area].cat[1]->n_cats > 0)) continue; break; case OP_OR: if (! (Centr[area].cat[0]->n_cats > 0 || Centr[area].cat[1]->n_cats > 0)) continue; break; case OP_NOT: if (! (Centr[area].cat[0]->n_cats > 0 && !(Centr[area].cat[1]->n_cats > 0))) continue; break; case OP_XOR: if ((Centr[area].cat[0]->n_cats > 0 && Centr[area].cat[1]->n_cats > 0) || (!(Centr[area].cat[0]->n_cats > 0) && !(Centr[area].cat[1]->n_cats > 0))) continue; break; } Vect_reset_line(Points); Vect_reset_cats(Cats); Vect_append_point(Points, Centr[area].x, Centr[area].y, 0.0); if (ofield[0] > 0) { /* Add new cats for all combinations of input cats (-1 in cycle for null) */ for (i = -1; i < Centr[area].cat[0]->n_cats; i++) { int j; if (i == -1 && Centr[area].cat[0]->n_cats > 0) continue; /* no need to make null */ for (j = -1; j < Centr[area].cat[1]->n_cats; j++) { if (j == -1 && Centr[area].cat[1]->n_cats > 0) continue; /* no need to make null */ if (ofield[0] > 0) Vect_cat_set(Cats, ofield[0], out_cat); /* attributes */ if (driver) { ATTR *at; sprintf(buf, "insert into %s values ( %d", Fi->table, out_cat); db_set_string(&stmt, buf); /* cata */ if (i >= 0) { if (attr[0].columns) { at = find_attr(&(attr[0]), Centr[area].cat[0]->cat[i]); if (!at) G_fatal_error(_("Attribute not found")); if (at->values) db_append_string(&stmt, at->values); else db_append_string(&stmt, attr[0].null_values); } else { sprintf(buf, ", %d", Centr[area].cat[0]->cat[i]); db_append_string(&stmt, buf); } } else { if (attr[0].columns) { db_append_string(&stmt, attr[0].null_values); } else { sprintf(buf, ", null"); db_append_string(&stmt, buf); } } /* catb */ if (j >= 0) { if (attr[1].columns) { at = find_attr(&(attr[1]), Centr[area].cat[1]->cat[j]); if (!at) G_fatal_error(_("Attribute not found")); if (at->values) db_append_string(&stmt, at->values); else db_append_string(&stmt, attr[1].null_values); } else { sprintf(buf, ", %d", Centr[area].cat[1]->cat[j]); db_append_string(&stmt, buf); } } else { if (attr[1].columns) { db_append_string(&stmt, attr[1].null_values); } else { sprintf(buf, ", null"); db_append_string(&stmt, buf); } } db_append_string(&stmt, " )"); G_debug(3, "%s", db_get_string(&stmt)); if (db_execute_immediate(driver, &stmt) != DB_OK) G_warning(_("Unable to insert new record: '%s'"), db_get_string(&stmt)); } out_cat++; } } } /* Add all cats from input vectors */ if (ofield[1] > 0 && field[0] > 0) { for (i = 0; i < Centr[area].cat[0]->n_cats; i++) { if (Centr[area].cat[0]->field[i] == field[0]) Vect_cat_set(Cats, ofield[1], Centr[area].cat[0]->cat[i]); } } if (ofield[2] > 0 && field[1] > 0 && ofield[1] != ofield[2]) { for (i = 0; i < Centr[area].cat[1]->n_cats; i++) { if (Centr[area].cat[1]->field[i] == field[1]) Vect_cat_set(Cats, ofield[2], Centr[area].cat[1]->cat[i]); } } Vect_write_line(Tmp, GV_CENTROID, Points, Cats); Vect_write_line(Out, GV_CENTROID, Points, Cats); } G_set_verbose(0); /* should be fast, be silent */ Vect_build_partial(Tmp, GV_BUILD_CENTROIDS); G_set_verbose(verbose); /* Copy valid boundaries to final output */ nlines = Vect_get_num_lines(Tmp); for (line = 1; line <= nlines; line++) { int i, ltype, side[2], centr[2]; G_percent(line, nlines, 1); /* must be before any continue */ if (!Vect_line_alive(Tmp, line)) continue; ltype = Vect_read_line(Tmp, Points, Cats, line); if (!(ltype & GV_BOUNDARY)) continue; Vect_get_line_areas(Tmp, line, &side[0], &side[1]); for (i = 0; i < 2; i++) { if (side[i] == 0) { /* This should not happen ! */ centr[i] = 0; continue; } if (side[i] > 0) { area = side[i]; } else { /* island */ area = Vect_get_isle_area(Tmp, abs(side[i])); } if (area > 0) centr[i] = Vect_get_area_centroid(Tmp, area); else centr[i] = 0; } if (centr[0] || centr[1]) Vect_write_line(Out, GV_BOUNDARY, 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; }