📄 fractals.c
字号:
/*
FRACTALS.C, FRACTALP.C and CALCFRAC.C actually calculate the fractal
images (well, SOMEBODY had to do it!). The modules are set up so that
all logic that is independent of any fractal-specific code is in
CALCFRAC.C, the code that IS fractal-specific is in FRACTALS.C, and the
struscture that ties (we hope!) everything together is in FRACTALP.C.
Original author Tim Wegner, but just about ALL the authors have
contributed SOME code to this routine at one time or another, or
contributed to one of the many massive restructurings.
The Fractal-specific routines are divided into three categories:
1. Routines that are called once-per-orbit to calculate the orbit
value. These have names like "XxxxFractal", and their function
pointers are stored in fractalspecific[fractype].orbitcalc. EVERY
new fractal type needs one of these. Return 0 to continue iterations,
1 if we're done. Results for integer fractals are left in 'lnew.x' and
'lnew.y', for floating point fractals in 'new.x' and 'new.y'.
2. Routines that are called once per pixel to set various variables
prior to the orbit calculation. These have names like xxx_per_pixel
and are fairly generic - chances are one is right for your new type.
They are stored in fractalspecific[fractype].per_pixel.
3. Routines that are called once per screen to set various variables.
These have names like XxxxSetup, and are stored in
fractalspecific[fractype].per_image.
4. The main fractal routine. Usually this will be StandardFractal(),
but if you have written a stand-alone fractal routine independent
of the StandardFractal mechanisms, your routine name goes here,
stored in fractalspecific[fractype].calctype.per_image.
Adding a new fractal type should be simply a matter of adding an item
to the 'fractalspecific' structure, writing (or re-using one of the existing)
an appropriate setup, per_image, per_pixel, and orbit routines.
-------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <string.h>
#ifdef __TURBOC__
#include <alloc.h>
#elif !defined(__386BSD__)
#include <malloc.h>
#endif
#include "fractint.h"
#include "mpmath.h"
#include "helpdefs.h"
#include "fractype.h"
#include "prototyp.h"
#define NEWTONDEGREELIMIT 100
extern int using_jiim;
extern _CMPLX initorbit;
extern _LCMPLX linitorbit;
extern char useinitorbit;
extern double fgLimit;
extern int distest;
#define CMPLXsqr_old(out) \
(out).y = (old.x+old.x) * old.y;\
(out).x = tempsqrx - tempsqry
#define CMPLXpwr(arg1,arg2,out) (out)= ComplexPower((arg1), (arg2))
#define CMPLXmult1(arg1,arg2,out) Arg2->d = (arg1); Arg1->d = (arg2);\
dStkMul(); Arg1++; Arg2++; (out) = Arg2->d
#define CMPLXmult(arg1,arg2,out) \
{\
_CMPLX TmP;\
TmP.x = (arg1).x*(arg2).x - (arg1).y*(arg2).y;\
TmP.y = (arg1).x*(arg2).y + (arg1).y*(arg2).x;\
(out) = TmP;\
}
#if 0
#define CMPLXmult(arg1,arg2,out) {CMPLXmult2(arg1,arg2,&out);}
#endif
void CMPLXmult2(_CMPLX arg1,_CMPLX arg2, _CMPLX *out)
{
_CMPLX TmP;
TmP.x = (arg1).x*(arg2).x - (arg1).y*(arg2).y;
TmP.y = (arg1).x*(arg2).y + (arg1).y*(arg2).x;
*out = TmP;
}
#define CMPLXadd(arg1,arg2,out) \
(out).x = (arg1).x + (arg2).x; (out).y = (arg1).y + (arg2).y
#define CMPLXsub(arg1,arg2,out) \
(out).x = (arg1).x - (arg2).x; (out).y = (arg1).y - (arg2).y
#define CMPLXtimesreal(arg,real,out) \
(out).x = (arg).x*(real);\
(out).y = (arg).y*(real)
#define CMPLXrecip(arg,out) \
{ double denom; denom = sqr((arg).x) + sqr((arg).y);\
if(denom==0.0) {(out).x = 1.0e10;(out).y = 1.0e10;}else\
{ (out).x = (arg).x/denom;\
(out).y = -(arg).y/denom;}}
extern int xshift, yshift;
extern int biomorph;
extern int forcesymmetry;
extern int symmetry;
_LCMPLX lcoefficient,lold,lnew,lparm, linit,ltmp,ltmp2,lparm2;
long ltempsqrx,ltempsqry;
extern int decomp[];
extern double param[];
extern int potflag; /* potential enabled? */
extern double f_radius,f_xcenter,f_ycenter; /* inversion radius, center */
extern double xxmin,xxmax,yymin,yymax; /* corners */
extern int overflow;
extern int integerfractal; /* TRUE if fractal uses integer math */
int maxcolor;
int root, degree,basin;
double floatmin,floatmax;
double roverd, d1overd, threshold;
_CMPLX tmp2;
extern _CMPLX init,tmp,old,new,saved,jbcfp;
_CMPLX coefficient;
_CMPLX staticroots[16]; /* roots array for degree 16 or less */
_CMPLX *roots = staticroots;
struct MPC *MPCroots;
extern int color, row, col;
extern int invert;
extern double far *dx0, far *dy0;
extern double far *dx1, far *dy1;
long FgHalf;
_CMPLX one;
_CMPLX pwr;
_CMPLX Coefficient;
extern int colors; /* maximum colors available */
extern int inside; /* "inside" color to use */
extern int outside; /* "outside" color to use */
extern int finattract;
extern int fractype; /* fractal type */
extern int debugflag; /* for debugging purposes */
extern double param[]; /* parameters */
extern long far *lx0, far *ly0; /* X, Y points */
extern long far *lx1, far *ly1; /* X, Y points */
extern long delx,dely; /* X, Y increments */
extern long delmin; /* min(max(dx),max(dy) */
extern double ddelmin; /* min(max(dx),max(dy) */
extern long fudge; /* fudge factor (2**n) */
extern int bitshift; /* bit shift for fudge */
int bitshiftless1; /* bit shift less 1 */
#ifndef sqr
#define sqr(x) ((x)*(x))
#endif
#ifndef lsqr
#define lsqr(x) (multiply((x),(x),bitshift))
#endif
#define modulus(z) (sqr((z).x)+sqr((z).y))
#define conjugate(pz) ((pz)->y = 0.0 - (pz)->y)
#define distance(z1,z2) (sqr((z1).x-(z2).x)+sqr((z1).y-(z2).y))
#define pMPsqr(z) (*pMPmul((z),(z)))
#define MPdistance(z1,z2) (*pMPadd(pMPsqr(*pMPsub((z1).x,(z2).x)),pMPsqr(*pMPsub((z1).y,(z2).y))))
double twopi = PI*2.0;
int c_exp;
/* These are local but I don't want to pass them as parameters */
_CMPLX lambda;
extern double magnitude, rqlim, rqlim2;
_CMPLX parm,parm2;
_CMPLX *floatparm;
_LCMPLX *longparm; /* used here and in jb.c */
extern int (*calctype)();
extern unsigned long lm; /* magnitude limit (CALCMAND) */
/* -------------------------------------------------------------------- */
/* These variables are external for speed's sake only */
/* -------------------------------------------------------------------- */
double sinx,cosx,sinhx,coshx;
double siny,cosy,sinhy,coshy;
double tmpexp;
double tempsqrx,tempsqry,tempsqrz,tempsqrt;
double foldxinitx,foldyinity,foldxinity,foldyinitx;
long oldxinitx,oldyinity,oldxinity,oldyinitx;
long longtmp;
extern long lmagnitud, llimit, llimit2, l16triglim;
extern periodicitycheck;
extern char floatflag;
/* These are for quaternions */
double qc,qci,qcj,qck;
/* temporary variables for trig use */
long lcosx, lcoshx, lsinx, lsinhx;
long lcosy, lcoshy, lsiny, lsinhy;
/*
** details of finite attractors (required for Magnet Fractals)
** (can also be used in "coloring in" the lakes of Julia types)
*/
extern int attractors; /* number of finite attractors */
extern _CMPLX attr[]; /* finite attractor values (f.p) */
extern _LCMPLX lattr[]; /* finite attractor values (int) */
extern int attrperiod[]; /* finite attractor period */
/*
** pre-calculated values for fractal types Magnet2M & Magnet2J
*/
_CMPLX T_Cm1; /* 3 * (floatparm - 1) */
_CMPLX T_Cm2; /* 3 * (floatparm - 2) */
_CMPLX T_Cm1Cm2; /* (floatparm - 1) * (floatparm - 2) */
void FloatPreCalcMagnet2() /* precalculation for Magnet2 (M & J) for speed */
{
T_Cm1.x = floatparm->x - 1.0; T_Cm1.y = floatparm->y;
T_Cm2.x = floatparm->x - 2.0; T_Cm2.y = floatparm->y;
T_Cm1Cm2.x = (T_Cm1.x * T_Cm2.x) - (T_Cm1.y * T_Cm2.y);
T_Cm1Cm2.y = (T_Cm1.x * T_Cm2.y) + (T_Cm1.y * T_Cm2.x);
T_Cm1.x += T_Cm1.x + T_Cm1.x; T_Cm1.y += T_Cm1.y + T_Cm1.y;
T_Cm2.x += T_Cm2.x + T_Cm2.x; T_Cm2.y += T_Cm2.y + T_Cm2.y;
}
/* -------------------------------------------------------------------- */
/* Bailout Routines Macros */
/* -------------------------------------------------------------------- */
static int near floatbailout()
{
if ( ( magnitude = ( tempsqrx=sqr(new.x) )
+ ( tempsqry=sqr(new.y) ) ) >= rqlim ) return(1);
old = new;
return(0);
}
/* longbailout() is equivalent to next */
#define LONGBAILOUT() \
ltempsqrx = lsqr(lnew.x); ltempsqry = lsqr(lnew.y);\
lmagnitud = ltempsqrx + ltempsqry;\
if (lmagnitud >= llimit || lmagnitud < 0 || labs(lnew.x) > llimit2\
|| labs(lnew.y) > llimit2 || overflow) \
{ overflow=0;return(1);}\
lold = lnew;
#define FLOATTRIGBAILOUT() \
if (fabs(old.y) >= rqlim2) return(1);
#define LONGTRIGBAILOUT() \
if(labs(lold.y) >= llimit2 || overflow) { overflow=0;return(1);}
#define LONGXYTRIGBAILOUT() \
if(labs(lold.x) >= llimit2 || labs(lold.y) >= llimit2 || overflow)\
{ overflow=0;return(1);}
#define FLOATXYTRIGBAILOUT() \
if (fabs(old.x) >= rqlim2 || fabs(old.y) >= rqlim2) return(1);
#define FLOATHTRIGBAILOUT() \
if (fabs(old.x) >= rqlim2) return(1);
#define LONGHTRIGBAILOUT() \
if(labs(lold.x) >= llimit2 || overflow) { overflow=0;return(1);}
#define TRIG16CHECK(X) \
if(labs((X)) > l16triglim || overflow) { overflow=0;return(1);}
#define FLOATEXPBAILOUT() \
if (fabs(old.y) >= 1.0e8) return(1);\
if (fabs(old.x) >= 6.4e2) return(1);
#define LONGEXPBAILOUT() \
if (labs(lold.y) >= (1000L<<bitshift)) return(1);\
if (labs(lold.x) >= (8L<<bitshift)) return(1);
#if 0
/* this define uses usual trig instead of fast trig */
#define FPUsincos(px,psinx,pcosx) \
*(psinx) = sin(*(px));\
*(pcosx) = cos(*(px));
#define FPUsinhcosh(px,psinhx,pcoshx) \
*(psinhx) = sinh(*(px));\
*(pcoshx) = cosh(*(px));
#endif
#define LTRIGARG(X) \
if(labs((X)) > l16triglim)\
{\
double tmp;\
tmp = (X);\
tmp /= fudge;\
tmp = fmod(tmp,twopi);\
tmp *= fudge;\
(X) = tmp;\
}\
static int near Halleybailout()
{
if ( fabs(modulus(new)-modulus(old)) < parm2.x)
return(1);
old = new;
return(0);
}
#ifndef XFRACT
#define MPCmod(m) (*pMPadd(*pMPmul((m).x, (m).x), *pMPmul((m).y, (m).y)))
struct MPC mpcold, mpcnew, mpctmp, mpctmp1;
struct MP mptmpparm2x;
static int near MPCHalleybailout()
{
static struct MP mptmpbailout;
mptmpbailout = *MPabs(*pMPsub(MPCmod(mpcnew), MPCmod(mpcold)));
if (pMPcmp(mptmpbailout, mptmpparm2x) < 0)
return(1);
mpcold = mpcnew;
return(0);
}
#endif
/* -------------------------------------------------------------------- */
/* Fractal (once per iteration) routines */
/* -------------------------------------------------------------------- */
static double xt, yt, t2;
/* Raise complex number (base) to the (exp) power, storing the result
** in complex (result).
*/
void cpower(_CMPLX *base, int exp, _CMPLX *result)
{
if (exp<0) {
cpower(base,-exp,result);
CMPLXrecip(*result,*result);
return;
}
xt = base->x; yt = base->y;
if (exp & 1)
{
result->x = xt;
result->y = yt;
}
else
{
result->x = 1.0;
result->y = 0.0;
}
exp >>= 1;
while (exp)
{
t2 = xt * xt - yt * yt;
yt = 2 * xt * yt;
xt = t2;
if (exp & 1)
{
t2 = xt * result->x - yt * result->y;
result->y = result->y * xt + yt * result->x;
result->x = t2;
}
exp >>= 1;
}
}
/* long version */
static long lxt, lyt, lt2;
lcpower(_LCMPLX *base, int exp, _LCMPLX *result, int bitshift)
{
static long maxarg;
maxarg = 64L<<bitshift;
overflow = 0;
lxt = base->x; lyt = base->y;
if (exp & 1)
{
result->x = lxt;
result->y = lyt;
}
else
{
result->x = 1L<<bitshift;
result->y = 0L;
}
exp >>= 1;
while (exp)
{
/*
if(labs(lxt) >= maxarg || labs(lyt) >= maxarg)
return(-1);
*/
lt2 = multiply(lxt, lxt, bitshift) - multiply(lyt,lyt,bitshift);
lyt = multiply(lxt,lyt,bitshiftless1);
if(overflow)
return(overflow);
lxt = lt2;
if (exp & 1)
{
lt2 = multiply(lxt,result->x, bitshift) - multiply(lyt,result->y,bitshift);
result->y = multiply(result->y,lxt,bitshift) + multiply(lyt,result->x,bitshift);
result->x = lt2;
}
exp >>= 1;
}
if(result->x == 0 && result->y == 0)
overflow = 1;
return(overflow);
}
#if 0
z_to_the_z(_CMPLX *z, _CMPLX *out)
{
static _CMPLX tmp1,tmp2;
/* raises complex z to the z power */
int errno_xxx;
errno_xxx = 0;
if(fabs(z->x) < DBL_EPSILON) return(-1);
/* log(x + iy) = 1/2(log(x*x + y*y) + i(arc_tan(y/x)) */
tmp1.x = .5*log(sqr(z->x)+sqr(z->y));
/* the fabs in next line added to prevent discontinuity in image */
tmp1.y = atan(fabs(z->y/z->x));
/* log(z)*z */
tmp2.x = tmp1.x * z->x - tmp1.y * z->y;
tmp2.y = tmp1.x * z->y + tmp1.y * z->x;
/* z*z = e**(log(z)*z) */
/* e**(x + iy) = e**x * (cos(y) + isin(y)) */
tmpexp = exp(tmp2.x);
FPUsincos(&tmp2.y,&siny,&cosy);
out->x = tmpexp*cosy;
out->y = tmpexp*siny;
return(errno_xxx);
}
#endif
int complex_div(_CMPLX arg1,_CMPLX arg2,_CMPLX *pz);
int complex_mult(_CMPLX arg1,_CMPLX arg2,_CMPLX *pz);
#ifdef XFRACT /* fractint uses the NewtonFractal2 code in newton.asm */
/* Distance of complex z from unit circle */
#define DIST1(z) (((z).x-1.0)*((z).x-1.0)+((z).y)*((z).y))
#define LDIST1(z) (lsqr((((z).x)-fudge)) + lsqr(((z).y)))
int NewtonFractal2()
{
static char start=1;
if(start)
{
start = 0;
}
cpower(&old, degree-1, &tmp);
complex_mult(tmp, old, &new);
if (DIST1(new) < threshold)
{
if(fractype==NEWTBASIN || fractype==MPNEWTBASIN)
{
int tmpcolor;
int i;
tmpcolor = -1;
/* this code determines which degree-th root of root the
Newton formula converges to. The roots of a 1 are
distributed on a circle of radius 1 about the origin. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -