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