我有一个Rectangle,它是一个由4个Point结构组成的数组。它可以在任何角度(0到360度)旋转到位并正确绘制。
用户还可以拖动一个角来调整矩形的大小。例如,如果它们移动左下角的点,它还将更新左上角的X坐标和右下角的Y坐标。这样,无论它们移动到哪一点,它总是一个矩形。
Points[point] = newValue;
switch (point)
{
case TopLeft:
Points[BottomLeft].X = newValue.X;
Points[TopRight].Y = newValue.Y;
break;
case BottomRight:
Points[TopRight].X = newValue.X;
Points[BottomLeft].Y = newValue.Y;
break;
case BottomLeft:
Points[TopLeft].X = newValue.X;
Points[BottomRight].Y = newValue.Y;
break;
case TopRight:
Points[BottomRight].X = newValue.X;
Points[TopLeft].Y = newValue.Y;
break;
}
这里我将四个点中的任意一个更改为给定的输入点(newValue),然后修改链接点以使其保持矩形形状。
但是,如果我的矩形像这样一个角度,我需要修改上面的代码:
此处添加示例代码:
http://www.assembla.com/code/moozhe-testing/subversion/nodes/rotateRectangle
答案 0 :(得分:2)
我看到2个解决方案。第一个理论上有效,但由于四舍五入,它最终无效。我会在那里放第一个解决方案,但第二个解决方案是好的。
在这些样本中,我将调用4角CornerA,B,C和D,以顺时针方式命名。假设您正在将“CornerA”从位置Point oldPoint
移动到位置Point newPoint
。
第一个解决方案:
sideAtoB
上投影该增量并将该矢量添加到PointD。sideDtoA
上投影该增量并将该矢量添加到PointB。第二个解决方案:
以下是第二个解决方案的代码:
public class Rectangle
{
// Obviously, one would need to assign values to these points.
Point CornerA = new Point();
Point CornerB = new Point();
Point CornerC = new Point();
Point CornerD = new Point();
Dictionary<int, Point> points = new Dictionary<int, Point>();
public Rectangle()
{
points.Add(0, CornerA);
points.Add(1, CornerB);
points.Add(2, CornerC);
points.Add(3, CornerD);
}
public void MoveAPoint(int id, Point newPoint)
{
// Get the old point
Point oldPoint = points[id];
// Get the previous point
Point pointPrevious = points[(id + 3) % 4];
// Get the next point
Point pointNext = points[(id + 1) % 4];
// Get the opposite point
Point pointOpposite = points[(id + 2) % 4];
// Get the delta (variation) of the moving point
Point delta = newPoint.Substract(oldPoint);
// I call sides points, but they are actually vectors.
// Get side from 'oldPoint' to 'pointPrevious'.
Point sidePrevious = pointPrevious.Substract(oldPoint);
// Get side from 'oldPoint' to 'pointNext'.
Point sideNext = pointNext.Substract(oldPoint);
// Get side from 'pointOpposite' to 'newPoint'.
Point sideTransversal = newPoint.Substract(pointOpposite);
PointF previousProjection;
PointF nextProjection;
if (sideNext.X == 0 && sideNext.Y == 0)
{
if (sidePrevious.X == 0 && sidePrevious.Y == 0)
{
return;
}
sideNext = new PointF(-sidePrevious.Y, sidePrevious.X);
}
else
{
sidePrevious = new PointF(-sideNext.Y, sideNext.X);
}
Point previousProjection = Projection(delta, sidePrevious);
Point nextProjection = Projection(delta, sideNext);
pointNext.SetToPoint(pointNext.AddPoints(previousProjection));
pointPrevious.SetToPoint(pointPrevious.AddPoints(nextProjection));
oldPoint.SetToPoint(newPoint);
}
private static Point Projection(Point vectorA, Point vectorB)
{
Point vectorBUnit = new Point(vectorB.X, vectorB.Y);
vectorBUnit = vectorBUnit.Normalize();
decimal dotProduct = vectorA.X * vectorBUnit.X + vectorA.Y * vectorBUnit.Y;
return vectorBUnit.MultiplyByDecimal(dotProduct);
}
}
public static class ExtendPoint
{
public static Point Normalize(this Point pointA)
{
double length = Math.Sqrt(pointA.X * pointA.X + pointA.Y * pointA.Y);
return new Point(pointA.X / length, pointA.Y / length);
}
public static Point MultiplyByDecimal (this Point point, decimal length)
{
return new Point((int)(point.X * length), (int)(point.Y * length));
}
public static Point AddPoints(this Point firstPoint, Point secondPoint)
{
return new Point(firstPoint.X + secondPoint.X, firstPoint.Y + secondPoint.Y);
}
public static Point Substract(this Point firstPoint, Point secondPoint)
{
return new Point(firstPoint.X - secondPoint.X, firstPoint.Y - secondPoint.Y);
}
public static void SetToPoint(this Point oldPoint, Point newPoint)
{
oldPoint.X = newPoint.X;
oldPoint.Y = newPoint.Y;
}
}