package org.ntlab.radishforandroidstudio.java3d;
public class Sphere extends Primitive {
public static final int BODY = 0;
static final int MID_REZ_DIV = 16;
private float radius;
int divisions;
private Shape3D bodyShape = null;
public Sphere(float r, Appearance ap){
divisions = MID_REZ_DIV;
radius = r;
// 各面のジオメトリを作成
IndexedTriangleArray bodyGeom = new IndexedTriangleArray(divisions * (divisions / 2 - 1) + 2,
IndexedTriangleArray.COORDINATES | IndexedTriangleArray.NORMALS | IndexedTriangleArray.TEXTURE_COORDINATE_2,
divisions * ((divisions - 2) * 6 + 2 * 3));
// 頂点座標と法線の設定
float coordinates[][] = new float[divisions * (divisions / 2 - 1) + 2][3];
for (int i = 0; i <= divisions / 2; i++) { // 緯度方向のループ(北極から南極に向かって)
if (i == 0) {
// 北極の場合
coordinates[0][0] = 0.0f;
coordinates[0][1] = radius;
coordinates[0][2] = 0.0f;
bodyGeom.setNormal(0, new float[]{0.0f, 1.0f, 0.0f});
} else if (i == divisions / 2) {
// 南極の場合
coordinates[divisions * (divisions / 2 - 1) + 1][0] = 0.0f;
coordinates[divisions * (divisions / 2 - 1) + 1][1] = -radius;
coordinates[divisions * (divisions / 2 - 1) + 1][2] = 0.0f;
bodyGeom.setNormal(divisions * (divisions / 2 - 1) + 1, new float[]{0.0f, -1.0f, 0.0f});
} else {
float y = r * (float) Math.cos(2 * Math.PI * ((double) i / divisions));
float r2 = r * (float) Math.sin(2 * Math.PI * ((double) i / divisions));
for (int j = 0; j < divisions; j++) { // 経度方向のループ
float x = r2 * (float) Math.cos(2 * Math.PI * ((double) j / divisions));
float z = -r2 * (float) Math.sin(2 * Math.PI * ((double) j / divisions));
coordinates[(i - 1) * divisions + j + 1][0] = x;
coordinates[(i - 1) * divisions + j + 1][1] = y;
coordinates[(i - 1) * divisions + j + 1][2] = z;
bodyGeom.setNormal((i - 1) * divisions + j + 1, new float[]{x / r, y / r, z / r});
}
}
}
for (int i = 0; i < divisions * (divisions / 2 - 1) + 2; i++) {
bodyGeom.setCoordinate(i , coordinates[i]);
}
int coordinateIndices[] = new int[divisions * ((divisions - 2) * 6 + 2 * 3)];
int index = 0;
for (int i = 0; i < divisions / 2; i++) {
for (int j = 0; j < divisions; j++) {
if (i == 0) {
// 北極付近
coordinateIndices[index] = 0; // 北極
coordinateIndices[index + 1] = j + 1;
coordinateIndices[index + 2] = (j + 1) % divisions + 1;
index += 3;
} else if (i == divisions / 2 - 1) {
// 南極付近
coordinateIndices[index] = (i - 1) * divisions + j + 1;
coordinateIndices[index + 1] = divisions * (divisions / 2 - 1) + 1; // 南極
coordinateIndices[index + 2] = (i - 1) * divisions + (j + 1) % divisions + 1;
index += 3;
} else {
coordinateIndices[index] = (i - 1) * divisions + j + 1;
coordinateIndices[index + 1] = i * divisions + j + 1;
coordinateIndices[index + 2] = i * divisions + (j + 1) % divisions + 1;
coordinateIndices[index + 3] = (i - 1) * divisions + j + 1;
coordinateIndices[index + 4] = i * divisions + (j + 1) % divisions + 1;
coordinateIndices[index + 5] = (i - 1) * divisions + (j + 1) % divisions + 1;
index += 6;
}
}
}
bodyGeom.setCoordinateIndices(0, coordinateIndices);
float uv[] = { 0, 0, 1, 0, 1, 1, 0, 1, };
bodyGeom.setTextureCoordinates(0, uv); //
// 表面属性の作成
if (ap == null) {
ap = new Appearance();
}
setAppearance(ap);
bodyShape = new Shape3D(bodyGeom, ap);
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
@Override
public Shape3D getShape(int partid) {
switch (partid) {
case BODY:
return bodyShape;
}
return null;
}
@Override
public Node cloneTree() {
Appearance ap = getAppearance();
if (ap != null) {
ap = (Appearance)ap.cloneNodeComponent();
}
Sphere s = new Sphere(radius, ap);
return s;
}
}