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 235 : GDBGridSettingsFromOGR(const OGRGeomFieldDefn *poSrcGeomFieldDefn, 30 : CSLConstList aosLayerCreationOptions) 31 : { 32 235 : const auto poSRS = poSrcGeomFieldDefn->GetSpatialRef(); 33 : 34 : double dfXOrigin; 35 : double dfYOrigin; 36 : double dfXYScale; 37 235 : double dfZOrigin = -100000; 38 235 : double dfMOrigin = -100000; 39 235 : double dfMScale = 10000; 40 : double dfXYTolerance; 41 : // default tolerance is 1mm in the units of the coordinate system 42 : double dfZTolerance = 43 235 : 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("VERT_CS") : 1.0); 44 235 : double dfZScale = 1 / dfZTolerance * 10; 45 235 : double dfMTolerance = 0.001; 46 : 47 235 : if (poSRS == nullptr || poSRS->IsProjected()) 48 : { 49 : // default tolerance is 1mm in the units of the coordinate system 50 190 : dfXYTolerance = 51 190 : 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("PROJCS") : 1.0); 52 : // default scale is 10x the tolerance 53 190 : 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 190 : dfXOrigin = -2147483647; 58 190 : dfYOrigin = -2147483647; 59 : } 60 : else 61 : { 62 45 : dfXOrigin = -400; 63 45 : dfYOrigin = -400; 64 45 : dfXYScale = 1000000000; 65 45 : dfXYTolerance = 0.000000008983153; 66 : } 67 : 68 235 : const auto &oSrcCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision(); 69 : 70 235 : if (oSrcCoordPrec.dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN) 71 : { 72 9 : dfXYScale = 1.0 / oSrcCoordPrec.dfXYResolution; 73 9 : dfXYTolerance = oSrcCoordPrec.dfXYResolution / 10.0; 74 : } 75 : 76 235 : if (oSrcCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN) 77 : { 78 9 : dfZScale = 1.0 / oSrcCoordPrec.dfZResolution; 79 9 : dfZTolerance = oSrcCoordPrec.dfZResolution / 10.0; 80 : } 81 : 82 235 : if (oSrcCoordPrec.dfMResolution != OGRGeomCoordinatePrecision::UNKNOWN) 83 : { 84 9 : dfMScale = 1.0 / oSrcCoordPrec.dfMResolution; 85 9 : dfMTolerance = oSrcCoordPrec.dfMResolution / 10.0; 86 : } 87 : 88 235 : 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 235 : &dfMOrigin, &dfMScale, &dfXYTolerance, &dfZTolerance, &dfMTolerance}; 94 : static_assert(CPL_ARRAYSIZE(paramNames) == CPL_ARRAYSIZE(pGridValues)); 95 : 96 : const auto oIterCoordPrecFileGeodatabase = 97 235 : 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 470 : CPLStringList aosCoordinatePrecisionOptions; 106 2585 : for (size_t i = 0; i < CPL_ARRAYSIZE(paramNames); i++) 107 : { 108 2350 : const char *pszVal = CSLFetchNameValueDef( 109 2350 : aosLayerCreationOptions, paramNames[i], 110 2350 : oIterCoordPrecFileGeodatabase != 111 2350 : oSrcCoordPrec.oFormatSpecificOptions.end() 112 160 : ? oIterCoordPrecFileGeodatabase->second.FetchNameValue( 113 80 : paramNames[i]) 114 : : nullptr); 115 2350 : 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 2350 : paramNames[i], CPLSPrintf("%.15g", *(pGridValues[i]))); 131 : } 132 : 133 235 : OGRGeomCoordinatePrecision oCoordPrec; 134 235 : oCoordPrec.dfXYResolution = 1.0 / dfXYScale; 135 235 : oCoordPrec.dfZResolution = 1.0 / dfZScale; 136 235 : oCoordPrec.dfMResolution = 1.0 / dfMScale; 137 470 : oCoordPrec.oFormatSpecificOptions["FileGeodatabase"] = 138 470 : std::move(aosCoordinatePrecisionOptions); 139 : 140 470 : return oCoordPrec; 141 : } 142 : 143 : #endif /* FILEGDB_COORDPREC_WRITE_H */