C#で立体を描く簡易的なプログラム

#C#で立体を描くプログラム

立体を描くライブラリはたくさんありますが、今回はそれらは一切使いません。

「極力ライブラリや人の作ったものに頼らない」という考えでやっています。が、高級なことができない・・・。

##立体を描くクラス

```cs:G3D.cs
using System;
using System.Drawing;
using System.Windows.Forms;

namespace _3D
{
    class G3D
    {
        private Bitmap canvas;
        private Graphics g;
        private PictureBox pictureBox;
        private double x_adj, y_adj;
        private double x_theta = 0, y_theta = 0, z_theta = 0;

        public G3D(PictureBox p)
        {
            pictureBox = p;
            canvas = new Bitmap(p.Width, p.Height);
            g = Graphics.FromImage(canvas);
            x_adj = p.Width / 2;
            y_adj = p.Height / 2;
        }

        public void cuboid(double x1, double y1, double z1, double x2, double y2, double z2)
        {
            g.Clear(Color.Black);

            Point[] p = { point_culc(x_theta, y_theta, z_theta, x1, y1, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y1, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y2, z1),
                 point_culc(x_theta, y_theta, z_theta, x1, y2, z1)};

            g.DrawPolygon(Pens.White, p);

            Point[] p1 = { point_culc(x_theta, y_theta, z_theta, x2, y1, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y2, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y2, z2),
                 point_culc(x_theta, y_theta, z_theta, x2, y1, z2)};

            g.DrawPolygon(Pens.White, p1);

            Point[] p2 = { point_culc(x_theta, y_theta, z_theta, x1, y1, z1),
                 point_culc(x_theta, y_theta, z_theta, x1, y2, z1),
                 point_culc(x_theta, y_theta, z_theta, x1, y2, z2),
                 point_culc(x_theta, y_theta, z_theta, x1, y1, z2)};

            g.DrawPolygon(Pens.White, p2);

            Point[] p3 = { point_culc(x_theta, y_theta, z_theta, x1, y1, z2),
                 point_culc(x_theta, y_theta, z_theta, x2, y1, z2),
                 point_culc(x_theta, y_theta, z_theta, x2, y2, z2),
                 point_culc(x_theta, y_theta, z_theta, x1, y2, z2)};

            g.DrawPolygon(Pens.White, p3);

            Point[] p4 = { point_culc(x_theta, y_theta, z_theta, x1, y1, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y1, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y1, z2),
                 point_culc(x_theta, y_theta, z_theta, x1, y1, z2)};

            g.DrawPolygon(Pens.White, p4);

            Point[] p5 = { point_culc(x_theta, y_theta, z_theta, x1, y2, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y2, z1),
                 point_culc(x_theta, y_theta, z_theta, x2, y2, z2),
                 point_culc(x_theta, y_theta, z_theta, x1, y2, z2)};

            g.DrawPolygon(Pens.White, p5);

            g.DrawLine(Pens.Red,
                point_culc(x_theta, y_theta, z_theta, 100, 0, 0),
                point_culc(x_theta, y_theta, z_theta, 0, 0, 0)
                );
            g.DrawLine(Pens.Green,
                point_culc(x_theta, y_theta, z_theta, 0, 100, 0),
                point_culc(x_theta, y_theta, z_theta, 0, 0, 0)
                );
            g.DrawLine(Pens.Yellow,
                point_culc(x_theta, y_theta, z_theta, 0, 0, 100),
                point_culc(x_theta, y_theta, z_theta, 0, 0, 0)
                );

            pictureBox.Image = canvas;
        }

        public void camera_change(double rotx,double roty,double rotz)
        {
            x_theta = rotx;
            y_theta = roty;
            z_theta = rotz;
            theta_lim(ref x_theta);
            theta_lim(ref y_theta);
            theta_lim(ref z_theta);
        }

        public void camera_step(double rotx, double roty, double rotz)
        {
            x_theta += rotx;
            y_theta += roty;
            z_theta += rotz;
            theta_lim(ref x_theta);
            theta_lim(ref y_theta);
            theta_lim(ref z_theta);
        }

        private void theta_lim(ref double t)
        {
            if (t > 360)
            {
                t -= 360;
            }
            if (t < 0)
            {
                t = 360 + t;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="rotx">X軸回転角度</param>
        /// <param name="roty">Y軸回転角度</param>
        /// <param name="rotz">Z軸回転角度</param>
        /// <param name="x">X座標</param>
        /// <param name="y">Y座標</param>
        /// <param name="z">Z座標</param>
        private Point point_culc(double rotx, double roty, double rotz, double x, double y, double z)
        {
            //X軸周りで回転
            double X_x = x * 1;
            double Y_x = y * Math.Cos(rotx * (Math.PI / 180)) - z * Math.Sin(rotx * (Math.PI / 180));
            double Z_x = y * Math.Sin(rotx * (Math.PI / 180)) + z * Math.Cos(rotx * (Math.PI / 180));

            //Y軸周りで回転
            double X_y = X_x * Math.Cos(roty * (Math.PI / 180)) + Z_x * Math.Sin(roty * (Math.PI / 180));
            double Y_y = Y_x * 1;
            double Z_y = -X_x * Math.Sin(roty * (Math.PI / 180)) + Z_x * Math.Cos(roty * (Math.PI / 180));

            //Z軸周りで回転
            double X_z = X_y * Math.Cos(rotz * (Math.PI / 180)) - Y_y * Math.Sin(rotz * (Math.PI / 180));
            double Y_z = X_y * Math.Sin(rotz * (Math.PI / 180)) + Y_y * Math.Cos(rotz * (Math.PI / 180));
            double Z_z = Z_y * 1;

            return new Point((int)(X_z + x_adj), (int)(Y_z + y_adj));
        }
    }
}
```

3D描画するクラスです。
コンストラクタは、描画するための`PictureBox`を引数に取っています。

```cs
void cuboid(double x1, double y1, double z1, double x2, double y2, double z2)
```

`cuboid`関数は、直方体の対角線上にある2点の座標を引数に取ります。
実行すれば、`PictureBox`に直方体を描くことができます。

```cs
void camera_change(double rotx,double roty,double rotz)
```

```cs
void camera_step(double rotx, double roty, double rotz)
```

`camera_change`関数と`camera_step`関数は視点を変える関数です。X,Y,Z軸の回転角度を引数に取ります。
`camera_change`関数は、指定された回転角度にします。
`camera_step`関数は、現在の回転角度から指定された回転角度分だけ回転させます。

##実行結果

![3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590410/4c143b6e-8736-efd5-7718-59bd649f520d.png)