座標を回転させる(描画図形を回転させる)

座標を回転させる方法をご紹介します。描画図形の回転に使えます。

高校の算数で、三角関数はこういうところに使えるんだよ、って教えることができたら、もっと算数が好きな人が増えると思うのですが。

Fig. 1 初期状態
Fig. 2 座標を30度回転
Fig. 3 座標を60度回転
Fig. 4 座標を90度回転

下記が座標を回転させるメソッドです。

private bool RotatePoint(
				ref double want_x,
				ref double want_y,
				int x,
				int y,
				double radian,
				int org_x,
				int org_y
				)
{

	// あらかじめ三角関数の値を計算しておく.
	double cos = Math.Cos( radian );
	double sin = Math.Sin( radian );

	// いったん座標をシフト移動する.
	double tmp_x = x - org_x;
	double tmp_y = y - org_y;

	// 座標を回転させる.
	double buf_x = (( cos * tmp_x ) - ( sin * tmp_y ));
	double buf_y = (( sin * tmp_x ) + ( cos * tmp_y ));

	// 回転させた座標をシフト移動してもどす.
	want_x = buf_x + org_x;
	want_y = buf_y + org_y;

	return true;

}

全体コード

クリックした点を左上隅座標として初期状態にします。ボタンを押すと図形が回転します。

Form1 に pictureBox1 と button1 を配置してください。

Form1_Load() を定義してください。
button1_Click() を定義してください。
pictureBox1_Paint() を定義してください。
pictureBox1_MouseDown() を定義してください。

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

namespace aaa
{
	public partial class Form1 : Form
	{

		const int RECT_W = 128;
		const int RECT_H =  64;

		int TheX0;
		int TheY0;

		int TheX1;
		int TheY1;

		int TheX2;
		int TheY2;

		int TheX3;
		int TheY3;

		public Form1()
		{
			InitializeComponent();
		}

		private void Form1_Load( object sender, EventArgs e )
		{

			int pw = pictureBox1.Width;
			int ph = pictureBox1.Height;

			// ピクチャボックスの中心座標.
			int org_x = pw >> 1; 
			int org_y = ph >> 1; 

			TheX0 = org_x;
			TheY0 = org_y;

			TheX1 = TheX0 + RECT_W;
			TheY1 = TheY0;

			TheX2 = TheX0 + RECT_W;
			TheY2 = TheY0 + RECT_H;

			TheX3 = TheX0;
			TheY3 = TheY0 + RECT_H;

		}

		private void pictureBox1_Paint( object sender, PaintEventArgs e )
		{

			int pw = pictureBox1.Width;
			int ph = pictureBox1.Height;

			// ピクチャボックスを塗りつぶす.
			Color brush_color = Color.Navy;
			using ( SolidBrush sb = new SolidBrush( brush_color ))
			{
				e.Graphics.FillRectangle( sb, 0, 0, pw, ph );
			}

			// 回転させた矩形を描画する.
			const float PEN_WIDTH_RECT = 3.0f;
			using ( Pen pen = new Pen( Color.Lime, PEN_WIDTH_RECT ))
			{
				// 4点をたどる線を描画.
				e.Graphics.DrawLine( pen, TheX0, TheY0, TheX1, TheY1 );
				e.Graphics.DrawLine( pen, TheX1, TheY1, TheX2, TheY2 );
				e.Graphics.DrawLine( pen, TheX2, TheY2, TheX3, TheY3 );
				e.Graphics.DrawLine( pen, TheX3, TheY3, TheX0, TheY0 );

				// 対角線を描画.
				e.Graphics.DrawLine( pen, TheX0, TheY0, TheX2, TheY2 );
			}

			// 補助線を描画する.
			const float PEN_WIDTH_GUIDE_LINE = 1.0f;
			using ( Pen pen = new Pen( Color.White, PEN_WIDTH_GUIDE_LINE ))
			{
				// 円を描画する.
				const int R = 8;
				int ex = TheX0 - R;
				int ey = TheY0 - R;
				int ew = ( R << 1 );
				int eh = ( R << 1 );
				e.Graphics.DrawEllipse( pen, ex, ey, ew, eh );

				// 十字カーソルを描画する.
				e.Graphics.DrawLine( pen, TheX0, 0, TheX0, ph );
				e.Graphics.DrawLine( pen, 0, TheY0, pw, TheY0 );
			}

		}

		private void pictureBox1_MouseDown( object sender, MouseEventArgs e )
		{

			TheX0 = e.X;
			TheY0 = e.Y;

			TheX1 = TheX0 + RECT_W;
			TheY1 = TheY0;

			TheX2 = TheX0 + RECT_W;
			TheY2 = TheY0 + RECT_H;

			TheX3 = TheX0;
			TheY3 = TheY0 + RECT_H;

			pictureBox1.Invalidate( true );

		}

		private bool RotatePoint(
						ref double want_x,
						ref double want_y,
						int x,
						int y,
						double radian,
						int org_x,
						int org_y
						)
		{

			// あらかじめ三角関数の値を計算しておく.
			double cos = Math.Cos( radian );
			double sin = Math.Sin( radian );

			// いったん座標をシフト移動する.
			double tmp_x = x - org_x;
			double tmp_y = y - org_y;

			// 座標を回転させる.
			double buf_x = (( cos * tmp_x ) - ( sin * tmp_y ));
			double buf_y = (( sin * tmp_x ) + ( cos * tmp_y ));

			// 回転させた座標をシフト移動してもどす.
			want_x = buf_x + org_x;
			want_y = buf_y + org_y;

			return true;

		}

		private void button1_Click( object sender, EventArgs e )
		{

			// 角度から弧度に変換.
			const double ROTATE_DEG = 30.0;
			double rad = Math.PI * ( ROTATE_DEG / 180.0 );

			// クリックした場所が回転中心の座標.
			int org_x = TheX0;
			int org_y = TheY0;

			// 回転させた座標を取得する.
			double rot_x0 = 0;
			double rot_y0 = 0;
			RotatePoint( ref rot_x0, ref rot_y0, TheX0, TheY0, rad, org_x, org_y );

			double rot_x1 = 0;
			double rot_y1 = 0;
			RotatePoint( ref rot_x1, ref rot_y1, TheX1, TheY1, rad, org_x, org_y );

			double rot_x2 = 0;
			double rot_y2 = 0;
			RotatePoint( ref rot_x2, ref rot_y2, TheX2, TheY2, rad, org_x, org_y );

			double rot_x3 = 0;
			double rot_y3 = 0;
			RotatePoint( ref rot_x3, ref rot_y3, TheX3, TheY3, rad, org_x, org_y );

			// double から int へ丸める.
			TheX0 = (int)( Math.Round( rot_x0 ));
			TheY0 = (int)( Math.Round( rot_y0 ));

			TheX1 = (int)( Math.Round( rot_x1 ));
			TheY1 = (int)( Math.Round( rot_y1 ));

			TheX2 = (int)( Math.Round( rot_x2 ));
			TheY2 = (int)( Math.Round( rot_y2 ));

			TheX3 = (int)( Math.Round( rot_x3 ));
			TheY3 = (int)( Math.Round( rot_y3 ));

			// 再描画を要請する.
			this.Invalidate( true );

		}
	}
}