« C#:立体を回転させて表示/その4 | トップページ | IEでlist-style-imageの画像が表示されない件 »

2012年12月28日 (金)

C#:3次元グラフを作る

図形と配列の扱いに慣れてきたので、面グラフを作ってみようと思う。

  1. ファイルから数値データを読み込み、3次元プロットする。
  2. 前回の立体回転の画面にグラフ描画機能を追加する。
  3. Graphボタンを押すとグラフモードに切り替わる。
  4. あとは立体回転と全く同様に、マウスドラッグやトラックバーで回転させることができる。
  5. 描画が複雑になるため、新たにグラフ専用の描画クラスを用意する。
  6. 閉じた立体と異なり、角度によっては面の裏側が見えるので、隠面処理を法線ベクトルと重心の座標の両面から行う。
  7. 立体回転と同じく、右方向から光が当たっている設定。
  8. ただしグラフ面の裏側はグレーで塗る。

凹凸のあるグラフでも、以下のように何とか表示できた。クリーム色の面は座標平面のつもり。

Graph1

Graph4_2

Graph2

Graph3

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

namespace CubicRotate1
{

    public class Form1 : Form//Designer.cs 削除
    {
        private System.ComponentModel.IContainer components = null;
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        PictureBox pb = new PictureBox();
        TrackBar t1 = new TrackBar();
        TrackBar t2 = new TrackBar();
        Label l1 = new Label();
        Label l2 = new Label();
        Label l3 = new Label();
        double rxz = 0;
        double ryz = 0;
        int axz = 0;
        int ayz = 0;
        int axz0 = 0;
        int ayz0 = 0;
        Point mp;
        int ck = 0;
        string[] Cubes = { "正四面体", "立方体", "正八面体", "立方体カット", "六角錐", "複合" };
        double Smin = 40000;
        int axzm = 0;
        int ayzm = 0;
        Button gbutton = new Button();
        double[][][] P;
        double[][][] P0;

        public Form1()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "CubicRotate1";
            this.ClientSize = new Size(300, 300);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
            this.Controls.Add(pb);
            pb.SetBounds(0, 0, 200, 200);
            pb.BackColor = Color.White;
            this.Controls.Add(t1);
            t1.AutoSize = false;
            t1.SetBounds(0, 200, 200, 20);
            t1.TickStyle = TickStyle.None;
            t1.Minimum = 0;
            t1.Maximum = 360;
            t1.Value = axz + 180;
            this.Controls.Add(t2);
            t2.AutoSize = false;
            t2.Orientation = Orientation.Vertical;
            t2.SetBounds(200, 0, 20, 200);
            t2.TickStyle = TickStyle.None;
            t2.Minimum = 0;
            t2.Maximum = 180;
            t2.Value = ayz + 90;
            this.Controls.Add(l1);
            this.Controls.Add(l2);
            this.Controls.Add(l3);
            l1.SetBounds(70, 220, 60, 20);
            l1.TextAlign = ContentAlignment.MiddleCenter;
            l1.Text = "Axz: " + axz.ToString();
            l2.SetBounds(220, 90, 60, 20);
            l2.TextAlign = ContentAlignment.MiddleCenter;
            l2.Text = "Ayz: " + ayz.ToString();
            l3.SetBounds(220, 140, 80, 60);
            l3.TextAlign = ContentAlignment.TopLeft;

            gbutton.SetBounds(220, 0, 80, 60);
            gbutton.Text = "Graph";
            this.Controls.Add(gbutton);

            pb.MouseDown += new MouseEventHandler(pb_MouseDown);
            pb.MouseMove += new MouseEventHandler(pb_MouseMove);

            t1.MouseDown += new MouseEventHandler(t_MouseDown);
            t2.MouseDown += new MouseEventHandler(t_MouseDown);
            t1.ValueChanged += new EventHandler(t_ValueChanged);
            t2.ValueChanged += new EventHandler(t_ValueChanged);

            GroupBox gb = new GroupBox();
            gb.SetBounds(10, 240, 280, 55);
            this.Controls.Add(gb);

            RadioButton[] rd = new RadioButton[Cubes.Length];

            for (int i = 0; i < Cubes.Length; ++i)
            {
                rd[i] = new RadioButton();
                if (i < 3)
                {
                    rd[i].SetBounds(10 + i * 90, 10, 85, 20);
                }
                else
                {
                    rd[i].SetBounds(10 + (i - 3) * 90, 30, 85, 20);
                }
                rd[i].Text = Cubes[i];
                rd[i].CheckedChanged += new EventHandler(rd_CheckedChanged);

            }
            rd[0].Checked = true;
            gb.Controls.AddRange(rd);

            gbutton.Click += new EventHandler(gbutton_Click);

            //座標平面
            P0 = new double[3][][];
            P0[0] = new double[3][];
            P0[1] = new double[3][];
            P0[2] = new double[3][];
            P0[0][0] = new double[3] { 40, 160, -60 };
            P0[0][1] = new double[3] { 100, 160, -60 };
            P0[0][2] = new double[3] { 160, 160, -60 };
            P0[1][0] = new double[3] { 40, 160, 0 };
            P0[1][1] = new double[3] { 100, 160, 0 };
            P0[1][2] = new double[3] { 160, 160, 0 };
            P0[2][0] = new double[3] { 40, 160, 60 };
            P0[2][1] = new double[3] { 100, 160, 60 };
            P0[2][2] = new double[3] { 160, 160, 60 };

            if (ck != 99) { Rotate(); } else { Rotate2(); }
            setFocus();
        }

        void gbutton_Click(object sender, EventArgs e)
        {
            ck = 99;
            P = getTable();
            Rotate2();
            setFocus();
        }

        private double[][][] getTable()
        {
            System.IO.StreamReader r = (new System.IO.StreamReader(@"C:\Data.txt", System.Text.Encoding.Default));
            string src = "";
            while (r.Peek() >= 0)
            {
                string line = r.ReadLine();
                if (line.Length > 2) { src += line + "\n"; }
            }
            r.Close();

            //末尾の改行を除去
            src = src.TrimEnd('\n');
            string[] lines = src.Split('\n');
            double[][][] data = new double[lines.Length][][];
            for (int i = 0; i < lines.Length; ++i)
            {
                string[] ele = lines[i].Split('\t');
                data[i] = new double[ele.Length][];
                int xrange = ele.Length - 1;
                int yrange = lines.Length - 1;
                for (int j = 0; j < ele.Length; ++j)
                {
                    data[i][j] = new double[3];
                    data[i][j][0] = j * (120 / xrange) + 40;
                    data[i][j][1] = 160 - Double.Parse(ele[j]) * 7;
                    data[i][j][2] = i * (120 / yrange) - 60;//データシートの縦方向を奥行き方向に
                }
            }
            return data;
        }

        private void Rotate2()
        {
            int[][][] Q = new int[P.Length][][];
            int[][][] Q0 = new int[P0.Length][][];
            double temp0, temp1, temp2;

            for (int i = 0; i < P.Length; ++i)
            {
                Q[i] = new int[P[i].Length][];
                for(int j = 0; j < P[i].Length; ++j)
                {
                    Q[i][j] = new int[3];
                    //y軸のまわりに回転
                    temp0 = (P[i][j][0] - 100) * Math.Cos(rxz) - P[i][j][2] * Math.Sin(rxz) + 100;
                    temp1 = P[i][j][1];
                    temp2 = (P[i][j][0] - 100) * Math.Sin(rxz) + P[i][j][2] * Math.Cos(rxz);
                    //x軸のまわりに回転
                    Q[i][j][0] = (int)temp0;
                    Q[i][j][1] = (int)((temp1 - 100) * Math.Cos(ryz) - temp2 * Math.Sin(ryz)) + 100;
                    Q[i][j][2] = (int)((temp1 - 100) * Math.Sin(ryz) + temp2 * Math.Cos(ryz));
                }
            }

            for (int i = 0; i < P0.Length; ++i)
            {
                Q0[i] = new int[P0.Length][];
                for (int j = 0; j < P0[i].Length; ++j)
                {
                    Q0[i][j] = new int[3];
                    //y軸のまわりに回転
                    temp0 = (P0[i][j][0] - 100) * Math.Cos(rxz) - P0[i][j][2] * Math.Sin(rxz) + 100;
                    temp1 = P0[i][j][1];
                    temp2 = (P0[i][j][0] - 100) * Math.Sin(rxz) + P0[i][j][2] * Math.Cos(rxz);
                    //x軸のまわりに回転
                    Q0[i][j][0] = (int)temp0;
                    Q0[i][j][1] = (int)((temp1 - 100) * Math.Cos(ryz) - temp2 * Math.Sin(ryz)) + 100;
                    Q0[i][j][2] = (int)((temp1 - 100) * Math.Sin(ryz) + temp2 * Math.Cos(ryz));
                }
            }

            //面の取得
            int[][][][] F = new int[Q.Length - 1][][][];
            int[][][][] F0 = new int[Q0.Length - 1][][][];
            int[][] G = new int[Q.Length - 1][];
            for (int i = 0; i < Q.Length - 1; ++i)
            {
                F[i] = new int[Q[i].Length - 1][][];
                G[i] = new int[F[i].Length];
                for (int j = 0; j < Q[i].Length - 1; ++j)
                {
                    F[i][j] = new int[4][];
                    F[i][j][0] = new int[3] { Q[i][j][0], Q[i][j][1], Q[i][j][2] };
                    F[i][j][1] = new int[3] { Q[i+1][j][0], Q[i+1][j][1], Q[i+1][j][2] };
                    F[i][j][2] = new int[3] { Q[i+1][j+1][0], Q[i+1][j+1][1], Q[i+1][j+1][2] };
                    F[i][j][3] = new int[3] { Q[i][j+1][0], Q[i][j+1][1], Q[i][j+1][2] };
                    G[i][j] = (Q[i][j][2] + Q[i + 1][j][2] + Q[i + 1][j + 1][2] + Q[i][j + 1][2]) / 4;
                }
            }

            int[][] pair = new int[G.Length * G[0].Length][];
            int[] gs = new int[G.Length * G[0].Length];
            int m = 0;
            for (int i = 0; i < G.Length; ++i)
            {
                for (int j = 0; j < G[0].Length; ++j)
                {
                    pair[m] = new int[2] { i, j };
                    gs[m] = G[i][j];
                    ++m;
                }
            }
            Array.Sort(gs, pair);


            for (int i = 0; i < Q0.Length - 1; ++i)
            {
                F0[i] = new int[Q0[i].Length - 1][][];
                for (int j = 0; j < Q0[i].Length - 1; ++j)
                {
                    F0[i][j] = new int[4][];
                    F0[i][j][0] = new int[3] { Q0[i][j][0], Q0[i][j][1], Q0[i][j][2] };
                    F0[i][j][1] = new int[3] { Q0[i + 1][j][0], Q0[i + 1][j][1], Q0[i + 1][j][2] };
                    F0[i][j][2] = new int[3] { Q0[i + 1][j + 1][0], Q0[i + 1][j + 1][1], Q0[i + 1][j + 1][2] };
                    F0[i][j][3] = new int[3] { Q0[i][j + 1][0], Q0[i][j + 1][1], Q0[i][j + 1][2] };
                }
            }

            //法線ベクトル
            double[][] Nx = new double[F.Length][];
            int[][] Nz = new int[F.Length][];
            for (int i = 0; i < F.Length; ++i)
            {
                int[] vec1 = new int[3];
                int[] vec2 = new int[3];
                int[] cr = new int[3];

                if (F[i].Length > 0)
                {
                    Nx[i] = new double[F[i].Length];
                    Nz[i] = new int[F[i].Length];
                    for (int j = 0; j < F[i].Length; ++j)
                    {
                        for (int k = 0; k < 3; ++k)
                        {
                            vec1[k] = F[i][j][1][k] - F[i][j][0][k];
                            vec2[k] = F[i][j][2][k] - F[i][j][1][k];

                        }
                        for (int k = 0; k < 3; ++k)
                        {
                            cr[k] = vec2[(k + 1) % 3] * vec1[(k + 2) % 3] - vec2[(k + 2) % 3] * vec1[(k + 1) % 3];
                        }
                        //法線ベクトルの大きさ
                        double len = Math.Sqrt(cr[0] * cr[0] + cr[1] * cr[1] + cr[2] * cr[2]);
                        //x成分を規格化
                        Nx[i][j] = cr[0] / len;
                        Nz[i][j] = cr[2];
                    }
                }
            }

            Bitmap sheet = new Bitmap(pb.Width, pb.Height);
            Graphics g = Graphics.FromImage(sheet);
            for (int i = 0; i < F0.Length; ++i)
            {
                for (int j = 0; j < F0[i].Length; ++j)
                {
                    if (F[i][j].Length > 0 )
                    {
                        Point[] p = new Point[F0[i][j].Length];
                        for (int l = 0; l < F0[i][j].Length; ++l)
                        {
                            //x,y座標のみ抽出
                            p[l] = new Point(F0[i][j][l][0], F0[i][j][l][1]);
                        }

                        //描画
                        Brush br = Brushes.Bisque;
                        g.FillPolygon(br, p);
                        g.DrawPolygon(Pens.Black, p);
                    }
                }
            }

            for (int r = 0; r < pair.Length; ++r)
            {
                int i = pair[r][0];
                int j = pair[r][1];
                Point[] p = new Point[F[i][j].Length];
                for(int l = 0; l < F[i][j].Length;++l)
                {
                    p[l] = new Point(F[i][j][l][0], F[i][j][l][1]);
                }
                Brush br;
                if (Nz[i][j] < 0) { br = Brushes.Gray; }
                else if (0.7 < Nx[i][j] && Nx[i][j] <= 1) { br = Brushes.LightCyan; }
                else if (0.3 < Nx[i][j] && Nx[i][j] <= 0.7) { br = Brushes.PaleTurquoise; }
                else if (-0.5 < Nx[i][j] && Nx[i][j] <= 0.3) { br = Brushes.Turquoise; }
                else { br = Brushes.DarkCyan; }
                g.FillPolygon(br, p);
                g.DrawPolygon(Pens.Black, p);
            }

            g.Dispose();
            pb.Image = sheet;
        }

        void rd_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton rbutton = sender as RadioButton;
            for (int i = 0; i < Cubes.Length; ++i)
            {
                if (rbutton.Text == Cubes[i])
                {
                    ck = i;
                }
            }
            Smin = 40000;
            Rotate();
            setFocus();
        }

        void setFocus()
        {
            pb.MouseMove -= new MouseEventHandler(pb_MouseMove);
            t1.ValueChanged += new EventHandler(t_ValueChanged);
            t2.ValueChanged += new EventHandler(t_ValueChanged);
            t1.Focus();
            axz0 = axz;
            ayz0 = ayz;
        }

        void t_MouseDown(object sender, MouseEventArgs e)
        {
            pb.MouseMove -= new MouseEventHandler(pb_MouseMove);
            t1.ValueChanged += new EventHandler(t_ValueChanged);
            t2.ValueChanged += new EventHandler(t_ValueChanged);
            axz0 = axz;
            ayz0 = ayz;
        }

        void t_ValueChanged(object sender, EventArgs e)
        {
            axz = t1.Value - 180;
            ayz = t2.Value - 90;

            if (axz > 180) { axz = 180; }
            else if (axz < -180) { axz = -180; }

            if (ayz > 90) { ayz = 90; }
            else if (ayz < -90) { ayz = -90; }

            l1.Text = "Axz: " + axz.ToString();
            l2.Text = "Ayz: " + ayz.ToString();
            rxz = (-1) * axz * Math.PI / 180;
            ryz = ayz * Math.PI / 180;
            if (ck != 99) { Rotate(); } else { Rotate2(); }
        }

        void pb_MouseDown(object sender, MouseEventArgs e)
        {
            t1.ValueChanged -= new EventHandler(t_ValueChanged);
            t2.ValueChanged -= new EventHandler(t_ValueChanged);
            pb.MouseMove += new MouseEventHandler(pb_MouseMove);
            mp = new Point(e.X, e.Y);
            axz0 = axz;
            ayz0 = ayz;
        }

        void pb_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                axz = axz0 + e.X - mp.X;
                ayz = ayz0 + mp.Y - e.Y;

                if (axz >= 180) { axz = 180; }
                else if (axz <= -180) { axz = -180; }

                if (ayz >= 90) { ayz = 90; }
                else if (ayz <= -90) { ayz = -90; }

                t1.Value = axz + 180;
                t2.Value = ayz + 90;
                l1.Text = "Axz: " + axz.ToString();
                l2.Text = "Ayz: " + ayz.ToString();
                rxz = (-1) * axz * Math.PI / 180;
                ryz = ayz * Math.PI / 180;
                if (ck != 99) { Rotate(); } else { Rotate2(); }
            }
        }

        private void Rotate()
        {
            //初期の頂点
            int[] P1 = new int[3];
            int[] P2 = new int[3];
            int[] P3 = new int[3];
            int[] P4 = new int[3];
            int[] P5 = new int[3];
            int[] P6 = new int[3];
            int[] P7 = new int[3];
            int[] P8 = new int[3];
            int[] P9 = new int[3];
            int[] P10 = new int[3];
            //移動後の頂点
            int[] Q1 = new int[3];
            int[] Q2 = new int[3];
            int[] Q3 = new int[3];
            int[] Q4 = new int[3];
            int[] Q5 = new int[3];
            int[] Q6 = new int[3];
            int[] Q7 = new int[3];
            int[] Q8 = new int[3];
            int[] Q9 = new int[3];
            int[] Q10 = new int[3];
            //面
            int[][] F1 = new int[][] { };
            int[][] F2 = new int[][] { };
            int[][] F3 = new int[][] { };
            int[][] F4 = new int[][] { };
            int[][] F5 = new int[][] { };
            int[][] F6 = new int[][] { };
            int[][] F7 = new int[][] { };
            int[][] F8 = new int[][] { };
            int[][] F9 = new int[][] { };
            int[][] F10 = new int[][] { };
            int[][] F11 = new int[][] { };
            int[][] F12 = new int[][] { };

            //点の割り当て
            switch (ck)
            {
                case 0://正四面体
                    P1 = new int[] { 100, 10, 0 };
                    P2 = new int[] { 100, 130, (int)(60 * Math.Sqrt(2)) };
                    P3 = new int[] { 100 + (int)(30 * Math.Sqrt(6)), 130, -(int)(30 * Math.Sqrt(2)) };
                    P4 = new int[] { 100 - (int)(30 * Math.Sqrt(6)), 130, -(int)(30 * Math.Sqrt(2)) };
                    break;
                case 1://立方体
                    P1 = new int[] { 150, 150, 50 };
                    P2 = new int[] { 50, 150, 50 };
                    P3 = new int[] { 50, 50, 50 };
                    P4 = new int[] { 150, 50, 50 };
                    P5 = new int[] { 150, 150, -50 };
                    P6 = new int[] { 50, 150, -50 };
                    P7 = new int[] { 50, 50, -50 };
                    P8 = new int[] { 150, 50, -50 };
                    break;
                case 2://正八面体
                    P1 = new int[] { 190, 100, 0 };
                    P2 = new int[] { 100, 190, 0 };
                    P3 = new int[] { 10, 100, 0 };
                    P4 = new int[] { 100, 10, 0 };
                    P5 = new int[] { 100, 100, 90 };
                    P6 = new int[] { 100, 100, -90 };
                    break;
                case 3://立方体カット
                    P1 = new int[] { 160, 40, -60 };
                    P2 = new int[] { 160, 40, 20 };
                    P3 = new int[] { 80, 40, -60 };
                    P4 = new int[] { 160, 70, 60 };
                    P5 = new int[] { 40, 160, 60 };
                    P6 = new int[] { 40, 70, -60 };
                    P7 = new int[] { 160, 160, -60 };
                    P8 = new int[] { 160, 160, 60 };
                    P9 = new int[] { 40, 160, -60 };
                    break;
                case 4://六角錐
                    P1 = new int[] { 100, 20, 0 };
                    P2 = new int[] { 100, 160, -60 };
                    P3 = new int[] { 100 - (int)(30 * Math.Sqrt(3)), 160, -30 };
                    P4 = new int[] { 100 - (int)(30 * Math.Sqrt(3)), 160, 30 };
                    P5 = new int[] { 100, 160, 60 };
                    P6 = new int[] { 100 + (int)(30 * Math.Sqrt(3)), 160, 30 };
                    P7 = new int[] { 100 + (int)(30 * Math.Sqrt(3)), 160, -30 };
                    break;
                case 5://複合
                    P1 = new int[] { 100, 10, 0 };
                    P2 = new int[] { 100, 130, (int)(60 * Math.Sqrt(2)) };
                    P3 = new int[] { 100 + (int)(30 * Math.Sqrt(6)), 130, -(int)(30 * Math.Sqrt(2)) };
                    P4 = new int[] { 100 - (int)(30 * Math.Sqrt(6)), 130, -(int)(30 * Math.Sqrt(2)) };
                    P5 = new int[] { 100, 190, 0 };
                    P6 = new int[] { 100, 70, -(int)(60 * Math.Sqrt(2)) };
                    P7 = new int[] { 100 + (int)(30 * Math.Sqrt(6)), 70, (int)(30 * Math.Sqrt(2)) };
                    P8 = new int[] { 100 - (int)(30 * Math.Sqrt(6)), 70, (int)(30 * Math.Sqrt(2)) };
                    break;
                default:
                    P1 = new int[] { 190, 100, 0 };
                    P2 = new int[] { 100, 190, 0 };
                    P3 = new int[] { 10, 100, 0 };
                    P4 = new int[] { 100, 10, 0 };
                    P5 = new int[] { 100, 100, 90 };
                    P6 = new int[] { 100, 100, -90 };
                    break;
            }

            int[][] Ps = { P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 };
            int[][] Qs = { Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10 };
            double temp0, temp1, temp2;

            //変換後の頂点の座標
            for (int i = 0; i < Ps.Length; ++i)
            {
                if (Ps[i].Length > 0)
                {
                    //y軸のまわりに回転
                    temp0 = (Ps[i][0] - 100) * Math.Cos(rxz) - Ps[i][2] * Math.Sin(rxz) + 100;
                    temp1 = Ps[i][1];
                    temp2 = (Ps[i][0] - 100) * Math.Sin(rxz) + Ps[i][2] * Math.Cos(rxz);

                    //x軸のまわりに回転
                    Qs[i][0] = (int)temp0;
                    Qs[i][1] = (int)((temp1 - 100) * Math.Cos(ryz) - temp2 * Math.Sin(ryz)) + 100;
                    Qs[i][2] = (int)((temp1 - 100) * Math.Sin(ryz) + temp2 * Math.Cos(ryz));
                }
            }

            //面の割り当て
            switch (ck)
            {
                case 0://正四面体
                    F1 = new int[][] { Q1, Q2, Q3 };
                    F2 = new int[][] { Q1, Q3, Q4 };
                    F3 = new int[][] { Q1, Q4, Q2 };
                    F4 = new int[][] { Q2, Q4, Q3 };
                    break;
                case 1://立方体
                    F1 = new int[][] { Q1, Q4, Q3, Q2 };
                    F2 = new int[][] { Q5, Q6, Q7, Q8 };
                    F3 = new int[][] { Q1, Q2, Q6, Q5 };
                    F4 = new int[][] { Q2, Q3, Q7, Q6 };
                    F5 = new int[][] { Q3, Q4, Q8, Q7 };
                    F6 = new int[][] { Q4, Q1, Q5, Q8 };
                    break;
                case 2://正八面体
                    F1 = new int[][] { Q5, Q2, Q1 };
                    F2 = new int[][] { Q5, Q3, Q2 };
                    F3 = new int[][] { Q5, Q4, Q3 };
                    F4 = new int[][] { Q5, Q1, Q4 };
                    F5 = new int[][] { Q6, Q1, Q2 };
                    F6 = new int[][] { Q6, Q2, Q3 };
                    F7 = new int[][] { Q6, Q3, Q4 };
                    F8 = new int[][] { Q6, Q4, Q1 };
                    break;
                case 3://立方体カット
                    F1 = new int[][] { Q1, Q3, Q2 };
                    F2 = new int[][] { Q2, Q3, Q6, Q5, Q4 };
                    F3 = new int[][] { Q1, Q2, Q4, Q8, Q7 };
                    F4 = new int[][] { Q1, Q7, Q9, Q6, Q3 };
                    F5 = new int[][] { Q4, Q5, Q8 };
                    F6 = new int[][] { Q6, Q9, Q5 };
                    F7 = new int[][] { Q5, Q9, Q7, Q8 };
                    break;
                case 4://六角錐
                    F1 = new int[][] { Q1, Q2, Q3 };
                    F2 = new int[][] { Q1, Q3, Q4 };
                    F3 = new int[][] { Q1, Q4, Q5 };
                    F4 = new int[][] { Q1, Q5, Q6 };
                    F5 = new int[][] { Q1, Q6, Q7 };
                    F6 = new int[][] { Q1, Q7, Q2 };
                    F7 = new int[][] { Q2, Q7, Q6, Q5, Q4, Q3 };
                    break;
                case 5://複合
                    F1 = new int[][] { Q6, Q4, Q1 };
                    F2 = new int[][] { Q6, Q3, Q4 };
                    F3 = new int[][] { Q6, Q1, Q3 };
                    F4 = new int[][] { Q8, Q4, Q2 };
                    F5 = new int[][] { Q8, Q2, Q1 };
                    F6 = new int[][] { Q8, Q1, Q4 };
                    F7 = new int[][] { Q5, Q2, Q4 };
                    F8 = new int[][] { Q5, Q4, Q3 };
                    F9 = new int[][] { Q5, Q3, Q2 };
                    F10 = new int[][] { Q7, Q1, Q2 };
                    F11 = new int[][] { Q7, Q2, Q3 };
                    F12 = new int[][] { Q7, Q3, Q1 };
                    break;
                default:
                    F1 = new int[][] { Q5, Q2, Q1 };
                    F2 = new int[][] { Q5, Q3, Q2 };
                    F3 = new int[][] { Q5, Q4, Q3 };
                    F4 = new int[][] { Q5, Q1, Q4 };
                    F5 = new int[][] { Q6, Q1, Q2 };
                    F6 = new int[][] { Q6, Q2, Q3 };
                    F7 = new int[][] { Q6, Q3, Q4 };
                    F8 = new int[][] { Q6, Q4, Q1 };
                    break;
            }

            int[][][] Fs = { F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12 };

            //法線ベクトル
            double[] Nx = new double[Fs.Length];
            int[] Nz = new int[Fs.Length];
            for (int i = 0; i < Fs.Length; ++i)
            {
                int[] vec1 = new int[3];
                int[] vec2 = new int[3];
                int[] cr = new int[3];

                if (Fs[i].Length > 0)
                {
                    for (int j = 0; j < 3; ++j)
                    {
                        vec1[j] = Fs[i][1][j] - Fs[i][0][j];
                        vec2[j] = Fs[i][2][j] - Fs[i][1][j];
                    }
                    for (int j = 0; j < 3; ++j)
                    {
                        cr[j] = vec2[(j + 1) % 3] * vec1[(j + 2) % 3] - vec2[(j + 2) % 3] * vec1[(j + 1) % 3];
                    }
                    //法線ベクトルの大きさ
                    double len = Math.Sqrt(cr[0] * cr[0] + cr[1] * cr[1] + cr[2] * cr[2]);
                    //x成分を規格化
                    Nx[i] = cr[0] / len;
                    Nz[i] = cr[2];
                }
            }

            Bitmap sheet = new Bitmap(pb.Width, pb.Height);
            Graphics g = Graphics.FromImage(sheet);
            double S = 0;
            for (int i = 0; i < Fs.Length; ++i)
            {
                //法線ベクトルが手前に向いている面のみ処理
                if (Fs[i].Length > 0 && Nz[i] >= 0)
                {
                    Point[] P = new Point[Fs[i].Length];
                    for (int j = 0; j < Fs[i].Length; ++j)
                    {
                        //x,y座標のみ抽出
                        P[j] = new Point(Fs[i][j][0], Fs[i][j][1]);
                        //面積
                        S += Fs[i][j][0] * Fs[i][(j + 1) % Fs[i].Length][1]
                            - Fs[i][(j + 1) % Fs[i].Length][0] * Fs[i][j][1];
                    }

                    //描画
                    Brush br;
                    if (0.7 < Nx[i] && Nx[i] <= 1) { br = Brushes.LightCyan; }
                    else if (0.3 < Nx[i] && Nx[i] <= 0.7) { br = Brushes.PaleTurquoise; }
                    else if (-0.5 < Nx[i] && Nx[i] <= 0.3) { br = Brushes.Turquoise; }
                    else { br = Brushes.DarkCyan; }
                    g.FillPolygon(br, P);
                    g.DrawPolygon(Pens.Black, P);
                }
            }
            g.Dispose();
            pb.Image = sheet;
            S = Math.Abs(S) * 0.5;
            if (S <= Smin) { Smin = S; axzm = axz; ayzm = ayz; }
            l3.Text = "S: " + S.ToString("0.") + "\nSmin: " + Smin.ToString("0.")
                + "\nAxzm: " + axzm.ToString() + "\nAyzm: " + ayzm.ToString();
        }

    }
}

 

 

« C#:立体を回転させて表示/その4 | トップページ | IEでlist-style-imageの画像が表示されない件 »

2019年9月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30          

ブックマーク

無料ブログはココログ