/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include "MemoryStream.h" #include "DynamicLinker.h" #include "RxDynamicModule.h" #include "diagnostics.h" #include "RxObjectImpl.h" #include "BrepBuilderFillerModule.h" #include "BaseMaterialAndColorHelper.h" #include "Br/BrBrep.h" #include "Br/BrEdge.h" #include "Br/BrBrepFaceTraverser.h" #include "Br/BrFaceLoopTraverser.h" #include "Br/BrLoopEdgeTraverser.h" #include "Br/BrBrepComplexTraverser.h" #include "DbBlockTableRecord.h" #include "DbBody.h" #include "ExHostAppServices.h" #include "ExSystemServices.h" #include "DgModelerGeometry.h" #include "DgDatabase.h" #include "DgSharedCellReference.h" #include "DgBRepEntityPE.h" #include "Dg3DObject.h" #include "ExDgnServices.h" #include "ExDgnHostAppServices.h" #include "ModelerGeometry/ModelerModule.h" #include const OdString kErrorIncorrectArguments(OdString().format(L"" \ L"Usage: OdParasolidToAcisEx \n" \ L" - .dgn file\n" \ L" - .dwg file\n")); /************************************************************************/ /* Define a Custom Services class. */ /* */ /* Combines the platform dependent functionality of */ /* ExSystemServices and OdExDgnHostAppServices */ /************************************************************************/ class MyServicesDgn : public ExSystemServices, public OdExDgnHostAppServices { protected: ODRX_USING_HEAP_OPERATORS(ExSystemServices); }; /************************************************************************/ /* Define a Custom Services class. */ /* */ /* Combines the platform dependent functionality of */ /* ExSystemServices and ExHostAppServices */ /************************************************************************/ class MyServicesDwg : public ExSystemServices, public ExHostAppServices { protected: ODRX_USING_HEAP_OPERATORS(ExSystemServices); }; /************************************************************************/ /* Define a Custom Helper class. */ /* */ /* Used to convert color from Dgn database into Dwg database */ /************************************************************************/ class Ps2DwgMaterialAndColorHelper : public OdBaseMaterialAndColorHelper { public: explicit Ps2DwgMaterialAndColorHelper(OdDbStub* pDefaultMaterial = NULL) : OdBaseMaterialAndColorHelper(pDefaultMaterial) { } OdResult convertColor(const OdCmEntityColor& srcColor, OdCmEntityColor& destColor) ODRX_OVERRIDE { destColor = srcColor; return eOk; } }; /************************************************************************/ /* Custom assertion method */ /************************************************************************/ static void CustomAssert(const char* expression, const char* fileName, int nLineNo) { OdString message; message.format(L"\n!!! Assertion failed: \"%ls\"\n file: %ls, line %d\n", OdString(expression).c_str(), OdString(fileName).c_str(), nLineNo); odPrintConsoleString(message); } /************************************************************************/ /* Method to count the number of complexes in brep */ /************************************************************************/ int getNumComplexesInBrep(OdBrBrep& brep) { int numComplexes = 0; OdBrErrorStatus err = odbrOK; OdBrBrepComplexTraverser bct; if (bct.setBrep(brep) == odbrOK) { while (!bct.done() && (err == odbrOK)) { ++numComplexes; err = bct.next(); } } return numComplexes; } /************************************************************************/ /* Method to count the number of faces in brep */ /************************************************************************/ int getNumFacesInBrep(OdBrBrep& brep) { int numFaces = 0; OdBrErrorStatus err = odbrOK; OdBrBrepFaceTraverser bft; if (bft.setBrep(brep) == odbrOK) { while (!bft.done() && (err == odbrOK)) { OdBrFace f = bft.getFace(); std::unique_ptr pSurf; try { pSurf.reset(f.getSurface()); } catch (...) { pSurf.reset(); } if (pSurf.get() == NULL) { OdGeNurbSurface srf; OdBrErrorStatus st = f.getSurfaceAsNurb(srf); if (st == odbrOK) { ++numFaces; } } else { ++numFaces; } err = bft.next(); } } return numFaces; } /************************************************************************/ /* Method to check if brep is empty (has no faces) */ /************************************************************************/ inline bool isBrepEmpty(OdBrBrep& brep) { int numComplexes = getNumComplexesInBrep(brep); if (numComplexes == 0) { return true; } int numFaces = getNumFacesInBrep(brep); return numFaces == 0; } /***************************************************************************************/ /* Method to check if brep is solid (has no boundary edges with single adjacent face) */ /***************************************************************************************/ bool isBrepSolid(OdBrBrep& brep) { std::map edgeCnt; OdBrErrorStatus err = odbrOK; OdBrBrepFaceTraverser bft; if (bft.setBrep(brep) != odbrOK) { return false; } while (!bft.done() && (err == odbrOK)) { OdBrFaceLoopTraverser faLoTrav; OdBrFace face = bft.getFace(); for (faLoTrav.setFace(face); !faLoTrav.done(); faLoTrav.next()) { OdBrLoopEdgeTraverser loEdTrav; OdBrLoop loop = faLoTrav.getLoop(); err = loEdTrav.setLoop(loop); for (; !loEdTrav.done(); loEdTrav.next()) { OdBrEdge edge = loEdTrav.getEdge(); ++edgeCnt[edge.getUniqueId()]; } } bft.next(); } for (std::map::const_iterator eit = edgeCnt.begin(); eit != edgeCnt.end(); eit++) { if (eit->second < 2) { return false; } } return true; } inline OdString getFileNameWithoutExt(const OdString& filename) { OdString sFileName = filename, sRes; const int nExtPos = sFileName.reverseFind(L'.'); if (-1 != nExtPos) { sRes = sFileName.left(nExtPos); } else { sRes = sFileName; } return sRes; } inline OdString getFileNameWithoutPath(const OdString& filename) { OdString sFileName = filename, sRes; #if defined(ODA_WINDOWS) sFileName.replace(L'/', L'\\'); const int nPathPos = sFileName.reverseFind(L'\\'); #else sFileName.replace(L'\\', L'/'); const int nPathPos = sFileName.reverseFind(L'/'); #endif if (-1 != nPathPos) { sRes = sFileName.right(sFileName.getLength() - nPathPos - 1); } else { sRes = sFileName; } return sRes; } inline OdString getFileExtension(const OdString& sFileName) { OdString sBuf = sFileName; OdString sExt; const int iDotPos = sBuf.makeLower().reverseFind(L'.'); if (-1 != iDotPos) sExt = sBuf.right(sBuf.getLength() - iDotPos - 1); return sExt; } enum ConversionResult { crOk, crNullInput, crNoBrep, crInvalidBrep, crEmptyBrep, crBadBrepData, crBrepBuilderCreationFailed, crBrepBuilderInitializationFailed, crBrepBuilderFailed, crBrepTransformationFailed, crSerializationFailed, crAppendFailed }; ConversionResult convertEntity(const OdDgElement* pInputEntity, OdDbDatabasePtr pDwgDb, OdDgDatabasePtr pDgnDb, OdDbHostAppServices* pDwgServices, OdBaseMaterialAndColorHelper* pMaterialHelper) { // entity skipped if it has no brep OdDbHandle entityHandle = pInputEntity->elementId().getHandle(); odPrintConsoleString(OD_T("Converting %ls entity:\n"), entityHandle.ascii().c_str()); OdDgBRepEntityPEPtr pBrep = OdDgBRepEntityPEPtr(pInputEntity); OdDgModelerGeometryPtr model; OdResult res = pBrep->getBrep(pInputEntity, model); if (res != eOk) return crNoBrep; OdBrBrep brep; model->brep(brep); // try to init additional brep data OdGeMatrix3d brepTransformation; bool isBrepTransformed = false; bool isBrepOpen = true; try { if (!brep.isValid()) { odPrintConsoleString(L" invalid brep -> skip\n\n."); return crInvalidBrep; } if (isBrepEmpty(brep)) { odPrintConsoleString(L" empty brep -> skip\n\n."); return crEmptyBrep; } isBrepOpen = !isBrepSolid(brep); isBrepTransformed = brep.getTransformation(brepTransformation); } catch (const OdError& e) { odPrintConsoleString(L" failed (%s) -> skip\n\n.", e.description().c_str()); return crBadBrepData; } catch (...) { odPrintConsoleString(L" failed (unknown error) -> skip\n\n."); return crBadBrepData; } // try to init converter OdBrepBuilder builder; OdBrepBuilderFiller filler; BrepType brepType = isBrepOpen ? kOpenShell : kSolid; OdResult err; try { err = pDwgServices->brepBuilder(builder, brepType); if (err != eOk) { odPrintConsoleString(L" failed to create BrepBuilder -> skip\n\n."); return crBrepBuilderCreationFailed; } builder.enableValidator(false); filler.params().setupFor(OdBrepBuilderFillerParams::kBrepPS, pDgnDb, OdBrepBuilderFillerParams::kBrepAcisDwg, pDwgDb); try { err = filler.initFrom(builder, brep, pMaterialHelper); } catch (const OdError& e) { odPrintConsoleString(L" failed (%s) -> skip\n\n.", e.description().c_str()); return crBrepBuilderInitializationFailed; } catch (...) { odPrintConsoleString(L" failed (unknown error) -> skip\n\n."); return crBrepBuilderInitializationFailed; } if (err != eOk) { odPrintConsoleString(L" failed to init BrepBuilder -> skip\n\n."); return crBrepBuilderInitializationFailed; } } catch (const OdError& e) { odPrintConsoleString(L" failed (%s) -> skip\n\n.", e.description().c_str()); return crBrepBuilderInitializationFailed; } catch (...) { odPrintConsoleString(L" failed (unknown error) -> skip\n\n."); return crBrepBuilderInitializationFailed; } if (err != eOk) { odPrintConsoleString(L" failed to init BrepBuilder -> skip\n\n."); return crBrepBuilderInitializationFailed; } // convert entity brep OdModelerGeometryPtr pConversionResult; try { pConversionResult = builder.finish(); if (pConversionResult.isNull()) { odPrintConsoleString(L" failed to convert (NULL result) -> skip\n\n."); return crBrepBuilderFailed; } if (isBrepTransformed) { pConversionResult->transformBy(brepTransformation); } } catch (const OdError& e) { odPrintConsoleString(L" failed to convert (%s) -> skip\n\n.", e.description().c_str()); return crBrepBuilderFailed; } catch (...) { odPrintConsoleString(L" failed to convert (unknown error) -> skip\n\n."); return crBrepBuilderFailed; } // add converted entity to database try { OdStreamBufPtr pMemStream = OdMemoryStream::createNew(); err = pConversionResult->out(pMemStream, kAfTypeVerAny); if (err != eOk) { odPrintConsoleString(L" failed to output entity to stream -> skip\n\n."); return crSerializationFailed; } pMemStream->rewind(); // create entity OdDbBodyPtr pBody = OdDbBody::createObject(); pBody->acisIn(pMemStream); OdDbBlockTableRecordPtr ms = pDwgDb->getModelSpaceId().safeOpenObject(OdDb::kForWrite); ms->appendOdDbEntity(pBody); } catch (const OdError& e) { odPrintConsoleString(L" failed to add entity to database (%s) -> skip\n\n.", e.description().c_str()); return crAppendFailed; } catch (...) { odPrintConsoleString(L" failed to add entity to database (unknown error) -> skip\n\n."); return crAppendFailed; } return crOk; } void addEntityToList(const OdDgElement* pE, OdArray& allElements) { OdDgCellHeader3dPtr pCell = OdDgCellHeader3d::cast(pE); if (!pCell.isNull()) { OdDgBRepEntityPEPtr pBrep = OdDgBRepEntityPEPtr(pCell); OdStreamBufPtr binData = OdMemoryStream::createNew(); OdUInt32 version = pBrep->brepVersion(pCell); if (pBrep->brepOutNative(pCell, *binData) == eOk && version != 0) { if (version & OdDgModelerGeometry::kParasolidMask) { allElements.append(pE); } } } } void addEntityToList(OdDgElementIteratorPtr iterator, OdArray& allElements) { for (; !iterator->done(); iterator->step()) { OdRxObjectPtr object = iterator->item().openObject(); OdDgCellHeader3dPtr pCell = OdDgCellHeader3d::cast(object); OdDgSolidPtr pSolid = OdDgSolid::cast(object); if (!pCell.isNull() || !pSolid.isNull()) { addEntityToList(OdDgElement::cast(object).get(), allElements); if (!pCell.isNull()) addEntityToList(pCell->createIterator(), allElements); continue; } OdDgSharedCellReferencePtr pShared = OdDgSharedCellReference::cast(object); if (!pShared.isNull()) { OdDgSharedCellDefinitionPtr pSharedDef = pShared->findDefinition(); if (!pSharedDef.isNull()) { addEntityToList(pSharedDef->createIterator(), allElements); } continue; } } } void collectAll(OdDgDatabasePtr pDgnDb, OdArray &allElements) { OdDgModelTablePtr pModelTable = pDgnDb->getModelTable(); OdDgElementIteratorPtr pIter = pModelTable->createIterator(); for (; !pIter->done(); pIter->step()) { OdDgModelPtr pModel = OdDgModel::cast(pIter->item().openObject()); if (pModel.get()) { int i = 0; while (i < 2) { OdDgElementIteratorPtr iterator = i++ == 0 ? pModel->createGraphicsElementsIterator() : pModel->createControlElementsIterator(); addEntityToList(iterator, allElements); } } } } void convertDatabase(const OdString& inputPath, const OdString& outputPath, const OdString& name, OdDbHostAppServices* pDwgServices, OdDgHostAppServices* pDgnServices) { // read DGN database OdDgDatabasePtr pDgnDb = pDgnServices->readFile(inputPath); odPrintConsoleString(L"Opened source database:%s\nProcessing entities...\n", inputPath.c_str()); // create DWG database OdDbDatabasePtr pDwgDb = pDwgServices->createDatabase(); // collect all entities with parasolid data OdArray allElements; collectAll(pDgnDb, allElements); int numConvertedEntities = 0; Ps2DwgMaterialAndColorHelper materialHelper; // Convert entities for (auto pInputEntity : allElements) { ConversionResult res = convertEntity(pInputEntity, pDwgDb, pDgnDb, pDwgServices, &materialHelper); if (res == crOk) { ++numConvertedEntities; } } if (numConvertedEntities > 0) { // save database to file pDwgDb->writeFile(outputPath, OdDb::kDwg, OdDb::kDHL_CURRENT); odPrintConsoleString(L"\nSave result to: %s\n", outputPath.c_str()); } else { odPrintConsoleString(L"\nEmpty conversion result. Database not saved.\n"); } } #ifndef _TOOLKIT_IN_DLL_ ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdDgnModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(DgModelerModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ModelerModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(ExRasterModule); ODRX_DECLARE_STATIC_MODULE_ENTRY_POINT(OdRecomputeDimBlockModule); ODRX_BEGIN_STATIC_MODULE_MAP() ODRX_DEFINE_STATIC_APPMODULE(OdDgnModelerGeometryModuleName, DgModelerModule) ODRX_DEFINE_STATIC_APPLICATION(OdDgnDbModuleName, OdDgnModule) ODRX_DEFINE_STATIC_APPLICATION(OdModelerGeometryModuleName, ModelerModule) ODRX_DEFINE_STATIC_APPLICATION(RX_RASTER_SERVICES_APPNAME, ExRasterModule) ODRX_DEFINE_STATIC_APPLICATION(OdRecomputeDimBlockModuleName, OdRecomputeDimBlockModule) ODRX_END_STATIC_MODULE_MAP() #endif /************************************************************************/ /* Main */ /************************************************************************/ #if defined(ODA_WINDOWS) int wmain(int argc, wchar_t* argv[]) #else int main(int argc, char* argv[]) #endif { #if defined(TARGET_OS_MAC) && !defined(__MACH__) argc = ccommand(&argv); #endif if( argc < 2 ) { oddgPrintConsoleString(kErrorIncorrectArguments); return 1; } OdString sFileToExport(argv[1]); // for UNICODE support OdString ext = getFileExtension(sFileToExport); if (ext.iCompare(L"dgn") != 0) { oddgPrintConsoleString(kErrorIncorrectArguments); return 1; } OdString sFileToImport(argv[2]); ext = getFileExtension(sFileToImport); if (ext.iCompare(L"dwg") != 0) { oddgPrintConsoleString(kErrorIncorrectArguments); return 1; } #ifndef _TOOLKIT_IN_DLL_ ODRX_INIT_STATIC_MODULE_MAP(); #endif // create some service OdStaticRxObject< MyServicesDgn > svcDgn; OdStaticRxObject< MyServicesDwg > svcDwg; // set custom assertion method odSetAssertFunc(CustomAssert); /**********************************************************************/ /* Initialize Runtime Extension environment */ /**********************************************************************/ odInitialize( &svcDwg); oddgPrintConsoleString(L"Developed using %ls ver %ls\n\n", svcDgn.product().c_str(), svcDgn.versionString().c_str()); bool bSuccess = false; try { ::odrxDynamicLinker()->loadModule(OdModelerGeometryModuleName, false); ::odrxDynamicLinker()->loadModule(OdDgnDbModuleName, false); ::odrxDynamicLinker()->loadModule(OdDgnModelerGeometryModuleName, false); OdString name = getFileNameWithoutExt(getFileNameWithoutPath(sFileToImport)); convertDatabase(sFileToExport, sFileToImport, name, &svcDwg, &svcDgn); } catch (OdError& e) { oddgPrintConsoleString(L"\nError: %ls\n", e.description().c_str()); } catch (...) { oddgPrintConsoleString(L"\nUnknown Error.\n"); } /**********************************************************************/ /* Uninitialize Runtime Extension environment */ /**********************************************************************/ odUninitialize(); return 0; }