开发者

limits line segment to the boundry of rectangle

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

limits line segment to the boundry of rectangle

 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


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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜