QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgsmeshlayerutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshlayerutils.cpp
3  --------------------------
4  begin : August 2018
5  copyright : (C) 2018 by Martin Dobias
6  email : wonder dot sk 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 
18 #include "qgsmeshlayerutils.h"
19 
20 #include "qgsmeshdataprovider.h"
21 
22 #include <limits>
23 
25 
26 void QgsMeshLayerUtils::calculateMinimumMaximum( double &min, double &max, const QVector<double> &arr )
27 {
28  bool found = false;
29 
30  min = std::numeric_limits<double>::max();
31  max = std::numeric_limits<double>::min();
32 
33  for ( const double val : arr )
34  {
35  if ( !std::isnan( val ) )
36  {
37  found = true;
38  if ( val < min )
39  min = val;
40  if ( val > max )
41  max = val;
42  }
43  }
44 
45  if ( !found )
46  {
47  min = std::numeric_limits<double>::quiet_NaN();
48  max = std::numeric_limits<double>::quiet_NaN();
49  }
50 }
51 
52 void QgsMeshLayerUtils::calculateMinMaxForDatasetGroup( double &min, double &max, QgsMeshDataProvider *provider, int groupIndex )
53 {
54  if ( groupIndex < 0 || !provider || groupIndex >= provider->datasetGroupCount() )
55  {
56  min = std::numeric_limits<double>::quiet_NaN();
57  max = std::numeric_limits<double>::quiet_NaN();
58  return;
59  }
60 
61  min = std::numeric_limits<double>::max();
62  max = std::numeric_limits<double>::min();
63 
64  int count = provider->datasetCount( groupIndex );
65  for ( int i = 0; i < count; ++i )
66  {
67  double dMin, dMax;
68  calculateMinMaxForDataset( dMin, dMax, provider, QgsMeshDatasetIndex( groupIndex, i ) );
69  min = std::min( min, dMin );
70  max = std::max( max, dMax );
71  }
72 }
73 
74 void QgsMeshLayerUtils::calculateMinMaxForDataset( double &min, double &max, QgsMeshDataProvider *provider, QgsMeshDatasetIndex index )
75 {
76  if ( !index.isValid() || !provider )
77  {
78  min = std::numeric_limits<double>::quiet_NaN();
79  max = std::numeric_limits<double>::quiet_NaN();
80  return;
81  }
82 
83  const QgsMeshDatasetGroupMetadata metadata = provider->datasetGroupMetadata( index );
84  bool onVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
85  int count;
86  if ( onVertices )
87  count = provider->vertexCount();
88  else
89  count = provider->faceCount();
90 
91  bool firstIteration = true;
92  for ( int i = 0; i < count; ++i )
93  {
94  double v = provider->datasetValue( index, i ).scalar();
95 
96  if ( std::isnan( v ) )
97  continue;
98  if ( firstIteration )
99  {
100  firstIteration = false;
101  min = v;
102  max = v;
103  }
104  else
105  {
106  if ( v < min )
107  {
108  min = v;
109  }
110  if ( v > max )
111  {
112  max = v;
113  }
114  }
115  }
116 
117 }
118 
119 void QgsMeshLayerUtils::boundingBoxToScreenRectangle( const QgsMapToPixel &mtp,
120  const QSize &outputSize,
121  const QgsRectangle &bbox,
122  int &leftLim,
123  int &rightLim,
124  int &topLim,
125  int &bottomLim )
126 {
127  QgsPointXY ll = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
128  QgsPointXY ur = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
129  topLim = std::max( int( ur.y() ), 0 );
130  bottomLim = std::min( int( ll.y() ), outputSize.height() - 1 );
131  leftLim = std::max( int( ll.x() ), 0 );
132  rightLim = std::min( int( ur.x() ), outputSize.width() - 1 );
133 }
134 
135 static void lamTol( double &lam )
136 {
137  const static double eps = 1e-6;
138  if ( ( lam < 0.0 ) && ( lam > -eps ) )
139  {
140  lam = 0.0;
141  }
142 }
143 
144 static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &pB, const QgsPointXY &pC, const QgsPointXY &pP,
145  double &lam1, double &lam2, double &lam3 )
146 {
147  if ( pA == pB || pA == pC || pB == pC )
148  return false; // this is not a valid triangle!
149 
150  // Compute vectors
151  QgsVector v0( pC - pA );
152  QgsVector v1( pB - pA );
153  QgsVector v2( pP - pA );
154 
155  // Compute dot products
156  double dot00 = v0 * v0;
157  double dot01 = v0 * v1;
158  double dot02 = v0 * v2;
159  double dot11 = v1 * v1;
160  double dot12 = v1 * v2;
161 
162  // Compute barycentric coordinates
163  double invDenom = 1.0 / ( dot00 * dot11 - dot01 * dot01 );
164  lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
165  lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
166  lam3 = 1.0 - lam1 - lam2;
167 
168  // Apply some tolerance to lam so we can detect correctly border points
169  lamTol( lam1 );
170  lamTol( lam2 );
171  lamTol( lam3 );
172 
173  // Return if POI is outside triangle
174  if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
175  {
176  return false;
177  }
178 
179  return true;
180 }
181 
182 double QgsMeshLayerUtils::interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
183  double val1, double val2, double val3, const QgsPointXY &pt )
184 {
185  double lam1, lam2, lam3;
186  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
187  return std::numeric_limits<double>::quiet_NaN();
188 
189  return lam1 * val3 + lam2 * val2 + lam3 * val1;
190 }
191 
192 double QgsMeshLayerUtils::interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
193  double val, const QgsPointXY &pt )
194 {
195  double lam1, lam2, lam3;
196  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
197  return std::numeric_limits<double>::quiet_NaN();
198 
199  return val;
200 }
201 
202 QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
203 {
204  QgsRectangle bbox;
205  bbox.combineExtentWith( p1.x(), p1.y() );
206  bbox.combineExtentWith( p2.x(), p2.y() );
207  bbox.combineExtentWith( p3.x(), p3.y() );
208  return bbox;
209 }
210 
A rectangle specified with double values.
Definition: qgsrectangle.h:40
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
virtual int faceCount() const =0
Returns number of faces in the native mesh.
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool isValid() const
Returns whether index is valid, ie at least groups is set.
virtual int datasetCount(int groupIndex) const =0
Returns number of datasets loaded in the group.
virtual int vertexCount() const =0
Returns number of vertices in the native mesh.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
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
double scalar() const
Returns magnitude of vector for vector data or scalar value for scalar data.
double x
Definition: qgspointxy.h:47
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces.
A class to represent a vector.
Definition: qgsvector.h:28
Base class for providing data for QgsMeshLayer.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
Definition: qgsrectangle.h:358
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
virtual int datasetGroupCount() const =0
Returns number of datasets groups loaded.
virtual QgsMeshDatasetValue datasetValue(QgsMeshDatasetIndex index, int valueIndex) const =0
Returns vector/scalar value associated with the index from the dataset.
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166
virtual QgsMeshDatasetGroupMetadata datasetGroupMetadata(int groupIndex) const =0
Returns dataset group metadata.