总的来说,我对C#和编程很陌生。我正在尝试计算直线和椭圆的交点。 当椭圆的半径大于 1f 时,代码按预期工作。
当半径(近似(小于 1f 时,"t" 返回 NaN。
我手动计算了这些数字,我注意到当半径下降到1f以下时,B * B = 30亿+。
我试图将"t"变成双精度,并且尝试使用System.Math而不是Mathf。 当半径<1f 时,"t" 仍返回 NaN。
任何反馈都非常感谢!
public static Vector2 GetEllipseOuterIntersection(Vector2 ellipseCentre, float radius, Vector2 lightDot, Vector2 objectDot) {
lightDot.x -= ellipseCentre.x;
lightDot.y -= ellipseCentre.y;
objectDot.x -= ellipseCentre.x;
objectDot.y -= ellipseCentre.y;
// Get the semiminor axis.
float vertRadius = radius/2;
// Calculate the quadratic parameters.
float A = (objectDot.x - lightDot.x) * (objectDot.x - lightDot.x) / radius / radius + (objectDot.y - lightDot.y) * (objectDot.y - lightDot.y) / vertRadius / vertRadius;
float B = 2 * lightDot.x * (objectDot.x - lightDot.x) / radius / radius + 2 * lightDot.y * (objectDot.y - lightDot.y) / vertRadius / vertRadius;
float C = lightDot.x * lightDot.x / radius / radius + lightDot.y * lightDot.y / vertRadius / vertRadius - 1;
double t = (-B + System.Math.Sqrt(B*B - (4*A*C))) / 2 / A;
print(t);
float x = (float) (lightDot.x + (objectDot.x - lightDot.x) * t + ellipseCentre.x);
float y = (float) (lightDot.y + (objectDot.y - lightDot.y) * t + ellipseCentre.y);
Vector2 outerIntersection = new Vector2(x, y);
return outerIntersection;
}
只要您的任何计算的任何组件都是NaN
那么整个结果也将是一个NaN
。
NaN
与数字增长到大无关(这会引发异常或行为意外 - 例如翻转到负值(。相反,它暗示在计算的某个点上,您正在创建一个数学上未定义的值。
当操作的结果未定义时,方法或运算符返回 NaN。例如,将零除以零的结果是 NaN,如以下示例所示。(但请注意,将非零数除以零返回正无穷大或负无穷大,具体取决于除数的符号。
除此之外,3 Billion * 3 Billion
会9E+24
,float
的最大值是3.40282347E+38
所以无论如何这都不是问题。
您可能在某处除以/ 0
例如,可能发生这种情况的地方是
当你通过
radius = 0
因为在很多情况下,您都在
除以/ radius
当你通过
radius = 2
因为那时你以后在做
vertRadius = radius / 2;
=> 是 1,然后你做
/ vertRadius - 1
例如C
所以
vertRadius - 1
会0
如果
A = 0
如果
objectDot.x - lightDot.x = 0
因为那时
A
,B
和C
都是0
如果
B*B - 4*A*C = 0
因为负数的平方根也是未定义的,而您确实
System.Math.Sqrt(B*B - 4*A*C)
您应该拆分计算并添加检查,以使调试,读取和维护更容易,例如有点像
public static Vector2 GetEllipseOuterIntersection(Vector2 ellipseCentre, float radius, Vector2 lightDot, Vector2 objectDot)
{
if(Mathf.Approximately(radius, 0))
{
Debug.LogError("radius may not be 0");
return default;
}
if(Mathf.Approximately(radius, 2))
{
Debug.LogError("radius may not be 2");
return default;
}
lightDot.x -= ellipseCentre.x;
lightDot.y -= ellipseCentre.y;
objectDot.x -= ellipseCentre.x;
objectDot.y -= ellipseCentre.y;
// Get the semiminor axis.
float vertRadius = radius/2;
var difX = objectDot.x - lightDot.x;
var difY = objectDot.y - lightDot.y;
if(Mathf.Approximately(difX, 0))
{
Debug.LogError("objectDot.x - lightDot.x may not be 0!");
return default;
}
if(Mathf.Approximately(difY, 0))
{
Debug.LogError("objectDot.y - lightDot.y may not be 0!");
return default;
}
var difXSqr = difX * difX;
var difYSqr = difY * difY;
var radiusSqr = radius * radius;
var vertRadiusSqr = vertRadius * vertRadius;
var lightDotXSqr = lightDot.x * lightDot.x;
var lightDotYSqr = lightDot.y * lightDot.y;
// Calculate the quadratic parameters.
float A = difXSqr / radiusSqrInverse + difYSqr / vertRadiusSqr;
float B = 2 * lightDot.x * difX / radiusSqr + 2 * lightDot.y * difY / vertRadiusSqr;
float C = lightDotXSqr / radiusSqr + lightDotYSqr / vertRadiusSqr - 1;
if(Mathf.Approximately(A, 0))
{
Debug.LogError("A may not be 0!");
return default;
}
double BSquare = B*B;
double AC4 = 4*A*C;
double DIF = BSquare - AC4;
if(DIF < 0)
{
Debug.LogError("DIF may not be negative!");
return default;
}
double t = (-B + System.Math.Sqrt(DIF)) / 2 / A;
print(t);
float x = (float) (lightDot.x + difX * t + ellipseCentre.x);
float y = (float) (lightDot.y + difY * t + ellipseCentre.y);
return new Vector2(x, y);
}
尝试改用长整型。
长值远高于整数。
// first number
long myLongNumber = 2345608830;
// second number
long secondLong = myLongNumber * 3;
第二长的结果:7036826490
编辑:我没有看到你需要小数。如果四舍五入到整数是一个问题,那么您可能需要其他解决方案。