Skip to content

Commit 2da53eb

Browse files
authored
Merge pull request #1726 from isivigno/fixFrechetSegFault
Fix seg fault and enable parameter error=0 in FrechetShortcut
2 parents bfdc406 + 7c78290 commit 2da53eb

File tree

6 files changed

+7381
-52
lines changed

6 files changed

+7381
-52
lines changed

ChangeLog.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,20 @@
106106

107107
- *Topology package*
108108
- Fix KhalimskySpaceND to get it work with BigInteger (Tristan Roussillon,
109-
[#1681](https://github.com/DGtal-team/DGtal/pull/1681)
109+
[#1681](https://github.com/DGtal-team/DGtal/pull/1681))
110110

111111
- *Geometry package*
112112
- Fix Issue #1676 in testStabbingCircleComputer (Tristan Roussillon,
113113
[#1688](https://github.com/DGtal-team/DGtal/pull/1688)
114114
- Fix BoundedLatticePolytopeCounter::countInterior method (Jacques-Olivier Lachaud,
115115
[#1717](https://github.com/DGtal-team/DGtal/pull/1717))
116116
- Fix const attribute that shouldn't be in FreemanChain (Colin Weill--Duflos,
117-
[#1723](https://github.com/DGtal-team/DGtal/pull/1723))
117+
[#1723](https://github.com/DGtal-team/DGtal/pull/1723))
118+
- Fix seg fault due to recent compilers in FrechetShortcut (Bertrand Kerautret,
119+
Isabelle Sivignon [#1726](https://github.com/DGtal-team/DGtal/pull/1726))
120+
- Fix FrechetShortcut to enable the parameter error to be equal to 0 and add new
121+
tests in testFrechetShortcut (Isabelle Sivignon, [#1726](https://github.com/DGtal-team/DGtal/pull/1726))
122+
118123

119124
- *IO*
120125
- Fix of the `getHSV` method in the `Color` class. (David Coeurjolly,

src/DGtal/geometry/curves/FrechetShortcut.h

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252

5353
#include "DGtal/geometry/curves/SegmentComputerUtils.h"
5454

55+
56+
#define PRECISION 0.00000001
57+
5558
namespace DGtal
5659
{
5760

@@ -399,6 +402,24 @@ namespace DGtal
399402
double *xi, double *yi,
400403
double *xi_prime, double *yi_prime)
401404
{
405+
// I. Sivignon 05/2024: fix to handle the case where r0=0 or
406+
// r1=0. Enables the case where error=0.
407+
// Other special cases where circles are tangent are treated
408+
// below.
409+
if(r0==0)
410+
{
411+
*xi = x0; *yi = y0;
412+
*xi_prime = x0 ; *yi_prime = y0;
413+
return 1;
414+
}
415+
else
416+
if(r1==0)
417+
{
418+
*xi = x1; *yi = y1;
419+
*xi_prime = x1 ; *yi_prime = y1;
420+
return 1;
421+
}
422+
402423
double a, dx, dy, d, h, rx, ry;
403424
double x2, y2;
404425

@@ -407,10 +428,21 @@ namespace DGtal
407428
*/
408429
dx = x1 - x0;
409430
dy = y1 - y0;
410-
431+
411432
/* Determine the straight-line distance between the centers. */
412433
//d = sqrt((dy*dy) + (dx*dx));
413434
d = hypot(dx,dy); // Suggested by Keith Briggs
435+
436+
if((r0+r1)*(r0+r1)-((dy*dy)+(dx*dx)) < PRECISION)
437+
{ // I. Sivignon 05/2024: fix to handle the case where
438+
// circles are tangent but radii are non zero.
439+
440+
double alpha= r0/d;
441+
*xi = x0 + dx*alpha;
442+
*yi = y0 + dy*alpha;
443+
*xi_prime = *xi; *yi_prime = *yi;
444+
return 1;
445+
}
414446

415447
/* Check for solvability. */
416448
if (d > (r0 + r1))
@@ -424,24 +456,26 @@ namespace DGtal
424456
/* no solution. one circle is contained in the other */
425457
return 0;
426458
}
427-
459+
460+
// }
428461
/* 'point 2' is the point where the line through the circle
429462
* intersection points crosses the line between the circle
430463
* centers.
431464
*/
432465

433466
/* Determine the distance from point 0 to point 2. */
434467
a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
435-
468+
436469
/* Determine the coordinates of point 2. */
437470
x2 = x0 + (dx * a/d);
438471
y2 = y0 + (dy * a/d);
439-
472+
473+
440474
/* Determine the distance from point 2 to either of the
441475
* intersection points.
442476
*/
443477
h = sqrt((r0*r0) - (a*a));
444-
478+
445479
/* Now determine the offsets of the intersection points from
446480
* point 2.
447481
*/
@@ -487,6 +521,7 @@ namespace DGtal
487521

488522
int res =
489523
circle_circle_intersection(x0,y0,r0,x1,y1,r1,xi,yi,xi_prime,yi_prime);
524+
490525

491526
return res;
492527

@@ -522,10 +557,13 @@ namespace DGtal
522557
}
523558
else
524559
{
525-
if(y>0)
526-
return M_PI_2;
527-
else
528-
return 3*M_PI_2;
560+
if(y==0)
561+
return 0;
562+
else
563+
if(y>0)
564+
return M_PI_2;
565+
else
566+
return 3*M_PI_2;
529567
}
530568
return -1;
531569
}
@@ -797,8 +835,6 @@ namespace DGtal
797835
ConstIterator end() const;
798836

799837

800-
801-
802838
public:
803839

804840
/**

src/DGtal/geometry/curves/FrechetShortcut.ih

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
// Class backpath
4040
////////////////////////////////////////////////////////////////
4141

42-
#define PRECISION 0.00001
42+
//#define PRECISION 0.00001
4343

4444

4545
//creation of a backPath
@@ -146,6 +146,7 @@ void DGtal::FrechetShortcut<TIterator,TInteger>::Backpath::updateOcculters()
146146
double angle_min=0;
147147
double angle_max=M_PI_4;
148148
bool occ = false;
149+
bool ok = true;
149150

150151
IntegerComputer<TInteger> ic;
151152

@@ -157,16 +158,14 @@ void DGtal::FrechetShortcut<TIterator,TInteger>::Backpath::updateOcculters()
157158
}
158159
else
159160
{
160-
typename occulter_list::iterator iter, next;
161-
bool ok = true;
161+
typename occulter_list::iterator iter=myOcculters.begin();
162+
162163
iter = myOcculters.begin();
163-
while(iter!=myOcculters.end() && ok)
164+
for(typename occulter_list::size_type i=0; i < myOcculters.size() && ok ; ++i)
164165
{
165166
pi = Point(*(iter->first));
166167
v = p-pi;
167168

168-
next = iter;
169-
next++;
170169
// pi is after p for all directions -> p is not an occulter
171170
if(ic.dotProduct(v,u1) < 0 && ic.dotProduct(v,u2) <0)
172171
{
@@ -178,7 +177,7 @@ void DGtal::FrechetShortcut<TIterator,TInteger>::Backpath::updateOcculters()
178177
// anymore, p is a new occulter.
179178
if(ic.dotProduct(v,u1) > 0 && ic.dotProduct(v,u2) > 0)
180179
{
181-
myOcculters.erase(iter);
180+
iter = myOcculters.erase(iter);
182181
occ = true;
183182
angle_min = 0;
184183
angle_max = M_PI_4;
@@ -198,12 +197,13 @@ void DGtal::FrechetShortcut<TIterator,TInteger>::Backpath::updateOcculters()
198197
angle_max = alpha;
199198
// pi's angle_min is updated
200199
iter->second.angle_min = alpha;
200+
iter++;
201201
}
202202
else
203203
if(alpha > iter->second.angle_max)
204204
{
205205
//pi is not an occulter anymore
206-
myOcculters.erase(iter);
206+
iter = myOcculters.erase(iter);
207207
occ=true;
208208
angle_min = 0;
209209
angle_max = M_PI_4;
@@ -225,21 +225,23 @@ void DGtal::FrechetShortcut<TIterator,TInteger>::Backpath::updateOcculters()
225225
angle_max = M_PI_4;
226226
// pi's angle_max is updated
227227
iter->second.angle_max = alpha;
228+
iter++;
228229
}
229230
else
230231
if(alpha < iter->second.angle_min)
231232
{
232233
//pi is not an occulter anymore
233-
myOcculters.erase(iter);
234+
iter = myOcculters.erase(iter);
234235
occ=true;
235236
angle_min = 0;
236237
angle_max = M_PI_4;
237238
}
239+
else
240+
iter++;
238241
// if(alpha > iter->second.angle_max), pi does not
239242
// change, p may be an occulter -> do nothing
240243

241244
}
242-
iter = next;
243245
}
244246
}
245247

@@ -369,7 +371,7 @@ DGtal::FrechetShortcut<TIterator,TInteger>::Cone::Cone()
369371
{
370372
myInf = true;
371373
myMin = 0;
372-
myMax = 0;
374+
myMax = 2*M_PI;
373375
}
374376

375377

@@ -441,7 +443,8 @@ bool DGtal::FrechetShortcut<TIterator,TInteger>::Cone::isEmpty() const
441443
if(myInf)
442444
return false;
443445
else
444-
if(myMin==myMax)
446+
// Fix 05/2024 to enable error = 0: a cone may be defined by two values myMin=myMax --> check for empty cone by setting myMin=myMax= -1 instead
447+
if(myMin==-1) // and then myMax = -1 too: way to represent the empty intersection of two cones.
445448
return true;
446449
else
447450
return false;
@@ -509,7 +512,7 @@ typename DGtal::FrechetShortcut<TIterator,TInteger>::Cone DGtal::FrechetShortcut
509512
// first possibility: the cones are disjoint
510513
if(!Tools::isBetween(myMin, c.myMin, c.myMax, 2*M_PI) && !Tools::isBetween(myMax, c.myMin,
511514
c.myMax, 2*M_PI))
512-
res = Cone(0,0);
515+
res = Cone(-1,-1); // empty cone: both angles are set to -1
513516
else
514517
// or the new cone includes the old one, nothing changes, the cone remains the same.
515518
res = *this;
@@ -523,6 +526,7 @@ typename DGtal::FrechetShortcut<TIterator,TInteger>::Cone DGtal::FrechetShortcut
523526
res = Cone(c.myMin, myMax);
524527
else
525528
res = Cone(myMin,c.myMax);
529+
526530

527531
return res;
528532
}
@@ -568,6 +572,7 @@ template <typename TIterator, typename TInteger>
568572
inline
569573
DGtal::FrechetShortcut<TIterator,TInteger>::FrechetShortcut(double error)
570574
{
575+
571576
myError = error;
572577
myCone = Cone();
573578

@@ -688,14 +693,18 @@ DGtal::FrechetShortcut<TIterator,TInteger>::computeNewCone()
688693
Point firstP = Point(*myBegin);
689694
Point newP = Point(*(myEnd+1));
690695

691-
692696
Cone newCone=myCone;
697+
698+
if(firstP == newP)
699+
return newCone;
693700

694701
// compute the tangent points defined by the first point and the
695702
// circle C(newP,error)
703+
704+
696705
bool intersect = Tools::circleTangentPoints(firstP[0],firstP[1], newP[0], newP[1], myError/(sqrt(2.0F)), &x0, &y0,
697706
&x1, &y1);
698-
707+
699708
if(intersect)
700709
{
701710
// define a cone according to the new tangent points
@@ -704,20 +713,16 @@ DGtal::FrechetShortcut<TIterator,TInteger>::computeNewCone()
704713
if(fabs(x0-x1) < PRECISION && fabs(y0-y1) < PRECISION)
705714
{
706715
double angle = Tools::computeAngle(firstP[0],firstP[1],newP[0],newP[1]);
707-
assert(angle != -1);
708-
double angle0 = angle - M_PI_2;
709-
if(angle0<0)
710-
angle0 = angle0+2*M_PI;
711-
double angle1 = angle + M_PI_2;
712-
if(angle1>2*M_PI)
713-
angle1 = angle1-2*M_PI;
714-
c = Cone(angle0,angle1);
716+
717+
// the cone is reduced to a line
718+
c = Cone(angle,angle);
715719
}
716720
else
717721
c = Cone(firstP[0],firstP[1],x0,y0,x1,y1);
718-
722+
719723
newCone.intersectCones(c);
720724
}
725+
721726

722727
return newCone;
723728

@@ -873,7 +878,7 @@ inline
873878
void DGtal::FrechetShortcut<TIterator,TInteger>::resetCone()
874879
{
875880
myCone.myMin = 0;
876-
myCone.myMax = 0;
881+
myCone.myMax = 2*M_PI; // default cone is the whole space
877882
myCone.myInf = true;
878883
}
879884

0 commit comments

Comments
 (0)