unit WindRoseGraph;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  GraphBase, ActnList, Placemnt, ExtCtrls, TeeProcs, TeEngine, Chart,
  ComCtrls, ToolWin,data,math, Series;

type
  TfmWindRoseGraph = class(TfmGraphBase)
    procedure Chart1AfterDraw(Sender: TObject);
    procedure Chart1Resize(Sender: TObject);
  private
    { Private declarations }
    FTabData : TTabData;
  public
    { Public declarations }

    constructor create(AOwner : TComponent); override;
    destructor destroy; override;
  end;

const
  Vci      : integer = 4;
  Vr       : integer = 12;
  Vco      : integer = 25;
  LegColor : TColor  = clGreen;

var
  fmWindRoseGraph: TfmWindRoseGraph;

implementation


{$R *.DFM}

procedure TfmWindRoseGraph.Chart1AfterDraw(Sender: TObject);


type
 TPoint2D    = record
                x,y : real;
               end;
 TPointArray = array of TPoint2d;

 function Rot(P : TPoint2d; ang : real) : TPoint2d;
 begin
   with Result do
   begin
     X:=p.X*Cos(Ang)-p.Y*Sin(Ang);
     Y:=p.Y*Cos(Ang)+p.X*Sin(Ang);
   end;
 end;


 function ConstructLeg(Tab : TTabData; d : integer) : TPointArray;
 const
  W : real = 0.2;
 var
  i   : integer;
  L1  : real;
  L2  : real;
  L3  : real;
  L4  : real;
  ang : real;
 begin
   SetLength(Result,16);
   L1 := 0;  L2 := 0;
   L3 := 0;  L4 := 0;
   with Tab do
   begin
     for i:=0 to Vci-1 do
      if i<=High(PerSectFreq) then
         L1 := L1 + PerSectFreq[i,d];
     for i:=Vci to Vr-1 do
      if i<=High(PerSectFreq) then
         L2 := L2 + PerSectFreq[i,d];
     for i:=Vr to Vco-1 do
      if i<=High(PerSectFreq) then
         L3 := L3 + PerSectFreq[i,d];
     for i:=Vco to High(PerSectFreq) do
         L4 := L4 + PerSectFreq[i,d];
   end;

   L1:=    (L1/1000) * Tab.TTLSectFreq[D];
   L2:= L1+(L2/1000) * Tab.TTLSectFreq[D];
   L3:= L2+(L3/1000) * Tab.TTLSectFreq[D];
   L4:= L3+(L4/1000) * Tab.TTLSectFreq[D];

   Result[0].X := 0;   Result[0].Y := 0;
   Result[1].X := 0;   Result[1].Y := L1;
   Result[2].X :=-W;   Result[2].Y := L1;
   Result[3].X :=-W;   Result[3].Y := L2;
   Result[4].X :=-2*W; Result[4].Y := L2;
   Result[5].X :=-2*W; Result[5].Y := L3;
   Result[6].X :=-3*W; Result[6].Y := L3;
   Result[7].X :=-3*W; Result[7].Y := L4;

   Result[8].X := 3*W; Result[8].Y := L4;
   Result[9].X := 3*W; Result[9].Y := L3;
   Result[10].X:= 2*W; Result[10].Y:= L3;
   Result[11].X:= 2*W; Result[11].Y:= L2;
   Result[12].X:= W;   Result[12].Y:= L2;
   Result[13].X:= W;   Result[13].Y:= L1;
   Result[14].X:= 0;   Result[14].Y:= L1;
   Result[15].X:= 0;   Result[15].Y:= 0;

   Ang:=-D*(2*pi/Tab.SectCount);
   for i:=0 to High(Result) do
     Result[i] := Rot(result[i],ang);
   {
   with Result[i] do
   begin
     oldx := X;
     //Y:=-Y;
     X:=X*Cos(Ang)-Y*Sin(Ang);
     Y:=Y*Cos(Ang)+OldX*Sin(Ang);
   end;
  }

 end;

const
  ofsX   : integer = 500;
  ofsY   : integer = 500;
  scale  : real = 20;
var
 pict : TPicture;
 c    : TCanvas;
 D    : integer;
 r    : real;
 Leg  : TPointArray;
 i    : integer;
 Poly : array of TPoint;
 phi  : real;
 p    : TPoint2d;
 th   ,
 tw   : integer;
 dnm  : string;
begin
  Leg := nil;

  if not Assigned(FTabData) then
     Exit;

  {
  Pict := Chart1.BackImage;
  if Assigned(Pict) then
     Pict.Free;
  }

  pict := TPicture.Create;
  pict.Metafile := TMetaFile.Create;
  Pict.Metafile.Width  := Chart1.Width;
  Pict.MetaFile.Height := Chart1.Height;

  r:= MaxValue(FTabData.ttlSectFreq);

  Scale := Min(Chart1.Width,Chart1.Height)/r/3;

  c := TMetaFileCanvas.Create(pict.Metafile,0);
  ofsX := Chart1.Width div 2; // Chart1.ChartXCenter;
  ofsY := Chart1.Height div 2; //Chart1.ChartYCenter;
  {
  c.Ellipse(ofsx-round(r*Scale*1.05),
            ofsy-round(r*scale*1.05),
            ofsx+round(r*scale*1.05),
            ofsy+Round(r*scale*1.05));
  }
  for D:=0 to FTabData.SectCount-1 do
  begin
    Leg := ConstructLeg(FTabData,d);
    SetLength(Poly,Length(Leg));
    for i:=0 to High(Leg) do
    begin
      Poly[i].X := ofsx+Round(Leg[i].X*Scale);
      Poly[i].Y := ofsy-Round(Leg[i].Y*Scale);
    end;
    c.Brush.Color := legColor;
    c.Polygon(Poly);
  end;
  c.Brush.Style := bsClear;

  phi := (2*pi/FTabData.SectCount);

  for i:=0 to FTabData.SectCount-1 do
  begin
    if FTabData.SectCount=12 then
       dnm := DirNames[i]
    else
       dnm := IntToStr(i);
    tw := c.TextWidth(dnm); //div 2;
    th := c.TextHeight(dnm); //div 2;
    p.x := R*Scale+tw/Scale;
    p.x := 1.1 * p.x;
    p.y := th/Scale;
    p.y := 1.1 * p.y;
    p := rot(p,i*phi-pi/2);
    c.TextOut(ofsx+Round(p.x)-tw div 2,ofsy+Round(p.y)-th div 2,dnm);
  end;

  c.Free;

  Chart1.BackImage := pict;
  
  Chart1.Foot.Text.Clear;
  Chart1.Foot.Text.Add(FTabData.Description);
end;

constructor TfmWindRoseGraph.create(AOwner: TComponent);
begin
  inherited create(AOwner);
  FTabData := TTabData.CreateFrom(Project)
end;

procedure TfmWindRoseGraph.Chart1Resize(Sender: TObject);
begin
  Chart1AfterDraw(Sender);
end;

destructor TfmWindRoseGraph.destroy;
begin
  if Assigned(FTabData) then
     FTabData.Free;
  inherited;
end;

initialization
  RegisterClass(TFmWindRoseGraph);
end.
