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