ограничивает отрезок линии границей прямоугольника - PullRequest
1 голос
/ 07 сентября 2011

Я использую следующий код для расширения сегмента линии до границы прямоугольника, он хорошо работает, если точки внутри прямоугольника, но если есть точка вне границы прямоугольника, это не удастся

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 Ответ

1 голос
/ 07 сентября 2011
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;

}

РЕДАКТИРОВАТЬ Я написал это в браузере, так что может быть несколько синтаксических ошибок ...

Суть в том, что вы тестируете, используя пересечение между линиями с каждой стороныпрямоугольникЕсли пересечение существует, убедитесь, что оно находится в границах стороны прямоугольников (отрезок).

...