contrek 1.1.9 → 1.2.1

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 +4 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +30 -9
  5. data/Rakefile +1 -1
  6. data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +10 -12
  7. data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +6 -0
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +1 -1
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +2 -0
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +36 -2
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +4 -4
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +2 -3
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +66 -158
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +0 -2
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.h +4 -2
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +2 -2
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +1 -5
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +0 -13
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +1 -3
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +0 -128
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +0 -6
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +0 -50
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +2 -8
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +22 -3
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +1 -57
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +0 -12
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +0 -3
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp +11 -3
  29. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +10 -0
  30. data/lib/contrek/finder/concurrent/cluster.rb +2 -3
  31. data/lib/contrek/finder/concurrent/cursor.rb +56 -120
  32. data/lib/contrek/finder/concurrent/end_point.rb +2 -0
  33. data/lib/contrek/finder/concurrent/hub.rb +1 -1
  34. data/lib/contrek/finder/concurrent/part.rb +2 -20
  35. data/lib/contrek/finder/concurrent/partitionable.rb +0 -81
  36. data/lib/contrek/finder/concurrent/polyline.rb +3 -47
  37. data/lib/contrek/finder/concurrent/position.rb +8 -2
  38. data/lib/contrek/finder/concurrent/queueable.rb +0 -41
  39. data/lib/contrek/finder/concurrent/tile.rb +0 -4
  40. data/lib/contrek/finder/concurrent/vertical_merger.rb +9 -5
  41. data/lib/contrek/version.rb +1 -1
  42. metadata +3 -3
  43. /data/{LICENSE-MIT.md → lib/LICENSE-MIT.md} +0 -0
@@ -15,10 +15,8 @@
15
15
  class EndPoint;
16
16
  class Hub {
17
17
  public:
18
- explicit Hub(int height, int start_x, int end_x);
18
+ explicit Hub(int height);
19
19
  int spawn_end_point();
20
- const int width() const { return width_; }
21
- const int start_x() const { return start_x_; }
22
20
  inline EndPoint* get(int key) {
23
21
  if (!is_set(key)) return nullptr;
24
22
  int index = payloads_[key];
@@ -34,9 +32,7 @@ class Hub {
34
32
  }
35
33
 
36
34
  private:
37
- int width_;
38
35
  int height_;
39
- int start_x_;
40
36
  std::vector<int> payloads_;
41
37
  std::vector<EndPoint> endpoint_pool_;
42
38
  Hub(const Hub&) = delete;
@@ -61,19 +61,6 @@ void Part::touch()
61
61
  { this->touched_ = true;
62
62
  }
63
63
 
64
- bool Part::intersect_part(Part* other_part)
65
- { bool intersect = false;
66
- other_part->each([&](QNode<Point>* pos) -> bool {
67
- Position *position = static_cast<Position*>(pos);
68
- if (position->end_point()->queues_include(this))
69
- { intersect = true;
70
- return(false);
71
- }
72
- return(true);
73
- });
74
- return(intersect);
75
- }
76
-
77
64
  void Part::orient()
78
65
  { if (this->size <= 1 || (this->size == 2 && this->inverts)) {
79
66
  this->versus_ = 0;
@@ -28,10 +28,10 @@ class Part : public Queueable<Point> {
28
28
  ADDED = 2
29
29
  };
30
30
  explicit Part(Types type, Polyline* polyline);
31
+ bool listable() const override { return true; }
31
32
  bool is(Types type);
32
33
  bool inverts = false;
33
34
  bool trasmuted = false;
34
- bool delayed = false;
35
35
  bool dead_end = false;
36
36
  Part* next = nullptr;
37
37
  Part* prev = nullptr;
@@ -45,8 +45,6 @@ class Part : public Queueable<Point> {
45
45
  const bool touched() const { return touched_; }
46
46
  const int versus() const { return versus_; }
47
47
  void touch();
48
- bool intersect_part(Part* other_part);
49
- void set_polyline(Polyline* polyline) { this->polyline_ = polyline; }
50
48
  void orient();
51
49
  std::string inspect();
52
50
  std::vector<EndPoint*> continuum_to(const Part& other_part) const;
@@ -35,17 +35,6 @@ void Partitionable::add_part(Part* new_part)
35
35
  if (new_part->is(Part::SEAM)) new_part->orient();
36
36
  }
37
37
 
38
- void Partitionable::insert_after(Part* part, Part* new_part) {
39
- auto it = std::find(parts_.begin(), parts_.end(), part);
40
- if (it != parts_.end()) parts_.insert(it + 1, new_part);
41
- new_part->prev = part;
42
- new_part->next = part->next;
43
- new_part->circular_next = part->next;
44
- if (part->next) part->next->prev = new_part;
45
- part->next = new_part;
46
- part->circular_next = new_part;
47
- }
48
-
49
38
  void Partitionable::partition()
50
39
  { this->parts_.clear();
51
40
  Polyline *polyline = static_cast<Polyline*>(this);
@@ -79,123 +68,6 @@ void Partitionable::partition()
79
68
  this->trasmute_parts();
80
69
  }
81
70
 
82
- Part* Partitionable::find_first_part_by_position(Position* position, int versus) {
83
- for (Part* part : this->parts_)
84
- { if ( part->is(Part::SEAM) &&
85
- part->versus() == -(versus) &&
86
- position->end_point()->queues_include(part)) return(part);
87
- }
88
- return(nullptr);
89
- }
90
-
91
- std::optional<SewReturnData> Partitionable::sew(std::vector<std::pair<int, int>> intersection, Polyline* other)
92
- { std::vector<int> matching_part_indexes;
93
- std::vector<int> other_matching_part_indexes;
94
- matching_part_indexes.reserve(intersection.size());
95
- other_matching_part_indexes.reserve(intersection.size());
96
-
97
- // traspose
98
- for (const auto& pair : intersection) {
99
- matching_part_indexes.push_back(pair.first);
100
- other_matching_part_indexes.push_back(pair.second);
101
- }
102
- std::sort(matching_part_indexes.begin(), matching_part_indexes.end());
103
- std::sort(other_matching_part_indexes.begin(), other_matching_part_indexes.end());
104
-
105
- auto start_it_before = other->parts_.begin() + other_matching_part_indexes.back() + 1;
106
- auto end_it_before = other->parts_.end();
107
- std::vector<Part*> before_parts(start_it_before, end_it_before);
108
- auto start_it_after = other->parts_.begin();
109
- auto end_it_after = other->parts_.begin() + other_matching_part_indexes.front();
110
- std::vector<Part*> after_parts(start_it_after, end_it_after);
111
-
112
- int start_idx = matching_part_indexes.front();
113
- int end_idx = matching_part_indexes.back();
114
- Part* part_start = parts_[start_idx];
115
- Part* part_end = parts_[end_idx];
116
-
117
- auto collect_sequences = [&](const std::vector<int>& indices, std::vector<Part*>& p_list)
118
- -> std::vector<std::vector<Point*>> {
119
- std::vector<std::vector<Point*>> result;
120
- int last_n = -1;
121
- if (indices.size() < 2) return result;
122
- for (int n = indices.front() + 1; n < indices.back(); ++n) {
123
- if (std::find(indices.begin(), indices.end(), n) == indices.end()) {
124
- Part* part = p_list[n];
125
- if (part->is(Part::SEAM) && part->size > 0 && !part->delayed) {
126
- part->delayed = true;
127
- result.clear();
128
- result.push_back({nullptr});
129
- return result;
130
- }
131
- if (last_n == (n - 1) && !result.empty()) {
132
- std::vector<Point*> pts = part->to_vector();
133
- result.back().insert(result.back().end(), pts.begin(), pts.end());
134
- } else {
135
- result.push_back(part->to_vector());
136
- }
137
- last_n = n;
138
- }
139
- }
140
- return result;
141
- };
142
- auto left = collect_sequences(matching_part_indexes, this->parts_);
143
- if (!left.empty() && !left[0].empty() && left[0][0] == nullptr) {
144
- return std::nullopt;
145
- }
146
- auto right = collect_sequences(other_matching_part_indexes, other->parts_);
147
- if (!right.empty() && !right[0].empty() && right[0][0] == nullptr) {
148
- return std::nullopt;
149
- }
150
-
151
- if (part_start != part_end) {
152
- for (int n = end_idx - 1; n > start_idx; --n) {
153
- Part* delete_part = parts_[n];
154
- // Topological detachment of pointers
155
- if (delete_part->prev) delete_part->prev->next = delete_part->next;
156
- if (delete_part->next) delete_part->next->prev = delete_part->prev;
157
- parts_.erase(parts_.begin() + n);
158
- }
159
- }
160
-
161
- std::vector<Part*> all_parts;
162
- Polyline* polyline = static_cast<Polyline*>(this);
163
- all_parts.reserve(before_parts.size() + after_parts.size());
164
- all_parts.insert(all_parts.end(), before_parts.begin(), before_parts.end());
165
- all_parts.insert(all_parts.end(), after_parts.begin(), after_parts.end());
166
- Part* will_be_last = all_parts.empty() ? nullptr : all_parts.back();
167
- for (auto it = all_parts.rbegin(); it != all_parts.rend(); ++it) {
168
- Part* p = *it;
169
- this->insert_after(part_start, p);
170
- auto& op = other->parts_;
171
- op.erase(std::remove(op.begin(), op.end(), p), op.end());
172
- p->set_polyline(polyline);
173
- }
174
-
175
- part_start->type = Part::EXCLUSIVE;
176
- PartPool& pool = polyline->tile->cluster->parts_pool;
177
- Part* new_end_part = pool.acquire(Part::EXCLUSIVE, polyline);
178
- new_end_part->add(part_end->tail);
179
- part_start->singleton();
180
-
181
- // deletes part_end
182
- if (part_start != part_end) {
183
- if (part_end->prev) part_end->prev->next = part_end->next;
184
- if (part_end->next) part_end->next->prev = part_end->prev;
185
- auto it = std::find(parts_.begin(), parts_.end(), part_end);
186
- if (it != parts_.end()) {
187
- parts_.erase(it);
188
- }
189
- }
190
-
191
- Part* reference_part = (will_be_last != nullptr) ? will_be_last : part_start;
192
- this->insert_after(reference_part, new_end_part);
193
-
194
- polyline->reset_tracked_endpoints();
195
-
196
- return std::make_pair(left, right);
197
- }
198
-
199
71
  void Partitionable::trasmute_parts()
200
72
  { std::vector<Part*> insides;
201
73
  for (Part* p : parts_) {
@@ -10,18 +10,13 @@
10
10
  #pragma once
11
11
  #include <vector>
12
12
  #include <utility>
13
- #include <optional>
14
13
  #include "Part.h"
15
14
 
16
- using SewReturnData = std::pair<std::vector<std::vector<Point*>>, std::vector<std::vector<Point*>>>;
17
-
18
15
  class Partitionable {
19
16
  public:
20
17
  explicit Partitionable() {}
21
18
  virtual ~Partitionable() = default;
22
19
  void partition();
23
- Part* find_first_part_by_position(Position* position, int versus);
24
- std::optional<SewReturnData> sew(std::vector<std::pair<int, int>> intersection, Polyline* other);
25
20
  const std::vector<Part*> parts() const { return parts_; }
26
21
 
27
22
  protected:
@@ -29,6 +24,5 @@ class Partitionable {
29
24
 
30
25
  private:
31
26
  void add_part(Part* new_part);
32
- void insert_after(Part* part, Part* new_part);
33
27
  void trasmute_parts();
34
28
  };
@@ -29,15 +29,6 @@ Polyline::Polyline(Tile* tile, const std::vector<Point*>& polygon, const std::op
29
29
  }
30
30
  }
31
31
 
32
- void Polyline::precalc() {
33
- next_tile_eligible_shapes_.clear(); // useless if called once
34
- for (Shape* s : tile->circular_next->boundary_shapes())
35
- { if (!s->outer_polyline->is_on(Polyline::TRACKED_OUTER) && this->vert_intersect(*s->outer_polyline) )
36
- { next_tile_eligible_shapes_.push_back(s);
37
- }
38
- }
39
- }
40
-
41
32
  bool Polyline::vert_intersect(Polyline& other) {
42
33
  return( !(this->max_y_ < other.min_y || other.max_y_ < this->min_y));
43
34
  }
@@ -51,10 +42,6 @@ bool Polyline::boundary() {
51
42
  return( tile->tg_border(Point{min_x, 0}) || tile->tg_border(Point{max_x, 0}));
52
43
  }
53
44
 
54
- void Polyline::reset_tracked_endpoints() {
55
- tracked_endpoints.clear();
56
- }
57
-
58
45
  void Polyline::find_boundary() {
59
46
  if (raw_.empty()) return;
60
47
  min_x = std::numeric_limits<int>::max();
@@ -72,43 +59,6 @@ void Polyline::find_boundary() {
72
59
  }
73
60
  }
74
61
 
75
- std::vector<std::pair<int, int>> Polyline::intersection(const Polyline* other) const {
76
- if (this->tracked_endpoints.empty()) {
77
- for (int i = 0; i < parts_.size(); ++i) {
78
- auto& part = parts_[i];
79
- if (!part->is(Part::SEAM) && part->trasmuted) continue;
80
- part->each([&](QNode<Point>* pos) -> bool {
81
- Position *position = static_cast<Position*>(pos);
82
- if (position->end_point() != nullptr)
83
- { this->tracked_endpoints[position->end_point()] = i;
84
- }
85
- return true;
86
- });
87
- }
88
- }
89
-
90
- std::vector<std::pair<int, int>> matching_parts;
91
- for (int j = 0; j < other->parts_.size(); ++j) {
92
- auto& other_part = other->parts_[j];
93
- if (!other_part->is(Part::SEAM) && other_part->trasmuted) {
94
- continue;
95
- }
96
- other_part->each([&](QNode<Point>* pos) -> bool {
97
- Position *position = static_cast<Position*>(pos);
98
- auto it = this->tracked_endpoints.find(position->end_point());
99
- if (it != this->tracked_endpoints.end()) {
100
- int self_index = it->second;
101
- matching_parts.push_back({self_index, j});
102
- return false;
103
- }
104
- return true;
105
- });
106
- }
107
-
108
- return matching_parts;
109
- }
110
-
111
-
112
62
  void Polyline::clear() {
113
63
  this->raw_.clear();
114
64
  }
@@ -29,8 +29,7 @@ class Polyline : public Partitionable {
29
29
  using Partitionable::Partitionable;
30
30
  Polyline(Tile* tile, const std::vector<Point*>& polygon, const std::optional<RectBounds>& bounds = std::nullopt);
31
31
  enum Flags : uint32_t {
32
- TRACKED_OUTER = 1 << 0,
33
- TRACKED_INNER = 1 << 1
32
+ TRACKED_OUTER = 1 << 0
34
33
  };
35
34
  void turn_on(Flags f) { flags_ |= f; }
36
35
  void turn_off(Flags f) { flags_ &= ~f; }
@@ -41,15 +40,12 @@ class Polyline : public Partitionable {
41
40
  Tile *tile = nullptr;
42
41
  Shape* shape = nullptr;
43
42
  std::vector<Point*> raw() const { return raw_; }
44
- const std::list<Shape*>& next_tile_eligible_shapes() const { return next_tile_eligible_shapes_; }
45
43
  const std::vector<Part*>& parts() const { return parts_; }
46
- std::vector<std::pair<int, int>> intersection(const Polyline* other) const;
47
44
  const int max_y() const { return max_y_; }
48
45
  void clear();
49
46
  bool is_empty();
50
47
  bool vert_intersect(Polyline& other);
51
- void reset_tracked_endpoints();
52
- bool mixed_tile_origin = false;
48
+ bool any_ancients = false;
53
49
  std::string info();
54
50
  bool vert_bounds_intersect(Bounds& vertical_bounds);
55
51
  bool within(std::vector<Point*>& points);
@@ -59,6 +55,4 @@ class Polyline : public Partitionable {
59
55
  int min_x, max_x, min_y, max_y_;
60
56
  void find_boundary();
61
57
  uint32_t flags_ = 0;
62
- std::list<Shape*> next_tile_eligible_shapes_;
63
- mutable std::unordered_map<const EndPoint*, int> tracked_endpoints;
64
58
  };
@@ -7,8 +7,11 @@
7
7
  * See the LICENSE file in this directory for the full license text.
8
8
  */
9
9
  #include <iostream>
10
+ #include <algorithm>
10
11
  #include "Position.h"
11
12
  #include "Hub.h"
13
+ #include "Part.h"
14
+ #include "Polyline.h"
12
15
 
13
16
  Position::Position(Hub* hub, Point* point)
14
17
  : QNode<Point>(point)
@@ -30,9 +33,25 @@ Position::Position(EndPoint* end_point)
30
33
  }
31
34
 
32
35
  void Position::before_rem(Queueable<Point>* q) {
33
- if (this->end_point_ != nullptr) this->end_point_->queues().erase(q);
36
+ /*if (this->end_point_ != nullptr)
37
+ { if (q->listable())
38
+ { auto& v = this->end_point_->queues();
39
+ v.erase(std::remove(v.begin(), v.end(), q), v.end());
40
+ }
41
+ }*/
34
42
  }
35
43
 
36
- void Position::after_add(Queueable<Point>* q) {
37
- if (this->end_point_ != nullptr) this->end_point_->queues().insert(q);
44
+ void Position::after_add(Queueable<Point>* q) {
45
+ if (this->end_point_ != nullptr && q->listable()) {
46
+ auto& q_vec = this->end_point_->queues();
47
+ auto it = std::find(q_vec.begin(), q_vec.end(), q);
48
+ if (it == q_vec.end()) {
49
+ q_vec.push_back(q);
50
+ if (q_vec.size() > 1) {
51
+ static_cast<Part*>(q)->polyline()->any_ancients = true;
52
+ Queueable<Point>* first_q = q_vec.front();
53
+ static_cast<Part*>(first_q)->polyline()->any_ancients = true;
54
+ }
55
+ }
56
+ }
38
57
  }
@@ -39,6 +39,7 @@ class Queueable {
39
39
  QNode<T>* _iterator {nullptr};
40
40
  bool _started = false;
41
41
  size_t size {0};
42
+ virtual bool listable() const { return false; }
42
43
  Queueable() = default;
43
44
  virtual ~Queueable() = default;
44
45
 
@@ -75,53 +76,6 @@ class Queueable {
75
76
  node->after_add(this);
76
77
  }
77
78
 
78
- void reset() {
79
- head = nullptr;
80
- tail = nullptr;
81
- _iterator = nullptr;
82
- _started = false;
83
- size = 0;
84
- }
85
-
86
- void singleton()
87
- { if (head && head->next) {
88
- head->next->prev = nullptr;
89
- head->next = nullptr;
90
- }
91
- tail = nullptr;
92
- size = 1;
93
- _iterator = nullptr;
94
- _started = false;
95
- }
96
-
97
- void replace(Queueable<T>& q) {
98
- reset();
99
- append(q);
100
- }
101
-
102
- void append(Queueable<T>& q) {
103
- if (q.size == 0) return;
104
- QNode<T>* current = q.head;
105
- while (current) {
106
- current->before_rem(&q);
107
- current->owner = this;
108
- current = current->next;
109
- }
110
- if (tail) {
111
- tail->next = q.head;
112
- q.head->prev = tail;
113
- } else {
114
- head = q.head;
115
- }
116
- tail = q.tail;
117
- size += q.size;
118
- q.reset();
119
- each([&](QNode<T>* n) -> bool {
120
- n->after_add(this);
121
- return(true);
122
- });
123
- }
124
-
125
79
  void rewind() {
126
80
  _iterator = nullptr;
127
81
  _started = false;
@@ -198,14 +152,4 @@ class Queueable {
198
152
  if (!tail) return nullptr;
199
153
  return rem(tail);
200
154
  }
201
-
202
- bool contains(const T& value) const {
203
- QNode<T>* current = head;
204
- while (current) {
205
- if (current->payload == value)
206
- return true;
207
- current = current->next;
208
- }
209
- return false;
210
- }
211
155
  };
@@ -104,18 +104,6 @@ std::string Tile::toString() {
104
104
  return s;
105
105
  }
106
106
 
107
- const std::list<Shape*>& Tile::boundary_shapes()
108
- { if (!boundary_shapes_initialized_)
109
- { for (Shape* s : shapes_)
110
- { if (s->outer_polyline->boundary())
111
- { boundary_shapes_.push_back(s);
112
- }
113
- }
114
- boundary_shapes_initialized_ = true;
115
- }
116
- return boundary_shapes_;
117
- }
118
-
119
107
  std::list<Polygon> Tile::to_raw_polygons()
120
108
  { std::list<Polygon> retme;
121
109
  for (Shape* s : shapes_)
@@ -31,8 +31,6 @@ class Tile {
31
31
  int end_x_;
32
32
  std::string name_;
33
33
  std::list<Shape*> shapes_;
34
- std::list<Shape*> boundary_shapes_;
35
- bool boundary_shapes_initialized_ = false;
36
34
 
37
35
  public:
38
36
  Tile(Finder *finder, int start_x, int end_x, std::string name, const Benchmarks& b);
@@ -46,7 +44,6 @@ class Tile {
46
44
  std::string name() const { return name_; }
47
45
  const std::list<Shape*>& shapes() const { return shapes_; }
48
46
  std::list<Shape*>& shapes() { return shapes_; }
49
- const std::list<Shape*>& boundary_shapes();
50
47
  bool whole();
51
48
  bool left();
52
49
  bool right();
@@ -12,6 +12,7 @@
12
12
  #include <vector>
13
13
  #include <algorithm>
14
14
  #include <utility>
15
+ #include <unordered_set>
15
16
  #include "VerticalMerger.h"
16
17
 
17
18
  VerticalMerger::VerticalMerger(int number_of_threads, std::vector<std::string> *options)
@@ -35,14 +36,21 @@ ProcessResult* VerticalMerger::process_info() {
35
36
 
36
37
  void VerticalMerger::transpose(ProcessResult& result) {
37
38
  std::swap(result.width, result.height);
38
-
39
+ std::unordered_set<Point*> seen;
39
40
  for (auto& polygon : result.polygons) {
41
+ auto process_p = [&](Point* p) {
42
+ if (p) {
43
+ if (seen.insert(p).second) {
44
+ std::swap(p->x, p->y);
45
+ }
46
+ }
47
+ };
40
48
  for (Point* p : polygon.outer) {
41
- if (p) std::swap(p->x, p->y);
49
+ process_p(p);
42
50
  }
43
51
  for (auto& sequence : polygon.inner) {
44
52
  for (Point* p : sequence) {
45
- if (p) std::swap(p->x, p->y);
53
+ process_p(p);
46
54
  }
47
55
  }
48
56
  std::swap(polygon.bounds.min_x, polygon.bounds.min_y);
@@ -6,6 +6,9 @@
6
6
  * Copyright 2025 Emanuele Cesaroni
7
7
  */
8
8
 
9
+ #ifdef HAVE_TCMALLOC
10
+ #include <gperftools/malloc_extension.h>
11
+ #endif
9
12
  #include <iostream>
10
13
  #include <list>
11
14
  #include <vector>
@@ -286,6 +289,13 @@ ProcessResult ruby_result_to_process_result(Rice::Object rb_result) {
286
289
 
287
290
  extern "C"
288
291
  void Init_cpp_polygon_finder() {
292
+ #ifdef HAVE_TCMALLOC
293
+ MallocExtension::instance()->SetNumericProperty(
294
+ "tcmalloc.max_total_thread_cache_bytes",
295
+ 1024 * 1024 * 1024
296
+ );
297
+ #endif
298
+
289
299
  Data_Type<Bitmap> rb_cBitmap =
290
300
  define_class<Bitmap>("CPPBitMap")
291
301
  .define_constructor(Constructor<Bitmap, std::string, int>())
@@ -6,7 +6,7 @@ module Contrek
6
6
  def initialize(finder:, height:, start_x:, end_x:)
7
7
  @finder = finder
8
8
  @tiles = []
9
- @hub = Hub.new(height:, start_x:, end_x:)
9
+ @hub = Hub.new(height: )
10
10
  end
11
11
 
12
12
  def add(tile)
@@ -34,7 +34,6 @@ module Contrek
34
34
  next if shape.outer_polyline.on?(Polyline::TRACKED_OUTER) || shape.outer_polyline.width == 0
35
35
  if shape.outer_polyline.boundary?
36
36
  shape.outer_polyline.partition!
37
- shape.outer_polyline.precalc!
38
37
  end
39
38
  end
40
39
  end
@@ -44,7 +43,7 @@ module Contrek
44
43
  tile.shapes.each do |shape|
45
44
  next if shape.outer_polyline.on?(Polyline::TRACKED_OUTER) || shape.outer_polyline.width == 0
46
45
 
47
- if shape.outer_polyline.boundary? && shape.outer_polyline.next_tile_eligible_shapes.any?
46
+ if shape.outer_polyline.any_ancients
48
47
  cursor = Cursor.new(cluster: self, shape: shape)
49
48
 
50
49
  new_outer = nil