{ Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina } unit varHyperboloid; interface uses BaseVariation, XFormMan; type TVariationHyperboloid = class(TBaseVariation) private kx, ky, kz, maxheight, h, hb: double; vkx, vky, vkz: double; limit, zero: byte; procedure CalcCut; procedure CalcCutBoarder; 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; procedure GetCalcFunction(var f: TCalcFunction); override; end; implementation uses Math; { TVariationHyperboloid } /////////////////////////////////////////////////////////////////////////////// procedure TVariationHyperboloid.Prepare; begin vkx := VVAR * kx; vky := VVAR * ky; vkz := VVAR * kz; h := sqrt(1 + sqr(maxheight / ky)); hb := sqrt(sqr(h) - 1); end; procedure TVariationHyperboloid.GetCalcFunction(var f: TCalcFunction); begin if (limit = 0) then f := CalcFunction else if (zero = 0) then f := CalcCutBoarder else f := CalcCut; end; procedure TVariationHyperboloid.CalcFunction; var sn, cn, sh, ch: double; begin SinCos(FTx^, sn, cn); SinhCosh(FTy^, sh, ch); FPx^ := FPx^ + vkx * ch * sn; FPy^ := FPy^ + vky * sh; FPz^ := FPz^ + vkz * ch * cn; end; procedure TVariationHyperboloid.CalcCut; var sn, cn, sh, ch: double; begin SinhCosh(FTy^, sh, ch); if (ch <= h) then // cut the surface begin SinCos(FTx^, sn, cn); FPx^ := FPx^ + vkx * ch * sn; FPy^ := FPy^ + vky * sh; FPz^ := FPz^ + vkz * ch * cn; end; end; procedure TVariationHyperboloid.CalcCutBoarder; var sn, cn, sh, ch: double; begin SinCos(FTx^, sn, cn); SinhCosh(FTy^, sh, ch); if (ch <= h) then // cut the surface begin FPx^ := FPx^ + vkx * ch * sn; FPy^ := FPy^ + vky * sh; FPz^ := FPz^ + vkz * ch * cn; end else begin // place the point on it's boarder FPx^ := FPx^ + vkx * h * sn; FPy^ := FPy^ + vky * sign(sh) * hb; FPz^ := FPz^ + vkz * h * cn; end; end; /////////////////////////////////////////////////////////////////////////////// constructor TVariationHyperboloid.Create; begin kx := 1; ky := 1; kz := 1; maxheight := RandomRange(3, 6); limit := 1; zero := 0; end; /////////////////////////////////////////////////////////////////////////////// class function TVariationHyperboloid.GetInstance: TBaseVariation; begin Result := TVariationHyperboloid.Create; end; /////////////////////////////////////////////////////////////////////////////// class function TVariationHyperboloid.GetName: string; begin Result := 'hourglass3D'; // AV: hyperbolic hyperboloid :) end; /////////////////////////////////////////////////////////////////////////////// function TVariationHyperboloid.GetVariableNameAt(const Index: integer): string; begin case Index Of 0: Result := 'hourglass3D_kx'; 1: Result := 'hourglass3D_ky'; 2: Result := 'hourglass3D_kz'; 3: Result := 'hourglass3D_maxheight'; 4: Result := 'hourglass3D_uselimit'; 5: Result := 'hourglass3D_zero_edges'; else Result := ''; end end; /////////////////////////////////////////////////////////////////////////////// function TVariationHyperboloid.SetVariable(const Name: string; var value: double): boolean; begin Result := False; if Name = 'hourglass3D_kx' then begin if (value < 1E-5) then Value := 1E-5; kx := Value; Result := True; end else if Name = 'hourglass3D_ky' then begin if (value < 1E-5) then Value := 1E-5; ky := Value; Result := True; end else if Name = 'hourglass3D_kz' then begin if (value < 1E-5) then Value := 1E-5; kz := Value; Result := True; end else if Name = 'hourglass3D_maxheight' then begin if (value < 0.1) then Value := 0.1; maxheight := Value; Result := True; end else if Name = 'hourglass3D_uselimit' then begin if (value < 0) then Value := 0; if (value > 1) then Value := 1; limit := Round(Value); Result := True; end else if Name = 'hourglass3D_zero_edges' then begin if (value < 0) then Value := 0; if (value > 1) then Value := 1; zero := Round(Value); Result := True; end; end; function TVariationHyperboloid.ResetVariable(const Name: string): boolean; begin Result := False; if Name = 'hourglass3D_kx' then begin kx:= 1; Result := True; end else if Name = 'hourglass3D_ky' then begin ky := 1; Result := True; end else if Name = 'hourglass3D_kz' then begin kz := 1; Result := True; end else if Name = 'hourglass3D_maxheight' then begin maxheight := 3; Result := True; end else if Name = 'hourglass3D_uselimit' then begin limit := IfThen(limit = 0, 1, 0); Result := True; end else if Name = 'hourglass3D_zero_edges' then begin zero := IfThen(zero = 0, 1, 0); Result := True; end; end; /////////////////////////////////////////////////////////////////////////////// function TVariationHyperboloid.GetNrVariables: integer; begin Result := 6; end; /////////////////////////////////////////////////////////////////////////////// function TVariationHyperboloid.GetVariable(const Name: string; var value: double): boolean; begin Result := False; if Name = 'hourglass3D_kx' then begin Value := kx; Result := True; end else if Name = 'hourglass3D_ky' then begin Value := ky; Result := True; end else if Name = 'hourglass3D_kz' then begin Value := kz; Result := True; end else if Name = 'hourglass3D_maxheight' then begin Value := maxheight; Result := True; end else if Name = 'hourglass3D_uselimit' then begin Value := limit; Result := True; end else if Name = 'hourglass3D_zero_edges' then begin Value := zero; Result := True; end; end; /////////////////////////////////////////////////////////////////////////////// initialization RegisterVariation(TVariationClassLoader.Create(TVariationHyperboloid), true, false); end.