文字列を回転して描画するのはGraphicsオブジェクトをワールド変換して描画することも可能ですが、ワールド変換はGraphicsオブジェクト全体の座標系が変換されてしまうため、少々使いづらく感じます。
そこで、文字だけを回転するGraphicsPathを使った方法で関数にまとめてみました。
この関数で、文字の描画位置、回転、回転の基準位置(左上、中心など)を設定できるようにしています。
実行結果の画面
サンプルプログラム
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
// アンチエイリアスの設定
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// グリッド線の描画(50画素ピッチ)
for (int i = 0; i < this.Width; i += 50)
{
g.DrawLine(Pens.Black, i, 0, i, this.Height);
}
for (int j = 0; j < this.Height; j += 50)
{
g.DrawLine(Pens.Black, 0, j, this.Width, j);
}
var font = new Font("Arial", 20);
// 文字の中心の座標が(100, 100)を中心に-30度回転
var format = new StringFormat();
format.Alignment = StringAlignment.Center; // 左右方向は中心寄せ
format.LineAlignment = StringAlignment.Center; // 上下方向は中心寄せ
DrawString(
g,
"[文字の中心が基準]",
font,
new SolidBrush(Color.Blue),
100, 100,
-30,
format
);
// 文字の左上の座標が(200, 100)を中心に45度回転
format.Alignment = StringAlignment.Near; // 左右方向は左寄せ
format.LineAlignment = StringAlignment.Near; // 上下方向は上寄せ
DrawString(
g,
"[文字の左上が基準]",
font,
new SolidBrush(Color.Red),
200, 100,
45,
format
);
}
/// <summary>
/// 文字列の描画、回転、基準位置指定
/// </summary>
/// <param name="g">描画先のGraphicsオブジェクト</param>
/// <param name="s">描画する文字列</param>
/// <param name="f">文字のフォント</param>
/// <param name="brush">描画用ブラシ</param>
/// <param name="x">基準位置のX座標</param>
/// <param name="y">基準位置のY座標</param>
/// <param name="deg">回転角度(度数、時計周りが正)</param>
/// <param name="format">基準位置をStringFormatクラスオブジェクトで指定します</param>
public void DrawString(Graphics g, string s, Font f, SolidBrush brush, float x, float y, float deg, StringFormat format)
{
using (var pathText = new System.Drawing.Drawing2D.GraphicsPath()) // パスの作成
using (var mat = new System.Drawing.Drawing2D.Matrix()) // アフィン変換行列
{
// 描画用Format
var formatTemp = (StringFormat)format.Clone();
formatTemp.Alignment = StringAlignment.Near; // 左寄せに修正
formatTemp.LineAlignment = StringAlignment.Near; // 上寄せに修正
// 文字列の描画
pathText.AddString(
s,
f.FontFamily,
(int)f.Style,
f.SizeInPoints,
new PointF(0, 0),
format);
formatTemp.Dispose();
// 文字の領域取得
var rect = pathText.GetBounds();
// 回転中心のX座標
float px;
switch (format.Alignment)
{
case StringAlignment.Near:
px = rect.Left;
break;
case StringAlignment.Center:
px = rect.Left + rect.Width / 2f;
break;
case StringAlignment.Far:
px = rect.Right;
break;
default:
px = 0;
break;
}
// 回転中心のY座標
float py;
switch (format.LineAlignment)
{
case StringAlignment.Near:
py = rect.Top;
break;
case StringAlignment.Center:
py = rect.Top + rect.Height / 2f;
break;
case StringAlignment.Far:
py = rect.Bottom;
break;
default:
py = 0;
break;
}
// 文字の回転中心座標を原点へ移動
mat.Translate(-px, -py, System.Drawing.Drawing2D.MatrixOrder.Append);
// 文字の回転
mat.Rotate(deg, System.Drawing.Drawing2D.MatrixOrder.Append);
// 表示位置まで移動
mat.Translate(x, y, System.Drawing.Drawing2D.MatrixOrder.Append);
// パスをアフィン変換
pathText.Transform(mat);
// 描画
g.FillPath(brush, pathText);
}
}
プログラムの解説
回転中心の座標(表示位置の座標)をx, y で指定します。
文字の回転角度(deg)は時計方向が正となります。
文字列の回転の基準位置(回転の中心の位置)はStringFormatクラスで指定します。
StringFormat.Alignmentプロパティが左右方向の基準位置で、
StringAlignment.Near | 左寄せ |
StringAlignment.Center | 中心寄せ |
StringAlignment.Far | 右寄せ |
となります。
同様にStringFormat.LineAlignmentプロパティが上下方向の基準位置で、
StringAlignment.Near | 上寄せ |
StringAlignment.Center | 中心寄せ |
StringAlignment.Far | 下寄せ |
となります。
これを使うと、こんな時計の文字盤のように文字を配置するのも簡単に書くことができます。
関連記事
【C#.NET】マイクロソフト仕様のアフィン変換
.NETでは座標のアフィン変換用にMatrixクラス(名前空間:System.Drawing.Drawing2D)が用意されています。 しかしながら、やっかいな事に、私の思う普通のアフィン変換の行列の表現が行と列が逆(転置されている)だし、...
【C#】GraphicsPath
GraphicsPath(名前空間:System.Drawing.Drawing2D)ですが、線や丸を書くだけで、DrawXXX系のメソッドでも出来るしなんか面倒臭いやつ?! と、思っていたのですが、GraphicsPathに含まれているメ...
【C#】GraphicsPathの描画
GraphicsPathの特長の一つでもあるアフィン変換を駆使した描画をしてみたいと思います。 パスの描画は、パスをnewしてAddLineなどのメソッドで図形を描画し、DrawPath(輪郭の描画)やFillPath(塗りつぶした描画)で...
【C#】寸法線の描画
GraphicsPathを使うことで、文字を任意角度で表示することが出来るのを知った元メカ屋な私。 これは寸法線の描画に使えそう! と思い、寸法線の描画部分をクラスにまとめたものを作成してみました。 実行画面 寸法線描画のクラス↓ publ...
←画像処理のためのC#テクニックへ戻る
コメント