diff --git a/CPP/Clipper2Lib/src/clipper.offset.cpp b/CPP/Clipper2Lib/src/clipper.offset.cpp index dab7d7a2..2b05409f 100644 --- a/CPP/Clipper2Lib/src/clipper.offset.cpp +++ b/CPP/Clipper2Lib/src/clipper.offset.cpp @@ -1,6 +1,6 @@ /******************************************************************************* * Author : Angus Johnson * -* Date : 28 November 2023 * +* Date : 21 December 2023 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : Path Offset (Inflate/Shrink) * @@ -516,6 +516,13 @@ void ClipperOffset::DoGroupOffset(Group& group) if (pathLen == 1) // single point { + if (deltaCallback64_) + { + group_delta_ = deltaCallback64_(*path_in_it, norms, 0, 0); + if (group.is_reversed) group_delta_ = -group_delta_; + abs_delta = std::fabs(group_delta_); + } + if (group_delta_ < 1) continue; const Point64& pt = (*path_in_it)[0]; //single vertex so build a circle or square ... diff --git a/CSharp/Clipper2Lib/Clipper.Offset.cs b/CSharp/Clipper2Lib/Clipper.Offset.cs index 67a6121d..f47125e0 100644 --- a/CSharp/Clipper2Lib/Clipper.Offset.cs +++ b/CSharp/Clipper2Lib/Clipper.Offset.cs @@ -1,6 +1,6 @@ /******************************************************************************* * Author : Angus Johnson * -* Date : 28 November 2023 * +* Date : 21 December 2023 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : Path Offset (Inflate/Shrink) * @@ -420,13 +420,21 @@ private void DoBevel(Path64 path, int j, int k) if (j == k) { double absDelta = Math.Abs(_groupDelta); - pt1 = new Point64(path[j].X - absDelta * _normals[j].x, path[j].Y - absDelta * _normals[j].y); - pt2 = new Point64(path[j].X + absDelta * _normals[j].x, path[j].Y + absDelta * _normals[j].y); + pt1 = new Point64( + path[j].X - absDelta * _normals[j].x, + path[j].Y - absDelta * _normals[j].y); + pt2 = new Point64( + path[j].X + absDelta * _normals[j].x, + path[j].Y + absDelta * _normals[j].y); } else { - pt1 = new Point64(path[j].X + _groupDelta * _normals[k].x, path[j].Y + _groupDelta * _normals[k].y); - pt2 = new Point64(path[j].X + _groupDelta * _normals[j].x, path[j].Y + _groupDelta * _normals[j].y); + pt1 = new Point64( + path[j].X + _groupDelta * _normals[k].x, + path[j].Y + _groupDelta * _normals[k].y); + pt2 = new Point64( + path[j].X + _groupDelta * _normals[j].x, + path[j].Y + _groupDelta * _normals[j].y); } pathOut.Add(pt1); pathOut.Add(pt2); @@ -743,6 +751,13 @@ private void DoGroupOffset(Group group) { Point64 pt = p[0]; + if (DeltaCallback != null) + { + _groupDelta = DeltaCallback(p, _normals, 0, 0); + if (group.pathsReversed) _groupDelta = -_groupDelta; + absDelta = Math.Abs(_groupDelta); + } + // single vertex so build a circle or square ... if (group.endType == EndType.Round) { diff --git a/Delphi/Clipper2Lib/Clipper.Core.pas b/Delphi/Clipper2Lib/Clipper.Core.pas index 1ed1e243..d93f8f81 100644 --- a/Delphi/Clipper2Lib/Clipper.Core.pas +++ b/Delphi/Clipper2Lib/Clipper.Core.pas @@ -2,7 +2,7 @@ (******************************************************************************* * Author : Angus Johnson * -* Date : 5 November 2023 * +* Date : 21 December 2023 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : Core Clipper Library module * @@ -337,6 +337,11 @@ procedure QuickSort(SortList: TPointerList; procedure CheckPrecisionRange(var precision: integer); +function Iif(eval: Boolean; trueVal, falseVal: Boolean): Boolean; overload; +function Iif(eval: Boolean; trueVal, falseVal: integer): integer; overload; +function Iif(eval: Boolean; trueVal, falseVal: Int64): Int64; overload; +function Iif(eval: Boolean; trueVal, falseVal: double): double; overload; + const MaxInt64 = 9223372036854775807; MinInt64 = -MaxInt64; @@ -655,6 +660,34 @@ procedure TListEx.Swap(idx1, idx2: integer); // Miscellaneous Functions ... //------------------------------------------------------------------------------ +function Iif(eval: Boolean; trueVal, falseVal: Boolean): Boolean; + {$IFDEF INLINING} inline; {$ENDIF} +begin + if eval then Result := trueVal else Result := falseVal; +end; +//------------------------------------------------------------------------------ + +function Iif(eval: Boolean; trueVal, falseVal: integer): integer; + {$IFDEF INLINING} inline; {$ENDIF} +begin + if eval then Result := trueVal else Result := falseVal; +end; +//------------------------------------------------------------------------------ + +function Iif(eval: Boolean; trueVal, falseVal: Int64): Int64; + {$IFDEF INLINING} inline; {$ENDIF} +begin + if eval then Result := trueVal else Result := falseVal; +end; +//------------------------------------------------------------------------------ + +function Iif(eval: Boolean; trueVal, falseVal: double): double; + {$IFDEF INLINING} inline; {$ENDIF} +begin + if eval then Result := trueVal else Result := falseVal; +end; +//------------------------------------------------------------------------------ + procedure CheckPrecisionRange(var precision: integer); begin if (precision < -MaxDecimalPrecision) or (precision > MaxDecimalPrecision) then diff --git a/Delphi/Clipper2Lib/Clipper.Engine.pas b/Delphi/Clipper2Lib/Clipper.Engine.pas index 9339134f..6a576abf 100644 --- a/Delphi/Clipper2Lib/Clipper.Engine.pas +++ b/Delphi/Clipper2Lib/Clipper.Engine.pas @@ -2,7 +2,7 @@ (******************************************************************************* * Author : Angus Johnson * -* Date : 1 December 2023 * +* Date : 21 December 2023 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : This is the main polygon clipping module * @@ -1721,23 +1721,18 @@ procedure TClipperBase.SetWindCountForClosedPathEdge(e: PActive); if (Abs(e2.windCnt) > 1) then begin // outside prev poly but still inside another. - if (e2.windDx * e.windDx < 0) then - // reversing direction so use the same WC - e.windCnt := e2.windCnt else - // otherwise keep 'reducing' the WC by 1 (ie towards 0) ... - e.windCnt := e2.windCnt + e.windDx; + e.windCnt := Iif(e2.windDx * e.windDx < 0, + e2.windCnt, // reversing direction so use the same WC + e2.windCnt + e.windDx); end // now outside all polys of same polytype so set own WC ... else e.windCnt := e.windDx; end else begin //'e' must be inside 'e2' - if (e2.windDx * e.windDx < 0) then - // reversing direction so use the same WC - e.windCnt := e2.windCnt - else - // otherwise keep 'increasing' the WC by 1 (ie away from 0) ... - e.windCnt := e2.windCnt + e.windDx; + e.windCnt := Iif(e2.windDx * e.windDx < 0, + e2.windCnt, // reversing direction so use the same WC + e2.windCnt + e.windDx); // else keep 'increasing' the WC end; e.windCnt2 := e2.windCnt2; e2 := e2.nextInAEL; @@ -1778,8 +1773,8 @@ procedure TClipperBase.SetWindCountForOpenPathEdge(e: PActive); else if not IsOpen(e2) then inc(cnt1); e2 := e2.nextInAEL; end; - if Odd(cnt1) then e.windCnt := 1 else e.windCnt := 0; - if Odd(cnt2) then e.windCnt2 := 1 else e.windCnt2 := 0; + e.windCnt := Iif(Odd(cnt1), 1, 0); + e.windCnt2 := Iif(Odd(cnt2), 1, 0); end else begin // if FClipType in [ctUnion, ctDifference] then e.WindCnt := e.WindDx; @@ -2637,12 +2632,10 @@ function TClipperBase.IntersectEdges(e1, e2: PActive; pt: TPoint64): POutPt; e2.windCnt := e1WindCnt; end else begin - if e1.windCnt + e2.windDx = 0 then - e1.windCnt := -e1.windCnt else - Inc(e1.windCnt, e2.windDx); - if e2.windCnt - e1.windDx = 0 then - e2.windCnt := -e2.windCnt else - Dec(e2.windCnt, e1.windDx); + e1.windCnt := Iif(e1.windCnt + e2.windDx = 0, + -e1.windCnt, e1.windCnt + e2.windDx); + e2.windCnt := Iif(e2.windCnt - e1.windDx = 0, + -e2.windCnt, e2.windCnt - e1.windDx); end; end else begin @@ -2909,14 +2902,14 @@ function HorzontalsOverlap(const horz1a, horz1b, horz2a, horz2b: TPoint64): bool begin if horz1a.X < horz1b.X then begin - if horz2a.X < horz2b.X then - Result := HorzOverlapWithLRSet(horz1a, horz1b, horz2a, horz2b) else - Result := HorzOverlapWithLRSet(horz1a, horz1b, horz2b, horz2a); + Result := Iif(horz2a.X < horz2b.X, + HorzOverlapWithLRSet(horz1a, horz1b, horz2a, horz2b), + HorzOverlapWithLRSet(horz1a, horz1b, horz2b, horz2a)); end else begin - if horz2a.X < horz2b.X then - Result := HorzOverlapWithLRSet(horz1b, horz1a, horz2a, horz2b) else - Result := HorzOverlapWithLRSet(horz1b, horz1a, horz2b, horz2a); + Result := Iif(horz2a.X < horz2b.X, + HorzOverlapWithLRSet(horz1b, horz1a, horz2a, horz2b), + HorzOverlapWithLRSet(horz1b, horz1a, horz2b, horz2a)); end; end; //------------------------------------------------------------------------------ @@ -3175,12 +3168,8 @@ procedure TClipperBase.AddNewIntersectNode(e1, e2: PActive; topY: Int64); ip := GetClosestPointOnSegment(ip, e2.bot, e2.top) else begin - if (ip.Y < topY) then - ip.Y := topY else - ip.Y := fBotY; - if (absDx1 < absDx2) then - ip.X := TopX(e1, ip.Y) else - ip.X := TopX(e2, ip.Y); + ip.Y := Iif(ip.Y < topY, topY , fBotY); + ip.X := Iif(absDx1 < absDx2, TopX(e1, ip.Y), TopX(e2, ip.Y)); end; end; new(node); @@ -4031,9 +4020,7 @@ function TPolyPathBase.GetLevel: Integer; function TPolyPathBase.GetIsHole: Boolean; begin - if not Assigned(Parent) then - Result := false else - Result := not Odd(GetLevel); + Result := Iif(Assigned(Parent), not Odd(GetLevel), false); end; //------------------------------------------------------------------------------ diff --git a/Delphi/Clipper2Lib/Clipper.Minkowski.pas b/Delphi/Clipper2Lib/Clipper.Minkowski.pas index 1d7a82b2..bacb3ea2 100644 --- a/Delphi/Clipper2Lib/Clipper.Minkowski.pas +++ b/Delphi/Clipper2Lib/Clipper.Minkowski.pas @@ -2,7 +2,7 @@ (******************************************************************************* * Author : Angus Johnson * -* Date : 15 October 2022 * +* Date : 21 December 2023 * * Copyright : Angus Johnson 2010-2022 * * Purpose : Minkowski Addition and Difference * * License : http://www.boost.org/LICENSE_1_0.txt * @@ -51,9 +51,7 @@ function Minkowski(const Base, Path: TPath64; tmp: TPaths64; quad: TPath64; begin - if IsClosed then - delta := 0 else - delta := 1; + delta := Iif(IsClosed, 0 , 1); baseLen := Length(Base); pathLen := Length(Path); setLength(tmp, pathLen); @@ -71,10 +69,7 @@ function Minkowski(const Base, Path: TPath64; SetLength(quad, 4); SetLength(Result, (pathLen - delta) * baseLen); - - if IsClosed then - g := pathLen - 1 else - g := 0; + g := Iif(IsClosed, pathLen - 1, 0); for i := delta to pathLen - 1 do begin diff --git a/Delphi/Clipper2Lib/Clipper.Offset.pas b/Delphi/Clipper2Lib/Clipper.Offset.pas index 0aa35138..86c7727e 100644 --- a/Delphi/Clipper2Lib/Clipper.Offset.pas +++ b/Delphi/Clipper2Lib/Clipper.Offset.pas @@ -2,7 +2,7 @@ (******************************************************************************* * Author : Angus Johnson * -* Date : 28 November 2023 * +* Date : 21 December 2023 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : Path Offset (Inflate/Shrink) * @@ -426,9 +426,7 @@ function GetPerpendicD(const pt: TPoint64; const norm: TPointD; delta: double): function ToggleBoolIf(val, condition: Boolean): Boolean; {$IFDEF INLINING} inline; {$ENDIF} begin - if condition then - Result := not val else - Result := val; + Result := Iif(condition, not val, val); end; //------------------------------------------------------------------------------ @@ -444,13 +442,10 @@ procedure TClipperOffset.DoGroupOffset(group: TGroup); if group.endType = etPolygon then begin if (group.lowestPathIdx < 0) then fDelta := Abs(fDelta); - if group.reversed then - fGroupDelta := -fDelta else - fGroupDelta := fDelta; - end else - begin - fGroupDelta := Abs(fDelta);// * 0.5; - end; + fGroupDelta := Iif(group.reversed, -fDelta, fDelta); + end + else + fGroupDelta := Abs(fDelta); absDelta := Abs(fGroupDelta); if not ValidateBounds(group.boundsList, absDelta) then @@ -467,9 +462,10 @@ procedure TClipperOffset.DoGroupOffset(group: TGroup); // curve imprecision that's allowed is based on the size of the // offset (delta). Obviously very large offsets will almost always // require much less precision. See also offset_triginometry2.svg - if fArcTolerance > 0.01 then - arcTol := Min(absDelta, fArcTolerance) else - arcTol := Log10(2 + absDelta) * 0.25; // empirically derived + arcTol := Iif(fArcTolerance > 0.01, + Min(absDelta, fArcTolerance), + Log10(2 + absDelta) * 0.25); // empirically derived + //http://www.angusj.com/clipper2/Docs/Trigonometry.htm stepsPer360 := Pi / ArcCos(1 - arcTol / absDelta); if (stepsPer360 > absDelta * Pi) then @@ -493,6 +489,14 @@ procedure TClipperOffset.DoGroupOffset(group: TGroup); begin if fGroupDelta < 1 then Continue; pt0 := fInPath[0]; + + if Assigned(fDeltaCallback64) then + begin + fGroupDelta := fDeltaCallback64(fInPath, fNorms, 0, 0); + if TGroup(fGroupList[0]).reversed then fGroupDelta := -fGroupDelta; + absDelta := Abs(fGroupDelta); + end; + if (group.endType = etRound) then begin r := absDelta; @@ -955,9 +959,9 @@ procedure TClipperOffset.DoRound(j, k: Integer; angle: double); // when fDeltaCallback64 is assigned, fGroupDelta won't be constant, // so we'll need to do the following calculations for *every* vertex. absDelta := Abs(fGroupDelta); - if fArcTolerance > 0.01 then - arcTol := Min(absDelta, fArcTolerance) else - arcTol := Log10(2 + absDelta) * 0.25; // empirically derived + arcTol := Iif(fArcTolerance > 0.01, + Min(absDelta, fArcTolerance), + Log10(2 + absDelta) * 0.25); // empirically derived //http://www.angusj.com/clipper2/Docs/Trigonometry.htm stepsPer360 := Pi / ArcCos(1 - arcTol / absDelta); if (stepsPer360 > absDelta * Pi) then diff --git a/Delphi/Clipper2Lib/Clipper.RectClip.pas b/Delphi/Clipper2Lib/Clipper.RectClip.pas index c687a1fc..3eab8963 100644 --- a/Delphi/Clipper2Lib/Clipper.RectClip.pas +++ b/Delphi/Clipper2Lib/Clipper.RectClip.pas @@ -2,7 +2,7 @@ (******************************************************************************* * Author : Angus Johnson * -* Date : 9 September 2023 * +* Date : 21 December 2023 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : FAST rectangular clipping * @@ -282,7 +282,7 @@ function GetAdjacentLocation(loc: TLocation; isClockwise: Boolean): TLocation; var delta: integer; begin - if isClockwise then delta := 1 else delta := 3; + delta := Iif(isClockwise, 1 , 3); Result := TLocation((Ord(loc) + delta) mod 4); end; //------------------------------------------------------------------------------ @@ -291,9 +291,9 @@ function IsClockwise(prev, curr: TLocation; const prevPt, currPt, rectMidPt: TPoint64): Boolean; {$IFDEF INLINING} inline; {$ENDIF} begin - if AreOpposites(prev, curr) then - Result := CrossProduct(prevPt, rectMidPt, currPt) < 0 else - Result := HeadingClockwise(prev, curr); + Result := Iif(AreOpposites(prev, curr), + CrossProduct(prevPt, rectMidPt, currPt) < 0, + HeadingClockwise(prev, curr)); end; //------------------------------------------------------------------------------ @@ -517,9 +517,7 @@ procedure TRectClip64.AddCorner(prev, curr: TLocation); cnrIdx: integer; begin if prev = curr then Exit; - if (HeadingClockwise(prev, curr)) then - cnrIdx := Ord(prev) else - cnrIdx := Ord(curr); + cnrIdx := Iif(HeadingClockwise(prev, curr), Ord(prev), Ord(curr)); Add(fRectPath[cnrIdx]); end; //------------------------------------------------------------------------------ diff --git a/Delphi/Clipper2Lib/Clipper.pas b/Delphi/Clipper2Lib/Clipper.pas index 1d34c92b..1c36223b 100644 --- a/Delphi/Clipper2Lib/Clipper.pas +++ b/Delphi/Clipper2Lib/Clipper.pas @@ -2,7 +2,7 @@ (******************************************************************************* * Author : Angus Johnson * -* Date : 18 November 2023 * +* Date : 21 December 2023 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2023 * * Purpose : This module provides a simple interface to the Clipper Library * @@ -836,9 +836,8 @@ function PerpendicDistSqrd(const pt, line1, line2: TPoint64): double; b := pt.Y - line1.Y; c := line2.X - line1.X; d := line2.Y - line1.Y; - if (c = 0) and (d = 0) then - result := 0 else - result := Sqr(a * d - c * b) / (c * c + d * d); + result := Iif((c = 0) and (d = 0), + 0, Sqr(a * d - c * b) / (c * c + d * d)); end; //------------------------------------------------------------------------------ @@ -865,7 +864,7 @@ function SimplifyPath(const path: TPath64; Result := nil; highI := High(path); - if isClosedPath then minHigh := 2 else minHigh := 1; + minHigh := Iif(isClosedPath, 2, 1); if highI < minHigh then Exit; SetLength(srArray, highI +1); @@ -874,9 +873,8 @@ function SimplifyPath(const path: TPath64; pt := path[0]; prev := @srArray[highI]; next := @srArray[1]; - if isClosedPath then - pdSqrd := PerpendicDistSqrd(path[0], path[highI], path[1]) else - pdSqrd := invalidD; + pdSqrd := Iif(isClosedPath, + PerpendicDistSqrd(path[0], path[highI], path[1]), invalidD); end; with srArray[highI] do @@ -884,9 +882,8 @@ function SimplifyPath(const path: TPath64; pt := path[highI]; prev := @srArray[highI-1]; next := @srArray[0]; - if isClosedPath then - pdSqrd := PerpendicDistSqrd(path[highI], path[highI-1], path[0]) else - pdSqrd := invalidD; + pdSqrd := Iif(isClosedPath, + PerpendicDistSqrd(path[highI], path[highI-1], path[0]), invalidD); end; for i := 1 to highI -1 do