Ilwis-Objects  1.0
GIS and Remote Sensing framework for data access and processing
 All Classes Functions Enumerations Pages
box.h
1 #ifndef BOX_H
2 #define BOX_H
3 
4 #include <QSize>
5 #include "size.h"
6 #include "errmessages.h"
7 #include "range.h"
8 
9 namespace Ilwis {
14 template<class PointType=Coordinate> class Box : public Range{
15 public:
16  enum Dimension{dim0=0, dimX=1, dimY=2, dimZ=4};
17 
18  Box() : _min_corner(PointType(0,0,0)), _max_corner(PointType(0,0,0)){
19  }
20 
21  Box(const PointType& pMin, const PointType& pMax) : _min_corner(pMin), _max_corner(pMax){
22  normalize();
23  }
24 
25  Box(const Box<PointType>& bx) : _min_corner(bx.min_corner()), _max_corner(bx.max_corner()) {
26 
27  }
28 
29  Box(Box<PointType>&& box) :
30  _min_corner(std::move(box._min_corner)),
31  _max_corner(std::move(box._max_corner))
32  {
33  box._min_corner = box._max_corner = PointType();
34  }
35 
36  Box(const QSize& sz) : _min_corner(PointType(0,0,0)),_max_corner(PointType(sz.width()-1, sz.height()-1),0){
37  }
38 
39  template<typename T> Box(const Size<T>& sz) : _min_corner(PointType(0,0,0)),_max_corner(PointType(sz.xsize()-1, sz.ysize()-1,sz.zsize()-1)){
40  }
41 
46  Box(const QString& envelope) : _min_corner(PointType(0,0)), _max_corner(PointType(0,0)){
47  int index1 = envelope.indexOf("(");
48  if ( index1 != -1) {
49  int index2 = envelope.indexOf(")") ;
50  if ( index2 == -1){
51  return;
52  }
53 
54  QString coords = envelope.mid(index1+1, index2 - index1 - 1);
55  coords = coords.trimmed();
56  QStringList parts = coords.split(",");
57  if ( parts.size() != 2){
58  return;
59  }
60  QStringList p1 = parts[0].trimmed().split(' ');
61  if ( p1.size() < 2)
62  return;
63  this->min_corner().x = p1[0].trimmed().toDouble();
64  this->min_corner().y = p1[1].trimmed().toDouble();
65  if ( p1.size() == 3)
66  this->min_corner().z = p1[2].trimmed().toDouble();
67 
68  QStringList p2 = parts[1].trimmed().split(' ');
69  if ( p1.size() < 2) {
70  this->min_corner().x = 0;
71  this->min_corner().y = 0;
72  this->min_corner().z = 0;
73  return;
74  }
75  this->max_corner().x = p2[0].trimmed().toDouble();
76  this->max_corner().y = p2[1].trimmed().toDouble();
77  if ( p2.size() == 3)
78  this->max_corner().z = p2[2].trimmed().toDouble();
79  }
80  }
81 
82  IlwisTypes valueType() const{
83  return max_corner().valuetype();
84  }
85 
86  Range *clone() const{
87  return new Box<PointType>(*this);
88  }
89 
90 
91  PointType min_corner() const {
92  return _min_corner;
93  }
94 
95  PointType max_corner() const {
96  return _max_corner;
97  }
98 
99  PointType& min_corner() {
100  return _min_corner;
101  }
102 
103  PointType& max_corner() {
104  return _max_corner;
105  }
106 
107  double xlength() const {
108  return std::abs(this->min_corner().x - this->max_corner().x) + 1;
109  }
110 
111  double ylength() const {
112  return std::abs(this->min_corner().y - this->max_corner().y) + 1;
113  }
114 
115  double zlength() const {
116  return std::abs(this->min_corner().z - this->max_corner().z) + 1;
117  }
118 
119  template<typename T=quint32> Size<T> size() const {
120  return Size<T>(xlength(), ylength(), zlength());
121  }
122 
123  bool is3D() const {
124  return this->min_corner().is3D() && this->max_corner().is3D();
125  }
126  quint64 area() const {
127  if ( !isValid())
128  return 0;
129  return xlength() * ylength();
130  }
131 
132  quint64 volume() const {
133  if (!is3D())
134  return area();
135  return xlength() * ylength() * zlength();
136  }
137 
138  bool contains(const PointType& p) const {
139  if (!p.isValid())
140  return false;
141  if(!isValid())
142  return false;
143 
144  const PointType& pmin = this->min_corner();
145  const PointType& pmax = this->max_corner();
146  bool ok = p.x >= pmin.x && p.x <= pmax.x &&
147  p.y >= pmin.y && p.y <= pmax.y;
148  if ( is3D() && p.is3D()) {
149  ok = p.z >= pmin.z && p.z <= pmax.z;
150  }
151  return ok;
152  }
153 
154  bool contains(Box<PointType>& box) const{
155  return contains(box.min_corner()) && contains(box.max_corner());
156  }
157 
158  bool contains(const QVariant& value, bool inclusive = true) const {
159  //TODO:
160  return false;
161  }
162 
163  bool equals(Box<PointType>& box, double delta=0) const {
164  if ( !box.isValid())
165  return false;
166  if (!isValid())
167  return false;
168 
169  const PointType& pmin = box.min_corner();
170  const PointType& pmax = box.max_corner();
171 
172  if ( std::abs( min_corner.x - pmin.x) > delta)
173  return false;
174  if ( std::abs( min_corner.y - pmin.y) > delta)
175  return false;
176  if ( std::abs( max_corner.x - pmax.x) > delta)
177  return false;
178  if ( std::abs( max_corner.y - pmax.y) > delta)
179  return false;
180  if ( is3D() && box.is3D()) {
181  if ( std::abs( min_corner.z - pmin.z) > delta)
182  return false;
183  if ( std::abs( max_corner.z - pmax.z) > delta)
184  return false;
185  }
186  return true;
187  }
188 
189  bool isValid() const {
190  return this->min_corner().isValid() && this->max_corner().isValid();
191  }
192 
193  bool isNull() const {
194  bool ok = this->min_corner().x == 0 && this->min_corner().y == 0 &&
195  this->max_corner().x == 0 && this->max_corner().y == 0;
196  if ( is3D()){
197  ok &= this->min_corner().z == 0 && this->max_corner().z == 0;
198  }
199  return ok;
200  }
201 
202  Box<PointType>& operator=(Box<PointType>&& box) {
203  _min_corner = std::move(box._min_corner);
204  _max_corner = std::move(box._max_corner);
205 
206  box._min_corner = box._max_corner = PointType();
207  return *this;
208  }
209 
210  Box<PointType>& operator=(const Box<PointType>& box) {
211  _min_corner = std::move(box._min_corner);
212  _max_corner = std::move(box._max_corner);
213  return *this;
214  }
215 
216  Box<PointType>& operator +=(const double& v) {
217  if ( isNumericalUndef(v))
218  return *this;
219 
220  PointType& pmin = this->min_corner();
221  PointType& pmax = this->max_corner();
222  pmin -= v;
223  pmax += v;
224  normalize();
225  }
226 
227  Box<PointType>& operator *=(const double& v) {
228  if ( isNumericalUndef(v))
229  return *this;
230  PointType& pmin = this->min_corner();
231  PointType& pmax = this->max_corner();
232  double deltaX = xlength() * v / 2;
233  double deltaY = ylength() * v / 2;
234  double deltaZ = 1;
235  if ( is3D())
236  deltaZ = zlength() * v / 2;
237  pmin *= {deltaX, deltaY, deltaZ};
238  pmax *= {deltaX, deltaY, deltaZ};
239  normalize();
240  }
241 
242 Box<PointType>& operator +=(const PointType& pnew) {
243  if ( !pnew.isValid())
244  return *this;
245 
246 
247 
248  PointType& pmin = this->min_corner();
249  PointType& pmax = this->max_corner();
250  if ( isNull() || !isValid()) {
251  pmin = pnew;
252  pmax = pnew;
253  return *this;
254  }
255 
256  if ( contains(pnew))
257  return *this;
258  if ( pmin.x > pnew.x)
259  pmin.x = pnew.x;
260  if ( pmin.y > pnew.y)
261  pmin.y = pnew.y;
262  if ( pmax.x < pnew.x)
263  pmax.x = pnew.x;
264  if ( pmax.y < pnew.y)
265  pmax.y = pnew.y;
266  if ( is3D() && pnew.is3D()){
267  if ( pmin.z > pnew.z)
268  pmin.z = pnew.z;
269  if ( pmax.z < pnew.z)
270  pmax.z = pnew.z;
271  }
272  normalize();
273 
274  return *this;
275 
276 }
277 
278 Box<PointType>& operator -=(const PointType& pnew) {
279  if ( !pnew.isValid())
280  return *this;
281 
282  PointType& pmin = this->min_corner();
283  PointType& pmax = this->max_corner();
284 
285  if ( isNull() || !isValid()) {
286  pmin = pnew;
287  pmax = pnew;
288  return *this;
289  }
290 
291  if ( !contains(pnew))
292  return *this;
293  if ( pmin.x() < pnew.x())
294  pmin.x = pnew.x();
295  if ( pmin.y < pnew.y)
296  pmin.y = pnew.y();
297  if ( pmax.x > pnew.x)
298  pmax.x = pnew.x();
299  if ( pmax.y > pnew.y)
300  pmax.y = pnew.y();
301  if ( is3D() && pnew.is3D()){
302  if ( pmin.z < pnew.z)
303  pmin.z = pnew.z;
304  if ( pmax.z > pnew.z)
305  pmax.z = pnew.z;
306  }
307  normalize();
308 
309  return *this;
310 
311 }
312 
313 template<class T> Box<PointType>& operator +=(const std::vector<T>& vec) {
314  int size = vec.size();
315  if ( size == 2 || size == 3) {
316  this->min_corner() += vec;
317  this->max_corner() += vec;
318  normalize();
319  }
320 
321  return *this;
322 }
323 
324 Box<PointType>& operator +=(const Box<PointType>& box) {
325  if ( !box.isValid())
326  return *this;
327 
328  operator+=(box.min_corner());
329  operator+=(box.max_corner());
330  return *this;
331 }
332 
333 bool operator==(const Box<PointType>& box ) const {
334  if ( !box.isValid())
335  return false;
336 
337  return box.max_corner() == this->max_corner() && this->min_corner() == box.min_corner();
338 }
339 
340 bool operator!=(const Box<PointType>& box ) const {
341  return !(operator==(box));
342 }
343 
344 QVariant impliedValue(const QVariant& v) const{
345  QString type = v.typeName();
346  bool ok = type == "Ilwis::Box<Pixel>" || type == "Ilwis::Box<Coordinate>" ||
347  type == "Ilwis::Box<Pixeld>" ;
348  if (!ok){
349  return sUNDEF;
350  }
351  if ( type == "Ilwis::Box<Coordinate>"){
352  Box<Coordinate> box = v.value<Box<Coordinate>>();
353  return box.toString();
354  }
355  if ( type == "Ilwis::Box<Pixel>"){
356  Box<Pixel> box = v.value<Box<Pixel>>();
357  return box.toString();
358  }
359  if ( type == "Ilwis::Box<Pixeld>"){
360  Box<Pixeld> box = v.value<Box<Pixeld>>();
361  return box.toString();
362  }
363  return sUNDEF;
364 
365 }
366 
367 template<typename T> void ensure(const Size<T>& sz) {
368  if ( xlength() > sz.xsize()) {
369  this->max_corner().x = sz.xsize() - 1 ;
370  }
371  if ( ylength() > sz.ysize()) {
372  this->max_corner().y = sz.ysize() - 1 ;
373  }
374  if ( zlength() > sz.zsize()) {
375  this->max_corner().z = sz.zsize() - 1 ;
376  }
377 }
378 
379 void copyFrom(const Box<PointType>& box, quint32 dimensions=dimX | dimY | dimZ) {
380  if ( dimensions & dimX) {
381  this->min_corner().x = box.min_corner().x;
382  this->max_corner().x =box.max_corner().x;
383  }
384  if ( dimensions & dimY) {
385  this->min_corner().y = box.min_corner().y;
386  this->max_corner().y = box.max_corner().y;
387  }
388  if ( dimensions & dimZ) {
389  this->min_corner().z = box.min_corner().z;
390  this->max_corner().z = box.max_corner().z;
391  }
392 }
393 
394 
395 QString toString() const {
396  if ( is3D()) {
397  if (this->min_corner().valuetype() == itDOUBLE)
398  return QString("POLYGON(%1 %2 %3,%4 %5 %6)").
399  arg((double)this->min_corner().x,0,'g').
400  arg((double)this->min_corner().y,0,'g').
401  arg((double)this->min_corner().z,0,'g').
402  arg((double)this->max_corner().x,0,'g').
403  arg((double)this->max_corner().y,0,'g').
404  arg((double)this->max_corner().z,0,'g');
405  else
406  return QString("POLYGON(%1 %2 %3,%4 %5 %6)").arg(this->min_corner().x).
407  arg(this->min_corner().y).
408  arg(this->min_corner().z).
409  arg(this->max_corner().x).
410  arg(this->max_corner().y).
411  arg(this->max_corner().z);
412 
413 
414  }else {
415  if (this->min_corner().valuetype() == itDOUBLE)
416  return QString("POLYGON(%1 %2,%3 %4)").
417  arg((double)this->min_corner().x,0,'g').
418  arg((double)this->min_corner().y,0,'g').
419  arg((double)this->max_corner().x,0,'g').
420  arg((double)this->max_corner().y,0,'g');
421  else
422  return QString("POLYGON(%1 %2,%3 %4)").
423  arg(this->min_corner().x).
424  arg(this->min_corner().y).
425  arg(this->max_corner().x).
426  arg(this->max_corner().y);
427  }
428 
429 }
430 
431 private:
432  PointType _min_corner;
433  PointType _max_corner;
434 
435 
436 void normalize() {
437  PointType& pmin = this->min_corner();
438  PointType& pmax = this->max_corner();
439  if ( pmin.x > pmax.x) {
440  double v1 = pmin.x;
441  double v2 = pmax.x;
442  std::swap(v1, v2);
443  pmin.x = v1;
444  pmax.x = v2;
445 
446  }
447  if ( pmin.y > pmax.y) {
448  double v1 = pmin.y;
449  double v2 = pmax.y;
450  std::swap(v1, v2);
451  pmin.y = v1;
452  pmax.y = v2;
453  }
454  if ( pmin.z > pmax.z) {
455  double v1 = pmin.z;
456  double v2 = pmax.z;
457  std::swap(v1, v2);
458  pmin.z = v1;
459  pmax.z = v2;
460  }
461 
462 }
463 
464 
465 };
466 
467 template<typename PointType> Box<PointType> operator *(const Box<PointType>& box, const double& v) {
468  PointType pmin = box.min_corner();
469  PointType pmax = box.max_corner();
470  double deltaX = box.xlength() * v / 2;
471  double deltaY = box.ylength() * v / 2;
472  double deltaZ = box.is3d() ? box.zlength() * v / 2 : 0;
473  pmin -= {deltaX, deltaY, deltaZ};
474  pmax += {deltaX, deltaY, deltaZ};
475  return Box<PointType>(pmin, pmax);
476 }
477 
478 typedef Ilwis::Box<Ilwis::Pixel> BoundingBox;
479 typedef Ilwis::Box<Ilwis::Coordinate> Envelope;
480 
481 }
482 
483 
484 Q_DECLARE_METATYPE(Ilwis::BoundingBox)
485 Q_DECLARE_METATYPE(Ilwis::Box<Ilwis::Pixeld>)
486 Q_DECLARE_METATYPE(Ilwis::Envelope)
487 
488 
489 
490 #endif // BOX_H