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 ebcd898..939875d 100644
--- a/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/elements/OsmUtils.cpp
@@ -42,6 +42,9 @@
#include <hoot/core/algorithms/Distance.h>
#include <hoot/core/criterion/ChainCriterion.h>
#include <hoot/core/ops/CopyMapSubsetOp.h>
+#include <hoot/core/criterion/AttributeValueCriterion.h>
+#include <hoot/core/util/StringUtils.h>
+#include <hoot/core/criterion/PointCriterion.h>
// Qt
#include <QDateTime>
@@ -142,10 +145,18 @@ QString OsmUtils::getRelationMembersDetailedString(const ConstRelationPtr& relat
{
QString str = "\nMember Detail:\n\n";
const std::vector<RelationData::Entry> relationMembers = relation->getMembers();
+ LOG_VART(relationMembers.size());
for (size_t i = 0; i < relationMembers.size(); i++)
{
str += "Member #" + QString::number(i + 1) + ":\n\n";
ConstElementPtr member = map->getElement(relationMembers[i].getElementId());
+ if (!member)
+ {
+ throw HootException(
+ "Unable to retrieve relation member: " + relationMembers[i].getElementId().toString() +
+ ". Skipping adding it to output...");
+ }
+ LOG_VART(member->getElementId());
str += member->toString() + "\n\n";
}
return str;
@@ -378,6 +389,16 @@ OsmMapPtr OsmUtils::getMapSubset(const ConstOsmMapPtr& map, const ElementCriteri
return output;
}
+bool OsmUtils::elementContainedByAnyRelation(const ElementId& elementId, const ConstOsmMapPtr& map)
+{
+ return map->getIndex().getElementToRelationMap()->getRelationByElement(elementId).size() > 0;
+}
+
+bool OsmUtils::nodeContainedByAnyWay(const long nodeId, const ConstOsmMapPtr& map)
+{
+ return map->getIndex().getNodeToWayMap()->getWaysByNode(nodeId).size() > 0;
+}
+
bool OsmUtils::nodeContainedByAnyWay(const long nodeId, const std::set<long> wayIds,
const ConstOsmMapPtr& map)
{
@@ -389,4 +410,148 @@ bool OsmUtils::nodeContainedByAnyWay(const long nodeId, const std::set<long> way
return commonWayIds.size() > 0;
}
+bool OsmUtils::isChild(const ElementId& elementId, const ConstOsmMapPtr& map)
+{
+ if (elementContainedByAnyRelation(elementId, map))
+ {
+ return true;
+ }
+ if (elementId.getType() == ElementType::Node && nodeContainedByAnyWay(elementId.getId(), map))
+ {
+ return true;
+ }
+ return false;
+}
+
+int OsmUtils::versionLessThanOneCount(const OsmMapPtr& map)
+{
+ std::shared_ptr<AttributeValueCriterion> attrCrit(
+ new AttributeValueCriterion(
+ ElementAttributeType(ElementAttributeType::Version), 1, NumericComparisonType::LessThan));
+ return
+ (int)FilteredVisitor::getStat(
+ attrCrit, std::shared_ptr<ElementCountVisitor>(new ElementCountVisitor()), map);
+}
+
+void OsmUtils::checkVersionLessThanOneCountAndLogWarning(const OsmMapPtr& map)
+{
+ const int numberOfRefElementsWithVersionLessThan1 = OsmUtils::versionLessThanOneCount(map);
+ if (numberOfRefElementsWithVersionLessThan1 > 0)
+ {
+ LOG_WARN(
+ StringUtils::formatLargeNumber(numberOfRefElementsWithVersionLessThan1) << " features in " <<
+ "the reference map have a version less than one. This could lead to difficulties when " <<
+ "applying the resulting changeset back to an authoritative data store. Are the versions " <<
+ "on the features being populated correctly?")
+ }
+}
+
+bool OsmUtils::mapIsPointsOnly(const OsmMapPtr& map)
+{
+ std::shared_ptr<PointCriterion> pointCrit(new PointCriterion());
+ pointCrit->setOsmMap(map.get());
+ return
+ (int)FilteredVisitor::getStat(
+ pointCrit, ElementVisitorPtr(new ElementCountVisitor()), map) ==
+ (int)map->getElementCount();
+}
+
+bool OsmUtils::allElementsHaveAnyTagKey(const QStringList& tagKeys,
+ const std::vector<ElementPtr>& elements)
+{
+ for (std::vector<ElementPtr>::const_iterator it = elements.begin(); it != elements.end(); ++it)
+ {
+ ElementPtr element = *it;
+ bool elementHasTagKey = false;
+ for (int i = 0; i < tagKeys.size(); i++)
+ {
+ if (element->getTags().contains(tagKeys.at(i)))
+ {
+ elementHasTagKey = true;
+ break;
+ }
+ }
+ if (!elementHasTagKey)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool OsmUtils::allElementsHaveAnyKvp(const QStringList& kvps,
+ const std::vector<ElementPtr>& elements)
+{
+
+ for (std::vector<ElementPtr>::const_iterator it = elements.begin(); it != elements.end(); ++it)
+ {
+ ElementPtr element = *it;
+ bool elementHasKvp = false;
+ for (int i = 0; i < kvps.size(); i++)
+ {
+ 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)
+ {
+ elementHasKvp = true;
+ break;
+ }
+ }
+ if (!elementHasKvp)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool OsmUtils::anyElementsHaveAnyTagKey(const QStringList& tagKeys,
+ const std::vector<ElementPtr>& elements)
+{
+ for (std::vector<ElementPtr>::const_iterator it = elements.begin(); it != elements.end(); ++it)
+ {
+ ElementPtr element = *it;
+ for (int i = 0; i < tagKeys.size(); i++)
+ {
+ if (element->getTags().contains(tagKeys.at(i)))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool OsmUtils::anyElementsHaveAnyKvp(const QStringList& kvps,
+ const std::vector<ElementPtr>& elements)
+{
+
+ for (std::vector<ElementPtr>::const_iterator it = elements.begin(); it != elements.end(); ++it)
+ {
+ ElementPtr element = *it;
+ for (int i = 0; i < kvps.size(); i++)
+ {
+ 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)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
}