QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 #include "qgsmeshtimesettings.h"
20 
21 #include <limits>
22 #include <QTime>
23 #include <QDateTime>
24 
26 
27 QVector<double> QgsMeshLayerUtils::calculateMagnitudes( const QgsMeshDataBlock &block )
28 {
29  Q_ASSERT( QgsMeshDataBlock::ActiveFlagInteger != block.type() );
30  int count = block.count();
31  QVector<double> ret( count );
32 
33  for ( int i = 0; i < count; ++i )
34  {
35  double mag = block.value( i ).scalar();
36  ret[i] = mag;
37  }
38  return ret;
39 }
40 
41 void QgsMeshLayerUtils::boundingBoxToScreenRectangle( const QgsMapToPixel &mtp,
42  const QSize &outputSize,
43  const QgsRectangle &bbox,
44  int &leftLim,
45  int &rightLim,
46  int &topLim,
47  int &bottomLim )
48 {
49  QgsPointXY ll = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
50  QgsPointXY ur = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
51  topLim = std::max( int( ur.y() ), 0 );
52  bottomLim = std::min( int( ll.y() ), outputSize.height() - 1 );
53  leftLim = std::max( int( ll.x() ), 0 );
54  rightLim = std::min( int( ur.x() ), outputSize.width() - 1 );
55 }
56 
57 static void lamTol( double &lam )
58 {
59  const static double eps = 1e-6;
60  if ( ( lam < 0.0 ) && ( lam > -eps ) )
61  {
62  lam = 0.0;
63  }
64 }
65 
66 static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &pB, const QgsPointXY &pC, const QgsPointXY &pP,
67  double &lam1, double &lam2, double &lam3 )
68 {
69  if ( pA == pB || pA == pC || pB == pC )
70  return false; // this is not a valid triangle!
71 
72  // Compute vectors
73  QgsVector v0( pC - pA );
74  QgsVector v1( pB - pA );
75  QgsVector v2( pP - pA );
76 
77  // Compute dot products
78  double dot00 = v0 * v0;
79  double dot01 = v0 * v1;
80  double dot02 = v0 * v2;
81  double dot11 = v1 * v1;
82  double dot12 = v1 * v2;
83 
84  // Compute barycentric coordinates
85  double invDenom = 1.0 / ( dot00 * dot11 - dot01 * dot01 );
86  lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
87  lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
88  lam3 = 1.0 - lam1 - lam2;
89 
90  // Apply some tolerance to lam so we can detect correctly border points
91  lamTol( lam1 );
92  lamTol( lam2 );
93  lamTol( lam3 );
94 
95  // Return if POI is outside triangle
96  if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
97  {
98  return false;
99  }
100 
101  return true;
102 }
103 
104 double QgsMeshLayerUtils::interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
105  double val1, double val2, double val3, const QgsPointXY &pt )
106 {
107  double lam1, lam2, lam3;
108  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
109  return std::numeric_limits<double>::quiet_NaN();
110 
111  return lam1 * val3 + lam2 * val2 + lam3 * val1;
112 }
113 
114 double QgsMeshLayerUtils::interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
115  double val, const QgsPointXY &pt )
116 {
117  double lam1, lam2, lam3;
118  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
119  return std::numeric_limits<double>::quiet_NaN();
120 
121  return val;
122 }
123 
124 QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
125 {
126  // p1
127  double xMin = p1.x();
128  double xMax = p1.x();
129  double yMin = p1.y();
130  double yMax = p1.y();
131 
132  //p2
133  xMin = ( ( xMin < p2.x() ) ? xMin : p2.x() );
134  xMax = ( ( xMax > p2.x() ) ? xMax : p2.x() );
135  yMin = ( ( yMin < p2.y() ) ? yMin : p2.y() );
136  yMax = ( ( yMax > p2.y() ) ? yMax : p2.y() );
137 
138  // p3
139  xMin = ( ( xMin < p3.x() ) ? xMin : p3.x() );
140  xMax = ( ( xMax > p3.x() ) ? xMax : p3.x() );
141  yMin = ( ( yMin < p3.y() ) ? yMin : p3.y() );
142  yMax = ( ( yMax > p3.y() ) ? yMax : p3.y() );
143 
144  QgsRectangle bbox( xMin, yMin, xMax, yMax );
145  return bbox;
146 }
147 
148 QString QgsMeshLayerUtils::formatTime( double hours, const QgsMeshTimeSettings &settings )
149 {
150  QString ret;
151  if ( settings.useAbsoluteTime() )
152  {
153  QString format( settings.absoluteTimeFormat() );
154  QDateTime dateTime( settings.absoluteTimeReferenceTime() );
155  int seconds = static_cast<int>( hours * 3600.0 );
156  dateTime = dateTime.addSecs( seconds );
157  ret = dateTime.toString( format );
158  if ( ret.isEmpty() ) // error
159  ret = dateTime.toString();
160  }
161  else
162  {
163  QString format( settings.relativeTimeFormat() );
164  format = format.trimmed();
165  hours = hours + settings.relativeTimeOffsetHours();
166  int totalHours = static_cast<int>( hours );
167 
168  if ( format == QStringLiteral( "hh:mm:ss.zzz" ) )
169  {
170  int ms = static_cast<int>( hours * 3600.0 * 1000 );
171  int seconds = ms / 1000;
172  int z = ms % 1000;
173  int m = seconds / 60;
174  int s = seconds % 60;
175  int h = m / 60;
176  m = m % 60;
177  ret = QStringLiteral( "%1:%2:%3.%4" ).
178  arg( h, 2, 10, QLatin1Char( '0' ) ).
179  arg( m, 2, 10, QLatin1Char( '0' ) ).
180  arg( s, 2, 10, QLatin1Char( '0' ) ).
181  arg( z, 3, 10, QLatin1Char( '0' ) );
182  }
183  else if ( format == QStringLiteral( "hh:mm:ss" ) )
184  {
185  int seconds = static_cast<int>( hours * 3600.0 );
186  int m = seconds / 60;
187  int s = seconds % 60;
188  int h = m / 60;
189  m = m % 60;
190  ret = QStringLiteral( "%1:%2:%3" ).
191  arg( h, 2, 10, QLatin1Char( '0' ) ).
192  arg( m, 2, 10, QLatin1Char( '0' ) ).
193  arg( s, 2, 10, QLatin1Char( '0' ) );
194 
195  }
196  else if ( format == QStringLiteral( "d hh:mm:ss" ) )
197  {
198  int seconds = static_cast<int>( hours * 3600.0 );
199  int m = seconds / 60;
200  int s = seconds % 60;
201  int h = m / 60;
202  m = m % 60;
203  int d = totalHours / 24;
204  h = totalHours % 24;
205  ret = QStringLiteral( "%1 d %2:%3:%4" ).
206  arg( d ).
207  arg( h, 2, 10, QLatin1Char( '0' ) ).
208  arg( m, 2, 10, QLatin1Char( '0' ) ).
209  arg( s, 2, 10, QLatin1Char( '0' ) );
210  }
211  else if ( format == QStringLiteral( "d hh" ) )
212  {
213  int d = totalHours / 24;
214  int h = totalHours % 24;
215  ret = QStringLiteral( "%1 d %2" ).
216  arg( d ).
217  arg( h );
218  }
219  else if ( format == QStringLiteral( "d" ) )
220  {
221  int d = totalHours / 24;
222  ret = QStringLiteral( "%1" ).arg( d );
223  }
224  else if ( format == QStringLiteral( "ss" ) )
225  {
226  int seconds = static_cast<int>( hours * 3600.0 );
227  ret = QStringLiteral( "%1" ).arg( seconds );
228  }
229  else // "hh"
230  {
231  ret = QStringLiteral( "%1" ).arg( hours );
232  }
233  }
234  return ret;
235 }
236 
A rectangle specified with double values.
Definition: qgsrectangle.h:41
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
int count() const
Number of items stored in the block.
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e...
DataType type() const
Type of data stored in the block.
double relativeTimeOffsetHours() const
Returns number of offset hours for relative time formatting.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:37
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
QString absoluteTimeFormat() const
Returns format used for absolute time.
Integer boolean flag whether face is active.
bool useAbsoluteTime() const
Returns whether to use absolute time format.
double scalar() const
Returns magnitude of vector for vector data or scalar value for scalar data.
Represents a mesh time settings for mesh datasets.
double x
Definition: qgspointxy.h:47
A class to represent a vector.
Definition: qgsvector.h:29
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
QDateTime absoluteTimeReferenceTime() const
Returns reference time used for absolute time format.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
QgsMeshDatasetValue value(int index) const
Returns a value represented by the index For active flag the behavior is undefined.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
QString relativeTimeFormat() const
Returns format used for relative time.