/******************************************************************************* * quatern.cpp * * This module implements Quaternion algebra julia fractals. * * This file was written by Pascal Massimino. * Revised and updated for POV-Ray 3.x by Tim Wegner * * --------------------------------------------------------------------------- * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd. * * POV-Ray is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * POV-Ray 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * --------------------------------------------------------------------------- * POV-Ray 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/public/povray/3.x/source/backend/math/quatern.cpp $ * $Revision: #1 $ * $Change: 6069 $ * $DateTime: 2013/11/06 11:59:40 $ * $Author: chrisc $ *******************************************************************************/ // frame.h must always be the first POV file included (pulls in platform config) #include "backend/frame.h" #include "povray.h" #include "backend/math/vector.h" #include "backend/shape/fractal.h" #include "backend/math/quatern.h" #include "backend/shape/spheres.h" // this must be the last file included #include "base/povdebug.h" namespace pov { /***************************************************************************** * Local preprocessor defines ******************************************************************************/ #define Deriv_z2(n1,n2,n3,n4) \ { \ tmp = (n1)*x - (n2)*y - (n3)*z - (n4)*w; \ (n2) = (n1)*y + x*(n2); \ (n3) = (n1)*z + x*(n3); \ (n4) = (n1)*w + x*(n4); \ (n1) = tmp; \ } #define Deriv_z3(n1,n2,n3,n4) \ { \ dtmp = 2.0*((n2)*y + (n3)*z + (n4)*w); \ dtmp2 = 6.0*x*(n1) - dtmp; \ (n1) = ( (n1)*x3 - x*dtmp )*3.0; \ (n2) = (n2)*x4 + y*dtmp2; \ (n3) = (n3)*x4 + z*dtmp2; \ (n4) = (n4)*x4 + w*dtmp2; \ } /***************************************************************************** * Local typedefs ******************************************************************************/ /***************************************************************************** * Static functions ******************************************************************************/ /***************************************************************************** * Local variables ******************************************************************************/ /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * - * * CHANGES * * Dec 1994 : Creation. * ******************************************************************************/ int Iteration_z3(const VECTOR point, const Fractal *Julia, DBL **IterStack) { int i; DBL x, y, z, w; DBL d, x2, tmp; DBL Exit_Value; IterStack[X][0] = x = point[X]; IterStack[Y][0] = y = point[Y]; IterStack[Z][0] = z = point[Z]; IterStack[W][0] = w = (Julia->SliceDist - Julia->Slice[X]*x - Julia->Slice[Y]*y - Julia->Slice[Z]*z)/Julia->Slice[T]; Exit_Value = Julia->Exit_Value; for (i = 1; i <= Julia->Num_Iterations; ++i) { d = y * y + z * z + w * w; x2 = x * x; if ((d + x2) > Exit_Value) { return (false); } tmp = 3.0 * x2 - d; IterStack[X][i] = x = x * (x2 - 3.0 * d) + Julia->Julia_Parm[X]; IterStack[Y][i] = y = y * tmp + Julia->Julia_Parm[Y]; IterStack[Z][i] = z = z * tmp + Julia->Julia_Parm[Z]; IterStack[W][i] = w = w * tmp + Julia->Julia_Parm[T]; } return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * - * * CHANGES * * Dec 1994 : Creation. * ******************************************************************************/ int Iteration_Julia(const VECTOR point, const Fractal *Julia, DBL **IterStack) { int i; DBL x, y, z, w; DBL d, x2; DBL Exit_Value; IterStack[X][0] = x = point[X]; IterStack[Y][0] = y = point[Y]; IterStack[Z][0] = z = point[Z]; IterStack[W][0] = w = (Julia->SliceDist - Julia->Slice[X]*x - Julia->Slice[Y]*y - Julia->Slice[Z]*z)/Julia->Slice[T]; Exit_Value = Julia->Exit_Value; for (i = 1; i <= Julia->Num_Iterations; ++i) { d = y * y + z * z + w * w; x2 = x * x; if ((d + x2) > Exit_Value) { return (false); } x *= 2.0; IterStack[Y][i] = y = x * y + Julia->Julia_Parm[Y]; IterStack[Z][i] = z = x * z + Julia->Julia_Parm[Z]; IterStack[W][i] = w = x * w + Julia->Julia_Parm[T]; IterStack[X][i] = x = x2 - d + Julia->Julia_Parm[X];; } return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * D_Iteration puts in *Dist a lower bound for the distance from *point to the * set * * CHANGES * * Dec 1994 : Creation. * ******************************************************************************/ /*----------- Distance estimator + iterations ------------*/ int D_Iteration_z3(const VECTOR point, const Fractal *Julia, const VECTOR &, DBL *Dist, DBL **IterStack) { int i, j; DBL Norm, d; DBL xx, yy, zz; DBL x, y, z, w; DBL tmp, x2; DBL Exit_Value; DBL Pow; x = IterStack[X][0] = point[X]; y = IterStack[Y][0] = point[Y]; z = IterStack[Z][0] = point[Z]; w = IterStack[W][0] = (Julia->SliceDist - Julia->Slice[X]*x - Julia->Slice[Y]*y - Julia->Slice[Z]*z)/Julia->Slice[T]; Exit_Value = Julia->Exit_Value; for (i = 1; i <= Julia->Num_Iterations; i++) { d = y * y + z * z + w * w; x2 = x * x; if ((Norm = d + x2) > Exit_Value) { /* Distance estimator */ x = IterStack[X][0]; y = IterStack[Y][0]; z = IterStack[Z][0]; w = IterStack[W][0]; Pow = 1.0 / 3.0; for (j = 1; j < i; ++j) { xx = x * IterStack[X][j] - y * IterStack[Y][j] - z * IterStack[Z][j] - w * IterStack[W][j]; yy = x * IterStack[Y][j] + y * IterStack[X][j] - z * IterStack[W][j] + w * IterStack[Z][j]; zz = x * IterStack[Z][j] + y * IterStack[W][j] + z * IterStack[X][j] - w * IterStack[Y][j]; w = x * IterStack[W][j] - y * IterStack[Z][j] + z * IterStack[Y][j] + w * IterStack[X][j]; x = xx; y = yy; z = zz; Pow /= 3.0; } *Dist = Pow * sqrt(Norm / (x * x + y * y + z * z + w * w)) * log(Norm); return (false); } tmp = 3.0 * x2 - d; IterStack[X][i] = x = x * (x2 - 3.0 * d) + Julia->Julia_Parm[X]; IterStack[Y][i] = y = y * tmp + Julia->Julia_Parm[Y]; IterStack[Z][i] = z = z * tmp + Julia->Julia_Parm[Z]; IterStack[W][i] = w = w * tmp + Julia->Julia_Parm[T]; } *Dist = Julia->Precision; return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * - * * CHANGES * * Dec 1994 : Creation. * ******************************************************************************/ int D_Iteration_Julia(const VECTOR point, const Fractal *Julia, const VECTOR &, DBL *Dist, DBL **IterStack) { int i, j; DBL Norm, d; DBL Exit_Value; DBL x, y, z, w; DBL xx, yy, zz, x2; DBL Pow; x = IterStack[X][0] = point[X]; y = IterStack[Y][0] = point[Y]; z = IterStack[Z][0] = point[Z]; w = IterStack[W][0] = (Julia->SliceDist - Julia->Slice[X]*x - Julia->Slice[Y]*y - Julia->Slice[Z]*z)/Julia->Slice[T]; Exit_Value = Julia->Exit_Value; for (i = 1; i <= Julia->Num_Iterations; i++) { d = y * y + z * z + w * w; x2 = x * x; if ((Norm = d + x2) > Exit_Value) { /* Distance estimator */ x = IterStack[X][0]; y = IterStack[Y][0]; z = IterStack[Z][0]; w = IterStack[W][0]; Pow = 1.0 / 2.0; for (j = 1; j < i; ++j) { xx = x * IterStack[X][j] - y * IterStack[Y][j] - z * IterStack[Z][j] - w * IterStack[W][j]; yy = x * IterStack[Y][j] + y * IterStack[X][j] + w * IterStack[Z][j] - z * IterStack[W][j]; zz = x * IterStack[Z][j] + z * IterStack[X][j] + y * IterStack[W][j] - w * IterStack[Y][j]; w = x * IterStack[W][j] + w * IterStack[X][j] + z * IterStack[Y][j] - y * IterStack[Z][j]; x = xx; y = yy; z = zz; Pow /= 2.0; } *Dist = Pow * sqrt(Norm / (x * x + y * y + z * z + w * w)) * log(Norm); return (false); } x *= 2.0; IterStack[Y][i] = y = x * y + Julia->Julia_Parm[Y]; IterStack[Z][i] = z = x * z + Julia->Julia_Parm[Z]; IterStack[W][i] = w = x * w + Julia->Julia_Parm[T]; IterStack[X][i] = x = x2 - d + Julia->Julia_Parm[X]; } *Dist = Julia->Precision; return (true); } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * Provided the iterations sequence has been built, perform the computation of * the Normal * * CHANGES * * Dec 1994 : Creation. * ******************************************************************************/ void Normal_Calc_z3(VECTOR Result, int N_Max, const Fractal *, DBL **IterStack) { DBL n11 = 1.0, n12 = 0.0, n13 = 0.0, n14 = 0.0, n21 = 0.0, n22 = 1.0, n23 = 0.0, n24 = 0.0, n31 = 0.0, n32 = 0.0, n33 = 1.0, n34 = 0.0; DBL x, y, z, w; int i; DBL tmp, dtmp, dtmp2, x2, x3, x4; x = IterStack[X][0]; y = IterStack[Y][0]; z = IterStack[Z][0]; w = IterStack[W][0]; for (i = 1; i <= N_Max; i++) { tmp = y * y + z * z + w * w; x2 = x * x; x3 = x2 - tmp; x4 = 3.0 * x2 - tmp; Deriv_z3(n11, n12, n13, n14); Deriv_z3(n21, n22, n23, n24); Deriv_z3(n31, n32, n33, n34); x = IterStack[X][i]; y = IterStack[Y][i]; z = IterStack[Z][i]; w = IterStack[W][i]; } Result[X] = n11 * x + n12 * y + n13 * z + n14 * w; Result[Y] = n21 * x + n22 * y + n23 * z + n24 * w; Result[Z] = n31 * x + n32 * y + n33 * z + n34 * w; } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * - * * CHANGES * * Dec 1994 : Creation. * ******************************************************************************/ void Normal_Calc_Julia(VECTOR Result, int N_Max, const Fractal *, DBL **IterStack) { DBL n11 = 1.0, n12 = 0.0, n13 = 0.0, n14 = 0.0, n21 = 0.0, n22 = 1.0, n23 = 0.0, n24 = 0.0, n31 = 0.0, n32 = 0.0, n33 = 1.0, n34 = 0.0; DBL tmp; DBL x, y, z, w; int i; x = IterStack[X][0]; y = IterStack[Y][0]; z = IterStack[Z][0]; w = IterStack[W][0]; for (i = 1; i <= N_Max; i++) { Deriv_z2(n11, n12, n13, n14); Deriv_z2(n21, n22, n23, n24); Deriv_z2(n31, n32, n33, n34); x = IterStack[X][i]; y = IterStack[Y][i]; z = IterStack[Z][i]; w = IterStack[W][i]; } Result[X] = n11 * x + n12 * y + n13 * z + n14 * w; Result[Y] = n21 * x + n22 * y + n23 * z + n24 * w; Result[Z] = n31 * x + n32 * y + n33 * z + n34 * w; } /***************************************************************************** * * FUNCTION * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * Pascal Massimino * * DESCRIPTION * * - * * CHANGES * * Dec 1994 : Creation. * ******************************************************************************/ int F_Bound_Julia(const Ray& ray, const Fractal *fractal, DBL *Depth_Min, DBL *Depth_Max) { return (Sphere::Intersect(ray, fractal->Center, fractal->Radius_Squared, Depth_Min, Depth_Max)); } }