【C#】在一個任意旋轉的矩形(由四個頂點定義)內繪制一個內切橢圓

核心點:在一個任意旋轉的矩形(由四個頂點定義)內繪制一個內切橢圓

實現步驟

  1. 計算矩形中心:作為旋轉中心點

  2. 創建橢圓路徑:在未旋轉狀態下定義橢圓

  3. 應用旋轉變換:使用矩陣繞中心點旋轉路徑

  4. 繪制變換后的路徑

實現方法

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);

?

關鍵點說明

  1. 直接使用旋轉后的頂點

    • 方法接受旋轉后矩形的四個頂點作為輸入

    • 不再依賴原始未旋轉的左上/右下坐標

  2. 正確計算尺寸

    // 寬度 = 左上到右上的距離
    float width = Distance(rotatedCorners[0], rotatedCorners[1]);// 高度 = 左上到左下的距離
    float height = Distance(rotatedCorners[0], rotatedCorners[3]);
  3. 變換順序至關重要

    // 正確順序:先旋轉后平移
    transform.Rotate(rotationAngle);
    transform.Translate(center.X, center.Y, MatrixOrder.Append);
  4. 原點中心法

    • 先在原點(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);

?

常見問題解決

  1. 橢圓位置偏移

    • 檢查中心點計算是否正確

    • 驗證頂點順序是否一致(順時針/逆時針)

    • 使用調試邊界框可視化

  2. 橢圓變形

    • 確保寬度/高度計算正確

    • 檢查旋轉角度單位(度/弧度)

    • 確認矩形頂點構成直角

  3. 性能優化:這種方法保證了橢圓始終精確適配旋轉后的矩形邊界,無論旋轉角度如何變化。

// 類級別緩存
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字段中,用于繪制和碰撞檢測

  • 路徑創建過程:

    1. 計算旋轉矩形的中心點

    2. 計算矩形的實際寬度和高度

    3. 創建以原點為中心的橢圓

    4. 應用旋轉變換矩陣

2. 鼠標碰撞檢測

  • HitTest方法使用GraphicsPath.IsVisible()檢測點是否在路徑內

  • 該方法利用GDI+的內置功能進行精確碰撞檢測

  • 在鼠標事件中調用該方法實現交互效果

3. 使用示例

  • 在窗體中創建旋轉橢圓工具實例

  • 計算旋轉后的矩形頂點

  • 創建橢圓路徑

  • 在Paint事件中繪制橢圓

  • 在鼠標事件中檢測碰撞

4. 輔助功能

  • CalculateRotatedCorners:從原始矩形計算旋轉后的頂點

  • Distance:計算兩點間距離

  • Dispose:正確釋放GDI資源

實現效果

  1. 在旋轉矩形內繪制完美適配的橢圓

  2. 橢圓隨矩形旋轉角度變化

  3. 鼠標在橢圓內部時指針變為手形

  4. 點擊橢圓內部顯示提示信息

  5. 使用高質量抗鋸齒渲染

注意事項

  1. 資源管理

    • 使用后務必調用Dispose()釋放資源

    • 路徑在重新創建前釋放舊路徑

  2. 碰撞檢測精度

    • IsVisible方法考慮了路徑的填充區域

    • 對于空心橢圓,可能需要調整檢測方式

  3. 性能優化

    • 路徑創建后緩存起來,避免重復計算

    • 只在必要時重新創建路徑(如矩形改變時)

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

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/97478.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/97478.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/97478.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

洛谷 P2052 [NOI2011] 道路修建-普及/提高-

P2052 [NOI2011] 道路修建 題目描述 在 W 星球上有 nnn 個國家。為了各自國家的經濟發展,他們決定在各個國家之間建設雙向道路使得國家之間連通。但是每個國家的國王都很吝嗇,他們只愿意修建恰好 n?1n - 1n?1 條雙向道路。 每條道路的修建都要付出一定…

springboot連接不上redis,但是redis客戶端是能連接上的

除了常規排查,還有一個就是檢查配置文件格式。這個舊版本格式會導致讀取不到配置,spring:# 對應 RedisProperties 類redis:host: 127.0.0.1port: 6379 # password: 123456 # Redis 服務器密碼,默認為空。生產中,一定要設置 Red…

GitBook 完整使用指南:從安裝到部署

文章目錄 環境準備 Node.js 安裝 GitBook CLI 安裝 項目初始化 創建項目結構 (可選) npm 初始化 目錄結構配置 開發與調試 本地服務啟動 構建靜態文件 配置文件詳解 插件系統 常用插件推薦 插件安裝與配置 自定義樣式 部署指南 GitHub Pages 部署 Netlify 部署 高級功能 多語言…

VS安裝 .NETFramework,Version=v4.6.x

一、前言 在使用VS2019打開項目時提示MSB3644 找不到 .NETFramework,Versionv4.6.2 的引用程序集的錯誤 二、解決方案 1.百度......找到了解決方法了 2.打開Visual Studio Install 3.點擊修改 4.點擊單個組件,安裝相對應的版本即可

Visual Studio Code中launch.json的解析筆記

<摘要> launch.json 是 Visual Studio Code 中用于配置調試任務的核心文件。本文解析了其最常用的配置字段&#xff0c;涵蓋了基本調試設置、程序控制、環境配置和高級調試功能。理解這些字段能幫助開發者高效配置調試環境&#xff0c;提升開發效率。<解析> 1. 背景…

試試 Xget 加速 GitHub 克隆倉庫

引言 在全球化軟件開發環境中&#xff0c;開發者經常面臨跨地域訪問GitHub等平臺的網絡挑戰&#xff1a;下載速度緩慢、連接不穩定、甚至完全無法訪問。這些問題嚴重影響了開發效率和協作體驗。Xget作為一個開源的高性能資源獲取加速引擎&#xff0c;通過智能路由、多節點分發…

優雅處理Go中的SIGTERM信

在Go語言中優雅處理SIGTERM信號需通過os/signal包實現&#xff0c;核心流程包括信號注冊、異步監聽和資源清理。SIGTERM 是一種常見的進程終止信號&#xff0c;它允許程序在退出前執行必要的清理操作。與之不同&#xff0c;SIGKILL 信號無法被進程捕獲或忽略。未處理的 SIGTERM…

《R for Data Science (2e)》免費中文翻譯 (第6章) --- scripts and projects

寫在前面 本系列推文為《R for Data Science (2)》的中文翻譯版本。所有內容都通過開源免費的方式上傳至Github&#xff0c;歡迎大家參與貢獻&#xff0c;詳細信息見&#xff1a; Books-zh-cn 項目介紹&#xff1a; Books-zh-cn&#xff1a;開源免費的中文書籍社區 r4ds-zh-cn …

GitHub Spark深度體驗:是革命前夜,還是又一個“大廠玩具”?

最近&#xff0c;AI 編碼工具層出不窮&#xff0c;幾乎每天都有新概念誕生。而當 GitHub 這樣的行業巨頭攜“Vibe Coding”概念入場時&#xff0c;所有開發者的期待值都被瞬間拉滿。GitHub Spark&#xff0c;一個承諾能用自然語言將你的想法直接變成全棧應用的工具&#xff0c;…

科學研究系統性思維的方法體系:研究設計相關模版

一、研究設計方案模板 模板說明本模板基于《研究設計原理與方法》深度解讀報告的理論框架&#xff0c;幫助研究者制定系統性的研究設計方案。模板整合了因果推斷理論、效度控制框架和現代實驗設計原理。1. 研究問題界定與假設陳述 1.1 研究問題核心要素 研究問題&#xff08;明…

法律審查prompt收集

當前DeepSeek等大模型已經具備初步合同審查能力。 這里收集合同審查及相關prompt&#xff0c;不管是做Coze等Agent&#xff0c;還是開發LLM應用&#xff0c;都有可能用到這些prompt。 https://github.com/LeeXYZABC/law_propmpts.git 1 條款分析 system_prompt&#xff0c;L…

貪心算法解決活動選擇問題:最多不重疊活動數量求解

題目描述問題背景活動選擇問題是貪心算法的經典應用場景之一。假設有若干個活動&#xff0c;每個活動都有獨立的開始時間和結束時間&#xff0c;且同一時間只能進行一個活動。要求從這些活動中選擇出最大數量的不重疊活動&#xff0c;即任意兩個選中的活動&#xff0c;前一個活…

2025年如何批量下載雪球帖子和文章導出pdf?

之前分享過雪球文章下載 2025 批量下載市場高標解讀/配置喵/wangdizhe 雪球帖子/文章導出excel和pdf 這里以市場高標解讀這個號為例 抓取下載的所有帖子excel數據包含文章日期&#xff0c;文章標題&#xff0c;文章鏈接&#xff0c;文章簡介&#xff0c;點贊數&#xff0c;轉…

【C++】紅黑樹(詳解)

文章目錄上文鏈接一、什么是紅黑樹二、紅黑樹的性質1. 顏色規則2. 紅黑樹的規則為什么可以控制平衡3. 紅黑樹的效率三、紅黑樹的整體結構四、紅黑樹的插入1. 空樹的插入2. 插入節點的父親為黑色3. 插入節點的父親為紅色(1) 叔叔為紅色&#xff1a;變色(2) 叔叔為空或為黑色&…

AI提升SEO關鍵詞效果新策略

內容概要 在2025年&#xff0c;人工智能&#xff08;AI&#xff09;技術正全面革新搜索引擎優化&#xff08;SEO&#xff09;的關鍵詞優化模式。通過智能分析用戶搜索意圖與語義關聯&#xff0c;AI能夠精準匹配關鍵詞并進行高效布局。本文將深入探討AI驅動的關鍵詞策略升級方案…

手動安裝的node到nvm吧版本管理的過程。

前言 本文記錄個人在使用nvm包管理器安裝node 14版本 npm安裝失敗&#xff0c;進行手動安裝的node到nvm吧版本管理的過程。 安裝node 14 時 npm總是安裝失敗&#xff0c;如下圖 通過手動下載對于版本 node下載地址 下載解壓點擊所需的版本下載后解壓 修改解壓后的文件夾名稱…

Python爬蟲實戰:構建Widgets 小組件數據采集和分析系統

1. 引言 1.1 研究背景 在當今數字化時代,Widgets 作為用戶界面的基本組成元素,廣泛應用于移動應用、網站和桌面軟件中,其設計質量直接影響用戶體驗。隨著市場競爭的加劇,了解市場上各類 Widgets 產品的特征、價格區間、用戶評價等信息,對于產品設計和商業決策具有重要價…

1.1 Internet簡介

1.網絡, 計算機網絡, 互聯網 2.不同的角度認識Internet1.網絡, 計算機網絡, 互聯網 網絡表示連接兩點以上的通路系統比如:a.你家到鄰居家的小路 -> 一個小網絡b.一個村子的所有道路 -> 一個更大的網絡c.送外賣的小哥騎車走的路線 -> 一個配送網絡計算機網絡表示專門傳…

pytest使用allure測試報告

&#x1f345; 點擊文末小卡片&#xff0c;免費獲取軟件測試全套資料&#xff0c;資料在手&#xff0c;漲薪更快 選用的項目為Selenium自動化測試Pytest框架實戰&#xff0c;在這個項目的基礎上說allure報告。 allure安裝 首先安裝python的allure-pytest包 pip install allu…

PortSwigger靶場之SQL injection with filter bypass via XML encoding通關秘籍

一、題目分析該實驗室的庫存查詢功能存在 SQL 注入漏洞。查詢結果為這些信息會出現在應用程序的響應中&#xff0c;因此您可以利用“聯合”攻擊來從其他表中獲取數據。該數據庫中有一個“用戶”表&#xff0c;該表包含了已注冊用戶的用戶名和密碼。要解決&#xff0c;需進行一次…