Calculating CAD Model Volume and Creating Relative Stock in HOOPS Exchange Parasolid Integration

Hello,

I am seeking assistance with two specific issues related to my project involving HOOPS Exchange and Parasolid integration:

1. Retrieving/Calculating CAD Model Volume:
I am currently working with the ExchangeParasolid sprocket as mentioned in this forum post. Despite reviewing this article on physical properties, I am unable to successfully retrieve or calculate the volume of the imported CAD models. Any advice or examples on how to achieve this would be greatly appreciated.

2. Creating Relative Stock Around CAD Model:
I aim to create a relative stock around the CAD model using the create solid function to generate rectangular or cylindrical stock, as demonstrated in the ExchangeParasolid sprocket environment in the previously mentioned forum post. Specifically, I need guidance on how to determine the dimensions of the stock to ensure it fully encompasses the CAD model, regardless of its geometry.

I would be very grateful for any guidance or sample codes you could provide or refer me to.

Thank you very much!

Hi Kahmed,

Regarding your questions:

  1. I’ve tried to call the A3DComputePhysicalProperties in the BlendDlg.cpp as below image. It works properly.

  2. You will be able to compute bounding box of RiBrepModel using A3DMiscComputeBoundingBox API as below image.


    Using box-min/max values, you can create a block / cylinder body which is surrounding a target body.

Best regards,
Toshi

Hi Toshi,

Thank you very much for the detailed explanation and your guidance. I will implement this. I just have another concern about computing the normal vector for selected and detected faces in the feature recognition class mentioned in your post : https://github.com/toshi-bata/mfc_sandbox_HE-Ps

I want to fetch the normal vector of faces and then display their xyz components.
I would be very grateful to you for all your help on how can I achieve this.

Kind regards,
Kazi

Hi Kazi,

You will be able to get normal vector of specific surface point using A3DSurfEvaluateNormal API.
https://docs.techsoft3d.com/exchange/latest/api/group__a3d__evaluate.html#_CPPv421A3DSurfEvaluateNormalPK11A3DSurfBasePK15A3DVector2dDataP15A3DVector3dData

Toshi

Hi Toshi,

Thank you for referring to the A3DSurfEvaluateNormal API. I attempted to implement it, but unfortunately, it’s not working as expected.

I have included a sample of my code in the FeatureRecognitionDlg. I believe I might be getting confused about how to correctly pass arguments to the A3DSurfEvaluateNormal function (I am trying to get the normal vector of the selected, and all detected faces):

// Normal Vector Function
void FeatureRecognitionDlg::NormalVectors(A3DTopoFace* pSelTopoFace, std::vector<A3DEntity*>& pEntityArr)
{
    A3DStatus status;
    A3DTopoFaceData faceData;
    A3D_INITIALIZE_DATA(A3DTopoFaceData, faceData);

    // Retrieve face data for selected face
    status = A3DTopoFaceGet(pSelTopoFace, &faceData);
    if (status != A3D_SUCCESS)
    {
        CString errorMessage;
        errorMessage.Format(L"Failed to get face data for selected face: Error code %d", status);
        AfxMessageBox(errorMessage);
        return;
    }

    // Retrieve UV parameters from face data
    A3DVector2dData uvParameter;
    uvParameter.m_dX = (faceData.m_sSurfaceDomain.m_sMin.m_dX + faceData.m_sSurfaceDomain.m_sMax.m_dX) / 2.0;
    uvParameter.m_dY = (faceData.m_sSurfaceDomain.m_sMin.m_dY + faceData.m_sSurfaceDomain.m_sMax.m_dY) / 2.0;

    A3DVector3dData normal;
    A3D_INITIALIZE_DATA(A3DVector3dData, normal);

    // Evaluate normal for the selected face
    status = A3DSurfEvaluateNormal((const A3DSurfBase*)pSelTopoFace, &uvParameter, &normal);
    if (status == A3D_SUCCESS)
    {
        CString message;
        message.Format(L"Selected Face Normal: X: %f, Y: %f, Z: %f", normal.m_dX, normal.m_dY, normal.m_dZ);
        AfxMessageBox(message);
    }
    else
    {
        CString errorMessage;
        errorMessage.Format(L"Failed to evaluate normal for selected face: Error code %d", status);
        AfxMessageBox(errorMessage);
    }

    // Evaluate normal for each detected face
    for (size_t i = 0; i < pEntityArr.size(); ++i)
    {
        A3DTopoFace* pTopoFace = (A3DTopoFace*)pEntityArr[i];

        // Retrieve face data for detected face
        A3DTopoFaceData detectedFaceData;
        A3D_INITIALIZE_DATA(A3DTopoFaceData, detectedFaceData);

        status = A3DTopoFaceGet(pTopoFace, &detectedFaceData);
        if (status != A3D_SUCCESS)
        {
            CString errorMessage;
            errorMessage.Format(L"Failed to get face data for detected face %zu: Error code %d", i, status);
            AfxMessageBox(errorMessage);
            continue;
        }

        // Retrieve UV parameters from detected face data
        uvParameter.m_dX = (detectedFaceData.m_sSurfaceDomain.m_sMin.m_dX + detectedFaceData.m_sSurfaceDomain.m_sMax.m_dX) / 2.0;
        uvParameter.m_dY = (detectedFaceData.m_sSurfaceDomain.m_sMin.m_dY + detectedFaceData.m_sSurfaceDomain.m_sMax.m_dY) / 2.0;

        status = A3DSurfEvaluateNormal((const A3DSurfBase*)pTopoFace, &uvParameter, &normal);
        if (status == A3D_SUCCESS)
        {
            CString message;
            message.Format(L"Detected Face %zu Normal: X: %f, Y: %f, Z: %f", i, normal.m_dX, normal.m_dY, normal.m_dZ);
            AfxMessageBox(message);
        }
        else
        {
            CString errorMessage;
            errorMessage.Format(L"Failed to evaluate normal for detected face %zu: Error code %d", i, status);
            AfxMessageBox(errorMessage);
        }
    }
}

Then I tried to call NormalVectors(…) in the OnTimer(…) under Exchange part. It seems that the it is not being called here properly as I checked with debug text messages, or it may not be the right place to call it.

#ifdef USING_EXCHANGE_PARASOLID
            selFace = ((HPS::Parasolid::Component)selCompArr[0]).GetParasolidEntity();

            HPS::Component bodyComp = view->GetOwnerPSBodyCompo(selCompArr[0]);
            PK_BODY_t body = ((HPS::Parasolid::Component)bodyComp).GetParasolidEntity();

            std::vector<PK_ENTITY_t> pkEntityArr;
            if (m_pProcess->FR((PsFRType)m_iFRType, selFace, pkEntityArr))
            {
                for (int i = 0; i < pkEntityArr.size(); i++)
                {
                    PK_FACE_t face = pkEntityArr[i];

                    if (selFace != face)
                    {
                        // Highlight face
                        HPS::Component comp = view->GetPsComponent(body, face);
                        highlightCompArr.push_back(comp);

                        // Show list box
                        CString sEnt;
                        sEnt.Format(_T("%d"), pkEntityArr[i]);
                        m_detectedFaceListBox.AddString(sEnt);
                    }
                }
            }

#else
            // Get owner BrepModel
            HPS::Component ownerComp = view->GetOwnerBrepModel(selCompArr[0]);
            A3DRiBrepModel* pRiBrepModel = HPS::Exchange::Component(ownerComp).GetExchangeEntity();

            A3DTopoFace* pSelTopoFace = HPS::Exchange::Component(selCompArr[0]).GetExchangeEntity();
            selFace = m_pProcess->GetEntityTag(pRiBrepModel, pSelTopoFace);

            std::vector<A3DEntity*> pEntityArr;
            if (m_pProcess->FR((PsFRType)m_iFRType, pRiBrepModel, pSelTopoFace, pEntityArr))
            {
                // Get component from selected A3DEntity
                HPS::Exchange::CADModel cad_model = view->GetDocument()->GetCADModel();
                for (int i = 0; i < pEntityArr.size(); i++)
                {
                    A3DEntity* pEntity = pEntityArr[i];

                    if (pSelTopoFace != pEntity)
                    {
                        HPS::Component comp = cad_model.GetComponentFromEntity(pEntity);
                        highlightCompArr.push_back(comp);

                        // Show list box
                        int iEnt = m_pProcess->GetEntityTag(pRiBrepModel, pEntity);

                        CString sEnt;
                        sEnt.Format(_T("%d"), iEnt);
                        m_detectedFaceListBox.AddString(sEnt);
                    }
                }
            }

            // Evaluate and display the normal vector
            NormalVectors(pSelTopoFace, pEntityArr);
#endif
            m_iSelFace = selFace;
            m_selectedFaceID = selFace; // Store the selected face ID

Could you please take a look at the code? I would sincerely appreciate it if you could point out the mistakes and guide me with the corrected code if possible.

Thank you very much again, for all your time.

Kazi

And, I also noticed that the current structure of the code for the FeatureRecognitionDlg is always executing the “#ifdef USING_EXCHANGE_PARASOLID” condition, (never executes the else condition which uses Exchange and so the A3D API if I have it right as shown above).