/src/gdal/ogr/ogrsf_frmts/wasp/ogrwaspdatasource.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: WAsP Translator |
4 | | * Purpose: Implements OGRWAsPDataSource class |
5 | | * Author: Vincent Mora, vincent dot mora at oslandia dot com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2014, Oslandia <info at oslandia dot com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "ogrwasp.h" |
14 | | #include "cpl_conv.h" |
15 | | #include "cpl_string.h" |
16 | | |
17 | | #include <cassert> |
18 | | #include <sstream> |
19 | | |
20 | | /************************************************************************/ |
21 | | /* OGRWAsPDataSource() */ |
22 | | /************************************************************************/ |
23 | | |
24 | | OGRWAsPDataSource::OGRWAsPDataSource(const char *pszName, VSILFILE *hFileHandle) |
25 | 14.7k | : sFilename(pszName), hFile(hFileHandle) |
26 | 14.7k | { |
27 | 14.7k | } |
28 | | |
29 | | /************************************************************************/ |
30 | | /* ~OGRWAsPDataSource() */ |
31 | | /************************************************************************/ |
32 | | |
33 | | OGRWAsPDataSource::~OGRWAsPDataSource() |
34 | | |
35 | 14.7k | { |
36 | 14.7k | oLayer.reset(); /* we write to file int layer dtor */ |
37 | 14.7k | VSIFCloseL(hFile); /* nothing smart can be done here in case of error */ |
38 | 14.7k | } |
39 | | |
40 | | /************************************************************************/ |
41 | | /* TestCapability() */ |
42 | | /************************************************************************/ |
43 | | |
44 | | int OGRWAsPDataSource::TestCapability(const char *pszCap) const |
45 | | |
46 | 0 | { |
47 | 0 | if (EQUAL(pszCap, ODsCCreateLayer) && oLayer.get() == nullptr) |
48 | 0 | return true; |
49 | 0 | else if (EQUAL(pszCap, ODsCZGeometries)) |
50 | 0 | return true; |
51 | | |
52 | 0 | return false; |
53 | 0 | } |
54 | | |
55 | | /************************************************************************/ |
56 | | /* GetLayerByName() */ |
57 | | /************************************************************************/ |
58 | | |
59 | | OGRLayer *OGRWAsPDataSource::GetLayerByName(const char *pszName) |
60 | | |
61 | 0 | { |
62 | 0 | return (oLayer.get() && EQUAL(pszName, oLayer->GetName())) ? oLayer.get() |
63 | 0 | : nullptr; |
64 | 0 | } |
65 | | |
66 | | /************************************************************************/ |
67 | | /* Load() */ |
68 | | /************************************************************************/ |
69 | | |
70 | | OGRErr OGRWAsPDataSource::Load(bool bSilent) |
71 | | |
72 | 14.7k | { |
73 | | /* if we don't have a layer, we read from file */ |
74 | 14.7k | if (oLayer.get()) |
75 | 0 | { |
76 | 0 | if (!bSilent) |
77 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "layer already loaded"); |
78 | 0 | return OGRERR_FAILURE; |
79 | 0 | } |
80 | | /* Parse the first line of the file in case it is a spatial ref*/ |
81 | 14.7k | const char *pszLine = CPLReadLine2L(hFile, 1024, nullptr); |
82 | 14.7k | if (!pszLine) |
83 | 80 | { |
84 | 80 | if (!bSilent) |
85 | 0 | CPLError(CE_Failure, CPLE_FileIO, "empty file"); |
86 | 80 | return OGRERR_FAILURE; |
87 | 80 | } |
88 | 14.6k | CPLString sLine(pszLine); |
89 | 14.6k | sLine = sLine.substr(0, sLine.find("|")); |
90 | 14.6k | OGRSpatialReference *poSpatialRef = new OGRSpatialReference; |
91 | 14.6k | poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
92 | 14.6k | if (poSpatialRef->importFromProj4(sLine.c_str()) != OGRERR_NONE) |
93 | 11.0k | { |
94 | 11.0k | if (!bSilent) |
95 | 0 | CPLError(CE_Warning, CPLE_FileIO, "cannot find spatial reference"); |
96 | 11.0k | delete poSpatialRef; |
97 | 11.0k | poSpatialRef = nullptr; |
98 | 11.0k | } |
99 | | |
100 | | /* TODO Parse those line since they define a coordinate transformation */ |
101 | 14.6k | CPLReadLineL(hFile); |
102 | 14.6k | CPLReadLineL(hFile); |
103 | 14.6k | CPLReadLineL(hFile); |
104 | | |
105 | 14.6k | oLayer.reset(new OGRWAsPLayer(this, |
106 | 14.6k | CPLGetBasenameSafe(sFilename.c_str()).c_str(), |
107 | 14.6k | hFile, poSpatialRef)); |
108 | 14.6k | if (poSpatialRef) |
109 | 3.62k | poSpatialRef->Release(); |
110 | | |
111 | 14.6k | const vsi_l_offset iOffset = VSIFTellL(hFile); |
112 | 14.6k | pszLine = CPLReadLineL(hFile); |
113 | 14.6k | if (!pszLine) |
114 | 14.0k | { |
115 | 14.0k | if (!bSilent) |
116 | 0 | CPLError(CE_Failure, CPLE_FileIO, "no feature in file"); |
117 | 14.0k | oLayer.reset(); |
118 | 14.0k | return OGRERR_FAILURE; |
119 | 14.0k | } |
120 | | |
121 | 540 | double dfValues[4] = {0}; |
122 | 540 | int iNumValues = 0; |
123 | 540 | { |
124 | 540 | std::istringstream iss(pszLine); |
125 | 997 | while (iNumValues < 4 && (iss >> dfValues[iNumValues])) |
126 | 457 | { |
127 | 457 | ++iNumValues; |
128 | 457 | } |
129 | | |
130 | 540 | if (iNumValues < 2) |
131 | 361 | { |
132 | 361 | if (!bSilent && iNumValues) |
133 | 0 | CPLError(CE_Failure, CPLE_FileIO, "no enough values"); |
134 | 361 | else if (!bSilent) |
135 | 0 | CPLError(CE_Failure, CPLE_FileIO, "no feature in file"); |
136 | | |
137 | 361 | oLayer.reset(); |
138 | 361 | return OGRERR_FAILURE; |
139 | 361 | } |
140 | 540 | } |
141 | | |
142 | 179 | if (iNumValues == 3 || iNumValues == 4) |
143 | 51 | { |
144 | 51 | OGRFieldDefn left("z_left", OFTReal); |
145 | 51 | OGRFieldDefn right("z_right", OFTReal); |
146 | 51 | oLayer->CreateField(&left); |
147 | 51 | oLayer->CreateField(&right); |
148 | 51 | } |
149 | 179 | if (iNumValues == 2 || iNumValues == 4) |
150 | 164 | { |
151 | 164 | OGRFieldDefn height("elevation", OFTReal); |
152 | 164 | oLayer->CreateField(&height); |
153 | 164 | } |
154 | | |
155 | 179 | VSIFSeekL(hFile, iOffset, SEEK_SET); |
156 | 179 | return OGRERR_NONE; |
157 | 540 | } |
158 | | |
159 | | /************************************************************************/ |
160 | | /* GetLayer() */ |
161 | | /************************************************************************/ |
162 | | |
163 | | const OGRLayer *OGRWAsPDataSource::GetLayer(int iLayer) const |
164 | | |
165 | 177 | { |
166 | 177 | return (iLayer == 0) ? oLayer.get() : nullptr; |
167 | 177 | } |
168 | | |
169 | | /************************************************************************/ |
170 | | /* ICreateLayer() */ |
171 | | /************************************************************************/ |
172 | | |
173 | | OGRLayer * |
174 | | OGRWAsPDataSource::ICreateLayer(const char *pszName, |
175 | | const OGRGeomFieldDefn *poGeomFieldDefn, |
176 | | CSLConstList papszOptions) |
177 | | |
178 | 0 | { |
179 | 0 | const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone; |
180 | 0 | const auto poSpatialRef = |
181 | 0 | poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr; |
182 | |
|
183 | 0 | if (eGType != wkbLineString && eGType != wkbLineString25D && |
184 | 0 | eGType != wkbMultiLineString && eGType != wkbMultiLineString25D && |
185 | 0 | eGType != wkbPolygon && eGType != wkbPolygon25D && |
186 | 0 | eGType != wkbMultiPolygon && eGType != wkbMultiPolygon25D) |
187 | 0 | { |
188 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "unsupported geometry type %s", |
189 | 0 | OGRGeometryTypeToName(eGType)); |
190 | 0 | return nullptr; |
191 | 0 | } |
192 | | |
193 | 0 | if (!OGRGeometryFactory::haveGEOS() && |
194 | 0 | (eGType == wkbPolygon || eGType == wkbPolygon25D || |
195 | 0 | eGType == wkbMultiPolygon || eGType == wkbMultiPolygon25D)) |
196 | 0 | { |
197 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
198 | 0 | "unsupported geometry type %s without GEOS support", |
199 | 0 | OGRGeometryTypeToName(eGType)); |
200 | 0 | return nullptr; |
201 | 0 | } |
202 | | |
203 | 0 | if (oLayer.get()) |
204 | 0 | { |
205 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
206 | 0 | "this data source does not support more than one layer"); |
207 | 0 | return nullptr; |
208 | 0 | } |
209 | | |
210 | 0 | CPLString sFirstField, sSecondField, sGeomField; |
211 | |
|
212 | 0 | const char *pszFields = CSLFetchNameValue(papszOptions, "WASP_FIELDS"); |
213 | 0 | CPLString sFields(pszFields ? pszFields : ""); |
214 | 0 | if (!sFields.empty()) |
215 | 0 | { |
216 | | /* parse the comma separated list of fields */ |
217 | 0 | const size_t iComma = sFields.find(','); |
218 | 0 | if (std::string::npos != iComma) |
219 | 0 | { |
220 | 0 | sFirstField = sFields.substr(0, iComma); |
221 | 0 | sSecondField = sFields.substr(iComma + 1); |
222 | 0 | } |
223 | 0 | else |
224 | 0 | { |
225 | 0 | sFirstField = std::move(sFields); |
226 | 0 | } |
227 | 0 | } |
228 | |
|
229 | 0 | const char *pszGeomField = |
230 | 0 | CSLFetchNameValue(papszOptions, "WASP_GEOM_FIELD"); |
231 | 0 | sGeomField = CPLString(pszGeomField ? pszGeomField : ""); |
232 | |
|
233 | 0 | const bool bMerge = |
234 | 0 | CPLTestBool(CSLFetchNameValueDef(papszOptions, "WASP_MERGE", "YES")); |
235 | |
|
236 | 0 | std::unique_ptr<double> pdfTolerance; |
237 | 0 | { |
238 | 0 | const char *pszToler = |
239 | 0 | CSLFetchNameValue(papszOptions, "WASP_TOLERANCE"); |
240 | |
|
241 | 0 | if (pszToler) |
242 | 0 | { |
243 | 0 | if (!OGRGeometryFactory::haveGEOS()) |
244 | 0 | { |
245 | 0 | CPLError( |
246 | 0 | CE_Warning, CPLE_IllegalArg, |
247 | 0 | "GEOS support not enabled, ignoring option WASP_TOLERANCE"); |
248 | 0 | } |
249 | 0 | else |
250 | 0 | { |
251 | 0 | pdfTolerance.reset(new double); |
252 | 0 | if (!(std::istringstream(pszToler) >> *pdfTolerance)) |
253 | 0 | { |
254 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
255 | 0 | "cannot set tolerance from %s", pszToler); |
256 | 0 | return nullptr; |
257 | 0 | } |
258 | 0 | } |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | 0 | std::unique_ptr<double> pdfAdjacentPointTolerance; |
263 | 0 | { |
264 | 0 | const char *pszAdjToler = |
265 | 0 | CSLFetchNameValue(papszOptions, "WASP_ADJ_TOLER"); |
266 | 0 | if (pszAdjToler) |
267 | 0 | { |
268 | 0 | pdfAdjacentPointTolerance.reset(new double); |
269 | 0 | if (!(std::istringstream(pszAdjToler) >> |
270 | 0 | *pdfAdjacentPointTolerance)) |
271 | 0 | { |
272 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
273 | 0 | "cannot set tolerance from %s", pszAdjToler); |
274 | 0 | return nullptr; |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | 0 | std::unique_ptr<double> pdfPointToCircleRadius; |
280 | 0 | { |
281 | 0 | const char *pszPtToCircRad = |
282 | 0 | CSLFetchNameValue(papszOptions, "WASP_POINT_TO_CIRCLE_RADIUS"); |
283 | 0 | if (pszPtToCircRad) |
284 | 0 | { |
285 | 0 | pdfPointToCircleRadius.reset(new double); |
286 | 0 | if (!(std::istringstream(pszPtToCircRad) >> |
287 | 0 | *pdfPointToCircleRadius)) |
288 | 0 | { |
289 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
290 | 0 | "cannot set tolerance from %s", pszPtToCircRad); |
291 | 0 | return nullptr; |
292 | 0 | } |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | 0 | OGRSpatialReference *poSRSClone = nullptr; |
297 | 0 | if (poSpatialRef) |
298 | 0 | { |
299 | 0 | poSRSClone = poSpatialRef->Clone(); |
300 | 0 | poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
301 | 0 | } |
302 | 0 | oLayer.reset(new OGRWAsPLayer( |
303 | 0 | this, CPLGetBasenameSafe(pszName).c_str(), hFile, poSRSClone, |
304 | 0 | sFirstField, sSecondField, sGeomField, bMerge, pdfTolerance.release(), |
305 | 0 | pdfAdjacentPointTolerance.release(), pdfPointToCircleRadius.release())); |
306 | 0 | if (poSRSClone) |
307 | 0 | poSRSClone->Release(); |
308 | |
|
309 | 0 | char *ppszWktSpatialRef = nullptr; |
310 | 0 | if (poSpatialRef && |
311 | 0 | poSpatialRef->exportToProj4(&ppszWktSpatialRef) == OGRERR_NONE) |
312 | 0 | { |
313 | 0 | VSIFPrintfL(hFile, "%s\n", ppszWktSpatialRef); |
314 | 0 | } |
315 | 0 | else |
316 | 0 | { |
317 | 0 | VSIFPrintfL(hFile, "no spatial ref sys\n"); |
318 | 0 | } |
319 | 0 | CPLFree(ppszWktSpatialRef); |
320 | |
|
321 | 0 | VSIFPrintfL(hFile, " 0.0 0.0 0.0 0.0\n"); |
322 | 0 | VSIFPrintfL(hFile, " 1.0 0.0 1.0 0.0\n"); |
323 | 0 | VSIFPrintfL(hFile, " 1.0 0.0\n"); |
324 | 0 | return oLayer.get(); |
325 | 0 | } |