TAChart: Fix bar series shapes when axes are rotated.

git-svn-id: trunk@60767 -
This commit is contained in:
wp 2019-03-25 00:56:54 +00:00
parent 0bfea66f90
commit b72b08174e
6 changed files with 203 additions and 72 deletions

4
.gitattributes vendored
View File

@ -5034,8 +5034,8 @@ components/tachart/demo/axistransf/axistransfdemo.lpi svneol=native#text/plain
components/tachart/demo/axistransf/axistransfdemo.lpr svneol=native#text/pascal
components/tachart/demo/axistransf/main.lfm svneol=native#text/plain
components/tachart/demo/axistransf/main.pas svneol=native#text/pascal
components/tachart/demo/barseriesshapes/BarShapes_Demo.lpi svneol=native#text/xml
components/tachart/demo/barseriesshapes/BarShapes_Demo.lpr svneol=native#text/pascal
components/tachart/demo/barseriesshapes/barshapes_demo.lpi svneol=native#text/xml
components/tachart/demo/barseriesshapes/barshapes_demo.lpr svneol=native#text/pascal
components/tachart/demo/barseriesshapes/main.lfm svneol=native#text/plain
components/tachart/demo/barseriesshapes/main.pas svneol=native#text/pascal
components/tachart/demo/barseriestools/barseriestools.lpi svneol=native#text/plain

View File

@ -34,8 +34,9 @@
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="BarShapes_Demo.lpr"/>
<Filename Value="barshapes_demo.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="BarShapes_Demo"/>
</Unit0>
<Unit1>
<Filename Value="main.pas"/>

View File

@ -1,17 +1,17 @@
object Form1: TForm1
Left = 332
Height = 278
Height = 317
Top = 127
Width = 535
Width = 495
Caption = 'Form1'
ClientHeight = 278
ClientWidth = 535
ClientHeight = 317
ClientWidth = 495
LCLVersion = '2.1.0.0'
object Chart1: TChart
Left = 0
Height = 243
Height = 282
Top = 0
Width = 535
Width = 495
AxisList = <
item
Marks.LabelBrush.Style = bsClear
@ -38,6 +38,8 @@ object Form1: TForm1
)
Align = alClient
object BarSeries: TBarSeries
AxisIndexX = 1
AxisIndexY = 0
BarBrush.Color = clRed
Depth = 20
DepthBrightnessDelta = -32
@ -48,13 +50,13 @@ object Form1: TForm1
object Panel1: TPanel
Left = 0
Height = 35
Top = 243
Width = 535
Top = 282
Width = 495
Align = alBottom
AutoSize = True
BevelOuter = bvNone
ClientHeight = 35
ClientWidth = 535
ClientWidth = 495
TabOrder = 1
object lblShape: TLabel
AnchorSideLeft.Control = cb3D
@ -140,6 +142,20 @@ object Form1: TForm1
TabOrder = 2
Value = 3
end
object cbRotated: TCheckBox
AnchorSideLeft.Control = seLevels
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = cmbShape
AnchorSideTop.Side = asrCenter
Left = 358
Height = 19
Top = 8
Width = 61
BorderSpacing.Left = 12
Caption = 'Rotated'
OnChange = cbRotatedChange
TabOrder = 3
end
end
object RandomChartSource1: TRandomChartSource
PointsNumber = 6

View File

@ -17,6 +17,7 @@ type
BarSeries: TBarSeries;
cb3D: TCheckBox;
ChartStyles1: TChartStyles;
cbRotated: TCheckBox;
cmbShape: TComboBox;
lblLevels: TLabel;
lblShape: TLabel;
@ -24,6 +25,7 @@ type
RandomChartSource1: TRandomChartSource;
seLevels: TSpinEdit;
procedure cb3DChange(Sender: TObject);
procedure cbRotatedChange(Sender: TObject);
procedure cmbShapeChange(Sender: TObject);
procedure seLevelsChange(Sender: TObject);
private
@ -50,8 +52,24 @@ begin
BarSeries.Depth := 20
else
BarSeries.Depth := 0;
Chart1.Margins.Top := 4 + Barseries.Depth;
Chart1.Margins.Right := 4 + IfThen(BarSeries.BarShape in [bsRectangular, bsPyramid], Barseries.Depth, 0);
if BarSeries.IsRotated then begin
Chart1.Margins.Top := 4 + IfThen(BarSeries.BarShape in [bsRectangular, bsPyramid], Barseries.Depth, 0);
Chart1.Margins.Right := 4 + BarSeries.Depth;
end else begin
Chart1.Margins.Top := 4 + Barseries.Depth;
Chart1.Margins.Right := 4 + IfThen(BarSeries.BarShape in [bsRectangular, bsPyramid], Barseries.Depth, 0);
end;
end;
procedure TForm1.cbRotatedChange(Sender: TObject);
begin
if cbRotated.Checked then begin
BarSeries.AxisIndexX := 0;
BarSeries.AxisIndexY := 1;
end else begin
BarSeries.AxisIndexX := 1;
BarSeries.AxisIndexY := 0;
end;
end;
procedure TForm1.cmbShapeChange(Sender: TObject);

View File

@ -1200,20 +1200,44 @@ var
SetLength(pts, 3);
if Depth = 0 then begin
pts[0] := Point(AR.Left, AR.Bottom);
pts[1] := Point(AR.Right, AR.Bottom);
pts[2] := Point((AR.Left + AR.Right) div 2, AR.Top);
if IsRotated then begin
pts[1] := Point(AR.Left, AR.Top);
pts[2] := Point(AR.Right, (AR.Top + AR.Bottom) div 2);
end else begin
pts[1] := Point(AR.Right, AR.Bottom);
pts[2] := Point((AR.Left + AR.Right) div 2, AR.Top);
end;
ADrawer.Polygon(pts, 0, 3);
end else
if IsRotated then begin
pts[0] := Point(AR.Left + scaled_depth, AR.Bottom - scaled_depth);
pts[1] := Point(AR.Left + scaled_depth, AR.Top - scaled_depth);
pts[2] := Point(AR.Right + scaled_depth2, (AR.Top + AR.Bottom - scaled_depth) div 2);
ADrawer.BrushColor := GetDepthColor(c);
ADrawer.Polygon(pts, 0, 3);
pts[1] := Point(AR.Left, AR.Bottom);
ADrawer.Polygon(pts, 0, 3);
pts[0] := Point(AR.Left + scaled_depth, AR.Top - scaled_depth);
pts[1] := Point(AR.Left, AR.Top);
ADrawer.Polygon(pts, 0, 3);
ADrawer.BrushColor := c;
pts[0] := Point(AR.Left, AR.Bottom);
ADrawer.Polygon(pts, 0, 3);
end else begin
// rear side
pts[0] := Point(AR.Left + scaled_depth, AR.Bottom - scaled_depth);
pts[1] := Point(AR.Right + scaled_depth, AR.Bottom - scaled_depth);
pts[2] := Point((AR.Left + AR.Right + scaled_depth) div 2, AR.Top - scaled_depth2);
ADrawer.BrushColor := GetDepthColor(c);
ADrawer.Polygon(pts, 0, 3);
// left side
pts[1] := Point(AR.Left, AR.Bottom);
ADrawer.Polygon(pts, 0, 3);
// right side
pts[0] := Point(AR.Right + scaled_depth, AR.Bottom - scaled_depth);
pts[1] := Point(AR.Right, AR.Bottom);
ADrawer.Polygon(pts, 0, 3);
// front face
ADrawer.BrushColor := c;
pts[0] := Point(AR.Left, AR.Bottom);
ADrawer.Polygon(pts, 0, 3);
@ -1223,7 +1247,15 @@ var
begin
if Depth = 0 then
ADrawer.Rectangle(AR)
else begin
else
if IsRotated then begin
ADrawer.Ellipse(AR.Left, AR.Top, AR.Left + scaled_depth, AR.Bottom);
ADrawer.FillRect(AR.Left + scaled_depth2, AR.Top, AR.Right + scaled_depth2, AR.Bottom);
ADrawer.Line(AR.Left + scaled_depth2, AR.Top, AR.Right + scaled_depth2, AR.Top);
ADrawer.Line(AR.Left + scaled_depth2, AR.Bottom, AR.Right + scaled_depth2, AR.Bottom);
ADrawer.BrushColor := GetDepthColor(ADrawer.BrushColor, false);
ADrawer.Ellipse(AR.Right, AR.Top, AR.Right + scaled_depth, AR.Bottom);
end else begin
ADrawer.Ellipse(AR.Left, AR.Bottom, AR.Right, AR.Bottom - scaled_depth);
ADrawer.FillRect(AR.Left, AR.Bottom - scaled_depth2, AR.Right, AR.Top - scaled_depth2);
ADrawer.Line(AR.Left, AR.Bottom - scaled_depth2, AR.Left, AR.Top - scaled_depth2);
@ -1237,83 +1269,147 @@ var
SetLength(pts, 3);
if Depth = 0 then begin
pts[0] := Point(AR.Left, AR.Bottom);
pts[1] := Point(AR.Right, AR.Bottom);
pts[2] := Point((AR.Left + AR.Right) div 2, AR.Top);
if IsRotated then begin
pts[1] := Point(AR.Left, AR.Top);
pts[2] := Point(AR.Right, (AR.Top + AR.Bottom) div 2);
end else begin
pts[1] := Point(AR.Right, AR.Bottom);
pts[2] := Point((AR.Left + AR.Right) div 2, AR.Top);
end;
ADrawer.Polygon(pts, 0, 3);
end else begin
ADrawer.Ellipse(AR.Left, AR.Bottom, AR.Right, AR.Bottom - scaled_depth);
// https://www.emathzone.com/tutorials/geometry/equation-of-tangent-and-normal-to-ellipse.html
// tangent to ellipse (x/a)² + (y/b)² = 1 at ellipse point (x1, y1):
// (x1 x) / + (y1 x) / = 1
h := AR.Bottom - AR.Top; // height of cone
if h > scaled_depth2 then begin
if IsRotated then begin
ADrawer.Ellipse(AR.Left, AR.Top, AR.Left + scaled_depth, AR.Bottom);
h := AR.Right - AR.Left;
if h <= scaled_depth2 then
exit;
a := (AR.Bottom - AR.Top) * 0.5;
b := scaled_depth2;
cx := (AR.Top + AR.Bottom) * 0.5;
cy := AR.Left + scaled_depth2;
factor := sqrt(1 - sqr(b/h));
pts[0] := Point(round(cy + sqr(b)/h), round(cx - a*factor));
pts[1] := Point(AR.Right + scaled_depth2, round(cx));
pts[2] := Point(round(cy + sqr(b)/h), round(cx + a*factor));
end else begin
ADrawer.Ellipse(AR.Left, AR.Bottom, AR.Right, AR.Bottom - scaled_depth);
// https://www.emathzone.com/tutorials/geometry/equation-of-tangent-and-normal-to-ellipse.html
// tangent to ellipse (x/a)² + (y/b)² = 1 at ellipse point (x1, y1):
// (x1 x) / + (y1 x) / = 1
h := AR.Bottom - AR.Top; // height of cone
if h <= scaled_depth2 then
exit;
a := (AR.Right - AR.Left) * 0.5;
b := scaled_depth2;
cx := (AR.Left + AR.Right) * 0.5; // center of cone ground area
cy := AR.Bottom - scaled_depth2;
factor := sqrt(1 - sqr(b/h));
pts[0] := Point(round(cx - a*factor), round(cy - sqr(b) / h));
pts[1] := Point((AR.Left + AR.Right) div 2, AR.Top - scaled_depth2);
pts[1] := Point(round(cx), AR.Top - scaled_depth2);
pts[2] := Point(round(cx + a*factor), round(cy - sqr(b) / h));
ADrawer.SetPenParams(psClear, clTAColor);
ADrawer.Polygon(pts, 0, 3);
ADrawer.Pen := BarPen;
if Styles <> nil then
Styles.Apply(ADrawer, stackIndex);
ADrawer.PolyLine(pts, 0, 3);
end;
ADrawer.SetPenParams(psClear, clTAColor);
ADrawer.Polygon(pts, 0, 3);
ADrawer.Pen := BarPen;
if Styles <> nil then
Styles.Apply(ADrawer, stackIndex);
ADrawer.PolyLine(pts, 0, 3);
end;
end;
bsHexPrism:
begin
a := (AR.Right - AR.Left) * 0.5;
cx := (AR.Left + AR.Right) * 0.5;
a := IfThen(IsRotated, AR.Bottom - AR.Top, AR.Right - AR.Left) * 0.5;
cx := IfThen(IsRotated, AR.Top + AR.Bottom, AR.Left + AR.Right) * 0.5;
cy := scaled_depth2;
SetLength(pts, 4);
factor := sin(pi * 30 / 180);
if Depth = 0 then begin
pts[0] := Point(AR.Left, AR.Bottom);
pts[1] := Point(round(cx - a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
pts[3] := Point(AR.Left, AR.Top);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(round(cx + a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Right, AR.Bottom);
pts[2] := Point(AR.Right, AR.Top);
ADrawer.Polygon(pts, 0, 4);
if IsRotated then begin
pts[1] := Point(AR.Left, round(cx + a*factor));
pts[2] := Point(AR.Right, pts[1].Y);
pts[3] := Point(AR.Right, AR.Bottom);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Left, round(cx - a*factor));
pts[2] := Point(AR.Right, pts[1].Y);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Left, AR.Top);
pts[2] := Point(AR.Right, AR.Top);
ADrawer.Polygon(pts, 0, 4);
end else begin
pts[1] := Point(round(cx - a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
pts[3] := Point(AR.Left, AR.Top);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(round(cx + a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Right, AR.Bottom);
pts[2] := Point(AR.Right, AR.Top);
ADrawer.Polygon(pts, 0, 4);
end;
end else begin
c := ADrawer.BrushColor;
pts[0] := Point(AR.Left, AR.Bottom - scaled_depth2);
pts[1] := Point(round(cx - a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
pts[3] := Point(AR.Left, AR.Top - scaled_depth2);
ADrawer.BrushColor := GetDepthColor(c);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(round(cx + a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
ADrawer.BrushColor := c;
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Right, AR.Bottom - scaled_depth2);
pts[2] := Point(AR.Right, AR.Top - scaled_depth2);
ADrawer.BrushColor := GetDepthColor(c);
ADrawer.Polygon(pts, 0, 4);
SetLength(pts, 6);
pts[0] := Point(AR.Left, AR.Top - scaled_depth2);
pts[1] := Point(round(cx - a*factor), AR.Top);
pts[2] := Point(round(cx + a*factor), AR.Top);
pts[3] := Point(AR.Right, AR.Top - scaled_depth2);
pts[4] := Point(round(cx + a*factor), AR.Top - scaled_depth);
pts[5] := Point(round(cx - a*factor), AR.Top - scaled_depth);
if IsRotated then begin
pts[0] := Point(AR.Left + scaled_depth2, AR.Bottom);
pts[1] := Point(AR.Left, round(cx + a*factor));
pts[2] := Point(AR.Right, pts[1].Y);
pts[3] := Point(AR.Right + scaled_depth2, AR.Bottom);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Left, round(cx - a*factor));
pts[2] := Point(AR.Right, pts[1].Y);
ADrawer.BrushColor := c;
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Left + scaled_depth2, AR.Top);
pts[2] := Point(AR.Right + scaled_depth2, pts[1].Y);
ADrawer.BrushColor := GetDepthColor(c);
ADrawer.Polygon(pts, 0, 4);
SetLength(pts, 6);
pts[0] := Point(AR.Right + scaled_depth2, AR.Bottom);
pts[1] := Point(AR.Right, round(cx + a*factor));
pts[2] := Point(AR.Right, round(cx - a*factor));
pts[3] := Point(AR.Right + scaled_depth2, AR.Top);
pts[4] := Point(AR.Right + scaled_depth, round(cx - a*factor));
pts[5] := Point(AR.Right + scaled_depth, round(cx + a*factor));
end else begin
pts[0] := Point(AR.Left, AR.Bottom - scaled_depth2);
pts[1] := Point(round(cx - a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
pts[3] := Point(AR.Left, AR.Top - scaled_depth2);
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(round(cx + a*factor), AR.Bottom);
pts[2] := Point(pts[1].X, AR.Top);
ADrawer.BrushColor := c;
ADrawer.Polygon(pts, 0, 4);
pts[0] := pts[1];
pts[3] := pts[2];
pts[1] := Point(AR.Right, AR.Bottom - scaled_depth2);
pts[2] := Point(AR.Right, AR.Top - scaled_depth2);
ADrawer.BrushColor := GetDepthColor(c);
ADrawer.Polygon(pts, 0, 4);
SetLength(pts, 6);
pts[0] := Point(AR.Left, AR.Top - scaled_depth2);
pts[1] := Point(round(cx - a*factor), AR.Top);
pts[2] := Point(round(cx + a*factor), AR.Top);
pts[3] := Point(AR.Right, AR.Top - scaled_depth2);
pts[4] := Point(round(cx + a*factor), AR.Top - scaled_depth);
pts[5] := Point(round(cx - a*factor), AR.Top - scaled_depth);
end;
ADrawer.BrushColor := GetDepthColor(c, true);
ADrawer.Polygon(pts, 0, 6);
end;