Skip to content

Commit

Permalink
NodesShiftVisitor to apply a predetermined shift to all nodes in a ma…
Browse files Browse the repository at this point in the history
…p. (#5571)
  • Loading branch information
bmarchant authored Feb 7, 2023
1 parent 9a7f889 commit 0fa9dfa
Show file tree
Hide file tree
Showing 7 changed files with 587 additions and 0 deletions.
7 changes: 7 additions & 0 deletions conf/core/ConfigOptions.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <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. Maxar
* copyrights will be updated automatically.
*
* @copyright Copyright (C) 2023 Maxar (http://www.maxar.com/)
*/

// Hoot
#include <hoot/core/TestUtils.h>
#include <hoot/core/elements/MapProjector.h>
#include <hoot/core/elements/OsmMap.h>
#include <hoot/core/io/OsmMapReaderFactory.h>
#include <hoot/core/io/OsmMapWriterFactory.h>
#include <hoot/core/visitors/NodesShiftVisitor.h>

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<Node> n = std::make_shared<Node>(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<OsmMap>();
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");

}
102 changes: 102 additions & 0 deletions hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.cpp
Original file line number Diff line number Diff line change
@@ -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 <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. Maxar
* copyrights will be updated automatically.
*
* @copyright Copyright (C) 2023 Maxar (http://www.maxar.com/)
*/
#include "NodesShiftVisitor.h"

// hoot
#include <hoot/core/criterion/AreaCriterion.h>
#include <hoot/core/criterion/BuildingCriterion.h>
#include <hoot/core/elements/ElementId.h>
#include <hoot/core/elements/OsmMap.h>
#include <hoot/core/geometry/ElementToGeometryConverter.h>
#include <hoot/core/geometry/GeometryUtils.h>
#include <hoot/core/index/OsmMapIndex.h>
#include <hoot/core/ops/RecursiveElementRemover.h>
#include <hoot/core/schema/TagComparator.h>
#include <hoot/core/schema/TagDifferencer.h>
#include <hoot/core/util/ConfigOptions.h>
#include <hoot/core/util/Factory.h>
#include <hoot/core/util/StringUtils.h>
#include <hoot/core/visitors/CompletelyContainedByMapElementVisitor.h>
#include <hoot/core/visitors/ElementOsmMapVisitor.h>

// Qt
#include <QElapsedTimer>

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<Element>& e)
{
if (e->getElementType() == ElementType::Node)
{
NodePtr node = std::dynamic_pointer_cast<Node>(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;
}

}
72 changes: 72 additions & 0 deletions hoot-core/src/main/cpp/hoot/core/visitors/NodesShiftVisitor.h
Original file line number Diff line number Diff line change
@@ -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 <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. 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 <hoot/core/elements/Node.h>
#include <hoot/core/visitors/ElementVisitor.h>

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<Element>& 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
100 changes: 100 additions & 0 deletions test-files/visitors/NodesShiftVisitorTest/applyToMapExpected1.osm
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="hootenanny" srs="+epsg:4326">
<bounds minlat="38.85342258711282" minlon="-104.9023164156062" maxlat="38.85514159728211" maxlon="-104.8960670937575"/>
<node visible="true" id="-36" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8543471617931857" lon="-104.8995917860605402"/>
<node visible="true" id="-35" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8542652689848182" lon="-104.9013324678325603"/>
<node visible="true" id="-34" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8544272800245096" lon="-104.9009636656164872"/>
<node visible="true" id="-33" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8544401295348365" lon="-104.9004643111126285"/>
<node visible="true" id="-32" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8551415972821061" lon="-104.8995972059394575"/>
<node visible="true" id="-31" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8547586644935521" lon="-104.8996019347873840"/>
<node visible="true" id="-30" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8544420069725831" lon="-104.8996019352981932"/>
<node visible="true" id="-29" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8541327121863063" lon="-104.8995688381858287"/>
<node visible="true" id="-28" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8538050055725179" lon="-104.8995782951748197"/>
<node visible="true" id="-27" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8534385077613535" lon="-104.8996390930517606"/>
<node visible="true" id="-26" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8534225871128172" lon="-104.8995716264190747"/>
<node visible="true" id="-25" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8534803087782379" lon="-104.8993376821570820"/>
<node visible="true" id="-24" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8535272076998623" lon="-104.8992519797621412"/>
<node visible="true" id="-23" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8536967652911542" lon="-104.8991546957748113"/>
<node visible="true" id="-22" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8537490753497039" lon="-104.8989415980316693"/>
<node visible="true" id="-21" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8537310371087514" lon="-104.8987169190074695"/>
<node visible="true" id="-20" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8537995814346075" lon="-104.8985918398362998"/>
<node visible="true" id="-19" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8539005942027273" lon="-104.8986080536256651"/>
<node visible="true" id="-18" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8541386953118888" lon="-104.8988003043902637"/>
<node visible="true" id="-17" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8543136628786456" lon="-104.8987748250400784"/>
<node visible="true" id="-16" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8543569535823252" lon="-104.8985918389371506"/>
<node visible="true" id="-15" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8544128705446781" lon="-104.8981957551550721"/>
<node visible="true" id="-14" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8546094825818358" lon="-104.8979502292744570"/>
<node visible="true" id="-13" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8547844487300154" lon="-104.8976606941296836"/>
<node visible="true" id="-12" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8548998898172400" lon="-104.8972067032790250"/>
<node visible="true" id="-11" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8550405834777948" lon="-104.8967434472719731"/>
<node visible="true" id="-10" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8550820697380672" lon="-104.8963242007241234"/>
<node visible="true" id="-9" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8550874807879580" lon="-104.8960670937574946"/>
<node visible="true" id="-8" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8550315682923113" lon="-104.9004541260845969"/>
<node visible="true" id="-7" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8551091302814058" lon="-104.9004101166603675"/>
<node visible="true" id="-6" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8550009044449141" lon="-104.9006927028607663"/>
<node visible="true" id="-5" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8545120820724819" lon="-104.9016724896239197"/>
<node visible="true" id="-4" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8543100586733630" lon="-104.9021913364233711"/>
<node visible="true" id="-3" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8542342996822114" lon="-104.9023164156061512"/>
<node visible="true" id="-2" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8551325774893854" lon="-104.8986236865207786"/>
<node visible="true" id="-1" timestamp="1970-01-01T00:00:00Z" version="1" lat="38.8551122842895538" lon="-104.8977898261494488"/>
<way visible="true" id="-4" timestamp="1970-01-01T00:00:00Z" version="1">
<nd ref="-35"/>
<nd ref="-34"/>
<nd ref="-33"/>
<nd ref="-30"/>
<tag k="error:circular" v="15"/>
<tag k="highway" v="road"/>
<tag k="note" v="2"/>
</way>
<way visible="true" id="-3" timestamp="1970-01-01T00:00:00Z" version="1">
<nd ref="-3"/>
<nd ref="-4"/>
<nd ref="-5"/>
<nd ref="-6"/>
<nd ref="-7"/>
<nd ref="-32"/>
<nd ref="-31"/>
<nd ref="-30"/>
<nd ref="-36"/>
<nd ref="-29"/>
<nd ref="-28"/>
<nd ref="-27"/>
<nd ref="-26"/>
<nd ref="-25"/>
<nd ref="-24"/>
<nd ref="-23"/>
<nd ref="-22"/>
<nd ref="-21"/>
<nd ref="-20"/>
<nd ref="-19"/>
<nd ref="-18"/>
<nd ref="-17"/>
<nd ref="-16"/>
<nd ref="-15"/>
<nd ref="-14"/>
<nd ref="-13"/>
<nd ref="-12"/>
<nd ref="-11"/>
<nd ref="-10"/>
<nd ref="-9"/>
<tag k="error:circular" v="15"/>
<tag k="highway" v="road"/>
<tag k="note" v="0"/>
</way>
<way visible="true" id="-2" timestamp="1970-01-01T00:00:00Z" version="1">
<nd ref="-33"/>
<nd ref="-8"/>
<nd ref="-7"/>
<tag k="error:circular" v="15"/>
<tag k="highway" v="road"/>
<tag k="note" v="3"/>
</way>
<way visible="true" id="-1" timestamp="1970-01-01T00:00:00Z" version="1">
<nd ref="-32"/>
<nd ref="-2"/>
<nd ref="-1"/>
<tag k="error:circular" v="15"/>
<tag k="highway" v="road"/>
<tag k="note" v="1"/>
</way>
</osm>
Loading

0 comments on commit 0fa9dfa

Please sign in to comment.