contrek 1.3.5 → 1.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +5 -2
  5. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +13 -17
  6. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +78 -33
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +31 -101
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.h +2 -1
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +1 -2
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/OptionValue.h +91 -0
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Options.h +123 -0
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +4 -3
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +14 -6
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.cpp +1 -1
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.h +2 -1
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +19 -11
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +5 -4
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h +4 -5
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.cpp +1 -1
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.h +1 -1
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp +28 -2
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.h +3 -1
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +12 -0
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +2 -0
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp +16 -6
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h +2 -2
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/SvgStreamingMerger.h +1 -1
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +1 -13
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp +1 -1
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.h +1 -1
  31. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +66 -24
  32. data/lib/contrek/finder/concurrent/finder.rb +2 -2
  33. data/lib/contrek/finder/concurrent/geo_json_streaming_merger.rb +3 -3
  34. data/lib/contrek/finder/concurrent/merger.rb +17 -1
  35. data/lib/contrek/finder/concurrent/shape.rb +6 -0
  36. data/lib/contrek/finder/concurrent/streaming_merger.rb +8 -4
  37. data/lib/contrek/finder/concurrent/tile.rb +2 -7
  38. data/lib/contrek/finder/node_cluster.rb +1 -1
  39. data/lib/contrek/finder/polygon_finder.rb +2 -0
  40. data/lib/contrek/reducers/visvalingam_reducer.rb +2 -1
  41. data/lib/contrek/version.rb +1 -1
  42. metadata +4 -3
  43. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/optionparser.h +0 -2858
@@ -0,0 +1,123 @@
1
+ /*
2
+ * Options.cpp
3
+ *
4
+ * Copyright (c) 2025-2026 Emanuele Cesaroni
5
+ *
6
+ * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
+ * See the LICENSE file in this directory for the full license text.
8
+ */
9
+
10
+ #pragma once
11
+ #include "OptionValue.h"
12
+ #include <initializer_list>
13
+ #include <map>
14
+ #include <memory>
15
+ #include <stdexcept>
16
+ #include <string>
17
+ #include <utility>
18
+ #include <sstream>
19
+
20
+
21
+ class Options {
22
+ public:
23
+ using Map = std::map<std::string, OptionValue>;
24
+ using value_type = Map::value_type;
25
+ using iterator = Map::iterator;
26
+ using const_iterator = Map::const_iterator;
27
+
28
+ Options() = default;
29
+
30
+ Options(std::initializer_list<value_type> values) : values_(values) {}
31
+
32
+ OptionValue& operator[](const std::string& key) { return values_[key]; }
33
+ OptionValue& operator[](std::string&& key) { return values_[std::move(key)]; }
34
+ OptionValue& at(const std::string& key) { return values_.at(key); }
35
+ const OptionValue& at(const std::string& key) const { return values_.at(key); }
36
+ iterator find(const std::string& key) { return values_.find(key); }
37
+ const_iterator find(const std::string& key) const { return values_.find(key); }
38
+ iterator begin() { return values_.begin(); }
39
+ const_iterator begin() const { return values_.begin(); }
40
+ const_iterator cbegin() const { return values_.cbegin(); }
41
+ iterator end() { return values_.end(); }
42
+ const_iterator end() const { return values_.end(); }
43
+ const_iterator cend() const { return values_.cend(); }
44
+ bool contains(const std::string& key) const { return values_.find(key) != values_.end();}
45
+ bool empty() const {return values_.empty();}
46
+ std::size_t size() const {return values_.size();}
47
+ void clear() { values_.clear();}
48
+ std::size_t erase(const std::string& key) { return values_.erase(key);}
49
+
50
+
51
+ std::string to_string(int indent = 0) const {
52
+ std::ostringstream out;
53
+ std::string pad(indent, ' ');
54
+ out << "{";
55
+ bool first = true;
56
+ for (const auto& [key, value] : values_) {
57
+ if (!first) {
58
+ out << ",";
59
+ }
60
+ out << "\n" << pad << " " << key << ": ";
61
+ if (value.is_bool()) {
62
+ out << (value.as_bool() ? "true" : "false");
63
+ } else if (value.is_integer()) {
64
+ out << value.as_integer();
65
+ } else if (value.is_double()) {
66
+ out << value.as_double();
67
+ } else if (value.is_string()) {
68
+ out << "\"" << value.as_string() << "\"";
69
+ } else if (value.is_identifier()) {
70
+ out << ":" << value.as_identifier().value;
71
+ } else if (value.is_options()) {
72
+ out << value.as_options().to_string(indent + 2);
73
+ } else {
74
+ out << "nil";
75
+ }
76
+ first = false;
77
+ }
78
+ if (!values_.empty()) {
79
+ out << "\n" << pad;
80
+ }
81
+ out << "}";
82
+ return out.str();
83
+ }
84
+
85
+ template <typename T>
86
+ T get(const std::string& key, T default_value) const {
87
+ const auto it = values_.find(key);
88
+ if (it == values_.end()) {
89
+ return default_value;
90
+ }
91
+ const T* value = it->second.get_if<T>();
92
+ return value != nullptr ? *value : default_value;
93
+ }
94
+
95
+ const Options* get_options(const std::string& key) const {
96
+ const auto it = values_.find(key);
97
+ if (it == values_.end()) {
98
+ return nullptr;
99
+ }
100
+ if (!it->second.is_options()) {
101
+ return nullptr;
102
+ }
103
+ return &it->second.as_options();
104
+ }
105
+
106
+ const Map& values() const {
107
+ return values_;
108
+ }
109
+
110
+ private:
111
+ Map values_;
112
+ };
113
+
114
+ inline OptionValue::OptionValue(const Options& value) : value_(std::make_shared<Options>(value)) {}
115
+ inline OptionValue::OptionValue(Options&& value) : value_(std::make_shared<Options>(std::move(value))) {}
116
+
117
+ inline const Options& OptionValue::as_options() const {
118
+ const auto& options = std::get<NestedOptions>(value_);
119
+ if (!options) {
120
+ throw std::runtime_error("OptionValue contains null Options");
121
+ }
122
+ return *options;
123
+ }
@@ -22,7 +22,6 @@
22
22
  #include "../matchers/Matcher.h"
23
23
  #include "../matchers/RGBMatcher.h"
24
24
  #include "../matchers/RGBNotMatcher.h"
25
- #include "optionparser.h"
26
25
  #include "NodeCluster.h"
27
26
  #include "Node.h"
28
27
  #include "FinderUtils.h"
@@ -30,15 +29,16 @@
30
29
  PolygonFinder::PolygonFinder(Bitmap *bitmap,
31
30
  Matcher *matcher,
32
31
  Bitmap *,
33
- std::vector<std::string> *options,
32
+ const Options& options,
34
33
  int start_x,
35
34
  int end_x)
36
35
  : start_x(start_x),
37
36
  end_x(end_x == -1 ? bitmap->w() : end_x),
37
+ incoming_options_(options),
38
38
  source_bitmap(bitmap),
39
39
  matcher(matcher)
40
40
  { this->rgb_matcher = dynamic_cast<RGBMatcher*>(matcher);
41
- if (options != nullptr) FinderUtils::sanitize_options(this->options, options);
41
+ FinderUtils::sanitize_options(this->options, options);
42
42
 
43
43
  this->node_cluster = new NodeCluster(source_bitmap->h(), source_bitmap->w(), &this->options);
44
44
 
@@ -109,6 +109,7 @@ ProcessResult* PolygonFinder::process_info() {
109
109
  pr->height = this->source_bitmap->h();
110
110
  pr->has_bounds = this->node_cluster->options->bounds;
111
111
  pr->versus = this->options.versus;
112
+ pr->options = this->incoming_options_;
112
113
 
113
114
  if (this->node_cluster->options->named_sequences && typeid(*this->source_bitmap) == typeid(Bitmap))
114
115
  { std::string sequence;
@@ -27,6 +27,7 @@
27
27
  #include "Node.h"
28
28
  #include "Polygon.h"
29
29
  #include "Node.h"
30
+ #include "Options.h"
30
31
  #include "../CpuTimer.h"
31
32
 
32
33
  class Bitmap;
@@ -50,6 +51,7 @@ struct pf_Options {
50
51
  bool compress_raster = false;
51
52
  bool compress_douglas_peucker = false;
52
53
  bool named_sequences = false;
54
+ bool unsafe_mode = false;
53
55
  bool bounds = false;
54
56
  int connectivity_offset = 0;
55
57
  float compress_visvalingam_tolerance = 10.0;
@@ -57,6 +59,9 @@ struct pf_Options {
57
59
  std::string get_alpha_versus() {
58
60
  return(versus == Node::A ? "a" : "o");
59
61
  }
62
+ bool any_compression() const {
63
+ return(compress_linear || compress_uniq || compress_raster || compress_douglas_peucker || compress_visvalingam);
64
+ }
60
65
  };
61
66
 
62
67
  struct ProcessResult {
@@ -68,21 +73,23 @@ struct ProcessResult {
68
73
  std::list<Polygon> polygons;
69
74
  std::string named_sequence;
70
75
  std::vector<std::pair<int, int>> treemap;
76
+ Options options;
71
77
 
72
78
  void draw_on_bitmap(RawBitmap& canvas) const;
73
79
 
74
80
  void print_polygons() {
75
81
  int counter = 0;
76
82
  for (const auto& polygon : polygons) {
77
- std::cout << counter << " - " << "outer" << "\n";
83
+ std::cout << "Polygon " << counter << std::endl;
84
+ std::cout << "outer=";
78
85
  for (const Point& p : polygon.outer) std::cout << p.toString();
79
- bool first = true;
86
+ std::cout << std::endl;
80
87
  for (const auto& seq : polygon.inner) {
81
- if (!first) std::cout << "\n";
82
- first = false;
88
+ std::cout << "inner=";
83
89
  for (const Point& p : seq) std::cout << p.toString();
90
+ std::cout << std::endl;
84
91
  }
85
- std::cout << "\n" << polygon.bounds.to_string() <<"\n";
92
+ std::cout << polygon.bounds.to_string() << std::endl;
86
93
  counter++;
87
94
  }
88
95
  }
@@ -150,6 +157,7 @@ class PolygonFinder {
150
157
  protected:
151
158
  int start_x;
152
159
  int end_x;
160
+ Options incoming_options_;
153
161
 
154
162
  private:
155
163
  Bitmap *source_bitmap;
@@ -262,7 +270,7 @@ class PolygonFinder {
262
270
  PolygonFinder(Bitmap *bitmap,
263
271
  Matcher *matcher,
264
272
  Bitmap *test_bitmap,
265
- std::vector<std::string> *options = nullptr,
273
+ const Options& options,
266
274
  int start_x = 0,
267
275
  int end_x = -1);
268
276
  ProcessResult* process_info();
@@ -10,6 +10,6 @@
10
10
  #include <vector>
11
11
  #include "ClippedPolygonFinder.h"
12
12
 
13
- ClippedPolygonFinder::ClippedPolygonFinder(Bitmap *bitmap, Matcher *matcher, int bitmap_start_x, int bitmap_end_x, std::vector<std::string> *options)
13
+ ClippedPolygonFinder::ClippedPolygonFinder(Bitmap *bitmap, Matcher *matcher, int bitmap_start_x, int bitmap_end_x, const Options& options)
14
14
  : PolygonFinder(bitmap, matcher, nullptr, options, bitmap_start_x, bitmap_end_x) {
15
15
  }
@@ -11,8 +11,9 @@
11
11
  #include <string>
12
12
  #include <vector>
13
13
  #include "../PolygonFinder.h"
14
+ #include "../Options.h"
14
15
 
15
16
  class ClippedPolygonFinder : public PolygonFinder {
16
17
  public:
17
- ClippedPolygonFinder(Bitmap *bitmap, Matcher *matcher, int bm_start_x, int bm_end_x, std::vector<std::string>* options = nullptr);
18
+ ClippedPolygonFinder(Bitmap *bitmap, Matcher *matcher, int bm_start_x, int bm_end_x, const Options& options);
18
19
  };
@@ -14,7 +14,6 @@
14
14
  #include "../../bitmaps/Bitmap.h"
15
15
  #include "../../matchers/Matcher.h"
16
16
  #include "../../matchers/RGBMatcher.h"
17
- #include "../optionparser.h"
18
17
  #include "../FinderUtils.h"
19
18
  #include "ClippedPolygonFinder.h"
20
19
  #include "Tile.h"
@@ -22,15 +21,15 @@
22
21
  #include "Cluster.h"
23
22
  #include "FakeCluster.h"
24
23
 
25
- Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vector<std::string> *options)
24
+ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, const Options& options)
26
25
  : Poolable(number_of_threads),
27
26
  bitmap(bitmap),
28
27
  matcher(matcher),
29
- input_options(*options),
28
+ input_options(options),
30
29
  maximum_width_(bitmap->w()),
31
30
  height(bitmap->h())
32
31
  { cpu_timer.start();
33
- if (options != nullptr) FinderUtils::sanitize_options(this->options_, options);
32
+ FinderUtils::sanitize_options(this->options_, options);
34
33
 
35
34
  double cw = static_cast<double>(this->maximum_width_) / this->options_.number_of_tiles;
36
35
  if (cw < 1.0) {
@@ -41,9 +40,17 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
41
40
  { int tile_end_x = static_cast<int>(cw * (tile_index + 1));
42
41
  TilePayload p { tile_index, x, tile_end_x };
43
42
  enqueue(p, [this](const TilePayload& payload) {
44
- std::vector<std::string> base_arguments = {"--bounds", "--versus=" + this->options_.get_alpha_versus()};
45
- if (this->options_.connectivity_offset == 1) base_arguments.push_back("--connectivity=8");
46
- if (this->options_.treemap) base_arguments.push_back("--treemap");
43
+ Options base_arguments = {
44
+ {"bounds", true},
45
+ {"versus", Identifier{this->options_.get_alpha_versus()}},
46
+ };
47
+ if (this->options_.connectivity_offset == 1) {
48
+ base_arguments["connectivity"] = 8;
49
+ }
50
+ if (this->options_.treemap) {
51
+ base_arguments["treemap"] = true;
52
+ }
53
+
47
54
  CpuTimer t;
48
55
  t.start();
49
56
  auto* finder = new ClippedPolygonFinder(
@@ -51,7 +58,7 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
51
58
  this->matcher,
52
59
  payload.tile_start_x,
53
60
  payload.tile_end_x,
54
- &base_arguments);
61
+ base_arguments);
55
62
  {
56
63
  std::lock_guard<std::mutex> lock(finders_mutex);
57
64
  finders.push(finder);
@@ -69,9 +76,9 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
69
76
  reports["init"] = cpu_timer.stop();
70
77
  }
71
78
 
72
- Finder::Finder(int number_of_threads, std::vector<std::string> *options)
73
- : Poolable(number_of_threads), bitmap(nullptr), matcher(nullptr), input_options(*options), maximum_width_(0) {
74
- if (options != nullptr) FinderUtils::sanitize_options(this->options_, options);
79
+ Finder::Finder(int number_of_threads, const Options& options)
80
+ : Poolable(number_of_threads), bitmap(nullptr), matcher(nullptr), input_options(options), maximum_width_(0) {
81
+ FinderUtils::sanitize_options(this->options_, options);
75
82
  reports["init"] = 0;
76
83
  }
77
84
 
@@ -140,6 +147,7 @@ ProcessResult* Finder::process_info() {
140
147
  pr->height = this->height;
141
148
  pr->has_bounds = this->options_.bounds;
142
149
  pr->versus = this->options_.versus;
150
+ pr->options = this->input_options;
143
151
  FakeCluster fake_cluster(pr->polygons, this->options_);
144
152
  cpu_timer.start();
145
153
  fake_cluster.compress_coords(pr->polygons, this->options_);
@@ -15,6 +15,7 @@
15
15
  #include <vector>
16
16
  #include "Poolable.h"
17
17
  #include "../PolygonFinder.h"
18
+ #include "../Options.h"
18
19
  #include "Queue.h"
19
20
  #include "Tile.h"
20
21
 
@@ -34,7 +35,7 @@ class Finder : public Poolable {
34
35
  Bitmap *bitmap;
35
36
  Matcher *matcher;
36
37
  pf_Options options_;
37
- std::vector<std::string> input_options;
38
+ Options input_options;
38
39
  std::queue<ClippedPolygonFinder*> finders;
39
40
  std::mutex finders_mutex;
40
41
  std::map<std::string, double> reports;
@@ -49,13 +50,13 @@ class Finder : public Poolable {
49
50
 
50
51
  public:
51
52
  using Poolable::Poolable;
52
- Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vector<std::string> *options);
53
- Finder(int number_of_threads, std::vector<std::string> *options);
53
+ Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, const Options& options);
54
+ Finder(int number_of_threads, const Options& options);
54
55
  virtual ~Finder();
55
56
  int maximum_width() const { return maximum_width_; }
56
57
  virtual ProcessResult* process_info();
57
58
  const pf_Options& options() const { return options_; }
58
59
  Queue<Tile*>& tiles() { return tiles_; }
59
60
  virtual bool transpose() const { return false; }
60
- int versus;
61
+ int versus = -1;
61
62
  };
@@ -36,13 +36,13 @@ class GeoJsonStreamingMerger : public StreamingMerger {
36
36
 
37
37
  public:
38
38
  GeoJsonStreamingMerger(int number_of_threads,
39
- std::vector<std::string>* options,
39
+ const Options& options,
40
40
  std::ofstream* stream_to,
41
41
  unsigned int pixel_value)
42
42
  : StreamingMerger(number_of_threads, options, stream_to),
43
43
  target_value(pixel_value) {}
44
44
 
45
- void stream_raw_polygon(const Shape* shape) override {
45
+ void stream_raw_polygon(const Polygon& polygon) override {
46
46
  if (!stream) return;
47
47
  if (!is_first_feature) {
48
48
  *stream << ",";
@@ -51,7 +51,7 @@ class GeoJsonStreamingMerger : public StreamingMerger {
51
51
 
52
52
  *stream << "{\"type\":\"Feature\",\"properties\":{\"PixelVal\":" << target_value
53
53
  << "},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[";
54
- const std::vector<Point>& points = shape->outer_polyline->raw();
54
+ const std::vector<Point>& points = polygon.outer;
55
55
  const size_t points_size = points.size();
56
56
  if (points_size > 0) {
57
57
  for (size_t i = 0; i < points_size; ++i) {
@@ -63,8 +63,7 @@ class GeoJsonStreamingMerger : public StreamingMerger {
63
63
  *stream << "]]";
64
64
  }
65
65
 
66
- for (const auto& inner_polyline : shape->inner_polylines) {
67
- const std::vector<Point>& inner_points = inner_polyline->raw();
66
+ for (const std::vector<Point>& inner_points : polygon.inner) {
68
67
  const size_t inner_size = inner_points.size();
69
68
  if (inner_size > 0) {
70
69
  *stream << ",[";
@@ -12,7 +12,7 @@
12
12
  #include <vector>
13
13
  #include "HorizontalMerger.h"
14
14
 
15
- HorizontalMerger::HorizontalMerger(int number_of_threads, std::vector<std::string> *options)
15
+ HorizontalMerger::HorizontalMerger(int number_of_threads, const Options& options)
16
16
  : Merger(number_of_threads, options) {
17
17
  }
18
18
 
@@ -14,6 +14,6 @@
14
14
 
15
15
  class HorizontalMerger : public Merger {
16
16
  public:
17
- HorizontalMerger(int number_of_threads, std::vector<std::string> *options);
17
+ HorizontalMerger(int number_of_threads, const Options& options);
18
18
  void add_tile(ProcessResult& result) override;
19
19
  };
@@ -12,15 +12,41 @@
12
12
  #include <vector>
13
13
  #include "Merger.h"
14
14
 
15
- Merger::Merger(int number_of_threads, std::vector<std::string> *options)
15
+ Merger::Merger(int number_of_threads, const Options& options)
16
16
  : Finder(number_of_threads, options) {
17
+ if (!this->safe()) {
18
+ std::cerr << "[Contrek WARNING] Processing tile with 'unsafe_mode: true'. "
19
+ << "Incompatible result options might lead to unexpected vector geometry.\n";
20
+ }
21
+ }
22
+
23
+ bool Merger::safe() {
24
+ return(!this->options().unsafe_mode);
17
25
  }
18
26
 
19
27
  void Merger::add_tile(ProcessResult& result)
20
28
  { if (this->height == 0) {
21
29
  this->height = result.height;
30
+ } else {
31
+ if (result.height != this->height && safe()) {
32
+ throw std::invalid_argument("All results must have the same height");
33
+ }
22
34
  }
23
- this->versus = result.versus;
35
+ if (this->versus == -1) {
36
+ this->versus = result.versus;
37
+ } else {
38
+ if (this->versus != result.versus && safe()) {
39
+ throw std::invalid_argument("All results must have the same versus option");
40
+ }
41
+ }
42
+ if (const Options* compress = result.options.get_options("compress")) {
43
+ if (this->safe()) {
44
+ if (compress->contains("visvalingam") || compress->contains("raster") || compress->contains("douglas_peucker"))
45
+ { throw std::invalid_argument("Result with not supported postprocessing compression mode");
46
+ }
47
+ }
48
+ }
49
+
24
50
  int end_x = this->current_x + result.width;
25
51
  Tile* tile = new Tile(this, this->current_x, end_x, std::to_string(tiles_.size()), Benchmarks {0, 0});
26
52
  tile->assign_raw_polygons(result.polygons, result.treemap);
@@ -11,12 +11,14 @@
11
11
  #include <string>
12
12
  #include <vector>
13
13
  #include "Finder.h"
14
+ #include "../Options.h"
14
15
 
15
16
  class Merger : public Finder {
16
17
  public:
17
- Merger(int number_of_threads, std::vector<std::string> *options);
18
+ Merger(int number_of_threads, const Options& options);
18
19
  virtual void add_tile(ProcessResult& result);
19
20
  ProcessResult* process_info() override;
21
+ bool safe();
20
22
 
21
23
  protected:
22
24
  void translate(ProcessResult& result, int offset);
@@ -45,3 +45,15 @@ void Shape::set_parent_shape(Shape* shape) {
45
45
  std::string Shape::name() {
46
46
  return(this->outer_polyline->named());
47
47
  }
48
+
49
+ Polygon Shape::to_raw_polygon(bool bounds) {
50
+ Polygon poly;
51
+ poly.outer = this->outer_polyline->raw();
52
+ if (bounds) {
53
+ this->outer_polyline->fill_bounds(poly.bounds);
54
+ }
55
+ for (auto inner : this->inner_polylines) {
56
+ poly.inner.push_back(inner->raw());
57
+ }
58
+ return(poly);
59
+ }
@@ -13,6 +13,7 @@
13
13
  #include <vector>
14
14
  #include <string>
15
15
  #include "InnerPolyline.h"
16
+ #include "../Polygon.h"
16
17
 
17
18
  class Point;
18
19
  class Polyline;
@@ -31,6 +32,7 @@ class Shape {
31
32
  void set_parent_shape(Shape*);
32
33
  std::string name();
33
34
  void detach_from_pool();
35
+ Polygon to_raw_polygon(bool bounds = false);
34
36
  private:
35
37
  Shape* parent_shape_ = nullptr;
36
38
  ShapePool* shape_pool_ = nullptr;
@@ -8,13 +8,16 @@
8
8
  */
9
9
 
10
10
  #include "StreamingMerger.h"
11
+ #include "FakeCluster.h"
11
12
  #include <sstream>
12
13
  #include <algorithm>
13
14
  #include <vector>
14
15
  #include <string>
16
+ #include <utility>
17
+ #include <list>
15
18
 
16
19
  StreamingMerger::StreamingMerger(int number_of_threads,
17
- std::vector<std::string>* options,
20
+ const Options& options,
18
21
  std::ofstream* stream_to)
19
22
  : VerticalMerger(number_of_threads, options), stream(stream_to) {
20
23
  if (!stream) {
@@ -45,7 +48,15 @@ void StreamingMerger::stream_polygons(Tile* tile, bool flush) {
45
48
  std::remove_if(tile->shapes().begin(), tile->shapes().end(), [this, flush, tile_end_x](Shape* shape) {
46
49
  if (flush || shape->outer_polyline->max_x() < (tile_end_x - 1)) {
47
50
  this->moved++;
48
- this->stream_raw_polygon(shape);
51
+ Polygon polygon = shape->to_raw_polygon();
52
+ if (this->options().any_compression()) {
53
+ std::list<Polygon> polygons;
54
+ polygons.push_back(polygon);
55
+ FakeCluster fake_cluster(polygons, this->options());
56
+ fake_cluster.compress_coords(polygons, this->options());
57
+ polygon = std::move(polygons.front());
58
+ }
59
+ this->stream_raw_polygon(polygon);
49
60
  shape->detach_from_pool();
50
61
  return true;
51
62
  }
@@ -59,20 +70,19 @@ void StreamingMerger::stream_polygons(Tile* tile, bool flush) {
59
70
  }
60
71
  }
61
72
 
62
- void StreamingMerger::stream_raw_polygon(const Shape* shape) {
73
+ void StreamingMerger::stream_raw_polygon(const Polygon& polygon) {
63
74
  std::ostringstream outer_oss;
64
75
 
65
76
  this->write_outer_polygon_start();
66
- const std::vector<Point>& points = shape->outer_polyline->raw();
77
+ const std::vector<Point>& points = polygon.outer;
67
78
  for (size_t i = 0; i < points.size(); ++i) {
68
79
  *stream << points[i].y << "," << points[i].x;
69
80
  if (i < points.size() - 1) *stream << " ";
70
81
  }
71
82
  this->write_outer_polygon_end();
72
83
 
73
- for (const auto& inner_polyline : shape->inner_polylines) {
84
+ for (const std::vector<Point>& inner_points : polygon.inner) {
74
85
  this->write_inner_polygon_start();
75
- const std::vector<Point>& inner_points = inner_polyline->raw();
76
86
  for (size_t i = 0; i < inner_points.size(); ++i) {
77
87
  *stream << inner_points[i].y << "," << inner_points[i].x;
78
88
  if (i < inner_points.size() - 1) *stream << " ";
@@ -21,7 +21,7 @@ class StreamingMerger : public VerticalMerger {
21
21
  int moved = 0;
22
22
 
23
23
  void stream_polygons(Tile* tile, bool flush = false);
24
- virtual void stream_raw_polygon(const Shape* shape);
24
+ virtual void stream_raw_polygon(const Polygon& polygon);
25
25
  virtual void write_header() = 0;
26
26
  virtual void write_footer() = 0;
27
27
  virtual void write_outer_polygon_start() = 0;
@@ -33,7 +33,7 @@ class StreamingMerger : public VerticalMerger {
33
33
 
34
34
  public:
35
35
  StreamingMerger(int number_of_threads,
36
- std::vector<std::string>* options,
36
+ const Options& options,
37
37
  std::ofstream* stream_to);
38
38
  void add_tile(ProcessResult& result, bool flush = false);
39
39
  ProcessResult* process_info() override;
@@ -43,7 +43,7 @@ class SvgStreamingMerger : public StreamingMerger {
43
43
 
44
44
  public:
45
45
  SvgStreamingMerger(int number_of_threads,
46
- std::vector<std::string>* options,
46
+ const Options& options,
47
47
  std::ofstream* stream_to,
48
48
  int total_width, int total_height)
49
49
  : StreamingMerger(number_of_threads, options, stream_to),
@@ -110,19 +110,7 @@ std::list<Polygon> Tile::to_raw_polygons()
110
110
  { std::list<Polygon> retme;
111
111
  bool bounds = this->finder->options().bounds;
112
112
  for (Shape* s : shapes_)
113
- { if (s->outer_polyline && !s->outer_polyline->is_empty())
114
- { Polygon poly;
115
- poly.outer = s->outer_polyline->raw();
116
- if (bounds) {
117
- s->outer_polyline->fill_bounds(poly.bounds);
118
- }
119
- if (!s->inner_polylines.empty()) {
120
- for (auto inner : s->inner_polylines) {
121
- poly.inner.push_back(inner->raw());
122
- }
123
- }
124
- retme.push_back(std::move(poly));
125
- }
113
+ { retme.push_back(std::move(s->to_raw_polygon(bounds)));
126
114
  }
127
115
  return(retme);
128
116
  }
@@ -14,7 +14,7 @@
14
14
  #include <utility>
15
15
  #include "VerticalMerger.h"
16
16
 
17
- VerticalMerger::VerticalMerger(int number_of_threads, std::vector<std::string> *options)
17
+ VerticalMerger::VerticalMerger(int number_of_threads, const Options& options)
18
18
  : Merger(number_of_threads, options) {
19
19
  }
20
20
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  class VerticalMerger : public Merger {
16
16
  public:
17
- VerticalMerger(int number_of_threads, std::vector<std::string> *options);
17
+ VerticalMerger(int number_of_threads, const Options& options);
18
18
  void add_tile(ProcessResult& result) override;
19
19
  ProcessResult* process_info() override;
20
20
  bool transpose() const override { return true; };