diff --git a/generator/borders_generator.cpp b/generator/borders_generator.cpp index 6f844de646..05d14e07bb 100644 --- a/generator/borders_generator.cpp +++ b/generator/borders_generator.cpp @@ -1,173 +1,66 @@ #include "borders_generator.hpp" -#include "osm_xml_parser.hpp" - -#include "../base/std_serialization.hpp" -#include "../base/logging.hpp" #include "../indexer/mercator.hpp" -#include "../coding/file_reader.hpp" -#include "../coding/file_writer.hpp" -#include "../coding/streams_sink.hpp" -#include "../coding/parse_xml.hpp" - -#include "../std/list.hpp" -#include "../std/vector.hpp" +#include "../base/logging.hpp" +#include "../base/string_utils.hpp" +#include "../std/fstream.hpp" +#include "../std/iostream.hpp" +#include "../std/sstream.hpp" namespace osm { - class BordersCreator + bool ReadPolygon(istream & stream, m2::RegionD & region, string const & filename) { - vector & m_borders; - OsmRawData const & m_data; - m2::RegionD m_currentRegion; + string line, name; + double lon, lat; - public: - BordersCreator(vector & outBorders, OsmRawData const & data) - : m_borders(outBorders), m_data(data) + // read ring id, fail if it's empty + getline(stream, name); + if (name.empty() || name == "END") + return false; + + while (stream.good()) { + getline(stream, line); + strings::Trim(line); + + if (line.empty()) + continue; + + if (line == "END") + break; + + istringstream iss(line); + iss >> lon >> lat; + CHECK(!iss.fail(), ("Incorrect data in", filename)); + + region.AddPoint(MercatorBounds::FromLatLon(lat, lon)); } - void CreateFromWays(OsmWays const & ways) - { - for (OsmWays::const_iterator it = ways.begin(); it != ways.end(); ++it) - { - // clear region - m_currentRegion = m2::RegionD(); - it->ForEachPoint(*this); - CHECK(m_currentRegion.IsValid(), ("Invalid region")); - m_borders.push_back(m_currentRegion); - } - } - - void operator()(OsmId nodeId) - { - try - { - OsmNode node = m_data.NodeById(nodeId); - m_currentRegion.AddPoint(MercatorBounds::FromLatLon(node.m_lat, node.m_lon)); - } - catch (OsmRawData::OsmInvalidIdException const & e) - { - LOG(LWARNING, (e.what())); - } - } - }; - - void GenerateBordersFromOsm(string const & tagAndOptValue, - string const & osmFile, - string const & outFile) - { - OsmRawData osmData; - { - FileReader file(osmFile); - ReaderSource source(file); - - OsmXmlParser parser(osmData); - CHECK(ParseXML(source, parser), ("Invalid XML")); - } - - // extract search tag key and value - size_t const delimeterPos = tagAndOptValue.find('='); - string const searchKey = tagAndOptValue.substr(0, delimeterPos); - string searchValue; - if (delimeterPos != string::npos) - searchValue = tagAndOptValue.substr(delimeterPos + 1, string::npos); - - // find country borders relation - OsmIds relationIds; - if (searchValue.empty()) - relationIds = osmData.RelationsByKey(searchKey); - else - relationIds = osmData.RelationsByTag(OsmTag(searchKey, searchValue)); - - CHECK(!relationIds.empty(), ("No relation found with tag", searchKey, searchValue)); - CHECK_EQUAL(relationIds.size(), 1, ("Found more than one relation with tag", - searchKey, searchValue)); - - OsmRelation countryRelation = osmData.RelationById(relationIds[0]); - - // get country name - string countryName; - if (!countryRelation.TagValueByKey("name:en", countryName)) - countryRelation.TagValueByKey("name", countryName); - LOG(LINFO, ("Processing boundaries for country", countryName)); - - // find border ways - OsmIds wayIdsOuterRole = countryRelation.MembersByTypeAndRole("way", "outer"); - OsmIds wayIdsNoRole = countryRelation.MembersByTypeAndRole("way", ""); - // collect all ways - list ways; - for(size_t i = 0; i < wayIdsOuterRole.size(); ++i) - ways.push_back(osmData.WayById(wayIdsOuterRole[i])); - for(size_t i = 0; i < wayIdsNoRole.size(); ++i) - ways.push_back(osmData.WayById(wayIdsNoRole[i])); - CHECK(!ways.empty(), ("No any ways in country border")); - - // merge all collected ways - OsmWays mergedWays; - do - { - OsmId lastMergedWayId = -1; // for debugging - OsmWay merged = ways.front(); - size_t lastSize = ways.size(); - ways.pop_front(); - // repeat until we merge everything - while (lastSize > ways.size()) - { - lastSize = ways.size(); - for (list::iterator it = ways.begin(); it != ways.end(); ++it) - { - if (merged.MergeWith(*it)) - { - lastMergedWayId = it->Id(); - ways.erase(it); - break; - } - } - } - if (!merged.IsClosed()) - { - LOG(LERROR, ("Way merge unsuccessful as borders are not closed. Last merged id:", - lastMergedWayId == -1 ? merged.Id() : lastMergedWayId)); - } - else - { - LOG(LINFO, ("Successfully merged boundaries with points count:", merged.PointsCount())); - mergedWays.push_back(merged); - } - } while (!ways.empty()); - - CHECK(!mergedWays.empty(), ("No borders were generated for country:", countryName)); - - // save generated borders - vector borders; - BordersCreator doCreateBorders(borders, osmData); - doCreateBorders.CreateFromWays(mergedWays); - CHECK_EQUAL(mergedWays.size(), borders.size(), ("Can't generate borders from ways")); - - FileWriter writer(outFile); - stream::SinkWriterStream stream(writer); - stream << borders; - - LOG(LINFO, ("Saved", borders.size(), "border(s) for", countryName)); + // drop inner rings + return name[0] != '!'; } bool LoadBorders(string const & borderFile, vector & outBorders) { - try - { - FileReader file(borderFile); - ReaderSource source(file); - stream::SinkReaderStream > stream(source); - - stream >> outBorders; - CHECK(!outBorders.empty(), ("No borders were loaded from", borderFile)); - } - catch (FileReader::OpenException const &) + ifstream stream(borderFile); + string line; + if (!getline(stream, line).good()) // skip title { + LOG(LERROR, ("Polygon file is empty:", borderFile)); return false; } + + m2::RegionD currentRegion; + while (ReadPolygon(stream, currentRegion, borderFile)) + { + CHECK(currentRegion.IsValid(), ("Invalid region in", borderFile)); + outBorders.push_back(currentRegion); + currentRegion = m2::RegionD(); + } + + CHECK(!outBorders.empty(), ("No borders were loaded from", borderFile)); return true; } } diff --git a/generator/borders_loader.hpp b/generator/borders_loader.hpp index 6b55671b80..962db8efe5 100644 --- a/generator/borders_loader.hpp +++ b/generator/borders_loader.hpp @@ -6,7 +6,7 @@ #include "../std/string.hpp" #define BORDERS_DIR "borders/" -#define BORDERS_EXTENSION ".borders" +#define BORDERS_EXTENSION ".poly" namespace borders {