簡體   English   中英

在 3D 空間中查找 3D 點和定向橢圓之間的距離 (C++)

[英]Find the distance between a 3D point and an Orientated Ellipse in 3D space (C++)

為了給這個問題提供一些背景知識,我正在創建一個游戲,它需要知道一個物體的“軌道”是否在另一個軌道的容差范圍內。 為了顯示這一點,我使用目標軌道繪制了一個具有給定半徑(公差)的圓環形狀,現在我需要檢查橢圓是否在該圓環內。

我迷失在數學/堆棧交換的方程式中,因此要求更具體的解決方案。 為了澄清起見,這里有一張帶有環面和軌道(紅線)的游戲圖像。 很簡單,我想檢查紅色軌道是否在環面形狀內。

在此處輸入圖片說明

我認為我需要做的是在其中一個軌道上繪制世界空間中的四個點(很容易做到)。 然后我需要計算該點與其他軌道橢圓之間的最短距離。 這是困難的部分。 有幾個例子可以找到點到橢圓的最短距離,但都是二維的,很難遵循。

如果該距離小於所有四個點的公差,則認為這相當於軌道在目標環面內。

為簡單起見,所有這些軌道的原點始終位於世界原點 (0, 0, 0) - 我的坐標系是 Z-Up。 每個軌道都有一系列定義它的參數(軌道元素)。

這里簡單的方法:

  1. 將每個軌道采樣到一組N個點。

    設來自第一個軌道的點為A ,來自第二個軌道的點為B

     const int N=36; float A[N][3],B[N][3];
  2. 找到 2 個最近的點

    所以d=|A[i]-B[i]| 是最小的。 如果d小於或等於您的邊界/閾值,則軌道彼此太靠近。

  3. 速度與准確度

    除非您對#2使用某種高級方法,否則它的計算將是O(N^2) ,這有點嚇人。 N越大,結果的准確性越高,但計算時間越長。 有兩種方法可以補救。 例如:

    1. N第一個樣本

    2. 當找到最近的點時,再次對兩個軌道進行采樣

      但只在那些有問題的點附近(更高的N )。

      在此處輸入圖片說明

    3. 您可以通過循環 #2 來遞歸地提高精度,直到達到所需的精度

    4. 測試d橢圓是否彼此靠得太近

我想我可能有一個新的解決方案。

  1. 繪制當前軌道上的四個點(橢圓)。
  2. 將這些點投影到目標軌道(環面)的平面上。
  3. 使用目標軌道傾角作為平面的法線,計算每個(歸一化)點與目標軌道上的近點參數之間的角度。
  4. 使用這個角度作為平均異常,並計算等效的偏心異常。
  5. 使用這些偏心異常繪制目標軌道上的四個點 - 這應該是離另一個軌道最近的點。
  6. 檢查這些點之間的距離。

這里的困難來自計算角度並將其轉換為另一個軌道上的異常。 不過,這應該比遞歸函數更准確、更快。 當我試過這個時會更新。

編輯:

是的,這有效!

    // 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM