将线段限制在矩形的边界内

发布于 2024-12-03 03:46:12 字数 3688 浏览 0 评论 0原文

我使用以下代码将线段延伸到矩形的边界,如果点在矩形内,它会很好地工作,但如果有一个点超出矩形边界,则会失败

在此处输入图像描述

 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;

                 }
             }


         }





     }

知道如何解决线点超出矩形的情况

I use the following code to extend line segment to the boundry of rectangle, it work well if points within the rectangle, but if there's a point out of the rectangle boundry it fail

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;

                 }
             }


         }





     }

any idea how to solve the case of points of line out of the rectangle

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

永言不败 2024-12-10 03:46:12
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;

}

编辑我在浏览器中编写了此内容,因此可能存在一些语法错误...

这个概念是您使用矩形每条边的线与线相交进行测试。如果存在交点,请确保它位于矩形边(线段)的边界内。

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;

}

EDIT I wrote this inside the browser so there may be a few syntax errors...

The concept is you test using Line to Line intersection with each side of the rectangle. If an intersection exists you make sure it's within the bounds of the rectangles side (line segment).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文