1 /***************************************************************************
2                           qgsmeshcalcutils.h
3                           ------------------
4     begin                : December 18th, 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 
18 #ifndef QGSMESHCALCUTILS_H
19 #define QGSMESHCALCUTILS_H
20 
21 #define SIP_NO_FILE
22 
23 ///@cond PRIVATE
24 
25 #include <QStringList>
26 #include <QMap>
27 #include <QVector>
28 
29 #include <algorithm>
30 #include <functional>
31 #include <math.h>
32 #include <numeric>
33 
34 #include "qgsrectangle.h"
35 #include "qgsmeshlayer.h"
36 #include "qgsmeshdataprovider.h"
37 #include "qgis_core.h"
38 
39 /**
40  * \ingroup core
41  * \class QgsMeshCalcUtils
42  * \brief Mathematical operations on QgsMeshMemoryDatasetGroup
43  *
44  * QgsMeshMemoryDatasetGroups must be compatible (same mesh structure, same number of datasets, ...)
45  * Any operation with NODATA is NODATA (e.g. NODATA + 1 = NODATA)
46  *
47  * \since QGIS 3.6
48  */
49 class CORE_EXPORT QgsMeshCalcUtils
50 {
51   public:
52 
53     /**
54      * Creates the utils and validates the input
55      *
56      * The constructor fetches all dataset values and creates memory datasets from them.
57      *
58      * \param layer mesh layer
59      * \param usedGroupNames dataset group's names that are used in the expression
60      * \param startTime start time
61      * \param endTime end time
62      */
63     QgsMeshCalcUtils( QgsMeshLayer *layer,
64                       const QStringList &usedGroupNames,
65                       double startTime,
66                       double endTime );
67 
68     /**
69      * Creates the utils and validates the input
70      *
71      * The constructor fetches dataset values from selected dataset corresponding to the relative time \a relativeTime
72      * (see QgsMeshLayer::datasetIndexAtRelativeTime() and creates memory datasets from them.
73      * There are only one dataset per group, selected with the matching method defined for the layer.
74      *
75      * \param layer mesh layer
76      * \param usedGroupNames dataset group's names that are used in the expression
77      * \param timeRange time range
78      */
79     QgsMeshCalcUtils( QgsMeshLayer *layer,
80                       const QStringList &usedGroupNames,
81                       const QgsInterval &relativeTime );
82 
83     //! Returns whether the input parameters are consistent and valid for given mesh layer
84     bool isValid() const;
85 
86     //! Returns associated mesh layer
87     const QgsMeshLayer *layer() const;
88 
89     //! Returns dataset group based on name
90     std::shared_ptr<const QgsMeshMemoryDatasetGroup> group( const QString &groupName ) const;
91 
92     //! Creates a single dataset with all values set to 1
93     void ones( QgsMeshMemoryDatasetGroup &group1 ) const;
94 
95     //! Creates a single dataset with all values set to NODATA
96     void nodata( QgsMeshMemoryDatasetGroup &group1 ) const;
97 
98     //! Returns a single dataset with all values set to val
99     std::shared_ptr<QgsMeshMemoryDataset> number( double val, double time ) const;
100 
101     //! Creates a deepcopy of group with groupName to group1. Does not copy datasets for filtered out times.
102     void copy( QgsMeshMemoryDatasetGroup &group1, const QString &groupName ) const;
103 
104     //! Creates a deepcopy of dataset0
105     std::shared_ptr<QgsMeshMemoryDataset> copy( std::shared_ptr<const QgsMeshMemoryDataset> dataset0 ) const;
106 
107     //! Changes ownership of all datasets from group2 to group1
108     void transferDatasets( QgsMeshMemoryDatasetGroup &group1, QgsMeshMemoryDatasetGroup &group2 ) const;
109 
110     //! If group2 has more datasets than group1, duplicates datasets in group1 so it has the same number of datasets as group2
111     void expand( QgsMeshMemoryDatasetGroup &group1,
112                  const QgsMeshMemoryDatasetGroup &group2 ) const;
113 
114     //! Creates a single dataset with custom number
115     void number( QgsMeshMemoryDatasetGroup &group1, double val ) const;
116 
117     //! If condition is TRUE (for given time&point), takes val from trueGroup else from falseGroup
118     void addIf( QgsMeshMemoryDatasetGroup &trueGroup,
119                 const QgsMeshMemoryDatasetGroup &falseGroup,
120                 const QgsMeshMemoryDatasetGroup &condition ) const;
121 
122     //! Creates a spatial filter from extent
123     void filter( QgsMeshMemoryDatasetGroup &group1, const QgsRectangle &extent ) const;
124 
125     //! Creates a spatial filter from geometry
126     void filter( QgsMeshMemoryDatasetGroup &group1, const QgsGeometry &mask ) const;
127 
128     //! Operator NOT
129     void logicalNot( QgsMeshMemoryDatasetGroup &group1 ) const;
130 
131     //! Operator SIGN
132     void changeSign( QgsMeshMemoryDatasetGroup &group1 ) const;
133 
134     //! Operator ABS
135     void abs( QgsMeshMemoryDatasetGroup &group1 ) const;
136 
137     //! Operator aggregated sum (over all datasets)
138     void sumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const;
139 
140     //! Operator aggregated min (over all datasets)
141     void minimumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const;
142 
143     //! Operator aggregated max (over all datasets)
144     void maximumAggregated( QgsMeshMemoryDatasetGroup &group1 ) const;
145 
146     //! Operator aggregated average (over all datasets)
147     void averageAggregated( QgsMeshMemoryDatasetGroup &group1 ) const;
148 
149     //! Operator +
150     void add( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
151 
152     //! Operator -
153     void subtract( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
154 
155     //! Operator *
156     void multiply( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
157 
158     //! Operator /
159     void divide( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
160 
161     //! Operator ^
162     void power( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
163 
164     //! Operator ==
165     void equal( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
166 
167     //! Operator !=
168     void notEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
169 
170     //! Operator >
171     void greaterThan( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
172 
173     //! Operator <
174     void lesserThan( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
175 
176     //! Operator <=
177     void lesserEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
178 
179     //! Operator >=
180     void greaterEqual( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
181 
182     //! Operator AND
183     void logicalAnd( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
184 
185     //! Operator OR
186     void logicalOr( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
187 
188     //! Operator minimum
189     void minimum( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
190 
191     //! Operator maximum
192     void maximum( QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
193 
194     //! Calculates the data type of result dataset group
195     static QgsMeshDatasetGroupMetadata::DataType determineResultDataType( QgsMeshLayer *layer, const QStringList &usedGroupNames );
196 
197     //! Returns the data type of result dataset group
198     QgsMeshDatasetGroupMetadata::DataType outputType() const;
199 
200   private:
201     double ffilter( double val1, double filter ) const;
202     double fadd( double val1, double val2 ) const;
203     double fsubtract( double val1, double val2 ) const;
204     double fmultiply( double val1, double val2 ) const;
205     double fdivide( double val1, double val2 ) const;
206     double fpower( double val1, double val2 ) const;
207     double fequal( double val1, double val2 ) const;
208     double fnotEqual( double val1, double val2 ) const;
209     double fgreaterThan( double val1, double val2 ) const;
210     double flesserThan( double val1, double val2 ) const;
211     double flesserEqual( double val1, double val2 ) const;
212     double fgreaterEqual( double val1, double val2 ) const;
213     double flogicalAnd( double val1, double val2 ) const;
214     double flogicalOr( double val1, double val2 ) const;
215     double flogicalNot( double val1 ) const;
216     double fchangeSign( double val1 ) const;
217     double fmin( double val1, double val2 ) const;
218     double fmax( double val1, double val2 ) const;
219     double fabs( double val1 ) const;
220     double fsumAggregated( QVector<double> &vals ) const;
221     double fminimumAggregated( QVector<double> &vals ) const;
222     double fmaximumAggregated( QVector<double> &vals ) const;
223     double faverageAggregated( QVector<double> &vals ) const;
224 
225     /**
226      * Clones the dataset data to memory
227      *
228      * Finds dataset group in provider with the name and copies all values to
229      * memory dataset group. Returns NULLPTR if no such dataset group
230      * exists. Resulting datasets are guaranteed to have the same mOutputType type
231      */
232     std::shared_ptr<QgsMeshMemoryDatasetGroup> createMemoryDatasetGroup( const QString &datasetGroupName, const QgsInterval &relativeTime = QgsInterval() ) const;
233 
234     /**
235      *  Creates dataset based on group. Initializes values and active based on group type.
236      */
237     std::shared_ptr<QgsMeshMemoryDataset> createMemoryDataset( const QgsMeshMemoryDatasetGroup &grp ) const;
238 
239     /**
240      *  Creates dataset based on group. Fill with values of corresponding dataset
241      */
242     std::shared_ptr<QgsMeshMemoryDataset> createMemoryDataset( const QgsMeshDatasetIndex &datasetIndex ) const;
243 
244     /**
245      *  Creates dataset with given type. Initializes values and active based on type.
246      */
247     std::shared_ptr<QgsMeshMemoryDataset> createMemoryDataset( const QgsMeshDatasetGroupMetadata::DataType type ) const;
248 
249     /**
250      * Returns dataset based on (time) index. If group has only 1 dataset, returns first one
251      */
252     std::shared_ptr<QgsMeshMemoryDataset> canditateDataset( QgsMeshMemoryDatasetGroup &group,
253         int datasetIndex ) const;
254 
255     /**
256      * Returns dataset based on on (time) index. If group has only 1 dataset, returns first one
257      */
258     std::shared_ptr<const QgsMeshMemoryDataset> constCandidateDataset( const QgsMeshMemoryDatasetGroup &group,
259         int datasetIndex ) const;
260 
261     /**
262      * Returns maximum number of datasets in the groups
263      */
264     int datasetCount( const QgsMeshMemoryDatasetGroup &group1, const QgsMeshMemoryDatasetGroup &group2 ) const;
265 
266     /**
267      * Set active property for vertices in dataset based on:
268      * if given vertex is active in dataset and refDataset
269      * if all values in vertices that are referenced by the dataset are not NODATA
270      */
271     void activate( std::shared_ptr<QgsMeshMemoryDataset> dataset,
272                    std::shared_ptr<const QgsMeshMemoryDataset> refDataset = nullptr ) const;
273 
274     //! Activates all datasets in group
275     void activate( QgsMeshMemoryDatasetGroup &group ) const;
276 
277     //! Creates spatial filter group from rectagle
278     void populateSpatialFilter( QgsMeshMemoryDatasetGroup &filter, const QgsRectangle &extent ) const; // create a filter from extent
279 
280     //! Creates mask filter group from geometry
281     void populateMaskFilter( QgsMeshMemoryDatasetGroup &filter, const QgsGeometry &mask ) const; // create a filter from mask
282 
283     //! Calculates unary operators
284     void func1( QgsMeshMemoryDatasetGroup &group,
285                 std::function<double( double )> func ) const;
286 
287     //! Calculates binary operators
288     void func2( QgsMeshMemoryDatasetGroup &group1,
289                 const QgsMeshMemoryDatasetGroup &group2,
290                 std::function<double( double, double )> func ) const;
291 
292     //! Calculates unary aggregate operator (e.g. sum of values of one vertex for all times)
293     void funcAggr( QgsMeshMemoryDatasetGroup &group1,
294                    std::function<double( QVector<double>& )> func ) const;
295 
296     const QgsTriangularMesh *triangularMesh() const;
297     const QgsMesh *nativeMesh() const;
298     void updateMesh() const;
299 
300     QgsMeshLayer *mMeshLayer; //!< Reference mesh
301     bool mIsValid; //!< All used datasets (in datasetMap) do have outputs for same times & all used dataset names are present in mesh
302     QgsMeshDatasetGroupMetadata::DataType mOutputType; //!< Mesh can work only with one output types, so you cannot mix
303     //!< E.g. one dataset with element outputs and one with node outputs
304     QVector<double> mTimes;
305     QMap < QString, std::shared_ptr<QgsMeshMemoryDatasetGroup> > mDatasetGroupMap; //!< Groups that are referenced in the expression
306 };
307 
308 ///@endcond
309 
310 #endif // QGSMESHCALCUTILS_H
311