/* * soi.c -- SOI * * Simultaneous Orbit Iteration Image Generation Method. Computes * rectangular regions by tracking the orbits of only a few key points. * * Copyright (c) 1994-1997 Michael R. Ganss. All Rights Reserved. * * This file is distributed under the same conditions as * AlmondBread. For further information see * . * */ #include #include #if !defined(_WIN32) #include #endif #include "port.h" #include "prototyp.h" #include "drivers.h" #define DBLS LDBL #define FABS(x) fabsl(x) /* the following needs to be changed back to frexpl once the portability issue has been addressed JCO */ #ifndef XFRACT #define FREXP(x,y) frexpl(x,y) #else #define FREXP(x,y) frexp(x,y) #endif #define TRUE 1 #define FALSE 0 #define EVERY 15 #define BASIN_COLOR 0 int rhombus_stack[10]; int rhombus_depth; int max_rhombus_depth; int minstackavail; /* int minstack=1700; */ /* need this much stack to recurse */ int minstack=2200; /* and this much stack to not crash when is pressed */ static DBLS twidth; static DBLS equal; static char baxinxx = FALSE; long iteration(register DBLS cr, register DBLS ci, register DBLS re, register DBLS im, long start) { register long iter,offset=0; int k,n; register DBLS ren,imn,sre,sim; #ifdef INTEL register float mag; register unsigned long bail=0x41800000,magi; /* bail=16.0 */ register unsigned long eq=*(unsigned long *)&equal; #else register DBLS mag; #endif DBLS d; int exponent; if (baxinxx) { sre=re; sim=im; ren=re*re; imn=im*im; if (start!=0) { offset=maxit-start+7; iter=offset>>3; offset&=7; offset=(8-offset); } else iter=maxit>>3; k=n=8; do { im=im*re; re=ren-imn; im+=im; re+=cr; im+=ci; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; #ifdef INTEL mag=FABS(sre-re); magi=*(unsigned long *)&mag; if (magi>3; offset&=7; offset=(8-offset); } else iter=maxit>>3; do { im=im*re; re=ren-imn; im+=im; re+=cr; im+=ci; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*re; ren=re+im; re=re-im; imn+=imn; re=ren*re; im=imn+ci; re+=cr; imn=im*im; ren=re*re; mag=ren+imn; #ifdef INTEL magi=*(unsigned long *)&mag; #endif } #ifdef INTEL while (magi>3])); } } static void puthline(int x1,int y1,int x2,int color) { int x; for (x=x1; x<=x2; x++) (*plot)(x,y1,color); } static void putbox(int x1, int y1, int x2, int y2, int color) { for (; y1<=y2; y1++) puthline(x1,y1,x2,color); } /* maximum side length beyond which we start regular scanning instead of subdividing */ #define SCAN 16 /* pixel interleave used in scanning */ #define INTERLEAVE 4 /* compute the value of the interpolation polynomial at (x,y) */ #define GET_REAL(x,y) \ interpolate(cim1,midi,cim2,\ interpolate(cre1,midr,cre2,zre1,zre5,zre2,x),\ interpolate(cre1,midr,cre2,zre6,zre9,zre7,x),\ interpolate(cre1,midr,cre2,zre3,zre8,zre4,x),y) #define GET_IMAG(x,y) \ interpolate(cre1,midr,cre2,\ interpolate(cim1,midi,cim2,zim1,zim6,zim3,y),\ interpolate(cim1,midi,cim2,zim5,zim9,zim8,y),\ interpolate(cim1,midi,cim2,zim2,zim7,zim4,y),x) /* compute the value of the interpolation polynomial at (x,y) from saved values before interpolation failed to stay within tolerance */ #define GET_SAVED_REAL(x,y) \ interpolate(cim1,midi,cim2,\ interpolate(cre1,midr,cre2,sr1,sr5,sr2,x),\ interpolate(cre1,midr,cre2,sr6,sr9,sr7,x),\ interpolate(cre1,midr,cre2,sr3,sr8,sr4,x),y) #define GET_SAVED_IMAG(x,y) \ interpolate(cre1,midr,cre2,\ interpolate(cim1,midi,cim2,si1,si6,si3,y),\ interpolate(cim1,midi,cim2,si5,si9,si8,y),\ interpolate(cim1,midi,cim2,si2,si7,si4,y),x) /* compute the value of the interpolation polynomial at (x,y) during scanning. Here, key values do not change, so we can precompute coefficients in one direction and simply evaluate the polynomial during scanning. */ #define GET_SCAN_REAL(x,y) \ interpolate(cim1,midi,cim2,\ EVALUATE(cre1,midr,br10,br11,br12,x),\ EVALUATE(cre1,midr,br20,br21,br22,x),\ EVALUATE(cre1,midr,br30,br31,br32,x),y) #define GET_SCAN_IMAG(x,y) \ interpolate(cre1,midr,cre2,\ EVALUATE(cim1,midi,bi10,bi11,bi12,y),\ EVALUATE(cim1,midi,bi20,bi21,bi22,y),\ EVALUATE(cim1,midi,bi30,bi31,bi32,y),x) /* compute coefficients of Newton polynomial (b0,..,b2) from (x0,w0),..,(x2,w2). */ #define INTERPOLATE(x0,x1,x2,w0,w1,w2,b0,b1,b2) \ b0=w0;\ b1=(w1-w0)/(LDBL)(x1-x0);\ b2=((w2-w1)/(LDBL)(x2-x1)-b1)/(x2-x0) /* evaluate Newton polynomial given by (x0,b0),(x1,b1) at x:=t */ #define EVALUATE(x0,x1,b0,b1,b2,t) \ ((b2*(t-x1)+b1)*(t-x0)+b0) /* Newton Interpolation. It computes the value of the interpolation polynomial given by (x0,w0)..(x2,w2) at x:=t */ static DBLS interpolate(DBLS x0, DBLS x1, DBLS x2, DBLS w0, DBLS w1, DBLS w2, DBLS t) { register DBLS b0=w0,b1=w1,b2=w2,b; /*b0=(r0*b1-r1*b0)/(x1-x0); b1=(r1*b2-r2*b1)/(x2-x1); b0=(r0*b1-r2*b0)/(x2-x0); return (DBLS)b0;*/ b=(b1-b0)/(x1-x0); return (DBLS)((((b2-b1)/(x2-x1)-b)/(x2-x0))*(t-x1)+b)*(t-x0)+b0; /* if (t max_rhombus_depth) max_rhombus_depth = rhombus_depth; rhombus_stack[rhombus_depth] = avail; if (driver_key_pressed()) { status = 1; goto rhombus_done; } if (iter>maxit) { putbox(x1,y1,x2,y2,0); status = 0; goto rhombus_done; } if ((y2-y1<=SCAN) || (avail < minstack)) { /* finish up the image by scanning the rectangle */ scan: INTERPOLATE(cre1,midr,cre2,zre1,zre5,zre2,br10,br11,br12); INTERPOLATE(cre1,midr,cre2,zre6,zre9,zre7,br20,br21,br22); INTERPOLATE(cre1,midr,cre2,zre3,zre8,zre4,br30,br31,br32); INTERPOLATE(cim1,midi,cim2,zim1,zim6,zim3,bi10,bi11,bi12); INTERPOLATE(cim1,midi,cim2,zim5,zim9,zim8,bi20,bi21,bi22); INTERPOLATE(cim1,midi,cim2,zim2,zim7,zim4,bi30,bi31,bi32); restep=(cre2-cre1)/(x2-x1); imstep=(cim2-cim1)/(y2-y1); interstep=INTERLEAVE*restep; for (y=y1, im=cim1; yx-INTERLEAVE; z--,helpre-=restep) { zre=GET_SCAN_REAL(helpre,im); zim=GET_SCAN_IMAG(helpre,im); helpcolor=iteration(helpre,im,zre,zim,iter); if (helpcolor < 0) { status = 1; goto rhombus_done; } else if (helpcolor==savecolor) break; (*plot)(z,y,(int)(helpcolor&255)); } if (savexsavex; z--,helpre-=restep) { zre=GET_SCAN_REAL(helpre,im); zim=GET_SCAN_IMAG(helpre,im); helpcolor=iteration(helpre,im,zre,zim,iter); if (helpcolor < 0) { status = 1; goto rhombus_done; } else if (helpcolor==savecolor) break; (*plot)(z,y,(int)(helpcolor&255)); } if (savex16.0|| (rq2+iq2)>16.0|| (rq3+iq3)>16.0|| (rq4+iq4)>16.0|| (rq5+iq5)>16.0|| (rq6+iq6)>16.0|| (rq7+iq7)>16.0|| (rq8+iq8)>16.0|| (rq9+iq9)>16.0|| (trq1+tiq1)>16.0|| (trq2+tiq2)>16.0|| (trq3+tiq3)>16.0|| (trq4+tiq4)>16.0) break; /* if maximum number of iterations is reached, the whole rectangle can be assumed part of M. This is of course best case behavior of SOI, we seldomly get there */ if (iter>maxit) { putbox(x1,y1,x2,y2,0); status = 0; goto rhombus_done; } /* now for all test points, check whether they exceed the allowed tolerance. if so, subdivide */ l1=GET_REAL(cr1,ci1); l1=(tzr1==0.0)? (l1==0.0)?1.0:1000.0: l1/tzr1; if (FABS(1.0-l1)>twidth) break; l2=GET_IMAG(cr1,ci1); l2=(tzi1==0.0)? (l2==0.0)?1.0:1000.0: l2/tzi1; if (FABS(1.0-l2)>twidth) break; l1=GET_REAL(cr2,ci1); l1=(tzr2==0.0)? (l1==0.0)?1.0:1000.0: l1/tzr2; if (FABS(1.0-l1)>twidth) break; l2=GET_IMAG(cr2,ci1); l2=(tzi2==0.0)? (l2==0.0)?1.0:1000.0: l2/tzi2; if (FABS(1.0-l2)>twidth) break; l1=GET_REAL(cr1,ci2); l1=(tzr3==0.0)? (l1==0.0)?1.0:1000.0: l1/tzr3; if (FABS(1.0-l1)>twidth) break; l2=GET_IMAG(cr1,ci2); l2=(tzi3==0.0)? (l2==0.0)?1.0:1000.0: l2/tzi3; if (FABS(1.0-l2)>twidth) break; l1=GET_REAL(cr2,ci2); l1=(tzr4==0.0)? (l1==0.0)?1.0:1000.0: l1/tzr4; if (FABS(1.0-l1)>twidth) break; l2=GET_IMAG(cr2,ci2); l2=(tzi4==0.0)? (l2==0.0)?1.0:1000.0: l2/tzi4; if (FABS(1.0-l2)>twidth) break; } iter--; /* this is a little heuristic I tried to improve performance. */ if (iter-before<10) { zre1=sr1; zim1=si1; zre2=sr2; zim2=si2; zre3=sr3; zim3=si3; zre4=sr4; zim4=si4; zre5=sr5; zim5=si5; zre6=sr6; zim6=si6; zre7=sr7; zim7=si7; zre8=sr8; zim8=si8; zre9=sr9; zim9=si9; goto scan; } /* compute key values for subsequent rectangles */ re10=interpolate(cre1,midr,cre2,sr1,sr5,sr2,cr1); im10=interpolate(cre1,midr,cre2,si1,si5,si2,cr1); re11=interpolate(cre1,midr,cre2,sr1,sr5,sr2,cr2); im11=interpolate(cre1,midr,cre2,si1,si5,si2,cr2); re20=interpolate(cre1,midr,cre2,sr3,sr8,sr4,cr1); im20=interpolate(cre1,midr,cre2,si3,si8,si4,cr1); re21=interpolate(cre1,midr,cre2,sr3,sr8,sr4,cr2); im21=interpolate(cre1,midr,cre2,si3,si8,si4,cr2); re15=interpolate(cre1,midr,cre2,sr6,sr9,sr7,cr1); im15=interpolate(cre1,midr,cre2,si6,si9,si7,cr1); re16=interpolate(cre1,midr,cre2,sr6,sr9,sr7,cr2); im16=interpolate(cre1,midr,cre2,si6,si9,si7,cr2); re12=interpolate(cim1,midi,cim2,sr1,sr6,sr3,ci1); im12=interpolate(cim1,midi,cim2,si1,si6,si3,ci1); re14=interpolate(cim1,midi,cim2,sr2,sr7,sr4,ci1); im14=interpolate(cim1,midi,cim2,si2,si7,si4,ci1); re17=interpolate(cim1,midi,cim2,sr1,sr6,sr3,ci2); im17=interpolate(cim1,midi,cim2,si1,si6,si3,ci2); re19=interpolate(cim1,midi,cim2,sr2,sr7,sr4,ci2); im19=interpolate(cim1,midi,cim2,si2,si7,si4,ci2); re13=interpolate(cim1,midi,cim2,sr5,sr9,sr8,ci1); im13=interpolate(cim1,midi,cim2,si5,si9,si8,ci1); re18=interpolate(cim1,midi,cim2,sr5,sr9,sr8,ci2); im18=interpolate(cim1,midi,cim2,si5,si9,si8,ci2); re91=GET_SAVED_REAL(cr1,ci1); re92=GET_SAVED_REAL(cr2,ci1); re93=GET_SAVED_REAL(cr1,ci2); re94=GET_SAVED_REAL(cr2,ci2); im91=GET_SAVED_IMAG(cr1,ci1); im92=GET_SAVED_IMAG(cr2,ci1); im93=GET_SAVED_IMAG(cr1,ci2); im94=GET_SAVED_IMAG(cr2,ci2); RHOMBUS(cre1,midr,cim1,midi,x1,((x1+x2)>>1),y1,((y1+y2)>>1), sr1,si1, sr5,si5, sr6,si6, sr9,si9, re10,im10, re12,im12, re13,im13, re15,im15, re91,im91, iter); RHOMBUS(midr,cre2,cim1,midi,(x1+x2)>>1,x2,y1,(y1+y2)>>1, sr5,si5, sr2,si2, sr9,si9, sr7,si7, re11,im11, re13,im13, re14,im14, re16,im16, re92,im92, iter); RHOMBUS(cre1,midr,midi,cim2,x1,(x1+x2)>>1,(y1+y2)>>1,y2, sr6,si6, sr9,si9, sr3,si3, sr8,si8, re15,im15, re17,im17, re18,im18, re20,im20, re93,im93, iter); RHOMBUS(midr,cre2,midi,cim2,(x1+x2)>>1,x2,(y1+y2)>>1,y2, sr9,si9, sr7,si7, sr8,si8, sr4,si4, re16,im16, re18,im18, re19,im19, re21,im21, re94,im94, iter); rhombus_done: rhombus_depth--; return(status); } void soi_ldbl(void) { int status; DBLS tolerance=0.1; DBLS stepx, stepy; DBLS xxminl, xxmaxl, yyminl, yymaxl; minstackavail = 30000; rhombus_depth = -1; max_rhombus_depth = 0; if (bf_math) { xxminl = bftofloat(bfxmin); yyminl = bftofloat(bfymin); xxmaxl = bftofloat(bfxmax); yymaxl = bftofloat(bfymax); } else { xxminl = xxmin; yyminl = yymin; xxmaxl = xxmax; yymaxl = yymax; } twidth=tolerance/(xdots-1); stepx = (xxmaxl - xxminl) / xdots; stepy = (yyminl - yymaxl) / ydots; equal = (stepx < stepy ? stepx : stepy); RHOMBUS(xxminl,xxmaxl,yymaxl,yyminl, 0,xdots,0,ydots, xxminl,yymaxl, xxmaxl,yymaxl, xxminl,yyminl, xxmaxl,yyminl, (xxmaxl+xxminl)/2,yymaxl, xxminl,(yymaxl+yyminl)/2, xxmaxl,(yymaxl+yyminl)/2, (xxmaxl+xxminl)/2,yyminl, (xxminl+xxmaxl)/2,(yymaxl+yyminl)/2, 1); }