contrek 1.3.1 → 1.3.3

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +3 -3
  5. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +23 -3
  6. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +2 -2
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp +2 -2
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +1 -1
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +2 -2
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +4 -2
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +6 -6
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +16 -10
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +1 -1
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +16 -15
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +3 -3
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +1 -9
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h +80 -0
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.cpp +9 -28
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.h +10 -11
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +7 -3
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +4 -3
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +7 -5
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +1 -1
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +2 -2
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +0 -14
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +0 -2
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +5 -5
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp +31 -26
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.h +7 -7
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp +14 -37
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h +11 -12
  32. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/SubPool.h +47 -0
  33. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/SvgStreamingMerger.h +56 -0
  34. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +18 -3
  35. data/lib/contrek/cpp/cpp_geo_json_concurrent_streaming_merger.rb +11 -0
  36. data/lib/contrek/cpp/{cpp_concurrent_streaming_merger.rb → cpp_svg_concurrent_streaming_merger.rb} +1 -1
  37. data/lib/contrek/finder/concurrent/cluster.rb +6 -5
  38. data/lib/contrek/finder/concurrent/cursor.rb +2 -1
  39. data/lib/contrek/finder/concurrent/finder.rb +1 -12
  40. data/lib/contrek/finder/concurrent/geo_json_streaming_merger.rb +46 -0
  41. data/lib/contrek/finder/concurrent/inner_polyline.rb +8 -25
  42. data/lib/contrek/finder/concurrent/sequence.rb +1 -17
  43. data/lib/contrek/finder/concurrent/streaming_merger.rb +5 -27
  44. data/lib/contrek/finder/concurrent/svg_streaming_merger.rb +35 -0
  45. data/lib/contrek/version.rb +1 -1
  46. data/lib/contrek.rb +4 -1
  47. metadata +12 -6
@@ -11,36 +11,18 @@
11
11
  #include <vector>
12
12
  #include "InnerPolyline.h"
13
13
 
14
- InnerPolyline::InnerPolyline(std::vector<Point> raw_coordinates, Shape* shape)
15
- : raw_coordinates_(std::move(raw_coordinates)),
16
- shape_(shape) {}
17
- InnerPolyline::InnerPolyline(Sequence* sequence)
18
- : sequence_(sequence) {
14
+ InnerPolyline::InnerPolyline(ShapePool* shape_pool, std::vector<Point> raw_coordinates, Shape* shape)
15
+ : shape(shape),
16
+ shape_pool(shape_pool),
17
+ raw_coordinates_(std::move(raw_coordinates)) {}
18
+ InnerPolyline::InnerPolyline(ShapePool* shape_pool, Sequence* sequence)
19
+ : shape_pool(shape_pool) {
19
20
  this->raw_coordinates_ = sequence->to_vector();
21
+ this->shape = sequence->shape;
20
22
  }
21
23
 
22
- std::vector<Point>& InnerPolyline::raw() {
23
- return this->raw_coordinates_;
24
- }
25
-
26
- Bounds& InnerPolyline::vertical_bounds() {
27
- if (sequence_ != nullptr) {
28
- return(sequence_->vertical_bounds);
29
- } else {
30
- return(this->raw_vertical_bounds());
31
- }
32
- }
33
-
34
- Shape* InnerPolyline::shape() {
35
- if (sequence_ != nullptr) {
36
- return(sequence_->shape);
37
- } else {
38
- return(this->shape_ ? this->shape_ : this->assigned_shape);
39
- }
40
- }
41
-
42
- Bounds& InnerPolyline::raw_vertical_bounds() {
43
- if (!raw_coordinates_.empty()) {
24
+ void InnerPolyline::compute_vertical_bounds()
25
+ { if (!raw_coordinates_.empty()) {
44
26
  int min_y = raw_coordinates_[0].y;
45
27
  int max_y = raw_coordinates_[0].y;
46
28
  for (const auto& pos : raw_coordinates_) {
@@ -50,5 +32,4 @@ Bounds& InnerPolyline::raw_vertical_bounds() {
50
32
  vertical_bounds_.min = min_y;
51
33
  vertical_bounds_.max = max_y;
52
34
  }
53
- return(vertical_bounds_);
54
35
  }
@@ -12,19 +12,18 @@
12
12
  #include <optional>
13
13
  #include "Sequence.h"
14
14
 
15
+ class ShapePool;
15
16
  class InnerPolyline {
16
17
  public:
17
- explicit InnerPolyline(std::vector<Point> raw_coordinates, Shape* shape);
18
- explicit InnerPolyline(Sequence* sequence);
19
- std::vector<Point>& raw();
20
- Sequence* sequence() { return this->sequence_; }
21
- Bounds& vertical_bounds();
22
- Shape* shape();
23
- Shape* assigned_shape = nullptr;
18
+ explicit InnerPolyline(ShapePool* shape_pool, std::vector<Point> raw_coordinates, Shape* shape);
19
+ explicit InnerPolyline(ShapePool* shape_pool, Sequence* sequence);
20
+ std::vector<Point>& raw() { return this->raw_coordinates_; }
21
+ Bounds& vertical_bounds() { return this->vertical_bounds_; }
22
+ Shape* shape = nullptr;
23
+ ShapePool* shape_pool = nullptr;
24
+ void compute_vertical_bounds();
25
+
24
26
  private:
25
27
  std::vector<Point> raw_coordinates_;
26
- Sequence* sequence_ = nullptr;
27
- Shape* shape_;
28
- Bounds& raw_vertical_bounds();
29
- Bounds vertical_bounds_;
28
+ Bounds vertical_bounds_{0, 0};
30
29
  };
@@ -35,6 +35,11 @@ class Part : public Queueable<Point> {
35
35
  bool transmutation_skip = false;
36
36
  bool dead_end = false;
37
37
  bool mirror = false;
38
+
39
+ private:
40
+ bool touched_ = false;
41
+
42
+ public:
38
43
  Part* next = nullptr;
39
44
  Part* next_seam = nullptr;
40
45
  Part* prev = nullptr;
@@ -45,8 +50,8 @@ class Part : public Queueable<Point> {
45
50
  void add_position(const Point& point);
46
51
  Types type;
47
52
  bool innerable();
48
- const bool touched() const { return touched_; }
49
- const int versus() const { return versus_; }
53
+ bool touched() const { return touched_; }
54
+ int versus() const { return versus_; }
50
55
  void touch();
51
56
  void orient();
52
57
  std::string inspect();
@@ -57,6 +62,5 @@ class Part : public Queueable<Point> {
57
62
 
58
63
  private:
59
64
  int versus_ = 0;
60
- bool touched_ = false;
61
65
  Polyline* polyline_;
62
66
  };
@@ -17,9 +17,10 @@
17
17
  #include "Tile.h"
18
18
  #include "Shape.h"
19
19
 
20
- Polyline::Polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds)
21
- : raw_(std::move(polygon)),
22
- tile(tile)
20
+ Polyline::Polyline(ShapePool* shape_pool, Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds)
21
+ : tile(tile),
22
+ shape_pool(shape_pool),
23
+ raw_(std::move(polygon))
23
24
  { if (bounds.has_value()) {
24
25
  min_x = bounds->min_x;
25
26
  max_x_ = bounds->max_x;
@@ -22,13 +22,14 @@
22
22
 
23
23
  class Tile;
24
24
  class Shape;
25
+ class ShapePool;
25
26
  class Point;
26
27
  class InnerPolyline;
27
28
 
28
29
  class Polyline : public Partitionable {
29
30
  public:
30
31
  using Partitionable::Partitionable;
31
- Polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds = std::nullopt);
32
+ Polyline(ShapePool* shape_pool, Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds = std::nullopt);
32
33
  enum Flags : uint32_t {
33
34
  TRACKED_OUTER = 1 << 0
34
35
  };
@@ -39,12 +40,13 @@ class Polyline : public Partitionable {
39
40
  void precalc();
40
41
  int width();
41
42
  Tile *tile = nullptr;
43
+ ShapePool* shape_pool = nullptr;
42
44
  Shape* shape = nullptr;
43
45
  const std::vector<Point>& raw() const { return raw_; }
44
46
  const std::vector<Part*>& parts() const { return parts_; }
45
- const int max_y() const { return max_y_; }
46
- const int min_y() const { return min_y_; }
47
- const int max_x() const { return max_x_; }
47
+ int max_y() const { return max_y_; }
48
+ int min_y() const { return min_y_; }
49
+ int max_x() const { return max_x_; }
48
50
  void clear();
49
51
  bool is_empty();
50
52
  bool any_ancients = false;
@@ -60,6 +62,6 @@ class Polyline : public Partitionable {
60
62
  int min_x, max_x_, min_y_, max_y_;
61
63
  void find_boundary();
62
64
  uint32_t flags_ = 0;
63
- std::string named_;
64
65
  int name;
66
+ std::string named_;
65
67
  };
@@ -32,7 +32,7 @@ Position::Position(EndPoint* end_point)
32
32
  { this->end_point_ = end_point;
33
33
  }
34
34
 
35
- void Position::before_rem(Queueable<Point>* q) {
35
+ void Position::before_rem(Queueable<Point>*) {
36
36
  /*if (this->end_point_ != nullptr)
37
37
  { if (q->listable())
38
38
  { auto& v = this->end_point_->queues();
@@ -26,8 +26,8 @@ class QNode {
26
26
  Queueable<T>* owner {nullptr};
27
27
  explicit QNode(const T& value) : payload(value) {}
28
28
  virtual ~QNode() = default;
29
- virtual void before_rem(Queueable<T>* q) {}
30
- virtual void after_add(Queueable<T>* q) {}
29
+ virtual void before_rem(Queueable<T>*) {}
30
+ virtual void after_add(Queueable<T>*) {}
31
31
  };
32
32
 
33
33
 
@@ -34,17 +34,3 @@ bool Sequence::is_not_vertical()
34
34
  }
35
35
  return false;
36
36
  }
37
-
38
- void Sequence::compute_vertical_bounds()
39
- { const auto& cache = get_vector_cache();
40
- if (!cache.empty()) {
41
- int min_y = cache[0].y;
42
- int max_y = cache[0].y;
43
- for (const auto& pos : cache) {
44
- if (pos.y < min_y) min_y = pos.y;
45
- if (pos.y > max_y) max_y = pos.y;
46
- }
47
- vertical_bounds.min = min_y;
48
- vertical_bounds.max = max_y;
49
- }
50
- }
@@ -22,8 +22,6 @@ class Sequence : public Queueable<Point>{
22
22
  std::string toString();
23
23
  bool is_not_vertical();
24
24
  Shape* shape = nullptr;
25
- Bounds vertical_bounds;
26
- void compute_vertical_bounds();
27
25
  const std::vector<Point>& get_vector_cache() {
28
26
  if (vector_cache.empty() && this->size > 0) {
29
27
  vector_cache = this->to_vector();
@@ -17,17 +17,17 @@
17
17
  Shape::Shape(ShapePool* shape_pool, Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines)
18
18
  : outer_polyline(outer_polyline),
19
19
  inner_polylines(inner_polylines),
20
- shape_pool_(shape_pool) {
21
- for (InnerPolyline* ip : inner_polylines) {
22
- ip->assigned_shape = this;
23
- }
24
- }
20
+ shape_pool_(shape_pool) {}
25
21
 
26
22
  void Shape::clear_inner() {
27
23
  inner_polylines.clear();
28
24
  }
29
25
 
30
26
  void Shape::detach_from_pool() {
27
+ this->outer_polyline->shape_pool->detach_polyline();
28
+ for (InnerPolyline* inner_polyline : this->inner_polylines) {
29
+ inner_polyline->shape_pool->detach_inner_polyline();
30
+ }
31
31
  shape_pool_->detach_shape();
32
32
  }
33
33
 
@@ -9,49 +9,54 @@
9
9
 
10
10
  #include <vector>
11
11
  #include <utility>
12
+ #include <iostream>
12
13
  #include "Shape.h"
13
14
  #include "ShapePool.h"
14
15
  #include "Tile.h"
15
16
 
16
17
  Shape* ShapePool::acquire_shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines) {
17
- shapes_storage.emplace_back(this, outer_polyline, inner_polylines);
18
- Shape* shape = &shapes_storage.back();
19
- this->shapes_count++;
18
+ Shape* shape = this->shapes.acquire(this, outer_polyline, inner_polylines);
20
19
  return shape;
21
20
  }
22
21
 
22
+ Polyline* ShapePool::acquire_polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds = std::nullopt) {
23
+ return this->polylines.acquire(this, tile, std::move(polygon), bounds);
24
+ }
25
+
26
+ InnerPolyline* ShapePool::acquire_inner_polyline(std::vector<Point> coords, Shape* shape) {
27
+ return this->inner_polylines.acquire(this, std::move(coords), shape);
28
+ }
29
+
30
+ InnerPolyline* ShapePool::acquire_inner_polyline(Sequence* seq) {
31
+ return this->inner_polylines.acquire(this, seq);
32
+ }
33
+
23
34
  void ShapePool::set_owner(Tile* tile) {
24
35
  this->owner_tile_ = tile;
25
36
  }
26
37
 
27
38
  void ShapePool::detach_shape() {
28
- this->shapes_count--;
29
- if (this->shapes_count == 0) {
30
- this->owner_tile_->unregister_pool(this);
31
- delete this;
32
- }
39
+ this->shapes.decrement();
40
+ this->check_destruction();
33
41
  }
34
42
 
35
- InnerPolyline* ShapePool::acquire_inner_polyline(std::vector<Point> coords, Shape* shape) {
36
- inner_polylines_storage.emplace_back(std::move(coords), shape);
37
- InnerPolyline* ip = &inner_polylines_storage.back();
38
- return ip;
43
+ void ShapePool::detach_polyline() {
44
+ this->polylines.decrement();
45
+ this->check_destruction();
39
46
  }
40
47
 
41
- InnerPolyline* ShapePool::acquire_inner_polyline(Sequence* seq) {
42
- inner_polylines_storage.emplace_back(seq);
43
- InnerPolyline* ip = &inner_polylines_storage.back();
44
- return ip;
48
+ void ShapePool::detach_inner_polyline() {
49
+ this->inner_polylines.decrement();
50
+ this->check_destruction();
45
51
  }
46
52
 
47
- Sequence* ShapePool::acquire_sequence() {
48
- sequences_storage.emplace_back();
49
- Sequence* s = &sequences_storage.back();
50
- return s;
51
- }
52
-
53
- Polyline* ShapePool::acquire_polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds = std::nullopt) {
54
- polylines_storage.emplace_back(tile, std::move(polygon), bounds);
55
- Polyline* p = &polylines_storage.back();
56
- return p;
53
+ void ShapePool::check_destruction() {
54
+ if (this->shapes.is_released() &&
55
+ this->polylines.is_released() &&
56
+ this->inner_polylines.is_released()) {
57
+ if (this->owner_tile_) {
58
+ this->owner_tile_->unregister_pool(this);
59
+ }
60
+ delete this;
61
+ }
57
62
  }
@@ -13,6 +13,7 @@
13
13
  #include "Shape.h"
14
14
  #include "../RectBounds.h"
15
15
  #include "Polyline.h"
16
+ #include "SubPool.h"
16
17
 
17
18
  class Shape;
18
19
  class Tile;
@@ -20,19 +21,18 @@ class Polyline;
20
21
  class InnerPolyline;
21
22
  class ShapePool {
22
23
  private:
23
- int shapes_count = 0;
24
24
  Tile* owner_tile_ = nullptr;
25
- std::deque<Shape> shapes_storage;
26
- std::deque<InnerPolyline> inner_polylines_storage;
27
- std::deque<Sequence> sequences_storage;
28
- std::deque<Polyline> polylines_storage;
29
-
25
+ SubPool<Shape> shapes{this};
26
+ SubPool<Polyline> polylines{this};
27
+ SubPool<InnerPolyline> inner_polylines{this};
30
28
  public:
31
29
  Shape* acquire_shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines);
32
30
  InnerPolyline* acquire_inner_polyline(std::vector<Point> coords, Shape* s);
33
31
  InnerPolyline* acquire_inner_polyline(Sequence* seq);
34
- Sequence* acquire_sequence();
35
32
  Polyline* acquire_polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds);
36
33
  void set_owner(Tile* tile);
37
34
  void detach_shape();
35
+ void detach_polyline();
36
+ void detach_inner_polyline();
37
+ void check_destruction();
38
38
  };
@@ -15,15 +15,11 @@
15
15
 
16
16
  StreamingMerger::StreamingMerger(int number_of_threads,
17
17
  std::vector<std::string>* options,
18
- std::ofstream* stream_to,
19
- int total_width, int total_height)
20
- : VerticalMerger(number_of_threads, options), stream(stream_to), total_width(total_width), total_height(total_height) {
18
+ std::ofstream* stream_to)
19
+ : VerticalMerger(number_of_threads, options), stream(stream_to) {
21
20
  if (!stream) {
22
21
  throw std::invalid_argument("Streaming requires a valid destination output. stream_to cannot be null.");
23
22
  }
24
- if (total_width <= 0 || total_height <= 0) {
25
- throw std::invalid_argument("Streaming requires valid canvas dimensions (width and height must be > 0).");
26
- }
27
23
  }
28
24
 
29
25
  void StreamingMerger::add_tile(ProcessResult& result, bool flush)
@@ -38,7 +34,7 @@ void StreamingMerger::add_tile(ProcessResult& result, bool flush)
38
34
 
39
35
  ProcessResult* StreamingMerger::process_info() {
40
36
  ProcessResult *pr = VerticalMerger::process_info();
41
- pr->groups = this->moved;
37
+ pr->groups = this->moved;
42
38
  return(pr);
43
39
  }
44
40
 
@@ -65,53 +61,34 @@ void StreamingMerger::stream_polygons(Tile* tile, bool flush) {
65
61
 
66
62
  void StreamingMerger::stream_raw_polygon(const Shape* shape) {
67
63
  std::ostringstream outer_oss;
64
+
65
+ this->write_outer_polygon_start();
68
66
  const std::vector<Point>& points = shape->outer_polyline->raw();
69
67
  for (size_t i = 0; i < points.size(); ++i) {
70
- outer_oss << points[i].y << "," << points[i].x;
71
- if (i < points.size() - 1) outer_oss << " ";
68
+ *stream << points[i].y << "," << points[i].x;
69
+ if (i < points.size() - 1) *stream << " ";
72
70
  }
73
- *stream << svg_outer_polygon_string(outer_oss.str());
71
+ this->write_outer_polygon_end();
74
72
 
75
73
  for (const auto& inner_polyline : shape->inner_polylines) {
76
- std::ostringstream inner_oss;
74
+ this->write_inner_polygon_start();
77
75
  const std::vector<Point>& inner_points = inner_polyline->raw();
78
76
  for (size_t i = 0; i < inner_points.size(); ++i) {
79
- inner_oss << inner_points[i].y << "," << inner_points[i].x;
80
- if (i < inner_points.size() - 1) inner_oss << " ";
77
+ *stream << inner_points[i].y << "," << inner_points[i].x;
78
+ if (i < inner_points.size() - 1) *stream << " ";
81
79
  }
82
- *stream << svg_inner_polygon_string(inner_oss.str());
80
+ this->write_inner_polygon_end();
83
81
  }
84
82
  }
85
83
 
86
84
  void StreamingMerger::ensure_header() {
87
85
  if (stream && stream->tellp() == 0) {
88
- *stream << svg_header_string();
86
+ this->write_header();
89
87
  }
90
88
  }
91
89
 
92
90
  void StreamingMerger::ensure_footer() {
93
91
  if (stream) {
94
- *stream << svg_footer_string();
92
+ this->write_footer();
95
93
  }
96
94
  }
97
-
98
- std::string StreamingMerger::svg_css() {
99
- return ".out{fill:none;stroke:red;stroke-width:1;}.in{fill:none;stroke:green;stroke-width:1;}.out:hover{stroke:yellow;}";
100
- }
101
-
102
- std::string StreamingMerger::svg_header_string() {
103
- return "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" + std::to_string(total_width) +
104
- "\" height=\"" + std::to_string(total_height) + "\"><style>" + svg_css() + "</style>";
105
- }
106
-
107
- std::string StreamingMerger::svg_footer_string() {
108
- return "</svg>";
109
- }
110
-
111
- std::string StreamingMerger::svg_outer_polygon_string(std::string_view points) {
112
- return "<polygon points=\"" + std::string(points) + "\" class=\"out\"/>";
113
- }
114
-
115
- std::string StreamingMerger::svg_inner_polygon_string(std::string_view points) {
116
- return "<polygon points=\"" + std::string(points) + "\" class=\"in\"/>";
117
- }
@@ -16,26 +16,25 @@
16
16
  #include <vector>
17
17
 
18
18
  class StreamingMerger : public VerticalMerger {
19
- private:
19
+ protected:
20
20
  std::ofstream* stream;
21
- int total_width;
22
- int total_height;
23
21
  int moved = 0;
22
+
23
+ void stream_polygons(Tile* tile, bool flush = false);
24
+ virtual void stream_raw_polygon(const Shape* shape);
25
+ virtual void write_header() = 0;
26
+ virtual void write_footer() = 0;
27
+ virtual void write_outer_polygon_start() = 0;
28
+ virtual void write_outer_polygon_end() = 0;
29
+ virtual void write_inner_polygon_start() = 0;
30
+ virtual void write_inner_polygon_end() = 0;
24
31
  void ensure_header();
25
32
  void ensure_footer();
26
- void stream_polygons(Tile* tile, bool flush = false);
27
- void stream_raw_polygon(const Shape* shape);
28
- virtual std::string svg_css();
29
- virtual std::string svg_header_string();
30
- virtual std::string svg_footer_string();
31
- virtual std::string svg_outer_polygon_string(std::string_view points);
32
- virtual std::string svg_inner_polygon_string(std::string_view points);
33
33
 
34
34
  public:
35
35
  StreamingMerger(int number_of_threads,
36
36
  std::vector<std::string>* options,
37
- std::ofstream* stream_to,
38
- int total_width, int total_height);
37
+ std::ofstream* stream_to);
39
38
  void add_tile(ProcessResult& result, bool flush = false);
40
39
  ProcessResult* process_info() override;
41
40
  };
@@ -0,0 +1,47 @@
1
+ /*
2
+ * SubPool.h
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 <deque>
12
+ #include <memory>
13
+ #include <utility>
14
+
15
+ class ShapePool;
16
+
17
+ template <typename T>
18
+ class SubPool {
19
+ private:
20
+ std::unique_ptr<std::deque<T>> storage_;
21
+ uint32_t active_count_ = 0;
22
+ ShapePool* macro_pool_ = nullptr;
23
+
24
+ public:
25
+ explicit SubPool(ShapePool* macro_pool) : macro_pool_(macro_pool) {
26
+ storage_ = std::make_unique<std::deque<T>>();
27
+ }
28
+
29
+ template <typename... Args>
30
+ T* acquire(Args&&... args) {
31
+ storage_->emplace_back(std::forward<Args>(args)...);
32
+ T* ptr = &storage_->back();
33
+ active_count_++;
34
+ return ptr;
35
+ }
36
+
37
+ void decrement() {
38
+ active_count_--;
39
+ if (active_count_ == 0 && storage_ != nullptr) {
40
+ storage_.reset();
41
+ }
42
+ }
43
+
44
+ bool is_released() const {
45
+ return storage_ == nullptr;
46
+ }
47
+ };
@@ -0,0 +1,56 @@
1
+ /*
2
+ * SvgStreamingMerger.h
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 <string>
12
+ #include <vector>
13
+ #include "StreamingMerger.h"
14
+
15
+ class SvgStreamingMerger : public StreamingMerger {
16
+ private:
17
+ int total_width;
18
+ int total_height;
19
+ std::string svg_css() {
20
+ return ".out{fill:none;stroke:red;stroke-width:1;}.in{fill:none;stroke:green;stroke-width:1;}.out:hover{stroke:yellow;}";
21
+ }
22
+
23
+ protected:
24
+ void write_header() override {
25
+ *stream << "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" << total_width
26
+ << "\" height=\"" << total_height << "\"><style>" << svg_css() << "</style>";
27
+ }
28
+ void write_footer() override {
29
+ *stream << "</svg>";
30
+ }
31
+ void write_outer_polygon_start() override {
32
+ *stream << "<polygon points=\"";
33
+ }
34
+ void write_outer_polygon_end() override {
35
+ *stream << "\" class=\"out\"/>";
36
+ }
37
+ void write_inner_polygon_start() override {
38
+ *stream << "<polygon points=\"";
39
+ }
40
+ void write_inner_polygon_end() override {
41
+ *stream << "\" class=\"in\"/>";
42
+ }
43
+
44
+ public:
45
+ SvgStreamingMerger(int number_of_threads,
46
+ std::vector<std::string>* options,
47
+ std::ofstream* stream_to,
48
+ int total_width, int total_height)
49
+ : StreamingMerger(number_of_threads, options, stream_to),
50
+ total_width(total_width),
51
+ total_height(total_height) {
52
+ if (total_width <= 0 || total_height <= 0) {
53
+ throw std::invalid_argument("SVG Streaming requires valid canvas dimensions (width and height must be > 0).");
54
+ }
55
+ }
56
+ };
@@ -96,6 +96,8 @@
96
96
  #include "PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp"
97
97
  #include "PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h"
98
98
  #include "PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp"
99
+ #include "PolygonFinder/src/polygon/finder/concurrent/SvgStreamingMerger.h"
100
+ #include "PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h"
99
101
  #include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.h"
100
102
  #include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp"
101
103
  extern "C" {
@@ -308,14 +310,23 @@ struct OfstreamWrapper {
308
310
  std::ofstream& get_stream() { return stream; }
309
311
  };
310
312
 
311
- StreamingMerger* create_streaming_merger(Object self,
313
+ SvgStreamingMerger* create_svg_streaming_merger(Object self,
312
314
  int number_of_threads,
313
315
  std::vector<std::string>* options,
314
316
  Object stream_obj,
315
317
  int total_width,
316
318
  int total_height) {
317
319
  OfstreamWrapper* wrapper = Rice::detail::From_Ruby<OfstreamWrapper*>().convert(stream_obj.value());
318
- return new StreamingMerger(number_of_threads, options, &wrapper->get_stream(), total_width, total_height);
320
+ return new SvgStreamingMerger(number_of_threads, options, &wrapper->get_stream(), total_width, total_height);
321
+ }
322
+
323
+ GeoJsonStreamingMerger* create_geo_json_streaming_merger(Object self,
324
+ int number_of_threads,
325
+ std::vector<std::string>* options,
326
+ Object stream_obj,
327
+ int pixel_val) {
328
+ OfstreamWrapper* wrapper = Rice::detail::From_Ruby<OfstreamWrapper*>().convert(stream_obj.value());
329
+ return new GeoJsonStreamingMerger(number_of_threads, options, &wrapper->get_stream(),pixel_val);
319
330
  }
320
331
 
321
332
  OfstreamWrapper* create_ofstream(Object self, std::string path) {
@@ -436,7 +447,11 @@ void Init_cpp_polygon_finder() {
436
447
  ProcessResult pr = Rice::detail::ruby_result_to_process_result(rb_result);
437
448
  self.add_tile(pr, flush);
438
449
  });
439
- rb_cstreaming_merger.define_singleton_method("new", &create_streaming_merger);
450
+
451
+ Data_Type<SvgStreamingMerger> rb_csvgstreaming_merger = define_class<SvgStreamingMerger, StreamingMerger>("CPPSvgStreamingMerger");
452
+ rb_csvgstreaming_merger.define_singleton_method("new", &create_svg_streaming_merger);
453
+ Data_Type<GeoJsonStreamingMerger> rb_cgeojsonstreaming_merger = define_class<GeoJsonStreamingMerger, StreamingMerger>("CPPGeoJsonStreamingMerger");
454
+ rb_cgeojsonstreaming_merger.define_singleton_method("new", &create_geo_json_streaming_merger);
440
455
 
441
456
  Module mContrek = define_module("Contrek");
442
457
  Module mCpp = define_module_under(mContrek, "Cpp");
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Contrek
4
+ module Cpp
5
+ class CPPGeoJsonConcurrentStreamingMerger < CPPGeoJsonStreamingMerger
6
+ def self.new(stream_to:, number_of_threads: 0, options: nil, pixel_val: 0)
7
+ super(number_of_threads, options, stream_to, pixel_val)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Contrek
4
4
  module Cpp
5
- class CPPConcurrentStreamingMerger < CPPStreamingMerger
5
+ class CPPSvgConcurrentStreamingMerger < CPPSvgStreamingMerger
6
6
  def self.new(stream_to:, total_width:, total_height:, number_of_threads: 0, options: nil)
7
7
  super(number_of_threads, options, stream_to, total_width, total_height)
8
8
  end