davideberly / GeometricTools

A collection of source code for computing in the fields of mathematics, geometry, graphics, image analysis and physics.
Boost Software License 1.0
1.08k stars 202 forks source link

Bug in box and cylinder intersection judgement #58

Closed Gatevin closed 1 year ago

Gatevin commented 1 year ago

Hello, recently I use the newest released package GTE-version-6.5 to judge intersection of box and cylinder, but found something seems like a bug.

Problem

I downloaded the package and changed the cylinder property to run the box and cylinder intersection sample, the test result is wrong.

The test case

After change the function void IntersectBoxCylinderWindow3::CreateScene() in GTE/Samples/Intersection/IntersectBoxCylinder/IntersectBoxCylinderWindow3.cpp to

void IntersectBoxCylinderWindow3::CreateScene()
{
    VertexFormat vformat;
    vformat.Bind(VASemantic::POSITION, DF_R32G32B32_FLOAT, 0);
    MeshFactory mf;
    mf.SetVertexFormat(vformat);

    // mCylinder.axis.origin = { 3.0f, 2.0f, 3.0f };
    // mCylinder.axis.direction = { 0.0f, 0.0f, 1.0f };
    // mCylinder.radius = 1.0f;
    // mCylinder.height = 8.0f;
    // I changed the cylinder property only
    mCylinder.axis.origin = { 6.0f, 0.0f, 0.0f };
    mCylinder.axis.direction = { -0.017459368f, -0.9998476f, 0.0f };
    mCylinder.radius = 0.5f;
    mCylinder.height = 2.0f;

    mCylinderMesh = mf.CreateCylinderClosed(16, 16, mCylinder.radius, mCylinder.height);
    mCylinderMesh->localTransform.SetTranslation(mCylinder.axis.origin);
    auto effect = std::make_shared<ConstantColorEffect>(mProgramFactory,
            Vector4<float>{ 0.0f, 0.5f, 0.0f, 0.5f });
    mCylinderMesh->SetEffect(effect);
    mPVWMatrices.Subscribe(mCylinderMesh->worldTransform, effect->GetPVWMatrixConstant());

    mRedEffect = std::make_shared<ConstantColorEffect>(mProgramFactory,
        Vector4<float>{ 0.5f, 0.0f, 0.0f, 0.5f });

    mBlueEffect = std::make_shared<ConstantColorEffect>(mProgramFactory,
        Vector4<float>{ 0.0f, 0.0f, 0.5f, 0.5f });

    mBox.center = { 0.0f, 0.0f, 0.0f };
    mBox.axis[0] = { 1.0f, 0.0f, 0.0f };
    mBox.axis[1] = { 0.0f, 1.0f, 0.0f };
    mBox.axis[2] = { 0.0f, 0.0f, 1.0f };
    mBox.extent = { 1.0f, 2.0f, 3.0f };

    mBoxMesh = mf.CreateBox(mBox.extent[0], mBox.extent[1], mBox.extent[2]);
    mBoxMesh->SetEffect(mBlueEffect);
    mPVWMatrices.Subscribe(mBoxMesh->worldTransform, mBlueEffect->GetPVWMatrixConstant());

    mTrackBall.Attach(mCylinderMesh);
    mTrackBall.Attach(mBoxMesh);
    mTrackBall.Update();
}

Result expected

The intersection test function gives intersected, but obviously they are not intersected.

Attachment

Here is the snapshot.

bug
davideberly commented 1 year ago

Thank you for the detailed information. In the sample application, the mathematical cylinder is mCylinder. The visualization is the mCylinderMesh object. You modified the mCylinder origin, and the localTransform.SetTranslation(...) still works correctly. However, you also modified the mCylinder direction. To ensure the mCylinderMesh object is consistent with mCylinder, you have to use localTransform.SetRotation(...) in order to rotate the canonical cylinder axis (0,0,1) to be the direction vector you chose.

#if defined(USE_MOD_CYLINDER)
    mCylinder.axis.origin = { 6.0f, 0.0f, 0.0f };
    mCylinder.axis.direction = { -0.017459368f, -0.9998476f, 0.0f };
    mCylinder.radius = 0.5f;
    mCylinder.height = 2.0f;
    std::array<Vector3<float>, 3> basis{};
    basis[0] = mCylinder.axis.direction;
    ComputeOrthogonalComplement(1, basis.data());
    Matrix3x3<float> rotate{};
    rotate.SetCol(0, basis[1]);
    rotate.SetCol(1, basis[2]);
    rotate.SetCol(2, basis[0]);
#else
    mCylinder.axis.origin = { 3.0f, 2.0f, 3.0f };
    mCylinder.axis.direction = { 0.0f, 0.0f, 1.0f };
    mCylinder.radius = 1.0f;
    mCylinder.height = 8.0f;
#endif

    mCylinderMesh = mf.CreateCylinderClosed(16, 16, mCylinder.radius, mCylinder.height);
    mCylinderMesh->localTransform.SetTranslation(mCylinder.axis.origin);
#if defined(USE_MOD_CYLINDER)
    mCylinderMesh->localTransform.SetRotation(rotate);
#endif

After making these changes, unfortunately the box is displayed in red which indicates the cylinder is intersecting it. This is incorrect. I am investigating the issue. I have extensive unit tests for this code, so I need to determine what is failing.

davideberly commented 1 year ago

I apologize for taking so long. Other bug investigations and fixes were in front of this one in my technical support queue.

In fact there was a bug in IntrCanonicalBox3Cylinder3.h. My unit tests found this in my local GTL development, and I fixed it there, but I failed to back-port it to GTE. I have posted the fix.