2012-05-18 3 views
3

Проще говоря, у меня есть:Finding Отрезок-Прямоугольник точка пересечения

  • Области просмотр прямоугольник, где (0,0) является нижним левым углом (1,1) находится в верхнем правом и (0,5,0,5) является центром экрана.
  • Точка (a, b), которая находится за пределами прямоугольника.

Это в координатах виджетов, поэтому + X справа, + Y на экране.

И мне нужна функция, которая берет эти параметры и возвращает точку на краю прямоугольника, где линия (между центром прямоугольника (0,5,0,5) и точкой (a, b)) пересекает его.

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

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

EDIT Чтобы уточнить, я ищу что-то вроде:

function IntersectFromViewportCenter(x : float, y : float) { 
    ... 
    return Point(x1, y1); 
} 

Где (х, у) точки вне окружности и (x1, y1) является точкой пересечения.

Благодаря

ответ

2

сдвиг всей системы, чтобы быть центром в точке (0,0). Calc пересечение луча от начала координат до (сдвинутой) точки (x ', y') с полем (-1, -1) - (1,1). Масштабируйте и сдвиньте назад. Я не рассматривал тривиальный случай с точкой внутри коробки (это необходимо?)

x = x - 0.5 
y = y - 0.5 
if Abs(x) >= Abs(y) then //vertical box edge 
    y1 = y/x //care with case both y and x = 0 
    x1 = Sign(x) //+-1 
else // horizontal edge 
    x1 = x/y 
    y1 = Sign(y) 

x1 = 0.5*x1 + 0.5 
y1 = 0.5*y1 + 0.5 
+0

Спасибо, что, кажется, работает для меня. Я должен был добавить быстрое исправление, чтобы заставить его работать для нижней и левой сторон экрана, но это, вероятно, из-за того, что преобразование, которое я делаю из 3D-пространства мира, предварительно меняет координаты. – jt78

+0

Умножение/добавление для точки на краю не нужно. – Jessy

1

MBo имеет правильную идею. Вот способ реализации в Unity. Я не думаю, что UnityScript стоит использовать - в частности, он не поддерживает методы расширения, поэтому вам действительно нужно переключать языки. (Кроме того, единство фактически не назван Unity3D.)

Этот сценарий может пойти куда-нибудь в проекте:

using UnityEngine; 

public static class UnityEngineExtensions { 

public static Vector2 Abs(this Vector2 vector) { 
    for (int i = 0; i < 2; ++i) vector[i] = Mathf.Abs(vector[i]); 
    return vector; 
} 

public static Vector2 DividedBy(this Vector2 vector, Vector2 divisor) { 
    for (int i = 0; i < 2; ++i) vector[i] /= divisor[i]; 
    return vector; 
} 

public static Vector2 Max(this Rect rect) { 
    return new Vector2(rect.xMax, rect.yMax); 
} 

public static Vector2 IntersectionWithRayFromCenter(this Rect rect, Vector2 pointOnRay) { 
    Vector2 pointOnRay_local = pointOnRay - rect.center; 
    Vector2 edgeToRayRatios = (rect.Max() - rect.center).DividedBy(pointOnRay_local.Abs()); 
    return (edgeToRayRatios.x < edgeToRayRatios.y) ? 
     new Vector2(pointOnRay_local.x > 0 ? rect.xMax : rect.xMin, 
      pointOnRay_local.y * edgeToRayRatios.x + rect.center.y) : 
     new Vector2(pointOnRay_local.x * edgeToRayRatios.y + rect.center.x, 
      pointOnRay_local.y > 0 ? rect.yMax : rect.yMin); 
} 

} 

Присоединить этот другой сценарий к игре объекта и установить его переменные в инспекторе.

#pragma warning disable 0649 
using System; 
using UnityEngine; 

public class VisualizeRectIntersectionWithRayFromCenter : MonoBehaviour { 

[SerializeField] Rect rect; 
[SerializeField] Vector2 point; 

[Serializable] class Colors { 
    public Color rect, point, intersection; 
} [SerializeField] Colors colors; 

void OnDrawGizmos() { 
    Gizmos.color = colors.rect; 
    Vector2[] corners = {new Vector2(rect.xMin, rect.yMin), new Vector2(rect.xMin, rect.yMax), 
     rect.Max(), new Vector2(rect.xMax, rect.yMin)}; 
    int i = 0; 
    while (i < 3) Gizmos.DrawLine(corners[i], corners[++i]); 
    Gizmos.DrawLine(corners[3], corners[0]); 

    Gizmos.color = colors.point; 
    Gizmos.DrawLine(rect.center, point); 

    Gizmos.color = colors.intersection; 
    Gizmos.DrawLine(rect.center, rect.IntersectionWithRayFromCenter(pointOnRay: point)); 
} 

} 
1
bool LineRectIntersection(Vector2 lineStartPoint, Vector2 lineEndPoint, Rect rectangle, ref double resultX, ref double resultY) 
{ 
    Vector2 minXLinePoint = (lineStartPoint.x <= lineEndPoint.x) ? (lineStartPoint) : (lineEndPoint); 
    Vector2 maxXLinePoint = (lineStartPoint.x <= lineEndPoint.x) ? (lineEndPoint) : (lineStartPoint); 
    Vector2 minYLinePoint = (lineStartPoint.y <= lineEndPoint.y) ? (lineStartPoint) : (lineEndPoint); 
    Vector2 maxYLinePoint = (lineStartPoint.y <= lineEndPoint.y) ? (lineEndPoint) : (lineStartPoint); 

    double rectMaxX = rectangle.xMax; 
    double rectMinX = rectangle.xMin; 
    double rectMaxY = rectangle.yMax; 
    double rectMinY = rectangle.yMin; 

    if (minXLinePoint.x <= rectMaxX && rectMaxX <= maxXLinePoint.x) 
    { 
     double m = (maxXLinePoint.y - minXLinePoint.y)/(maxXLinePoint.x - minXLinePoint.x); 

     double intersectionY = ((rectMaxX - ((double)minXLinePoint.x)) * m) + ((double)minXLinePoint.y); 

     if(minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y) 
     { 
      resultX = rectMaxX; 
      resultY = intersectionY; 

      return true; 
     } 
    } 

    if (minXLinePoint.x <= rectMinX && rectMinX <= maxXLinePoint.x) 
    { 
     double m = (maxXLinePoint.y - minXLinePoint.y)/(maxXLinePoint.x - minXLinePoint.x); 

     double intersectionY = ((rectMinX - ((double)minXLinePoint.x)) * m) + ((double)minXLinePoint.y); 

     if (minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y) 
     { 
      resultX = rectMinX; 
      resultY = intersectionY; 

      return true; 
     } 
    } 

    if (minYLinePoint.y <= rectMaxY && rectMaxY <= maxYLinePoint.y) 
    { 
     double rm = (maxYLinePoint.x - minYLinePoint.x)/(maxYLinePoint.y - minYLinePoint.y); 

     double intersectionX = ((rectMaxY - ((double)minYLinePoint.y)) * rm) + ((double)minYLinePoint.x); 

     if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x) 
     { 
      resultX = intersectionX; 
      resultY = rectMaxY; 

      return true; 
     } 
    } 

    if (minYLinePoint.y <= rectMinY && rectMinY <= maxYLinePoint.y) 
    { 
     double rm = (maxYLinePoint.x - minYLinePoint.x)/(maxYLinePoint.y - minYLinePoint.y); 

     double intersectionX = ((rectMinY - ((double)minYLinePoint.y)) * rm) + ((double)minYLinePoint.x); 

     if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x) 
     { 
      resultX = intersectionX; 
      resultY = rectMinY; 

      return true; 
     } 
    } 

    return false; 
} 
0

@chakmeshma, ваше решение почти правильно, но вы должны также проверить, находится ли в пределах прямоугольника точка пересечения, чтобы избежать пограничных случаев:

private static bool LineRectIntersection(Vector2 lineStartPoint, Vector2 lineEndPoint, Rect rectangle, ref Vector2 result) 
    { 
     Vector2 minXLinePoint = lineStartPoint.x <= lineEndPoint.x ? lineStartPoint : lineEndPoint; 
     Vector2 maxXLinePoint = lineStartPoint.x <= lineEndPoint.x ? lineEndPoint : lineStartPoint; 
     Vector2 minYLinePoint = lineStartPoint.y <= lineEndPoint.y ? lineStartPoint : lineEndPoint; 
     Vector2 maxYLinePoint = lineStartPoint.y <= lineEndPoint.y ? lineEndPoint : lineStartPoint; 

     double rectMaxX = rectangle.xMax; 
     double rectMinX = rectangle.xMin; 
     double rectMaxY = rectangle.yMax; 
     double rectMinY = rectangle.yMin; 

     if (minXLinePoint.x <= rectMaxX && rectMaxX <= maxXLinePoint.x) 
     { 
      double m = (maxXLinePoint.y - minXLinePoint.y)/(maxXLinePoint.x - minXLinePoint.x); 

      double intersectionY = ((rectMaxX - minXLinePoint.x) * m) + minXLinePoint.y; 

      if (minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y 
       && rectMinY <= intersectionY && intersectionY <= rectMaxY) 
      { 
       result = new Vector2((float)rectMaxX, (float)intersectionY); 

       return true; 
      } 
     } 

     if (minXLinePoint.x <= rectMinX && rectMinX <= maxXLinePoint.x) 
     { 
      double m = (maxXLinePoint.y - minXLinePoint.y)/(maxXLinePoint.x - minXLinePoint.x); 

      double intersectionY = ((rectMinX - minXLinePoint.x) * m) + minXLinePoint.y; 

      if (minYLinePoint.y <= intersectionY && intersectionY <= maxYLinePoint.y 
       && rectMinY <= intersectionY && intersectionY <= rectMaxY) 
      { 
       result = new Vector2((float)rectMinX, (float)intersectionY); 

       return true; 
      } 
     } 

     if (minYLinePoint.y <= rectMaxY && rectMaxY <= maxYLinePoint.y) 
     { 
      double rm = (maxYLinePoint.x - minYLinePoint.x)/(maxYLinePoint.y - minYLinePoint.y); 

      double intersectionX = ((rectMaxY - minYLinePoint.y) * rm) + minYLinePoint.x; 

      if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x 
       && rectMinX <= intersectionX && intersectionX <= rectMaxX) 
      { 
       result = new Vector2((float)intersectionX, (float)rectMaxY); 

       return true; 
      } 
     } 

     if (minYLinePoint.y <= rectMinY && rectMinY <= maxYLinePoint.y) 
     { 
      double rm = (maxYLinePoint.x - minYLinePoint.x)/(maxYLinePoint.y - minYLinePoint.y); 

      double intersectionX = ((rectMinY - minYLinePoint.y) * rm) + minYLinePoint.x; 

      if (minXLinePoint.x <= intersectionX && intersectionX <= maxXLinePoint.x 
       && rectMinX <= intersectionX && intersectionX <= rectMaxX) 
      { 
       result = new Vector2((float)intersectionX, (float)rectMinY); 

       return true; 
      } 
     } 

     return false; 
    } 
} 
Смежные вопросы