12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085 |
- /*!
- \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;}
- #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;
- }
- /* 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);
- }
- 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 */
- 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
|