12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469 |
- /*!
- \file lib/vector/Vlib/intersect.c
- \brief Vector library - intersection
- Higher level functions for reading/writing/manipulating vectors.
- Some parts of code taken from grass50 v.spag/linecros.c
- Based on the following:
- <code>
- (ax2-ax1)r1 - (bx2-bx1)r2 = ax2 - ax1
- (ay2-ay1)r1 - (by2-by1)r2 = ay2 - ay1
- </code>
- Solving for r1 and r2, if r1 and r2 are between 0 and 1, then line
- segments (ax1,ay1)(ax2,ay2) and (bx1,by1)(bx2,by2) intersect.
- Intersect 2 line segments.
- Returns: 0 - do not intersect
- 1 - intersect at one point
- <pre>
- \ / \ / \ /
- \/ \/ \/
- /\ \
- / \ \
- 2 - partial overlap ( \/ )
- ------ a ( distance < threshold )
- ------ b ( )
- 3 - a contains b ( /\ )
- ---------- a ----------- a
- ---- b ----- b
- 4 - b contains a
- ---- a ----- a
- ---------- b ----------- b
- 5 - identical
- ---------- a
- ---------- b
- </pre>
- Intersection points:
- <pre>
- return point1 breakes: point2 breaks: distance1 on: distance2 on:
- 0 - - - -
- 1 a,b - a b
- 2 a b a b
- 3 a a a a
- 4 b b b b
- 5 - - - -
- </pre>
- Sometimes (often) is important to get the same coordinates for a x
- b and b x a. To reach this, the segments a,b are 'sorted' at the
- beginning, so that for the same switched segments, results are
- identical. (reason is that double values are always rounded because
- of limited number of decimal places and for different order of
- coordinates, the results would be different)
- (C) 2001-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 Original author CERL, probably Dave Gerdes or Mike Higgins.
- \author Update to GRASS 5.7 Radim Blazek.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <math.h>
- #include <grass/vector.h>
- #include <grass/glocale.h>
- /* function prototypes */
- static int cmp_cross(const void *pa, const void *pb);
- static void add_cross(int asegment, double adistance, int bsegment,
- double bdistance, double x, double y);
- static double dist2(double x1, double y1, double x2, double y2);
- static int debug_level = -1;
- #if 0
- static int ident(double x1, double y1, double x2, double y2, double thresh);
- #endif
- static int cross_seg(int id, const struct RTree_Rect *rect, void *arg);
- static int find_cross(int id, const struct RTree_Rect *rect, void *arg);
- #define D ((ax2-ax1)*(by1-by2) - (ay2-ay1)*(bx1-bx2))
- #define D1 ((bx1-ax1)*(by1-by2) - (by1-ay1)*(bx1-bx2))
- #define D2 ((ax2-ax1)*(by1-ay1) - (ay2-ay1)*(bx1-ax1))
- /*!
- * \brief Check for intersect of 2 line segments.
- *
- * \param ax1,ay1,az1,ax2,ay2,az2 input line a
- * \param bx1,by1,bz1,bx2,by2,bz2 input line b
- * \param[out] x1,y1,z1 intersection point1 (case 2-4)
- * \param[out] x2,y2,z2 intersection point2 (case 2-4)
- * \param with_z use z coordinate (3D) (TODO)
- *
- * \return 0 - do not intersect,
- * \return 1 - intersect at one point,
- * \return 2 - partial overlap,
- * \return 3 - a contains b,
- * \return 4 - b contains a,
- * \return 5 - identical
- */
- 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)
- {
- static int first_3d = 1;
- double d, d1, d2, r1, dtol, t;
- int switched;
- int end_points;
- /* TODO: Works for points ? */
- G_debug(4, "Vect_segment_intersection()");
- G_debug(4, " %.15g , %.15g - %.15g , %.15g", ax1, ay1, ax2, ay2);
- G_debug(4, " %.15g , %.15g - %.15g , %.15g", bx1, by1, bx2, by2);
- /* TODO 3D */
- if (with_z && first_3d) {
- G_warning(_("3D not supported by Vect_segment_intersection()"));
- first_3d = 0;
- }
- *x1 = 0;
- *y1 = 0;
- *z1 = 0;
- *x2 = 0;
- *y2 = 0;
- *z2 = 0;
- /* 'Sort' each segment by x, y
- * MUST happen before D, D1, D2 are calculated */
- switched = 0;
- if (bx2 < bx1)
- switched = 1;
- else if (bx2 == bx1) {
- if (by2 < by1)
- switched = 1;
- }
- if (switched) {
- t = bx1;
- bx1 = bx2;
- bx2 = t;
- t = by1;
- by1 = by2;
- by2 = t;
- t = bz1;
- bz1 = bz2;
- bz2 = t;
- }
- switched = 0;
- if (ax2 < ax1)
- switched = 1;
- else if (ax2 == ax1) {
- if (ay2 < ay1)
- switched = 1;
- }
- if (switched) {
- t = ax1;
- ax1 = ax2;
- ax2 = t;
- t = ay1;
- ay1 = ay2;
- ay2 = t;
- t = az1;
- az1 = az2;
- az2 = t;
- }
- /* Check for identical segments */
- if (ax1 == bx1 && ay1 == by1 && ax2 == bx2 && ay2 == by2) {
- G_debug(2, " -> identical segments");
- *x1 = ax1;
- *y1 = ay1;
- *z1 = az1;
- *x2 = ax2;
- *y2 = ay2;
- *z2 = az2;
- return 5;
- }
- /* 'Sort' segments by x, y: make sure a <= b
- * MUST happen before D, D1, D2 are calculated */
- switched = 0;
- 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;
- }
- }
- }
- if (switched) {
- t = ax1;
- ax1 = bx1;
- bx1 = t;
- t = ax2;
- ax2 = bx2;
- bx2 = t;
- t = ay1;
- ay1 = by1;
- by1 = t;
- t = ay2;
- ay2 = by2;
- by2 = t;
- t = az1;
- az1 = bz1;
- bz1 = t;
- t = az2;
- az2 = bz2;
- bz2 = t;
- }
- d = D;
- d1 = D1;
- d2 = D2;
- G_debug(2, "Vect_segment_intersection(): d = %f, d1 = %f, d2 = %f", d, d1,
- d2);
- end_points = 0;
- if (ax1 == bx1 && ay1 == by1) {
- end_points = 1;
- *x1 = ax1;
- *y1 = ay1;
- }
- if (ax1 == bx2 && ay1 == by2) {
- end_points = 1;
- *x1 = ax1;
- *y1 = ay1;
- }
- if (ax2 == bx1 && ay2 == by1) {
- end_points = 2;
- *x1 = ax2;
- *y1 = ay2;
- }
- if (ax2 == bx2 && ay2 == by2) {
- end_points = 2;
- *x1 = ax2;
- *y1 = ay2;
- }
- /* TODO: dtol was originally set to 1.0e-10, which was usually working but not always.
- * Can it be a problem to set the tolerance to 0.0 ? */
- dtol = 0.0;
- if (fabs(d) > dtol) {
- G_debug(2, " -> not parallel/collinear: d1 = %f, d2 = %f", d1, d2);
- if (d > 0) {
- if (d1 < 0 || d1 > d || d2 < 0 || d2 > d) {
- if (end_points) {
- G_debug(2, " -> fp error, but intersection at end points %f, %f", *x1, *y1);
- return 1;
- }
- else {
- G_debug(2, " -> no intersection");
- return 0;
- }
- }
- }
- else {
- if (d1 < d || d1 > 0 || d2 < d || d2 > 0) {
- if (end_points) {
- G_debug(2, " -> fp error, but intersection at end points %f, %f", *x1, *y1);
- return 1;
- }
- else {
- G_debug(2, " -> no intersection");
- return 0;
- }
- }
- }
- r1 = d1 / d;
- *x1 = ax1 + r1 * (ax2 - ax1);
- *y1 = ay1 + r1 * (ay2 - ay1);
- *z1 = 0;
- G_debug(2, " -> intersection %f, %f", *x1, *y1);
- return 1;
- }
- /* segments are parallel or collinear */
- G_debug(3, " -> parallel/collinear");
- if (d1 || d2) { /* lines are parallel */
- G_debug(2, " -> parallel");
- if (end_points)
- G_debug(2, "Segments are apparently parallel, but connected at end points -> collinear");
- else
- return 0;
- }
- /* segments are colinear. check for overlap */
- /* Collinear vertical */
- /* original code assumed lines were not both vertical
- * so there is a special case if they are */
- if (ax1 == ax2) {
- G_debug(2, " -> collinear vertical");
- if (ay1 > by2 || ay2 < by1) {
- G_debug(2, " -> no intersection");
- return 0;
- }
- /* end points */
- if (ay1 == by2) {
- G_debug(2, " -> connected by end points");
- *x1 = ax1;
- *y1 = ay1;
- *z1 = 0;
- return 1; /* endpoints only */
- }
- if (ay2 == by1) {
- G_debug(2, " -> connected by end points");
- *x1 = ax2;
- *y1 = ay2;
- *z1 = 0;
- 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;
- *z1 = 0;
- *x2 = bx2;
- *y2 = by2;
- *z2 = 0;
- return 3;
- }
- /* b contains a */
- if (ay1 >= by1 && ay2 <= by2) {
- G_debug(2, " -> b contains a");
- *x1 = ax1;
- *y1 = ay1;
- *z1 = 0;
- *x2 = ax2;
- *y2 = ay2;
- *z2 = 0;
- return 4;
- }
- /* general overlap, 2 intersection points */
- G_debug(2, " -> partial overlap");
- if (by1 > ay1 && by1 < ay2) { /* b1 in a */
- G_debug(2, " -> b1 in a");
- *x1 = bx1;
- *y1 = by1;
- *z1 = 0;
- *x2 = ax2;
- *y2 = ay2;
- *z2 = 0;
- return 2;
- }
- if (by2 > ay1 && by2 < ay2) { /* b2 in a */
- G_debug(2, " -> b2 in a");
- *x1 = ax1;
- *y1 = ay1;
- *z1 = 0;
- *x2 = bx2;
- *y2 = by2;
- *z2 = 0;
- return 2;
- }
- /* should not be reached */
- G_warning(_("Vect_segment_intersection() ERROR (collinear vertical segments)"));
- G_warning("a");
- G_warning("%.15g %.15g", ax1, ay1);
- G_warning("%.15g %.15g", ax2, ay2);
- G_warning("b");
- G_warning("%.15g %.15g", bx1, by1);
- G_warning("%.15g %.15g", bx2, by2);
- return 0;
- }
- /* Collinear non vertical */
- G_debug(2, " -> collinear non vertical");
- /* b is to the left or right of a */
- if ((bx1 > ax2) || (bx2 < ax1)) {
- /* should not happen if segments are selected from rtree */
- 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 == bx2 && ay1 == by2) {
- G_debug(2, " -> connected by end points");
- *x1 = ax1;
- *y1 = ay1;
- *z1 = 0;
- return 1;
- }
- if (ax2 == bx1 && ay2 == by1) {
- G_debug(2, " -> connected by end points");
- *x1 = ax2;
- *y1 = ay2;
- *z1 = 0;
- return 1;
- }
- /* a contains b */
- if (ax1 <= bx1 && ax2 >= bx2) {
- G_debug(2, " -> a contains b");
- *x1 = bx1;
- *y1 = by1;
- *z1 = 0;
- *x2 = bx2;
- *y2 = by2;
- *z2 = 0;
- return 3;
- }
- /* b contains a */
- if (ax1 >= bx1 && ax2 <= bx2) {
- G_debug(2, " -> b contains a");
- *x1 = ax1;
- *y1 = ay1;
- *z1 = 0;
- *x2 = ax2;
- *y2 = ay2;
- *z2 = 0;
- return 4;
- }
- /* general overlap, 2 intersection points (lines are not vertical) */
- G_debug(2, " -> partial overlap");
- if (bx1 > ax1 && bx1 < ax2) { /* b1 is in a */
- G_debug(2, " -> b1 in a");
- *x1 = bx1;
- *y1 = by1;
- *z1 = 0;
- *x2 = ax2;
- *y2 = ay2;
- *z2 = 0;
- return 2;
- }
- if (bx2 > ax1 && bx2 < ax2) { /* b2 is in a */
- G_debug(2, " -> b2 in a");
- *x1 = ax1;
- *y1 = ay1;
- *z1 = 0;
- *x2 = bx2;
- *y2 = by2;
- *z2 = 0;
- return 2;
- }
- /* should not be reached */
- G_warning(_("Vect_segment_intersection() ERROR (collinear non vertical segments)"));
- G_warning("a");
- G_warning("%.15g %.15g", ax1, ay1);
- G_warning("%.15g %.15g", ax2, ay2);
- G_warning("b");
- G_warning("%.15g %.15g", bx1, by1);
- G_warning("%.15g %.15g", bx2, by2);
- return 0;
- }
- typedef struct
- { /* in arrays 0 - A line , 1 - B line */
- int segment[2]; /* segment number, start from 0 for first */
- double distance[2];
- double x, y, z;
- } CROSS;
- /* Current line in arrays is for some functions like cmp() set by: */
- static int current;
- static int second; /* line which is not current */
- static int a_cross = 0;
- static int n_cross;
- static CROSS *cross = NULL;
- static int *use_cross = NULL;
- static void add_cross(int asegment, double adistance, int bsegment,
- double bdistance, double x, double y)
- {
- if (n_cross == a_cross) {
- /* Must be space + 1, used later for last line point, do it better */
- cross =
- (CROSS *) G_realloc((void *)cross,
- (a_cross + 101) * sizeof(CROSS));
- use_cross =
- (int *)G_realloc((void *)use_cross,
- (a_cross + 101) * sizeof(int));
- a_cross += 100;
- }
- G_debug(5,
- " add new cross: aseg/dist = %d/%f bseg/dist = %d/%f, x = %f y = %f",
- asegment, adistance, bsegment, bdistance, x, y);
- cross[n_cross].segment[0] = asegment;
- cross[n_cross].distance[0] = adistance;
- cross[n_cross].segment[1] = bsegment;
- cross[n_cross].distance[1] = bdistance;
- cross[n_cross].x = x;
- cross[n_cross].y = y;
- n_cross++;
- }
- static int cmp_cross(const void *pa, const void *pb)
- {
- CROSS *p1 = (CROSS *) pa;
- CROSS *p2 = (CROSS *) pb;
- if (p1->segment[current] < p2->segment[current])
- return -1;
- if (p1->segment[current] > p2->segment[current])
- return 1;
- /* the same segment */
- if (p1->distance[current] < p2->distance[current])
- return -1;
- if (p1->distance[current] > p2->distance[current])
- return 1;
- return 0;
- }
- static double dist2(double x1, double y1, double x2, double y2)
- {
- double dx, dy;
- dx = x2 - x1;
- dy = y2 - y1;
- return (dx * dx + dy * dy);
- }
- #if 0
- /* returns 1 if points are identical */
- static int ident(double x1, double y1, double x2, double y2, double thresh)
- {
- double dx, dy;
- dx = x2 - x1;
- dy = y2 - y1;
- if ((dx * dx + dy * dy) <= thresh * thresh)
- return 1;
- return 0;
- }
- #endif
- /* shared by Vect_line_intersection, Vect_line_check_intersection, cross_seg, find_cross */
- static struct line_pnts *APnts, *BPnts;
- /* break segments (called by rtree search) */
- static int cross_seg(int id, const struct RTree_Rect *rect, void *arg)
- {
- double x1, y1, z1, x2, y2, z2;
- int i, j, ret;
- /* !!! segment number for B lines is returned as +1 */
- i = *(int *)arg;
- j = id - 1;
- /* Note: -1 to make up for the +1 when data was inserted */
- ret = Vect_segment_intersection(APnts->x[i], APnts->y[i], APnts->z[i],
- APnts->x[i + 1], APnts->y[i + 1],
- APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
- BPnts->z[j], BPnts->x[j + 1],
- BPnts->y[j + 1], BPnts->z[j + 1], &x1,
- &y1, &z1, &x2, &y2, &z2, 0);
- /* add ALL (including end points and duplicates), clean later */
- if (ret > 0) {
- G_debug(2, " -> %d x %d: intersection type = %d", i, j, ret);
- if (ret == 1) { /* one intersection on segment A */
- G_debug(3, " in %f, %f ", x1, y1);
- add_cross(i, 0.0, j, 0.0, x1, y1);
- }
- else if (ret == 2 || ret == 3 || ret == 4 || ret == 5) {
- /* partial overlap; a broken in one, b broken in one
- * or a contains b; a is broken in 2 points (but 1 may be end)
- * or b contains a; b is broken in 2 points (but 1 may be end)
- * or identical */
- G_debug(3, " in %f, %f; %f, %f", x1, y1, x2, y2);
- add_cross(i, 0.0, j, 0.0, x1, y1);
- add_cross(i, 0.0, j, 0.0, x2, y2);
- }
- }
- return 1; /* keep going */
- }
- /*!
- * \brief Intersect 2 lines.
- *
- * Creates array of new lines created from original A line, by
- * intersection with B line. Points (Points->n_points == 1) are not
- * supported.
- *
- * \param APoints first input line
- * \param BPoints second input line
- * \param[out] ALines array of new lines created from original A line
- * \param[out] BLines array of new lines created from original B line
- * \param[out] nalines number of new lines (ALines)
- * \param[out] nblines number of new lines (BLines)
- * \param with_z 3D, not supported!
- *
- * \return 0 no intersection
- * \return 1 intersection found
- */
- int
- Vect_line_intersection(struct line_pnts *APoints,
- struct line_pnts *BPoints,
- struct bound_box *ABox,
- struct bound_box *BBox,
- struct line_pnts ***ALines,
- struct line_pnts ***BLines,
- int *nalines, int *nblines, int with_z)
- {
- int i, j, k, l, last_seg, seg, last;
- int n_alive_cross;
- double dist, curdist, last_x, last_y, last_z;
- double x, y, rethresh;
- struct line_pnts **XLines, *Points;
- struct RTree *MyRTree;
- struct line_pnts *Points1, *Points2; /* first, second points */
- int seg1, seg2, vert1, vert2;
- static struct RTree_Rect rect;
- static int rect_init = 0;
- struct bound_box box, abbox;
- if (debug_level == -1) {
- const char *dstr = G_getenv_nofatal("DEBUG");
- if (dstr != NULL)
- debug_level = atoi(dstr);
- else
- debug_level = 0;
- }
- if (!rect_init) {
- rect.boundary = G_malloc(6 * sizeof(RectReal));
- rect_init = 6;
- }
- n_cross = 0;
- rethresh = 0.000001; /* TODO */
- APnts = APoints;
- BPnts = BPoints;
- /* RE (representation error).
- * RE thresh above is nonsense of course, the RE threshold should be based on
- * number of significant digits for double (IEEE-754) which is 15 or 16 and exponent.
- * The number above is in fact not required threshold, and will not work
- * for example: equator length is 40.075,695 km (8 digits), units are m (+3)
- * and we want precision in mm (+ 3) = 14 -> minimum rethresh may be around 0.001
- * ?Maybe all nonsense?
- * Use rounding error of the unit in the least place ?
- * max of fabs(x), fabs(y)
- * rethresh = pow(2, log2(max) - 53) */
- /* Warning: This function is also used to intersect the line by itself i.e. APoints and
- * BPoints are identical. I am not sure if it is clever, but it seems to work, but
- * we have to keep this in mind and handle some special cases (maybe) */
- /* TODO: 3D, RE threshold, GV_POINTS (line x point) */
- /* Take each segment from A and intersect by each segment from B.
- *
- * All intersections are found first and saved to array, then sorted by a distance along the line,
- * and then the line is split to pieces.
- *
- * Note: If segments are collinear, check if previous/next segments are also collinear,
- * in that case do not break:
- * +----------+
- * +----+-----+ etc.
- * doesn't need to be broken
- *
- * Note: If 2 adjacent segments of line B have common vertex exactly (or within thresh) on line A,
- * intersection points for these B segments may differ due to RE:
- * ------------ a ----+--+---- ----+--+----
- * /\ => / \ or maybe \/
- * b0 / \ b1 / \ even: /\
- *
- * -> solution: snap all breaks to nearest vertices first within RE threshold
- *
- * Question: Snap all breaks to each other within RE threshold?
- *
- * Note: If a break is snapped to end point or two breaks are snapped to the same vertex
- * resulting new line is degenerated => before line is added to array, it must be checked
- * if line is not degenerated
- *
- * Note: to snap to vertices is important for cases where line A is broken by B and C line
- * at the same point:
- * \ / b no snap \ /
- * \/ could ----+--+----
- * ------ a result
- * /\ in ?: /\
- * / \ c / \
- *
- * Note: once we snap breaks to vertices, we have to do that for both lines A and B in the same way
- * and because we cannot be sure that A childrens will not change a bit by break(s)
- * we have to break both A and B at once i.e. in one Vect_line_intersection () call.
- */
- /* Spatial index: lines may be very long (thousands of segments) and check each segment
- * with each from second line takes a long time (n*m). Because of that, spatial index
- * is build first for the second line and segments from the first line are broken by segments
- * in bound box */
- if (!Vect_box_overlap(ABox, BBox)) {
- *nalines = 0;
- *nblines = 0;
- return 0;
- }
-
- abbox = *BBox;
- if (abbox.N > ABox->N)
- abbox.N = ABox->N;
- if (abbox.S < ABox->S)
- abbox.S = ABox->S;
- if (abbox.E > ABox->E)
- abbox.E = ABox->E;
- if (abbox.W < ABox->W)
- abbox.W = ABox->W;
- if (abbox.T > ABox->T)
- abbox.T = ABox->T;
- if (abbox.B < ABox->B)
- abbox.B = ABox->B;
- abbox.N += rethresh;
- abbox.S -= rethresh;
- abbox.E += rethresh;
- abbox.W -= rethresh;
- abbox.T += rethresh;
- abbox.B -= rethresh;
-
- /* Create rtree for B line */
- MyRTree = RTreeCreateTree(-1, 0, 2);
- RTreeSetOverflow(MyRTree, 0);
- for (i = 0; i < BPoints->n_points - 1; i++) {
- if (BPoints->x[i] <= BPoints->x[i + 1]) {
- rect.boundary[0] = BPoints->x[i];
- rect.boundary[3] = BPoints->x[i + 1];
- }
- else {
- rect.boundary[0] = BPoints->x[i + 1];
- rect.boundary[3] = BPoints->x[i];
- }
- if (BPoints->y[i] <= BPoints->y[i + 1]) {
- rect.boundary[1] = BPoints->y[i];
- rect.boundary[4] = BPoints->y[i + 1];
- }
- else {
- rect.boundary[1] = BPoints->y[i + 1];
- rect.boundary[4] = BPoints->y[i];
- }
- if (BPoints->z[i] <= BPoints->z[i + 1]) {
- rect.boundary[2] = BPoints->z[i];
- rect.boundary[5] = BPoints->z[i + 1];
- }
- else {
- rect.boundary[2] = BPoints->z[i + 1];
- rect.boundary[5] = BPoints->z[i];
- }
- box.W = rect.boundary[0] - rethresh;
- box.S = rect.boundary[1] - rethresh;
- box.B = rect.boundary[2] - rethresh;
- box.E = rect.boundary[3] + rethresh;
- box.N = rect.boundary[4] + rethresh;
- box.T = rect.boundary[5] + rethresh;
- if (Vect_box_overlap(&abbox, &box)) {
- RTreeInsertRect(&rect, i + 1, MyRTree); /* B line segment numbers in rtree start from 1 */
- }
- }
- /* Break segments in A by segments in B */
- for (i = 0; i < APoints->n_points - 1; i++) {
- if (APoints->x[i] <= APoints->x[i + 1]) {
- rect.boundary[0] = APoints->x[i];
- rect.boundary[3] = APoints->x[i + 1];
- }
- else {
- rect.boundary[0] = APoints->x[i + 1];
- rect.boundary[3] = APoints->x[i];
- }
- if (APoints->y[i] <= APoints->y[i + 1]) {
- rect.boundary[1] = APoints->y[i];
- rect.boundary[4] = APoints->y[i + 1];
- }
- else {
- rect.boundary[1] = APoints->y[i + 1];
- rect.boundary[4] = APoints->y[i];
- }
- if (APoints->z[i] <= APoints->z[i + 1]) {
- rect.boundary[2] = APoints->z[i];
- rect.boundary[5] = APoints->z[i + 1];
- }
- else {
- rect.boundary[2] = APoints->z[i + 1];
- rect.boundary[5] = APoints->z[i];
- }
- box.W = rect.boundary[0] - rethresh;
- box.S = rect.boundary[1] - rethresh;
- box.B = rect.boundary[2] - rethresh;
- box.E = rect.boundary[3] + rethresh;
- box.N = rect.boundary[4] + rethresh;
- box.T = rect.boundary[5] + rethresh;
- if (Vect_box_overlap(&abbox, &box)) {
- j = RTreeSearch(MyRTree, &rect, cross_seg, &i); /* A segment number from 0 */
- }
- }
- /* Free RTree */
- RTreeDestroyTree(MyRTree);
- G_debug(2, "n_cross = %d", n_cross);
- /* Lines do not cross each other */
- if (n_cross == 0) {
- *nalines = 0;
- *nblines = 0;
- return 0;
- }
- /* Snap breaks to nearest vertices within RE threshold */
- /* Calculate distances along segments */
- for (i = 0; i < n_cross; i++) {
- /* 1. of A seg */
- seg = cross[i].segment[0];
- curdist =
- dist2(cross[i].x, cross[i].y, APoints->x[seg], APoints->y[seg]);
- x = APoints->x[seg];
- y = APoints->y[seg];
- cross[i].distance[0] = curdist;
- /* 2. of A seg */
- dist =
- dist2(cross[i].x, cross[i].y, APoints->x[seg + 1],
- APoints->y[seg + 1]);
- if (dist < curdist) {
- curdist = dist;
- x = APoints->x[seg + 1];
- y = APoints->y[seg + 1];
- }
- /* 1. of B seg */
- seg = cross[i].segment[1];
- dist =
- dist2(cross[i].x, cross[i].y, BPoints->x[seg], BPoints->y[seg]);
- cross[i].distance[1] = dist;
- if (dist < curdist) {
- curdist = dist;
- x = BPoints->x[seg];
- y = BPoints->y[seg];
- }
- /* 2. of B seg */
- dist = dist2(cross[i].x, cross[i].y, BPoints->x[seg + 1], BPoints->y[seg + 1]);
- if (dist < curdist) {
- curdist = dist;
- x = BPoints->x[seg + 1];
- y = BPoints->y[seg + 1];
- }
- if (curdist < rethresh * rethresh) {
- cross[i].x = x;
- cross[i].y = y;
- /* Update distances along segments */
- seg = cross[i].segment[0];
- cross[i].distance[0] =
- dist2(APoints->x[seg], APoints->y[seg], cross[i].x, cross[i].y);
- seg = cross[i].segment[1];
- cross[i].distance[1] =
- dist2(BPoints->x[seg], BPoints->y[seg], cross[i].x, cross[i].y);
- }
- }
- /* l = 1 ~ line A, l = 2 ~ line B */
- for (l = 1; l < 3; l++) {
- for (i = 0; i < n_cross; i++)
- use_cross[i] = 1;
- /* Create array of lines */
- XLines = G_malloc((n_cross + 1) * sizeof(struct line_pnts *));
- if (l == 1) {
- G_debug(2, "Clean and create array for line A");
- Points = APoints;
- Points1 = APoints;
- Points2 = BPoints;
- current = 0;
- second = 1;
- }
- else {
- G_debug(2, "Clean and create array for line B");
- Points = BPoints;
- Points1 = BPoints;
- Points2 = APoints;
- current = 1;
- second = 0;
- }
- /* Sort points along lines */
- qsort((void *)cross, sizeof(char) * n_cross, sizeof(CROSS),
- cmp_cross);
- /* Print all (raw) breaks */
- /* avoid loop when not debugging */
- if (debug_level > 2) {
- for (i = 0; i < n_cross; i++) {
- G_debug(3,
- " cross = %d seg1/dist1 = %d/%f seg2/dist2 = %d/%f x = %f y = %f",
- i, cross[i].segment[current],
- sqrt(cross[i].distance[current]),
- cross[i].segment[second], sqrt(cross[i].distance[second]),
- cross[i].x, cross[i].y);
- }
- }
- /* Remove breaks on first/last line vertices */
- for (i = 0; i < n_cross; i++) {
- if (use_cross[i] == 1) {
- j = Points1->n_points - 1;
- /* Note: */
- if ((cross[i].segment[current] == 0 &&
- cross[i].x == Points1->x[0] &&
- cross[i].y == Points1->y[0]) ||
- (cross[i].segment[current] == j - 1 &&
- cross[i].x == Points1->x[j] &&
- cross[i].y == Points1->y[j])) {
- use_cross[i] = 0; /* first/last */
- G_debug(3, "cross %d deleted (first/last point)", i);
- }
- }
- }
- /* Remove breaks with collinear previous and next segments on 1 and 2 */
- /* Note: breaks with collinear previous and nex must be remove duplicates,
- * otherwise some cross may be lost. Example (+ is vertex):
- * B first cross intersections: A/B segment:
- * | 0/0, 0/1, 1/0, 1/1 - collinear previous and next
- * AB -----+----+--- A 0/4, 0/5, 1/4, 1/5 - OK
- * \___|
- * B
- * This should not inluence that break is always on first segment, see below (I hope)
- */
- /* TODO: this doesn't find identical with breaks on revious/next */
- for (i = 0; i < n_cross; i++) {
- if (use_cross[i] == 0)
- continue;
- G_debug(3, " is %d between colinear?", i);
- seg1 = cross[i].segment[current];
- seg2 = cross[i].segment[second];
- /* Is it vertex on 1, which? */
- if (cross[i].x == Points1->x[seg1] &&
- cross[i].y == Points1->y[seg1]) {
- vert1 = seg1;
- }
- else if (cross[i].x == Points1->x[seg1 + 1] &&
- cross[i].y == Points1->y[seg1 + 1]) {
- vert1 = seg1 + 1;
- }
- else {
- G_debug(3, " -> is not vertex on 1. line");
- continue;
- }
- /* Is it vertex on 2, which? */
- /* For 1. line it is easy, because breaks on vertex are always at end vertex
- * for 2. line we need to find which vertex is on break if any (vert2 starts from 0) */
- if (cross[i].x == Points2->x[seg2] &&
- cross[i].y == Points2->y[seg2]) {
- vert2 = seg2;
- }
- else if (cross[i].x == Points2->x[seg2 + 1] &&
- cross[i].y == Points2->y[seg2 + 1]) {
- vert2 = seg2 + 1;
- }
- else {
- G_debug(3, " -> is not vertex on 2. line");
- continue;
- }
- G_debug(3, " seg1/vert1 = %d/%d seg2/ver2 = %d/%d", seg1,
- vert1, seg2, vert2);
- /* Check if the second vertex is not first/last */
- if (vert2 == 0 || vert2 == Points2->n_points - 1) {
- G_debug(3, " -> vertex 2 (%d) is first/last", vert2);
- continue;
- }
- /* Are there first vertices of this segment identical */
- if (!((Points1->x[vert1 - 1] == Points2->x[vert2 - 1] &&
- Points1->y[vert1 - 1] == Points2->y[vert2 - 1] &&
- Points1->x[vert1 + 1] == Points2->x[vert2 + 1] &&
- Points1->y[vert1 + 1] == Points2->y[vert2 + 1]) ||
- (Points1->x[vert1 - 1] == Points2->x[vert2 + 1] &&
- Points1->y[vert1 - 1] == Points2->y[vert2 + 1] &&
- Points1->x[vert1 + 1] == Points2->x[vert2 - 1] &&
- Points1->y[vert1 + 1] == Points2->y[vert2 - 1])
- )
- ) {
- G_debug(3, " -> previous/next are not identical");
- continue;
- }
- use_cross[i] = 0;
- G_debug(3, " -> collinear -> remove");
- }
- /* Remove duplicates, i.e. merge all identical breaks to one.
- * We must be careful because two points with identical coordinates may be distant if measured along
- * the line:
- * | Segments b0 and b1 overlap, b0 runs up, b1 down.
- * | Two inersections may be merged for a, because they are identical,
- * -----+---- a but cannot be merged for b, because both b0 and b1 must be broken.
- * | I.e. Breaks on b have identical coordinates, but there are not identical
- * b0 | b1 if measured along line b.
- *
- * -> Breaks may be merged as identical if lay on the same segment, or on vertex connecting
- * 2 adjacent segments the points lay on
- *
- * Note: if duplicate is on a vertex, the break is removed from next segment =>
- * break on vertex is always on first segment of this vertex (used below)
- */
- last = -1;
- for (i = 0; i < n_cross; i++) {
- if (use_cross[i] == 0)
- continue;
- if (last == -1) { /* set first alive */
- last = i;
- continue;
- }
- seg = cross[i].segment[current];
- /* compare with last */
- G_debug(3, " duplicate ?: cross = %d seg = %d dist = %f", i,
- cross[i].segment[current], cross[i].distance[current]);
- if ((cross[i].segment[current] == cross[last].segment[current] &&
- cross[i].distance[current] == cross[last].distance[current])
- || (cross[i].segment[current] ==
- cross[last].segment[current] + 1 &&
- cross[i].distance[current] == 0 &&
- cross[i].x == cross[last].x &&
- cross[i].y == cross[last].y)) {
- G_debug(3, " cross %d identical to last -> removed", i);
- use_cross[i] = 0; /* identical */
- }
- else {
- last = i;
- }
- }
- /* Create array of new lines */
- /* Count alive crosses */
- n_alive_cross = 0;
- G_debug(3, " alive crosses:");
- for (i = 0; i < n_cross; i++) {
- if (use_cross[i] == 1) {
- G_debug(3, " %d", i);
- n_alive_cross++;
- }
- }
- k = 0;
- if (n_alive_cross > 0) {
- /* Add last line point at the end of cross array (cross alley) */
- use_cross[n_cross] = 1;
- j = Points->n_points - 1;
- cross[n_cross].x = Points->x[j];
- cross[n_cross].y = Points->y[j];
- cross[n_cross].segment[current] = Points->n_points - 2;
- last_seg = 0;
- last_x = Points->x[0];
- last_y = Points->y[0];
- last_z = Points->z[0];
- /* Go through all cross (+last line point) and create for each new line
- * starting at last_* and ending at cross (last point) */
- for (i = 0; i <= n_cross; i++) { /* i.e. n_cross + 1 new lines */
- seg = cross[i].segment[current];
- G_debug(2, "%d seg = %d dist = %f", i, seg,
- cross[i].distance[current]);
- if (use_cross[i] == 0) {
- G_debug(3, " removed -> next");
- continue;
- }
- G_debug(2, " New line:");
- XLines[k] = Vect_new_line_struct();
- /* add last intersection or first point first */
- Vect_append_point(XLines[k], last_x, last_y, last_z);
- G_debug(2, " append last vert: %f %f", last_x, last_y);
- /* add first points of segments between last and current seg */
- for (j = last_seg + 1; j <= seg; j++) {
- G_debug(2, " segment j = %d", j);
- /* skipp vertex identical to last break */
- if ((j == last_seg + 1) && Points->x[j] == last_x &&
- Points->y[j] == last_y) {
- G_debug(2, " -> skip (identical to last break)");
- continue;
- }
- Vect_append_point(XLines[k], Points->x[j], Points->y[j],
- Points->z[j]);
- G_debug(2, " append first of seg: %f %f", Points->x[j],
- Points->y[j]);
- }
- last_seg = seg;
- last_x = cross[i].x;
- last_y = cross[i].y;
- last_z = 0;
- /* calculate last_z */
- if (Points->z[last_seg] == Points->z[last_seg + 1]) {
- last_z = Points->z[last_seg + 1];
- }
- else if (last_x == Points->x[last_seg] &&
- last_y == Points->y[last_seg]) {
- last_z = Points->z[last_seg];
- }
- else if (last_x == Points->x[last_seg + 1] &&
- last_y == Points->y[last_seg + 1]) {
- last_z = Points->z[last_seg + 1];
- }
- else {
- dist = dist2(Points->x[last_seg],
- Points->x[last_seg + 1],
- Points->y[last_seg],
- Points->y[last_seg + 1]);
- last_z = (Points->z[last_seg] * sqrt(cross[i].distance[current]) +
- Points->z[last_seg + 1] * (sqrt(dist) - sqrt(cross[i].distance[current]))) /
- sqrt(dist);
- }
- /* add current cross or end point */
- Vect_append_point(XLines[k], cross[i].x, cross[i].y, last_z);
- G_debug(2, " append cross / last point: %f %f", cross[i].x,
- cross[i].y);
- /* Check if line is degenerate */
- if (dig_line_degenerate(XLines[k]) > 0) {
- G_debug(2, " line is degenerate -> skipped");
- Vect_destroy_line_struct(XLines[k]);
- }
- else {
- k++;
- }
- }
- }
- if (l == 1) {
- *nalines = k;
- *ALines = XLines;
- }
- else {
- *nblines = k;
- *BLines = XLines;
- }
- }
-
- /* clean up */
- return 1;
- }
- static struct line_pnts *APnts, *BPnts, *IPnts;
- static int cross_found; /* set by find_cross() */
- /* break segments (called by rtree search) */
- static int find_cross(int id, const struct RTree_Rect *rect, void *arg)
- {
- double x1, y1, z1, x2, y2, z2;
- int i, j, ret;
- /* !!! segment number for B lines is returned as +1 */
- i = *(int *)arg;
- j = id - 1;
- /* Note: -1 to make up for the +1 when data was inserted */
- ret = Vect_segment_intersection(APnts->x[i], APnts->y[i], APnts->z[i],
- APnts->x[i + 1], APnts->y[i + 1],
- APnts->z[i + 1], BPnts->x[j], BPnts->y[j],
- BPnts->z[j], BPnts->x[j + 1],
- BPnts->y[j + 1], BPnts->z[j + 1], &x1,
- &y1, &z1, &x2, &y2, &z2, 0);
- switch (ret) {
- case 0:
- case 5:
- break;
- case 1:
- if (0 > Vect_copy_xyz_to_pnts(IPnts, &x1, &y1, &z1, 1))
- G_warning(_("Error while adding point to array. Out of memory"));
- break;
- case 2:
- case 3:
- case 4:
- if (0 > Vect_copy_xyz_to_pnts(IPnts, &x1, &y1, &z1, 1))
- G_warning(_("Error while adding point to array. Out of memory"));
- if (0 > Vect_copy_xyz_to_pnts(IPnts, &x2, &y2, &z2, 1))
- G_warning(_("Error while adding point to array. Out of memory"));
- break;
- }
- /* add ALL (including end points and duplicates), clean later */
- if (ret > 0) {
- cross_found = 1;
- return 0;
- }
- return 1; /* keep going */
- }
- /*!
- * \brief Check if 2 lines intersect.
- *
- * Points (Points->n_points == 1) are also supported.
- *
- * \param APoints first input line
- * \param BPoints second input line
- * \param with_z 3D, not supported (only if one or both are points)!
- *
- * \return 0 no intersection
- * \return 1 intersection found
- */
- int
- Vect_line_check_intersection(struct line_pnts *APoints,
- struct line_pnts *BPoints, int with_z)
- {
- int i;
- double dist, rethresh;
- struct RTree *MyRTree;
- static struct RTree_Rect rect;
- static int rect_init = 0;
- if (!rect_init) {
- rect.boundary = G_malloc(6 * sizeof(RectReal));
- rect_init = 6;
- }
- rethresh = 0.000001; /* TODO */
- APnts = APoints;
- BPnts = BPoints;
- /* TODO: 3D, RE (representation error) threshold, GV_POINTS (line x point) */
- if (!IPnts)
- IPnts = Vect_new_line_struct();
- Vect_reset_line(IPnts);
- /* If one or both are point (Points->n_points == 1) */
- if (APoints->n_points == 1 && BPoints->n_points == 1) {
- if (APoints->x[0] == BPoints->x[0] && APoints->y[0] == BPoints->y[0]) {
- if (!with_z) {
- if (0 >
- Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0],
- &APoints->y[0], NULL, 1))
- G_warning(_("Error while adding point to array. Out of memory"));
- return 1;
- }
- else {
- if (APoints->z[0] == BPoints->z[0]) {
- if (0 >
- Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0],
- &APoints->y[0], &APoints->z[0],
- 1))
- G_warning(_("Error while adding point to array. Out of memory"));
- return 1;
- }
- else
- return 0;
- }
- }
- else {
- return 0;
- }
- }
- if (APoints->n_points == 1) {
- Vect_line_distance(BPoints, APoints->x[0], APoints->y[0],
- APoints->z[0], with_z, NULL, NULL, NULL, &dist,
- NULL, NULL);
- if (dist <= rethresh) {
- if (0 >
- Vect_copy_xyz_to_pnts(IPnts, &APoints->x[0], &APoints->y[0],
- &APoints->z[0], 1))
- G_warning(_("Error while adding point to array. Out of memory"));
- return 1;
- }
- else {
- return 0;
- }
- }
- if (BPoints->n_points == 1) {
- Vect_line_distance(APoints, BPoints->x[0], BPoints->y[0],
- BPoints->z[0], with_z, NULL, NULL, NULL, &dist,
- NULL, NULL);
- if (dist <= rethresh) {
- if (0 >
- Vect_copy_xyz_to_pnts(IPnts, &BPoints->x[0], &BPoints->y[0],
- &BPoints->z[0], 1))
- G_warning(_("Error while adding point to array. Out of memory"));
- return 1;
- }
- else
- return 0;
- }
- /* Take each segment from A and find if intersects any segment from B. */
- /* Spatial index: lines may be very long (thousands of segments) and check each segment
- * with each from second line takes a long time (n*m). Because of that, spatial index
- * is build first for the second line and segments from the first line are broken by segments
- * in bound box */
- /* Create rtree for B line */
- MyRTree = RTreeCreateTree(-1, 0, 2);
- RTreeSetOverflow(MyRTree, 0);
- for (i = 0; i < BPoints->n_points - 1; i++) {
- if (BPoints->x[i] <= BPoints->x[i + 1]) {
- rect.boundary[0] = BPoints->x[i];
- rect.boundary[3] = BPoints->x[i + 1];
- }
- else {
- rect.boundary[0] = BPoints->x[i + 1];
- rect.boundary[3] = BPoints->x[i];
- }
- if (BPoints->y[i] <= BPoints->y[i + 1]) {
- rect.boundary[1] = BPoints->y[i];
- rect.boundary[4] = BPoints->y[i + 1];
- }
- else {
- rect.boundary[1] = BPoints->y[i + 1];
- rect.boundary[4] = BPoints->y[i];
- }
- if (BPoints->z[i] <= BPoints->z[i + 1]) {
- rect.boundary[2] = BPoints->z[i];
- rect.boundary[5] = BPoints->z[i + 1];
- }
- else {
- rect.boundary[2] = BPoints->z[i + 1];
- rect.boundary[5] = BPoints->z[i];
- }
- RTreeInsertRect(&rect, i + 1, MyRTree); /* B line segment numbers in rtree start from 1 */
- }
- /* Find intersection */
- cross_found = 0;
- for (i = 0; i < APoints->n_points - 1; i++) {
- if (APoints->x[i] <= APoints->x[i + 1]) {
- rect.boundary[0] = APoints->x[i];
- rect.boundary[3] = APoints->x[i + 1];
- }
- else {
- rect.boundary[0] = APoints->x[i + 1];
- rect.boundary[3] = APoints->x[i];
- }
- if (APoints->y[i] <= APoints->y[i + 1]) {
- rect.boundary[1] = APoints->y[i];
- rect.boundary[4] = APoints->y[i + 1];
- }
- else {
- rect.boundary[1] = APoints->y[i + 1];
- rect.boundary[4] = APoints->y[i];
- }
- if (APoints->z[i] <= APoints->z[i + 1]) {
- rect.boundary[2] = APoints->z[i];
- rect.boundary[5] = APoints->z[i + 1];
- }
- else {
- rect.boundary[2] = APoints->z[i + 1];
- rect.boundary[5] = APoints->z[i];
- }
- RTreeSearch(MyRTree, &rect, find_cross, &i); /* A segment number from 0 */
- if (cross_found) {
- break;
- }
- }
- /* Free RTree */
- RTreeDestroyTree(MyRTree);
- return cross_found;
- }
- /*!
- * \brief Get 2 lines intersection points.
- *
- * A wrapper around Vect_line_check_intersection() function.
- *
- * \param APoints first input line
- * \param BPoints second input line
- * \param[out] IPoints output with intersection points
- * \param with_z 3D, not supported (only if one or both are points)!
- *
- * \return 0 no intersection
- * \return 1 intersection found
- */
- int
- Vect_line_get_intersections(struct line_pnts *APoints,
- struct line_pnts *BPoints,
- struct line_pnts *IPoints, int with_z)
- {
- int ret;
- IPnts = IPoints;
- ret = Vect_line_check_intersection(APoints, BPoints, with_z);
- return ret;
- }
|