From c423a794b5355d549e3e888f9e1975442abace84 Mon Sep 17 00:00:00 2001 From: mattias Date: Mon, 10 Jul 2023 23:19:21 +0200 Subject: [PATCH] lazutils: added TPointArray to graphtype, added EllipsePolygon to GraphMath --- components/lazutils/graphmath.pp | 129 ++++++++++++++++++++++------- components/lazutils/graphtype.pp | 2 + lcl/interfaces/gtk2/gtk2winapi.inc | 75 +++-------------- lcl/lazregions.pas | 4 +- 4 files changed, 113 insertions(+), 97 deletions(-) diff --git a/components/lazutils/graphmath.pp b/components/lazutils/graphmath.pp index 12363fd792..921bccb843 100644 --- a/components/lazutils/graphmath.pp +++ b/components/lazutils/graphmath.pp @@ -32,7 +32,7 @@ interface Uses Types, Classes, SysUtils, Math, // LazUtils - LazUtilities; + GraphType, LazUtilities; Type TFloatPoint = Record @@ -72,6 +72,7 @@ function Distance(const Pt, SP, EP : TFloatPoint) : Extended; overload; function EccentricAngle(const PT : TPoint; const Rect : TRect) : Extended; function EllipseRadialLength(const Rect : TRect; EccentricAngle : Extended) : Longint; +function EllipsePolygon(const aRect: TRect): TPointArray; function FloatPoint(AX,AY : Extended): TFloatPoint; inline; @@ -139,7 +140,7 @@ Operator = (const Compare1, Compare2 : TRect) : Boolean; implementation -Operator + (const Addend1, Addend2 : TFloatPoint) : TFloatPoint; +operator+(const Addend1, Addend2: TFloatPoint): TFloatPoint; Begin With Result do begin X := Addend1.X + Addend2.X; @@ -147,7 +148,7 @@ Begin end; end; -Operator + (const Addend1 : TFloatPoint; Addend2 : Extended) : TFloatPoint; +operator+(const Addend1: TFloatPoint; Addend2: Extended): TFloatPoint; Begin With Result do begin X := Addend1.X + Addend2; @@ -155,12 +156,12 @@ Begin end; end; -Operator + (Addend1 : Extended; const Addend2 : TFloatPoint) : TFloatPoint; +operator+(Addend1: Extended; const Addend2: TFloatPoint): TFloatPoint; begin Result := Addend2 + Addend1; end; -Operator + (const Addend1 : TFloatPoint; const Addend2 : TPoint) : TFloatPoint; +operator+(const Addend1: TFloatPoint; const Addend2: TPoint): TFloatPoint; Begin With Result do begin X := Addend1.X + Addend2.X; @@ -168,12 +169,12 @@ Begin end; end; -Operator + (const Addend1 : TPoint; const Addend2 : TFloatPoint) : TFloatPoint; +operator+(const Addend1: TPoint; const Addend2: TFloatPoint): TFloatPoint; begin Result := Addend2 + Addend1; end; -Operator - (const Minuend, Subtrahend:TFloatPoint) : TFloatPoint; +operator-(const Minuend, Subtrahend: TFloatPoint): TFloatPoint; Begin With Result do begin X := Minuend.X - Subtrahend.X; @@ -181,7 +182,7 @@ Begin end; end; -Operator - (const Minuend : TFloatPoint; Subtrahend : Extended) : TFloatPoint; +operator-(const Minuend: TFloatPoint; Subtrahend: Extended): TFloatPoint; Begin With Result do begin X := Minuend.X - Subtrahend; @@ -189,7 +190,7 @@ Begin end; end; -Operator - (const Minuend : TFloatPoint; const Subtrahend : TPoint) : TFloatPoint; +operator-(const Minuend: TFloatPoint; const Subtrahend: TPoint): TFloatPoint; begin With Result do begin X := Minuend.X - Subtrahend.X; @@ -197,7 +198,7 @@ begin end; end; -Operator - (const Minuend : TPoint; const Subtrahend : TFloatPoint) : TFloatPoint; +operator-(const Minuend: TPoint; const Subtrahend: TFloatPoint): TFloatPoint; begin With Result do begin X := Minuend.X - Subtrahend.X; @@ -205,7 +206,7 @@ begin end; end; -Operator * (const Multiplicand, Multiplier : TFloatPoint) : TFloatPoint; +operator*(const Multiplicand, Multiplier: TFloatPoint): TFloatPoint; Begin With Result do begin X := Multiplicand.X * Multiplier.X; @@ -213,7 +214,7 @@ Begin end; end; -Operator * (const Multiplicand : TFloatPoint; Multiplier : Extended) : TFloatPoint; +operator*(const Multiplicand: TFloatPoint; Multiplier: Extended): TFloatPoint; Begin With Result do begin X := Multiplicand.X * Multiplier; @@ -221,12 +222,13 @@ Begin end; end; -Operator * (Multiplicand : Extended; const Multiplier : TFloatPoint) : TFloatPoint; +operator*(Multiplicand: Extended; const Multiplier: TFloatPoint): TFloatPoint; Begin Result := Multiplier*Multiplicand; end; -Operator * (const Multiplicand : TFloatPoint; const Multiplier : TPoint) : TFloatPoint; +operator*(const Multiplicand: TFloatPoint; const Multiplier: TPoint + ): TFloatPoint; begin With Result do begin X := Multiplicand.X * Multiplier.X; @@ -234,12 +236,13 @@ begin end; end; -Operator * (const Multiplicand : TPoint; const Multiplier : TFloatPoint) : TFloatPoint; +operator*(const Multiplicand: TPoint; const Multiplier: TFloatPoint + ): TFloatPoint; begin Result := Multiplier*Multiplicand; end; -Operator / (const Dividend, Divisor : TFloatPoint) : TFloatPoint; +operator/(const Dividend, Divisor: TFloatPoint): TFloatPoint; Begin With Result do begin X := Dividend.X / Divisor.X; @@ -247,7 +250,7 @@ Begin end; end; -Operator / (const Dividend : TFloatPoint; Divisor : Extended) : TFloatPoint; +operator/(const Dividend: TFloatPoint; Divisor: Extended): TFloatPoint; begin With Result do begin X := Dividend.X / Divisor; @@ -255,7 +258,7 @@ begin end; end; -Operator / (const Dividend : TFloatPoint; const Divisor : TPoint) : TFloatPoint; +operator/(const Dividend: TFloatPoint; const Divisor: TPoint): TFloatPoint; begin With Result do begin X := Dividend.X / Divisor.X; @@ -263,7 +266,7 @@ begin end; end; -Operator / (const Dividend : TPoint; const Divisor : TFloatPoint) : TFloatPoint; +operator/(const Dividend: TPoint; const Divisor: TFloatPoint): TFloatPoint; begin With Result do begin X := Dividend.X / Divisor.X; @@ -271,23 +274,23 @@ begin end; end; -Operator = (const Compare1, Compare2 : TPoint) : Boolean; +operator=(const Compare1, Compare2: TPoint): Boolean; begin Result := (Compare1.X = Compare2.X) and (Compare1.Y = Compare2.Y); end; -Operator = (const Compare1, Compare2 : TFloatPoint) : Boolean; +operator=(const Compare1, Compare2: TFloatPoint): Boolean; begin Result := (Compare1.X = Compare2.X) and (Compare1.Y = Compare2.Y); end; -Operator := (const Value : TFloatPoint) : TPoint; +operator:=(const Value: TFloatPoint): TPoint; begin Result.X := Trunc(SimpleRoundTo(Value.X, 0)); Result.Y := Trunc(SimpleRoundTo(Value.Y, 0)); end; -Operator := (const Value : TPoint) : TFloatPoint; +operator:=(const Value: TPoint): TFloatPoint; begin With Result do begin X := Value.X; @@ -295,7 +298,7 @@ begin end; end; -Operator = (const Compare1, Compare2 : TRect) : Boolean; +operator=(const Compare1, Compare2: TRect): Boolean; begin Result := (Compare1.Left = Compare2.Left) and (Compare1.Top = Compare2.Top) and @@ -665,7 +668,7 @@ end; for use in other routines such as EccentricAngle. ------------------------------------------------------------------------------} -function Distance(const Pt1,Pt2 : TPoint) : Extended; +function Distance(const PT1, Pt2: TPoint): Extended; begin Result := Sqrt(Sqr(Pt2.X - Pt1.X) + Sqr(Pt2.Y - Pt1.Y)); end; @@ -783,6 +786,72 @@ begin Result := TruncToInt(R); end; +function EllipsePolygon(const aRect: TRect): TPointArray; +{ Our Ellipse is axis-aligned, so it's parametrization is: + + X(t) = Xc + a * cos(t) + Y(t) = Yc + b * sin(t) + + (Xc,Yc) is the center of the ellipse } +var + n_points, i, n4, aLeft, aRight, aTop, aBottom: Integer; + Xc, Yc, a, b, MaxR, t: single; + AX, AY, BX, BY, CX, CY, Deviation: single; +begin + Xc:=single(aRect.Left+aRect.Right)/2; + Yc:=single(aRect.Top+aRect.Bottom)/2; + a:=single(aRect.Width)/2; + b:=single(aRect.Height)/2; + MaxR:=Max(a,b); + + // Choose the minimum number of points, so that the error - the distance + // between the edges and the mathematical circle is less than the rounding + // error (0.5), for a smoother step 0.4. + n_points:=0; + repeat + inc(n_points,4); + t := single(1) / single(n_points) * 2 * Pi; + AX := MaxR * cos(t); + AY := MaxR * sin(t); + BX := MaxR * cos(t/2); + BY := MaxR * sin(t/2); + CX := (AX + MaxR) /2; + CY := (AY + 0) /2; + Deviation := sqrt(sqr(BX-CX)+sqr(BY-CY)); + until Deviation<0.4; + SetLength(Result{%H-}, n_points); + + // And fill them iterating through the ellipse + // by computing the upper right quarter and mirror the other three quartes. + // This way a perfectly symmetrical ellipse is created. + n4 := n_points div 4; + for i := 0 to n4 do + begin + t := single(i) / single(n_points) * 2 * Pi; + aRight := Round(Xc + a * cos(t)); + aLeft := Trunc(2*Xc - aRight); + aTop := Round(Yc + b * sin(t)); + aBottom := Trunc(2*Yc - aTop); + Result[i].X := aRight; + Result[i].Y := aTop; + if i>0 then + begin + Result[n_points - i].X := aRight; + Result[n_points - i].Y := aBottom; + end; + if i0 then + begin + Result[2*n4 + i].X := aLeft; + Result[2*n4 + i].Y := aBottom; + end; + end; + end; +end; + {------------------------------------------------------------------------------ Method: FloatPoint Params: AX, AY @@ -895,8 +964,8 @@ end; be Freed when done by calling to ReallocMem(Points, 0). ------------------------------------------------------------------------------} -procedure PolyBezier2Polyline(Beziers: Array of TBezier; - var Points : PPoint; var Count : Longint); +procedure PolyBezier2Polyline(Beziers: array of TBezier; var Points: PPoint; + var Count: Longint); var I : Integer; begin @@ -930,8 +999,8 @@ end; by calling to ReallocMem(Points, 0). ------------------------------------------------------------------------------} -procedure PolyBezier2Polyline(Beziers : Array of TPoint; var Points : PPoint; - var Count : Longint; Continuous : Boolean); +procedure PolyBezier2Polyline(Beziers: array of TPoint; var Points: PPoint; + var Count: Longint; Continuous: Boolean); begin PolyBezier2Polyline(@Beziers[0],High(Beziers) + 1, Points, Count, Continuous); end; @@ -1052,7 +1121,7 @@ end; that is, it is the Center. ------------------------------------------------------------------------------} -function Quadrant(const Pt,Center : TPoint) : Integer; +function Quadrant(const PT, Center: TPoint): Integer; var X,Y,CX,CY : Longint; begin diff --git a/components/lazutils/graphtype.pp b/components/lazutils/graphtype.pp index f44d513a06..34ca17ab2e 100644 --- a/components/lazutils/graphtype.pp +++ b/components/lazutils/graphtype.pp @@ -39,6 +39,8 @@ uses {$endif} type + TPointArray = array of TPoint; + TGraphicsColor = {$ifdef UseSystemUITypes}System.UITypes.TColor{$else}-$7FFFFFFF-1..$7FFFFFFF{$endif}; TGraphicsFillStyle = ( diff --git a/lcl/interfaces/gtk2/gtk2winapi.inc b/lcl/interfaces/gtk2/gtk2winapi.inc index 1fc0d4ccc7..475afa4cfb 100644 --- a/lcl/interfaces/gtk2/gtk2winapi.inc +++ b/lcl/interfaces/gtk2/gtk2winapi.inc @@ -1294,83 +1294,28 @@ end; { Gtk2 has no function to build an elliptical region so we approximate it to a - polygon. Our Ellipse is axis-aligned, so it's parametrization is: - - X(t) = Xc + a * cos(t) - Y(t) = Yc + b * sin(t) - - (Xc,Yc) is the center of the ellipse + polygon. } function TGtk2WidgetSet.CreateEllipticRgn(X1, Y1, X2, Y2: Integer): HRGN; var - points: array of TGdkPoint; - n_points, i, n4, aLeft, aRight, aTop, aBottom: Integer; - Xc, Yc, a, b, MaxR, t: single; - AX, AY, BX, BY, CX, CY, Deviation: single; + Points: TPointArray; + gPoints: array of TGdkPoint; + i: Integer; GObject: PGdiObject; RegionObj: PGdkRegion; begin - Xc:=single(X1+X2)/2; - Yc:=single(Y1+Y2)/2; - a:=single(X2-X1)/2; - b:=single(Y2-Y1)/2; - MaxR:=Max(a,b); - - // Choose the minimum number of points - // so that the error - the distance between the edges and the mathematical - // circle is less than the rounding error (0.5), for a smoother step 0.4. - n_points:=0; - repeat - inc(n_points,4); - t := single(1) / single(n_points) * 2 * Pi; - AX := MaxR * cos(t); - AY := MaxR * sin(t); - BX := MaxR * cos(t/2); - BY := MaxR * sin(t/2); - CX := (AX + MaxR) /2; - CY := (AY + 0) /2; - Deviation := sqrt(sqr(BX-CX)+sqr(BY-CY)); - until Deviation<0.4; - SetLength(points{%H-}, n_points); - - // And fill them iterating through the ellipse - // by computing the upper right quarter and mirror the other three quartes. - // This way a perfectly symmetrical ellipse is created. - n4 := n_points div 4; - for i := 0 to n4 do - begin - t := single(i) / single(n_points) * 2 * Pi; - aRight := Round(Xc + a * cos(t)); - aLeft := Trunc(2*Xc - aRight); - aTop := Round(Yc + b * sin(t)); - aBottom := Trunc(2*Yc - aTop); - points[i].X := aRight; - points[i].Y := aTop; - if i>0 then - begin - points[n_points - i].X := aRight; - points[n_points - i].Y := aBottom; - end; - if i0 then - begin - points[2*n4 + i].X := aLeft; - points[2*n4 + i].Y := aBottom; - end; - end; + Points:=EllipsePolygon(Rect(X1,Y1,X2,Y2)); + SetLength(gPoints,length(Points)); + for i:=0 to length(Points)-1 do begin + gPoints[i].x:=Points[i].x; + gPoints[i].y:=Points[i].y; end; GObject := NewGDIObject(gdiRegion); - RegionObj := gdk2.gdk_region_polygon(@points[0], n_points, GDK_WINDING_RULE); + RegionObj := gdk2.gdk_region_polygon(@gPoints[0], length(gPoints), GDK_WINDING_RULE); GObject^.GDIRegionObject := RegionObj; Result := HRGN({%H-}PtrUInt(GObject)); - - // Free the allocated array - SetLength(points, 0); //DebugLn('TGtk2WidgetSet.CreateRectRgn A ',GDKRegionAsString(RegionObj)); end; diff --git a/lcl/lazregions.pas b/lcl/lazregions.pas index 92b119de74..7bc0ac018e 100644 --- a/lcl/lazregions.pas +++ b/lcl/lazregions.pas @@ -11,12 +11,12 @@ interface uses Classes, SysUtils, fpcanvas, - LCLType; + LCLType, GraphType; type TLazRegionFillMode = (rfmOddEven, rfmWinding); - TPointArray = array of TPoint; + TPointArray = GraphType.TPointArray; { TLazRegionPart }