核心點:在一個任意旋轉的矩形(由四個頂點定義)內繪制一個內切橢圓
實現步驟
-
計算矩形中心:作為旋轉中心點
-
創建橢圓路徑:在未旋轉狀態下定義橢圓
-
應用旋轉變換:使用矩陣繞中心點旋轉路徑
-
繪制變換后的路徑
實現方法
public void DrawRotatedEllipse(Graphics g, PointF[] rotatedCorners, float rotationAngle)
{// 確保輸入是四個點if (rotatedCorners.Length != 4)throw new ArgumentException("必須提供矩形的四個頂點");// 初始化畫筆(根據您的原有邏輯)if (g != m_LastGraphic){m_ControlPen = new Pen(Color.FromKnownColor(AnnotationSysINI.GetSetToolsColor()), AnnotationSysINI.GetSetToolsLineWide());m_BackPen = new Pen(Color.FromKnownColor(KnownColor.Black), 5);m_LastGraphic = g;}// 設置高質量繪圖g.SmoothingMode = SmoothingMode.AntiAlias;g.PixelOffsetMode = PixelOffsetMode.HighQuality;g.CompositingQuality = CompositingQuality.HighQuality;// 1. 計算旋轉矩形的中心點PointF center = new PointF((rotatedCorners[0].X + rotatedCorners[1].X + rotatedCorners[2].X + rotatedCorners[3].X) / 4,(rotatedCorners[0].Y + rotatedCorners[1].Y + rotatedCorners[2].Y + rotatedCorners[3].Y) / 4);// 2. 計算矩形的實際寬度和高度float width = (float)Math.Sqrt(Math.Pow(rotatedCorners[1].X - rotatedCorners[0].X, 2) +Math.Pow(rotatedCorners[1].Y - rotatedCorners[0].Y, 2));float height = (float)Math.Sqrt(Math.Pow(rotatedCorners[3].X - rotatedCorners[0].X, 2) +Math.Pow(rotatedCorners[3].Y - rotatedCorners[0].Y, 2));// 3. 創建橢圓路徑(在原點處創建)using (GraphicsPath path = new GraphicsPath()){// 創建以原點為中心的橢圓RectangleF baseRect = new RectangleF(-width / 2, -height / 2, width, height);path.AddEllipse(baseRect);// 4. 應用變換:先旋轉后平移using (Matrix transform = new Matrix()){// 注意順序:先旋轉后平移transform.Rotate(rotationAngle);transform.Translate(center.X, center.Y, MatrixOrder.Append);path.Transform(transform);}// 5. 繪制橢圓if (AnnotationSysINI.GetSetToolsLineBackPen())g.DrawPath(m_BackPen, path);g.DrawPath(m_ControlPen, path);}// 6. (可選) 繪制旋轉矩形邊界用于驗證using (Pen debugPen = new Pen(Color.Red, 1)){g.DrawPolygon(debugPen, rotatedCorners);}
}
使用示例
// 創建旋轉后的矩形四個頂點
PointF[] rotatedCorners = new PointF[4]
{new PointF(100, 50), // 旋轉后的左上new PointF(200, 70), // 旋轉后的右上new PointF(180, 170), // 旋轉后的右下new PointF(80, 150) // 旋轉后的左下
};// 計算旋轉角度(如果需要)
float angle = 30; // 已知的旋轉角度// 在Paint事件中調用
DrawRotatedEllipse(e.Graphics, rotatedCorners, angle);
?
關鍵點說明
-
直接使用旋轉后的頂點:
-
方法接受旋轉后矩形的四個頂點作為輸入
-
不再依賴原始未旋轉的左上/右下坐標
-
-
正確計算尺寸:
// 寬度 = 左上到右上的距離 float width = Distance(rotatedCorners[0], rotatedCorners[1]);// 高度 = 左上到左下的距離 float height = Distance(rotatedCorners[0], rotatedCorners[3]);
-
變換順序至關重要:
// 正確順序:先旋轉后平移 transform.Rotate(rotationAngle); transform.Translate(center.X, center.Y, MatrixOrder.Append);
-
原點中心法:
-
先在原點(0,0)創建橢圓
-
然后通過變換移動到實際位置
-
如果只有原始矩形和旋轉角度
public PointF[] CalculateRotatedCorners(PointF topLeft, PointF bottomRight, float angle)
{float width = bottomRight.X - topLeft.X;float height = bottomRight.Y - topLeft.Y;PointF center = new PointF(topLeft.X + width/2, topLeft.Y + height/2);PointF[] corners = new PointF[4]{topLeft, // 原始左上new PointF(topLeft.X + width, topLeft.Y), // 原始右上bottomRight, // 原始右下new PointF(topLeft.X, topLeft.Y + height) // 原始左下};using (Matrix matrix = new Matrix()){matrix.RotateAt(angle, center);matrix.TransformPoints(corners);}return corners;
}// 使用:
PointF topLeft = new PointF(50, 50);
PointF bottomRight = new PointF(250, 150);
float angle = 30f;PointF[] rotatedCorners = CalculateRotatedCorners(topLeft, bottomRight, angle);
DrawRotatedEllipse(g, rotatedCorners, angle);
?
常見問題解決
-
橢圓位置偏移:
-
檢查中心點計算是否正確
-
驗證頂點順序是否一致(順時針/逆時針)
-
使用調試邊界框可視化
-
-
橢圓變形:
-
確保寬度/高度計算正確
-
檢查旋轉角度單位(度/弧度)
-
確認矩形頂點構成直角
-
-
性能優化:這種方法保證了橢圓始終精確適配旋轉后的矩形邊界,無論旋轉角度如何變化。
// 類級別緩存
private PointF[] _lastCorners;
private GraphicsPath _cachedPath;// 在方法中:
if (_lastCorners != rotatedCorners)
{// 重新計算路徑_cachedPath?.Dispose();_cachedPath = CreateEllipsePath(rotatedCorners, angle);_lastCorners = (PointF[])rotatedCorners.Clone();
}
g.DrawPath(pen, _cachedPath);
?在旋轉矩形內繪制橢圓并實現鼠標碰撞檢測
?
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;public class RotatedEllipseTool
{// 存儲橢圓路徑用于碰撞檢測private GraphicsPath _ellipsePath;// 畫筆設置private Pen _controlPen;private Pen _backPen;private Graphics _lastGraphic;// 橢圓屬性public PointF[] RotatedCorners { get; private set; }public float RotationAngle { get; private set; }public RotatedEllipseTool(){// 初始化畫筆_controlPen = new Pen(Color.Blue, 2);_backPen = new Pen(Color.Black, 5);}// 創建旋轉橢圓路徑(用于繪制和碰撞檢測)public void CreateRotatedEllipse(PointF[] rotatedCorners, float rotationAngle){// 確保輸入是四個點if (rotatedCorners.Length != 4)throw new ArgumentException("必須提供矩形的四個頂點");// 保存參數RotatedCorners = rotatedCorners;RotationAngle = rotationAngle;// 計算旋轉矩形的中心點PointF center = new PointF((rotatedCorners[0].X + rotatedCorners[1].X + rotatedCorners[2].X + rotatedCorners[3].X) / 4,(rotatedCorners[0].Y + rotatedCorners[1].Y + rotatedCorners[2].Y + rotatedCorners[3].Y) / 4);// 計算矩形的實際寬度和高度float width = Distance(rotatedCorners[0], rotatedCorners[1]);float height = Distance(rotatedCorners[0], rotatedCorners[3]);// 創建橢圓路徑_ellipsePath?.Dispose(); // 釋放舊路徑_ellipsePath = new GraphicsPath();// 創建以原點為中心的橢圓RectangleF baseRect = new RectangleF(-width / 2, -height / 2, width, height);_ellipsePath.AddEllipse(baseRect);// 應用變換:先旋轉后平移using (Matrix transform = new Matrix()){// 注意順序:先旋轉后平移transform.Rotate(rotationAngle);transform.Translate(center.X, center.Y, MatrixOrder.Append);_ellipsePath.Transform(transform);}}// 繪制橢圓public void Draw(Graphics g){if (_ellipsePath == null) return;// 初始化畫筆(如果需要)if (g != _lastGraphic){// 這里使用您原有的配置邏輯_controlPen = new Pen(AnnotationSysINI.GetSetToolsColor(), AnnotationSysINI.GetSetToolsLineWide());_backPen = new Pen(Color.Black, 5);_lastGraphic = g;}// 設置高質量繪圖g.SmoothingMode = SmoothingMode.AntiAlias;g.PixelOffsetMode = PixelOffsetMode.HighQuality;g.CompositingQuality = CompositingQuality.HighQuality;// 繪制橢圓if (AnnotationSysINI.GetSetToolsLineBackPen())g.DrawPath(_backPen, _ellipsePath);g.DrawPath(_controlPen, _ellipsePath);// 繪制邊界框(調試用)using (Pen debugPen = new Pen(Color.Red, 1)){g.DrawPolygon(debugPen, RotatedCorners);}}// 鼠標碰撞檢測public bool HitTest(PointF point){if (_ellipsePath == null) return false;// 使用路徑的IsVisible方法進行碰撞檢測return _ellipsePath.IsVisible(point);}// 輔助方法:計算兩點距離private float Distance(PointF p1, PointF p2){float dx = p2.X - p1.X;float dy = p2.Y - p1.Y;return (float)Math.Sqrt(dx * dx + dy * dy);}// 計算旋轉后的矩形頂點public static PointF[] CalculateRotatedCorners(PointF topLeft, PointF bottomRight, float angle){float width = bottomRight.X - topLeft.X;float height = bottomRight.Y - topLeft.Y;PointF center = new PointF(topLeft.X + width/2, topLeft.Y + height/2);PointF[] corners = new PointF[4]{topLeft, // 原始左上new PointF(topLeft.X + width, topLeft.Y), // 原始右上bottomRight, // 原始右下new PointF(topLeft.X, topLeft.Y + height) // 原始左下};using (Matrix matrix = new Matrix()){matrix.RotateAt(angle, center);matrix.TransformPoints(corners);}return corners;}// 釋放資源public void Dispose(){_ellipsePath?.Dispose();_controlPen?.Dispose();_backPen?.Dispose();}
}// 使用示例
public class DrawingForm : Form
{private RotatedEllipseTool _ellipseTool = new RotatedEllipseTool();public DrawingForm(){this.DoubleBuffered = true;this.Size = new Size(800, 600);// 創建旋轉矩形PointF topLeft = new PointF(100, 100);PointF bottomRight = new PointF(300, 200);float rotationAngle = 30f;// 計算旋轉后的頂點PointF[] rotatedCorners = RotatedEllipseTool.CalculateRotatedCorners(topLeft, bottomRight, rotationAngle);// 創建橢圓路徑_ellipseTool.CreateRotatedEllipse(rotatedCorners, rotationAngle);// 設置鼠標事件this.MouseClick += DrawingForm_MouseClick;this.MouseMove += DrawingForm_MouseMove;}protected override void OnPaint(PaintEventArgs e){base.OnPaint(e);_ellipseTool.Draw(e.Graphics);}private void DrawingForm_MouseClick(object sender, MouseEventArgs e){if (_ellipseTool.HitTest(e.Location)){MessageBox.Show("點擊了橢圓內部!");}}private void DrawingForm_MouseMove(object sender, MouseEventArgs e){// 改變鼠標指針當在橢圓內部時this.Cursor = _ellipseTool.HitTest(e.Location) ? Cursors.Hand : Cursors.Default;}protected override void Dispose(bool disposing){if (disposing){_ellipseTool.Dispose();}base.Dispose(disposing);}
}
關鍵實現說明
1. 路徑創建與保存
-
CreateRotatedEllipse
方法計算并保存橢圓路徑 -
路徑存儲在
_ellipsePath
字段中,用于繪制和碰撞檢測 -
路徑創建過程:
-
計算旋轉矩形的中心點
-
計算矩形的實際寬度和高度
-
創建以原點為中心的橢圓
-
應用旋轉變換矩陣
-
2. 鼠標碰撞檢測
-
HitTest
方法使用GraphicsPath.IsVisible()
檢測點是否在路徑內 -
該方法利用GDI+的內置功能進行精確碰撞檢測
-
在鼠標事件中調用該方法實現交互效果
3. 使用示例
-
在窗體中創建旋轉橢圓工具實例
-
計算旋轉后的矩形頂點
-
創建橢圓路徑
-
在Paint事件中繪制橢圓
-
在鼠標事件中檢測碰撞
4. 輔助功能
-
CalculateRotatedCorners
:從原始矩形計算旋轉后的頂點 -
Distance
:計算兩點間距離 -
Dispose
:正確釋放GDI資源
實現效果
-
在旋轉矩形內繪制完美適配的橢圓
-
橢圓隨矩形旋轉角度變化
-
鼠標在橢圓內部時指針變為手形
-
點擊橢圓內部顯示提示信息
-
使用高質量抗鋸齒渲染
注意事項
-
資源管理:
-
使用后務必調用
Dispose()
釋放資源 -
路徑在重新創建前釋放舊路徑
-
-
碰撞檢測精度:
-
IsVisible
方法考慮了路徑的填充區域 -
對于空心橢圓,可能需要調整檢測方式
-
-
性能優化:
-
路徑創建后緩存起來,避免重復計算
-
只在必要時重新創建路徑(如矩形改變時)
-
URL
C# 圖像旋轉一定角度后,對應坐標怎么計算?_c# 求點旋轉之后的坐標-CSDN博客文章瀏覽閱讀1.8k次,點贊16次,收藏10次。本文詳細解釋了如何在二維空間中計算圖像內坐標在旋轉特定角度后的新坐標,包括中心點、角度轉換、旋轉公式以及使用C#代碼示例展示如何應用這些概念。同時提到了處理邊界問題和使用GDI+或OpenCV庫進行旋轉的功能。https://blog.csdn.net/wangnaisheng/article/details/137919395?spm=1011.2415.3001.5331?C# Bitmap實現角度旋轉_c# bitmap 旋轉-CSDN博客文章瀏覽閱讀2.2k次,點贊10次,收藏8次。本文介紹了在C#中對Bitmap對象進行旋轉的三種方法:使用Bitmap.RotateFlip方法進行90度旋轉,使用System.Drawing.Drawing2D.Matrix類進行任意角度旋轉,以及利用第三方庫如ImageSharp進行高級圖像處理。
https://blog.csdn.net/wangnaisheng/article/details/138160242?spm=1011.2415.3001.5331
?