23 #include <grass/gis.h>
24 #include <grass/Vect.h>
25 #include <grass/glocale.h>
28 static int cmp_cross(
const void *pa,
const void *pb);
29 static void add_cross(
int asegment,
double adistance,
int bsegment,
30 double bdistance,
double x,
double y);
31 static double dist2(
double x1,
double y1,
double x2,
double y2);
34 static int ident(
double x1,
double y1,
double x2,
double y2,
double thresh);
36 static int cross_seg(
int id,
int *arg);
37 static int find_cross(
int id,
int *arg);
52 #define D ((ax2-ax1)*(by1-by2) - (ay2-ay1)*(bx1-bx2))
53 #define D1 ((bx1-ax1)*(by1-by2) - (by1-ay1)*(bx1-bx2))
54 #define D2 ((ax2-ax1)*(by1-ay1) - (ay2-ay1)*(bx1-ax1))
110 double ay2,
double az2,
double bx1,
double by1,
111 double bz1,
double bx2,
double by2,
double bz2,
112 double *x1,
double *y1,
double *z1,
double *x2,
113 double *y2,
double *z2,
int with_z)
115 static int first_3d = 1;
116 double d, d1, d2, r1, dtol, t;
121 G_debug(4,
"Vect_segment_intersection()");
122 G_debug(4,
" %.15g , %.15g - %.15g , %.15g", ax1, ay1, ax2, ay2);
123 G_debug(4,
" %.15g , %.15g - %.15g , %.15g", bx1, by1, bx2, by2);
126 if (with_z && first_3d) {
127 G_warning(_(
"3D not supported by Vect_segment_intersection()"));
132 if ((ax1 == bx1 && ay1 == by1 && ax2 == bx2 && ay2 == by2) ||
133 (ax1 == bx2 && ay1 == by2 && ax2 == bx1 && ay2 == by1)) {
134 G_debug(2,
" -> identical segments");
149 else if (bx2 == bx1) {
169 else if (ax2 == ax1) {
190 G_debug(2,
"Vect_segment_intersection(): d = %f, d1 = %f, d2 = %f", d, d1,
196 if (fabs(d) > dtol) {
198 G_debug(2,
" -> not parallel/collinear: d1 = %f, d2 = %f", d1, d2);
200 if (d1 < 0 || d1 > d || d2 < 0 || d2 > d) {
201 G_debug(2,
" -> no intersection");
206 if (d1 < d || d1 > 0 || d2 < d || d2 > 0) {
207 G_debug(2,
" -> no intersection");
214 *x1 = ax1 + r1 * (ax2 - ax1);
215 *y1 = ay1 + r1 * (ay2 - ay1);
218 G_debug(2,
" -> intersection %f, %f", *x1, *y1);
223 G_debug(3,
" -> parallel/collinear");
236 G_debug(2,
" -> collinear vertical");
237 if (ay1 > by2 || ay2 < by1) {
238 G_debug(2,
" -> no intersection");
244 G_debug(2,
" -> connected by end points");
252 G_debug(2,
" -> connected by end points");
261 G_debug(3,
" -> vertical overlap");
263 if (ay1 <= by1 && ay2 >= by2) {
264 G_debug(2,
" -> a contains b");
275 if (ay1 >= by1 && ay2 <= by2) {
276 G_debug(2,
" -> b contains a");
288 G_debug(2,
" -> partial overlap");
289 if (by1 > ay1 && by1 < ay2) {
300 if (by2 > ay1 && by2 < ay2) {
313 G_warning(_(
"Vect_segment_intersection() ERROR (collinear vertical segments)"));
326 G_debug(2,
" -> collinear non vertical");
329 if ((bx1 > ax2) || (bx2 < ax1)) {
331 G_debug(2,
" -> no intersection");
336 G_debug(2,
" -> overlap/connected end points");
339 if (ax1 == bx2 && ay1 == by2) {
340 G_debug(2,
" -> connected by end points");
347 if (ax2 == bx1 && ay2 == by1) {
348 G_debug(2,
" -> connected by end points");
357 if (ax1 <= bx1 && ax2 >= bx2) {
358 G_debug(2,
" -> a contains b");
369 if (ax1 >= bx1 && ax2 <= bx2) {
370 G_debug(2,
" -> b contains a");
382 G_debug(2,
" -> partial overlap");
383 if (bx1 > ax1 && bx1 < ax2) {
394 if (bx2 > ax1 && bx2 < ax2) {
407 G_warning(_(
"Vect_segment_intersection() ERROR (collinear non vertical segments)"));
429 static int a_cross = 0;
432 static int *use_cross =
NULL;
434 static void add_cross(
int asegment,
double adistance,
int bsegment,
435 double bdistance,
double x,
double y)
437 if (n_cross == a_cross) {
440 (
CROSS *) G_realloc((
void *)cross,
441 (a_cross + 101) *
sizeof(
CROSS));
443 (
int *)G_realloc((
void *)use_cross,
444 (a_cross + 101) *
sizeof(
int));
449 " add new cross: aseg/dist = %d/%f bseg/dist = %d/%f, x = %f y = %f",
450 asegment, adistance, bsegment, bdistance, x, y);
451 cross[n_cross].
segment[0] = asegment;
452 cross[n_cross].
distance[0] = adistance;
453 cross[n_cross].
segment[1] = bsegment;
454 cross[n_cross].
distance[1] = bdistance;
455 cross[n_cross].
x = x;
456 cross[n_cross].
y =
y;
460 static int cmp_cross(
const void *pa,
const void *pb)
477 static double dist2(
double x1,
double y1,
double x2,
double y2)
483 return (dx * dx + dy * dy);
488 static int ident(
double x1,
double y1,
double x2,
double y2,
double thresh)
494 if ((dx * dx + dy * dy) <= thresh * thresh)
502 static struct line_pnts *APnts, *BPnts;
505 static int cross_seg(
int id,
int *arg)
507 double x1, y1, z1, x2, y2, z2;
516 APnts->x[i + 1], APnts->y[i + 1],
517 APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
518 BPnts->z[j], BPnts->x[j + 1],
519 BPnts->y[j + 1], BPnts->z[j + 1], &x1,
520 &y1, &z1, &x2, &y2, &z2, 0);
524 G_debug(2,
" -> %d x %d: intersection type = %d", i, j, ret);
526 G_debug(3,
" in %f, %f ", x1, y1);
527 add_cross(i, 0.0, j, 0.0, x1, y1);
529 else if (ret == 2 || ret == 3 || ret == 4 || ret == 5) {
534 G_debug(3,
" in %f, %f; %f, %f", x1, y1, x2, y2);
535 add_cross(i, 0.0, j, 0.0, x1, y1);
536 add_cross(i, 0.0, j, 0.0, x2, y2);
562 struct line_pnts *BPoints,
563 struct line_pnts ***ALines,
564 struct line_pnts ***BLines,
565 int *nalines,
int *nblines,
int with_z)
567 int i, j, k,
l, last_seg, seg, last;
569 double dist, curdist, last_dist, last_x, last_y, last_z;
570 double x,
y, rethresh;
572 struct line_pnts **XLines, *Points;
574 struct line_pnts *Points1, *Points2;
575 int seg1, seg2, vert1, vert2;
641 for (i = 0; i < BPoints->n_points - 1; i++) {
642 if (BPoints->x[i] <= BPoints->x[i + 1]) {
644 rect.
boundary[3] = BPoints->x[i + 1];
647 rect.
boundary[0] = BPoints->x[i + 1];
651 if (BPoints->y[i] <= BPoints->y[i + 1]) {
653 rect.
boundary[4] = BPoints->y[i + 1];
656 rect.
boundary[1] = BPoints->y[i + 1];
660 if (BPoints->z[i] <= BPoints->z[i + 1]) {
662 rect.
boundary[5] = BPoints->z[i + 1];
665 rect.
boundary[2] = BPoints->z[i + 1];
673 for (i = 0; i < APoints->n_points - 1; i++) {
674 if (APoints->x[i] <= APoints->x[i + 1]) {
676 rect.
boundary[3] = APoints->x[i + 1];
679 rect.
boundary[0] = APoints->x[i + 1];
683 if (APoints->y[i] <= APoints->y[i + 1]) {
685 rect.
boundary[4] = APoints->y[i + 1];
688 rect.
boundary[1] = APoints->y[i + 1];
691 if (APoints->z[i] <= APoints->z[i + 1]) {
693 rect.
boundary[5] = APoints->z[i + 1];
696 rect.
boundary[2] = APoints->z[i + 1];
700 j =
RTreeSearch(RTree, &rect, (
void *)cross_seg, &i);
706 G_debug(2,
"n_cross = %d", n_cross);
715 for (i = 0; i < n_cross; i++) {
719 dist2(cross[i].x, cross[i].y, APoints->
x[seg], APoints->y[seg]);
725 dist2(cross[i].x, cross[i].y, APoints->
x[seg + 1],
726 APoints->y[seg + 1]);
727 if (dist < curdist) {
729 x = APoints->x[seg + 1];
730 y = APoints->y[seg + 1];
736 dist2(cross[i].x, cross[i].y, BPoints->
x[seg], BPoints->y[seg]);
737 if (dist < curdist) {
742 dist = dist2(cross[i].x, cross[i].y, BPoints->
x[seg + 1], BPoints->y[seg + 1]);
743 if (dist < curdist) {
745 x = BPoints->x[seg + 1];
746 y = BPoints->y[seg + 1];
748 if (curdist < rethresh * rethresh) {
755 for (i = 0; i < n_cross; i++) {
758 dist2(APoints->x[seg], APoints->y[seg], cross[i].
x, cross[i].
y);
761 dist2(BPoints->x[seg], BPoints->y[seg], cross[i].
x, cross[i].
y);
765 for (l = 1; l < 3; l++) {
766 for (i = 0; i < n_cross; i++)
770 XLines = G_malloc((n_cross + 1) *
sizeof(
struct line_pnts *));
773 G_debug(2,
"Clean and create array for line A");
781 G_debug(2,
"Clean and create array for line B");
790 qsort((
void *)cross,
sizeof(
char) * n_cross,
sizeof(
CROSS),
794 for (i = 0; i < n_cross; i++) {
796 " cross = %d seg1/dist1 = %d/%f seg2/dist2 = %d/%f x = %f y = %f",
797 i, cross[i].segment[current],
798 sqrt(cross[i].distance[current]),
799 cross[i].segment[second], sqrt(cross[i].distance[second]),
800 cross[i].x, cross[i].y);
804 for (i = 0; i < n_cross; i++) {
805 if (use_cross[i] == 1) {
806 j = Points1->n_points - 1;
809 if ((cross[i].segment[current] == 0 &&
810 cross[i].x == Points1->
x[0] &&
811 cross[i].
y == Points1->y[0]) ||
812 (cross[i].
segment[current] == j - 1 &&
813 cross[i].
x == Points1->x[j] &&
814 cross[i].
y == Points1->y[j])) {
816 G_debug(3,
"cross %d deleted (first/last point)", i);
832 for (i = 0; i < n_cross; i++) {
833 if (use_cross[i] == 0)
835 G_debug(3,
" is %d between colinear?", i);
837 seg1 = cross[i].
segment[current];
838 seg2 = cross[i].
segment[second];
841 if (cross[i].x == Points1->
x[seg1] &&
842 cross[i].
y == Points1->y[seg1]) {
845 else if (cross[i].x == Points1->
x[seg1 + 1] &&
846 cross[i].
y == Points1->y[seg1 + 1]) {
850 G_debug(3,
" -> is not vertex on 1. line");
857 if (cross[i].x == Points2->
x[seg2] &&
858 cross[i].
y == Points2->y[seg2]) {
861 else if (cross[i].x == Points2->
x[seg2 + 1] &&
862 cross[i].
y == Points2->y[seg2 + 1]) {
866 G_debug(3,
" -> is not vertex on 2. line");
869 G_debug(3,
" seg1/vert1 = %d/%d seg2/ver2 = %d/%d", seg1,
873 if (vert2 == 0 || vert2 == Points2->n_points - 1) {
874 G_debug(3,
" -> vertex 2 (%d) is first/last", vert2);
879 if (!((Points1->x[vert1 - 1] == Points2->x[vert2 - 1] &&
880 Points1->y[vert1 - 1] == Points2->y[vert2 - 1] &&
881 Points1->x[vert1 + 1] == Points2->x[vert2 + 1] &&
882 Points1->y[vert1 + 1] == Points2->y[vert2 + 1]) ||
883 (Points1->x[vert1 - 1] == Points2->x[vert2 + 1] &&
884 Points1->y[vert1 - 1] == Points2->y[vert2 + 1] &&
885 Points1->x[vert1 + 1] == Points2->x[vert2 - 1] &&
886 Points1->y[vert1 + 1] == Points2->y[vert2 - 1])
889 G_debug(3,
" -> previous/next are not identical");
895 G_debug(3,
" -> collinear -> remove");
914 for (i = 1; i < n_cross; i++) {
915 if (use_cross[i] == 0)
921 seg = cross[i].
segment[current];
923 G_debug(3,
" duplicate ?: cross = %d seg = %d dist = %f", i,
924 cross[i].segment[current], cross[i].distance[current]);
925 if ((cross[i].segment[current] == cross[last].segment[current] &&
926 cross[i].distance[current] == cross[last].distance[current])
927 || (cross[i].segment[current] ==
928 cross[last].segment[current] + 1 &&
929 cross[i].distance[current] == 0 &&
930 cross[i].x == cross[last].x &&
931 cross[i].y == cross[last].y)) {
932 G_debug(3,
" cross %d identical to last -> removed", i);
944 for (i = 0; i < n_cross; i++) {
945 if (use_cross[i] == 1) {
952 if (n_alive_cross > 0) {
954 use_cross[n_cross] = 1;
955 j = Points->n_points - 1;
956 cross[n_cross].
x = Points->x[j];
957 cross[n_cross].
y = Points->y[j];
958 cross[n_cross].
segment[current] = Points->n_points - 2;
962 last_x = Points->x[0];
963 last_y = Points->y[0];
964 last_z = Points->z[0];
967 for (i = 0; i <= n_cross; i++) {
968 seg = cross[i].
segment[current];
969 G_debug(2,
"%d seg = %d dist = %f", i, seg,
970 cross[i].distance[current]);
971 if (use_cross[i] == 0) {
972 G_debug(3,
" removed -> next");
980 G_debug(2,
" append last vert: %f %f", last_x, last_y);
983 for (j = last_seg + 1; j <= seg; j++) {
984 G_debug(2,
" segment j = %d", j);
986 if ((j == last_seg + 1) && Points->x[j] == last_x &&
987 Points->y[j] == last_y) {
988 G_debug(2,
" -> skip (identical to last break)");
993 G_debug(2,
" append first of seg: %f %f", Points->x[j],
999 G_debug(2,
" append cross / last point: %f %f", cross[i].x,
1002 last_x = cross[i].
x;
1003 last_y = cross[i].
y, last_z = 0;
1007 G_debug(2,
" line is degenerate -> skipped");
1028 static struct line_pnts *APnts, *BPnts, *IPnts;
1030 static int cross_found;
1033 static int find_cross(
int id,
int *arg)
1035 double x1, y1, z1, x2, y2, z2;
1044 APnts->x[i + 1], APnts->y[i + 1],
1045 APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
1046 BPnts->z[j], BPnts->x[j + 1],
1047 BPnts->y[j + 1], BPnts->z[j + 1], &x1,
1048 &y1, &z1, &x2, &y2, &z2, 0);
1059 G_warning(_(
"Error while adding point to array. Out of memory"));
1065 G_warning(_(
"Error while adding point to array. Out of memory"));
1067 G_warning(_(
"Error while adding point to array. Out of memory"));
1092 struct line_pnts *BPoints,
int with_z)
1095 double dist, rethresh;
1099 rethresh = 0.000001;
1109 if (APoints->n_points == 1 && BPoints->n_points == 1) {
1110 if (APoints->x[0] == BPoints->x[0] && APoints->y[0] == BPoints->y[0]) {
1114 &APoints->y[0],
NULL, 1))
1115 G_warning(_(
"Error while adding point to array. Out of memory"));
1119 if (APoints->z[0] == BPoints->z[0]) {
1122 &APoints->y[0], &APoints->z[0],
1124 G_warning(_(
"Error while adding point to array. Out of memory"));
1136 if (APoints->n_points == 1) {
1141 if (dist <= rethresh) {
1145 G_warning(_(
"Error while adding point to array. Out of memory"));
1153 if (BPoints->n_points == 1) {
1158 if (dist <= rethresh) {
1162 G_warning(_(
"Error while adding point to array. Out of memory"));
1178 for (i = 0; i < BPoints->n_points - 1; i++) {
1179 if (BPoints->x[i] <= BPoints->x[i + 1]) {
1181 rect.
boundary[3] = BPoints->x[i + 1];
1184 rect.
boundary[0] = BPoints->x[i + 1];
1188 if (BPoints->y[i] <= BPoints->y[i + 1]) {
1190 rect.
boundary[4] = BPoints->y[i + 1];
1193 rect.
boundary[1] = BPoints->y[i + 1];
1197 if (BPoints->z[i] <= BPoints->z[i + 1]) {
1199 rect.
boundary[5] = BPoints->z[i + 1];
1202 rect.
boundary[2] = BPoints->z[i + 1];
1212 for (i = 0; i < APoints->n_points - 1; i++) {
1213 if (APoints->x[i] <= APoints->x[i + 1]) {
1215 rect.
boundary[3] = APoints->x[i + 1];
1218 rect.
boundary[0] = APoints->x[i + 1];
1222 if (APoints->y[i] <= APoints->y[i + 1]) {
1224 rect.
boundary[4] = APoints->y[i + 1];
1227 rect.
boundary[1] = APoints->y[i + 1];
1230 if (APoints->z[i] <= APoints->z[i + 1]) {
1232 rect.
boundary[5] = APoints->z[i + 1];
1235 rect.
boundary[2] = APoints->z[i + 1];
1239 RTreeSearch(RTree, &rect, (
void *)find_cross, &i);
1267 struct line_pnts *BPoints,
1268 struct line_pnts *IPoints,
int with_z)
RectReal boundary[NUMSIDES]
struct line_pnts * Vect_new_line_struct()
Creates and initializes a struct line_pnts.
int Vect_line_get_intersections(struct line_pnts *APoints, struct line_pnts *BPoints, struct line_pnts *IPoints, int with_z)
Get 2 lines intersection points.
int RTreeSearch(struct Node *N, struct Rect *R, SearchHitCallback shcb, void *cbarg)
void RTreeDestroyNode(struct Node *)
int Vect_line_check_intersection(struct line_pnts *APoints, struct line_pnts *BPoints, int with_z)
Check if 2 lines intersect.
int RTreeInsertRect(struct Rect *R, int Tid, struct Node **Root, int Level)
int Vect_append_point(struct line_pnts *Points, double x, double y, double z)
Appends one point to the end of a line.
int dig_line_degenerate(struct line_pnts *points)
int Vect_copy_xyz_to_pnts(struct line_pnts *Points, double *x, double *y, double *z, int n)
Copy points from array to line structure.
int Vect_segment_intersection(double ax1, double ay1, double az1, double ax2, double ay2, double az2, double bx1, double by1, double bz1, double bx2, double by2, double bz2, double *x1, double *y1, double *z1, double *x2, double *y2, double *z2, int with_z)
Check for intersect of 2 line segments.
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
int G_debug(int level, const char *msg,...)
Print debugging message.
int Vect_line_intersection(struct line_pnts *APoints, struct line_pnts *BPoints, struct line_pnts ***ALines, struct line_pnts ***BLines, int *nalines, int *nblines, int with_z)
Intersect 2 lines.
struct Node * RTreeNewIndex(void)
int Vect_line_distance(struct line_pnts *points, double ux, double uy, double uz, int with_z, double *px, double *py, double *pz, double *dist, double *spdist, double *lpdist)
calculate line distance.
int Vect_destroy_line_struct(struct line_pnts *p)
Frees all memory associated with a struct line_pnts, including the struct itself. ...