root/graph/JavaPopWeb/src/jp/ac/nime/computer/grpsimulator/VecPr/AnalyzeProjection.java

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. AnalyzeProjection
  2. Parallel
  3. Perspective
  4. Zface
  5. 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;
                        }
                }
        }
}

        

/* [<][>][^][v][top][bottom][index][help] */