Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: OpenGIS Simple Features Reference Implementation 4 : * Purpose: Implements Open FileGDB OGR driver. 5 : * Author: Even Rouault, <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #ifndef FILEGDB_COORDPREC_WRITE_H 14 : #define FILEGDB_COORDPREC_WRITE_H 15 : 16 : #include "ogr_spatialref.h" 17 : #include "ogr_geomcoordinateprecision.h" 18 : 19 : /*************************************************************************/ 20 : /* GDBGridSettingsFromOGR() */ 21 : /*************************************************************************/ 22 : 23 : /** Compute grid settings from coordinate precision of source geometry field 24 : * and layer creation options. 25 : * The "FileGeodatabase" key of the output oFormatSpecificOptions will be 26 : * set with the values. 27 : */ 28 : static OGRGeomCoordinatePrecision 29 333 : GDBGridSettingsFromOGR(const OGRGeomFieldDefn *poSrcGeomFieldDefn, 30 : CSLConstList aosLayerCreationOptions) 31 : { 32 333 : const auto poSRS = poSrcGeomFieldDefn->GetSpatialRef(); 33 : 34 : double dfXOrigin; 35 : double dfYOrigin; 36 : double dfXYScale; 37 333 : double dfZOrigin = -100000; 38 333 : double dfMOrigin = -100000; 39 333 : double dfMScale = 10000; 40 : double dfXYTolerance; 41 : // default tolerance is 1mm in the units of the coordinate system 42 : double dfZTolerance = 43 333 : 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("VERT_CS") : 1.0); 44 333 : double dfZScale = 1 / dfZTolerance * 10; 45 333 : double dfMTolerance = 0.001; 46 : 47 333 : if (poSRS == nullptr || poSRS->IsProjected()) 48 : { 49 : // default tolerance is 1mm in the units of the coordinate system 50 196 : dfXYTolerance = 51 196 : 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("PROJCS") : 1.0); 52 : // default scale is 10x the tolerance 53 196 : dfXYScale = 1 / dfXYTolerance * 10; 54 : 55 : // Ideally we would use the same X/Y origins as ArcGIS, but we need 56 : // the algorithm they use. 57 196 : dfXOrigin = -2147483647; 58 196 : dfYOrigin = -2147483647; 59 : } 60 : else 61 : { 62 137 : dfXOrigin = -400; 63 137 : dfYOrigin = -400; 64 137 : dfXYScale = 1000000000; 65 137 : dfXYTolerance = 0.000000008983153; 66 : } 67 : 68 333 : const auto &oSrcCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision(); 69 : 70 333 : if (oSrcCoordPrec.dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN) 71 : { 72 10 : dfXYScale = 1.0 / oSrcCoordPrec.dfXYResolution; 73 10 : dfXYTolerance = oSrcCoordPrec.dfXYResolution / 10.0; 74 : } 75 : 76 333 : if (oSrcCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN) 77 : { 78 10 : dfZScale = 1.0 / oSrcCoordPrec.dfZResolution; 79 10 : dfZTolerance = oSrcCoordPrec.dfZResolution / 10.0; 80 : } 81 : 82 333 : if (oSrcCoordPrec.dfMResolution != OGRGeomCoordinatePrecision::UNKNOWN) 83 : { 84 10 : dfMScale = 1.0 / oSrcCoordPrec.dfMResolution; 85 10 : dfMTolerance = oSrcCoordPrec.dfMResolution / 10.0; 86 : } 87 : 88 333 : const char *const paramNames[] = { 89 : "XOrigin", "YOrigin", "XYScale", "ZOrigin", "ZScale", 90 : "MOrigin", "MScale", "XYTolerance", "ZTolerance", "MTolerance"}; 91 : double *pGridValues[] = { 92 : &dfXOrigin, &dfYOrigin, &dfXYScale, &dfZOrigin, &dfZScale, 93 333 : &dfMOrigin, &dfMScale, &dfXYTolerance, &dfZTolerance, &dfMTolerance}; 94 : static_assert(CPL_ARRAYSIZE(paramNames) == CPL_ARRAYSIZE(pGridValues)); 95 : 96 : const auto oIterCoordPrecFileGeodatabase = 97 333 : oSrcCoordPrec.oFormatSpecificOptions.find("FileGeodatabase"); 98 : 99 : /* 100 : * Use coordinate precision layer creation options in priority. 101 : * Otherwise use the settings from the "FileGeodatabase" entry in 102 : * oSrcCoordPrec.oFormatSpecificOptions when set. 103 : * Otherwise, use above defaults. 104 : */ 105 666 : CPLStringList aosCoordinatePrecisionOptions; 106 3663 : for (size_t i = 0; i < CPL_ARRAYSIZE(paramNames); i++) 107 : { 108 3330 : const char *pszVal = CSLFetchNameValueDef( 109 3330 : aosLayerCreationOptions, paramNames[i], 110 3330 : oIterCoordPrecFileGeodatabase != 111 3330 : oSrcCoordPrec.oFormatSpecificOptions.end() 112 160 : ? oIterCoordPrecFileGeodatabase->second.FetchNameValue( 113 80 : paramNames[i]) 114 : : nullptr); 115 3330 : if (pszVal) 116 : { 117 292 : *(pGridValues[i]) = CPLAtof(pszVal); 118 292 : if (strstr(paramNames[i], "Scale") || 119 215 : strstr(paramNames[i], "Tolerance")) 120 : { 121 154 : if (*(pGridValues[i]) <= 0) 122 : { 123 0 : CPLError(CE_Warning, CPLE_AppDefined, 124 : "%s should be strictly greater than zero", 125 0 : paramNames[i]); 126 : } 127 : } 128 : } 129 : aosCoordinatePrecisionOptions.SetNameValue( 130 3330 : paramNames[i], CPLSPrintf("%.15g", *(pGridValues[i]))); 131 : } 132 : 133 333 : OGRGeomCoordinatePrecision oCoordPrec; 134 333 : oCoordPrec.dfXYResolution = 1.0 / dfXYScale; 135 333 : oCoordPrec.dfZResolution = 1.0 / dfZScale; 136 333 : oCoordPrec.dfMResolution = 1.0 / dfMScale; 137 666 : oCoordPrec.oFormatSpecificOptions["FileGeodatabase"] = 138 666 : std::move(aosCoordinatePrecisionOptions); 139 : 140 666 : return oCoordPrec; 141 : } 142 : 143 : #endif /* FILEGDB_COORDPREC_WRITE_H */