QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgstininterpolator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstininterpolator.cpp
3  ----------------------
4  begin : March 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 "qgstininterpolator.h"
20 #include "DualEdgeTriangulation.h"
21 #include "NormVecDecorator.h"
23 #include "Point3D.h"
24 #include "qgsfeature.h"
25 #include "qgsgeometry.h"
26 #include "qgsvectorlayer.h"
27 #include <QProgressDialog>
28 
29 QgsTINInterpolator::QgsTINInterpolator( const QList<LayerData>& inputData, TIN_INTERPOLATION interpolation, bool showProgressDialog )
30  : QgsInterpolator( inputData )
31  , mTriangulation( 0 )
32  , mTriangleInterpolator( 0 )
33  , mIsInitialized( false )
34  , mShowProgressDialog( showProgressDialog )
35  , mExportTriangulationToFile( false )
36  , mInterpolation( interpolation )
37 {
38 }
39 
41 {
42  delete mTriangulation;
43  delete mTriangleInterpolator;
44 }
45 
46 int QgsTINInterpolator::interpolatePoint( double x, double y, double& result )
47 {
48  if ( !mIsInitialized )
49  {
50  initialize();
51  }
52 
53  if ( !mTriangleInterpolator )
54  {
55  return 1;
56  }
57 
58  Point3D r;
59  if ( !mTriangleInterpolator->calcPoint( x, y, &r ) )
60  {
61  return 2;
62  }
63  result = r.getZ();
64  return 0;
65 }
66 
68 {
69  DualEdgeTriangulation* theDualEdgeTriangulation = new DualEdgeTriangulation( 100000, 0 );
71  {
73  dec->addTriangulation( theDualEdgeTriangulation );
74  mTriangulation = dec;
75  }
76  else
77  {
78  mTriangulation = theDualEdgeTriangulation;
79  }
80 
81  //get number of features if we use a progress bar
82  int nFeatures = 0;
83  int nProcessedFeatures = 0;
84  if ( mShowProgressDialog )
85  {
86  QList<LayerData>::iterator layerDataIt = mLayerData.begin();
87  for ( ; layerDataIt != mLayerData.end(); ++layerDataIt )
88  {
89  if ( layerDataIt->vectorLayer )
90  {
91  nFeatures += layerDataIt->vectorLayer->featureCount();
92  }
93  }
94  }
95 
96  QProgressDialog* theProgressDialog = 0;
97  if ( mShowProgressDialog )
98  {
99  theProgressDialog = new QProgressDialog( QObject::tr( "Building triangulation..." ), QObject::tr( "Abort" ), 0, nFeatures, 0 );
100  theProgressDialog->setWindowModality( Qt::WindowModal );
101  }
102 
103 
104  QgsFeature f;
105  QList<LayerData>::iterator layerDataIt = mLayerData.begin();
106  for ( ; layerDataIt != mLayerData.end(); ++layerDataIt )
107  {
108  if ( layerDataIt->vectorLayer )
109  {
110  QgsAttributeList attList;
111  if ( !layerDataIt->zCoordInterpolation )
112  {
113  attList.push_back( layerDataIt->interpolationAttribute );
114  }
115 
116  QgsFeatureIterator fit = layerDataIt->vectorLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( attList ) );
117 
118  while ( fit.nextFeature( f ) )
119  {
120  if ( mShowProgressDialog )
121  {
122  if ( theProgressDialog->wasCanceled() )
123  {
124  break;
125  }
126  theProgressDialog->setValue( nProcessedFeatures );
127  }
128  insertData( &f, layerDataIt->zCoordInterpolation, layerDataIt->interpolationAttribute, layerDataIt->mInputType );
129  ++nProcessedFeatures;
130  }
131  }
132  }
133 
134  delete theProgressDialog;
135 
136  if ( mInterpolation == CloughTocher )
137  {
138  CloughTocherInterpolator* ctInterpolator = new CloughTocherInterpolator();
139  NormVecDecorator* dec = dynamic_cast<NormVecDecorator*>( mTriangulation );
140  if ( dec )
141  {
142  QProgressDialog* progressDialog = 0;
143  if ( mShowProgressDialog ) //show a progress dialog because it can take a long time...
144  {
145  progressDialog = new QProgressDialog();
146  progressDialog->setLabelText( QObject::tr( "Estimating normal derivatives..." ) );
147  }
148  dec->estimateFirstDerivatives( progressDialog );
149  delete progressDialog;
150  ctInterpolator->setTriangulation( dec );
151  dec->setTriangleInterpolator( ctInterpolator );
152  mTriangleInterpolator = ctInterpolator;
153  }
154  }
155  else //linear
156  {
157  mTriangleInterpolator = new LinTriangleInterpolator( theDualEdgeTriangulation );
158  }
159  mIsInitialized = true;
160 
161  //debug
163  {
164  theDualEdgeTriangulation->saveAsShapefile( mTriangulationFilePath );
165  }
166 }
167 
168 int QgsTINInterpolator::insertData( QgsFeature* f, bool zCoord, int attr, InputType type )
169 {
170  if ( !f )
171  {
172  return 1;
173  }
174 
175  QgsGeometry* g = f->geometry();
176  {
177  if ( !g )
178  {
179  return 2;
180  }
181  }
182 
183  //check attribute value
184  double attributeValue = 0;
185  bool attributeConversionOk = false;
186  if ( !zCoord )
187  {
188  QVariant attributeVariant = f->attribute( attr );
189  if ( !attributeVariant.isValid() ) //attribute not found, something must be wrong (e.g. NULL value)
190  {
191  return 3;
192  }
193  attributeValue = attributeVariant.toDouble( &attributeConversionOk );
194  if ( !attributeConversionOk || qIsNaN( attributeValue ) ) //don't consider vertices with attributes like 'nan' for the interpolation
195  {
196  return 4;
197  }
198  }
199 
200  //parse WKB. It is ugly, but we cannot use the methods with QgsPoint because they don't contain z-values for 25D types
201  bool hasZValue = false;
202  double x, y, z;
203  const unsigned char* currentWkbPtr = g->asWkb();
204  //maybe a structure or break line
205  Line3D* line = 0;
206 
207  QGis::WkbType wkbType = g->wkbType();
208  switch ( wkbType )
209  {
210  case QGis::WKBPoint25D:
211  hasZValue = true;
212  case QGis::WKBPoint:
213  {
214  currentWkbPtr += ( 1 + sizeof( int ) );
215  x = *(( double * )( currentWkbPtr ) );
216  currentWkbPtr += sizeof( double );
217  y = *(( double * )( currentWkbPtr ) );
218  if ( zCoord && hasZValue )
219  {
220  currentWkbPtr += sizeof( double );
221  z = *(( double * )( currentWkbPtr ) );
222  }
223  else
224  {
225  z = attributeValue;
226  }
227  Point3D* thePoint = new Point3D( x, y, z );
228  if ( mTriangulation->addPoint( thePoint ) == -100 )
229  {
230  return -1;
231  }
232  break;
233  }
235  hasZValue = true;
236  case QGis::WKBMultiPoint:
237  {
238  currentWkbPtr += ( 1 + sizeof( int ) );
239  int* npoints = ( int* )currentWkbPtr;
240  currentWkbPtr += sizeof( int );
241  for ( int index = 0; index < *npoints; ++index )
242  {
243  currentWkbPtr += ( 1 + sizeof( int ) ); //skip endian and point type
244  x = *(( double* )currentWkbPtr );
245  currentWkbPtr += sizeof( double );
246  y = *(( double* )currentWkbPtr );
247  currentWkbPtr += sizeof( double );
248  if ( hasZValue ) //skip z-coordinate for 25D geometries
249  {
250  z = *(( double* )currentWkbPtr );
251  currentWkbPtr += sizeof( double );
252  }
253  else
254  {
255  z = attributeValue;
256  }
257  }
258  break;
259  }
261  hasZValue = true;
262  case QGis::WKBLineString:
263  {
264  if ( type != POINTS )
265  {
266  line = new Line3D();
267  }
268  currentWkbPtr += ( 1 + sizeof( int ) );
269  int* npoints = ( int* )currentWkbPtr;
270  currentWkbPtr += sizeof( int );
271  for ( int index = 0; index < *npoints; ++index )
272  {
273  x = *(( double * )( currentWkbPtr ) );
274  currentWkbPtr += sizeof( double );
275  y = *(( double * )( currentWkbPtr ) );
276  currentWkbPtr += sizeof( double );
277  if ( zCoord && hasZValue ) //skip z-coordinate for 25D geometries
278  {
279  z = *(( double * )( currentWkbPtr ) );
280  }
281  else
282  {
283  z = attributeValue;
284  }
285  if ( hasZValue )
286  {
287  currentWkbPtr += sizeof( double );
288  }
289 
290  if ( type == POINTS )
291  {
292  //todo: handle error code -100
293  mTriangulation->addPoint( new Point3D( x, y, z ) );
294  }
295  else
296  {
297  line->insertPoint( new Point3D( x, y, z ) );
298  }
299  }
300 
301  if ( type != POINTS )
302  {
303  mTriangulation->addLine( line, type == BREAK_LINES );
304  }
305  break;
306  }
308  hasZValue = true;
310  {
311  currentWkbPtr += ( 1 + sizeof( int ) );
312  int* nlines = ( int* )currentWkbPtr;
313  int* npoints = 0;
314  currentWkbPtr += sizeof( int );
315  for ( int index = 0; index < *nlines; ++index )
316  {
317  if ( type != POINTS )
318  {
319  line = new Line3D();
320  }
321  currentWkbPtr += ( sizeof( int ) + 1 );
322  npoints = ( int* )currentWkbPtr;
323  currentWkbPtr += sizeof( int );
324  for ( int index2 = 0; index2 < *npoints; ++index2 )
325  {
326  x = *(( double* )currentWkbPtr );
327  currentWkbPtr += sizeof( double );
328  y = *(( double* )currentWkbPtr );
329  currentWkbPtr += sizeof( double );
330 
331  if ( hasZValue ) //skip z-coordinate for 25D geometries
332  {
333  z = *(( double* ) currentWkbPtr );
334  currentWkbPtr += sizeof( double );
335  }
336  else
337  {
338  z = attributeValue;
339  }
340 
341  if ( type == POINTS )
342  {
343  //todo: handle error code -100
344  mTriangulation->addPoint( new Point3D( x, y, z ) );
345  }
346  else
347  {
348  line->insertPoint( new Point3D( x, y, z ) );
349  }
350  }
351  if ( type != POINTS )
352  {
353  mTriangulation->addLine( line, type == BREAK_LINES );
354  }
355  }
356  break;
357  }
358  case QGis::WKBPolygon25D:
359  hasZValue = true;
360  case QGis::WKBPolygon:
361  {
362  currentWkbPtr += ( 1 + sizeof( int ) );
363  int* nrings = ( int* )currentWkbPtr;
364  currentWkbPtr += sizeof( int );
365  int* npoints;
366  for ( int index = 0; index < *nrings; ++index )
367  {
368  if ( type != POINTS )
369  {
370  line = new Line3D();
371  }
372 
373  npoints = ( int* )currentWkbPtr;
374  currentWkbPtr += sizeof( int );
375  for ( int index2 = 0; index2 < *npoints; ++index2 )
376  {
377  x = *(( double* )currentWkbPtr );
378  currentWkbPtr += sizeof( double );
379  y = *(( double* )currentWkbPtr );
380  currentWkbPtr += sizeof( double );
381  if ( hasZValue ) //skip z-coordinate for 25D geometries
382  {
383  z = *(( double* )currentWkbPtr );;
384  currentWkbPtr += sizeof( double );
385  }
386  else
387  {
388  z = attributeValue;
389  }
390  if ( type == POINTS )
391  {
392  //todo: handle error code -100
393  mTriangulation->addPoint( new Point3D( x, y, z ) );
394  }
395  else
396  {
397  line->insertPoint( new Point3D( x, y, z ) );
398  }
399  }
400 
401  if ( type != POINTS )
402  {
403  mTriangulation->addLine( line, type == BREAK_LINES );
404  }
405  }
406  break;
407  }
408 
410  hasZValue = true;
412  {
413  currentWkbPtr += ( 1 + sizeof( int ) );
414  int* npolys = ( int* )currentWkbPtr;
415  int* nrings;
416  int* npoints;
417  currentWkbPtr += sizeof( int );
418  for ( int index = 0; index < *npolys; ++index )
419  {
420  currentWkbPtr += ( 1 + sizeof( int ) ); //skip endian and polygon type
421  nrings = ( int* )currentWkbPtr;
422  currentWkbPtr += sizeof( int );
423  for ( int index2 = 0; index2 < *nrings; ++index2 )
424  {
425  if ( type != POINTS )
426  {
427  line = new Line3D();
428  }
429  npoints = ( int* )currentWkbPtr;
430  currentWkbPtr += sizeof( int );
431  for ( int index3 = 0; index3 < *npoints; ++index3 )
432  {
433  x = *(( double* )currentWkbPtr );
434  currentWkbPtr += sizeof( double );
435  y = *(( double* )currentWkbPtr );
436  currentWkbPtr += sizeof( double );
437  if ( hasZValue ) //skip z-coordinate for 25D geometries
438  {
439  z = *(( double* )currentWkbPtr );
440  currentWkbPtr += sizeof( double );
441  }
442  else
443  {
444  z = attributeValue;
445  }
446  if ( type == POINTS )
447  {
448  //todo: handle error code -100
449  mTriangulation->addPoint( new Point3D( x, y, z ) );
450  }
451  else
452  {
453  line->insertPoint( new Point3D( x, y, z ) );
454  }
455  }
456  if ( type != POINTS )
457  {
458  mTriangulation->addLine( line, type == BREAK_LINES );
459  }
460  }
461  }
462  break;
463  }
464  default:
465  //should not happen...
466  break;
467  }
468 
469  return 0;
470 }
471