Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

xstarplot2.C

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

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