barus's diary

とても真面目なblogですにゃ

C#3D立方体ワイヤーフレーム (第2回) for VS2013 Express

f:id:hatakeka:20160912174949g:plain

C#3D立方体ワイヤーフレーム (第1回) for VS2013 Express

に続き2回目、

 

CThreeD.cs  C#3D立方体ワイヤーフレーム (第1回) for VS2013 Express
CBond.cs   C#3D立方体ワイヤーフレーム (第2回) for VS2013 Express
CRubic.cs     C#3D立方体ワイヤーフレーム (第3回) for VS2013 Express
Form1.cs    C#3D立方体ワイヤーフレーム (第4回) for VS2013 Express

 

 

 

CThreeDクラスでは座標を2次元に投影する機能を紹介した。

  

今回はCBondクラスを紹介する。

このクラスを差し替えることで、様々な立体情報を記述する事が出来る。

 

 

 

 

CBondクラス

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Windows.Forms;
using System.Drawing;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        class CBond
        {
            public CThreeD m_pThreeD;

            public Vertex m_Center = new Vertex();  //相対座標の中心
            List m_Vertex = new List();

            public int mGourp_num;      //グループ名の個数

            public CBond(int x, int y, int z, ref CThreeD pThreeD)
            {
                InitBond(x, y, z);
                m_pThreeD = pThreeD;
            }

            /*=============================================================================
             機能  初期化する
             引数  x, y, z : 
            =============================================================================*/
            public void InitBond(int x, int y, int z)
            {
                InitVertex(x - 1, y - 1, z - 1);
            }

            /*=============================================================================
             機能  頂点を初期化する
             引数  x, y, z : 立方体の番号( -1 ~ 1 )
            =============================================================================*/
            public void InitVertex(int x, int y, int z)
            {
                int cx, cy, cz;
                m_Center.x = 0;
                m_Center.y = 0;
                m_Center.z = 0;
                cx = 0; cy = 0; cz = 0;
                mGourp_num = 0;

                MyPoint3D[] A = new MyPoint3D[8];

                A[0] = new MyPoint3D(cx + 100, cy + 100, cz + 100);
                A[1] = new MyPoint3D(cx - 100, cy + 100, cz + 100);
                A[2] = new MyPoint3D(cx - 100, cy - 100, cz + 100);
                A[3] = new MyPoint3D(cx + 100, cy - 100, cz + 100);

                A[4] = new MyPoint3D(cx + 100, cy + 100, cz - 100);
                A[5] = new MyPoint3D(cx - 100, cy + 100, cz - 100);
                A[6] = new MyPoint3D(cx - 100, cy - 100, cz - 100);
                A[7] = new MyPoint3D(cx + 100, cy - 100, cz - 100);

                //コネクト情報

                A[0].bond.Add(1);
                A[1].bond.Add(2);
                A[2].bond.Add(3);
                A[3].bond.Add(0);


                A[4].bond.Add(5);
                A[5].bond.Add(6);
                A[6].bond.Add(7);
                A[7].bond.Add(4);

                A[0].bond.Add(4);
                A[1].bond.Add(5);
                A[2].bond.Add(6);
                A[3].bond.Add(7);


                List result = new List();

                //格納
                for (int i = 0; 8 > i; i++)
                {
                    result.Add(A[i]);
                }

                for (int i = 0; result.Count > i; i++)
                {

                    SetVertex(0, i, result[i].bond, result[i].x, result[i].y, result[i].z);

                }

            }

            /*=============================================================================
             機能  頂点を決める
             引数     group: グループ番号
                         n : 線の番号
                         m : どこと繋がるか
                   x, y, z : 端の座標
            =============================================================================*/
            public void SetVertex(int group, int n, List bond, int x, int y, int z)
            {

                Vertex ver = new Vertex();
                ver.group = group;

                for (int i = 0; bond.Count > i; i++) ver.bond.Add(bond[i]);

                ver.x = x;
                ver.y = y;
                ver.z = z;

                m_Vertex.Add(ver);

            }


            /*=============================================================================
             機能  2次元座標系に変換する(回転行列をつくる)
             引数  ViewPolar : 視点の極座標
            =============================================================================*/
            public void TransferScreen(Polar ViewPolar)
            {
                int i;

                Vertex ver = new Vertex();

                for (i = 0; i < m_Vertex.Count; i++)
                {
                    if (m_Vertex[i] != null)
                    {
                        ver = m_Vertex[i];
                        m_pThreeD.TransferScreen(ViewPolar, ref ver);

                        m_Vertex[i] = ver;
                    }
                }
            }


            /*=============================================================================
             機能  立方体を描画する
             引数  pDC        : メモリデバイスコンテキストへのポインタ
                   ViewVertex : 視点の座標
            =============================================================================*/
            public void DrawBond(Graphics gra, Pen pen, Vertex ViewVertex)
            {
                int i, j;
                Point[] point = new Point[2];

                i = 0;

                for (i = 0; i < m_Vertex.Count; i++)
                {
                    if (m_Vertex[i] != null)
                    {
                        for (j = 0; j < m_Vertex[i].bond.Count; j++)
                        {

                            int c = m_Vertex[i].bond[j]; //接続先

                            point[0].X = m_Center.x + m_Vertex[i].point.X;
                            point[0].Y = m_Center.y + m_Vertex[i].point.Y;

                            point[1].X = m_Center.x + m_Vertex[c].point.X;
                            point[1].Y = m_Center.y + m_Vertex[c].point.Y;


                            gra.DrawLine(pen, point[0], point[1]);

                        }
                    }
                }
            }
        }
    }
}

 


DrawBond   ・・・描画
TransferScreen ・・・座標を2次元に投影。CThreeDクラスに投げる。
SetVertex    ・・・座標情報を格納
InitVertex    ・・・初期の座標情報を作成
CBond     ・・・このプログラムの最初に呼び出される。


立方体なので、サイコロを思い出して欲しいのですが
頂点が8個あるので

MyPoint3D[ ]  A = new MyPoint3D[8];

で、8個の座標を格納する MyPoint3D型 を生成している。

  

       
        A[0] = new MyPoint3D(cx + 100, cy + 100, cz + 100);
                A[1] = new MyPoint3D(cx - 100, cy + 100, cz + 100);
                A[2] = new MyPoint3D(cx - 100, cy - 100, cz + 100);
                A[3] = new MyPoint3D(cx + 100, cy - 100, cz + 100);
 
                A[4] = new MyPoint3D(cx + 100, cy + 100, cz - 100);
                A[5] = new MyPoint3D(cx - 100, cy + 100, cz - 100);
                A[6] = new MyPoint3D(cx - 100, cy - 100, cz - 100);
                A[7] = new MyPoint3D(cx + 100, cy - 100, cz - 100);
 

 

A[0]にx、y、z座標=(  100、  100、 100)

A[1]にx、y、z座標= ー100、  100、 100

A[2]にx、y、z座標= ー100、 ー100、 100

A[3]にx、y、z座標=  100、 ー100、 100

A[4]にx、y、z座標=(  100、  100、ー100)

A[5]にx、y、z座標= ー100、  100、ー100

A[6]にx、y、z座標= ー100、 ー100、ー100

A[7]にx、y、z座標=  100、 ー100、ー100

 

f:id:hatakeka:20160912180241p:plain

 

A[0]から、A[7]には図に示す通り、立方体の頂点を格納した。
cx,cy,czは、この塊を動かす際に用いる。

 

 

 

 

相対座標と絶対座標

cx,cy,czはこの物体の中心座標(相対座標ということにする)

これに対して、絶対座標は第1回のCThreeDクラスの上に定義した以下

 
        //絶対座標の中心
        static public int RUBIC_X = 300;
        static public int RUBIC_Y = 300;
 

 

で示す通り、このプログラム上で動かさない座標(300,300,0)を

絶対座標ということにした。

 

仮に絶対座標がない場合を考えてみる。

ある物体がどのくらい動いたか知りたい場合、

基準(ものさし)となる座標がないと、移動距離が分からない。

 

なので、基準となるものさし絶対座標(動かさない)と、

それに対して相対的に動く座標=相対座標という概念が生まれた。(と思う。)

 

 

 
       //コネクト情報
                
                A[0].bond.Add(1);
                A[1].bond.Add(2);
                A[2].bond.Add(3);
                A[3].bond.Add(0);
                
                
                A[4].bond.Add(5);
                A[5].bond.Add(6);
                A[6].bond.Add(7);
                A[7].bond.Add(4);
                
                A[0].bond.Add(4);
                A[1].bond.Add(5);
                A[2].bond.Add(6);
                A[3].bond.Add(7);
                

 

 

 コネクト情報で、どの点と点を結ぶか情報を与えている。

 

A[0].bond.Add(1); 0から1を接続

A[1].bond.Add(2); 1から2を接続

A[2].bond.Add(3); 2から3を接続

A[3].bond.Add(0); 3から0を接続

 

これを結べば、下記図の赤い四角形になる。

f:id:hatakeka:20160912180241p:plain

 

 同様に青い四角形を接続情報をもたせ、最後に

 

A[0].bond.Add(4);  A(0)とA(4)を接続
A[1].bond.Add(5);  A(1)とA(5)を接続
A[2].bond.Add(6);  A(2)とA(6)を接続
A[3].bond.Add(7);  A(3)とA(7)を接続

 

にて、赤い四角形と、青い四角形を結び立方体としている。

 

 
                List<MyPoint3D> result = new List<MyPoint3D>();
                
                //格納
                for (int i = 0; 8 > i; i++)
                {
                    result.Add(A[i]);
                }
 
                for (int i = 0; result.Count > i; i++)
                {
                    
                    SetVertex(0, i, result[i].bond, result[i].x, result[i].y, result[i].z);
                    
                }
 

 

resultに再度入れているが、ここは別に必要ないっすね。
まあ、List型に入れとくと便利なので使用。

 

SetVertex()で、List<Vertex>型 の m_Vertex に座標を格納。

 

 
   public void TransferScreen(Polar ViewPolar)
            {
                int i;
 
                Vertex ver = new Vertex();
 
                for (i = 0; i < m_Vertex.Count; i++)
                {
                    if (m_Vertex[i] != null)
                    {
                        ver = m_Vertex[i];
                        m_pThreeD.TransferScreen(ViewPolar, ref ver);
 
                        m_Vertex[i] = ver;
                    }
                }
            }
 

 

 

TransferScreen()関数でList<Vertex> の m_Vertex に格納した座標を
マウスが上下に動かした分を、それぞれ角度に見立て、極座標を直行座標に変換し
X軸固定回転、Y軸固定回転のマトリックスで座標変換。

詳細は C#3D立方体ワイヤーフレーム (第1回) for VS2013 Express

 

 
   public void DrawBond(Graphics gra, Pen pen, Vertex ViewVertex)
            {
                int i,j;
                Point[] point = new Point[2];
 
                i = 0;
 
                for (i = 0; i < m_Vertex.Count; i++)
                {
                    if (m_Vertex[i] != null)
                    {
                        for (j = 0; j < m_Vertex[i].bond.Count; j++)
                        {
 
                            int c = m_Vertex[i].bond[j]; //接続先
                            
                            point[0].X = m_Center.x + m_Vertex[i].point.X;
                            point[0].Y = m_Center.y + m_Vertex[i].point.Y;
 
                            point[1].X = m_Center.x + m_Vertex[c].point.X;
                            point[1].Y = m_Center.y + m_Vertex[c].point.Y;
                            
                            
                            gra.DrawLine(pen, point[0], point[1]);
                            
                        }
                    }
                }
            }
 

 

List<Vertex> の m_Vertex に格納した座標の要素数m_Vertex[i].bond.Count;)
のそれぞれの座標に接続するラインを

gra.DrawLine(pen, point[0], point[1]);

で描画している。

 

このクラスをいろいろいじると様々な立体を3D化出来るので
一番楽しいところだ。

 

次の第三回は CRubic クラス。

 

 

終わり

 

 


 

 


 

 


 

作って覚えるVisual C# 2015 デスクトップアプリ入門

作って覚えるVisual C# 2015 デスクトップアプリ入門

 
猫でもわかるC#プログラミング 第3版 (猫でもわかるプログラミング)

猫でもわかるC#プログラミング 第3版 (猫でもわかるプログラミング)