[英]Program to find line segment and bezier curve intersection
考虑足球场的给定图像
如您在图像中看到的,各种球的运动,其中一些是弯曲的(即,在图像中的(1),(2),(3)的情况下),而有些则可能不是弯曲的(即,线(4)) ,
所以我需要找到球线与球门线和边线的交点。 有时输入可能不是曲线(即一条线),如(4)给定图像的情况
我已经写了一个程序,不知道出了什么问题-这是解决这种程序的正确方法。
如果是,那么如何将贝塞尔曲线转换为方程式以更好地求解
考虑给定为
beizer curve eqaution -> a(x*x) + b*x + c
and line segment equation -> y = y1 + m(x-x1)
// maxCurvedPoint是曲线的最高点
var getIntersectionPoint = function (room, ballFromPosition, ballToPosition, maxCurvePoint)
{
var linepoints = [[m1,n1], [m2, n2], [m3, n3], [m4, n4]];
//converting three points(ballFromPosition, maxCurvePoint, ballToPosition) into the quadratic equation (Bezier curve) --(1)
//getting the equation of the line segment using the linepoints --(2)
//equating (1) and (2) and getting a quadratic equation and solving and finding intersection points
return intersectionPoint;
}
// solves //(-b(+-)sqrt(b*b - 4ac)/2ac)
function solve(a, b, c)
{
//check curve intersects line or not
if((Math.pow(b, 2) - (4 * a * c)) >= 0)
{
result1 = (-1 * b + Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
result2 = (-1 * b - Math.sqrt(Math.pow(b, 2) - (4 * a * c))) / (2 * a);
return [result1, result2];
}
return [];
}
谁能帮我这个? 也是最大的曲线点可以称为曲线的顶点吗?
我发现使用矢量方程更容易,因为代数将是旋转不变的(因此,您不必重新编写代码即可处理“水平”抛物线)。
1.曲线表示+相交测试
考虑具有端点A, C
,控制点B
和参数t
的二次Bezier曲线 :
并带有源O
,方向D
和参数s
的无限线 :
等式P
和R
给出了一对二次联立方程,可以重新安排它们以消除s
并找到抛物线参数t
:
求解t
二次方程,只接受范围[0, 1]
实根。 这样可以确保任何交点始终位于线段本身上。
2.处理线段
您还可以通过使用上述公式从t
计算s
并限制其值-将交点限制为线段 ,如果将D
归一化,该值等于沿线到O
的距离。
3.计算控制点B
注意,控制点B
的一般值不会给出对称的抛物线。 要为一般对称曲线计算B
:
定义变量:
M
: AB
中点 n
: 顺时针垂直于AC
方向 q
: 凸出凸出距离 -绝对值是从M
到曲线中点的距离 k
: M
到B
符号距离 一个令人惊讶的简单结果。
4.示例C#(样式)代码
public static Vector2[] computeIntersection
(
Vector2 A, Vector2 C, double q, // parabola segment
Vector2 O, Vector2 P // line segment
)
{
// quadratic solve
double[] solve(double a, double b, double c)
{
double d = b * b - 4.0 * a * c;
if (d < 0.0) // imaginary roots - no intersection at all
return null;
if (d > 0.0) // two distinct real roots
{
double sd = Math.Sqrt(d);
return new double[2] { (-b + sd) / (2.0 * a),
(-b - sd) / (2.0 * a) };
}
else // only one (line segment is tangent to curve)
{
return new double[1] { -b / (2.0 * a) };
}
}
// cross product (in-case undefined)
double cross(Vector2 i, Vector2 j)
{
return i.x * j.y - i.y * j.x;
}
// validity check for t and s
bool valid(double v)
{
return (v >= 0.0) && (v <= 1.0);
}
// compute control point B
Vector2 E = C - A;
Vector2 M = 0.5 * (A + C);
Vector2 N = (new Vector2(E.y, -E.x)).normalize();
Vector2 B = M + (2.0 * q) * N;
// solving for t
Vector2 D = P - O;
bool useX = Math.Abs(D.X) > Math.Abs(D.Y);
double[] T = solve(cross(A + C - 2.0 * B, D),
cross(B - A, D) * 2.0,
cross(A - O, D));
if (T == null) return null;
Vector2[] I = new Vector2[2];
int c = 0;
for (int i = 0; i < T.Length; i++)
{
// check if t is within curve range
double t = T[i];
if (!valid(t)) continue;
// solve for s and check if is within line range
double u = (1 - t) * (1 - t);
double v = 2 * t * (1 - t);
double w = t * t;
double s = useX ? ((u * A.X + v * B.X + w * C.X - O.X) / D.X)
: ((u * A.Y + v * B.Y + w * C.Y - O.Y) / D.Y);
if (!valid(s)) continue;
// compute the corresponding intersection point
I[c++] = O + s * D;
}
// only return valid solutions
if (c == 0) return null;
Array.Resize(ref I, c);
return I;
}
如果以使线段变为(0, 0)-(d, 0)
的方式平移和旋转所有端点,则问题会得到简化。
设控制点为(Xk, Yk)
, k= 0, 1, 2
。 通过求解t
二次方程获得与X轴的交点
Y0 (1-t)² + 2 Y1 t(1-t) + Y2 t² = 0.
相应的横坐标为
X0 (1-t)² + 2 X1 t(1-t) + X2 t² = 0.
您可以检查它们是否属于间隔[0, d]
。 然后应用反向旋转和平移。
附录:两个二次贝塞尔曲线的交点
可以写出其中一条曲线的矢量方程
P = P0 (1 - t)² + 2 P1 t (1 - t) + P2 t²
= P0 + 2 (P1 - P0) t + (P0 - 2 P1 + P2) t².
如果应用坐标的仿射更改,以使参考系变为(P0, P1 - P0, P0 - 2 P1 + P2)
,则方程式简化为
X = 2t
Y = t²
这是隐式方程
X² = 4Y.
现在,通过对第二条曲线的控制点应用相同的变换并插入上面的参数方程式,您可以得到t
的四次方程(一侧是二次多项式的平方,另一侧是二次多项式的平方)。
对于四次方程的根有封闭式公式,并且可以有四个。 在[0, 1]
选择实根之后,您将评估第一条曲线的t
参数,并在[0, 1]
检查从属关系。
不要忘记恢复原始坐标。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.