{ Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina }

unit varButterfly;

interface

uses
  BaseVariation, XFormMan;

type
  TVariationButterfly = class(TBaseVariation)
  const
    str_sx: string = 'butterfly_scale_negX';
    str_sy: string = 'butterfly_scale_negY';
    str_sz: string = 'butterfly_3D_shift';
  private
	  sx, sy, sz, vpi: 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;

{ TVariationButterfly }

///////////////////////////////////////////////////////////////////////////////

procedure TVariationButterfly.Prepare;
begin
	vpi := vvar * 4.0 / sqrt(3.0 * pi);
end;

procedure TVariationButterfly.CalcFunction;
var	r, y2: double;
begin 
  y2 := FTy^ * 2.0;
  r := vpi * sqrt(abs(FTy^ * FTx^)/(sqr(FTx^) + sqr(y2) + 1E-20));

  if (FTy^ < 0) then begin
	  FPx^ := FPx^ + FTx^ * r;
	  FPy^ := FPy^ + r * y2;
  end else begin
	  FPx^ := FPx^ + sx * FTx^ * r;
	  FPy^ := FPy^ + sy * r * y2;
  end;
  
  if (sz <> 0) then
	  FPz^ := FPz^ + sz * r * abs(FTx^); //* Hypot(FTx^, FTy^);
end;


///////////////////////////////////////////////////////////////////////////////
constructor TVariationButterfly.Create;
begin
	sx := 1;
	sy := 1;
	sz := 0;
end;

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

///////////////////////////////////////////////////////////////////////////////
class function TVariationButterfly.GetName: string;
begin
  Result := 'butterfly';
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationButterfly.GetVariableNameAt(const Index: integer): string;
begin
  case Index Of
	0: Result := str_sx;
	1: Result := str_sy;
	2: Result := str_sz;
  else
    Result := '';
  end
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationButterfly.SetVariable(const Name: string; var value: double): boolean;
begin
  Result := False;
  if Name = str_sx then begin
    if (value < 0) then value := abs(value);
    sx := Value;
    Result := True;
  end else if Name = str_sy then begin
    if (value < 0) then value := abs(value);
    sy := Value;
    Result := True;
  end else if Name = str_sz then begin
    if (value < -0.1) then value := -0.1;
    sz := Value;
    Result := True;
  end;
end;

function TVariationButterfly.ResetVariable(const Name: string): boolean;
begin
  Result := False;
  if Name = str_sx then begin
    sx := 1;
    Result := True;
  end else if Name = str_sy then begin
    sy := 1;
    Result := True;
  end else if Name = str_sz then begin
    sz := 0;
    Result := True;
  end;
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationButterfly.GetNrVariables: integer;
begin
  Result := 3;
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationButterfly.GetVariable(const Name: string; var value: double): boolean;
begin
  Result := False;
    if Name = str_sx then begin
    Value := sx;
    Result := True;
  end else if Name = str_sy then begin
    Value := sy;
    Result := True;
  end else if Name = str_sz then begin
    Value := sz;
    Result := True;
  end
end;

///////////////////////////////////////////////////////////////////////////////
initialization
  RegisterVariation(TVariationClassLoader.Create(TVariationButterfly), true, false);
end.
