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

feature_builder.hpp « generator - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 58d31d3a94c5eca8760748e3baafeeb93b4c5003 (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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#pragma once

#include "indexer/feature_data.hpp"

#include "coding/file_reader.hpp"
#include "coding/file_writer.hpp"
#include "coding/internal/file_data.hpp"
#include "coding/read_write_utils.hpp"

#include "base/geo_object_id.hpp"
#include "base/stl_helpers.hpp"
#include "base/thread_pool_delayed.hpp"

#include <functional>
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

namespace serial
{
class GeometryCodingParams;
}  // namespace serial

namespace feature
{
class FeatureBuilder
{
public:
  using PointSeq = std::vector<m2::PointD>;
  using Geometry = std::list<PointSeq>;
  using Buffer = std::vector<char>;
  using Offsets = std::vector<uint32_t>;

  struct SupportingData
  {
    Offsets m_ptsOffset;
    Offsets m_trgOffset;
    uint8_t m_ptsMask = 0;
    uint8_t m_trgMask = 0;
    uint32_t m_ptsSimpMask = 0;
    PointSeq m_innerPts;
    PointSeq m_innerTrg;
    Buffer m_buffer;
  };

  FeatureBuilder();
  // Checks for equality. The error of coordinates is allowed.
  bool operator==(FeatureBuilder const & fb) const;
  // Checks for equality. The error of coordinates isn't allowed. Binary equality check of
  // coordinates is used.
  bool IsExactEq(FeatureBuilder const & fb) const;

  bool IsValid() const;

  // To work with geometry.
  void AddPoint(m2::PointD const & p);
  void SetHoles(Geometry const & holes);
  void AddPolygon(std::vector<m2::PointD> & poly);
  void ResetGeometry();
  m2::RectD const & GetLimitRect() const { return m_limitRect; }
  Geometry const & GetGeometry() const { return m_polygons; }
  PointSeq const & GetOuterGeometry() const { return m_polygons.front(); }
  GeomType GetGeomType() const { return m_params.GetGeomType(); }
  bool IsGeometryClosed() const;
  m2::PointD GetGeometryCenter() const;
  m2::PointD GetKeyPoint() const;
  size_t GetPointsCount() const;
  size_t GetPolygonsCount() const { return m_polygons.size(); }
  size_t GetTypesCount() const { return m_params.m_types.size(); }

  template <class ToDo>
  void ForEachPoint(ToDo && toDo) const
  {
    if (IsPoint())
    {
      toDo(m_center);
    }
    else
    {
      for (auto const & points : m_polygons)
      {
        for (auto const & pt : points)
          toDo(pt);
      }
    }
  }

  template <class ToDo>
  bool ForAnyPoint(ToDo && toDo) const
  {
    if (IsPoint())
      return toDo(m_center);

    for (auto const & points : m_polygons)
    {
      if (base::AnyOf(points, std::forward<ToDo>(toDo)))
        return true;
    }

    return false;
  }

  template <class ToDo>
  void ForEachPolygon(ToDo && toDo) const
  {
    for (auto const & points : m_polygons)
      toDo(points);
  }

  // To work with geometry type.
  void SetCenter(m2::PointD const & p);
  void SetLinear(bool reverseGeometry = false);
  void SetArea() { m_params.SetGeomType(GeomType::Area); }
  bool IsPoint() const { return GetGeomType() == GeomType::Point; }
  bool IsLine() const { return GetGeomType() == GeomType::Line; }
  bool IsArea() const { return GetGeomType() == GeomType::Area; }

  // To work with types.
  void SetType(uint32_t type) { m_params.SetType(type); }
  void AddType(uint32_t type) { m_params.AddType(type); }
  bool PopExactType(uint32_t type) { return m_params.PopExactType(type); }

  template <class Fn>
  bool RemoveTypesIf(Fn && fn)
  {
    base::EraseIf(m_params.m_types, std::forward<Fn>(fn));
    return m_params.m_types.empty();
  }

  bool HasType(uint32_t t) const { return m_params.IsTypeExist(t); }
  bool HasType(uint32_t t, uint8_t level) const { return m_params.IsTypeExist(t, level); }
  uint32_t FindType(uint32_t comp, uint8_t level) const { return m_params.FindType(comp, level); }
  FeatureParams::Types const & GetTypes() const { return m_params.m_types; }

  // To work with additional information.
  void SetRank(uint8_t rank);
  bool AddName(std::string const & lang, std::string const & name);
  void SetParams(FeatureBuilderParams const & params) { m_params.SetParams(params); }

  FeatureBuilderParams const & GetParams() const { return m_params; }
  FeatureBuilderParams & GetParams() { return m_params; }
  std::string GetName(int8_t lang = StringUtf8Multilang::kDefaultCode) const;
  StringUtf8Multilang const & GetMultilangName() const { return m_params.name; }
  uint8_t GetRank() const { return m_params.rank; }
  AddressData const & GetAddressData() const { return m_params.GetAddressData(); }

  Metadata const & GetMetadata() const { return m_params.GetMetadata(); }
  Metadata & GetMetadata() { return m_params.GetMetadata(); }

  // To work with types and names based on drawing.
  // Check classificator types for their compatibility with feature geometry type.
  // Need to call when using any classificator types manipulating.
  // Return false If no any valid types.
  bool RemoveInvalidTypes();
  // Clear name if it's not visible in scale range [minS, maxS].
  void RemoveNameIfInvisible(int minS = 0, int maxS = 1000);
  void RemoveUselessNames();
  int GetMinFeatureDrawScale() const;
  bool IsDrawableInRange(int lowScale, int highScale) const;

  // Serialization.
  bool PreSerialize();
  bool PreSerializeAndRemoveUselessNamesForIntermediate();
  void SerializeForIntermediate(Buffer & data) const;
  void SerializeBorderForIntermediate(serial::GeometryCodingParams const & params,
                                      Buffer & data) const;
  void DeserializeFromIntermediate(Buffer & data);

  // These methods use geometry without loss of accuracy.
  void SerializeAccuratelyForIntermediate(Buffer & data) const;
  void DeserializeAccuratelyFromIntermediate(Buffer & data);

  bool PreSerializeAndRemoveUselessNamesForMwm(SupportingData const & data);
  void SerializeLocalityObject(serial::GeometryCodingParams const & params,
                               SupportingData & data) const;
  void SerializeForMwm(SupportingData & data, serial::GeometryCodingParams const & params) const;

  // Get common parameters of feature.
  TypesHolder GetTypesHolder() const;

  // To work with osm ids.
  void AddOsmId(base::GeoObjectId id);
  void SetOsmId(base::GeoObjectId id);
  base::GeoObjectId GetFirstOsmId() const;
  base::GeoObjectId GetLastOsmId() const;
  // Returns an id of the most general element: node's one if there is no area or relation,
  // area's one if there is no relation, and relation id otherwise.
  base::GeoObjectId GetMostGenericOsmId() const;
  bool HasOsmId(base::GeoObjectId const & id) const;
  bool HasOsmIds() const { return !m_osmIds.empty(); }
  std::vector<base::GeoObjectId> const & GetOsmIds() const { return m_osmIds; }

  // To work with coasts.
  void SetCoastCell(int64_t iCell) { m_coastCell = iCell; }
  bool IsCoastCell() const { return (m_coastCell != -1); }

protected:
  // Can be one of the following:
  // - point in point-feature
  // - origin point of text [future] in line-feature
  // - origin point of text or symbol in area-feature
  m2::PointD m_center;  // Check  HEADER_HAS_POINT
  // List of geometry polygons.
  Geometry m_polygons;  // Check HEADER_IS_AREA
  m2::RectD m_limitRect;
  std::vector<base::GeoObjectId> m_osmIds;
  FeatureBuilderParams m_params;
  /// Not used in GEOM_POINTs
  int64_t m_coastCell;
};

std::string DebugPrint(FeatureBuilder const & fb);

// SerializationPolicy serialization and deserialization.
namespace serialization_policy
{
enum class SerializationVersion : uint32_t
{
  Undefined,
  MinSize,
  MaxAccuracy
};

using TypeSerializationVersion = typename std::underlying_type<SerializationVersion>::type;

struct MinSize
{
  auto static const kSerializationVersion =
      static_cast<TypeSerializationVersion>(SerializationVersion::MinSize);

  static void Serialize(FeatureBuilder const & fb, FeatureBuilder::Buffer & data)
  {
    fb.SerializeForIntermediate(data);
  }

  static void Deserialize(FeatureBuilder & fb, FeatureBuilder::Buffer & data)
  {
    fb.DeserializeFromIntermediate(data);
  }
};

struct MaxAccuracy
{
  auto static const kSerializationVersion =
      static_cast<TypeSerializationVersion>(SerializationVersion::MinSize);

  static void Serialize(FeatureBuilder const & fb, FeatureBuilder::Buffer & data)
  {
    fb.SerializeAccuratelyForIntermediate(data);
  }

  static void Deserialize(FeatureBuilder & fb, FeatureBuilder::Buffer & data)
  {
    fb.DeserializeAccuratelyFromIntermediate(data);
  }
};
}  // namespace serialization_policy

// TODO(maksimandrianov): I would like to support the verification of serialization versions,
// but this requires reworking of FeatureCollector class and its derived classes. It is in future
// plans

// template <class SerializationPolicy, class Source>
// void TryReadAndCheckVersion(Source & src)
//{
//  if (src.Size() - src.Pos() >= sizeof(serialization_policy::TypeSerializationVersion))
//  {
//    auto const type = ReadVarUint<serialization_policy::TypeSerializationVersion>(src);
//    CHECK_EQUAL(type, SerializationPolicy::kSerializationVersion, ());
//  }
//  else
//  {
//    LOG(LWARNING, ("Unable to read file version."))
//  }
//}

// Read feature from feature source.
template <class SerializationPolicy = serialization_policy::MinSize, class Source>
void ReadFromSourceRawFormat(Source & src, FeatureBuilder & fb)
{
  uint32_t const sz = ReadVarUint<uint32_t>(src);
  typename FeatureBuilder::Buffer buffer(sz);
  src.Read(&buffer[0], sz);
  SerializationPolicy::Deserialize(fb, buffer);
}

// Process features in features file.
template <class SerializationPolicy = serialization_policy::MinSize, class ToDo>
void ForEachFeatureRawFormat(std::string const & filename, ToDo && toDo)
{
  FileReader reader(filename);
  ReaderSource<FileReader> src(reader);
  // TryReadAndCheckVersion<SerializationPolicy>(src);
  auto const fileSize = reader.Size();
  auto currPos = src.Pos();
  // read features one by one
  while (currPos < fileSize)
  {
    FeatureBuilder fb;
    ReadFromSourceRawFormat<SerializationPolicy>(src, fb);
    toDo(fb, currPos);
    currPos = src.Pos();
  }
}

template <class SerializationPolicy = serialization_policy::MinSize>
std::vector<FeatureBuilder> ReadAllDatRawFormat(std::string const & fileName)
{
  std::vector<FeatureBuilder> fbs;
  ForEachFeatureRawFormat<SerializationPolicy>(fileName, [&](auto && fb, auto const &) {
    fbs.emplace_back(std::move(fb));
  });
  return fbs;
}

template <class SerializationPolicy = serialization_policy::MinSize, class Writer = FileWriter>
class FeatureBuilderWriter
{
public:
  explicit FeatureBuilderWriter(std::string const & filename,
                                bool mangleName = false,
                                FileWriter::Op op = FileWriter::Op::OP_WRITE_TRUNCATE)
    : m_filename(filename)
    , m_mangleName(mangleName)
    , m_writer(std::make_unique<Writer>(m_mangleName ? m_filename  + "_" : m_filename, op))
  {
    // TODO(maksimandrianov): I would like to support the verification of serialization versions,
    // but this requires reworking of FeatureCollector class and its derived classes. It is in
    // future plans WriteVarUint(m_writer,
    // static_cast<serialization_policy::TypeSerializationVersion>(SerializationPolicy::kSerializationVersion));
  }

  explicit FeatureBuilderWriter(std::string const & filename,
                                FileWriter::Op op)
    : FeatureBuilderWriter(filename, false /* mangleName */, op)
  {
  }

  ~FeatureBuilderWriter()
  {
    if (m_mangleName)
    {
      // Flush and close.
      auto const currentFilename = m_writer->GetName();
      m_writer.reset();
      CHECK(base::RenameFileX(currentFilename, m_filename), (currentFilename, m_filename));
    }
  }

  void Write(FeatureBuilder const & fb)
  {
    Write(*m_writer, fb);
  }

  template <typename Sink>
  static void Write(Sink & writer, FeatureBuilder const & fb)
  {
    FeatureBuilder::Buffer buffer;
    SerializationPolicy::Serialize(fb, buffer);
    WriteVarUint(writer, static_cast<uint32_t>(buffer.size()));
    writer.Write(buffer.data(), buffer.size() * sizeof(FeatureBuilder::Buffer::value_type));
  }

private:
  std::string m_filename;
  bool m_mangleName = false;
  std::unique_ptr<Writer> m_writer;
};
}  // namespace feature