📄 particle3d.java
字号:
/***************************************************
Copyright 2003 Ben Childs
This file is part of Physics 3D.
Physics 3D 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.
Physics 3D 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 Physics 3D; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************/
package com.bchilds.Physics3D;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.io.*;
import java.util.ArrayList;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.image.TextureLoader;
//Explode behavior
import org.selman.java3d.book.behaviortest.*;
public class Particle3D implements ExplosionListener
{
//Current time (in milliseconds) of the simulation
private static long time = 0;
//Collision Types
public static final int EXPLODE = 1;
public static final int MOMENTUM = 2;
///////////////////////////////////////
//What sort of collision should there be
private static int collisionHandling = MOMENTUM;
///////////////////////////////////////////////
private static int explodeBlastRadiusMultiplier = 3;
//Environmental Variables
private static double gravity = 6.673E-11;
///////////////////////////////////////////////////////
//List of all particles in system
private static ArrayList particles = new ArrayList();
/////////////////////////////////////////////////////
//Variables to keep track of tracking
private static int traceNumFrames = -1;
private static int currentFrame = -1;
/////////////////////////////////////
//Appearance for the tracks
private Appearance tracerAppearance;
///////////////////////////////////
//State variables for the particle
private String name = null;
private Vector3d velocityVector = null;
private Vector3d initialVelocityVector = null;
private Vector3d angularVelocity = new Vector3d(0,0,0);
private Vector3d initialAngularVelocity = new Vector3d(0,0,0);
private Vector3d position = null;
private Vector3d initialPosition = null;
private Vector3d lastPosition = null;
private Quat4d orientation = makeQFromEulerAngles(0,0,0);
private Quat4d initialOrientation = makeQFromEulerAngles(0,0,0);
private Quat4d lastOrientation = null;
private Matrix3d momentOfInertia = null;
private double mass = 1;
private double radius = .1;
private double elasticity = 1; //Between 0 and 1
///////////////////////////////////////
//For updates if true use last position, otherwise use current position
//in calculation of acceleration
private boolean updated = false;
/////////////////////////////////////
//Java3D objects representing the particle
private TransformGroup object3D = null; //The transform group for setting position/size
private Shape3D shape3D = null; //The shape for exploding
private BranchGroup bg = null; //The branch group for removing from the
private BranchGroup bgTracer = null; //Branch group for holding all the tracer objects
private static BranchGroup bgRoot = null; //The root branch group, what we remove stuff from...
private Point3d[] geom = null; //All the vertices for the object
private ArrayList p3dadj = null; //The adjacent table
private Feature[] closestFeatures = null;
//Bounding Box Stuff
private static Point3d ufrBounding = null;
private static Point3d lblBounding = null;
private static double boundsElasticity = 1;
/////////////////
//Creates a Particle3D object given a Java3D Transform group, a velocity vector and the mass
public Particle3D(String name, TransformGroup object, Vector3d velocity, double mass, Vector3d initialPosition, BranchGroup bGroup, Shape3D shape, double elasticity)
{
this.name = name;
setSpeed(velocity);
this.mass = mass;
object3D = object;
this.elasticity = elasticity;
setPosition(initialPosition);
bgTracer = new BranchGroup();
bgTracer.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
bgTracer.setCapability(BranchGroup.ALLOW_DETACH);
bg = bGroup;
bg.addChild(bgTracer);
shape3D = shape;
tracerAppearance = (Appearance)shape3D.getAppearance().cloneNodeComponent();
tracerAppearance.setTransparencyAttributes(new TransparencyAttributes(TransparencyAttributes.NICEST, .75f));
particles.add(this);
//Calculate Moment of Inertia (standard formula for sphere
double ixx, iyy, izz;
ixx = (2/5.0) * mass * radius * radius;
iyy = ixx;
izz = ixx;
momentOfInertia = new Matrix3d(ixx, 0, 0, 0, iyy, 0, 0, 0, izz);
/////////////////////////////
//Calculate adjacent vertices (for new Collision detection scheme)
//Get the vertices
GeometryArray g = (GeometryArray)shape3D.getGeometry();
g.setCapability( GeometryArray.ALLOW_COORDINATE_READ );
g.setCapability( GeometryArray.ALLOW_COORDINATE_WRITE );
g.setCapability( GeometryArray.ALLOW_COUNT_READ );
geom = new Point3d[g.getVertexCount()];
for(int i = 0; i < geom.length; i++)
{
geom[i] = new Point3d(0.0,0.0,0.0);
}
g.getCoordinates(0, geom);
///////////////////////////
//Set large negative doubles to 0
for(int i = 0; i < geom.length; i++)
{
if(Math.abs(geom[i].x) < 1E-10)
geom[i].x = 0.0;
if(Math.abs(geom[i].y) < 1E-10)
geom[i].y = 0.0;
if(Math.abs(geom[i].z) < 1E-10)
geom[i].z = 0.0;
}
/////////////////////////////////////
p3dadj = new ArrayList(); //Initialize the arraylist of vertices/adjacents
ArrayList p3dKeys = new ArrayList(); //Temporary Arraylist to keep the adjacent particles
//Iterate through all the vertices
for(int i = 0; i < geom.length; i++)
{
//Check to see if the vertex has already been done
boolean unique = true;
for(int m = 0; m < p3dadj.size(); m++)
{
if(((Point3DAdjacent)p3dadj.get(m)).equals(geom[i]))
{
unique = false;
break;
}
}
if(!unique)
continue;
//////////////////////////////////////////////////////
//List of equal vertices
ArrayList l = new ArrayList();
for(int j = i; j < geom.length; j++)
{
//Get all equal.
if(geom[i].x == geom[j].x &&
geom[i].y == geom[j].y &&
geom[i].z == geom[j].z)
l.add(new Integer(j));
}
///////////////////////////////
//System.out.println("Found " + l.size() + " identical points at positions:");
//for(int j = 0; j < l.size(); j++)
//{
// System.out.print(l.get(j) + " : ");
//}
//System.out.println();
//List of indices of adjacent particles
ArrayList adjacent = new ArrayList();
//Cycle through equal vertices
for(int k = 0; k < l.size(); k++)
{
//Get the current particle to test
int current = ((Integer)l.get(k)).intValue();
//Either the particle is the middle of a triangle, or the top/bottom, copy appropriately
if(current > 0 && current < geom.length -1 &&
current % 3 == 1)
{
// System.out.println("Going up and down from pt:" + current);
adjacent.add(new Integer(current-1));
adjacent.add(new Integer(current+1));
}
else if(current > 1 && current % 3 == 2)
{
// System.out.println("Going up from pt:" + current);
adjacent.add(new Integer(current-1));
adjacent.add(new Integer(current-2));
}
else if(current < geom.length - 2 && current % 3 == 0)
{
// System.out.println("Going down from pt:" + current);
adjacent.add(new Integer(current+1));
adjacent.add(new Integer(current+2));
}
//remove duplicates
// removeDupP3d(adjacent, geom);
}
//Adjacent keys...
Point3DAdjacent pa = new Point3DAdjacent();
pa.point = geom[i];
p3dadj.add(pa);
Point3d p3dadjacents[] = new Point3d[adjacent.size()];
//System.out.println("For Point: " + geom[i] + " calculated adjacents to be:");
for(int n = 0; n < p3dadjacents.length; n++)
{
p3dadjacents[n] = geom[((Integer)adjacent.get(n)).intValue()];
// System.out.println(p3dadjacents[n]);
}
p3dKeys.add(p3dadjacents);
}
//Calculate the keys and add them to the adjacent table
for(int i = 0; i < p3dadj.size() && i < p3dKeys.size(); i++)
{
Point3DAdjacent pa = (Point3DAdjacent)p3dadj.get(i);
Point3d[] adjacents = (Point3d[])p3dKeys.get(i);
int[] iAdj = new int[adjacents.length];
//System.out.println("Calculated Keys for : " + pa.point );
for(int j = 0; j < adjacents.length; j++)
{
for(int k = 0; k < p3dadj.size(); k++)
{
if(p3dadj.get(k).equals(adjacents[j]))
{
iAdj[j] = k;
break;
}
}
//System.out.print(iAdj[j] + ",");
}
//System.out.println();
pa.key = iAdj;
}
/*
BranchGroup bgCollision = new BranchGroup();
CollisionBehavior cb = new CollisionBehavior(this);
bgCollision.addChild(cb);
bg.addChild(bgCollision);
*/
}
//Removes duplicate keys from the arraylist (used for calculation of adjacent vertices)
private void removeDupP3d(ArrayList keys, Point3d[] p3ds)
{
for(int i = 0; i < keys.size(); i++)
{
Point3d current = p3ds[((Integer)keys.get(i)).intValue()];
for(int j = i+1; j < keys.size(); j++)
{
Point3d test = p3ds[((Integer)keys.get(j)).intValue()];
if(current.x == test.x &&
current.y == test.y &&
current.z == test.z)
{
keys.remove(j);
j--;
}
}
}
}
private Quat4d quatMult43(Quat4d v4, Vector3d v3)
{
return new Quat4d( v4.w * v3.x + v4.y * v3.z - v4.z * v3.y,
v4.w * v3.y + v4.z * v3.x - v4.x * v3.z,
v4.w * v3.z + v4.x * v3.y - v4.y * v3.x,
-(v4.x * v3.x + v4.y * v3.y + v4.z * v3.z));
}
//Update the objects position based on some timeDifferential (time change to represent)
private boolean update(float timeDifferential)
{
//Calculate the acceleration on the object
Vector3d accelerationVector = calculateAcceleration(this);
//Calculate the change in velocity given the time differential
Vector3d velocityChange = accelerationVector;
velocityChange.scale(timeDifferential);
//Update the velocity vector
velocityVector.add(velocityChange);
//Calculate the change in position
Vector3d positionChange = (Vector3d)velocityVector.clone();
positionChange.scale(timeDifferential);
//Store last position
lastPosition = position;
//Update current position
position.add(positionChange);
//Calculate new Orientation from Angular Velocity
Quat4d newOrientation;
newOrientation = quatMult43(orientation, angularVelocity);
newOrientation.scale(.5 * timeDifferential);
newOrientation.add(orientation);
lastOrientation = orientation;
orientation = newOrientation;
orientation.normalize();
//Update the transform group
Transform3D updateTransform = new Transform3D();
updateTransform.setTranslation(position);
updateTransform.setScale(radius*10);
updateTransform.setRotation(newOrientation);
object3D.setTransform(updateTransform);
//If we are tracing and it is the right frame add trace object
if(currentFrame == 0)
{
TransformGroup tgTracer = new TransformGroup();
Transform3D t3d = new Transform3D();
t3d.setScale(radius*10);
t3d.setTranslation(position);
t3d.setRotation(newOrientation);
tgTracer.setTransform(t3d);
tgTracer.addChild(new Sphere(0.1f, Primitive.GENERATE_NORMALS, 20, tracerAppearance));
BranchGroup bgNew = new BranchGroup();
bgNew.addChild(tgTracer);
bgTracer.addChild(bgNew);
}
updated = true;
return true;
}
//Calculate the Acceleration due to gravity of some Particle3D
private static Vector3d calculateAcceleration(Particle3D p)
{
Vector3d totalAcceleration = new Vector3d(0.0,0.0,0.0); //Total acceleration so far
if(gravity == 0) //Efficiency test (avoids an O(n) operation if needless)
return totalAcceleration;
//Iterate through all particles and add the acceleration of all of them
int length = particles.size();
for(int i = 0; i < length; i++)
{
totalAcceleration.add(calculateAttraction2Particles(p, (Particle3D)particles.get(i)));
}
/////////////////////////////////////
return totalAcceleration;
}
//Calculate the acceleration on p1 due to p2.
private static Vector3d calculateAttraction2Particles(Particle3D p1, Particle3D p2)
{
if(p1.equals(p2))
{
// System.out.println("Got same particles, aborting");
return new Vector3d(0.0,0.0,0.0);
}
//Get the current positions of the particles (for this update cycle)
Vector3d positionp1 = (p1.updated ? p1.lastPosition : p1.position),
positionp2 = (p2.updated ? p2.lastPosition : p2.position);
//Get distance between them
Vector3d vdistance = (Vector3d)positionp2.clone();
vdistance.sub(positionp1);
double fdistance = vdistance.length();
//Get mass of p2
double mass = p2.mass;
//Formula for acceleration due to gravity
double acceleration = (gravity * mass) / (fdistance * fdistance);
////////////////////////////////////////
//Get the acceleration vector
Vector3d vAcceleration = vdistance;
vAcceleration.scale((double)(acceleration / fdistance));
/////////////////////////////////////
return vAcceleration;
}
////////EXPLOSION STUFF/////////////////
BranchGroup explodeBg;
public void explode()
{
ExplodeBehavior exp = new ExplodeBehavior(shape3D, 10, 60, this, 50);
exp.setSchedulingBounds(Physics3DThread.getBoundingSphere());
explodeBg = new BranchGroup();
explodeBg.setCapability(BranchGroup.ALLOW_DETACH);
explodeBg.addChild(exp);
bg.addChild(explodeBg);
}
public WakeupCondition onExplosionFinished( ExplodeBehavior explodeBehavior, Shape3D shape3D )
{
bgRoot.removeChild(bg);
return null;
}
///////////////////////////////////////
///////Collision Stuff/////////
private static Vector3d multMatrixVector(Matrix3d m, Vector3d v)
{
return new Vector3d( m.m00 * v.x + m.m01 * v.y + m.m02 * v.z,
m.m10 * v.x + m.m11 * v.y + m.m12 * v.z,
m.m20 * v.x + m.m21 * v.y + m.m22 * v.z);
}
//Calculate the resultantVelocity of a collision between particles 1 and 2
public static void calculateResultantVelocities(Particle3D p1, Particle3D p2, int time, int i1, int i2)
{
//Get current velocities
Vector3d p1vector = (Vector3d)p1.velocityVector.clone();
Vector3d p2vector = (Vector3d)p2.velocityVector.clone();
Vector3d p1avector = (Vector3d)p1.angularVelocity.clone();
Vector3d p2avector = (Vector3d)p2.angularVelocity.clone();
///////////////////////
Vector3d relPosition1 = new Vector3d(p1.closestFeatures[i2].getPoint());
relPosition1.sub(p1.position);
Vector3d relPosition2 = new Vector3d(p2.closestFeatures[i1].getPoint());
relPosition2.sub(p2.position);
//Calculate relative velocity
Vector3d relativeVelocity = (Vector3d)p1vector.clone();
Vector3d angRel = (Vector3d)p1.angularVelocity.clone();
angRel.cross(angRel, relPosition1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -