立方体をマウスで動かす

立方体をマウスで動かす

 立方体を描きましたが動かないのじゃつまらないので、マウスで動かすことをしてみます。
先ほどの回転行列式の角度を変化させるとできると思うのですが、マウスで動かすために、マウスの動きをセンサーとして使って、マウスの動きを角度の変化にして実行してみます。
また動かすには、角度の変化を累積して、累積した角度を回転行列式に代入して座標を求める方法と、小さい角度の変化を回転行列式に代入して新しい点座標を求めて保存し、この保存した座標から、また小さい角度の変化で新しい座標を計算するやり方と二とおりあると思うのですが、後者のやり方でやってみます。

 前回作成した、MainCubeTest_01、GCanvas、MaPane、Viewp の各クラスファイルは同じですので流用します。
最初は、GFrameの変更を紹介します。マウスのセンサーを設定します。そのためマウスアクションリスナーを設定します。
また、最初の表示に戻すため用にリセットボタンも付けます。


import java.awt.BorderLayout;
import java.awt.Dimension;

import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;
import javax.swing.JButton;
public class GFrame extends JFrame{

		  private MaPane MPane = null;
		  private GCanvas GCan = null;
		  private int DispWidth;
		  private int DispHeight;
		  private JPanel jPanel1 = new JPanel();
		  private BorderLayout borderLayout1 = new BorderLayout();
		  private JScrollPane jScrollPane1 = new JScrollPane();
		  private JButton jButton1 = new JButton();
		  private JToolBar jToolBar1 = new JToolBar();
		  /**
		   * メインフレームを作成する。
		   */
		  
		  public GFrame(Dimension Size){
		    this.DispWidth = Size.width;
		    this.DispHeight = Size.height;
		    // フレームの作成
		    initial();
		  }

		  /**
		   * フレームのイニシャル
		   */
		  void initial(){
		    // キャンバスの作成
		    GCan = new GCanvas();
		    MPane = new MaPane(GCan);	//add
		    // フレームの初期化
		    jInit();
		    jScrollPane1.setViewportView(MPane);
		    Viewp.setViewport(jScrollPane1.getViewport());
		    setSize(DispWidth, DispHeight);
		    setVisible(true);
		    MPane.setLayerSize();
		    // 再描画
		    GCan.repaint();
		  }

		  /**
		   * イベント初期化処理。
		   */
		  private void jInit() {
		    this.addWindowListener(new java.awt.event.WindowAdapter() {
		      public void windowClosing(WindowEvent e) {
		        this_windowClosing(e);
		      }
		    });
		    this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		    this.setTitle("ここはタイトル(^o^) ^o^ ^o^");
		    jButton1.setToolTipText("Reset");
		    jButton1.setBorder(null);
		    jButton1.setText("Reset");
		    jButton1.addActionListener(new java.awt.event.ActionListener() {
		      public void actionPerformed(ActionEvent e) {
		        jButton1_actionPerformed(e);
		      }
		    });	
		    jToolBar1.add(jButton1, null);
		    jPanel1.setLayout(borderLayout1);
		    this.getContentPane().add(jPanel1,  BorderLayout.CENTER);
		    jPanel1.add(jToolBar1, BorderLayout.NORTH);
		    jPanel1.add(jScrollPane1, BorderLayout.CENTER);

		// マウスアクションリスナー
		    jScrollPane1.addMouseListener(new java.awt.event.MouseAdapter() {
		    	public void mousePressed(MouseEvent e) {
		    		jScrollPane1_mousePressed(e);
		    	}
		    });
		    jScrollPane1.setWheelScrollingEnabled(false);
		    jScrollPane1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
		        public void mouseDragged(MouseEvent e) {
		          jScrollPane1_mouseDragged(e);
		        }
		      });
		  }

		  /**
		   * クローズボタンアクションリスナ
		   */
		  private void this_windowClosing(WindowEvent e) {
		    // 確認ダイアログの表示
			  if(JOptionPane.showConfirmDialog(this, "アプリケーションを終了します",
					  this.getTitle(),
					  JOptionPane.OK_CANCEL_OPTION)
					  != JOptionPane.YES_OPTION) { // OK
				  return;
			  }
			  System.exit(0);
		  }

		  /**
		   * resetボタンアクションリスナ		   * 
		   */
		  void jButton1_actionPerformed(ActionEvent e) {
			  CubeVert.setangl();			  
			  GCan.repaint();
		  }
		  
		  /**
		   * マウスアクションリスナ
		   */	
		  // マウスプレスイベント
		  private void jScrollPane1_mousePressed(MouseEvent e) {
			  del_x=e.getX();
			  del_y=e.getY();
		  }

		  // マウスドラッグイベント。

		  private void jScrollPane1_mouseDragged(MouseEvent e) {
			  int dx=e.getX()-del_x;
			  int dy=e.getY()-del_y;
			  del_x=e.getX();
			  del_y=e.getY();
			  phi=dy*sense;
			  theta = dx*sense;
			  CubeVert.setangl(phi,theta);
			  GCan.repaint(); 
		  }
	

		  double phi=0,theta=0;
		  double sense=0.01;
		  
		  int del_x=DrawGraphi.Center_x;
		  int del_y=DrawGraphi.Center_y;

}

マウスの位置の変化は、マウスをドラッグした時に求めています。マウスの変化と画面の変化が一致するようにxyの符号や変化量を調整するなどして下さい。
マウスドラッグがあるたびに、リペイントして、再表示するようにしています。リペイントされるとGCanの再描画処理に飛び、DrawGraphiのDrawメソッドで処理されます。
次は座標位置を累積記憶するCubeVertの処理です。


public class CubeVert {
	public static Vertex vt[];
	public static Vertex ax[];
	static int vt_num=8;
	static double phi0=0.1;
	static double theta0=-0.2;
	static double phi=phi0;
	static double theta=theta0;
	
	  // 初期化されないコンストラクタ
	  private CubeVert(){
		  setReangl();
	  }
	
	public static int getVt_num() {
		return vt_num;
	}
	
	  public static  void setModelData() {
	        vt  = new Vertex[vt_num];
	        ax=new Vertex[3];
	        vt[0]=new Vertex( -1, -1, 1);
	        vt[1]=new Vertex( -1, 1, 1);
	        vt[2]=new Vertex( 1, 1, 1);
	        vt[3]=new Vertex( 1, -1, 1);
	        vt[4]=new Vertex( -1, -1,-1);
	        vt[5]=new Vertex( -1, 1,-1);
	        vt[6]=new Vertex( 1, 1,-1);
	        vt[7]=new Vertex( 1, -1,-1);
	        
	        ax[0]=new Vertex( 2, 0, 0);	//x
	        ax[1]=new Vertex( 0, 2, 0);	//y
	        ax[2]=new Vertex( 0, 0, 2);	//z
	  }

	public static void rotate() {
		double cosp=Math.cos(phi),sinp=Math.sin(phi);
		double cost=Math.cos(theta),sint=Math.sin(theta);	
		double dtx,dty;
		
		for(int i=0;i<vt_num;i++){
			dty=vt[i].y;
			vt[i].y= dty*cosp -vt[i].z*sinp;
			  vt[i].z= dty*sinp +vt[i].z*cosp;
			  dtx=vt[i].x;
			  vt[i].x= dtx*cost +vt[i].z*sint;
			  vt[i].z= -dtx*sint +vt[i].z*cost;
		 }

		for(int i=0;i<3;i++){
			dty=ax[i].y;
			ax[i].y= dty*cosp -ax[i].z*sinp;
			ax[i].z= dty*sinp +ax[i].z*cosp;
			dtx=ax[i].x;
			ax[i].x= dtx*cost +ax[i].z*sint;
			ax[i].z= -dtx*sint +ax[i].z*cost;
		 }
	}

	public static void setangl(double phai, double thet) {
		phi=phai;
		theta=thet;		
	}
	public static void setangl() {
		setReangl();
		setModelData();
	}
	
	static void setReangl(){
		phi=phi0;
		theta=theta0;	
	}
}

//==================
// Vertex クラス
//==================
  class Vertex
  {
      public double x,y,z;
  
      public Vertex(double x,double y,double z)
      {
          this.x = x;
          this.y = y;
          this.z = z;
      }
  }

頂点の配列は、計算が面倒になったので、立方体の中心を原点0にし、各頂点の位置データを配列にしています。またXYZ軸も配列にしてしまいました。実にスマートではなく素人のやり方です。中心を原点0にしたのでマイナスの数値も扱うことになったので、配列位置データVertexはintではなくdoubleに変更しました。
その他は、回転行列の計算であったり、初期値の設定用のメソッドを追加したりです。

 次は立方体を描く、DrawGraphiの処理です。


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;

public class DrawGraphi {

	
		static int Center_y;
		static int Center_x;
	   
	DrawGraphi(){
		initial();
	}

	void initial(){
		CubeVert.setModelData();
	}
	
	public void Draw(Graphics g){
		Graphics2D g2 = (Graphics2D)g;

		g2.setBackground(backColor);
		g2.clearRect(0,0,600,600);
		g2.setColor(dc);

		vtt=CubeVert.getVt_num();
		int Canvas_w = 600;
		int Canvas_h = 600;
			Center_x= Canvas_w/2;
			Center_y= Canvas_h/2;
		int x0,y0;
		int g_Scale=100;
		int line[][]=new int[8][2];
		CubeVert.rotate();
		for(int i=0;i<vtt;i++){
			x0=(int)((CubeVert.vt[i].x) * g_Scale) ;
			y0=(int)((CubeVert.vt[i].y) * g_Scale) ;
			line[i][0]=x0;line[i][1]=y0;
		}

		g2.setColor(new Color(255,255,255));	//white
		for(int j=0;j<vtt;j++){
			if(j==3){
				g2.drawLine(Center_x+line[j][0],Center_y-line[j][1],Center_x+line[j-3][0],Center_y-line[j-3][1]);				
				
			}else if(j==7){	//うまくor処理ができないので分離した
				g2.drawLine(Center_x+line[j][0],Center_y-line[j][1],Center_x+line[j-3][0],Center_y-line[j-3][1]);				
			}else{
				g2.drawLine(Center_x+line[j][0],Center_y-line[j][1],Center_x+line[j+1][0],Center_y-line[j+1][1]);				
			}
		}
		for(int i=0;i<vtt/2;i++){
			g2.drawLine(Center_x+line[i][0],Center_y-line[i][1],Center_x+line[i+4][0],Center_y-line[i+4][1]);				
		}
		
		//xyz line
		g2.setColor(new Color(100,255,255));	//シアン
		
		for(int i=0;i<3;i++){
			if(i==1){
				g2.setColor(new Color(0,255,0));	//green
			}else if(i==2){
				g2.setColor(new Color(0,0,255));	//blue
			}
			x0=(int)((CubeVert.ax[i].x) * g_Scale) ;
			y0=(int)((CubeVert.ax[i].y) * g_Scale) ;
			g2.drawLine(Center_x,Center_y,Center_x+x0,Center_y-y0);
		}		
	  }
		int vtt=0;
		private Color dc =new Color(255,0,255);	//pink
		private Color backColor = new Color(0,0,80);//dark blue
}


 回転計算は、CubeVert.rotate()で実行し、結果は配列に格納されますので、ここでは配列のデータから表示する処理です。
●文字は位置合わせが面倒なのでやめて、立方体の線だけにしました。



実行すると、右図のようになります。
マウスをドラッグすると、立方体が変化しましたでしょうか?。リセットボタンで最初の表示になりましたでしょうか?