/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- AnalyzeProjection
- Parallel
- Perspective
- Zface
- compareTo
package jp.ac.nime.computer.grpsimulator.VecPr;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.util.*;
/** 画像解析 投影
* @author Kikuchi
* @version 1.0.0
*/
public class AnalyzeProjection {
// クラス変数
private int nWidth_;
private int nHeight_;
protected int nOp_;
protected BufferedImage imgSrc_;
protected BufferedImage imgDst_;
protected int[] nBorder_;
// 画像を線分で表した図形
private Cube cube_[] = new Cube[2];
// ワールド座標位置
private Vertex vcube_[] = new Vertex[2];
/** コンストラクタ
* 物体の座標を内部で作成する
*/
public AnalyzeProjection() {
//cube_[0] = new Cube(40, -70, 0, 220);
//cube_[1] = new Cube(40, 30, 0, 260);
cube_[0] = new Cube(80, 0, 0, 0);
cube_[1] = new Cube(80, 0, 0, 0);
vcube_[0] = new Vertex(-140, 0, 220);
vcube_[1] = new Vertex(40, 0, 260);
}
/** 平行投影 投影面は、xy平面に平行であるとする。視点は、x軸上(y = z = 0)にあるとする。
* 視点(x座標のみ)と投影面(z座標のみ)を指定する
* 出力される画像は、画面左下がワールド座標系の原点に近いとする
* 投影面のz座標は、出力画像に影響しない
* @param img 描画するバッファ
* @param cx カメラのx座標
* @param pz 投影面のz座標
*/
public void Parallel(BufferedImage img, double cx, double pz) {
double sx = (double)img.getWidth() / 2;
double sy = (double)img.getHeight() / 2;
// 描画する面
Zface[] zf = new Zface[12]; // 最大値で確保
for (int i = 0; i < 12; i++)
zf[i] = new Zface();
// 平面数
int num = 0;
// 描画するべき面を選択
for (int i = 0; i < 2; i ++) {
// 図形をワールド座標に変換する行列
Matrix m1 = new Matrix();
m1.rotate(new Vertex(0, 0, 0));
m1.trans(vcube_[i]);
// カメラ座標系に変換する行列
Matrix m2 = new Matrix();
m2.trans(-cx, 0, 0);
m2.revRotate(new Vertex(0, 0, 0));
// あわせた行列
Matrix m3 = Matrix.mul(m1, m2);
// 視線について
Vertex eye = new Vertex(0, 0, 0);
Vertex eye2 = Vertex.mul(eye, Matrix.inverse(m3));
// 座標を変換
for (int j = 0; j < cube_[i].f_.length; j ++) {
/*
Face4 projf = new Face4();
projf.v_[0] = Vertex.mul(cube_[i].f_[j].v_[0], m3);
projf.v_[1] = Vertex.mul(cube_[i].f_[j].v_[1], m3);
projf.v_[2] = Vertex.mul(cube_[i].f_[j].v_[2], m3);
projf.v_[3] = Vertex.mul(cube_[i].f_[j].v_[3], m3);
projf.normal();
// これが見えるか調べる
double dot = Vertex.dot(projf.normal_, eye2);
System.out.println("n , i, j, dot, dist = " + num + ", " + i + ", " + j + ", " + dot + ", " + projf.dist_);
if (dot <= projf.dist_) continue; // 見えない
*/
double dot = Vertex.dot(cube_[i].f_[j].normal_, eye2);
//System.out.println("n , i, j, dot, dist = " + num + ", " + i + ", " + j + ", " + dot + ", " + cube_[i].f_[j].dist_);
if (dot > cube_[i].f_[j].dist_) continue; // 見えない
//if (j != 0) continue;
// 面を登録
// 見えるハズ
// この平面を記憶する
zf[num].f_ = cube_[i].f_[j];
zf[num].m_ = m3; // 変換行列
//System.out.println("n , i, j = " + num + ", " + i + ", " + j);
num ++;
}
}
// 描画するべき面を変換
for (int i = 0; i < num; i ++) {
// 座標を変換
Face4 projf = new Face4();
projf.v_[0] = Vertex.mul(zf[i].f_.v_[0], zf[i].m_);
projf.v_[1] = Vertex.mul(zf[i].f_.v_[1], zf[i].m_);
projf.v_[2] = Vertex.mul(zf[i].f_.v_[2], zf[i].m_);
projf.v_[3] = Vertex.mul(zf[i].f_.v_[3], zf[i].m_);
projf.normal();
// z方向の距離を求めて新たに記憶する
zf[i].f_ = projf;
zf[i].z_ = 0;
for (int k = 0; k < projf.v_.length; k ++) {
zf[i].z_ += projf.v_[k].z_;
}
}
// 平行投影
for (int i = 0; i < num; i ++) {
for (int j = 0; j < 4; j ++) {
zf[i].x_[j] = sx + (zf[i].f_.v_[j].x_);
zf[i].y_[j] = (sy * 2) -(zf[i].f_.v_[j].y_) - sy;
}
}
// z 方向の距離の遠い順にソート
Arrays.sort(zf);
// 背景を白で塗りつぶす
Graphics2D g = img.createGraphics();
g.setBackground(Color.white);
g.clearRect(0, 0, 320, 240);
g.setStroke(new BasicStroke(0.0f)); // 一番細く 引数はfloat
// 遠い順に書く
Color col[] = { Color.blue, Color.cyan, Color.green, Color.red, Color.orange, Color.pink};
for (int i = 0; i < num; i++) {
GeneralPath polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
polygon.moveTo((float)zf[i].x_[0], (float)zf[i].y_[0]);
polygon.lineTo((float)zf[i].x_[1], (float)zf[i].y_[1]);
polygon.lineTo((float)zf[i].x_[2], (float)zf[i].y_[2]);
polygon.lineTo((float)zf[i].x_[3], (float)zf[i].y_[3]);
polygon.closePath();
/*
System.out.print("Face(" + i + ") = ");
for (int j = 0; j < 4; j ++) {
System.out.print( "( " + zf[i].x_[j] + ", " + zf[i].y_[j] + ") ");
}
System.out.println(" ");
*/
// 投影面に書く
g.setColor(col[0]);
g.fill(polygon);
g.setColor(Color.black);
g.draw(polygon);
}
// 文字
g.setColor(Color.black);
g.drawString( "Parallel", 10, 21 );
g.dispose();
}
/*
int sx = img.getWidth() / 2;
int sy = img.getHeight() / 2;
// 背景を白で塗りつぶす
Graphics2D g = img.createGraphics();
// 白でクリア
g.setBackground(Color.white);
g.clearRect(0, 0, 320, 240);
g.setStroke(new BasicStroke(0.0f)); // 一番細く 引数はfloat
// 図形の数だけループ
for (int i = 0; i < 2; i ++) {
double x, y, w, h;
// 平面0だけ描画する
// zを0とする
w = Math.abs(cube_[i].f_[0].v_[1].x_ - cube_[i].f_[0].v_[0].x_);
h = Math.abs(cube_[i].f_[0].v_[3].y_ - cube_[i].f_[0].v_[0].y_);
x = cube_[i].f_[0].v_[0].x_ - cx + sx; // 画面の中央に移動
y = cube_[i].f_[0].v_[0].y_ - h + sy; // 画面の中央に移動
g.setColor(Color.blue);
g.fill(new Rectangle2D.Double(x, y, w, h));
g.setColor(Color.black);
g.draw(new Rectangle2D.Double(x, y, w, h));
System.out.println("x, y, w, h = " + x + ", " + y + ", " + w + ", " + h);
}
// 文字
g.setColor(Color.black);
g.drawString( "Parallel", 10, 21 );
g.dispose();
*/
/** 透視投影 投影面は、xy平面に平行であるとする。視点は、x軸上(y = z = 0)にあるとする。
* 視点(x座標のみ)と投影面(z座標のみ)を指定する
* 出力される画像は、画面左下がワールド座標系の原点に近いとする
* @param img 描画するバッファ
* @param cx カメラのx座標
* @param pz 投影面のz座標
*/
public void Perspective(BufferedImage img, double cx, double pz) {
double sx = (double)img.getWidth() / 2;
double sy = (double)img.getHeight() / 2;
// 描画する面
Zface[] zf = new Zface[12]; // 最大値で確保
for (int i = 0; i < 12; i++)
zf[i] = new Zface();
// 平面数
int num = 0;
// 描画するべき面を選択
for (int i = 0; i < 2; i ++) {
// 図形をワールド座標に変換する行列
Matrix m1 = new Matrix();
m1.rotate(new Vertex(0, 0, 0));
m1.trans(vcube_[i]);
// カメラ座標系に変換する行列
Matrix m2 = new Matrix();
m2.trans(-cx, 0, 0);
m2.revRotate(new Vertex(0, 0, 0));
// あわせた行列
Matrix m3 = Matrix.mul(m1, m2);
// 視線について
Vertex eye = new Vertex(0, 0, 0);
Vertex eye2 = Vertex.mul(eye, Matrix.inverse(m3));
// 座標を変換
for (int j = 0; j < cube_[i].f_.length; j ++) {
/*
Face4 projf = new Face4();
projf.v_[0] = Vertex.mul(cube_[i].f_[j].v_[0], m3);
projf.v_[1] = Vertex.mul(cube_[i].f_[j].v_[1], m3);
projf.v_[2] = Vertex.mul(cube_[i].f_[j].v_[2], m3);
projf.v_[3] = Vertex.mul(cube_[i].f_[j].v_[3], m3);
projf.normal();
// これが見えるか調べる
double dot = Vertex.dot(projf.normal_, eye2);
System.out.println("n , i, j, dot, dist = " + num + ", " + i + ", " + j + ", " + dot + ", " + projf.dist_);
if (dot <= projf.dist_) continue; // 見えない
*/
double dot = Vertex.dot(cube_[i].f_[j].normal_, eye2);
//System.out.println("n , i, j, dot, dist = " + num + ", " + i + ", " + j + ", " + dot + ", " + cube_[i].f_[j].dist_);
if (dot > cube_[i].f_[j].dist_) continue; // 見えない
//if (j != 0) continue;
// 面を登録
// 見えるハズ
// この平面を記憶する
zf[num].f_ = cube_[i].f_[j];
zf[num].m_ = m3; // 変換行列
//System.out.println("n , i, j = " + num + ", " + i + ", " + j);
num ++;
}
}
// 描画するべき面を変換
for (int i = 0; i < num; i ++) {
// 座標を変換
Face4 projf = new Face4();
projf.v_[0] = Vertex.mul(zf[i].f_.v_[0], zf[i].m_);
projf.v_[1] = Vertex.mul(zf[i].f_.v_[1], zf[i].m_);
projf.v_[2] = Vertex.mul(zf[i].f_.v_[2], zf[i].m_);
projf.v_[3] = Vertex.mul(zf[i].f_.v_[3], zf[i].m_);
projf.normal();
// z方向の距離を求めて新たに記憶する
zf[i].f_ = projf;
zf[i].z_ = 0;
for (int k = 0; k < projf.v_.length; k ++) {
zf[i].z_ += projf.v_[k].z_;
}
}
// 透視投影
for (int i = 0; i < num; i ++) {
for (int j = 0; j < 4; j ++) {
double dz = pz / zf[i].f_.v_[j].z_;
zf[i].x_[j] = sx + (zf[i].f_.v_[j].x_ * dz);
zf[i].y_[j] = (sy * 2) -(zf[i].f_.v_[j].y_ * dz) - sy;
}
}
// z 方向の距離の遠い順にソート
Arrays.sort(zf);
// 背景を白で塗りつぶす
Graphics2D g = img.createGraphics();
g.setBackground(Color.white);
g.clearRect(0, 0, 320, 240);
g.setStroke(new BasicStroke(0.0f)); // 一番細く 引数はfloat
// 遠い順に書く
Color col[] = { Color.blue, Color.cyan, Color.green, Color.red, Color.orange, Color.pink};
for (int i = 0; i < num; i++) {
GeneralPath polygon = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
polygon.moveTo((float)zf[i].x_[0], (float)zf[i].y_[0]);
polygon.lineTo((float)zf[i].x_[1], (float)zf[i].y_[1]);
polygon.lineTo((float)zf[i].x_[2], (float)zf[i].y_[2]);
polygon.lineTo((float)zf[i].x_[3], (float)zf[i].y_[3]);
polygon.closePath();
/*
System.out.print("Face(" + i + ") = ");
for (int j = 0; j < 4; j ++) {
System.out.print( "( " + zf[i].x_[j] + ", " + zf[i].y_[j] + ") ");
}
System.out.println(" ");
*/
// 投影面に書く
g.setColor(col[0]);
g.fill(polygon);
g.setColor(Color.black);
g.draw(polygon);
}
// 文字
g.setColor(Color.black);
g.drawString( "Perspective", 10, 21 );
g.dispose();
}
// 描画する面
class Zface implements Comparable {
public Zface() {
z_ = 0;
x_ = new double[4];
y_ = new double[4];
}
Face4 f_;
// 上に対応するzバッファ
double z_;
// 行列
Matrix m_;
// 投影する座標
double[] x_;
double[] y_;
/** 比較メソッド。zの降順にソートしたい。
* @param object 比較対象のZfaceオブジェクト
*/
public int compareTo(Object object) {
Zface operand = (Zface) object;
if (z_ < operand.z_) {
return 1;
} else if (z_ > operand.z_) {
return -1;
} else {
return 0;
}
}
}
}