/////////////////////////////////////////////////////////////////////////////// // 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 "ExDwgCompare.h" #include "DbBlockTableRecord.h" #include "DebugStuff.h" #include "MemoryStream.h" #include "XRefMan.h" #include "DbBlockReference.h" #include "Editor.h" #include "RxEvent.h" #include "DbIdMapping.h" #include "Tf/TfRevisionControl.h" #include "DbCommandContext.h" #include "DbLayerTable.h" ODRX_DEFINE_DYNAMIC_MODULE(OdDwgCompareModule); void OdDwgCompareModule::initApp() { OdEdCommandStackPtr pCommands = odedRegCmds(); pCommands->addCommand(&m_dwgCompare); pCommands->addCommand(&m_dwgCompareExit); m_dwgCompare.m_module = this; m_dwgCompareExit.m_module = this; } void OdDwgCompareModule::uninitApp() { OdEdCommandStackPtr pCommands = odedRegCmds(); pCommands->removeGroup(m_dwgCompare.groupName()); } void OdDwgCompareModule::restoreLayerState(OdDbDatabase*) { for (auto i : m_lockLayerCacheArr) { OdDbLayerTableRecordPtr pLayerRec = i.openObject(OdDb::kForWrite); pLayerRec->setIsLocked(false); } m_lockLayerCacheArr.clear(); } void OdDwgCompareModule::storeLayerState(OdDbDatabase* pDb) { const OdDbLayerTablePtr pLayerTable = pDb->getLayerTableId().safeOpenObject(); OdDbSymbolTableIteratorPtr pIt = pLayerTable->newIterator(); for(;!pIt->done(); pIt->step()) { OdDbLayerTableRecordPtr pLayerRec = pIt->getRecord(OdDb::kForWrite); const bool isLayerLocked = pLayerRec->isLocked(); if (!isLayerLocked) { m_lockLayerCacheArr.append(pLayerRec->id()); pLayerRec->setIsLocked(true); } } } void OdDwgCompareModule::setBlockRefId(const OdDbObjectId id) { m_blockRefId = id; } void OdDwgCompareModule::setEntityColorCache(const OdDbObjectId2ColorArray arr) { m_entityColorCacheArr = arr; } OdDbObjectId OdDwgCompareModule::getBlockRefId() const { return m_blockRefId; } OdDbObjectId2ColorArray OdDwgCompareModule::getEntityColorCache() const { return m_entityColorCacheArr; } bool OdDwgCompareModule::isDwgCompareActive() const { return !m_lockLayerCacheArr.isEmpty(); } OdDbObjectId attachBlockRef(OdDbDatabase* pDb, OdDbObjectId blockId) { OdDbBlockReferencePtr pRef = OdDbBlockReference::createObject(); pRef->setDatabaseDefaults(pDb); pRef->setNormal(OdGeVector3d::kZAxis); pRef->setRotation(0.0); OdGePoint3d defaultInsertionPoint; pRef->setPosition(defaultInsertionPoint); pRef->setScaleFactors(OdGeScale3d::kIdentity); pRef->setBlockTableRecord(blockId); OdDbBlockTableRecordPtr pModelSpace = pDb->getModelSpaceId().safeOpenObject(OdDb::kForWrite); return pModelSpace->appendOdDbEntity(pRef); } void OdDwgCompare::execute(OdEdCommandContext* pCmdCtx) { if (::odrxDynamicLinker()->loadModule(TfModuleName, false).isNull()) throw OdError(L"Error load TD_Tf"); if (!pCmdCtx) throw OdError(eNoDatabase); if(m_module->isDwgCompareActive()) throw OdError(eAlreadyActive); OdDbDatabase* pDbRuntime = OdDbCommandContextPtr(pCmdCtx)->database(); odTfInitialize(pDbRuntime->appServices()); OdStreamBufPtr sFile = OdMemoryStream::createNew(); OdTfRepositoryPtr ptrRep = OdTfRepository::createObject(sFile, pDbRuntime->appServices()); ptrRep->init(true); const OdTfDigest shaDbRuntime = ptrRep->store(pDbRuntime); OdDbCommandContextPtr pDbCmdCtx(pCmdCtx); OdDbUserIO* pIO = OdDbUserIO::cast(pDbCmdCtx->userIO()); if (!pIO) throw OdError("OdDbUserIO not available"); OdString fname = pIO->getFilePath(OD_T("Enter file name to compare:"), OdEd::kGfpForOpen, OD_T("Select drawing to compare"), OD_T("dwg"), OdString::kEmpty, OD_T("TD drawing (*.dwg)|*.dwg||")); OdDbDatabasePtr ptrDbCompre = pDbRuntime->appServices()->readFile(fname); const OdTfDigest shaDbCompare = ptrRep->store(ptrDbCompre); ptrDbCompre = 0; OdTfRevisionControl::ChangeList changeList; ptrRep->getRevisionDifference(shaDbRuntime, shaDbCompare, changeList); OdTfRevisionControl::detachRepository(pDbRuntime); if (changeList.empty()) { pIO->putString(L"No differences found"); return; } OdDbBlockTableRecordPtr pRec = OdDbXRefManExt::addNewXRefDefBlock(pDbRuntime, fname, "CompareBlock", false); if (pRec.isNull()) throw OdError("OdDbXRefManExt::addNewXRefDefBlock() can't load .dwg file"); OdResult eRes = OdDbXRefMan::load(pRec); if (eRes != eOk) { pRec->erase(); throw eRes; } OdDbObjectId refId = attachBlockRef(pDbRuntime, pRec->id()); m_module->setBlockRefId(refId); if (0) return; //pDbRuntime->startTransaction(); OdDbDatabase* pDbCompre = pRec->xrefDatabase(); auto changeEntColor = [](const OdDbObjectId id, OdUInt16 color, OdDbObjectId2ColorArray*const id2colorArr) { if (!id.isValid() || id.isErased()) return; OdDbObjectPtr obj = id.safeOpenObject(); OdDbEntityPtr pEnt = OdDbEntity::cast(obj); if (!pEnt.isNull()) { pEnt->upgradeOpen(); if (id2colorArr) { OdCmEntityColor colorEnt = pEnt->entityColor(); id2colorArr->append(std::make_pair(id, colorEnt)); } pEnt->setColorIndex(color);//green 90; } }; OdDbObjectId2ColorArray objI2dColorArr; for (const auto i : changeList) { switch (i.second) { case OdTfRevisionControl::kObjectAdded: case OdTfRevisionControl::kObjectDeleted: case OdTfRevisionControl::kObjectModified: { changeEntColor(pDbRuntime->getOdDbObjectId(i.first), 1, &objI2dColorArr);//1 green changeEntColor(pDbCompre->getOdDbObjectId(i.first), 3, 0);//3 red } } } m_module->setEntityColorCache(objI2dColorArr); m_module->storeLayerState(pDbRuntime); } void OdDwgCompareExit::execute(OdEdCommandContext* pCmdCtx) { if (!m_module->isDwgCompareActive()) return; OdDbDatabase* pDbRuntime = OdDbCommandContextPtr(pCmdCtx)->database(); m_module->restoreLayerState(pDbRuntime); restoreColor(); OdDbBlockReferencePtr pRef = m_module->getBlockRefId().safeOpenObject(OdDb::kForWrite); OdDbObjectIdArray idArr; idArr.append(pRef->blockTableRecord()); OdDbXRefMan::unload(idArr); OdDbBlockTableRecordPtr pBlock = pRef->blockTableRecord().safeOpenObject(OdDb::kForWrite); OdDbXRefMan::detach(pBlock); m_module->setBlockRefId(OdDbObjectId()); //pDbRuntime->endTransaction(); //pDbRuntime->undo(); } void OdDwgCompareExit::restoreColor() { const OdDbObjectId2ColorArray objI2dColorArr = m_module->getEntityColorCache(); for (const auto i : objI2dColorArr) { OdDbEntityPtr pEnt = i.first.safeOpenObject(OdDb::kForWrite); OdCmColor cm; cm.setColorMethod(i.second.colorMethod()); switch (i.second.colorMethod()) { case OdCmEntityColor::kByLayer: case OdCmEntityColor::kByBlock: break; case OdCmEntityColor::kByACI: case OdCmEntityColor::kByPen: case OdCmEntityColor::kForeground: break; case OdCmEntityColor::kByColor: cm.setColor(i.second.color()); case OdCmEntityColor::kByDgnIndex: cm.setColorIndex(i.second.colorIndex()); break; default: ODA_FAIL_ONCE(); } pEnt->setColor(cm); } m_module->setEntityColorCache(OdDbObjectId2ColorArray()); }