-
Notifications
You must be signed in to change notification settings - Fork 74
v0.2.48..v0.2.49 changeset PertyMatchScorer.cpp
Garret Voltz edited this page Oct 2, 2019
·
1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/algorithms/perty/PertyMatchScorer.cpp b/hoot-core/src/main/cpp/hoot/core/algorithms/perty/PertyMatchScorer.cpp
new file mode 100644
index 0000000..51c2295
--- /dev/null
+++ b/hoot-core/src/main/cpp/hoot/core/algorithms/perty/PertyMatchScorer.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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) 2015, 2016, 2017, 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ */
+#include "PertyMatchScorer.h"
+
+// hoot
+#include <hoot/core/elements/OsmMap.h>
+#include <hoot/core/ops/MapCleaner.h>
+#include <hoot/core/algorithms/rubber-sheet/RubberSheet.h>
+#include <hoot/core/conflate/UnifyingConflator.h>
+#include <hoot/core/conflate/matching/MatchThreshold.h>
+#include <hoot/core/ops/BuildingOutlineUpdateOp.h>
+#include <hoot/core/util/ConfigOptions.h>
+#include <hoot/core/util/IoUtils.h>
+#include <hoot/core/util/Log.h>
+#include <hoot/core/util/MapProjector.h>
+#include <hoot/core/schema/MetadataTags.h>
+#include <hoot/core/visitors/AddRef1Visitor.h>
+#include <hoot/core/visitors/SetTagValueVisitor.h>
+#include <hoot/core/visitors/TagCountVisitor.h>
+#include <hoot/core/visitors/TagRenameKeyVisitor.h>
+#include <hoot/core/algorithms/perty/PertyOp.h>
+#include <hoot/core/scoring/MatchScoringMapPreparer.h>
+
+// Qt
+#include <QFileInfo>
+#include <QDir>
+
+namespace hoot
+{
+
+PertyMatchScorer::PertyMatchScorer() :
+_settings(conf())
+{
+ ConfigOptions configOptions;
+ setSearchDistance(configOptions.getPertySearchDistance());
+ if (ConfigOptions().getConflatePreOps().contains("hoot::RubberSheet"))
+ {
+ setApplyRubberSheet(false);
+ }
+ else
+ {
+ setApplyRubberSheet(configOptions.getPertyApplyRubberSheet());
+ }
+}
+
+QString PertyMatchScorer::toString()
+{
+ QString str = "_searchDistance: " + QString::number(_searchDistance) + ", _applyRubberSheet: ";
+ if (_applyRubberSheet)
+ {
+ str += "true";
+ }
+ else
+ {
+ str += "false";
+ }
+ return str;
+}
+
+std::shared_ptr<MatchComparator> PertyMatchScorer::scoreMatches(const QString& referenceMapInputPath,
+ const QString& outputPath)
+{
+ LOG_INFO(toString());
+
+ QDir().mkpath(outputPath);
+ QFileInfo inputFileInfo(referenceMapInputPath);
+ const QString referenceMapOutputPath =
+ outputPath + "/" + inputFileInfo.baseName() + "-reference-out.osm";
+ _referenceMapOutput = referenceMapOutputPath;
+ const QString perturbedMapOutputPath =
+ outputPath + "/" + inputFileInfo.baseName() + "-perturbed-out.osm";
+ _perturbedMapOutput = perturbedMapOutputPath;
+ const QString combinedMapOutputPath =
+ outputPath + "/" + inputFileInfo.baseName() + "-combined-out.osm";
+ const QString conflatedMapOutputPath =
+ outputPath + "/" + inputFileInfo.baseName() + "-conflated-out.osm";
+ _conflatedMapOutput = conflatedMapOutputPath;
+
+ OsmMapPtr referenceMap = _loadReferenceMap(referenceMapInputPath, referenceMapOutputPath);
+ _loadPerturbedMap(referenceMapOutputPath, perturbedMapOutputPath);
+ OsmMapPtr combinedMap =
+ _combineMapsAndPrepareForConflation(referenceMap, perturbedMapOutputPath);
+
+ MapProjector::projectToWgs84(combinedMap);
+ IoUtils::saveMap(combinedMap, combinedMapOutputPath);
+
+ return _conflateAndScoreMatches(combinedMap, conflatedMapOutputPath);
+}
+
+OsmMapPtr PertyMatchScorer::_loadReferenceMap(const QString& referenceMapInputPath,
+ const QString& referenceMapOutputPath)
+{
+ LOG_DEBUG("Loading the reference data with status " << MetadataTags::Unknown1() << " and adding " << MetadataTags::Ref1() <<
+ " tags to it; Saving a copy to " << referenceMapOutputPath << "...");
+
+ OsmMapPtr referenceMap(new OsmMap());
+ IoUtils::loadMap(referenceMap, referenceMapInputPath, false, Status::Unknown1);
+ MapCleaner().apply(referenceMap);
+
+ std::shared_ptr<AddRef1Visitor> addRef1Visitor(new AddRef1Visitor());
+ referenceMap->visitRw(*addRef1Visitor);
+ std::shared_ptr<SetTagValueVisitor> setAccuracyVisitor(
+ new SetTagValueVisitor(MetadataTags::ErrorCircular(), QString::number(_searchDistance)));
+ referenceMap->visitRw(*setAccuracyVisitor);
+ LOG_VARD(referenceMap->getNodes().size());
+ LOG_VARD(referenceMap->getWays().size());
+ if (Log::getInstance().getLevel() <= Log::Debug)
+ {
+ TagCountVisitor tagCountVisitor;
+ referenceMap->visitRo(tagCountVisitor);
+ const long numTotalTags = (long)tagCountVisitor.getStat();
+ LOG_VARD(numTotalTags);
+ }
+
+ OsmMapPtr referenceMapCopy(referenceMap);
+ MapProjector::projectToWgs84(referenceMapCopy);
+ IoUtils::saveMap(referenceMapCopy, referenceMapOutputPath);
+
+ return referenceMap;
+}
+
+void PertyMatchScorer::_loadPerturbedMap(const QString& perturbedMapInputPath,
+ const QString& perturbedMapOutputPath)
+{
+ LOG_DEBUG("Loading the reference data to be used by the data to be perturbed; renaming " <<
+ MetadataTags::Ref1() << " tags to " << MetadataTags::Ref2() << "...");
+
+ //load from the modified reference data output to get the added ref1 tags; don't copy the map,
+ //since updates to the names of the ref tags on this map will propagate to the map copied from
+ OsmMapPtr perturbedMap(new OsmMap());
+ IoUtils::loadMap(perturbedMap, perturbedMapInputPath, false, Status::Unknown2);
+ MapCleaner().apply(perturbedMap);
+
+ std::shared_ptr<TagRenameKeyVisitor> tagRenameKeyVisitor(
+ new TagRenameKeyVisitor(MetadataTags::Ref1(), MetadataTags::Ref2()));
+ perturbedMap->visitRw(*tagRenameKeyVisitor);
+ // This could be replaced with a SetTagValueVisitor passed in from the command line
+ // instead.
+ std::shared_ptr<SetTagValueVisitor> setAccuracyVisitor(
+ new SetTagValueVisitor(MetadataTags::ErrorCircular(), QString::number(_searchDistance)));
+ perturbedMap->visitRw(*setAccuracyVisitor);
+ LOG_VARD(perturbedMap->getNodes().size());
+ LOG_VARD(perturbedMap->getWays().size());
+ if (Log::getInstance().getLevel() <= Log::Debug)
+ {
+ TagCountVisitor tagCountVisitor;
+ perturbedMap->visitRo(tagCountVisitor);
+ const long numTotalTags = (long)tagCountVisitor.getStat();
+ LOG_VARD(numTotalTags);
+ }
+
+ LOG_DEBUG("Perturbing the copied reference data and saving it to: " << perturbedMapOutputPath);
+
+ PertyOp pertyOp;
+ pertyOp.setConfiguration(_settings);
+ pertyOp.apply(perturbedMap);
+ LOG_VARD(perturbedMap->getNodes().size());
+ LOG_VARD(perturbedMap->getWays().size());
+ if (Log::getInstance().getLevel() <= Log::Debug)
+ {
+ TagCountVisitor tagCountVisitor;
+ perturbedMap->visitRo(tagCountVisitor);
+ const long numTotalTags = (long)tagCountVisitor.getStat();
+ LOG_VARD(numTotalTags);
+ }
+
+ MapProjector::projectToWgs84(perturbedMap);
+ IoUtils::saveMap(perturbedMap, perturbedMapOutputPath);
+}
+
+OsmMapPtr PertyMatchScorer::_combineMapsAndPrepareForConflation(const OsmMapPtr& referenceMap, const QString& perturbedMapInputPath)
+{
+ LOG_DEBUG("Combining the reference and perturbed data into a single file ...");
+
+// QFileInfo fileInfo(perturbedMapInputPath);
+// QString combinedOutputPath = fileInfo.path() + "/ref-after-combination.osm";
+// LOG_DEBUG("saving a debug copy to " << combinedOutputPath << " ...");
+
+ OsmMapPtr combinedMap(referenceMap);
+ IoUtils::loadMap(combinedMap, perturbedMapInputPath, false, Status::Unknown2);
+ LOG_VARD(combinedMap->getNodes().size());
+ LOG_VARD(combinedMap->getWays().size());
+ if (Log::getInstance().getLevel() <= Log::Debug)
+ {
+ TagCountVisitor tagCountVisitor;
+ combinedMap->visitRo(tagCountVisitor);
+ const long numTotalTags = (long)tagCountVisitor.getStat();
+ LOG_VARD(numTotalTags);
+ }
+
+// OsmMapPtr combinedMapCopy(combinedMap);
+// MapProjector::reprojectToWgs84(combinedMapCopy);
+// IoUtils::saveMap(combinedMapCopy, combinedOutputPath);
+
+// LOG_DEBUG("Preparing the reference data for conflation ...");
+// QString combinedOutputPath2 = fileInfo.path() + "/ref-after-prep.osm";
+// LOG_DEBUG("saving a debug copy to " << combinedOutputPath2 << " ...");
+
+ MatchScoringMapPreparer().prepMap(combinedMap, true);
+ LOG_VARD(combinedMap->getNodes().size());
+ LOG_VARD(combinedMap->getWays().size());
+ if (Log::getInstance().getLevel() <= Log::Debug)
+ {
+ TagCountVisitor tagCountVisitor;
+ combinedMap->visitRo(tagCountVisitor);
+ const long numTotalTags = (long)tagCountVisitor.getStat();
+ LOG_VARD(numTotalTags);
+ }
+
+// OsmMapPtr combinedMapCopy2(combinedMap);
+// MapProjector::reprojectToWgs84(combinedMapCopy2);
+// IoUtils::saveMap(combinedMapCopy2, combinedOutputPath2);
+
+ if (_applyRubberSheet)
+ {
+ // LOG_DEBUG("Applying rubber sheet to pre-conflated data to move perturbed data towards " <<
+ // "reference data ...");
+ // QString combinedOutputPath3 = fileInfo.path() + "/ref-after-rubber-sheet.osm";
+ // LOG_DEBUG("saving a debug copy to " << combinedOutputPath3 << " ...");
+
+ //move Unknown2 toward Unknown1
+ conf().set(RubberSheet::refKey(), true);
+ std::shared_ptr<RubberSheet> rubberSheetOp(new RubberSheet());
+ rubberSheetOp->apply(combinedMap);
+
+ LOG_VARD(combinedMap->getNodes().size());
+ LOG_VARD(combinedMap->getWays().size());
+ if (Log::getInstance().getLevel() <= Log::Debug)
+ {
+ TagCountVisitor tagCountVisitor;
+ combinedMap->visitRo(tagCountVisitor);
+ const long numTotalTags = (long)tagCountVisitor.getStat();
+ LOG_VARD(numTotalTags);
+ }
+
+ // OsmMapPtr combinedMapCopy3(combinedMapCopy2);
+ // MapProjector::reprojectToWgs84(combinedMapCopy3);
+ // IoUtils::saveMap(combinedMapCopy3, combinedOutputPath3);
+ }
+
+ return combinedMap;
+}
+
+std::shared_ptr<MatchComparator> PertyMatchScorer::_conflateAndScoreMatches(
+ const OsmMapPtr& combinedDataToConflate, const QString& conflatedMapOutputPath)
+{
+ LOG_DEBUG("Conflating the reference data with the perturbed data, scoring the matches, and " <<
+ "saving the conflated output to: " << conflatedMapOutputPath);
+
+ std::shared_ptr<MatchComparator> comparator(new MatchComparator());
+ //shared_ptr<MatchThreshold> matchThreshold;
+ OsmMapPtr conflationCopy(new OsmMap(combinedDataToConflate));
+
+ UnifyingConflator conflator/*(matchThreshold)*/;
+ conflator.setConfiguration(_settings);
+ conflator.apply(conflationCopy);
+
+ try
+ {
+ comparator->evaluateMatches(combinedDataToConflate, conflationCopy);
+ }
+ catch (const HootException&)
+ {
+ // save map modifies the map so we want to make sure comparator runs first. 'finally' would be
+ // nice.
+ _saveMap(conflationCopy, conflatedMapOutputPath);
+ throw;
+ }
+
+ _saveMap(conflationCopy, conflatedMapOutputPath);
+
+ return comparator;
+}
+
+void PertyMatchScorer::_saveMap(OsmMapPtr& map, const QString& path)
+{
+ BuildingOutlineUpdateOp().apply(map);
+
+ LOG_VARD(map->getNodes().size());
+ LOG_VARD(map->getWays().size());
+ if (Log::getInstance().getLevel() <= Log::Debug)
+ {
+ TagCountVisitor tagCountVisitor;
+ map->visitRo(tagCountVisitor);
+ const long numTotalTags = (long)tagCountVisitor.getStat();
+ LOG_VARD(numTotalTags);
+ }
+
+ MapProjector::projectToWgs84(map);
+ IoUtils::saveMap(map, path);
+}
+
+}