package framework.model3D;
import java.util.ArrayList;
import java.util.Enumeration;
import java3d.BoundingPolytope;
import java3d.Box;
import java3d.Cone;
import java3d.Cylinder;
import java3d.IndexedTriangleArray;
import java3d.IndexedTriangleFanArray;
import java3d.IndexedTriangleStripArray;
import java3d.Node;
import java3d.TriangleStripArray;
import java3d.Vector3d;
import java3d.Vector4d;
import java3d.Appearance;
import java3d.Geometry;
import java3d.Shape3D;
import java3d.Sphere;
import java3d.TransformGroup;
import java3d.TriangleArray;
import java3d.TriangleFanArray;
public class BaseObject3D implements Placeable {
public TransformGroup center;
protected BoundingSurface[] boundingSurfaces = null;
public BaseObject3D() {
center = new TransformGroup();
}
public BaseObject3D(Geometry g, Appearance a) {
center = new TransformGroup();
Shape3D shape = new Shape3D(g, a);
center.addChild(shape);
}
@Override
public TransformGroup getTransformGroupToPlace() {
return getBody().center;
}
public BaseObject3D getBody() {
return this;
}
public Node getPrimitiveNode() {
return (Node)center.getChild(0);
}
public Enumeration<Node> getPrimitiveNodes() {
return (Enumeration<Node>)center.getAllChildren();
}
/**
* 衝突判定用のボリューム(ポリゴンと粗い判定用の多角柱)を取得する
* @return 衝突判定用のボリューム列
*/
public BoundingSurface[] getBoundingSurfaces() {
if (boundingSurfaces == null) {
Node node = getPrimitiveNode();
if (node == null) return null;
ArrayList<Vector3d> vertex3DList = null;
if (node instanceof Box) {
// Boxの場合
Box box = ((Box)node);
// 頂点列を取得する
vertex3DList = getVertexList(box.getShape(Box.BACK).getGeometry());
vertex3DList.addAll(getVertexList(box.getShape(Box.BOTTOM).getGeometry()));
vertex3DList.addAll(getVertexList(box.getShape(Box.FRONT).getGeometry()));
vertex3DList.addAll(getVertexList(box.getShape(Box.LEFT).getGeometry()));
vertex3DList.addAll(getVertexList(box.getShape(Box.RIGHT).getGeometry()));
vertex3DList.addAll(getVertexList(box.getShape(Box.TOP).getGeometry()));
} else if (node instanceof Cylinder) {
// Cylinderの場合
Cylinder cylinder = ((Cylinder)node);
// 頂点列を取得する
vertex3DList = getVertexList(cylinder.getShape(Cylinder.BODY).getGeometry());
vertex3DList.addAll(getVertexList(cylinder.getShape(Cylinder.BOTTOM).getGeometry()));
vertex3DList.addAll(getVertexList(cylinder.getShape(Cylinder.TOP).getGeometry()));
} else if (node instanceof Cone) {
// Coneの場合
Cone cone = ((Cone)node);
// 頂点列を取得する
vertex3DList = getVertexList(cone.getShape(Cone.BODY).getGeometry());
vertex3DList.addAll(getVertexList(cone.getShape(Cone.CAP).getGeometry()));
} else if (node instanceof Sphere) {
// Sphereの場合
Sphere sphere = ((Sphere)node);
// 頂点列を取得する
vertex3DList = getVertexList(sphere.getShape(Sphere.BODY).getGeometry());
} else if (node instanceof Shape3D) {
// Shape3Dの場合
Shape3D shape = (Shape3D)node;
// 頂点列を取得する
vertex3DList = getVertexList(shape.getGeometry());
}
if (vertex3DList == null) return null;
BoundingSurface[] surfaces = new BoundingSurface[vertex3DList.size() / 3];
for (int i = 0; i < vertex3DList.size(); i += 3) {
Vector3d v1 = vertex3DList.get(i);
Vector3d v2 = vertex3DList.get(i + 1);
Vector3d v3 = vertex3DList.get(i + 2);
BoundingSurface bSurface = new BoundingSurface();
bSurface.addVertex((Vector3d)v1.clone());
bSurface.addVertex((Vector3d)v2.clone());
bSurface.addVertex((Vector3d)v3.clone());
bSurface.setBounds(createBoundingPolytope(v1, v2, v3));
surfaces[i / 3] = bSurface;
}
boundingSurfaces = surfaces;
}
return boundingSurfaces;
}
private ArrayList<Vector3d> getVertexList(Geometry g) {
ArrayList<Vector3d> vertex3DList = new ArrayList<Vector3d>();
double coordinate1[] = new double[3];
if (g instanceof IndexedTriangleArray) {
// IndexedTriangleArray の場合
IndexedTriangleArray triArray = (IndexedTriangleArray)g;
// 全頂点を3D上の頂点をvertex3DListに入れていく。
for (int i = 0; i < triArray.getIndexCount(); i++) {
triArray.getCoordinates(triArray.getCoordinateIndex(i), coordinate1);
vertex3DList.add(new Vector3d(coordinate1));
}
} else if (g instanceof TriangleArray) {
// TriangleArray の場合
TriangleArray triArray = (TriangleArray)g;
// 全頂点を3D上の頂点をvertex3DListに入れていく。
for (int i = 0; i < triArray.getVertexCount(); i++) {
triArray.getCoordinates(i, coordinate1);
vertex3DList.add(new Vector3d(coordinate1));
}
} else if (g instanceof IndexedTriangleStripArray) {
// IndexedTriangleStripArray の場合
IndexedTriangleStripArray triStripAttay = (IndexedTriangleStripArray)g;
int stripVertexCounts[] = new int[triStripAttay.getNumStrips()];
triStripAttay.getStripIndexCounts(stripVertexCounts);
// 全頂点を3D上の頂点をvertex3DListに入れていく
int index = 0;
double coordinate2[] = new double[3];
double coordinate3[] = new double[3];
double coordinate4[] = new double[3];
for (int i = 0; i < triStripAttay.getNumStrips(); i++) {
for (int j = 0; j < stripVertexCounts[i]; j += 2) {
triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index), coordinate1);
triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+1), coordinate2);
triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+2), coordinate3);
triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+3), coordinate4);
vertex3DList.add(new Vector3d(coordinate1)); //1つめの三角形
vertex3DList.add(new Vector3d(coordinate2));
vertex3DList.add(new Vector3d(coordinate3));
vertex3DList.add(new Vector3d(coordinate2)); //2つめの三角形
vertex3DList.add(new Vector3d(coordinate4));
vertex3DList.add(new Vector3d(coordinate3));
index += 2;
}
}
} else if (g instanceof TriangleStripArray) {
// TriangleStripArray の場合
TriangleStripArray triStripAttay = (TriangleStripArray)g;
int stripVertexCounts[] = new int[triStripAttay.getNumStrips()];
triStripAttay.getStripVertexCounts(stripVertexCounts);
// 全頂点を3D上の頂点をvertex3DListに入れていく
int index = 0;
double coordinate2[] = new double[3];
double coordinate3[] = new double[3];
double coordinate4[] = new double[3];
for (int i = 0; i < triStripAttay.getNumStrips(); i++) {
for (int j = 0; j < stripVertexCounts[i]; j += 2) {
triStripAttay.getCoordinates(index, coordinate1);
triStripAttay.getCoordinates(index+1, coordinate2);
triStripAttay.getCoordinates(index+2, coordinate3);
triStripAttay.getCoordinates(index+3, coordinate4);
vertex3DList.add(new Vector3d(coordinate1)); //1つめの三角形
vertex3DList.add(new Vector3d(coordinate2));
vertex3DList.add(new Vector3d(coordinate3));
vertex3DList.add(new Vector3d(coordinate2)); //2つめの三角形
vertex3DList.add(new Vector3d(coordinate4));
vertex3DList.add(new Vector3d(coordinate3));
index += 2;
}
}
} else if (g instanceof IndexedTriangleFanArray) {
// IndexedTriangleFanArray の場合
IndexedTriangleFanArray triFanAttay = (IndexedTriangleFanArray)g;
int stripVertexCounts[] = new int[triFanAttay.getNumStrips()];
triFanAttay.getStripIndexCounts(stripVertexCounts);
// 全頂点を3D上の頂点をvertex3DListに入れていく
int index = 0;
double coordinate2[] = new double[3];
double coordinate3[] = new double[3];
double coordinate4[] = null;
for (int i = 0; i < triFanAttay.getNumStrips(); i++) {
triFanAttay.getCoordinates(triFanAttay.getCoordinateIndex(index), coordinate1); // 中心点
triFanAttay.getCoordinates(triFanAttay.getCoordinateIndex(index+1), coordinate2);
index += 2;
for (int j = 2; j < stripVertexCounts[i]; j++) {
triFanAttay.getCoordinates(triFanAttay.getCoordinateIndex(index), coordinate3);
vertex3DList.add(new Vector3d(coordinate1));
vertex3DList.add(new Vector3d(coordinate2));
vertex3DList.add(new Vector3d(coordinate3));
coordinate4 = coordinate2;
coordinate2 = coordinate3;
coordinate3 = coordinate4;
index++;
}
}
} else if (g instanceof TriangleFanArray) {
// TriangleFanArray の場合
TriangleFanArray triFanAttay = (TriangleFanArray)g;
int stripVertexCounts[] = new int[triFanAttay.getNumStrips()];
triFanAttay.getStripVertexCounts(stripVertexCounts);
// 全頂点を3D上の頂点をvertex3DListに入れていく
int index = 0;
double coordinate2[] = new double[3];
double coordinate3[] = new double[3];
double coordinate4[] = null;
for (int i = 0; i < triFanAttay.getNumStrips(); i++) {
triFanAttay.getCoordinates(index, coordinate1); // 中心点
triFanAttay.getCoordinates(index + 1, coordinate2);
index += 2;
for (int j = 2; j < stripVertexCounts[i]; j++) {
triFanAttay.getCoordinates(index, coordinate3);
vertex3DList.add(new Vector3d(coordinate1));
vertex3DList.add(new Vector3d(coordinate2));
vertex3DList.add(new Vector3d(coordinate3));
coordinate4 = coordinate2;
coordinate2 = coordinate3;
coordinate3 = coordinate4;
index++;
}
}
} else {
return null;
}
return vertex3DList;
}
protected BoundingPolytope createBoundingPolytope(Vector3d vertex1,
Vector3d vertex2, Vector3d vertex3) {
Vector3d v1 = new Vector3d();
Vector3d v2 = new Vector3d();
Vector3d v3 = new Vector3d();
Vector3d v4 = new Vector3d();
Vector3d v5 = new Vector3d();
Vector3d v6 = new Vector3d();
Vector3d cv1 = new Vector3d();
Vector3d cv2 = new Vector3d();
cv1.sub(vertex3, vertex1);
cv2.sub(vertex2, vertex1);
Vector3d cv = new Vector3d();
cv.cross(cv1, cv2);
cv.normalize();
cv.scale(0.01);
v1.set(vertex1);
v2.set(vertex2);
v3.set(vertex3);
v4.set(vertex1);
v4.add(cv);
v5.set(vertex2);
v5.add(cv);
v6.set(vertex3);
v6.add(cv);
Vector3d pv1 = new Vector3d();
Vector3d pv2 = new Vector3d();
Vector3d pv3 = new Vector3d();
Vector3d pn = new Vector3d();
Vector4d[] plane = new Vector4d[5];
// 0
pv1 = v1;
pv2.sub(v2, v1);
pv3.sub(v3, v1);
pn.cross(pv2, pv3);
pn.normalize();
plane[0] = new Vector4d(pn.x, pn.y, pn.z, -pn.dot(pv1));
// 1
pv1 = v1;
pv2.sub(v4, v1);
pv3.sub(v2, v1);
pn.cross(pv2, pv3);
pn.normalize();
plane[1] = new Vector4d(pn.x, pn.y, pn.z, -pn.dot(pv1));
// 2
pv1 = v1;
pv2.sub(v3, v1);
pv3.sub(v4, v1);
pn.cross(pv2, pv3);
pn.normalize();
plane[2] = new Vector4d(pn.x, pn.y, pn.z, -pn.dot(pv1));
// 3
pv1 = v6;
pv2.sub(v3, v6);
pv3.sub(v5, v6);
pn.cross(pv2, pv3);
pn.normalize();
plane[3] = new Vector4d(pn.x, pn.y, pn.z, -pn.dot(pv1));
// 4
pv1 = v6;
pv2.sub(v5, v6);
pv3.sub(v4, v6);
pn.cross(pv2, pv3);
pn.normalize();
plane[4] = new Vector4d(pn.x, pn.y, pn.z, -pn.dot(pv1));
return new BoundingPolytope(plane);
}
public boolean hasAppearancePrepared() {
return true;
}
}