diff --git a/conf/core/ConfigOptions.asciidoc b/conf/core/ConfigOptions.asciidoc index 685450b470..ee2fbfec5a 100644 --- a/conf/core/ConfigOptions.asciidoc +++ b/conf/core/ConfigOptions.asciidoc @@ -5501,6 +5501,13 @@ shape file and cannot be used in combination with a translation. If this option then the list of columns will be automatically determined based on the most frequently populated tags. +=== shift.nodes.xy + +* Data Type: string +* Default Value: `0.0,0.0` + +Shift all nodes in the map by x, y meters when using the `NodesShiftVisitor` + === small.disconnected.way.remover.max.node.count * Data Type: int diff --git a/hoot-core-test/src/test/cpp/hoot/core/visitors/NodesShiftVisitorTest.cpp b/hoot-core-test/src/test/cpp/hoot/core/visitors/NodesShiftVisitorTest.cpp new file mode 100644 index 0000000000..eb837178d7 --- /dev/null +++ b/hoot-core-test/src/test/cpp/hoot/core/visitors/NodesShiftVisitorTest.cpp @@ -0,0 +1,106 @@ +/* + * 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 . + * + * -------------------------------------------------------------------- + * + * 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. Maxar + * copyrights will be updated automatically. + * + * @copyright Copyright (C) 2023 Maxar (http://www.maxar.com/) + */ + +// Hoot +#include +#include +#include +#include +#include +#include + +namespace hoot +{ + +class NodesShiftVisitorTest : public HootTestFixture +{ + CPPUNIT_TEST_SUITE(NodesShiftVisitorTest); + CPPUNIT_TEST(singleNodeApplyTest); + CPPUNIT_TEST(applyToMapTest); + CPPUNIT_TEST_SUITE_END(); + +public: + + NodesShiftVisitorTest() + : HootTestFixture("test-files/visitors/NodesShiftVisitorTest/", + "test-output/visitors/NodesShiftVisitorTest/") + { + } + + void singleNodeApplyTest() + { + std::shared_ptr n = std::make_shared(Status::Unknown1, 1, 0.0, 0.0); + // Positive moves + NodesShiftVisitor visitor(10.0, 12.0); + visitor.visit(n); + CPPUNIT_ASSERT_EQUAL(12.0, n->getX()); + CPPUNIT_ASSERT_EQUAL(10.0, n->getY()); + // Negative moves + visitor.setShift(-2.0, -100.0); + visitor.visit(n); + CPPUNIT_ASSERT_EQUAL(-88.0, n->getX()); + CPPUNIT_ASSERT_EQUAL(8.0, n->getY()); + } + + void applyToMapTest() + { + OsmMapPtr map = std::make_shared(); + OsmMapReaderFactory::read(map, "test-files/ToyTestA.osm", false, Status::Unknown1); + MapProjector::projectToPlanar(map); + + conf().set(ConfigOptions::getShiftNodesXyKey(), "10.0,20.0"); + + NodesShiftVisitor uut; + map->visitRw(uut); + + MapProjector::projectToWgs84(map); + OsmMapWriterFactory::write(map, _outputPath + "applyToMapOutput1.osm"); + + HOOT_FILE_EQUALS(_inputPath + "applyToMapExpected1.osm", + _outputPath + "applyToMapOutput1.osm"); + + map->clear(); + OsmMapReaderFactory::read(map, "test-files/ToyTestA.osm", false, Status::Unknown1); + MapProjector::projectToPlanar(map); + + uut.setShift(-100.0, -55.0); + + map->visitRw(uut); + + MapProjector::projectToWgs84(map); + OsmMapWriterFactory::write(map, _outputPath + "applyToMapOutput2.osm"); + + HOOT_FILE_EQUALS(_inputPath + "applyToMapExpected2.osm", + _outputPath + "applyToMapOutput2.osm"); + + conf().set(ConfigOptions::getShiftNodesXyKey(), ConfigOptions::getShiftNodesXyDefaultValue()); + } +}; + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(NodesShiftVisitorTest, "quick"); + +} diff --git a/hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.cpp b/hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.cpp new file mode 100644 index 0000000000..d71d8b0de6 --- /dev/null +++ b/hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.cpp @@ -0,0 +1,102 @@ +/* + * 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 . + * + * -------------------------------------------------------------------- + * + * 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. Maxar + * copyrights will be updated automatically. + * + * @copyright Copyright (C) 2023 Maxar (http://www.maxar.com/) + */ +#include "NodesShiftVisitor.h" + +// hoot +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Qt +#include + +using namespace geos::geom; +using namespace std; + +namespace hoot +{ + +HOOT_FACTORY_REGISTER(ElementVisitor, NodesShiftVisitor) + +NodesShiftVisitor::NodesShiftVisitor() + : _northShift(0.0), + _eastShift(0.0) +{ + _parseShift(); +} + +NodesShiftVisitor::NodesShiftVisitor(Meters north_shift, Meters east_shift) + : _northShift(north_shift), + _eastShift(east_shift) +{ +} + +void NodesShiftVisitor::setShift(Meters north_shift, Meters east_shift) +{ + _northShift = north_shift; + _eastShift = east_shift; +} + +void NodesShiftVisitor::visit(const std::shared_ptr& e) +{ + if (e->getElementType() == ElementType::Node) + { + NodePtr node = std::dynamic_pointer_cast(e); + node->setX(node->getX() + _eastShift); + node->setY(node->getY() + _northShift); + } +} + +void NodesShiftVisitor::_parseShift() +{ + QString shift = ConfigOptions().getShiftNodesXy(); + QStringList values = shift.split(","); + if (values.size() != 2) + return; + bool goodX = false; + bool goodY = false; + double x = values[0].toDouble(&goodX); + double y = values[1].toDouble(&goodY); + if (!goodX || !goodY) + return; + _northShift = y; + _eastShift = x; +} + +} diff --git a/hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.h b/hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.h new file mode 100644 index 0000000000..ec96df56e0 --- /dev/null +++ b/hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.h @@ -0,0 +1,72 @@ +/* + * 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 . + * + * -------------------------------------------------------------------- + * + * 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. Maxar + * copyrights will be updated automatically. + * + * @copyright Copyright (C) 2023 Maxar (http://www.maxar.com/) + */ +#ifndef NODES_SHIFT_VISITOR_H +#define NODES_SHIFT_VISITOR_H + +// hoot +#include +#include + +namespace hoot +{ + +/** + * @brief The NodesShiftVisitor class shifts all nodes in a map by Y meters north and X meters east + * NOTE: The map must be in planar coordinates for this visitor to work + */ +class NodesShiftVisitor : public ElementVisitor +{ +public: + + static QString className() { return "NodesShiftVisitor"; } + + NodesShiftVisitor(); + NodesShiftVisitor(Meters north_shift, Meters east_shift); + ~NodesShiftVisitor() override = default; + + void setShift(Meters north_shift, Meters east_shift); + + /** + * @see ElementVisitor + */ + void visit(const std::shared_ptr& e) override; + + QString getDescription() const override { return "Shift all nodes by an offset"; } + QString getName() const override { return className(); } + QString getClassName() const override { return className(); } + +private: + + void _parseShift(); + + Meters _northShift; + Meters _eastShift; +}; + +} + +#endif // NODES_SHIFT_VISITOR_H diff --git a/test-files/visitors/NodesShiftVisitorTest/applyToMapExpected1.osm b/test-files/visitors/NodesShiftVisitorTest/applyToMapExpected1.osm new file mode 100644 index 0000000000..8a71050ff9 --- /dev/null +++ b/test-files/visitors/NodesShiftVisitorTest/applyToMapExpected1.osm @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/visitors/NodesShiftVisitorTest/applyToMapExpected2.osm b/test-files/visitors/NodesShiftVisitorTest/applyToMapExpected2.osm new file mode 100644 index 0000000000..2c2c46f101 --- /dev/null +++ b/test-files/visitors/NodesShiftVisitorTest/applyToMapExpected2.osm @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-files/visitors/NodesShiftVisitorTest/applyToMapOutput2.osm b/test-files/visitors/NodesShiftVisitorTest/applyToMapOutput2.osm new file mode 100644 index 0000000000..2c2c46f101 --- /dev/null +++ b/test-files/visitors/NodesShiftVisitorTest/applyToMapOutput2.osm @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +