diff --git a/src/lib/marble/geodata/data/GeoDataLineString.h b/src/lib/marble/geodata/data/GeoDataLineString.h --- a/src/lib/marble/geodata/data/GeoDataLineString.h +++ b/src/lib/marble/geodata/data/GeoDataLineString.h @@ -136,6 +136,10 @@ */ void setTessellationFlags( TessellationFlags f ); +/*! + \brief Reverses the LineString. +*/ + void reverse(); /*! \brief Returns the smallest latLonAltBox that contains the LineString. diff --git a/src/lib/marble/geodata/data/GeoDataLineString.cpp b/src/lib/marble/geodata/data/GeoDataLineString.cpp --- a/src/lib/marble/geodata/data/GeoDataLineString.cpp +++ b/src/lib/marble/geodata/data/GeoDataLineString.cpp @@ -522,6 +522,17 @@ p()->m_tessellationFlags = f; } +void GeoDataLineString::reverse() +{ + GeoDataGeometry::detach(); + GeoDataLineStringPrivate* d = p(); + delete d->m_rangeCorrected; + d->m_rangeCorrected = 0; + d->m_dirtyRange = true; + d->m_dirtyBox = true; + std::reverse(begin(), end()); +} + GeoDataLineString GeoDataLineString::toNormalized() const { GeoDataLineString normalizedLineString; diff --git a/tools/osm-simplify/BaseFilter.h b/tools/osm-simplify/BaseFilter.h --- a/tools/osm-simplify/BaseFilter.h +++ b/tools/osm-simplify/BaseFilter.h @@ -28,6 +28,9 @@ virtual void process() = 0; + QList::const_iterator objectsBegin() const; + QList::const_iterator objectsEnd() const; + protected: GeoDataDocument* m_document; QList m_objects; diff --git a/tools/osm-simplify/BaseFilter.cpp b/tools/osm-simplify/BaseFilter.cpp --- a/tools/osm-simplify/BaseFilter.cpp +++ b/tools/osm-simplify/BaseFilter.cpp @@ -29,3 +29,13 @@ { } + +QList::const_iterator BaseFilter::objectsBegin() const +{ + return m_objects.begin(); +} + +QList::const_iterator BaseFilter::objectsEnd() const +{ + return m_objects.end(); +} diff --git a/tools/osm-simplify/CMakeLists.txt b/tools/osm-simplify/CMakeLists.txt --- a/tools/osm-simplify/CMakeLists.txt +++ b/tools/osm-simplify/CMakeLists.txt @@ -27,6 +27,9 @@ LineStringProcessor.cpp TinyPlanetProcessor.cpp NodeReducer.cpp + TagsFilter.cpp + WayConcatenator.cpp +WayChunk.cpp ) add_definitions( -DMAKE_MARBLE_LIB ) diff --git a/tools/osm-simplify/TagsFilter.h b/tools/osm-simplify/TagsFilter.h new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/TagsFilter.h @@ -0,0 +1,37 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2016 Akshat Tandon +// + + +#ifndef MARBLE_TAGSFILTER_H +#define MARBLE_TAGSFILTER_H + +#include "PlacemarkFilter.h" +#include +#include + + +namespace Marble{ + +class GeoDataDocument; + +class TagsFilter : public PlacemarkFilter +{ +public: + //Filters placemarks which have tags in the hash + TagsFilter(GeoDataDocument* document, const QStringList& tagsList, bool andFlag = false); + virtual void process(); + QList::const_iterator rejectedObjectsBegin() const; + QList::const_iterator rejectedObjectsEnd() const; +private: + QList m_rejectedObjects; +}; + +} +#endif diff --git a/tools/osm-simplify/TagsFilter.cpp b/tools/osm-simplify/TagsFilter.cpp new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/TagsFilter.cpp @@ -0,0 +1,95 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2016 Akshat Tandon +// + +#include +#include + +#include "PlacemarkFilter.h" +#include "TagsFilter.h" +#include "GeoDataObject.h" +#include "GeoDataDocument.h" +#include "OsmPlacemarkData.h" +#include "GeoDataPlacemark.h" + +namespace Marble{ + +TagsFilter::TagsFilter(GeoDataDocument *document, const QStringList &tagsList, bool andFlag ) : PlacemarkFilter(document) +{ + int total=0, tagCount=0; + // qDebug()<<"Entered tagFilter"; + QList previousObjects(m_objects); + m_objects.clear(); + foreach (GeoDataObject *object, previousObjects) { + ++total; + GeoDataPlacemark *placemark = static_cast(object); + bool flag = andFlag; + QStringList::const_iterator itr = tagsList.begin(); + for (; itr != tagsList.end(); ++itr) { + QStringList currentTag = (*itr).split('='); + QString currentKey; + QString currentValue; + if (currentTag.size() != 2) { + qDebug()<< "Invalid tag : "<< currentTag<<" ,rejecting it"<osmData().containsTagKey(currentKey); + } else { + contains = placemark->osmData().containsTag(currentKey, currentValue); + } + if (!contains) { + if (andFlag) { + flag = false; + break; + } + } else { + if (!andFlag) { + flag = true; + break; + } + } + } + if (flag) { + ++tagCount; + // qDebug()<<"Contained tag"; + m_objects.append(object); + // qDebug()<<"ID "<osmData().id(); + } else { + m_rejectedObjects.append(object); + } + + } + // qDebug()<<"Done TagFiltering"; + // qDebug()<<"Total"<::const_iterator TagsFilter::rejectedObjectsBegin() const +{ + return m_rejectedObjects.begin(); +} + +QList::const_iterator TagsFilter::rejectedObjectsEnd() const +{ + return m_rejectedObjects.end(); +} diff --git a/tools/osm-simplify/WayChunk.h b/tools/osm-simplify/WayChunk.h new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/WayChunk.h @@ -0,0 +1,60 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2016 Akshat Tandon +// + +#ifndef MARBLE_WAYCHUNK_H +#define MARBLE_WAYCHUNK_H + +#include + +#include "GeoDataFeature.h" +#include "GeoDataLineString.h" + + +namespace Marble +{ + +class GeoDataPlacemark; + +class WayChunk +{ +public: + WayChunk(GeoDataPlacemark *placemark, qint64 first, qint64 last ); + ~WayChunk(); + void append(GeoDataPlacemark *placemark, qint64 last); + void append(WayChunk *chunk); + void prepend(GeoDataPlacemark *placemark, qint64 first); + + /* + * Creates a new placemark object by concatenating all the linsetrings which exist in the WayChunk + * Caller has the responsibility of deleting the object. + */ + GeoDataPlacemark* merge(); + + qint64 first() const; + qint64 last() const; + void reverse(); + qint64 id() const; + void printIds() const; + int size() const; + bool concatPossible(GeoDataPlacemark *placemark) const; + GeoDataFeature::GeoDataVisualCategory visualCategory() const; + +private: + QList m_wayList; + qint64 m_first; + qint64 m_last; + GeoDataFeature::GeoDataVisualCategory m_visualCategory; + +}; + +} + +#endif + diff --git a/tools/osm-simplify/WayChunk.cpp b/tools/osm-simplify/WayChunk.cpp new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/WayChunk.cpp @@ -0,0 +1,129 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2016 Akshat Tandon +// + +#include +#include +#include + +#include "WayChunk.h" +#include "GeoDataCoordinates.h" +#include "GeoDataFeature.h" +#include "GeoDataPlacemark.h" +#include "GeoDataLineString.h" +#include "OsmPlacemarkData.h" + +namespace Marble +{ + +WayChunk::WayChunk(GeoDataPlacemark *placemark, qint64 first, qint64 last) +{ + m_wayList.append(placemark); + m_first = first; + m_last = last; + m_visualCategory = placemark->visualCategory(); +} + +WayChunk::~WayChunk() +{ + +} + +qint64 WayChunk::first() const +{ + return m_first; +} + +qint64 WayChunk::last() const +{ + return m_last; +} + +void WayChunk::append(GeoDataPlacemark *placemark, qint64 last) +{ + m_wayList.append(placemark); + m_last = last; + +} + +void WayChunk::prepend(GeoDataPlacemark *placemark, qint64 first) +{ + m_wayList.prepend(placemark); + m_first = first; + +} + +void WayChunk::append(WayChunk *chunk) +{ + m_wayList << chunk->m_wayList; + m_last = chunk->last(); +} + +GeoDataPlacemark* WayChunk::merge() +{ + Q_ASSERT(!m_wayList.isEmpty()); + + GeoDataPlacemark *placemark = new GeoDataPlacemark(*(m_wayList.first())); + GeoDataLineString *line = static_cast(placemark->geometry()); + QList::iterator itr = m_wayList.begin(); + QList::iterator itrEnd = m_wayList.end(); + ++itr; + for (; itr != itrEnd; ++itr) { + GeoDataLineString *currentLine = static_cast( (*itr)->geometry() ); + currentLine->remove(0); + (*line) << *currentLine; + } + //qDebug()<<"Merging placemark"; + return placemark; +} + +void WayChunk::reverse() +{ + std::reverse(m_wayList.begin(), m_wayList.end()); + QList::iterator itr = m_wayList.begin(); + for (; itr != m_wayList.end(); ++itr) { + GeoDataPlacemark *placemark = *itr; + GeoDataLineString *line = static_cast(placemark->geometry()); + line->reverse(); + } + qSwap(m_first, m_last); +} + +qint64 WayChunk::id() const +{ + return m_wayList.first()->osmData().id(); +} + +void WayChunk::printIds() const +{ + QList::const_iterator itr = m_wayList.begin(); + qDebug()<<"IDs of placemarks in chunk"; + for (; itr != m_wayList.end(); ++itr) { + qDebug()<<"Id :- "<<(*itr)->osmData().id(); + } +} + +int WayChunk::size() const +{ + return m_wayList.size(); +} + +bool WayChunk::concatPossible(GeoDataPlacemark *placemark) const +{ + GeoDataFeature::GeoDataVisualCategory category = placemark->visualCategory(); + return (category == m_visualCategory); +} + +GeoDataFeature::GeoDataVisualCategory WayChunk::visualCategory() const +{ + return m_visualCategory; +} + + +} diff --git a/tools/osm-simplify/WayConcatenator.h b/tools/osm-simplify/WayConcatenator.h new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/WayConcatenator.h @@ -0,0 +1,45 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2016 Akshat Tandon +// + +#ifndef MARBLE_WAYCONCATENATOR_H +#define MARBLE_WAYCONCATENATOR_H + +#include "PlacemarkFilter.h" +#include "TagsFilter.h" + +namespace Marble +{ +class WayChunk; + +class WayConcatenator : public TagsFilter +{ +public: + WayConcatenator(GeoDataDocument *document, const QStringList &tagsList, bool andFlag = false); + virtual void process(); + ~WayConcatenator(); +private: + QMultiHash m_hash; + QVector m_chunks; + QList m_placemarks; + void createWayChunk(GeoDataPlacemark *placemark, qint64 firstId, qint64 lastId); + WayChunk* getWayChunk(GeoDataPlacemark *placemark, qint64 matchId); + void concatFirst(GeoDataPlacemark *placemark, WayChunk *chunk); + void concatLast(GeoDataPlacemark *placemark, WayChunk *chunk); + void concatBoth(GeoDataPlacemark *placemark, WayChunk *chunk, WayChunk *otherChunk); + void addRejectedPlacemarks(); + void addWayChunks(); + void modifyDocument(); +}; + +} + +#endif + + diff --git a/tools/osm-simplify/WayConcatenator.cpp b/tools/osm-simplify/WayConcatenator.cpp new file mode 100644 --- /dev/null +++ b/tools/osm-simplify/WayConcatenator.cpp @@ -0,0 +1,344 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2016 Akshat Tandon +// + +#include +#include + +#include "GeoDataPlacemark.h" +#include "GeoDataDocument.h" +#include "GeoDataObject.h" +#include "OsmPlacemarkData.h" +#include "StyleBuilder.h" + +#include "WayConcatenator.h" +#include "WayChunk.h" +#include "TagsFilter.h" + +namespace Marble +{ + +WayConcatenator::WayConcatenator(GeoDataDocument *document, const QStringList &tagsList, bool andFlag) : TagsFilter(document, tagsList, andFlag) +{ + // qDebug()<< "Entered WayConcatenator"; +} + +WayConcatenator::~WayConcatenator() +{ + QVector::iterator itr = m_chunks.begin(); + for (; itr != m_chunks.end(); ++itr) { + delete *itr; + } +} + +void WayConcatenator::process() +{ + qint64 count = 0; + qint64 chunkCount = 0; + qint64 newCount = 0; + qint64 placemarkCount = 0; + + // qDebug()<<"** Number of TagFiletered placemarks "<< m_objects.size(); + foreach (GeoDataObject *object, m_objects) { + GeoDataPlacemark *placemark = static_cast(object); + + qDebug()<<" "; + ++placemarkCount; + // qDebug()<<"No."<geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType) { + qDebug()<<"-- Placemark ID : "<osmData().id()<<" visualCategory: "<visualCategory()); + GeoDataLineString *line = static_cast(placemark->geometry()); + qint64 firstId = placemark->osmData().nodeReference(line->first()).id(); + qint64 lastId = placemark->osmData().nodeReference(line->last()).id(); + + bool containsFirst = m_hash.contains(firstId); + bool containsLast = m_hash.contains(lastId); + + if (!containsFirst && !containsLast) { + qDebug()<<"No coords matched, creating a new chunk"; + createWayChunk(placemark, firstId, lastId); + ++count; + ++chunkCount; + } else if (containsFirst && !containsLast) { + qDebug()<<"First coord matched"; + WayChunk *chunk = getWayChunk(placemark, firstId); + if (chunk != nullptr) { + // qDebug()<< "First* Chunk found, concatenating to it"; + concatFirst(placemark, chunk); + } else { + // qDebug()<<""; + qDebug()<< "First* No possible chunk found, creating a new chunk"; + qDebug()<<"FirstId"<::const_iterator itr = rejectedObjectsBegin(); + QList::const_iterator endItr = rejectedObjectsEnd(); + for (; itr != endItr; ++itr) { + GeoDataPlacemark *placemark = static_cast(*itr); + m_placemarks.append(*placemark); + } +} + +void WayConcatenator::addWayChunks() +{ + qint64 totalSize = 0; + QSet chunkSet; + // QList chunkList = m_hash.values(); + // QList::iterator cItr = chunkList.begin(); + // qDebug()<<"* Chunk list size = "<::iterator itr = m_chunks.begin(); + for (; itr != m_chunks.end(); ++itr) { + if (!chunkSet.contains(*itr)) { + chunkSet.insert(*itr); + GeoDataPlacemark* placemark = (*itr)->merge(); + if (placemark) { + m_placemarks.append(*placemark); + totalSize += (*itr)->size(); + qDebug()<<"Chunk:"; + (*itr)->printIds(); + qDebug()<<"Size of this chunk"<<(*itr)->size(); + qDebug()<<"Merged"; + qDebug()<<" "; + delete placemark; + } + } + } + qDebug()<<"*** Total number of ways merged"<clear(); + QList::iterator itr; + itr = m_placemarks.begin(); + for (; itr != m_placemarks.end(); ++itr) { + GeoDataPlacemark *placemark = new GeoDataPlacemark(*itr); + m_document->append(placemark); + } +} + +void WayConcatenator::createWayChunk(GeoDataPlacemark *placemark, qint64 firstId, qint64 lastId) +{ + WayChunk *chunk = new WayChunk(placemark, firstId, lastId); + m_hash.insert(firstId, chunk); + if (firstId != lastId) { + m_hash.insert(lastId, chunk); + } + m_chunks.append(chunk); +} + +WayChunk* WayConcatenator::getWayChunk(GeoDataPlacemark *placemark, qint64 matchId) +{ + qDebug()<<"Searching for a compatible WayChunk"; + qDebug()<<"Visual category for placemark"<visualCategory()); + + QHash::iterator matchItr = m_hash.find(matchId); + while (matchItr != m_hash.end() && matchItr.key() == matchId) { + WayChunk *chunk = matchItr.value(); + qDebug()<<" * Chunk ID: "<id()<<" Visual category for chunk"<visualCategory()); + if (chunk->concatPossible(placemark)) { + qDebug()<<"Match found"; + return chunk; + } + ++matchItr; + } + qDebug()<<"### No Chunk found, returning nullptr"; + return nullptr; +} + +void WayConcatenator::concatFirst(GeoDataPlacemark *placemark, WayChunk *chunk) +{ + qDebug()<<"First coord matched"; + qDebug()<<"Matched with: "; + chunk->printIds(); + + GeoDataLineString *line = static_cast(placemark->geometry()); + qint64 firstId = placemark->osmData().nodeReference(line->first()).id(); + qint64 lastId = placemark->osmData().nodeReference(line->last()).id(); + + if (chunk->first() != chunk->last()) { + int chunksRemoved = m_hash.remove(firstId, chunk); + Q_ASSERT(chunksRemoved == 1); + } + m_hash.insert(lastId, chunk); + + if (firstId == chunk->last()) { + //First node matches with an existing last node + qDebug()<<"Appended chunk"; + chunk->append(placemark, lastId); + } else { + //First node matches with an existing first node + //Reverse the GeoDataLineString of the placemark + line->reverse(); + chunk->prepend(placemark, lastId); + qDebug()<<"Reversed line and then prepended"; + } + +} + +void WayConcatenator::concatLast(GeoDataPlacemark *placemark, WayChunk *chunk) +{ + qDebug()<<"Last coord matched"; + qDebug()<<"Matched with: "; + chunk->printIds(); + + GeoDataLineString *line = static_cast(placemark->geometry()); + qint64 firstId = placemark->osmData().nodeReference(line->first()).id(); + qint64 lastId = placemark->osmData().nodeReference(line->last()).id(); + + if (chunk->first() != chunk->last()) { + int chunksRemoved = m_hash.remove(lastId, chunk); + Q_ASSERT(chunksRemoved == 1); + } + m_hash.insert(firstId, chunk); + + if (lastId == chunk->first()) { + qDebug()<<"Prepended chunk"; + chunk->prepend(placemark, firstId); + } else { + line->reverse(); + chunk->append(placemark, firstId); + qDebug()<<"Reversed line and then appended"; + } + +} + +void WayConcatenator::concatBoth(GeoDataPlacemark *placemark, WayChunk *chunk, WayChunk *otherChunk) +{ + + qDebug()<<" Concat possible"; + qDebug()<<"Inserting in the middle"; + qDebug()<<"Matched first coord with: "; + chunk->printIds(); + qDebug()<<"Matched last coord with"; + otherChunk->printIds(); + + GeoDataLineString *line = static_cast(placemark->geometry()); + qint64 firstId = placemark->osmData().nodeReference(line->first()).id(); + qint64 lastId = placemark->osmData().nodeReference(line->last()).id(); + + int chunksRemoved; + if (chunk->first() != chunk->last()) { + chunksRemoved = m_hash.remove(firstId, chunk); + Q_ASSERT(chunksRemoved == 1); + } + + if (firstId == chunk->first()) { + chunk->reverse(); + } + + chunk->append(placemark, lastId); + + if (lastId == otherChunk->last()) { + qDebug()<<" otherChunk reversed"; + otherChunk->reverse(); + } + chunk->append(otherChunk); + + chunksRemoved = m_hash.remove(otherChunk->first(), otherChunk); + Q_ASSERT(chunksRemoved == 1); + + if (otherChunk->first() != otherChunk->last()) { + chunksRemoved = m_hash.remove(otherChunk->last(), otherChunk); + Q_ASSERT(chunksRemoved == 1); + } + + m_hash.insert(otherChunk->last(), chunk); + + m_chunks.removeOne(otherChunk); + +} + + + +} diff --git a/tools/osm-simplify/main.cpp b/tools/osm-simplify/main.cpp --- a/tools/osm-simplify/main.cpp +++ b/tools/osm-simplify/main.cpp @@ -26,6 +26,7 @@ #include "ShpCoastlineProcessor.h" #include "TinyPlanetProcessor.h" #include "NodeReducer.h" +#include "WayConcatenator.h" using namespace Marble; @@ -133,6 +134,22 @@ }, { + {"t", "tags-filter"}, + QCoreApplication::translate("main", "Tag key-value pairs which are to be be considered"), + QCoreApplication::translate("main", "k1=v1,k2=v2...") + }, + + { + {"and", "tags-and"}, + QCoreApplication::translate("main", "For a feature to be considered for processing it must contain all the specified using tags-filter"), + }, + + { + {"w", "concat-ways"}, + QCoreApplication::translate("main", "Concatenates the ways which are specified using tags-filter"), + }, + + { {"o", "output"}, QCoreApplication::translate("main", "Generates an output .osmfile based on other flags. If the cut-to-tiles flag is set, then this needs to be a directory."), QCoreApplication::translate("main", "output_file.osm") @@ -389,8 +406,37 @@ } } - } else { + } else if(parser.isSet("tags-filter") && parser.isSet("concat-ways")){ + + + //Parses the tags given at command line and makes a Hash of key-value pairs + qDebug()<<" Parsed tf value: "<