package framework.model3D;
import java.util.ArrayList;
import javax.media.j3d.BoundingPolytope;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.Transform3D;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector4d;
public class BoundingSurface implements Cloneable {
private Bounds bounds = null; // 粗い衝突判定用(粗い地面用)
private ArrayList<BoundingSurface> children = new ArrayList<BoundingSurface>();
private ArrayList<Vector3d> vertexList = new ArrayList<Vector3d>();
private static Vector4d plane[] = { new Vector4d(), new Vector4d(), new Vector4d(),
new Vector4d(), new Vector4d() };
public Object clone() {
BoundingSurface s = new BoundingSurface();
if (bounds != null) {
s.setBounds((Bounds)bounds.clone());
}
for (int i = 0; i < children.size(); i++) {
s.children.add((BoundingSurface)children.get(i).clone());
}
for (int i = 0; i < vertexList.size(); i++) {
s.vertexList.add((Vector3d)vertexList.get(i).clone());
}
return s;
}
public void setBounds(Bounds bounds) {
this.bounds = bounds;
}
public Bounds getBounds() {
return bounds;
}
public void addVertex(Vector3d v) {
vertexList.add(v);
}
public void addChild(BoundingSurface bs, boolean bCombineBounds) {
children.add(bs);
if (bCombineBounds) {
if (bounds == null) {
bounds = (Bounds)bs.bounds.clone();
} else {
bounds.combine(bs.bounds);
}
}
}
public void transform(Transform3D transform3D) {
bounds.transform(transform3D);
for (int i = 0; i < vertexList.size(); i++) {
Matrix4d mat4d = new Matrix4d();
transform3D.get(mat4d);
double x = mat4d.m00 * vertexList.get(i).x + mat4d.m01
* vertexList.get(i).y + mat4d.m02 * vertexList.get(i).z
+ mat4d.m03;
double y = mat4d.m10 * vertexList.get(i).x + mat4d.m11
* vertexList.get(i).y + mat4d.m12 * vertexList.get(i).z
+ mat4d.m13;
double z = mat4d.m20 * vertexList.get(i).x + mat4d.m21
* vertexList.get(i).y + mat4d.m22 * vertexList.get(i).z
+ mat4d.m23;
vertexList.get(i).x = x;
vertexList.get(i).y = y;
vertexList.get(i).z = z;
}
}
/**
* BoundingSphereとの粗い衝突判定
* @param bs 衝突判定の対象
* @return 衝突しているBoundingSurfaceのリスト(nullを返すことはない)
*/
public ArrayList<BoundingSurface> intersect(BoundingSphere bs) {
ArrayList<BoundingSurface> results = new ArrayList<BoundingSurface>();
if (children == null || children.size() == 0) {
if (bounds.intersect(bs)) {
results.add(this);
}
} else {
if (bounds == null || bounds.intersect(bs)) {
for (int n = 0; n < children.size(); n++) {
results.addAll(children.get(n).intersect(bs));
}
}
}
return results;
}
/**
* OBBとの詳細な衝突判定
* @param obb 衝突判定の対象
* @return 衝突判定の結果
*/
public CollisionResult intersect(OBB obb) {
if (children == null || children.size() == 0) {
// 葉の場合は、凸ポリゴンを立ち上げた薄い多角柱
if (bounds instanceof BoundingPolytope) {
((BoundingPolytope)bounds).getPlanes(plane);
CollisionResult cr = obb.intersect(plane[0]); // obbが底面を含む無限平面と交わっているか?
if (cr != null) {
// 無限平面と交わっている場合、無限平面との衝突点が凸ポリゴンの内部に位置するか?
if (GeometryUtility.inside(vertexList, cr.collisionPoint.getVector3d(), cr.normal)) {
return cr;
}
}
}
return null;
} else {
for (int n = 0; n < children.size(); n++) {
CollisionResult cr = children.get(n).intersect(obb);
if (cr != null) {
return cr;
}
}
return null;
}
}
}