-
Notifications
You must be signed in to change notification settings - Fork 74
v0.2.54..v0.2.55 changeset CollectionRelationMerger.cpp
Garret Voltz edited this page Aug 14, 2020
·
1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/conflate/merging/CollectionRelationMerger.cpp b/hoot-core/src/main/cpp/hoot/core/conflate/merging/CollectionRelationMerger.cpp
new file mode 100644
index 0000000..84488b2
--- /dev/null
+++ b/hoot-core/src/main/cpp/hoot/core/conflate/merging/CollectionRelationMerger.cpp
@@ -0,0 +1,267 @@
+/*
+ * This file is part of Hootenanny.
+ *
+ * Hootenanny is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --------------------------------------------------------------------
+ *
+ * The following copyright notices are generated automatically. If you
+ * have a new notice to add, please use the format:
+ * " * @copyright Copyright ..."
+ * This will properly maintain the copyright information. DigitalGlobe
+ * copyrights will be updated automatically.
+ *
+ * @copyright Copyright (C) 2020 DigitalGlobe (http://www.digitalglobe.com/)
+ */
+#include "CollectionRelationMerger.h"
+
+// hoot
+#include <hoot/core/schema/TagMergerFactory.h>
+#include <hoot/core/ops/ReplaceElementOp.h>
+#include <hoot/core/io/OsmMapWriterFactory.h>
+#include <hoot/core/ops/RemoveRelationByEid.h>
+#include <hoot/core/elements/RelationMemberComparison.h>
+
+namespace hoot
+{
+
+CollectionRelationMerger::CollectionRelationMerger()
+{
+}
+
+void CollectionRelationMerger::merge(const ElementId& elementId1, const ElementId& elementId2)
+{
+ if (elementId1.getType() != ElementType::Relation ||
+ elementId2.getType() != ElementType::Relation)
+ {
+ throw IllegalArgumentException(
+ "Element types other than relation were passed to CollectionRelationMerger.");
+ }
+
+ LOG_TRACE("Merging relations " << elementId1 << " and " << elementId2 << "...");
+
+ RelationPtr relation1 = _map->getRelation(elementId1.getId());
+ RelationPtr relation2 = _map->getRelation(elementId2.getId());
+
+ LOG_TRACE("Merging tags...");
+ Tags newTags =
+ TagMergerFactory::mergeTags(relation1->getTags(), relation2->getTags(), ElementType::Relation);
+ relation1->setTags(newTags);
+
+ // copy relation 2's members into 1
+ _mergeMembers(relation1, relation2);
+
+ LOG_TRACE("Replacing " << elementId2 << " with " << elementId1 << "...");
+ ReplaceElementOp(elementId2, elementId1, true).apply(_map);
+
+ LOG_TRACE("Removing " << elementId2 << "...");
+ RemoveRelationByEid(elementId2.getId()).apply(_map);
+
+ LOG_TRACE("Merged relations " << elementId1 << " and " << elementId2);
+ // ONLY ENABLE THIS DURING DEBUGGING
+ //OsmMapWriterFactory::writeDebugMap(
+ //_map, "CollectionRelationMerger-" + elementId1.toString() + "-" + elementId2.toString());
+}
+
+void CollectionRelationMerger::_mergeMembers(
+ RelationPtr replacingRelation, RelationPtr relationBeingReplaced)
+{
+ LOG_TRACE("Merging members...");
+
+ const std::vector<RelationData::Entry> replacingRelationMembers = replacingRelation->getMembers();
+ LOG_VART(replacingRelationMembers.size());
+ const std::vector<RelationData::Entry> relationBeingReplacedMembers =
+ relationBeingReplaced->getMembers();
+ LOG_VART(relationBeingReplacedMembers.size());
+
+ // if insertion ever proves too slow with these lists, then we can switch them over to linked
+ // lists
+ QList<RelationMemberComparison> replacingRelationMemberComps;
+ for (size_t i = 0; i < replacingRelationMembers.size(); i++)
+ {
+ const RelationData::Entry member = replacingRelationMembers[i];
+ ConstElementPtr memberElement = _map->getElement(member.getElementId());
+ if (memberElement)
+ {
+ ElementPtr memberElement2 = std::const_pointer_cast<Element>(memberElement);
+ replacingRelationMemberComps.append(
+ RelationMemberComparison(memberElement2, *_map, member.getRole(), true));
+ }
+ }
+ LOG_VART(replacingRelationMemberComps.size());
+
+ QList<RelationMemberComparison> relationBeingReplacedMemberComps;
+ for (size_t i = 0; i < relationBeingReplacedMembers.size(); i++)
+ {
+ const RelationData::Entry member = relationBeingReplacedMembers[i];
+ ConstElementPtr memberElement = _map->getElement(member.getElementId());
+ if (memberElement)
+ {
+ ElementPtr memberElement2 = std::const_pointer_cast<Element>(memberElement);
+ relationBeingReplacedMemberComps.append(
+ RelationMemberComparison(memberElement2, *_map, member.getRole(), true));
+ }
+ }
+ LOG_VART(relationBeingReplacedMemberComps.size());
+
+ for (int i = 0; i < relationBeingReplacedMemberComps.size(); i++)
+ {
+ const RelationMemberComparison currentMemberFromReplaced = relationBeingReplacedMemberComps[i];
+ LOG_VART(currentMemberFromReplaced);
+
+ // skip copying members our replacing relation already has
+ if (replacingRelationMemberComps.contains(currentMemberFromReplaced))
+ {
+ LOG_TRACE(
+ "Skipping adding member being replaced already in the replacing relation: " <<
+ currentMemberFromReplaced << "...");
+ LOG_TRACE("************************");
+ continue;
+ }
+
+ RelationMemberComparison beforeMemberFromReplaced;
+ RelationMemberComparison afterMemberFromReplaced;
+ if (i != 0)
+ {
+ // find the member right before our current member in the relation being replaced
+ beforeMemberFromReplaced = relationBeingReplacedMemberComps[i - 1];
+ }
+ if (i != relationBeingReplacedMemberComps.size() - 1)
+ {
+ // find the member right after our current member in the relation being replaced
+ afterMemberFromReplaced = relationBeingReplacedMemberComps[i + 1];
+ }
+ if (!beforeMemberFromReplaced.isNull())
+ {
+ LOG_VART(beforeMemberFromReplaced);
+ }
+ if (!afterMemberFromReplaced.isNull())
+ {
+ LOG_VART(afterMemberFromReplaced);
+ }
+
+ // use the relation size as the null value for size_t, since it can't be negative like the
+ // not found index coming back from QList will be
+ int matchingFromReplacingBeforeIndex = relationBeingReplacedMemberComps.size();
+ if (!beforeMemberFromReplaced.isNull())
+ {
+ // if there was a member directly preceding our current member in the relation being replaced,
+ // see if it exists in the replacing relation; if so record that member's index from the
+ // replacing relation
+ const int index = replacingRelationMemberComps.indexOf(beforeMemberFromReplaced);
+ if (index != -1)
+ {
+ matchingFromReplacingBeforeIndex = index;
+ }
+ }
+ int matchingFromReplacingAfterIndex = relationBeingReplacedMemberComps.size();
+ if (!afterMemberFromReplaced.isNull())
+ {
+ // if there was a member directly following our current member in the relation being replaced,
+ // see if it exists in the replacing relation; if so record that member's index from the
+ // replacing relation
+ const int index = replacingRelationMemberComps.indexOf(afterMemberFromReplaced);
+ if (index != -1)
+ {
+ matchingFromReplacingAfterIndex = index;
+ }
+ }
+ if (matchingFromReplacingBeforeIndex != relationBeingReplacedMemberComps.size())
+ {
+ LOG_VART(matchingFromReplacingBeforeIndex);
+ }
+ if (matchingFromReplacingAfterIndex != relationBeingReplacedMemberComps.size())
+ {
+ LOG_VART(matchingFromReplacingAfterIndex);
+ }
+
+ if (matchingFromReplacingBeforeIndex != relationBeingReplacedMemberComps.size() &&
+ matchingFromReplacingAfterIndex != relationBeingReplacedMemberComps.size())
+ {
+ if ((matchingFromReplacingAfterIndex - matchingFromReplacingBeforeIndex) == 1)
+ {
+ // if the replacing relation has matching directly preceding/following members for the
+ // current member from the relation being replaced and they are consecutive, insert our
+ // current member in between them in the replacing relation
+ LOG_TRACE(
+ "Consecutive directly preceding and following members. Inserting current member: " <<
+ currentMemberFromReplaced << " between indexes " <<
+ matchingFromReplacingBeforeIndex << " and " << matchingFromReplacingAfterIndex << "...");
+ replacingRelationMemberComps.insert(
+ matchingFromReplacingAfterIndex, currentMemberFromReplaced);
+ }
+ else
+ {
+ // if the replacing relation has matching directly preceding/following members for the
+ // current member from the relation being replaced and they are not consecutive,
+ // arbitrarily insert our current member just after the preceding member
+ LOG_TRACE(
+ "Non-consecutive directly preceding and following members. Inserting current member: " <<
+ currentMemberFromReplaced << " after index " << matchingFromReplacingBeforeIndex <<
+ "...");
+ replacingRelationMemberComps.insert(
+ matchingFromReplacingBeforeIndex + 1, currentMemberFromReplaced);
+ }
+ }
+ else if (matchingFromReplacingAfterIndex == relationBeingReplacedMemberComps.size() &&
+ matchingFromReplacingBeforeIndex != relationBeingReplacedMemberComps.size())
+ {
+ // if the replacing relation has a matching directly preceding member but not a directly
+ // following member, insert our current member from the relation being replaced just after the
+ // preceding member in the replacing relation
+ LOG_TRACE(
+ "Directly preceding member only. Inserting current member: " <<
+ currentMemberFromReplaced << " after index " << matchingFromReplacingBeforeIndex <<
+ "...");
+ replacingRelationMemberComps.insert(
+ matchingFromReplacingBeforeIndex + 1, currentMemberFromReplaced);
+ }
+ else if (matchingFromReplacingAfterIndex != relationBeingReplacedMemberComps.size() &&
+ matchingFromReplacingBeforeIndex == relationBeingReplacedMemberComps.size())
+ {
+ // if the replacing relation has a matching directly following member but not a directly
+ // preceding member, insert our current member from the relation being replaced just before
+ // the following member in the replacing relation
+ LOG_TRACE(
+ "Directly following member only. Inserting current member: " <<
+ currentMemberFromReplaced << " before index " << matchingFromReplacingAfterIndex << "...");
+ replacingRelationMemberComps.insert(
+ matchingFromReplacingAfterIndex - 1, currentMemberFromReplaced);
+ }
+ else
+ {
+ // if the replacing relation has no matching directly preceding/following members, arbitrarily
+ // add the current member from the relation being replacd to the end of the replacing relation
+ LOG_TRACE(
+ "No directly preceding or following members. Inserting current member: " <<
+ currentMemberFromReplaced << " at the end of the relation...");
+ replacingRelationMemberComps.append(currentMemberFromReplaced);
+ }
+ LOG_TRACE("************************");
+ }
+ LOG_VART(replacingRelationMemberComps);
+
+ std::vector<RelationData::Entry> modifiedMembers;
+ for (int i = 0; i < replacingRelationMemberComps.size(); i++)
+ {
+ const RelationMemberComparison currentMemberFromReplaced = replacingRelationMemberComps[i];
+ modifiedMembers.push_back(
+ RelationData::Entry(
+ currentMemberFromReplaced.getRole(),
+ currentMemberFromReplaced.getElement()->getElementId()));
+ }
+ replacingRelation->setMembers(modifiedMembers);
+}
+
+}