调整角度上的矩形的大小

时间:2011-09-15 21:30:00

标签: c# .net resize angle

我有一个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://thesaurus.maths.org/mmkb/media/png/Rectangle.png

此处添加示例代码:

http://www.assembla.com/code/moozhe-testing/subversion/nodes/rotateRectangle

1 个答案:

答案 0 :(得分:2)

我看到2个解决方案。第一个理论上有效,但由于四舍五入,它最终无效。我会在那里放第一个解决方案,但第二个解决方案是好的

在这些样本中,我将调用4角CornerA,B,C和D,以顺时针方式命名。假设您正在将“CornerA”从位置Point oldPoint移动到位置Point newPoint

第一个解决方案:

  1. 获取位置delta
  2. 在边sideAtoB上投影该增量并将该矢量添加到PointD。
  3. 在边sideDtoA上投影该增量并将该矢量添加到PointB。
  4. 将PointA设置为newPoint。
  5. 第二个解决方案:

    1. 获取将对角连接到移动角落新位置的向量,让我们将其称为“对角线”。
    2. 将B的位置设为“C + [侧面对角线投影]。
    3. 将D的位置设为“C + [侧面对角线投影A]”。
    4. 将PointA设置为newPoint。
    5. 以下是第二个解决方案的代码:

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