TAChart: Add TAGeometry.TPolygon utility object

git-svn-id: trunk@38575 -
This commit is contained in:
ask 2012-09-08 09:48:31 +00:00
parent df21315edc
commit 1a87d875b4

View File

@ -24,6 +24,17 @@ uses
TAChartUtils, Types; TAChartUtils, Types;
type type
TPolygon = object
public
FPoints: TPointArray;
FCount: Integer;
public
constructor Init;
procedure Add(const APoint: TPoint);
function LastPoint: TPoint; inline;
function Purge: TPointArray; inline;
end;
TEllipse = object TEllipse = object
public public
FC: TDoublePoint; FC: TDoublePoint;
@ -31,6 +42,8 @@ type
constructor InitBoundingBox(AX1, AY1, AX2, AY2: Integer); constructor InitBoundingBox(AX1, AY1, AX2, AY2: Integer);
public public
function GetPoint(AParametricAngle: Double): TDoublePoint; function GetPoint(AParametricAngle: Double): TDoublePoint;
procedure RadialPieToPolygon(
AAngleStart, AAngleLength: Double; AStep: Integer; var APoly: TPolygon);
function TesselateRadialPie( function TesselateRadialPie(
AAngleStart, AAngleLength: Double; AStep: Integer): TPointArray; AAngleStart, AAngleLength: Double; AStep: Integer): TPointArray;
end; end;
@ -531,6 +544,33 @@ begin
Result.Y := ASize.cy; Result.Y := ASize.cy;
end; end;
{ TPolygon }
procedure TPolygon.Add(const APoint: TPoint);
begin
if FCount > High(FPoints) then
SetLength(FPoints, Max(2 * FCount, 16));
FPoints[FCount] := APoint;
FCount += 1;
end;
constructor TPolygon.Init;
begin
FCount := 0;
FPoints := nil;
end;
function TPolygon.LastPoint: TPoint;
begin
Result := FPoints[FCount - 1];
end;
function TPolygon.Purge: TPointArray;
begin
SetLength(FPoints, FCount);
Result := FPoints;
end;
{ TEllipse } { TEllipse }
function TEllipse.GetPoint(AParametricAngle: Double): TDoublePoint; function TEllipse.GetPoint(AParametricAngle: Double): TDoublePoint;
@ -549,27 +589,15 @@ begin
FR.Y := Abs(AY1 - AY2) / 2; FR.Y := Abs(AY1 - AY2) / 2;
end; end;
// Represent the ellipse sector with a polygon on an integer grid. procedure TEllipse.RadialPieToPolygon(
// Polygon vertices are no more then AStep pixels apart. AAngleStart, AAngleLength: Double; AStep: Integer; var APoly: TPolygon);
function TEllipse.TesselateRadialPie(
AAngleStart, AAngleLength: Double; AStep: Integer): TPointArray;
var var
resultPoints: TPointArray = nil;
cnt: Integer = 0;
lastAngle: Double; lastAngle: Double;
procedure AddPoint(APoint: TPoint);
begin
if cnt > High(resultPoints) then
SetLength(resultPoints, 2 * cnt);
resultPoints[cnt] := Point(APoint.X, APoint.Y);
cnt += 1;
end;
procedure SafeAddPoint(APoint: TPoint; AAngle: Double); procedure SafeAddPoint(APoint: TPoint; AAngle: Double);
begin begin
if resultPoints[cnt - 1] <> APoint then begin if APoly.LastPoint <> APoint then begin
AddPoint(APoint); APoly.Add(APoint);
lastAngle := AAngle; lastAngle := AAngle;
end; end;
end; end;
@ -579,7 +607,7 @@ var
pt: TPoint; pt: TPoint;
begin begin
pt := RoundPoint(GetPoint(AHi)); pt := RoundPoint(GetPoint(AHi));
if PointDist(resultPoints[cnt - 1], pt) <= Sqr(AStep) then if PointDist(APoly.LastPoint, pt) <= Sqr(AStep) then
SafeAddPoint(pt, AHi) SafeAddPoint(pt, AHi)
else begin else begin
Rec(ALo, (ALo + AHi) / 2); Rec(ALo, (ALo + AHi) / 2);
@ -599,15 +627,13 @@ var
begin begin
tprev := AAngleStart; tprev := AAngleStart;
tlast := AAngleStart + AAngleLength; tlast := AAngleStart + AAngleLength;
APoly.Add(RoundPoint(GetPoint(tprev)));
if (FR.X < 1) or (FR.Y < 1) then begin if (FR.X < 1) or (FR.Y < 1) then begin
// Ellipse has degenerated into a line. // Ellipse has degenerated into a line.
SetLength(resultPoints, 2);
AddPoint(RoundPoint(GetPoint(tprev)));
Add(tlast); Add(tlast);
exit(resultPoints); exit;
end; end;
SetLength(resultPoints, 32); APoly.Add(RoundPoint(GetPoint(tprev)));
AddPoint(RoundPoint(GetPoint(tprev)));
lastAngle := tprev; lastAngle := tprev;
t := Ceil(tprev / HalfPi) * HalfPi; t := Ceil(tprev / HalfPi) * HalfPi;
while t < tlast do begin while t < tlast do begin
@ -619,8 +645,18 @@ begin
Rec(tprev, tlast); Rec(tprev, tlast);
Add(tlast); Add(tlast);
SafeAddPoint(RoundPoint(FC), 0); SafeAddPoint(RoundPoint(FC), 0);
SetLength(resultPoints, cnt); end;
Result := resultPoints;
// Represent the ellipse sector with a polygon on an integer grid.
// Polygon vertices are no more then AStep pixels apart.
function TEllipse.TesselateRadialPie(
AAngleStart, AAngleLength: Double; AStep: Integer): TPointArray;
var
resultPoly: TPolygon;
begin
resultPoly.Init;
RadialPieToPolygon(AAngleStart, AAngleLength, AStep, resultPoly);
Result := resultPoly.Purge;
end; end;
end. end.