24 #include <grass/kdtree.h>
46 static int sort_new(
const void *pa,
const void *pb)
51 return (p1->along < p2->along ? -1 : (p1->along > p2->along));
63 double x, y, z, along;
67 static int sort_new2(
const void *pa,
const void *pb)
69 NEW2 *p1 = (NEW2 *)pa;
70 NEW2 *p2 = (NEW2 *)pb;
72 return (p1->along < p2->along ? -1 : (p1->along > p2->along));
92 static int find_item_box(
int id,
const struct RTree_Rect *rect,
void *
list)
110 static int add_item_box(
int id,
const struct RTree_Rect *rect,
void *
list)
126 static void Vect_snap_lines_list_rtree(
struct Map_info *,
const struct ilist *,
129 static void Vect_snap_lines_list_kdtree(
struct Map_info *,
const struct ilist *,
170 double thresh,
struct Map_info *Err)
172 if (getenv(
"GRASS_VECTOR_LOWMEM"))
173 Vect_snap_lines_list_rtree(Map, List_lines, thresh, Err);
175 Vect_snap_lines_list_kdtree(Map, List_lines, thresh, Err);
178 static void Vect_snap_lines_list_kdtree(
struct Map_info *Map,
179 const struct ilist *List_lines,
180 double thresh,
struct Map_info *Err)
184 int line, ltype, line_idx;
188 int nsnapped, ncreated;
190 int apoints, npoints;
201 int *kduid, kd_found;
213 thresh2 = thresh * thresh;
222 for (line_idx = 0; line_idx < List_lines->
n_values; line_idx++) {
227 line = List_lines->
value[line_idx];
235 for (v = 0; v < Points->
n_points; v++) {
237 G_debug(3,
" vertex v = %d", v);
245 if ((point - 1) == apoints) {
248 (XPNT *)
G_realloc(XPnts, (apoints + 1) *
sizeof(XPNT));
250 XPnts[point].x = Points->
x[v];
251 XPnts[point].y = Points->
y[v];
252 XPnts[point].anchor = -1;
266 for (point = 1; point <= npoints; point++) {
271 G_debug(3,
" point = %d", point);
273 if (XPnts[point].anchor >= 0)
276 XPnts[point].anchor = 0;
279 c[0] = XPnts[point].x;
280 c[1] = XPnts[point].y;
283 kd_found =
kdtree_dnn(KDTree, c, &kduid, &kdd, thresh, &point);
284 G_debug(4,
" %d points in threshold box", kd_found);
286 for (i = 0; i < kd_found; i++) {
288 double dx, dy, dist2;
294 dx = XPnts[pointb].x - XPnts[point].x;
295 dy = XPnts[pointb].y - XPnts[point].y;
296 dist2 = dx * dx + dy * dy;
302 if (XPnts[pointb].anchor == -1) {
303 XPnts[pointb].anchor = point;
305 else if (XPnts[pointb].anchor >
309 dx = XPnts[XPnts[pointb].anchor].x - XPnts[pointb].x;
310 dy = XPnts[XPnts[pointb].anchor].y - XPnts[pointb].y;
311 dist2_a = dx * dx + dy * dy;
314 if (dist2 < dist2_a) {
315 XPnts[pointb].anchor = point;
330 nsnapped = ncreated = 0;
334 for (line_idx = 0; line_idx < List_lines->
n_values; line_idx++) {
335 int v, spoint, anchor;
341 line = List_lines->
value[line_idx];
351 Index = (
int *)
G_realloc(Index, aindex *
sizeof(
int));
355 G_debug(3,
"Snap all vertices");
356 for (v = 0; v < Points->
n_points; v++) {
369 anchor = XPnts[spoint].anchor;
372 Points->
x[v] = XPnts[anchor].x;
373 Points->
y[v] = XPnts[anchor].y;
387 G_debug(3,
"Snap all segments");
388 for (v = 0; v < Points->
n_points - 1; v++) {
390 double x1, x2, y1, y2, xmin, xmax, ymin, ymax;
393 G_debug(3,
" segment = %d end anchors : %d %d", v, Index[v],
397 x2 = Points->
x[v + 1];
399 y2 = Points->
y[v + 1];
424 G_debug(3,
" search anchors for segment %g,%g to %g,%g", x1, y1,
430 rc[0] = xmin - thresh * 2;
431 rc[1] = ymin - thresh * 2;
432 rc[2] = xmax + thresh * 2;
433 rc[3] = ymax + thresh * 2;
437 G_debug(3,
" %d points in box", kd_found);
441 for (i = 0; i < kd_found; i++) {
446 G_debug(4,
" spoint = %d anchor = %d", spoint,
447 XPnts[spoint].anchor);
449 if (spoint == Index[v] || spoint == Index[v + 1])
451 if (XPnts[spoint].anchor > 0)
456 XPnts[spoint].
x, XPnts[spoint].y, 0, x1, y1, 0, x2, y2, 0,
459 G_debug(4,
" distance = %lf", sqrt(dist2));
461 if (status == 0 && dist2 <= thresh2) {
462 G_debug(4,
" anchor in thresh, along = %lf", along);
466 New = (NEW *)
G_realloc(New, anew *
sizeof(NEW));
468 New[nnew].anchor = spoint;
469 New[nnew].along = along;
476 G_debug(3,
" nnew = %d", nnew);
480 qsort(New,
sizeof(
char) * nnew,
sizeof(NEW), sort_new);
482 for (i = 0; i < nnew; i++) {
483 anchor = New[i].anchor;
526 static void Vect_snap_lines_list_rtree(
struct Map_info *Map,
527 const struct ilist *List_lines,
528 double thresh,
struct Map_info *Err)
532 int line, ltype, line_idx;
536 int nsnapped, ncreated;
538 int apoints, npoints;
549 static int rect_init = 0;
563 if (getenv(
"GRASS_VECTOR_LOWMEM")) {
566 rtreefd =
open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
572 thresh2 = thresh * thresh;
581 for (line_idx = 0; line_idx < List_lines->
n_values; line_idx++) {
586 line = List_lines->
value[line_idx];
594 for (v = 0; v < Points->
n_points; v++) {
595 G_debug(3,
" vertex v = %d", v);
613 if ((point - 1) == apoints) {
616 (XPNT *)
G_realloc(XPnts, (apoints + 1) *
sizeof(XPNT));
618 XPnts[point].x = Points->
x[v];
619 XPnts[point].y = Points->
y[v];
620 XPnts[point].anchor = -1;
634 for (point = 1; point <= npoints; point++) {
639 G_debug(3,
" point = %d", point);
641 if (XPnts[point].anchor >= 0)
644 XPnts[point].anchor = 0;
647 rect.
boundary[0] = XPnts[point].x - thresh;
648 rect.
boundary[3] = XPnts[point].x + thresh;
649 rect.
boundary[1] = XPnts[point].y - thresh;
650 rect.
boundary[4] = XPnts[point].y + thresh;
658 for (i = 0; i < List->
n_values; i++) {
660 double dx, dy, dist2;
662 pointb = List->
value[i];
666 dx = XPnts[pointb].x - XPnts[point].x;
667 dy = XPnts[pointb].y - XPnts[point].y;
668 dist2 = dx * dx + dy * dy;
674 if (XPnts[pointb].anchor == -1) {
675 XPnts[pointb].anchor = point;
677 else if (XPnts[pointb].anchor >
681 dx = XPnts[XPnts[pointb].anchor].x - XPnts[pointb].x;
682 dy = XPnts[XPnts[pointb].anchor].y - XPnts[pointb].y;
683 dist2_a = dx * dx + dy * dy;
686 if (dist2 < dist2_a) {
687 XPnts[pointb].anchor = point;
698 nsnapped = ncreated = 0;
702 for (line_idx = 0; line_idx < List_lines->
n_values; line_idx++) {
703 int v, spoint, anchor;
708 line = List_lines->
value[line_idx];
718 Index = (
int *)
G_realloc(Index, aindex *
sizeof(
int));
722 for (v = 0; v < Points->
n_points; v++) {
736 spoint = List->
value[0];
737 anchor = XPnts[spoint].anchor;
740 Points->
x[v] = XPnts[anchor].x;
741 Points->
y[v] = XPnts[anchor].y;
755 for (v = 0; v < Points->
n_points - 1; v++) {
757 double x1, x2, y1, y2, xmin, xmax, ymin, ymax;
759 G_debug(3,
" segment = %d end anchors : %d %d", v, Index[v],
763 x2 = Points->
x[v + 1];
765 y2 = Points->
y[v + 1];
803 for (i = 0; i < List->
n_values; i++) {
807 spoint = List->
value[i];
808 G_debug(4,
" spoint = %d anchor = %d", spoint,
809 XPnts[spoint].anchor);
811 if (spoint == Index[v] || spoint == Index[v + 1])
813 if (XPnts[spoint].anchor > 0)
818 XPnts[spoint].
x, XPnts[spoint].y, 0, x1, y1, 0, x2, y2, 0,
821 G_debug(4,
" distance = %lf", sqrt(dist2));
823 if (status == 0 && dist2 <= thresh2) {
824 G_debug(4,
" anchor in thresh, along = %lf", along);
828 New = (NEW *)
G_realloc(New, anew *
sizeof(NEW));
830 New[nnew].anchor = spoint;
831 New[nnew].along = along;
835 G_debug(3,
" nnew = %d", nnew);
839 qsort(New,
sizeof(
char) * nnew,
sizeof(NEW), sort_new);
841 for (i = 0; i < nnew; i++) {
842 anchor = New[i].anchor;
902 int line, nlines, ltype;
910 for (line = 1; line <= nlines; line++) {
953 struct line_pnts *Points,
double thresh,
int with_z,
954 int *nsnapped,
int *ncreated)
958 int i, v, line, nlines;
970 struct RTree *pnt_tree,
1003 with_z = (with_z != 0);
1009 thresh2 = thresh * thresh;
1011 point = segment = 1;
1017 for (i = 0; i < nlines; i++) {
1019 line = reflist->
value[i];
1021 G_debug(3,
"line = %d", line);
1028 for (v = 0; v < LPoints->
n_points; v++) {
1029 G_debug(3,
" vertex v = %d", v);
1043 RTreeSearch(pnt_tree, &rect, find_item_box, (
void *)List);
1044 G_debug(3,
"List : nvalues = %d", List->n_values);
1046 if (List->n_values == 0) {
1059 if (LPoints->
x[v - 1] < LPoints->
x[v]) {
1068 if (LPoints->
y[v - 1] < LPoints->
y[v]) {
1077 if (LPoints->
z[v - 1] < LPoints->
z[v]) {
1091 if ((segment - 1) == asegments) {
1094 (asegments + 1) *
sizeof(char));
1096 XSegs[segment] = sides;
1104 for (v = 0; v < Points->
n_points; v++) {
1105 double dist2, tmpdist2;
1108 dist2 = thresh2 + thresh2;
1114 rect.
boundary[0] = Points->
x[v] - thresh;
1115 rect.
boundary[3] = Points->
x[v] + thresh;
1116 rect.
boundary[1] = Points->
y[v] - thresh;
1117 rect.
boundary[4] = Points->
y[v] + thresh;
1119 rect.
boundary[2] = Points->
z[v] - thresh;
1120 rect.
boundary[5] = Points->
z[v] + thresh;
1125 RTreeSearch(pnt_tree, &rect, add_item_box, (
void *)List);
1127 for (i = 0; i < List->n_values; i++) {
1128 double dx = List->box[i].E - Points->
x[v];
1129 double dy = List->box[i].N - Points->
y[v];
1133 dz = List->box[i].T - Points->
z[v];
1135 tmpdist2 = dx * dx + dy * dy + dz * dz;
1137 if (tmpdist2 < dist2) {
1146 if (dist2 <= thresh2 && dist2 > 0) {
1159 for (v = 0; v < Points->
n_points; v++) {
1160 double dist2, tmpdist2;
1163 dist2 = thresh2 + thresh2;
1169 rect.
boundary[0] = Points->
x[v] - thresh;
1170 rect.
boundary[3] = Points->
x[v] + thresh;
1171 rect.
boundary[1] = Points->
y[v] - thresh;
1172 rect.
boundary[4] = Points->
y[v] + thresh;
1174 rect.
boundary[2] = Points->
z[v] - thresh;
1175 rect.
boundary[5] = Points->
z[v] + thresh;
1180 RTreeSearch(seg_tree, &rect, add_item_box, (
void *)List);
1182 for (i = 0; i < List->n_values; i++) {
1183 double x1, y1, z1, x2, y2, z2;
1184 double tmpx, tmpy, tmpz;
1187 segment = List->id[i];
1189 if (XSegs[segment] &
X1W) {
1190 x1 = List->box[i].W;
1191 x2 = List->box[i].E;
1194 x1 = List->box[i].E;
1195 x2 = List->box[i].W;
1197 if (XSegs[segment] &
Y1S) {
1198 y1 = List->box[i].S;
1199 y2 = List->box[i].N;
1202 y1 = List->box[i].N;
1203 y2 = List->box[i].S;
1205 if (XSegs[segment] &
Z1B) {
1206 z1 = List->box[i].B;
1207 z2 = List->box[i].T;
1210 z1 = List->box[i].T;
1211 z2 = List->box[i].B;
1216 Points->
x[v], Points->
y[v], Points->
z[v], x1, y1, z1, x2, y2,
1217 z2, with_z, &tmpx, &tmpy, &tmpz,
NULL, &status);
1219 if (tmpdist2 < dist2 && status == 0) {
1228 if (dist2 <= thresh2 && dist2 > 0) {
1244 for (v = 0; v < Points->
n_points - 1; v++) {
1245 double x1, x2, y1, y2, z1, z2;
1246 double xmin, xmax, ymin, ymax, zmin, zmax;
1249 x2 = Points->
x[v + 1];
1251 y2 = Points->
y[v + 1];
1254 z2 = Points->
z[v + 1];
1297 RTreeSearch(pnt_tree, &rect, add_item_box, (
void *)List);
1299 G_debug(3,
" %d points in box", List->n_values);
1303 for (i = 0; i < List->n_values; i++) {
1304 double dist2, along;
1310 if (Points->
x[v] == List->box[i].E &&
1311 Points->
y[v] == List->box[i].N &&
1312 Points->
z[v] == List->box[i].T)
1315 if (Points->
x[v + 1] == List->box[i].E &&
1316 Points->
y[v + 1] == List->box[i].N &&
1317 Points->
z[v + 1] == List->box[i].T)
1322 List->box[i].E, List->box[i].N, List->box[i].T, x1, y1, z1, x2,
1325 if (dist2 <= thresh2 && status == 0) {
1326 G_debug(4,
" anchor in thresh, along = %lf", along);
1330 New = (NEW2 *)
G_realloc(New, anew *
sizeof(NEW2));
1332 New[nnew].x = List->box[i].E;
1333 New[nnew].y = List->box[i].N;
1334 New[nnew].z = List->box[i].T;
1335 New[nnew].along = along;
1338 G_debug(3,
"dist: %g, thresh: %g", dist2, thresh2);
1340 G_debug(3,
" nnew = %d", nnew);
1344 qsort(New, nnew,
sizeof(NEW2), sort_new2);
1346 for (i = 0; i < nnew; i++) {
void Vect_snap_lines_list(struct Map_info *Map, const struct ilist *List_lines, double thresh, struct Map_info *Err)
Snap selected lines to existing vertex in threshold.
void Vect_snap_lines(struct Map_info *Map, int type, double thresh, struct Map_info *Err)
Snap lines in vector map to existing vertex in threshold.
int Vect_snap_line(struct Map_info *Map, struct ilist *reflist, struct line_pnts *Points, double thresh, int with_z, int *nsnapped, int *ncreated)
Snap a line to reference lines in Map with threshold.
void G_percent(long, long, int)
Print percent complete messages.
void G_free(void *)
Free allocated memory.
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void void G_verbose_message(const char *,...) __attribute__((format(printf
char * G_tempfile(void)
Returns a temporary file name.
void void void G_important_message(const char *,...) __attribute__((format(printf
void G_ilist_add(struct ilist *, int)
Add item to ilist.
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
off_t Vect_rewrite_line(struct Map_info *, off_t, int, const struct line_pnts *, const struct line_cats *)
Rewrites existing feature (topological level required)
int Vect_reset_boxlist(struct boxlist *)
Reset boxlist structure.
plus_t Vect_get_num_lines(struct Map_info *)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
struct boxlist * Vect_new_boxlist(int)
Creates and initializes a struct boxlist.
void Vect_destroy_boxlist(struct boxlist *)
Frees all memory associated with a struct boxlist, including the struct itself.
void Vect_destroy_list(struct ilist *)
Frees all memory associated with a struct ilist, including the struct itself.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
int Vect_line_alive(struct Map_info *, int)
Check if feature is alive or dead (topological level required)
int Vect_delete_line(struct Map_info *, off_t)
Delete existing feature (topological level required)
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
void Vect_reset_line(struct line_pnts *)
Reset line.
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_reset_list(struct ilist *)
Reset ilist structure.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
int Vect_append_points(struct line_pnts *, const struct line_pnts *, int)
Appends points to the end of a line.
#define GV_FORWARD
Line direction indicator forward/backward.
double dig_distance2_point_to_line(double, double, double, double, double, double, double, double, double, int, double *, double *, double *, double *, int *)
int dig_boxlist_add(struct boxlist *, int, const struct bound_box *)
Header file for msvc/open.c and msvc/creat.c.
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
int kdtree_rnn(struct kdtree *t, double *c, int **puid, int *skip)
struct kdtree * kdtree_create(char ndims, int *btol)
int kdtree_insert(struct kdtree *t, double *c, int uid, int dc)
int kdtree_knn(struct kdtree *t, double *c, int *uid, double *d, int k, int *skip)
void kdtree_destroy(struct kdtree *t)
int kdtree_dnn(struct kdtree *t, double *c, int **puid, double **pd, double maxdist, int *skip)
List of bounding boxes with id.
int n_values
Number of values in the list.
int * value
Array of values.
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.
double * z
Array of Z coordinates.
void RTreeSetOverflow(struct RTree *t, char overflow)
Enable/disable R*-tree forced reinsertion (overflow)
int RTreeInsertRect(struct RTree_Rect *r, int tid, struct RTree *t)
Insert an item into a R*-Tree.
void RTreeDestroyTree(struct RTree *t)
Destroy an R*-Tree.
int RTreeSearch(struct RTree *t, struct RTree_Rect *r, SearchHitCallback *shcb, void *cbarg)
Search an R*-Tree.
struct RTree * RTreeCreateTree(int fd, off_t rootpos, int ndims)
Create new empty R*-Tree.