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 9 : oLayer.reset(new OGRWAsPLayer(this,
106 18 : CPLGetBasenameSafe(sFilename.c_str()).c_str(),
107 9 : hFile, poSpatialRef));
108 9 : if (poSpatialRef)
109 1 : poSpatialRef->Release();
110 :
111 9 : const vsi_l_offset iOffset = VSIFTellL(hFile);
112 9 : pszLine = CPLReadLineL(hFile);
113 9 : if (!pszLine)
114 : {
115 6 : if (!bSilent)
116 0 : CPLError(CE_Failure, CPLE_FileIO, "no feature in file");
117 6 : oLayer.reset();
118 6 : return OGRERR_FAILURE;
119 : }
120 :
121 3 : double dfValues[4] = {0};
122 3 : int iNumValues = 0;
123 : {
124 6 : std::istringstream iss(pszLine);
125 9 : while (iNumValues < 4 && (iss >> dfValues[iNumValues]))
126 : {
127 6 : ++iNumValues;
128 : }
129 :
130 3 : if (iNumValues < 2)
131 : {
132 0 : if (!bSilent && iNumValues)
133 0 : CPLError(CE_Failure, CPLE_FileIO, "no enough values");
134 0 : else if (!bSilent)
135 0 : CPLError(CE_Failure, CPLE_FileIO, "no feature in file");
136 :
137 0 : oLayer.reset();
138 0 : return OGRERR_FAILURE;
139 : }
140 : }
141 :
142 3 : if (iNumValues == 3 || iNumValues == 4)
143 : {
144 0 : OGRFieldDefn left("z_left", OFTReal);
145 0 : OGRFieldDefn right("z_right", OFTReal);
146 0 : oLayer->CreateField(&left);
147 0 : oLayer->CreateField(&right);
148 : }
149 3 : if (iNumValues == 2 || iNumValues == 4)
150 : {
151 6 : OGRFieldDefn height("elevation", OFTReal);
152 3 : oLayer->CreateField(&height);
153 : }
154 :
155 3 : VSIFSeekL(hFile, iOffset, SEEK_SET);
156 3 : return OGRERR_NONE;
157 : }
158 :
159 : /************************************************************************/
160 : /* GetLayer() */
161 : /************************************************************************/
162 :
163 1 : OGRLayer *OGRWAsPDataSource::GetLayer(int iLayer)
164 :
165 : {
166 1 : return (iLayer == 0) ? oLayer.get() : nullptr;
167 : }
168 :
169 : /************************************************************************/
170 : /* ICreateLayer() */
171 : /************************************************************************/
172 :
173 : OGRLayer *
174 40 : OGRWAsPDataSource::ICreateLayer(const char *pszName,
175 : const OGRGeomFieldDefn *poGeomFieldDefn,
176 : CSLConstList papszOptions)
177 :
178 : {
179 40 : const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
180 : const auto poSpatialRef =
181 40 : poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
182 :
183 40 : if (eGType != wkbLineString && eGType != wkbLineString25D &&
184 26 : eGType != wkbMultiLineString && eGType != wkbMultiLineString25D &&
185 19 : eGType != wkbPolygon && eGType != wkbPolygon25D &&
186 11 : eGType != wkbMultiPolygon && eGType != wkbMultiPolygon25D)
187 : {
188 8 : CPLError(CE_Failure, CPLE_NotSupported, "unsupported geometry type %s",
189 : OGRGeometryTypeToName(eGType));
190 8 : return nullptr;
191 : }
192 :
193 32 : if (!OGRGeometryFactory::haveGEOS() &&
194 0 : (eGType == wkbPolygon || eGType == wkbPolygon25D ||
195 0 : eGType == wkbMultiPolygon || eGType == wkbMultiPolygon25D))
196 : {
197 0 : CPLError(CE_Failure, CPLE_NotSupported,
198 : "unsupported geometry type %s without GEOS support",
199 : OGRGeometryTypeToName(eGType));
200 0 : return nullptr;
201 : }
202 :
203 32 : if (oLayer.get())
204 : {
205 8 : CPLError(CE_Failure, CPLE_NotSupported,
206 : "this data source does not support more than one layer");
207 8 : return nullptr;
208 : }
209 :
210 48 : CPLString sFirstField, sSecondField, sGeomField;
211 :
212 24 : const char *pszFields = CSLFetchNameValue(papszOptions, "WASP_FIELDS");
213 48 : const CPLString sFields(pszFields ? pszFields : "");
214 24 : if (!sFields.empty())
215 : {
216 : /* parse the comma separated list of fields */
217 3 : const size_t iComma = sFields.find(',');
218 3 : if (std::string::npos != iComma)
219 : {
220 1 : sFirstField = sFields.substr(0, iComma);
221 1 : sSecondField = sFields.substr(iComma + 1);
222 : }
223 : else
224 : {
225 2 : sFirstField = sFields;
226 : }
227 : }
228 :
229 : const char *pszGeomField =
230 24 : CSLFetchNameValue(papszOptions, "WASP_GEOM_FIELD");
231 24 : sGeomField = CPLString(pszGeomField ? pszGeomField : "");
232 :
233 : const bool bMerge =
234 24 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "WASP_MERGE", "YES"));
235 :
236 24 : std::unique_ptr<double> pdfTolerance;
237 : {
238 : const char *pszToler =
239 24 : CSLFetchNameValue(papszOptions, "WASP_TOLERANCE");
240 :
241 24 : if (pszToler)
242 : {
243 1 : if (!OGRGeometryFactory::haveGEOS())
244 : {
245 0 : CPLError(
246 : CE_Warning, CPLE_IllegalArg,
247 : "GEOS support not enabled, ignoring option WASP_TOLERANCE");
248 : }
249 : else
250 : {
251 1 : pdfTolerance.reset(new double);
252 1 : if (!(std::istringstream(pszToler) >> *pdfTolerance))
253 : {
254 0 : CPLError(CE_Failure, CPLE_IllegalArg,
255 : "cannot set tolerance from %s", pszToler);
256 0 : return nullptr;
257 : }
258 : }
259 : }
260 : }
261 :
262 24 : std::unique_ptr<double> pdfAdjacentPointTolerance;
263 : {
264 : const char *pszAdjToler =
265 24 : CSLFetchNameValue(papszOptions, "WASP_ADJ_TOLER");
266 24 : if (pszAdjToler)
267 : {
268 0 : pdfAdjacentPointTolerance.reset(new double);
269 0 : if (!(std::istringstream(pszAdjToler) >>
270 0 : *pdfAdjacentPointTolerance))
271 : {
272 0 : CPLError(CE_Failure, CPLE_IllegalArg,
273 : "cannot set tolerance from %s", pszAdjToler);
274 0 : return nullptr;
275 : }
276 : }
277 : }
278 :
279 24 : std::unique_ptr<double> pdfPointToCircleRadius;
280 : {
281 : const char *pszPtToCircRad =
282 24 : CSLFetchNameValue(papszOptions, "WASP_POINT_TO_CIRCLE_RADIUS");
283 24 : if (pszPtToCircRad)
284 : {
285 0 : pdfPointToCircleRadius.reset(new double);
286 0 : if (!(std::istringstream(pszPtToCircRad) >>
287 0 : *pdfPointToCircleRadius))
288 : {
289 0 : CPLError(CE_Failure, CPLE_IllegalArg,
290 : "cannot set tolerance from %s", pszPtToCircRad);
291 0 : return nullptr;
292 : }
293 : }
294 : }
295 :
296 24 : OGRSpatialReference *poSRSClone = nullptr;
297 24 : if (poSpatialRef)
298 : {
299 3 : poSRSClone = poSpatialRef->Clone();
300 3 : poSRSClone->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
301 : }
302 24 : oLayer.reset(new OGRWAsPLayer(
303 48 : this, CPLGetBasenameSafe(pszName).c_str(), hFile, poSRSClone,
304 24 : sFirstField, sSecondField, sGeomField, bMerge, pdfTolerance.release(),
305 24 : pdfAdjacentPointTolerance.release(), pdfPointToCircleRadius.release()));
306 24 : if (poSRSClone)
307 3 : poSRSClone->Release();
308 :
309 24 : char *ppszWktSpatialRef = nullptr;
310 27 : if (poSpatialRef &&
311 3 : poSpatialRef->exportToProj4(&ppszWktSpatialRef) == OGRERR_NONE)
312 : {
313 3 : VSIFPrintfL(hFile, "%s\n", ppszWktSpatialRef);
314 : }
315 : else
316 : {
317 21 : VSIFPrintfL(hFile, "no spatial ref sys\n");
318 : }
319 24 : CPLFree(ppszWktSpatialRef);
320 :
321 24 : VSIFPrintfL(hFile, " 0.0 0.0 0.0 0.0\n");
322 24 : VSIFPrintfL(hFile, " 1.0 0.0 1.0 0.0\n");
323 24 : VSIFPrintfL(hFile, " 1.0 0.0\n");
324 24 : return oLayer.get();
325 : }
|