Skip to content

v0.2.52..v0.2.53 changeset OsmUtils.cpp

Garret Voltz edited this page Feb 12, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp b/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp
index 5ca0849..538d31e 100644
--- a/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp
@@ -22,7 +22,7 @@
  * This will properly maintain the copyright information. DigitalGlobe
  * copyrights will be updated automatically.
  *
- * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ * @copyright Copyright (C) 2015, 2016, 2017, 2018, 2019, 2020 DigitalGlobe (http://www.digitalglobe.com/)
  */
 
 #include "OsmUtils.h"
@@ -47,19 +47,28 @@
 #include <hoot/core/criterion/PointCriterion.h>
 #include <hoot/core/visitors/UniqueElementIdVisitor.h>
 #include <hoot/core/criterion/IdTagMatchesId.h>
+#include <hoot/core/elements/ElementConverter.h>
+#include <hoot/core/util/Factory.h>
 
 // Qt
 #include <QDateTime>
 #include <QRegExp>
+#include <QStringBuilder>
 
+// Std
 #include <float.h>
 
+// GEOS
+#include <geos/util/TopologyException.h>
+
 using namespace geos::geom;
 using namespace std;
 
 namespace hoot
 {
 
+int OsmUtils::_badGeomCount = 0;
+
 void OsmUtils::printNodes(const QString& nodeCollectionName,
                           const QList<std::shared_ptr<const Node>>& nodes)
 {
@@ -103,6 +112,20 @@ std::vector<long> OsmUtils::nodesToNodeIds(const std::vector<std::shared_ptr<con
   return nodeIds;
 }
 
+QSet<ElementId> OsmUtils::elementsToElementIds(const std::vector<ElementPtr>& elements)
+{
+  QSet<ElementId> ids;
+  for (std::vector<ElementPtr>::const_iterator it = elements.begin(); it != elements.end(); ++it)
+  {
+    ElementPtr element = *it;
+    if (element)
+    {
+      ids.insert(element->getElementId());
+    }
+  }
+  return ids;
+}
+
 QList<std::shared_ptr<const Node>> OsmUtils::nodeIdsToNodes(
   const QList<long>& nodeIds, const std::shared_ptr<const OsmMap>& map)
 {
@@ -293,6 +316,17 @@ QString OsmUtils::getElementDetailString(const ConstElementPtr& element, const C
   return str;
 }
 
+QString OsmUtils::getElementsDetailString(const std::vector<ElementPtr>& elements,
+                                          const ConstOsmMapPtr& map)
+{
+  QString str;
+  for (std::vector<ElementPtr>::const_iterator it = elements.begin(); it != elements.end(); ++it)
+  {
+    str += getElementDetailString(*it, map);
+  }
+  return str;
+}
+
 bool OsmUtils::oneWayConflictExists(const ConstElementPtr& element1,
                                     const ConstElementPtr& element2)
 {
@@ -737,4 +771,221 @@ bool OsmUtils::anyElementsHaveAnyKvp(const QStringList& kvps,
   return anyElementsHaveAnyKvp(kvps, elements);
 }
 
+std::shared_ptr<geos::geom::Geometry> OsmUtils::_getGeometry(
+  const ConstElementPtr& element, ConstOsmMapPtr map)
+{
+  if (!element)
+  {
+    throw IllegalArgumentException("The input element is null.");
+  }
+
+  std::shared_ptr<geos::geom::Geometry> newGeom;
+  QString errorMsg =
+    "Feature passed to OsmUtils caused topology exception on conversion to a geometry: ";
+  try
+  {
+    newGeom = ElementConverter(map).convertToGeometry(element);
+  }
+  catch (const geos::util::TopologyException& e)
+  {
+    if (_badGeomCount <= Log::getWarnMessageLimit())
+    {
+      LOG_TRACE(errorMsg << element->toString() << "\n" << e.what());
+      _badGeomCount++;
+    }
+  }
+  catch (const HootException& e)
+  {
+    if (_badGeomCount <= Log::getWarnMessageLimit())
+    {
+      LOG_TRACE(errorMsg << element->toString() << "\n" << e.what());
+      _badGeomCount++;
+    }
+  }
+  if (newGeom.get() &&
+      QString::fromStdString(newGeom->toString()).toUpper().contains("EMPTY"))
+  {
+    if (_badGeomCount <= Log::getWarnMessageLimit())
+    {
+      LOG_TRACE("Invalid element passed: " << newGeom->toString());
+      _badGeomCount++;
+    }
+    newGeom.reset();
+  }
+  return newGeom;
+}
+
+bool OsmUtils::elementContains(const ConstElementPtr& containingElement,
+                               const ConstElementPtr& containedElement, ConstOsmMapPtr map)
+{
+  if (!containingElement || !containedElement)
+  {
+    throw IllegalArgumentException("One of the input elements is null.");
+  }
+  if (containingElement->getElementType() != ElementType::Way &&
+      containingElement->getElementType() != ElementType::Relation)
+  {
+    throw IllegalArgumentException("One of the input elements is of the wrong type.");
+  }
+  LOG_VART(containedElement->getElementId());
+  LOG_VART(containingElement->getElementId());
+
+  std::shared_ptr<geos::geom::Geometry> containingElementGeom =
+    _getGeometry(containingElement, map);
+  std::shared_ptr<geos::geom::Geometry> containedElementGeom = _getGeometry(containedElement, map);
+  bool contains = false;
+  if (containingElementGeom && containedElementGeom)
+  {
+    contains = containingElementGeom->contains(containedElementGeom.get());
+    LOG_TRACE(
+      "Calculated contains: " << contains << " for containing element: " <<
+      containingElement->getElementId() <<
+      " and contained element: " << containedElement->getElementId() << ".");
+  }
+  else
+  {
+    LOG_TRACE(
+      "Unable to calculate contains for containing element: " <<
+      containingElement->getElementId() << " and contained element: " <<
+      containedElement->getElementId() << ".");
+  }
+  return contains;
+}
+
+bool OsmUtils::containsMember(const ConstElementPtr& parent, const ElementId& memberId)
+{
+  if (!parent ||
+      (parent->getElementType() != ElementType::Way &&
+       parent->getElementType() != ElementType::Relation))
+  {
+    throw IllegalArgumentException("The parent element is null or of the wrong element type.");
+  }
+  if (parent->getElementType() != ElementType::Way && memberId.getType() != ElementType::Node)
+  {
+    throw IllegalArgumentException("The inputs are of the wrong element type.");
+  }
+  if (parent->getElementType() != ElementType::Relation &&
+      memberId.getType() == ElementType::Unknown)
+  {
+    throw IllegalArgumentException("The inputs are of the wrong element type.");
+  }
+
+  bool containsMember = false;
+  if (parent->getElementType() == ElementType::Way)
+  {
+    containsMember =
+      (std::dynamic_pointer_cast<const Way>(parent))->containsNodeId(memberId.getId());
+  }
+  else
+  {
+    containsMember =
+      (std::dynamic_pointer_cast<const Relation>(parent))->contains(memberId);
+  }
+  return containsMember;
+}
+
+bool OsmUtils::elementsIntersect(const ConstElementPtr& element1, const ConstElementPtr& element2,
+                                 ConstOsmMapPtr map)
+{
+  if (!element1 || !element2)
+  {
+    throw IllegalArgumentException("One of the input elements is null.");
+  }
+
+  std::shared_ptr<geos::geom::Geometry> geom1 = _getGeometry(element1, map);
+  std::shared_ptr<geos::geom::Geometry> geom2 = _getGeometry(element2, map);
+  bool intersects = false;
+  if (geom1 && geom2)
+  {
+    intersects = geom1->intersects(geom2.get());
+  }
+  else
+  {
+    LOG_TRACE(
+      "Unable to calculate intersects for: " << element1->getElementId() <<
+      " and: " << element2->getElementId() << ".");
+  }
+  return intersects;
+}
+
+double OsmUtils::getDistance(const ConstElementPtr& element1, const ConstElementPtr& element2,
+                             ConstOsmMapPtr map)
+{
+  if (!element1 || !element2)
+  {
+    throw IllegalArgumentException("One of the input elements is null.");
+  }
+  LOG_VART(element1->getElementId());
+  LOG_VART(element2->getElementId());
+
+  double distance = -1.0;
+
+  std::shared_ptr<geos::geom::Geometry> element1Geom = _getGeometry(element1, map);
+  std::shared_ptr<geos::geom::Geometry> element2Geom = _getGeometry(element2, map);
+  if (element1Geom && element2Geom)
+  {
+    distance = element1Geom->distance(element2Geom.get());
+    LOG_TRACE(
+      "Calculated distance: " << distance << " for: " << element1->getElementId() <<
+      " and: " << element2->getElementId() << ".");
+  }
+  else
+  {
+    LOG_TRACE(
+      "Unable to calculate distance for: " << element1->getElementId() <<
+      " and: " << element2->getElementId() << ".");
+  }
+
+  return distance;
+}
+
+double OsmUtils::getArea(const ConstElementPtr& element, ConstOsmMapPtr map)
+{
+  if (!element)
+  {
+    throw IllegalArgumentException("The input element is null.");
+  }
+
+  std::shared_ptr<geos::geom::Geometry> geom = _getGeometry(element, map);
+  double area = -1.0;
+  if (geom)
+  {
+    area = geom->getArea();
+  }
+  else
+  {
+    LOG_TRACE("Unable to calculate area for: " << element->getElementId() << ".");
+  }
+  return area;
+}
+
+bool OsmUtils::hasCriterion(const ConstElementPtr& element, const QString& criterionClassName)
+{
+  if (!element || criterionClassName.trimmed().isEmpty())
+  {
+    throw IllegalArgumentException(
+      "The input element is null or the criterion class name is empty.");
+  }
+
+  return _getCrit(criterionClassName)->isSatisfied(element);
+}
+
+ElementCriterionPtr OsmUtils::_getCrit(const QString& criterionClassName)
+{
+  if (criterionClassName.trimmed().isEmpty())
+  {
+    throw IllegalArgumentException("The criterion class name is empty.");
+  }
+
+  ElementCriterionPtr crit =
+    ElementCriterionPtr(
+      Factory::getInstance().constructObject<ElementCriterion>(criterionClassName));
+  if (!crit)
+  {
+    throw IllegalArgumentException(
+      "Invalid criterion passed to PoiPolygonInfoCache::hasCriterion: " + criterionClassName);
+  }
+  return crit;
+}
+
 }
Clone this wiki locally