如何在一条线(线渲染器)的两点(Vector2)之间找到一个点(vector2)
how to find a point(vector2) between two points(Vector2) of a line (line renderer)
正如问题所解释的,如何在一条线(线渲染器)的两点(Vector2)之间找到一个点(vector2),
我正在使用线条渲染器绘制带有两个点的线条(从矢量和端点开始),我想要的是线条中的点 A,如图中所示。
从理论上讲,我想为我的用例缩短线的原始长度,我正在对重叠的两条线进行线相交检查,但问题是在某些情况下线从同一点开始,并且在那些情况下,如果点相遇,它仍然算作线相交。所以理论上我想缩短线相交检查的线,这样如果点相遇它就不会与另一条线相交。
这是我的线相交检查脚本!
public bool isIntersecting = false;
LineRenderer lineRenderer;
private void Start()
{
lineRenderer = this.GetComponent<LineRenderer>();
}
private void Update()
{
LineRenderer recievedLine;
if (FindObjectOfType<LineDynamics>().ropeRenderer != null)
{
recievedLine = FindObjectOfType<LineDynamics>().ropeRenderer;
}
else
{
return;
}
AreLineSegmentsIntersectingDotProduct(lineRenderer.GetPosition(0), lineRenderer.GetPosition(lineRenderer.positionCount - 1), recievedLine.GetPosition(0), recievedLine.GetPosition(recievedLine.positionCount - 1));
}
//Line segment-line segment intersection in 2d space by using the dot product
//p1 and p2 belongs to line 1, and p3 and p4 belongs to line 2
public bool AreLineSegmentsIntersectingDotProduct(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
{
if (IsPointsOnDifferentSides(p1, p2, p3, p4) && IsPointsOnDifferentSides(p3, p4, p1, p2))
{
isIntersecting = true;
}
else
{
isIntersecting = false;
}
return isIntersecting;
}
//Are the points on different sides of a line?
private bool IsPointsOnDifferentSides(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
{
bool isOnDifferentSides = false;
//The direction of the line
Vector2 lineDir = p2 - p1;
//The normal to a line is just flipping x and z and making z negative
Vector2 lineNormal = new Vector2(-lineDir.y, lineDir.x);
//Now we need to take the dot product between the normal and the points on the other line
float dot1 = Vector2.Dot(lineNormal, p3 - p1);
float dot2 = Vector2.Dot(lineNormal, p4 - p1);
//If you multiply them and get a negative value then p3 and p4 are on different sides of the line
if (dot1 * dot2 < 0f)
{
isOnDifferentSides = true;
}
return isOnDifferentSides;
}
如有任何建议和帮助,我们将不胜感激。
针对你的问题
你可以,例如使用 Vector2.Lerp
以获得起点和终点之间的任何点,给定 0
和 1
之间的因数,其中
0
:等于起点
1
:等于终点
{0;1}
:等于开始和结束之间的线性插值
对于中心,例如是
var center = Vector2.Lerp(startPosition, endPosition, 0.5f);
如果您更愿意从起点开始一定的行进距离,您可以使用 Vector2.MoveTowards
like
var otherPoint = Vector2.MoveTowards(startPoint, endPoint, desiredDistanceFromStartPoint);
基本上你也可以完全手动,基本上做同样的事情
var direction = (endPoint - startPoint).normalized;
var otherPoint = startPoint + direction * desiredDistanceFromStartPoint;
但是,这并不能防止您超过终点。
解决你的实际问题
你知道 Unity 社区早就在 Wiki - Math functions 下实现了功能,它已经提供了例如
//Calculate the intersection point of two lines. Returns true if lines intersect, otherwise false.
//Note that in 3d, two lines do not intersect most of the time. So if the two lines are not in the
//same plane, use ClosestPointsOnTwoLines() instead.
public static bool LineLineIntersection(out Vector3 intersection, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){
Vector3 lineVec3 = linePoint2 - linePoint1;
Vector3 crossVec1and2 = Vector3.Cross(lineVec1, lineVec2);
Vector3 crossVec3and2 = Vector3.Cross(lineVec3, lineVec2);
float planarFactor = Vector3.Dot(lineVec3, crossVec1and2);
//is coplanar, and not parrallel
if(Mathf.Abs(planarFactor) < 0.0001f && crossVec1and2.sqrMagnitude > 0.0001f)
{
float s = Vector3.Dot(crossVec3and2, crossVec1and2) / crossVec1and2.sqrMagnitude;
intersection = linePoint1 + (lineVec1 * s);
return true;
}
else
{
intersection = Vector3.zero;
return false;
}
}
//Two non-parallel lines which may or may not touch each other have a point on each line which are closest
//to each other. This function finds those two points. If the lines are not parallel, the function
//outputs true, otherwise false.
public static bool ClosestPointsOnTwoLines(out Vector3 closestPointLine1, out Vector3 closestPointLine2, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){
closestPointLine1 = Vector3.zero;
closestPointLine2 = Vector3.zero;
float a = Vector3.Dot(lineVec1, lineVec1);
float b = Vector3.Dot(lineVec1, lineVec2);
float e = Vector3.Dot(lineVec2, lineVec2);
float d = a*e - b*b;
//lines are not parallel
if(d != 0.0f){
Vector3 r = linePoint1 - linePoint2;
float c = Vector3.Dot(lineVec1, r);
float f = Vector3.Dot(lineVec2, r);
float s = (b*f - c*e) / d;
float t = (a*f - c*b) / d;
closestPointLine1 = linePoint1 + lineVec1 * s;
closestPointLine2 = linePoint2 + lineVec2 * t;
return true;
}
else{
return false;
}
}
如前所述,如果您担心的实际上是两条线的起点相等(非常不可能),那么与您正在进行的其余计算相比,进行 50 Vector3 ==
检查非常便宜。
正如问题所解释的,如何在一条线(线渲染器)的两点(Vector2)之间找到一个点(vector2),
我正在使用线条渲染器绘制带有两个点的线条(从矢量和端点开始),我想要的是线条中的点 A,如图中所示。
从理论上讲,我想为我的用例缩短线的原始长度,我正在对重叠的两条线进行线相交检查,但问题是在某些情况下线从同一点开始,并且在那些情况下,如果点相遇,它仍然算作线相交。所以理论上我想缩短线相交检查的线,这样如果点相遇它就不会与另一条线相交。
这是我的线相交检查脚本!
public bool isIntersecting = false;
LineRenderer lineRenderer;
private void Start()
{
lineRenderer = this.GetComponent<LineRenderer>();
}
private void Update()
{
LineRenderer recievedLine;
if (FindObjectOfType<LineDynamics>().ropeRenderer != null)
{
recievedLine = FindObjectOfType<LineDynamics>().ropeRenderer;
}
else
{
return;
}
AreLineSegmentsIntersectingDotProduct(lineRenderer.GetPosition(0), lineRenderer.GetPosition(lineRenderer.positionCount - 1), recievedLine.GetPosition(0), recievedLine.GetPosition(recievedLine.positionCount - 1));
}
//Line segment-line segment intersection in 2d space by using the dot product
//p1 and p2 belongs to line 1, and p3 and p4 belongs to line 2
public bool AreLineSegmentsIntersectingDotProduct(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
{
if (IsPointsOnDifferentSides(p1, p2, p3, p4) && IsPointsOnDifferentSides(p3, p4, p1, p2))
{
isIntersecting = true;
}
else
{
isIntersecting = false;
}
return isIntersecting;
}
//Are the points on different sides of a line?
private bool IsPointsOnDifferentSides(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
{
bool isOnDifferentSides = false;
//The direction of the line
Vector2 lineDir = p2 - p1;
//The normal to a line is just flipping x and z and making z negative
Vector2 lineNormal = new Vector2(-lineDir.y, lineDir.x);
//Now we need to take the dot product between the normal and the points on the other line
float dot1 = Vector2.Dot(lineNormal, p3 - p1);
float dot2 = Vector2.Dot(lineNormal, p4 - p1);
//If you multiply them and get a negative value then p3 and p4 are on different sides of the line
if (dot1 * dot2 < 0f)
{
isOnDifferentSides = true;
}
return isOnDifferentSides;
}
如有任何建议和帮助,我们将不胜感激。
针对你的问题
你可以,例如使用 Vector2.Lerp
以获得起点和终点之间的任何点,给定 0
和 1
之间的因数,其中
0
:等于起点1
:等于终点{0;1}
:等于开始和结束之间的线性插值
对于中心,例如是
var center = Vector2.Lerp(startPosition, endPosition, 0.5f);
如果您更愿意从起点开始一定的行进距离,您可以使用 Vector2.MoveTowards
like
var otherPoint = Vector2.MoveTowards(startPoint, endPoint, desiredDistanceFromStartPoint);
基本上你也可以完全手动,基本上做同样的事情
var direction = (endPoint - startPoint).normalized;
var otherPoint = startPoint + direction * desiredDistanceFromStartPoint;
但是,这并不能防止您超过终点。
解决你的实际问题
你知道 Unity 社区早就在 Wiki - Math functions 下实现了功能,它已经提供了例如
//Calculate the intersection point of two lines. Returns true if lines intersect, otherwise false.
//Note that in 3d, two lines do not intersect most of the time. So if the two lines are not in the
//same plane, use ClosestPointsOnTwoLines() instead.
public static bool LineLineIntersection(out Vector3 intersection, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){
Vector3 lineVec3 = linePoint2 - linePoint1;
Vector3 crossVec1and2 = Vector3.Cross(lineVec1, lineVec2);
Vector3 crossVec3and2 = Vector3.Cross(lineVec3, lineVec2);
float planarFactor = Vector3.Dot(lineVec3, crossVec1and2);
//is coplanar, and not parrallel
if(Mathf.Abs(planarFactor) < 0.0001f && crossVec1and2.sqrMagnitude > 0.0001f)
{
float s = Vector3.Dot(crossVec3and2, crossVec1and2) / crossVec1and2.sqrMagnitude;
intersection = linePoint1 + (lineVec1 * s);
return true;
}
else
{
intersection = Vector3.zero;
return false;
}
}
//Two non-parallel lines which may or may not touch each other have a point on each line which are closest
//to each other. This function finds those two points. If the lines are not parallel, the function
//outputs true, otherwise false.
public static bool ClosestPointsOnTwoLines(out Vector3 closestPointLine1, out Vector3 closestPointLine2, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2){
closestPointLine1 = Vector3.zero;
closestPointLine2 = Vector3.zero;
float a = Vector3.Dot(lineVec1, lineVec1);
float b = Vector3.Dot(lineVec1, lineVec2);
float e = Vector3.Dot(lineVec2, lineVec2);
float d = a*e - b*b;
//lines are not parallel
if(d != 0.0f){
Vector3 r = linePoint1 - linePoint2;
float c = Vector3.Dot(lineVec1, r);
float f = Vector3.Dot(lineVec2, r);
float s = (b*f - c*e) / d;
float t = (a*f - c*b) / d;
closestPointLine1 = linePoint1 + lineVec1 * s;
closestPointLine2 = linePoint2 + lineVec2 * t;
return true;
}
else{
return false;
}
}
如前所述,如果您担心的实际上是两条线的起点相等(非常不可能),那么与您正在进行的其余计算相比,进行 50 Vector3 ==
检查非常便宜。