apophysis/2.02f/Source/XForm.pas

585 lines
14 KiB
ObjectPascal
Raw Normal View History

2005-01-09 13:00:21 -05:00
unit XForm;
interface
const
NVARS = 22;
EPS = 1E-10;
type
TCalcMethod = procedure of object;
type
TXForm = class
private
FNrFunctions: Integer;
FFunctionList: array[0..NVARS] of TCalcMethod;
FTx, FTy: double;
FPx, FPy: double;
FAngle: double;
FLength: double;
CalculateAngle: boolean;
CalculateLength: boolean;
procedure Linear; // var[0]
procedure Sinusoidal; // var[1]
procedure Spherical; // var[2]
procedure Swirl; // var[3]
procedure Horseshoe; // var[4]
procedure Polar; // var[5]
procedure FoldedHandkerchief; // var[6]
procedure Heart; // var[7]
procedure Disc; // var[8]
procedure Spiral; // var[9]
procedure hyperbolic; // var[10]
procedure Square; // var[11]
procedure Ex; // var[12]
procedure Julia; // var[13]
procedure Bent; // var[14]
procedure Waves; // var[15]
procedure Fisheye; // var[16]
procedure Popcorn; // var[17]
procedure Exponential; // var[18]
procedure Power; // var[19]
procedure Cosine; // var[20]
procedure SawTooth; // var[21]
public
vars: array[0..NVARS - 1] of double; // normalized interp coefs between variations
c: array[0..2, 0..1] of double; // the coefs to the affine part of the function
density: double; // prob is this function is chosen. 0 - 1
color: double; // color coord for this function. 0 - 1
symmetry: double;
c00, c01, c10, c11, c20, c21: double;
varType: integer;
Orientationtype: integer;
constructor Create;
procedure Prepare;
procedure NextPoint(var px, py, pc: double); overload;
procedure NextPoint(var px, py, pz, pc: double); overload;
end;
implementation
uses
SysUtils, Math;
{ TXForm }
///////////////////////////////////////////////////////////////////////////////
constructor TXForm.Create;
var
i: Integer;
begin
density := 0;
Color := 0;
Vars[0] := 1;
for i := 1 to NVARS - 1 do begin
Vars[i] := 0;
end;
c[0, 0] := 1;
c[0, 1] := 0;
c[1, 0] := 0;
c[1, 1] := 1;
c[2, 0] := 0;
c[2, 1] := 0;
Symmetry := 0;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Prepare;
begin
c00 := c[0][0];
c01 := c[0][1];
c10 := c[1][0];
c11 := c[1][1];
c20 := c[2][0];
c21 := c[2][1];
FNrFunctions := 0;
if (vars[0] <> 0.0) then begin
FFunctionList[FNrFunctions] := Linear;
Inc(FNrFunctions);
end;
if (vars[1] <> 0.0) then begin
FFunctionList[FNrFunctions] := Sinusoidal;
Inc(FNrFunctions);
end;
if (vars[2] <> 0.0) then begin
FFunctionList[FNrFunctions] := Spherical;
Inc(FNrFunctions);
end;
if (vars[3] <> 0.0) then begin
FFunctionList[FNrFunctions] := Swirl;
Inc(FNrFunctions);
end;
if (vars[4] <> 0.0) then begin
FFunctionList[FNrFunctions] := Horseshoe;
Inc(FNrFunctions);
end;
if (vars[5] <> 0.0) then begin
FFunctionList[FNrFunctions] := Polar;
Inc(FNrFunctions);
end;
if (vars[6] <> 0.0) then begin
FFunctionList[FNrFunctions] := FoldedHandkerchief;
Inc(FNrFunctions);
end;
if (vars[7] <> 0.0) then begin
FFunctionList[FNrFunctions] := Heart;
Inc(FNrFunctions);
end;
if (vars[8] <> 0.0) then begin
FFunctionList[FNrFunctions] := Disc;
Inc(FNrFunctions);
end;
if (vars[9] <> 0.0) then begin
FFunctionList[FNrFunctions] := Spiral;
Inc(FNrFunctions);
end;
if (vars[10] <> 0.0) then begin
FFunctionList[FNrFunctions] := Hyperbolic;
Inc(FNrFunctions);
end;
if (vars[11] <> 0.0) then begin
FFunctionList[FNrFunctions] := Square;
Inc(FNrFunctions);
end;
if (vars[12] <> 0.0) then begin
FFunctionList[FNrFunctions] := Ex;
Inc(FNrFunctions);
end;
if (vars[13] <> 0.0) then begin
FFunctionList[FNrFunctions] := Julia;
Inc(FNrFunctions);
end;
if (vars[14] <> 0.0) then begin
FFunctionList[FNrFunctions] := Bent;
Inc(FNrFunctions);
end;
if (vars[15] <> 0.0) then begin
FFunctionList[FNrFunctions] := Waves;
Inc(FNrFunctions);
end;
if (vars[16] <> 0.0) then begin
FFunctionList[FNrFunctions] := Fisheye;
Inc(FNrFunctions);
end;
if (vars[17] <> 0.0) then begin
FFunctionList[FNrFunctions] := Popcorn;
Inc(FNrFunctions);
end;
if (vars[18] <> 0.0) then begin
FFunctionList[FNrFunctions] := Exponential;
Inc(FNrFunctions);
end;
if (vars[19] <> 0.0) then begin
FFunctionList[FNrFunctions] := Power;
Inc(FNrFunctions);
end;
if (vars[20] <> 0.0) then begin
FFunctionList[FNrFunctions] := Cosine;
Inc(FNrFunctions);
end;
if (vars[21] <> 0.0) then begin
FFunctionList[FNrFunctions] := SawTooth;
Inc(FNrFunctions);
end;
CalculateAngle := (vars[5] <> 0.0) or (vars[6] <> 0.0) or (vars[7] <> 0.0) or (vars[8] <> 0.0) or
(vars[9] <> 0.0) or (vars[10] <> 0.0) or (vars[11] <> 0.0) or (vars[12] <> 0.0) or
(vars[13] <> 0.0) or (vars[19] <> 0.0) or (vars[21] <> 0.0);
CalculateLength := False;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.NextPoint(var px,py,pc: double);
var
i: Integer;
begin
// first compute the color coord
pc := (pc + color) * 0.5 * (1 - symmetry) + symmetry * pc;
FTx := c00 * px + c10 * py + c20;
FTy := c01 * px + c11 * py + c21;
if CalculateAngle then begin
if (FTx < -EPS) or (FTx > EPS) or (FTy < -EPS) or (FTy > EPS) then
FAngle := arctan2(FTx, FTy)
else
FAngle := 0.0;
end;
// if CalculateLength then begin
// FLength := sqrt(FTx * FTx + FTy * FTy);
// end;
Fpx := 0;
Fpy := 0;
for i:= 0 to FNrFunctions-1 do
FFunctionList[i];
px := FPx;
py := FPy;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Linear;
begin
FPx := FPx + vars[0] * FTx;
FPy := FPy + vars[0] * FTy;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Sinusoidal;
begin
FPx := FPx + vars[1] * sin(FTx);
FPy := FPy + vars[1] * sin(FTy);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Spherical;
var
r2: double;
begin
r2 := FTx * FTx + FTy * FTy + 1E-6;
FPx := FPx + vars[2] * (FTx / r2);
FPy := FPy + vars[2] * (FTy / r2);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Swirl;
var
c1, c2, r2: double;
begin
r2 := FTx * FTx + FTy * FTy;
c1 := sin(r2);
c2 := cos(r2);
FPx := FPx + vars[3] * (c1 * FTx - c2 * FTy);
FPy := FPy + vars[3] * (c2 * FTx + c1 * FTy);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Horseshoe;
var
a, c1, c2: double;
begin
if (FTx < -EPS) or (FTx > EPS) or (FTy < -EPS) or (FTy > EPS) then
a := arctan2(FTx, FTy)
else
a := 0.0;
c1 := sin(a);
c2 := cos(a);
FPx := FPx + vars[4] * (c1 * FTx - c2 * FTy);
FPy := FPy + vars[4] * (c2 * FTx + c1 * FTy);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Polar;
var
ny: double;
begin
ny := sqrt(FTx * FTx + FTy * FTy) - 1.0;
FPx := FPx + vars[5] * (FAngle/PI);
FPy := FPy + vars[5] * ny;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.FoldedHandkerchief;
var
r: double;
begin
r := sqrt(FTx * FTx + FTy * FTy);
FPx := FPx + vars[6] * sin(FAngle + r) * r;
FPy := FPy + vars[6] * cos(FAngle - r) * r;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Heart;
var
r: double;
begin
r := sqrt(FTx * FTx + FTy * FTy);
FPx := FPx + vars[7] * sin(FAngle * r) * r;
FPy := FPy + vars[7] * cos(FAngle * r) * -r;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Disc;
var
nx, ny, r: double;
begin
nx := FTx * PI;
ny := FTy * PI;
r := sqrt(nx * nx + ny * ny);
FPx := FPx + vars[8] * sin(r) * FAngle / PI;
FPy := FPy + vars[8] * cos(r) * FAngle / PI;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Spiral;
var
r: double;
begin
r := sqrt(FTx * FTx + FTy * FTy) + 1E-6;
FPx := FPx + vars[9] * (cos(FAngle) + sin(r)) / r;
FPy := FPy + vars[9] * (sin(FAngle) - cos(r)) / r;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.hyperbolic;
var
r: double;
begin
r := sqrt(FTx * FTx + FTy * FTy) + 1E-6;
FPx := FPx + vars[10] * sin(FAngle) / r;
FPy := FPy + vars[10] * cos(FAngle) * r;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Square;
var
r: double;
begin
r := sqrt(FTx * FTx + FTy * FTy);
FPx := FPx + vars[11] * sin(FAngle) * cos(r);
FPy := FPy + vars[11] * cos(FAngle) * sin(r);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Ex;
var
r: double;
n0,n1, m0, m1: double;
begin
r := sqrt(FTx * FTx + FTy * FTy);
n0 := sin(FAngle + r);
n1 := cos(FAngle - r);
m0 := n0 * n0 * n0 * r;
m1 := n1 * n1 * n1 * r;
FPx := FPx + vars[12] * (m0 + m1);
FPy := FPy + vars[12] * (m0 - m1);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Julia;
var
a,r: double;
begin
r := Math.power(FTx * FTx + FTy * FTy, 0.25);
a := FAngle/2 + Trunc(random * 2) * PI;
FPx := FPx + vars[13] * r * cos(a);
FPy := FPy + vars[13] * r * sin(a);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Bent;
var
nx, ny: double;
begin
nx := FTx;
ny := FTy;
if (nx < 0) and (nx > -1E100) then
nx := nx * 2;
if ny < 0 then
ny := ny / 2;
FPx := FPx + vars[14] * nx;
FPy := FPy + vars[14] * ny;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Waves;
var
dx,dy,nx,ny: double;
begin
dx := c20;
dy := c21;
nx := FTx + c10 * sin(FTy / ((dx * dx) + EPS));
ny := FTy + c11 * sin(FTx / ((dy * dy) + EPS));
FPx := FPx + vars[15] * nx;
FPy := FPy + vars[15] * ny;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Fisheye;
var
a, r: double;
begin
r := sqrt(FTx * FTx + FTy * FTy);
a := arctan2(FTx, FTy);
r := 2 * r / (r + 1);
FPx := FPx + vars[16] * r * cos(a);
FPy := FPy + vars[16] * r * sin(a);
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Popcorn;
var
dx, dy: double;
nx, ny: double;
begin
dx := tan(3 * FTy);
if (dx <> dx) then
dx := 0.0; // < probably won't work in Delphi
dy := tan(3 * FTx); // NAN will raise an exception...
if (dy <> dy) then
dy := 0.0; // remove for speed?
nx := FTx + c20 * sin(dx);
ny := FTy + c21 * sin(dy);
FPx := FPx + vars[17] * nx;
FPy := FPy + vars[17] * ny;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Exponential;
var
dx, dy: double;
begin
dx := exp(FTx)/ 2.718281828459045;
dy := PI * FTy;
FPx := FPx + vars[18] * cos(dy) * dx;
FPy := FPy + vars[18] * sin(dy) * dx;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Power;
var
r,sa: double;
nx, ny: double;
begin
r := sqrt(FTx * FTx + FTy * FTy);
sa := sin(FAngle);
r := Math.power(r, sa);
nx := r * cos(FAngle);
ny := r * sa;
FPx := FPx + vars[19] * nx;
FPy := FPy + vars[19] * ny;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.Cosine;
var
nx, ny: double;
begin
nx := cos(Ftx * PI) * cosh(Fty);
ny := -sin(Ftx * PI) * sinh(Fty);
FPx := FPx + vars[20] * nx;
FPy := FPy + vars[20] * ny;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.SawTooth;
var
r: double;
nx, ny: double;
begin
r := sqrt(FTx * FTx + FTy * FTy);
// r := fmod(r + 1.0, 2.0) - 1.0;
r := r + 1;
r := r - System.Int(r/2) * 2.0 - 1;
nx := cos(FAngle) * r;
ny := sin(FAngle) * r;
FPx := FPx + vars[21] * nx;
FPy := FPy + vars[21] * ny;
end;
///////////////////////////////////////////////////////////////////////////////
procedure TXForm.NextPoint(var px, py, pz, pc: double);
var
i: Integer;
tpx, tpy: double;
begin
// first compute the color coord
pc := (pc + color) * 0.5 * (1 - symmetry) + symmetry * pc;
case Orientationtype of
1:
begin
tpx := px;
tpy := pz;
end;
2:
begin
tpx := py;
tpy := pz;
end;
else
tpx := px;
tpy := py;
end;
FTx := c00 * tpx + c10 * tpy + c20;
FTy := c01 * tpx + c11 * tpy + c21;
if CalculateAngle then begin
if (FTx < -EPS) or (FTx > EPS) or (FTy < -EPS) or (FTy > EPS) then
FAngle := arctan2(FTx, FTy)
else
FAngle := 0.0;
end;
if CalculateLength then begin
FLength := sqrt(FTx * FTx + FTy * FTy);
end;
Fpx := 0;
Fpy := 0;
for i:= 0 to FNrFunctions-1 do
FFunctionList[i];
case Orientationtype of
1:
begin
px := FPx;
pz := FPy;
end;
2:
begin
py := FPx;
pz := FPy;
end;
else
px := FPx;
py := FPy;
end;
end;
///////////////////////////////////////////////////////////////////////////////
end.