Recent

Author Topic: Problem with PieChart  (Read 7019 times)

bigeno

  • Sr. Member
  • ****
  • Posts: 266
Problem with PieChart
« on: March 08, 2019, 01:13:39 pm »
I know there is a bug in PieChart with Depth>0 and exploded slice, I need this feature like hell.
I try correct code but... at first I thought its problem with order of painting slices but its quite hard problem.
Can anyone help and give some directions ?

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #1 on: March 08, 2019, 10:58:45 pm »
Please try the new version in Laz trunk. I am not 100% sure if I covered all cases, but the 3D pie series now paints much better. See also the radialdemo in folder demo/radial

bigeno

  • Sr. Member
  • ****
  • Posts: 266
Re: Problem with PieChart
« Reply #2 on: March 08, 2019, 11:43:12 pm »
Please try the new version in Laz trunk. I am not 100% sure if I covered all cases, but the 3D pie series now paints much better. See also the radialdemo in folder demo/radial
it looks damn good to me, you are the best  8)
I will test more cases...
THX

bigeno

  • Sr. Member
  • ****
  • Posts: 266
Re: Problem with PieChart
« Reply #3 on: March 10, 2019, 07:34:07 pm »
@wp, is Depth restricted to 0..10 ?
with Depth = 20 little glitch in some cases.

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #4 on: March 10, 2019, 07:39:56 pm »
Can you send the values that you have in this series for me to reproduce?

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #5 on: March 10, 2019, 11:29:17 pm »
No need to provide any data, I can reproduce the issue. Not clear if it can be fixed because all these are not true 3D drawings, just painting areas in a given order.

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #6 on: March 11, 2019, 11:10:02 pm »
I modified the painting approach again, but I am not sure if it leads to a real improvement. There are always some special cases, mostly in combination with very narrow slices where the drawing order should be reversed, but this would result in issues at other slices. I am stopping here - this is probably close to the best that we can get without a true hidden-line and hidden-area algorithm.
« Last Edit: March 12, 2019, 07:38:48 pm by wp »

bigeno

  • Sr. Member
  • ****
  • Posts: 266
Re: Problem with PieChart
« Reply #7 on: March 12, 2019, 07:06:40 pm »
Looks good to me, I don't see more problems. Thx

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #8 on: March 12, 2019, 08:02:06 pm »
I just added a new property DepthBrightnessDelta which is added to the rgb values of the slice colors in order to enhance the 3d appearance of the series. Use something like -32 or -64 for darker side areas.

[EDIT]
Plus some more enhancements (http://wiki.freepascal.org/Lazarus_2.2.0_release_notes#TAChart):
- "Orientation" and "ViewAngle" for different views of the series
- "InnerRadiusPercent" for drawing a ring chart.
- "StartAngle" to define the position of the first pie slice.
- "MarkPositionCentered" for attaching data point labels to the pie center instead of the pie perimeter.
« Last Edit: March 19, 2019, 11:57:01 pm by wp »

bigeno

  • Sr. Member
  • ****
  • Posts: 266
Re: Problem with PieChart
« Reply #9 on: March 22, 2019, 09:45:28 pm »
- "InnerRadiusPercent" for drawing a ring chart.

 8) 8) that ring/donut chart rules !! thank you.

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #10 on: March 22, 2019, 10:40:29 pm »
How did you do the gradients? BGRABitmap? Would you mind to share the code?
« Last Edit: March 23, 2019, 12:52:25 am by wp »

bigeno

  • Sr. Member
  • ****
  • Posts: 266
Re: Problem with PieChart
« Reply #11 on: March 23, 2019, 11:13:21 am »
How did you do the gradients? BGRABitmap? Would you mind to share the code?
sure, its TADrawerBGRA, but I'm not happy of gradient for now, its based on rectangle, need adjust to pie.

Code: Pascal  [Select][+][-]
  1. procedure TBGRABitmapDrawer.MultiPolygonF(const APoints: ArrayOfTPointF; AStartIndex, ANumPts: Integer; const c1, c2: TColor; const GradType: byte;  const border, closed: boolean);
  2. var
  3.   gradScan1 : TBGRAGradientScanner;
  4.   gradScan2 : TBGRACustomBitmap;
  5.   BC1,BC2   : TBGRAPixel;
  6.   i         : integer;
  7.   Pleft,PRight,PTop,PBottom : single;
  8. begin
  9.   gradScan1:=nil;
  10.   gradScan2:=nil;
  11.   bc1:=ColorToBGRA(c1);
  12.   bc2:=ColorToBGRA(c2);
  13.   Pleft := 99999999;
  14.   Pright := -99999999;
  15.   PTop := 99999999;
  16.   PBottom := -99999999;
  17.   for i:=0 to Length(APoints)-1 do begin
  18.       if APoints[i].x < Pleft then   PLeft := (APoints[i].x);
  19.       if APoints[i].x > Pright then  PRight := (APoints[i].x);
  20.       if APoints[i].y < PTop then    PTop := (APoints[i].y);
  21.       if APoints[i].y > PBottom then PBottom := (APoints[i].y);
  22.   end;
  23.  
  24.   if not ((AStartIndex=-1) and (ANumPts=1)) then begin
  25.      if FBrushStyle = bsSolid then begin
  26.         case GradType of
  27.            1 : gradScan1 := TBGRAGradientScanner.Create(bc1,bc2,gtLinear,PointF(PLeft,PTop),PointF(PLeft,PBottom),True);
  28.            2 : gradScan1 := TBGRAGradientScanner.Create(bc1,bc2,gtLinear,PointF(PLeft,PTop),PointF(PRight,PTop),True);
  29.         end;
  30.         try
  31.           FCanvas.FillPolyAntialias(APoints, gradScan1);
  32.         finally
  33.           gradScan1.Free;
  34.         end;
  35.      end;
  36.   end;
  37.   if (GetPenStyle <> psClear) and (border) then begin
  38.      FCanvas.DrawPolyLineAntialias(APoints, FPenColor, FPenWidth, closed);
  39.   end;  
  40. end;

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #12 on: March 23, 2019, 11:19:57 am »
Would it be helpful if I provide events OnBeforeDrawPie and OnBeforeDrawPieSides with all the points defining the shapes? Similar to OnBeforeDrawBar for a TBarSeries.

bigeno

  • Sr. Member
  • ****
  • Posts: 266
Re: Problem with PieChart
« Reply #13 on: March 23, 2019, 06:38:11 pm »
Would it be helpful if I provide events OnBeforeDrawPie and OnBeforeDrawPieSides with all the points defining the shapes? Similar to OnBeforeDrawBar for a TBarSeries.
if you think about points for setting gradient type that would be awesome. For every pie slice need two points to get proper gradients
---
I also think about about radial gradient (gtRadial)...
« Last Edit: March 23, 2019, 06:46:53 pm by bigeno »

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Problem with PieChart
« Reply #14 on: March 23, 2019, 07:52:20 pm »
Please try the current revision with the new even OnDrawPie of TPieSeries. When a handler is assigned you must fill all areas of the slices yourself. It gets several parameters to tell you where the currently drawn slice is:

Code: Pascal  [Select][+][-]
  1. type
  2.   TSlicePart = (spTop, spOuterArcSide, spInnerArcSide, spStartSide, spEndSide);
  3.  
  4.   TPieSlice = object
  5.     FBase: TPoint;
  6.     FFlags: Integer;  // 1: 1st part, 2: 2nd part of diviced slice
  7.     FLabel: TLabelParams;
  8.     FOrigIndex: Integer;
  9.     FPrevAngle, FNextAngle: Double; // in CCW direction
  10.                                     // FNextAngle may become < FPrevAngle when crossing 360°
  11.     FVisible: Boolean;
  12.     function Angle: Double; inline;
  13.     function CenterAngle: Double; inline;
  14.     function FixedNextAngle: Double; inline;
  15.   end;
  16.  
  17.   TDrawPieEvent = procedure(ASeries: TCustomPieSeries; ADrawer: IChartDrawer;
  18.     ASlice: TPieSlice; APart: TSlicePart; const APoints: TPointArray) of object;

The event is called several times for drawing every slice, the parameter "Part" identifies the currently drawn part: the radial sides, the curved arcs, or the top face which is the only part visible also in 2D mode.

Tha parameter "ADrawer" is the drawing interface used, in your case TBGRABitmapDrawer. There is no need to modify the code of TBGRABitmapDrawer any more.

The parameter "ASlice" identifies the slice which is currently painted:
  • FOrigIndex is the index of the slice, i.e. the index of the data point correspondingto the series. Note that slices are reordered to paint from "back" to "front".
  • FPrevAngle is the angle at which the slice starts (in radians),
  • FNextAngle is the angle at which the slice ends. Unlike your sketch, angles are oriented in counter-clockwise direction here. Usually FNextAngle is greater than FPrevAngle, but when the StartAngle of the series is changed it may happen that a slice crosses the 2 pi line. Use FixedNextAngle instead to make sure that the end angle is always greater than the start angle.
  • FVisible can be ignored because the event fires only for visible slices.
  • Angle is the opening angle spanned by the slice, i.e. FixedNextAngle - FPrevAngle.
  • CenterAngle is the angle at the center of the slice, i.e. (FixedNextAngle + FPrevAngle) / 2.
  • FBase tells you the coordinates of the center of the slice.

APoints is an array of TPoint records defining the polygon of the slice part being drawn.

Slices and faces are drawn in the correct order to (hopefully) guarantee that hidden faces are not painted or over-drawn by visible faces.

Call TPieSeries.SliceColor(ASlice.FOrigIndex) to get the color of the slice.

Call TPieSeries.GetDepthColor(-- slice color --) to get the color of the slice sides.

In order to determine the coordinates at the perimeter and the center of a slice (e.g., the points marked on your sketch by circles) call the method CalcBorderPoint:
Code: Pascal  [Select][+][-]
  1. var
  2.   pCenter: TPoint;
  3. ..
  4.   pCenter := PieSeries.CalcBorderPoint(ASlice, ARadius, AAngle);
The radius of the outer arc is given by the property Radius of the series, the radius of the inner arc of a donut series is given by method CalcInnerRadius. The method automatically takes care of the aspect ratio in case of an oblique viewing angle.

ATM, the border lines of the slices as drawn by the series. If you want to draw them yourself set the PieSeries.EdgePen.Style to psClear and just draw the PolyLine given by APoints. Be carefuly however, when a slice has an opening angle > 180° - to avoid 3D drawing artefacts, these slices are split in the center to two pieces having only half of the total opening angle. The FFlag tells you which slice is currently drawn: 1 = first part from FPrevAngle to CenterAngle, 2 = second part = CenterAngle to FNextAngle, 0 = non-split slice. Not all points of the polygon must be connected in the case of split slices, otherwise a radial line will appear in the center of the split slices. Have a look at the source code of TCustomPieSeries.Draw, local procedure DrawArc3D,  to learn which points are affected.

« Last Edit: March 23, 2019, 08:05:42 pm by wp »

 

TinyPortal © 2005-2018