QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsmeshlayerinterpolator.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshlayerinterpolator.cpp
3  ----------------------------
4  begin : April 2018
5  copyright : (C) 2018 by Peter Petrik
6  email : zilolv at gmail dot com
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 
19 
20 #include <memory>
21 
23 
24 #include "qgsrasterinterface.h"
25 #include "qgsmaptopixel.h"
26 #include "qgsvector.h"
27 #include "qgspoint.h"
28 #include "qgspointxy.h"
29 
30 static void bbox2rect(
31  const QgsMapToPixel &mtp,
32  const QSize &outputSize,
33  const QgsRectangle &bbox,
34  int &leftLim, int &rightLim, int &topLim, int &bottomLim )
35 {
36  QgsPointXY ll = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
37  QgsPointXY ur = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
38  topLim = std::max( int( ur.y() ), 0 );
39  bottomLim = std::min( int( ll.y() ), outputSize.height() - 1 );
40  leftLim = std::max( int( ll.x() ), 0 );
41  rightLim = std::min( int( ur.x() ), outputSize.width() - 1 );
42 }
43 
44 static void lamTol( double &lam )
45 {
46  const static double eps = 1e-6;
47  if ( ( lam < 0.0 ) && ( lam > -eps ) )
48  {
49  lam = 0.0;
50  }
51 }
52 
53 static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &pB, const QgsPointXY &pC, const QgsPointXY &pP,
54  double &lam1, double &lam2, double &lam3 )
55 {
56  if ( pA == pB || pA == pC || pB == pC )
57  return false; // this is not a valid triangle!
58 
59  // Compute vectors
60  QgsVector v0( pC - pA );
61  QgsVector v1( pB - pA );
62  QgsVector v2( pP - pA );
63 
64  // Compute dot products
65  double dot00 = v0 * v0;
66  double dot01 = v0 * v1;
67  double dot02 = v0 * v2;
68  double dot11 = v1 * v1;
69  double dot12 = v1 * v2;
70 
71  // Compute barycentric coordinates
72  double invDenom = 1.0 / ( dot00 * dot11 - dot01 * dot01 );
73  lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
74  lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
75  lam3 = 1.0 - lam1 - lam2;
76 
77  // Apply some tolerance to lam so we can detect correctly border points
78  lamTol( lam1 );
79  lamTol( lam2 );
80  lamTol( lam3 );
81 
82  // Return if POI is outside triangle
83  if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
84  {
85  return false;
86  }
87 
88  return true;
89 }
90 
91 
92 double interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
93  double val1, double val2, double val3, const QgsPointXY &pt )
94 {
95  double lam1, lam2, lam3;
96  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
97  return std::numeric_limits<double>::quiet_NaN();
98 
99  return lam1 * val3 + lam2 * val2 + lam3 * val1;
100 }
101 
102 double interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, double val, const QgsPointXY &pt )
103 {
104  double lam1, lam2, lam3;
105  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
106  return std::numeric_limits<double>::quiet_NaN();
107 
108  return val;
109 }
110 
111 QgsMeshLayerInterpolator::QgsMeshLayerInterpolator(
112  const QgsTriangularMesh &m,
113  const QVector<double> &datasetValues,
114  bool dataIsOnVertices,
115  const QgsRenderContext &context,
116  const QSize &size )
117  : mTriangularMesh( m ),
118  mDatasetValues( datasetValues ),
119  mContext( context ),
120  mDataOnVertices( dataIsOnVertices ),
121  mOutputSize( size )
122 {
123 }
124 
125 QgsMeshLayerInterpolator::~QgsMeshLayerInterpolator() = default;
126 
127 QgsRasterInterface *QgsMeshLayerInterpolator::clone() const
128 {
129  assert( false ); // we should not need this (hopefully)
130  return nullptr;
131 }
132 
133 Qgis::DataType QgsMeshLayerInterpolator::dataType( int ) const
134 {
135  return Qgis::Float64;
136 }
137 
138 int QgsMeshLayerInterpolator::bandCount() const
139 {
140  return 1;
141 }
142 
143 QgsRasterBlock *QgsMeshLayerInterpolator::block( int, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
144 {
145  std::unique_ptr<QgsRasterBlock> outputBlock( new QgsRasterBlock( Qgis::Float64, width, height ) );
146  outputBlock->setIsNoData(); // assume initially that all values are unset
147  double *data = reinterpret_cast<double *>( outputBlock->bits() );
148 
149  const QVector<QgsMeshFace> &triangles = mTriangularMesh.triangles();
150  const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
151 
152  // currently expecting that triangulation does not add any new extra vertices on the way
153  if ( mDataOnVertices )
154  Q_ASSERT( mDatasetValues.count() == mTriangularMesh.vertices().count() );
155 
156  for ( int i = 0; i < triangles.size(); ++i )
157  {
158  if ( feedback && feedback->isCanceled() )
159  break;
160 
161  const QgsMeshFace &face = triangles[i];
162 
163  const int v1 = face[0], v2 = face[1], v3 = face[2];
164  const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];
165 
166  QgsRectangle bbox;
167  bbox.combineExtentWith( p1.x(), p1.y() );
168  bbox.combineExtentWith( p2.x(), p2.y() );
169  bbox.combineExtentWith( p3.x(), p3.y() );
170  if ( !extent.intersects( bbox ) )
171  continue;
172 
173  // Get the BBox of the element in pixels
174  int topLim, bottomLim, leftLim, rightLim;
175  bbox2rect( mContext.mapToPixel(), mOutputSize, bbox, leftLim, rightLim, topLim, bottomLim );
176 
177  // interpolate in the bounding box of the face
178  for ( int j = topLim; j <= bottomLim; j++ )
179  {
180  double *line = data + ( j * width );
181  for ( int k = leftLim; k <= rightLim; k++ )
182  {
183  double val;
184  const QgsPointXY p = mContext.mapToPixel().toMapCoordinates( k, j );
185  if ( mDataOnVertices )
186  val = interpolateFromVerticesData(
187  p1,
188  p2,
189  p3,
190  mDatasetValues[v1],
191  mDatasetValues[v2],
192  mDatasetValues[v3],
193  p );
194  else
195  {
196  int face = mTriangularMesh.trianglesToNativeFaces()[i];
197  val = interpolateFromFacesData(
198  p1,
199  p2,
200  p3,
201  mDatasetValues[face],
202  p
203  );
204  }
205 
206  if ( !std::isnan( val ) )
207  {
208  line[k] = val;
209  outputBlock->setIsData( j, k );
210  }
211  }
212  }
213 
214  }
215 
216  return outputBlock.release();;
217 }
218 
A rectangle specified with double values.
Definition: qgsrectangle.h:40
double y
Definition: qgspoint.h:42
Triangular/Derived Mesh.
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
DataType
Raster data types.
Definition: qgis.h:91
Sixty four bit floating point (double)
Definition: qgis.h:100
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
QgsRectangle extent() const override
Returns the extent of the layer.
Raster data container.
Base class for processing filters like renderers, reprojector, resampler etc.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
double x
Definition: qgspointxy.h:47
A class to represent a vector.
Definition: qgsvector.h:28
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
Definition: qgsrectangle.h:352
Contains information about the context of a rendering operation.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
QVector< int > QgsMeshFace
List of vertex indexes.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:321
Feedback object tailored for raster block reading.
double x
Definition: qgspoint.h:41