简单地说,我有:
这是在视口坐标中所以+ X是正确的,+ Y在屏幕上。
我需要一个函数,它接受这些参数并返回矩形边缘上的点(矩形中心(0.5,0.5)和点(a,b)之间)与之相交的点。 / p>
我知道如何在给定坐标的纸上做到这一点,但是当我谈到代码时我无法弄明白。此外,我意识到这样的问题已在不同的线程中得到解决 - 但我无法在任何地方找到输出函数的简单输入。
我在Unity3D引擎中这样做,所以最好用Javascript,但任何语言或伪代码都会有很大的帮助,因为我可以手动转换它。
修改 为了澄清,我正在寻找类似的东西:
function IntersectFromViewportCenter(x : float, y : float) {
...
return Point(x1, y1);
}
其中(x,y)是圆外的点,(x1,y1)是交点。
由于
答案 0 :(得分:2)
将所有系统移至中心点(0,0)。使用方框(-1,-1) - (1,1)从原点到(移位)点(x',y')的光线交点。缩放并转回。我没有考虑盒子里面的琐事(是否需要?)
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
答案 1 :(得分:1)
MBo有正确的想法。这是在Unity中实现的一种方法。我认为UnityScript不值得使用 - 特别是它不支持扩展方法 - 所以你真的应该切换语言。 (另外,Unity实际上并未命名为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));
}
}
答案 2 :(得分:1)
由于已经提供了一些常规的“线/矩形”方法,因此该方法经过优化,可以避免在琐碎情况下(完全在Rect内部或完全在Rect外部)进行射线投射:https://gist.github.com/JohannesMP/50dad3175bf2925df508b642091e41c4
这是此方法的基本概述:
按以下方式将rect周围的区域划分为Sector(其中S4是rect本身):
S0| S1 |S2
--+----+-- ^
S3| S4 |S5 |
--+----+-- y
S6| S7 |S8 x-->
鉴于线段开始和结束的扇区,我们知道需要执行哪些射线广播(例如:S0-S2不需要射线广播,而S4-S1只需要射线广播顶部边缘,等等)
另外,如果分别处理垂直线和水平线,则可以将射线投射简化为一维。
在我的个人用例(很多线段,其中大部分完全位于Rect内部或完全位于Rect外部)中,这种方法比一般情况下要快,因为仅在必要时才执行Raycasts。
答案 3 :(得分:0)
$scope.setTotals = function(item){
if (item){
item.total = item.quantity * item.unitCost;
$scope.invoiceCount += item.quantity;
}
}
答案 4 :(得分: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;
}
}