Jambax
Jambax

Reputation: 171

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

To give some background to this question, I'm creating a game that needs to know whether the 'Orbit' of an object is within tolerance to another Orbit. To show this, I plot a Torus-shape with a given radius (the tolerance) using the Target Orbit, and now I need to check if the ellipse is within that torus.

I'm getting lost in the equations on Math/Stack exchange so asking for a more specific solution. For clarification, here's an image of the game with the Torus and an Orbit (the red line). Quite simply, I want to check if that red orbit is within that Torus shape.

enter image description here

What I believe I need to do, is plot four points in World-Space on one of those orbits (easy enough to do). I then need to calculate the shortest distance between that point, and the other orbits' ellipse. This is the difficult part. There are several examples out there of finding the shortest distance of a point to an ellipse, but all are 2D and quite difficult to follow.

If that distance is then less than the tolerance for all four points, then in think that equates to the orbit being inside the target torus.

For simplicity, the origin of all of these orbits is always at the world Origin (0, 0, 0) - and my coordinate system is Z-Up. Each orbit has a series of parameters that defines it (Orbital Elements).

Upvotes: 2

Views: 1370

Answers (2)

Jambax
Jambax

Reputation: 171

I think I may have a new solution.

  1. Plot the four points on the current orbit (the ellipse).
  2. Project those points onto the plane of the target orbit (the torus).
  3. Using the Target Orbit inclination as the normal of a plane, calculate the angle between each (normalized) point and the argument of periapse on the target orbit.
  4. Use this angle as the mean anomaly, and compute the equivalent eccentric anomaly.
  5. Use those eccentric anomalies to plot the four points on the target orbit - which should be the nearest points to the other orbit.
  6. Check the distance between those points.

The difficulty here comes from computing the angle and converting it to the anomaly on the other orbit. This should be more accurate and faster than a recursive function though. Will update when I've tried this.

EDIT:

Yep, this works!

    // 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);}

I hope the comments describe how this works. Finally solved after several months of head-scratching. Thanks all!

Upvotes: 0

Spektre
Spektre

Reputation: 51845

Here simple approach:

  1. Sample each orbit to set of N points.

    Let points from first orbit be A and from second orbit B.

    const int N=36;
    float A[N][3],B[N][3];
    
  2. find 2 closest points

    so d=|A[i]-B[i]| is minimal. If d is less or equal to your margin/treshold then orbits are too close to each other.

  3. speed vs. accuracy

    Unless you are using some advanced method for #2 then its computation will be O(N^2) which is a bit scary. The bigger the N the better accuracy of result but a lot more time to compute. There are ways how to remedy both. For example:

    1. first sample with small N

    2. when found the closest points sample both orbits again

      but only near those points in question (with higher N).

      enter image description here

    3. you can recursively increase accuracy by looping #2 until you have desired precision

    4. test d if ellipses are too close to each other

Upvotes: 1

Related Questions