swift
geoobjectlist.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2015 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #ifndef SWIFT_MISC_GEO_GEOOBJECTLIST_H
7 #define SWIFT_MISC_GEO_GEOOBJECTLIST_H
8 
9 #include <tuple>
10 
11 #include <QList>
12 
13 #include "misc/aviation/altitude.h"
15 #include "misc/pq/length.h"
16 #include "misc/sequence.h"
17 #include "misc/swiftmiscexport.h"
18 
19 namespace swift::misc::geo
20 {
22  template <class OBJ, class CONTAINER>
24  {
25  public:
27  using MinMaxAverageHeight = std::tuple<aviation::CAltitude, aviation::CAltitude, aviation::CAltitude, int>;
28 
32  CONTAINER findWithinRange(const ICoordinateGeodetic &coordinate,
33  const physical_quantities::CLength &range) const
34  {
35  return this->container().findBy(
36  [&](const OBJ &geoObj) { return calculateGreatCircleDistance(geoObj, coordinate) <= range; });
37  }
38 
42  CONTAINER findOutsideRange(const ICoordinateGeodetic &coordinate,
43  const physical_quantities::CLength &range) const
44  {
45  return this->container().findBy(
46  [&](const OBJ &geoObj) { return calculateGreatCircleDistance(geoObj, coordinate) > range; });
47  }
48 
51  const physical_quantities::CLength &range) const
52  {
53  return this->container().findFirstByOrDefault(
54  [&](const OBJ &geoObj) { return calculateGreatCircleDistance(geoObj, coordinate) <= range; });
55  }
56 
58  CONTAINER findWithGeodeticMSLHeight() const
59  {
60  return this->container().findBy(&OBJ::hasMSLGeodeticHeight, true);
61  }
62 
65  const physical_quantities::CLength &range) const
66  {
67  return this->container().containsBy([&](const OBJ &geoObj) {
69  return d <= range;
70  });
71  }
72 
75  const physical_quantities::CLength &range) const
76  {
77  return this->container().containsBy([&](const OBJ &geoObj) {
79  return d > range;
80  });
81  }
82 
84  bool containsNullPosition() const
85  {
86  return this->container().containsBy([&](const ICoordinateGeodetic &geoObj) { return geoObj.isNull(); });
87  }
88 
91  {
92  return this->container().containsBy(
93  [&](const ICoordinateGeodetic &geoObj) { return geoObj.isNull() || geoObj.isGeodeticHeightNull(); });
94  }
95 
98  {
101  if (this->container().isEmpty()) { return stats; } // avoid div by zero
102  int count = 0;
103  double avgFt = 0;
104  for (const OBJ &obj : this->container())
105  {
106  if (!obj.hasMSLGeodeticHeight()) { continue; }
107  const aviation::CAltitude alt = obj.geodeticHeight();
108  if (std::get<0>(stats).isNull() || std::get<0>(stats) > alt)
109  {
110  std::get<0>(stats) = alt; // min.
111  }
112  if (std::get<1>(stats).isNull() || std::get<1>(stats) < alt)
113  {
114  std::get<1>(stats) = alt; // max.
115  }
116  avgFt += alt.value(physical_quantities::CLengthUnit::ft()); // add up
117  count++;
118  }
119 
120  if (count > 0)
121  {
122  std::get<2>(stats) = aviation::CAltitude(avgFt / count, aviation::CAltitude::MeanSeaLevel,
124  }
125  std::get<3>(stats) = count;
126  return stats;
127  }
128 
131  {
132  if (this->container().isEmpty()) { return aviation::CAltitude::null(); }
134  for (const OBJ &obj : this->container())
135  {
136  if (!obj.hasMSLGeodeticHeight()) { continue; }
137  const aviation::CAltitude alt = obj.geodeticHeight();
138  if (max.isNull() || alt > max) { max = alt; }
139  }
140  return max;
141  }
142 
145  {
146  const int size = this->container().size();
147  const CONTAINER copy = this->container().findOutsideRange(coordinate, range);
148  const int d = size - copy.size();
149  if (d > 0) { *this = copy; }
150  return d;
151  }
152 
155  {
156  const int size = this->container().size();
157  const CONTAINER copy = this->container().findWithinRange(coordinate, range);
158  const int d = size - copy.size();
159  if (d > 0) { *this = copy; }
160  return d;
161  }
162 
165  {
166  const int size = this->container().size();
167  const CONTAINER copy = this->findWithGeodeticMSLHeight();
168  const int d = size - copy.size();
169  if (d > 0) { *this = copy; }
170  return d;
171  }
172 
174  CONTAINER findClosest(int number, const ICoordinateGeodetic &coordinate) const
175  {
176  CONTAINER closest = this->container().partiallySorted(number, [&](const OBJ &a, const OBJ &b) {
177  return calculateEuclideanDistanceSquared(a, coordinate) <
178  calculateEuclideanDistanceSquared(b, coordinate);
179  });
180  closest.truncate(number);
181  return closest;
182  }
183 
185  CONTAINER findFarthest(int number, const ICoordinateGeodetic &coordinate) const
186  {
187  CONTAINER farthest = this->container().partiallySorted(number, [&](const OBJ &a, const OBJ &b) {
188  return calculateEuclideanDistanceSquared(a, coordinate) >
189  calculateEuclideanDistanceSquared(b, coordinate);
190  });
191  farthest.truncate(number);
192  return farthest;
193  }
194 
197  const physical_quantities::CLength &range) const
198  {
199  OBJ closest;
201  for (const OBJ &obj : this->container())
202  {
204  if (d > range) { continue; }
205  if (distance.isNull() || distance > d)
206  {
207  distance = d;
208  closest = obj;
209  }
210  }
211  return closest;
212  }
213 
216  {
217  this->container().sort([&](const OBJ &a, const OBJ &b) {
218  return calculateEuclideanDistanceSquared(a, coordinate) <
219  calculateEuclideanDistanceSquared(b, coordinate);
220  });
221  }
222 
224  CONTAINER sortedByEuclideanDistanceSquared(const ICoordinateGeodetic &coordinate) const
225  {
226  CONTAINER copy(this->container());
227  copy.sortByEuclideanDistanceSquared(coordinate);
228  return copy;
229  }
230 
231  protected:
234 
236  const CONTAINER &container() const { return static_cast<const CONTAINER &>(*this); }
237 
239  CONTAINER &container() { return static_cast<CONTAINER &>(*this); }
240  };
241 
243  template <class OBJ, class CONTAINER>
244  class IGeoObjectWithRelativePositionList : public IGeoObjectList<OBJ, CONTAINER>
245  {
246  public:
248  void sortByRange(const ICoordinateGeodetic &position, bool updateValues)
249  {
250  if (updateValues) { this->calculcateAndUpdateRelativeDistanceAndBearing(position); }
251  this->container().sort(
252  [&](const OBJ &a, const OBJ &b) { return a.getRelativeDistance() < b.getRelativeDistance(); });
253  }
254 
258  {
259  this->container().sort(
260  [&](const OBJ &a, const OBJ &b) { return a.getRelativeDistance() < b.getRelativeDistance(); });
261  }
262 
265  {
266  this->container().partiallySort(
267  number, [&](const OBJ &a, const OBJ &b) { return a.getRelativeDistance() < b.getRelativeDistance(); });
268  }
269 
271  CONTAINER getClosestObjects(int number) const
272  {
273  if (number < 1) { return CONTAINER(); }
274  if (this->container().size() >= number) { return (this->container()); }
275  CONTAINER closest(this->container());
276  closest.partiallySortByDistanceToReferencePosition(number);
277  Q_ASSERT_X(closest.size() <= number, Q_FUNC_INFO, "size exceeded");
278  return closest;
279  }
280 
283  bool updateValues)
284  {
285  this->container().removeIf([&](OBJ &geoObj) {
286  return updateValues ? geoObj.calculcateAndUpdateRelativeDistanceAndBearing(position) > maxDistance :
287  geoObj.calculateGreatCircleDistance(position) > maxDistance;
288  });
289  }
290 
293  {
294  for (OBJ &geoObj : this->container()) { geoObj.calculcateAndUpdateRelativeDistanceAndBearing(position); }
295  }
296 
297  protected:
300  };
301 } // namespace swift::misc::geo
302 
303 #endif // SWIFT_MISC_GEO_GEOOBJECTLIST_H
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
static const CAltitude & null()
Null altitude (MSL)
Definition: altitude.cpp:439
Geodetic coordinate, a position in 3D space relative to the reference geoid.
physical_quantities::CLength calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const
Great circle distance.
virtual bool isNull() const
Is null, means vector x, y, z == 0.
bool isGeodeticHeightNull() const
Geodetic height null?
List of objects with geo coordinates.
Definition: geoobjectlist.h:24
CONTAINER findOutsideRange(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range) const
Find 0..n objects outside range of given coordinate.
Definition: geoobjectlist.h:42
bool containsNullPosition() const
Any NULL position?
Definition: geoobjectlist.h:84
CONTAINER sortedByEuclideanDistanceSquared(const ICoordinateGeodetic &coordinate) const
Sorted by distance.
CONTAINER & container()
Container.
void sortByEuclideanDistanceSquared(const ICoordinateGeodetic &coordinate)
Sort by distance.
int removeWithoutGeodeticHeight()
Remove if there is no geodetic height.
OBJ findFirstWithinRangeOrDefault(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range) const
Find first in range.
Definition: geoobjectlist.h:50
bool containsObjectInRange(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range) const
Any object in range?
Definition: geoobjectlist.h:64
CONTAINER findWithinRange(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range) const
Find 0..n objects within range of given coordinate.
Definition: geoobjectlist.h:32
OBJ findClosestWithinRange(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range) const
Find closest within range to the given coordinate.
bool containsObjectOutsideRange(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range) const
Any object in range?
Definition: geoobjectlist.h:74
int removeInsideRange(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range)
Remove inside range.
const CONTAINER & container() const
Container.
int removeOutsideRange(const ICoordinateGeodetic &coordinate, const physical_quantities::CLength &range)
Remove outside range.
bool containsNullPositionOrHeight() const
Any NULL position or NULL height.
Definition: geoobjectlist.h:90
aviation::CAltitude findMaxHeight() const
Find min/max/average height.
MinMaxAverageHeight findMinMaxAverageHeight() const
Find min/max/average height.
Definition: geoobjectlist.h:97
CONTAINER findWithGeodeticMSLHeight() const
Elements with geodetic height (only MSL)
Definition: geoobjectlist.h:58
CONTAINER findClosest(int number, const ICoordinateGeodetic &coordinate) const
Find 0..n objects closest to the given coordinate.
CONTAINER findFarthest(int number, const ICoordinateGeodetic &coordinate) const
Find 0..n objects farthest to the given coordinate.
std::tuple< aviation::CAltitude, aviation::CAltitude, aviation::CAltitude, int > MinMaxAverageHeight
For statistics.
Definition: geoobjectlist.h:27
List of objects with geo coordinates.
void calculcateAndUpdateRelativeDistanceAndBearing(const ICoordinateGeodetic &position)
Calculate distances.
void partiallySortByDistanceToReferencePosition(int number)
Sort the first n closest objects.
void sortByRange(const ICoordinateGeodetic &position, bool updateValues)
Calculate distances, then sort by range.
void sortByDistanceToReferencePosition()
If distance is already set, just sort container.
CONTAINER getClosestObjects(int number) const
Get n closest objects.
void removeIfOutsideRange(const ICoordinateGeodetic &position, const physical_quantities::CLength &maxDistance, bool updateValues)
Calculate distances, remove if outside range.
Physical unit length (length)
Definition: length.h:18
static CLengthUnit ft()
Foot ft.
Definition: units.h:159
double value(MU unit) const
Value in given unit.