Anonymous avatar Anonymous committed d37d9bb

[project @ Arch-1:yminsky@cs.cornell.edu--2004%planets--mainline--1.0--base-0]
initial import

(automatically generated log message)

Comments (0)

Files changed (49)

+collision.cmo: state.cmo 
+collision.cmx: state.cmx 
+constants.cmo: options.cmo 
+constants.cmx: options.cmx 
+display.cmo: augSet.cmo common.cmo constants.cmo help.cmo lstrings.cmo \
+    mTimer.cmo options.cmo physics.cmo saveState.cmi state.cmo 
+display.cmx: augSet.cmx common.cmx constants.cmx help.cmx lstrings.cmx \
+    mTimer.cmx options.cmx physics.cmx saveState.cmx state.cmx 
+fast_physics.cmo: common.cmo constants.cmo mTimer.cmo rk4.cmi state.cmo 
+fast_physics.cmx: common.cmx constants.cmx mTimer.cmx rk4.cmx state.cmx 
+fqueue.cmo: fqueue.cmi 
+fqueue.cmx: fqueue.cmi 
+help.cmo: common.cmo lstrings.cmo saveState.cmi 
+help.cmx: common.cmx lstrings.cmx saveState.cmx 
+options.cmo: augMap.cmo common.cmo lstrings.cmo 
+options.cmx: augMap.cmx common.cmx lstrings.cmx 
+physics.cmo: common.cmo constants.cmo fast_physics.cmo state.cmo 
+physics.cmx: common.cmx constants.cmx fast_physics.cmx state.cmx 
+rk4.cmo: rk4.cmi 
+rk4.cmx: rk4.cmi 
+saveState.cmo: common.cmo state.cmo saveState.cmi 
+saveState.cmx: common.cmx state.cmx saveState.cmi 
+sqrt.cmo: mTimer.cmo 
+sqrt.cmx: mTimer.cmx 
+state.cmo: augMap.cmo augSet.cmo fqueue.cmi options.cmo 
+state.cmx: augMap.cmx augSet.cmx fqueue.cmx options.cmx 
+BUGS
+CHANGES
+COPYING
+CREDITS
+FILES
+INSTALL
+INSTALL.txt
+INSTALL_w32.txt
+KEYBINDINGS.txt
+LICENSE
+README
+README.txt
+TODO
+VERSION
+planets.1.gz
+uni.9
+getting_started.html
+planets
+0.1.10 - A number of small changes:
+       * cleaned up the makefile and .spec file.  There is now a debian
+         package as well.
+       * Added a "-debug" command line option that turns on debugging
+         messages (useful for figuring out what the right keysym is for a
+         certain key)
+       * Fixed the zoom in/out so it works with the keypad.
+       * A manpage is now included
+
+0.1.9 - Fixed some problems in the Danish translation
+
+0.1.8 - Integrated Daniel Andor's fourth-order runge-kutta code.  Now the
+        physical simulation is finally decent. Added pixmap and desktop
+        entries, donated by Gunner Poulson.  Implemented some dialog cleanups
+        proposed by Bulia Byak, as well as a new command "J", for adding
+        clockwise-only random orbital planets.  True bouncing has been
+        removed, leaving only force-bouncing.  At the moment, I'm not sure
+        how to do a good, energy-preserving true-bounce in combination with
+        the runge-kutta method.
+
+0.1.7 - Improved behavior of random-orbital planet (introduced by key "j") to
+        behave more sensibly.  In particular, the "implied distance" is
+        computed not based on the center of mass of the remaining planets,
+        but on the induced acceleration on the point in question.
+
+0.1.6 - Changed kid key-bindings so that keypad introduces random non-orbital
+        planets.
+	
+	Fixed bug where pressing Dismiss button on dialog did not commit
+	changes.
+
+0.1.5 - Danish translation added
+
+0.1.4 - Debugging messages no longer listed by default
+ 
+        Basic (and ad-hoc) support for internationalization (see display.ml
+        and lstrings.ml).
+
+        Universes no longer saved by default in current working directory.
+        Instead, they are saved in $HOME/.planets, if $HOME exists.  If $HOME
+        exists but $HOME/.planets does not, then the latter is created.
+ 
+	Help dialog is now displayed initially.  This displays the basic
+	keybindings, and can be disabled so it doesn't pop up initially.
+
+0.1.3 - added more information to README.txt on windows about getting Tcl/Tk.
+        No other user-visible changes, but some changes made towards
+        sensible behavior for traces during COM-following mode.
+
+0.1.2 - minor bugfixes
+
+0.1.1 - code updated to work with OCaml 3.04.  Mostly of the work is to
+        accommodate the new labeling regime.  
+
+0.1 - First public release
+This software is only available under the GNU General Public License (GNU
+GPL).
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+* Yaron Minsky is the main author
+
+* Sandor Lehoczky helped out in implementing planet bouncing
+
+* Gunner Poulsen <gp@lyngbjerggaardskolen.dk> provided a number of useful
+  suggestions, as well as a Danish translation.
+
+* Daniel Andor contributed the 4th-order runge-kutta code
+
+* Martin Pitt contributed many packaging fixes while building a debian
+  package, and also wrote the initial version of the manpage.
+BUGS
+CHANGES
+codeguide.txt
+COPYING
+CREDITS
+FILES
+BINFILES
+INSTALL
+INSTALL.txt
+INSTALL_w32.txt
+KEYBINDINGS.txt
+LICENSE
+Makefile
+README
+README.txt
+TODO
+VERSION
+planets.1
+planets.desktop
+planets.png
+planets.spec
+sqrt.c
+uni.9
+.depend
+getting_started.html
+planets.src.spec
+*.ml
+*.mli
+Unix Compilation
+----------------
+
+To install, you need Tcl/Tk version 8.3 and ocaml version 3.04.  Getting
+these is pretty straightforward on a unix box, so I'll just point you to the
+URLs:
+
+   http://www.scriptics.com    (for Tcl/Tk)
+   http://www.ocaml.org
+
+In order to compile planets, you simply move to the planets directory and
+type:
+
+   make planets
+
+That should compile the planets executable.  Note that planets looks for and
+saves universe files in the directory from which planets was invoked.
+
+Win32 Compilation
+-----------------
+
+To compile under windows, you need to find and install a number of unix-style
+tools.   The following explanation assumes a basic understanding of how to
+get around in a unix shell.
+
+Planets on Win32 currently depends on cygwin, a free (as in speech)
+UNIX-compatibility layer.  Cygwin is available at http://cygwin.com.
+Download the setup.exe file, run it, and follow the instructions.  You
+should end up with a bash shell, gcc, and make, which are the main
+prerequisites.
+
+You also need to install Tcl/Tk 8.3.  You can get the ActiveTcl distribution
+at http://scriptics.com or http://activestate.com.  Make sure you install
+Tcl at a path that doesn't include any spaces.  Thus, installing at C:\Tcl
+is OK, C:\Program Files\Tcl isn't.  
+
+Once you have cygwin and Tcl/Tk installed, you should get ocaml 3.04.
+Download that from www.ocaml.org.  Once you unpack the archive, read the
+INSTALL file, which will give you the basic instructions.  You need to enable
+labltk support, so your invocation of configure should look something like
+this:
+
+./configure -tklibs -L/cygdrive/C/Tcl/lib -tkdefs -I/cygdrive/C/Tcl/include
+
+Look at the output of configure, and make sure that labltk was properly
+configured.  You'll need to do "make world; make opt; make install" to
+actually compile and install ocaml.
+
+Once ocaml is installed, go to the planets directory.  Type "make clean; make
+dep; make planets", and that, ideally, should do it.
+
+At this point, planets should be invokeable from the cygwin shell.  To make
+it work from the GUI, you need to ensure that cygwin1.dll is in the path.
+You can do this either by copying cygwin1.dll from /usr/bin/ to the directory
+planets is in, or else by editing the normal windows path to ensure 
+
+Unix Compilation
----------------
   http://www.scriptics.com    (for Tcl/Tk)
   http://www.ocaml.org
   make planets
-----------------
+When installing the binary on windows, you need to make sure that you have
+Tcl/Tk 8.3 installed.  You can get it at scriptics.com or activestate.com.
+Once it's installed, you may need to reboot, to ensure that the path to the
+Tcl libraries (typically C:\Tcl) is in your path.  You can add it manually if
+you like.
+
+Note that you also need the cygwin dll, which is included in the zip file.
+If you already have cygwin installed, then you can run planets from the
+cygwin command line without this installation of the cygwin dll.  
+Note that universe files are now stored in ~/.planets, so you might want to
+drop the uni.9 example universe there.
+
+Normal keybindings
+
+   H                Display help dialog
+   a                Add Planet
+   =                Zoom In
+   -                Zoom Out
+   B                Toggle true bounce
+   b                Toggle bounce
+   c, space                 Center
+   k                Display option dialog
+   o                Change all colors
+   q, Escape        Quit
+   e                Reset to empty universe
+   s                Save Universe
+   l                Load Universe
+   u                Undo (undoes last planet insertion)
+   g                Go Back (goes back to last planet insertion)
+   p                Toggle Pause
+   t                Toggle Trace
+   d                Double Trace Length
+   h                Halve Trace Length
+   j                Place random orbital planet
+   r                Place random planet
+   x                Initiate C-O-M tracking
+   Up               Pan Up
+   Down             Pan Down
+   Left             Pan Left
+   Right            Pan Right
+
+Also:
+
+  * Drag a box around a set of planets to follow the center of mass of those
+    planets.
+  * Click on a planet to delete it
+
+
+Kidmode bindings:
+
+numbers : toggle tracing
+q,w,e,a,s,d,z,x,c: change colors
+space: move to center of mass
+escape: erase all planets
+all other buttons: add random planet
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+ifndef OCAMLC 
+	OCAMLC=ocamlc
+endif
+ifndef OCAMLOPT
+	OCAMLOPT=ocamlopt
+endif
+ifndef CAMLP4O
+	CAMLP4O=camlp4o
+endif
+ifndef PREFIX
+	PREFIX=/usr/local
+endif
+
+INCLUDES=-I +labltk
+CAMLP4=-pp $(CAMLP4O)
+OCAMLDEP=ocamldep
+CAMLLIBS=unix.cma str.cma labltk.cma # libjpf.cma mylibs.cma
+OCAMLFLAGS=$(INCLUDES) $(CAMLP4) -g -custom $(CAMLLIBS) -cclib -lunix 
+OCAMLOPTFLAGS=$(INCLUDES) $(CAMLP4) $(CAMLLIBS:.cma=.cmxa) -inline 50 -cclib -lunix
+
+ifdef PROFILING
+  OCAMLC=ocamlcp
+  OCAMLOPTFLAGS = -p $(INCLUDES) $(CAMLLIBS:.cma=.cmxa) -inline 40 -cclib -lunix
+endif
+
+OBJS =  augSet.cmx augMap.cmx mTimer.cmx common.cmx lstrings.cmx options.cmx \
+	constants.cmx fqueue.cmx state.cmx saveState.cmx \
+	rk4.cmx fast_physics.cmx \
+	collision.cmx physics.cmx help.cmx display.cmx
+
+VERSION := $(shell cat VERSION)
+PREFIX = planets-$(VERSION)
+FILES := $(shell sed -e s/.*/$(PREFIX)\\/\&/ FILES)
+BINFILES := $(shell sed -e s/.*/$(PREFIX)\\/\&/ BINFILES)
+
+all: planets planets.1.gz
+
+install: planets.1.gz
+	if [ -x planets ]; then install planets $(PREFIX)/bin/planets; fi
+	if [ -x planets.bc ]; then install planets.bc $(PREFIX)/bin/planets; fi
+	if [ -x $(PREFIX)/share/applications ]; \
+	then install planets.desktop $(PREFIX)/share/applications; fi
+	if [ -x $(PREFIX)/share/applnk/Games ]; \
+	then install planets.desktop $(PREFIX)/share/applnk/Games; fi
+	if [ -x $(PREFIX)/share/pixmaps ]; \
+	then install planets.png $(PREFIX)/share/pixmaps; fi
+	if [ -x $(PREFIX)/share/man/man1 ]; \
+	then install planets.1.gz $(PREFIX)/share/man/man1; fi
+
+planets.1.gz: planets.1
+	gzip -c planets.1 > planets.1.gz
+
+rpm: planets.spec src
+	rpmbuild -ta ../planets-$(VERSION).tgz
+
+src: planets.spec
+	if [ ! -x planets-$(VERSION) ]; then ln -s . planets-$(VERSION); fi
+	tar cfz ../planets-$(VERSION).tgz $(FILES)
+	rm planets-$(VERSION)
+
+w32: planets
+	cp /usr/bin/cygwin1.dll .
+	zip -r ../planets.zip planets.exe cygwin1.dll getting_started.html \
+	README.txt KEYBINDINGS.txt LICENSE CHANGES BUGS CREDITS \
+	COPYING VERSION uni.*
+	rm cygwin1.dll
+
+bin: all
+	if [ ! -x planets-$(VERSION) ]; then ln -s . planets-$(VERSION); fi
+	tar cfz ../planets-x86_Linux-$(VERSION).tgz $(BINFILES)
+	rm planets-$(VERSION)
+
+planets: $(OBJS)
+	$(OCAMLOPT) -o planets $(OCAMLOPTFLAGS) $^
+
+planets.bc: $(OBJS:.cmx=.cmo)
+	$(OCAMLC) -o planets.bc $(OCAMLFLAGS) $^
+
+test: test.ml
+	$(OCAMLC) -o test $(OCAMLFLAGS) $^
+
+sqrt: sqrt.ml
+	$(OCAMLOPT) -o sqrt $(OCAMLOPTFLAGS) $^
+
+collision: constants.cmx options.cmx fqueue.cmx state.cmx collision.cmx
+	$(OCAMLOPT) -o collision $(OCAMLOPTFLAGS) $^
+
+convert: convert.ml
+	$(OCAMLC) -o convert $(OCAMLFLAGS) $^
+
+
+common.ml: common.src.ml VERSION
+	sed s/__VERSION__/$(VERSION)/ < common.src.ml > common.ml
+
+planets.spec: planets.src.spec VERSION
+	sed s/__VERSION__/$(VERSION)/ < planets.src.spec > planets.spec
+
+# Common rules
+.SUFFIXES: .ml .mli .cmo .cmi .cmx
+
+.ml.cmo:
+	$(OCAMLC) $(OCAMLFLAGS) -c $<
+
+.mli.cmi:
+	$(OCAMLC) $(OCAMLFLAGS) -c $<
+
+.ml.cmx:
+	$(OCAMLOPT) $(OCAMLOPTFLAGS) -c $<
+
+# Clean up
+clean:
+	rm -f *.[0-9].gz
+	rm -f *.exe
+	rm -f *.obj
+	rm -f *.o
+	rm -f *.cm[iox]
+	rm -f planets
+	rm -f planets.bc
+
+# Dependencies
+dep:
+	$(OCAMLDEP)  $(CAMLP4) $(INCLUDES) *.ml *.mli > .depend
+
+include .depend
+
+Planets is a simple interactive orbital simulator.  

README.txt

+* Physics
+
+ - implement better approximation --- 4th order runge kutta would be a nice
+   start, but there's a lot of stuff to do under this rubric, such as
+   varying the step size depending on the conditions.
+
+ - add in solar system snapshot.
+
+ - Better bouncing:
+    + repulsion field that drops off more quickly (nearly to zero outside of
+      radius bound?) so as not to affect normal physics.
+
+ - Redo COM-follow mode so it computes an offset for the COM, and then uses
+   those to reposition before display.  By keeping a record of the COM
+   offsets, tracing could be made to do something reasonable in COM-follow
+   mode. 
+
+ - Make 3D?  Could be done with a 2D-display and a simple
+   projection.... Use 2d-mouse movement for changing angle, maybe a scrollbar
+   for depth.  Could be done...
+
+ - Make 3D for real:  using LablGL.  This will hurt portability and
+   performance, however
+
+* Display
+
+  - Consider breaking up traces into lots of little line segments.  Whether
+    this is an improvement depends on the internals of Tcl/Tk, but it does
+    avoid the need for a linear scan (both in OCaml and in Tcl/Tk) every time
+    a planet moves.
+
+  - Consider using built-in Tcl/Tk scaling when zooming in and out.  It's not
+    clear, though, if that would really help performance.
+
+  - Port to LablGtk?  Canvas performance should be higher, there is
+    anti-aliasing, and gtk can be linked in to make a small windows
+    executable.
+
+    This would be a lot of work, unfortunately.  Also, what about
+    portability?  Should wait until LablGtk�is more clearly the standard for
+    OCaml, or at least until it's better supported.
+
+  - Allow for display of planet names next to planets
+
+* UI
+
+ - improved GUI controls for optionbox
+    + exponential control
+    + Little up-and-down arrows on the entry controls would be nice.
+
+* Config Files
+
+ - Allow files to refrain from setting some variables, like G and G-exp.
+   This should be controllable from the UI.  Perhaps add a keyword to
+   indicate that the current values should not be overwritten.
+
+ - Modify lexer to enable forward and backward compatibility. i.e.,
+   non-understood entries are simply dropped.
+
+open StdLabels
+open MoreLabels
+
+module type OrderedType =
+sig
+  type t
+  val compare: t -> t -> int
+end
+
+module type S =
+sig
+  type key
+  type 'a t
+  val empty: 'a t
+  val add: key:key -> (data:'a -> ('a t -> 'a t))
+  val find: key -> 'a t -> 'a
+  val remove: key -> 'a t -> 'a t
+  val mem:  key -> 'a t -> bool
+  val has_key: key -> 'a t -> bool
+  val iter: f:(key:key -> (data:'a -> unit)) -> ('a t -> unit)
+  val map: f:('a -> 'b) -> ('a t -> 'b t)
+  val mapi: f:(key -> 'a -> 'b) -> ('a t -> 'b t)
+  val fold: f:(key:key -> (data:'a -> ('b -> 'b))) -> ('a t -> (init:'b -> 'b))
+  val of_list: (key * 'a) list -> 'a t
+  val to_list: 'a t -> (key * 'a) list
+  val build_index: key list -> int t
+  val filter: f:(key:key -> (data:'a -> bool)) -> ('a t -> 'a t)
+  val keys: 'a t -> key list
+end
+
+module Make(Ord: OrderedType) : (S with type key = Ord.t) = 
+struct
+
+  (* create the underlying map module *)
+  module UMap = Map.Make(Ord)
+  type key = UMap.key
+  type 'a t = 'a UMap.t
+  let empty = UMap.empty
+  let add = UMap.add
+  let find = UMap.find
+  let remove = UMap.remove
+  let mem = UMap.mem
+  let iter = UMap.iter
+  let map = UMap.map
+  let mapi = UMap.mapi
+  let fold = UMap.fold
+
+  let has_key key map =
+    try 
+      let _ = find key map in
+	true
+    with
+	Not_found -> false
+
+  let of_list pairlist = 
+    let rec loop pairlist map = 
+      match pairlist with
+	  [] -> map
+	| (key,data)::tl -> loop tl (add key data map)
+    in
+      loop pairlist empty
+
+  let to_list map = 
+    fold ~f:(fun ~key ~data list -> (key,data)::list) map ~init:[]
+
+  (* takes a list with no duplicates, and produces a 
+     map from elements of that list to indices into the list *)
+  let build_index list = 
+    let rec loop list map i = match list with
+	[] -> map
+      | hd::tl -> loop tl (add ~key:hd ~data:i map) (i+1)
+    in
+      loop list empty 0
+
+  let keys map =
+    fold ~f:(fun ~key ~data list -> key::list) map ~init:[]
+
+
+  let filter ~f map =
+    fold ~f:(fun ~key ~data map -> 
+	       if f ~key ~data
+	       then add ~key ~data map
+	       else map)
+      map
+    ~init:empty
+
+end
+
+
+(* A painful and boring extension to the Set module.  *)
+(* This is basically a somewhat extended and more efficient 
+    implementation of Set. *)
+(* Extended in that it has of_list, exists and for_all *)
+(* More efficient in that cardinal is now (usually)
+   O(1) instead of O(n) *)
+
+open StdLabels
+open MoreLabels
+
+module type S =
+  sig
+    type elt
+    and t
+    val empty : t
+    val is_empty : t -> bool
+    val mem : elt -> t -> bool
+    val add : elt -> t -> t  
+    val singleton : elt -> t
+    val remove : elt -> t -> t
+    val union : t -> t -> t  
+    val inter : t -> t -> t  
+    val diff : t -> t -> t   
+    val compare : t -> t -> int
+    val equal : t -> t -> bool
+    val subset : t -> t -> bool
+    val iter : f:(elt -> unit) -> (t -> unit)
+    val fold : f:(elt -> 'a -> 'a) -> (t -> (init:'a -> 'a))
+    val cardinal : t -> int  (* more efficient than original *)
+    val elements : t -> elt list
+    val min_elt : t -> elt
+    val max_elt : t -> elt
+    val choose : t -> elt
+    (* these are my additions to Set.S *)
+    val of_list : elt list -> t
+    val exists : (elt -> bool) -> t -> bool
+    val for_all : (elt -> bool) -> t -> bool
+  end
+
+
+module MakeFromSet(SomeSet : Set.S ) : (S with type elt = SomeSet.elt) =
+struct 
+  type t = { set: SomeSet.t;
+	     mutable length: int; } 
+      (* a length of (-1) implies the length is currently 
+	 unknown *)
+  type elt = SomeSet.elt
+
+  let unary unary_func s =  unary_func s.set
+  let merge merge_func s t = { set = merge_func s.set t.set; length = -1 }
+  let join join_func s t = join_func s.set t.set
+  let incr v inc = if v >= 0 then v + inc else v
+
+
+  let empty = { set = SomeSet.empty; length = 0 }
+  and is_empty = unary SomeSet.is_empty
+  and mem elt s = SomeSet.mem elt s.set
+  and add elt s = 
+    if SomeSet.mem elt s.set 
+    then s
+    else { set = SomeSet.add elt s.set; length = incr s.length 1 }
+  and singleton elt = { set = SomeSet.singleton elt; length = 1 }
+  and remove elt s = 
+    if SomeSet.mem elt s.set 
+    then { set = SomeSet.remove elt s.set; length = incr s.length (-1) }
+    else s
+
+  let union = merge SomeSet.union
+  and inter = merge SomeSet.inter
+  and diff = merge SomeSet.diff
+
+  and compare = join SomeSet.compare
+  and equal = join SomeSet.equal
+  and subset = join SomeSet.subset
+
+  and iter ~f s = SomeSet.iter ~f s.set
+  and fold ~f s = SomeSet.fold ~f s.set
+  and cardinal s = 
+    (if s.length < 0 
+     then s.length <- SomeSet.cardinal s.set);
+    s.length
+  and elements = unary SomeSet.elements
+  and min_elt = unary SomeSet.min_elt
+  and max_elt = unary SomeSet.max_elt
+  and choose = unary SomeSet.choose
+
+  let of_list list =
+    let add_elem set elem = SomeSet.add elem set in
+    let new_set = List.fold_left ~f:add_elem ~init:SomeSet.empty list
+    in { set = new_set; length = -1 }
+  let exists test s = 
+    SomeSet.fold ~f:(fun elt tval -> tval || (test elt)) s.set ~init:true
+  let for_all test s = 
+    SomeSet.fold ~f:(fun elt tval -> tval && (test elt)) s.set ~init:true
+end
+
+
+module Make = functor (Elt : Set.OrderedType) -> MakeFromSet(Set.Make(Elt))
+
+
+let test () =
+  let module IntSet = Make(struct type t = int let compare = compare end) in
+  let passed = ref true in
+  let test_cond tval fail_str = if not tval then begin Printf.printf "%s\n" fail_str; passed := false end in
+  test_cond ((IntSet.cardinal IntSet.empty) = 0) "Empty set length test failed";
+
+  let set1 = IntSet.union (IntSet.of_list [1;2;3]) (IntSet.of_list [3;4;5])
+  and set2 = IntSet.of_list [1;2;3;4;5] in
+  test_cond (IntSet.equal set1 set2)  "union equality test failed";
+  test_cond ((IntSet.cardinal set1) = (IntSet.cardinal set2)) "union size test failed";
+
+  let set1 = IntSet.inter (IntSet.of_list [1;2;3;4]) (IntSet.of_list [3;4;5;6])
+  and set2 = IntSet.of_list [3;4] in
+  test_cond (IntSet.equal set1 set2)  "inter equality test failed";
+  test_cond ((IntSet.cardinal set1) = (IntSet.cardinal set2)) "inter size test failed";
+
+  let set1 = IntSet.diff (IntSet.of_list [1;2;3;4]) (IntSet.of_list [3;4;5;6])
+  and set2 = IntSet.of_list [1;2] in
+  test_cond (IntSet.equal set1 set2)  "diff equality test failed";
+  test_cond ((IntSet.cardinal set1) = (IntSet.cardinal set2)) "diff size test failed";
+  
+  test_cond ((IntSet.elements (IntSet.of_list [0;1;2;3;4;5])) = [0;1;2;3;4;5]) "of_list/elements test failed";
+  test_cond ((IntSet.max_elt (IntSet.of_list [1;3;0;5;4;2])) = 5) "max_elt test failed";
+  test_cond ((IntSet.min_elt (IntSet.of_list [1;3;0;5;4;2])) = 0) "min_elt test failed";
+
+  test_cond (IntSet.subset (IntSet.of_list [1;4;3;4;4]) (IntSet.of_list [1;2;4;65;3;4;6;4])) "Subset/of_list test failed";
+  test_cond (IntSet.mem 3 (IntSet.of_list [1;2;5;3;5;6;7])) "mem test failed";
+  test_cond ((IntSet.cardinal (IntSet.of_list [1;2;3;1;2;3;3;1]))  = 3) "cardinal test failed";
+  !passed
+Some quick notes on the code.  Planets is written entirely in OCaml, a
+functional language developed at INRIA, a variant on ML.  OCaml has a lot of
+nice features---the compiled code runs at near-C speeds, it has type
+inference, which means you need very few type declarations, which makes it
+terser and easier to read.  And it is statically typed, which means that it
+catches a lot of errors at compile time rather than run time.  And the
+compilers themselves are lightning fast compared to gcc.
+
+OCaml, however, has one big misfeature: it's unusual, and it's hard for
+someone who has never used it before to get use to the programming style.
+But OCaml is great language, so it could well be worth learing.
+
+Here's a list of the different modules and what they do.
+
+state.ml  
+
+   contains basic type definitions and holds the variables containing the
+   state.  This includes things like the definitions of vector operations.
+
+physics.ml
+
+   Contains the basic physics, including computing the action of bodies on
+   each other and a simple algorithm for collision detection and handling.
+   Some of the actual code is really implemented in fast_physics.ml, which is
+   where the physics code is moved to when it's optimized and made grungy.
+
+display.ml
+
+   This is the user interface.  It has a bunch of kinky stuff for setting up
+   things like the placement of a new planet.  You probably don?t want to
+   look at it for a while.  But it also contains some important and easy to
+   modify stuff, including the key bindings, and the constants determining
+   how many iterations are done per display cycle, and how long the display
+   cycle is.
+
+options.ml
+
+   This is somewhat hairy, so newbies beware.  This is the code for
+   implementing the little box containing the listing of configuration
+   variables.  The core data type here is a live value, which is just an
+   class wrapping a value such that callbacks are invoked whenever the value
+   is updated.  These callbacks are used to update the display when
+   configuration options are changed from outside the display, and to update
+   the simulation when the configuration options are changed.
+
+   Also contained in here is GUI code for generating the various kinds of
+   displays required for the differnent options.  There is much
+   object-and-inheritance stuff going on, which is always hard to understand.
+
+collision.ml
+
+   This code has all the raw material for the "true collision" mode.
+   Basically it knows how to play billiards.  The only function called by
+   other modules is one that takes as its argument a sequence of planets and
+   a time interval, and computes the motion, collisions and bounces that
+   would happen assuming all host's velocities stay constant.  This is done
+   by repeatedly computing the next collision, moving the time forward to
+   when that happens, and the computing how that collision causes planets to
+   bounce.  This is repeated until there are no further collisions in the
+   time period.
+
+common.ml
+
+   Contains a few definitions that are used in lots of places, primarily the
+   debugging information.
+   
+constants.ml
+
+   A couple of physics constants that need to be accessed in a few different places.
+
+fast_physics.ml
+
+   Contains the faster array-based implementation of some of the physics
+   primitives.  Full of lots of not-very-functional code.
+
+fqueue.ml
+
+   A simple functional queue implementation used to store planet traces
+
+saveState.ml:
+
+   Code for loading and saving universe files.  This is a tad more
+   sophisticated than your average flat config file --- it uses the ocaml
+   Genlex module to generating a lexer, which in turn allows for a pretty
+   flexible and readable file format.
+
+help.ml:
+	
+   Code for initial help window.  
+
+lstrings.ml: 
+
+   Localization.  Basically, it contains a bunch of functions (english,
+   danish, etc.) that provide translations from certain polymorphic variants
+   (i.e., `save or `load) to the appropriate string in the appropriate
+   language.  One of those functions is chosen at run-time as the one to
+   actually use.
+
+augMap.ml, augSet.ml: 
+
+   simple, augmented versions of the Set and Map modules.  The main
+   improvement is that these keep track of their size, so that getting the
+   number of elements is not linear.
+open State
+
+(***************************************************************)
+(**  Collision detection   *************************************)
+(***************************************************************)
+
+(* Computes smallest positive solution to the quadratic equation 
+   |p + t*v|^2 - dist = 0.  The solution is:
+
+   - v.p +/- sqrt((v.p)^2 - v.v*(p.p - dist))
+   ------------------------------------------ 
+                     v.v
+
+   if the sqrt term is imaginary, then bail out early (before computing the
+   sqrt).  This is a big performance win.
+
+ *)
+let next_collision_values p v dist dotpp = 
+  let dotvp = dot v p in
+  let dotvpsq = dotvp *. dotvp 
+  and dotpp = dot p p
+  and dotvv = dot v v in
+  let pre_sqrt_term = dotvpsq -. dotvv *. (dotpp -. (dist *. dist)) in
+    if pre_sqrt_term <= 0. then infinity
+    else
+      let sqrt_term = sqrt pre_sqrt_term  in
+      let soln1 = (-. dotvp -. sqrt_term) /. dotvv
+      and soln2 = (-. dotvp +. sqrt_term) /. dotvv
+      in
+	(* It's important to ignore planets that are currently touching *)
+	(* note that soln2 is always greater than soln1 *)
+	if soln2 <= 0. then infinity
+	else if soln1 > 0. then soln1
+	else soln2 
+
+
+(* computes time of next collision given two bodies *)
+let next_collision_bodies b1 b2  =
+  let dist = b1.radius +. b2.radius in
+  let p = b1.pos <-> b2.pos in
+  let v = b1.velocity <-> b2.velocity in
+  let dotpp = dot p p in
+  if dotpp < dist *. dist then infinity
+  else next_collision_values p v dist dotpp
+
+(* computes nearest collision *)
+
+let next_collision bodies =
+  let len = Array.length bodies in
+  let best = ref (infinity, None) in
+  for i = 0 to len - 2 do
+    for j = i + 1 to len - 1 do
+      let time = next_collision_bodies bodies.(i) bodies.(j) in
+      let ( best_time, _ ) = !best in
+      if time < best_time then best := (time, Some (i,j));
+    done
+  done;
+  match !best with
+      (time,None) -> raise Not_found
+    | (time,Some (i,j)) -> (time, (i,j))
+
+
+(***************************************************************)
+(***  Bouncing   ***********************************************)
+(***************************************************************)
+(*  Computes the bounce of two touching bodies.  It is assumed that the two
+    bodies are touching. *)
+
+(* compute new velocities from 1-dimensional bounce problem *)
+let bounce_1d ~s1 ~s2 ~m1 ~m2 = 
+  let new_s1 = (( m1 -. m2) *. s1 +. 2. *. m2 *. s2) /. (m1 +. m2)
+  and new_s2 = (( m2 -. m1) *. s2 +. 2. *. m1 *. s1) /. (m1 +. m2)
+  in
+  (new_s1,new_s2)
+
+
+let magsq v = dot v v
+let mag v = sqrt (magsq v)
+let uvec v = mag v <|> v
+
+let bounce_pair b1 b2 =
+  let v1 = b1.velocity and v2 = b2.velocity
+  and m1 = b1.mass and m2 = b2.mass
+  and p1 = b1.pos and p2 = b2.pos 
+  in
+  let u =  uvec (p2 <-> p1) in
+  (* speed in collision direction *)
+  let s1 = dot v1 u and s2 = dot v2 u in 
+  (* perpendicular components of velocity *)
+  let v1p = v1 <-> (s1 <*> u) and v2p = v2 <-> (s2 <*> u) in
+  let new_s1,new_s2 = bounce_1d ~s1 ~s2 ~m1 ~m2 in
+
+  let new_v1 = (new_s1 <*> u) <+> v1p
+  and new_v2 = (new_s2 <*> u) <+> v2p
+  in
+  
+  ( { b1 with velocity = new_v1 }, 
+    { b2 with velocity = new_v2 } )
+		 
+
+(***************************************************************)
+(****   Moving Forward  ****************************************)
+(***************************************************************)
+
+let move_forward_simple bodies time =
+  for i = 0 to Array.length bodies - 1 do
+    let body = bodies.(i) in
+    bodies.(i) <- 
+    { body with pos = body.pos <+> (time <*> body.velocity) }
+  done
+
+let rec move_forward_array time bodies =
+  try
+    let (ctime,(i,j)) = next_collision bodies in
+    if ctime > time then 
+      move_forward_simple bodies time
+    else (
+      move_forward_simple bodies ctime; 
+      (* move to collision time *)
+      let b_i,b_j = bodies.(i),bodies.(j) in
+      let b_i,b_j = bounce_pair b_i b_j in
+      bodies.(i) <- b_i;
+      bodies.(j) <- b_j;
+      move_forward_array (time -. ctime) bodies
+    )
+  with 
+      Not_found -> 
+	move_forward_simple bodies time
+
+
+let move_forward time bodies = 
+  let bodies = Array.of_list bodies in
+  move_forward_array time bodies;
+  Array.to_list bodies
+(*  Planets:  A celestial simulator
+    Copyright (C) 2001-2003  Yaron M. Minsky
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+let version = "0.1.11"
+
+let debugging = ref false
+let debug_msg msg = 
+  if !debugging then
+    (print_string msg;
+     print_newline ())
+
+type 'a reference = { mutable v: 'a }
+type fref = { mutable fv: float }
+
+let lpush el l = l := el::!l
+
+(** argument parsing code *)
+
+let anonymous = ref []
+
+let spec = [
+  ("-debug", Arg.Set debugging, "Turn debugging mode on")
+]
+
+
+let () = Arg.parse spec (fun s -> lpush s anonymous) "planets [-debug]"
+(*  Planets:  A celestial simulator
+    Copyright (C) 2001-2003  Yaron M. Minsky
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+let version = "__VERSION__"
+
+let debugging = ref false
+let debug_msg msg = 
+  if !debugging then
+    (print_string msg;
+     print_newline ())
+
+type 'a reference = { mutable v: 'a }
+type fref = { mutable fv: float }
+
+let lpush el l = l := el::!l
+
+(** argument parsing code *)
+
+let anonymous = ref []
+
+let spec = [
+  ("-debug", Arg.Set debugging, "Turn debugging mode on")
+]
+
+
+let () = Arg.parse spec (fun s -> lpush s anonymous) "planets [-debug]"
+(*  Planets:  A celestial simulator
+    Copyright (C) 2001-2003  Yaron M. Minsky
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+let gconst = new Options.live_value 1.0
+let grav_exp = new Options.live_value 2.0
+
+(*  Planets:  A simple 2-d celestial simulator
+    Copyright (C) 2001  Yaron M. Minsky
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+(* When run in a given directory, converts all the uni.[0-9a-z] files from
+ * the old to the new format.  
+ *)
+ 
+
+open Printf
+open Tk
+
+type body = { pos: float * float;
+	      velocity: float * float;
+	      radius: float;
+	      color: color;
+	      mass: float;
+	      id: int;
+	    }
+
+type state = { mutable zoom:  float;
+	       mutable center:  float * float;
+	       mutable delta:  float;
+	       mutable bodies:  body list;
+	     }
+
+let state = { zoom = 0.0;
+	      center = (0.0, 0.0);
+	      delta = 0.0;
+	      bodies = [];
+	    }
+
+let load_universe filename = 
+  try
+    let in_c = open_in_bin filename in
+    let nstate = ((Marshal.from_channel in_c):state) in
+      state.zoom <- nstate.zoom;
+      state.center <- nstate.center;
+      state.delta <- nstate.delta;
+      state.bodies <- nstate.bodies;
+  with 
+      Sys_error str ->
+	print_string ("error opening file: " ^  str);
+	print_newline ();
+	()
+
+(******************************************************************)
+(******************************************************************)
+
+
+let string_of_float x = sprintf "%.20e" x
+let string_of_int x = sprintf "%d" x
+
+let string_of_pair pair = 
+  sprintf "(%s, %s)" (string_of_float (fst pair)) (string_of_float (snd pair))
+
+let string_of_color color = match color with
+    `Color string -> string
+  | `Black -> "black"
+  | `Blue -> "blue"
+  | `Red -> "red"
+  | `White -> "white"
+  | `Green -> "green"
+  | `Yellow -> "yellow"
+
+
+let write_body out_c body =
+  let indent = "   " in
+    fprintf out_c "\nbody\n";
+    fprintf out_c "%spos      %s\n" indent (string_of_pair body.pos);
+    fprintf out_c "%svelocity %s\n" indent (string_of_pair body.velocity);
+    fprintf out_c "%sradius   %s\n" indent (string_of_float body.radius);
+    fprintf out_c "%smass     %s\n" indent (string_of_float body.mass);
+    fprintf out_c "%scolor    \"%s\"\n" indent (string_of_color body.color);
+    fprintf out_c "%sid       %s\n" indent (string_of_int body.id)
+
+let write_state out_c = 
+  fprintf out_c "zoom   %s\n" (string_of_float state.zoom);
+  fprintf out_c "center %s\n" (string_of_pair state.center);
+  fprintf out_c "delta  %s\n" (string_of_float state.delta);
+  List.iter ~f:(write_body out_c) state.bodies;
+  close_out out_c
+
+let write_state_file filename = write_state (open_out filename)
+
+
+let get_files ~f dir =
+  let rec loop files = 
+    try
+      let file = Unix.readdir dir in
+	if f file then loop (file::files)
+	else loop files
+    with
+	End_of_file -> files
+  in 
+    loop []
+
+let is_uni str = 
+  let pat = Str.regexp "^uni\.[0-9a-z]$" in
+    Str.string_match ~pat str ~pos:0
+
+let main () =  
+  let dir = Unix.opendir(".") in
+  let files = get_files ~f:is_uni dir in
+    List.iter ~f:(fun filename ->
+		    load_universe filename;
+		    write_state_file filename)
+      files
+
+  
+
+let _ = if not !Sys.interactive then main () 
+(*  Planets:  A simple 2-d celestial simulator
+    Copyright (C) 2001-2003  Yaron M. Minsky
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *)
+
+open StdLabels
+open MoreLabels
+
+open Tk
+open Printf
+
+open State
+open Common
+open Constants
+
+let gap_ms = Options.named_live_value "gap_ms" 30   
+	       (* period, in ms, between callbacks.
+                  30ms corresponds to roughly 33 frames/sec *)
+let iterations = Options.named_live_value "iterations" (gap_ms#v / 15)
+		   (* # iterations per callback *)
+let init_screen_width = 500
+let init_screen_height = 500
+
+let diameter_multiplier = Options.named_live_value "diameter_multiplier" 1.0
+let random_vel_multiplier = Options.named_live_value "random_vel_multiplier" 1.0
+
+let penergy = Options.named_live_value "penergy" 0.0
+let kenergy = Options.named_live_value "kenergy" 0.0
+let energy = Options.named_live_value "energy" 0.0
+let num_bodies = Options.named_live_value "number of bodies" 0
+
+let truebounce = new Options.live_toggle false
+let kidmode = new Options.live_toggle false
+let _ = 
+  truebounce#set_name "truebounce";
+  kidmode#set_name "kidmode"
+
+let app_class = "Planets"
+
+(********************************************************)
+module IntSet = 
+  AugSet.Make(struct type t = int 
+		     let compare = compare 
+	      end)
+
+(********************************************************)
+(**  Color Operations  **********************************)
+(********************************************************)
+
+let intensity r g b  = sqrt ((float_of_int r)**2.0 +.
+                              (float_of_int g)**2.0 +.
+                              (float_of_int b)**2.0)
+
+let max_intensity r g b = 
+  let maxval = max (max r g) b in
+  let mult = 255.0 /. (float_of_int maxval) in
+  let max_r = (float_of_int r) *. mult
+  and max_g = (float_of_int g) *. mult
+  and max_b = (float_of_int b) *. mult in
+    sqrt (max_r ** 2.0 +. max_g ** 2.0 +. max_b ** 2.0)
+
+let test_color r g b = 
+  (r >= 0 && r < 256) &&
+  (g >= 0 && g < 256) &&
+  (b >= 0 && b < 256)
+
+let renormalize r g b =
+  let m = max_intensity r g b in
+  let i = intensity r g b in
+  let new_i = (m +. i) /. 2.0 in
+  let r = int_of_float ((float_of_int r) *. new_i /. i)
+  and g = int_of_float ((float_of_int g) *. new_i /. i)
+  and b = int_of_float ((float_of_int b) *. new_i /. i)
+  in 
+    assert (test_color r g b);
+    rgb r g b
+
+let rand_range () = Random.int 256
+let rand_color () = 
+  renormalize (rand_range ()) (rand_range ()) (rand_range ())
+
+let change_trace_color id color = 
+  try
+    let trace = IntMap.find id transient.traces in
+      transient.traces <- 
+      IntMap.add ~key:id ~data:{trace with t_color = color} transient.traces
+  with
+      Not_found -> ()
+
+let change_body_color_by_id id = 
+  let color = rand_color () in
+  let changebodies bodies = 
+    List.map ~f:(fun body -> 
+		   if body.id = id then
+		     { body with color = color }
+		   else
+		     body)
+      bodies
+  in
+    state.bodies <- changebodies state.bodies;
+    change_trace_color id color
+
+let hlcolor = `Yellow
+let fgcolor = `White
+let bgcolor = `Black
+
+let uw opt = match opt with
+    Some x -> x
+  | None -> failwith "Display.uw: attempt to unwrap null option"
+
+
+(****************************************************)
+(****************************************************)
+(****************************************************)
+
+let compute_energy () = 
+  let p = Physics.penergy state.bodies
+  and k = Physics.kenergy state.bodies 
+  in
+  penergy#set (log (abs_float p));
+  kenergy#set (log k);
+  energy#set (log (abs_float (p +. k)))
+
+(****************************************************)
+(****************************************************)
+(****************************************************)
+
+type ('a,'b,'c,'d) disp_state = 
+    { mutable toplevel: Widget.toplevel Widget.widget option;
+      mutable frame:    Widget.frame Widget.widget option;
+      mutable canvas:   Widget.canvas Widget.widget option;
+      mutable optionbox: ('c,'d) Options.optionbox option;
+      mutable dbodies:  'a IntMap.t;
+      mutable dtraces:  'b IntMap.t;
+      mutable tracked_ids: IntSet.t;
+      paused:   Options.live_toggle;
+      tracing:  Options.live_toggle;
+      tracking: Options.live_toggle;
+    }
+
+
+let disp_state = 
+  { toplevel = None;
+    frame = None;
+    canvas = None;
+    optionbox = None;
+    dbodies = IntMap.empty;
+    dtraces = IntMap.empty;
+    tracked_ids = IntSet.empty;
+    paused = new Options.live_toggle false;
+    tracing = new Options.live_toggle false;
+    tracking = new Options.live_toggle false;
+  }
+
+
+
+let get_dbody id = IntMap.find id disp_state.dbodies
+let canvas () = uw disp_state.canvas
+
+let init_optionbox () = 
+  let obox = new Options.optionbox (uw disp_state.toplevel) in
+    obox#set_liveness true;
+
+    Options.add_option_live obox disp_state.paused
+      (new Options.toggle_option 
+	 ~text:(Lstrings.get `paused)
+	 ~set:disp_state.paused#set
+	 ~get:disp_state.paused#get ());
+
+    Options.add_option_live obox disp_state.tracing
+      (new Options.toggle_option 
+	 ~text:(Lstrings.get `tracing)
+	 ~set:disp_state.tracing#set
+	 ~get:disp_state.tracing#get ());
+
+    Options.add_option_live obox truebounce
+      (new Options.toggle_option 
+	 ~text:(Lstrings.get `true_bounce)
+	 ~set:truebounce#set
+	 ~get:truebounce#get ());
+
+
+    Options.add_option_live obox transient.bound
+      (new Options.int_scale_option 
+	 ~text:(Lstrings.get `trace_length)
+	 ~set:transient.bound#set
+	 ~get:transient.bound#get
+	 ~min:3.0 ~max:300.0 ());
+
+    Options.add_option_live obox gap_ms
+      (new Options.int_scale_option 
+	 ~text:(Lstrings.get `disp_period)
+	 ~set:gap_ms#set
+	 ~get:gap_ms#get
+	 ~min:1.0 ~max:100.0 ());
+
+    Options.add_option_live obox iterations
+      (new Options.int_scale_option
+	 ~text:(Lstrings.get `iter_display)
+	 ~set:iterations#set
+	 ~get:iterations#get
+	 ~min:1.0 ~max:100.0 ());
+
+    Options.add_option_live obox state.delta
+      (new Options.float_entry_option
+	 ~text:(Lstrings.get `time_step)
+	 ~mult:1.05
+	 ~set:state.delta#set
+	 ~get:state.delta#get ());
+
+    Options.add_option_live obox gconst
+      (new Options.float_entry_option
+	 ~text:(Lstrings.get `g)
+	 ~mult:1.05
+	 ~set:gconst#set
+	 ~get:gconst#get ());
+
+    Options.add_option_live obox grav_exp
+      (new Options.float_entry_option
+	 ~text:(Lstrings.get `grav_exp)
+	 ~mult:1.01
+	 ~set:grav_exp#set
+	 ~get:grav_exp#get ());
+
+    Options.add_option obox  
+      (new Options.void_entry_display
+	 ~text:"New random bodies:" ());
+
+    Options.add_option_live obox diameter_multiplier
+      (new Options.float_entry_option
+	 ~text:(Lstrings.get `diam_mult)
+	 ~mult:1.01
+	 ~set:diameter_multiplier#set
+	 ~get:diameter_multiplier#get ());
+
+    Options.add_option_live obox random_vel_multiplier
+      (new Options.float_entry_option
+	 ~text:(Lstrings.get `rand_vel_mult)
+	 ~mult:1.01
+	 ~set:random_vel_multiplier#set
+	 ~get:random_vel_multiplier#get ());	 
+
+(* Energy Display *)
+
+    Options.add_option_live obox kenergy
+      (new Options.float_entry_display
+	 ~text:(Lstrings.get `log_k_energy)
+	 ~set:kenergy#set
+	 ~get:kenergy#get ());
+
+    Options.add_option_live obox penergy
+      (new Options.float_entry_display
+	 ~text:(Lstrings.get `log_p_energy)
+	 ~set:penergy#set
+	 ~get:penergy#get ());
+
+    Options.add_option_live obox energy
+      (new Options.float_entry_display
+	 ~text:(Lstrings.get `log_energy)
+	 ~set:energy#set
+	 ~get:energy#get ());
+
+    Options.add_option_live obox num_bodies
+      (new Options.int_entry_display
+	 ~text:(Lstrings.get `num_planets)
+	 ~set:num_bodies#set
+	 ~get:num_bodies#get ());
+
+    disp_state.optionbox <- Some obox
+
+let toggle_opt_dialog () = 
+  match disp_state.optionbox with
+      None -> failwith "Display.create_dialog: Attempt to display optionbox when none is available"
+    | Some obox -> 
+	if obox#mapped 
+	then obox#destroy
+	else obox#create_dialog ~geometry:"+0+0" ~transient:(uw disp_state.toplevel) ~clas:app_class ()
+
+
+(********************************************************)
+(**  Display Classes  ***********************************)
+(********************************************************)
+
+(** Note:  just screwing around here.  Classes are not yet used.   **)
+class virtual ['a] display_item tag = 
+object (self)  
+
+  val tag = tag
+  val mutable alive = true
+
+  method destroy = 
+    if not alive then 
+      failwith "Attempt to destroy same display_item more than once"
+    else
+      (Canvas.delete (canvas ()) [tag]; 
+       alive <- false)
+
+  method draw item = 
+    if not alive 
+    then failwith "Display.display_item#draw: attempt to draw deleted item." 
+    else self#draw_internal item
+
+  (* Here's where you put the logic for drawing an item*)
+  method virtual draw_internal : 'a -> unit
+end
+
+(************************************************)
+
+class dbody body tag =
+  let tag = tag in
+object (self)
+  inherit [body] display_item tag
+
+  val id = body.id
+
+  method draw_internal body =
+    let r = body.radius *. state.zoom#v
+    and (x,y) = real_to_screen body.pos in
+    let (x1,y1,x2,y2) = (int_of_float (x -. r), int_of_float (y -. r),
+			 int_of_float (x +. r), int_of_float (y +. r))
+    in
+      Canvas.configure_oval ~fill:body.color ~outline:fgcolor (canvas ()) tag;
+      Canvas.coords_set (canvas ()) tag ~xys:[ (x1,y1) ; (x2,y2) ]
+
+  initializer
+    begin
+      Canvas.bind ~events:[`ButtonPress] ~extend:false ~fields:[] 
+	~action:(fun e -> delete_body_by_id id)
+		   (* change_body_color_by_id id)  *)
+	(canvas ()) tag; 
+      self#draw_internal body
+    end
+end
+
+let new_dbody_with_tag body tag = 
+  new dbody body tag
+
+let new_dbody_from_body body =
+  let tag = Canvas.create_oval ~x1:0 ~y1:0 ~x2:0 ~y2:0 (canvas ()) in
+    new dbody body tag
+
+(************************************************)
+
+class dtrace () = 
+  let tag = Canvas.create_line ~xys:[] (canvas ()) in
+  let _ = Canvas.configure_line ~smooth:false (canvas ()) tag in
+object (self)
+  inherit [trace] display_item tag
+
+  method draw_internal trace = 
+    let screen_trace = 
+      List.map ~f:pair_to_int (List.map ~f:real_to_screen (trace_to_list trace))
+    in
+      if List.length screen_trace > 1 then
+        ( Canvas.configure_line ~fill:trace.t_color (canvas ()) tag;
+	  Canvas.coords_set (canvas ()) tag ~xys:screen_trace )
+end
+
+(**********************************************************)
+(**  Classes used in the placement of new planets   *******)
+(**********************************************************)
+
+class ['a] new_planet () =
+  let tag = Canvas.create_oval ~x1:0 ~y1:0 ~x2:0 ~y2:0 (canvas ()) in
+object (self)
+
+  inherit ['a] display_item tag
+
+  val mutable radius = 0.0
+  val mutable pos = (0,0)
+  val mutable color = fgcolor
+
+  method draw_internal (x,y) =
+    let radius = int_of_float radius in
+    let coords = [(x-radius,y-radius);(x+radius,y+radius)] in
+      Canvas.coords_set (canvas ()) tag ~xys:coords;
+      pos <- (x,y)
+
+  method set_radius _radius = 
+    radius <- _radius;
+    self#draw_internal pos
+
+  method set_color _color =
+    Canvas.configure_oval ~fill:_color (canvas ()) tag;
+    color <- _color
+
+  method tag = tag
+  method pos = pos
+  method radius = radius
+  method color = color
+
+  initializer
+    Canvas.configure_oval ~outline:fgcolor (canvas ()) tag
+
+end
+
+(******)
+
+class ['a] new_velocity planet = 
+  let pos = planet#pos in
+  let tag = Canvas.create_line ~xys:[pos; pos] ~arrow:`Last (canvas ()) in
+  let _ = Canvas.configure_line ~fill:fgcolor  (canvas ()) tag in
+object (self) 
+
+  inherit ['a] display_item tag
+
+  val mutable vpos = planet#pos
+    
+  method draw_internal _vpos = 
+    Canvas.coords_set (canvas ()) tag ~xys:[pos; _vpos];
+    vpos <- _vpos
+
+  method vpos = vpos
+  method tag = tag
+
+end
+
+
+(*********************************************************)
+(**  Functions for selecting bodies  *********************)
+(*********************************************************)
+
+let selected_bodies pos1 pos2 = 
+  let (x1,y1) = pair_to_float pos1
+  and (x2,y2) = pair_to_float pos2
+  in
+  let x1,x2 = (min x1 x2), (max x1 x2)
+  and y1,y2 = (min y1 y2), (max y1 y2)
+  in
+    List.filter ~f:(fun body -> 
+		      let (x,y) = real_to_screen body.pos in
+			x1 <= x && x <= x2 &&
+			y1 <= y && y <= y2)
+      state.bodies
+
+
+
+let selected_ids pos1 pos2 = 
+  IntSet.of_list
+    (List.map ~f:(fun body -> body.id) (selected_bodies pos1 pos2))
+
+
+
+let recenter_on_selection pos1 pos2 = 
+  debug_msg "recentering on selection";
+  let bodies = selected_bodies pos1 pos2 in
+    if bodies != [] then 
+      begin
+	debug_msg (sprintf "recentering on %d bodies" (List.length bodies));
+	Physics.zero_speed_bodies bodies;
+	Physics.center_bodies bodies
+      end
+    else
+      debug_msg "no bodies selected to recenter on"
+
+let create_rectangle color pos1 pos2 = 
+  let (x1,y1) = pos1
+  and (x2,y2) = pos2 
+  in
+    Canvas.create_rectangle ~x1 ~y1 ~x2 ~y2 ~outline:color (canvas ())
+
+
+(***********************************************************)
+(**  Primitives for displaying and deleting display items  *)
+(***********************************************************)
+
+let delete_dbody_id id = 
+  try
+    let dbody = get_dbody id in
+      disp_state.dbodies <- IntMap.remove id disp_state.dbodies;
+      dbody#destroy
+  with Not_found ->
+    printf "No dbody with id %d" id;
+    print_newline ()
+
+let delete_trace_id id = 
+  try
+    let dtrace = IntMap.find id disp_state.dtraces in
+      disp_state.dtraces <- IntMap.remove id disp_state.dtraces;
+      dtrace#destroy
+  with Not_found ->
+    printf "No dtrace with id: %d" id;
+    print_newline ()
+
+(***************************************************) 
+
+(* Lookup functions for dbody/dtrace.  
+ * If one is not found, one is created. 
+ *)
+