QGIS API Documentation  2.99.0-Master (f1c3692)
qgsrastermatrix.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrastermatrix.cpp
3  -------------------
4  begin : 2010-10-23
5  copyright : (C) 20010 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole 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 "qgsrastermatrix.h"
19 #include <cstring>
20 #include <cmath>
21 
22 QgsRasterMatrix::QgsRasterMatrix( int nCols, int nRows, double *data, double nodataValue )
23  : mColumns( nCols )
24  , mRows( nRows )
25  , mData( data )
26  , mNodataValue( nodataValue )
27 {
28 }
29 
31 {
32  operator=( m );
33 }
34 
36 {
37  delete[] mData;
38 }
39 
41 {
42  delete[] mData;
43  mColumns = m.nColumns();
44  mRows = m.nRows();
45  int nEntries = mColumns * mRows;
46  mData = new double[nEntries];
47  memcpy( mData, m.mData, sizeof( double ) * nEntries );
48  mNodataValue = m.nodataValue();
49  return *this;
50 }
51 
52 void QgsRasterMatrix::setData( int cols, int rows, double *data, double nodataValue )
53 {
54  delete[] mData;
55  mColumns = cols;
56  mRows = rows;
57  mData = data;
58  mNodataValue = nodataValue;
59 }
60 
62 {
63  double *data = mData;
64  mData = nullptr;
65  mColumns = 0;
66  mRows = 0;
67  return data;
68 }
69 
71 {
72  return twoArgumentOperation( opPLUS, other );
73 }
74 
76 {
77  return twoArgumentOperation( opMINUS, other );
78 }
79 
81 {
82  return twoArgumentOperation( opMUL, other );
83 }
84 
86 {
87  return twoArgumentOperation( opDIV, other );
88 }
89 
91 {
92  return twoArgumentOperation( opPOW, other );
93 }
94 
96 {
97  return twoArgumentOperation( opEQ, other );
98 }
99 
101 {
102  return twoArgumentOperation( opNE, other );
103 }
104 
106 {
107  return twoArgumentOperation( opGT, other );
108 }
109 
111 {
112  return twoArgumentOperation( opLT, other );
113 }
114 
116 {
117  return twoArgumentOperation( opGE, other );
118 }
119 
121 {
122  return twoArgumentOperation( opLE, other );
123 }
124 
126 {
127  return twoArgumentOperation( opAND, other );
128 }
129 
131 {
132  return twoArgumentOperation( opOR, other );
133 }
134 
136 {
137  return oneArgumentOperation( opSQRT );
138 }
139 
141 {
142  return oneArgumentOperation( opSIN );
143 }
144 
146 {
147  return oneArgumentOperation( opASIN );
148 }
149 
151 {
152  return oneArgumentOperation( opCOS );
153 }
154 
156 {
157  return oneArgumentOperation( opACOS );
158 }
159 
161 {
162  return oneArgumentOperation( opTAN );
163 }
164 
166 {
167  return oneArgumentOperation( opATAN );
168 }
169 
171 {
172  return oneArgumentOperation( opSIGN );
173 }
174 
176 {
177  return oneArgumentOperation( opLOG );
178 }
179 
181 {
182  return oneArgumentOperation( opLOG10 );
183 }
184 
185 bool QgsRasterMatrix::oneArgumentOperation( OneArgOperator op )
186 {
187  if ( !mData )
188  {
189  return false;
190  }
191 
192  int nEntries = mColumns * mRows;
193  double value;
194  for ( int i = 0; i < nEntries; ++i )
195  {
196  value = mData[i];
197  if ( value != mNodataValue )
198  {
199  switch ( op )
200  {
201  case opSQRT:
202  if ( value < 0 ) //no complex numbers
203  {
204  mData[i] = mNodataValue;
205  }
206  else
207  {
208  mData[i] = std::sqrt( value );
209  }
210  break;
211  case opSIN:
212  mData[i] = std::sin( value );
213  break;
214  case opCOS:
215  mData[i] = std::cos( value );
216  break;
217  case opTAN:
218  mData[i] = std::tan( value );
219  break;
220  case opASIN:
221  mData[i] = std::asin( value );
222  break;
223  case opACOS:
224  mData[i] = std::acos( value );
225  break;
226  case opATAN:
227  mData[i] = std::atan( value );
228  break;
229  case opSIGN:
230  mData[i] = -value;
231  break;
232  case opLOG:
233  if ( value <= 0 )
234  {
235  mData[i] = mNodataValue;
236  }
237  else
238  {
239  mData[i] = ::log( value );
240  }
241  break;
242  case opLOG10:
243  if ( value <= 0 )
244  {
245  mData[i] = mNodataValue;
246  }
247  else
248  {
249  mData[i] = ::log10( value );
250  }
251  break;
252  }
253  }
254  }
255  return true;
256 }
257 
258 double QgsRasterMatrix::calculateTwoArgumentOp( TwoArgOperator op, double arg1, double arg2 ) const
259 {
260  switch ( op )
261  {
262  case opPLUS:
263  return arg1 + arg2;
264  case opMINUS:
265  return arg1 - arg2;
266  case opMUL:
267  return arg1 * arg2;
268  case opDIV:
269  if ( arg2 == 0 )
270  {
271  return mNodataValue;
272  }
273  else
274  {
275  return arg1 / arg2;
276  }
277  case opPOW:
278  if ( !testPowerValidity( arg1, arg2 ) )
279  {
280  return mNodataValue;
281  }
282  else
283  {
284  return std::pow( arg1, arg2 );
285  }
286  case opEQ:
287  return ( arg1 == arg2 ? 1.0 : 0.0 );
288  case opNE:
289  return ( arg1 == arg2 ? 0.0 : 1.0 );
290  case opGT:
291  return ( arg1 > arg2 ? 1.0 : 0.0 );
292  case opLT:
293  return ( arg1 < arg2 ? 1.0 : 0.0 );
294  case opGE:
295  return ( arg1 >= arg2 ? 1.0 : 0.0 );
296  case opLE:
297  return ( arg1 <= arg2 ? 1.0 : 0.0 );
298  case opAND:
299  return ( arg1 && arg2 ? 1.0 : 0.0 );
300  case opOR:
301  return ( arg1 || arg2 ? 1.0 : 0.0 );
302  }
303  return mNodataValue;
304 }
305 
306 bool QgsRasterMatrix::twoArgumentOperation( TwoArgOperator op, const QgsRasterMatrix &other )
307 {
308  if ( isNumber() && other.isNumber() ) //operation on two 1x1 matrices
309  {
310  //operations with nodata values always generate nodata
311  if ( mData[0] == mNodataValue || other.number() == other.nodataValue() )
312  {
313  mData[0] = mNodataValue;
314  }
315  else
316  {
317  mData[0] = calculateTwoArgumentOp( op, mData[0], other.number() );
318  }
319  return true;
320  }
321 
322  //two matrices
323  if ( !isNumber() && !other.isNumber() )
324  {
325  double *matrix = other.mData;
326  int nEntries = mColumns * mRows;
327  double value1, value2;
328 
329  for ( int i = 0; i < nEntries; ++i )
330  {
331  value1 = mData[i];
332  value2 = matrix[i];
333  if ( value1 == mNodataValue || value2 == other.mNodataValue )
334  {
335  mData[i] = mNodataValue;
336  }
337  else
338  {
339  mData[i] = calculateTwoArgumentOp( op, value1, value2 );
340  }
341  }
342  return true;
343  }
344 
345  //this matrix is a single number and the other one a real matrix
346  if ( isNumber() )
347  {
348  double *matrix = other.mData;
349  int nEntries = other.nColumns() * other.nRows();
350  double value = mData[0];
351  delete[] mData;
352  mData = new double[nEntries];
353  mColumns = other.nColumns();
354  mRows = other.nRows();
355  mNodataValue = other.nodataValue();
356 
357  if ( value == mNodataValue )
358  {
359  for ( int i = 0; i < nEntries; ++i )
360  {
361  mData[i] = mNodataValue;
362  }
363  return true;
364  }
365 
366  for ( int i = 0; i < nEntries; ++i )
367  {
368  if ( matrix[i] == other.mNodataValue )
369  {
370  mData[i] = mNodataValue;
371  continue;
372  }
373 
374  mData[i] = calculateTwoArgumentOp( op, value, matrix[i] );
375  }
376  return true;
377  }
378  else //this matrix is a real matrix and the other a number
379  {
380  double value = other.number();
381  int nEntries = mColumns * mRows;
382 
383  if ( other.number() == other.mNodataValue )
384  {
385  for ( int i = 0; i < nEntries; ++i )
386  {
387  mData[i] = mNodataValue;
388  }
389  return true;
390  }
391 
392  for ( int i = 0; i < nEntries; ++i )
393  {
394  if ( mData[i] == mNodataValue )
395  {
396  continue;
397  }
398 
399  mData[i] = calculateTwoArgumentOp( op, mData[i], value );
400  }
401  return true;
402  }
403 }
404 
405 bool QgsRasterMatrix::testPowerValidity( double base, double power ) const
406 {
407  return !( ( base == 0 && power < 0 ) || ( base < 0 && ( power - std::floor( power ) ) > 0 ) );
408 }
double * takeData()
Returns data and ownership.
bool isNumber() const
Returns true if matrix is 1x1 (=scalar number)
QgsRasterMatrix & operator=(const QgsRasterMatrix &m)
bool add(const QgsRasterMatrix &other)
Adds another matrix to this one.
double nodataValue() const
bool power(const QgsRasterMatrix &other)
bool greaterThan(const QgsRasterMatrix &other)
bool notEqual(const QgsRasterMatrix &other)
bool equal(const QgsRasterMatrix &other)
int nRows() const
bool logicalOr(const QgsRasterMatrix &other)
void setData(int cols, int rows, double *data, double nodataValue)
QgsRasterMatrix()=default
Takes ownership of data array.
bool subtract(const QgsRasterMatrix &other)
Subtracts another matrix from this one.
bool multiply(const QgsRasterMatrix &other)
int nColumns() const
bool lesserEqual(const QgsRasterMatrix &other)
bool divide(const QgsRasterMatrix &other)
bool greaterEqual(const QgsRasterMatrix &other)
double number() const
double * data()
Returns data array (but not ownership)
bool lesserThan(const QgsRasterMatrix &other)
bool logicalAnd(const QgsRasterMatrix &other)