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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #ifndef FILEGDB_COORDPREC_WRITE_H
30 : #define FILEGDB_COORDPREC_WRITE_H
31 :
32 : #include "ogr_spatialref.h"
33 : #include "ogr_geomcoordinateprecision.h"
34 :
35 : /*************************************************************************/
36 : /* GDBGridSettingsFromOGR() */
37 : /*************************************************************************/
38 :
39 : /** Compute grid settings from coordinate precision of source geometry field
40 : * and layer creation options.
41 : * The "FileGeodatabase" key of the output oFormatSpecificOptions will be
42 : * set with the values.
43 : */
44 : static OGRGeomCoordinatePrecision
45 331 : GDBGridSettingsFromOGR(const OGRGeomFieldDefn *poSrcGeomFieldDefn,
46 : CSLConstList aosLayerCreationOptions)
47 : {
48 331 : const auto poSRS = poSrcGeomFieldDefn->GetSpatialRef();
49 :
50 : double dfXOrigin;
51 : double dfYOrigin;
52 : double dfXYScale;
53 331 : double dfZOrigin = -100000;
54 331 : double dfMOrigin = -100000;
55 331 : double dfMScale = 10000;
56 : double dfXYTolerance;
57 : // default tolerance is 1mm in the units of the coordinate system
58 : double dfZTolerance =
59 331 : 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("VERT_CS") : 1.0);
60 331 : double dfZScale = 1 / dfZTolerance * 10;
61 331 : double dfMTolerance = 0.001;
62 :
63 331 : if (poSRS == nullptr || poSRS->IsProjected())
64 : {
65 : // default tolerance is 1mm in the units of the coordinate system
66 196 : dfXYTolerance =
67 196 : 0.001 * (poSRS ? poSRS->GetTargetLinearUnits("PROJCS") : 1.0);
68 : // default scale is 10x the tolerance
69 196 : dfXYScale = 1 / dfXYTolerance * 10;
70 :
71 : // Ideally we would use the same X/Y origins as ArcGIS, but we need
72 : // the algorithm they use.
73 196 : dfXOrigin = -2147483647;
74 196 : dfYOrigin = -2147483647;
75 : }
76 : else
77 : {
78 135 : dfXOrigin = -400;
79 135 : dfYOrigin = -400;
80 135 : dfXYScale = 1000000000;
81 135 : dfXYTolerance = 0.000000008983153;
82 : }
83 :
84 331 : const auto &oSrcCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision();
85 :
86 331 : if (oSrcCoordPrec.dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
87 : {
88 9 : dfXYScale = 1.0 / oSrcCoordPrec.dfXYResolution;
89 9 : dfXYTolerance = oSrcCoordPrec.dfXYResolution / 10.0;
90 : }
91 :
92 331 : if (oSrcCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
93 : {
94 9 : dfZScale = 1.0 / oSrcCoordPrec.dfZResolution;
95 9 : dfZTolerance = oSrcCoordPrec.dfZResolution / 10.0;
96 : }
97 :
98 331 : if (oSrcCoordPrec.dfMResolution != OGRGeomCoordinatePrecision::UNKNOWN)
99 : {
100 9 : dfMScale = 1.0 / oSrcCoordPrec.dfMResolution;
101 9 : dfMTolerance = oSrcCoordPrec.dfMResolution / 10.0;
102 : }
103 :
104 331 : const char *const paramNames[] = {
105 : "XOrigin", "YOrigin", "XYScale", "ZOrigin", "ZScale",
106 : "MOrigin", "MScale", "XYTolerance", "ZTolerance", "MTolerance"};
107 : double *pGridValues[] = {
108 : &dfXOrigin, &dfYOrigin, &dfXYScale, &dfZOrigin, &dfZScale,
109 331 : &dfMOrigin, &dfMScale, &dfXYTolerance, &dfZTolerance, &dfMTolerance};
110 : static_assert(CPL_ARRAYSIZE(paramNames) == CPL_ARRAYSIZE(pGridValues));
111 :
112 : const auto oIterCoordPrecFileGeodatabase =
113 331 : oSrcCoordPrec.oFormatSpecificOptions.find("FileGeodatabase");
114 :
115 : /*
116 : * Use coordinate precision layer creation options in priority.
117 : * Otherwise use the settings from the "FileGeodatabase" entry in
118 : * oSrcCoordPrec.oFormatSpecificOptions when set.
119 : * Otherwise, use above defaults.
120 : */
121 662 : CPLStringList aosCoordinatePrecisionOptions;
122 3641 : for (size_t i = 0; i < CPL_ARRAYSIZE(paramNames); i++)
123 : {
124 3310 : const char *pszVal = CSLFetchNameValueDef(
125 3310 : aosLayerCreationOptions, paramNames[i],
126 3310 : oIterCoordPrecFileGeodatabase !=
127 3310 : oSrcCoordPrec.oFormatSpecificOptions.end()
128 140 : ? oIterCoordPrecFileGeodatabase->second.FetchNameValue(
129 70 : paramNames[i])
130 : : nullptr);
131 3310 : if (pszVal)
132 : {
133 282 : *(pGridValues[i]) = CPLAtof(pszVal);
134 282 : if (strstr(paramNames[i], "Scale") ||
135 208 : strstr(paramNames[i], "Tolerance"))
136 : {
137 148 : if (*(pGridValues[i]) <= 0)
138 : {
139 0 : CPLError(CE_Warning, CPLE_AppDefined,
140 : "%s should be strictly greater than zero",
141 0 : paramNames[i]);
142 : }
143 : }
144 : }
145 : aosCoordinatePrecisionOptions.SetNameValue(
146 3310 : paramNames[i], CPLSPrintf("%.15g", *(pGridValues[i])));
147 : }
148 :
149 331 : OGRGeomCoordinatePrecision oCoordPrec;
150 331 : oCoordPrec.dfXYResolution = 1.0 / dfXYScale;
151 331 : oCoordPrec.dfZResolution = 1.0 / dfZScale;
152 331 : oCoordPrec.dfMResolution = 1.0 / dfMScale;
153 662 : oCoordPrec.oFormatSpecificOptions["FileGeodatabase"] =
154 662 : std::move(aosCoordinatePrecisionOptions);
155 :
156 662 : return oCoordPrec;
157 : }
158 :
159 : #endif /* FILEGDB_COORDPREC_WRITE_H */
|