{ 
	Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina
	Restored Z_ZVortex variation from Apophysis Cothe's plugin pack 
}

unit varZVortex;

interface
uses
  BaseVariation, XFormMan;

type
  TVariationZVortex = class(TBaseVariation)
  private
    sides: integer;
	angle, spin: double;
	sds2, ang2: double;
  public
    constructor Create;

    class function GetName: string; override;
    class function GetInstance: TBaseVariation; override;

    function GetNrVariables: integer; override;
    function GetVariableNameAt(const Index: integer): string; override;

    function SetVariable(const Name: string; var value: double): boolean; override;
    function GetVariable(const Name: string; var value: double): boolean; override;
    function ResetVariable(const Name: string): boolean; override;

    procedure Prepare; override;
	procedure CalcFunction; override;
  end;


implementation

uses
  Math;
////////////////////////
procedure TVariationZVortex.Prepare;
begin
	sds2 := sides * 0.5 / pi;
	ang2 := angle * 0.5 * pi;
end;

procedure TVariationZVortex.CalcFunction;
var
  r, phi, t, sn, cn, sn1, cn1: double;
begin
  r := Math.Hypot(FTx^, FTy^);
  phi := arctan2(FTy^, FTx^);

  if (r = 0) then r := 1E-300;
  t := sds2 * phi + spin * Math.log2(r);
  // AV: these Z+ variations with lost sources are drive me crazy:
  // they are always use vvar in a non-linear way!
  t := vvar * (t - floor(t)) / sds2;

  sn := sin(ang2) * t + phi;
  cn := cos(ang2) * t - 1;
  
  SinCos(sn, sn1, cn1);

  FPx^ := FPx^ + (r * cn1 + FTx^ * cn);
  FPy^ := FPy^ + (r * sn1 + FTy^ * cn);
end;

constructor TVariationZVortex.Create;
begin
  sides := random(12) + 1;
  angle := 2 * random - 1;
  spin := 2 * random - 1;
end;

class function TVariationZVortex.GetInstance: TBaseVariation;
begin
   Result := TVariationZVortex.Create;
end;

class function TVariationZVortex.GetName: string;
begin
   Result := 'Z_vortex';
end;

function TVariationZVortex.GetNrVariables: integer;
begin
   Result := 3;
end;

function TVariationZVortex.GetVariable(const Name: string;
  var value: double): boolean;
begin
  Result := False;
  if Name = 'Z_vortex_sides' then begin
    value := sides;
    Result := True;
  end
  else if Name = 'Z_vortex_angle' then begin
    value := angle;
    Result := True;
  end
  else   if Name = 'Z_vortex_spin' then begin
    value := spin;
    Result := True;
  end;
end;

function TVariationZVortex.GetVariableNameAt(const Index: integer): string;
begin
  case Index of
    0: Result := 'Z_vortex_sides';
	1: Result := 'Z_vortex_angle';
	2: Result := 'Z_vortex_spin';
  else
    Result := '';
  end;
end;

function TVariationZVortex.SetVariable(const Name: string;
  var value: double): boolean;
begin
  Result := False;
  if Name = 'Z_vortex_sides' then begin
    if Value = 0 then Value := 1;
    sides := Round(value);
    Result := True;
  end
  else if Name = 'Z_vortex_angle' then begin
    angle := value;
    Result := True;
  end
   else if Name = 'Z_vortex_spin' then begin
    spin := value;
    Result := True;
  end;
end;

function TVariationZVortex.ResetVariable(const Name: string): boolean;
begin
  Result := False;
  if Name = 'Z_vortex_sides' then begin
    sides := 1;
    Result := True;
   end
  else if Name = 'Z_vortex_angle' then begin
    angle := 0;
    Result := True;
  end
   else if Name = 'Z_vortex_spin' then begin
    spin := 0;
    Result := True; 
  end;
end;

//////////////////////////////
initialization
  RegisterVariation(TVariationClassLoader.Create(TVariationZVortex), false, false);

end.
