C#:3次元グラフを作る
図形と配列の扱いに慣れてきたので、面グラフを作ってみようと思う。
- ファイルから数値データを読み込み、3次元プロットする。
- 前回の立体回転の画面にグラフ描画機能を追加する。
- Graphボタンを押すとグラフモードに切り替わる。
- あとは立体回転と全く同様に、マウスドラッグやトラックバーで回転させることができる。
- 描画が複雑になるため、新たにグラフ専用の描画クラスを用意する。
- 閉じた立体と異なり、角度によっては面の裏側が見えるので、隠面処理を法線ベクトルと重心の座標の両面から行う。
- 立体回転と同じく、右方向から光が当たっている設定。
- ただしグラフ面の裏側はグレーで塗る。
凹凸のあるグラフでも、以下のように何とか表示できた。クリーム色の面は座標平面のつもり。
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の画像が表示されない件 »