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

unit varInversion3D;

interface

uses
  BaseVariation, XFormMan;

const
  sr = 'inversion3D_radius';
  sx0 = 'inversion3D_x0';
  sy0 = 'inversion3D_y0';
  sz0 = 'inversion3D_z0';
    
type
  TVariationInversion3D = class(TBaseVariation)
  private
    r, r2, x0, y0, z0: 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;

{ TVariationInversion3D }

//////////////////////////////////////////
procedure TVariationInversion3D.Prepare;
begin
	r2 := sqr(r);
end;

//////////////////////////////////////////
procedure TVariationInversion3D.CalcFunction;
var	x, y, z, dist: double;
begin
  x := FTx^ - x0;
  y := FTy^ - y0;
	z := FTz^ - z0;
	
	dist := sqr(x) + sqr(y) + sqr(z) + 1E-30;
	
	FPx^ := FPx^ + vvar * (r2 * x / dist + x0);
  FPy^ := FPy^ + vvar * (r2 * y / dist + y0);
	FPz^ := FPz^ + vvar * (r2 * z / dist + z0);
end;

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

constructor TVariationInversion3D.Create;
begin
  r := 1;
  x0 := 0;
  y0 := 0;
  z0 := 0;
end;

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

///////////////////////////////////////////////////////////////////////////////
class function TVariationInversion3D.GetName: string;
begin
  Result := 'inversion3D';
end;

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function TVariationInversion3D.GetVariableNameAt(const Index: integer): string;
begin
  case Index of
    0: Result := sr;
    1: Result := sx0;
	  2: Result := sy0;
	  3: Result := sz0;
  else
    Result := '';
  end
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationInversion3D.SetVariable(const Name: string; var value: double): boolean;
begin
  Result := False;
  if Name = sr then begin
    if (Value < 1E-6) then Value := 1E-6;
    r := value;
    Result := True;
  end else if Name = sx0 then begin
	x0 := Value;
    Result := True;
  end else if Name = sy0 then begin
	y0 := Value;
    Result := True;
  end else if Name = sz0 then begin
	z0 := Value;
    Result := True;
  end;
end;

function TVariationInversion3D.ResetVariable(const Name: string): boolean;
begin
  Result := False;
  if Name = sr then begin
    r := 1;
    Result := True;
  end else if Name = sx0 then begin
	x0 := 0;
    Result := True;
  end else if Name = sy0 then begin
	y0	:= 0;
    Result := True;
  end else if Name = sz0 then begin
	z0 := 0;
    Result := True;
  end;
end;

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

function TVariationInversion3D.GetNrVariables: integer;
begin
  Result := 4;
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationInversion3D.GetVariable(const Name: string; var value: double): boolean;
begin
  Result := False;
  if Name = sr then begin
    Value := r; 
    Result := True;
  end else if Name = sx0 then begin
    Value := x0;
    Result := True;
  end else if Name = sy0 then begin
	Value := y0;
    Result := True;
  end else if Name = sz0 then begin
	Value := z0;
    Result := True;
  end;
end;

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