home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / sun / volume1 / FastMand < prev    next >
Encoding:
Internet Message Format  |  1989-09-12  |  24.5 KB

  1. Path: uunet!seismo!ukma!mailrus!cs.utexas.edu!rutgers!aramis.rutgers.edu!dartagnan.rutgers.edu!mcgrew
  2. From: mcgrew@dartagnan.rutgers.edu (Charles Mcgrew)
  3. Newsgroups: comp.sources.sun
  4. Subject: v01i060:  FastMtool - a SunView mandelbrot image maker
  5. Message-ID: <Sep.13.00.08.30.1989.8740@dartagnan.rutgers.edu>
  6. Date: 13 Sep 89 04:08:33 GMT
  7. Organization: Rutgers Univ., New Brunswick, N.J.
  8. Lines: 768
  9. Approved: mcgrew@aramis.rutgers.edu
  10.  
  11. Submitted-by: P{r Emanuelsson <pell@isy.liu.se>
  12. Posting-number: Volume 1, Issue 60
  13. Archive-name: FastMand
  14.  
  15.  
  16. I have written a program to implement the FastM algorithm as described
  17. in the book "The Science of Fractal Images" edited by Peitgen and Saupe.
  18.  
  19. The FastM algorithm is good for fast calculation of a (rough) outline of
  20. the Mandelbrot set and thus suitable for interactive manipulations. This
  21. makes it possible to iterate e.g. only every 10:th row and column of the image,
  22. reducing the time by a factor of 100 compared to the standard Mandelbrot
  23. algorithm. It's also fun to watch, since it's recursive...
  24.  
  25. The shar file to "FastMtool" follows.
  26.  
  27. Have fun! But beware - it's addictive!
  28.  
  29.    /Pell
  30. --
  31. #!/bin/sh
  32. # shar:    Shell Archiver  (v1.22)
  33. #
  34. #    Run the following text with /bin/sh to create:
  35. #      README
  36. #      Makefile
  37. #      FastMtool.1
  38. #      FastMtool.c
  39. #
  40. if test -f README; then echo "File README exists"; else
  41. sed 's/^X//' << 'SHAR_EOF' > README &&
  42. X    This is a program for interactive Mandelbrot exploration for Sun
  43. Xworkstations using SunView.
  44. X
  45. X    What's new and exciting with this program (IMHO :-) ) is that it implements
  46. Xa new algorithm. This is good for fast calculation of a (rough) outline of
  47. Xthe Mandelbrot set and thus suitable for interactive manipulations. This
  48. Xmakes it possible to iterate e.g. only every 10:th row and column of the image,
  49. Xreducing the time by a factor of 100 compared to the standard Mandelbrot
  50. Xalgorithm. It's also fun to watch, since it's recursive...
  51. X
  52. X    It has been tested on the following configurations:
  53. X
  54. XSun-2/120 under SunOS 3.5, Sun-3/50, 3/75, 3/110 with FPA, 3/280, 4/110
  55. Xand 4/280, all using SunOS 4.0(.1). Hopefully it should work on others too.
  56. X
  57. X    So how does it work? Well, using some intricate mathematics you can
  58. Xarrive at an equation that estimates the distance from a point outside the
  59. XMandelbrot set to the nearest point IN the set. Using this knowledge, it's
  60. Xpossible to exclude all points lying inside a disk with the radius equal to
  61. Xthis distance. You know they can't be part of the set and mark them as
  62. Xuninteresting. Then you repeat the calculation with a couple of points
  63. Xpicked from the edge of this disk. In this fashion, you will get an outline
  64. Xof the set in a very short time.
  65. X
  66. X    Time for the bad news: if you want an image with the same resolution
  67. Xas one generated with the standard algorithm, this algorithm will be just
  68. Xas slow. This is because this algorithm quickly excludes points that are
  69. Xnot part of the Mandelbrot set. Unfortunately, the calculations for these
  70. Xpoints will usually be fast since they rapidly diverges to infinity. So the
  71. Xpoints left that need to be iterated are all very time-consuming. Furthermore,
  72. Xthis algorithm cannot provide those good-looking color images you have all
  73. Xseen. It only provides information whether a point is in the set or not.
  74. XOf course, on a B/W screen this will usually suffice. Using this program, you
  75. Xcan quickly find interesting areas and then run off to your cray and feed the
  76. Xcoordinates to a standard Mandelbrot algorithm.
  77. X
  78. X    I certainly didn't invent this myself. I urge you to get the book
  79. X"The Science of Fractal Images" edited by Peitgen and Saupe. Springer Verlag,
  80. XISBN 0-387-96608-0. It's filled with good stuff like this.
  81. X
  82. X    A possible enhancement would be for the program to draw disks INSIDE
  83. Xthe Mandelbrot set too. Unfortunately, this problem is quite non-deterministic
  84. Xand does not have a simple solution. Besides, the set, at larger magnifications,
  85. Xhas a very intricate structure and it would probably not be possible to
  86. Xdraw any large disks inside it.
  87. X
  88. X    I refer you to the man-page for more instructions about running the stuff.
  89. XTo get going, just hit the DRAW button as soon as it starts.
  90. X
  91. X    You will probably see a lot of inefficient coding, e.g. using array
  92. Xsubscripting instead of pointers etc. Let me just say that profiling shows
  93. Xthat without the Sun-specific stuff, it can spend as much as 98% of the
  94. Xtime in the MSetDist routine (most of which are floating-point
  95. Xcalculations)... That is why I have kept the inefficient, but more
  96. Xreadable, code. Using GCC, you cannot achive much better speed hand-coding
  97. XMSetDist in assembler, but you are welcome to try...
  98. X
  99. X    Finally, don't flame me for the coding. I just wanted to try this
  100. Xalgorithm, and whipped together a demonstration program using parts from
  101. Xother programs in a very short time. Specifically: don't run it through lint!
  102. X(I haven't :-). I don't have the time to work on this anymore but I thought
  103. Xthis was interesting enough to warrant posting.
  104. X
  105. X    One thing I would really love is an X version of this (hint, hint!).
  106. XPoor me only knows the workings of SunView... :-(
  107. X
  108. XHave fun!
  109. X
  110. X    /Pell
  111. X--
  112. X"Don't think; let the machine do it for you!"
  113. X                                   -- E. C. Berkeley
  114. XDept. of Electrical Engineering             ====>>>    pell@isy.liu.se
  115. XUniversity of Linkoping, Sweden         ...!uunet!enea!isy.liu.se!pell
  116. SHAR_EOF
  117. chmod 0644 README || echo "restore of README fails"
  118. fi
  119. if test -f Makefile; then echo "File Makefile exists"; else
  120. sed 's/^X//' << 'SHAR_EOF' > Makefile &&
  121. XLIBS = -lm -lsuntool -lsunwindow -lpixrect
  122. X
  123. X# Choose the compile line that suits you best.
  124. X# Note that cc -O4 gives 25% faster code that gcc 1.30. I'm not sure why.
  125. X# If you have a later version you may want to try gcc anyway, perhaps
  126. X# with fancier optimizations...
  127. X
  128. XFastMtool: FastMtool.c
  129. X# GCC, Sun-3 with 68881 math chip.
  130. X#    gcc -O -traditional -m68881 -o FastMtool FastMtool.c $(LIBS)
  131. X# Sun-3 with SunOS 4, 68881 math chip:
  132. X    cc -O4 -f68881 -o FastMtool FastMtool.c $(LIBS)
  133. X# Sun-4 with SunOS 4:
  134. X#    cc -O4 -o FastMtool FastMtool.c $(LIBS)
  135. X# Other suns, configure for maximum speed yourself:
  136. X#    cc -O -o FastMtool FastMtool.c $(LIBS)
  137. SHAR_EOF
  138. chmod 0644 Makefile || echo "restore of Makefile fails"
  139. fi
  140. if test -f FastMtool.1; then echo "File FastMtool.1 exists"; else
  141. sed 's/^X//' << 'SHAR_EOF' > FastMtool.1 &&
  142. X.TH FastMtool 1 "1989 February 25"
  143. X.UC 4
  144. X.SH NAME
  145. XFastMtool \- Explore the Mandelbrot set under SunView(1)
  146. X.SH SYNOPSIS
  147. X.B FastMtool
  148. X.SH DESCRIPTION
  149. X.I FastMtool
  150. Xuses a new algorithm, presented in the book
  151. X.B
  152. X"The Science of Fractal Images"
  153. Xpublished by Springer Verlag. This algorithm is well suited to interactive
  154. Xexplorations, providing a rough outline of the Mandelbrot set very quickly.
  155. XUsing the mouse, you can then select and enlarge interesting regions.
  156. X.PP
  157. X.B Controls:
  158. X.PP
  159. XThere are three sliders. Their functions are:
  160. X.IP Recur
  161. XAffects the recursive part of the algorithm.
  162. X.I Recur
  163. Xis the minimum distance to the Mandelbrot set at which the recursion
  164. Xshould stop. I.e. if
  165. X.I Recur
  166. Xis equal to 10 then the recursive part of the algorithm will never try
  167. Xto get closer than 10 pixels to the set. 5 is probably a good value
  168. Xto start with.
  169. X.IP Increment
  170. XAffects the iterative part of the algorithm. The algorithm starts by scanning
  171. Xthe image line after line, pixel for pixel. When it hits a pixel not part
  172. Xof the set, it invokes the recursive algorithm. Then it continues scanning.
  173. X
  174. XIf
  175. X.I Increment
  176. Xis set e.g. to 5, then only every 5:th line and pixel will be scanned,
  177. Xreducing the time 25-fold.
  178. X.IP Maxiter
  179. XThis determines how many iterations are required before a pixel is considered
  180. Xpart of the set. One can view this parameter as the "focusing". This parameter
  181. Xneeds to be increased as the magnification increases. If it is set too low
  182. Xyou will not get any details in the image; too many pixels will erroneously
  183. Xbe considered part of the set. Increasing this also increases the time.
  184. XExperiment!
  185. X.PP
  186. X.B Buttons:
  187. X.PP
  188. XThere are four buttons:
  189. X.IP DRAW
  190. XDraws a new image. If you haven't selected new coordinates the old image
  191. Xis redrawn, perhaps with new parameters.
  192. X.IP UP
  193. XReturns you to your previous image, before the last
  194. X.I DRAW
  195. Xwith new coordinates.
  196. X.IP STOP
  197. XEmergency stop. It's only possible to stop the iterative refinement. The
  198. Xrecursive refinement is usually fast anyway.
  199. X.IP Quit
  200. XQuits the program (without confirm on SunOS older than 4.0).
  201. X.PP
  202. X.B
  203. XMouse usage:
  204. X.PP
  205. XTo mark a new area for exploration, press the
  206. X.I left
  207. Xmouse button and move the mouse, keeping the button down. When you release
  208. Xthe button a new area has been marked. Now you can select the
  209. X.I DRAW
  210. Xbutton to magnify this area, perhaps changing some of the sliders first.
  211. X
  212. XYou will see the coordinates in the panel change when you move the mouse.
  213. X
  214. XIf you hit the
  215. X.I middle
  216. Xbutton, your selected area will be cancelled and the coordinates restored.
  217. X.SH RESTRICTIONS
  218. XYou cannot save the images to file.
  219. X.SH SEE ALSO
  220. Xsunview(1)
  221. X.SH AUTHORS
  222. X.PP
  223. XP. Emanuelsson, pell@isy.liu.se.
  224. X.br
  225. X.I
  226. X"The Science of Fractal Images"
  227. X\(em Peitgen & Saupe (eds.)
  228. SHAR_EOF
  229. chmod 0644 FastMtool.1 || echo "restore of FastMtool.1 fails"
  230. fi
  231. if test -f FastMtool.c; then echo "File FastMtool.c exists"; else
  232. sed 's/^X//' << 'SHAR_EOF' > FastMtool.c &&
  233. X/*
  234. X * FastMtool - Perform interactive exploring of the Mandelbrot set on
  235. X * Sun workstations.
  236. X * Copyright (c) 1989 P{r Emanuelsson, pell@isy.liu.se. All Rights Reserved.
  237. X * This program is free software; you can redistribute it and/or modify
  238. X * it under the terms of the GNU General Public License as published by
  239. X * the Free Software Foundation; either version 1, or any later version.
  240. X * This program is distributed in the hope that it will be useful,
  241. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  242. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  243. X * GNU General Public License for more details.
  244. X * You can receive a copy of the GNU General Public License from the
  245. X * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  246. X * See the README for more information.
  247. X */
  248. X
  249. X#include <suntool/sunview.h>
  250. X#include <suntool/panel.h>
  251. X#include <suntool/canvas.h>
  252. X
  253. X/* Change event_action to event_id(event) for pre 4.0 */
  254. X#ifndef event_action
  255. X#define event_action event_id
  256. X#define oldSunOS
  257. X#endif
  258. X
  259. X#ifndef oldSunOS
  260. X#include <suntool/alert.h>    /* Only for SunOS 4 */
  261. X#include <alloca.h>        /* Cannot find this on 3.5 */
  262. X#endif
  263. X
  264. X#include <math.h>
  265. X
  266. Xtypedef unsigned char Bool;
  267. X
  268. X#define Stacksize 100        /* Dynamic allocation would be cleaner */
  269. X
  270. Xstruct stack {
  271. X  Pixrect *pr;
  272. X  double xmin, xmax, ymin, ymax;
  273. X} Stack [Stacksize];
  274. X
  275. Xstatic int sp = 0;        /* Stackpointer */
  276. X
  277. X#define MAX(a,b) ((a) > (b) ? (a) : (b))
  278. X#define MIN(a,b) ((a) < (b) ? (a) : (b))
  279. X#define sgn(x) ((x) >= 0 ? 1 : -1)
  280. X
  281. X#define SQRT_2 1.41421356237
  282. X#define Nmax 800        /* Maximum image size */
  283. X
  284. Xstatic Bool MSet[Nmax][Nmax];
  285. Xstatic double xmin = -2.0, xmax=0.5, ymin = -1.25, ymax=1.25,
  286. X              side=2.5, delta, recur;
  287. Xstatic int maxiter=20, incr=5, rec=5;
  288. Xstatic int start_x, start_y, new_x, new_y; /* For region select */
  289. Xstatic Bool selected = FALSE, draw_new_image=FALSE, abort=FALSE;
  290. X
  291. X#define BUTTONFONT "/usr/lib/fonts/fixedwidthfonts/gallant.r.19"
  292. Xstatic char *default_font =
  293. X  "DEFAULT_FONT=/usr/lib/fonts/fixedwidthfonts/screen.r.13";
  294. X
  295. Xstatic Frame fr;
  296. Xstatic Canvas cv;
  297. Xstatic Pixwin *pw;
  298. Xstatic Pixfont *bf, *pf;
  299. Xstatic Panel pn;
  300. Xstatic Panel_item recur_p, incr_p, maxiter_p, stop_p;
  301. X
  302. X#ifdef notdef            /* Future enhancement */
  303. Xstatic int N=512;        /* Current image size */
  304. X#else
  305. X#define N 512
  306. X#endif
  307. X
  308. Xstatic char Nmax_str[10];
  309. X
  310. Xextern int panel_pw_text(), panel_fonthome(); /* Undocumented, but nice */
  311. X
  312. Xdouble MSetDist();
  313. Xvoid quit(), stop(), up(), draw(), sel_region();
  314. X
  315. Xvoid main()
  316. X{
  317. X  (void) putenv(default_font);
  318. X  bf = pf_open(BUTTONFONT);
  319. X  pf = pf_default();
  320. X
  321. X/* This code is full of strange magic numbers. I apologize for that!!! */
  322. X
  323. X  fr = window_create(0, FRAME,
  324. X             WIN_X, 400,
  325. X             WIN_Y, 150,
  326. X             WIN_SHOW, TRUE,
  327. X             FRAME_LABEL, "FastMtool - Mandelbrot exploring",
  328. X             0);
  329. X  pn = window_create(fr, PANEL, 0);
  330. X
  331. X/* The brain-damaged SunView uses the PANEL_MAX_VALUE to determine the
  332. X   position of the slider, instead of e.g. always allocate 10 positions
  333. X   for this and right-justify or something. This means that I have to
  334. X   use delicate (ugly) pixel-positioning to get the sliders to line up. */
  335. X
  336. X  recur_p = panel_create_item(pn, PANEL_SLIDER,
  337. X                  PANEL_LABEL_X, 5,
  338. X                  PANEL_LABEL_Y, 5,
  339. X                  PANEL_VALUE_X, 110,
  340. X                  PANEL_VALUE_Y, 5,
  341. X                  PANEL_LABEL_STRING, "Recur:",
  342. X                  PANEL_VALUE, rec,
  343. X                  PANEL_MIN_VALUE, 1,
  344. X                  PANEL_MAX_VALUE, 50,
  345. X                  0);
  346. X  incr_p = panel_create_item(pn, PANEL_SLIDER,
  347. X                 PANEL_LABEL_X, 5,
  348. X                 PANEL_LABEL_Y, 25,
  349. X                 PANEL_VALUE_X, 110,
  350. X                 PANEL_VALUE_Y, 25,
  351. X                 PANEL_LABEL_STRING, "Increment:",
  352. X                 PANEL_VALUE, incr,
  353. X                 PANEL_MIN_VALUE, 1,
  354. X                 PANEL_MAX_VALUE, 10,
  355. X                 0);
  356. X  maxiter_p = panel_create_item(pn, PANEL_SLIDER,
  357. X                PANEL_LABEL_X, 5,
  358. X                PANEL_LABEL_Y, 45,
  359. X                PANEL_VALUE_X, 78,
  360. X                PANEL_VALUE_Y, 45,
  361. X                PANEL_LABEL_STRING, "Maxiter:",
  362. X                PANEL_VALUE, maxiter,
  363. X                PANEL_MIN_VALUE, 10,
  364. X                PANEL_MAX_VALUE, 1000,
  365. X                0);
  366. X  panel_create_item(pn, PANEL_MESSAGE,
  367. X            PANEL_ITEM_X, 5,
  368. X            PANEL_ITEM_Y, 100,
  369. X            PANEL_LABEL_STRING, "Xmin:",
  370. X            PANEL_LABEL_BOLD, TRUE,
  371. X            0);
  372. X  panel_create_item(pn, PANEL_MESSAGE,
  373. X            PANEL_ITEM_X, 200,
  374. X            PANEL_ITEM_Y, 100,
  375. X            PANEL_LABEL_STRING, "Xmax:",
  376. X            PANEL_LABEL_BOLD, TRUE,
  377. X            0);
  378. X  panel_create_item(pn, PANEL_MESSAGE,
  379. X            PANEL_ITEM_X, 5,
  380. X            PANEL_ITEM_Y, 120,
  381. X            PANEL_LABEL_STRING, "Ymin:",
  382. X            PANEL_LABEL_BOLD, TRUE,
  383. X            0);
  384. X  panel_create_item(pn, PANEL_MESSAGE,
  385. X            PANEL_ITEM_X, 200,
  386. X            PANEL_ITEM_Y, 120,
  387. X            PANEL_LABEL_STRING, "Ymax:",
  388. X            PANEL_LABEL_BOLD, TRUE,
  389. X            0);
  390. X
  391. X#ifdef notdef            /* Possible future enhancement... */
  392. X  sprintf(Nmax_str, "%d", Nmax);
  393. X  panel_create_item(pn, PANEL_CYCLE,
  394. X            PANEL_ITEM_X, 350,
  395. X            PANEL_ITEM_Y, 5,
  396. X            PANEL_LABEL_STRING, "Image size:",
  397. X            PANEL_LABEL_BOLD, TRUE,
  398. X            PANEL_CHOICE_STRINGS, Nmax_str, "512", "256", 0,
  399. X            PANEL_VALUE, 1,
  400. X            0);
  401. X#endif
  402. X
  403. X  panel_create_item(pn, PANEL_BUTTON,
  404. X            PANEL_ITEM_X, 360,
  405. X            PANEL_ITEM_Y, 30,
  406. X            PANEL_LABEL_IMAGE, panel_button_image(pn, "DRAW", 0, bf),
  407. X            PANEL_NOTIFY_PROC, draw,
  408. X            0);
  409. X  panel_create_item(pn, PANEL_BUTTON,
  410. X            PANEL_ITEM_X, 360,
  411. X            PANEL_ITEM_Y, 70,
  412. X            PANEL_LABEL_IMAGE, panel_button_image(pn, " UP ", 0, bf),
  413. X            PANEL_NOTIFY_PROC, up,
  414. X            0);
  415. X  panel_create_item(pn, PANEL_BUTTON,
  416. X            PANEL_ITEM_X, 360,
  417. X            PANEL_ITEM_Y, 110,
  418. X            PANEL_LABEL_IMAGE, panel_button_image(pn, "STOP", 0, bf),
  419. X            PANEL_NOTIFY_PROC, stop,
  420. X            0);
  421. X  panel_create_item(pn, PANEL_BUTTON,
  422. X            PANEL_ITEM_X, 450,
  423. X            PANEL_ITEM_Y, 72,
  424. X            PANEL_LABEL_IMAGE, panel_button_image(pn, "Quit", 0, pf),
  425. X            PANEL_NOTIFY_PROC, quit,
  426. X            0);
  427. X  window_fit_height(pn);
  428. X  cv = window_create(fr, CANVAS,
  429. X             WIN_WIDTH, N,
  430. X             WIN_HEIGHT, N,
  431. X             WIN_CONSUME_PICK_EVENT, LOC_DRAG,
  432. X             WIN_EVENT_PROC, sel_region,
  433. X             0);
  434. X
  435. X  window_fit(fr);
  436. X  notify_interpose_destroy_func(fr, quit);
  437. X
  438. X  pw = canvas_pixwin(cv);
  439. X  notify_dispatch();        /* To make the next put_coords work */
  440. X  put_coords(0, N-1, N-1, 0);
  441. X
  442. X  bzero((char *) MSet, sizeof(MSet));
  443. X  pw_writebackground(pw, 0, 0, N, N, PIX_SRC | PIX_COLOR(1));
  444. X
  445. X  /* Cannot use window_main_loop() because the notifier can't dispatch
  446. X     events inside a PANEL_NOTIFY_PROC. */
  447. X
  448. X  while (1) {
  449. X    notify_dispatch();
  450. X    if (draw_new_image) {
  451. X      panel_pw_text(pn, 347, 5 + panel_fonthome(bf), PIX_SRC, bf, "Drawing!");
  452. X      compute();
  453. X      panel_pw_text(pn, 347, 5 + panel_fonthome(bf), PIX_SRC, bf, "        ");
  454. X      draw_new_image = FALSE;
  455. X    }
  456. X    usleep(50000);
  457. X  }
  458. X}
  459. X
  460. Xput_coords(ixmin, ixmax, iymin, iymax)
  461. X     int ixmin, ixmax, iymin, iymax;
  462. X{
  463. X  char str[20];
  464. X
  465. X  sprintf(str, "%10.7lf", xmin + side * ixmin/(N-1));
  466. X  panel_pw_text(pn, 50, 100 + panel_fonthome(pf), PIX_SRC, pf, str);
  467. X  sprintf(str, "%10.7lf", xmin + side * ixmax/(N-1));
  468. X  panel_pw_text(pn, 245, 100 + panel_fonthome(pf), PIX_SRC, pf, str);
  469. X  sprintf(str, "%10.7lf", ymin + side * (N-1-iymin)/(N-1));
  470. X  panel_pw_text(pn, 50, 120 + panel_fonthome(pf), PIX_SRC, pf, str);
  471. X  sprintf(str, "%10.7lf", ymin + side * (N-1-iymax)/(N-1));
  472. X  panel_pw_text(pn, 245, 120 + panel_fonthome(pf), PIX_SRC, pf, str);
  473. X}
  474. X
  475. Xvoid sel_region(canvas, event, arg)
  476. X     Canvas canvas;
  477. X     Event *event;
  478. X     char *arg;
  479. X{
  480. X  static Bool mouseing = FALSE;
  481. X  register int maxdist, tmpx, tmpy;
  482. X
  483. X#define mkbox(a,b,c,d) \
  484. X  pw_vector(pw, a, b, c, b, PIX_SRC^PIX_DST, 1);\
  485. X  pw_vector(pw, a, b, a, d, PIX_SRC^PIX_DST, 1);\
  486. X  pw_vector(pw, c, b, c, d, PIX_SRC^PIX_DST, 1);\
  487. X  pw_vector(pw, a, d, c, d, PIX_SRC^PIX_DST, 1)
  488. X
  489. X  switch (event_action(event)) {
  490. X    case MS_LEFT:
  491. X      if (event_is_down(event)) {
  492. X    if (selected) {        /* Remove old box first */
  493. X      mkbox(start_x, start_y, new_x, new_y);
  494. X    }
  495. X    start_x = new_x = event_x(event);
  496. X    start_y = new_y = event_y(event);
  497. X    put_coords(new_x, new_x, new_y, new_y);
  498. X    mouseing = TRUE;
  499. X      } else {
  500. X    mouseing = FALSE;
  501. X    selected = TRUE;
  502. X      }
  503. X      break;
  504. X    case LOC_DRAG:
  505. X      if (mouseing) {
  506. X    mkbox(start_x, start_y, new_x, new_y); /* Remove old box */
  507. X
  508. X    /* We want to restrict the size to be square */
  509. X    tmpx = event_x(event) - start_x;
  510. X    tmpy = start_y - event_y(event);
  511. X    maxdist = MIN(tmpx * sgn(tmpx), tmpy * sgn(tmpy));
  512. X    new_x = start_x + maxdist * sgn(tmpx);
  513. X    new_y = start_y - maxdist * sgn(tmpy);
  514. X
  515. X    mkbox(start_x, start_y, new_x, new_y); /* Draw new box */
  516. X    put_coords(MIN(start_x, new_x), MAX(start_x, new_x),
  517. X           MAX(start_y, new_y), MIN(start_y, new_y));
  518. X      }
  519. X      break;
  520. X    case MS_MIDDLE:
  521. X      if (selected) {
  522. X    mkbox(start_x, start_y, new_x, new_y);
  523. X    selected = FALSE;
  524. X      }
  525. X    }
  526. X}
  527. X
  528. Xvoid stop()
  529. X{
  530. X  abort = TRUE;
  531. X}
  532. X
  533. Xvoid up()
  534. X{
  535. X  if (sp > 0) {
  536. X    Pixrect *old;
  537. X    register int i, j, k;
  538. X    Bool *mem;
  539. X
  540. X    selected = FALSE;
  541. X    sp--;
  542. X    xmin = Stack[sp].xmin;
  543. X    xmax = Stack[sp].xmax;
  544. X    ymin = Stack[sp].ymin;
  545. X    ymax = Stack[sp].ymax;
  546. X    side = xmax - xmin;
  547. X    put_coords(0, N-1, N-1, 0);
  548. X    old = Stack[sp].pr;
  549. X    pw_write(pw, 0, 0, N, N, PIX_SRC, old, 0, 0);
  550. X
  551. X    /* Restore MSet */
  552. X    /* This is ugly - I'm assuming that sizeof(Bool) == 1. Shame on me! */
  553. X    mem = (Bool *) mpr_d(old)->md_image;
  554. X    for (i=0; i<N; i++) {
  555. X      for (j=0; j<N; j+=8) {
  556. X    for (k=0; k<8; k++)
  557. X      MSet[j+k][N-1-i] = ((*mem & (1<<(7-k))) >> (7-k)) == 0 ? 1 : 0;
  558. X    mem++;
  559. X      }
  560. X    }
  561. X    pr_destroy(old);
  562. X  }
  563. X}
  564. X    
  565. Xvoid draw()
  566. X{
  567. X  draw_new_image = TRUE;
  568. X}
  569. X
  570. Xvoid quit()
  571. X{
  572. X#ifdef oldSunOS
  573. X  exit(0);            /* You won't miss the following fancy stuff.. */
  574. X#else
  575. X  if (alert_prompt(fr, (Event *)0,
  576. X           ALERT_MESSAGE_STRINGS,
  577. X             "Please confirm:",
  578. X             "Do you know what you're doing??",
  579. X             0,
  580. X           ALERT_BUTTON_YES, "Of course, quit bugging me!",
  581. X           ALERT_BUTTON_NO, "Sorry, I hit the wrong button...",
  582. X           ALERT_MESSAGE_FONT, bf,
  583. X           ALERT_BUTTON_FONT, pf,
  584. X           0)
  585. X      == ALERT_YES) {
  586. X    exit(0);
  587. X  } else
  588. X    notify_veto_destroy(fr);
  589. X#endif
  590. X}
  591. X
  592. Xcompute()
  593. X{
  594. X  register int ix, iy;
  595. X
  596. X  if (selected && start_x != new_x) { /* New region selected */
  597. X    Pixrect *save = mem_create(N, N, 1);
  598. X    mkbox(start_x, start_y, new_x, new_y); /* Remove the box first */
  599. X    pw_read(save, 0, 0, N, N, PIX_SRC, pw, 0, 0);
  600. X    Stack[sp].pr = save;
  601. X    Stack[sp].xmin = xmin;
  602. X    Stack[sp].xmax = xmax;
  603. X    Stack[sp].ymin = ymin;
  604. X    Stack[sp].ymax = ymax;
  605. X    if (sp < Stacksize) sp++;    /* Hard to imagine this happen, but... */
  606. X    bzero((char *) MSet, sizeof(MSet));
  607. X    pw_writebackground(pw, 0, 0, N, N, PIX_SRC | PIX_COLOR(1));
  608. X
  609. X    xmax = xmin + side * MAX(start_x, new_x) /(N-1);
  610. X    xmin += side * MIN(start_x, new_x) /(N-1);
  611. X    ymax = ymin + side * (N-1-MIN(start_y, new_y)) /(N-1);
  612. X    ymin += side * (N-1-MAX(start_y, new_y)) /(N-1);
  613. X    selected = FALSE;
  614. X  } else {
  615. X    /* No region selected, just redraw. Perhaps using new parameters. */
  616. X    put_coords(0, N-1, N-1, 0);
  617. X  }
  618. X
  619. X  rec = (int) panel_get_value(recur_p);
  620. X  incr = (int) panel_get_value(incr_p);
  621. X  maxiter = (int) panel_get_value(maxiter_p);
  622. X
  623. X  side = xmax - xmin;
  624. X  delta = 0.25 * side / (N-1);    /* 0.25 seems OK */
  625. X  recur = rec * delta;
  626. X
  627. X  abort = FALSE;
  628. X
  629. X/*************************************************************************/
  630. X/*************************************************************************/
  631. X
  632. X/* From now on, you will find the new Mandelbrot algorithm. No Sun specific
  633. X   stuff, except the notify_dispatch() and some pw_put() and pw_line(). */
  634. X
  635. X  for (iy = 0; iy < N; iy += incr) {
  636. X    notify_dispatch();        /* Allow user to hit the STOP button */
  637. X    if (abort) break;
  638. X    for (ix = 0; ix < N; ix += incr)
  639. X      if (!MSet[ix][iy])
  640. X    MDisk(ix,iy);
  641. X  }
  642. X}
  643. X
  644. XMDisk(ix, iy)
  645. X     register int ix, iy;
  646. X{
  647. X  register double cx, cy, dist;
  648. X  register int irad;
  649. X
  650. X  if (ix<0 || ix>=N || iy<0 || iy>=N || MSet[ix][iy]) return;
  651. X
  652. X  cx = xmin + (side * ix) / (N-1);
  653. X  cy = ymin + (side * iy) / (N-1);
  654. X  dist = 0.25 * MSetDist(cx, cy, maxiter);
  655. X  irad = dist / side * (N-1);    /* Bug in the original algorithm */
  656. X
  657. X  if (irad == 1) {
  658. X    MSet[ix][iy] = 1;
  659. X    pw_put(pw, ix, N-1-iy, 0);    /* Sun specific */
  660. X  } else if (irad > 1)
  661. X    FILLDISK(ix, iy, irad);
  662. X  else if (dist > delta) {
  663. X    MSet[ix][iy] = 1;
  664. X    pw_put(pw, ix, N-1-iy, 0);    /* Sun specific */
  665. X  }
  666. X
  667. X  if (dist > recur) {
  668. X    if (irad > 1) irad++;
  669. X    MDisk(ix, iy + irad);
  670. X    MDisk(ix, iy - irad);
  671. X    MDisk(ix + irad, iy);
  672. X    MDisk(ix - irad, iy);
  673. X
  674. X/* It will be slightly faster if I leave out the following "45-degree"
  675. X   recursions. The reason is that most of these points will probably
  676. X   be filled already and MDisk will return immediately. But since
  677. X   they are in the original algorithm and the improvement is only marginal
  678. X   I will leave them here. */
  679. X
  680. X    irad = 0.5 + irad / SQRT_2;
  681. X    MDisk(ix + irad, iy + irad);
  682. X    MDisk(ix - irad, iy - irad);
  683. X    MDisk(ix - irad, iy + irad);
  684. X    MDisk(ix + irad, iy - irad);
  685. X  }
  686. X}
  687. X
  688. Xdouble MSetDist(cx, cy, maxiter)
  689. X     register double cx, cy;
  690. X     register int maxiter;
  691. X{
  692. X# define overflow 10e10        /* Don't know if this is foolproof */
  693. X
  694. X  register int iter=0;
  695. X  register double zx, zy, zx2, zy2;
  696. X  register double *xorbit, *yorbit;
  697. X
  698. X  /* Could use a static array for this, if you don't have alloca */
  699. X  xorbit = (double *) alloca(maxiter * sizeof(double));
  700. X  yorbit = (double *) alloca(maxiter * sizeof(double));
  701. X
  702. X  /* This is the standard Mandelbrot iteration */
  703. X  zx = zy = zx2 = zy2 = xorbit[0] = yorbit[0] = 0.0;
  704. X  do {
  705. X    zy = (zx * zy) + (zx * zy) + cy; /* gcc generates only one mult for this */
  706. X    zx = zx2 - zy2 + cx;
  707. X    iter++;
  708. X    xorbit[iter] = zx;        /* Save the iteration orbits for later */
  709. X    yorbit[iter] = zy;
  710. X    zx2 = zx * zx;
  711. X    zy2 = zy * zy;
  712. X  } while ((zx2 + zy2) < 1000.0 && iter<maxiter);
  713. X
  714. X  if (iter < maxiter) {        /* Generate derivatives */
  715. X    register double zpx, zpy, tmp;
  716. X    register int i;
  717. X
  718. X    zpx = zpy = 0.0;
  719. X
  720. X    for (i=0; i<iter; i++) {
  721. X      tmp = 2 * (xorbit[i] * zpx - yorbit[i] * zpy) + 1.0;
  722. X      zpy = 2 * (xorbit[i] * zpy + yorbit[i] * zpx);
  723. X      zpx = tmp;
  724. X      if (fabs(zpx) > overflow || fabs(zpy) > overflow)
  725. X    return 0.0;
  726. X    }
  727. X    /* This is the distance estimation */
  728. X    return log(zx2 + zy2) * sqrt(zx2 + zy2) / sqrt(zpx*zpx + zpy*zpy);
  729. X  }
  730. X  return 0.0;
  731. X}
  732. X
  733. XFILLDISK(ix, iy, irad)
  734. X     register int ix, iy;
  735. X     int irad;
  736. X{
  737. X  register int x, y, e;
  738. X
  739. X  /* The "Mini"-algorithm. Perhaps I should use display locking around the
  740. X     plotline's, but after all, the fun is watching it work... */
  741. X
  742. X  x = 0;
  743. X  y = irad;
  744. X  e = irad / 2;
  745. X  while (x <= y) {
  746. X    plotline(ix - x, ix + x, iy + y);
  747. X    plotline(ix - y, ix + y, iy + x);
  748. X    plotline(ix - x, ix + x, iy - y);
  749. X    plotline(ix - y, ix + y, iy - x);
  750. X    e -= x;
  751. X    if (e < 0) {
  752. X      e += y;
  753. X      y--;
  754. X    }
  755. X    x++;
  756. X  }
  757. X}
  758. X
  759. Xplotline(x1, x2, y)
  760. X     register int x1, x2, y;
  761. X{
  762. X  register int i;
  763. X  if (y<0 || y>N-1 || (x1<0 && x2<0) || (x1>=N-1 && x2 >=N-1)) return;
  764. X
  765. X  if (x1 < 0) x1 = 0;
  766. X  if (x1 > N-1) x1 = N-1;
  767. X  if (x2 < 0) x2 = 0;
  768. X  if (x2 > N-1) x2 = N-1;
  769. X
  770. X  pw_vector(pw, x1, N-1-y, x2, N-1-y, PIX_SRC, 0); /* Sun specific */
  771. X
  772. X  for (i=x1; i<=x2; i++)
  773. X    MSet[i][y] = 1;
  774. X}
  775. SHAR_EOF
  776. chmod 0644 FastMtool.c || echo "restore of FastMtool.c fails"
  777. fi
  778. exit 0
  779.