123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089 |
- /*!
- \file lib/vector/Vlib/e_intersect.c
- \brief Vector library - intersection (lower level functions)
- Higher level functions for reading/writing/manipulating vectors.
- (C) 2008-2009 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- \author Rewritten by Rosen Matev (Google Summer of Code 2008)
- */
- #include <stdlib.h>
- #include <math.h>
- #include <grass/gis.h>
- #include "e_intersect.h"
- #define SWAP(a,b) {double t = a; a = b; b = t;}
- #ifndef MIN
- #define MIN(X,Y) ((X<Y)?X:Y)
- #endif
- #ifndef MAX
- #define MAX(X,Y) ((X>Y)?X:Y)
- #endif
- #define D ((ax2-ax1)*(by1-by2) - (ay2-ay1)*(bx1-bx2))
- #define DA ((bx1-ax1)*(by1-by2) - (by1-ay1)*(bx1-bx2))
- #define DB ((ax2-ax1)*(by1-ay1) - (ay2-ay1)*(bx1-ax1))
- #ifdef ASDASDASFDSAFFDAS
- mpf_t p11, p12, p21, p22, t1, t2;
- mpf_t dd, dda, ddb, delta;
- mpf_t rra, rrb;
- int initialized = 0;
- void initialize_mpf_vars()
- {
- mpf_set_default_prec(2048);
- mpf_init(p11);
- mpf_init(p12);
- mpf_init(p21);
- mpf_init(p22);
- mpf_init(t1);
- mpf_init(t2);
- mpf_init(dd);
- mpf_init(dda);
- mpf_init(ddb);
- mpf_init(delta);
- mpf_init(rra);
- mpf_init(rrb);
- initialized = 1;
- }
- /*
- Caclulates:
- |a11-b11 a12-b12|
- |a21-b21 a22-b22|
- */
- void det22(mpf_t rop, double a11, double b11, double a12, double b12,
- double a21, double b21, double a22, double b22)
- {
- mpf_set_d(t1, a11);
- mpf_set_d(t2, b11);
- mpf_sub(p11, t1, t2);
- mpf_set_d(t1, a12);
- mpf_set_d(t2, b12);
- mpf_sub(p12, t1, t2);
- mpf_set_d(t1, a21);
- mpf_set_d(t2, b21);
- mpf_sub(p21, t1, t2);
- mpf_set_d(t1, a22);
- mpf_set_d(t2, b22);
- mpf_sub(p22, t1, t2);
- mpf_mul(t1, p11, p22);
- mpf_mul(t2, p12, p21);
- mpf_sub(rop, t1, t2);
- return;
- }
- void swap(double *a, double *b)
- {
- double t = *a;
- *a = *b;
- *b = t;
- return;
- }
- /* multi-precision version */
- int segment_intersection_2d_e(double ax1, double ay1, double ax2, double ay2,
- double bx1, double by1, double bx2, double by2,
- double *x1, double *y1, double *x2, double *y2)
- {
- double t;
- double max_ax, min_ax, max_ay, min_ay;
- double max_bx, min_bx, max_by, min_by;
- int sgn_d, sgn_da, sgn_db;
- int vertical;
- int f11, f12, f21, f22;
- mp_exp_t exp;
- char *s;
- if (!initialized)
- initialize_mpf_vars();
- /* TODO: Works for points ? */
- G_debug(3, "segment_intersection_2d_e()");
- G_debug(4, " ax1 = %.18f, ay1 = %.18f", ax1, ay1);
- G_debug(4, " ax2 = %.18f, ay2 = %.18f", ax2, ay2);
- G_debug(4, " bx1 = %.18f, by1 = %.18f", bx1, by1);
- G_debug(4, " bx2 = %.18f, by2 = %.18f", bx2, by2);
- f11 = ((ax1 == bx1) && (ay1 == by1));
- f12 = ((ax1 == bx2) && (ay1 == by2));
- f21 = ((ax2 == bx1) && (ay2 == by1));
- f22 = ((ax2 == bx2) && (ay2 == by2));
- /* Check for identical segments */
- if ((f11 && f22) || (f12 && f21)) {
- G_debug(3, " identical segments");
- *x1 = ax1;
- *y1 = ay1;
- *x2 = ax2;
- *y2 = ay2;
- return 5;
- }
- /* Check for identical endpoints */
- if (f11 || f12) {
- G_debug(3, " connected by endpoints");
- *x1 = ax1;
- *y1 = ay1;
- return 1;
- }
- if (f21 || f22) {
- G_debug(3, " connected by endpoints");
- *x1 = ax2;
- *y1 = ay2;
- return 1;
- }
- if ((MAX(ax1, ax2) < MIN(bx1, bx2)) || (MAX(bx1, bx2) < MIN(ax1, ax2))) {
- G_debug(3, " no intersection (disjoint bounding boxes)");
- return 0;
- }
- if ((MAX(ay1, ay2) < MIN(by1, by2)) || (MAX(by1, by2) < MIN(ay1, ay2))) {
- G_debug(3, " no intersection (disjoint bounding boxes)");
- return 0;
- }
- det22(dd, ax2, ax1, bx1, bx2, ay2, ay1, by1, by2);
- sgn_d = mpf_sgn(dd);
- if (sgn_d != 0) {
- G_debug(3, " general position");
- det22(dda, bx1, ax1, bx1, bx2, by1, ay1, by1, by2);
- sgn_da = mpf_sgn(dda);
- /*mpf_div(rra, dda, dd);
- mpf_div(rrb, ddb, dd);
- s = mpf_get_str(NULL, &exp, 10, 40, rra);
- G_debug(4, " ra = %sE%d", (s[0]==0)?"0":s, exp);
- s = mpf_get_str(NULL, &exp, 10, 24, rrb);
- G_debug(4, " rb = %sE%d", (s[0]==0)?"0":s, exp);
- */
- if (sgn_d > 0) {
- if ((sgn_da < 0) || (mpf_cmp(dda, dd) > 0)) {
- G_debug(3, " no intersection");
- return 0;
- }
- det22(ddb, ax2, ax1, bx1, ax1, ay2, ay1, by1, ay1);
- sgn_db = mpf_sgn(ddb);
- if ((sgn_db < 0) || (mpf_cmp(ddb, dd) > 0)) {
- G_debug(3, " no intersection");
- return 0;
- }
- }
- else { /* if sgn_d < 0 */
- if ((sgn_da > 0) || (mpf_cmp(dda, dd) < 0)) {
- G_debug(3, " no intersection");
- return 0;
- }
- det22(ddb, ax2, ax1, bx1, ax1, ay2, ay1, by1, ay1);
- sgn_db = mpf_sgn(ddb);
- if ((sgn_db > 0) || (mpf_cmp(ddb, dd) < 0)) {
- G_debug(3, " no intersection");
- return 0;
- }
- }
- /*G_debug(3, " ra=%.17g rb=%.17g", mpf_get_d(dda)/mpf_get_d(dd), mpf_get_d(ddb)/mpf_get_d(dd)); */
- /*G_debug(3, " sgn_d=%d sgn_da=%d sgn_db=%d cmp(dda,dd)=%d cmp(ddb,dd)=%d", sgn_d, sgn_da, sgn_db, mpf_cmp(dda, dd), mpf_cmp(ddb, dd)); */
- mpf_set_d(delta, ax2 - ax1);
- mpf_mul(t1, dda, delta);
- mpf_div(t2, t1, dd);
- *x1 = ax1 + mpf_get_d(t2);
- mpf_set_d(delta, ay2 - ay1);
- mpf_mul(t1, dda, delta);
- mpf_div(t2, t1, dd);
- *y1 = ay1 + mpf_get_d(t2);
- G_debug(3, " intersection %.16g, %.16g", *x1, *y1);
- return 1;
- }
- /* segments are parallel or collinear */
- det22(dda, bx1, ax1, bx1, bx2, by1, ay1, by1, by2);
- sgn_da = mpf_sgn(dda);
- if (sgn_da != 0) {
- /* segments are parallel */
- G_debug(3, " parallel segments");
- return 0;
- }
- /* segments are colinear. check for overlap */
- /* swap endpoints if needed */
- /* if segments are vertical, we swap x-coords with y-coords */
- vertical = 0;
- if (ax1 > ax2) {
- SWAP(ax1, ax2);
- SWAP(ay1, ay2);
- }
- else if (ax1 == ax2) {
- vertical = 1;
- if (ay1 > ay2)
- SWAP(ay1, ay2);
- SWAP(ax1, ay1);
- SWAP(ax2, ay2);
- }
- if (bx1 > bx2) {
- SWAP(bx1, bx2);
- SWAP(by1, by2);
- }
- else if (bx1 == bx2) {
- if (by1 > by2)
- SWAP(by1, by2);
- SWAP(bx1, by1);
- SWAP(bx2, by2);
- }
- G_debug(3, " collinear segments");
- if ((bx2 < ax1) || (bx1 > ax2)) {
- G_debug(3, " no intersection");
- return 0;
- }
- /* there is overlap or connected end points */
- G_debug(3, " overlap");
- /* a contains b */
- if ((ax1 < bx1) && (ax2 > bx2)) {
- G_debug(3, " a contains b");
- if (!vertical) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = bx2;
- *y2 = by2;
- }
- else {
- *x1 = by1;
- *y1 = bx1;
- *x2 = by2;
- *y2 = bx2;
- }
- return 3;
- }
- /* b contains a */
- if ((ax1 > bx1) && (ax2 < bx2)) {
- G_debug(3, " b contains a");
- if (!vertical) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = bx2;
- *y2 = by2;
- }
- else {
- *x1 = by1;
- *y1 = bx1;
- *x2 = by2;
- *y2 = bx2;
- }
- return 4;
- }
- /* general overlap, 2 intersection points */
- G_debug(3, " partial overlap");
- if ((bx1 > ax1) && (bx1 < ax2)) { /* b1 is in a */
- if (!vertical) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = ax2;
- *y2 = ay2;
- }
- else {
- *x1 = by1;
- *y1 = bx1;
- *x2 = ay2;
- *y2 = ax2;
- }
- return 2;
- }
- if ((bx2 > ax1) && (bx2 < ax2)) { /* b2 is in a */
- if (!vertical) {
- *x1 = bx2;
- *y1 = by2;
- *x2 = ax1;
- *y2 = ay1;
- }
- else {
- *x1 = by2;
- *y1 = bx2;
- *x2 = ay1;
- *y2 = ax1;
- }
- return 2;
- }
- /* should not be reached */
- G_warning(("segment_intersection_2d() ERROR (should not be reached)"));
- G_warning("%.16g %.16g", ax1, ay1);
- G_warning("%.16g %.16g", ax2, ay2);
- G_warning("x");
- G_warning("%.16g %.16g", bx1, by1);
- G_warning("%.16g %.16g", bx2, by2);
- return 0;
- }
- #endif
- /* OLD */
- /* tollerance aware version */
- /* TODO: fix all ==s left */
- int segment_intersection_2d_tol(double ax1, double ay1, double ax2,
- double ay2, double bx1, double by1,
- double bx2, double by2, double *x1,
- double *y1, double *x2, double *y2,
- double tol)
- {
- double tola, tolb;
- double d, d1, d2, ra, rb, t;
- int switched = 0;
- /* TODO: Works for points ? */
- G_debug(4, "segment_intersection_2d()");
- G_debug(4, " ax1 = %.18f, ay1 = %.18f", ax1, ay1);
- G_debug(4, " ax2 = %.18f, ay2 = %.18f", ax2, ay2);
- G_debug(4, " bx1 = %.18f, by1 = %.18f", bx1, by1);
- G_debug(4, " bx2 = %.18f, by2 = %.18f", bx2, by2);
- /* Check identical lines */
- if ((FEQUAL(ax1, bx1, tol) && FEQUAL(ay1, by1, tol) &&
- FEQUAL(ax2, bx2, tol) && FEQUAL(ay2, by2, tol)) ||
- (FEQUAL(ax1, bx2, tol) && FEQUAL(ay1, by2, tol) &&
- FEQUAL(ax2, bx1, tol) && FEQUAL(ay2, by1, tol))) {
- G_debug(2, " -> identical segments");
- *x1 = ax1;
- *y1 = ay1;
- *x2 = ax2;
- *y2 = ay2;
- return 5;
- }
- /* 'Sort' lines by x1, x2, y1, y2 */
- if (bx1 < ax1)
- switched = 1;
- else if (bx1 == ax1) {
- if (bx2 < ax2)
- switched = 1;
- else if (bx2 == ax2) {
- if (by1 < ay1)
- switched = 1;
- else if (by1 == ay1) {
- if (by2 < ay2)
- switched = 1; /* by2 != ay2 (would be identical */
- }
- }
- }
- if (switched) {
- t = ax1;
- ax1 = bx1;
- bx1 = t;
- t = ay1;
- ay1 = by1;
- by1 = t;
- t = ax2;
- ax2 = bx2;
- bx2 = t;
- t = ay2;
- ay2 = by2;
- by2 = t;
- }
- d = (ax2 - ax1) * (by1 - by2) - (ay2 - ay1) * (bx1 - bx2);
- d1 = (bx1 - ax1) * (by1 - by2) - (by1 - ay1) * (bx1 - bx2);
- d2 = (ax2 - ax1) * (by1 - ay1) - (ay2 - ay1) * (bx1 - ax1);
- G_debug(2, " d = %.18g", d);
- G_debug(2, " d1 = %.18g", d1);
- G_debug(2, " d2 = %.18g", d2);
- tola = tol / MAX(fabs(ax2 - ax1), fabs(ay2 - ay1));
- tolb = tol / MAX(fabs(bx2 - bx1), fabs(by2 - by1));
- G_debug(2, " tol = %.18g", tol);
- G_debug(2, " tola = %.18g", tola);
- G_debug(2, " tolb = %.18g", tolb);
- if (!FZERO(d, tol)) {
- ra = d1 / d;
- rb = d2 / d;
- G_debug(2, " not parallel/collinear: ra = %.18g", ra);
- G_debug(2, " rb = %.18g", rb);
- if ((ra <= -tola) || (ra >= 1 + tola) || (rb <= -tolb) ||
- (rb >= 1 + tolb)) {
- G_debug(2, " no intersection");
- return 0;
- }
- ra = MIN(MAX(ra, 0), 1);
- *x1 = ax1 + ra * (ax2 - ax1);
- *y1 = ay1 + ra * (ay2 - ay1);
- G_debug(2, " intersection %.18f, %.18f", *x1, *y1);
- return 1;
- }
- /* segments are parallel or collinear */
- G_debug(3, " -> parallel/collinear");
- if ((!FZERO(d1, tol)) || (!FZERO(d2, tol))) { /* lines are parallel */
- G_debug(2, " -> parallel");
- return 0;
- }
- /* segments are colinear. check for overlap */
- /* aa = adx*adx + ady*ady;
- bb = bdx*bdx + bdy*bdy;
- t = (ax1-bx1)*bdx + (ay1-by1)*bdy; */
- /* Collinear vertical */
- /* original code assumed lines were not both vertical
- * so there is a special case if they are */
- if (FEQUAL(ax1, ax2, tol) && FEQUAL(bx1, bx2, tol) &&
- FEQUAL(ax1, bx1, tol)) {
- G_debug(2, " -> collinear vertical");
- if (ay1 > ay2) {
- t = ay1;
- ay1 = ay2;
- ay2 = t;
- } /* to be sure that ay1 < ay2 */
- if (by1 > by2) {
- t = by1;
- by1 = by2;
- by2 = t;
- } /* to be sure that by1 < by2 */
- if (ay1 > by2 || ay2 < by1) {
- G_debug(2, " -> no intersection");
- return 0;
- }
- /* end points */
- if (FEQUAL(ay1, by2, tol)) {
- *x1 = ax1;
- *y1 = ay1;
- G_debug(2, " -> connected by end points");
- return 1; /* endpoints only */
- }
- if (FEQUAL(ay2, by1, tol)) {
- *x1 = ax2;
- *y1 = ay2;
- G_debug(2, " -> connected by end points");
- return 1; /* endpoints only */
- }
- /* general overlap */
- G_debug(3, " -> vertical overlap");
- /* a contains b */
- if (ay1 <= by1 && ay2 >= by2) {
- G_debug(2, " -> a contains b");
- *x1 = bx1;
- *y1 = by1;
- *x2 = bx2;
- *y2 = by2;
- if (!switched)
- return 3;
- else
- return 4;
- }
- /* b contains a */
- if (ay1 >= by1 && ay2 <= by2) {
- G_debug(2, " -> b contains a");
- *x1 = ax1;
- *y1 = ay1;
- *x2 = ax2;
- *y2 = ay2;
- if (!switched)
- return 4;
- else
- return 3;
- }
- /* general overlap, 2 intersection points */
- G_debug(2, " -> partial overlap");
- if (by1 > ay1 && by1 < ay2) { /* b1 in a */
- if (!switched) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = ax2;
- *y2 = ay2;
- }
- else {
- *x1 = ax2;
- *y1 = ay2;
- *x2 = bx1;
- *y2 = by1;
- }
- return 2;
- }
- if (by2 > ay1 && by2 < ay2) { /* b2 in a */
- if (!switched) {
- *x1 = bx2;
- *y1 = by2;
- *x2 = ax1;
- *y2 = ay1;
- }
- else {
- *x1 = ax1;
- *y1 = ay1;
- *x2 = bx2;
- *y2 = by2;
- }
- return 2;
- }
- /* should not be reached */
- G_warning(("Vect_segment_intersection() ERROR (collinear vertical segments)"));
- G_warning("%.15g %.15g", ax1, ay1);
- G_warning("%.15g %.15g", ax2, ay2);
- G_warning("x");
- G_warning("%.15g %.15g", bx1, by1);
- G_warning("%.15g %.15g", bx2, by2);
- return 0;
- }
- G_debug(2, " -> collinear non vertical");
- /* Collinear non vertical */
- if ((bx1 > ax1 && bx2 > ax1 && bx1 > ax2 && bx2 > ax2) ||
- (bx1 < ax1 && bx2 < ax1 && bx1 < ax2 && bx2 < ax2)) {
- G_debug(2, " -> no intersection");
- return 0;
- }
- /* there is overlap or connected end points */
- G_debug(2, " -> overlap/connected end points");
- /* end points */
- if ((ax1 == bx1 && ay1 == by1) || (ax1 == bx2 && ay1 == by2)) {
- *x1 = ax1;
- *y1 = ay1;
- G_debug(2, " -> connected by end points");
- return 1;
- }
- if ((ax2 == bx1 && ay2 == by1) || (ax2 == bx2 && ay2 == by2)) {
- *x1 = ax2;
- *y1 = ay2;
- G_debug(2, " -> connected by end points");
- return 1;
- }
- if (ax1 > ax2) {
- t = ax1;
- ax1 = ax2;
- ax2 = t;
- t = ay1;
- ay1 = ay2;
- ay2 = t;
- } /* to be sure that ax1 < ax2 */
- if (bx1 > bx2) {
- t = bx1;
- bx1 = bx2;
- bx2 = t;
- t = by1;
- by1 = by2;
- by2 = t;
- } /* to be sure that bx1 < bx2 */
- /* a contains b */
- if (ax1 <= bx1 && ax2 >= bx2) {
- G_debug(2, " -> a contains b");
- *x1 = bx1;
- *y1 = by1;
- *x2 = bx2;
- *y2 = by2;
- if (!switched)
- return 3;
- else
- return 4;
- }
- /* b contains a */
- if (ax1 >= bx1 && ax2 <= bx2) {
- G_debug(2, " -> b contains a");
- *x1 = ax1;
- *y1 = ay1;
- *x2 = ax2;
- *y2 = ay2;
- if (!switched)
- return 4;
- else
- return 3;
- }
- /* general overlap, 2 intersection points (lines are not vertical) */
- G_debug(2, " -> partial overlap");
- if (bx1 > ax1 && bx1 < ax2) { /* b1 is in a */
- if (!switched) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = ax2;
- *y2 = ay2;
- }
- else {
- *x1 = ax2;
- *y1 = ay2;
- *x2 = bx1;
- *y2 = by1;
- }
- return 2;
- }
- if (bx2 > ax1 && bx2 < ax2) { /* b2 is in a */
- if (!switched) {
- *x1 = bx2;
- *y1 = by2;
- *x2 = ax1;
- *y2 = ay1;
- }
- else {
- *x1 = ax1;
- *y1 = ay1;
- *x2 = bx2;
- *y2 = by2;
- }
- return 2;
- }
- /* should not be reached */
- G_warning(("segment_intersection_2d() ERROR (collinear non vertical segments)"));
- G_warning("%.15g %.15g", ax1, ay1);
- G_warning("%.15g %.15g", ax2, ay2);
- G_warning("x");
- G_warning("%.15g %.15g", bx1, by1);
- G_warning("%.15g %.15g", bx2, by2);
- return 0;
- }
- int segment_intersection_2d(double ax1, double ay1, double ax2, double ay2,
- double bx1, double by1, double bx2, double by2,
- double *x1, double *y1, double *x2, double *y2)
- {
- const int DLEVEL = 4;
- int vertical;
- int f11, f12, f21, f22;
- double d, da, db;
- /* TODO: Works for points ? */
- G_debug(DLEVEL, "segment_intersection_2d()");
- G_debug(4, " ax1 = %.18f, ay1 = %.18f", ax1, ay1);
- G_debug(4, " ax2 = %.18f, ay2 = %.18f", ax2, ay2);
- G_debug(4, " bx1 = %.18f, by1 = %.18f", bx1, by1);
- G_debug(4, " bx2 = %.18f, by2 = %.18f", bx2, by2);
- f11 = ((ax1 == bx1) && (ay1 == by1));
- f12 = ((ax1 == bx2) && (ay1 == by2));
- f21 = ((ax2 == bx1) && (ay2 == by1));
- f22 = ((ax2 == bx2) && (ay2 == by2));
- /* Check for identical segments */
- if ((f11 && f22) || (f12 && f21)) {
- G_debug(DLEVEL, " identical segments");
- *x1 = ax1;
- *y1 = ay1;
- *x2 = ax2;
- *y2 = ay2;
- return 5;
- }
- /* Check for identical endpoints */
- if (f11 || f12) {
- G_debug(DLEVEL, " connected by endpoints");
- *x1 = ax1;
- *y1 = ay1;
- return 1;
- }
- if (f21 || f22) {
- G_debug(DLEVEL, " connected by endpoints");
- *x1 = ax2;
- *y1 = ay2;
- return 1;
- }
- if ((MAX(ax1, ax2) < MIN(bx1, bx2)) || (MAX(bx1, bx2) < MIN(ax1, ax2))) {
- G_debug(DLEVEL, " no intersection (disjoint bounding boxes)");
- return 0;
- }
- if ((MAX(ay1, ay2) < MIN(by1, by2)) || (MAX(by1, by2) < MIN(ay1, ay2))) {
- G_debug(DLEVEL, " no intersection (disjoint bounding boxes)");
- return 0;
- }
- d = D;
- if (d != 0) {
- G_debug(DLEVEL, " general position");
- da = DA;
- /*mpf_div(rra, dda, dd);
- mpf_div(rrb, ddb, dd);
- s = mpf_get_str(NULL, &exp, 10, 40, rra);
- G_debug(4, " ra = %sE%d", (s[0]==0)?"0":s, exp);
- s = mpf_get_str(NULL, &exp, 10, 24, rrb);
- G_debug(4, " rb = %sE%d", (s[0]==0)?"0":s, exp);
- */
- if (d > 0) {
- if ((da < 0) || (da > d)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- db = DB;
- if ((db < 0) || (db > d)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- }
- else { /* if d < 0 */
- if ((da > 0) || (da < d)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- db = DB;
- if ((db > 0) || (db < d)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- }
- /*G_debug(DLEVEL, " ra=%.17g rb=%.17g", mpf_get_d(dda)/mpf_get_d(dd), mpf_get_d(ddb)/mpf_get_d(dd)); */
- /*G_debug(DLEVEL, " sgn_d=%d sgn_da=%d sgn_db=%d cmp(dda,dd)=%d cmp(ddb,dd)=%d", sgn_d, sgn_da, sgn_db, mpf_cmp(dda, dd), mpf_cmp(ddb, dd)); */
- *x1 = ax1 + (ax2 - ax1) * da / d;
- *y1 = ay1 + (ay2 - ay1) * da / d;
- G_debug(DLEVEL, " intersection %.16g, %.16g", *x1, *y1);
- return 1;
- }
- /* segments are parallel or collinear */
- da = DA;
- db = DB;
- if ((da != 0) || (db != 0)) {
- /* segments are parallel */
- G_debug(DLEVEL, " parallel segments");
- return 0;
- }
- /* segments are colinear. check for overlap */
- /* swap endpoints if needed */
- /* if segments are vertical, we swap x-coords with y-coords */
- vertical = 0;
- if (ax1 > ax2) {
- SWAP(ax1, ax2);
- SWAP(ay1, ay2);
- }
- else if (ax1 == ax2) {
- vertical = 1;
- if (ay1 > ay2)
- SWAP(ay1, ay2);
- SWAP(ax1, ay1);
- SWAP(ax2, ay2);
- }
- if (bx1 > bx2) {
- SWAP(bx1, bx2);
- SWAP(by1, by2);
- }
- else if (bx1 == bx2) {
- if (by1 > by2)
- SWAP(by1, by2);
- SWAP(bx1, by1);
- SWAP(bx2, by2);
- }
- G_debug(DLEVEL, " collinear segments");
- if ((bx2 < ax1) || (bx1 > ax2)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- /* there is overlap or connected end points */
- G_debug(DLEVEL, " overlap");
- /* a contains b */
- if ((ax1 < bx1) && (ax2 > bx2)) {
- G_debug(DLEVEL, " a contains b");
- if (!vertical) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = bx2;
- *y2 = by2;
- }
- else {
- *x1 = by1;
- *y1 = bx1;
- *x2 = by2;
- *y2 = bx2;
- }
- return 3;
- }
- /* b contains a */
- if ((ax1 > bx1) && (ax2 < bx2)) {
- G_debug(DLEVEL, " b contains a");
- if (!vertical) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = bx2;
- *y2 = by2;
- }
- else {
- *x1 = by1;
- *y1 = bx1;
- *x2 = by2;
- *y2 = bx2;
- }
- return 4;
- }
- /* general overlap, 2 intersection points */
- G_debug(DLEVEL, " partial overlap");
- if ((bx1 > ax1) && (bx1 < ax2)) { /* b1 is in a */
- if (!vertical) {
- *x1 = bx1;
- *y1 = by1;
- *x2 = ax2;
- *y2 = ay2;
- }
- else {
- *x1 = by1;
- *y1 = bx1;
- *x2 = ay2;
- *y2 = ax2;
- }
- return 2;
- }
- if ((bx2 > ax1) && (bx2 < ax2)) { /* b2 is in a */
- if (!vertical) {
- *x1 = bx2;
- *y1 = by2;
- *x2 = ax1;
- *y2 = ay1;
- }
- else {
- *x1 = by2;
- *y1 = bx2;
- *x2 = ay1;
- *y2 = ax1;
- }
- return 2;
- }
- /* should not be reached */
- G_warning(("segment_intersection_2d() ERROR (should not be reached)"));
- G_warning("%.16g %.16g", ax1, ay1);
- G_warning("%.16g %.16g", ax2, ay2);
- G_warning("x");
- G_warning("%.16g %.16g", bx1, by1);
- G_warning("%.16g %.16g", bx2, by2);
- return 0;
- }
- #define N 52 /* double's mantisa size in bits */
- /* a and b are different in at most <bits> significant digits */
- int almost_equal(double a, double b, int bits)
- {
- int ea, eb, e;
- if (a == b)
- return 1;
- if (a == 0 || b == 0) {
- /* return (0 < -N+bits); */
- return (bits > N);
- }
- frexp(a, &ea);
- frexp(b, &eb);
- if (ea != eb)
- return (bits > N + abs(ea - eb));
- frexp(a - b, &e);
- return (e < ea - N + bits);
- }
- #ifdef ASDASDFASFEAS
- int segment_intersection_2d_test(double ax1, double ay1, double ax2,
- double ay2, double bx1, double by1,
- double bx2, double by2, double *x1,
- double *y1, double *x2, double *y2)
- {
- double t;
- double max_ax, min_ax, max_ay, min_ay;
- double max_bx, min_bx, max_by, min_by;
- int sgn_d, sgn_da, sgn_db;
- int vertical;
- int f11, f12, f21, f22;
- mp_exp_t exp;
- char *s;
- double d, da, db, ra, rb;
- if (!initialized)
- initialize_mpf_vars();
- /* TODO: Works for points ? */
- G_debug(3, "segment_intersection_2d_test()");
- G_debug(3, " ax1 = %.18e, ay1 = %.18e", ax1, ay1);
- G_debug(3, " ax2 = %.18e, ay2 = %.18e", ax2, ay2);
- G_debug(3, " bx1 = %.18e, by1 = %.18e", bx1, by1);
- G_debug(3, " bx2 = %.18e, by2 = %.18e", bx2, by2);
- f11 = ((ax1 == bx1) && (ay1 == by1));
- f12 = ((ax1 == bx2) && (ay1 == by2));
- f21 = ((ax2 == bx1) && (ay2 == by1));
- f22 = ((ax2 == bx2) && (ay2 == by2));
- /* Check for identical segments */
- if ((f11 && f22) || (f12 && f21)) {
- G_debug(4, " identical segments");
- *x1 = ax1;
- *y1 = ay1;
- *x2 = ax2;
- *y2 = ay2;
- return 5;
- }
- /* Check for identical endpoints */
- if (f11 || f12) {
- G_debug(4, " connected by endpoints");
- *x1 = ax1;
- *y1 = ay1;
- return 1;
- }
- if (f21 || f22) {
- G_debug(4, " connected by endpoints");
- *x1 = ax2;
- *y1 = ay2;
- return 1;
- }
- if ((MAX(ax1, ax2) < MIN(bx1, bx2)) || (MAX(bx1, bx2) < MIN(ax1, ax2))) {
- G_debug(4, " no intersection (disjoint bounding boxes)");
- return 0;
- }
- if ((MAX(ay1, ay2) < MIN(by1, by2)) || (MAX(by1, by2) < MIN(ay1, ay2))) {
- G_debug(4, " no intersection (disjoint bounding boxes)");
- return 0;
- }
- d = (ax2 - ax1) * (by1 - by2) - (ay2 - ay1) * (bx1 - bx2);
- da = (bx1 - ax1) * (by1 - by2) - (by1 - ay1) * (bx1 - bx2);
- db = (ax2 - ax1) * (by1 - ay1) - (ay2 - ay1) * (bx1 - ax1);
- det22(dd, ax2, ax1, bx1, bx2, ay2, ay1, by1, by2);
- sgn_d = mpf_sgn(dd);
- s = mpf_get_str(NULL, &exp, 10, 40, dd);
- G_debug(3, " dd = %sE%d", (s[0] == 0) ? "0" : s, exp);
- G_debug(3, " d = %.18E", d);
- if (sgn_d != 0) {
- G_debug(3, " general position");
- det22(dda, bx1, ax1, bx1, bx2, by1, ay1, by1, by2);
- det22(ddb, ax2, ax1, bx1, ax1, ay2, ay1, by1, ay1);
- sgn_da = mpf_sgn(dda);
- sgn_db = mpf_sgn(ddb);
- ra = da / d;
- rb = db / d;
- mpf_div(rra, dda, dd);
- mpf_div(rrb, ddb, dd);
- s = mpf_get_str(NULL, &exp, 10, 40, rra);
- G_debug(4, " rra = %sE%d", (s[0] == 0) ? "0" : s, exp);
- G_debug(4, " ra = %.18E", ra);
- s = mpf_get_str(NULL, &exp, 10, 40, rrb);
- G_debug(4, " rrb = %sE%d", (s[0] == 0) ? "0" : s, exp);
- G_debug(4, " rb = %.18E", rb);
- if (sgn_d > 0) {
- if ((sgn_da < 0) || (mpf_cmp(dda, dd) > 0)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- if ((sgn_db < 0) || (mpf_cmp(ddb, dd) > 0)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- }
- else { /* if sgn_d < 0 */
- if ((sgn_da > 0) || (mpf_cmp(dda, dd) < 0)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- if ((sgn_db > 0) || (mpf_cmp(ddb, dd) < 0)) {
- G_debug(DLEVEL, " no intersection");
- return 0;
- }
- }
- mpf_set_d(delta, ax2 - ax1);
- mpf_mul(t1, dda, delta);
- mpf_div(t2, t1, dd);
- *x1 = ax1 + mpf_get_d(t2);
- mpf_set_d(delta, ay2 - ay1);
- mpf_mul(t1, dda, delta);
- mpf_div(t2, t1, dd);
- *y1 = ay1 + mpf_get_d(t2);
- G_debug(2, " intersection at:");
- G_debug(2, " xx = %.18e", *x1);
- G_debug(2, " x = %.18e", ax1 + ra * (ax2 - ax1));
- G_debug(2, " yy = %.18e", *y1);
- G_debug(2, " y = %.18e", ay1 + ra * (ay2 - ay1));
- return 1;
- }
- G_debug(3, " parallel/collinear...");
- return -1;
- }
- #endif
|