{**********************************************}
{  TeeChart Pro                                }
{                                              }
{  TPolarContourSeries                         }
{                                              }
{  Copyright (c) 2013-2020 by Steema Software  }
{**********************************************}
unit TeePolarContour;
{$I TeeDefs.inc}

interface

uses
  {$IFDEF MSWINDOWS}
  Windows,
  {$ENDIF}

  Classes, SysUtils,

  {$IFDEF D17}
  System.UITypes,
  {$ENDIF}
  
  {$IFDEF FMX}
  FMX.Types, FMXTee.Procs,
  FMXTee.Engine, FMXTee.Series.Polar, FMXTee.Series.Surface
  {$ELSE}
  Graphics,
  TeeProcs, TeEngine, TeePolar, TeeSurfa
  {$ENDIF}
  ;

type
  TPolarContourSeries=class(TPolarSeries)
  private
    FContour : TContourSeries;

    function IsLevelsStored: Boolean;
    procedure SetLevels(const Value: TContourLevels);
    function GetLevels: TContourLevels;
    function GetAutomaticLevels: Boolean;
    procedure SetAutomaticLevels(const Value: Boolean);
    function GetNumLevels: Integer;
    procedure SetNumLevels(const Value: Integer);
  protected
    Procedure AddValues(Source:TChartSeries); override;
    Procedure AddSampleValues(NumValues:Integer; OnlyMandatory:Boolean=False); override;
    procedure DrawAllValues; override;
    class Function GetEditorClass:String; override;
    procedure SetParentChart(const Value: TCustomAxisPanel); override;
  public
    Constructor Create(AOwner:TComponent); override;
    Destructor Destroy; override;

    procedure Clear; override;

    function AddXYZ(X:Integer; const Y:TChartValue; Z:Integer):Integer;
    function AddNullXZ(X,Z:Integer):Integer;

    Function MaxXValue:TChartValue; override;
    Function MinXValue:TChartValue; override;

    Function MaxYValue:TChartValue; override;
    Function MinYValue:TChartValue; override;

    property Contour:TContourSeries read FContour;
  published
    property AutomaticLevels:Boolean read GetAutomaticLevels write SetAutomaticLevels default True;
    property Levels:TContourLevels read GetLevels write SetLevels stored IsLevelsStored;
    property NumLevels:Integer read GetNumLevels write SetNumLevels default 10;
    property PointerBehind;
  end;

implementation

uses
  {$IFDEF FMX}
  FMXTee.Chart, FMXTee.Series, FMXTee.Canvas, FMXTee.ProConstants
  {$ELSE}
  Chart, Series, TeCanvas, TeeProCo
  {$ENDIF}
  ;

type
  TInnerContour=class(TContourSeries)
  private
    IPolar : TPolarSeries;
  protected
    function CalcXYPoint(const P:TLevelPoint):TPoint; override;
    function CreateIso:TIsoSurfaceSeries; override;
  end;

  TPolarIso=class(TIsoSurfaceSeries)
  protected
    function CalcXYPoint(const Value:TLevelPoint3D):TPoint; override;
  end;

  TContourAccess=class(TContourSeries);
  TPolarAccess=class(TCustomPolarSeries);

function TInnerContour.CalcXYPoint(const P:TLevelPoint):TPoint;
var tmpX : Single;
    {$IFDEF FMX}
    pX,
    pY : Integer;
    {$ENDIF}
begin
  tmpX:=P.X*360/(NumXValues-1);

  TPolarAccess(IPolar).CalcXYPosition(tmpX,P.Y,TPolarAccess(IPolar).AxisYRadius,IPolar.GetVertAxis,
               {$IFDEF FMX}pX,pY{$ELSE}result.X,result.Y{$ENDIF});

  {$IFDEF FMX}
  result.X:=pX;
  result.Y:=pY;
  {$ENDIF}
end;

function TInnerContour.CreateIso:TIsoSurfaceSeries;
begin
  result:=TPolarIso.Create(Self);
end;

function TPolarIso.CalcXYPoint(const Value:TLevelPoint3D):TPoint;
var tmp : TLevelPoint;
begin
  tmp.X:=Value.X;
  tmp.Y:=Value.Y;
  result:=TInnerContour(Owner).CalcXYPoint(tmp);
end;

{ TPolarContourSeries }

Constructor TPolarContourSeries.Create(AOwner: TComponent);
begin
  inherited;
  TreatNulls:=tnDontPaint;

  Pointer.Hide;

  FContour:=TInnerContour.Create(nil);
  TInnerContour(FContour).IPolar:=Self;
end;

Destructor TPolarContourSeries.Destroy;
begin
  FreeAndNil(FContour);
  inherited;
end;

function TPolarContourSeries.AddNullXZ(X, Z: Integer): Integer;
begin
  AddNull;
  result:=FContour.AddXYZ(X,0,Z);
  FContour.SetNull(result);
end;

function TPolarContourSeries.AddXYZ(X: Integer; const Y: TChartValue;
  Z: Integer): Integer;
begin
  AddNull(Y);
  result:=FContour.AddXYZ(X,Y,Z);
end;

procedure TPolarContourSeries.Clear;
begin
  inherited;

  if Assigned(FContour) then
     FContour.Clear;
end;

procedure TPolarContourSeries.DrawAllValues;
begin
  inherited;

  // Match fixed common properties:

  FContour.ColorEachPoint:=ColorEachPoint;
  FContour.Pen:=Pen;
  FContour.Brush:=Brush;
  FContour.Color:=Color;

  TContourAccess(FContour).FParent:=ParentChart;
  TContourAccess(FContour).RecalcGetAxis;
  TContourAccess(FContour).DoBeforeDrawChart;
  TContourAccess(FContour).DrawAllValues;
end;

function TPolarContourSeries.MaxXValue:TChartValue;
begin
  result:=FContour.XValues.MaxValue;
end;

function TPolarContourSeries.MaxYValue: TChartValue;
begin
  result:=FContour.ZValues.MaxValue;
end;

function TPolarContourSeries.MinXValue:TChartValue;
begin
  result:=FContour.XValues.MinValue;
end;

function TPolarContourSeries.MinYValue: TChartValue;
begin
  result:=FContour.ZValues.MinValue;
end;

procedure TPolarContourSeries.AddSampleValues(NumValues: Integer;
  OnlyMandatory: Boolean);
var t : Integer;
begin
  inherited;

  Clear;

  FContour.FillSampleValues(10);

  for t:=0 to FContour.Count-1 do
      AddNull(FContour.YValues.Value[t]);
end;

class function TPolarContourSeries.GetEditorClass: String;
begin
  result:='TPolarContourSeriesEditor';
end;

function TPolarContourSeries.IsLevelsStored: Boolean;
begin
  result:=not FContour.AutomaticLevels;
end;

procedure TPolarContourSeries.SetLevels(const Value: TContourLevels);
begin
  FContour.Levels:=Value;
end;

function TPolarContourSeries.GetLevels: TContourLevels;
begin
  result:=FContour.Levels;
end;

function TPolarContourSeries.GetAutomaticLevels: Boolean;
begin
  result:=FContour.AutomaticLevels;
end;

procedure TPolarContourSeries.SetAutomaticLevels(const Value: Boolean);
begin
  FContour.AutomaticLevels:=Value;
end;

function TPolarContourSeries.GetNumLevels: Integer;
begin
  result:=FContour.NumLevels;
end;

procedure TPolarContourSeries.SetNumLevels(const Value: Integer);
begin
  FContour.NumLevels:=Value;
end;

// Very special code, to allow assigning data from any 3D-derived series
procedure TPolarContourSeries.AddValues(Source: TChartSeries);
var t : Integer;
begin
  if Source is TCustom3DSeries then
  begin
    FContour.AssignValues(Source);

    // Call inherited to avoid clearing FContour:
    inherited Clear;

    for t:=0 to FContour.Count-1 do
        AddNull(FContour.YValues.Value[t]);
  end
  else
    inherited;
end;

procedure TPolarContourSeries.SetParentChart(const Value: TCustomAxisPanel);
begin
  inherited;

  if Assigned(FContour) then
     TContourAccess(FContour).FParent:=Value;
end;

initialization
  RegisterTeeSeries( TPolarContourSeries, @TeeMsg_GalleryPolarContour,
                                          @TeeMsg_Gallery3D,1);
finalization
  UnRegisterTeeSeries([TPolarContourSeries]);
end.
