【发布时间】:2015-07-30 12:35:37
【问题描述】:
是否需要缩放双精度值,或者在使用真实世界值时它们是否更精确?使用 double 进行计算以获得最佳精度的最佳范围是哪个?
即我定义了三次贝塞尔曲线。我应该对三次曲线使用真实世界的位置值,还是应该在计算时使用标准化大小的值,然后在我想读取真实世界的值时按比例放大它们?
我举个例子,看看这段代码:
void CCubic::getTAtDistance(const CCubicPoint& pFrom, const double& distance, double& t)
{
CPoint pEnd = getP(t);
double cLength = (pEnd - pFrom).getLength();
int compare = GLOBAL::DoubleCompare(cLength, distance);
if(compare > 0)
{
t-=(t - pFrom.t)*0.5;
getTAtDistance(pFrom, distance, t);
}
else if(compare < 0)
{
t+=(t - pFrom.t)*0.5;
getTAtDistance(pFrom, distance, t);
}//else if
}
此方法计算三次曲线上一个点与三次曲线上另一个点的距离。
- pFrom 是计算距离的点。
- t 将被增量计算并定义新的 增量完成时曲线上指定距离处的点。
- getP 方法计算并返回三次曲线上指定 t 处的一个点。
最初调用方法时,t 设置为 1.0(曲线结束)。 由于三次贝塞尔曲线不是线性的,我需要增量计算距点 pFrom 指定距离处的最近点。
在曲线上创建所有点的代码如下所示:
void CCubic::initEvenPointList(double distance, double offset)
{
//TODO: Check if r can be 0 in the 1/r code, and how to handle/show it.
lPoints.clear();
minRadius = DBL_MAX;
double t = 0;
CCubicPoint ccP = getCubicPoint(t);
lPoints.push_back(ccP);
if(ccP.radius<minRadius) minRadius = ccP.radius;
if(offset>0)
{
t = 1.0;
getTAtDistance(getCubicPoint(0), offset, t);
ccP = getCubicPoint(t);
lPoints.push_back(ccP);
if(ccP.radius<minRadius) minRadius = ccP.radius;
}//if
std::cout << "CCubic::initEventPointList -- Starting loop\n";
while(t<1.0)
{
double newT = 1.0;
getTAtDistance(ccP, distance, newT);
if(newT>1) break;
t = newT;
ccP = getCubicPoint(t);
lPoints.push_back(ccP);
if(ccP.radius<minRadius) minRadius = ccP.radius;
}
ccP = getCubicPoint(1.0);
lPoints.push_back(ccP);
if(ccP.radius<minRadius) minRadius = ccP.radius;
std::cout << "P(" << 0 << "): t = " << lPoints[0].t << "\n";
double d = 0;
for(int i=1; i<lPoints.size(); i++)
{
d+= (lPoints[i] - lPoints[i-1]).getLength();
std::cout << "P(" << i - 1<< "): t = " << lPoints[i].t << ", d = " << d*400 << "\n";
}//for
}
如果我在实际值中定义三次贝塞尔曲线:
- A(-400, 0, 0)(起点)
- B(0, -200, 0)(A 的控制点)
- C(0, -200, 0)(D 的控制点)
- D(400, 0, 0)(终点)
并将距离设置为 25。
我得到大约 34 分,两者之间的距离正确。一切正常。
然后我注意到,如果我将三次贝塞尔曲线定义为标准化并按比例放大(最大值为 1.0),即:
- A(-1, 0, 0)(起点)
- B(0, -0.5, 0)(A 的控制点)
- C(0, -0.5, 0)(D 的控制点)
- D(1, 0, 0)(终点)
然后我将距离设置为 25/400(比例为 400)。 如果计算整个曲线,放大后我只得到大约 4 个点。这不应该发生在数学中。所以应该有舍入错误,或者我的代码错误。
我给你getCubicPoint和getP的代码,还有DoubleCompare:
CPoint CCubic::getP(double f) const
{
CPoint rP = pA*pow(1-f, 3) + pB*3*f*pow(1-f, 2) + pC*3*(1-f)*pow(f, 2) + pD*pow(f,3);
return rP;
}
CCubicPoint CCubic::getCubicPoint(double f) const
{
CPoint cP = pA*pow(1-f, 3) + pB*3*f*pow(1-f, 2) + pC*3*(1-f)*pow(f, 2) + pD*pow(f,3);
CPoint pI = (pB - pA)*3 + (pA + pC - pB*2)*6*f + (pD + pB*3 - pC*3 - pA)*3*pow(f,2);
CPoint pII = (pA + pC - pB*2)*6 + (pD + pB*3 - pC*3 - pA)*6*f;
double r = (pI.x*pII.y - pII.x*pI.y) / pow((pow(pI.x,2) + pow(pI.y, 2)), 3.0/2.0);
r = 1/r;
if(r<0) r = -r;
pII = pI.getNormal(true); //Right normal
pII = pII.getNormalized();
return CCubicPoint(cP, pII, r, f);
}
int GLOBAL::DoubleCompare(double A, double B)
{
if(abs(A - B) < std::numeric_limits<double>::epsilon()) return 0;
if(A < B) return -1;
return 1;
}
【问题讨论】: