diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/extractors/Histogram.cpp b/hoot-core/src/main/cpp/hoot/core/algorithms/extractors/Histogram.cpp index 54d86d2741..8755aeae1b 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/extractors/Histogram.cpp +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/extractors/Histogram.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "Histogram.h" @@ -59,52 +59,40 @@ double Histogram::diff(Histogram& other) assert(_bins.size() == other._bins.size()); double diff = 0.0; for (size_t i = 0; i < _bins.size(); i++) - { diff += fabs(_bins[i] - other._bins[i]); - } - return diff / 2.0; } size_t Histogram::getBin(Radians theta) const { while (theta < 0.0) - { theta += 2 * M_PI; - } - return (theta / (2 * M_PI)) * _bins.size(); + return static_cast((theta / (2 * M_PI)) * static_cast(_bins.size())); } Radians Histogram::_getBinAngle(size_t i) const { - return 2 * M_PI / _bins.size() * i + M_PI / _bins.size(); + return 2 * M_PI / static_cast(_bins.size()) * static_cast(i) + M_PI / static_cast(_bins.size()); } Radians Histogram::getBinCenter(size_t bin) const { assert(bin < _bins.size()); - Radians binSize = 2.0 * M_PI / (double)_bins.size(); - return bin * binSize + binSize / 2.0; + return static_cast(bin) * binSize + binSize / 2.0; } void Histogram::normalize() { double sum = 0.0; - for (size_t i = 0; i < _bins.size(); i++) - { - sum += _bins[i]; - } + for (auto val : _bins) + sum += val; if (sum <= 0.0) - { sum = 1.0; - } for (size_t i = 0; i < _bins.size(); i++) - { _bins[i] /= sum; - } } void Histogram::smooth(Radians sigma) @@ -129,12 +117,7 @@ QString Histogram::toString() const { QStringList l; for (size_t i = 0; i < _bins.size(); ++i) - { - l << - QString("%1°: %2") - .arg(QString::number(toDegrees(getBinCenter(i)), 'g', 6)) - .arg(QString::number(_bins[i], 'g', 6)); - } + l << QString("%1°: %2").arg(QString::number(toDegrees(getBinCenter(i)), 'g', 6), QString::number(_bins[i], 'g', 6)); return l.join(", "); } @@ -144,12 +127,7 @@ QString Histogram::printPositiveBins() const for (size_t i = 0; i < _bins.size(); ++i) { if (_bins[i] > 0.0) - { - l << - QString("%1°: %2") - .arg(QString::number(toDegrees(getBinCenter(i)), 'g', 6)) - .arg(QString::number(_bins[i], 'g', 6)); - } + l << QString("%1°: %2").arg(QString::number(toDegrees(getBinCenter(i)), 'g', 6), QString::number(_bins[i], 'g', 6)); } return l.join(", "); } diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.cpp b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.cpp index 49a52752d0..a23a061a78 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.cpp +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.cpp @@ -23,7 +23,7 @@ * copyrights will be updated automatically. * * @copyright Copyright (C) 2005 VividSolutions (http://www.vividsolutions.com/) - * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "LocationOfPoint.h" @@ -33,8 +33,8 @@ #include // Hoot -#include #include +#include // Standard #include @@ -45,9 +45,9 @@ using namespace geos::geom; namespace hoot { -LocationOfPoint::LocationOfPoint(const ConstOsmMapPtr& map, ConstWayPtr way) : - _map(map), - _way(way) +LocationOfPoint::LocationOfPoint(const ConstOsmMapPtr& map, ConstWayPtr way) + : _map(map), + _way(way) { _length = -1; } @@ -62,18 +62,12 @@ double distance(const Node& n1, const Node& n2) Coordinate LocationOfPoint::locate(double d) { if (_length == -1) - { _length = ElementToGeometryConverter(_map).convertToLineString(_way)->getLength(); - } if (d <= 0) - { return _map->getNode(_way->getNodeId(0))->toCoordinate(); - } else if (d >= _length) - { - return _map->getNode(_way->getNodeId(_way->getNodeCount() - 1))->toCoordinate(); - } + return _map->getNode(_way->getNodeId(static_cast(_way->getNodeCount() - 1)))->toCoordinate(); double running = 0.0; double step = 0.0; @@ -100,8 +94,7 @@ Coordinate LocationOfPoint::locate(double d) return result; } -WayLocation LocationOfPoint::locate(const ConstOsmMapPtr& map, ConstWayPtr way, - const Coordinate& inputPt) +WayLocation LocationOfPoint::locate(const ConstOsmMapPtr& map, ConstWayPtr way, const Coordinate& inputPt) { LocationOfPoint locater(map, way); return locater.locate(inputPt); @@ -119,12 +112,9 @@ WayLocation LocationOfPoint::locate(const Coordinate& inputPt) const if (_length == -1) { - std::shared_ptr lineString = - ElementToGeometryConverter(_map).convertToLineString(_way); + std::shared_ptr lineString = ElementToGeometryConverter(_map).convertToLineString(_way); if (lineString) - { _length = lineString->getLength(); - } else { LOG_TRACE("Invalid line string. Returning empty way location..."); @@ -134,9 +124,7 @@ WayLocation LocationOfPoint::locate(const Coordinate& inputPt) const LOG_VART(_length); if (_length <= 0.0) - { return WayLocation(_map, _way, 0, 0); - } if (_way->getNodeCount() >= 1) { @@ -144,33 +132,28 @@ WayLocation LocationOfPoint::locate(const Coordinate& inputPt) const Coordinate lastCoord = _map->getNode(_way->getNodeId(0))->toCoordinate(); for (size_t i = 0; i < _way->getNodeCount() - 1; i++) { - ConstNodePtr node = _map->getNode(_way->getNodeId((long)(i + 1))); + ConstNodePtr node = _map->getNode(_way->getNodeId(static_cast(i + 1))); Coordinate nextCoord = node->toCoordinate(); seg.p0 = lastCoord; seg.p1 = nextCoord; lastCoord = nextCoord; double segDistance = seg.distance(inputPt); double segFrac = segmentFraction(seg, inputPt); - if (segDistance < minDistance) { - minIndex = i; + minIndex = static_cast(i); minFrac = segFrac; minDistance = segDistance; } } } - return WayLocation(_map, _way, minIndex, minFrac); } -WayLocation LocationOfPoint::locateAfter(const Coordinate& inputPt, const WayLocation& minLocation) - const +WayLocation LocationOfPoint::locateAfter(const Coordinate& inputPt, const WayLocation& minLocation) const { if (minLocation.isValid() == false) - { return locate(inputPt); - } assert(minLocation.getWay() == _way); @@ -183,13 +166,11 @@ WayLocation LocationOfPoint::locateAfter(const Coordinate& inputPt, const WayLoc for (size_t i = startIndex; i < _way->getNodeCount() - 1; i++) { - seg.p0 = _map->getNode(_way->getNodeId(i))->toCoordinate(); - seg.p1 = _map->getNode(_way->getNodeId(i + 1))->toCoordinate(); + seg.p0 = _map->getNode(_way->getNodeId(static_cast(i)))->toCoordinate(); + seg.p1 = _map->getNode(_way->getNodeId(static_cast(i + 1)))->toCoordinate(); if (i == startIndex) - { seg.p0 = minLocation.getCoordinate(); - } double segDistance = seg.distance(inputPt); double segFrac = segmentFraction(seg, inputPt); @@ -197,50 +178,36 @@ WayLocation LocationOfPoint::locateAfter(const Coordinate& inputPt, const WayLoc if (segDistance < minDistance) { // if this is the first case (a partial line segment) - if (i == startIndex) - { - // recalculate the segFrac in terms of the whole line segment. - segFrac = - minLocation.getSegmentFraction() + (1 - minLocation.getSegmentFraction()) * segFrac; - } - nextClosestLocation = WayLocation(_map, _way, i, segFrac); + if (i == startIndex) // recalculate the segFrac in terms of the whole line segment. + segFrac = minLocation.getSegmentFraction() + (1 - minLocation.getSegmentFraction()) * segFrac; + nextClosestLocation = WayLocation(_map, _way, static_cast(i), segFrac); minDistance = segDistance; } } // Return the minDistanceLocation found. This will not be null, since it was initialized to // minLocation. if (!(nextClosestLocation >= minLocation)) - { throw HootException("Computed location is before specified minimum location"); - } - return nextClosestLocation; } bool LocationOfPoint::isGreater(int i, double segFrac, const WayLocation& loc) const { - return WayLocation::compareLocationValues(i, segFrac, - loc.getSegmentIndex(), loc.getSegmentFraction()) > 0; + return WayLocation::compareLocationValues(i, segFrac, loc.getSegmentIndex(), loc.getSegmentFraction()) > 0; } double LocationOfPoint::segmentFraction(const LineSegment& seg, const Coordinate& inputPt) { double segFrac; if (seg.p0.equals2D(seg.p1)) - { segFrac = 0.0; - } else { segFrac = seg.projectionFactor(inputPt); if (segFrac < 0.000001) - { segFrac = 0.0; - } else if (segFrac > 0.999999) - { segFrac = 1.0; - } } return segFrac; } diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.h b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.h index 5e17f7ba18..40a5b16334 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.h +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/LocationOfPoint.h @@ -23,7 +23,7 @@ * copyrights will be updated automatically. * * @copyright Copyright (C) 2005 VividSolutions (http://www.vividsolutions.com/) - * @copyright Copyright (C) 2015, 2017, 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2017, 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef LOCATIONOFPOINT_H @@ -52,7 +52,7 @@ class LocationOfPoint LocationOfPoint(const ConstOsmMapPtr& map, ConstWayPtr way); static WayLocation locate(const ConstOsmMapPtr& map, ConstWayPtr way, - const geos::geom::Coordinate& inputPt); + const geos::geom::Coordinate& inputPt); /** * @brief locate finds the nearest location along a {@link Way} to a given point. @@ -90,8 +90,8 @@ class LocationOfPoint */ bool isGreater(int i, double segFrac, const WayLocation& loc) const; - static double segmentFraction( - const geos::geom::LineSegment& seg, const geos::geom::Coordinate& inputPt); + static double segmentFraction(const geos::geom::LineSegment& seg, + const geos::geom::Coordinate& inputPt); private: diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.cpp b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.cpp index 28b9b498b4..86fd832cd2 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.cpp +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.cpp @@ -23,7 +23,7 @@ * copyrights will be updated automatically. * * @copyright Copyright (C) 2005 VividSolutions (http://www.vividsolutions.com/) - * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "WayLocation.h" @@ -47,53 +47,48 @@ int WayLocation::logWarnCount = 0; const double WayLocation::SLOPPY_EPSILON = 1e-10; -WayLocation::WayLocation() : -_segmentIndex(-1), -_segmentFraction(-1) +WayLocation::WayLocation() + : _segmentIndex(-1), + _segmentFraction(-1.0) { } -WayLocation::WayLocation(ConstOsmMapPtr map, ConstWayPtr way, double distance) : -_map(map), -_way(way), -_segmentIndex(-1), -_segmentFraction(-1) +WayLocation::WayLocation(ConstOsmMapPtr map, ConstWayPtr way, double distance) + : _map(map), + _way(way), + _segmentIndex(-1), + _segmentFraction(-1.0) { double d = 0.0; - std::shared_ptr lineString = - ElementToGeometryConverter(map).convertToLineString(way); + std::shared_ptr lineString = ElementToGeometryConverter(map).convertToLineString(way); if (lineString) { const double length = lineString->getLength(); - if (distance <= 0) { - _segmentIndex = 0.0; - _segmentFraction = 0; + _segmentIndex = 0; + _segmentFraction = 0.0; } else if (distance >= length) { - _segmentIndex = _way->getNodeCount() - 1; + _segmentIndex = static_cast(_way->getNodeCount()) - 1; _segmentFraction = 0.0; } else { ConstNodePtr lastNode = _map->getNode(way->getNodeId(0)); Coordinate last = lastNode->toCoordinate(); - - _segmentIndex = way->getNodeCount() - 1; - _segmentFraction = 0; - + _segmentIndex = static_cast(way->getNodeCount()) - 1; + _segmentFraction = 0.0; for (size_t i = 1; i < way->getNodeCount(); i++) { ConstNodePtr n = _map->getNode(_way->getNodeId(i)); Coordinate next = n->toCoordinate(); double delta = next.distance(last); last = next; - if (d <= distance && d + delta > distance) { - _segmentIndex = i - 1; + _segmentIndex = static_cast(i) - 1; _segmentFraction = (distance - d) / delta; // this can sometimes happen due to rounding errors. if (_segmentFraction >= 1.0) @@ -116,23 +111,19 @@ _segmentFraction(-1) } } -WayLocation::WayLocation( - ConstOsmMapPtr map, ConstWayPtr way, int segmentIndex, double segmentFraction) : -_map(map), -_way(way), -_segmentIndex(segmentIndex), -_segmentFraction(segmentFraction) +WayLocation::WayLocation(ConstOsmMapPtr map, ConstWayPtr way, int segmentIndex, double segmentFraction) + : _map(map), + _way(way), + _segmentIndex(segmentIndex), + _segmentFraction(segmentFraction) { if (_segmentFraction == 1.0) { _segmentIndex++; _segmentFraction = 0.0; } - if (_segmentFraction < 0.0 || _segmentFraction >= 1.0) - { throw HootException("Segment Fraction is out of range."); - } if (_segmentIndex < 0) { @@ -142,35 +133,31 @@ _segmentFraction(segmentFraction) if (_segmentIndex >= (int)_way->getNodeCount() - 1) { - _segmentIndex = _way->getNodeCount() - 1; + _segmentIndex = static_cast(_way->getNodeCount()) - 1; _segmentFraction = 0.0; } } -WayLocation::WayLocation(const WayLocation& other) : -_map(other.getMap()), -_way(other.getWay()), -_segmentIndex(other.getSegmentIndex()), -_segmentFraction(other.getSegmentFraction()) +WayLocation::WayLocation(const WayLocation& other) + : _map(other.getMap()), + _way(other.getWay()), + _segmentIndex(other.getSegmentIndex()), + _segmentFraction(other.getSegmentFraction()) { } Meters WayLocation::calculateDistanceFromEnd() const { - return - ElementToGeometryConverter(getMap()).convertToLineString(getWay())->getLength() - - calculateDistanceOnWay(); + return ElementToGeometryConverter(getMap()).convertToLineString(getWay())->getLength() - + calculateDistanceOnWay(); } Meters WayLocation::calculateDistanceOnWay() const { Meters result = 0.0; - ConstNodePtr firstNode = _map->getNode(_way->getNodeId(0)); if (!firstNode) - { return result; - } Coordinate last = firstNode->toCoordinate(); for (int i = 1; i < (int)_way->getNodeCount() && i <= _segmentIndex; i++) { @@ -182,7 +169,6 @@ Meters WayLocation::calculateDistanceOnWay() const last = next; } } - if (_segmentIndex < (int)_way->getNodeCount() - 1) { ConstNodePtr n = _map->getNode(_way->getNodeId(_segmentIndex + 1)); @@ -193,7 +179,6 @@ Meters WayLocation::calculateDistanceOnWay() const result += d * _segmentFraction; } } - return result; } @@ -213,9 +198,7 @@ int WayLocation::compareLocationValues(int segmentIndex0, double segmentFraction int WayLocation::compareTo(const WayLocation& other) const { if (!isValid() || !other.isValid()) - { return 1; - } if (!(_segmentFraction < 1.0 && other._segmentFraction < 1.0)) { @@ -231,41 +214,41 @@ int WayLocation::compareTo(const WayLocation& other) const } assert(_segmentFraction < 1.0 && other._segmentFraction < 1.0); // compare way ids - if (_way->getId() < other._way->getId()) return -1; - if (_way->getId() > other._way->getId()) return 1; + if (_way->getId() < other._way->getId()) + return -1; + if (_way->getId() > other._way->getId()) + return 1; // compare segments - if (_segmentIndex < other._segmentIndex) return -1; - if (_segmentIndex > other._segmentIndex) return 1; + if (_segmentIndex < other._segmentIndex) + return -1; + if (_segmentIndex > other._segmentIndex) + return 1; // same segment, so compare segment fraction - if (_segmentFraction < other._segmentFraction) return -1; - if (_segmentFraction > other._segmentFraction) return 1; + if (_segmentFraction < other._segmentFraction) + return -1; + if (_segmentFraction > other._segmentFraction) + return 1; // same location return 0; } WayLocation WayLocation::createAtEndOfWay(const ConstOsmMapPtr& map, const ConstWayPtr way) { - return WayLocation(map, way, way->getNodeCount() - 1, 0.0); + return WayLocation(map, way, static_cast(way->getNodeCount()) - 1, 0.0); } Coordinate WayLocation::getCoordinate() const { ConstNodePtr p0 = _map->getNode(_way->getNodeId(_segmentIndex)); if (!p0) - { return Coordinate(); - } - if (_segmentFraction <= 0.0) - { + else if (_segmentFraction <= 0.0) return p0->toCoordinate(); - } else { ConstNodePtr p1 = _map->getNode(_way->getNodeId(_segmentIndex + 1)); if (!p1) - { return Coordinate(); - } return pointAlongSegmentByFraction(p0->toCoordinate(), p1->toCoordinate(), _segmentFraction); } } @@ -273,34 +256,18 @@ Coordinate WayLocation::getCoordinate() const ConstNodePtr WayLocation::getNode(double epsilon) const { if (!isNode(epsilon)) - { throw IllegalArgumentException("getNode() is only valid if WayLocation is on a node."); - } - // Round to the appropriate segment index. This may be necessary due to floating point errors. if (_segmentFraction >= 0.5) - { return _map->getNode(getWay()->getNodeId(_segmentIndex + 1)); - } else - { return _map->getNode(getWay()->getNodeId(_segmentIndex)); - } } bool WayLocation::isLast(double epsilon) const { - bool result = false; - if (_segmentIndex == (int)_way->getNodeCount() - 1) - { - result = true; - } - else if (_segmentIndex == (int)_way->getNodeCount() - 2 && _segmentFraction >= 1 - epsilon) - { - result = true; - } - - return result; + return (_segmentIndex == (int)_way->getNodeCount() - 1) || + (_segmentIndex == (int)_way->getNodeCount() - 2 && _segmentFraction >= 1 - epsilon); } WayLocation WayLocation::move(Meters distance) const @@ -310,9 +277,7 @@ WayLocation WayLocation::move(Meters distance) const WayLocation result(*this); Coordinate last = result.getCoordinate(); if (last.isNull()) - { return result; - } LOG_VART(last.toString()); // This odd statement helps us avoid adding irrelevantly small distances. @@ -320,20 +285,16 @@ WayLocation WayLocation::move(Meters distance) const { // if we're at the end of the way if (result.isLast()) - { return result; - } ConstNodePtr n = _map->getNode(_way->getNodeId(result.getSegmentIndex() + 1)); LOG_VART(n.get()); + // Missing nodes can occur in workflows where missing child refs are allowed, like Cut and + // Replace. This seems to be the best way to handle it so far. if (!n) - { - // Missing nodes can occur in workflows where missing child refs are allowed, like Cut and - // Replace. This seems to be the best way to handle it so far. return result; - } - Coordinate next = n->toCoordinate(); + Coordinate next = n->toCoordinate(); double delta = last.distance(next); // if the next node is too far @@ -343,9 +304,7 @@ WayLocation WayLocation::move(Meters distance) const ConstNodePtr lastSegmentNode = _map->getNode(_way->getNodeId(result.getSegmentIndex())); LOG_VART(lastSegmentNode.get()); if (!lastSegmentNode) - { return result; - } Coordinate lastSegment = lastSegmentNode->toCoordinate(); double segmentLength = lastSegment.distance(next); result._segmentFraction += (distance / segmentLength); @@ -357,7 +316,6 @@ WayLocation WayLocation::move(Meters distance) const result._segmentFraction = 0.0; result._segmentIndex = result._segmentIndex + 1; } - distance = 0; } // if we need to go past the next node @@ -375,18 +333,14 @@ WayLocation WayLocation::move(Meters distance) const { // if we're at the end of the way if (result.isFirst()) - { return result; - } if (result._segmentFraction > 0) { ConstNodePtr nextNode = _map->getNode(_way->getNodeId(result.getSegmentIndex())); LOG_VART(nextNode.get()); if (!nextNode) - { return result; - } Coordinate next = nextNode->toCoordinate(); Meters delta = last.distance(next); @@ -396,9 +350,7 @@ WayLocation WayLocation::move(Meters distance) const ConstNodePtr lastNode = _map->getNode(_way->getNodeId(result._segmentIndex + 1)); LOG_VART(lastNode.get()); if (!lastNode) - { return result; - } double segmentLength = lastNode->toCoordinate().distance(next); result._segmentFraction += (distance / segmentLength); @@ -409,7 +361,6 @@ WayLocation WayLocation::move(Meters distance) const result._segmentFraction = 0.0; result._segmentIndex = result._segmentIndex + 1; } - distance = 0; } else @@ -424,9 +375,7 @@ WayLocation WayLocation::move(Meters distance) const ConstNodePtr nextNode = _map->getNode(_way->getNodeId(result.getSegmentIndex() - 1)); LOG_VART(nextNode.get()); if (!nextNode) - { return result; - } Coordinate next = nextNode->toCoordinate(); Meters delta = last.distance(next); @@ -436,9 +385,7 @@ WayLocation WayLocation::move(Meters distance) const ConstNodePtr lastNode = _map->getNode(_way->getNodeId(result.getSegmentIndex())); LOG_VART(lastNode.get()); if (!lastNode) - { return result; - } double segmentLength = lastNode->toCoordinate().distance(next); result._segmentFraction = 1.0 + (distance / segmentLength); // if we're suffering from a floating point issue. @@ -449,9 +396,7 @@ WayLocation WayLocation::move(Meters distance) const result._segmentFraction = 0; } else - { result._segmentIndex = result.getSegmentIndex() - 1; - } distance = 0; } else @@ -473,8 +418,10 @@ Coordinate WayLocation::pointAlongSegmentByFraction(const Coordinate& p0, const Coordinate& p1, double frac) { - if (frac <= 0.0) return p0; - if (frac >= 1.0) return p1; + if (frac <= 0.0) + return p0; + if (frac >= 1.0) + return p1; double x = (p1.x - p0.x) * frac + p0.x; double y = (p1.y - p0.y) * frac + p0.y; @@ -484,15 +431,9 @@ Coordinate WayLocation::pointAlongSegmentByFraction(const Coordinate& p0, QString WayLocation::toString() const { if (isValid()) - { - return - QString("way(%1) index: %2 fraction: %3").arg(_way->getId()).arg(_segmentIndex). - arg(_segmentFraction, 0, 'g', 15); - } + return QString("way(%1) index: %2 fraction: %3").arg(_way->getId()).arg(_segmentIndex).arg(_segmentFraction, 0, 'g', 15); else - { return QString("way: index: %1 fraction: %2").arg(_segmentIndex).arg(_segmentFraction); - } } bool WayLocation::isNode(double epsilon) const diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.h b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.h index 0d43e25289..12888764ca 100644 --- a/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.h +++ b/hoot-core/src/main/cpp/hoot/core/algorithms/linearreference/WayLocation.h @@ -23,7 +23,7 @@ * copyrights will be updated automatically. * * @copyright Copyright (C) 2005 VividSolutions (http://www.vividsolutions.com/) - * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef __WAY_LOCATION_H__ #define __WAY_LOCATION_H__ @@ -75,8 +75,7 @@ class WayLocation */ Meters calculateDistanceOnWay() const; - static int compareLocationValues( - int segmentIndex0, double segmentFraction0, int segmentIndex1, double segmentFraction1); + static int compareLocationValues(int segmentIndex0, double segmentFraction0, int segmentIndex1, double segmentFraction1); /** * @brief compareTo compares this object with the specified object for order. @@ -102,8 +101,8 @@ class WayLocation * @param length the length to the desired point * @return the Coordinate of the desired point */ - static geos::geom::Coordinate pointAlongSegmentByFraction( - const geos::geom::Coordinate& p0, const geos::geom::Coordinate& p1, double frac); + static geos::geom::Coordinate pointAlongSegmentByFraction(const geos::geom::Coordinate& p0, + const geos::geom::Coordinate& p1, double frac); /** * @brief getNode returns the node at this WayLocation. If isNode() returns false, this will throw diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/matching/NodeMatcher.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/matching/NodeMatcher.cpp index 722c360b96..679b807c1b 100644 --- a/hoot-core/src/main/cpp/hoot/core/conflate/matching/NodeMatcher.cpp +++ b/hoot-core/src/main/cpp/hoot/core/conflate/matching/NodeMatcher.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "NodeMatcher.h" @@ -54,9 +54,9 @@ namespace hoot int NodeMatcher::logWarnCount = 0; QList> NodeMatcher::_networkFeatureTypeCriteria; -NodeMatcher::NodeMatcher() : -_strictness(ConfigOptions().getNodeMatcherStrictness()), -_delta(ConfigOptions().getNodeMatcherAngleCalcDelta()) +NodeMatcher::NodeMatcher() + : _strictness(ConfigOptions().getNodeMatcherStrictness()), + _delta(ConfigOptions().getNodeMatcherAngleCalcDelta()) { } @@ -75,28 +75,23 @@ bool NodeMatcher::isNetworkFeatureType(ConstElementPtr element) if (_networkFeatureTypeCriteria.isEmpty()) { const QStringList critClasses = getNetworkCriterionClassNames(); - for (int i = 0; i < critClasses.size(); i++) - { - _networkFeatureTypeCriteria.append( - Factory::getInstance().constructObject(critClasses.at(i))); - } + for (const auto& crit_class : qAsConst(critClasses)) + _networkFeatureTypeCriteria.append(Factory::getInstance().constructObject(crit_class)); } - for (int i = 0; i < _networkFeatureTypeCriteria.size(); i++) + for (const auto& criteria : qAsConst(_networkFeatureTypeCriteria)) { - if (_networkFeatureTypeCriteria.at(i)->isSatisfied(element)) + if (criteria->isSatisfied(element)) { - LOG_TRACE( - element->getElementId() << " recognized as network feature types by " << - _networkFeatureTypeCriteria.at(i)->toString() << "."); + LOG_TRACE(element->getElementId() << " recognized as network feature types by " << + criteria->toString() << "."); return true; } } return false; } -vector NodeMatcher::calculateAngles( - const OsmMap* map, long nid, const set& wids, Meters delta) +vector NodeMatcher::calculateAngles(const OsmMap* map, long nid, const set& wids, Meters delta) { vector result; result.reserve(wids.size()); @@ -104,10 +99,10 @@ vector NodeMatcher::calculateAngles( LOG_VART(nid); ConstNodePtr node = map->getNode(nid); LOG_VART(node); - QSet badWayIds; - for (set::const_iterator it = wids.begin(); it != wids.end(); ++it) + set badWayIds; + for (auto way_id : wids) { - const ConstWayPtr& w = map->getWay(*it); + const ConstWayPtr& w = map->getWay(way_id); LOG_VART(w->getId()); LOG_VART(w->getLastNodeId()); LOG_VART(w->getNodeId(0)); @@ -124,20 +119,16 @@ vector NodeMatcher::calculateAngles( Radians heading = WayHeading::calculateHeading(wl, delta); // This is the first node so the angle is an inbound angle, reverse the value. if (heading < 0.0) - { heading += M_PI; - } else - { heading -= M_PI; - } LOG_VART(heading); result.push_back(heading); } else if (w->getLastNodeId() == nid) { LOG_TRACE("End node: " << nid); - WayLocation wl(map->shared_from_this(), w, w->getNodeCount() - 1, 1.0); + WayLocation wl(map->shared_from_this(), w, static_cast(w->getNodeCount()) - 1, 1.0); Radians heading = WayHeading::calculateHeading(wl, delta); LOG_VART(heading); result.push_back(heading); @@ -158,9 +149,9 @@ vector NodeMatcher::calculateAngles( "Found " << badWayIds.size() << " bad spot(s) in NodeMatcher when calculating angles " << "with node: " << nid); LOG_TRACE("wids: " << badWayIds); - for (QSet::const_iterator it = badWayIds.begin(); it != badWayIds.end(); ++it) + for (auto way_id : badWayIds) { - const ConstWayPtr& w = map->getWay(*it); + const ConstWayPtr& w = map->getWay(way_id); LOG_VART(w->getId()); LOG_VART(w->getTags().get("REF1")); LOG_VART(w->getTags().get("REF2")); @@ -172,22 +163,19 @@ vector NodeMatcher::calculateAngles( if (ConfigOptions().getNodeMatcherFailOnBadAngleSpots()) { throw HootException( - QString("NodeMatcher::calculateAngles was called with a node that was not a start or ") + - QString("end node on the specified way.")); + QString("NodeMatcher::calculateAngles was called with a node that was not a start or end node on the specified way.")); } } return result; } -double NodeMatcher::_calculateAngleScore(const vector& theta1, - const vector& theta2, vector& exclude, size_t depth, bool debug) +double NodeMatcher::_calculateAngleScore(const vector& theta1, const vector& theta2, + vector& exclude, size_t depth, bool debug) { assert(theta1.size() <= theta2.size()); if (depth == theta1.size()) - { return 1.0; - } double max = 0; for (int j = 0; j < (int)theta2.size(); j++) @@ -197,16 +185,12 @@ double NodeMatcher::_calculateAngleScore(const vector& theta1, Radians m = WayHeading::deltaMagnitude(theta1[depth], theta2[j]); double r = 0; if (m < M_PI / 2.0) - { r = pow(cos(WayHeading::deltaMagnitude(theta1[depth], theta2[j])), _strictness); - } exclude[j] = true; double v = r * _calculateAngleScore(theta1, theta2, exclude, depth + 1, debug); exclude[j] = false; if (v > max) - { max = v; - } } } return max; @@ -230,14 +214,12 @@ double NodeMatcher::scorePair(long nid1, long nid2) LOG_VART(wids2); double acc = 0; - for (set::const_iterator it = wids1.begin(); it != wids1.end(); ++it) - { - acc = max(acc, _map->getWay(*it)->getCircularError()); - } - for (set::const_iterator it = wids2.begin(); it != wids2.end(); ++it) - { - acc = max(acc, _map->getWay(*it)->getCircularError()); - } + for (auto way_id : wids1) + acc = max(acc, _map->getWay(way_id)->getCircularError()); + + for (auto way_id : wids2) + acc = max(acc, _map->getWay(way_id)->getCircularError()); + LOG_VART(acc); vector theta1 = calculateAngles(_map.get(), nid1, wids1, _delta); @@ -245,15 +227,13 @@ double NodeMatcher::scorePair(long nid1, long nid2) vector theta2 = calculateAngles(_map.get(), nid2, wids2, _delta); LOG_VART(theta2); - int s1 = theta1.size(); + int s1 = static_cast(theta1.size()); LOG_VART(s1); - int s2 = theta2.size(); + int s2 = static_cast(theta2.size()); LOG_VART(s2); if (s1 < 3 || s2 < 3) - { return 0.0; - } double d = n1->toCoordinate().distance(n2->toCoordinate()); @@ -268,9 +248,7 @@ double NodeMatcher::scorePair(long nid1, long nid2) LOG_VART(Normal::phi(d, acc / 2.0)); if (theta1.size() < theta2.size()) - { swap(theta1, theta2); - } double thetaScore; // this is very unsual and will slow things down. diff --git a/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.cpp b/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.cpp index cbee971d1a..593369e5ed 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.cpp +++ b/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.cpp @@ -22,36 +22,35 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "ElementIdSynchronizer.h" // Hoot -#include -#include +#include +#include #include +#include #include -#include -#include +#include #include #include -#include +#include namespace hoot { -ElementIdSynchronizer::ElementIdSynchronizer() : -_useNodeTagsForHash(true), -_coordinateComparisonSensitivity(ConfigOptions().getNodeComparisonCoordinateSensitivity()), -_updatedNodeCtr(0), -_updatedWayCtr(0), -_updatedRelationCtr(0) +ElementIdSynchronizer::ElementIdSynchronizer() + : _useNodeTagsForHash(true), + _coordinateComparisonSensitivity(ConfigOptions().getNodeComparisonCoordinateSensitivity()), + _updatedNodeCtr(0), + _updatedWayCtr(0), + _updatedRelationCtr(0) { } -void ElementIdSynchronizer::synchronize( - const OsmMapPtr& map1, const OsmMapPtr& map2, const ElementType& elementType) +void ElementIdSynchronizer::synchronize(const OsmMapPtr& map1, const OsmMapPtr& map2, const ElementType& elementType) { _updatedNodeCtr = 0; _updatedWayCtr = 0; @@ -61,9 +60,7 @@ void ElementIdSynchronizer::synchronize( QString msg = "Synchronizing IDs for identical elements"; if (!_map1->getName().trimmed().isEmpty() && !_map2->getName().trimmed().isEmpty()) - { msg += " between " + _map1->getName() + " and " + _map2->getName(); - } msg += "..."; LOG_INFO(msg); @@ -92,40 +89,32 @@ void ElementIdSynchronizer::synchronize( // Overwrite map2 IDs with the IDs from map1 for the features that are identical. _syncElementIds(identicalHashes); - LOG_DEBUG( - "Updated IDs on " << StringUtils::formatLargeNumber(getNumTotalFeatureIdsSynchronized()) << - " identical elements in second map."); + LOG_DEBUG("Updated IDs on " << StringUtils::formatLargeNumber(getNumTotalFeatureIdsSynchronized()) << + " identical elements in second map."); } -QSet ElementIdSynchronizer::_getHashesByElementType( - const QMap& hashesByElementId, const ElementType& elementType) const +QSet ElementIdSynchronizer::_getHashesByElementType(const QMap& hashesByElementId, + const ElementType& elementType) const { QSet filteredHashes; - for (QMap::const_iterator itr = hashesByElementId.begin(); - itr != hashesByElementId.end(); ++itr) + for (auto itr = hashesByElementId.begin(); itr != hashesByElementId.end(); ++itr) { if (itr.key().getType() == elementType) - { filteredHashes.insert(itr.value()); - } } return filteredHashes; } void ElementIdSynchronizer::_syncElementIds(const QSet& identicalHashes) { - for (QSet::const_iterator itr = identicalHashes.begin(); itr != identicalHashes.end(); - ++itr) + for (const auto& identicalHash : qAsConst(identicalHashes)) { - const QString identicalHash = *itr; LOG_VART(identicalHash); - // Get the element with matching hash from the ref map. ElementPtr map1IdenticalElement = _map1->getElement(_map1HashesToElementIds[identicalHash]); if (map1IdenticalElement) { LOG_VART(map1IdenticalElement->getElementId()); - // Make sure the map being updated doesn't already have an element with this ID and that // we haven't already synced an element to this ID. if (!_map2->containsElement(map1IdenticalElement->getElementId()) && @@ -139,7 +128,6 @@ void ElementIdSynchronizer::_syncElementIds(const QSet& identicalHashes if (map2IdenticalElement) { LOG_VART(map2IdenticalElement->getElementId()); - // Here, we're verifying both that two way nodes don't belong to ways of very dissimilar // types and that they share at least one way in common before syncing their IDs. Using // either one of these checks separately causes issue with the output. This is probably @@ -170,17 +158,17 @@ void ElementIdSynchronizer::_syncElementIds(const QSet& identicalHashes switch (map1IdenticalElementCopy->getElementType().getEnum()) { - case ElementType::Node: - _updatedNodeCtr++; - break; - case ElementType::Way: - _updatedWayCtr++; - break; - case ElementType::Relation: - _updatedRelationCtr++; - break; - default: - throw IllegalArgumentException("Invalid element type."); + case ElementType::Node: + _updatedNodeCtr++; + break; + case ElementType::Way: + _updatedWayCtr++; + break; + case ElementType::Relation: + _updatedRelationCtr++; + break; + default: + throw IllegalArgumentException("Invalid element type."); } // expensive; leave disabled by default @@ -194,11 +182,9 @@ void ElementIdSynchronizer::_syncElementIds(const QSet& identicalHashes } } -bool ElementIdSynchronizer::_areWayNodesInWaysOfMismatchedType( - ElementPtr element1, ElementPtr element2) +bool ElementIdSynchronizer::_areWayNodesInWaysOfMismatchedType(ElementPtr element1, ElementPtr element2) { // This method is similar to ElementDeduplicator::_areWayNodesInWaysOfMismatchedType. - LOG_VART(element1->getElementId()); LOG_VART(element2->getElementId()); @@ -210,29 +196,22 @@ bool ElementIdSynchronizer::_areWayNodesInWaysOfMismatchedType( const bool element2IdWayNode = _wayNodeCrit.isSatisfied(element2); // If they are both way nodes, if (!element1IdWayNode ||!element2IdWayNode) - { return false; - } // get the ways that contain each. - const std::vector containingWays1 = - WayUtils::getContainingWaysConst(element1->getId(), _map1); + const std::vector containingWays1 = WayUtils::getContainingWaysConst(element1->getId(), _map1); LOG_VART(containingWays1.size()); - const std::vector containingWays2 = - WayUtils::getContainingWaysConst(element2->getId(), _map2); + const std::vector containingWays2 = WayUtils::getContainingWaysConst(element2->getId(), _map2); LOG_VART(containingWays2.size()) // See if any of the ways between the two have a matching type. OsmSchema& schema = OsmSchema::getInstance(); TagCriterion adminBoundsCrit("boundary", "administrative"); - for (std::vector::const_iterator containingWays1Itr = containingWays1.begin(); - containingWays1Itr != containingWays1.end(); ++containingWays1Itr) + for (const auto& way1 : containingWays1) { - ConstWayPtr way1 = *containingWays1Itr; if (way1) { LOG_VART(way1->getElementId()); - // If either of our containing ways is a administrative boundary, we're going to bail on the // type comparison, since many different types of ways could be part of an admin boundary. // This may not end up being the best way to deal with this. @@ -242,14 +221,11 @@ bool ElementIdSynchronizer::_areWayNodesInWaysOfMismatchedType( return false; } - for (std::vector::const_iterator containingWays2Itr = containingWays2.begin(); - containingWays2Itr != containingWays2.end(); ++containingWays2Itr) + for (const auto& way2 : containingWays2) { - ConstWayPtr way2 = *containingWays2Itr;; if (way2) { LOG_VART(way2->getElementId()); - if (RelationMemberUtils::isMemberOfRelationSatisfyingCriterion( way2->getElementId(), adminBoundsCrit, _map2)) { @@ -272,12 +248,10 @@ bool ElementIdSynchronizer::_areWayNodesInWaysOfMismatchedType( } } } - return false; } -bool ElementIdSynchronizer::_areWayNodesWithoutAWayInCommon( - ElementPtr element1, ElementPtr element2) +bool ElementIdSynchronizer::_areWayNodesWithoutAWayInCommon(ElementPtr element1, ElementPtr element2) { LOG_VART(element1->getElementId()); LOG_VART(element2->getElementId()); @@ -290,9 +264,7 @@ bool ElementIdSynchronizer::_areWayNodesWithoutAWayInCommon( const bool element2IdWayNode = _wayNodeCrit.isSatisfied(element2); // If they are both way nodes, if (!element1IdWayNode ||!element2IdWayNode) - { return false; - } // Get the ways that contain each. const QSet containingWayIds1 = @@ -302,23 +274,18 @@ bool ElementIdSynchronizer::_areWayNodesWithoutAWayInCommon( CollectionUtils::stdSetToQSet(WayUtils::getContainingWayIds(element2->getId(), _map2)); LOG_VART(containingWayIds2); - for (QSet::const_iterator containingWays1Itr = containingWayIds1.begin(); - containingWays1Itr != containingWayIds1.end(); ++containingWays1Itr) + for (auto way1_id : qAsConst(containingWayIds1)) { - const QString way1Hash = - _map1ElementIdsToHashes[ElementId(ElementType::Way, *containingWays1Itr)]; + const QString way1Hash = _map1ElementIdsToHashes[ElementId(ElementType::Way, way1_id)]; LOG_VART(way1Hash); if (!way1Hash.trimmed().isEmpty()) { - for (QSet::const_iterator containingWays2Itr = containingWayIds2.begin(); - containingWays2Itr != containingWayIds2.end(); ++containingWays2Itr) + for (auto way2_id : qAsConst(containingWayIds2)) { - const QString way2Hash = - _map2ElementIdsToHashes[ElementId(ElementType::Way, *containingWays2Itr)]; + const QString way2Hash = _map2ElementIdsToHashes[ElementId(ElementType::Way, way2_id)]; LOG_VART(way2Hash); - if (!way2Hash.trimmed().isEmpty() && - // If any of the ways between the two are identical, then they share a parent way. - way1Hash == way2Hash) + // If any of the ways between the two are identical, then they share a parent way. + if (!way2Hash.trimmed().isEmpty() && way1Hash == way2Hash) { LOG_TRACE( "Found common way node for " << element1->getElementId() << " and " << @@ -328,13 +295,11 @@ bool ElementIdSynchronizer::_areWayNodesWithoutAWayInCommon( } } } - return true; } -void ElementIdSynchronizer::_calcElementHashes( - const OsmMapPtr& map, QMap& hashesToElementIds, - QMap& elementIdsToHashes) const +void ElementIdSynchronizer::_calcElementHashes(const OsmMapPtr& map, QMap& hashesToElementIds, + QMap& elementIdsToHashes) const { LOG_DEBUG("Calculating " << map->getName() << " element hashes..."); diff --git a/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.h b/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.h index 1b119378bf..1ea53492e4 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.h +++ b/hoot-core/src/main/cpp/hoot/core/elements/ElementIdSynchronizer.h @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef ELEMENT_ID_SYNCHRONIZER_H @@ -58,9 +58,8 @@ class ElementIdSynchronizer * @param elementType the type of element to synchronize the IDs of; all element types will have * IDs synchronized if no type is specified */ - virtual void synchronize( - const OsmMapPtr& map1, const OsmMapPtr& map2, - const ElementType& elementType = ElementType::Unknown); + virtual void synchronize(const OsmMapPtr& map1, const OsmMapPtr& map2, + const ElementType& elementType = ElementType::Unknown); int getNumNodeIdsSynchronized() const { return _updatedNodeCtr; } int getNumWayIdsSynchronized() const { return _updatedWayCtr; } @@ -98,9 +97,8 @@ class ElementIdSynchronizer /* * Calculates the element unique hashes used for comparison */ - void _calcElementHashes( - const OsmMapPtr& map, QMap& hashesToElementIds, - QMap& elementIdsToHashes) const; + void _calcElementHashes(const OsmMapPtr& map, QMap& hashesToElementIds, + QMap& elementIdsToHashes) const; /* * Determines if two elements (one from each input map) are way nodes which don't have a way @@ -114,8 +112,8 @@ class ElementIdSynchronizer */ bool _areWayNodesInWaysOfMismatchedType(ElementPtr element1, ElementPtr element2); - QSet _getHashesByElementType( - const QMap& hashesByElementId, const ElementType& elementType) const; + QSet _getHashesByElementType(const QMap& hashesByElementId, + const ElementType& elementType) const; private: diff --git a/hoot-core/src/main/cpp/hoot/core/elements/TagUtils.cpp b/hoot-core/src/main/cpp/hoot/core/elements/TagUtils.cpp index ede6a01734..051bdf7822 100644 --- a/hoot-core/src/main/cpp/hoot/core/elements/TagUtils.cpp +++ b/hoot-core/src/main/cpp/hoot/core/elements/TagUtils.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "TagUtils.h" @@ -33,22 +33,19 @@ namespace hoot bool TagUtils::allElementsHaveAnyTagKey(const QStringList& tagKeys, const std::vector& elements) { - for (std::vector::const_iterator it = elements.begin(); it != elements.end(); ++it) + for (const auto& element : elements) { - ElementPtr element = *it; bool elementHasTagKey = false; - for (int i = 0; i < tagKeys.size(); i++) + for (const auto& key : qAsConst(tagKeys)) { - if (element->getTags().contains(tagKeys.at(i))) + if (element->getTags().contains(key)) { elementHasTagKey = true; break; } } if (!elementHasTagKey) - { return false; - } } return true; } @@ -56,15 +53,12 @@ bool TagUtils::allElementsHaveAnyTagKey(const QStringList& tagKeys, bool TagUtils::anyElementsHaveAnyTagKey(const QStringList& tagKeys, const std::vector& elements) { - for (std::vector::const_iterator it = elements.begin(); it != elements.end(); ++it) + for (const auto& element : elements) { - ElementPtr element = *it; - for (int i = 0; i < tagKeys.size(); i++) + for (const auto& key : qAsConst(tagKeys)) { - if (element->getTags().contains(tagKeys.at(i))) - { + if (element->getTags().contains(key)) return true; - } } } return false; @@ -73,24 +67,18 @@ bool TagUtils::anyElementsHaveAnyTagKey(const QStringList& tagKeys, bool TagUtils::anyElementsHaveAnyKvp(const QStringList& kvps, const std::vector& elements) { - - for (std::vector::const_iterator it = elements.begin(); it != elements.end(); ++it) + for (const auto& element : elements) { - ElementPtr element = *it; - for (int i = 0; i < kvps.size(); i++) + for (const auto& kvp : qAsConst(kvps)) { - const QString kvp = kvps.at(i); const QStringList kvpParts = kvp.split("="); if (kvpParts.size() != 2) - { throw IllegalArgumentException("Invalid kvp: " + kvp); - } const QString key = kvpParts[0]; const QString val = kvpParts[1]; - if (element->getTags()[key] == val) - { + const Tags& tags = element->getTags(); + if (tags.contains(key) && tags.get(key) == val) return true; - } } } return false; @@ -100,10 +88,8 @@ bool TagUtils::anyElementsHaveAnyKvp(const QStringList& kvps, const std::set& elementIds, const OsmMapPtr& map) { std::vector elements; - for (std::set::const_iterator it = elementIds.begin(); it != elementIds.end(); ++it) - { - elements.push_back(map->getElement(*it)); - } + for (const auto& id : elementIds) + elements.push_back(map->getElement(id)); return anyElementsHaveAnyKvp(kvps, elements); } @@ -111,10 +97,8 @@ bool TagUtils::allElementsHaveAnyTagKey(const QStringList& tagKeys, const std::set& elementIds, const OsmMapPtr& map) { std::vector elements; - for (std::set::const_iterator it = elementIds.begin(); it != elementIds.end(); ++it) - { - elements.push_back(map->getElement(*it)); - } + for (const auto& id : elementIds) + elements.push_back(map->getElement(id)); return allElementsHaveAnyTagKey(tagKeys, elements); } @@ -122,18 +106,15 @@ bool TagUtils::anyElementsHaveAnyTagKey(const QStringList& tagKeys, const std::set& elementIds, const OsmMapPtr& map) { std::vector elements; - for (std::set::const_iterator it = elementIds.begin(); it != elementIds.end(); ++it) - { - elements.push_back(map->getElement(*it)); - } + for (const auto& id : elementIds) + elements.push_back(map->getElement(id)); return anyElementsHaveAnyTagKey(tagKeys, elements); } bool TagUtils::nameConflictExists(const ConstElementPtr& element1, const ConstElementPtr& element2) { - return - element1->getTags().hasName() && element2->getTags().hasName() && - !Tags::haveMatchingName(element1->getTags(), element2->getTags()); + return element1->getTags().hasName() && element2->getTags().hasName() && + !Tags::haveMatchingName(element1->getTags(), element2->getTags()); } } diff --git a/hoot-core/src/main/cpp/hoot/core/io/OsmPgCsvWriter.cpp b/hoot-core/src/main/cpp/hoot/core/io/OsmPgCsvWriter.cpp index a127e3617e..27f4d7cd83 100644 --- a/hoot-core/src/main/cpp/hoot/core/io/OsmPgCsvWriter.cpp +++ b/hoot-core/src/main/cpp/hoot/core/io/OsmPgCsvWriter.cpp @@ -22,15 +22,15 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "OsmPgCsvWriter.h" // hoot #include -#include #include +#include using namespace std; @@ -49,7 +49,7 @@ OsmPgCsvWriter::OsmPgCsvWriter() void OsmPgCsvWriter::open(const QString& url) { QFileInfo path(url); - QString base = QString("%1/%2").arg(path.absolutePath()).arg(path.baseName()); + QString base = QString("%1/%2").arg(path.absolutePath(), path.baseName()); // Create new filenames, i.e. /path/filename.pgcsv turns into /path/filename-nodes.pgcsv array filenames; filenames[FileType::Nodes] = base + QString("-nodes.") + path.completeSuffix(); @@ -156,30 +156,30 @@ void OsmPgCsvWriter::write(const ConstOsmMapPtr& map) QList ids; // Start with the nodes const NodeMap& nodes = map->getNodes(); - for (NodeMap::const_iterator it = nodes.begin(); it != nodes.end(); ++it) + for (auto it = nodes.begin(); it != nodes.end(); ++it) ids.append(it->first); // Sort the values to give consistent results. qSort(ids.begin(), ids.end(), qLess()); - for (int i = 0; i < ids.size(); i++) - writePartial(map->getNode(ids[i])); + for (auto id : qAsConst(ids)) + writePartial(map->getNode(id)); // Next are the ways ids.clear(); const WayMap& ways = map->getWays(); - for (WayMap::const_iterator it = ways.begin(); it != ways.end(); ++it) + for (auto it = ways.begin(); it != ways.end(); ++it) ids.append(it->first); // Sort the values to give consistent results. qSort(ids.begin(), ids.end(), qLess()); - for (int i = 0; i < ids.size(); i++) - writePartial(map->getWay(ids[i])); + for (auto id : qAsConst(ids)) + writePartial(map->getWay(id)); // Finally the relations ids.clear(); const RelationMap& relations = map->getRelations(); - for (RelationMap::const_iterator it = relations.begin(); it != relations.end(); ++it) + for (auto it = relations.begin(); it != relations.end(); ++it) ids.append(it->first); // Sort the values to give consistent results. qSort(ids.begin(), ids.end(), qLess()); - for (int i = 0; i < ids.size(); i++) - writePartial(map->getRelation(ids[i])); + for (auto id : qAsConst(ids)) + writePartial(map->getRelation(id)); } void OsmPgCsvWriter::writePartial(const ConstNodePtr& n) @@ -252,7 +252,7 @@ QString OsmPgCsvWriter::_getTags(const ConstElementPtr& e) const stream.setCodec("UTF-8"); const Tags& tags = e->getTags(); QRegExp regex("[\"=>, -]"); - for (Tags::const_iterator it = tags.constBegin(); it != tags.constEnd(); ++it) + for (auto it = tags.constBegin(); it != tags.constEnd(); ++it) { // Comma separated list if (it != tags.constBegin()) diff --git a/hoot-core/src/main/cpp/hoot/core/ops/AddHilbertReviewSortOrderOp.cpp b/hoot-core/src/main/cpp/hoot/core/ops/AddHilbertReviewSortOrderOp.cpp index 1f27d227ef..61808bead5 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/AddHilbertReviewSortOrderOp.cpp +++ b/hoot-core/src/main/cpp/hoot/core/ops/AddHilbertReviewSortOrderOp.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "AddHilbertReviewSortOrderOp.h" @@ -51,26 +51,19 @@ HOOT_FACTORY_REGISTER(OsmMapOperation, AddHilbertReviewSortOrderOp) bool reviewLess(const pair& p1, const pair& p2) { if (p1.second < p2.second) - { return true; - } else if (p1.second == p2.second) - { return p1.first < p2.first; - } else - { return false; - } } void AddHilbertReviewSortOrderOp::apply(OsmMapPtr& map) { if (!ConfigOptions().getWriterIncludeConflateReviewDetailTags()) { - LOG_DEBUG( - "AddHilbertReviewSortOrderOp disabled due to " << - ConfigOptions::getWriterIncludeConflateReviewDetailTagsKey() << "=false."); + LOG_DEBUG("AddHilbertReviewSortOrderOp disabled due to " << + ConfigOptions::getWriterIncludeConflateReviewDetailTagsKey() << "=false."); return; } @@ -84,7 +77,7 @@ void AddHilbertReviewSortOrderOp::apply(OsmMapPtr& map) // reserves at least as much as we need reviewOrder.reserve(relations.size()); - for (RelationMap::const_iterator it = relations.begin(); it != relations.end(); ++it) + for (auto it = relations.begin(); it != relations.end(); ++it) { RelationPtr r = it->second; LOG_VART(r->getElementId()); @@ -104,9 +97,6 @@ void AddHilbertReviewSortOrderOp::apply(OsmMapPtr& map) } else { - // don't think this really needs to be an exceptional situation -// throw HootException( -// "No review elements returned for relation with ID: " + r->getElementId().toString()); LOG_WARN("No review elements returned for relation with ID: " << r->getElementId()); if (logWarnCount < Log::getWarnMessageLimit()) { @@ -126,50 +116,41 @@ void AddHilbertReviewSortOrderOp::apply(OsmMapPtr& map) for (size_t i = 0; i < reviewOrder.size(); ++i) { RelationPtr r = map->getRelation(reviewOrder[i].first.getId()); - r->getTags().set(MetadataTags::HootReviewSortOrder(), (long)i); _numAffected++; } } -int64_t AddHilbertReviewSortOrderOp::_calculateHilbertValue( - const ConstOsmMapPtr& map, const std::set& eids) +int64_t AddHilbertReviewSortOrderOp::_calculateHilbertValue(const ConstOsmMapPtr& map, const std::set& eids) { std::shared_ptr env; - for (set::const_iterator it = eids.begin(); it != eids.end(); ++it) + for (const auto& eid : eids) { - ConstElementPtr element = map->getElement(*it); + ConstElementPtr element = map->getElement(eid); if (element) { std::unique_ptr te(element->getEnvelope(map)); LOG_VART(env.get()); if (env.get() == nullptr) - { env = std::make_shared(*te); - } else - { env->expandToInclude(te.get()); - } } } if (!env) - { return -1; - } + LOG_VART(env->toString()); if (_mapEnvelope.get() == nullptr) - { _mapEnvelope = std::make_shared(CalculateMapBoundsVisitor::getGeosBounds(map)); - } Coordinate center; env->centre(center); Meters cellSize = 10.0; - int xorder = max(1.0, ceil(log(_mapEnvelope->getWidth() / cellSize) / log(2.0))); - int yorder = max(1.0, ceil(log(_mapEnvelope->getHeight() / cellSize) / log(2.0))); + int xorder = static_cast(max(1.0, ceil(log(_mapEnvelope->getWidth() / cellSize) / log(2.0)))); + int yorder = static_cast(max(1.0, ceil(log(_mapEnvelope->getHeight() / cellSize) / log(2.0)))); // 31 bits is the most supported for 2 dimensions. int order = min(31, max(xorder, yorder)); @@ -178,10 +159,10 @@ int64_t AddHilbertReviewSortOrderOp::_calculateHilbertValue( int64_t maxRange = 1 << order; int point[2]; - point[0] = max(0, min(maxRange - 1, - round((center.x - _mapEnvelope->getMinX()) / cellSize))); - point[1] = max(0, min(maxRange - 1, - round((center.y - _mapEnvelope->getMinY()) / cellSize))); + point[0] = static_cast(max(0, min(maxRange - 1, + static_cast(round((center.x - _mapEnvelope->getMinX()) / cellSize))))); + point[1] = static_cast(max(0, min(maxRange - 1, + static_cast(round((center.y - _mapEnvelope->getMinY()) / cellSize))))); // Pad with zeros to make sorting a little easier. return c.encode(point); diff --git a/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.cpp b/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.cpp index 8f706453aa..64c2e63582 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.cpp +++ b/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "ElementIdRemapper.h" @@ -35,23 +35,22 @@ namespace hoot HOOT_FACTORY_REGISTER(OsmMapOperation, ElementIdRemapper) -ElementIdRemapper::ElementIdRemapper() : -_restoredIds(0) +ElementIdRemapper::ElementIdRemapper() + : _restoredIds(0) { } -ElementIdRemapper::ElementIdRemapper(const ElementCriterionPtr& remapFilter) : -_remapFilter(remapFilter), -_restoreFilter(remapFilter), -_restoredIds(0) +ElementIdRemapper::ElementIdRemapper(const ElementCriterionPtr& remapFilter) + : _remapFilter(remapFilter), + _restoreFilter(remapFilter), + _restoredIds(0) { } -ElementIdRemapper::ElementIdRemapper( - const ElementCriterionPtr& remapFilter, const ElementCriterionPtr& restoreFilter) : -_remapFilter(remapFilter), -_restoreFilter(restoreFilter), -_restoredIds(0) +ElementIdRemapper::ElementIdRemapper(const ElementCriterionPtr& remapFilter, const ElementCriterionPtr& restoreFilter) + : _remapFilter(remapFilter), + _restoreFilter(restoreFilter), + _restoredIds(0) { } @@ -63,24 +62,19 @@ void ElementIdRemapper::apply(OsmMapPtr& map) _restoredIds = 0; _originalToRemappedElementIds.clear(); - // TODO: make this more generic, if possible; use ElementIterator? + // TODO: make this more generic, if possible; use ElementIterator? The next three loops are almost identical const NodeMap nodes = map->getNodes(); - for (NodeMap::const_iterator it = nodes.begin(); it != nodes.end(); ++it) + for (auto it = nodes.begin(); it != nodes.end(); ++it) { ElementPtr currentElement = it->second; _numProcessed++; if (!currentElement || (_remapFilter && !_remapFilter->isSatisfied(currentElement))) - { continue; - } ElementPtr newElement = currentElement->clone(); - const ElementId newElementId = - ElementId(ElementType::Node, IdGenerator::getInstance()->createNodeId()); + const ElementId newElementId = ElementId(ElementType::Node, IdGenerator::getInstance()->createNodeId()); newElement->setId(newElementId.getId()); - LOG_TRACE( - "Remapping " << currentElement->getElementId() << " to " << newElement->getElementId() << - "..."); + LOG_TRACE("Remapping " << currentElement->getElementId() << " to " << newElement->getElementId() << "..."); _originalToRemappedElementIds[newElementId] = currentElement->getElementId(); map->addElement(newElement); map->replace(currentElement, newElement); @@ -88,21 +82,16 @@ void ElementIdRemapper::apply(OsmMapPtr& map) } const WayMap ways = map->getWays(); - for (WayMap::const_iterator it = ways.begin(); it != ways.end(); ++it) + for (auto it = ways.begin(); it != ways.end(); ++it) { ElementPtr currentElement = it->second; _numProcessed++; if (!currentElement || (_remapFilter && !_remapFilter->isSatisfied(currentElement))) - { continue; - } ElementPtr newElement = currentElement->clone(); - const ElementId newElementId = - ElementId(ElementType::Way, IdGenerator::getInstance()->createWayId()); + const ElementId newElementId = ElementId(ElementType::Way, IdGenerator::getInstance()->createWayId()); newElement->setId(newElementId.getId()); - LOG_TRACE( - "Remapping " << currentElement->getElementId() << " to " << newElement->getElementId() << - "..."); + LOG_TRACE("Remapping " << currentElement->getElementId() << " to " << newElement->getElementId() << "..."); _originalToRemappedElementIds[newElementId] = currentElement->getElementId(); map->addElement(newElement); map->replace(currentElement, newElement); @@ -110,21 +99,16 @@ void ElementIdRemapper::apply(OsmMapPtr& map) } const RelationMap relations = map->getRelations(); - for (RelationMap::const_iterator it = relations.begin(); it != relations.end(); ++it) + for (auto it = relations.begin(); it != relations.end(); ++it) { ElementPtr currentElement = it->second; _numProcessed++; if (!currentElement || (_remapFilter && !_remapFilter->isSatisfied(currentElement))) - { continue; - } ElementPtr newElement = currentElement->clone(); - const ElementId newElementId = - ElementId(ElementType::Relation, IdGenerator::getInstance()->createRelationId()); + const ElementId newElementId = ElementId(ElementType::Relation, IdGenerator::getInstance()->createRelationId()); newElement->setId(newElementId.getId()); - LOG_TRACE( - "Remapping " << currentElement->getElementId() << " to " << newElement->getElementId() << - "..."); + LOG_TRACE("Remapping " << currentElement->getElementId() << " to " << newElement->getElementId() << "..."); _originalToRemappedElementIds[newElementId] = currentElement->getElementId(); map->addElement(newElement); map->replace(currentElement, newElement); @@ -139,35 +123,25 @@ void ElementIdRemapper::restore(const OsmMapPtr& map) _restoredIds = 0; _numProcessed = 0; if (!_restoreFilter) - { _restoreFilter = _remapFilter; - } - // TODO: make this more generic, if possible; use ElementIterator? + // TODO: make this more generic, if possible; use ElementIterator? The next three loops are almost identical const RelationMap relations = map->getRelations(); - for (RelationMap::const_iterator it = relations.begin(); it != relations.end(); ++it) + for (auto it = relations.begin(); it != relations.end(); ++it) { ElementPtr currentElement = it->second; _numProcessed++; if (!currentElement || (_restoreFilter && !_restoreFilter->isSatisfied(currentElement))) - { continue; - } - const ElementId originalElementId = - _originalToRemappedElementIds[currentElement->getElementId()]; + const ElementId originalElementId = _originalToRemappedElementIds[currentElement->getElementId()]; if (!originalElementId.isNull()) { if (map->containsElement(originalElementId)) - { RemoveElementByEid::removeElement(map, originalElementId); - } - ElementPtr originalElement = currentElement->clone(); originalElement->setId(originalElementId.getId()); - LOG_TRACE( - "Restoring " << currentElement->getElementId() << " to " << - originalElement->getElementId() << "..."); + LOG_TRACE("Restoring " << currentElement->getElementId() << " to " << originalElement->getElementId() << "..."); map->addElement(originalElement); map->replace(currentElement, originalElement); _restoredIds++; @@ -175,28 +149,20 @@ void ElementIdRemapper::restore(const OsmMapPtr& map) } const WayMap ways = map->getWays(); - for (WayMap::const_iterator it = ways.begin(); it != ways.end(); ++it) + for (auto it = ways.begin(); it != ways.end(); ++it) { ElementPtr currentElement = it->second; _numProcessed++; if (!currentElement || (_restoreFilter && !_restoreFilter->isSatisfied(currentElement))) - { continue; - } - const ElementId originalElementId = - _originalToRemappedElementIds[currentElement->getElementId()]; + const ElementId originalElementId = _originalToRemappedElementIds[currentElement->getElementId()]; if (!originalElementId.isNull()) { if (map->containsElement(originalElementId)) - { RemoveElementByEid::removeElement(map, originalElementId); - } - ElementPtr originalElement = currentElement->clone(); originalElement->setId(originalElementId.getId()); - LOG_TRACE( - "Restoring " << currentElement->getElementId() << " to " << - originalElement->getElementId() << "..."); + LOG_TRACE("Restoring " << currentElement->getElementId() << " to " << originalElement->getElementId() << "..."); map->addElement(originalElement); map->replace(currentElement, originalElement); _restoredIds++; @@ -204,28 +170,20 @@ void ElementIdRemapper::restore(const OsmMapPtr& map) } const NodeMap nodes = map->getNodes(); - for (NodeMap::const_iterator it = nodes.begin(); it != nodes.end(); ++it) + for (auto it = nodes.begin(); it != nodes.end(); ++it) { ElementPtr currentElement = it->second; _numProcessed++; if (!currentElement || (_restoreFilter && !_restoreFilter->isSatisfied(currentElement))) - { continue; - } - const ElementId originalElementId = - _originalToRemappedElementIds[currentElement->getElementId()]; + const ElementId originalElementId = _originalToRemappedElementIds[currentElement->getElementId()]; if (!originalElementId.isNull()) { if (map->containsElement(originalElementId)) - { RemoveElementByEid::removeElement(map, originalElementId); - } - ElementPtr originalElement = currentElement->clone(); originalElement->setId(originalElementId.getId()); - LOG_TRACE( - "Restoring " << currentElement->getElementId() << " to " << - originalElement->getElementId() << "..."); + LOG_TRACE("Restoring " << currentElement->getElementId() << " to " << originalElement->getElementId() << "..."); map->addElement(originalElement); map->replace(currentElement, originalElement); _restoredIds++; diff --git a/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.h b/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.h index c87fb0d802..f4df110622 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.h +++ b/hoot-core/src/main/cpp/hoot/core/ops/ElementIdRemapper.h @@ -22,16 +22,16 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef _ELEMENT_ID_REMAPPER_H_ #define _ELEMENT_ID_REMAPPER_H_ // Hoot +#include #include #include #include -#include namespace hoot { @@ -48,8 +48,7 @@ class ElementIdRemapper : public OsmMapOperation ElementIdRemapper(); ElementIdRemapper(const ElementCriterionPtr& remapFilter); - ElementIdRemapper( - const ElementCriterionPtr& remapFilter, const ElementCriterionPtr& restoreFilter); + ElementIdRemapper(const ElementCriterionPtr& remapFilter, const ElementCriterionPtr& restoreFilter); ~ElementIdRemapper() override = default; /** diff --git a/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.cpp b/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.cpp index a79a4af722..cf814701a7 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.cpp +++ b/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.cpp @@ -23,7 +23,7 @@ * copyrights will be updated automatically. * * @copyright Copyright (C) 2021 DigitalGlobe (http://www.digitalglobe.com/) - * @copyright Copyright (C) 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2021, 2022 Maxar (http://www.maxar.com/) */ #include "ResolveReviewsOp.h" @@ -69,7 +69,7 @@ void ResolveReviewsOp::apply(std::shared_ptr& map) // Go through all the relations to get reviews const RelationMap& relations = map->getRelations(); RelationMap reviews; - for (RelationMap::const_iterator it = relations.begin(); it != relations.end(); ++it) + for (auto it = relations.begin(); it != relations.end(); ++it) { ElementId eid = ElementId::relation(it->first); if (ReviewMarker::isReviewUid(map, eid)) @@ -83,14 +83,14 @@ void ResolveReviewsOp::apply(std::shared_ptr& map) { LOG_INFO("ResolveReviews operator removing reviews"); // Remove all of the review relations one by one - for (RelationMap::iterator it = reviews.begin(); it != reviews.end(); ++it) + for (auto it = reviews.begin(); it != reviews.end(); ++it) RemoveElementByEid(ElementId::relation(it->first)).apply(map); } else { LOG_INFO("ResolveReviews operator resolving reviews"); // Iterate all reviews and resolve them - for (RelationMap::iterator it = reviews.begin(); it != reviews.end(); ++it) + for (auto it = reviews.begin(); it != reviews.end(); ++it) { ElementId rid = ElementId::relation(it->first); set elements = ReviewMarker::getReviewElements(map, rid); @@ -103,9 +103,9 @@ void ResolveReviewsOp::apply(std::shared_ptr& map) { // Check if any elements are part of multiple reviews bool multipleReviews = false; - for (set::iterator it2 = elements.begin(); it2 != elements.end(); ++it2) + for (auto eid : elements) { - if (ReviewMarker::getReviewUids(map, *it2).size() > 1) + if (ReviewMarker::getReviewUids(map, eid).size() > 1) multipleReviews = true; } std::vector eids(elements.begin(), elements.end()); @@ -119,18 +119,16 @@ void ResolveReviewsOp::apply(std::shared_ptr& map) } } -void ResolveReviewsOp::_resolveReview( - const std::shared_ptr& map, const ElementId& relation_id, const ElementId& eid1, - const ElementId& eid2) +void ResolveReviewsOp::_resolveReview(const std::shared_ptr& map, const ElementId& relation_id, + const ElementId& eid1, const ElementId& eid2) { MatchPtr match = _getCachedMatch(map, relation_id, eid1, eid2); // Resolve the match review _resolveMatchReview(match, map, relation_id, eid1, eid2); } -void ResolveReviewsOp::_resolveMultipleReviews( - const std::shared_ptr& map, const ElementId& relation_id, const ElementId& eid1, - const ElementId& eid2) +void ResolveReviewsOp::_resolveMultipleReviews(const std::shared_ptr& map, const ElementId& relation_id, + const ElementId& eid1, const ElementId& eid2) { LOG_TRACE( "Resolving multiple reviews for review: " << relation_id << ", elements: " << @@ -147,13 +145,12 @@ void ResolveReviewsOp::_resolveMultipleReviews( double score = match->getScore(); std::vector element_ids = { eid1, eid2 }; // Iterate both sides of the relation looking for the best result - for (std::vector::iterator it = element_ids.begin(); it != element_ids.end(); ++it) + for (auto eid : element_ids) { // Iterate all of the reviews involving this element ID looking for a score higher than the current score - std::set reviews_eid = ReviewMarker::getReviewUids(map, *it); - for (std::set::iterator rit = reviews_eid.begin(); rit != reviews_eid.end(); ++rit) + std::set reviews_eid = ReviewMarker::getReviewUids(map, eid); + for (const auto& rid : reviews_eid) { - ReviewMarker::ReviewUid rid = *rit; // Ignore the current review if (relation_id == rid) continue; @@ -201,49 +198,38 @@ void ResolveReviewsOp::_resolveMatchReview(const std::shared_ptr& match, eids.emplace(eid1, eid2); MergerFactory::getInstance().createMergers(map, matches, mergers); - for (std::vector::iterator it = mergers.begin(); it != mergers.end(); ++it) + for (const auto& merger : mergers) { std::vector> replaced; - MergerPtr merger = *it; merger->apply(map, replaced); } } // Once the match is merged, delete the review relation or after removing all other distractions ReviewMarker::removeElement(map, relation_id); } - else - { - // Manually resolve the review relation + else // Manually resolve the review relation _resolveManualReview(map, relation_id, eid1, eid2); - } } void ResolveReviewsOp::_resolveManualReview( const std::shared_ptr& map, const ElementId& relation_id, const ElementId& eid1, const ElementId& eid2) const { - LOG_TRACE( - "Manually resolving review: " << relation_id << ", elements: " << eid1 << ", " << eid2 << "..."); + LOG_TRACE("Manually resolving review: " << relation_id << ", elements: " << eid1 << ", " << eid2 << "..."); ElementPtr element1 = map->getElement(eid1); ElementPtr element2 = map->getElement(eid2); // Remove UNKNOWN2 if (element1->getStatus() == Status::Unknown2) - { ReviewMarker::removeElement(map, eid1); - } - if (element2->getStatus() == Status::Unknown2) - { ReviewMarker::removeElement(map, eid2); - } // Remove the review relation ReviewMarker::removeElement(map, relation_id); } -MatchPtr ResolveReviewsOp::_getCachedMatch( - const std::shared_ptr& map, const ElementId& relation_id, const ElementId& eid1, - const ElementId& eid2) +MatchPtr ResolveReviewsOp::_getCachedMatch(const std::shared_ptr& map, const ElementId& relation_id, + const ElementId& eid1, const ElementId& eid2) { MatchPtr match; // Check for a previously cached match diff --git a/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.h b/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.h index 0b6a44820a..9042796182 100644 --- a/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.h +++ b/hoot-core/src/main/cpp/hoot/core/ops/ResolveReviewsOp.h @@ -23,7 +23,7 @@ * copyrights will be updated automatically. * * @copyright Copyright (C) 2021 DigitalGlobe (http://www.digitalglobe.com/) - * @copyright Copyright (C) 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef RESOLVE_REVIEWS_OP_H #define RESOLVE_REVIEWS_OP_H @@ -85,9 +85,7 @@ class ResolveReviewsOp : public OsmMapOperation, public Configurable { return "Resolving conflation reviews..."; } QString getCompletedStatusMessage() const override { - return - "Resolved " + StringUtils::formatLargeNumber(_numAffected) + - " conflation review relations"; + return "Resolved " + StringUtils::formatLargeNumber(_numAffected) + " conflation review relations"; } ResolveType getResolveType() const { return _type; } diff --git a/hoot-js/src/main/cpp/hoot/js/schema/JsonOsmSchemaLoader.cpp b/hoot-js/src/main/cpp/hoot/js/schema/JsonOsmSchemaLoader.cpp index 3887ef5260..bc64edb599 100644 --- a/hoot-js/src/main/cpp/hoot/js/schema/JsonOsmSchemaLoader.cpp +++ b/hoot-js/src/main/cpp/hoot/js/schema/JsonOsmSchemaLoader.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "JsonOsmSchemaLoader.h" @@ -30,6 +30,7 @@ #include #include #include + #include #include @@ -56,9 +57,7 @@ void JsonOsmSchemaLoader::load(QString path, OsmSchema& s) { QFile fp(path); if (fp.open(QFile::ReadOnly) == false) - { throw HootException("Error opening JSON file: " + path); - } // Maintain a stack of file locations so imports happen properly. _baseDir.append(QDir(path + "/..").absolutePath() + "/"); @@ -74,21 +73,18 @@ void JsonOsmSchemaLoader::load(QString path, OsmSchema& s) QVariantList l = toCpp(result); - for (int i = 0; i < l.size(); i++) + for (const auto& var : qAsConst(l)) { try { - if (l[i].type() != QVariant::Map) - { - throw HootException(QString("Expected to get a dict as the 'object', got: %2"). - arg(l[i].typeName())); - } - _processObject(l[i].toMap(), s); + if (var.type() != QVariant::Map) + throw HootException(QString("Expected to get a dict as the 'object', got: %2").arg(var.typeName())); + _processObject(var.toMap(), s); } catch(const HootException& e) { throw HootException(QString("Error processing '%1' in object '%2'. %3"). - arg(path).arg(toJson(toV8(l[i]))).arg(e.getWhat())); + arg(path).arg(toJson(toV8(var))).arg(e.getWhat())); } } @@ -119,14 +115,10 @@ double JsonOsmSchemaLoader::_asDouble(const QVariant& v) const QString JsonOsmSchemaLoader::_asString(const QVariant& v) const { if (v.type() == QVariant::String) - { return v.toString(); - } else - { throw IllegalArgumentException(QString("Expected to receive a string, but got: %1 (%2)"). arg(toString(v)).arg(v.typeName())); - } } QStringList JsonOsmSchemaLoader::_asStringList(const QVariant& v) const @@ -138,10 +130,8 @@ QStringList JsonOsmSchemaLoader::_asStringList(const QVariant& v) const QVariantList l = v.toList(); result.reserve(l.size()); - for (int i = 0; i < l.size(); i++) - { - result.push_back(_asString(l[i])); - } + for (const auto& var : qAsConst(l)) + result.push_back(_asString(var)); } else { @@ -152,21 +142,15 @@ QStringList JsonOsmSchemaLoader::_asStringList(const QVariant& v) const return result; } -void JsonOsmSchemaLoader::_loadAssociatedWith( - const SchemaVertex& tv, const QVariant& v, const OsmSchema& s) const +void JsonOsmSchemaLoader::_loadAssociatedWith(const SchemaVertex& tv, const QVariant& v, const OsmSchema& s) const { if (v.type() != QVariant::List) - { throw HootException("Expected an array for associatedWith."); - } else { const QVariantList l = v.toList(); - - for (int i = 0; i < l.size(); ++i) - { - s.addAssociatedWith(tv.getName(), toString(l[i])); - } + for (const auto& var : qAsConst(l)) + s.addAssociatedWith(tv.getName(), toString(var)); } } @@ -178,54 +162,31 @@ void JsonOsmSchemaLoader::_loadBase(QVariantMap& copy, const OsmSchema& s, Schem copy.remove("tagInfoCount"); if (copy.contains("associatedWith")) - { _loadAssociatedWith(tv, copy.take("associatedWith"), s); - } if (copy.contains("isA")) - { s.addIsA(tv.getName(), _asString(copy.take("isA"))); - } if (copy.contains("similarTo")) - { _loadSimilarTo(tv.getName(), copy.take("similarTo"), s); - } if (copy.contains("description")) - { tv.setDescription(_asString(copy.take("description"))); - } if (copy.contains("tagInfoDescription")) { if (tv.getDescription().isEmpty()) - { tv.setDescription(_asString(copy["tagInfoDescription"])); - } copy.remove("tagInfoDescription"); } if (copy.contains("influence")) - { tv.setInfluence(_asDouble(copy.take("influence"))); - } if (copy.contains("childWeight")) - { tv.setChildWeight(_asDouble(copy.take("childWeight"))); - } if (copy.contains("mismatchScore")) - { tv.setMismatchScore(_asDouble(copy.take("mismatchScore"))); - } if (copy.contains("aliases")) - { tv.setAliases(_asStringList(copy.take("aliases"))); - } if (copy.contains("categories")) - { tv.setCategories(_asStringList(copy.take("categories"))); - } if (copy.contains("geometries")) - { _loadGeometries(tv, copy.take("geometries")); - } - if (copy.size() != 0) { if (logWarnCount < Log::getWarnMessageLimit()) @@ -245,34 +206,24 @@ void JsonOsmSchemaLoader::_loadCompound(const QVariantMap& v, const OsmSchema& s { QVariantMap copy; // copy all the non-comments - for (QVariantMap::const_iterator it = v.begin(); it != v.end(); ++it) + for (auto it = v.begin(); it != v.end(); ++it) { if (it.key().startsWith('#') == false) - { copy[it.key()] = it.value(); - } } SchemaVertex tv; tv.setType(SchemaVertex::Compound); if (copy.contains("name")) - { tv.setName(_asString(copy.take("name"))); - } else - { throw HootException("Expected the object to contain a name."); - } + if (copy.contains("tags")) - { _loadCompoundTags(tv, copy.take("tags")); - } else - { - throw HootException(QString("Expected compound to contain a 'tags' entry. (%1)"). - arg(copy["name"].toString())); - } + throw HootException(QString("Expected compound to contain a 'tags' entry. (%1)").arg(copy["name"].toString())); // load all the values common to tag and compound. _loadBase(copy, s, tv); @@ -283,45 +234,30 @@ void JsonOsmSchemaLoader::_loadCompound(const QVariantMap& v, const OsmSchema& s void JsonOsmSchemaLoader::_loadCompoundTags(SchemaVertex& tv, const QVariant& value) const { if (value.type() != QVariant::List) - { throw HootException("Expected an array for compound tags."); - } else { QVariantList arr = value.toList(); if (arr.size() == 0) - { throw HootException("A compound tag must have 1 or more tag entries."); - } - for (int i = 0; i < arr.size(); i++) + for (const auto& v2 : qAsConst(arr)) { - const QVariant& v2 = arr[i]; - if (v2.type() != QVariant::List) - { throw HootException("A compound tag must have 1 or more sub-arrays."); - } - QVariantList a2 = v2.toList(); + QVariantList a2 = v2.toList(); if (a2.size() == 0) - { throw HootException("A compound tag entry must have 1 or more KVP entries."); - } QList rule; - for (int j = 0; j < a2.size(); j++) + for (const auto& v3 : qAsConst(a2)) { - QVariant v3 = a2[j]; if (v3.type() != QVariant::String) - { throw HootException("A compound tag rule must be an array of strings."); - } - rule.append(std::make_shared(_asString(v3))); } - tv.addCompoundRule(rule); } } @@ -330,42 +266,33 @@ void JsonOsmSchemaLoader::_loadCompoundTags(SchemaVertex& tv, const QVariant& va void JsonOsmSchemaLoader::_loadGeometries(SchemaVertex& tv, const QVariant& v) const { if (v.type() != QVariant::List) - { throw HootException("Expected an array for associatedWith."); - } else { const QVariantList arr = v.toList(); - uint16_t g = 0; - for (int i = 0; i < arr.size(); i++) + for (const auto& var : qAsConst(arr)) { - QString value = toString(_asString(arr[i])).toLower(); + QString value = toString(_asString(var)).toLower(); LOG_VART(value); uint16_t e = OsmGeometries::fromString(value); g |= e; } LOG_VART(g); - tv.setGeometries(g); } } -void JsonOsmSchemaLoader::_loadSimilarTo( - QString fromName, const QVariant& value, const OsmSchema& s) const +void JsonOsmSchemaLoader::_loadSimilarTo(QString fromName, const QVariant& value, const OsmSchema& s) const { if (value.type() == QVariant::List) { QVariantList l = value.toList(); - for (int i = 0; i < l.size(); ++i) - { - _loadSimilarTo(fromName, l[i], s); - } + for (const auto& var : qAsConst(l)) + _loadSimilarTo(fromName, var, s); } else if (value.type() != QVariant::Map) - { throw HootException("Expected an dict for similar to."); - } else { QVariantMap obj = value.toMap(); @@ -375,61 +302,44 @@ void JsonOsmSchemaLoader::_loadSimilarTo( double weight2 = -1; bool oneway = false; - for (QVariantMap::const_iterator it = obj.begin(); it != obj.end(); ++it) + for (auto it = obj.cbegin(); it != obj.cend(); ++it) { if (it.key() == "name") { toName = _asString(it.value()); if (toName.isEmpty()) - { throw HootException("Name must be non-null."); - } } else if (it.key() == "weight") { if (it.value().type() == QVariant::List) { QVariantList arr = it.value().toList(); - if (arr.size() != 2) - { - throw HootException("Expected either an array of size 2, or a single double as the " - "weight."); - } + throw HootException("Expected either an array of size 2, or a single double as the weight."); + weight1 = _asDouble(arr[0]); weight2 = _asDouble(arr[1]); } else - { weight1 = _asDouble(it.value()); - } } else if (it.key() == "oneway") - { oneway = it.value().toBool(); - } else - { - throw HootException("Only 'tag' is supported at the top level at this time. " + - it.key()); - } + throw HootException("Only 'tag' is supported at the top level at this time. " + it.key()); } if (weight1 >= 0 && weight2 >= 0) { if (oneway) - { - throw HootException("Expected only oneway and a single weight, or two weights. " - "Got both."); - } + throw HootException("Expected only oneway and a single weight, or two weights. Got both."); s.addSimilarTo(fromName, toName, weight1, true); s.addSimilarTo(toName, fromName, weight2, true); } else - { s.addSimilarTo(fromName, toName, weight1, oneway); - } } } @@ -437,29 +347,22 @@ void JsonOsmSchemaLoader::_loadTag(const QVariantMap& v, const OsmSchema& s) con { QVariantMap copy; // copy all the non-comments - for (QVariantMap::const_iterator it = v.begin(); it != v.end(); ++it) + for (auto it = v.begin(); it != v.end(); ++it) { if (it.key().startsWith('#') == false) - { copy[it.key()] = it.value(); - } } SchemaVertex tv; tv.setType(SchemaVertex::Tag); if (copy.contains("name")) - { tv.setNameKvp(_asString(copy.take("name"))); - } else - { throw HootException("Expected the object to contain a name."); - } + if (copy.contains("dataType")) - { tv.setValueTypeString(_asString(copy.take("dataType"))); - } // load all the values common to tag and compound. _loadBase(copy, s, tv); @@ -478,22 +381,14 @@ void JsonOsmSchemaLoader::_processObject(const QVariantMap& v, OsmSchema& s) { QString ot = _asString(v["objectType"]); if (ot == "tag") - { _loadTag(v, s); - } else if (ot == "compound") - { _loadCompound(v, s); - } else - { throw HootException("Unexpected object type: " + ot); - } } else - { throw HootException("Unexpected record type in: " + toString(v)); - } } } diff --git a/tgs/src/main/cpp/tgs/Optimization/NelderMead.h b/tgs/src/main/cpp/tgs/Optimization/NelderMead.h index 17e883a2c5..25b665b024 100644 --- a/tgs/src/main/cpp/tgs/Optimization/NelderMead.h +++ b/tgs/src/main/cpp/tgs/Optimization/NelderMead.h @@ -23,7 +23,7 @@ * copyrights will be updated automatically. * * @copyright Copyright (C) 2012 Sebastian Morr - * @copyright Copyright (C) 2015, 2016, 2017, 2019, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2016, 2017, 2019, 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef NELDERMEAD_H #define NELDERMEAD_H @@ -56,142 +56,120 @@ class Vector { public: - Vector() = default; - ~Vector() = default; + Vector() = default; + ~Vector() = default; - Vector(double c0) - { - coords.push_back(c0); - } - - Vector(double c0, double c1) - { - coords.push_back(c0); - coords.push_back(c1); - } - Vector(double c0, double c1, double c2) - { - coords.push_back(c0); - coords.push_back(c1); - coords.push_back(c2); - } - - // add more constructors when N gets > 3 + Vector(double c0) + { + coords.push_back(c0); + } + Vector(double c0, double c1) + { + coords.push_back(c0); + coords.push_back(c1); + } + Vector(double c0, double c1, double c2) + { + coords.push_back(c0); + coords.push_back(c1); + coords.push_back(c2); + } + // add more constructors when N gets > 3 - double& operator[](int i) - { - return coords[i]; - } - double at(int i) const - { - return coords[i]; - } - int dimension() const - { - return coords.size(); - } - void prepare(int size) - { - for (int i=0; i(coords.size()); + } + void prepare(int size) + { + for (int i = 0; i < size; ++i) + coords.push_back(0); + } + Vector operator+(Vector other) + { + Vector result; + result.prepare(dimension()); + for (int i = 0; i < dimension(); ++i) + result[i] = coords[i] + other[i]; + return result; + } + void operator+=(Vector other) + { + for (int i = 0; i < dimension(); ++i) + coords[i] += other[i]; + } + Vector operator-(Vector other) + { + Vector result; + result.prepare(dimension()); + for (int i = 0; i < dimension(); ++i) + result[i] = coords[i] - other[i]; + return result; + } + bool operator==(Vector other) + { + if (dimension() != other.dimension()) + return false; + for (int i = 0; i < dimension(); ++i) { - for (int i=0; i other.at(i)) - return true; - } + if (other[i] != coords[i]) return false; } - double length() + return true; + } + Vector operator*(double factor) + { + Vector result; + result.prepare(dimension()); + for (int i = 0; i < dimension(); ++i) + result[i] = coords[i] * factor; + return result; + } + Vector operator/(double factor) + { + Vector result; + result.prepare(dimension()); + for (int i = 0; i < dimension(); ++i) + result[i] = coords[i] / factor; + return result; + } + void operator/=(double factor) + { + for (int i = 0; i < dimension(); ++i) + coords[i] /= factor; + } + bool operator<(const Vector& other) const + { + for (int i = 0; i < dimension(); ++i) { - double sum = 0; - for (int i=0; i other.at(i)) + return true; } + return false; + } + double length() + { + double sum = 0; + for (int i = 0; i < dimension(); ++i) + sum += coords[i] * coords[i]; + return pow(sum, 0.5); + } - const std::vector& getVector() const { return coords; } + const std::vector& getVector() const { return coords; } private: - std::vector coords; + std::vector coords; }; // This class stores known values for vectors. It throws unknown vectors. @@ -204,13 +182,9 @@ class ValueDB double lookup(Vector vec) { if (!contains(vec)) - { throw Tgs::Exception("Vector was not found in DB. Internal error."); - } else - { return values[vec]; - } } void insert(Vector vec, double value) @@ -220,8 +194,7 @@ class ValueDB bool contains(Vector vec) { - std::map::iterator it = values.find(vec); // TODO add tolerance - return it != values.end(); + return values.find(vec) != values.end(); } private: @@ -267,19 +240,17 @@ class NelderMead /** * Takes ownership of the function object. */ - NelderMead( - size_t dimensionSize, std::shared_ptr function, - double terminationDistance = 0.001) : - _function(function), - dimension(dimensionSize), - alpha(1), - gamma(2), - rho(-0.5), - sigma(0.5), - termination_distance(terminationDistance), - _bestDistance(std::numeric_limits::max()), - _noChange(0), - _maxNoChange(4) + NelderMead(size_t dimensionSize, std::shared_ptr function, double terminationDistance = 0.001) + : _function(function), + dimension(dimensionSize), + alpha(1), + gamma(2), + rho(-0.5), + sigma(0.5), + termination_distance(terminationDistance), + _bestDistance(std::numeric_limits::max()), + _noChange(0), + _maxNoChange(4) { } ~NelderMead() = default; @@ -290,20 +261,15 @@ class NelderMead { bool result = true; if (vectors.size() < dimension) - { result = false; - } else { - for (size_t i=0; i termination_distance) - { result = false; - } } } } - _noChange++; if (_noChange > _maxNoChange) - { result = true; - } - return result; } void insert(Vector vec) { - if (vectors.size() < dimension+1) - { - vectors.push_back(vec); - } + if (vectors.size() < dimension + 1) + vectors.push_back(vec); } void setMaxNoChange(int maxNoChange) { _maxNoChange = maxNoChange; } @@ -339,71 +297,55 @@ class NelderMead Vector step(Vector vec, double score) { db.insert(vec, score); - - if (vectors.size() < dimension+1) - { - vectors.push_back(vec); - } - + if (vectors.size() < dimension + 1) + vectors.push_back(vec); // otherwise: optimize! - if (vectors.size() == dimension+1) + if (vectors.size() == dimension + 1) { - while (!done()) + while (!done()) + { + //cout << "count: " << count++ << endl; + sort(vectors.begin(), vectors.end(), VectorSort(this)); + Vector cog; // center of gravity + cog.prepare(static_cast(dimension)); + for (size_t i = 1; i <= dimension; ++i) + cog += vectors[i]; + cog /= static_cast(dimension); + Vector best = vectors[dimension]; + Vector worst = vectors[0]; + Vector second_worst = vectors[1]; + // reflect + Vector reflected = cog + (cog - worst)*alpha; + if (f(reflected) > f(second_worst) && f(reflected) < f(best)) + vectors[0] = reflected; + else if (f(reflected) > f(best)) { - //cout << "count: " << count++ << endl; - sort(vectors.begin(), vectors.end(), VectorSort(this)); - Vector cog; // center of gravity - cog.prepare(dimension); - for (size_t i = 1; i<=dimension; i++) - { - cog += vectors[i]; - } - cog /= dimension; - Vector best = vectors[dimension]; - Vector worst = vectors[0]; - Vector second_worst = vectors[1]; - // reflect - Vector reflected = cog + (cog - worst)*alpha; - if (f(reflected) > f(second_worst) && f(reflected) < f(best)) - { - vectors[0] = reflected; - } else if (f(reflected) > f(best)) - { - // expand - Vector expanded = cog + (cog - worst)*gamma; - if (f(expanded) > f(reflected)) - { - vectors[0] = expanded; - } else - { - vectors[0] = reflected; - } - } else - { - // contract - Vector contracted = cog + (cog - worst)*rho; - if (f(contracted) > f(worst)) - { - vectors[0] = contracted; - } - else - { - for (size_t i=0; i f(reflected)) + vectors[0] = expanded; + else + vectors[0] = reflected; } - - // algorithm is terminating, output: simplex' center of gravity - Vector cog; - cog.prepare(dimension); - for (size_t i = 0; i<=dimension; i++) + else { - cog += vectors[i]; + // contract + Vector contracted = cog + (cog - worst)*rho; + if (f(contracted) > f(worst)) + vectors[0] = contracted; + else + { + for (size_t i = 0; i < dimension; ++i) + vectors[i] = best + (vectors[i] - best) * sigma; + } } - return cog/(dimension+1); + } + // algorithm is terminating, output: simplex' center of gravity + Vector cog; + cog.prepare(static_cast(dimension)); + for (size_t i = 0; i <= dimension; ++i) + cog += vectors[i]; + return cog / (static_cast(dimension) + 1); } else { @@ -411,11 +353,9 @@ class NelderMead // with coordinates between 0 and 1. If you want other start vectors, // simply ignore these and use `step` on the vectors you want. Vector result; - result.prepare(dimension); - for (size_t i = 0; i(dimension)); + for (int i = 0; i < static_cast(dimension); ++i) result[i] = 0.001 * (Tgs::Random::instance()->generateInt(1000)); - } return result; } } @@ -436,9 +376,7 @@ class NelderMead db.insert(vec, s); } else - { s = db.lookup(vec); - } return s; } diff --git a/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.cpp b/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.cpp index 862d1135ee..185c2b55a0 100644 --- a/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.cpp +++ b/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2017, 2018, 2019, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2017, 2018, 2019, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "RandomForestUtilities.h" @@ -38,295 +38,233 @@ #include #include +using namespace std; + namespace Tgs { - std::vector>> RandomForestUtilities::createDataSets( - RandomForestInputs rfInputs, std::vector splitPercentages) +vector>> + RandomForestUtilities::createDataSets(RandomForestInputs rfInputs, vector splitPercentages) +{ + try { - try - { - std::vector>> dataSets(splitPercentages.size()); - - std::map>>::iterator trainItr; + vector>> dataSets(splitPercentages.size()); - for (trainItr = rfInputs.trainingVectors.begin(); trainItr != rfInputs.trainingVectors.end(); ++trainItr) + for (auto trainItr = rfInputs.trainingVectors.begin(); trainItr != rfInputs.trainingVectors.end(); ++trainItr) + { + string className = trainItr->first; + double startPercent = 0; + for (unsigned int i = 0; i < splitPercentages.size(); ++i) { - std::string className = trainItr->first; - - double startPercent = 0; + double endPercent = splitPercentages[i]; - for (unsigned int i = 0; i < splitPercentages.size(); i++) - { + if (i == splitPercentages.size() - 1 && endPercent != 1.0) + throw Exception(__LINE__, "The final splitPercentages entry should be 1.0"); - double endPercent = splitPercentages[i]; + dataSets[i][className].first = static_cast(static_cast(rfInputs.trainingVectors[className].size()) * startPercent); + dataSets[i][className].second = static_cast(static_cast(rfInputs.trainingVectors[className].size()) * endPercent); - if (i == splitPercentages.size() - 1 && endPercent != 1.0) - { - throw Exception(__LINE__, "The final splitPercentages entry should be 1.0"); - } - - dataSets[i][className].first = rfInputs.trainingVectors[className].size() * startPercent; - dataSets[i][className].second = - rfInputs.trainingVectors[className].size() * endPercent; - - startPercent = endPercent; - } + startPercent = endPercent; } - - return dataSets; - } - catch(const Tgs::Exception & e) - { - throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); } + return dataSets; } - - RandomForestManager RandomForestUtilities::generateModel(RandomForestInputs & rfInputs, - unsigned int numTrees, - std::map> & trainingRangeMap) + catch(const Tgs::Exception & e) { - try - { - Tgs::RandomForestManager initialModel; - - initialModel.init(BaseRandomForestManager::MULTICLASS, rfInputs.featureLabels); - - std::map>>::iterator mapItr; - - for (mapItr = rfInputs.trainingVectors.begin(); mapItr != rfInputs.trainingVectors.end(); ++mapItr) - { - std::string className = mapItr->first; + throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + } +} - unsigned int initialTrainingIndex = trainingRangeMap[className].first; - unsigned int initialTrainingSize = trainingRangeMap[className].second; +RandomForestManager RandomForestUtilities::generateModel(RandomForestInputs & rfInputs, unsigned int numTrees, + map> & trainingRangeMap) +{ + try + { + Tgs::RandomForestManager initialModel; + initialModel.init(BaseRandomForestManager::MULTICLASS, rfInputs.featureLabels); - for (unsigned int i = 0; i < initialTrainingSize; i++) - { - initialModel.addTrainingVector(className, mapItr->second[initialTrainingIndex + i]); - } - } + for (auto mapItr = rfInputs.trainingVectors.begin(); mapItr != rfInputs.trainingVectors.end(); ++mapItr) + { + string className = mapItr->first; - initialModel.train(numTrees); + unsigned int initialTrainingIndex = trainingRangeMap[className].first; + unsigned int initialTrainingSize = trainingRangeMap[className].second; - return initialModel; - } - catch(const Tgs::Exception & e) - { - throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + for (unsigned int i = 0; i < initialTrainingSize; i++) + initialModel.addTrainingVector(className, mapItr->second[initialTrainingIndex + i]); } + initialModel.train(numTrees); + return initialModel; } - - MultithreadedRandomForestManager RandomForestUtilities::generateMultithreadModel( - RandomForestInputs & rfInputs, unsigned int numTrees, - std::map> & trainingRangeMap) + catch(const Tgs::Exception & e) { - try - { - std::cerr << "DEBUG GEN MULTI MODEL" << std::endl; - - MultithreadedRandomForestManager initialModel; - - initialModel.init(BaseRandomForestManager::MULTICLASS, rfInputs.featureLabels); - - std::map>>::iterator mapItr; + throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + } +} - for (mapItr = rfInputs.trainingVectors.begin(); mapItr != rfInputs.trainingVectors.end(); ++mapItr) - { - std::string className = mapItr->first; +MultithreadedRandomForestManager RandomForestUtilities::generateMultithreadModel(RandomForestInputs & rfInputs, unsigned int numTrees, + map> & trainingRangeMap) +{ + try + { + cerr << "DEBUG GEN MULTI MODEL" << endl; - unsigned int initialTrainingIndex = trainingRangeMap[className].first; - unsigned int initialTrainingSize = trainingRangeMap[className].second; + MultithreadedRandomForestManager initialModel; + initialModel.init(BaseRandomForestManager::MULTICLASS, rfInputs.featureLabels); - for (unsigned int i = 0; i < initialTrainingSize; i++) - { - initialModel.addTrainingVector(className, mapItr->second[initialTrainingIndex + i]); - } - } + for (auto mapItr = rfInputs.trainingVectors.begin(); mapItr != rfInputs.trainingVectors.end(); ++mapItr) + { + string className = mapItr->first; - initialModel.train(numTrees); + unsigned int initialTrainingIndex = trainingRangeMap[className].first; + unsigned int initialTrainingSize = trainingRangeMap[className].second; - return initialModel; - } - catch(const Tgs::Exception & e) - { - throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + for (unsigned int i = 0; i < initialTrainingSize; i++) + initialModel.addTrainingVector(className, mapItr->second[initialTrainingIndex + i]); } + initialModel.train(numTrees); + return initialModel; } - - RandomForestInputs RandomForestUtilities::generateTrainingDataFromFile( - const std::string& filename) + catch(const Tgs::Exception & e) { - try - { - QFileInfo fi(filename.c_str()); - QString suffix = fi.suffix().toUpper(); + throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + } +} - if (suffix == "ARFF") - { - return _generateTrainingDataFromAARFFile(filename); +RandomForestInputs RandomForestUtilities::generateTrainingDataFromFile(const string& filename) +{ + try + { + QFileInfo fi(filename.c_str()); + QString suffix = fi.suffix().toUpper(); - } - else - { - std::stringstream ss; - ss << "The file suffix " << suffix.toLatin1().constData() << " is not supported."; - throw Tgs::Exception(__LINE__, ss.str()); - } - } - catch(const Tgs::Exception & e) + if (suffix == "ARFF") + return _generateTrainingDataFromAARFFile(filename); + else { - throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + stringstream ss; + ss << "The file suffix " << suffix.toLatin1().constData() << " is not supported."; + throw Tgs::Exception(__LINE__, ss.str()); } } + catch(const Tgs::Exception & e) + { + throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + } +} - RandomForestInputs RandomForestUtilities::_generateTrainingDataFromAARFFile( - const std::string& filename) +RandomForestInputs RandomForestUtilities::_generateTrainingDataFromAARFFile(const string& filename) +{ + try { - try + RandomForestInputs rfInputs; + + fstream arrfStream(filename.c_str(), fstream::in); + + if (!arrfStream.is_open()) { - RandomForestInputs rfInputs; + stringstream ss; + ss << "Unable to open file " << filename; + throw Tgs::Exception(__LINE__, ss.str()); + } - std::fstream arrfStream(filename.c_str(), std::fstream::in); + bool readingData = false; + int dataLine = 0; - if (!arrfStream.is_open()) + string buffer; + while (!arrfStream.eof()) + { + getline(arrfStream, buffer); + if (buffer.empty()) { - std::stringstream ss; - ss << "Unable to open file " << filename; - throw Tgs::Exception(__LINE__, ss.str()); + dataLine++; + continue; } - bool readingData = false; - int dataLine = 0; + stringstream bufferStr(buffer); + vector tokenList; + string token; - std::string buffer; - while (!arrfStream.eof()) + if (readingData) // Read training data { - std::getline(arrfStream, buffer); + while (getline(bufferStr, token, ',')) + tokenList.push_back(token); - if (buffer.empty()) - { - dataLine++; - continue; - } + if ((tokenList.size() - 1) != rfInputs.featureLabels.size()) + throw Tgs::Exception(__LINE__, "The number features read in the attribute section does not match the number of values in the data section"); - std::stringstream bufferStr(buffer); - std::vector tokenList; - std::string token; + vector data(tokenList.size() - 1); - if (readingData) //Read training data - { - while (std::getline(bufferStr, token, ',')) - { - tokenList.push_back(token); - } - - if ((tokenList.size() - 1) != rfInputs.featureLabels.size()) - { - throw Tgs::Exception(__LINE__, "The number features read in the attribute section does" - " not match the number of values in the data section"); - } + bool parseOk; - std::vector data(tokenList.size() - 1); - - bool parseOk; - - for (unsigned int i = 0; i < tokenList.size(); i++) + for (unsigned int i = 0; i < tokenList.size(); i++) + { + if (i != tokenList.size() - 1) // Read numeric data { - if (i != tokenList.size() - 1) //Read numeric data + double value = QString(tokenList[i].c_str()).toDouble(&parseOk); + if (parseOk) + data[i] = value; + else { - - double value = QString(tokenList[i].c_str()).toDouble(&parseOk); - - if (parseOk) - { - data[i] = value; - } - else - { - std::cerr << "SKIPPING: " << buffer << std::endl; - break; - // std::stringstream ss; - // ss << "Parsing of data failed for vector at Line: " << dataLine << " with data vector: " << - // std::endl << buffer; - // throw Tgs::Exception(__LINE__, ss.str()); - } - } - else //Read class name - { - rfInputs.trainingVectors[tokenList[i]].push_back(data); + cerr << "SKIPPING: " << buffer << endl; + break; } } + else // Read class name + rfInputs.trainingVectors[tokenList[i]].push_back(data); + } + } + else + { + while (getline(bufferStr, token, ' ')) + tokenList.push_back(token); + + if (tokenList.empty()) + continue; + else if (tokenList.size() == 1) + { + if (tokenList[0] == "@DATA") + readingData = true; } else { - while (std::getline(bufferStr, token, ' ')) - { - tokenList.push_back(token); - } - - if (tokenList.empty()) - { - continue; - } - else if (tokenList.size() == 1) + if (tokenList[0] == "@ATTRIBUTE") { - if (tokenList[0] == "@DATA") + if (tokenList[1] != "class") { - readingData = true; + if (tokenList.size() == 3) // Format @ATTRIBUTE FeatureName Type + rfInputs.featureLabels.push_back(tokenList[1]); + else + throw Tgs::Exception(__LINE__, "Invalid reading for @ATTRIBUTE"); } - } - else - { - if (tokenList[0] == "@ATTRIBUTE") + else { - if (tokenList[1] != "class") + if (tokenList.size() == 3) // Format @ATTRIBUTE class {class1,class2,classN} { - if (tokenList.size() == 3) //Format @ATTRIBUTE FeatureName Type - { - rfInputs.featureLabels.push_back(tokenList[1]); - } - else - { - throw Tgs::Exception(__LINE__, "Invalid reading for @ATTRIBUTE"); - } + char chars[] = "{}"; + string classes = tokenList[2]; + for (unsigned int i = 0; i < strlen(chars); ++i) + classes.erase (remove(classes.begin(), classes.end(), chars[i]), classes.end()); + + stringstream classStr(classes); + string classToken; + + while (getline(classStr, classToken, ',')) + rfInputs.classLabels.push_back(classToken); } else - { - if (tokenList.size() == 3) //Format @ATTRIBUTE class {class1,class2,classN} - { - char chars[] = "{}"; - std::string classes = tokenList[2]; - for (unsigned int i = 0; i < strlen(chars); ++i) - { - classes.erase (std::remove(classes.begin(), classes.end(), chars[i]), classes.end()); - } - - std::stringstream classStr(classes); - std::string classToken; - - while (std::getline(classStr, classToken, ',')) - { - rfInputs.classLabels.push_back(classToken); - } - } - else - { - throw Tgs::Exception(__LINE__, "Invalid reading for @ATTRIBUTE class"); - } - } + throw Tgs::Exception(__LINE__, "Invalid reading for @ATTRIBUTE class"); } } } - - dataLine++; } - - return rfInputs; - } - catch(const Tgs::Exception & e) - { - throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); + dataLine++; } + return rfInputs; + } + catch(const Tgs::Exception & e) + { + throw Tgs::Exception("RandomForestUtilities", __FUNCTION__, __LINE__, e); } } +} diff --git a/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.h b/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.h index f12d0ab0c6..84c021fa75 100644 --- a/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.h +++ b/tgs/src/main/cpp/tgs/RandomForest/RandomForestUtilities.h @@ -22,12 +22,12 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2018, 2019, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2018, 2019, 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef RANDOMFORESTUTILITIES_H #define RANDOMFORESTUTILITIES_H -//Std Includes +// Std Includes #include #include #include @@ -37,67 +37,67 @@ namespace Tgs { - struct RandomForestInputs - { - std::vector featureLabels; //The feature labels matching each element in _dataVectors - std::vector classLabels; //The ordered class labels - std::map>> trainingVectors; //The data for each training vector - }; - class RandomForestUtilities - { - public: +struct RandomForestInputs +{ + std::vector featureLabels; // The feature labels matching each element in _dataVectors + std::vector classLabels; // The ordered class labels + std::map>> trainingVectors; // The data for each training vector +}; - /** - * @brief createDataSets takes the input data and splits it by classes into output indices - * - * If you want one the first set with 30% and the rest in the second then splitPercentages would contain 0.3 and 1.0. - * A 30%, 40%, 30% split would be 0.3, 0.7 and 1.0. - * - * @param rfInputs the struct of training data - * @param splitPercentages the percentages values for splitting data (should be size of number of splits and final value should be 1.0) - * @return sets of data vector indices by classes - */ - static std::vector>> createDataSets( - RandomForestInputs rfInputs, std::vector splitPercentages); +class RandomForestUtilities +{ +public: - /** - * @brief generateModel generates a random forest model - * @param rfInputs the struct of training data - * @param numTrees the number of trees in the model - * @param trainingRangeMap the map of classNames to indices within the rfInput trainingVectors to use for training - * @return the trained random forest model - */ - static RandomForestManager generateModel(RandomForestInputs & rfInputs, unsigned int numTrees, - std::map> & trainingRangeMap); + /** + * @brief createDataSets takes the input data and splits it by classes into output indices + * + * If you want one the first set with 30% and the rest in the second then splitPercentages would contain 0.3 and 1.0. + * A 30%, 40%, 30% split would be 0.3, 0.7 and 1.0. + * + * @param rfInputs the struct of training data + * @param splitPercentages the percentages values for splitting data (should be size of number of splits and final value should be 1.0) + * @return sets of data vector indices by classes + */ + static std::vector>> + createDataSets(RandomForestInputs rfInputs, std::vector splitPercentages); - /** - * @brief generateModel generates a multithreaded random forest model - * @param rfInputs the struct of training data - * @param numTrees the number of trees in the model - * @param trainingRangeMap the map of classNames to indices within the rfInput trainingVectors to use for training - * @return the trained random forest model - */ - static MultithreadedRandomForestManager generateMultithreadModel(RandomForestInputs & rfInputs, - unsigned int numTrees, - std::map> & trainingRangeMap); + /** + * @brief generateModel generates a random forest model + * @param rfInputs the struct of training data + * @param numTrees the number of trees in the model + * @param trainingRangeMap the map of classNames to indices within the rfInput trainingVectors to use for training + * @return the trained random forest model + */ + static RandomForestManager generateModel(RandomForestInputs & rfInputs, unsigned int numTrees, + std::map> & trainingRangeMap); - /** - * @brief generateTrainingDataFromFile creates a random forest from a file containing labeled training data - * @param filename the path to the target file - * @return a set of training vectors - */ - static RandomForestInputs generateTrainingDataFromFile(const std::string& filename); + /** + * @brief generateModel generates a multithreaded random forest model + * @param rfInputs the struct of training data + * @param numTrees the number of trees in the model + * @param trainingRangeMap the map of classNames to indices within the rfInput trainingVectors to use for training + * @return the trained random forest model + */ + static MultithreadedRandomForestManager generateMultithreadModel(RandomForestInputs & rfInputs, unsigned int numTrees, + std::map> & trainingRangeMap); - private: - /** - * @brief _generateTrainingDataFromAARFFile reads a WEKA AARF file - * @param filename the name of the file - * @return a set of training vectors - */ - static RandomForestInputs _generateTrainingDataFromAARFFile(const std::string& filename); - }; -} + /** + * @brief generateTrainingDataFromFile creates a random forest from a file containing labeled training data + * @param filename the path to the target file + * @return a set of training vectors + */ + static RandomForestInputs generateTrainingDataFromFile(const std::string& filename); +private: + /** + * @brief _generateTrainingDataFromAARFFile reads a WEKA AARF file + * @param filename the name of the file + * @return a set of training vectors + */ + static RandomForestInputs _generateTrainingDataFromAARFFile(const std::string& filename); +}; + +} #endif // RANDOMFORESTUTILITIES_H diff --git a/tgs/src/main/cpp/tgs/System/SystemInfo.cpp b/tgs/src/main/cpp/tgs/System/SystemInfo.cpp index 8f9a023c27..07e4d0f609 100644 --- a/tgs/src/main/cpp/tgs/System/SystemInfo.cpp +++ b/tgs/src/main/cpp/tgs/System/SystemInfo.cpp @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2017, 2018, 2019, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2017, 2018, 2019, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #include "SystemInfo.h" @@ -50,227 +50,215 @@ namespace Tgs { - int SystemInfo::getNumberOfProcessors() - { - int result; -# ifdef _WIN32 - SYSTEM_INFO info; - GetSystemInfo(&info); - result = info.dwNumberOfProcessors; -# elif defined(linux) || defined(__linux) - result = sysconf( _SC_NPROCESSORS_ONLN ); -# else -# warning("Warning: SystemInfo::getNumberOfProcessors() has not been implemented for this platform.") - result = 1; -# endif - return result; - } +int SystemInfo::getNumberOfProcessors() +{ + int result; +# ifdef _WIN32 + SYSTEM_INFO info; + GetSystemInfo(&info); + result = info.dwNumberOfProcessors; +# elif defined(linux) || defined(__linux) + result = static_cast(sysconf(_SC_NPROCESSORS_ONLN)); +# else +# warning("Warning: SystemInfo::getNumberOfProcessors() has not been implemented for this platform.") + result = 1; +# endif + return result; +} # ifdef _WIN32 # error "Memory usage stats not defined for WIN32" # endif - void SystemInfo::_getCurrentProcessMemoryUsage(long& vmUsage, long& residentSet) - { - using std::ios_base; - using std::ifstream; - using std::string; - - vmUsage = 0.0; - residentSet = 0.0; - - // 'file' stat seems to give the most reliable results - ifstream stat_stream("/proc/self/stat", ios_base::in); - - // dummy vars for leading entries in stat that we don't care about - string pid, comm, state, ppid, pgrp, session, tty_nr; - string tpgid, flags, minflt, cminflt, majflt, cmajflt; - string utime, stime, cutime, cstime, priority, nice; - string O, itrealvalue, starttime; - - // the two fields we want - unsigned long vsize; - long rss; - - stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr - >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt - >> utime >> stime >> cutime >> cstime >> priority >> nice - >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest - - stat_stream.close(); - - long page_size_kb = sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages - vmUsage = vsize; - residentSet = rss * page_size_kb; - - if (vmUsage == 0.0 && residentSet == 0.0) - { - throw Tgs::Exception("Error retrieving memory usage."); - } - } - - std::string SystemInfo::humanReadableStorageSize(long bytes) - { - std::stringstream ss; - - ss << std::setprecision(4); - if (bytes >= 1024l * 1024l * 1024l * 1024l) - { - ss << (bytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)) << "TB"; - } - if (bytes >= 1024l * 1024l * 1024l) - { - ss << (bytes / (1024.0 * 1024.0 * 1024.0)) << "GB"; - } - else if (bytes >= 1024 * 1024) - { - ss << (bytes / (1024.0 * 1024.0)) << "MB"; - } - else if (bytes >= 1024) - { - ss << (bytes / 1024.0) << "KB"; - } - else - { - ss << bytes << "B"; - } - - return ss.str(); - } - - std::string SystemInfo::getCurrentProcessMemoryUsageString() - { - std::stringstream ss; - long vm; - long rss; - _getCurrentProcessMemoryUsage(vm, rss); - - ss << "Process memory usage: virtual:\t" << humanReadableStorageSize(vm) << "\tphysical:\t" << - humanReadableStorageSize(rss); - - return ss.str(); - } - - std::string SystemInfo::getMemoryDetailString() - { - std::stringstream ss; - - ss << "Total system virtual memory: " << - SystemInfo::humanReadableStorageSize(SystemInfo::getTotalSystemVirtualMemory()) << - "\n"; - ss << "System virtual memory used: " << - SystemInfo::humanReadableStorageSize(SystemInfo::getSystemVirtualMemoryUsed()) << - "\n"; - ss << "Current process virtual memory usage (kb): " << - SystemInfo::humanReadableStorageSize(SystemInfo::getCurrentProcessVirtualMemoryUsage()) << - "\n"; - ss << "Virtual memory available: " << - SystemInfo::humanReadableStorageSize(SystemInfo::getVirtualMemoryAvailable()) << "\n"; - ss << "Percentage of virtual memory used: " << - SystemInfo::getPercentageOfVirtualMemoryUsed() << "%" << "\n"; - - ss << "Total system physical memory: " << - SystemInfo::humanReadableStorageSize(SystemInfo::getTotalSystemPhysicalMemory()) << - "\n"; - ss << "System physical memory used: " << - SystemInfo::humanReadableStorageSize(SystemInfo::getSystemPhysicalMemoryUsed()) << - "\n"; - ss << "Current process physical memory usage: " << - SystemInfo::humanReadableStorageSize(SystemInfo::getCurrentProcessPhysicalMemoryUsage()) << - "\n"; - ss << "Physical memory available: " << - SystemInfo::humanReadableStorageSize(SystemInfo::getPhysicalMemoryAvailable()) << - "\n"; - ss << "Percentage of physical memory used: " << - SystemInfo::getPercentageOfPhysicalMemoryUsed() << "%" << "\n"; - - return ss.str(); - } - - long SystemInfo::getTotalSystemVirtualMemory() - { - struct sysinfo memInfo; - sysinfo (&memInfo); - long long totalVirtualMem = memInfo.totalram; - //Add other values in next statement to avoid int overflow on right hand side... - totalVirtualMem += memInfo.totalswap; - totalVirtualMem *= memInfo.mem_unit; - return (long)totalVirtualMem; - } - - long SystemInfo::getSystemVirtualMemoryUsed() - { - struct sysinfo memInfo; - sysinfo (&memInfo); - long long virtualMemUsed = memInfo.totalram - memInfo.freeram; - //Add other values in next statement to avoid int overflow on right hand side... - virtualMemUsed += memInfo.totalswap - memInfo.freeswap; - virtualMemUsed *= memInfo.mem_unit; - return (long)virtualMemUsed; - } - - long SystemInfo::getCurrentProcessVirtualMemoryUsage() - { - long v; - long rss; - _getCurrentProcessMemoryUsage(v, rss); - return v; - } - - long SystemInfo::getVirtualMemoryAvailable() - { - return getTotalSystemVirtualMemory() - getSystemVirtualMemoryUsed(); - } - - double SystemInfo::getPercentageOfVirtualMemoryUsed() - { - return (double)getSystemVirtualMemoryUsed() / (double)getTotalSystemVirtualMemory(); - } - - double SystemInfo::getPercentageOfVirtualMemoryUsedByCurrentProcess() - { - return (double)getCurrentProcessVirtualMemoryUsage() / (double)getTotalSystemVirtualMemory(); - } - - long SystemInfo::getTotalSystemPhysicalMemory() - { - struct sysinfo memInfo; - sysinfo(&memInfo); - long long totalPhysMem = memInfo.totalram; - // Multiply in next statement to avoid int overflow on right hand side... - totalPhysMem *= memInfo.mem_unit; - return (long)totalPhysMem; - } - - long SystemInfo::getSystemPhysicalMemoryUsed() - { - struct sysinfo memInfo; - sysinfo(&memInfo); - long long physMemUsed = memInfo.totalram - memInfo.freeram; - // Multiply in next statement to avoid int overflow on right hand side... - physMemUsed *= memInfo.mem_unit; - return (long)physMemUsed; - } - - long SystemInfo::getCurrentProcessPhysicalMemoryUsage() - { - long v; - long rss; - _getCurrentProcessMemoryUsage(v, rss); - return rss; - } - - long SystemInfo::getPhysicalMemoryAvailable() - { - return getTotalSystemPhysicalMemory() - getSystemPhysicalMemoryUsed(); - } - - double SystemInfo::getPercentageOfPhysicalMemoryUsed() - { - return (double)getSystemPhysicalMemoryUsed() / (double)getTotalSystemPhysicalMemory(); - } - - double SystemInfo::getPercentageOfPhysicalMemoryUsedByCurrentProcess() - { - return (double)getCurrentProcessPhysicalMemoryUsage() / (double)getTotalSystemPhysicalMemory(); - } +void SystemInfo::_getCurrentProcessMemoryUsage(long& vmUsage, long& residentSet) +{ + using std::ios_base; + using std::ifstream; + using std::string; + + vmUsage = 0.0; + residentSet = 0.0; + + // 'file' stat seems to give the most reliable results + ifstream stat_stream("/proc/self/stat", ios_base::in); + + // dummy vars for leading entries in stat that we don't care about + string pid, comm, state, ppid, pgrp, session, tty_nr; + string tpgid, flags, minflt, cminflt, majflt, cmajflt; + string utime, stime, cutime, cstime, priority, nice; + string O, itrealvalue, starttime; + + // the two fields we want + unsigned long vsize; + long rss; + + stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr + >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt + >> utime >> stime >> cutime >> cstime >> priority >> nice + >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest + + stat_stream.close(); + + long page_size_kb = sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages + vmUsage = vsize; + residentSet = rss * page_size_kb; + + if (vmUsage == 0 && residentSet == 0) + throw Tgs::Exception("Error retrieving memory usage."); +} + +std::string SystemInfo::humanReadableStorageSize(long bytes) +{ + std::stringstream ss; + + ss << std::setprecision(4); + if (bytes >= 1024l * 1024l * 1024l * 1024l) + ss << (static_cast(bytes) / (1024.0 * 1024.0 * 1024.0 * 1024.0)) << "TB"; + else if (bytes >= 1024l * 1024l * 1024l) + ss << (static_cast(bytes) / (1024.0 * 1024.0 * 1024.0)) << "GB"; + else if (bytes >= 1024l * 1024l) + ss << (static_cast(bytes) / (1024.0 * 1024.0)) << "MB"; + else if (bytes >= 1024l) + ss << (static_cast(bytes) / 1024.0) << "KB"; + else + ss << bytes << "B"; + return ss.str(); +} + +std::string SystemInfo::getCurrentProcessMemoryUsageString() +{ + std::stringstream ss; + long vm; + long rss; + _getCurrentProcessMemoryUsage(vm, rss); + + ss << "Process memory usage: virtual:\t" << humanReadableStorageSize(vm) << "\tphysical:\t" << + humanReadableStorageSize(rss); + + return ss.str(); +} + +std::string SystemInfo::getMemoryDetailString() +{ + std::stringstream ss; + + ss << "Total system virtual memory: " << + SystemInfo::humanReadableStorageSize(SystemInfo::getTotalSystemVirtualMemory()) << + "\n"; + ss << "System virtual memory used: " << + SystemInfo::humanReadableStorageSize(SystemInfo::getSystemVirtualMemoryUsed()) << + "\n"; + ss << "Current process virtual memory usage (kb): " << + SystemInfo::humanReadableStorageSize(SystemInfo::getCurrentProcessVirtualMemoryUsage()) << + "\n"; + ss << "Virtual memory available: " << + SystemInfo::humanReadableStorageSize(SystemInfo::getVirtualMemoryAvailable()) << "\n"; + ss << "Percentage of virtual memory used: " << + SystemInfo::getPercentageOfVirtualMemoryUsed() << "%" << "\n"; + + ss << "Total system physical memory: " << + SystemInfo::humanReadableStorageSize(SystemInfo::getTotalSystemPhysicalMemory()) << + "\n"; + ss << "System physical memory used: " << + SystemInfo::humanReadableStorageSize(SystemInfo::getSystemPhysicalMemoryUsed()) << + "\n"; + ss << "Current process physical memory usage: " << + SystemInfo::humanReadableStorageSize(SystemInfo::getCurrentProcessPhysicalMemoryUsage()) << + "\n"; + ss << "Physical memory available: " << + SystemInfo::humanReadableStorageSize(SystemInfo::getPhysicalMemoryAvailable()) << + "\n"; + ss << "Percentage of physical memory used: " << + SystemInfo::getPercentageOfPhysicalMemoryUsed() << "%" << "\n"; + + return ss.str(); +} + +long SystemInfo::getTotalSystemVirtualMemory() +{ + struct sysinfo memInfo; + sysinfo (&memInfo); + long long totalVirtualMem = memInfo.totalram; + //Add other values in next statement to avoid int overflow on right hand side... + totalVirtualMem += memInfo.totalswap; + totalVirtualMem *= memInfo.mem_unit; + return (long)totalVirtualMem; +} + +long SystemInfo::getSystemVirtualMemoryUsed() +{ + struct sysinfo memInfo; + sysinfo (&memInfo); + long long virtualMemUsed = memInfo.totalram - memInfo.freeram; + //Add other values in next statement to avoid int overflow on right hand side... + virtualMemUsed += memInfo.totalswap - memInfo.freeswap; + virtualMemUsed *= memInfo.mem_unit; + return (long)virtualMemUsed; +} + +long SystemInfo::getCurrentProcessVirtualMemoryUsage() +{ + long v; + long rss; + _getCurrentProcessMemoryUsage(v, rss); + return v; +} + +long SystemInfo::getVirtualMemoryAvailable() +{ + return getTotalSystemVirtualMemory() - getSystemVirtualMemoryUsed(); +} + +double SystemInfo::getPercentageOfVirtualMemoryUsed() +{ + return (double)getSystemVirtualMemoryUsed() / (double)getTotalSystemVirtualMemory(); +} + +double SystemInfo::getPercentageOfVirtualMemoryUsedByCurrentProcess() +{ + return (double)getCurrentProcessVirtualMemoryUsage() / (double)getTotalSystemVirtualMemory(); +} + +long SystemInfo::getTotalSystemPhysicalMemory() +{ + struct sysinfo memInfo; + sysinfo(&memInfo); + long long totalPhysMem = memInfo.totalram; + // Multiply in next statement to avoid int overflow on right hand side... + totalPhysMem *= memInfo.mem_unit; + return (long)totalPhysMem; +} + +long SystemInfo::getSystemPhysicalMemoryUsed() +{ + struct sysinfo memInfo; + sysinfo(&memInfo); + long long physMemUsed = memInfo.totalram - memInfo.freeram; + // Multiply in next statement to avoid int overflow on right hand side... + physMemUsed *= memInfo.mem_unit; + return (long)physMemUsed; +} + +long SystemInfo::getCurrentProcessPhysicalMemoryUsage() +{ + long v; + long rss; + _getCurrentProcessMemoryUsage(v, rss); + return rss; +} + +long SystemInfo::getPhysicalMemoryAvailable() +{ + return getTotalSystemPhysicalMemory() - getSystemPhysicalMemoryUsed(); +} + +double SystemInfo::getPercentageOfPhysicalMemoryUsed() +{ + return (double)getSystemPhysicalMemoryUsed() / (double)getTotalSystemPhysicalMemory(); +} + +double SystemInfo::getPercentageOfPhysicalMemoryUsedByCurrentProcess() +{ + return (double)getCurrentProcessPhysicalMemoryUsage() / (double)getTotalSystemPhysicalMemory(); +} + } diff --git a/tgs/src/main/cpp/tgs/System/SystemInfo.h b/tgs/src/main/cpp/tgs/System/SystemInfo.h index ba60096609..82f9c5463a 100644 --- a/tgs/src/main/cpp/tgs/System/SystemInfo.h +++ b/tgs/src/main/cpp/tgs/System/SystemInfo.h @@ -22,7 +22,7 @@ * This will properly maintain the copyright information. Maxar * copyrights will be updated automatically. * - * @copyright Copyright (C) 2015, 2017, 2018, 2020, 2021 Maxar (http://www.maxar.com/) + * @copyright Copyright (C) 2015, 2017, 2018, 2020, 2021, 2022 Maxar (http://www.maxar.com/) */ #ifndef __SYSTEM_INFO_H__ #define __SYSTEM_INFO_H__ @@ -35,151 +35,152 @@ namespace Tgs { +/** + * Utilities for obtaining operating system info + * + * Portions of this source code are derived from the following: + * + * http://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-run-time-in-c + * https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process + */ +class TGS_EXPORT SystemInfo +{ +public: + + /** + * Determines the number of processors available in the system + * + * @return the number of processors + */ + static int getNumberOfProcessors(); + + /** + * Returns the amount of total configured system virtual memory + * + * @return memory size in bytes + */ + static long getTotalSystemVirtualMemory(); + + /** + * Determines the amount of total system virtual memory in use + * + * @return memory size in bytes + */ + static long getSystemVirtualMemoryUsed(); + + /** + * Determines the amount of virtual memory used by the calling process + * + * @return memory size in bytes + */ + static long getCurrentProcessVirtualMemoryUsage(); + + /** + * Determines the amount of virtual memory available + * + * @return memory size in bytes + */ + static long getVirtualMemoryAvailable(); + + /** + * Determines the percentage of total virtual memory in use out of the total configured system + * virtual memory + * + * @return memory size in bytes + */ + static double getPercentageOfVirtualMemoryUsed(); + + /** + * Determines the percentage of virtual memory in use by the calling process out of the total + * configured system virtual memory + * + * @return memory size in bytes + */ + static double getPercentageOfVirtualMemoryUsedByCurrentProcess(); + + /** + * Returns the amount of total configured system physical memory + * + * @return memory size in bytes + */ + static long getTotalSystemPhysicalMemory(); + /** - * Utilities for obtaining operating system info - * - * Portions of this source code are derived from the following: - * - * http://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-run-time-in-c - * https://stackoverflow.com/questions/63166/how-to-determine-cpu-and-memory-consumption-from-inside-a-process - */ - class TGS_EXPORT SystemInfo - { - public: - - /** - * Determines the number of processors available in the system - * - * @return the number of processors - */ - static int getNumberOfProcessors(); - - /** - * Returns the amount of total configured system virtual memory - * - * @return memory size in bytes - */ - static long getTotalSystemVirtualMemory(); - - /** - * Determines the amount of total system virtual memory in use - * - * @return memory size in bytes - */ - static long getSystemVirtualMemoryUsed(); - - /** - * Determines the amount of virtual memory used by the calling process - * - * @return memory size in bytes - */ - static long getCurrentProcessVirtualMemoryUsage(); - - /** - * Determines the amount of virtual memory available - * - * @return memory size in bytes - */ - static long getVirtualMemoryAvailable(); - - /** - * Determines the percentage of total virtual memory in use out of the total configured system - * virtual memory - * - * @return memory size in bytes - */ - static double getPercentageOfVirtualMemoryUsed(); - - /** - * Determines the percentage of virtual memory in use by the calling process out of the total - * configured system virtual memory - * - * @return memory size in bytes - */ - static double getPercentageOfVirtualMemoryUsedByCurrentProcess(); - - /** - * Returns the amount of total configured system physical memory - * - * @return memory size in bytes - */ - static long getTotalSystemPhysicalMemory(); - - /** - * Determines the amount of total system physical memory in use - * - * @return memory size in bytes - */ - static long getSystemPhysicalMemoryUsed(); - - /** - * Determines the amount of physical memory used by the calling process - * - * @return memory size in bytes - */ - static long getCurrentProcessPhysicalMemoryUsage(); - - /** - * Determines the amount of physicalv memory available - * - * @return memory size in bytes - */ - static long getPhysicalMemoryAvailable(); - - /** - * Determines the percentage of total physical memory in use out of the total configured system - * physical memory - * - * @return memory size in bytes - */ - static double getPercentageOfPhysicalMemoryUsed(); - - /** - * - * Determines the percentage of physical memory in use by the calling process out of the total - * configured system physicalv memory - * - * @return memory size in bytes - */ - static double getPercentageOfPhysicalMemoryUsedByCurrentProcess(); - - /** - * A human readable brief summary of the memory used by the calling process - * - * @return a string - */ - static std::string getCurrentProcessMemoryUsageString(); - - /** - * A human readable detailed summary of the memory used by the calling process - * - * @return a string - */ - static std::string getMemoryDetailString(); - - /** - * Converts bytes to human readable string - * - * @param bytes the number of bytes to convert - * @return a string - */ - static std::string humanReadableStorageSize(long bytes); - - private: - - friend class SystemInfoTest; - - /* - * Attempts to read the system-dependent data for a process's virtual memory - * size and resident set size, and return the results in bytes. - * - * @param vmUsage populates the current process's virtual memory size in bytes; on failure, - * returns 0 - * @param residentSet populates the current process's resident set size in bytes; on failure, - * returns 0 - */ - static void _getCurrentProcessMemoryUsage(long& vmUsage, long& residentSet); - }; + * Determines the amount of total system physical memory in use + * + * @return memory size in bytes + */ + static long getSystemPhysicalMemoryUsed(); + + /** + * Determines the amount of physical memory used by the calling process + * + * @return memory size in bytes + */ + static long getCurrentProcessPhysicalMemoryUsage(); + + /** + * Determines the amount of physicalv memory available + * + * @return memory size in bytes + */ + static long getPhysicalMemoryAvailable(); + + /** + * Determines the percentage of total physical memory in use out of the total configured system + * physical memory + * + * @return memory size in bytes + */ + static double getPercentageOfPhysicalMemoryUsed(); + + /** + * + * Determines the percentage of physical memory in use by the calling process out of the total + * configured system physicalv memory + * + * @return memory size in bytes + */ + static double getPercentageOfPhysicalMemoryUsedByCurrentProcess(); + + /** + * A human readable brief summary of the memory used by the calling process + * + * @return a string + */ + static std::string getCurrentProcessMemoryUsageString(); + + /** + * A human readable detailed summary of the memory used by the calling process + * + * @return a string + */ + static std::string getMemoryDetailString(); + + /** + * Converts bytes to human readable string + * + * @param bytes the number of bytes to convert + * @return a string + */ + static std::string humanReadableStorageSize(long bytes); + +private: + + friend class SystemInfoTest; + + /* + * Attempts to read the system-dependent data for a process's virtual memory + * size and resident set size, and return the results in bytes. + * + * @param vmUsage populates the current process's virtual memory size in bytes; on failure, + * returns 0 + * @param residentSet populates the current process's resident set size in bytes; on failure, + * returns 0 + */ + static void _getCurrentProcessMemoryUsage(long& vmUsage, long& residentSet); +}; + } #endif