{ Apophysis Copyright (C) 2001-2004 Mark Townsend Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Borys, Peter Sdobnov Apophysis Copyright (C) 2007-2008 Piotr Borys, Peter Sdobnov Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } unit varPreMobius; interface uses BaseVariation, XFormMan; type TVariationPreMobius = class(TBaseVariation) private Re_A, Im_A, Re_B, Im_B, Re_C, Im_C, Re_D, Im_D: double; mobius_invert : byte; procedure CalcInvert; 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 CalcFunction; override; procedure GetCalcFunction(var f: TCalcFunction); override; end; implementation uses Math; /////////////////////////////////////////////////////////////////////////////// procedure TVariationPreMobius.GetCalcFunction(var f: TCalcFunction); begin // AV: this helps to increase the calc speed if (mobius_invert <> 0) then f := CalcInvert else f := CalcFunction; end; procedure TVariationPreMobius.CalcFunction; const EPS = 1E-100; var uRe, uIm, vRe, vIm, vDenom : double; begin uRe := (Re_A) * FTx^ - (Im_A) * FTy^ + (Re_B); uIm := (Re_A) * FTy^ + (Im_A) * FTx^ + (Im_B); vRe := (Re_C) * FTx^ - (Im_C) * FTy^ + (Re_D); vIm := (Re_C) * FTy^ + (Im_C) * FTx^ + (Im_D); vDenom := vRe * vRe + vIm * vIm; if abs(vDenom) < EPS then vDenom := EPS; FTx^ := VVAR * (uRe*vRe + uIm*vIm) / vDenom; FTy^ := VVAR * (uIm*vRe - uRe*vIm) / vDenom; end; procedure TVariationPreMobius.CalcInvert; // inverse Mobius transformation const EPS = 1E-100; var uRe, uIm, vRe, vIm, vDenom : double; begin uRe := (Re_D) * FTX^ - (Im_D) * FTY^ - (Re_B); uIm := (Re_D) * FTY^ + (Im_D) * FTx^ - (Im_B); vRe := -(Re_C) * FTx^ + (Im_C) * FTy^ + (Re_A); vIm := -(Re_C) * FTy^ - (Im_C) * FTx^ + (Im_A); vDenom := vRe * vRe + vIm * vIm; if abs(vDenom) < EPS then vDenom := EPS; FTx^ := VVAR * (uRe*vRe + uIm*vIm) / vDenom; FTy^ := VVAR * (uIm*vRe - uRe*vIm) / vDenom; end; /////////////////////////////////////////////////////////////////////////////// constructor TVariationPreMobius.Create; begin Re_A := 1; Im_A := 0; Re_B := 0; Im_B := 0; Re_C := 0; Im_C := 0; Re_D := 1; Im_D := 0; mobius_invert := 0; end; /////////////////////////////////////////////////////////////////////////////// class function TVariationPreMobius.GetInstance: TBaseVariation; begin Result := TVariationPreMobius.Create; end; /////////////////////////////////////////////////////////////////////////////// class function TVariationPreMobius.GetName: string; begin Result := 'pre_mobius'; end; /////////////////////////////////////////////////////////////////////////////// function TVariationPreMobius.GetVariableNameAt(const Index: integer): string; begin case Index of 0: Result := 'pre_mobius_Re_A'; 1: Result := 'pre_mobius_Im_A'; 2: Result := 'pre_mobius_Re_B'; 3: Result := 'pre_mobius_Im_B'; 4: Result := 'pre_mobius_Re_C'; 5: Result := 'pre_mobius_Im_C'; 6: Result := 'pre_mobius_Re_D'; 7: Result := 'pre_mobius_Im_D'; 8: Result := 'pre_mobius_invert'; else Result := ''; end end; /////////////////////////////////////////////////////////////////////////////// function TVariationPreMobius.SetVariable(const Name: string; var value: double): boolean; begin Result := False; if Name = 'pre_mobius_Re_A' then begin Re_A := Value; Result := True; end else if Name = 'pre_mobius_Im_A' then begin Im_A := Value; Result := True; end else if Name = 'pre_mobius_Re_B' then begin Re_B := Value; Result := True; end else if Name = 'pre_mobius_Im_B' then begin Im_B := Value; Result := True; end else if Name = 'pre_mobius_Re_C' then begin Re_C := Value; Result := True; end else if Name = 'pre_mobius_Im_C' then begin Im_C := Value; Result := True; end else if Name = 'pre_mobius_Re_D' then begin Re_D := Value; Result := True; end else if Name = 'pre_mobius_Im_D' then begin Im_D := Value; Result := True; end else if Name = 'pre_mobius_invert' then begin if (Value > 1) then Value := 1; if (Value < 0) then Value := 0; mobius_invert := Round(Value); Result := True; end end; function TVariationPreMobius.ResetVariable(const Name: string): boolean; begin Result := False; if Name = 'pre_mobius_Re_A' then begin Re_A := 1; Result := True; end else if Name = 'pre_mobius_Im_A' then begin Im_A := 0; Result := True; end else if Name = 'pre_mobius_Re_B' then begin Re_B := 0; Result := True; end else if Name = 'pre_mobius_Im_B' then begin Im_B := 0; Result := True; end else if Name = 'pre_mobius_Re_C' then begin Re_C := 0; Result := True; end else if Name = 'pre_mobius_Im_C' then begin Im_C := 0; Result := True; end else if Name = 'pre_mobius_Re_D' then begin Re_D := 1; Result := True; end else if Name = 'pre_mobius_Im_D' then begin Im_D := 0; Result := True; end else if Name = 'pre_mobius_invert' then begin mobius_invert := 0; Result := True; end end; /////////////////////////////////////////////////////////////////////////////// function TVariationPreMobius.GetNrVariables: integer; begin Result := 9 end; /////////////////////////////////////////////////////////////////////////////// function TVariationPreMobius.GetVariable(const Name: string; var value: double): boolean; begin Result := False; if Name = 'pre_mobius_Re_A' then begin Value := Re_A; Result := True; end else if Name = 'pre_mobius_Im_A' then begin Value := Im_A; Result := True; end else if Name = 'pre_mobius_Re_B' then begin Value := Re_B; Result := True; end else if Name = 'pre_mobius_Im_B' then begin Value := Im_B; Result := True; end else if Name = 'pre_mobius_Re_C' then begin Value := Re_C; Result := True; end else if Name = 'pre_mobius_Im_C' then begin Value := Im_C; Result := True; end else if Name = 'pre_mobius_Re_D' then begin Value := Re_D; Result := True; end else if Name = 'pre_mobius_Im_D' then begin Value := Im_D; Result := True; end else if Name = 'pre_mobius_invert' then begin Value := mobius_invert; Result := True; end end; /////////////////////////////////////////////////////////////////////////////// initialization RegisterVariation(TVariationClassLoader.Create(TVariationPreMobius), false, false); end.