[v8i MDL] Removing all holes from a solid automatically

Hi,

I want to remove all holes on these smart solids automatically in the attached DGN file. How can I do that?

sink.dgn

Parents
  • Hi Ahmet,

    If your slab is primarily created, all its faceId.nodeId should be 1. Based on this, I wrote the following code to retain the faces which nodeId = 1 and remove all other faces. This seems meet your requirement.

        MSElementDescrP edP = NULL;
        KIBODY *pBody = NULL;
        KIENTITY_LIST*  pFaceList = NULL;
        KIENTITY_LIST*  pRemovedFaceList = NULL;
        Transform trans;
        int cnt;
        mdlAssoc_getElementDescr(&edP, NULL, 875L, ACTIVEMODEL, FALSE);
        mdlKISolid_elementToBody2(&pBody, &trans, edP, ACTIVEMODEL, 1L, FALSE);
        mdlElmdscr_freeAll(&edP);
        mdlKISolid_listCreate(&pRemovedFaceList);
        mdlKISolid_listCreate(&pFaceList);
        mdlKISolid_getFaceList(pFaceList, pBody);
        mdlKISolid_listCount(&cnt, pFaceList);
        for (int i = 0; i < cnt; i++)
            {
            KIFACE *pFace;
            FaceId  faceId;
            mdlKISolid_listNthEl(&pFace, pFaceList, i);
            mdlKISolid_idFromFace(&faceId, pFace, TRUE);
            if (1 != faceId.nodeId)
                {
                mdlKISolid_listAdd(pRemovedFaceList, pFace);
                }
            }
        mdlKISolid_listDelete(&pFaceList);
        //Here can't free body because it will be used later
    
        KIENTITY_LIST*  pBodyList = NULL;
        mdlKISolid_listCreate(&pBodyList);
        if (SUCCESS == mdlKISolid_removeFaces2(pBodyList, pRemovedFaceList, HEAL_Parent, TRUE))
            {
            mdlKISolid_listCount(&cnt, pBodyList);
            for (int i = 0; i < cnt; i++)
                {
                KIBODY *pCreatedBody = NULL;
                mdlKISolid_listNthEl(&pCreatedBody, pBodyList, i);
                mdlKISolid_bodyToElement(&edP, pCreatedBody, TRUE, -1, NULL, ACTIVEMODEL);
                mdlKISolid_beginCurrTrans(ACTIVEMODEL);
                mdlElmdscr_transform(edP, &trans);
                mdlKISolid_endCurrTrans();
                mdlElmdscr_add(edP);
                mdlElmdscr_freeAll(&edP);
                }
            }
        mdlKISolid_listDelete(&pRemovedFaceList);
        mdlKISolid_listDelete(&pBodyList);
        mdlKISolid_freeBody(pBody);

    HTH, YongAn



  • Hi Yongan,

    Thank you so much for the code. I tried it but all faceId.nodeId values return 1. How can I distinguish holes?

    Kind regards,

    Sedat Alis
    AEC Technology Inc.

  • Unknown said:

    Do you mind to upload your DGN file and let us analyze it ?

    Hi Yongan,

    Thank you so much. :)

    DGN file is attached.010614S01116@001.dgn

    Kind regards,

    Sedat Alis
    AEC Technology Inc.

  • Hi Ahmet,

    I realized that your creation solid method is different than me. I firstly create a base slab and then use "Cut Solids by Curves" tool to create holes on base slab. So my code is just appropriate for this case. I inferred that your creation method is firstly creating a 2D group hole profile element and then extruding this profile to solid.

     

    Please see my attached DGN file. Two solids are same from its appearance but with different creation method. The red one is mine and my code is suitable for it.

    010614S01116-test.dgn

    I will investigate your situation and try to write a more common code to suit two cases.

    Regards, YongAn



  • Unknown said:

    I realized that your creation solid method is different than me. I firstly create a base slab and then use "Cut Solids by Curves" tool to create holes on base slab. So my code is just appropriate for this case. I inferred that your creation method is firstly creating a 2D group hole profile element and then extruding this profile to solid.

    You are right.

    Unknown said:

    I will investigate your situation and try to write a more common code to suit two cases.

    Thank you so much. :)

    Kind regards,

    Sedat Alis
    AEC Technology Inc.

  • Hi Ahmet,
    I have some ideas to do this but haven't implemented by coding.
    1. Collect and record all edge ids in internal loops (using mdlKISolid_loopExternal to determine which loop is external or internal);
    2. Iterate every face and remove internal loops for every face (using an undocumented function mdlKISolid_deleteLoopsFromSheetBody);
    3. Iterate every face and remove all faces which has internal loop's edge (using the result of 1).
    4. Sew all faces into final solid (using mdlKISolid_sewBodies).
    HTH, YongAn



  • Unknown said:

    Hi Ahmet,
    I have some ideas to do this but haven't implemented by coding.
    1. Collect and record all edge ids in internal loops (using mdlKISolid_loopExternal to determine which loop is external or internal);
    2. Iterate every face and remove internal loops for every face (using an undocumented function mdlKISolid_deleteLoopsFromSheetBody);
    3. Iterate every face and remove all faces which has internal loop's edge (using the result of 1).
    4. Sew all faces into final solid (using mdlKISolid_sewBodies).

    I wish to know all undocumented functions and conclude the job. :)

    Kind regards,

    Sedat Alis
    AEC Technology Inc.

  • Hi Ahmet,

    I wrote following long code snippet to process your case and it works. But for more complex cases, it doesn't work. FYI.

    class edgeId_finder
        {
        public:
            edgeId_finder(const EdgeId edgeId) :m_edgeId(edgeId){}
            bool operator ()(const vector<EdgeId>::value_type &value)
                {
                return (value.faces[0].entityId == m_edgeId.faces[0].entityId &&
                    value.faces[0].nodeId == m_edgeId.faces[0].nodeId &&
                    value.faces[1].entityId == m_edgeId.faces[1].entityId &&
                    value.faces[1].nodeId == m_edgeId.faces[1].nodeId);
                }
         private:
             EdgeId  m_edgeId;
         };
    
    void getInternalEdgeArray(vector<EdgeId>& internalEdgeArray, KIBODY* pBody)
        {
        KIENTITY_LIST*  pLoopList = NULL;
        int cnt;
    
        mdlKISolid_listCreate(&pLoopList);
        mdlKISolid_getLoopList(pLoopList, pBody);
        mdlKISolid_listCount(&cnt, pLoopList);
        for (int i = 0; i < cnt; i++)
            {
            KILOOP* pLoop;
            mdlKISolid_listNthEl(&pLoop, pLoopList, i);
    
            //mdlKISolid_loopExternal can't function for unclear loop case
            KIFACE*         pFace;
            KIENTITY_LIST*  pFaceList = NULL;
            mdlKISolid_faceFromLoop(&pFace, pLoop);
            mdlKISolid_listCreate(&pFaceList);
            mdlKISolid_getEdgeListFromFace(pFaceList, pFace);
            int cntFace;
            mdlKISolid_listCount(&cntFace, pFaceList);
            mdlKISolid_listDelete(&pFaceList);
            if (cntFace < 6)
                continue;
    
            int isExternal;
            mdlKISolid_loopExternal(&isExternal, pLoop);
            if (!isExternal)
                {
                KICOEDGE* pCoEdge;
                int status = mdlKISolid_loopData(NULL, &pCoEdge, NULL, pLoop);
                BoolInt reversed = FALSE;
                while (SUCCESS == status)
                    {
                    KIEDGE* pEdge;
                    EdgeId  edgeId;
                    status = mdlKISolid_coedgeData(&pEdge, NULL, NULL, &pCoEdge, NULL, NULL, NULL, &reversed, pCoEdge);
                    mdlKISolid_idFromEdge(&edgeId, pEdge, TRUE);
                    if (find_if (internalEdgeArray.begin(), internalEdgeArray.end(), edgeId_finder(edgeId)) != internalEdgeArray.end())
                        break;
                    internalEdgeArray.push_back(edgeId);
                    }
                }
            }
        mdlKISolid_listDelete(&pLoopList);
        }
    extern "C" StatusInt  mdlKISolid_deleteLoopsFromSheetBody(KIENTITY_LIST *pLoopList);
    bool removeInternalLoops(KIENTITY_LIST* pFaceList, KIFACE* pFace)
        {
        KIBODY* pSheetBody = NULL;
        KIENTITY_LIST*  pLoopList = NULL;
        KIENTITY_LIST*  pRemovedLoopList = NULL;
        int cnt;
    
        mdlKISolid_sheetFromFace(&pSheetBody, pFace);
        mdlKISolid_listCreate(&pRemovedLoopList);
        mdlKISolid_listCreate(&pLoopList);
        mdlKISolid_getLoopList(pLoopList, pSheetBody);
        mdlKISolid_listCount(&cnt, pLoopList);
        bool bNeedRemove = false;
        for (int i = 0; i < cnt; i++)
            {
            KILOOP* pLoop;
            mdlKISolid_listNthEl(&pLoop, pLoopList, i);
            int isExternal;
            mdlKISolid_loopExternal(&isExternal, pLoop);
            if (!isExternal)
                {
                mdlKISolid_listAdd(pRemovedLoopList, pLoop);
                bNeedRemove = true;
                }
            }
        if (bNeedRemove)
            {
            KIENTITY_LIST* pSheetFaceList = NULL;
            KIFACE* pNewFace;
    
            mdlKISolid_deleteLoopsFromSheetBody(pRemovedLoopList);
            mdlKISolid_listCreate(&pSheetFaceList);
            mdlKISolid_getFaceList(pSheetFaceList, pSheetBody);
            mdlKISolid_listNthEl(&pNewFace, pSheetFaceList, 0);
    
            mdlKISolid_listRemove(pFaceList, pFace);
            mdlKISolid_listAdd(pFaceList, pNewFace);
    
            mdlKISolid_listDelete(&pSheetFaceList);
            }
        mdlKISolid_listDelete(&pLoopList);
        mdlKISolid_listDelete(&pRemovedLoopList);
        //Here can't free sheet body
        return bNeedRemove;
        }
    bool includeInternalEdge(KIFACE* pFace, vector<EdgeId>& internalEdgeArray)
        {
        KIENTITY_LIST*  pEdgeList = NULL;
        int             cnt;
        bool            bFound = false;
        mdlKISolid_listCreate(&pEdgeList);
        mdlKISolid_getEdgeListFromFace(pEdgeList, pFace);
        mdlKISolid_listCount(&cnt, pEdgeList);
        for (int i = 0; i < cnt; i++)
            {
            KIEDGE *pEdge;
            EdgeId edgeId;
            mdlKISolid_listNthEl(&pEdge, pEdgeList, i);
            mdlKISolid_idFromEdge(&edgeId, pEdge, TRUE);
            if (find_if(internalEdgeArray.begin(), internalEdgeArray.end(), edgeId_finder(edgeId)) != internalEdgeArray.end())
                {
                bFound = true;
                break;
                }
            }
        mdlKISolid_listDelete(&pEdgeList);
        return bFound;
        }
    void removeAllHolesFromSmartSolid2(ElementId elId)
        {
        MSElementDescrP edP = NULL;
        KIBODY *pBody = NULL;
        Transform trans;
        
        mdlAssoc_getElementDescr(&edP, NULL, elId, ACTIVEMODEL, FALSE);
        mdlKISolid_elementToBody2(&pBody, &trans, edP, ACTIVEMODEL, 1L, FALSE);
        mdlElmdscr_freeAll(&edP);
    
        // 1 -- Get internalEdgeList
        vector<EdgeId>  internalEdgeArray;
        getInternalEdgeArray(internalEdgeArray, pBody);
        //printf("internalEdge Cnt = %d", internalEdgeArray.size());
    
        // 2 -- Remove internal loops for every face
        KIENTITY_LIST*  pFaceList = NULL;
        int             cnt;
        mdlKISolid_listCreate(&pFaceList);
        mdlKISolid_getFaceList(pFaceList, pBody);
        mdlKISolid_listCount(&cnt, pFaceList);
        for (int i = 0; i < cnt; i++)
            {
            KIFACE *pFace;
            mdlKISolid_listNthEl(&pFace, pFaceList, i);
            if (removeInternalLoops(pFaceList, pFace))
                i--;
            }
    
        // 3 -- Remove all faces with internal edges
        for (int i = 0; i < cnt; i++)
            {
            KIFACE *pFace;
            mdlKISolid_listNthEl(&pFace, pFaceList, i);
            if (includeInternalEdge(pFace, internalEdgeArray))
                {
                mdlKISolid_listRemove(pFaceList, pFace);
                i--;
                }
            }
    
        // 4 -- sew all faces into body
        KIENTITY_LIST*  pSheetBodyList = NULL;
        KIENTITY_LIST*  pSewBodyList = NULL;
        KIENTITY_LIST*  pUnsewBodyList = NULL;
        mdlKISolid_listCreate(&pSheetBodyList);
        mdlKISolid_listCreate(&pSewBodyList);
        mdlKISolid_listCreate(&pUnsewBodyList);
        mdlKISolid_listCount(&cnt, pFaceList);
        for (int i = 0; i < cnt; i++)
            {
            KIFACE* pFace;
            KIBODY* pSheetBody;
            mdlKISolid_listNthEl(&pFace, pFaceList, i);
            mdlKISolid_sheetFromFace(&pSheetBody, pFace);
            mdlKISolid_listAdd(pSheetBodyList, pSheetBody);
            }
        mdlKISolid_freeBody(pBody);
        if (SUCCESS == mdlKISolid_sewBodies(pSewBodyList, pUnsewBodyList, pSheetBodyList, 1e-06))
            {
            mdlKISolid_listNthEl(&pBody, pSheetBodyList, 0);
            MSElementDescrP edP = NULL;
            mdlKISolid_bodyToElement(&edP, pBody, FALSE, -1, NULL, ACTIVEMODEL);
            mdlElmdscr_add(edP);
            mdlElmdscr_freeAll(&edP);
            }
        mdlKISolid_listDelete(&pFaceList);
        mdlKISolid_listDelete(&pUnsewBodyList);
        mdlKISolid_listDelete(&pSewBodyList);
        mdlKISolid_listDelete(&pSheetBodyList);
        }

    Regards, YongAn



  • Unknown said:
    if (find_if (internalEdgeArray.begin(), internalEdgeArray.end(), edgeId_finder(edgeId)) != internalEdgeArray.end())

    Good example of the C++ Standard Library!

     
    Regards, Jon Summers
    LA Solutions

  • Thank you so much Yongan. :)

    I am using pure MDL, does C++ portions will work too?

    Kind regards,

    Sedat Alis
    AEC Technology Inc.

  • Hi Ahmet,
    C++ portions can't work in pure MDL. You can rewrite them by using pure MDL's mdlDArray_xxx functions.
    I strongly recommend you to upgrade to native code because more new features are released in C++ classes which pure MDL can't call directly. Furthermore, next version of MicroStation (MicroStation CONNECT Edition) doesn't support pure MDL. All pure MDL projects have to be upgraded to native code.
    Rgds, YongAn



  • Unknown said:
    I am using pure MDL, does C++ portions will work too?

    Here's an article that compares the C++ Standard Library and MDL's elastic arrays

     
    Regards, Jon Summers
    LA Solutions

Reply Children
No Data