threebody.rb
Path: threebody.rb
Modified: Sun Mar 21 22:16:47 JST 2004
Required files
opengl    glut    mathn   
Methods
init    main    showstep   
Included modules
Math
Public Instance methods
init()

Init: setup some GL/GLUT parmeters

# File threebody.rb, line 11
def init
  mat_specular = [ 1.0, 1.0, 1.0, 1.0 ];
  light_position = [ 0.0, 30.0, 50.0, 0.0 ];

  GL.ClearColor(0.0, 0.0, 0.0, 0.0);
  GL.ShadeModel(GL::SMOOTH);
  GL.Enable(GL::DEPTH_TEST);
  GL.Light(GL::LIGHT0, GL::POSITION, light_position);
  GL.Enable(GL::LIGHTING);
  GL.Enable(GL::LIGHT0);

  GL.Material(GL::FRONT, GL::DIFFUSE, $diffuseMaterial);
  #   GL.Material(GL::FRONT, GL::SPECULAR, mat_specular);
  #   GL.Material(GL::FRONT, GL::SHININESS, 25.0);
  #   GL.ColorMaterial(GL::FRONT, GL::DIFFUSE);
  GL.Enable(GL::COLOR_MATERIAL);
  GL.MatrixMode(GL::PROJECTION);
  GLU.Perspective(40.0, 1.0, 1.0,  10.0);
  GL.MatrixMode(GL::MODELVIEW);
  GLU.LookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
  
end
showstep(direction)

showstep: do a single step in the current direction and wait

# File threebody.rb, line 35
def showstep(direction)
  if $runstate == 1
    GLUT.IdleFunc(nil) 
    $runstate = 0;
  end
  $inc = -$inc if $inc < 0
  $inc = 1  if $inc == 0
  $inc = -$inc if direction < 0
end
main()

main: do all the dirty works…

# File threebody.rb, line 46
def main

# 

# the above single blanck comment seems to be necessary to prevent the
# next comment block from appearing at the top of the file.


# Parameter setups to be used in display function.
# Specialized to three particles. If you need to use N!=3, you need to 
# change this part and display function below accordingly.
# In particular, you need to change $color and $size.
# If yu just want to show all particles in same size and colur,
# you can use something like 
# $color = [0.0,1.0,1.0]
# $size  = 0.1
# and remove index from their uses in the display function below.
  $diffuseMaterial = [0.5,0.5,0.5,1.0];
  $Material = [[0.1,0.1,0.1,1.0],[0.0,1.0,1.0,1.0],[1.0,1.0,1.0,1.0]]
  $color = [[0.0,1.0,1.0],[1.0,0.0,1.0],[1.0,1.0,0.0]]
  $frame = 0
  $inc = 3
  $size=[0.1,0.05,0.1]
  $scale = 20
  $radius = 10
  $theta= -60
  $phi = -135

# display function for three particles. 
  display = Proc.new {
    scale = $scale
    GL.Clear(GL::COLOR_BUFFER_BIT | GL::DEPTH_BUFFER_BIT);
    GL.PushMatrix
    print $theta," ", $phi, "\n"
#need to change the next line if you have N!=3
    for j in 0..2
      GL.PushMatrix
      #    GL.Material(GL::FRONT, GL::AMBIENT, $Material[j]);
      GL.Color(*$color[j])
      GL.Rotate($theta, 0.0, 0.0, 1.0)
      GL.Rotate($phi, 1.0, 0.0, 0.0)
      GL.Translate($parray[$frame][j][0]/scale,$parray[$frame][j][1]/scale,
                   $parray[$frame][j][2]/scale)
      GLUT.SolidSphere($size[j]/scale*$radius, 10, 6);
      GL.PopMatrix
    end
    GL.PopMatrix
    GLUT.SwapBuffers();
    $frame += $inc
    if $frame >= $parray.size 
      $frame=0
# for onetrip (useful for making GIF files)
#     exit
    elsif $frame <= 0
      $frame = $parray.size - 1
    end
#   activate the next line (and the above "exit" to make GIF images of
#   each frames
#   system "xwd -nobdrs -name threebody.rb|xwdtopnm|ppmtogif> #{$frame}.gif"
  }

# keyboard function
  keyboard = Proc.new {|key, x, y|
    case key
# H/h to stop animation
    when ?h,?H
      $inc =0
# A/a to increase the speed
    when ?a,?A
      if $inc >= 0
        $inc += 1
      else
        $inc -= 1
      end
# D/d to decrease the speed
    when ?d,?D
      if $inc > 0
        $inc -= 1
      else
        $inc += 1
      end
# s/S to scale down/up
    when ?s
      $scale *= 1.2
    when ?S
      $scale /= 1.2
# R/r to increase/decrease sphere radius
    when ?R
      $radius *= 1.2
    when ?r
      $radius /= 1.2
# x/X to rotate frame
    when ?x
      $phi += 3
    when ?X
      $phi -= 3
# y/Y to rotate frame 
    when ?y
      $theta += 3
    when ?Y
      $theta -= 3
# >/. to single step forward
    when ?>,?.
      showstep(1)
# </, to single step backward
    when ?<,?,
      showstep(-1)
# q/Q/ESC to quit
    when ?q,?Q,27
      exit(0);
    end
    GLUT.PostRedisplay() if $runstate == 0

  }

  $runstate = 0
# mouse function
  mouse = Proc.new {|button, state, x, y|
    case button
# left button to start
    when GLUT::LEFT_BUTTON
      if (state == GLUT::DOWN) 
        GLUT.IdleFunc($reDisplay) 
        $runstate = 1
      end
#middle button to stop
    when GLUT::MIDDLE_BUTTON
      if (state == GLUT::DOWN) 
        GLUT.IdleFunc(nil) 
        $runstate = 0
      end
#right botton to change the time direction
    when GLUT::RIGHT_BUTTON
      $inc = - $inc if (state == GLUT::DOWN)
    end
  }

  $reDisplay = Proc.new {
    #  print "redisplay called"
    GLUT.PostRedisplay();
  }

# read in the input snapshots. The idea here is to store the entire
# sequence of the snapshot to a single array called $parray. So
# $parray is a three-dimentional file, of (in fortran notation) the
# dimension of (3,N,Nsnapshots)

  f = open("testdata","r")
  $parray = []
  while s = f.gets
    pos = []
    a = s.split
    time = a[0].to_f
    for i in 0..2
      pos.push [a[i*3+1].to_f,a[i*3+2].to_f,a[i*3+3].to_f]
    end
    $parray.push(pos)
    s = f.gets
  end



  GLUT.Init
  GLUT.InitDisplayMode(GLUT::DOUBLE | GLUT::RGB | GLUT::DEPTH);
  GLUT.InitWindowSize(700, 700); 
  GLUT.InitWindowPosition(100, 0);
  GLUT.CreateWindow($0);
  init
  GLUT.KeyboardFunc(keyboard);
  GLUT.MouseFunc(mouse);
  GLUT.DisplayFunc(display); 
  GLUT.MainLoop();
end