TruncatedCone.java は、こちらをお使いください。
フラグやx,y分割数等に関してプリミティブの仕様に完全に一致させたつもりです。
前回のコードは、破棄してください。
import javax.media.j3d.Appearance;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.Group;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.TriangleFanArray;
import javax.vecmath.Point3d;
import com.sun.j3d.utils.geometry.GeometryInfo;
import com.sun.j3d.utils.geometry.NormalGenerator;
import com.sun.j3d.utils.geometry.Primitive;
import com.sun.j3d.utils.geometry.Stripifier;
/**
* プリミティブ図形と同等なコンストラクタによって、円錐台を生成します。
* 用法もプリミティブ図形と同じです。
*/
public class TruncatedCone extends Group {
/** 上面を表すpartID */
public static final int TOP = 0;
/** 側面を表すpartID */
public static final int BODY = 1;
/** 底面を表すpartID */
public static final int BOTTOM = 2;
/** 法線を生成するための定数 */
public static final int GENERATE_NORMALS = Primitive.GENERATE_NORMALS;
/** 裏面の法線を生成するための定数 */
public static final int GENERATE_NORMALS_INWARD = Primitive.GENERATE_NORMALS_INWARD;
/** テクスチャ座標を生成するための定数 */
public static final int GENERATE_TEXTURE_COORDS = Primitive.GENERATE_TEXTURE_COORDS;
/** ピッキングを許可するための定数 */
public static final int ENABLE_GEOMETRY_PICKING = Primitive.ENABLE_GEOMETRY_PICKING;
/** アピアランスの更新を許可するための定数 */
public static final int ENABLE_APPEARANCE_MODIFY = Primitive.ENABLE_APPEARANCE_MODIFY;
/**
* 上面半径 0.5 底面半径 1.0 高さ 2.0 の円錐台を生成します。
*/
public TruncatedCone() {
this( 0.5, 1.0, 2.0 );
}
/**
* 上面半径, 底面半径, 高さ を指定して円錐台を生成します。
* @param topRadius 上面半径
* @param bottomRadius 底面半径
* @param height 高さ
*/
public TruncatedCone( double topRadius, double bottomRadius, double height ) {
this( topRadius, bottomRadius, height, GENERATE_NORMALS );
}
/**
* 上面半径, 底面半径, 高さ 及び アピアランスを指定して円錐台を生成します。
* @param topRadius 上面半径
* @param bottomRadius 底面半径
* @param height 高さ
* @param appearance アピアランス
*/
public TruncatedCone( double topRadius, double bottomRadius, double height, Appearance appearance ) {
this( topRadius, bottomRadius, height, GENERATE_NORMALS, 15, 1, appearance );
}
/**
* 上面半径, 底面半径, 高さ 及び フラグを指定して円錐台を生成します。
* @param topRadius 上面半径
* @param bottomRadius 底面半径
* @param height 高さ
* @param primflags フラグ
*/
public TruncatedCone( double topRadius, double bottomRadius, double height, int primflags ) {
this( topRadius, bottomRadius, height, primflags, 15, 1, null );
}
/**
* 円錐台を生成します。
* 引数の意味は基本的に組込のプリミティブ図形と同じです。
* @param topRadius 上面半径
* @param bottomRadius 底面半径
* @param height 高さ
* @param primflags フラッグ
* @param xDivision x方向分割数
* @param xDivision y方向分割数
* @param appearance アピアランス
*/
public TruncatedCone( double topRadius, double bottomRadius, double height, int primflags, int xDivision, int yDivision, Appearance appearance ) {
boolean isNormals = (primflags & GENERATE_NORMALS) == GENERATE_NORMALS;
boolean isTexture = (primflags & GENERATE_TEXTURE_COORDS) == GENERATE_TEXTURE_COORDS;
int geometryFlags = GeometryArray.COORDINATES | (isNormals ? GeometryArray.NORMALS : 0) | (isTexture ? GeometryArray.TEXTURE_COORDINATE_4 : 0);
boolean isBackFace = (primflags & GENERATE_NORMALS_INWARD) == GENERATE_NORMALS_INWARD;
boolean isGeometryPicking = (primflags & ENABLE_GEOMETRY_PICKING) == ENABLE_GEOMETRY_PICKING;
boolean isAppearanceModify = (primflags & ENABLE_APPEARANCE_MODIFY) == ENABLE_APPEARANCE_MODIFY;
if( isBackFace ) {
if( appearance == null ) {
appearance = new Appearance();
}
appearance.setPolygonAttributes( new PolygonAttributes( PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_FRONT, 0, isBackFace ) );
}
if( isAppearanceModify ) {
if( appearance == null ) {
appearance = new Appearance();
}
appearance.setCapability( Appearance.ALLOW_POLYGON_ATTRIBUTES_READ );
appearance.setCapability( Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE );
}
addChild( new Shape3D( getTop(topRadius, height, xDivision, geometryFlags, isGeometryPicking, isNormals), appearance ) );
addChild( new Shape3D( getBody(topRadius, bottomRadius, height, xDivision, yDivision, geometryFlags, isGeometryPicking, isNormals), appearance ) );
addChild( new Shape3D( getBottom(bottomRadius, height, xDivision, geometryFlags, isGeometryPicking, isNormals), appearance ) );
}
/* 上面作製部 */
private GeometryArray getTop( double topRadius, double height, int xDivision, int geometryFlags, boolean isGeometryPicking, boolean isNormals ) {
GeometryArray topSurface = new TriangleFanArray( xDivision+2, geometryFlags, new int[]{xDivision+2} );
if( isGeometryPicking ) {
topSurface.setCapability( GeometryArray.ALLOW_INTERSECT );
}
Point3d[] topGeometries = new Point3d[xDivision+2]; // 上面座標
topGeometries[0] = new Point3d(0.0,height/2,0.0);
for(int i=0; i<=xDivision; i++) {
double theta = -2*Math.PI*i/xDivision;
topGeometries[i+1] = new Point3d( topRadius*Math.cos(theta), height/2, topRadius*Math.sin(theta) );
}
topSurface.setCoordinates( 0, topGeometries );
if( isNormals ) {
GeometryInfo topInfo = new GeometryInfo(topSurface);
NormalGenerator normalGenerator = new NormalGenerator();
normalGenerator.generateNormals( topInfo ); // 法線ベクトルの自動生成
return topInfo.getIndexedGeometryArray();
} else {
return topSurface;
}
}
/* 側面作製部 */
private GeometryArray getBody( double topRadius, double bottomRadius, double height, int xDivision, int yDivision, int geometryFlags, boolean isGeometryPicking, boolean isNormals ) {
GeometryArray bodySurface = new QuadArray( 4*xDivision*yDivision, geometryFlags );
if( isGeometryPicking ) {
bodySurface.setCapability( GeometryArray.ALLOW_INTERSECT );
}
Point3d[] bodyGeometries = new Point3d[4*xDivision*yDivision]; // 上面座標
bodyGeometries[0] = new Point3d(0.0,-height/2,0.0);
for(int i=0; i<xDivision; i++) {
double theta0 = 2*Math.PI*(i+0)/xDivision;
double theta1 = 2*Math.PI*(i+1)/xDivision;
Point3d top0 = new Point3d( topRadius*Math.cos(theta0), height/2, topRadius*Math.sin(theta0));
Point3d top1 = new Point3d( topRadius*Math.cos(theta1), height/2, topRadius*Math.sin(theta1));
Point3d btm0 = new Point3d(bottomRadius*Math.cos(theta0),-height/2,bottomRadius*Math.sin(theta0));
Point3d btm1 = new Point3d(bottomRadius*Math.cos(theta1),-height/2,bottomRadius*Math.sin(theta1));
for(int j=0; j<yDivision; j++) {
Point3d t0 = new Point3d(top0);
Point3d b0 = new Point3d(top0);
Point3d t1 = new Point3d(top1);
Point3d b1 = new Point3d(top1);
t0.interpolate( btm0, (double)(j+0)/yDivision );
b0.interpolate( btm0, (double)(j+1)/yDivision );
t1.interpolate( btm1, (double)(j+0)/yDivision );
b1.interpolate( btm1, (double)(j+1)/yDivision );
bodyGeometries[(i*yDivision+j)*4+0] = t0;
bodyGeometries[(i*yDivision+j)*4+1] = t1;
bodyGeometries[(i*yDivision+j)*4+2] = b1;
bodyGeometries[(i*yDivision+j)*4+3] = b0;
}
}
bodySurface.setCoordinates( 0, bodyGeometries );
if( isNormals ) {
GeometryInfo bodyInfo = new GeometryInfo(bodySurface);
NormalGenerator normalGenerator = new NormalGenerator();
normalGenerator.generateNormals( bodyInfo ); // 法線ベクトルの自動生成
Stripifier stripifier =new Stripifier();
stripifier.stripify( bodyInfo );
return bodyInfo.getIndexedGeometryArray();
} else {
return bodySurface;
}
}
/* 底面作製部 */
private GeometryArray getBottom( double bottomRadius, double height, int xDivision, int geometryFlags, boolean isGeometryPicking, boolean isNormals ) {
GeometryArray bottomSurface = new TriangleFanArray( xDivision+2, geometryFlags, new int[]{xDivision+2} );
if( isGeometryPicking ) {
bottomSurface.setCapability( GeometryArray.ALLOW_INTERSECT );
}
Point3d[] bottomGeometries = new Point3d[xDivision+2]; // 底面座標
bottomGeometries[0] = new Point3d(0.0,-height/2,0.0);
for(int i=0; i<=xDivision; i++) {
double theta = 2*Math.PI*i/xDivision;
bottomGeometries[i+1] = new Point3d( bottomRadius*Math.cos(theta), -height/2, bottomRadius*Math.sin(theta) );
}
bottomSurface.setCoordinates( 0, bottomGeometries );
if( isNormals ) {
GeometryInfo bottomInfo = new GeometryInfo(bottomSurface);
NormalGenerator normalGenerator = new NormalGenerator();
normalGenerator.generateNormals( bottomInfo ); // 法線ベクトルの自動生成
return bottomInfo.getIndexedGeometryArray();
} else {
return bottomSurface;
}
}
/**
* 指定パートのアピアランスを取得します。
* @param partId TOP, BODY, BOTTOM のいずれか
* @return アピアランス
*/
public Appearance getAppearance(int partId) {
return getShape(partId).getAppearance();
}
/**
* アピアランスを設定します。
* @param ap アピアランス
*/
public void setAppearance(Appearance ap) {
for(int i=0; i<3; i++) {
setAppearance( i, ap );
}
}
/**
* 指定パートの図形を取得します。
* @param partId TOP, BODY, BOTTOM のいずれか
* @return 図形
*/
public Shape3D getShape(int partId) {
return (Shape3D)getChild( partId );
}
/**
* 特定パートにのみアピアランスを設定します。
* @param partId TOP, BODY, BOTTOM のいずれか
* @param ap アピアランス
*/
public void setAppearance(int partId, Appearance ap ) {
getShape( partId ).setAppearance( ap );
}
}
お礼
何回にもわたりご丁寧な回答をいただきありがとうございました。 同じ件名の質問に対して、何回かの回答の場合、各々にお礼のポイントを贈らせていただけるのかどうか不明ですが、とりあえずANo3に贈らせていただきたいと思います。
補足
HarukaV49さん、ご丁寧な回答をいただきありがとうございました。 とりあえず、Eclipseにて、示していただいた「TrancatedConeSample」ソースを前回のコード「TruncatedCone」と同じパッケージに保存し、[実行]-[アプリケーションの実行]をしたところ、左から「赤色コーン」、「緑色円錐台」、「青色球」を表示させることができました。 このような方法は私にとって初めてのことでしたので、また少し時間をかけていろいろトライしたいと思います。 とりあえずお礼まで。 お礼ポイントの方は、おって送らせていただきたいと思います。 いろいろとテーマを抱えており、また今後も教えていただく機会があろうかと思います。今後とも、よろしくお願いいたします。 今回は、誠にありがとうございました。