Download doc - Dr. Manuel Carcenac

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Dr. Manuel Carcenac - European University of Lefke
Advanced topics
in animation
- presented with JOGL 2
kinematic animation: time interpolation of degrees of freedom
dynamic animation: time integration of degrees of freedom
dynamic animation: all-pairs n-body problem and gravitation
References:
http://jogamp.org/ (for JOGL 2.0)
http://download.java.net/media/jogl/jogl-2.x-docs/
http://www.glprogramming.com/red/
http://eng.eul.edu.tr/manuel/Course_on_Graphics_in_Java/Course_on_Graphics_in_Java.htm
(for practical introduction to JOGL 2.0)
Advanced Animation and Rendering Techniques – Theory and Practice
Alan Watt, Mark Watt; Addison-Wesley, ACM press
Michael Thomas Flanagan's Java Scientific and Numerical Library
http://www.ee.ucl.ac.uk/~mflanaga/java/index.html
http://www.ee.ucl.ac.uk/~mflanaga/java/CubicSpline.html (for cubic spline interpolation)
http://farside.ph.utexas.edu/teaching/329/lectures/node35.html
for Runge-Kutta method
http://www.ast.cam.ac.uk/~sverre/web/pages/nbody.htm
for n-body problem
http://www.scholarpedia.org/article/N-body_simulations_(gravitational)
1
Dr. Manuel Carcenac - European University of Lefke
kinematic animation: time interpolation of degrees of freedom
cubic spline interpolation:
install Flanagan's scientific library:

put flanagan.jar into folder C:\Program Files\Java\jdk1.6.0_23\jre\lib\ext

add to system variable CLASSPATH (already exists, was created for JOGL)

Computer  Properties  Advanced system settings  Environment Variables

edit system variable CLASSPATH (already exists, was created for JOGL)
 add at the end of it:
;C:\Program Files\Java\jdk1.6.0_23\jre\lib\ext\flanagan.jar
import statement:
import flanagan.interpolation.*;
cubic spline with Nk control points ( tk , xk ) :
double[] xk = new double[Nk];
double[] tk = new double[Nk];
CubicSpline csx = new CubicSpline(tk , xk);
interpolation of function x(t) :
double x = csx.interpolate(t);
for every control point k , csx.interpolate(tk[k]) yields value xk[k]
2
Dr. Manuel Carcenac - European University of Lefke
example: interpolated curve with interactive selection and modification of control points
..........
import flanagan.interpolation.*;
public class P
{ public static void main(String[] arg)
{ Gui gui = new Gui(); } }
class Gui
{
JFrame f; DrawingPanel p;
JPanel ps; JSlider skx , sky , skz , skt; JLabel lkx , lky , lkz , lkt;
int Nk = 8; int ks = 0; // ks = k of selected key
double[] xk = new double[Nk] , yk = new double[Nk] , zk = new double[Nk] , tk = new double[Nk];
int N = 60;
double L = 100.0 , T = 100.0;
{ for (int k = 0 ; k < Nk ; k++)
{ xk[k] = 0.0; yk[k] = - L / 2 + L * k / (Nk - 1); zk[k] = 0.0;
tk[k] = T * k / (Nk - 1); } }
class DrawingPanel extends GLJPanel
{
GLU glu; GLUquadric quad;
float[] RED = new float[] { 1.0f , 0.0f , 0.0f , 1.0f } , GREEN = new float[] { 0.0f , 1.0f , 0.0f , 1.0f }
, WHITE = new float[] { 1.0f , 1.0f , 1.0f , 1.0f };
DrawingPanel()
{ super(new GLCapabilities(GLProfile.getDefault()));
this.addGLEventListener(new GLEventListener()
{
..........
public void display(GLAutoDrawable drawable) //****
{
..........
DISPLAY
////------- KEY POINTS
for (int k = 0 ; k < Nk ; k++)
{
gl.glMaterialfv(GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , (k == ks ? RED : GREEN) , 0);
gl.glPushMatrix(); gl.glTranslatef((float)xk[k] , (float)yk[k] , (float)zk[k]);
glu.gluSphere(quad , 2.0f , 10 , 10);
gl.glPopMatrix();
}
3
Dr. Manuel Carcenac - European University of Lefke
////------- INTERPOLATED POINTS
gl.glMaterialfv(GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , WHITE , 0);
CubicSpline csx = new CubicSpline(tk , xk)
, csy = new CubicSpline(tk , yk)
, csz = new CubicSpline(tk , zk);
for (int k = 0 ; k < N ; k++)
{
double t = T * k / (N - 1);
double x = csx.interpolate(t)
, y = csy.interpolate(t)
, z = csz.interpolate(t);
gl.glPushMatrix(); gl.glTranslatef((float)x , (float)y , (float)z);
glu.gluSphere(quad , 1.0f , 10 , 10);
gl.glPopMatrix();
}
gl.glFlush();
}
..........
} );
}
}
4
Dr. Manuel Carcenac - European University of Lefke
Gui()
{
f = new JFrame(); f.setFocusable(true); f.setVisible(true);
p = new DrawingPanel(); f.getContentPane().add(p , BorderLayout.CENTER);
f.addMouseListener(new MouseAdapter()
{ public void mouseClicked(MouseEvent e)
{ int bt = e.getButton();
switch (bt)
{ case MouseEvent.BUTTON1: ks--;
if (ks == -1) ks = Nk - 1;
case MouseEvent.BUTTON3: ks++; if (ks == Nk) ks = 0;
break;
break; }
skx.setValue((int)(1000 * (0.5 + xk[ks] / L)));
sky.setValue((int)(1000 * (0.5 + yk[ks] / L)));
skz.setValue((int)(1000 * (0.5 + zk[ks] / L)));
skt.setValue((int)(1000 * tk[ks] / T));
f.repaint(); } } );
ps = new JPanel(); ps.setLayout(new GridLayout(0 , 2));
f.getContentPane().add(ps , BorderLayout.EAST);
skx = new JSlider(JSlider.HORIZONTAL , 0 , 1000 , 0);
lkx = new JLabel(" x of selected key");
sky = new JSlider(JSlider.HORIZONTAL , 0 , 1000 , 0);
lky = new JLabel(" y of selected key");
skz = new JSlider(JSlider.HORIZONTAL , 0 , 1000 , 0);
lkz = new JLabel(" z of selected key");
skt = new JSlider(JSlider.HORIZONTAL , 0 , 1000 , 0);
lkt = new JLabel(" t of selected key");
ps.add(skx);
ps.add(lkx);
ps.add(sky);
ps.add(lky);
ps.add(skz);
ps.add(lkz);
ps.add(skt);
ps.add(lkt);
skx.addChangeListener( . . . . . . . . . . { xk[ks] = -L/2+L*skx.getValue()/1000; f.repaint(); } } );
sky.addChangeListener( . . . . . . . . . . { yk[ks] = -L/2+L*sky.getValue()/1000; f.repaint(); } } );
skz.addChangeListener( . . . . . . . . . . { zk[ks] = -L/2+L*skz.getValue()/1000; f.repaint(); } } );
skt.addChangeListener( . . . . . . . . . .
{ if (ks != 0 && ks != Nk - 1) tk[ks] = T*skt.getValue()/1000;
if (ks > 0
&& tk[ks - 1] + T / 100 > tk[ks]) { tk[ks] = tk[ks - 1] + T / 100; }
if (ks < Nk - 1 && tk[ks] > tk[ks + 1] - T / 100) { tk[ks] = tk[ks + 1] - T / 100; }
f.repaint(); } } );
f.setSize(new Dimension(900 + 16 , 600 + 38));
}
}
5
Dr. Manuel Carcenac - European University of Lefke
6
Dr. Manuel Carcenac - European University of Lefke
example: interpolated trajectory of a ball:
interactive creation of key frames over time
followed by spline driven animation
..........
import flanagan.interpolation.*;
public class P
{ public static void main(String[] arg)
{ Gui gui = new Gui();
while (true)
{
if (gui.read_perform_anim())
{ gui.animation();
gui.write_perform_anim(false); }
Thread.yield();
}
}
}
class Gui
{
JFrame f; DrawingPanel p;
JPanel ps; JSlider skx , sky , skz;
JLabel lkx , lky , lkz;
JButton b_new_key , b_perform_anim;
int Nk , nk;
double[] xk , yk , zk , tk;
double L = 100.0 , T = 20.0;
double time;
boolean perform_anim = false;
synchronized void write_perform_anim(boolean value) { perform_anim = value; }
synchronized boolean read_perform_anim() { return perform_anim; }
void animation()
{
time = 0; long dt = 50; // 0.05s
while (time + dt * 0.001 < T)
{ long t_start = System.currentTimeMillis();
f.repaint();
time += dt * 0.001;
long dt_real = System.currentTimeMillis() - t_start;
if (dt_real < dt) try {Thread.sleep(dt - dt_real);} catch(InterruptedException ee){}
else System.out.println("PC too slow; please increase dt"); }
}
7
Dr. Manuel Carcenac - European University of Lefke
class DrawingPanel extends GLJPanel
{
GLU glu; GLUquadric quad;
float[] RED = new float[] { 1.0f , 0.0f , 0.0f , 1.0f } , GREEN = new float[] { 0.0f , 1.0f , 0.0f , 1.0f }
, WHITE = new float[] { 1.0f , 1.0f , 1.0f , 1.0f };
DrawingPanel()
{ super(new GLCapabilities(GLProfile.getDefault()));
this.addGLEventListener(new GLEventListener()
{
..........
public void display(GLAutoDrawable drawable) //****
{
..........
DISPLAY
////------- KEY POINTS
for (int k = 0 ; k < nk ; k++)
{
gl.glMaterialfv(GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , (k == nk - 1 ? RED : GREEN) , 0);
gl.glPushMatrix(); gl.glTranslatef((float)xk[k] , (float)yk[k] , (float)zk[k]);
glu.gluSphere(quad , 4.0f , 10 , 10);
gl.glPopMatrix();
}
////------- ANIMATED POINT
if (read_perform_anim())
{
gl.glMaterialfv(GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , WHITE , 0);
CubicSpline csx = new CubicSpline(tk , xk)
, csy = new CubicSpline(tk , yk)
, csz = new CubicSpline(tk , zk);
double x = csx.interpolate(time)
, y = csy.interpolate(time)
, z = csz.interpolate(time);
gl.glPushMatrix(); gl.glTranslatef((float)x , (float)y , (float)z);
glu.gluSphere(quad , 4.0f , 10 , 10);
gl.glPopMatrix();
}
gl.glFlush();
}
. . . . . . . . . . } );
} }
8
Dr. Manuel Carcenac - European University of Lefke
Gui()
{
f = new JFrame(); f.setFocusable(true); f.setVisible(true);
p = new DrawingPanel(); f.getContentPane().add(p , BorderLayout.CENTER);
String s = JOptionPane.showInputDialog(f , "number of ctrl pts over " + T + "s ; at least 3");
Nk = Integer.valueOf(s).intValue(); if (Nk<3) { System.out.println("Nk < 3"); System.exit(0); }
nk = 0;
xk = new double[Nk]; yk = new double[Nk]; zk = new double[Nk]; tk = new double[Nk];
ps = new JPanel(); ps.setLayout(new GridLayout(0 , 2));
f.getContentPane().add(ps , BorderLayout.EAST);
skx = new JSlider(JSlider.HORIZONTAL , 0 , 1000 , 0); ps.add(skx);
lkx = new JLabel(" x of new key");
ps.add(lkx);
sky = new JSlider(JSlider.HORIZONTAL , 0 , 1000 , 0); ps.add(sky);
lky = new JLabel(" y of new key");
ps.add(lky);
skz = new JSlider(JSlider.HORIZONTAL , 0 , 1000 , 0); ps.add(skz);
lkz = new JLabel(" z of new key");
ps.add(lkz);
skx.addChangeListener(new ChangeListener()
{ public void stateChanged(ChangeEvent e)
{ if (nk > 0) { xk[nk - 1] = L * skx.getValue() / 1000; f.repaint(); } } } );
sky.addChangeListener(new ChangeListener()
{ public void stateChanged(ChangeEvent e)
{ if (nk > 0) { yk[nk - 1] = L * sky.getValue() / 1000; f.repaint(); } } } );
skz.addChangeListener(new ChangeListener()
{ public void stateChanged(ChangeEvent e)
{ if (nk > 0) { zk[nk - 1] = L * skz.getValue() / 1000; f.repaint(); } } } );
b_new_key = new JButton(); b_new_key.setText("record new key");
b_new_key.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e)
{ if (nk + 1 <= Nk) nk++;
xk[nk - 1] = L * skx.getValue() / 1000;
yk[nk - 1] = L * sky.getValue() / 1000;
zk[nk - 1] = L * skz.getValue() / 1000;
tk[nk - 1] = T * (nk - 1) / (Nk - 1);
f.repaint(); } } );
ps.add(b_new_key);
b_perform_anim = new JButton(); b_perform_anim.setText("anim"); ps.add(b_perform_anim);
b_perform_anim.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e)
{ if (nk < Nk) JOptionPane.showMessageDialog(f , "you have not yet recorded all the keys!");
else write_perform_anim(true); } } );
f.setSize(new Dimension(1000 + 16 , 600 + 38));
}
}
9
Dr. Manuel Carcenac - European University of Lefke
10
Dr. Manuel Carcenac - European University of Lefke
example : angles of an articulated structure:
interactive creation of key frames over time
followed by spline driven animation
..........
import flanagan.interpolation.*;
public class P
{ public static void main(String[] arg)
{ Gui gui = new Gui();
while (true)
{
if (gui.read_perform_anim())
{ gui.animation();
gui.write_perform_anim(false); }
Thread.yield();
}
}
}
class Gui
{
int Na = 7;
JFrame f; DrawingPanel p; JPanel ps;
JSlider[] ska = new JSlider[Na]; JButton b_new_key , b_perform_anim;
float b0 = 110 , b1 = 90 , b2 = 30 , b3 = 20 , b4 = 30 , b5 = 20;
float r0 = 16 , r1 = 10 , r2 = 6 , r3 = 4 , r4 = 6 , r5 = 4;
int Nk , nk;
double[][] ak; double[] tk;
double T = 20.0 , time;
boolean perform_anim = false;
synchronized void write_perform_anim(boolean value) { perform_anim = value; }
synchronized boolean read_perform_anim() { return perform_anim; }
void animation()
{
time = 0; long dt = 50; // 0.05s
while (time + dt * 0.001 < T)
{ long t_start = System.currentTimeMillis();
f.repaint();
time += dt * 0.001;
long dt_real = System.currentTimeMillis() - t_start;
if (dt_real < dt) try {Thread.sleep(dt - dt_real);} catch(InterruptedException ee){}
else System.out.println("PC too slow; please increase dt"); }
}
11
Dr. Manuel Carcenac - European University of Lefke
class DrawingPanel extends GLJPanel
{
GLU glu; GLUquadric quad;
DrawingPanel()
{ super(new GLCapabilities(GLProfile.getDefault()));
this.addGLEventListener(new GLEventListener()
{
..........
public void display(GLAutoDrawable drawable) //**********
{
..........
DISPLAY
////------- LATEST KEY FRAME
if (nk > 0 && ! read_perform_anim())
{
float[] ai = new float[Na];
for (int a = 0 ; a < Na ; a++) ai[a] = (float)(ak[a][nk - 1]);
articulated_arm(gl , glu , quad , ai);
}
////------- ANIMATED ARM
if (read_perform_anim())
{
CubicSpline[] csa = new CubicSpline[Na];
for (int a = 0 ; a < Na ; a++) csa[a] = new CubicSpline(tk , ak[a]);
float[] ai = new float[Na];
for (int a = 0 ; a < Na ; a++) ai[a] = (float)(csa[a].interpolate(time));
articulated_arm(gl , glu , quad , ai);
}
gl.glFlush();
}
. . . . . . . . . . } );
} }
12
Dr. Manuel Carcenac - European University of Lefke
Gui()
{
f = new JFrame(); f.setFocusable(true); f.setVisible(true);
p = new DrawingPanel(); f.getContentPane().add(p , BorderLayout.CENTER);
String s = JOptionPane.showInputDialog(f , "n. of ctrl pts over " + T + "s ; at least 3");
Nk = Integer.valueOf(s).intValue(); if (Nk<3) { System.out.println("Nk<3"); System.exit(0); }
nk = 0;
ak = new double[Na][Nk]; tk = new double[Nk];
ps = new JPanel(); ps.setLayout(new GridLayout(0 , 1));
f.getContentPane().add(ps , BorderLayout.EAST);
for (int a = 0 ; a < Na ; a++)
{ ska[a] = new JSlider(JSlider.HORIZONTAL , 0 , 90 , 0); ps.add(ska[a]);
final int af = a;
ska[a].addChangeListener(new ChangeListener()
{ public void stateChanged(ChangeEvent e) { if (nk > 0) { ak[af][nk - 1] = ska[af].getValue();
f.repaint(); } } } ); }
b_new_key = new JButton(); b_new_key.setText("record new key");
b_new_key.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e)
{ if (nk + 1 <= Nk) nk++;
for (int a = 0 ; a < Na ; a++) ak[a][nk - 1] = ska[a].getValue();
tk[nk - 1] = T * (nk - 1) / (Nk - 1);
f.repaint(); } } );
ps.add(b_new_key);
b_perform_anim = new JButton(); b_perform_anim.setText("anim"); ps.add(b_perform_anim);
b_perform_anim.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent e)
{ if (nk < Nk) JOptionPane.showMessageDialog(f , "you have not yet recorded all the keys!");
else write_perform_anim(true); } } );
f.setSize(new Dimension(800 + 16 , 600 + 38));
}
13
Dr. Manuel Carcenac - European University of Lefke
void articulated_arm(GL2 gl , GLU glu , GLUquadric quad , float[] ai)
{
gl.glMaterialfv(GL.GL_FRONT_AND_BACK , GLLightingFunc.GL_AMBIENT_AND_DIFFUSE
, new float[] { 1.0f , 1.0f , 0.0f , 1.0f } , 0);
gl.glRotatef(ai[0] , 0.0f , 0.0f , 1.0f); gl.glRotatef( 90 - ai[1] , 1.0f , 0.0f , 0.0f);
glu.gluSphere(quad , r0 , 10 , 10);
glu.gluCylinder(quad , r0 , r1 , b0 , 10 , 10);
gl.glTranslatef(0f , 0f , b0); gl.glRotatef(ai[2] , 1.0f , 0.0f , 0.0f);
glu.gluSphere(quad , r1 , 10 , 10);
glu.gluCylinder(quad , r1 , r2 , b1 , 10 , 10);
gl.glTranslatef(0f , 0f , b1);
gl.glPushMatrix();
gl.glRotatef( - ai[3] , 1.0f , 0.0f , 0.0f);
glu.gluSphere(quad , r2 , 10 , 10);
glu.gluCylinder(quad , r2 , r3 , b2 , 10 , 10);
gl.glTranslatef(0f , 0f , b2); gl.glRotatef(ai[4] , 1.0f , 0.0f , 0.0f);
glu.gluSphere(quad , r3 , 10 , 10);
glu.gluCylinder(quad , r3 , 0.0f , b3 , 10 , 10);
gl.glPopMatrix();
gl.glRotatef(ai[5] , 1.0f , 0.0f , 0.0f);
glu.gluSphere(quad , r4 , 10 , 10);
glu.gluCylinder(quad , r4 , r5 , b4 , 10 , 10);
gl.glTranslatef(0f , 0f , b4); gl.glRotatef( - ai[6] , 1.0f , 0.0f , 0.0f);
glu.gluSphere(quad , r5 , 10 , 10);
glu.gluCylinder(quad , r5 , 0.0f , b5 , 10 , 10);
}
}
14
Dr. Manuel Carcenac - European University of Lefke
15
Dr. Manuel Carcenac - European University of Lefke
dynamic animation: time integration of degrees of freedom
example: balls under the influence of gravity and bouncing off the floor
..........
public class P
{ public static void main(String[] arg)
{ Gui gui = new Gui();
gui.animation(); } }
class Ball
{
float[] color;
double x , y , z;
double vx , vy , vz;
Ball(float[] color , double x , double y ,double z , double vx , double vy , double vz)
{ this.color = color;
this.x = x; this.y = y;
this.z = z;
this.vx = vx; this.vy = vy; this.vz = vz; }
}
class Gui
{
JFrame f; DrawingPanel p;
int N; Ball[] ball;
double V = 30.0 , DELTA = 10.0 , ALPHA = 0.9;
//// V in m/s; DELTA in degrees; ALPHA <= 1.0
void animation()
{
double delta_t = 0.05; long dt = (long)(delta_t * 1000);
while (true)
{ long t_start = System.currentTimeMillis();
for (int i = 0 ; i < N ; i++)
{
ball[i].vz += -9.81 * delta_t;
ball[i].x += ball[i].vx * delta_t;
ball[i].y += ball[i].vy * delta_t;
if (ball[i].z <= 1.0)
{ ball[i].z = 1.0; ball[i].vx *= ALPHA;
ball[i].vy *= ALPHA;
ball[i].z += ball[i].vz * delta_t;
ball[i].vz *= - ALPHA; }
}
f.repaint();
long dt_real = System.currentTimeMillis() - t_start;
if (dt_real < dt) try {Thread.sleep(dt - dt_real);} catch(InterruptedException ee){}
else System.out.println("PC too slow; please increase dt"); }
}
16
Dr. Manuel Carcenac - European University of Lefke
float[] RED = new float[] { 1.0f , 0.0f , 0.0f , 1.0f } , GREEN = new float[] { 0.0f , 1.0f , 0.0f , 1.0f }
, BLUE = new float[] { 0.0f , 0.0f , 1.0f , 1.0f }, WHITE = new float[] { 1.0f , 1.0f , 1.0f , 1.0f };
class DrawingPanel extends GLJPanel
{
GLU glu; GLUquadric quad;
DrawingPanel()
{ super(new GLCapabilities(GLProfile.getDefault()));
this.addGLEventListener(new GLEventListener()
{
..........
public void display(GLAutoDrawable drawable) //**********
{
..........
DISPLAY
////------- GROUND
gl.glMaterialfv( GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , WHITE , 0);
glu.gluDisk(quad , 0.0f , 100.0f , 150 , 150);
////------- ANIMATED BALLS
for (int i = 0 ; i < N ; i++)
{
gl.glMaterialfv( GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , ball[i].color , 0);
gl.glPushMatrix(); gl.glTranslatef((float)(ball[i].x) , (float)(ball[i].y), (float)(ball[i].z));
glu.gluSphere(quad , 1.0f , 10 , 10);
gl.glPopMatrix();
}
gl.glFlush();
}
. . . . . . . . . . } );
} }
17
Dr. Manuel Carcenac - European University of Lefke
Gui()
{
f = new JFrame(); f.setFocusable(true); f.setVisible(true);
p = new DrawingPanel(); f.getContentPane().add(p , BorderLayout.CENTER);
String s = JOptionPane.showInputDialog(f , "number of balls; at least 1");
N = Integer.valueOf(s).intValue(); if (N < 1) { System.out.println("N < 1"); System.exit(0); }
ball = new Ball[N];
for (int i = 0 ; i < N ; i++)
{ double v = V * (0.2 * Math.random() + 0.8);
double a = 2 * Math.PI * Math.random();
double b = DELTA * (Math.PI / 180) * Math.random();
ball[i] = new Ball( (i%3==0 ? RED : i%3==1 ? GREEN : BLUE)
, 0.0 , 0.0 , 0.0
, v * Math.sin(b) * Math.cos(a)
, v * Math.sin(b) * Math.sin(a)
, v * Math.cos(b)); }
f.setSize(new Dimension(600 + 16 , 600 + 38));
}
}
18
Dr. Manuel Carcenac - European University of Lefke
19
Dr. Manuel Carcenac - European University of Lefke
dynamic animation: all-pairs n-body problem and gravitation
all-pairs n-body problem:
n bodies fully interacting with each other:
action of all bodies j
over body i
body i
i
j
position pi and velocity vi of body i :
 xi 
 y 
 i 
p   z 
pv i   i    i 
 v i   vx i 
 vy i 


 vz i 
time derivative of the system's global state:
  pv 0 

 pv 0 


 . 
 . 
 



d 

 .   D  .  , t
 

dt 




.
.




 

pv n 1 

 pv n 1 

20
Dr. Manuel Carcenac - European University of Lefke
time integration:
global state s(t) is known at time t
d
s t   D s t  , t 
dt
obtain global state s(t + t)
at time t + t
Euler method:
s t  Δt   s t   D s t  , t   Δt
inaccurate + numerical instability: errors pile up over time
second-order Runge-Kutta method:
D1  D s t  , t 
first estimate of D (at t )
D 2  D s t   D1  Δt / 2 , t  Δt / 2
second estimate of D (at t + t / 2 )
s t  Δt   s t   D 2  Δt
accurate + numerically stable = excellent
fourth-order Runge-Kutta method is often preferred...
21
Dr. Manuel Carcenac - European University of Lefke
gravitational interactions:
body i of mass mi
gravitational constant G = 6.67384e-11
softening length ε
Newton's law of gravity:
D s t  , t  
.

 

 

 

.

 

 

p i 


d  
   
dt  

v i 
G
 

 

 

.

 

 

 . 

.
.
vi

j i
m j  p j  pi 
p p
j
.
.
2
i
 2











3 
2 







22
Dr. Manuel Carcenac - European University of Lefke
case study: collision of two galaxies - simulation parameters and initial state:
total mass of the two galaxies = 4×1042 kg
initial diameter of each galaxy H = 1021 m
softening length ε = H / 100
initial velocity between the two galaxies V = 350×103 m/s
initial state:
random distribution
of half the bodies
V/2
V/2
random distribution
of half the bodies
time step DT = 105×31536000 s (100,000 years)
23
Dr. Manuel Carcenac - European University of Lefke
class encapsulating the simulation parameters:
class Para
{
static double G = 6.67384e-11;
static double M = 4.0e42; // total mass of the two galaxies
static double H = 1.0e21; // diameter of each galaxy
static double EPS = H / 100;
static double DX = H; // distance between the two galaxies over X axis
static double DY = H; // distance between the two galaxies over Y axis
static double V = 350.0 * 1.e3; // velocity between the two galaxies along X axis
static double DT = 1.0e5 * 31536000; // 100,000 years
}
24
Dr. Manuel Carcenac - European University of Lefke
classes describing the state of the n-body system:
class PositionVelocity
{
double x , y , z;
double vx , vy , vz;
PositionVelocity() {}
PositionVelocity(double x , double y ,double z , double vx , double vy , double vz)
{ this.x = x;
this.y = y;
this.z = z;
this.vx = vx; this.vy = vy; this.vz = vz; }
}
class State
{
int n;
double t;
double[] m = new double[n];
PositionVelocity[] pv;
PositionVelocity[] dpv , pv_; // for Runge-Kutta
State(int n)
{ ...... }
void evolve_over_time_step(double dt)
{ ...... }
void increment_positions_velocities( PositionVelocity[] pv1 , PositionVelocity[] pv0
, PositionVelocity[] dpv , double k)
{ ...... }
void derivatives_positions_velocities(PositionVelocity[] pv)
{ ...... }
void display(GL2 gl , GLU glu , GLUquadric quad)
{ ...... }
}
25
Dr. Manuel Carcenac - European University of Lefke
initialization of the state:
State(int n)
{
double h , gal_x , gal_y , gal_z , gal_vx , gal_vy , gal_vz;
this.n = n;
t = 0.0;
m = new double[n];
pv = new PositionVelocity[n];
dpv = new PositionVelocity[n];
pv_ = new PositionVelocity[n];
for (int i = 0 ; i < n ; i++)
{
if (i < n / 2) { gal_x = - Para.DX / 2;
gal_vx = Para.V / 2;
else { gal_x = Para.DX / 2;
gal_vx = - Para.V / 2;
gal_y = - Para.DY / 2; gal_z = 0.0;
gal_vy = 0.0; gal_vz = 0.0; }
gal_y = Para.DY / 2; gal_z = 0.0;
gal_vy = 0.0; gal_vz = 0.0; }
m[i] = Para.M / n;
do
{
pv[i] = new PositionVelocity( gal_x + Para.H * ( -0.5 + Math.random())
, gal_y + Para.H * ( -0.5 + Math.random())
, gal_z + Para.H * ( -0.5 + Math.random())
, gal_vx , gal_vy , gal_vz);
h = Math.sqrt( (pv[i].x - gal_x) * (pv[i].x - gal_x)
+ (pv[i].y - gal_y) * (pv[i].y - gal_y)
+ (pv[i].z - gal_z) * (pv[i].z - gal_z));
}
while (h > Para.H / 2);
dpv[i] = new PositionVelocity();
pv_[i] = new PositionVelocity();
}
}
26
Dr. Manuel Carcenac - European University of Lefke
time integration with Runge-Kutta:
void evolve_over_time_step(double dt)
{
derivatives_positions_velocities(pv);
increment_positions_velocities(pv_ , pv , dpv , dt / 2);
D1
s(t) + D1 × t / 2
derivatives_positions_velocities(pv_);
D2
increment_positions_velocities(pv , pv , dpv , dt);
s(t) + D2 × t
t += dt;
}
void increment_positions_velocities( PositionVelocity[] pv1
, PositionVelocity[] pv0
, PositionVelocity[] dpv
, double k)
{
for (int i = 0 ; i < n ; i++)
{
pv1[i].x = pv0[i].x + dpv[i].x * k;
pv1[i].y = pv0[i].y + dpv[i].y * k;
pv1[i].z = pv0[i].z + dpv[i].z * k;
pv1[i].vx = pv0[i].vx + dpv[i].vx * k;
pv1[i].vy = pv0[i].vy + dpv[i].vy * k;
pv1[i].vz = pv0[i].vz + dpv[i].vz * k;
}
}
27
Dr. Manuel Carcenac - European University of Lefke
time derivatives of positions and velocities:
//// calculate dpv for pv = state.pv or state.pv_
void derivatives_positions_velocities(PositionVelocity[] pv)
{
double pipjx , pipjy , pipjz , d2 , q;
for (int i = 0 ; i < n ; i++)
{
dpv[i].x = pv[i].vx;
dpv[i].y = pv[i].vy;
dpv[i].z = pv[i].vz;
dpv[i].vx = 0.0;
dpv[i].vy = 0.0;
dpv[i].vz = 0.0;
for (int j = 0 ; j < n ; j++)
if (j != i)
{
pipjx = pv[j].x - pv[i].x;
pipjy = pv[j].y - pv[i].y;
pipjz = pv[j].z - pv[i].z;
d2 = pipjx * pipjx + pipjy * pipjy + pipjz * pipjz + Para.EPS * Para.EPS;
q = m[j] / d2 / Math.sqrt(d2);
dpv[i].vx += q * pipjx;
dpv[i].vy += q * pipjy;
dpv[i].vz += q * pipjz;
}
dpv[i].vx *= Para.G;
dpv[i].vy *= Para.G;
dpv[i].vz *= Para.G;
}
}
28
Dr. Manuel Carcenac - European University of Lefke
displaying the state:
void display(GL2 gl , GLU glu , GLUquadric quad)
{
for (int i = 0 ; i < n ; i++)
{
if (i < n / 2)
gl.glMaterialfv( GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , Gui.COLOR1 , 0);
else
gl.glMaterialfv( GL.GL_FRONT_AND_BACK
, GLLightingFunc.GL_AMBIENT_AND_DIFFUSE , Gui.COLOR2 , 0);
gl.glPushMatrix();
gl.glTranslatef( (float)(pv[i].x / Para.H)
, (float)(pv[i].y / Para.H)
, (float)(pv[i].z / Para.H));
glu.gluSphere(quad , 0.01f , 10 , 10);
gl.glPopMatrix();
}
}
29
Dr. Manuel Carcenac - European University of Lefke
main class and Gui class:
public class P
{ public static void main(String[] arg)
{ Gui gui = new Gui();
gui.animation(); } }
class Gui
{
JFrame f;
DrawingPanel p;
State state;
void animation()
{
while (true)
{
state.evolve_over_time_step(Para.DT);
f.repaint();
}
}
class DrawingPanel extends GLJPanel
{
..........
public void display(GLAutoDrawable drawable)
{
..........
state.display(gl , glu , quad);
..........
}
..........
}
Gui()
{
..........
state = new State(n);
..........
}
}
30
Dr. Manuel Carcenac - European University of Lefke
example: simulation with n = 4000
31
Dr. Manuel Carcenac - European University of Lefke
32
Related documents