mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-16 16:12:57 +02:00
TAChart: Improved drawing algorithm for 3d pie series.
git-svn-id: trunk@60694 -
This commit is contained in:
parent
9a22507cdb
commit
f175271dc3
@ -87,6 +87,7 @@ type
|
|||||||
protected
|
protected
|
||||||
function CalcInnerRadius: Integer; inline;
|
function CalcInnerRadius: Integer; inline;
|
||||||
procedure GetLegendItems(AItems: TChartLegendItems); override;
|
procedure GetLegendItems(AItems: TChartLegendItems); override;
|
||||||
|
procedure SortSlices;
|
||||||
property InnerRadiusPercent: Integer
|
property InnerRadiusPercent: Integer
|
||||||
read FInnerRadiusPercent write SetInnerRadiusPercent default 0;
|
read FInnerRadiusPercent write SetInnerRadiusPercent default 0;
|
||||||
property MarkPositionCentered: Boolean
|
property MarkPositionCentered: Boolean
|
||||||
@ -190,6 +191,13 @@ uses
|
|||||||
Math,
|
Math,
|
||||||
TAChartStrConsts, TATypes, TACustomSource, TAGeometry, TAGraph;
|
TAChartStrConsts, TATypes, TACustomSource, TAGeometry, TAGraph;
|
||||||
|
|
||||||
|
const
|
||||||
|
TWO_PI = 2 * pi;
|
||||||
|
PI_1_4 = pi / 4;
|
||||||
|
PI_3_4 = (3 / 4) * pi;
|
||||||
|
PI_5_4 = (5 / 4) * pi;
|
||||||
|
PI_7_4 = (7 / 4) * pi;
|
||||||
|
|
||||||
{ TPieSlice }
|
{ TPieSlice }
|
||||||
|
|
||||||
function TPieSlice.Angle: Double;
|
function TPieSlice.Angle: Double;
|
||||||
@ -284,30 +292,31 @@ end;
|
|||||||
procedure TCustomPieSeries.Draw(ADrawer: IChartDrawer);
|
procedure TCustomPieSeries.Draw(ADrawer: IChartDrawer);
|
||||||
const
|
const
|
||||||
STEP = 4;
|
STEP = 4;
|
||||||
TWO_PI = 2 * pi;
|
|
||||||
PI_1_4 = pi / 4;
|
|
||||||
PI_3_4 = (3 / 4) * pi;
|
|
||||||
PI_5_4 = (5 / 4) * pi;
|
|
||||||
PI_7_4 = (7 / 4) * pi;
|
|
||||||
var
|
var
|
||||||
ps: TPieSlice;
|
ps: TPieSlice;
|
||||||
scaled_depth: Integer;
|
scaled_depth: Integer;
|
||||||
innerRadius: Integer;
|
innerRadius: Integer;
|
||||||
|
|
||||||
function PrevSlice(ASlice: TPieSlice): TPieSlice;
|
function PrevSlice(ASlice: TPieSlice): TPieSlice;
|
||||||
|
var
|
||||||
|
slice: TPieSlice;
|
||||||
begin
|
begin
|
||||||
if ASlice.FOrigIndex = 0 then
|
for slice in FSlices do
|
||||||
Result := FSlices[High(FSlices)]
|
if slice.FNextAngle = ASlice.FPrevAngle then begin
|
||||||
else
|
Result := slice;
|
||||||
Result := FSlices[ASlice.FOrigIndex - 1];
|
exit;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function NextSlice(ASlice: TPieSlice): TPieSlice;
|
function NextSlice(ASlice: TPieSlice): TPieSlice;
|
||||||
|
var
|
||||||
|
slice: TPieSlice;
|
||||||
begin
|
begin
|
||||||
if ASlice.FOrigIndex = High(FSlices) then
|
for slice in FSlices do
|
||||||
Result := FSlices[0]
|
if slice.FPrevAngle = ASlice.FNextAngle then begin
|
||||||
else
|
Result := slice;
|
||||||
Result := FSlices[ASlice.FOrigIndex + 1]
|
exit;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function SliceExploded(ASlice: TPieSlice): Boolean;
|
function SliceExploded(ASlice: TPieSlice): Boolean;
|
||||||
@ -316,15 +325,25 @@ var
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function StartEdgeVisible(ASlice: TPieSlice): Boolean;
|
function StartEdgeVisible(ASlice: TPieSlice): Boolean;
|
||||||
|
var
|
||||||
|
prev: TPieSlice;
|
||||||
begin
|
begin
|
||||||
Result := InRange(ASlice.FPrevAngle, PI_1_4, PI_5_4) and
|
Result := InRange(ASlice.FPrevAngle, PI_1_4, PI_5_4);
|
||||||
(SliceExploded(ASlice) or (SliceExploded(PrevSlice(ASlice))));
|
if Result then begin
|
||||||
|
prev := PrevSlice(ASlice);
|
||||||
|
Result := SliceExploded(ASlice) or SliceExploded(prev) or not prev.FVisible;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function EndEdgeVisible(ASlice: TPieSlice): Boolean;
|
function EndEdgeVisible(ASlice: TPieSlice): Boolean;
|
||||||
|
var
|
||||||
|
next: TPieSlice;
|
||||||
begin
|
begin
|
||||||
Result := not InRange(ASlice.FNextAngle, PI_1_4, PI_5_4) and
|
Result := not InRange(ASlice.FNextAngle, PI_1_4, PI_5_4);
|
||||||
(SliceExploded(ASlice) or SliceExploded(NextSlice(ASlice)));
|
if Result then begin
|
||||||
|
next := NextSlice(ASlice);
|
||||||
|
Result := SliceExploded(ASlice) or SliceExploded(next) or not next.FVisible;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure DrawArc3D(ASlice: TPieSlice; AInside: Boolean);
|
procedure DrawArc3D(ASlice: TPieSlice; AInside: Boolean);
|
||||||
@ -464,51 +483,14 @@ begin
|
|||||||
ADrawer.SetPen(EdgePen);
|
ADrawer.SetPen(EdgePen);
|
||||||
if Depth > 0 then begin
|
if Depth > 0 then begin
|
||||||
scaled_depth := ADrawer.Scale(Depth);
|
scaled_depth := ADrawer.Scale(Depth);
|
||||||
FindLeftMostIndex(iL);
|
for i:=0 to High(FSlices) do begin
|
||||||
FindRegionIndexes(i14);
|
ps := FSlices[i];
|
||||||
|
if EndEdgeVisible(ps) then
|
||||||
if FSlices[iL].FVisible then begin
|
DrawEndEdge3D(ps);
|
||||||
if StartEdgeVisible(FSlices[iL]) then
|
DrawVisibleArc3D(ps);
|
||||||
DrawStartEdge3D(FSlices[iL]);
|
if StartEdgeVisible(ps) then
|
||||||
if EndEdgeVisible(FSlices[iL]) then
|
DrawStartEdge3D(ps);
|
||||||
DrawEndEdge3D(FSlices[iL]);
|
|
||||||
DrawArc3D(FSlices[iL], false);
|
|
||||||
DrawArc3D(FSlices[iL], true);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
for i:=iL+1 to High(FSlices) do
|
|
||||||
if FSlices[i].FVisible then begin
|
|
||||||
if StartEdgeVisible(FSlices[i]) then
|
|
||||||
DrawStartEdge3D(FSlices[i]);
|
|
||||||
if EndEdgeVisible(FSlices[i]) then
|
|
||||||
DrawEndEdge3D(FSlices[i]);
|
|
||||||
DrawArc3D(FSlices[i], false);
|
|
||||||
DrawArc3d(FSlices[i], true);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if iL <> 0 then
|
|
||||||
for i:= iL downto 0 do
|
|
||||||
if FSlices[i].FVisible then begin
|
|
||||||
if StartEdgeVisible(FSlices[i]) then
|
|
||||||
DrawStartEdge3D(FSlices[i]);
|
|
||||||
if (i <> iL) and EndEdgeVisible(FSlices[i]) then
|
|
||||||
DrawEndEdge3D(FSlices[i]);
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Draw arcs
|
|
||||||
if FSlices[iL].FNextAngle > PI_7_4 then dec(iL);
|
|
||||||
if FSlices[i14].FNextAngle > PI_7_4 then dec(i14);
|
|
||||||
for i := iL downto i14 do
|
|
||||||
DrawVisibleArc3D(FSlices[i]);
|
|
||||||
|
|
||||||
for i := 0 to i14 do begin
|
|
||||||
if EndEdgeVisible(FSlices[i]) then DrawEndEdge3D(FSlices[i]);
|
|
||||||
DrawVisibleArc3D(FSlices[i]);
|
|
||||||
end;
|
|
||||||
{
|
|
||||||
for i:= iL downto 0 do
|
|
||||||
DrawVisibleArc3D(FSlices[i]);
|
|
||||||
}
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ADrawer.SetPen(EdgePen);
|
ADrawer.SetPen(EdgePen);
|
||||||
@ -724,6 +706,44 @@ begin
|
|||||||
Result := ColorDef(Result, SLICE_COLORS[AIndex mod Length(SLICE_COLORS)]);
|
Result := ColorDef(Result, SLICE_COLORS[AIndex mod Length(SLICE_COLORS)]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomPieSeries.SortSlices;
|
||||||
|
|
||||||
|
function CompareSlices(ASlice1, ASlice2: TPieSlice): Integer;
|
||||||
|
var
|
||||||
|
angle1, angle2: Double;
|
||||||
|
begin
|
||||||
|
angle1 := Max(cos(ASlice1.FPrevAngle - PI_1_4), cos(ASlice1.FNextAngle - PI_1_4));
|
||||||
|
angle2 := Max(cos(ASlice2.FPrevAngle - PI_1_4), cos(ASlice2.FNextAngle - PI_1_4));
|
||||||
|
Result := CompareValue(angle1, angle2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure QuickSort(const L, R: Integer);
|
||||||
|
var
|
||||||
|
i, j, m: Integer;
|
||||||
|
ps: TPieSlice;
|
||||||
|
begin
|
||||||
|
i := L;
|
||||||
|
j := R;
|
||||||
|
m := (L + R) div 2;
|
||||||
|
while (i <= j) do begin
|
||||||
|
while CompareSlices(FSlices[i], FSlices[m]) < 0 do inc(i);
|
||||||
|
while CompareSlices(FSlices[j], FSlices[m]) > 0 do dec(j);
|
||||||
|
if i <= j then begin
|
||||||
|
ps := FSlices[i];
|
||||||
|
FSlices[i] := FSlices[j];
|
||||||
|
FSlices[j] := ps;
|
||||||
|
inc(i);
|
||||||
|
dec(j);
|
||||||
|
end;
|
||||||
|
if L < j then QuickSort(L, j);
|
||||||
|
if i < R then QuickSort(i, R);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
QuickSort(0, High(FSlices));
|
||||||
|
end;
|
||||||
|
|
||||||
function TCustomPieSeries.TryRadius(ADrawer: IChartDrawer): TRect;
|
function TCustomPieSeries.TryRadius(ADrawer: IChartDrawer): TRect;
|
||||||
|
|
||||||
function EndPoint(AAngle, ARadius: Double): TPoint;
|
function EndPoint(AAngle, ARadius: Double): TPoint;
|
||||||
@ -850,6 +870,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
SetLength(FSlices, j);
|
SetLength(FSlices, j);
|
||||||
InflateRect(Result, MARGIN, MARGIN);
|
InflateRect(Result, MARGIN, MARGIN);
|
||||||
|
SortSlices;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user