v0.2.47..v0.2.48 changeset OsmMap.cpp
Garret Voltz edited this page Sep 27, 2019
·
1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/elements/OsmMap.cpp b/hoot-core/src/main/cpp/hoot/core/elements/OsmMap.cpp
index 685fbc3..faf5691 100644
--- a/hoot-core/src/main/cpp/hoot/core/elements/OsmMap.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/elements/OsmMap.cpp
@@ -47,6 +47,7 @@
#include <hoot/core/util/MapProjector.h>
#include <hoot/core/util/SignalCatcher.h>
#include <hoot/core/util/Validate.h>
+#include <hoot/core/elements/ElementComparer.h>
using namespace hoot::elements;
// Qt
@@ -59,8 +60,8 @@ namespace hoot
std::shared_ptr<OGRSpatialReference> OsmMap::_wgs84;
-OsmMap::OsmMap()
- : _idSwap(new IdSwap())
+OsmMap::OsmMap() :
+_idSwap(new IdSwap())
{
if (!_wgs84)
{
@@ -70,37 +71,52 @@ OsmMap::OsmMap()
setIdGenerator(IdGenerator::getInstance());
_index.reset(new OsmMapIndex(*this));
_srs = _wgs84;
+ _initCounters();
}
OsmMap::OsmMap(const ConstOsmMapPtr& map)
{
_copy(map);
+ _initCounters();
}
OsmMap::OsmMap(const OsmMapPtr& map)
{
_copy(map);
+ _initCounters();
}
-OsmMap::OsmMap(const std::shared_ptr<OGRSpatialReference>& srs)
- : _idSwap(new IdSwap())
+OsmMap::OsmMap(const std::shared_ptr<OGRSpatialReference>& srs) :
+_idSwap(new IdSwap())
{
setIdGenerator(IdGenerator::getInstance());
_index.reset(new OsmMapIndex(*this));
_srs = srs;
+ _initCounters();
}
OsmMap::OsmMap(const ConstOsmMapPtr& map, const std::shared_ptr<OGRSpatialReference>& srs)
{
_copy(map);
_srs = srs;
+ _initCounters();
}
OsmMap::~OsmMap()
{
}
-void OsmMap::append(const ConstOsmMapPtr& appendFromMap)
+void OsmMap::_initCounters()
+{
+ _numNodesAppended = 0;
+ _numWaysAppended = 0;
+ _numRelationsAppended = 0;
+ _numNodesSkippedForAppending = 0;
+ _numWaysSkippedForAppending = 0;
+ _numRelationsSkippedForAppending = 0;
+}
+
+void OsmMap::append(const ConstOsmMapPtr& appendFromMap, const bool throwOutDupes)
{
if (this == appendFromMap.get())
{
@@ -118,44 +134,135 @@ void OsmMap::append(const ConstOsmMapPtr& appendFromMap)
"Incompatible maps. Map being appended to has projection:\n" + proj1 +
"\nMap being appended from has projection:\n" + proj2);
}
+
+ LOG_DEBUG("Appending maps...");
+
+ _initCounters();
_srs = appendFromMap->getProjection();
+ // These indexes need to be force initialized before appending.
+ _index->getNodeToWayMap();
+ _index->getElementToRelationMap();
+ ElementComparer elementComparer;
- const RelationMap& allRelations = appendFromMap->getRelations();
- for (RelationMap::const_iterator it = allRelations.begin(); it != allRelations.end(); ++it)
+ // The append order must be nodes, ways, and then relations. If not, the map indexes won't update
+ // properly.
+
+ NodeMap::const_iterator itn = appendFromMap->_nodes.begin();
+ while (itn != appendFromMap->_nodes.end())
{
- RelationPtr relation = it->second;
- if (containsElement(ElementId(relation->getElementId())))
+ bool appendElement = true;
+ NodePtr node = itn->second;
+ if (containsElement(ElementId(node->getElementId())))
{
- throw HootException("Map already contains this relation: " + relation->toString());
+ // If they have the same ID but aren't considerd to be identical elements, throw an error.
+ // Otherwise we'll just skip adding the identical element, since we already have it.
+ // throwOutDupes being enabled lets us skip it whether the two are identical or not.
+ ElementPtr existingElement = getElement(node->getElementId());
+ if (!throwOutDupes && !elementComparer.isSame(node, existingElement))
+ {
+ const QString msg =
+ QString("Map already contains %1; existing element: %2; attempting to replace with element: %3")
+ .arg(node->getElementId().toString())
+ .arg(getElement(node->getElementId())->toString())
+ .arg(node->toString());
+ throw HootException(msg);
+ }
+ else
+ {
+ LOG_TRACE("Skipping appending same element: " << node->getElementId());
+ appendElement = false;
+ }
+ }
+
+ if (appendElement)
+ {
+ NodePtr n = NodePtr(new Node(*node));
+ LOG_TRACE("Appending: " << n->getElementId() << "...");
+ addNode(n);
+ _numNodesAppended++;
+ }
+ else
+ {
+ _numNodesSkippedForAppending++;
}
- RelationPtr r = RelationPtr(new Relation(*relation));
- addRelation(r);
+
+ ++itn;
}
WayMap::const_iterator it = appendFromMap->_ways.begin();
while (it != appendFromMap->_ways.end())
{
+ bool appendElement = true;
WayPtr way = it->second;
if (containsElement(ElementId(way->getElementId())))
{
- throw HootException("Map already contains this way: " + way->toString());
+ ElementPtr existingElement = getElement(way->getElementId());
+ if (!throwOutDupes && !elementComparer.isSame(way, existingElement))
+ {
+ const QString msg =
+ QString("Map already contains %1; existing element: %2; attempting to replace with element: %3")
+ .arg(way->getElementId().toString())
+ .arg(getElement(way->getElementId())->toString())
+ .arg(way->toString());
+ throw HootException(msg);
+ }
+ else
+ {
+ LOG_TRACE("Skipping appending same element: " << way->getElementId());
+ appendElement = false;
+ }
}
- WayPtr w = WayPtr(new Way(*way));
- addWay(w);
+
+ if (appendElement)
+ {
+ WayPtr w = WayPtr(new Way(*way));
+ LOG_TRACE("Appending: " << w->getElementId() << "...");
+ addWay(w);
+ _numWaysAppended++;
+ }
+ else
+ {
+ _numWaysSkippedForAppending++;
+ }
+
++it;
}
- NodeMap::const_iterator itn = appendFromMap->_nodes.begin();
- while (itn != appendFromMap->_nodes.end())
+ const RelationMap& allRelations = appendFromMap->getRelations();
+ for (RelationMap::const_iterator it = allRelations.begin(); it != allRelations.end(); ++it)
{
- NodePtr node = itn->second;
- if (containsElement(ElementId(node->getElementId())))
+ bool appendElement = true;
+ RelationPtr relation = it->second;
+ if (containsElement(ElementId(relation->getElementId())))
{
- throw HootException("Map already contains this node: " + node->toString());
+ ElementPtr existingElement = getElement(relation->getElementId());
+ if (!throwOutDupes && !elementComparer.isSame(relation, existingElement))
+ {
+ const QString msg =
+ QString("Map already contains %1; existing element: %2; attempting to replace with element: %3")
+ .arg(relation->getElementId().toString())
+ .arg(getElement(relation->getElementId())->toString())
+ .arg(relation->toString());
+ throw HootException(msg);
+ }
+ else
+ {
+ LOG_TRACE("Skipping appending same element: " << relation->getElementId());
+ appendElement = false;
+ }
+ }
+
+ if (appendElement)
+ {
+ RelationPtr r = RelationPtr(new Relation(*relation));
+ LOG_TRACE("Appending: " << r->getElementId() << "...");
+ addRelation(r);
+ _numRelationsAppended++;
+ }
+ else
+ {
+ _numRelationsSkippedForAppending++;
}
- NodePtr n = NodePtr(new Node(*node));
- addNode(n);
- ++itn;
}
for (size_t i = 0; i < appendFromMap->getListeners().size(); i++)
@@ -163,11 +270,18 @@ void OsmMap::append(const ConstOsmMapPtr& appendFromMap)
std::shared_ptr<OsmMapListener> l = appendFromMap->getListeners()[i];
_listeners.push_back(l->clone());
}
+
+ LOG_VARD(_numNodesAppended);
+ LOG_VARD(_numNodesSkippedForAppending);
+ LOG_VARD(_numWaysAppended);
+ LOG_VARD(_numWaysSkippedForAppending);
+ LOG_VARD(_numRelationsAppended);
+ LOG_VARD(_numRelationsSkippedForAppending);
}
void OsmMap::addElement(const std::shared_ptr<Element>& e)
{
- switch(e->getElementType().getEnum())
+ switch (e->getElementType().getEnum())
{
case ElementType::Node:
addNode(std::dynamic_pointer_cast<Node>(e));
@@ -201,6 +315,7 @@ void OsmMap::addNodes(const std::vector<NodePtr>& nodes)
// this seemed like a clever optimization. However, this impacts the BigPertyCmd.sh test b/c
// it modifies the order in which the elements are written to the output. Which presumably (?)
// impacts the ID when reading the file with re-numbering. Sad.
+ // TODO: The BigPertyCmd.sh test no longer exists, so maybe try it again.
// size_t minBuckets = _nodes.size() + nodes.size() * 1.1;
// if (_nodes.bucket_count() < minBuckets)
// {
@@ -238,15 +353,6 @@ void OsmMap::addWay(const WayPtr& w)
_ways[w->getId()] = w;
w->registerListener(_index.get());
_index->addWay(w);
- //_wayCounter = std::min(w->getId() - 1, _wayCounter);
-
- // this is a bit too strict, especially when dealing with MapReduce
-//# ifdef DEBUG
-// for (int i = 0; i < w->getNodeCount(); i++)
-// {
-// assert(_nodes.contains(w->getNodeId(i)));
-// }
-//# endif
}
void OsmMap::clear()
@@ -297,6 +403,7 @@ void OsmMap::_copy(const ConstOsmMapPtr& from)
_srs = from->getProjection();
_roundabouts = from->getRoundabouts();
_idSwap = from->getIdSwap();
+ _name = from->getName();
int i = 0;
const RelationMap& allRelations = from->getRelations();
@@ -453,7 +560,7 @@ void OsmMap::replace(const std::shared_ptr<const Element>& from, const QList<Ele
}
if (from->getElementType() == ElementType::Node && to.size() == 1 &&
- to[0]->getElementType() == ElementType::Node)
+ to[0]->getElementType() == ElementType::Node)
{
replaceNode(from->getId(), to[0]->getId());
}