我想验证一个点是否是由点 p0、p1 和 p2 定义的二次贝塞尔曲线的一部分..
这是我获取曲线中具有特定 t 的点的函数:
public static final Point quadratic (Point p0, Point p1, Point p2, double t) {
double x = Math.pow(1-t, 2) * p0.x + 2 * (1-t) * t * p1.x + Math.pow(t, 2) * p2.x;
double y = Math.pow(1-t, 2) * p0.y + 2 * (1-t) * t * p1.y + Math.pow(t, 2) * p2.y;
return new Point((int)x, (int)y);
}
考虑到二次曲线中的点B(t)的获取方式如下:
B(t) = (1 - t)^2 * p0 + 2 * t * (1 - t) * p1 + t^2 * p2
我应该通过获取该点的 t 值并将其与使用该 t 参数获得的点进行比较来验证点 P 是否属于曲线,但在 Java 中我遇到了变量精度的问题。
我验证点的函数如下:
public static final boolean belongsQuadratic (Point p, Point p0, Point p1, Point p2) {
double[] tx = obtainTs(p.x, p0, p1, p2);
double[] ty = obtainTs(p.y, p0, p1, p2);
if (tx[0] >= 0) {
if ((tx[0] >= ty[0] - ERROR && tx[0] <= ty[0] + ERROR) || (tx[0] >= ty[1] - ERROR && tx[0] <= ty[1] + ERROR)) {
return true;
}
}
if (tx[1] >= 0) {
if ((tx[1] >= ty[0] - ERROR && tx[1] <= ty[0] + ERROR) || (tx[1] >= ty[1] - ERROR && tx[1] <= ty[1] + ERROR)) {
return true;
}
}
return false;
}
public static double[] obtainTs (int comp, Point p0, Point p1, Point p2) {
double a = p0.x - 2*p1.x + p2.x;
double b = 2*p1.x - 2*p0.x ;
double c = p0.x - comp;
double t1 = (-b + Math.sqrt(b*b - 4*a*c)) / (2*a);
double t2 = (-b - Math.sqrt(b*b - 4*a*c)) / (2*a);
return new double[] {t1, t2};
}
因此,如果我使用以下值运行代码:
Point p0 = new Point(320, 480);
Point p1 = new Point(320, 240);
Point p2 = new Point(0, 240);
double t = 0.10f;
Point p = Bezier.quadratic(p0, p1, p2, t);
double[] ts = Bezier.obtainTs(p.x, p0, p1, p2);
我得到以下输出:
For t=0.10000000149011612, java.awt.Point[x=316,y=434]
For t1: -0.1118033988749895, java.awt.Point[x=316,y=536]
For t2: 0.1118033988749895, java.awt.Point[x=316,y=429]
java.awt.Point[x=316,y=434] belongs?: false
我应该使用BigDecimal
来执行操作吗?还有其他方法可以验证这一点吗?谢谢
最佳答案
作为替代答案,为了规避 Martin R 指出的问题,您可以简单地构建一个查找表并以这种方式将坐标解析为曲线上的坐标。当您构建曲线时,为增量 t 值生成一个 N 点坐标数组,然后当您需要测试坐标是否位于曲线上时,找到最近的 t em> 通过检查该坐标是否在查找表中,或者“足够接近”查找表中的坐标来对该坐标值进行赋值。在代码中:
point[] points = new point[100];
for(i=0; i<100; i++) {
t = i/100;
points[i] = new point(computeX(t), computeY(t));
}
然后当您需要曲线测试时:
for(i=0; i<points.length; i++) {
point = points[i];
if(abs(point-coordinate)<3) {
// close enough to the curve to count,
// so we can use t value map(i,0,100,0,1)
}
}
构建 LUT 几乎不需要任何成本,因为我们已经生成了这些坐标-for-t 值来绘制曲线,并且在没有首先确保坐标均匀的情况下,您不会运行曲线上测试在曲线的边界框中。
关于java - Java中验证一个点是否是二次贝塞尔曲线的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17119876/