将线段限制为矩形的边界

时间:2011-09-07 12:41:03

标签: algorithm graphics c#-3.0 line

我使用下面的代码将线段扩展到矩形的边界,如果矩形内的点有效,但是如果矩形边界有一个点,它会失败

enter image description here

 static void extend(Rectangle bounds, ref PointF start, ref PointF end)
         {


         if (start != end) // this to avoid small changes in orientation 
         {

             float slope = (end.Y - start.Y) / (end.X - start.X);

             if (Math.Round(start.Y, 2) == Math.Round(end.Y, 2) || Math.Abs(slope) <= 0.01d) // 0.01 is offset to check if the slope is very small
             {
                 start.X = bounds.X;
                 start.Y = start.Y;

                 end.X = bounds.X + bounds.Width;
                 end.Y = end.Y;
                 return;

             }

             if (Math.Round(start.X, 2) == Math.Round(end.X, 2) || Math.Abs(slope) <= 0.01d)
             {
                 start.X = start.X;
                 start.Y = bounds.Y;

                 end.X = end.X;
                 end.Y = bounds.Y + bounds.Height;

                 return;


             }

             // based on (y - y1) / (x - x1) == (y2 - y1) / (x2 - x1)
             // => (y - y1) * (x2 - x1) == (y2 - y1) * (x - x1)

             //    y_for_xmin = y1      +   (y2    - y1)      * (xmin - x1) / (x2 - x1)
             float y_for_xmin = start.Y + ((end.Y - start.Y) * (bounds.X - start.X) / (end.X - start.X));

             // y_for_xmax = y1 + (y2 - y1) * (xmax - x1) / (x2 - x1)
             float y_for_xmax = start.Y + ((end.Y - start.Y) * (bounds.X + bounds.Width - start.X) / (end.X - start.X));

             // x_for_ymin = x1 + (x2 - x1) * (ymin - y1) / (y2 - y1)

             float x_for_ymin = start.X + ((end.X - start.X) * (bounds.Y - start.Y) / (end.Y - start.Y));


             //x_for_ymax = x1 + (x2 - x1) * (ymax - y1) / (y2 - y1)
             float x_for_ymax = start.X + ((end.X - start.X) * (bounds.Y + bounds.Height - start.Y) / (end.Y - start.Y));



             if ((bounds.Y <= y_for_xmin) && (y_for_xmin <= bounds.Y + bounds.Height))
             {



                 if ((bounds.X <= x_for_ymax) && (bounds.X <= bounds.X + bounds.Width))
                 {
                     start.X = bounds.X;
                     start.Y = y_for_xmin;

                     end.X = x_for_ymax;
                     end.Y = bounds.Y + bounds.Height;
                     return;
                 }

                 if ((bounds.X <= x_for_ymin && x_for_ymin <= bounds.X + bounds.Width))
                 {
                     start.X = bounds.X;
                     start.Y = y_for_xmin;

                     end.X = x_for_ymin;
                     end.Y = bounds.Y;
                     return;

                 }

             }

             if ((bounds.Y <= y_for_xmax) && (bounds.Y <= bounds.Y + bounds.Height))
             {
                 if ((bounds.X <= x_for_ymin) && (x_for_ymin <= bounds.X + bounds.Width))
                 {
                     start.X = x_for_ymin;
                     start.Y = bounds.Y;

                     end.X = bounds.X + bounds.Width;
                     end.Y = y_for_xmax;

                     return;

                 }
                 if ((bounds.X <= x_for_ymax) && (x_for_ymax <= bounds.X + bounds.Width))
                 {

                     start.X = x_for_ymax;
                     start.Y = bounds.Y + bounds.Height;

                     end.X = bounds.X + bounds.Width;
                     end.Y = y_for_xmax;
                     return;

                 }
             }


         }





     }

任何想法如何解决矩形的线点

的情况

1 个答案:

答案 0 :(得分:1)

static bool intersection(PointF a1, PointF a2, PointF b1, PointF b2, ref PointF ans)
{
  float x = ((a1.X*a2.Y - a1.Y*a2.X)*(b1.X - b2.X) - (a1.X - a2.X)*(b1.X*b2.Y - b1.Y*b2.X)) / ((a1.X - a2.X)*(b1.Y - b2.Y) - (a1.Y - a2.Y)*(b1.X - b2.X));
  float y = ((a1.X*a2.Y - a1.Y*a2.X)*(b1.Y - b2.Y) - (a1.Y - a2.Y)*(b1.X*b2.Y - b1.Y*b2.X)) / ((a1.X - a2.X)*(b1.Y - b2.Y) - (a1.Y - a2.Y)*(b1.X - b2.X));

  if(x == float.NaN || x == float.PositiveInfinity || x == float.NegativeInfinity || y == float.NaN || y == float.PositiveInfinity || y == float.NegativeInfinity)
  { // the lines are equal or never intersect
   return false;
  }
  ans.X = x;
  ans.Y = y;
  return true;
}

static void extend(Rectangle bounds, ref PointF start, ref PointF end)
{

  List<PointF> ansFinal = new List<PointF>();
  PointF ansLeft = new PointF();
  bool hitLeft = intersection(start, end, new PointF(bounds.X, bounds.Y), new PointF(bounds.X, bounds.Y + bounds.Height), ansLeft);
  if(hitLeft && (ansLeft.Y < bounds.Y || ansLeft.Y > bounds.Y + bounds.Height)) hitLeft = false;
  if(hitLeft) ansFinal.Add(ansLeft);

  PointF ansTop = new PointF();
  bool hitTop = intersection(start, end, new PointF(bounds.X, bounds.Y), new PointF(bounds.X + bounds.Width, bounds.Y), ansTop);
  if(hitTop && (ansTop.X < bounds.X || ansTop.X > bounds.X + bounds.Width)) hitTop = false;
  if(hitTop) ansFinal.Add(ansTop);

  PointF ansRight = new PointF();
  bool hitRight = intersection(start, end, new PointF(bounds.X + bounds.Width, bounds.Y), new PointF(bounds.X + bounds.Width, bounds.Y + bounds.Height), ansRight);
  if(hitRight && (ansRight.Y < bounds.Y || ansRight.Y > bounds.Y + bounds.Height)) hitRight = false;
  if(hitRight) ansFinal.Add(ansRight);

  PointF ansBottom = new PointF();
  bool hitBottom = intersection(start, end, new PointF(bounds.X, bounds.Y + bounds.Height), new PointF(bounds.X + bounds.Height, bounds.Y + bounds.Height), ansBottom);
  if(hitBottom && (ansBottom.X < bounds.X || ansBottom.X > bounds.X + bounds.Width)) hitBottom = false;
  if(hitBottom) ansFinal.Add(ansBottom);

  if(!hitLeft && !hitTop && !hitRight && !hitBottom)
  {
   throw new Exception("No interections");
  }
  /*
  // IF YOU HAD LINQ
  PointF[] ans = ansFinal.Distinct().ToArray();
  if(ans.Length < 2)
  {
   throw new Exception("Corner case *wink*");
  }
  start.X = ans[0].X; start.Y = ans[0].Y;
  end.X = ans[1].X; end.Y = ans[1].Y;
  */

  // the following is sufficient to cull out corner to corner, one corner
  for(int x=ansFinal.Count-1; x>=1; x--)
   if(ansFinal[x] == ansFinal[x-1])
    ansFinal.RemoveAt(x);
  if(ansFinal.Count < 2)
  {
   throw new Exception("Corner case *wink*");
  }

  start.X = ansFinal[0].X; start.Y = ansFinal[0].Y;
  end.X = ansFinal[1].X; end.Y = ansFinal[1].Y;

}

编辑我在浏览器中写了这个,所以可能会有一些语法错误......

概念是您使用与矩形每边的线对线交点进行测试。如果存在交叉点,则确保它在矩形边(线段)的范围内。