2

この質問の背景を説明するために、オブジェクトの「軌道」が別の軌道に対する許容範囲内にあるかどうかを知る必要があるゲームを作成しています。これを示すために、Target Orbit を使用して、指定された半径 (許容値) でトーラス形状をプロットし、楕円がそのトーラス内にあるかどうかを確認する必要があります。

Math/Stack exchange の方程式で迷子になっているので、より具体的な解決策を求めています。わかりやすくするために、トーラスと軌道 (赤い線) を使用したゲームの画像を次に示します。簡単に言えば、その赤い軌道がそのトーラス形状内にあるかどうかを確認したいのです。

ここに画像の説明を入力

私がしなければならないことは、これらの軌道の 1 つに World-Space の 4 つの点をプロットすることです (実行するのは簡単です)。次に、その点と他の軌道の楕円との間の最短距離を計算する必要があります。これは難しい部分です。点から楕円までの最短距離を求める例はいくつかありますが、すべて 2D であり、追跡するのは非常に困難です。

その距離が 4 つのポイントすべての許容値よりも小さい場合、それは軌道がターゲット トーラスの内側にあることに相当すると考えてください。

簡単にするために、これらすべての軌道の原点は常に世界の原点 (0, 0, 0) にあり、私の座標系は Z-Up です。各軌道には、それを定義する一連のパラメータ (軌道要素) があります。

4

2 に答える 2

1

ここで簡単なアプローチ:

  1. 各軌道をサンプリングしてN点のセットにします。

    最初の軌道からの点をAとし、2 番目の軌道からの点を とする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楕円が互いに近すぎるかどうかをテストする

于 2016-04-01T15:48:42.713 に答える
0

新しい解決策があるかもしれないと思います。

  1. 現在の軌道 (楕円) に 4 つの点をプロットします。
  2. これらの点をターゲット軌道 (トーラス) の平面に投影します。
  3. ターゲット軌道傾斜角を平面の法線として使用して、各 (正規化された) ポイントとターゲット軌道上の近点の引数との間の角度を計算します。
  4. この角度を平均異常として使用し、同等の偏心異常を計算します。
  5. これらの偏心異常を使用して、ターゲット軌道上の 4 つの点をプロットします。これは、他の軌道に最も近い点である必要があります。
  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);}

コメントがこれがどのように機能するかを説明してくれることを願っています。数か月の頭のひっかき傷の後、最終的に解決しました。皆さんありがとう!

于 2016-04-04T11:46:28.010 に答える