QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsinterpolator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsinterpolator.cpp
3  -------------------
4  begin : Marco 10, 2008
5  copyright : (C) 2008 by Marco Hugentobler
6  email : marco dot hugentobler at karto dot baug dot ethz dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsinterpolator.h"
19 #include "qgsvectordataprovider.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsgeometry.h"
22 
23 QgsInterpolator::QgsInterpolator( const QList<LayerData>& layerData )
24  : mDataIsCached( false )
25  , mLayerData( layerData )
26 {
27 
28 }
29 
30 QgsInterpolator::QgsInterpolator()
31  : mDataIsCached( false )
32 {
33 
34 }
35 
37 {
38 
39 }
40 
42 {
43  if ( mLayerData.size() < 1 )
44  {
45  return 0;
46  }
47 
48  //reserve initial memory for 100000 vertices
49  mCachedBaseData.clear();
50  mCachedBaseData.reserve( 100000 );
51 
52  QList<LayerData>::iterator v_it = mLayerData.begin();
53 
54  for ( ; v_it != mLayerData.end(); ++v_it )
55  {
56  if ( v_it->vectorLayer == 0 )
57  {
58  continue;
59  }
60 
61  QgsVectorLayer* vlayer = v_it->vectorLayer;
62  if ( !vlayer )
63  {
64  return 2;
65  }
66 
67  QgsAttributeList attList;
68  if ( !v_it->zCoordInterpolation )
69  {
70  attList.push_back( v_it->interpolationAttribute );
71  }
72 
73 
74  double attributeValue = 0.0;
75  bool attributeConversionOk = false;
76 
77  QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( attList ) );
78 
79  QgsFeature theFeature;
80  while ( fit.nextFeature( theFeature ) )
81  {
82  if ( !v_it->zCoordInterpolation )
83  {
84  QVariant attributeVariant = theFeature.attribute( v_it->interpolationAttribute );
85  if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value)
86  {
87  continue;
88  }
89  attributeValue = attributeVariant.toDouble( &attributeConversionOk );
90  if ( !attributeConversionOk || qIsNaN( attributeValue ) ) //don't consider vertices with attributes like 'nan' for the interpolation
91  {
92  continue;
93  }
94  }
95 
96  if ( addVerticesToCache( theFeature.geometry(), v_it->zCoordInterpolation, attributeValue ) != 0 )
97  {
98  return 3;
99  }
100  }
101  }
102 
103  return 0;
104 }
105 
106 int QgsInterpolator::addVerticesToCache( QgsGeometry* geom, bool zCoord, double attributeValue )
107 {
108  if ( !geom )
109  return 1;
110 
111  bool hasZValue = false;
112  QgsConstWkbPtr currentWkbPtr( geom->asWkb() + 1 + sizeof( int ) );
113  vertexData theVertex; //the current vertex
114 
115  QGis::WkbType wkbType = geom->wkbType();
116  switch ( wkbType )
117  {
118  case QGis::WKBPoint25D:
119  hasZValue = true;
120  //intentional fall-through
121  case QGis::WKBPoint:
122  {
123  currentWkbPtr >> theVertex.x >> theVertex.y;
124  if ( zCoord && hasZValue )
125  {
126  currentWkbPtr >> theVertex.z;
127  }
128  else
129  {
130  theVertex.z = attributeValue;
131  }
132  mCachedBaseData.push_back( theVertex );
133  break;
134  }
136  hasZValue = true;
137  //intentional fall-through
138  case QGis::WKBLineString:
139  {
140  int nPoints;
141  currentWkbPtr >> nPoints;
142  for ( int index = 0; index < nPoints; ++index )
143  {
144  currentWkbPtr >> theVertex.x >> theVertex.y;
145  if ( zCoord && hasZValue ) //skip z-coordinate for 25D geometries
146  {
147  currentWkbPtr >> theVertex.z;
148  }
149  else
150  {
151  theVertex.z = attributeValue;
152  }
153  mCachedBaseData.push_back( theVertex );
154  }
155  break;
156  }
157 #if 0
158  case QGis::WKBPolygon25D:
159  hasZValue = true;
160  //intentional fall-through
161  case QGis::WKBPolygon:
162  {
163  int nRings;
164  wkbPtr >> nRings;
165  for ( int index = 0; index < nRings; ++index )
166  {
167  int nPoints;
168  wkbPtr >> nPoints;
169  for ( int index2 = 0; index2 < *npoints; ++index2 )
170  {
171  double x, y;
172  wkbPtr >> x >> y;
173  if ( point.sqrDist( x, y ) < actdist )
174  {
175  actdist = point.sqrDist( x, y );
176  vertexnr = vertexcounter;
177  //assign the rubber band indices
178  if ( index2 == 0 )
179  {
180  beforeVertex = vertexcounter + ( *npoints - 2 );
181  afterVertex = vertexcounter + 1;
182  }
183  else if ( index2 == ( *npoints - 1 ) )
184  {
185  beforeVertex = vertexcounter - 1;
186  afterVertex = vertexcounter - ( *npoints - 2 );
187  }
188  else
189  {
190  beforeVertex = vertexcounter - 1;
191  afterVertex = vertexcounter + 1;
192  }
193  }
194  if ( hasZValue ) //skip z-coordinate for 25D geometries
195  {
196  wkbPtr += sizeof( double );
197  }
198  ++vertexcounter;
199  }
200  }
201  break;
202  }
204  hasZValue = true;
205  //intentional fall-through
206  case QGis::WKBMultiPoint:
207  {
208  int nPoints;
209  wkbPtr >> nPoints;
210  for ( int index = 0; index < nPoints; ++index )
211  {
212  wkbPtr += 1 + sizeof( int ); //skip endian and point type
213 
214  double x, y;
215  wkbPtr >> x >> y;
216  if ( point.sqrDist( x, y ) < actdist )
217  {
218  actdist = point.sqrDist( x, y );
219  vertexnr = index;
220  }
221  if ( hasZValue ) //skip z-coordinate for 25D geometries
222  {
223  wkbPtr += sizeof( double );
224  }
225  }
226  break;
227  }
229  hasZValue = true;
230  //intentional fall-through
232  {
233  int nLines;
234  wkbPtr >> nLines;
235  for ( int index = 0; index < nLines; ++index )
236  {
237  int nPoints;
238  wkbPtr >> nPoints;
239  for ( int index2 = 0; index2 < nPoints; ++index2 )
240  {
241  double x, y;
242  wkbPtr >> x >> y;
243  if ( point.sqrDist( x, y ) < actdist )
244  {
245  actdist = point.sqrDist( x, y );
246  vertexnr = vertexcounter;
247 
248  if ( index2 == 0 )//assign the rubber band indices
249  {
250  beforeVertex = -1;
251  }
252  else
253  {
254  beforeVertex = vertexnr - 1;
255  }
256  if ( index2 == nPoints - 1 )
257  {
258  afterVertex = -1;
259  }
260  else
261  {
262  afterVertex = vertexnr + 1;
263  }
264  }
265  if ( hasZValue ) //skip z-coordinate for 25D geometries
266  {
267  wkbPtr += sizeof( double );
268  }
269  ++vertexcounter;
270  }
271  }
272  break;
273  }
275  hasZValue = true;
276  //intentional fall-through
278  {
279  int nPolys;
280  wkbPtr >> nPolys;
281  for ( int index = 0; index < nPolys; ++index )
282  {
283  wkbPtr += 1 + sizeof( int ); //skip endian and polygon type
284  int nRings;
285  wkbPtr >> nRings;
286  for ( int index2 = 0; index2 < nRings; ++index2 )
287  {
288  int nPoints;
289  wkbPtr >> nPoints;
290  for ( int index3 = 0; index3 < nPoints; ++index3 )
291  {
292  double x, y;
293  wkbPtr >> x >> y;
294  if ( point.sqrDist( x, y ) < actdist )
295  {
296  actdist = point.sqrDist( x, y );
297  vertexnr = vertexcounter;
298 
299  //assign the rubber band indices
300  if ( index3 == 0 )
301  {
302  beforeVertex = vertexcounter + ( nPoints - 2 );
303  afterVertex = vertexcounter + 1;
304  }
305  else if ( index3 == ( *npoints - 1 ) )
306  {
307  beforeVertex = vertexcounter - 1;
308  afterVertex = vertexcounter - ( nPoints - 2 );
309  }
310  else
311  {
312  beforeVertex = vertexcounter - 1;
313  afterVertex = vertexcounter + 1;
314  }
315  }
316  if ( hasZValue ) //skip z-coordinate for 25D geometries
317  {
318  wkbPtr += sizeof( double );
319  }
320  ++vertexcounter;
321  }
322  }
323  }
324  break;
325  }
326 #endif //0
327  default:
328  break;
329  }
330  mDataIsCached = true;
331  return 0;
332 }