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