/***************************************************************************** * hcmplx.cpp * * This module implements hypercomplex Julia fractals. * * This file was written by Pascal Massimino. * * from Persistence of Vision(tm) Ray Tracer version 3.6. * Copyright 1991-2003 Persistence of Vision Team * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd. *--------------------------------------------------------------------------- * NOTICE: This source code file is provided so that users may experiment * with enhancements to POV-Ray and to port the software to platforms other * than those supported by the POV-Ray developers. There are strict rules * regarding how you are permitted to use this file. These rules are contained * in the distribution and derivative versions licenses which should have been * provided with this file. * * These licences may be found online, linked from the end-user license * agreement that is located at http://www.povray.org/povlegal.html *--------------------------------------------------------------------------- * This program is based on the popular DKB raytracer version 2.12. * DKBTrace was originally written by David K. Buck. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. *--------------------------------------------------------------------------- * $File: //depot/povray/3.6-release/source/hcmplx.cpp $ * $Revision: #3 $ * $Change: 3032 $ * $DateTime: 2004/08/02 18:43:41 $ * $Author: chrisc $ * $Log$ *****************************************************************************/ #include "frame.h" #include "povray.h" #include "vector.h" #include "fractal.h" #include "spheres.h" #include "hcmplx.h" BEGIN_POV_NAMESPACE /***************************************************************************** * Local preprocessor defines ******************************************************************************/ const DBL Fractal_Tolerance = 1e-8; #define HMult(xr,yr,zr,wr,x1,y1,z1,w1,x2,y2,z2,w2) \ (xr) = (x1) * (x2) - (y1) * (y2) - (z1) * (z2) + (w1) * (w2); \ (yr) = (y1) * (x2) + (x1) * (y2) - (w1) * (z2) - (z1) * (w2); \ (zr) = (z1) * (x2) - (w1) * (y2) + (x1) * (z2) - (y1) * (w2); \ (wr) = (w1) * (x2) + (z1) * (y2) + (y1) * (z2) + (x1) * (w2); #define HSqr(xr,yr,zr,wr,x,y,z,w) \ (xr) = (x) * (x) - (y) * (y) - (z) * (z) + (w) * (w) ; \ (yr) = 2.0 * ( (x) * (y) - (z) * (w) ); \ (zr) = 2.0 * ( (z) * (x) - (w) * (y) ); \ (wr) = 2.0 * ( (w) * (x) + (z) * (y) ); /***************************************************************************** * Local typedefs ******************************************************************************/ /***************************************************************************** * Static functions ******************************************************************************/ static int HReciprocal (DBL * xr, DBL * yr, DBL * zr, DBL * wr, DBL x, DBL y, DBL z, DBL w); static void HFunc (DBL * xr, DBL * yr, DBL * zr, DBL * wr, DBL x, DBL y, DBL z, DBL w, FRACTAL *f); /***************************************************************************** * Local variables ******************************************************************************/ static CMPLX exponent = {0,0}; // GLOBAL VARIABLE /******** Computations with Hypercomplexes **********/ /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ static int HReciprocal(DBL *xr, DBL *yr, DBL *zr, DBL *wr, DBL x, DBL y, DBL z, DBL w) { DBL det, mod, xt_minus_yz; det = ((x - w) * (x - w) + (y + z) * (y + z)) * ((x + w) * (x + w) + (y - z) * (y - z)); if (det == 0.0) { return (-1); } mod = (x * x + y * y + z * z + w * w); xt_minus_yz = x * w - y * z; *xr = (x * mod - 2 * w * xt_minus_yz) / det; *yr = (-y * mod - 2 * z * xt_minus_yz) / det; *zr = (-z * mod - 2 * y * xt_minus_yz) / det; *wr = (w * mod - 2 * x * xt_minus_yz) / det; return (0); } /***************************************************************************** * * FUNCTION Hfunc * * INPUT 4D Hypercomplex number, pointer to fractal object * * OUTPUT calculates the 4D generalization of fractal->Complex_Function * * RETURNS void * * AUTHOR * * Pascal Massimino * * DESCRIPTION * Hypercomplex numbers allow generalization of any complex->complex * function in a uniform way. This function implements a general * unary 4D function based on the corresponding complex function. * * CHANGES * Generalized to use Complex_Function() TW * ******************************************************************************/ static void HFunc(DBL *xr, DBL *yr, DBL *zr, DBL *wr, DBL x, DBL y, DBL z, DBL w, FRACTAL *f) { CMPLX a, b, ra, rb; /* convert to duplex form */ a.x = x - w; a.y = y + z; b.x = x + w; b.y = y - z; if(f->Sub_Type == PWR_STYPE) { exponent = f->exponent; } /* apply function to each part */ Complex_Function(&ra, &a, f); Complex_Function(&rb, &b, f); /* convert back */ *xr = .5 * (ra.x + rb.x); *yr = .5 * (ra.y + rb.y); *zr = .5 * (ra.y - rb.y); *wr = .5 * (rb.x - ra.x); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ /*------------------ z2 Iteration method ------------------*/ int Iteration_HCompl(VECTOR IPoint, FRACTAL *HCompl) { int i; DBL yz, xw; DBL Exit_Value; DBL x, y, z, w; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Z]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { yz = y * y + z * z; xw = x * x + w * w; if ((xw + yz) > Exit_Value) { return (false); } Sx[i] = xw - yz + HCompl->Julia_Parm[X]; Sy[i] = 2.0 * (x * y - z * w) + HCompl->Julia_Parm[Y]; Sz[i] = 2.0 * (x * z - w * y) + HCompl->Julia_Parm[Z]; Sw[i] = 2.0 * (x * w + y * z) + HCompl->Julia_Parm[T]; w = Sw[i]; x = Sx[i]; z = Sz[i]; y = Sy[i]; } return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int D_Iteration_HCompl(VECTOR IPoint, FRACTAL *HCompl, DBL *Dist) { int i; DBL yz, xw; DBL Exit_Value, F_Value, Step; DBL x, y, z, w; VECTOR H_Normal; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Z]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { yz = y * y + z * z; xw = x * x + w * w; if ((F_Value = xw + yz) > Exit_Value) { Normal_Calc_HCompl(H_Normal, i - 1, HCompl); VDot(Step, H_Normal, Direction); if (Step < -Fractal_Tolerance) { Step = -2.0 * Step; if ((F_Value > Precision * Step) && (F_Value < 30 * Precision * Step)) { *Dist = F_Value / Step; return (false); } } *Dist = Precision; return (false); } Sx[i] = xw - yz + HCompl->Julia_Parm[X]; Sy[i] = 2.0 * (x * y - z * w) + HCompl->Julia_Parm[Y]; Sz[i] = 2.0 * (x * z - w * y) + HCompl->Julia_Parm[Z]; Sw[i] = 2.0 * (x * w + y * z) + HCompl->Julia_Parm[T]; w = Sw[i]; x = Sx[i]; z = Sz[i]; y = Sy[i]; } *Dist = Precision; return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ void Normal_Calc_HCompl(VECTOR Result, int N_Max, FRACTAL *) { DBL n1, n2, n3, n4; int i; DBL x, y, z, w; DBL xx, yy, zz, ww; DBL Pow; /* * Algebraic properties of hypercomplexes allows simplifications in * computations... */ x = Sx[0]; y = Sy[0]; z = Sz[0]; w = Sw[0]; Pow = 2.0; for (i = 1; i < N_Max; ++i) { /* * For a map z->f(z), f depending on c, one must perform here : * * (x,y,z,w) * df/dz(Sx[i],Sy[i],Sz[i],Sw[i]) -> (x,y,z,w) , * * up to a constant. */ /******************* Case z->z^2+c *****************/ /* the df/dz part needs no work */ HMult(xx, yy, zz, ww, Sx[i], Sy[i], Sz[i], Sw[i], x, y, z, w); w = ww; z = zz; y = yy; x = xx; Pow *= 2.0; } n1 = Sx[N_Max] * Pow; n2 = Sy[N_Max] * Pow; n3 = Sz[N_Max] * Pow; n4 = Sw[N_Max] * Pow; Result[X] = x * n1 + y * n2 + z * n3 + w * n4; Result[Y] = -y * n1 + x * n2 - w * n3 + z * n4; Result[Z] = -z * n1 - w * n2 + x * n3 + y * n4; } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int F_Bound_HCompl(RAY *Ray, FRACTAL *Fractal, DBL *Depth_Min, DBL *Depth_Max) { return (Intersect_Sphere(Ray, Fractal->Center, Fractal->Radius_Squared, Depth_Min, Depth_Max)); } /****************************************************************/ /*--------------------------- z3 -------------------------------*/ /****************************************************************/ /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int Iteration_HCompl_z3(VECTOR IPoint, FRACTAL *HCompl) { int i; DBL Norm, xx, yy, zz, ww; DBL Exit_Value; DBL x, y, z, w; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Z]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { Norm = x * x + y * y + z * z + w * w; /* is this test correct ? */ if (Norm > Exit_Value) { return (false); } /*************** Case: z->z^2+c *********************/ HSqr(xx, yy, zz, ww, x, y, z, w); x = Sx[i] = xx + HCompl->Julia_Parm[X]; y = Sy[i] = yy + HCompl->Julia_Parm[Y]; z = Sz[i] = zz + HCompl->Julia_Parm[Z]; w = Sw[i] = ww + HCompl->Julia_Parm[T]; } return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int D_Iteration_HCompl_z3(VECTOR IPoint, FRACTAL *HCompl, DBL *Dist) { int i; DBL xx, yy, zz, ww; DBL Exit_Value, F_Value, Step; DBL x, y, z, w; VECTOR H_Normal; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Z]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { F_Value = x * x + y * y + z * z + w * w; if (F_Value > Exit_Value) { Normal_Calc_HCompl_z3(H_Normal, i - 1, HCompl); VDot(Step, H_Normal, Direction); if (Step < -Fractal_Tolerance) { Step = -2.0 * Step; if ((F_Value > Precision * Step) && (F_Value < 30 * Precision * Step)) { *Dist = F_Value / Step; return (false); } } *Dist = Precision; return (false); } /*************** Case: z->z^2+c *********************/ HSqr(xx, yy, zz, ww, x, y, z, w); x = Sx[i] = xx + HCompl->Julia_Parm[X]; y = Sy[i] = yy + HCompl->Julia_Parm[Y]; z = Sz[i] = zz + HCompl->Julia_Parm[Z]; w = Sw[i] = ww + HCompl->Julia_Parm[T]; } *Dist = Precision; return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ void Normal_Calc_HCompl_z3(VECTOR Result, int N_Max, FRACTAL *) { DBL n1, n2, n3, n4; int i; DBL x, y, z, w; DBL xx, yy, zz, ww; /* * Algebraic properties of hypercomplexes allows simplifications in * computations... */ x = Sx[0]; y = Sy[0]; z = Sz[0]; w = Sw[0]; for (i = 1; i < N_Max; ++i) { /* * For a map z->f(z), f depending on c, one must perform here : * * (x,y,z,w) * df/dz(Sx[i],Sy[i],Sz[i],Sw[i]) -> (x,y,z,w) , * * up to a constant. */ /******************* Case z->z^2+c *****************/ /* the df/dz part needs no work */ HMult(xx, yy, zz, ww, Sx[i], Sy[i], Sz[i], Sw[i], x, y, z, w); x = xx; y = yy; z = zz; w = ww; } n1 = Sx[N_Max]; n2 = Sy[N_Max]; n3 = Sz[N_Max]; n4 = Sw[N_Max]; Result[X] = x * n1 + y * n2 + z * n3 + w * n4; Result[Y] = -y * n1 + x * n2 - w * n3 + z * n4; Result[Z] = -z * n1 - w * n2 + x * n3 + y * n4; } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int F_Bound_HCompl_z3(RAY *Ray, FRACTAL *Fractal, DBL *Depth_Min, DBL *Depth_Max) { return F_Bound_HCompl(Ray, Fractal, Depth_Min, Depth_Max); } /*--------------------------- Inv -------------------------------*/ /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int Iteration_HCompl_Reciprocal(VECTOR IPoint, FRACTAL *HCompl) { int i; DBL Norm, xx, yy, zz, ww; DBL Exit_Value; DBL x, y, z, w; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Z]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { Norm = x * x + y * y + z * z + w * w; if (Norm > Exit_Value) { return (false); } HReciprocal(&xx, &yy, &zz, &ww, x, y, z, w); x = Sx[i] = xx + HCompl->Julia_Parm[X]; y = Sy[i] = yy + HCompl->Julia_Parm[Y]; z = Sz[i] = zz + HCompl->Julia_Parm[Z]; w = Sw[i] = ww + HCompl->Julia_Parm[T]; } return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int D_Iteration_HCompl_Reciprocal(VECTOR IPoint, FRACTAL *HCompl, DBL *Dist) { int i; DBL xx, yy, zz, ww; DBL Exit_Value, F_Value, Step; DBL x, y, z, w; VECTOR H_Normal; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Z]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { F_Value = x * x + y * y + z * z + w * w; if (F_Value > Exit_Value) { Normal_Calc_HCompl_Reciprocal(H_Normal, i - 1, HCompl); VDot(Step, H_Normal, Direction); if (Step < -Fractal_Tolerance) { Step = -2.0 * Step; if ((F_Value > Precision * Step) && F_Value < (30 * Precision * Step)) { *Dist = F_Value / Step; return (false); } } *Dist = Precision; return (false); } HReciprocal(&xx, &yy, &zz, &ww, x, y, z, w); x = Sx[i] = xx + HCompl->Julia_Parm[X]; y = Sy[i] = yy + HCompl->Julia_Parm[Y]; z = Sz[i] = zz + HCompl->Julia_Parm[Z]; w = Sw[i] = ww + HCompl->Julia_Parm[T]; } *Dist = Precision; return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ void Normal_Calc_HCompl_Reciprocal(VECTOR Result, int N_Max, FRACTAL *) { DBL n1, n2, n3, n4; int i; DBL x, y, z, w; DBL xx, yy, zz, ww; DBL xxx, yyy, zzz, www; /* * Algebraic properties of hypercomplexes allows simplifications in * computations... */ x = Sx[0]; y = Sy[0]; z = Sz[0]; w = Sw[0]; for (i = 1; i < N_Max; ++i) { /******************* Case: z->1/z+c *****************/ HReciprocal(&xx, &yy, &zz, &ww, Sx[i], Sy[i], Sz[i], Sw[i]); HSqr(xxx, yyy, zzz, www, xx, yy, zz, ww); HMult(xx, yy, zz, ww, x, y, z, w, -xxx, -yyy, -zzz, -www); x = xx; y = yy; z = zz; w = ww; } n1 = Sx[N_Max]; n2 = Sy[N_Max]; n3 = Sz[N_Max]; n4 = Sw[N_Max]; Result[X] = x * n1 + y * n2 + z * n3 + w * n4; Result[Y] = -y * n1 + x * n2 - w * n3 + z * n4; Result[Z] = -z * n1 - w * n2 + x * n3 + y * n4; } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int F_Bound_HCompl_Reciprocal(RAY *Ray, FRACTAL *Fractal, DBL *Depth_Min, DBL *Depth_Max) { return F_Bound_HCompl(Ray, Fractal, Depth_Min, Depth_Max); } /*--------------------------- Function -------------------------------*/ /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int Iteration_HCompl_Func(VECTOR IPoint, FRACTAL *HCompl) { int i; DBL Norm, xx, yy, zz, ww; DBL Exit_Value; DBL x, y, z, w; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Y]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { Norm = x * x + y * y + z * z + w * w; if (Norm > Exit_Value) { return (false); } HFunc(&xx, &yy, &zz, &ww, x, y, z, w, HCompl); x = Sx[i] = xx + HCompl->Julia_Parm[X]; y = Sy[i] = yy + HCompl->Julia_Parm[Y]; z = Sz[i] = zz + HCompl->Julia_Parm[Z]; w = Sw[i] = ww + HCompl->Julia_Parm[T]; } return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int D_Iteration_HCompl_Func(VECTOR IPoint, FRACTAL *HCompl, DBL *Dist) { int i; DBL xx, yy, zz, ww; DBL Exit_Value, F_Value, Step; DBL x, y, z, w; VECTOR H_Normal; x = Sx[0] = IPoint[X]; y = Sy[0] = IPoint[Y]; z = Sz[0] = IPoint[Z]; w = Sw[0] = (HCompl->SliceDist - HCompl->Slice[X]*x - HCompl->Slice[Y]*y - HCompl->Slice[Z]*z)/HCompl->Slice[T]; Exit_Value = HCompl->Exit_Value; for (i = 1; i <= HCompl->n; ++i) { F_Value = x * x + y * y + z * z + w * w; if (F_Value > Exit_Value) { Normal_Calc_HCompl_Func(H_Normal, i - 1, HCompl); VDot(Step, H_Normal, Direction); if (Step < -Fractal_Tolerance) { Step = -2.0 * Step; if ((F_Value > Precision * Step) && F_Value < (30 * Precision * Step)) { *Dist = F_Value / Step; return (false); } } *Dist = Precision; return (false); } HFunc(&xx, &yy, &zz, &ww, x, y, z, w, HCompl); x = Sx[i] = xx + HCompl->Julia_Parm[X]; y = Sy[i] = yy + HCompl->Julia_Parm[Y]; z = Sz[i] = zz + HCompl->Julia_Parm[Z]; w = Sw[i] = ww + HCompl->Julia_Parm[T]; } *Dist = Precision; return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ void Normal_Calc_HCompl_Func(VECTOR Result, int N_Max, FRACTAL *fractal) { DBL n1, n2, n3, n4; int i; DBL x, y, z, w; DBL xx, yy, zz, ww; DBL xxx, yyy, zzz, www; /* * Algebraic properties of hypercomplexes allows simplifications in * computations... */ x = Sx[0]; y = Sy[0]; z = Sz[0]; w = Sw[0]; for (i = 1; i < N_Max; ++i) { /**************** Case: z-> f(z)+c ************************/ HFunc(&xx, &yy, &zz, &ww, Sx[i], Sy[i], Sz[i], Sw[i], fractal); HMult(xxx, yyy, zzz, www, xx, yy, zz, ww, x, y, z, w); x = xxx; y = yyy; z = zzz; w = www; } n1 = Sx[N_Max]; n2 = Sy[N_Max]; n3 = Sz[N_Max]; n4 = Sw[N_Max]; Result[X] = x * n1 + y * n2 + z * n3 + w * n4; Result[Y] = -y * n1 + x * n2 - w * n3 + z * n4; Result[Z] = -z * n1 - w * n2 + x * n3 + y * n4; } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * CHANGES * ******************************************************************************/ int F_Bound_HCompl_Func(RAY *Ray, FRACTAL *Fractal, DBL *Depth_Min, DBL *Depth_Max) { return F_Bound_HCompl(Ray, Fractal, Depth_Min, Depth_Max); } /***************************************************************************** * * FUNCTION Complex transcental functions * * INPUT pointer to source complex number * * OUTPUT fn(input) * * RETURNS void * * AUTHOR * * Tim Wegner * * DESCRIPTION Calculate common functions on complexes * Since our purpose is fractals, error checking is lax. * * CHANGES * ******************************************************************************/ void Complex_Mult (CMPLX *target, CMPLX *source1, CMPLX *source2) { DBL tmpx; tmpx = source1->x * source2->x - source1->y * source2->y; target->y = source1->x * source2->y + source1->y * source2->x; target->x = tmpx; } void Complex_Div (CMPLX *target, CMPLX *source1, CMPLX *source2) { DBL mod,tmpx,yxmod,yymod; mod = Sqr(source2->x) + Sqr(source2->y); if (mod==0) return; yxmod = source2->x/mod; yymod = - source2->y/mod; tmpx = source1->x * yxmod - source1->y * yymod; target->y = source1->x * yymod + source1->y * yxmod; target->x = tmpx; } /* End Complex_Mult() */ void Complex_Exp (CMPLX *target, CMPLX *source) { DBL expx; expx = exp(source->x); target->x = expx * cos(source->y); target->y = expx * sin(source->y); } /* End Complex_Exp() */ void Complex_Sin (CMPLX *target, CMPLX *source) { target->x = sin(source->x) * cosh(source->y); target->y = cos(source->x) * sinh(source->y); } /* End Complex_Sin() */ void Complex_Sinh (CMPLX *target, CMPLX *source) { target->x = sinh(source->x) * cos(source->y); target->y = cosh(source->x) * sin(source->y); } /* End Complex_Sinh() */ void Complex_Cos (CMPLX *target, CMPLX *source) { target->x = cos(source->x) * cosh(source->y); target->y = -sin(source->x) * sinh(source->y); } /* End Complex_Cos() */ void Complex_Cosh (CMPLX *target, CMPLX *source) { target->x = cosh(source->x) * cos(source->y); target->y = sinh(source->x) * sin(source->y); } /* End Complex_Cosh() */ void Complex_Ln (CMPLX *target, CMPLX *source) { DBL mod,zx,zy; mod = sqrt(source->x * source->x + source->y * source->y); zx = log(mod); zy = atan2(source->y,source->x); target->x = zx; target->y = zy; } /* End Complex_Ln() */ void Complex_Sqrt(CMPLX *target, CMPLX *source) { DBL mag; DBL theta; if(source->x == 0.0 && source->y == 0.0) { target->x = target->y = 0.0; } else { mag = sqrt(sqrt(Sqr(source->x) + Sqr(source->y))); theta = atan2(source->y, source->x) / 2; target->y = mag * sin(theta); target->x = mag * cos(theta); } } /* End Complex_Sqrt() */ /* rz=Arcsin(z)=-i*Log{i*z+sqrt(1-z*z)} */ void Complex_ASin(CMPLX *target, CMPLX *source) { CMPLX tempz1,tempz2; Complex_Mult(&tempz1, source, source); tempz1.x = 1 - tempz1.x; tempz1.y = -tempz1.y; Complex_Sqrt( &tempz1, &tempz1); tempz2.x = -source->y; tempz2.y = source->x; tempz1.x += tempz2.x; tempz1.y += tempz2.y; Complex_Ln( &tempz1, &tempz1); target->x = tempz1.y; target->y = -tempz1.x; } /* End Complex_ASin() */ void Complex_ACos(CMPLX *target, CMPLX *source) { CMPLX temp; Complex_Mult(&temp, source, source); temp.x -= 1; Complex_Sqrt(&temp, &temp); temp.x += source->x; temp.y += source->y; Complex_Ln(&temp, &temp); target->x = temp.y; target->y = -temp.x; } /* End Complex_ACos() */ void Complex_ASinh(CMPLX *target, CMPLX *source) { CMPLX temp; Complex_Mult (&temp, source, source); temp.x += 1; Complex_Sqrt (&temp, &temp); temp.x += source->x; temp.y += source->y; Complex_Ln(target, &temp); } /* End Complex_ASinh */ /* rz=Arccosh(z)=Log(z+sqrt(z*z-1)} */ void Complex_ACosh (CMPLX *target, CMPLX *source) { CMPLX tempz; Complex_Mult(&tempz, source, source); tempz.x -= 1; Complex_Sqrt (&tempz, &tempz); tempz.x = source->x + tempz.x; tempz.y = source->y + tempz.y; Complex_Ln (target, &tempz); } /* End Complex_ACosh() */ /* rz=Arctanh(z)=1/2*Log{(1+z)/(1-z)} */ void Complex_ATanh(CMPLX *target, CMPLX *source) { CMPLX temp0,temp1,temp2; if( source->x == 0.0) { target->x = 0; target->y = atan( source->y); return; } else { if( fabs(source->x) == 1.0 && source->y == 0.0) { return; } else if( fabs( source->x) < 1.0 && source->y == 0.0) { target->x = log((1+source->x)/(1-source->x))/2; target->y = 0; return; } else { temp0.x = 1 + source->x; temp0.y = source->y; temp1.x = 1 - source->x; temp1.y = -source->y; Complex_Div(&temp2, &temp0, &temp1); Complex_Ln(&temp2, &temp2); target->x = .5 * temp2.x; target->y = .5 * temp2.y; return; } } } /* End Complex_ATanh() */ /* rz=Arctan(z)=i/2*Log{(1-i*z)/(1+i*z)} */ void Complex_ATan(CMPLX *target, CMPLX *source) { CMPLX temp0,temp1,temp2,temp3; if( source->x == 0.0 && source->y == 0.0) target->x = target->y = 0; else if( source->x != 0.0 && source->y == 0.0){ target->x = atan(source->x); target->y = 0; } else if( source->x == 0.0 && source->y != 0.0){ temp0.x = source->y; temp0.y = 0.0; Complex_ATanh(&temp0, &temp0); target->x = -temp0.y; target->y = temp0.x; } else if( source->x != 0.0 && source->y != 0.0) { temp0.x = -source->y; temp0.y = source->x; temp1.x = 1 - temp0.x; temp1.y = -temp0.y; temp2.x = 1 + temp0.x; temp2.y = temp0.y; Complex_Div(&temp3, &temp1, &temp2); Complex_Ln(&temp3, &temp3); target->x = -temp3.y * .5; target->y = .5 * temp3.x; } } /* End Complex_ATanz() */ void Complex_Tan(CMPLX *target, CMPLX *source) { DBL x, y, sinx, cosx, sinhy, coshy, denom; x = 2 * source->x; y = 2 * source->y; sinx = sin(x); cosx = cos(x); sinhy = sinh(y); coshy = cosh(y); denom = cosx + coshy; if(denom == 0) return; target->x = sinx/denom; target->y = sinhy/denom; } /* End Complex_Tan() */ void Complex_Tanh(CMPLX *target, CMPLX *source) { DBL x, y, siny, cosy, sinhx, coshx, denom; x = 2 * source->x; y = 2 * source->y; siny = sin(y); cosy = cos(y); sinhx = sinh(x); coshx = cosh(x); denom = coshx + cosy; if(denom == 0) return; target->x = sinhx/denom; target->y = siny/denom; } /* End Complex_Tanh() */ void Complex_Power (CMPLX *target, CMPLX *source1, CMPLX *source2) { CMPLX cLog, t; DBL e2x; if(source1->x == 0 && source1->y == 0) { target->x = target->y = 0.0; return; } Complex_Ln (&cLog, source1); Complex_Mult (&t, &cLog, source2); if(t.x < -690) e2x = 0; else e2x = exp(t.x); target->x = e2x * cos(t.y); target->y = e2x * sin(t.y); } #if 1 void Complex_Pwr (CMPLX *target, CMPLX *source) { Complex_Power(target, source, &exponent); } #else void Complex_Pwr (CMPLX *target, CMPLX *source) { /* the sqr dunction for testing */ Complex_Mult(target, source, source); } #endif END_POV_NAMESPACE