Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

xstarplot22.C

Go to the documentation of this file.
00001 
00032 
00033 //.............................................................................
00034 //    version 1:  May 1989   Piet Hut            email: piet@iassns.bitnet
00035 //                           Institute for Advanced Study, Princeton, NJ, USA
00036 //    version 2:  Dec 1992   Piet Hut      adapted to the new C++-based Starlab
00037 //    version 3:  Dec 1992   Steve McMillan      email: steve@zonker.drexel.edu
00038 //                           Drexel University, Philadelphia, PA, USA
00039 //                           Converted original ASCIIplot to X --- FIRST DRAFT!
00040 //    version 4:  Jan 1994   Biao Lu             email: biao@eagle.drexel.edu
00041 //                           Drexel University, Philadelphia, PA, USA
00042 //                           Use new X interface for movie.
00043 //            Aug/Sep 1994   Cleaned up and expanded, SMcM
00044 //                Sep 1995   Extended to sdyn3 and nonzero radii, SMcM
00045 //                Aug 1996   Added forward/backward step modes, SMcM
00046 //                Aug 1996   Reworked for hdyn and nonzero radii, SMcM
00047 //                Jul 1998   New end-of-data behavior; more robust
00048 //                           X interface, SMcM
00049 //.............................................................................
00050 //  non-local functions: 
00051 //    xstarplot22
00052 //.............................................................................
00053 //  uses:
00054 //    liblux.a (X interface)
00055 //    The X graphics library
00056 //.............................................................................
00057 
00058 // NOTE: On some systems, it appears that overflow can occur, causing the
00059 //       win.lnx and win.lny entries to be overwritten and leading to
00060 //       spurious "log10" errors in draw.c (in lux_set_item, specifically).
00061 //       This isn't fatal, but it should be fixed someday...
00062 
00063 #include "worldline.h"
00064 #include "xstarplot.h"
00065 #include "dyn_util.h"
00066 
00067 // Use dyn if we only want to deal with dynamical quantities.
00068 // Use pdyn if we want to see quantities too.
00069 
00070 #define DYN pdyn
00071 #define DYNPTR pdynptr
00072 
00073 //-------------------------------------------------------------------------
00074 
00075 
00076 // These shouldn't really be global, but keep them this way for now...
00077 
00078 unsigned long  win, dia, instr, colwin;
00079 unsigned long c_energy[10], c_index[N_COLORS+1];
00080 int      init_status = 0;
00081 
00082 // The plotting box is determined completely by origin and lmax3d.
00083 // Its projection onto the viewing plane is xmin, xmax, ymin, ymax
00084 
00085 float  xmin, xmax, ymin, ymax, base_point_size, lmax3d, origin[3];
00086 
00087 int   win_size;
00088 int   point_scale_mode = 0;
00089 int   kx = 1, ky = 2, kproj = 3;
00090 int   origin_star = -1;
00091 int   nodes = 0, links = 0, root = 0, multiples = 0, unperturbed = 0;
00092 float theta = 0.33, costheta = cos(0.33), sintheta = sin(0.33), dtheta = 0.03;
00093 float phi = 0.33, cosphi = cos(0.33), sinphi = sin(0.33);
00094 real  local_offset[3];
00095 
00096 #define MIN_DELAY  1.0
00097 float delay_time = MIN_DELAY;
00098 
00099 float r_factor = 1.0;
00100 
00101 char  graph3d = 1, track = 0, cenergy = 0; // convenient to distinguish these
00102 
00103 char   temp_buffer[255];        // convenient to share this temporary space
00104 
00105 //-------------------------------------------------------------------------
00106 
00107 // base_point_size defines the size of the default "dot" size on the display.
00108 // It is used (with scaling) for stars and (without scaling) for nodes.
00109 
00110 local void set_base_point_size(DYN* b, float rel_point_size)
00111 {
00112     base_point_size = 2 * SMALL_DOT_SIZE;       // default point size
00113 
00114     if (point_scale_mode == 1) {
00115 
00116         // Scale so the average initial mass has a reasonable size.
00117 
00118         real m_tot = 0;
00119         real n_tot = 0;
00120         for_all_leaves(DYN, b, bi) {
00121             n_tot++;
00122             m_tot += bi->get_mass();
00123         }
00124 
00125         if (n_tot > 0) base_point_size /= sqrt(m_tot/n_tot);    // NB sqrt below
00126 
00127     } else if (point_scale_mode == 2 || point_scale_mode == 3) {
00128 
00129         // In the case point_scale_mode = 2, use unscaled (i.e. true)
00130         // radii if rel_point_size < 0.
00131 
00132         if (point_scale_mode == 2 && rel_point_size < 0) {
00133 
00134             base_point_size = 1;
00135 
00136         } else {
00137 
00138             // Scale so the average initial radius has a reasonable size.
00139 
00140             real r_tot = 0;
00141             real n_tot = 0;
00142             for_all_leaves(DYN, b, bi) {
00143                 n_tot++;
00144                 r_tot += bi->get_radius();
00145             }
00146 
00147             if (n_tot > 0) {
00148                 if (point_scale_mode == 2)
00149                     base_point_size /= r_tot/n_tot;
00150                 else
00151                     base_point_size /= sqrt(r_tot/n_tot);
00152             }
00153         }
00154     }
00155 
00156     // Optional additional scaling:
00157 
00158     if (rel_point_size > 0.0)  base_point_size *= rel_point_size;
00159 }
00160 
00161 local float get_point_size(DYN* bi)
00162 {
00163     // Scaling by mass is too extreme.  Use sqrt(mass).
00164     // Also, impose a lower limit on the point size.
00165 
00166     // For pdyns, radius is in solar units.  Better place a limit so
00167     // supergiants don't just vanish!
00168 
00169     if (point_scale_mode == 1)
00170         return max(SMALL_DOT_SIZE,
00171                    base_point_size * sqrt(bi->get_mass()));
00172     else if (point_scale_mode == 2)
00173         return max(SMALL_DOT_SIZE,
00174                    base_point_size * min(20., bi->get_radius()));
00175     else if (point_scale_mode == 3)
00176         return max(SMALL_DOT_SIZE,
00177                    base_point_size * min(20., sqrt(bi->get_radius())));
00178     else
00179         return base_point_size;
00180 }
00181 
00182 local void draw_star_point(unsigned long win, float r, float s,
00183                            float actual_point_size, bool f_flag)
00184 
00185 // Plot a point of size actual_point_size at (r,s), filled or unfilled
00186 // according to the value of f_flag.
00187 
00188 {
00189     // May be able to improve appearance of larger filled points by
00190     // drawing a circle around them...
00191 
00192     if (f_flag) {
00193         lux_fill_arcf(win, r - actual_point_size/2, s - actual_point_size/2,
00194                       actual_point_size, actual_point_size, 0.0, 360.0);
00195         if (actual_point_size < 12*lmax3d/win_size) return;
00196         actual_point_size *= 0.8;
00197     }
00198     lux_draw_arcf(win, r - actual_point_size/2, s - actual_point_size/2, 
00199                   actual_point_size, actual_point_size, 0.0, 360.0);
00200 }
00201 
00202 local void draw_links_2d(DYN* b, float r, float s)
00203 {
00204     for_all_daughters(DYN, b, bb) {
00205 
00206         float rr = bb->get_pos()[kx]-local_offset[kx];
00207         float ss = bb->get_pos()[ky]-local_offset[ky];
00208         float stemp;
00209 
00210         // Deal with the 9 possible locations of (rr,ss) with respect
00211         // to the box defined by xmin, xmax, ymin, and ymax.
00212 
00213         if (rr < xmin) {
00214 
00215             if (ss < ymin) {
00216                 float stemp = interp_to_x(r, s, rr, ss, xmin);
00217                 if (stemp >= ymin)
00218                     rr = xmin, ss = stemp;
00219                 else
00220                     rr = interp_to_y(r, s, rr, ss, ymin), ss = ymin;
00221             } else if (ss > ymax) {
00222                 if ((stemp = interp_to_x(r, s, rr, ss, xmin)) <= ymax)
00223                     rr = xmin, ss = stemp;
00224                 else
00225                     rr = interp_to_y(r, s, rr, ss, ymax), ss = ymax;
00226             } else
00227                 ss = interp_to_x(r, s, rr, ss, xmin), rr = xmin;
00228 
00229         } else if (rr > xmax) {
00230 
00231             if (ss < ymin) {
00232                 if ((stemp = interp_to_x(r, s, rr, ss, xmax)) >= ymin)
00233                     rr = xmax, ss = stemp;
00234                 else
00235                     rr = interp_to_y(r, s, rr, ss, ymin), ss = ymin;
00236             } else if (ss > ymax) {
00237                 if ((stemp = interp_to_x(r, s, rr, ss, xmax)) <= ymax)
00238                     rr = xmax, ss = stemp;
00239                 else
00240                     rr = interp_to_y(r, s, rr, ss, ymax), ss = ymax;
00241             } else
00242                 ss = interp_to_x(r, s, rr, ss, xmax), rr = xmax;
00243 
00244         } else {
00245 
00246             if (ss < ymin)
00247                 rr = interp_to_y(r, s, rr, ss, ymin), ss = ymin;
00248             else if (ss > ymax)
00249                 rr = interp_to_y(r, s, rr, ss, ymax), ss = ymax;
00250 
00251         }
00252         lux_draw_linef(win, r, s, rr, ss);
00253     }
00254 }                                          
00255 
00256 local void draw_links_3d(DYN* b, float r, float s)
00257 {
00258     for_all_daughters(DYN, b, bb) {
00259 
00260         float X = (float)bb->get_pos()[0] - local_offset[0] - origin[0];
00261         float Y = (float)bb->get_pos()[1] - local_offset[1] - origin[1];
00262         float Z = (float)bb->get_pos()[2] - local_offset[2] - origin[2];
00263 
00264         // Don't attempt to deal with the 27 possible locations
00265         // of (X, Y, Z) with respect to the box!
00266 
00267         float rr, ss;
00268         project3d(X, Y, Z, rr, ss, costheta, sintheta, cosphi, sinphi);
00269         lux_draw_linef(win, r, s, rr, ss);
00270     }
00271 }                                          
00272 
00273 local int clean_index(DYN* b)
00274 {
00275     int clean_name = 0;
00276 
00277     if (b->get_index() > 0) 
00278         clean_name = b->get_index();
00279     else if (b->get_name()) {
00280         int i = 0;
00281         if (sscanf(b->get_name(), "%d", &i)) clean_name = i;
00282     }
00283 
00284     return clean_name;
00285 }
00286 
00287 static real max_cm = 2;
00288 
00289 local void plot_star(DYN *bi, float r, float s,
00290                      float actual_point_size, int f_flag)
00291 {
00292     // Plot a point at (r, s) representing star bi.
00293     // Logic regarding colors and resetting link colors needs
00294     // reconsideration...
00295 
00296     // Determine the color to use.
00297 
00298     bool temp_flag = f_flag;
00299     if (bi->get_oldest_daughter()) {
00300 
00301         lux_set_color(win, lux_lookup_color(win, "grey"));
00302         temp_flag =  1 - f_flag;
00303 
00304     } else {
00305 
00306         if (cenergy) {
00307 
00308             char c;
00309 
00310             compute_energies(bi->get_root(), bi, c);
00311             lux_set_color(win, c_energy[c]);
00312 
00313         } else if (clean_index(bi) > 0) {
00314 
00315             // Wrap the color map.
00316 
00317             int ii = clean_index(bi);
00318             while (ii > N_COLORS) ii -= N_COLORS;
00319 
00320             lux_set_color(win,c_index[ii]);
00321         }
00322     }
00323 
00324     if (track)
00325 
00326         lux_draw_pointf(win, r, s);
00327 
00328     else {
00329 
00330         real scale = 1.0;
00331         real reset_grey = false;
00332 
00333         // Deal with possible highlighted systems.
00334         //
00335         // CM color schemes:
00336         //
00337         //      green           any unbound binary
00338         //      light blue      bound perturbed binary
00339         //      blue            bound unperturbed binary
00340         //      yellow          triple system
00341         //      orange          quadruple system
00342         //      red             quintuple or higher-order system
00343 
00344         DYN *od = bi->get_oldest_daughter();
00345 
00346         if (multiples && od && bi->is_top_level_node()) {
00347 
00348             if (bi->n_leaves() == 2) {
00349 
00350                 // PRL(od->get_kepler());
00351 
00352                 if (od->get_kepler() == (kepler*)2) {
00353 
00354                     // Highlight lightly perturbed top-level binaries.
00355 
00356                     scale = 2.0;
00357                     lux_set_color(win, lux_lookup_color(win, "purple"));
00358                     reset_grey = true;
00359 
00360                 } else if (!od->get_kepler()) {
00361 
00362                     // Highlight perturbed top-level binaries.
00363 
00364                     scale = 2.0;
00365                     lux_set_color(win, lux_lookup_color(win, "lightblue"));
00366                     reset_grey = true;
00367                 }
00368 
00369             } else {
00370 
00371                 // Highlight multiples.
00372 
00373                 scale = 4.0;
00374                 if (bi->n_leaves() == 3)
00375                     lux_set_color(win, lux_lookup_color(win, "yellow"));
00376                 else if (bi->n_leaves() == 4)
00377                     lux_set_color(win, lux_lookup_color(win, "orange"));
00378                 else
00379                     lux_set_color(win, lux_lookup_color(win, "red"));
00380 
00381                 reset_grey = true;
00382             }
00383         }
00384 
00385         if (unperturbed && od
00386             && od->get_kepler() && od->get_kepler() != (kepler*)2) {
00387 
00388             // Highlight all unperturbed binaries.
00389 
00390             scale = 2.0;
00391             lux_set_color(win, lux_lookup_color(win, "blue"));
00392             reset_grey = true;
00393         }
00394 
00395         // Plot the point.
00396 
00397         real psize = scale*actual_point_size;
00398 
00399         if (scale > 1.0) {
00400 
00401             // Compare binary size to actual_point_size and use the
00402             // larger of the two.  Best to use semi-major axis, so
00403             // we need *velocity* information in this case.  Also,
00404             // don't bother with special treatment of unbound pairs.
00405 
00406             real dr = abs(od->get_pos()
00407                            - od->get_younger_sister()->get_pos());
00408             real dv2 = square(od->get_vel()
00409                                - od->get_younger_sister()->get_vel());
00410 
00411             real sma2 = 1 / (1/dr - 0.5*dv2/bi->get_mass());    // >0 if bound
00412 
00413             // Change color for unbound binary.
00414 
00415             if (sma2 <= 0) {
00416                 sma2 = -sma2;
00417                 if (scale == 2.0)
00418                     lux_set_color(win, lux_lookup_color(win, "green"));
00419             }
00420 
00421             // Place limits on point size.
00422 
00423             if (sma2 > max_cm) sma2 = max(dr, max_cm);
00424 
00425             psize = max(psize, 1.2*sma2);
00426             //PRC(bi->format_label()); PRC(dr); PRC(dv2); PRL(sma2);
00427         }
00428 
00429         draw_star_point(win, r, s, psize, temp_flag);
00430 
00431         if (bi->get_oldest_daughter()
00432             && psize > 3*actual_point_size) {
00433             lux_set_color(win, lux_lookup_color(win, "grey"));
00434             draw_star_point(win, r, s, actual_point_size, temp_flag);
00435         }
00436 
00437         if (links && reset_grey)
00438             lux_set_color(win, lux_lookup_color(win, "grey"));
00439     }
00440 }
00441 
00442 local int plot_all_stars(DYN* b, int f_flag)
00443 {
00444     int  n_stars = b->n_leaves();
00445     if (b->get_oldest_daughter() == NULL) n_stars = 0;
00446 
00447     int  n_nodes = count_nodes(b);
00448     float r, s;
00449 
00450     if (graph3d) {
00451 
00452         for_all_nodes(DYN, b, bi) if (root || bi->get_parent()) {
00453             if (nodes
00454                 || (multiples && bi->is_top_level_node())
00455                 || (unperturbed && bi->get_oldest_daughter())
00456                 || (bi->get_oldest_daughter() == NULL)) {
00457                 
00458                 float X = (float)bi->get_pos()[0] - local_offset[0] - origin[0];
00459                 float Y = (float)bi->get_pos()[1] - local_offset[1] - origin[1];
00460                 float Z = (float)bi->get_pos()[2] - local_offset[2] - origin[2];
00461 
00462                 float actual_point_size = get_point_size(bi);
00463 
00464                 if (   (X > (-lmax3d + actual_point_size))
00465                     && (X < ( lmax3d - actual_point_size)) 
00466                     && (Y > (-lmax3d + actual_point_size))
00467                     && (Y < ( lmax3d - actual_point_size)) 
00468                     && (Z > (-lmax3d + actual_point_size))
00469                     && (Z < ( lmax3d - actual_point_size))) {
00470 
00471                     // Should really sort by depth here...
00472 
00473                     project3d(X, Y, Z, r, s,
00474                               costheta, sintheta,
00475                               cosphi, sinphi);
00476 
00477                     plot_star(bi, r, s, actual_point_size, f_flag);
00478 
00479                     if (links && bi->get_oldest_daughter())
00480                         draw_links_3d(bi, r, s);
00481                 }
00482             }
00483         }
00484 
00485     } else {
00486 
00487         // Make a list of all nodes, *including* the root node if root = 1.
00488         // Root will be at the start of the list if it is being displayed.
00489 
00490         DYNPTR* p = new DYNPTR[n_nodes+root];
00491 
00492         int ip = 0;
00493         for_all_nodes(DYN, b, bi) if (root || bi != b) p[ip++] = bi;
00494         if (ip != n_nodes+root) {
00495             cerr << "plot_all_stars: n_nodes = " << n_nodes+root
00496                 << " counted " << ip << endl;
00497             exit(1);
00498         }
00499 
00500         // Sort by kproj (note that kproj = 1, 2, or 3 for x, y, or z):
00501 
00502         for (ip = 0; ip < n_nodes+root; ip++)
00503             for (int jp = ip+1; jp < n_nodes+root; jp++)
00504                 if (p[jp]->get_pos()[kproj-1] < p[ip]->get_pos()[kproj-1]) {
00505                     DYNPTR bb = p[jp];
00506                     p[jp] = p[ip];
00507                     p[ip] = bb;
00508                 }
00509 
00510         // Plot ordered by depth.
00511 
00512         for (ip = 0; ip < n_nodes+root; ip++) {
00513             DYN * bi = p[ip];
00514             if ( (root || bi != b)
00515                 && (nodes
00516                     || (multiples && bi->is_top_level_node())
00517                     || (unperturbed && bi->get_oldest_daughter())
00518                     || (bi->get_oldest_daughter() == NULL))) {
00519 
00520                 r = (float)bi->get_pos()[kx] - local_offset[kx];
00521                 s = (float)bi->get_pos()[ky] - local_offset[ky];
00522 
00523                 float actual_point_size = get_point_size(bi);
00524 
00525                 if (   (r > (xmin + actual_point_size))
00526                     && (r < (xmax - actual_point_size)) 
00527                     && (s > (ymin + actual_point_size))
00528                     && (s < (ymax - actual_point_size)) ) {
00529 
00530                     if (bi->get_index() != -42)
00531                         plot_star(bi, r, s, actual_point_size, f_flag);
00532 
00533                     if (links && bi->get_oldest_daughter())
00534                         draw_links_2d(bi, r, s);
00535                 }
00536             }
00537         }
00538         delete [] p;
00539     }
00540     return n_stars;
00541 }
00542 
00543 local int type(int which)
00544 {
00545     if (which == tracking || which == graph3dim || which == colorenergy)
00546         return BUTTON_WINDOW;
00547     else
00548         return INPUT_WINDOW;
00549 }
00550 
00551 local int subtype(int which)
00552 {
00553     if (which == tracking || which == graph3dim || which == colorenergy)
00554         return CHECK_BUTTON;
00555     else
00556         return NO_TYPE;
00557 }
00558 
00559 local void set_temp_buffer(int which)
00560 {
00561     // Translate ID into a string representing the value.
00562 
00563     char c = -1;
00564     int i = -1;
00565     float f = 1.e30;    // Don't use VERY_LARGE_NUMBER here (DEC may object!)
00566 
00567     switch (which) {
00568         case colorenergy:       c = cenergy; break;
00569         case tracking:          c = track;   break;
00570         case graph3dim:         c = graph3d; break;
00571         case xminimum:          f = xmin; break;
00572         case xmaximum:          f = xmax; break;
00573         case yminimum:          f = ymin; break;
00574         case ymaximum:          f = ymax; break;
00575         case basepointsize:     f = base_point_size; break;
00576         case pointscalemode:    i = point_scale_mode; break;
00577         case lmax3D:            f = 2*lmax3d; break;
00578         case theta3D:           f = theta; break;
00579         case phi3D:             f = phi; break;
00580         case DelayTime:         f = delay_time; break;
00581         case dtheta3D:          f = dtheta; break;
00582         case Xorigin:           f = origin[0]; break;
00583         case Yorigin:           f = origin[0]; break;
00584         case Zorigin:           f = origin[0]; break;
00585         case view2D:            i = kproj; break;
00586         case originstar:        i = origin_star; break;
00587         default:                cerr << "xstarplot22: diag error...\n";
00588     }
00589 
00590     if (f < 1.e30)
00591         sprintf(temp_buffer, "%f", f);
00592     else if (c == -1)
00593         sprintf(temp_buffer, " %d ", i);
00594     else
00595         temp_buffer[0] = c;
00596 }
00597 
00598 local void set_diag_item(int which, char* id, int label_on_left,
00599                          int x1, int x2, int y)
00600 {
00601     set_temp_buffer(which);
00602 
00603     if (label_on_left) {        // label to left of (real) input box
00604 
00605         lux_set_item(dia, which, TEXT_WINDOW, NO_TYPE,
00606                      _R_(x1), _R_(y), strlen(id), id);
00607         lux_set_item(dia, which, INPUT_WINDOW, NO_TYPE,
00608                      _R_(x2), _R_(y), 10, temp_buffer);
00609 
00610     } else {                    // label to right of (integer) input box/button
00611 
00612         if (type(which) == INPUT_WINDOW) {
00613 
00614             lux_set_item(dia, which, INPUT_WINDOW, NO_TYPE,
00615                          _R_(x1), _R_(y), 3, temp_buffer);
00616             lux_set_item(dia, which, TEXT_WINDOW, NO_TYPE,
00617                          _R_(x2), _R_(y), strlen(id), id);
00618 
00619         } else {
00620 
00621             lux_set_item(dia, which, BUTTON_WINDOW, CHECK_BUTTON,
00622                          _R_(x1), _R_(y), 1, temp_buffer);
00623             lux_set_item(dia, which, TEXT_WINDOW, CHECK_BUTTON,
00624                          _R_(x2), _R_(y), strlen(id), id);
00625         }
00626     }
00627 }
00628 
00629 local void initialize_dialog(int xorigin, int yorigin)
00630 {
00631     // Initialize dialog box material (note: y is measured up from bottom!)
00632 
00633     float save = r_factor;
00634     if (r_factor > 1) r_factor = 1;
00635 
00636     int xsize = 550;
00637     int ysize = 550;
00638     if (r_factor <= 0.6) xsize = (int) (xsize / (r_factor/0.6));
00639     dia = lux_open_dialog(xorigin, yorigin, _R_(xsize), _R_(ysize));
00640 
00641     // ---------- 3-D origin info across top of box (special case): ----------
00642 
00643      lux_set_item(dia, Origin, TEXT_WINDOW, NO_TYPE,
00644                  _R_(70), _R_(500), 6, "origin");
00645 
00646     sprintf(temp_buffer, "%f", origin[0]);
00647     lux_set_item(dia, Xorigin, INPUT_WINDOW, NO_TYPE,
00648                  _R_(160), _R_(500), 10, temp_buffer);
00649 
00650     sprintf(temp_buffer, "%f", origin[1]);
00651     lux_set_item(dia, Yorigin, INPUT_WINDOW, NO_TYPE,
00652                  _R_(280), _R_(500), 10, temp_buffer);
00653 
00654     sprintf(temp_buffer, "%f", origin[2]);
00655     lux_set_item(dia, Zorigin, INPUT_WINDOW, NO_TYPE,
00656                  _R_(400), _R_(500), 10, temp_buffer);
00657 
00658 
00659     // ---------- Left-hand column of dialog box: ----------
00660 
00661     //          xmin
00662     //          xmax
00663     //          ymin
00664     //          ymax
00665     //          3-D cube size
00666     //          projection theta
00667     //          projection phi
00668     //          projection dtheta
00669     //          point scale
00670     //          delay time
00671 
00672     // Minima and maxima of 2-D display:
00673 
00674     set_diag_item(xminimum, "xmin", 1, 70, 160, 460);
00675     set_diag_item(xmaximum, "xmax", 1, 70, 160, 420);
00676     set_diag_item(yminimum, "ymin", 1, 70, 160, 380);
00677     set_diag_item(ymaximum, "ymax", 1, 70, 160, 340);
00678 
00679     // 3-D cube size:
00680 
00681     set_diag_item(lmax3D, "cube size", 1, 70, 180, 300);
00682 
00683     // 3-D projection direction:
00684 
00685     set_diag_item(theta3D,  "theta",  1, 70, 180, 260);
00686     set_diag_item(phi3D,    "phi",    1, 70, 180, 220);
00687     set_diag_item(dtheta3D, "dtheta", 1, 70, 180, 180);
00688 
00689     // Point size:
00690 
00691     set_diag_item(basepointsize, "point scale", 1, 70, 180, 140);
00692 
00693     // Delay time:
00694 
00695     set_diag_item(DelayTime, "delay time", 1, 70, 180, 100);
00696 
00697 
00698     // ---------- Right-hand column of dialog box: ----------
00699 
00700     //          origin star
00701     //          2-D view axis
00702     //          3-D plot?
00703 
00704     //          point display mode
00705     //          color by energy?
00706     //          track particles?
00707 
00708     // Origin star:
00709 
00710     set_diag_item(originstar, "Origin Star", 0, 320, 360, 460);
00711 
00712     // 2-D view axis:
00713 
00714     set_diag_item(view2D, "2-D view axis", 0, 320, 360, 420);
00715 
00716     // 3D graphics:
00717 
00718     set_diag_item(graph3dim, "3-D graph", 0, 320, 350, 380);
00719 
00720     // Point display mode
00721 
00722     set_diag_item(pointscalemode, "point display mode", 0, 320, 360, 300);
00723 
00724     // Color by energy:
00725 
00726     set_diag_item(colorenergy, "color by energy", 0, 320, 350, 260);
00727 
00728     // Track particles:
00729 
00730     set_diag_item(tracking, "track particles", 0, 320, 350, 220);
00731 
00732     // lux_draw_palette(dia);
00733 
00734     // OK/cancel:
00735 
00736     lux_set_item(dia, ok, BUTTON_WINDOW, OK_BUTTON,
00737                  _R_(100), _R_(25), 9, "OK, CLEAR");
00738     lux_set_item(dia, ok_keep, BUTTON_WINDOW, OK_KEEP_BUTTON,
00739                  _R_(250), _R_(25), 8, "OK, KEEP");
00740     lux_set_item(dia, cancel, BUTTON_WINDOW, CANCEL_BUTTON,
00741                  _R_(400), _R_(25), 6, "CANCEL");
00742 
00743     r_factor = save;
00744 }
00745 
00746 local void make_relative_to_root(DYN* b)
00747 {
00748     vector root_pos = b->get_pos();
00749     vector root_vel = b->get_vel();
00750     for_all_nodes(DYN, b, bi) {
00751         bi->inc_pos(-root_pos);
00752         bi->inc_vel(-root_vel);
00753     }
00754 }
00755 
00756 local void update_diag_item(int which)
00757 {
00758     set_temp_buffer(which);
00759     lux_update_itemvalue(dia, which, type(which), subtype(which),
00760                          temp_buffer);
00761 }
00762 
00763 local void get_diag_string(int which) {
00764 }
00765 
00766 // Overloaded function:
00767 
00768 local void read_diag_item(int which, float& f)
00769 {
00770     lux_get_itemvalue(dia, which, type(which), subtype(which),
00771                       temp_buffer);
00772     sscanf(temp_buffer, "%f", &f);
00773 }
00774 
00775 local void read_diag_item(int which, int& i)
00776 {
00777     lux_get_itemvalue(dia, which, type(which), subtype(which),
00778                       temp_buffer);
00779     sscanf(temp_buffer, "%d", &i);
00780 }
00781 
00782 local void read_diag_item(int which, char& c)
00783 {
00784     lux_get_itemvalue(dia, which, type(which), subtype(which),
00785                       temp_buffer);
00786     c = temp_buffer[0];
00787 }
00788 
00789 local void update_from_dialog(bool r_flag)
00790 {
00791     // Read all data from the dialog box.  Note that it is
00792     // important that the box be maintained correctly.
00793     // Any errors in the data displayed in the box will be
00794     // propogated to the "real" data by this procedure.
00795 
00796     read_diag_item(view2D, kproj);
00797     if (kproj == 1)
00798         kx = 1, ky = 2;
00799     else if (kproj == 2)
00800         kx = 2, ky = 0;
00801     else
00802         kx = 0, ky = 1;
00803 
00804     read_diag_item(originstar, origin_star);
00805 
00806     read_diag_item(Xorigin, origin[0]);
00807     read_diag_item(Yorigin, origin[1]);
00808     read_diag_item(Zorigin, origin[2]);
00809 
00810     read_diag_item(lmax3D, lmax3d);
00811     lmax3d /= 2;                        // display twice lmax3d
00812 
00813     // ------------------------------------------------------
00814 
00815     // NOTE: xmin, xmax, ymin, ymax are IRRELEVANT, since they
00816     // will be forced to be consistent with origin and lmax3d.
00817 
00818     read_diag_item(xminimum, xmin);
00819     read_diag_item(xmaximum, xmax);
00820     read_diag_item(yminimum, ymin);
00821     read_diag_item(ymaximum, ymax);
00822 
00823     set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
00824 
00825     // Make sure entries in the dialog box are consistent:
00826 
00827     update_diag_item(xminimum);
00828     update_diag_item(xmaximum);
00829     update_diag_item(yminimum);
00830     update_diag_item(ymaximum);
00831 
00832     // ------------------------------------------------------
00833 
00834     read_diag_item(basepointsize,base_point_size);
00835 
00836     read_diag_item(theta3D, theta);
00837     costheta = cos(theta);
00838     sintheta = sin(theta);
00839 
00840     read_diag_item(phi3D, phi);
00841     cosphi = cos(phi);
00842     sinphi = sin(phi);
00843 
00844     read_diag_item(dtheta3D, dtheta);
00845 
00846     read_diag_item(DelayTime, delay_time);
00847     if (delay_time < MIN_DELAY) delay_time = MIN_DELAY;
00848 
00849     read_diag_item(colorenergy, cenergy);
00850     show_color_scheme(colwin, c_energy, c_index,
00851                       r_factor, cenergy, r_flag, 1);
00852 
00853     read_diag_item(tracking, track);
00854     read_diag_item(graph3dim, graph3d);
00855 
00856     lux_clear_window(win);
00857 
00858     if (graph3d) {
00859         lux_setup_axis(win, -FAC3D*lmax3d, FAC3D*lmax3d, 
00860                             -FAC3D*lmax3d, FAC3D*lmax3d);
00861         draw3d_axis(win, lmax3d, costheta, sintheta,
00862                     cosphi, sinphi);
00863     } else {
00864         lux_setup_axis(win, xmin, xmax, ymin, ymax);
00865         draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
00866     }
00867 
00868     read_diag_item(pointscalemode, point_scale_mode);
00869 }
00870 
00871 local void show_static_rotation(DYN* b, bool f_flag)
00872 {
00873     // Handle static rotation using lux_check_keypress:
00874 
00875     show_instructions(instr, r_factor,
00876                       "Pause...\n  r: rotate, (p,c): continue                ",
00877                       1);
00878 
00879     char rotate = 0;
00880     do {
00881         if (lux_check_keypress(win,'r')) {
00882             show_instructions(instr, r_factor,
00883                       "Rotate... p: pause, c: continue, c: exit rotation     ",
00884                               0);
00885             rotate = 1;
00886 
00887             do {
00888                 theta += dtheta;
00889                 if (theta < 0.0)
00890                     theta += 2*PI;
00891                 else if (theta > PI*2)
00892                     theta -= 2*PI;
00893                 costheta = cos(theta);
00894                 sintheta = sin(theta);
00895                 update_diag_item(theta3D);
00896 
00897                 lux_clear_current_region(win);
00898                 draw3d_axis(win, lmax3d, costheta, sintheta,
00899                             cosphi, sinphi);
00900 
00901                 for_all_leaves(DYN, b, bi) {
00902 
00903                     float X = (float)bi->get_pos()[0] - origin[0];
00904                     float Y = (float)bi->get_pos()[1] - origin[1];
00905                     float Z = (float)bi->get_pos()[2] - origin[2];
00906 
00907                     float actual_point_size = get_point_size(bi);
00908 
00909                     if (   (X > (-lmax3d + actual_point_size))
00910                         && (X < ( lmax3d - actual_point_size)) 
00911                         && (Y > (-lmax3d + actual_point_size))
00912                         && (Y < ( lmax3d - actual_point_size)) 
00913                         && (Z > (-lmax3d + actual_point_size))
00914                         && (Z < ( lmax3d - actual_point_size))){
00915 
00916                         float r, s;
00917                         project3d(X, Y, Z, r, s,
00918                                   costheta, sintheta,
00919                                   cosphi, sinphi);
00920 
00921                         if (cenergy) {
00922                             char c;
00923                             compute_energies(b, bi, c);
00924                             lux_set_color(win,c_energy[c]);
00925                         } else if (clean_index(bi)>0) {
00926                             if (clean_index(bi) <= N_COLORS)
00927                                 lux_set_color(win,
00928                                               c_index[clean_index(bi)]);
00929                             else
00930                                 lux_set_color(win,c_index[1]);
00931                         }
00932 
00933                         if (track) 
00934                             lux_draw_pointf(win,r,s);
00935                         else
00936                             if (f_flag)
00937                                 lux_fill_arcf(win,
00938                                               r - actual_point_size/2,
00939                                               s - actual_point_size/2, 
00940                                               actual_point_size,
00941                                               actual_point_size,
00942                                               0.0, 360.0);
00943                             else
00944                                 lux_draw_arcf(win,
00945                                               r - actual_point_size/2,
00946                                               s - actual_point_size/2, 
00947                                               actual_point_size,
00948                                               actual_point_size,
00949                                               0.0, 360.0);
00950                     }
00951                 }
00952                 update_with_delay(win, max(MIN_DELAY, delay_time));
00953 
00954                 if (lux_check_keypress(win,'p')) 
00955                     while(!lux_check_keypress(win,'c'));
00956 
00957             } while(!lux_check_keypress(win,'c'));
00958 
00959             // Flush "c"s from input stream:
00960 
00961             while(lux_check_keypress(win,'c'));
00962         }
00963 
00964     } while(!lux_check_keypress(win,'p')
00965             && !lux_check_keypress(win,'c') && !rotate);
00966 
00967     rotate = 0;
00968     lux_set_color(win,c_energy[default_color]);
00969 }
00970 
00971 local char check_for_input(unsigned long win, DYN* b,
00972                            real &t, real &dt, bool &E_flag,
00973                            bool r_flag, bool f_flag, bool eod)
00974 {
00975     // Check for (and immediately act upon) interactive input.
00976     // Loop through the input buffer until no more events remain.
00977 
00978     // lux_next_keypress gets and discards the next key in the input stream.
00979 
00980     char key, string[20], shift, control;
00981     bool key_pressed = false;
00982 
00983     while (lux_next_keypress(win, &key, string, &shift, &control)) {
00984 
00985         // A "defined" key has been pressed.  See if it is one we want.
00986 
00987         key_pressed = true;
00988 
00989         if (key == 0                    // key = 0 for non-ASCII character
00990                                         // e.g. Up, Down, Home, etc.--see win.c
00991             || key == 'h'
00992             || key == 'a') {
00993 
00994             // "Shift" functions:
00995 
00996             int change = 0;
00997 
00998             if (key == 'h')             // keyboard lookalikes for
00999                 change = 4;             // function keys
01000             else if (key == 'a')
01001                 change = 5;
01002 
01003             else if (strcmp(string, "Up") == 0) {
01004                 change = ky + 1;
01005                 origin[ky] += lmax3d/2;
01006             } else if (strcmp(string, "Down") == 0) {
01007                 change = ky + 1;
01008                 origin[ky] -= lmax3d/2;
01009             } else if (strcmp(string, "Right") == 0) {
01010                 change = kx + 1;
01011                 origin[kx] += lmax3d/2;
01012             } else if (strcmp(string, "Left") == 0) {
01013                 change = kx + 1;
01014                 origin[kx] -= lmax3d/2;
01015             } else if (strcmp(string, "PgUp") == 0) {
01016                 change = kproj;
01017                 origin[kproj-1] += lmax3d/2;
01018             } else if (strcmp(string, "PgDn") == 0) {
01019                 change = kproj;
01020                 origin[kproj-1] -= lmax3d/2;
01021             } else if (strcmp(string, "Home") == 0)
01022                 change = 4;
01023             else if (strcmp(string, "R11") == 0)
01024                 change = 5;
01025 
01026             if (change) {
01027 
01028                 if (change == 4) {
01029                     origin[kx] = origin[ky] = origin[kproj-1] = 0;
01030                 } else if (change == 5) {
01031 
01032                     real save = lmax3d;
01033                     lmax3d = 0;
01034 
01035                     // Use all dimensions in redetermining the scale!
01036 
01037                     for_all_leaves(DYN, b, bi)
01038                         for (int kk = 0; kk < 3; kk++)
01039                             lmax3d = max(lmax3d, abs(bi->get_pos()[kk]
01040                                                      - local_offset[kk]));
01041                 
01042                     // Round lmax3d up to something reasonable:
01043                 
01044                     lmax3d *= 1.2;
01045                     if (lmax3d <= 0) lmax3d = 1;
01046                 
01047                     real m_log = log10(lmax3d);
01048                     int i_log = (int) m_log;
01049                     if (m_log - i_log > 0.699) i_log++;
01050                     real scale = pow(10.0, i_log);
01051                     lmax3d = ((int) (lmax3d/scale) + 1) * scale;
01052 
01053                     origin[kx] = origin[ky] = origin[kproj-1] = 0;              
01054                     base_point_size *= lmax3d/save;
01055                 }
01056 
01057                 set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01058 
01059                 // Update all entries in the dialog box, as needed:
01060 
01061                 update_diag_item(xminimum);
01062                 update_diag_item(xmaximum);
01063                 update_diag_item(yminimum);
01064                 update_diag_item(ymaximum);
01065 
01066                 if (change == 1 || change >= 4) update_diag_item(Xorigin);
01067                 if (change == 2 || change >= 4) update_diag_item(Yorigin);
01068                 if (change == 3 || change >= 4) update_diag_item(Zorigin);
01069 
01070                 if (change == 5) {
01071                     update_diag_item(basepointsize);
01072                     update_diag_item(lmax3D);
01073                 }
01074 
01075                 // No redrawing of axes is needed for 3D graphs for change != 5.
01076                 
01077                 if (!graph3d) {
01078                     lux_clear_window(win);
01079                     lux_setup_axis(win, xmin, xmax, ymin, ymax);
01080                     draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01081                 } else if (change == 5) {
01082                     lux_clear_window(win);
01083                     lux_setup_axis(win, -FAC3D*lmax3d, FAC3D*lmax3d, 
01084                                    -FAC3D*lmax3d, FAC3D*lmax3d);
01085                     draw3d_axis(win, lmax3d, costheta, sintheta,
01086                                 cosphi, sinphi);
01087                 }
01088             }
01089 
01090         } else {                        // key is the ASCII code
01091 
01092             // Check for "quit" first.
01093 
01094             if (key == 'q') {
01095                 show_instructions(instr, r_factor,
01096                     "\n   Quitting...                                        ",
01097                                   1);
01098                 lux_exit();             // note that this is now quick_exit
01099             }
01100 
01101             //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01102 
01103             if (graph3d && !track) {
01104                 int button;
01105 
01106                 // 3-D operations:
01107 
01108                 if (key== 'R') {
01109 
01110                     show_static_rotation(b, f_flag);
01111 
01112                 } else {
01113 
01114                     button = lux_check_buttonpress(win);
01115 
01116                     if (key == '^') {
01117                         phi = phi - dtheta;
01118                         if (phi < -PI) phi = phi + 2.0*PI;
01119                         cosphi = cos(phi);
01120                         sinphi = sin(phi);
01121                         update_diag_item(phi3D);
01122                     } else if (key == 'V') {
01123                         phi = phi + dtheta;
01124                         if (phi > PI) phi = phi - 2.0*PI;
01125                         cosphi = cos(phi);
01126                         sinphi = sin(phi);
01127                         update_diag_item(phi3D);
01128                     } else if (key == '<') {
01129                         theta = theta + dtheta;
01130                         if (theta > 2*PI) theta -= 2*PI;
01131                         costheta = cos(theta);
01132                         sintheta = sin(theta);
01133                         update_diag_item(theta3D);
01134                     } else if (key == '>') {
01135                         theta = theta - dtheta;
01136                         if (theta < 0.0) theta += 2*PI;
01137                         costheta = cos(theta);
01138                         sintheta = sin(theta);
01139                         update_diag_item(theta3D);
01140                     }
01141                 }
01142             }
01143 
01144             //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
01145 
01146             if (key == 'p' || key == 'P') {     // modify base point size
01147 
01148                 if (key == 'p') {
01149                     if (base_point_size > 4*lmax3d/win_size)
01150                         base_point_size /= PFAC;
01151                 } else
01152                     base_point_size *= PFAC;
01153 
01154                 update_diag_item(basepointsize);
01155 
01156             } else if (key == 'm') {            // toggle multiple display
01157 
01158                 multiples = 1 - multiples;
01159                 if (multiples == 1) nodes = 1;
01160 
01161             } else if (key == 'n') {            // toggle tree display
01162 
01163                 nodes = 1 - nodes;
01164                 if (nodes == 0) links = 0;
01165 
01166             } else if (key == 'l') {            // toggle links/nodes
01167 
01168                 links = 1 - links;
01169                 if (links == 1) nodes = 1;
01170 
01171             } else if (key == 'r') {            // show root node
01172 
01173                 root = 1 - root;
01174 
01175             } else if (key == 't') {            // toggle tracking
01176 
01177                 track = 1 - track;
01178                 update_diag_item(tracking);
01179 
01180             } else if (key == 'u') {            // toggle unperturbed display
01181 
01182                 unperturbed = 1 - unperturbed;
01183 
01184             } else if (key == '3' && !graph3d) {    // enter 3D mode
01185 
01186                 graph3d = 1;
01187                 update_diag_item(graph3dim);
01188                 lux_clear_window(win);
01189                 lux_setup_axis(win, -FAC3D*lmax3d, FAC3D*lmax3d, 
01190                                -FAC3D*lmax3d, FAC3D*lmax3d);
01191                 draw3d_axis(win, lmax3d, costheta, sintheta, cosphi, sinphi);
01192 
01193                 // Refresh the color window.
01194 
01195 //              show_color_scheme(colwin, c_energy, c_index,
01196 //                                r_factor, cenergy, r_flag, 1);
01197 
01198             } else if (graph3d &&
01199                        (key == '2' || key == 'x'
01200                           || key == 'y' || key == 'k')) {   // enter 2D mode
01201 
01202                 graph3d = 0;
01203                 update_diag_item(graph3dim);
01204                 lux_clear_window(win);
01205                 lux_setup_axis(win, xmin, xmax, ymin, ymax);
01206                 draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01207 
01208                 // Refresh the color window.
01209 
01210 //              show_color_scheme(colwin, c_energy, c_index,
01211 //                                r_factor, cenergy, r_flag, 1);
01212 
01213             } else if (key == 'E') {            // toggle escaper display
01214 
01215                 E_flag = !E_flag;
01216 
01217             } else if (key == 'e') {            // color by energy
01218 
01219                 cenergy = !cenergy;
01220                 update_diag_item(colorenergy);
01221                 show_color_scheme(colwin, c_energy, c_index,
01222                                   r_factor, cenergy, r_flag, 1);
01223 
01224             } else if (key == '*') {            // increase dt
01225 
01226 //#define DTFAC 1.77827941003892275873          // fourth root of 10
01227 #define DTFAC   1.41421356237309514547          // square root of 2
01228 
01229                 dt *= DTFAC;
01230 
01231             } else if (key == '/') {            // decrease dt
01232 
01233                 dt /= DTFAC;
01234 
01235             } else if (key == '\\') {           // reverse dt
01236 
01237                 dt = -dt;
01238 
01239             } else if (key == 'j') {
01240 
01241                 cerr << "jump to time: " << flush;
01242                 cin >> t;
01243                 t -= dt;
01244                 return 'j';
01245 
01246             } else if (key == 'J') {
01247 
01248                 cerr << "time, dt: " << flush;
01249                 cin >> t >> dt;
01250                 t -= dt;
01251                 return 'J';
01252 
01253             } else if (key == '>') {
01254 
01255                 max_cm *= 2;
01256 
01257             } else if (key == '<') {
01258 
01259                 max_cm /= 2;
01260 
01261             } else if (key == '+' || key == '=') {    // increase delay time
01262 
01263                 delay_time *= 2;
01264                 update_diag_item(DelayTime);
01265 
01266             } else if (key == '-') {            // decrease delay time
01267 
01268                 delay_time /= 2;
01269                 if (delay_time < MIN_DELAY) delay_time = MIN_DELAY;
01270                 update_diag_item(DelayTime);
01271 
01272             } else if (key == '0') {            // set delay time = "0"
01273 
01274                 delay_time = MIN_DELAY;
01275                 update_diag_item(DelayTime);
01276 
01277                 // Flush the queue:
01278 
01279                 while(lux_check_keypress(win,'+')
01280                       || lux_check_keypress(win,'-'));
01281 
01282             } else if (key == 'R') {            // color by energy
01283 
01284                 show_color_scheme(colwin, c_energy, c_index,
01285                                   r_factor, cenergy, r_flag, 1);
01286 
01287             } else if (key == 'z') {            // zoom in
01288                                                 // (fixed axes and origin)
01289 
01290                 lmax3d /= ZOOM;
01291                 set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01292                 base_point_size /= ZOOM;
01293 
01294                 if (graph3d) {
01295                     lux_clear_window(win);
01296                     lux_setup_axis(win,-FAC3D*lmax3d,FAC3D*lmax3d, 
01297                                    -FAC3D*lmax3d, FAC3D*lmax3d);
01298                     draw3d_axis(win, lmax3d, costheta, sintheta,
01299                                 cosphi, sinphi);
01300                 } else {
01301                     lux_clear_window(win);
01302                     lux_setup_axis(win, xmin, xmax, ymin, ymax);
01303                     draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01304                 }
01305 
01306                 update_diag_item(basepointsize);
01307                 update_diag_item(lmax3D);
01308                 update_diag_item(xminimum);
01309                 update_diag_item(xmaximum);
01310                 update_diag_item(yminimum);
01311                 update_diag_item(ymaximum);
01312 
01313             } else if (key == 'Z') {            // zoom out
01314 
01315                 lmax3d *= ZOOM;
01316                 set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01317                 base_point_size *= ZOOM;
01318 
01319                 if (graph3d) {
01320                     lux_clear_window(win);
01321                     lux_setup_axis(win, -FAC3D*lmax3d, FAC3D*lmax3d, 
01322                                    -FAC3D*lmax3d, FAC3D*lmax3d);
01323                     draw3d_axis(win, lmax3d, costheta, sintheta,
01324                                 cosphi, sinphi);
01325                 } else {
01326                     lux_clear_window(win);
01327                     lux_setup_axis(win, xmin, xmax, ymin, ymax);
01328                     draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01329                 }
01330 
01331                 update_diag_item(basepointsize);
01332                 update_diag_item(lmax3D);
01333                 update_diag_item(xminimum);
01334                 update_diag_item(xmaximum);
01335                 update_diag_item(yminimum);
01336                 update_diag_item(ymaximum);
01337 
01338             } else if (key == 'k') {            // change projection axis to z
01339                                                 // (fixed origin, scale)
01340                 if (graph3d) {
01341 
01342                     theta = -PI/2;
01343                     phi = PI/2.0;
01344                     costheta = cos(theta);
01345                     sintheta = sin(theta);
01346                     cosphi = cos(phi);
01347                     sinphi = sin(phi);
01348 
01349                     update_diag_item(theta3D);
01350                     update_diag_item(phi3D);
01351 
01352                     while (lux_check_keypress(win,'<')
01353                            || lux_check_keypress(win,'>')
01354                            || lux_check_keypress(win,'^')
01355                            || lux_check_keypress(win,'V') );
01356 
01357                 } else {
01358 
01359                     kproj = 3;
01360                     kx = 0;
01361                     ky = 1;
01362                     set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01363                     lux_clear_window(win);
01364                     lux_setup_axis(win, xmin, xmax, ymin, ymax);
01365                     draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01366 
01367                     update_diag_item(view2D);
01368 
01369                 }
01370 
01371             } else if (key == 'y') {            // change projection axis to y
01372 
01373                 if (graph3d) {
01374 
01375                     theta = -PI/2.0;
01376                     phi = 0.0;
01377                     costheta = cos(theta);
01378                     sintheta = sin(theta);
01379                     cosphi = cos(phi);
01380                     sinphi = sin(phi);
01381 
01382                     while (lux_check_keypress(win,'<')
01383                            || lux_check_keypress(win,'>')
01384                            || lux_check_keypress(win,'^')
01385                            || lux_check_keypress(win,'V') );
01386 
01387                     update_diag_item(theta3D);
01388                     update_diag_item(phi3D);
01389 
01390                 } else {
01391 
01392                     kproj = 2;
01393                     kx = 2;
01394                     ky = 0;
01395                     set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01396                     lux_clear_window(win);
01397                     lux_setup_axis(win, xmin, xmax, ymin, ymax);
01398                     draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01399 
01400                     update_diag_item(view2D);
01401 
01402                 }
01403 
01404             } else if (key == 'x') {            // change projection axis to x
01405 
01406                 if (graph3d) {
01407                     theta = 0.0;
01408                     phi = 0.0;
01409                     costheta = cos(theta);
01410                     sintheta = sin(theta);
01411                     cosphi = cos(phi);
01412                     sinphi = sin(phi);
01413 
01414                     while (lux_check_keypress(win,'<')
01415                            || lux_check_keypress(win,'>')
01416                            || lux_check_keypress(win,'^')
01417                            || lux_check_keypress(win,'V') );
01418 
01419                     update_diag_item(theta3D);
01420                     update_diag_item(phi3D);
01421 
01422                 } else {
01423 
01424                     kproj = 1;
01425                     kx = 1;
01426                     ky = 2;
01427                     set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01428                     lux_clear_window(win);
01429                     lux_setup_axis(win, xmin, xmax, ymin, ymax);
01430                     draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01431 
01432                     update_diag_item(view2D);
01433 
01434                 }
01435             }
01436 
01437             // Select new origin: 'o' ==> point in space, 'O' ==> star
01438 
01439             if (key == 'o' && !graph3d) {
01440 
01441                 show_instructions(instr, r_factor,
01442                 " Use mouse-right to select new origin...\n",1);
01443                 float r, s;
01444                 get_mouse_position(win, &r, &s);
01445 
01446                 // Looks like r and s come back in the correct units!
01447 
01448                 origin[kx] = r;
01449                 origin[ky] = s;
01450                 set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01451 
01452                 lux_clear_window(win);
01453                 lux_setup_axis(win, xmin, xmax, ymin, ymax);
01454                 draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01455 
01456                 origin_star = -1;
01457 
01458                 update_diag_item(Xorigin);
01459                 update_diag_item(Yorigin);
01460                 update_diag_item(Zorigin);
01461                 update_diag_item(xminimum);
01462                 update_diag_item(xmaximum);
01463                 update_diag_item(yminimum);
01464                 update_diag_item(ymaximum);
01465                 update_diag_item(originstar);
01466 
01467             } else if (!graph3d && key == 'O') {
01468 
01469                 show_instructions(instr, r_factor,
01470                 " Use mouse-right to select new origin star...\n",1);
01471                 float r, s;
01472                 get_mouse_position(win, &r, &s);
01473 
01474                 // Looks like r and s come back in the correct units!
01475 
01476                 // Find the star closest to the (2-D) mouse position.
01477 
01478                 origin_star = nearest_index(b, r, s, kx, ky);
01479 
01480                 if (origin_star > 0) {
01481                     for (int kk = 0; kk < 3; kk++) origin[kk] = 0;
01482                     set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01483                 }
01484 
01485                 lux_clear_window(win);
01486                 lux_setup_axis(win, xmin, xmax, ymin, ymax);
01487                 draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01488 
01489                 update_diag_item(Xorigin);
01490                 update_diag_item(Yorigin);
01491                 update_diag_item(Zorigin);
01492                 update_diag_item(xminimum);
01493                 update_diag_item(xmaximum);
01494                 update_diag_item(yminimum);
01495                 update_diag_item(ymaximum);
01496                 update_diag_item(originstar);
01497 
01498             } else if (key == 'b' || key == 'B') {
01499 
01500                 return 'b';
01501 
01502             } else if (key == 'c' || key == 'C') {
01503 
01504                 return 'c';
01505 
01506             } else if (key == 'f' || key == 'F' || key == 's' || key == 'S') {
01507 
01508                 return 'f';
01509 
01510             }
01511 
01512             // -------------------------------------------------------------
01513 
01514             while(lux_check_keypress(win,'r'));  // clean up any replay garbage
01515 
01516             // Idle mode and dialog box input:
01517 
01518             int return_value = 0;
01519 
01520             if (key == 'i') {
01521 
01522                 show_instructions(instr, r_factor,
01523                   " Idle...\n  d: dialog, r: replay, c: continue, q: quit",1);
01524                 return_value = lux_getevent();
01525 
01526             } else if (key == 'd') {
01527 
01528                 show_instructions(instr, r_factor,
01529 "Dialog mode keyboard options\n\n\
01530   Dialog window:\n\
01531     o   OK, keep dialog window\n\
01532     O   OK, close dialog window\n\
01533     c   CANCEL, keep dialog window\n\
01534     C   CANCEL, close dialog window\n\n\
01535   Other windows:\n\
01536     r   replay\n\
01537     c   continue (keep dialog window,\n\
01538                   ignore dialog changes)\n\
01539     q   quit\n\
01540 ",1);
01541                 lux_show_dialog(dia);
01542                 return_value = lux_getevent();
01543             }
01544             
01545             // Update all values if OK button was clicked (clicking
01546             // OK forces a return value of 3).
01547             
01548             if (return_value == 3) update_from_dialog(r_flag);
01549 
01550         }
01551     }
01552 
01553     if (key_pressed) {
01554 
01555         // Hitting any key will cause the instruction and color
01556         // windows to be updated immediately.
01557 
01558         show_main_instructions(instr, r_factor, graph3d, 1, eod,
01559                                nodes, links, multiples, unperturbed, root);
01560         show_color_scheme(colwin, c_energy, c_index,
01561                           r_factor, cenergy, r_flag, 1);
01562 
01563         return ' ';
01564     }
01565 
01566     return 0;
01567 }
01568 
01569 /*-----------------------------------------------------------------------------
01570  *  xstarplot22.C  --  project the positions of all particles onto the screen
01571  *                    input:   pn: a pointer to a nbody system,
01572  *                              k: the number of the coordinate axis along which
01573  *                                 the projection is directed, with {k,x,y}
01574  *                                 having a right-handed orientation,
01575  *                            xmax: displayed x-axis spans [-xmax, xmax]
01576  *                            ymax: displayed y-axis spans [-ymax, ymax]
01577  *-----------------------------------------------------------------------------
01578  */
01579 
01580 #define INSTR_FREQ_MAX 32
01581 #define INSTR_FREQ_FAC 64
01582 static int instr_freq = INSTR_FREQ_MAX;
01583 static int count_instr = 0;
01584 
01585 void xstarplot22(DYN* b, float scale, int k, int d, float lmax,
01586                 int point_mode, float rel_point_size,
01587                 real &t, real &dt, float D, int ce,
01588                 bool &E_flag, bool r_flag, bool f_flag, bool t_flag,
01589                 int init_flag, int& step_mode, bool eod)
01590 {
01591     if (!b) return;
01592 
01593     r_factor = scale;
01594 
01595     if (!eod && init_flag == 0) {
01596 
01597         int xorigin, yorigin;
01598 
01599         if (t_flag) nodes = links = 1;
01600 
01601         // Open windows for plotting and instructions, set up color
01602         // schemes, etc.
01603 
01604         if (init_status == 0) initialize_graphics(r_factor, r_flag,
01605                                                   win, instr, colwin,
01606                                                   c_index, c_energy,
01607                                                   win_size, xorigin, yorigin);
01608         lux_clear_window(win);
01609         lux_update_fg(win);
01610         lux_clear_window(colwin);
01611         lux_update_fg(colwin);
01612         lux_clear_window(instr);
01613         lux_update_fg(instr);
01614 
01615         // Determine which axes to plot:
01616 
01617         kproj = k;
01618         switch (kproj) {
01619             case 1:     kx = 1; ky = 2; graph3d = 0; break;
01620             case 2:     kx = 2; ky = 0; graph3d = 0; break;
01621             case 3:     kx = 0; ky = 1; graph3d = 0; break;
01622             default:    cerr << "xstarplot22: k = " << k
01623                              << ": illegal value; choose from {1, 2, 3}"
01624                              << endl;
01625                         exit(0);
01626         }
01627 
01628         switch(d) {
01629             case 2:     graph3d = 0;  break;
01630             case 3:     graph3d = 1;  break;
01631             default:    cerr << "xstarplot22: d = " << d
01632                              << " illegal value; choose from {2, 3)"
01633                              << endl;
01634                         exit(0);
01635         }
01636 
01637         point_scale_mode = point_mode;
01638 
01639         cenergy = ce?1:0;
01640         show_color_scheme(colwin, c_energy, c_index,
01641                           r_factor, cenergy, r_flag, 1);
01642 
01643         delay_time = D;
01644 
01645         if (lmax > 0.0)
01646 
01647             lmax3d = lmax;
01648 
01649         else {
01650 
01651             lmax3d = 0;
01652 
01653             // Use all dimensions in determining the initial scale!
01654 
01655             for_all_leaves(DYN, b, bi)
01656                 for (int kk = 0; kk < 3; kk++)
01657                     lmax3d = max(lmax3d, abs(bi->get_pos()[kk]));
01658 
01659             // Round lmax3d up to something reasonable:
01660 
01661             lmax3d *= 1.2;
01662 
01663             // Hmmm...  Maybe we should exclude some outliers.
01664 
01665             lmax3d /= 2;
01666 
01667             if (lmax3d <= 0) lmax3d = 1;
01668 
01669             real m_log = log10(lmax3d);
01670             int i_log = (int) m_log;
01671             if (m_log - i_log > 0.699) i_log++;
01672             real scale = pow(10.0, i_log);
01673             lmax3d = ((int) (lmax3d/scale) + 1) * scale;
01674         }
01675 
01676         for (int ko = 0; ko < 3; ko++)
01677             origin[ko] = 0;
01678 
01679         set_limits(origin, lmax3d, kx, xmin, xmax, ky, ymin, ymax);
01680         set_base_point_size(b, rel_point_size);
01681         
01682         if (graph3d) {
01683             lux_setup_axis(win, -FAC3D*lmax3d, FAC3D*lmax3d, 
01684                            -FAC3D*lmax3d, FAC3D*lmax3d);      
01685             draw3d_axis(win, lmax3d, costheta, sintheta, cosphi, sinphi);
01686         } else {
01687             lux_setup_axis(win, xmin, xmax, ymin, ymax);
01688             draw2d_axis(win, xmin, xmax, ymin, ymax, kproj);
01689         }
01690 
01691         // Complete the initialization with the dialog box.
01692 
01693         if (init_status == 0)
01694             initialize_dialog(xorigin, yorigin);
01695 
01696         init_status = 1;
01697             
01698     }
01699 
01700     //------------------------------------------------------------------------
01701 
01702     // End of initialization or start of next plot.
01703     // Delete current points, and possibly redraw axes and instructions.
01704 
01705     if (track == 0) {
01706         lux_clear_current_region(win);
01707         if (graph3d) draw3d_axis(win, lmax3d, costheta, sintheta,
01708                                  cosphi, sinphi);
01709     }
01710 
01711     if (!eod) {
01712 
01713         // Showing these instructions too frequently causes malloc problems
01714         // in lux_draw_image_string (for unknown reasons; possibly this is
01715         // a timing problem of some sort with the X display).
01716         //
01717         // Work around the problem by reducing the display frequency.
01718         // See also gfx_util for further limitations.
01719 
01720         instr_freq = INSTR_FREQ_FAC / b->n_leaves();
01721         if (instr_freq > INSTR_FREQ_MAX) instr_freq = INSTR_FREQ_MAX;
01722         if (instr_freq < 1) instr_freq = 1;
01723 
01724         if (count_instr++%instr_freq == 0)
01725             show_main_instructions(instr, r_factor, graph3d, 1, eod,
01726                                    nodes, links, multiples, unperturbed, root);
01727     }
01728 
01729     //------------------------------------------------------------------------
01730 
01731     // Always express all positions and velocities relative to the root node.
01732     // (There is no requirement that the root node be at rest at the origin...)
01733 
01734     make_relative_to_root(b);
01735 
01736     // Determine local offset, if any.
01737 
01738     if (origin_star > 0) {
01739         for_all_leaves(DYN, b, bi)
01740             if (clean_index(bi) == origin_star) {
01741                 for (int kk = 0; kk < 3; kk++)
01742                     local_offset[kk] = bi->get_pos()[kk];
01743                 break;
01744             }
01745     } else
01746         for (int kk = 0; kk < 3; kk++)
01747             local_offset[kk] = 0;
01748 
01749     // Plot the data points (sorted by kproj-component in the 2D case):
01750 
01751     int n_stars = plot_all_stars(b, f_flag);
01752 
01753     // Update headers.
01754 
01755     lux_set_color(win, c_energy[default_color]);
01756 
01757     if (graph3d) {
01758 
01759         //sprintf(temp_buffer, "   N = %d (snapshot #%5d) max=%5.3f   ",
01760         //      n_stars, init_flag + 1, lmax3d);
01761         sprintf(temp_buffer, "   N = %d (t = %.6f) max=%5.3f   ",
01762                 n_stars, b->get_real_system_time(), lmax3d);
01763         lux_draw_image_string(win, 0.0, lmax3d*FAC3D, 0.5, temp_buffer, 0);
01764 
01765     } else {
01766 
01767         //sprintf(temp_buffer, "   N = %d  (snapshot #%5d)   ",
01768         //      n_stars, init_flag + 1);
01769         sprintf(temp_buffer, "   N = %d  (t = %.6f)   ",
01770                 n_stars, b->get_real_system_time());
01771         lux_draw_image_string(win, (xmin+xmax)/2.0, ymax, 0.5, temp_buffer, 0);
01772 
01773     }
01774 
01775     // Update the display.
01776 
01777     update_with_delay(win, max(MIN_DELAY, delay_time));
01778 
01779     // Deal with user input.  In step mode, wait for
01780     // 'b', 'c', or 's' before continuing.
01781 
01782     while (true) {
01783 
01784         char c = check_for_input(win, b, t, dt, E_flag, r_flag, f_flag, eod);
01785 
01786         // Special treatment required for forward/backward step modes.
01787 
01788         if (c == 'b' || c == 'f') {             // Enter/continue step mode
01789 
01790             step_mode = (c == 'b' ? -1 : 1);
01791             return;
01792 
01793         } else if (c == 'c') {                  // Cancel step mode
01794 
01795             if (eod)
01796                 step_mode = 1;
01797             else
01798                 step_mode = 0;
01799 
01800             return;
01801 
01802         } else if (c == 'j' || c == 'J') {
01803 
01804             step_mode = 1;
01805             return;
01806         }
01807 
01808         // In eod mode, hitting 'b' or 'f' will go to a new frame.
01809         // Hitting any other key will cause the current frame to be
01810         // redisplayed (with any specified changes made).
01811 
01812         if (eod && c != 0) {
01813             step_mode = 0;
01814             return;
01815         }
01816         if (!eod && step_mode == 0) return;
01817 
01818         // Wait for 10 milliseconds before retrying.
01819 
01820         lux_pause(10000);
01821     }
01822 
01823 }
01824 
01825 //======================================================================
01826 
01827 local void print_worldlines(worldbundleptr wh[], int nh)
01828 {
01829     for (int ih = 0; ih < nh; ih++) {
01830         cerr << "worldbundle " << ih << ":" << endl;
01831         wh[ih]->dump(4);
01832     }
01833 }
01834 
01835 local void print_escapes(worldbundleptr wh[], int nh)
01836 {
01837     DYN *b = create_interpolated_tree2(wh[0], 0);
01838     for_all_daughters(DYN, b, bb) {
01839 
01840         PRL(bb->format_label());
01841 
01842         // Follow the complete worldline set (all worldbundles) of bb.
01843 
01844         for (int ih = 0; ih < nh; ih++) {
01845 
01846             worldline *w = wh[ih]->find_worldline(bb);
01847             if (w->get_start_esc_flag() || w->get_end_esc_flag()) {
01848                 PRC(ih); PRL(w->get_t_esc());
01849             }
01850         }
01851     }
01852 }
01853 
01854 /*-----------------------------------------------------------------------------
01855  *  main  --  driver to use  xstarplot22()  as a tool. 
01856  *               The argument -a is interpreted as the axis along which to
01857  *            view the N-body system: the number of the coordinate axis along
01858  *            which the projection is directed, with {k,x,y} having a
01859  *            right-handend orientation.
01860  *               If an argument -l is provided, it defines the maximum
01861  *            lengths along the remaining axes.
01862  *-----------------------------------------------------------------------------
01863  */
01864 
01865 main(int argc, char** argv)
01866 {
01867     // Establish some defaults:
01868 
01869     int   k = 3;                // note x = 1, y = 2, z = 3 here!
01870     int   d = 2;
01871     float D = 16*MIN_DELAY;
01872     real dt = 0.015625;         // powers of 2 are preferred, but not essential
01873     int   cenergy = 0;
01874     float lmax = -1.0;
01875     int   point_mode = 0;
01876     float rel_point_size = 0.5;
01877     float scale = 1.0;
01878 
01879     char infile[128];
01880     strcpy(infile, "run.out");
01881 
01882     bool f_flag = TRUE;         // if TRUE, the star is solid
01883     bool o_flag = FALSE;        // if TRUE, output stdin to stdout
01884     bool r_flag = TRUE;         // if TRUE, the background is black
01885     bool t_flag = FALSE;        // if TRUE, show tree structure
01886     bool E_flag = true;         // if true, show escapers
01887 
01888     int verbose = 0;
01889 
01890     check_help();
01891 
01892     extern char *poptarg;
01893     char* params = "a:bd:D:eEfF:lL:mop:P:rs:tuv.";
01894     int   c;
01895 
01896     while ((c = pgetopt(argc, argv, params)) != -1)
01897         switch(c) {
01898 
01899             case 'a': k = atoi(poptarg);        // projection axis [z]
01900                       break;
01901             case 'd': d = atoi(poptarg);        // number of dimensions [2]
01902                       break;
01903             case 'D': dt = atof(poptarg);       // delay between frames [0.01]
01904                       if (dt < 0)               // usual convention
01905                           dt = pow(2.0, dt);
01906                       break;
01907             case 'e': cenergy = 1;              // color by energy [no]
01908                       break;
01909             case 'E': E_flag = !E_flag;
01910                       break;
01911             case 'f': f_flag = FALSE;           // fill star points [yes]
01912                       break;
01913             case 'F': strcpy(infile, poptarg);
01914                       break;
01915             case 'k': max_cm = atoi(poptarg);   // max CM size (/N) [2]
01916                       break;
01917             case 'L': lmax = atof(poptarg);     // axes +/- lmax [use data]
01918                       break;
01919             case 'l': links = 1 - links;
01920                       nodes = links;
01921                       break;
01922             case 'm': multiples = 1 - multiples;
01923                       break;
01924             case 'o': o_flag = TRUE;            // output stdin to stdout [no]
01925                       break;
01926             case 'p': point_mode = atoi(poptarg);       // point scale mode [0]
01927                       break;
01928             case 'P': rel_point_size = atof(poptarg);   // point scale factor
01929                       if (rel_point_size < 0.5)
01930                           rel_point_size = 0.5;
01931                       break;
01932             case 'r': r_flag = FALSE;           // black background [yes]
01933                       break;
01934             case 's': scale = atof(poptarg);    // rescale display [1.0]
01935                       break;
01936             case 't': t_flag = TRUE;            // show tree links [no]
01937                       break;
01938             case 'u': unperturbed = 1 - unperturbed;
01939                       break;
01940             case 'v': if (poptarg)
01941                           verbose = atoi(poptarg);
01942                       else
01943                           verbose = true;
01944                       break;
01945             case '?': params_to_usage(cerr, argv[0], params);
01946                       get_help();
01947                       exit(0);
01948         }
01949 
01950     ifstream s(infile);
01951     if (!s) {
01952         cerr << "Data file " << infile << " not found." << endl;
01953         exit(1);
01954     }
01955 
01956     // Read in an array of worldbundles (a "worldhistory", when this
01957     // becomes the next level of structure in the world hierarchy).
01958     // Eventually, the display can start as soon as the first
01959     // worldbundle is ready, and the remainder can be read in
01960     // asynchronously.
01961 
01962     worldbundleptr wb, wh[1024];
01963 
01964     int nh = 0;
01965     while (nh < 1024 && (wb = read_bundle(s, verbose))) wh[nh++] = wb;
01966 
01967     // PRL(mass_scale_factor());
01968 
01969     cerr << endl << "statistics on " << nh << " worldbundle";
01970     if (nh != 1) cerr << "s";
01971     cerr << ":" << endl;
01972 
01973     int nwtot = 0, nstot = 0, netot = 0;
01974     for (int ih = 0; ih < nh; ih++) {
01975         wb = wh[ih];
01976         real t = wb->get_t_min();
01977         int nw = wb->get_nw(), ns = count_segments(wb), ne = count_events(wb);
01978         cerr << "worldbundle " << ih << ": "
01979              << nw << " worldlines, "
01980              << ns << " segments, "
01981              << ne << " events, t = "
01982              << wb->get_t_min() << " to " << wb->get_t_max()
01983              << endl;
01984         nwtot += nw;
01985         nstot += ns;
01986         netot += ne;
01987     }
01988     cerr << "totals: " << nwtot << " worldlines, "
01989          << nstot << " segments, " << netot << " events"
01990          << endl << endl;
01991 
01992     // print_worldlines(wh, nh);
01993     // print_escapes(wh, nh);
01994 
01995     set_center(wh, nh, 1, true);
01996     PRC(get_center()); PRL(get_center_id());
01997 
01998     // Now display the data.
01999 
02000     bool eod = false;
02001     int step_mode = 0;
02002     int init = 0;
02003 
02004     int ih = 0;
02005     wb = wh[ih];
02006     real t = wb->get_t_min();
02007 
02008     bool max_cm_set = false;
02009 
02010     while (1) {
02011 
02012         DYN *root = create_interpolated_tree2(wb, t);
02013 
02014         if (!E_flag) {
02015 
02016             // Flag non-members (not switchable at runtime...).
02017 
02018             int n_mem = 0;
02019             for_all_nodes(DYN, root, bb)
02020                 if (bb != root) {
02021                     if (is_member(wb, bb))
02022                         n_mem++;
02023                     else
02024                         bb->set_index(-42);             // or whatever
02025                 }
02026             // PRC(t); PRL(n_mem);
02027         }
02028 
02029         if (!max_cm_set) {
02030             max_cm /= root->n_daughters();
02031             max_cm_set = true;
02032         }
02033 
02034         if (root) {
02035             convert_relative_to_absolute(root);
02036 
02037             real dts = dt;
02038             xstarplot22(root, scale, k, d, lmax,
02039                        point_mode, rel_point_size,
02040                        t, dt, D, cenergy,
02041                        E_flag, r_flag, f_flag, t_flag, init++,
02042                        step_mode, eod);
02043             if (dt != dts) PRL(dt);
02044             //rmtree(root);
02045         }
02046 
02047         t += dt;
02048 
02049         // Move to the next worldbundle, or loop, as necessary.
02050 
02051 #define EPS 1.e-12
02052 
02053         if (dt > 0 && t > wb->get_t_max() + EPS) {
02054             if (++ih >= nh) {
02055                 ih = 0;
02056                 wb = wh[ih];
02057                 t = wb->get_t_min();
02058             } else
02059                 wb = wh[ih];
02060         }
02061 
02062         // May be moving backwards, so check that too.
02063 
02064         if (dt < 0 && t < wb->get_t_min() - EPS) {
02065             if (--ih < 0) {
02066                 ih = nh-1;
02067                 wb = wh[ih];
02068                 t = wb->get_t_max();
02069             } else
02070                 wb = wh[ih];
02071         }
02072 
02073     }
02074 }

Generated at Sun Feb 24 09:57:23 2002 for STARLAB by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001