|
2 | 2 |
|
3 | 3 | (******************************************************************************* |
4 | 4 | * Author : Angus Johnson * |
5 | | -* Date : 12 August 2024 * |
6 | | -* Website : http://www.angusj.com * |
7 | | -* Copyright : Angus Johnson 2010-2024 * |
| 5 | +* Date : 22 January 2025 * |
| 6 | +* Website : https://www.angusj.com * |
| 7 | +* Copyright : Angus Johnson 2010-2025 * |
8 | 8 | * Purpose : Path Offset (Inflate/Shrink) * |
9 | | -* License : http://www.boost.org/LICENSE_1_0.txt * |
| 9 | +* License : https://www.boost.org/LICENSE_1_0.txt * |
10 | 10 | *******************************************************************************) |
11 | 11 |
|
12 | 12 | {$I Clipper.inc} |
@@ -142,6 +142,20 @@ implementation |
142 | 142 | TwoPi : Double = 2 * PI; |
143 | 143 | InvTwoPi : Double = 1/(2 * PI); |
144 | 144 |
|
| 145 | +// Clipper2 approximates arcs by using series of relatively short straight |
| 146 | +//line segments. And logically, shorter line segments will produce better arc |
| 147 | +// approximations. But very short segments can degrade performance, usually |
| 148 | +// with little or no discernable improvement in curve quality. Very short |
| 149 | +// segments can even detract from curve quality, due to the effects of integer |
| 150 | +// rounding. Since there isn't an optimal number of line segments for any given |
| 151 | +// arc radius (that perfectly balances curve approximation with performance), |
| 152 | +// arc tolerance is user defined. Nevertheless, when the user doesn't define |
| 153 | +// an arc tolerance (ie leaves alone the 0 default value), the calculated |
| 154 | +// default arc tolerance (offset_radius / 500) generally produces good (smooth) |
| 155 | +// arc approximations without producing excessively small segment lengths. |
| 156 | +// See also: https://www.angusj.com/clipper2/Docs/Trigonometry.htm |
| 157 | +const arc_const = 0.002; // <-- 1/500 |
| 158 | + |
145 | 159 | //------------------------------------------------------------------------------ |
146 | 160 | // Miscellaneous offset support functions |
147 | 161 | //------------------------------------------------------------------------------ |
@@ -364,13 +378,12 @@ procedure TClipperOffset.DoGroupOffset(group: TGroup); |
364 | 378 | if (group.joinType = jtRound) or (group.endType = etRound) then |
365 | 379 | begin |
366 | 380 | // calculate the number of steps required to approximate a circle |
367 | | - // (see http://www.angusj.com/clipper2/Docs/Trigonometry.htm) |
| 381 | + // (see https://www.angusj.com/clipper2/Docs/Trigonometry.htm) |
368 | 382 | // arcTol - when arc_tolerance_ is undefined (0) then curve imprecision |
369 | 383 | // will be relative to the size of the offset (delta). Obviously very |
370 | 384 | //large offsets will almost always require much less precision. |
371 | | - arcTol := Iif(fArcTolerance > 0.01, |
372 | | - Min(absDelta, fArcTolerance), |
373 | | - Log10(2 + absDelta) * 0.25); // empirically derived |
| 385 | + arcTol := Iif(fArcTolerance > 0.0, |
| 386 | + Min(absDelta, fArcTolerance), absDelta * arc_const); |
374 | 387 |
|
375 | 388 | stepsPer360 := Pi / ArcCos(1 - arcTol / absDelta); |
376 | 389 | if (stepsPer360 > absDelta * Pi) then |
@@ -745,7 +758,7 @@ function IntersectPoint(const ln1a, ln1b, ln2a, ln2b: TPointD): TPointD; |
745 | 758 | m1,b1,m2,b2: double; |
746 | 759 | begin |
747 | 760 | result := NullPointD; |
748 | | - //see http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/ |
| 761 | + //see https://paulbourke.net/geometry/pointlineplane/#i2l |
749 | 762 | if (ln1B.X = ln1A.X) then |
750 | 763 | begin |
751 | 764 | if (ln2B.X = ln2A.X) then exit; //parallel lines |
@@ -917,10 +930,8 @@ procedure TClipperOffset.DoRound(j, k: Integer; angle: double); |
917 | 930 | // when fDeltaCallback64 is assigned, fGroupDelta won't be constant, |
918 | 931 | // so we'll need to do the following calculations for *every* vertex. |
919 | 932 | absDelta := Abs(fGroupDelta); |
920 | | - arcTol := Iif(fArcTolerance > 0.01, |
921 | | - Min(absDelta, fArcTolerance), |
922 | | - Log10(2 + absDelta) * 0.25); // empirically derived |
923 | | - //http://www.angusj.com/clipper2/Docs/Trigonometry.htm |
| 933 | + arcTol := Iif(fArcTolerance > 0.0, |
| 934 | + Min(absDelta, fArcTolerance), absDelta * arc_const); |
924 | 935 | stepsPer360 := Pi / ArcCos(1 - arcTol / absDelta); |
925 | 936 | if (stepsPer360 > absDelta * Pi) then |
926 | 937 | stepsPer360 := absDelta * Pi; // avoid excessive precision |
@@ -997,15 +1008,11 @@ procedure TClipperOffset.DoRound(j, k: Integer; angle: double); |
997 | 1008 | // (ie over-shrunk paths) are removed. |
998 | 1009 | {$IFDEF USINGZ} |
999 | 1010 | AddPoint(GetPerpendic(fInPath[j], fNorms[k], fGroupDelta), fInPath[j].Z); |
1000 | | -{$ELSE} |
1001 | | - AddPoint(GetPerpendic(fInPath[j], fNorms[k], fGroupDelta)); |
1002 | | -{$ENDIF} |
1003 | | - // when the angle is almost flat (cos_a ~= 1), |
1004 | | - // it's safe to skip inserting this middle point |
1005 | | - if (cosA < 0.999) then AddPoint(fInPath[j]); // (#405, #873) |
1006 | | -{$IFDEF USINGZ} |
| 1011 | + AddPoint(fInPath[j]); // (#405, #873) |
1007 | 1012 | AddPoint(GetPerpendic(fInPath[j], fNorms[j], fGroupDelta), fInPath[j].Z); |
1008 | 1013 | {$ELSE} |
| 1014 | + AddPoint(GetPerpendic(fInPath[j], fNorms[k], fGroupDelta)); |
| 1015 | + AddPoint(fInPath[j]); // (#405, #873) |
1009 | 1016 | AddPoint(GetPerpendic(fInPath[j], fNorms[j], fGroupDelta)); |
1010 | 1017 | {$ENDIF} |
1011 | 1018 | end |
|
0 commit comments