/*********************************************************************************************************************** * * Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc. * The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret * as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event * of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized * employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the * scope and manner of such use. * ***********************************************************************************************************************/ /** \file Collision.cpp This program demonstrates how to programmatically use the A3DCollisionCompute function. This program reads a model file and outputs a text file. Specify these files on the command line (see 'Usage'). A sample file can be find in data directory : data\inventor\collision.iam Usage: Collision [INPUT] [OUTPUT] [UUIDs...] INPUT The input CAD file. Default is '00242AC8' OUTPUT The output result file. Default is 'CURRENT_DIR/Collision.txt' UUID1 UUID2... Any number of space separated UUIDs of representation items to be checked to each other. If not set, two relevant UUIDs from the CAD file will be picked ***********************************************************************************************************************/ #ifdef _MSC_VER # define SAMPLE_DEFAULT_CAD_FILE _T(SAMPLES_DATA_DIRECTORY"\\inventor\\collision.iam") # define SAMPLE_DEFAULT_RESULT_FILE _T("Collision.txt") #else # define SAMPLE_DEFAULT_CAD_FILE SAMPLES_DATA_DIRECTORY"/inventor/collision.iam" # define SAMPLE_DEFAULT_RESULT_FILE "Collision.txt" #endif #define INITIALIZE_A3D_API #include #include #include "../common.hpp" #include "visitor/VisitorContainer.h" #include "visitor/VisitorCascadedAttribute.h" #include "visitor/VisitorTree.h" #include "visitor/VisitorTransfo.h" #include "visitor/CascadedAttributeConnector.h" #include "visitor/TransfoConnector.h" #include #ifdef _MSC_VER # include #endif #include #include #include #include using string_t = std::basic_string; // function declared in createssellatedbox.cpp A3DStatus CreatePolyBrepModelFromABBox(A3DBoundingBoxData const & sABBox, A3DRiPolyBrepModel ** pRiPolyBrepModel); //###################################################################################################################### struct A3DFlattenVisitor : public A3DTreeVisitor { std::vector m_vA3DRiBrepModel; std::vector m_vA3DMatrix4x4; std::vector m_vProductIdentifier; A3DUTF8Char * m_pcProductIdentifier = nullptr; double m_dScaleToMm = 1.; A3DFlattenVisitor(A3DVisitorContainer* psContainer = NULL) : A3DTreeVisitor(psContainer) { psContainer->SetTraverseInstance(true); } ~A3DFlattenVisitor() { for (A3DUTF8Char* p: m_vProductIdentifier) free(p); } A3DStatus visitEnter(const A3DPartConnector& sConnector) override { A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector); if (iRet == A3D_SUCCESS) { A3DAsmProductOccurrenceGetIdentifier(sConnector.GetProductOccurrenceFather(), &m_pcProductIdentifier); } return iRet; } A3DStatus visitLeave(const A3DPartConnector& sConnector) override { A3DStatus iRet = A3DTreeVisitor::visitLeave(sConnector); if (m_pcProductIdentifier) { A3DAsmProductOccurrenceGetIdentifier(nullptr, &m_pcProductIdentifier); } return iRet; } virtual A3DStatus visitEnter(const A3DRiConnector& sConnector) override { A3DStatus iRet = A3DTreeVisitor::visitEnter(sConnector); const A3DEntity* pRi = sConnector.GetA3DEntity(); A3DEEntityType eType = kA3DTypeUnknown; iRet = A3DEntityGetType(pRi, &eType); if ((iRet == A3D_SUCCESS) && (eType == kA3DTypeRiBrepModel || eType == kA3DTypeRiPolyBrepModel)) { A3DVisitorColorMaterials *pA3DCascadedVisitor = static_cast(m_psContainer->GetVisitorByName("CascadedAttribute")); if (pA3DCascadedVisitor) { ColorMaterialsConnector sColorConnector(nullptr); pA3DCascadedVisitor->GetColorMaterialConnector(sColorConnector); if (!sColorConnector.IsShow()) return A3D_SUCCESS; } m_vA3DRiBrepModel.push_back((A3DRiRepresentationItem*)sConnector.GetA3DEntity()); A3DVisitorTransfo* psVisitorTransfo = static_cast(m_psContainer->GetVisitorByName("Transformation")); A3DTransfoConnector* pConnector = psVisitorTransfo->GetTransfoConnector(); A3DMatrix4x4 sTransfo; pConnector->GetGlobalTransfo(sTransfo); delete pConnector; // Get global transfo if (m_dScaleToMm != 1.) { A3DMatrix4x4 sScale; sScale.ResetToIdentity(); sScale.m_adM[0] = m_dScaleToMm; sScale.m_adM[5] = m_dScaleToMm; sScale.m_adM[10] = m_dScaleToMm; sScale.m_adM[15] = m_dScaleToMm; A3DMatrix4x4 sScaledTransfo; sScaledTransfo = sTransfo * sScale; sScaledTransfo.m_adM[15] = 1.; m_vA3DMatrix4x4.push_back(sScaledTransfo); } else m_vA3DMatrix4x4.push_back(sTransfo); // Get product occurrence identifier ... assuming that there only on rep item by part A3DUTF8Char * pcProductID = nullptr; if (m_pcProductIdentifier != nullptr) { size_t iLen = strlen(m_pcProductIdentifier); pcProductID = static_cast(malloc(sizeof(A3DUTF8Char)*(iLen + 1))); strcpy(pcProductID, m_pcProductIdentifier); } m_vProductIdentifier.push_back(pcProductID); } return iRet; } }; //##################################################################################################################### A3DStatus stGetFlattenRepItemInMmFromModelFile( A3DAsmModelFile * pModelFile, std::vector & apRepItem, std::vector & asIdentifiers) { A3DAsmModelFileData sMFData; A3D_INITIALIZE_DATA(A3DAsmModelFileData, sMFData); A3DAsmModelFileGet(pModelFile, &sMFData); double dUnitInMm = sMFData.m_dUnit; A3DAsmModelFileGet(NULL, &sMFData); A3DVisitorContainer sA3DVisitorContainer(CONNECT_TRANSFO); sA3DVisitorContainer.SetTraverseInstance(true); A3DVisitorColorMaterials *pA3DCascadedVisitor = new A3DVisitorColorMaterials(&sA3DVisitorContainer); sA3DVisitorContainer.push(pA3DCascadedVisitor); A3DFlattenVisitor *pA3DFlattenVisitor = new A3DFlattenVisitor(&sA3DVisitorContainer); sA3DVisitorContainer.push(pA3DFlattenVisitor); pA3DFlattenVisitor->m_dScaleToMm = dUnitInMm; A3DModelFileConnector sModelFileConnector(pModelFile); A3DStatus sStatus = sModelFileConnector.Traverse(&sA3DVisitorContainer); if (sStatus != A3D_SUCCESS) return A3D_ERROR; size_t uiRI, uiNbRepItem = pA3DFlattenVisitor->m_vA3DRiBrepModel.size(); if (uiNbRepItem == 0) return A3D_MODELFILE_INCONSISTENT_EMPTY; apRepItem.resize(uiNbRepItem); asIdentifiers.resize(uiNbRepItem); for (uiRI = 0; uiRI < uiNbRepItem; uiRI++) { A3DTransfoRepresentationItemData & sTransfRI = apRepItem[uiRI]; A3D_INITIALIZE_DATA(A3DTransfoRepresentationItemData, sTransfRI); sTransfRI.m_pRepItem = pA3DFlattenVisitor->m_vA3DRiBrepModel[uiRI]; sTransfRI.m_pOptPlacement = new double[16]; memcpy( const_cast(sTransfRI.m_pOptPlacement), pA3DFlattenVisitor->m_vA3DMatrix4x4[uiRI].m_adM, 16 * sizeof(double)); if (A3DUTF8Char* psId = pA3DFlattenVisitor->m_vProductIdentifier[uiRI]) { std::basic_ostringstream stream; stream << psId; asIdentifiers[uiRI] = stream.str(); } } return A3D_SUCCESS; } void PrintUsage() { #ifdef _MSC_VER std::wcout << "Usage:" << std::endl #else std::cout << "Usage:" << std::endl #endif << "Collision [INPUT] [OUTPUT] [UUIDs...]" << std::endl << "\tINPUT The input CAD file. Default is '" << SAMPLE_DEFAULT_CAD_FILE << "'" << std::endl << "\tOUTPUT The output result file. Default is 'CURRENT_DIR/Collision.txt'" << std::endl << "\tUUID1 UUID2... Any number of space separated UUIDs of representation items to be checked to each other. If not set, two relevant UUIDs from the CAD file will be picked" << std::endl; } //###################################################################################################################### #ifdef _MSC_VER int wmain(A3DInt32 iArgc, A3DUniChar** ppcArgv) #else int main(A3DInt32 iArgc, A3DUTF8Char** ppcArgv) #endif { PrintUsage(); // INITIALIZE HOOPS EXCHANGE A3DSDKHOOPSExchangeLoader sHoopsExchangeLoader(_T(HOOPS_BINARY_DIRECTORY), HOOPS_LICENSE); CHECK_RET(sHoopsExchangeLoader.m_eSDKStatus); CHECK_RET(A3DDllSetCallbacksMemory(CheckMalloc, CheckFree)); CHECK_RET(A3DDllSetCallbacksReport(PrintLogMessage, PrintLogWarning, PrintLogError)); // Parsing arguments string_t acInputCADFile = SAMPLE_DEFAULT_CAD_FILE; string_t acResultFile = SAMPLE_DEFAULT_RESULT_FILE; std::vector asInputUUID; // Default Input CAD overridden by first argument if (iArgc > 1) { acInputCADFile = ppcArgv[1]; } // Default result file overridden by second argument if (iArgc > 2) { acResultFile = ppcArgv[2]; } // Get all UUIDs for (A3DInt32 i = 3; i < iArgc; ++i) { asInputUUID.emplace_back(ppcArgv[i]); } //##################################### // ### Import input XML file //##################################### A3DImport sImport(acInputCADFile.c_str()); A3DStatus iRet = A3D_ERROR; const size_t uiSize = acInputCADFile.size(); if (uiSize >= 4) { const string_t sExtension = acInputCADFile.substr(uiSize - 4, 4); #ifdef _MSC_VER if (sExtension == _T(".xml") || sExtension == _T(".XML") || sExtension == _T(".Xml")) { std::wstring_convert> converter; const std::string aScrFileNameUTF8 = converter.to_bytes(acInputCADFile); iRet = A3DAsmModelFileLoadFromXMLFile(aScrFileNameUTF8.c_str(), &sImport.m_sLoadData, &sHoopsExchangeLoader.m_psModelFile); } #else if (sExtension == ".xml" || sExtension == ".XML" || sExtension == ".Xml") iRet = A3DAsmModelFileLoadFromXMLFile(acInputCADFile.c_str(), &sImport.m_sLoadData, &sHoopsExchangeLoader.m_psModelFile); #endif else iRet = sHoopsExchangeLoader.Import(sImport); } else iRet = sHoopsExchangeLoader.Import(sImport); if (iRet != A3D_SUCCESS && iRet != A3D_LOAD_MISSING_COMPONENTS) CHECK_RET(iRet); //##################################### // ### Flatten Representation Items //##################################### std::vector apRepItem; std::vector asIdentifier; iRet = stGetFlattenRepItemInMmFromModelFile(sHoopsExchangeLoader.m_psModelFile, apRepItem, asIdentifier); CHECK_RET(iRet); //##################################### // ### Some Checks //##################################### if (apRepItem.size() < 2) { std::cout << "Collision sample needs at least 2 representation items in the model file to process." << std::endl; return A3D_ERROR; } assert(apRepItem.size() == asIdentifier.size()); // If no UUID given by the user, take the first available if (asInputUUID.empty()) { asInputUUID.push_back(asIdentifier.front()); } ////##################################### //// ### Build collision group ////##################################### std::vector asGroup1, asGroup2; std::vector auiGroupIndex1, auiGroupIndex2; for (size_t iIndex = 0; iIndex < apRepItem.size(); iIndex++) { bool bInSecondGroup = true; string_t const & sCurID = asIdentifier[iIndex]; for (auto const & sInputID : asInputUUID) { if (sCurID.compare(sInputID) == 0) { asGroup1.push_back(apRepItem[iIndex]); auiGroupIndex1.push_back(iIndex); bInSecondGroup = false; break; } } if (bInSecondGroup) { asGroup2.push_back(apRepItem[iIndex]); auiGroupIndex2.push_back(iIndex); } } // fill first group structure A3DCollisionGroupData sGroup1; A3D_INITIALIZE_DATA(A3DCollisionGroupData, sGroup1); sGroup1.m_uRepItemSize = (A3DUns32)asGroup1.size(); if (sGroup1.m_uRepItemSize) sGroup1.m_apRepItems = &asGroup1[0]; else { printf("Invalid first group\n"); return -1; } // fill second group structure A3DCollisionGroupData sGroup2; A3D_INITIALIZE_DATA(A3DCollisionGroupData, sGroup2); sGroup2.m_uRepItemSize = (A3DUns32)asGroup2.size(); if (sGroup2.m_uRepItemSize) sGroup2.m_apRepItems = &asGroup2[0]; //##################################### // ### Specify collision parameters //##################################### A3DCollisionParameterData sCollisionParameter; A3D_INITIALIZE_DATA(A3DCollisionParameterData, sCollisionParameter); sCollisionParameter.m_dContactLimit = 0.1; sCollisionParameter.m_dSafetyDistance = 1.; sCollisionParameter.m_dTessellationTolerance = 0.01; //##################################### // ### Compute //##################################### A3DUns32 uCollisionResultsSize = 0; A3DCollisionResultData * apCollisionResults = nullptr; iRet = A3DCollisionCompute(&sGroup1, sGroup2.m_uRepItemSize?&sGroup2:nullptr, &sCollisionParameter, &uCollisionResultsSize, &apCollisionResults); CHECK_RET(iRet); std::basic_ofstream sOutput; sOutput.open(acResultFile); if (sOutput.is_open()) { for (A3DUns32 uiRes = 0; uiRes < uCollisionResultsSize; uiRes++) { A3DCollisionResultData const & sCurResult = apCollisionResults[uiRes]; size_t iGlobalIndex1 = auiGroupIndex1[sCurResult.m_iRepItemIndex1]; size_t iGlobalIndex2 = (sGroup2.m_uRepItemSize != 0) ? auiGroupIndex2[sCurResult.m_iRepItemIndex2] : auiGroupIndex1[sCurResult.m_iRepItemIndex2]; sOutput << "Check " << asIdentifier[iGlobalIndex1] << " with " << asIdentifier[iGlobalIndex2] << " : "; switch (sCurResult.m_eStatus) { case A3DCollision_Unknown: sOutput << "Unknown"; break; case A3DCollision_NoCollision: sOutput << "No Collision"; break; case A3DCollision_Clearance: sOutput << "Clearance"; break; case A3DCollision_Contact: sOutput << "Contact"; break; case A3DCollision_Collision: sOutput << "Collision"; break; case A3DCollision_FirstInside: sOutput << "First is Inside"; break; case A3DCollision_SecondInside: sOutput << "Second is Inside"; break; } sOutput << std::endl; } sOutput.close(); } // Free memory iRet = A3DCollisionCompute(nullptr, nullptr, nullptr, &uCollisionResultsSize, &apCollisionResults); CHECK_RET(iRet); for (auto & sTransfoRep : apRepItem) { delete [] sTransfoRep.m_pOptPlacement; } // Check memory allocations return (int)ListLeaks(); }