TAChart: Add clsRoundRect and clsRoundSides to TChartLabelShape enumeration

git-svn-id: trunk@38579 -
This commit is contained in:
ask 2012-09-08 11:24:09 +00:00
parent 5417050ae2
commit c7d446ef38
2 changed files with 82 additions and 25 deletions

View File

@ -31,6 +31,7 @@ type
public public
constructor Init; constructor Init;
procedure Add(const APoint: TPoint); procedure Add(const APoint: TPoint);
procedure AddNoDup(const APoint: TPoint); inline;
function LastPoint: TPoint; inline; function LastPoint: TPoint; inline;
function Purge: TPointArray; inline; function Purge: TPointArray; inline;
end; end;
@ -42,7 +43,7 @@ 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( procedure SliceToPolygon(
AAngleStart, AAngleLength: Double; AStep: Integer; var APoly: TPolygon); AAngleStart, AAngleLength: Double; AStep: Integer; var APoly: TPolygon);
function TesselateRadialPie( function TesselateRadialPie(
AAngleStart, AAngleLength: Double; AStep: Integer): TPointArray; AAngleStart, AAngleLength: Double; AStep: Integer): TPointArray;
@ -82,8 +83,10 @@ function RectIntersectsRect(
function RotatePoint(const APoint: TDoublePoint; AAngle: Double): TDoublePoint; overload; function RotatePoint(const APoint: TDoublePoint; AAngle: Double): TDoublePoint; overload;
function RotatePoint(const APoint: TPoint; AAngle: Double): TPoint; overload; function RotatePoint(const APoint: TPoint; AAngle: Double): TPoint; overload;
function RotatePointX(AX, AAngle: Double): TPoint; function RotatePointX(AX, AAngle: Double): TPoint;
function RotateRect(const ARect: TRect; AAngle: Double): TPointArray;
function RoundPoint(APoint: TDoublePoint): TPoint; function RoundPoint(APoint: TDoublePoint): TPoint;
function TesselateRect(const ARect: TRect): TPointArray;
function TesselateEllipse(const ABounds: TRect; AStep: Integer): TPointArray;
function TesselateRoundRect(const ARect: TRect; ARadius, AStep: Integer): TPointArray;
operator +(const A: TPoint; B: TSize): TPoint; overload; inline; operator +(const A: TPoint; B: TSize): TPoint; overload; inline;
operator +(const A, B: TPoint): TPoint; overload; inline; operator +(const A, B: TPoint): TPoint; overload; inline;
@ -430,9 +433,13 @@ begin
Result.Y := Round(sa * AX); Result.Y := Round(sa * AX);
end; end;
function RotateRect(const ARect: TRect; AAngle: Double): TPointArray; function RoundPoint(APoint: TDoublePoint): TPoint;
var begin
i: Integer; Result.X := Round(APoint.X);
Result.Y := Round(APoint.Y);
end;
function TesselateRect(const ARect: TRect): TPointArray;
begin begin
SetLength(Result, 4); SetLength(Result, 4);
with ARect do begin with ARect do begin
@ -441,14 +448,54 @@ begin
Result[2] := BottomRight; Result[2] := BottomRight;
Result[3] := Point(Right, Top); Result[3] := Point(Right, Top);
end; end;
for i := 0 to High(Result) do
Result[i] := RotatePoint(Result[i], AAngle);
end; end;
function RoundPoint(APoint: TDoublePoint): TPoint; function TesselateEllipse(const ABounds: TRect; AStep: Integer): TPointArray;
var
e: TEllipse;
p: TPolygon;
begin begin
Result.X := Round(APoint.X); with ABounds do
Result.Y := Round(APoint.Y); e.InitBoundingBox(Left, Top, Right, Bottom);
p.Init;
e.SliceToPolygon(0, 2 * Pi, AStep, p);
Result := p.Purge;
end;
function TesselateRoundRect(
const ARect: TRect; ARadius, AStep: Integer): TPointArray;
var
e: TEllipse;
p: TPolygon;
begin
with ARect do begin
if Min(Right - Left, Bottom - Top) < 2 * ARadius then exit(nil);
p.Init;
e.FR := DoublePoint(ARadius, ARadius);
p.AddNoDup(Point(Right, Bottom - ARadius));
p.AddNoDup(Point(Right, Top + ARadius));
e.FC := DoublePoint(Right - ARadius, Top + ARadius);
e.SliceToPolygon(0, Pi / 2, AStep, p);
p.AddNoDup(Point(Right - ARadius, Top));
p.AddNoDup(Point(Left + ARadius, Top));
e.FC := DoublePoint(Left + ARadius, Top + ARadius);
e.SliceToPolygon(Pi / 2, Pi / 2, AStep, p);
p.AddNoDup(Point(Left, Top + ARadius));
p.AddNoDup(Point(Left, Bottom - ARadius));
e.FC := DoublePoint(Left + ARadius, Bottom - ARadius);
e.SliceToPolygon(Pi, Pi / 2, AStep, p);
p.AddNoDup(Point(Left + ARadius, Bottom));
p.AddNoDup(Point(Right - ARadius, Bottom));
e.FC := DoublePoint(Right - ARadius, Bottom - ARadius);
e.SliceToPolygon(Pi * 3/2, Pi / 2, AStep, p);
end;
Result := p.Purge;
end; end;
operator + (const A: TPoint; B: TSize): TPoint; operator + (const A: TPoint; B: TSize): TPoint;
@ -554,6 +601,12 @@ begin
FCount += 1; FCount += 1;
end; end;
procedure TPolygon.AddNoDup(const APoint: TPoint);
begin
if (FCount = 0) or (LastPoint <> APoint) then
Add(APoint);
end;
constructor TPolygon.Init; constructor TPolygon.Init;
begin begin
FCount := 0; FCount := 0;
@ -589,7 +642,7 @@ begin
FR.Y := Abs(AY1 - AY2) / 2; FR.Y := Abs(AY1 - AY2) / 2;
end; end;
procedure TEllipse.RadialPieToPolygon( procedure TEllipse.SliceToPolygon(
AAngleStart, AAngleLength: Double; AStep: Integer; var APoly: TPolygon); AAngleStart, AAngleLength: Double; AStep: Integer; var APoly: TPolygon);
var var
lastAngle: Double; lastAngle: Double;
@ -644,7 +697,6 @@ begin
end; end;
Rec(tprev, tlast); Rec(tprev, tlast);
Add(tlast); Add(tlast);
SafeAddPoint(RoundPoint(FC), 0);
end; end;
// Represent the ellipse sector with a polygon on an integer grid. // Represent the ellipse sector with a polygon on an integer grid.
@ -655,7 +707,8 @@ var
resultPoly: TPolygon; resultPoly: TPolygon;
begin begin
resultPoly.Init; resultPoly.Init;
RadialPieToPolygon(AAngleStart, AAngleLength, AStep, resultPoly); SliceToPolygon(AAngleStart, AAngleLength, AStep, resultPoly);
resultPoly.AddNoDup(RoundPoint(FC));
Result := resultPoly.Purge; Result := resultPoly.Purge;
end; end;

View File

@ -39,7 +39,7 @@ type
property Top default DEF_LABEL_MARGIN_Y; property Top default DEF_LABEL_MARGIN_Y;
end; end;
TChartLabelShape = (clsRectangle, clsEllipse); TChartLabelShape = (clsRectangle, clsEllipse, clsRoundRect, clsRoundSide);
TChartTextElement = class(TChartElement) TChartTextElement = class(TChartElement)
strict private strict private
@ -349,25 +349,29 @@ end;
function TChartTextElement.GetLabelPolygon( function TChartTextElement.GetLabelPolygon(
ADrawer: IChartDrawer; ASize: TPoint): TPointArray; ADrawer: IChartDrawer; ASize: TPoint): TPointArray;
const
STEP = 3;
var var
e: TEllipse;
a: Double; a: Double;
i: Integer;
b: TRect; b: TRect;
i: Integer;
begin begin
a := GetLabelAngle;
b := GetBoundingBox(ADrawer, ASize); b := GetBoundingBox(ADrawer, ASize);
case Shape of case Shape of
clsRectangle: clsRectangle:
Result := RotateRect(b, a); Result := TesselateRect(b);
clsEllipse: begin clsEllipse:
e.InitBoundingBox(b.Left, b.Top, b.Right, b.Bottom); Result := TesselateEllipse(b, STEP);
Result := e.TesselateRadialPie(0, 2 * Pi, 3); clsRoundRect:
SetLength(Result, Length(Result) - 1); Result := TesselateRoundRect(
for i := 0 to High(Result) do b, Min(b.Right - b.Left, b.Bottom - b.Top) div 3, STEP);
Result[i] := RotatePoint(Result[i], a); clsRoundSide:
end; Result := TesselateRoundRect(
b, Min(b.Right - b.Left, b.Bottom - b.Top) div 2, STEP);
end; end;
a := GetLabelAngle;
for i := 0 to High(Result) do
Result[i] := RotatePoint(Result[i], a);
end; end;
function TChartTextElement.GetLinkPen: TChartPen; function TChartTextElement.GetLinkPen: TChartPen;