[英]How to Draw a Rubber Band Selection Rectangle accurately on a Rotated 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上。
如果畫布的相機未旋轉,則效果很好。 旋轉顯示器時,我需要橡皮筋與屏幕保持對齊,而不是與繪制在畫布上的對齊。 我只是離開它,橡皮筋也被拉動旋轉。
如果我旋轉橡皮筋矩形以使其與屏幕對齊,則矩形將無法正確調整大小。 因此,經過一番混亂之后,我嘗試了一些三角函數:
var width = (float)((dragPt.X - pressPt.X) / Math.Cos(rotation));
var height = (float)((dragPt.Y - pressPt.Y) / Math.Cos(rotation));
鑒於旋轉角度可以是0> 360的任何角度,這不起作用並且變得非常混亂
我看過其他有關如何創建選擇矩形的代碼,包括以下問題的答案: 如何制作可調整大小的矩形選擇工具? 但我想盡可能使用我擁有的基本代碼,因為它與我使用的圖形引擎(Piccolo)有關。
我會放一些屏幕截圖,但是我無法捕捉橡皮筋。 我認為這比其他任何問題更多的是數學問題,並且應該易於修復,但是我無法計算出要考慮旋轉顯示效果的數學計算。
此代碼使用Paint
事件繪制
不旋轉的橡皮筋
並檢查示例矩形的角落
// 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
。
當然,更復雜的對象將需要更多的點列表。 為了獲得真正准確的結果,您甚至可能需要使用GraphicsPaths
及其支持的Regions
上的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<Point> points = new List<Point>();
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";
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.