contrek 1.3.1 → 1.3.2

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -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 +81 -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 +5 -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 +12 -31
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h +10 -8
  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 +43 -0
  34. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +2 -1
  35. data/lib/contrek/finder/concurrent/cluster.rb +6 -5
  36. data/lib/contrek/finder/concurrent/cursor.rb +2 -1
  37. data/lib/contrek/finder/concurrent/finder.rb +1 -12
  38. data/lib/contrek/finder/concurrent/inner_polyline.rb +8 -25
  39. data/lib/contrek/finder/concurrent/sequence.rb +1 -17
  40. data/lib/contrek/version.rb +1 -1
  41. metadata +8 -5
@@ -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,9 @@ class Part : public Queueable<Point> {
35
35
  bool transmutation_skip = false;
36
36
  bool dead_end = false;
37
37
  bool mirror = false;
38
+ private:
39
+ bool touched_ = false;
40
+ public:
38
41
  Part* next = nullptr;
39
42
  Part* next_seam = nullptr;
40
43
  Part* prev = nullptr;
@@ -45,8 +48,8 @@ class Part : public Queueable<Point> {
45
48
  void add_position(const Point& point);
46
49
  Types type;
47
50
  bool innerable();
48
- const bool touched() const { return touched_; }
49
- const int versus() const { return versus_; }
51
+ bool touched() const { return touched_; }
52
+ int versus() const { return versus_; }
50
53
  void touch();
51
54
  void orient();
52
55
  std::string inspect();
@@ -57,6 +60,5 @@ class Part : public Queueable<Point> {
57
60
 
58
61
  private:
59
62
  int versus_ = 0;
60
- bool touched_ = false;
61
63
  Polyline* polyline_;
62
64
  };
@@ -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
  };
@@ -38,7 +38,7 @@ void StreamingMerger::add_tile(ProcessResult& result, bool flush)
38
38
 
39
39
  ProcessResult* StreamingMerger::process_info() {
40
40
  ProcessResult *pr = VerticalMerger::process_info();
41
- pr->groups = this->moved;
41
+ pr->groups = this->moved;
42
42
  return(pr);
43
43
  }
44
44
 
@@ -65,53 +65,34 @@ void StreamingMerger::stream_polygons(Tile* tile, bool flush) {
65
65
 
66
66
  void StreamingMerger::stream_raw_polygon(const Shape* shape) {
67
67
  std::ostringstream outer_oss;
68
+
69
+ this->write_outer_polygon_start();
68
70
  const std::vector<Point>& points = shape->outer_polyline->raw();
69
71
  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 << " ";
72
+ *stream << points[i].y << "," << points[i].x;
73
+ if (i < points.size() - 1) *stream << " ";
72
74
  }
73
- *stream << svg_outer_polygon_string(outer_oss.str());
75
+ this->write_outer_polygon_end();
74
76
 
75
77
  for (const auto& inner_polyline : shape->inner_polylines) {
76
- std::ostringstream inner_oss;
78
+ this->write_inner_polygon_start();
77
79
  const std::vector<Point>& inner_points = inner_polyline->raw();
78
80
  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 << " ";
81
+ *stream << inner_points[i].y << "," << inner_points[i].x;
82
+ if (i < inner_points.size() - 1) *stream << " ";
81
83
  }
82
- *stream << svg_inner_polygon_string(inner_oss.str());
84
+ this->write_inner_polygon_end();
83
85
  }
84
86
  }
85
87
 
86
88
  void StreamingMerger::ensure_header() {
87
89
  if (stream && stream->tellp() == 0) {
88
- *stream << svg_header_string();
90
+ this->write_header();
89
91
  }
90
92
  }
91
93
 
92
94
  void StreamingMerger::ensure_footer() {
93
95
  if (stream) {
94
- *stream << svg_footer_string();
96
+ this->write_footer();
95
97
  }
96
98
  }
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,20 +16,22 @@
16
16
  #include <vector>
17
17
 
18
18
  class StreamingMerger : public VerticalMerger {
19
- private:
19
+ protected:
20
20
  std::ofstream* stream;
21
21
  int total_width;
22
22
  int total_height;
23
23
  int moved = 0;
24
+
25
+ void stream_polygons(Tile* tile, bool flush = false);
26
+ virtual void stream_raw_polygon(const Shape* shape);
27
+ virtual void write_header() = 0;
28
+ virtual void write_footer() = 0;
29
+ virtual void write_outer_polygon_start() = 0;
30
+ virtual void write_outer_polygon_end() = 0;
31
+ virtual void write_inner_polygon_start() = 0;
32
+ virtual void write_inner_polygon_end() = 0;
24
33
  void ensure_header();
25
34
  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
35
 
34
36
  public:
35
37
  StreamingMerger(int number_of_threads,
@@ -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,43 @@
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 "StreamingMerger.h"
13
+
14
+ class SvgStreamingMerger : public StreamingMerger {
15
+ private:
16
+ std::string svg_css() {
17
+ return ".out{fill:none;stroke:red;stroke-width:1;}.in{fill:none;stroke:green;stroke-width:1;}.out:hover{stroke:yellow;}";
18
+ }
19
+
20
+ protected:
21
+ void write_header() override {
22
+ *stream << "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" << total_width
23
+ << "\" height=\"" << total_height << "\"><style>" << svg_css() << "</style>";
24
+ }
25
+ void write_footer() override {
26
+ *stream << "</svg>";
27
+ }
28
+ void write_outer_polygon_start() override {
29
+ *stream << "<polygon points=\"";
30
+ }
31
+ void write_outer_polygon_end() override {
32
+ *stream << "\" class=\"out\"/>";
33
+ }
34
+ void write_inner_polygon_start() override {
35
+ *stream << "<polygon points=\"";
36
+ }
37
+ void write_inner_polygon_end() override {
38
+ *stream << "\" class=\"in\"/>";
39
+ }
40
+
41
+ public:
42
+ using StreamingMerger::StreamingMerger;
43
+ };
@@ -96,6 +96,7 @@
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"
99
100
  #include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.h"
100
101
  #include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp"
101
102
  extern "C" {
@@ -315,7 +316,7 @@ StreamingMerger* create_streaming_merger(Object self,
315
316
  int total_width,
316
317
  int total_height) {
317
318
  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);
319
+ return new SvgStreamingMerger(number_of_threads, options, &wrapper->get_stream(), total_width, total_height);
319
320
  }
320
321
 
321
322
  OfstreamWrapper* create_ofstream(Object self, std::string path) {
@@ -5,7 +5,7 @@ module Contrek
5
5
  class Cluster
6
6
  attr_reader :tiles, :hub, :finder
7
7
 
8
- def initialize(finder:, height:, start_x:, end_x:)
8
+ def initialize(finder:, height:)
9
9
  @finder = finder
10
10
  @tiles = []
11
11
  @hub = Hub.new(height:)
@@ -57,23 +57,24 @@ module Contrek
57
57
  new_inners = shape.inner_polylines
58
58
  new_inner_polylines = []
59
59
  tot_inner += Benchmark.measure do
60
- new_inner_polylines = cursor.join_inners!(new_outer, treemap)
60
+ new_inner_polylines = cursor.join_inners!(treemap)
61
61
  new_inners += new_inner_polylines
62
62
  if treemap
63
63
  new_inner_polylines.each do |inner_polyline|
64
- inner_polyline.sequence.compute_vertical_bounds!
64
+ inner_polyline.compute_vertical_bounds!
65
65
  all_new_inner_polylines += new_inner_polylines
66
66
  end
67
67
  end
68
68
  new_inners += cursor.orphan_inners
69
69
  end.real
70
+ shape.clear_inner!
70
71
 
71
72
  polyline = Polyline.new(tile: tile, polygon: new_outer.to_a)
72
73
  inserting_new_shape = Shape.init_by(polyline, new_inners)
73
74
  new_shapes << inserting_new_shape
74
75
  polyline.shape = inserting_new_shape
75
76
 
76
- new_inner_polylines.each { |inner_polyline| inner_polyline.sequence.shape = inserting_new_shape }
77
+ new_inner_polylines.each { |inner_polyline| inner_polyline.shape = inserting_new_shape }
77
78
 
78
79
  if treemap
79
80
  cursor.shapes_sequence.each do |merged_shape|
@@ -115,7 +116,7 @@ module Contrek
115
116
  private
116
117
 
117
118
  def assign_ancestry(shape, inner_polyline)
118
- shape.set_parent_shape(inner_polyline.sequence.shape)
119
+ shape.set_parent_shape(inner_polyline.shape)
119
120
  shape.parent_inner_polyline = inner_polyline
120
121
  shape.fixed = true
121
122
  end
@@ -40,7 +40,7 @@ module Contrek
40
40
  outer_joined_polyline
41
41
  end
42
42
 
43
- def join_inners!(outer_seq, treemap)
43
+ def join_inners!(treemap)
44
44
  return_inner_polylines = []
45
45
  shape_index = 0
46
46
 
@@ -174,6 +174,7 @@ module Contrek
174
174
  if !dest_part.polyline.on?(Polyline::TRACKED_OUTER)
175
175
  @shapes_sequence << shape
176
176
  @orphan_inners += shape.inner_polylines
177
+ shape.clear_inner!
177
178
  end
178
179
  dest_part.polyline.turn_on(Polyline::TRACKED_OUTER)
179
180
  if !dest_part.touched
@@ -114,18 +114,7 @@ module Contrek
114
114
  return
115
115
  end
116
116
  if (twin_tile = arriving_tiles.find { |b| (b.start_x == (tile.end_x - 1)) || ((b.end_x - 1) == tile.start_x) })
117
-
118
- if twin_tile.start_x == (tile.end_x - 1)
119
- start_x = tile.start_x
120
- end_x = twin_tile.end_x
121
- else
122
- start_x = twin_tile.start_x
123
- end_x = tile.end_x
124
- end
125
-
126
- # puts "start = #{start_x} end = #{end_x}"
127
-
128
- cluster = Cluster.new(finder: self, height: height, start_x:, end_x:)
117
+ cluster = Cluster.new(finder: self, height: height)
129
118
  if twin_tile.start_x == (tile.end_x - 1)
130
119
  cluster.add(tile)
131
120
  cluster.add(twin_tile)
@@ -3,37 +3,20 @@
3
3
  module Contrek
4
4
  module Concurrent
5
5
  class InnerPolyline
6
- attr_reader :sequence
6
+ attr_reader :raw, :vertical_bounds
7
+ attr_accessor :shape
7
8
 
8
9
  def initialize(shape: nil, raw_coordinates: [], sequence: nil)
9
- @raw = raw_coordinates if raw_coordinates
10
- @sequence = sequence if sequence
11
- @shape = shape
12
- end
13
-
14
- def raw
15
- @sequence ? @sequence.to_a : @raw
16
- end
17
-
18
- def vertical_bounds
19
- if @sequence
20
- @sequence.vertical_bounds
10
+ if sequence
11
+ @shape = sequence.shape
12
+ @raw = sequence.to_a
21
13
  else
22
- raw_vertical_bounds
14
+ @shape = shape
15
+ @raw = raw_coordinates
23
16
  end
24
17
  end
25
18
 
26
- def shape
27
- if @sequence
28
- @sequence.shape
29
- else
30
- @shape
31
- end
32
- end
33
-
34
- private
35
-
36
- def raw_vertical_bounds
19
+ def compute_vertical_bounds!
37
20
  @vertical_bounds ||= begin
38
21
  min_y = Float::INFINITY
39
22
  max_y = 0