Search code examples
linear-algebracomputational-geometrygame-development

Finding the shortest vector from a point to a truncated cone in 3D


I am trying to understand a certain implementation of calculating the shortest vector between a point and a truncated cone in 3D. The original idea is introduced in this paper.

So if we have two spherical objects: Object A with radius rA, position pA and velocity vA and Object B with radius rB, position pB and velocity vB, then we can represent this in a simpler way calculating the relative position and relative velocity and assuming that object A is a point and the radius of object B is rA + rB.

In 2D, this will look like doing the transformation from figure (a) to figure (b) where tau is just a scalar factor: enter image description here A

The 3D figure is similar but instead of circles, we have spheres.

Now, if the relative velocity vector lies in the grayed truncated cone, we should find the vector u which is the smallest change to the relative velocity V to move it to the circumference of the cone as depicted in the following figure (note: P is the relative position): enter image description here

This has two cases:

  1. If the relative velocity is below the center of the cut-off circle (below the dashed blue line). In this case u will be on the cut-off circle (the smaller circle).

  2. The second case, which I don't understand how it is calculated, is when the relative velocity is above the center of the small circle(sphere), in this case uwill be projected on the tangents of the cone. The intersection of the plane represented by P and V vectors and the big sphere is a circle that u will lie on.

        const Vector3 relativePosition = other->position_ - position_;
        const Vector3 relativeVelocity = velocity_ - other->velocity_;
        const float distSq = absSq(relativePosition);
        const float combinedRadius = radius_ + other->radius_;
        const float combinedRadiusSq = sqr(combinedRadius);
    
        Plane plane;
        Vector3 u;
    
        if (distSq > combinedRadiusSq) {
            /* No collision. */
            const Vector3 w = relativeVelocity - tau * relativePosition;
            /* Vector from cutoff center to relative velocity. */
            const float wLengthSq = absSq(w);
    
            const float dotProduct = w * relativePosition;
    
            if (dotProduct < 0.0f && sqr(dotProduct) > combinedRadiusSq * wLengthSq) {
                /* Project on cut-off circle. */
                const float wLength = std::sqrt(wLengthSq);
                const Vector3 unitW = w / wLength;
    
                plane.normal = unitW;
                u = (combinedRadius * tau - wLength) * unitW;
            }
            else {
                **/* Project on cone. I Don't understand this! */
    
    
                const float a = distSq;
                const float b = relativePosition * relativeVelocity;
                const float c = absSq(relativeVelocity) - absSq(cross(relativePosition, relativeVelocity)) / (distSq - combinedRadiusSq);
                const float t = (b + std::sqrt(sqr(b) - a * c)) / a;
                const Vector3 ww = relativeVelocity - t * relativePosition;
                const float wwLength = abs(ww);
                const Vector3 unitWW = ww / wwLength;
                plane.normal = unitWW;
                u = (combinedRadius * t - wwLength) * unitWW;**
            }
        }
    

I know in the end we need to find t (as in the code) to scale P. However, I don't understand how the cross product is utilized here and what does the quadratic equation that we are trying to solve represent.

This function can be found here.


Solution

  • …Though I do not understand how the collision avoidance model works, but it seems that the relevant equation can be obtained by considering some angles around the axis.

    Geometry and some math expressions to obtain quadratic equation for new velocity calculation in three dimensional reciprocal collision avoidance model.

    By the way, it looks like a pure math problem which is not suitable for SO. Mathematics Stack Exchange might be better place if you'd like to ask this kind of question.

    Appendix : Another approach

    To make the problem/answer a little bit more SO-conscious, I'd like to think about possibility of another coding approach. Since we can use a lot of math-functions (e.g. asin(), sqrt()) without hesitation in actual programs, it's also possible to calculate the crossing point without quadratic equation by utilizing math functions and vector algebra, as follows .

    /* Project on cone. */
    const float sin_phi = combinedRadius / std::sqrt(distSq);
    const float cos_phi = std::cos(std::asin(sin_phi));
    
    Vector3 E_axial = normalize(relativePosition);
    Vector3 E_inplane = normalize(cross(cross(relativePosition, relativeVelocity), E_axial));
    
    Vector3 E_dir = E_axial * cos_phi + E_inplane * sin_phi;
    
    // Based on math: (s * E_dir - relativeVelocity) * E_dir = 0
    const float s = relativeVelocity * E_dir;
    
    u = s * E_dir - relativeVelocity;
    plane.normal = -normalize(u);