2012-05-18 78 views
3

簡單地說,我有:查找線段矩形交點

  • 視口矩形,其中(0,0)是左下角,(1,1)是右上角和( 0.5,0.5)是屏幕的中心。
  • 矩形外的點(a,b)。

這是在視口座標系中,+ X是正確的,+ Y在屏幕上。

而且我需要一個函數,它接受這些參數,並返回矩形邊(矩形中心(0.5,0.5)和點(a,b))之間的直線相交的點。

我知道如何用給定的座標在紙上做到這一點,但是當它涉及到代碼時我無法弄清楚。此外,我意識到這樣的問題已經在不同的線程中得到了解決 - 但我無法在任何地方找到簡單的輸入來輸出函數。

我在Unity3D引擎中這麼做,所以最好在Javascript中,但任何語言或僞代碼將是一個很大的幫助,因爲我可以手工轉換它。

編輯 爲了澄清,我正在尋找類似:

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

其中(x,y)是圓和(X1,Y1)之外的點的交點。

謝謝

回答

2

將所有系統都移到以點(0,0)爲中心。計算從原點到(移位)點(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; 
    } 
}