1 /*
2  * soi.c --  SOI
3  *
4  *	Simultaneous Orbit Iteration Image Generation Method. Computes
5  *      rectangular regions by tracking the orbits of only a few key points.
6  *
7  * Copyright (c) 1994-1997 Michael R. Ganss. All Rights Reserved.
8  *
9  * This file is distributed under the same conditions as
10  * AlmondBread. For further information see
11  * <URL:http://www.cs.tu-berlin.de/~rms/AlmondBread>.
12  *
13  */
14 #include <time.h>
15 #include <string.h>
16 #ifdef __APPLE__
17 #include <malloc/malloc.h>
18 #elif !defined(BIG_ANSI_C)
19 #include <malloc.h>
20 #endif
21 #include "port.h"
22 #include "prototyp.h"
23 
24 #define DBLS double
25 #define FABS(x)  fabs(x)
26 #define FREXP(x,y) frexp(x,y)
27 
28 #define TRUE 1
29 #define FALSE 0
30 #define EVERY 15
31 #define BASIN_COLOR 0
32 
33 extern int rhombus_stack[10];
34 extern int rhombus_depth;
35 extern int max_rhombus_depth;
36 extern int minstackavail;
37 extern int minstack; /* need this much stack to recurse */
38 static DBLS twidth;
39 static DBLS equal;
40 
41 #if 0
42 static long iteration1(register DBLS cr, register DBLS ci,
43 	      register DBLS re, register DBLS im,
44 	      long start)
45 {
46    DBLS oldreal, oldimag, newreal, newimag, magnitude;
47    long color;
48    magnitude = 0.0;
49    color = start;
50    oldreal = re;
51    oldimag = im;
52    while ((magnitude < 16.0) && (color < maxit)) {
53       newreal = oldreal * oldreal - oldimag * oldimag + cr;
54       newimag = 2 * oldreal * oldimag + ci;
55       color++;
56       oldreal = newreal;
57       oldimag = newimag;
58       magnitude = newreal * newreal + newimag * newimag;
59    }
60    if (color >= maxit) color = BASIN_COLOR;
61    return((int)color);
62 }
63 #endif
64 
iteration(register DBLS cr,register DBLS ci,register DBLS re,register DBLS im,long start)65 static long iteration(register DBLS cr, register DBLS ci,
66 	      register DBLS re, register DBLS im,
67 	      long start)
68 {
69    old.x = re;
70    old.y = im;
71    tempsqrx = sqr(old.x);
72    tempsqry = sqr(old.y);
73    floatparm = &init;
74    floatparm->x = cr;
75    floatparm->y = ci;
76    while(ORBITCALC()==0 && start < maxit)
77       start++;
78    if (start >= maxit)
79       start = BASIN_COLOR;
80    return(start);
81 }
82 #if 0
83 JuliafpFractal()
84 {
85    /* floating point version of classical Mandelbrot/Julia */
86    new.x = tempsqrx - tempsqry + floatparm->x;
87    new.y = 2.0 * old.x * old.y + floatparm->y;
88    return(floatbailout());
89 }
90 #endif
91 
puthline(int x1,int y1,int x2,int color)92 static void puthline(int x1,int y1,int x2,int color)
93 {
94    int x;
95    for(x=x1;x<=x2;x++)
96       (*plot)(x,y1,color);
97 }
98 
putbox(int x1,int y1,int x2,int y2,int color)99 static void putbox(int x1, int y1, int x2, int y2, int color)
100 {
101   for(; y1<=y2; y1++)
102     puthline(x1,y1,x2,color);
103 }
104 
105 /* maximum side length beyond which we start regular scanning instead of
106    subdividing */
107 #define SCAN 16
108 
109 /* pixel interleave used in scanning */
110 #define INTERLEAVE 4
111 
112 /* compute the value of the interpolation polynomial at (x,y) */
113 #define GET_REAL(x,y) \
114 interpolate(cim1,midi,cim2,\
115 	    interpolate(cre1,midr,cre2,zre1,zre5,zre2,x),\
116 	    interpolate(cre1,midr,cre2,zre6,zre9,zre7,x),\
117 	    interpolate(cre1,midr,cre2,zre3,zre8,zre4,x),y)
118 #define GET_IMAG(x,y) \
119 interpolate(cre1,midr,cre2,\
120 	    interpolate(cim1,midi,cim2,zim1,zim6,zim3,y),\
121 	    interpolate(cim1,midi,cim2,zim5,zim9,zim8,y),\
122 	    interpolate(cim1,midi,cim2,zim2,zim7,zim4,y),x)
123 
124 /* compute the value of the interpolation polynomial at (x,y)
125    from saved values before interpolation failed to stay within tolerance */
126 #define GET_SAVED_REAL(x,y) \
127 interpolate(cim1,midi,cim2,\
128 	    interpolate(cre1,midr,cre2,sr1,sr5,sr2,x),\
129 	    interpolate(cre1,midr,cre2,sr6,sr9,sr7,x),\
130 	    interpolate(cre1,midr,cre2,sr3,sr8,sr4,x),y)
131 #define GET_SAVED_IMAG(x,y) \
132 interpolate(cre1,midr,cre2,\
133 	    interpolate(cim1,midi,cim2,si1,si6,si3,y),\
134 	    interpolate(cim1,midi,cim2,si5,si9,si8,y),\
135 	    interpolate(cim1,midi,cim2,si2,si7,si4,y),x)
136 
137 /* compute the value of the interpolation polynomial at (x,y)
138    during scanning. Here, key values do not change, so we can precompute
139    coefficients in one direction and simply evaluate the polynomial
140    during scanning. */
141 #define GET_SCAN_REAL(x,y) \
142 interpolate(cim1,midi,cim2,\
143 	    EVALUATE(cre1,midr,br10,br11,br12,x),\
144 	    EVALUATE(cre1,midr,br20,br21,br22,x),\
145 	    EVALUATE(cre1,midr,br30,br31,br32,x),y)
146 #define GET_SCAN_IMAG(x,y) \
147 interpolate(cre1,midr,cre2,\
148 	    EVALUATE(cim1,midi,bi10,bi11,bi12,y),\
149 	    EVALUATE(cim1,midi,bi20,bi21,bi22,y),\
150 	    EVALUATE(cim1,midi,bi30,bi31,bi32,y),x)
151 
152 /* compute coefficients of Newton polynomial (b0,..,b2) from
153    (x0,w0),..,(x2,w2). */
154 #define INTERPOLATE(x0,x1,x2,w0,w1,w2,b0,b1,b2) \
155 b0=w0;\
156 b1=(w1-w0)/(x1-x0);\
157 b2=((w2-w1)/(x2-x1)-b1)/(x2-x0)
158 
159 /* evaluate Newton polynomial given by (x0,b0),(x1,b1) at x:=t */
160 #define EVALUATE(x0,x1,b0,b1,b2,t) \
161 ((b2*(t-x1)+b1)*(t-x0)+b0)
162 
163 /* Newton Interpolation.
164    It computes the value of the interpolation polynomial given by
165    (x0,w0)..(x2,w2) at x:=t */
interpolate(DBLS x0,DBLS x1,DBLS x2,DBLS w0,DBLS w1,DBLS w2,DBLS t)166 static DBLS interpolate(DBLS x0, DBLS x1, DBLS x2,
167 			  DBLS w0, DBLS w1, DBLS w2,
168 			  DBLS t)
169 {
170   register DBLS b0=w0,b1=w1,b2=w2,b;
171 
172   /*b0=(r0*b1-r1*b0)/(x1-x0);
173   b1=(r1*b2-r2*b1)/(x2-x1);
174   b0=(r0*b1-r2*b0)/(x2-x0);
175 
176   return (DBLS)b0;*/
177   b=(b1-b0)/(x1-x0);
178   return (DBLS)((((b2-b1)/(x2-x1)-b)/(x2-x0))*(t-x1)+b)*(t-x0)+b0;
179   /*
180   if(t<x1)
181     return w0+((t-x0)/(x1-x0))*(w1-w0);
182   else
183     return w1+((t-x1)/(x2-x1))*(w2-w1);*/
184 }
185 #if (_MSC_VER >= 700)
186 #pragma code_seg ("soi3_text")     /* place following in an overlay */
187 #endif
188 
189 /* SOICompute - Perform simultaneous orbit iteration for a given rectangle
190 
191    Input: cre1..cim2 : values defining the four corners of the rectangle
192           x1..y2     : corresponding pixel values
193 	  zre1..zim9 : intermediate iterated values of the key points (key values)
194 
195 	  (cre1,cim1)               (cre2,cim1)
196 	  (zre1,zim1)  (zre5,zim5)  (zre2,zim2)
197 	       +------------+------------+
198 	       |            |            |
199 	       |            |            |
200 	  (zre6,zim6)  (zre9,zim9)  (zre7,zim7)
201 	       |            |            |
202 	       |            |            |
203 	       +------------+------------+
204 	  (zre3,zim3)  (zre8,zim8)  (zre4,zim4)
205 	  (cre1,cim2)               (cre2,cim2)
206 
207 	  iter       : current number of iterations
208 	  */
209 static DBLS zre1, zim1, zre2, zim2, zre3, zim3, zre4, zim4, zre5, zim5,
210             zre6, zim6, zre7, zim7, zre8, zim8, zre9, zim9;
211 /*
212    The purpose of this macro is to reduce the number of parameters of the
213    function rhombus(), since this is a recursive function, and stack space
214    under DOS is extremely limited.
215 */
216 
217 #define RHOMBUS(CRE1,CRE2,CIM1,CIM2,X1,X2,Y1,Y2,ZRE1,ZIM1,ZRE2,ZIM2,ZRE3,ZIM3,\
218  ZRE4, ZIM4, ZRE5, ZIM5,ZRE6, ZIM6, ZRE7, ZIM7, ZRE8, ZIM8, ZRE9, ZIM9,ITER) \
219  zre1=(ZRE1);zim1=(ZIM1);\
220  zre2=(ZRE2);zim2=(ZIM2);\
221  zre3=(ZRE3);zim3=(ZIM3);\
222  zre4=(ZRE4);zim4=(ZIM4);\
223  zre5=(ZRE5);zim5=(ZIM5);\
224  zre6=(ZRE6);zim6=(ZIM6);\
225  zre7=(ZRE7);zim7=(ZIM7);\
226  zre8=(ZRE8);zim8=(ZIM8);\
227  zre9=(ZRE9);zim9=(ZIM9);\
228  status=rhombus((CRE1),(CRE2),(CIM1),(CIM2),(X1),(X2),(Y1),(Y2),(ITER))
229 
rhombus(DBLS cre1,DBLS cre2,DBLS cim1,DBLS cim2,int x1,int x2,int y1,int y2,long iter)230 static int rhombus(DBLS cre1, DBLS cre2, DBLS cim1, DBLS cim2,
231 			   int x1, int x2, int y1, int y2, long iter)
232 {
233   /* The following variables do not need their values saved */
234   /* used in scanning */
235   static long far savecolor, color, helpcolor;
236   static int far x,y,z,savex;
237 
238 #if 0
239   static DBLS far re,im,restep,imstep,interstep,helpre;
240   static DBLS far zre,zim;
241   /* interpolation coefficients */
242   static DBLS far br10,br11,br12,br20,br21,br22,br30,br31,br32;
243   static DBLS far bi10,bi11,bi12,bi20,bi21,bi22,bi30,bi31,bi32;
244   /* ratio of interpolated test point to iterated one */
245   static DBLS far l1,l2;
246   /* squares of key values */
247   static DBLS far rq1,iq1;
248   static DBLS far rq2,iq2;
249   static DBLS far rq3,iq3;
250   static DBLS far rq4,iq4;
251   static DBLS far rq5,iq5;
252   static DBLS far rq6,iq6;
253   static DBLS far rq7,iq7;
254   static DBLS far rq8,iq8;
255   static DBLS far rq9,iq9;
256 
257   /* test points */
258   static DBLS far cr1,cr2;
259   static DBLS far ci1,ci2;
260   static DBLS far tzr1,tzi1,tzr2,tzi2,tzr3,tzi3,tzr4,tzi4;
261   static DBLS far trq1,tiq1,trq2,tiq2,trq3,tiq3,trq4,tiq4;
262 #else
263 #define re        mem_static[ 0]
264 #define im        mem_static[ 1]
265 #define restep    mem_static[ 2]
266 #define imstep    mem_static[ 3]
267 #define interstep mem_static[ 4]
268 #define helpre    mem_static[ 5]
269 #define zre       mem_static[ 6]
270 #define zim       mem_static[ 7]
271 #define br10      mem_static[ 8]
272 #define br11      mem_static[ 9]
273 #define br12      mem_static[10]
274 #define br20      mem_static[11]
275 #define br21      mem_static[12]
276 #define br22      mem_static[13]
277 #define br30      mem_static[14]
278 #define br31      mem_static[15]
279 #define br32      mem_static[16]
280 #define bi10      mem_static[17]
281 #define bi11      mem_static[18]
282 #define bi12      mem_static[19]
283 #define bi20      mem_static[20]
284 #define bi21      mem_static[21]
285 #define bi22      mem_static[22]
286 #define bi30      mem_static[23]
287 #define bi31      mem_static[24]
288 #define bi32      mem_static[25]
289 #define l1        mem_static[26]
290 #define l2        mem_static[27]
291 #define rq1       mem_static[28]
292 #define iq1       mem_static[29]
293 #define rq2       mem_static[30]
294 #define iq2       mem_static[31]
295 #define rq3       mem_static[32]
296 #define iq3       mem_static[33]
297 #define rq4       mem_static[34]
298 #define iq4       mem_static[35]
299 #define rq5       mem_static[36]
300 #define iq5       mem_static[37]
301 #define rq6       mem_static[38]
302 #define iq6       mem_static[39]
303 #define rq7       mem_static[40]
304 #define iq7       mem_static[41]
305 #define rq8       mem_static[42]
306 #define iq8       mem_static[43]
307 #define rq9       mem_static[44]
308 #define iq9       mem_static[45]
309 #define cr1       mem_static[46]
310 #define cr2       mem_static[47]
311 #define ci1       mem_static[48]
312 #define ci2       mem_static[49]
313 #define tzr1      mem_static[50]
314 #define tzi1      mem_static[51]
315 #define tzr2      mem_static[52]
316 #define tzi2      mem_static[53]
317 #define tzr3      mem_static[54]
318 #define tzi3      mem_static[55]
319 #define tzr4      mem_static[56]
320 #define tzi4      mem_static[57]
321 #define trq1      mem_static[58]
322 #define tiq1      mem_static[59]
323 #define trq2      mem_static[60]
324 #define tiq2      mem_static[61]
325 #define trq3      mem_static[62]
326 #define tiq3      mem_static[63]
327 #define trq4      mem_static[64]
328 #define tiq4      mem_static[65]
329 
330 #endif
331   /* number of iterations before SOI iteration cycle */
332   static long far before;
333   static int far avail;
334 
335   /* the variables below need to have local copies for recursive calls */
336   int  far *mem_int;
337   DBLS far *mem;
338   DBLS far *mem_static;
339   /* center of rectangle */
340   DBLS midr=(cre1+cre2)/2,midi=(cim1+cim2)/2;
341 
342 #if 0
343   /* saved values of key values */
344   DBLS sr1,si1,sr2,si2,sr3,si3,sr4,si4;
345   DBLS sr5,si5,sr6,si6,sr7,si7,sr8,si8,sr9,si9;
346   /* key values for subsequent rectangles */
347   DBLS re10,re11,re12,re13,re14,re15,re16,re17,re18,re19,re20,re21;
348   DBLS im10,im11,im12,im13,im14,im15,im16,im17,im18,im19,im20,im21;
349   DBLS re91,re92,re93,re94,im91,im92,im93,im94;
350 #else
351 #define esc1  mem_int[0]
352 #define esc2  mem_int[1]
353 #define esc3  mem_int[2]
354 #define esc4  mem_int[3]
355 #define esc5  mem_int[4]
356 #define esc6  mem_int[5]
357 #define esc7  mem_int[6]
358 #define esc8  mem_int[7]
359 #define esc9  mem_int[8]
360 #define tesc1 mem_int[9]
361 #define tesc2 mem_int[10]
362 #define tesc3 mem_int[11]
363 #define tesc4 mem_int[12]
364 
365 #define sr1  mem[ 0]
366 #define si1  mem[ 1]
367 #define sr2  mem[ 2]
368 #define si2  mem[ 3]
369 #define sr3  mem[ 4]
370 #define si3  mem[ 5]
371 #define sr4  mem[ 6]
372 #define si4  mem[ 7]
373 #define sr5  mem[ 8]
374 #define si5  mem[ 9]
375 #define sr6  mem[10]
376 #define si6  mem[11]
377 #define sr7  mem[12]
378 #define si7  mem[13]
379 #define sr8  mem[14]
380 #define si8  mem[15]
381 #define sr9  mem[16]
382 #define si9  mem[17]
383 #define re10 mem[18]
384 #define re11 mem[19]
385 #define re12 mem[20]
386 #define re13 mem[21]
387 #define re14 mem[22]
388 #define re15 mem[23]
389 #define re16 mem[24]
390 #define re17 mem[25]
391 #define re18 mem[26]
392 #define re19 mem[27]
393 #define re20 mem[28]
394 #define re21 mem[29]
395 #define im10 mem[30]
396 #define im11 mem[31]
397 #define im12 mem[32]
398 #define im13 mem[33]
399 #define im14 mem[34]
400 #define im15 mem[35]
401 #define im16 mem[36]
402 #define im17 mem[37]
403 #define im18 mem[38]
404 #define im19 mem[39]
405 #define im20 mem[40]
406 #define im21 mem[41]
407 #define re91 mem[42]
408 #define re92 mem[43]
409 #define re93 mem[44]
410 #define re94 mem[45]
411 #define im91 mem[46]
412 #define im92 mem[47]
413 #define im93 mem[48]
414 #define im94 mem[49]
415 #endif
416 
417   int status = 0;
418   rhombus_depth++;
419 
420 #if 1
421   /* what we go through under DOS to deal with memory! We re-use
422      the sizeofstring array (8k). The first 660 bytes is for
423      static variables, then we make our own "stack" with copies
424      for each recursive call of rhombus() for the rest.
425    */
426   mem_int    = (int far *)sizeofstring;
427   mem_static = (DBLS far *)(mem_int + 13);
428   mem = mem_static+ 66 + 50*rhombus_depth;
429 #endif
430 
431   if((avail = stackavail()) < minstackavail)
432      minstackavail = avail;
433   if(rhombus_depth > max_rhombus_depth)
434      max_rhombus_depth = rhombus_depth;
435   rhombus_stack[rhombus_depth] = avail;
436 
437   if(keypressed())
438     {
439     status = 1;
440     goto rhombus_done;
441     }
442   if(iter>maxit)
443     {
444       putbox(x1,y1,x2,y2,0);
445       status = 0;
446       goto rhombus_done;
447     }
448 
449   if((y2-y1<=SCAN) || (avail < minstack))
450     {
451       /* finish up the image by scanning the rectangle */
452     scan:
453       INTERPOLATE(cre1,midr,cre2,zre1,zre5,zre2,br10,br11,br12);
454       INTERPOLATE(cre1,midr,cre2,zre6,zre9,zre7,br20,br21,br22);
455       INTERPOLATE(cre1,midr,cre2,zre3,zre8,zre4,br30,br31,br32);
456 
457       INTERPOLATE(cim1,midi,cim2,zim1,zim6,zim3,bi10,bi11,bi12);
458       INTERPOLATE(cim1,midi,cim2,zim5,zim9,zim8,bi20,bi21,bi22);
459       INTERPOLATE(cim1,midi,cim2,zim2,zim7,zim4,bi30,bi31,bi32);
460 
461       restep=(cre2-cre1)/(x2-x1);
462       imstep=(cim2-cim1)/(y2-y1);
463       interstep=INTERLEAVE*restep;
464 
465       for(y=y1, im=cim1; y<y2; y++, im+=imstep)
466 	{
467 	  if(keypressed())
468 	    {
469 	    status = 1;
470             goto rhombus_done;
471 	    }
472 	  zre=GET_SCAN_REAL(cre1,im);
473 	  zim=GET_SCAN_IMAG(cre1,im);
474 	  savecolor=iteration(cre1,im,zre,zim,iter);
475           if(savecolor < 0)
476           {
477 	    status = 1;
478             goto rhombus_done;
479           }
480 	  savex=x1;
481 	  for(x=x1+INTERLEAVE, re=cre1+interstep; x<x2;
482 	      x+=INTERLEAVE, re+=interstep)
483 	    {
484 	      zre=GET_SCAN_REAL(re,im);
485 	      zim=GET_SCAN_IMAG(re,im);
486 
487 	      color=iteration(re,im,zre,zim,iter);
488               if(color < 0)
489                 {
490                 status = 1;
491                 goto rhombus_done;
492                 }
493               else if(color==savecolor)
494 		continue;
495 
496 	      for (z=x-1, helpre=re-restep; z>x-INTERLEAVE; z--,helpre-=restep)
497 		{
498 		  zre=GET_SCAN_REAL(helpre,im);
499 		  zim=GET_SCAN_IMAG(helpre,im);
500 		  helpcolor=iteration(helpre,im,zre,zim,iter);
501 		  if(helpcolor < 0)
502 		    {
503           	    status = 1;
504                     goto rhombus_done;
505 		    }
506 		  else if(helpcolor==savecolor)
507 		    break;
508 		  (*plot)(z,y,(int)(helpcolor&255));
509 		}
510 
511 	      if(savex<z)
512 		puthline(savex, y, z, (int)(savecolor&255));
513 	      else
514 		(*plot)(savex, y, (int)(savecolor&255));
515 
516 	      savex = x;
517 	      savecolor = color;
518 	    }
519 
520 	  for (z=x2-1, helpre=cre2-restep; z>savex; z--,helpre-=restep)
521 	    {
522 	      zre=GET_SCAN_REAL(helpre,im);
523 	      zim=GET_SCAN_IMAG(helpre,im);
524 	      helpcolor=iteration(helpre,im,zre,zim,iter);
525 	      if(helpcolor < 0)
526 	        {
527                 status = 1;
528                 goto rhombus_done;
529 		}
530 	      else if(helpcolor==savecolor)
531 		break;
532 
533 	      (*plot)(z,y,(int)(helpcolor&255));
534 	    }
535 
536 	  if(savex<z)
537 	    puthline(savex, y, z, (int)(savecolor&255));
538 	  else
539 	    (*plot)(savex, y, (int)(savecolor&255));
540 	}
541         status = 0;
542         goto rhombus_done;
543       }
544 
545   rq1=zre1*zre1; iq1=zim1*zim1;
546   rq2=zre2*zre2; iq2=zim2*zim2;
547   rq3=zre3*zre3; iq3=zim3*zim3;
548   rq4=zre4*zre4; iq4=zim4*zim4;
549   rq5=zre5*zre5; iq5=zim5*zim5;
550   rq6=zre6*zre6; iq6=zim6*zim6;
551   rq7=zre7*zre7; iq7=zim7*zim7;
552   rq8=zre8*zre8; iq8=zim8*zim8;
553   rq9=zre9*zre9; iq9=zim9*zim9;
554 
555   cr1=0.75*cre1+0.25*cre2; cr2=0.25*cre1+0.75*cre2;
556   ci1=0.75*cim1+0.25*cim2; ci2=0.25*cim1+0.75*cim2;
557 
558   tzr1=GET_REAL(cr1,ci1);
559   tzi1=GET_IMAG(cr1,ci1);
560 
561   tzr2=GET_REAL(cr2,ci1);
562   tzi2=GET_IMAG(cr2,ci1);
563 
564   tzr3=GET_REAL(cr1,ci2);
565   tzi3=GET_IMAG(cr1,ci2);
566 
567   tzr4=GET_REAL(cr2,ci2);
568   tzi4=GET_IMAG(cr2,ci2);
569 
570   trq1=tzr1*tzr1;
571   tiq1=tzi1*tzi1;
572 
573   trq2=tzr2*tzr2;
574   tiq2=tzi2*tzi2;
575 
576   trq3=tzr3*tzr3;
577   tiq3=tzi3*tzi3;
578 
579   trq4=tzr4*tzr4;
580   tiq4=tzi4*tzi4;
581 
582   before=iter;
583 
584   for(;;)
585   {
586       sr1=zre1; si1=zim1;
587       sr2=zre2; si2=zim2;
588       sr3=zre3; si3=zim3;
589       sr4=zre4; si4=zim4;
590       sr5=zre5; si5=zim5;
591       sr6=zre6; si6=zim6;
592       sr7=zre7; si7=zim7;
593       sr8=zre8; si8=zim8;
594       sr9=zre9; si9=zim9;
595 
596 
597 #define SOI_ORBIT1(zr,rq,zi,iq,cr,ci,esc) \
598         tempsqrx = rq;\
599         tempsqry = iq;\
600         old.x = zr;\
601         old.y = zi;\
602         floatparm->x = cr;\
603         floatparm->y = ci;\
604         esc = ORBITCALC();\
605         rq = tempsqrx;\
606         iq = tempsqry;\
607         zr = new.x;\
608         zi = new.y
609 
610 #define SOI_ORBIT(zr,rq,zi,iq,cr,ci,esc) \
611       zi=(zi+zi)*zr+ci;\
612       zr=rq-iq+cr;\
613       rq=zr*zr;\
614       iq=zi*zi;\
615       esc = ((rq+iq)>16.0)?1:0
616 
617       /* iterate key values */
618       SOI_ORBIT(zre1,rq1,zim1,iq1,cre1,cim1,esc1);
619 /*
620       zim1=(zim1+zim1)*zre1+cim1;
621       zre1=rq1-iq1+cre1;
622       rq1=zre1*zre1;
623       iq1=zim1*zim1;
624 */
625       SOI_ORBIT(zre2,rq2,zim2,iq2,cre2,cim1,esc2);
626 /*
627       zim2=(zim2+zim2)*zre2+cim1;
628       zre2=rq2-iq2+cre2;
629       rq2=zre2*zre2;
630       iq2=zim2*zim2;
631 */
632       SOI_ORBIT(zre3,rq3,zim3,iq3,cre1,cim2,esc3);
633 /*
634       zim3=(zim3+zim3)*zre3+cim2;
635       zre3=rq3-iq3+cre1;
636       rq3=zre3*zre3;
637       iq3=zim3*zim3;
638 */
639       SOI_ORBIT(zre4,rq4,zim4,iq4,cre2,cim2,esc4);
640 /*
641       zim4=(zim4+zim4)*zre4+cim2;
642       zre4=rq4-iq4+cre2;
643       rq4=zre4*zre4;
644       iq4=zim4*zim4;
645 */
646       SOI_ORBIT(zre5,rq5,zim5,iq5,midr,cim1,esc5);
647 /*
648       zim5=(zim5+zim5)*zre5+cim1;
649       zre5=rq5-iq5+midr;
650       rq5=zre5*zre5;
651       iq5=zim5*zim5;
652 */
653       SOI_ORBIT(zre6,rq6,zim6,iq6,cre1,midi,esc6);
654 /*
655       zim6=(zim6+zim6)*zre6+midi;
656       zre6=rq6-iq6+cre1;
657       rq6=zre6*zre6;
658       iq6=zim6*zim6;
659 */
660       SOI_ORBIT(zre7,rq7,zim7,iq7,cre2,midi,esc7);
661 /*
662       zim7=(zim7+zim7)*zre7+midi;
663       zre7=rq7-iq7+cre2;
664       rq7=zre7*zre7;
665       iq7=zim7*zim7;
666 */
667       SOI_ORBIT(zre8,rq8,zim8,iq8,midr,cim2,esc8);
668 /*
669       zim8=(zim8+zim8)*zre8+cim2;
670       zre8=rq8-iq8+midr;
671       rq8=zre8*zre8;
672       iq8=zim8*zim8;
673 */
674       SOI_ORBIT(zre9,rq9,zim9,iq9,midr,midi,esc9);
675 /*
676       zim9=(zim9+zim9)*zre9+midi;
677       zre9=rq9-iq9+midr;
678       rq9=zre9*zre9;
679       iq9=zim9*zim9;
680 */
681       /* iterate test point */
682       SOI_ORBIT(tzr1,trq1,tzi1,tiq1,cr1,ci1,tesc1);
683 /*
684       tzi1=(tzi1+tzi1)*tzr1+ci1;
685       tzr1=trq1-tiq1+cr1;
686       trq1=tzr1*tzr1;
687       tiq1=tzi1*tzi1;
688 */
689 
690       SOI_ORBIT(tzr2,trq2,tzi2,tiq2,cr2,ci1,tesc2);
691 /*
692       tzi2=(tzi2+tzi2)*tzr2+ci1;
693       tzr2=trq2-tiq2+cr2;
694       trq2=tzr2*tzr2;
695       tiq2=tzi2*tzi2;
696 */
697       SOI_ORBIT(tzr3,trq3,tzi3,tiq3,cr1,ci2,tesc3);
698 /*
699       tzi3=(tzi3+tzi3)*tzr3+ci2;
700       tzr3=trq3-tiq3+cr1;
701       trq3=tzr3*tzr3;
702       tiq3=tzi3*tzi3;
703 */
704       SOI_ORBIT(tzr4,trq4,tzi4,tiq4,cr2,ci2,tesc4);
705 /*
706       tzi4=(tzi4+tzi4)*tzr4+ci2;
707       tzr4=trq4-tiq4+cr2;
708       trq4=tzr4*tzr4;
709       tiq4=tzi4*tzi4;
710 */
711       iter++;
712 
713       /* if one of the iterated values bails out, subdivide */
714 /*
715       if((rq1+iq1)>16.0||
716 	 (rq2+iq2)>16.0||
717 	 (rq3+iq3)>16.0||
718 	 (rq4+iq4)>16.0||
719 	 (rq5+iq5)>16.0||
720 	 (rq6+iq6)>16.0||
721 	 (rq7+iq7)>16.0||
722 	 (rq8+iq8)>16.0||
723 	 (rq9+iq9)>16.0||
724 	 (trq1+tiq1)>16.0||
725 	 (trq2+tiq2)>16.0||
726 	 (trq3+tiq3)>16.0||
727 	 (trq4+tiq4)>16.0)
728 	break;
729 */
730       if(esc1||esc2||esc3||esc4||esc5||esc6||esc7||esc8||esc9||
731          tesc1||tesc2||tesc3||tesc4)
732          break;
733 
734       /* if maximum number of iterations is reached, the whole rectangle
735 	 can be assumed part of M. This is of course best case behavior
736 	 of SOI, we seldomly get there */
737       if(iter>maxit)
738 	{
739 	  putbox(x1,y1,x2,y2,0);
740           status = 0;
741           goto rhombus_done;
742 	}
743 
744       /* now for all test points, check whether they exceed the
745 	 allowed tolerance. if so, subdivide */
746       l1=GET_REAL(cr1,ci1);
747       l1=(tzr1==0.0)?
748 	(l1==0.0)?1.0:1000.0:
749 	l1/tzr1;
750       if(FABS(1.0-l1)>twidth)
751 	break;
752 
753       l2=GET_IMAG(cr1,ci1);
754       l2=(tzi1==0.0)?
755 	(l2==0.0)?1.0:1000.0:
756 	l2/tzi1;
757       if(FABS(1.0-l2)>twidth)
758 	break;
759 
760       l1=GET_REAL(cr2,ci1);
761       l1=(tzr2==0.0)?
762 	(l1==0.0)?1.0:1000.0:
763 	l1/tzr2;
764       if(FABS(1.0-l1)>twidth)
765 	break;
766 
767       l2=GET_IMAG(cr2,ci1);
768       l2=(tzi2==0.0)?
769 	(l2==0.0)?1.0:1000.0:
770 	l2/tzi2;
771       if(FABS(1.0-l2)>twidth)
772 	break;
773 
774       l1=GET_REAL(cr1,ci2);
775       l1=(tzr3==0.0)?
776 	(l1==0.0)?1.0:1000.0:
777 	l1/tzr3;
778       if(FABS(1.0-l1)>twidth)
779 	break;
780 
781       l2=GET_IMAG(cr1,ci2);
782       l2=(tzi3==0.0)?
783 	(l2==0.0)?1.0:1000.0:
784 	l2/tzi3;
785       if(FABS(1.0-l2)>twidth)
786 	break;
787 
788       l1=GET_REAL(cr2,ci2);
789       l1=(tzr4==0.0)?
790 	(l1==0.0)?1.0:1000.0:
791 	l1/tzr4;
792       if(FABS(1.0-l1)>twidth)
793 	break;
794 
795       l2=GET_IMAG(cr2,ci2);
796       l2=(tzi4==0.0)?
797 	(l2==0.0)?1.0:1000.0:
798 	l2/tzi4;
799       if(FABS(1.0-l2)>twidth)
800 	break;
801     }
802 
803   iter--;
804 
805   /* this is a little heuristic I tried to improve performance. */
806   if(iter-before<10)
807     {
808       zre1=sr1; zim1=si1;
809       zre2=sr2; zim2=si2;
810       zre3=sr3; zim3=si3;
811       zre4=sr4; zim4=si4;
812       zre5=sr5; zim5=si5;
813       zre6=sr6; zim6=si6;
814       zre7=sr7; zim7=si7;
815       zre8=sr8; zim8=si8;
816       zre9=sr9; zim9=si9;
817       goto scan;
818     }
819 
820   /* compute key values for subsequent rectangles */
821 
822   re10=interpolate(cre1,midr,cre2,sr1,sr5,sr2,cr1);
823   im10=interpolate(cre1,midr,cre2,si1,si5,si2,cr1);
824 
825   re11=interpolate(cre1,midr,cre2,sr1,sr5,sr2,cr2);
826   im11=interpolate(cre1,midr,cre2,si1,si5,si2,cr2);
827 
828   re20=interpolate(cre1,midr,cre2,sr3,sr8,sr4,cr1);
829   im20=interpolate(cre1,midr,cre2,si3,si8,si4,cr1);
830 
831   re21=interpolate(cre1,midr,cre2,sr3,sr8,sr4,cr2);
832   im21=interpolate(cre1,midr,cre2,si3,si8,si4,cr2);
833 
834   re15=interpolate(cre1,midr,cre2,sr6,sr9,sr7,cr1);
835   im15=interpolate(cre1,midr,cre2,si6,si9,si7,cr1);
836 
837   re16=interpolate(cre1,midr,cre2,sr6,sr9,sr7,cr2);
838   im16=interpolate(cre1,midr,cre2,si6,si9,si7,cr2);
839 
840   re12=interpolate(cim1,midi,cim2,sr1,sr6,sr3,ci1);
841   im12=interpolate(cim1,midi,cim2,si1,si6,si3,ci1);
842 
843   re14=interpolate(cim1,midi,cim2,sr2,sr7,sr4,ci1);
844   im14=interpolate(cim1,midi,cim2,si2,si7,si4,ci1);
845 
846   re17=interpolate(cim1,midi,cim2,sr1,sr6,sr3,ci2);
847   im17=interpolate(cim1,midi,cim2,si1,si6,si3,ci2);
848 
849   re19=interpolate(cim1,midi,cim2,sr2,sr7,sr4,ci2);
850   im19=interpolate(cim1,midi,cim2,si2,si7,si4,ci2);
851 
852   re13=interpolate(cim1,midi,cim2,sr5,sr9,sr8,ci1);
853   im13=interpolate(cim1,midi,cim2,si5,si9,si8,ci1);
854 
855   re18=interpolate(cim1,midi,cim2,sr5,sr9,sr8,ci2);
856   im18=interpolate(cim1,midi,cim2,si5,si9,si8,ci2);
857 
858   re91=GET_SAVED_REAL(cr1,ci1);
859   re92=GET_SAVED_REAL(cr2,ci1);
860   re93=GET_SAVED_REAL(cr1,ci2);
861   re94=GET_SAVED_REAL(cr2,ci2);
862 
863   im91=GET_SAVED_IMAG(cr1,ci1);
864   im92=GET_SAVED_IMAG(cr2,ci1);
865   im93=GET_SAVED_IMAG(cr1,ci2);
866   im94=GET_SAVED_IMAG(cr2,ci2);
867 
868   RHOMBUS(cre1,midr,cim1,midi,x1,((x1+x2)>>1),y1,((y1+y2)>>1),
869 	     sr1,si1,
870 	     sr5,si5,
871 	     sr6,si6,
872 	     sr9,si9,
873 	     re10,im10,
874 	     re12,im12,
875 	     re13,im13,
876 	     re15,im15,
877 	     re91,im91,
878 	     iter);
879   RHOMBUS(midr,cre2,cim1,midi,(x1+x2)>>1,x2,y1,(y1+y2)>>1,
880 	     sr5,si5,
881 	     sr2,si2,
882 	     sr9,si9,
883 	     sr7,si7,
884 	     re11,im11,
885 	     re13,im13,
886 	     re14,im14,
887 	     re16,im16,
888 	     re92,im92,
889 	     iter);
890   RHOMBUS(cre1,midr,midi,cim2,x1,(x1+x2)>>1,(y1+y2)>>1,y2,
891 	     sr6,si6,
892 	     sr9,si9,
893 	     sr3,si3,
894 	     sr8,si8,
895 	     re15,im15,
896 	     re17,im17,
897 	     re18,im18,
898 	     re20,im20,
899 	     re93,im93,
900 	     iter);
901   RHOMBUS(midr,cre2,midi,cim2,(x1+x2)>>1,x2,(y1+y2)>>1,y2,
902 	     sr9,si9,
903 	     sr7,si7,
904 	     sr8,si8,
905 	     sr4,si4,
906 	     re16,im16,
907 	     re18,im18,
908 	     re19,im19,
909 	     re21,im21,
910 	     re94,im94,
911 	     iter);
912 rhombus_done:
913   rhombus_depth--;
914   return(status);
915 }
916 
917 #if (_MSC_VER >= 700)
918 #pragma code_seg ()
919 #endif
920 
soi(void)921 void soi(void)
922 {
923    int status;
924    DBLS tolerance=0.1;
925    DBLS stepx, stepy;
926    DBLS xxminl, xxmaxl, yyminl, yymaxl;
927    minstackavail = 30000;
928    rhombus_depth = -1;
929    max_rhombus_depth = 0;
930    if(bf_math)
931    {
932       xxminl = (DBLS)bftofloat(bfxmin);
933       yyminl = (DBLS)bftofloat(bfymin);
934       xxmaxl = (DBLS)bftofloat(bfxmax);
935       yymaxl = (DBLS)bftofloat(bfymax);
936    }
937    else
938    {
939       xxminl = xxmin;
940       yyminl = yymin;
941       xxmaxl = xxmax;
942       yymaxl = yymax;
943    }
944   twidth=tolerance/(xdots-1);
945   stepx = (xxmaxl - xxminl) / xdots;
946   stepy = (yyminl - yymaxl) / ydots;
947   equal = (stepx < stepy ? stepx : stepy);
948 
949   RHOMBUS(xxminl,xxmaxl,yymaxl,yyminl,
950 	      0,xdots,0,ydots,
951 	      xxminl,yymaxl,
952 	      xxmaxl,yymaxl,
953 	      xxminl,yyminl,
954 	      xxmaxl,yyminl,
955 	      (xxmaxl+xxminl)/2,yymaxl,
956 	      xxminl,(yymaxl+yyminl)/2,
957 	      xxmaxl,(yymaxl+yyminl)/2,
958 	      (xxmaxl+xxminl)/2,yyminl,
959 	      (xxminl+xxmaxl)/2,(yymaxl+yyminl)/2,
960   	      1);
961 }
962