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