在Java中验证点是否是二次Bezier曲线的一部分
我想验证一个点是否是由点p0、p1和p2定义的二次贝塞尔曲线的一部分 这是我的函数,用于获得曲线中具有特定t的点:在Java中验证点是否是二次Bezier曲线的一部分,java,math,bezier,Java,Math,Bezier,我想验证一个点是否是由点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-
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);
}
考虑到二次曲线中的点Bt如下所示:
Bt=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};
}
我获得以下输出:
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来执行这些操作吗?有没有其他方法来验证这一点?谢谢这里有一个错误:
double[] ty = obtainTs(p.y, p0, p1, p2);
因为obtainTs使用p0、p1、p2的x坐标来查找
p的y坐标
如果将方法参数更改为int,可以是点的x坐标或y坐标:
public static double[] obtainTs (int comp, int p0, int p1, int p2) {
double a = p0 - 2*p1 + p2;
double b = 2*p1 - 2*p0 ;
double c = p0 - 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};
}
叫它
double[] tx = obtainTs(p.x, p0.x, p1.x, p2.x);
double[] ty = obtainTs(p.y, p0.y, p1.y, p2.y);
然后测试代码将返回true tested,错误=0.02
注意,如果你写下方程式
B(t) = (1 - t)^2 * p0 + 2 * t * (1 - t) * p1 + t^2 * p2
对于x坐标和y坐标,则可以消除t^2项,得到一个
t的线性方程。这就给出了下面的方法,可能稍微简单一些
并且不使用平方根:
public static final boolean belongsQuadratic2 (Point p, Point p0, Point p1, Point p2) {
double ax = p0.x - 2*p1.x + p2.x;
double bx = 2*p1.x - 2*p0.x ;
double cx = p0.x - p.x;
double ay = p0.y - 2*p1.y + p2.y;
double by = 2*p1.y - 2*p0.y ;
double cy = p0.y - p.y;
// "Candidate" for t:
double t = -(cx*ay - cy*ax)/(bx*ay - by*ax);
if (t < 0 || t > 1)
return false;
// Compute the point corresponding to this candidate value ...
Point q = Bezier.quadratic(p0, p1, p2, t);
// ... and check if it is near the given point p:
return Math.abs(q.x - p.x) <= 1 && Math.abs(q.y - p.y) <= 1;
}
当然,必须检查特殊情况,例如bx*ay-by*ax==0
还要注意的是,很难准确确定点是否位于曲线上,因为
点坐标四舍五入为整数 这里有一个错误:
double[] ty = obtainTs(p.y, p0, p1, p2);
因为obtainTs使用p0、p1、p2的x坐标来查找
p的y坐标
如果将方法参数更改为int,可以是点的x坐标或y坐标:
public static double[] obtainTs (int comp, int p0, int p1, int p2) {
double a = p0 - 2*p1 + p2;
double b = 2*p1 - 2*p0 ;
double c = p0 - 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};
}
叫它
double[] tx = obtainTs(p.x, p0.x, p1.x, p2.x);
double[] ty = obtainTs(p.y, p0.y, p1.y, p2.y);
然后测试代码将返回true tested,错误=0.02
注意,如果你写下方程式
B(t) = (1 - t)^2 * p0 + 2 * t * (1 - t) * p1 + t^2 * p2
对于x坐标和y坐标,则可以消除t^2项,得到一个
t的线性方程。这就给出了下面的方法,可能稍微简单一些
并且不使用平方根:
public static final boolean belongsQuadratic2 (Point p, Point p0, Point p1, Point p2) {
double ax = p0.x - 2*p1.x + p2.x;
double bx = 2*p1.x - 2*p0.x ;
double cx = p0.x - p.x;
double ay = p0.y - 2*p1.y + p2.y;
double by = 2*p1.y - 2*p0.y ;
double cy = p0.y - p.y;
// "Candidate" for t:
double t = -(cx*ay - cy*ax)/(bx*ay - by*ax);
if (t < 0 || t > 1)
return false;
// Compute the point corresponding to this candidate value ...
Point q = Bezier.quadratic(p0, p1, p2, t);
// ... and check if it is near the given point p:
return Math.abs(q.x - p.x) <= 1 && Math.abs(q.y - p.y) <= 1;
}
当然,必须检查特殊情况,例如bx*ay-by*ax==0
还要注意的是,很难准确确定点是否位于曲线上,因为
点坐标四舍五入为整数 作为一个替代答案,为了避免Martin R指出的问题,您可以简单地构建一个查找表,并通过这种方式将坐标解析为曲线上的坐标。构建曲线时,为增量t值生成一个N点坐标数组,然后当需要测试坐标是否位于曲线上时,通过检查该坐标是否在查找表中,或是否足够接近查找表中的坐标,找到距离该坐标最近的t值。代码:
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的成本几乎为零,因为为了绘制曲线,我们已经生成了这些t坐标值,并且如果不首先确保坐标在曲线的边界框中,就不会运行曲线上的测试。作为替代答案,为了避免Martin R指出的问题,您可以简单地构建一个查找表,并通过这种方式将坐标解析为曲线上的坐标。构建曲线时,为增量t值生成一个N点坐标数组,然后当需要测试坐标是否位于曲线上时,通过检查该坐标是否在查找表中,或是否足够接近查找表中的坐标,找到距离该坐标最近的t值。代码:
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的成本几乎为零,因为我们已经生成了这些t坐标值,以便绘制曲线,如果不先确保坐标在曲线的边界框中是均匀的,你就不能运行曲线测试。你不能使用Graphics2D包来使用CubicCurve2D方法吗?@Sebastian在我的问题中,我使用的是二次函数,Cubic不起作用。。nachokk我将尝试一下BigDecimal,thanksany二次曲线完美地表示为三次曲线。如果你的二次曲线有点{p1,p2,p3},那么三次等价完美等价使用{p1,p1+2*p2/3,2*p2+p3/3,p3}。不要重新发明轮子=你不能使用Graphics2D软件包来使用CubicCurve2D方法吗?@Sebastian在我的问题中,我使用的是二次函数,立方函数不起作用。。nachokk我将尝试一下BigDecimal,thanksany二次曲线完美地表示为三次曲线。如果你的二次曲线有点{p1,p2,p3},那么三次等价完美等价使用{p1,p1+2*p2/3,2*p2+p3/3,p3}。不要重新发明轮子=谢谢@Martin!我喜欢你的没有平方根的方法,我会尝试一下:谢谢@Martin!我喜欢你没有平方根的方法 不要尝试: