/////////////////////////////////////////////////////////////////////////////// // 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 "RxObject.h" #include "RxSystemServices.h" #include "DgHostAppServices.h" #include "OdDgGeoDataPEImpl.h" #include "RxObjectImpl.h" #include "DgModel.h" #include "DgDatabase.h" #include "Ge/GeMatrix3d.h" #include "Ge/GeExtents2d.h" #include "Ge/avgpc.h" ODRX_CONS_DEFINE_MEMBERS(OdDgGeoDataReprojectionCoordinateTransformerImpl, OdDgGeoDataReprojectionCoordinateTransformer, RXIMPL_CONSTR) ODRX_CONS_DEFINE_MEMBERS(OdDgGeoDataCoordinateConverterImpl, OdDgGeoDataCoordinateConverter, RXIMPL_CONSTR) ODRX_CONS_DEFINE_MEMBERS(OdDgGeoDataExportPEImpl, OdDbBaseGeoDataExportPE, RXIMPL_CONSTR); //======================================================================================================================== // Implementation of OdDgGeoDataCoordinateConverterImpl //======================================================================================================================== OdDgGeoDataCoordinateConverterImpl::OdDgGeoDataCoordinateConverterImpl() { m_dModelToCoordinateSystemUnitsScale = 1.0; m_bApplyHelmertTransform = false; m_bApplyScale = false; } //======================================================================================================================== OdDgGeoDataCoordinateConverterImpl::~OdDgGeoDataCoordinateConverterImpl() { } //======================================================================================================================== OdResult OdDgGeoDataCoordinateConverterImpl::transformXYZPointLL(const OdGePoint3d& xyzPoint, OdGePoint3d& llPoint) const { if( m_pOperation.isNull() ) return eNullObjectPointer; llPoint = xyzPoint; if( m_bApplyScale ) llPoint.transformBy(OdGeMatrix3d::scaling(m_dModelToCoordinateSystemUnitsScale)); if( m_bApplyHelmertTransform ) { llPoint.x = m_geoDataHelmertParams.m_dParamA * llPoint.x - m_geoDataHelmertParams.m_dParamB * llPoint.y + m_geoDataHelmertParams.m_ptOffset.x; llPoint.y = m_geoDataHelmertParams.m_dParamB * llPoint.x + m_geoDataHelmertParams.m_dParamA * llPoint.y + m_geoDataHelmertParams.m_ptOffset.y; llPoint.z = llPoint.z + m_geoDataHelmertParams.m_ptOffset.z; } return m_pOperation->convertToLonLat(llPoint.x, llPoint.y, llPoint.z); } //======================================================================================================================== OdResult OdDgGeoDataCoordinateConverterImpl::transformXYZPointsLL(const OdGePoint3dArray& arrXYZPoints, OdGePoint3dArray& arrLLPoints) const { if (m_pOperation.isNull()) return eNullObjectPointer; arrLLPoints.clear(); arrLLPoints.resize(arrXYZPoints.size()); for(OdUInt32 i = 0; i < arrXYZPoints.size(); i++) { if(transformXYZPointLL(arrXYZPoints[i], arrLLPoints[i]) != eOk ) { arrLLPoints.clear(); return eOutOfRange; } } return eOk; } //======================================================================================================================== OdResult OdDgGeoDataCoordinateConverterImpl::transformLLPointXYZ(const OdGePoint3d& llPoint, OdGePoint3d& xyzPoint) const { if (m_pOperation.isNull()) return eNullObjectPointer; xyzPoint = llPoint; OdResult retVal = m_pOperation->convertFromLonLat(xyzPoint.x, xyzPoint.y, xyzPoint.z); if (m_bApplyHelmertTransform) { double dY = (xyzPoint.y - m_geoDataHelmertParams.m_ptOffset.y)*m_geoDataHelmertParams.m_dParamA - (xyzPoint.x - m_geoDataHelmertParams.m_ptOffset.x)*m_geoDataHelmertParams.m_dParamB; dY = dY / (m_geoDataHelmertParams.m_dParamA*m_geoDataHelmertParams.m_dParamA + m_geoDataHelmertParams.m_dParamB*m_geoDataHelmertParams.m_dParamB); double dX = (xyzPoint.x - m_geoDataHelmertParams.m_ptOffset.x + m_geoDataHelmertParams.m_dParamB * dY) / m_geoDataHelmertParams.m_dParamA; xyzPoint.x = dX; xyzPoint.y = dY; xyzPoint.z = xyzPoint.z - m_geoDataHelmertParams.m_ptOffset.z; } if (m_bApplyScale) xyzPoint.transformBy(OdGeMatrix3d::scaling(1.0 / m_dModelToCoordinateSystemUnitsScale)); return retVal; } //======================================================================================================================== OdResult OdDgGeoDataCoordinateConverterImpl::transformLLPointsXYZ(const OdGePoint3dArray& arrLLPoints, OdGePoint3dArray& arrXYZPoints) const { if (m_pOperation.isNull()) return eNullObjectPointer; arrXYZPoints.clear(); arrXYZPoints.resize(arrXYZPoints.size()); for (OdUInt32 i = 0; i < arrXYZPoints.size(); i++) { if (transformXYZPointLL(arrLLPoints[i], arrXYZPoints[i]) != eOk) { arrXYZPoints.clear(); return eOutOfRange; } } return eOk; } //======================================================================================================================== void OdDgGeoDataCoordinateConverterImpl::init(OdSpatialReference::OdCoordinateReferenceSystemDefinition* pCsData, double dUnitConversionScale, const OdDgGeoDataHelmertParams& transformData, bool bUseTransform) { OdSpatialReference::OdCoordinateReferenceSystemOperation::load(pCsData, m_pOperation); m_dModelToCoordinateSystemUnitsScale = dUnitConversionScale; m_geoDataHelmertParams = transformData; m_bApplyHelmertTransform = bUseTransform; m_bApplyScale = !OdEqual(m_dModelToCoordinateSystemUnitsScale, 1.0); } //======================================================================================================================== // Implementation of OdDgGeoDataReprojectionCoordinateTransformerImpl //======================================================================================================================== OdDgGeoDataReprojectionCoordinateTransformerImpl::OdDgGeoDataReprojectionCoordinateTransformerImpl() { m_dSourceModelToCoordinateSystemUnitsScale = 1.0; m_bSourceApplyHelmertTransform = false; m_bSourceApplyScale = false; m_dDestModelToCoordinateSystemUnitsScale = 1.0; m_bDestApplyHelmertTransform = false; m_bDestApplyScale = false; m_bReprojectEllevation = true; } //======================================================================================================================== OdDgGeoDataReprojectionCoordinateTransformerImpl::~OdDgGeoDataReprojectionCoordinateTransformerImpl() { } //======================================================================================================================== OdResult OdDgGeoDataReprojectionCoordinateTransformerImpl::transformPoint(OdGePoint2d& point) const { OdGePoint3d ptRet(point.x, point.y, 0.0); OdResult retVal = transformPoint(ptRet); point = ptRet.convert2d(); return retVal; } //======================================================================================================================== OdResult OdDgGeoDataReprojectionCoordinateTransformerImpl::transformPoints(OdGePoint2dArray& arrPoints) const { if (m_pSourceOperation.isNull() || m_pTargetOperation.isNull()) return eNullObjectPointer; OdGePoint2dArray arrTmp = arrPoints; for (OdUInt32 i = 0; i < arrPoints.size(); i++) { if (transformPoint(arrPoints[i]) != eOk) { arrPoints = arrTmp; return eOutOfRange; } } return eOk; } //======================================================================================================================== OdResult OdDgGeoDataReprojectionCoordinateTransformerImpl::transformPoint(OdGePoint3d& point) const { if (m_pSourceOperation.isNull() || m_pTargetOperation.isNull()) return eNullObjectPointer; double dZConst = 0.0; OdGePoint3d ptRet = point; if( !m_bReprojectEllevation ) dZConst = ptRet.z; if (m_bSourceApplyScale) ptRet.transformBy(OdGeMatrix3d::scaling(m_dSourceModelToCoordinateSystemUnitsScale)); if (m_bSourceApplyHelmertTransform) { ptRet.x = m_sourceGeoDataHelmertParams.m_dParamA * ptRet.x - m_sourceGeoDataHelmertParams.m_dParamB * ptRet.y + m_sourceGeoDataHelmertParams.m_ptOffset.x; ptRet.y = m_sourceGeoDataHelmertParams.m_dParamB * ptRet.x + m_sourceGeoDataHelmertParams.m_dParamA * ptRet.y + m_sourceGeoDataHelmertParams.m_ptOffset.y; ptRet.z = ptRet.z + m_sourceGeoDataHelmertParams.m_ptOffset.z; } double dStartZ = ptRet.z; m_pSourceOperation->convertToLonLat(ptRet.x, ptRet.y, ptRet.z); if( !m_pDatumShift.isNull() ) { double dZ = ptRet.z; ptRet.z = dStartZ; m_pDatumShift->convert3D(ptRet.x, ptRet.y, ptRet.z); ptRet.z = dZ; } m_pTargetOperation->convertFromLonLat(ptRet.x, ptRet.y, ptRet.z); point = ptRet; if (m_bDestApplyHelmertTransform) { double dX = (point.x - m_destGeoDataHelmertParams.m_ptOffset.x)*m_destGeoDataHelmertParams.m_dParamA + (point.y - m_destGeoDataHelmertParams.m_ptOffset.y)*m_destGeoDataHelmertParams.m_dParamB; dX = dX / (m_destGeoDataHelmertParams.m_dParamA*m_destGeoDataHelmertParams.m_dParamA + m_destGeoDataHelmertParams.m_dParamB*m_destGeoDataHelmertParams.m_dParamB); double dY = (point.y - m_destGeoDataHelmertParams.m_ptOffset.y - m_destGeoDataHelmertParams.m_dParamB * dX) / m_destGeoDataHelmertParams.m_dParamA; point.x = dX; point.y = dY; point.z = point.z - m_destGeoDataHelmertParams.m_ptOffset.z; } if (m_bDestApplyScale) point.transformBy(OdGeMatrix3d::scaling(1.0 / m_dDestModelToCoordinateSystemUnitsScale)); if (!m_bReprojectEllevation) point.z = dZConst; return eOk; } //======================================================================================================================== OdResult OdDgGeoDataReprojectionCoordinateTransformerImpl::transformPoints(OdGePoint3dArray& arrPoints) const { if( m_pSourceOperation.isNull() || m_pTargetOperation.isNull()) return eNullObjectPointer; OdGePoint3dArray arrTmp = arrPoints; for (OdUInt32 i = 0; i < arrPoints.size(); i++) { if (transformPoint(arrPoints[i]) != eOk) { arrPoints = arrTmp; return eOutOfRange; } } return eOk; } //======================================================================================================================== void OdDgGeoDataReprojectionCoordinateTransformerImpl::init(const OdSpatialReference::OdCoordinateReferenceSystemDefinition* pCsDataSource, double dSourceUnitConversionScale, const OdDgGeoDataHelmertParams& sourceTransformData, bool bSourceUseTransform, const OdSpatialReference::OdCoordinateReferenceSystemDefinition* pCsDataDest, double dDestUnitConversionScale, const OdDgGeoDataHelmertParams& destTransformData, bool bDestUseTransform, bool bReprojectEllevation ) { m_dSourceModelToCoordinateSystemUnitsScale = dSourceUnitConversionScale; m_sourceGeoDataHelmertParams = sourceTransformData; m_bSourceApplyHelmertTransform = bSourceUseTransform; m_bSourceApplyScale = !OdEqual(dDestUnitConversionScale,1.0); m_dDestModelToCoordinateSystemUnitsScale = dDestUnitConversionScale; m_destGeoDataHelmertParams = destTransformData; m_bDestApplyHelmertTransform = bDestUseTransform; m_bDestApplyScale = !OdEqual(dSourceUnitConversionScale, 1.0); m_bReprojectEllevation = bReprojectEllevation; OdSpatialReference::OdCoordinateReferenceSystemOperation::load(pCsDataSource, m_pSourceOperation); OdSpatialReference::OdCoordinateReferenceSystemOperation::load(pCsDataDest, m_pTargetOperation); OdString strSourceDatum; OdString strTargetDatum; if( pCsDataSource ) pCsDataSource->getDatum(strSourceDatum); if( pCsDataDest ) pCsDataDest->getDatum(strTargetDatum); OdSpatialReference::OdDatumShift::load(strSourceDatum, strTargetDatum, m_pDatumShift); } //======================================================================================================================== // Implementation of OdDgGeoDataPEImpl //======================================================================================================================== unsigned short getCoordSystemKodeByName(const char* keyName) { // BF CS OdSpatialReference::ProjectionCode retVal = OdSpatialReference::kProjectionCodeUnknown; OdSpatialReference::Helper::getProjectionCode(keyName, retVal); return (unsigned short)(retVal); } //======================================================================================================================== OdDgGeoDataCoordinateSystemPtr createCoordinateSystem(const OdSpatialReference::OdCoordinateReferenceSystemDefinition* pCSDef) { if (!pCSDef) return OdDgGeoDataCoordinateSystemPtr(); OdSpatialReference::ProjectionCode prj_code = OdSpatialReference::kProjectionCodeUnknown; pCSDef->getProjectionCode(prj_code); OdDgGeoDataCoordinateSystem::OdDgGeoDataCoordSystemProjectionType projType = (OdDgGeoDataCoordinateSystem::OdDgGeoDataCoordSystemProjectionType)(prj_code); OdDgGeoDataCoordinateSystemPtr pRet = OdDgGeoDataCoordinateSystem::createObject((OdDgGeoDataCoordinateSystem::OdDgGeoDataCoordSystemProjectionType)(prj_code)); if( !pRet.isNull() ) { double dLongMin = 0.0; double dLongMax = 0.0; double dLatMin = 0.0; double dLatMax = 0.0; pCSDef->getLonMin(dLongMin); pCSDef->getLatMin(dLatMin); pCSDef->getLonMax(dLongMax); pCSDef->getLatMax(dLatMax); OdGePoint2d ptMin(dLongMin, dLatMin); OdGePoint2d ptMax(dLongMax, dLatMax); OdGeExtents2d extGeo(ptMin, ptMax); OdString strKeyName; OdString strDesc; OdString strSource; OdString strUnits; OdString strGroup; pCSDef->getCode(strKeyName); pCSDef->getDescription(strDesc); pCSDef->getSource(strSource); pCSDef->getUnits(strUnits); pCSDef->getGroup(strGroup); pRet->setName(strKeyName); pRet->setDescription(strDesc); pRet->setSource(strSource); pRet->setUnits(strUnits); pRet->setGeodeticExtents(extGeo); pRet->setGroupName(strGroup); OdDgGeoDataCoordinateSystemCSMapsData csData; pCSDef->getOriginLatitude(csData.m_dOrgLatitude); pCSDef->getOriginLongitude(csData.m_dOrgLongitude); pCSDef->getScaleReduction(csData.m_dScaleReduction); pCSDef->getOffsetX(csData.m_dFalseEasting); pCSDef->getOffsetY(csData.m_dFalseNorthing); pCSDef->getQuadrant(csData.m_iQuadrant); OdUInt32 iParamMax = 0; pCSDef->getProjectionParameterCount(iParamMax); for (OdUInt32 iParam = 0; iParam < iParamMax; iParam++) pCSDef->getProjectionParameter(iParam, csData.m_dParams[iParam]); switch (projType) { case OdDgGeoDataCoordinateSystem::kGeographic : { if( OdZero(csData.m_dParams[0]) ) csData.m_dParams[0] = ptMin.x; if( OdZero(csData.m_dParams[1]) ) csData.m_dParams[1] = ptMax.x; } break; case OdDgGeoDataCoordinateSystem::kUniversalTransverseMercator: case OdDgGeoDataCoordinateSystem::kUniversalTransverseMercatorBF: { csData.m_uRegion = (OdUInt32)(csData.m_dParams[0]); csData.m_iHemisphere = (OdInt32)(csData.m_dParams[1]); } break; case OdDgGeoDataCoordinateSystem::kDanishSystemNoKMS: case OdDgGeoDataCoordinateSystem::kDanishSystemKMS1999: case OdDgGeoDataCoordinateSystem::kDanishSystemKMS2001: { csData.m_uRegion = (OdUInt32)(csData.m_dParams[0]); } break; } pRet->setFromExternalData(csData); } return pRet; } //======================================================================================================================== OdDgGeoDataEllipsoid createEllipsoid(const OdSpatialReference::OdEllipsoidDefinition* pEllDef) { OdDgGeoDataEllipsoid ellipsoid; if (!pEllDef) return ellipsoid; OdString strCode; OdString strDesc; OdString strSource; double dERadius = 0.0; double dPRadius = 0.0; double dEccent = 1.0; pEllDef->getCode(strCode); pEllDef->getDescription(strDesc); pEllDef->getSource(strSource); pEllDef->getEquatorialRadius(dERadius); pEllDef->getPolarRadius(dPRadius); pEllDef->getEccentricity(dEccent); ellipsoid.setName(strCode); ellipsoid.setDescription(strDesc); ellipsoid.setSource(strSource); ellipsoid.setEquatorialRadius(dERadius); ellipsoid.setPolarRadius(dPRadius); ellipsoid.setEccentricity(dEccent); return ellipsoid; } //======================================================================================================================== OdResult createEllipsoid(const OdString& ellipKey, OdDgGeoDataEllipsoid& ellipsoid) { OdSpatialReference::OdEllipsoidDefinitionPtr pEllipsoid; OdSpatialReference::OdEllipsoidDefinition::load(ellipKey, pEllipsoid); if( !pEllipsoid.isNull() ) { ellipsoid = createEllipsoid(pEllipsoid); return eOk; } return eInvalidInput; } //======================================================================================================================== OdDgGeoDataDatum createDatum(const OdSpatialReference::OdDatumDefinition* pCSDatum) { OdDgGeoDataDatum datum; if (!pCSDatum) return datum; OdString strKey; OdString strDesc; OdString strSource; OdSpatialReference::DatumCalculationTechnique uConversionMethod = OdSpatialReference::kDatumCalcTechNone; OdGePoint3d ptOffset; double dScale; OdGePoint3d ptRot; pCSDatum->getCode(strKey); pCSDatum->getDescription(strDesc); pCSDatum->getSource(strSource); pCSDatum->getDatumCalculationTechnique(uConversionMethod); pCSDatum->getOffset(ptOffset.x, ptOffset.y, ptOffset.z); pCSDatum->getScale(dScale); pCSDatum->getRotationAngles(ptRot.x, ptRot.y, ptRot.z); datum.setName(strKey); datum.setDescription(strDesc); datum.setSource(strSource); datum.setDatumConversionMethod((OdDgGeoDataDatum::OdDgGeoDataConversionMethod)(uConversionMethod)); datum.setOffset(ptOffset); if (OdZero(dScale)) datum.setScale(1.0); else datum.setScale(dScale); datum.setXRotation(ptRot.x); datum.setYRotation(ptRot.y); datum.setZRotation(ptRot.z); return datum; } //======================================================================================================================== OdResult createDatum(const OdString& datumKey, OdDgGeoDataDatum& datum, OdDgGeoDataEllipsoid& ellipsoid ) { OdSpatialReference::OdDatumDefinitionPtr pCSDatum; OdSpatialReference::OdDatumDefinition::load(datumKey, pCSDatum); if( !pCSDatum.isNull() ) { OdSpatialReference::OdEllipsoidDefinitionPtr pEllipsoid; pCSDatum->getEllipsoidDefinition(pEllipsoid); datum = createDatum(pCSDatum); ellipsoid = createEllipsoid(pEllipsoid); return eOk; } return eInvalidInput; } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::getGeoDataByName(const OdString& strName, OdDgGeoDataCoordinateSystemPtr& pCoordSystem, OdDgGeoDataDatum& datum, OdDgGeoDataEllipsoid& ellipsoid) { OdString strCsName = strName; strCsName.trimLeft(); strCsName.trimRight(); if (!strCsName.isEmpty()) { OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCsData; OdSpatialReference::FormatConverter::getCoordinateReferenceSystemDefinition(strCsName, pCsData); if( !pCsData.isNull() ) { OdString strDatum; OdString strEllipsoid; pCsData->getDatum(strDatum); pCsData->getEllipsoid(strEllipsoid); pCoordSystem = createCoordinateSystem(pCsData); createDatum(strDatum, datum, ellipsoid); if( datum.getName().isEmpty() ) createEllipsoid(strEllipsoid, ellipsoid); } } return !pCoordSystem.isNull() ? eOk : eInvalidInput; } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::getGeoDataDatumByName(const OdString& strDatumName, OdDgGeoDataDatum& datum, OdDgGeoDataEllipsoid& ellipsoid) { OdString strUpdatedDatum(strDatumName); if (strUpdatedDatum.getLength() > 24) strUpdatedDatum = strUpdatedDatum.left(24); return createDatum(strUpdatedDatum, datum, ellipsoid); } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::getGeoDataEllipsoidByName(const OdString& strEllipsoidName, OdDgGeoDataEllipsoid& ellipsoid) { OdString strUpdatedEll(strEllipsoidName); if (strUpdatedEll.getLength() > 24) strUpdatedEll = strUpdatedEll.left(24); return createEllipsoid(strUpdatedEll, ellipsoid); } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::createAll(const OdGePoint3d& geoPt, OdArray& allCoordSys) { allCoordSys.clear(); OdSpatialReference::OdCoordinateReferenceSystemDefinitionArray arrCSRefs; OdSpatialReference::OdCoordinateReferenceSystemDefinition::loadAll(arrCSRefs); int csCount = arrCSRefs.size(); allCoordSys.reserve(csCount); for (int i = 0; i < csCount; ++i) { OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCS = arrCSRefs[i]; OdDgGeoDataCoordinateSystemPtr pObj; OdDgGeoDataDatum datum; OdDgGeoDataEllipsoid ellipsoid; if (pCS.isNull()) continue; OdString strKey; pCS->getCode(strKey); if( getGeoDataByName(strKey, pObj, datum, ellipsoid) != eOk ) continue; if( !pObj.isNull() && pObj->getProjectionType() != OdDgGeoDataCoordinateSystem::kGeographic ) { OdGeExtents2d ext = pObj->getGeodeticExtents(); //even if one of extents ordinate is invalid we must check second bool bAppendCS = true; if (ext.minPoint().x <= ext.maxPoint().x) { bAppendCS &= (geoPt.x >= ext.minPoint().x && geoPt.x <= ext.maxPoint().x); } if (ext.minPoint().y <= ext.maxPoint().y) { bAppendCS &= (geoPt.y >= ext.minPoint().y && geoPt.y <= ext.maxPoint().y); } if (bAppendCS) { allCoordSys.append(pObj); } } } return eOk; } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::createAll(OdArray& allCoordSys, const OdDgGeoDataCoordinateSystemCategory* pCategory) { allCoordSys.clear(); if( pCategory == NULL ) { OdSpatialReference::OdCoordinateReferenceSystemDefinitionArray arrCSRefs; OdSpatialReference::OdCoordinateReferenceSystemDefinition::loadAll(arrCSRefs); int csCount = arrCSRefs.size(); allCoordSys.reserve(csCount); for (int i = 0; i < csCount; ++i) { OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCS = arrCSRefs[i]; if (pCS.isNull()) continue; OdDgGeoDataCoordinateSystemPtr pObj; OdDgGeoDataDatum datum; OdDgGeoDataEllipsoid ellipsoid; OdString strKey; pCS->getCode(strKey); if (getGeoDataByName(strKey, pObj, datum, ellipsoid) != eOk) continue; allCoordSys.append(pObj); } } else { int csCount = 0; pCategory->getNumOfCoordinateSystem(csCount); allCoordSys.reserve(csCount); for (int csIndex = 0; csIndex < csCount; ++csIndex) { OdDgGeoDataCoordinateSystemPtr pCs; pCategory->getCoordinateSystemAt(csIndex, pCs); allCoordSys.append(pCs); } } return eOk; } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::transformGeoPointByDatum(const OdString& strDatumNameFrom, const OdString& strDatumNameTo, const OdGePoint3d& ptGeoPoint, OdGePoint3d& ptResult) { OdSpatialReference::OdDatumShiftPtr pDatumShift; OdSpatialReference::OdDatumShift::load(strDatumNameFrom, strDatumNameTo, pDatumShift); OdResult retVal = eOk; ptResult = ptGeoPoint; if( !pDatumShift.isNull() ) { double ptLLA[3] = { ptGeoPoint.x * 180 / OdaPI, ptGeoPoint.y * 180 / OdaPI, ptGeoPoint.z }; double dZ = ptLLA[2]; //store Z to reassign pDatumShift->convert3D(ptLLA[0], ptLLA[1], ptLLA[2]); ptResult.x = ptLLA[0] / 180.0 * OdaPI; ptResult.y = ptLLA[1] / 180.0 * OdaPI; ptResult.z = dZ; } return eOk; } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::createGeoPointFromCS(const OdString& strCSFrom, const OdString& strDatumNameTo, const OdGePoint3d& ptXYZPoint, OdGePoint3d& ptResult) { if( strCSFrom.isEmpty() ) return eNotApplicable; OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCSFrom; OdSpatialReference::OdCoordinateReferenceSystemDefinition::load(strCSFrom, pCSFrom); if (pCSFrom.isNull()) return eNotApplicable; double ptLLA[3] = { ptXYZPoint.x, ptXYZPoint.y, ptXYZPoint.z }; OdSpatialReference::OdCoordinateReferenceSystemOperationPtr pOperation; OdSpatialReference::OdCoordinateReferenceSystemOperation::load(strCSFrom, pOperation); OdString strSourceDatum; pCSFrom->getDatum(strSourceDatum); OdSpatialReference::OdDatumShiftPtr pDatumShift; OdSpatialReference::OdDatumShift::load(strSourceDatum, strDatumNameTo, pDatumShift); pOperation->convertToLonLat(ptLLA[0], ptLLA[1], ptLLA[2]); double dZ = ptLLA[2]; //store Z to reassign if( !pDatumShift.isNull()) pDatumShift->convert3D(ptLLA[0], ptLLA[1], ptLLA[2]); ptResult.x = ptLLA[0] / 180.0 * OdaPI; ptResult.y = ptLLA[1] / 180.0 * OdaPI; ptResult.z = dZ; return eOk; } //======================================================================================================================== OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr createCSDataByDgnCoordinateSystem(const OdDgGeoDataInfo* pGeoData) { OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCsDef; if (pGeoData->getPlacemarkSourceFlag() && !pGeoData->getCoordinateSystem().isNull() && (pGeoData->getCoordinateSystem()->getProjectionType() == OdDgGeoDataCoordinateSystem::kAzimuthalEqualArea)) { OdSpatialReference::OdCoordinateReferenceSystemDefinition::load(L"ETRS89.Europe/EqArea", pCsDef); if( !pCsDef.isNull() ) { OdDgAzimuthalEqualAreaCoordinateSystemPtr pDgCoordSystem = pGeoData->getCoordinateSystem(); pCsDef->setUnitCode((OdSpatialReference::UnitCode)(pDgCoordSystem->getUnits())); pCsDef->setOriginLongitude(pDgCoordSystem->getOriginLongitude() * 180 / OdaPI); pCsDef->setOriginLatitude(pDgCoordSystem->getOriginLatitude() * 180 / OdaPI); pCsDef->setProjectionParameter(0, pDgCoordSystem->getYAxisAzimuth() * 180 / OdaPI); pCsDef->setOffsetX(pDgCoordSystem->getFalseEasting()); pCsDef->setOffsetY(pDgCoordSystem->getFalseNorthing()); pCsDef->setScaleReduction(1.0); pCsDef->setQuadrant((short)pDgCoordSystem->getQuadrant()); OdGeExtents2d extGeo = pDgCoordSystem->getGeodeticExtents(); pCsDef->setXYBounds(extGeo.minPoint().x * 180 / OdaPI, extGeo.minPoint().y * 180 / OdaPI, extGeo.maxPoint().x * 180 / OdaPI, extGeo.maxPoint().y * 180 / OdaPI); } } else { OdSpatialReference::OdCoordinateReferenceSystemDefinition::load(pGeoData->getCoordinateSystem()->getName(), pCsDef); OdDgGeoDataCoordinateSystemPtr pDgCoordSystem = pGeoData->getCoordinateSystem(); if (!pCsDef.isNull() && !pDgCoordSystem.isNull()) { pCsDef->setCode(pDgCoordSystem->getName()); pCsDef->setGroup(pDgCoordSystem->getGroupName()); pCsDef->setDescription(pDgCoordSystem->getDescription()); pCsDef->setSource(pDgCoordSystem->getSource()); pCsDef->setProjection(OdDgGeoDataCoordinateSystem::getShortProjectionString(pDgCoordSystem->getProjectionType())); pCsDef->setOriginLongitude(0.0); pCsDef->setOriginLatitude(0.0); pCsDef->setMapScale(1.0); //pCsDef->hgt_zz = 0; //pCsDef->scale = 1.0; //pCsDef->order = 0; //pCsDef->zones = 0; //pCsDef->protect = 1; //pCsDef->epsg_qd = 1; //pCsDef->srid = 0; //pCsDef->epsgNbr = 0; //pCsDef->wktFlvr = 0; pCsDef->setUnitCode((OdSpatialReference::UnitCode)(pDgCoordSystem->getUnits())); pCsDef->setScaleReduction(1.0); OdDgGeoDataCoordinateSystemCSMapsData externalData = pDgCoordSystem->getExternalData(); pCsDef->setOriginLatitude(externalData.m_dOrgLatitude); pCsDef->setOriginLongitude(externalData.m_dOrgLongitude); pCsDef->setOffsetX(externalData.m_dFalseEasting); pCsDef->setOffsetY(externalData.m_dFalseNorthing); pCsDef->setScaleReduction(externalData.m_dScaleReduction); pCsDef->setQuadrant((short)externalData.m_iQuadrant); for (OdUInt32 k = 0; k < 24; k++) pCsDef->setProjectionParameter(k, externalData.m_dParams[k]); switch (pDgCoordSystem->getProjectionType()) { case OdDgGeoDataCoordinateSystem::kUniversalTransverseMercatorBF: case OdDgGeoDataCoordinateSystem::kUniversalTransverseMercator: pCsDef->setProjectionParameter(1, externalData.m_iHemisphere); case OdDgGeoDataCoordinateSystem::kDanishSystemNoKMS: case OdDgGeoDataCoordinateSystem::kDanishSystemKMS1999: case OdDgGeoDataCoordinateSystem::kDanishSystemKMS2001: pCsDef->setProjectionParameter(0, externalData.m_uRegion); } OdGeExtents2d extGeo = pDgCoordSystem->getGeodeticExtents(); pCsDef->setXYBounds(extGeo.minPoint().x * 180 / OdaPI, extGeo.minPoint().y * 180 / OdaPI, extGeo.maxPoint().x * 180 / OdaPI, extGeo.maxPoint().y * 180 / OdaPI); } } if (pCsDef) { OdString strDatum( pGeoData->getDatum().getName() ); OdString strEllepsoid( pGeoData->getEllipsoid().getName() ); OdSpatialReference::OdDatumDefinitionPtr pCSDatum; pCsDef->getDatumDefinition(pCSDatum); OdString strCSDatumName; if( !pCSDatum.isNull() ) pCSDatum->getCode(strCSDatumName); if( !strDatum.isEmpty() && (strCSDatumName != strDatum) ) { if (strDatum.getLength() > 24) strDatum = strDatum.left(24); OdSpatialReference::OdDatumDefinitionPtr pDatum; OdSpatialReference::OdDatumDefinition::load(strDatum, pDatum); if( !pDatum.isNull() ) { if (strEllepsoid.isEmpty()) { OdSpatialReference::OdEllipsoidDefinitionPtr pDatumEllipsoid; pDatum->getEllipsoidDefinition(pDatumEllipsoid); if (!pDatumEllipsoid.isNull()) pCsDef->setEllipsoidDefinition(pDatumEllipsoid); } else pCsDef->setEllipsoid(strEllepsoid); pCsDef->setDatumDefinition(pDatum); } } OdString strCSEllipsoid; pCsDef->getEllipsoid(strCSEllipsoid); if( !strEllepsoid.isEmpty() && (strEllepsoid != strCSEllipsoid) ) { if (strEllepsoid.getLength() > 24) strEllepsoid = strEllepsoid.left(24); OdSpatialReference::OdDatumDefinitionPtr pDatum; pCsDef->getDatumDefinition(pDatum); OdSpatialReference::OdEllipsoidDefinitionPtr pCurEllipsoid; OdSpatialReference::OdEllipsoidDefinition::load(strEllepsoid, pCurEllipsoid); if (!pCurEllipsoid.isNull()) { pDatum->setEllipsoidDefinition(pCurEllipsoid); pCsDef->setEllipsoidDefinition(pCurEllipsoid); pCsDef->setDatumDefinition(pDatum); } } } return pCsDef; } //======================================================================================================================== OdDgGeoDataReprojectionCoordinateTransformerPtr OdDgGeoDataPEImpl::createReprojectionTransformer(const OdDgGeoDataInfo* pGeoDataFrom, const OdDgGeoDataInfo* pGeoDataTo, double dModelScale, bool bReprojectEllevation ) { if(!pGeoDataFrom || !pGeoDataTo) return OdDgGeoDataReprojectionCoordinateTransformerPtr(); OdDgGeoDataReprojectionCoordinateTransformerPtr pRet = OdRxObjectImpl::createObject(); OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCsSourceData = createCSDataByDgnCoordinateSystem(pGeoDataFrom); if (!pCsSourceData) return OdDgGeoDataReprojectionCoordinateTransformerPtr(); OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCsDestData = createCSDataByDgnCoordinateSystem(pGeoDataTo); if (!pCsDestData) return OdDgGeoDataReprojectionCoordinateTransformerPtr(); double dSourceUnitConversionScale = 1.0; double dDestUnitConversionScale = 1.0; double dSourceUS = 1.0; double dDestUS = 1.0; pCsSourceData->getUnitScale(dSourceUS); pCsDestData->getUnitScale(dDestUS); dSourceUnitConversionScale = dModelScale / dSourceUS; dDestUnitConversionScale = dModelScale / dDestUS; OdDgGeoDataReprojectionCoordinateTransformerImpl* pRetImpl = (OdDgGeoDataReprojectionCoordinateTransformerImpl*)(pRet.get()); pRetImpl->init(pCsSourceData, dSourceUnitConversionScale, pGeoDataFrom->getHelmertParams(), pGeoDataFrom->getLocalTransformType() == OdDgGeoDataInfo::kHelmertTransform, pCsDestData, dDestUnitConversionScale, pGeoDataTo->getHelmertParams(), pGeoDataTo->getLocalTransformType() == OdDgGeoDataInfo::kHelmertTransform, bReprojectEllevation); return pRet; } //======================================================================================================================== OdDgGeoDataCoordinateConverterPtr OdDgGeoDataPEImpl::createGeoDataCoordinateConvertor(const OdDgGeoDataInfo* pGeoData, const OdDgModel* pModel) { OdDgGeoDataCoordinateConverterPtr pRet = OdRxObjectImpl::createObject(); OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCsData = createCSDataByDgnCoordinateSystem(pGeoData); if( !pCsData ) return OdDgGeoDataCoordinateConverterPtr(); double dUnitConversionScale = 1.0; if( pModel ) { double dUnitScale = 1.0; pCsData->getUnitScale(dUnitScale); OdDgModel::UnitDescription modelUnits; pModel->getMasterUnit(modelUnits); dUnitConversionScale = modelUnits.m_denominator / modelUnits.m_numerator / dUnitScale; } OdDgGeoDataCoordinateConverterImpl* pRetImpl = (OdDgGeoDataCoordinateConverterImpl*)(pRet.get()); pRetImpl->init(pCsData, dUnitConversionScale, pGeoData->getHelmertParams(), pGeoData->getLocalTransformType() == OdDgGeoDataInfo::kHelmertTransform); return pRet; } //======================================================================================================================== void csUnitScaleToString(OdString & sUnitScale, double dUnitScale) { if (dUnitScale > 1e-4) { sUnitScale.format(L"%lf", dUnitScale); sUnitScale.trimRight('0'); sUnitScale.trimRight('.'); if (sUnitScale.isEmpty()) { sUnitScale = L"0"; } } else if (dUnitScale > 1e-12) { sUnitScale.format(L"%lE", dUnitScale); } else { sUnitScale = L"0"; } } //======================================================================================================================== OdResult OdDgGeoDataPEImpl::getWktRepresentation(const OdDgGeoDataInfo* pGeoData, OdString& strWkt) const { OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCsData = createCSDataByDgnCoordinateSystem(pGeoData); if( pCsData ) return OdSpatialReference::FormatConverter::definitionToWkt(pCsData, OdSpatialReference::kWktFlvrOgc, strWkt); return eNotApplicable; } //======================================================================================================================== // Implementation of OdDgGeoDataCoordinateSystemCategoryPEImpl //======================================================================================================================== OdResult OdDgGeoDataCoordinateSystemCategoryPEImpl::getNumOfCoordinateSystem(int& num, const OdString& strCategoryId ) const { OdSpatialReference::OdCategoryDefinitionPtr pCategory; OdSpatialReference::OdCategoryDefinition::load(strCategoryId, pCategory); if( pCategory.isNull() ) { return eNullPtr; } OdUInt32 uCount = 0; OdResult status = pCategory->getCount(uCount); num = (int)(uCount); return status; } //======================================================================================================================== OdResult OdDgGeoDataCoordinateSystemCategoryPEImpl::getCoordinateSystemAt(int index, const OdString& strCategoryId, OdDgGeoDataCoordinateSystemPtr& pCoordSys) const { OdSpatialReference::OdCategoryDefinitionPtr pCategory; OdSpatialReference::OdCategoryDefinition::load(strCategoryId, pCategory); if (pCategory.isNull()) { return eNullPtr; } OdString sName; OdResult status = pCategory->getAt(index, sName); if (eOk != status) { return status; } if( !sName.isEmpty() ) { OdSpatialReference::OdCoordinateReferenceSystemDefinitionPtr pCsData; OdSpatialReference::OdCoordinateReferenceSystemDefinition::load(sName, pCsData); if( !pCsData.isNull() ) { pCoordSys = createCoordinateSystem(pCsData); return eOk; } } return eInvalidCategory; } //======================================================================================================================== OdResult OdDgGeoDataCoordinateSystemCategoryPEImpl::createAll(OdArray& allCategories) { OdSpatialReference::OdCategoryDefinitionArray arrCD; OdResult status = OdSpatialReference::OdCategoryDefinition::loadAll(arrCD); if (eOk != status) { return eNotApplicable; } allCategories.reserve(arrCD.size()); for (OdUInt32 i = 0; i < arrCD.size(); ++i) { OdString strCategoryName; if (arrCD[i]->getCode(strCategoryName) == eOk) { OdDgGeoDataCoordinateSystemCategoryPtr pCategory = OdDgGeoDataCoordinateSystemCategory::createObject(strCategoryName); allCategories.append(pCategory.get()); } } return eOk; } //======================================================================================================================== OdResult OdDgGeoDataExportPEImpl::getGeoDataParams(const OdDbBaseDatabase* pDb, OdString& sWktDef, int& type, int& epsgCode) const { if(!pDb) return eNullPtr; const OdDgDatabase* pDatabase = dynamic_cast(pDb); if(!pDatabase) return eNullPtr; OdDgModelPtr pModel = pDatabase->getActiveModelId().safeOpenObject(); if(pModel.isNull()) return eNullPtr; OdDgGeoDataInfoPtr pGeo = pModel->getGeoData(OdDg::kForRead); if(pGeo.isNull()) return eNullPtr; OdResult res = pGeo->getWktRepresentation(sWktDef); if(res != eOk || sWktDef.isEmpty()) return eInvalidInput; OdDgGeoDataCoordinateSystemPtr pCs = pGeo->getCoordinateSystem(); if(!pCs.isNull()) type = (int)pCs->getProjectionType(); return eOk; } //convert drawing coordinates to geo coordinates or opposite depending on bToLLA flag OdResult convertLLA(const OdDgGeoDataCoordinateConverterPtr& pGeoDataConvertor, const OdGePoint2dArray& from, OdGePoint2dArray& to, bool bToLLA) { if(pGeoDataConvertor.isNull()) return eNullPtr; if(from.isEmpty()) return eInvalidInput; OdGePoint3d ptBuf; OdResult res = eOk; to.clear(); to.resize(from.size()); for(OdUInt32 i = 0; i < from.size(); ++i) { if(bToLLA) res = pGeoDataConvertor->transformXYZPointLL(OdGePoint3d(from[i].x, from[i].y, 0.), ptBuf); else res = pGeoDataConvertor->transformLLPointXYZ(OdGePoint3d(from[i].x, from[i].y, 0.), ptBuf); if(res != eOk) break; to[i] = ptBuf.convert2d(); } return res; } bool intersectContours(const OdGePoint2dArray& geoPoints, const OdGePoint2dArray& clipPoints, OdGePoint2dArray& outPoints) { gpc_polygon gpMap, gpViewport, gpResult; gpMap.num_contours = 1; gpMap.hole = 0; gpMap.contour = ::gpc_alloc(1); gpMap.contour->num_vertices = geoPoints.size(); gpMap.contour->vertex = ::gpc_alloc(geoPoints.size());; for(OdUInt32 i = 0; i < geoPoints.size(); i++) { gpMap.contour[0].vertex[i].x = geoPoints[i].x; gpMap.contour[0].vertex[i].y = geoPoints[i].y; } gpViewport.num_contours = 1; gpViewport.hole = 0; gpViewport.contour = ::gpc_alloc(1); gpViewport.contour->num_vertices = clipPoints.size(); gpViewport.contour->vertex = ::gpc_alloc(clipPoints.size());; for(OdUInt32 i = 0; i < clipPoints.size(); i++) { gpViewport.contour[0].vertex[i].x = clipPoints[i].x; gpViewport.contour[0].vertex[i].y = clipPoints[i].y; } gpResult.hole = NULL; gpResult.contour = NULL; gpResult.num_contours = 0; ::gpc_polygon_clip(GPC_INT, &gpMap, &gpViewport, &gpResult); for(int j = 0; j < gpResult.num_contours; j++) { for(int k = 0; k < gpResult.contour[j].num_vertices; k++) outPoints.push_back(OdGePoint2d(gpResult.contour[j].vertex[k].x, gpResult.contour[j].vertex[k].y)); } gpc_free_polygon(&gpMap); gpc_free_polygon(&gpViewport); gpc_free_polygon(&gpResult); return true; } OdResult OdDgGeoDataExportPEImpl::getGeoExtents(const OdDbBaseDatabase* pDb, OdGePoint2dArray& geoPoints, OdGePoint2dArray& clipPoints) const { const OdDgDatabase* pDatabase = dynamic_cast(pDb); if(!pDatabase) return eNullPtr; OdDgModelPtr pModel = pDatabase->getActiveModelId().safeOpenObject(); if(pModel.isNull()) return eNullPtr; OdDgGeoDataInfoPtr pGeo = pModel->getGeoData(OdDg::kForRead); if(pGeo.isNull()) return eNullPtr; OdDgGeoDataPEPtr pGeoDataPE = OdDgGeoDataPE::cast(pGeo.get()); if(pGeoDataPE.isNull()) return eNullPtr; OdDgGeoDataCoordinateConverterPtr pGeoDataConvertor = pGeoDataPE->createGeoDataCoordinateConvertor(pGeo, pModel); if(pGeoDataConvertor.isNull()) return eNullPtr; if(clipPoints.isEmpty() || clipPoints.size() && clipPoints.size() != 4) //extents of viewport are expected here return eInvalidInput; OdResult res = convertLLA(pGeoDataConvertor, clipPoints, geoPoints, true); if(res != eOk) { clipPoints.clear(); return res; } OdGePoint2d ptMin; OdGePoint2d ptMax; ptMin.x = -180;/*OdBingMaps::MinLongitude*/ ptMin.y = -85.05112878;/*OdBingMaps::MinLatitude*/ ptMax.x = 180;/*OdBingMaps::MaxLongitude*/ ptMax.y = 85.05112878;/*OdBingMaps::MaxLatitude*/ OdGePoint2dArray mapPoints; mapPoints.resize(4); mapPoints[0].set(ptMin.x, ptMin.y); mapPoints[1].set(ptMax.x, ptMin.y); mapPoints[2].set(ptMax.x, ptMax.y); mapPoints[3].set(ptMin.x, ptMax.y); OdGePoint2dArray intersectedPoints; try { if(!intersectContours(mapPoints, geoPoints, intersectedPoints) || intersectedPoints.size() < 3) { geoPoints.clear(); clipPoints.clear(); return eInvalidInput; } } catch(...) { geoPoints.clear(); clipPoints.clear(); return eInvalidInput; } geoPoints = intersectedPoints; res = convertLLA(pGeoDataConvertor, intersectedPoints, clipPoints, false); if(res != eOk) { geoPoints.clear(); clipPoints.clear(); return res; } return eOk; }