[英]Find the distance between a 3D point and an Orientated Ellipse in 3D space (C++)
為了給這個問題提供一些背景知識,我正在創建一個游戲,它需要知道一個物體的“軌道”是否在另一個軌道的容差范圍內。 為了顯示這一點,我使用目標軌道繪制了一個具有給定半徑(公差)的圓環形狀,現在我需要檢查橢圓是否在該圓環內。
我迷失在數學/堆棧交換的方程式中,因此要求更具體的解決方案。 為了澄清起見,這里有一張帶有環面和軌道(紅線)的游戲圖像。 很簡單,我想檢查紅色軌道是否在環面形狀內。
我認為我需要做的是在其中一個軌道上繪制世界空間中的四個點(很容易做到)。 然后我需要計算該點與其他軌道橢圓之間的最短距離。 這是困難的部分。 有幾個例子可以找到點到橢圓的最短距離,但都是二維的,很難遵循。
如果該距離小於所有四個點的公差,則認為這相當於軌道在目標環面內。
為簡單起見,所有這些軌道的原點始終位於世界原點 (0, 0, 0) - 我的坐標系是 Z-Up。 每個軌道都有一系列定義它的參數(軌道元素)。
這里簡單的方法:
將每個軌道采樣到一組N
個點。
設來自第一個軌道的點為A
,來自第二個軌道的點為B
。
const int N=36; float A[N][3],B[N][3];
找到 2 個最近的點
所以d=|A[i]-B[i]|
是最小的。 如果d
小於或等於您的邊界/閾值,則軌道彼此太靠近。
速度與准確度
除非您對#2使用某種高級方法,否則它的計算將是O(N^2)
,這有點嚇人。 N
越大,結果的准確性越高,但計算時間越長。 有兩種方法可以補救。 例如:
我想我可能有一個新的解決方案。
這里的困難來自計算角度並將其轉換為另一個軌道上的異常。 不過,這應該比遞歸函數更准確、更快。 當我試過這個時會更新。
編輯:
是的,這有效!
// The Four Locations we will use for the checks
TArray<FVector> CurrentOrbit_CheckPositions;
TArray<FVector> TargetOrbit_ProjectedPositions;
CurrentOrbit_CheckPositions.SetNum(4);
TargetOrbit_ProjectedPositions.SetNum(4);
// We first work out the plane of the target orbit.
const FVector Target_LANVector = FVector::ForwardVector.RotateAngleAxis(TargetOrbit.LongitudeAscendingNode, FVector::UpVector); // Vector pointing to Longitude of Ascending Node
const FVector Target_INCVector = FVector::UpVector.RotateAngleAxis(TargetOrbit.Inclination, Target_LANVector); // Vector pointing up the inclination axis (orbit normal)
const FVector Target_AOPVector = Target_LANVector.RotateAngleAxis(TargetOrbit.ArgumentOfPeriapsis, Target_INCVector); // Vector pointing towards the periapse (closest approach)
// Geometric plane of the orbit, using the inclination vector as the normal.
const FPlane ProjectionPlane = FPlane(Target_INCVector, 0.f); // Plane of the orbit. We only need the 'normal', and the plane origin is the Earths core (periapse focal point)
// Plot four points on the current orbit, using an equally-divided eccentric anomaly.
const float ECCAngle = PI / 2.f;
for (int32 i = 0; i < 4; i++)
{
// Plot the point, then project it onto the plane
CurrentOrbit_CheckPositions[i] = PosFromEccAnomaly(i * ECCAngle, CurrentOrbit);
CurrentOrbit_CheckPositions[i] = FVector::PointPlaneProject(CurrentOrbit_CheckPositions[i], ProjectionPlane);
// TODO: Distance from the plane is the 'Depth'. If the Depth is > Acceptance Radius, we are outside the torus and can early-out here
// Normalize the point to find it's direction in world-space (origin in our case is always 0,0,0)
const FVector PositionDirectionWS = CurrentOrbit_CheckPositions[i].GetSafeNormal();
// Using the Inclination as the comparison plane - find the angle between the direction of this vector, and the Argument of Periapse vector of the Target orbit
// TODO: we can probably compute this angle once, using the Periapse vectors from each orbit, and just multiply it by the Index 'I'
float Angle = FMath::Acos(FVector::DotProduct(PositionDirectionWS, Target_AOPVector));
// Compute the 'Sign' of the Angle (-180.f - 180.f), using the Cross Product
const FVector Cross = FVector::CrossProduct(PositionDirectionWS, Target_AOPVector);
if (FVector::DotProduct(Cross, Target_INCVector) > 0)
{
Angle = -Angle;
}
// Using the angle directly will give us the position at th eccentric anomaly. We want to take advantage of the Mean Anomaly, and use it as the ecc anomaly
// We can use this to plot a point on the target orbit, as if it was the eccentric anomaly.
Angle = Angle - TargetOrbit.Eccentricity * FMathD::Sin(Angle);
TargetOrbit_ProjectedPositions[i] = PosFromEccAnomaly(Angle, TargetOrbit);}
我希望評論描述了這是如何工作的。 折騰了幾個月終於解決了。 謝謝大家!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.