/////////////////////////////////////////////////////////////////////////////// // 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 "DbUserIO.h" #include "DbCommandContext.h" #include "DbGeoData.h" #include "SpatialReference/OdCsdFormatter.h" #include "SpatialReference/OdGeodeticPathDefinition.h" #include "SpatialReference/OdGeodeticTransformationDefinition.h" #include "SpatialReference/OdCategoryDefinition.h" #include "SpatialReference/OdCoordinateReferenceSystemTransformation.h" #include "SpatialReference/OdGeodeticTransformationAnalytical.h" #define STL_USING_SET #define STL_USING_MAP #include "OdaSTL.h" using namespace OdSpatialReference; bool registerEllipsoid(OdEllipsoidDefinitionPtr pEllipsoid) { OdString sCode; if (!pEllipsoid || eOk != pEllipsoid->getCode(sCode)) { return false; } OdEllipsoidDefinitionPtr pLoadedEllipsoid; return eOk == OdEllipsoidDefinition::load(sCode, pLoadedEllipsoid) || eOk == pEllipsoid->update(); } bool registerDatum(OdDatumDefinitionPtr pDatum) { OdString sCode; if (!pDatum || eOk != pDatum->getCode(sCode)) { return false; } OdDatumDefinitionPtr pLoadedDatum; return eOk == OdDatumDefinition::load(sCode, pLoadedDatum) || eOk == pDatum->update(); } bool registerCSAndCategory(OdCoordinateReferenceSystemDefinitionPtr pCS) { OdString sCode; if (!pCS || eOk != pCS->getCode(sCode)) { return false; } OdCoordinateReferenceSystemDefinitionPtr pLoadedCRSD; if (eOk == OdCoordinateReferenceSystemDefinition::load(sCode, pLoadedCRSD)) { return true; } if (eOk != pCS->update()) { return false; } OdString sCategoryName = OD_T("Auto-Registered"); OdCategoryDefinitionPtr pCategory; if (eOk != OdCategoryDefinition::load(sCategoryName, pCategory)) { OdCategoryDefinitionPtr pNewCategory = OdCategoryDefinition::createObject(); pNewCategory->initialize(); pNewCategory->setCode(sCategoryName); if (eOk != pNewCategory->update()) { return false; } if (eOk != OdCategoryDefinition::load(sCategoryName, pCategory)) { return false; } } bool bContains = false; if (eOk != pCategory->contains(sCode, bContains)) { return false; } return bContains || eOk == pCategory->add(sCode) && eOk == pCategory->update(); } bool registerGeodeticTransformation(OdCoordinateReferenceSystemDefinitionPtr pCS) { if (!pCS) { return false; } OdDatumDefinitionPtr pDatum; if (eOk != pCS->getDatumDefinition(pDatum)) { return true; } OdString sCode; if (eOk != pCS->getCode(sCode)) { return false; } OdCoordinateReferenceSystemTransformationPtr pCRSTransformation; if (eOk != OdCoordinateReferenceSystemTransformation::load(sCode, OD_T("LL84"), pCRSTransformation)) { return false; } OdDatumShiftPtr pDatumShift; if (eOk != pCRSTransformation->getDatumShift(pDatumShift)) { return false; } OdGeodeticPathDefinitionPtr pGeodeticPath; if (eOk != pDatumShift->getPath(pGeodeticPath)) { return false; } bool bIsReversed = false; OdGeodeticTransformationDefinitionPtr pTransformation; if (eOk != pDatumShift->getAt(0, bIsReversed, pTransformation)) { return true; } OdGeodeticTransformationParametersPtr pParameters; if (eOk != pTransformation->getParameters(pParameters)) { return false; } auto pAnalytical = OdGeodeticTransformationAnalytical::cast(pParameters); if (!pAnalytical) { return false; } OdString sTransformationCode; if (eOk != pTransformation->getCode(sTransformationCode)) { return false; } OdGeodeticTransformationDefinitionPtr pLoadedTransformation; return eOk == OdGeodeticTransformationDefinition::load(sTransformationCode, pLoadedTransformation) || eOk == pTransformation->update(); } #if defined(_MSC_VER) && (_MSC_VER <= 1910) #pragma warning(disable : 4503) #endif bool registerGeodeticPathAndTransformations(OdCoordinateReferenceSystemDefinitionPtr pCS, OdGeodeticPathDefinitionPtr pGeodeticPath, const OdGeodeticTransformationDefinitionArray& arrTransformation) { if (arrTransformation.isEmpty()) { return registerGeodeticTransformation(pCS); } bool bRegisterGeodeticPath = false; if (pGeodeticPath) { OdString sCode; if (eOk != pGeodeticPath->getCode(sCode)) { return false; } OdGeodeticPathDefinitionPtr pLoadedGeodeticPath; if (eOk == OdGeodeticPathDefinition::load(sCode, pLoadedGeodeticPath)) { return true; } bRegisterGeodeticPath = true; } struct OdStringCompare { bool operator()(const OdString& a, const OdString& b) const { return a.iCompare(b) < 0; } }; using TargetSet = std::set; using TransformationMap = std::map; TransformationMap mapTransformation; OdGeodeticTransformationDefinitionArray arrTransformationToCreate; for (const auto& pTransformation : arrTransformation) { OdString sSourceDatum; OdString sTargetDatum; bool bInverseSupported = false; OdString sCode; if (eOk != pTransformation->getSourceDatum(sSourceDatum) || eOk != pTransformation->getTargetDatum(sTargetDatum) || eOk != pTransformation->getInverseSupported(bInverseSupported) || eOk != pTransformation->getCode(sCode)) { return false; } // transformation can be loaded case: { OdGeodeticTransformationDefinitionPtr pLoadedTransformation; if (eOk == OdGeodeticTransformationDefinition::load(sCode, pLoadedTransformation)) { if (bRegisterGeodeticPath) { OdString sLoadedSourceDatum; OdString sLoadedTargetDatum; bool bLoadedInverseSupported = false; if (eOk != pLoadedTransformation->getSourceDatum(sLoadedSourceDatum) || eOk != pLoadedTransformation->getTargetDatum(sLoadedTargetDatum) || eOk != pLoadedTransformation->getInverseSupported(bLoadedInverseSupported)) { return false; } bRegisterGeodeticPath = (bInverseSupported == bLoadedInverseSupported) && (0 == sSourceDatum.iCompare(sLoadedSourceDatum) && 0 == sTargetDatum.iCompare(sLoadedTargetDatum) || bInverseSupported && 0 == sTargetDatum.iCompare(sLoadedSourceDatum) && 0 == sSourceDatum.iCompare(sLoadedTargetDatum)); } continue; } } // transformation can't be loaded case: { if (bRegisterGeodeticPath) { arrTransformationToCreate.push_back(pTransformation); continue; } if (mapTransformation.empty()) { OdGeodeticTransformationDefinitionArray arrLoadedTransformation; if (eOk != OdGeodeticTransformationDefinition::loadAll(arrLoadedTransformation)) { return false; } for (const auto& pLoadedTransformation : arrLoadedTransformation) { OdString sLoadedSourceDatum; OdString sLoadedTargetDatum; bool bLoadedInverseSupported = false; if (eOk != pLoadedTransformation->getSourceDatum(sLoadedSourceDatum) || eOk != pLoadedTransformation->getTargetDatum(sLoadedTargetDatum) || eOk != pLoadedTransformation->getInverseSupported(bLoadedInverseSupported)) { return false; } mapTransformation[sLoadedSourceDatum].insert(sLoadedTargetDatum); if (bLoadedInverseSupported) { mapTransformation[sLoadedTargetDatum].insert(sLoadedSourceDatum); } } } auto pIt = mapTransformation.find(sSourceDatum); if (pIt == mapTransformation.end() || pIt->second.find(sTargetDatum) == pIt->second.end()) { arrTransformationToCreate.push_back(pTransformation); } } } for (auto& pTransformationToCreate : arrTransformationToCreate) { if (eOk != pTransformationToCreate->update()) { return false; } } if (!bRegisterGeodeticPath) { return true; } OdString sSourceDatum; OdString sTargetDatum; bool bIsReversible = false; if (eOk != pGeodeticPath->getSourceDatum(sSourceDatum) || eOk != pGeodeticPath->getTargetDatum(sTargetDatum) || eOk != pGeodeticPath->getIsReversible(bIsReversible)) { return false; } OdGeodeticPathDefinitionArray arrLoadedGeodeticPath; if (eOk != OdGeodeticPathDefinition::loadAll(arrLoadedGeodeticPath)) { return false; } for (const auto& pLoadedGeodeticPath : arrLoadedGeodeticPath) { OdString sLoadedSourceDatum; OdString sLoadedTargetDatum; bool bLoadedIsReversible = false; if (eOk != pLoadedGeodeticPath->getSourceDatum(sLoadedSourceDatum) || eOk != pLoadedGeodeticPath->getTargetDatum(sLoadedTargetDatum) || eOk != pLoadedGeodeticPath->getIsReversible(bLoadedIsReversible)) { return false; } if (0 == sSourceDatum.iCompare(sLoadedSourceDatum) && 0 == sTargetDatum.iCompare(sLoadedTargetDatum) || (bIsReversible || bLoadedIsReversible) && 0 == sTargetDatum.iCompare(sLoadedSourceDatum) && 0 == sSourceDatum.iCompare(sLoadedTargetDatum)) { return false; } } return eOk == pGeodeticPath->update(); } void _GeoDataRegisterUnknownCS_func(OdEdCommandContext* pCmdCtx) { OdDbCommandContextPtr pDbCmdCtx(pCmdCtx); OdDbDatabase* pDb = pDbCmdCtx->database(); OdDbUserIO* pIO = pDbCmdCtx->dbUserIO(); // get coordinate system string OdDbObjectId objIdGeoData; if (eOk != oddbGetGeoDataObjId(pDb, objIdGeoData)) { pIO->putString(L"No OdDbGeoData object found in the database."); return; } auto pGeoData = OdDbGeoData::cast(objIdGeoData.openObject()); if (pGeoData.isNull()) { pIO->putString(L"The geo data object is not of type OdDbGeoData."); return; } // parse definitions OdDefinitionBaseArray arrDefinition; if (eOk != OdCsdFormatter::parseXml(pGeoData->coordinateSystem(), arrDefinition) || arrDefinition.isEmpty()) { pIO->putString(L"Failed to parse the coordinate system."); return; } // filter definitions OdCoordinateReferenceSystemDefinitionPtr pCS; OdDatumDefinitionPtr pDatum; OdEllipsoidDefinitionPtr pEllipsoid; OdGeodeticPathDefinitionPtr pGeodeticPath; OdGeodeticTransformationDefinitionArray arrTransformation; for (const auto& pDefinition : arrDefinition) { if (pCS.isNull() && pDefinition->isKindOf(OdCoordinateReferenceSystemDefinition::desc())) { pCS = pDefinition; continue; } if (pDatum.isNull() && pDefinition->isKindOf(OdDatumDefinition::desc())) { pDatum = pDefinition; continue; } if (pEllipsoid.isNull() && pDefinition->isKindOf(OdEllipsoidDefinition::desc())) { pEllipsoid = pDefinition; continue; } if (pGeodeticPath.isNull() && pDefinition->isKindOf(OdGeodeticPathDefinition::desc())) { pGeodeticPath = pDefinition; continue; } if (pDefinition->isKindOf(OdGeodeticTransformationDefinition::desc())) { arrTransformation.push_back(pDefinition); } } //register definitions and update OdDbGeoData transformation data if ((pEllipsoid.isNull() || registerEllipsoid(pEllipsoid)) && (pDatum.isNull() || registerDatum(pDatum)) && (pCS.isNull() || registerCSAndCategory(pCS)) && registerGeodeticPathAndTransformations(pCS, pGeodeticPath, arrTransformation)) { pGeoData->upgradeOpen(); pGeoData->updateTransformationMatrix(); pIO->putString(L"Coordinate system successfully updated."); } else { pIO->putString(L"Failed to update the coordinate system."); } }