inline void BoundingSphere::CreateFromPoints()

in Inc/DirectXCollision.inl [1069:1169]


inline void BoundingSphere::CreateFromPoints(BoundingSphere& Out, size_t Count, const XMFLOAT3* pPoints, size_t Stride) noexcept
{
    assert(Count > 0);
    assert(pPoints);

    // Find the points with minimum and maximum x, y, and z
    XMVECTOR MinX, MaxX, MinY, MaxY, MinZ, MaxZ;

    MinX = MaxX = MinY = MaxY = MinZ = MaxZ = XMLoadFloat3(pPoints);

    for (size_t i = 1; i < Count; ++i)
    {
        XMVECTOR Point = XMLoadFloat3(reinterpret_cast<const XMFLOAT3*>(reinterpret_cast<const uint8_t*>(pPoints) + i * Stride));

        float px = XMVectorGetX(Point);
        float py = XMVectorGetY(Point);
        float pz = XMVectorGetZ(Point);

        if (px < XMVectorGetX(MinX))
            MinX = Point;

        if (px > XMVectorGetX(MaxX))
            MaxX = Point;

        if (py < XMVectorGetY(MinY))
            MinY = Point;

        if (py > XMVectorGetY(MaxY))
            MaxY = Point;

        if (pz < XMVectorGetZ(MinZ))
            MinZ = Point;

        if (pz > XMVectorGetZ(MaxZ))
            MaxZ = Point;
    }

    // Use the min/max pair that are farthest apart to form the initial sphere.
    XMVECTOR DeltaX = XMVectorSubtract(MaxX, MinX);
    XMVECTOR DistX = XMVector3Length(DeltaX);

    XMVECTOR DeltaY = XMVectorSubtract(MaxY, MinY);
    XMVECTOR DistY = XMVector3Length(DeltaY);

    XMVECTOR DeltaZ = XMVectorSubtract(MaxZ, MinZ);
    XMVECTOR DistZ = XMVector3Length(DeltaZ);

    XMVECTOR vCenter;
    XMVECTOR vRadius;

    if (XMVector3Greater(DistX, DistY))
    {
        if (XMVector3Greater(DistX, DistZ))
        {
            // Use min/max x.
            vCenter = XMVectorLerp(MaxX, MinX, 0.5f);
            vRadius = XMVectorScale(DistX, 0.5f);
        }
        else
        {
            // Use min/max z.
            vCenter = XMVectorLerp(MaxZ, MinZ, 0.5f);
            vRadius = XMVectorScale(DistZ, 0.5f);
        }
    }
    else // Y >= X
    {
        if (XMVector3Greater(DistY, DistZ))
        {
            // Use min/max y.
            vCenter = XMVectorLerp(MaxY, MinY, 0.5f);
            vRadius = XMVectorScale(DistY, 0.5f);
        }
        else
        {
            // Use min/max z.
            vCenter = XMVectorLerp(MaxZ, MinZ, 0.5f);
            vRadius = XMVectorScale(DistZ, 0.5f);
        }
    }

    // Add any points not inside the sphere.
    for (size_t i = 0; i < Count; ++i)
    {
        XMVECTOR Point = XMLoadFloat3(reinterpret_cast<const XMFLOAT3*>(reinterpret_cast<const uint8_t*>(pPoints) + i * Stride));

        XMVECTOR Delta = XMVectorSubtract(Point, vCenter);

        XMVECTOR Dist = XMVector3Length(Delta);

        if (XMVector3Greater(Dist, vRadius))
        {
            // Adjust sphere to include the new point.
            vRadius = XMVectorScale(XMVectorAdd(vRadius, Dist), 0.5f);
            vCenter = XMVectorAdd(vCenter, XMVectorMultiply(XMVectorSubtract(XMVectorReplicate(1.0f), XMVectorDivide(vRadius, Dist)), Delta));
        }
    }

    XMStoreFloat3(&Out.Center, vCenter);
    XMStoreFloat(&Out.Radius, vRadius);
}