⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 particle3d.java

📁 运用java3D模拟刚体间的碰撞,爆炸及在万有引力作用下的运动轨迹,设置适当的参数可以模拟天体运动等多种物理现象.
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/***************************************************

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 + -