Welcome to mirror list, hosted at ThFree Co, Russian Federation.

borders_generator.cpp « generator - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0ede044ed07fbbc2d4c6ccb825c5ece2ee0ce62d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#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"

namespace osm
{
  class BordersCreator
  {
    vector<m2::RegionD> & m_borders;
    OsmRawData const & m_data;
    m2::RegionD m_currentRegion;

  public:
    BordersCreator(vector<m2::RegionD> & outBorders, OsmRawData const & data)
      : m_borders(outBorders), m_data(data)
    {
    }

    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(m2::PointD(MercatorBounds::LonToX(node.m_lon),
                                            MercatorBounds::LatToY(node.m_lat)));
      }
      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<FileReader> 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<OsmWay> 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<OsmWay>::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<m2::RegionD> 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<Writer> stream(writer);
    stream << borders;

    LOG(LINFO, ("Saved", borders.size(), "border(s) for", countryName));
  }

  bool LoadBorders(string const & borderFile, vector<m2::RegionD> & outBorders)
  {
    try
    {
      FileReader file(borderFile);
      ReaderSource<FileReader> source(file);
      stream::SinkReaderStream<ReaderSource<FileReader> > stream(source);

      stream >> outBorders;
      CHECK(!outBorders.empty(), ("No borders were loaded from", borderFile));
    }
    catch (FileReader::OpenException const &)
    {
      return false;
    }
    return true;
  }
}