1 /******************************************************************************
2 *
3 * Project: GTM Driver
4 * Purpose: Implementation of GTMTrackLayer class.
5 * Author: Leonardo de Paula Rosa Piga; http://lampiao.lsc.ic.unicamp.br/~piga
6 *
7 *
8 ******************************************************************************
9 * Copyright (c) 2009, Leonardo de Paula Rosa Piga
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29 #include "ogr_gtm.h"
30
31 CPL_CVSID("$Id: gtmtracklayer.cpp 8e5eeb35bf76390e3134a4ea7076dab7d478ea0e 2018-11-14 22:55:13 +0100 Even Rouault $")
32
GTMTrackLayer(const char * pszNameIn,OGRSpatialReference * poSRSIn,int,OGRGTMDataSource * poDSIn)33 GTMTrackLayer::GTMTrackLayer( const char* pszNameIn,
34 OGRSpatialReference *poSRSIn,
35 int /* bWriterIn */,
36 OGRGTMDataSource* poDSIn )
37 {
38 poCT = nullptr;
39
40 /* We are implementing just WGS84, although GTM supports other datum
41 formats. */
42 if( poSRSIn != nullptr )
43 {
44 poSRS = new OGRSpatialReference(nullptr);
45 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
46 poSRS->SetWellKnownGeogCS( "WGS84" );
47 if (!poSRS->IsSame(poSRSIn))
48 {
49 poCT = OGRCreateCoordinateTransformation( poSRSIn, poSRS );
50 if( poCT == nullptr && poDSIn->isFirstCTError() )
51 {
52 /* If we can't create a transformation, issue a warning - but
53 continue the transformation*/
54 char *pszWKT = nullptr;
55
56 poSRSIn->exportToPrettyWkt( &pszWKT, FALSE );
57
58 CPLError( CE_Warning, CPLE_AppDefined,
59 "Failed to create coordinate transformation between "
60 "the\n"
61 "input coordinate system and WGS84. This may be "
62 "because they\n"
63 "are not transformable.\n"
64 "This message will not be issued any more. \n"
65 "\nSource:\n%s",
66 pszWKT );
67
68 CPLFree( pszWKT );
69 poDSIn->issuedFirstCTError();
70 }
71 }
72 }
73 else
74 {
75 poSRS = nullptr;
76 }
77
78 poDS = poDSIn;
79
80 nNextFID = 0;
81 nTotalFCount = poDS->getNTracks();
82
83 pszName = CPLStrdup(pszNameIn);
84
85 poFeatureDefn = new OGRFeatureDefn( pszName );
86 SetDescription( poFeatureDefn->GetName() );
87 poFeatureDefn->Reference();
88 poFeatureDefn->SetGeomType ( wkbLineString );
89 poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
90
91 /* We implement just name, type, and color for tracks, if others
92 needed feel free to append more parameters and implement the
93 code */
94 OGRFieldDefn oFieldName( "name", OFTString );
95 poFeatureDefn->AddFieldDefn( &oFieldName );
96
97 OGRFieldDefn oFieldTrackType( "type", OFTInteger );
98 poFeatureDefn->AddFieldDefn( &oFieldTrackType );
99
100 OGRFieldDefn oFieldColor( "color", OFTInteger );
101 poFeatureDefn->AddFieldDefn( &oFieldColor );
102 }
103
~GTMTrackLayer()104 GTMTrackLayer::~GTMTrackLayer()
105 {
106 /* poDS, poSRS, poCT, pszName, and poFeatureDefn are released in
107 parent class */
108 }
109
110 /************************************************************************/
111 /* WriteFeatureAttributes() */
112 /************************************************************************/
WriteFeatureAttributes(OGRFeature * poFeature)113 void GTMTrackLayer::WriteFeatureAttributes( OGRFeature *poFeature )
114 {
115 char* psztrackname = nullptr;
116 int type = 1;
117 unsigned int color = 0;
118 for (int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
119 {
120 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
121 if( poFeature->IsFieldSetAndNotNull( i ) )
122 {
123 const char* l_pszName = poFieldDefn->GetNameRef();
124 /* track name */
125 if (STARTS_WITH(l_pszName, "name"))
126 {
127 CPLFree(psztrackname);
128 psztrackname = CPLStrdup( poFeature->GetFieldAsString( i ) );
129 }
130 /* track type */
131 else if (STARTS_WITH(l_pszName, "type"))
132 {
133 type = poFeature->GetFieldAsInteger( i );
134 // Check if it is a valid type
135 if (type < 1 || type > 30)
136 type = 1;
137 }
138 /* track color */
139 else if (STARTS_WITH(l_pszName, "color"))
140 {
141 color = (unsigned int) poFeature->GetFieldAsInteger( i );
142 if (color > 0xFFFFFF)
143 color = 0xFFFFFFF;
144 }
145 }
146 }
147
148 if (psztrackname == nullptr)
149 psztrackname = CPLStrdup( "" );
150
151 const size_t trackNameLength = strlen(psztrackname);
152
153 const size_t bufferSize = 14 + trackNameLength;
154 void* pBuffer = CPLMalloc(bufferSize);
155 void* pBufferAux = pBuffer;
156 /* Write track string name size to buffer */
157 appendUShort(pBufferAux, (unsigned short) trackNameLength);
158 pBufferAux = (char*)pBufferAux + 2;
159
160 /* Write track name */
161 memcpy((char*)pBufferAux, psztrackname, trackNameLength);
162 pBufferAux = (char*)pBufferAux + trackNameLength;
163
164 /* Write track type */
165 appendUChar(pBufferAux, (unsigned char) type);
166 pBufferAux = (char*)pBufferAux + 1;
167
168 /* Write track color */
169 appendInt(pBufferAux, color);
170 pBufferAux = (char*)pBufferAux + 4;
171
172 /* Write track scale */
173 appendFloat(pBufferAux, 0);
174 pBufferAux = (char*)pBufferAux + 4;
175
176 /* Write track label */
177 appendUChar(pBufferAux, 0);
178 pBufferAux = (char*)pBufferAux + 1;
179
180 /* Write track layer */
181 appendUShort(pBufferAux, 0);
182
183 VSIFWriteL(pBuffer, bufferSize, 1, poDS->getTmpTracksFP());
184 poDS->incNumTracks();
185
186 CPLFree(psztrackname);
187 CPLFree(pBuffer);
188 }
189
190 /************************************************************************/
191 /* WriteTrackpoint() */
192 /************************************************************************/
WriteTrackpoint(double lat,double lon,float altitude,bool start)193 inline void GTMTrackLayer::WriteTrackpoint( double lat, double lon,
194 float altitude, bool start )
195 {
196 void* pBuffer = CPLMalloc(25);
197 void* pBufferAux = pBuffer;
198 // latitude
199 appendDouble(pBufferAux, lat);
200 pBufferAux = (char*)pBufferAux + 8;
201 // longitude
202 appendDouble(pBufferAux, lon);
203 pBufferAux = (char*)pBufferAux + 8;
204 // date
205 appendInt(pBufferAux, 0);
206 pBufferAux = (char*)pBufferAux + 4;
207 // start
208 appendUChar(pBufferAux, static_cast<int>(start));
209 pBufferAux = (char*)pBufferAux + 1;
210 // altitude
211 appendFloat(pBufferAux, altitude);
212 VSIFWriteL(pBuffer, 25, 1, poDS->getTmpTrackpointsFP());
213 poDS->incNumTrackpoints();
214 CPLFree(pBuffer);
215 }
216
217 /************************************************************************/
218 /* ICreateFeature() */
219 /************************************************************************/
ICreateFeature(OGRFeature * poFeature)220 OGRErr GTMTrackLayer::ICreateFeature (OGRFeature *poFeature)
221 {
222 VSILFILE* fpTmpTrackpoints = poDS->getTmpTrackpointsFP();
223 if (fpTmpTrackpoints == nullptr)
224 return OGRERR_FAILURE;
225
226 VSILFILE* fpTmpTracks = poDS->getTmpTracksFP();
227 if (fpTmpTracks == nullptr)
228 return OGRERR_FAILURE;
229
230 OGRGeometry *poGeom = poFeature->GetGeometryRef();
231 if ( poGeom == nullptr )
232 {
233 CPLError( CE_Failure, CPLE_AppDefined,
234 "Features without geometry not supported by GTM writer in "
235 "track layer." );
236 return OGRERR_FAILURE;
237 }
238
239 if (nullptr != poCT)
240 {
241 poGeom = poGeom->clone();
242 poGeom->transform( poCT );
243 }
244
245 switch( poGeom->getGeometryType() )
246 {
247 case wkbLineString:
248 case wkbLineString25D:
249 {
250 WriteFeatureAttributes(poFeature);
251 OGRLineString* line = poGeom->toLineString();
252 for(int i = 0; i < line->getNumPoints(); ++i)
253 {
254 double lat = line->getY(i);
255 double lon = line->getX(i);
256 float altitude = 0;
257 CheckAndFixCoordinatesValidity(lat, lon);
258 poDS->checkBounds((float)lat, (float)lon);
259 if (line->getGeometryType() == wkbLineString25D)
260 altitude = static_cast<float>(line->getZ(i));
261 WriteTrackpoint( lat, lon, altitude, i==0 );
262 }
263 break;
264 }
265
266 case wkbMultiLineString:
267 case wkbMultiLineString25D:
268 {
269 for( auto&& line: poGeom->toMultiLineString() )
270 {
271 WriteFeatureAttributes(poFeature);
272 int n = line->getNumPoints();
273 for(int i = 0; i < n; ++i)
274 {
275 double lat = line->getY(i);
276 double lon = line->getX(i);
277 float altitude = 0;
278 CheckAndFixCoordinatesValidity(lat, lon);
279 if (line->getGeometryType() == wkbLineString25D)
280 altitude = static_cast<float>(line->getZ(i));
281 WriteTrackpoint( lat, lon, altitude, i==0 );
282 }
283 }
284 break;
285 }
286
287 default:
288 {
289 CPLError( CE_Failure, CPLE_NotSupported,
290 "Geometry type of `%s' not supported for 'track' element.\n",
291 OGRGeometryTypeToName(poGeom->getGeometryType()) );
292 if (nullptr != poCT)
293 delete poGeom;
294 return OGRERR_FAILURE;
295 }
296 }
297
298 if (nullptr != poCT)
299 delete poGeom;
300
301 return OGRERR_NONE;
302 }
303
GetNextFeature()304 OGRFeature* GTMTrackLayer::GetNextFeature()
305 {
306 if( bError )
307 return nullptr;
308
309 while (poDS->hasNextTrack())
310 {
311 Track* poTrack = poDS->fetchNextTrack();
312 if (poTrack == nullptr)
313 {
314 CPLError(CE_Failure, CPLE_AppDefined,
315 "Could not read track. File probably corrupted");
316 bError = true;
317 return nullptr;
318 }
319 OGRFeature* poFeature = new OGRFeature( poFeatureDefn );
320 OGRLineString* lineString = new OGRLineString ();
321
322 for (int i = 0; i < poTrack->getNumPoints(); ++i)
323 {
324 const TrackPoint* psTrackPoint = poTrack->getPoint(i);
325 lineString->addPoint(psTrackPoint->x,
326 psTrackPoint->y);
327 }
328 if (poSRS)
329 lineString->assignSpatialReference(poSRS);
330 poFeature->SetField( NAME, poTrack->getName());
331 poFeature->SetField( TYPE, poTrack->getType());
332 poFeature->SetField( COLOR, poTrack->getColor());
333 poFeature->SetFID( nNextFID++ );
334 delete poTrack;
335
336 poFeature->SetGeometryDirectly(lineString);
337 if( (m_poFilterGeom == nullptr
338 || FilterGeometry( poFeature->GetGeometryRef() ) )
339 && (m_poAttrQuery == nullptr
340 || m_poAttrQuery->Evaluate( poFeature )) )
341 return poFeature;
342
343 delete poFeature;
344 }
345 return nullptr;
346 }
347
GetFeatureCount(int bForce)348 GIntBig GTMTrackLayer::GetFeatureCount(int bForce)
349 {
350 if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
351 return poDS->getNTracks();
352
353 return OGRLayer::GetFeatureCount(bForce);
354 }
355
ResetReading()356 void GTMTrackLayer::ResetReading()
357 {
358 nNextFID = 0;
359 poDS->rewindTrack();
360 }
361