如何在旋转canvas上精确绘制橡皮筋选择矩形?

这是在canvas上绘制的橡皮筋选择矩形。 我的问题是,如果canvas内容没有旋转,很容易获得正确的矩形大小。 但是一旦旋转,矩形就不再与光标一起变大。 我需要橡皮筋与屏幕保持平行

var dragPt = new PointF(e.Position.X - G.ReferenceOffset.X, e.Position.Y - G.ReferenceOffset.Y); var rotation = ADEEnvironment.RotateAngle; var width = (dragPt.X - pressPt.X); var height = (dragPt.Y - pressPt.Y); 

代码非常简单。 我在鼠标按下时捕获鼠标的位置:pressPt。 在鼠标移动事件中,我得到当前鼠标位置dragPt并计算橡皮筋矩形的宽度和高度,并使用这些值创建一个矩形,其原点在pressPt上。

如果canvas的相机没有旋转,这可以正常工作。 当我旋转显示器时,我需要橡皮筋与屏幕保持对齐而不是绘制它的canvas。 它我只是留下它旋转绘制的橡皮筋。

如果我旋转橡皮筋矩形使其返回到与屏幕对齐,则矩形不再正确resize。 所以在经历了很多混乱之后我尝试了一些三角函数:

  var width = (float)((dragPt.X - pressPt.X) / Math.Cos(rotation)); var height = (float)((dragPt.Y - pressPt.Y) / Math.Cos(rotation)); 

考虑到旋转角度可以是0> 360的任何值,这不起作用并且变得非常混乱

我已经查看了有关如何创建选择矩形的其他代码,包括这个问题的答案: 如何制作可resize的矩形选择工具? 但我想使用我拥有的基本代码,因为它与我正在使用的图形引擎(Piccolo)有关。

我会张贴一些截图,但我无法捕捉橡皮筋。 我认为这更像是一个数学问题,而且应该很容易修复,但我无法确定要对旋转显示效果进行何种数学计算。

此代码使用Paint事件进行绘制

  • 旋转canvas上的一个固定矩形
  • 一个未旋转的副本
  • 未旋转的橡皮筋

  • 并检查示例rectanlge的角落


 // one example 'object' Rectangle R0 = new Rectangle(182,82,31,31); // a few helpers Point curMouse = Point.Empty; Point downMouse = Point.Empty; Rectangle RM = Rectangle.Empty; float angle = 30; Point center = new Point(-55, -22); private void canvas_Paint(object sender, PaintEventArgs e) { // preprare the canvas to rotate around a center point: e.Graphics.TranslateTransform(center.X , center.Y); e.Graphics.RotateTransform(angle); e.Graphics.TranslateTransform(-center.X, -center.Y); // draw one object and reset e.Graphics.DrawRectangle(Pens.Green, R0); e.Graphics.ResetTransform(); // for testing (and hittesting): this is the unrotated obejct: e.Graphics.DrawRectangle(Pens.LightGray, R0); // allowing for any way the rubber band is drawn.. // ..should be moved to a helper function! Size S = new Size( Math.Abs(downMouse.X - curMouse.X), Math.Abs(downMouse.Y - curMouse.Y)); Point P0 = new Point(Math.Min(downMouse.X, curMouse.X), Math.Min(downMouse.Y, curMouse.Y)); RM = new Rectangle(P0, S); // the ruber band e.Graphics.DrawRectangle(Pens.Red, RM); } private void canvas_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) curMouse = e.Location; canvas.Invalidate(); } private void canvas_MouseDown(object sender, MouseEventArgs e) { downMouse = e.Location; curMouse = e.Location; } 

IMO,更有趣的部分是决定选择哪些对象。 任何交叉点都会计算还是应该完全包含?

我在这篇文章中找到了一个很好的旋转代码,并添加了一个示例来检查固定的Rectangle

当然,更复杂的对象将需要更多涉及的点列表。 为了获得非常精确的结果,您甚至可能需要在它们支持的Regions上使用GraphicsPaths和set操作; 但也许一个简单的凸壳会做..

当然,您需要存储旋转的点而不是重新计算它们。

 static Point RotatePoint(Point pointToRotate, Point centerPoint, double angleInDegrees) { double angleInRadians = angleInDegrees * (Math.PI / 180); double cosTheta = Math.Cos(angleInRadians); double sinTheta = Math.Sin(angleInRadians); return new Point { X = (int) (cosTheta * (pointToRotate.X - centerPoint.X) - sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X), Y = (int) (sinTheta * (pointToRotate.X - centerPoint.X) + cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y) }; } private void canvas_MouseUp(object sender, MouseEventArgs e) { List points = new List(); points.Add(RotatePoint(new Point(R0.Left, R0.Top), center, angle)); points.Add(RotatePoint(new Point(R0.Right, R0.Top), center, angle) ); points.Add(RotatePoint(new Point(R0.Right, R0.Bottom), center, angle) ); points.Add(RotatePoint(new Point(R0.Left, R0.Bottom), center, angle)); bool ok = true; foreach (Point pt in points) if (!RM.Contains(pt)) ok = false; if (ok) this.Text = "HIT"; else this.Text = "no hit"; }