contrek 1.0.7 → 1.0.9

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +80 -8
  5. data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +39 -0
  6. data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +43 -0
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +72 -0
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +19 -24
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +1 -2
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +3 -5
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +1 -1
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +2 -2
  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 +29 -9
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +1 -0
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +11 -1
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +6 -5
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +12 -8
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +2 -1
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +2 -0
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +108 -66
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +5 -3
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +35 -28
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +5 -1
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +13 -10
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +1 -1
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +16 -22
  28. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +1 -1
  29. data/lib/contrek/bitmaps/rgb_color.rb +0 -15
  30. data/lib/contrek/bitmaps/rgb_cpp_color.rb +10 -0
  31. data/lib/contrek/finder/concurrent/cluster.rb +2 -2
  32. data/lib/contrek/finder/concurrent/cursor.rb +34 -16
  33. data/lib/contrek/finder/concurrent/finder.rb +12 -1
  34. data/lib/contrek/finder/concurrent/hub.rb +3 -4
  35. data/lib/contrek/finder/concurrent/part.rb +8 -2
  36. data/lib/contrek/finder/concurrent/partitionable.rb +61 -33
  37. data/lib/contrek/finder/concurrent/polyline.rb +45 -2
  38. data/lib/contrek/finder/concurrent/position.rb +3 -4
  39. data/lib/contrek/finder/concurrent/queueable.rb +12 -20
  40. data/lib/contrek/version.rb +1 -1
  41. data/lib/contrek.rb +4 -3
  42. metadata +6 -4
  43. data/ext/cpp_polygon_finder/PolygonFinder/Makefile +0 -44
  44. data/ext/cpp_polygon_finder/PolygonFinder/src/Main.cpp +0 -50
@@ -9,6 +9,7 @@
9
9
  #include <vector>
10
10
  #include <utility>
11
11
  #include <iostream>
12
+ #include <algorithm>
12
13
  #include "Partitionable.h"
13
14
  #include "Polyline.h"
14
15
  #include "Sequence.h"
@@ -31,6 +32,17 @@ void Partitionable::add_part(Part* new_part)
31
32
  new_part->circular_next = this->parts_.front();
32
33
  }
33
34
 
35
+ void Partitionable::insert_after(Part* part, Part* new_part) {
36
+ auto it = std::find(parts_.begin(), parts_.end(), part);
37
+ if (it != parts_.end()) parts_.insert(it + 1, new_part);
38
+ new_part->prev = part;
39
+ new_part->next = part->next;
40
+ new_part->circular_next = part->next;
41
+ if (part->next) part->next->prev = new_part;
42
+ part->next = new_part;
43
+ part->circular_next = new_part;
44
+ }
45
+
34
46
  void Partitionable::partition()
35
47
  { this->parts_.clear();
36
48
  Polyline *polyline = dynamic_cast<Polyline*>(this);
@@ -73,85 +85,115 @@ Part* Partitionable::find_first_part_by_position(Position* position) {
73
85
  return(nullptr);
74
86
  }
75
87
 
76
- std::pair<
77
- std::vector<std::vector<Point*>>,
78
- std::vector<std::vector<Point*>>
79
- >
80
- Partitionable::sew(std::vector<Point*> intersection, Polyline* other)
81
- { std::vector<int> matching_part_indexes;
82
- for (int i = 0; i < static_cast<int>(parts_.size()); ++i) {
83
- Part* part = parts_[i];
84
- if (!part || part->trasmuted) continue;
85
- if (part->intersection_with_array(intersection)) {
86
- matching_part_indexes.push_back(i);
87
- }
88
- }
88
+ std::optional<SewReturnData> Partitionable::sew(std::vector<std::pair<int, int>> intersection, Polyline* other)
89
+ { std::vector<int> matching_part_indexes;
89
90
  std::vector<int> other_matching_part_indexes;
90
- for (int i = 0; i < static_cast<int>(other->parts_.size()); ++i) {
91
- Part* part = other->parts_[i];
92
- if (!part || part->trasmuted) continue;
93
- if (part->intersection_with_array(intersection)) {
94
- other_matching_part_indexes.push_back(i);
95
- }
91
+ matching_part_indexes.reserve(intersection.size());
92
+ other_matching_part_indexes.reserve(intersection.size());
93
+
94
+ // traspose
95
+ for (const auto& pair : intersection) {
96
+ matching_part_indexes.push_back(pair.first);
97
+ other_matching_part_indexes.push_back(pair.second);
96
98
  }
97
- std::vector<Part*> before_parts;
98
- for (int i = other_matching_part_indexes.back() + 1;
99
- i < static_cast<int>(other->parts_.size()); ++i)
100
- { before_parts.push_back(other->parts_[i]);
99
+ std::sort(matching_part_indexes.begin(), matching_part_indexes.end());
100
+ std::sort(other_matching_part_indexes.begin(), other_matching_part_indexes.end());
101
+
102
+ auto start_it_before = other->parts_.begin() + other_matching_part_indexes.back() + 1;
103
+ auto end_it_before = other->parts_.end();
104
+ std::vector<Part*> before_parts(start_it_before, end_it_before);
105
+ auto start_it_after = other->parts_.begin();
106
+ auto end_it_after = other->parts_.begin() + other_matching_part_indexes.front();
107
+ std::vector<Part*> after_parts(start_it_after, end_it_after);
108
+
109
+ int start_idx = matching_part_indexes.front();
110
+ int end_idx = matching_part_indexes.back();
111
+ Part* part_start = parts_[start_idx];
112
+ Part* part_end = parts_[end_idx];
113
+
114
+ auto collect_sequences = [&](const std::vector<int>& indices, std::vector<Part*>& p_list)
115
+ -> std::vector<std::vector<Point*>> {
116
+ std::vector<std::vector<Point*>> result;
117
+ int last_n = -1;
118
+ if (indices.size() < 2) return result;
119
+ for (int n = indices.front() + 1; n < indices.back(); ++n) {
120
+ if (std::find(indices.begin(), indices.end(), n) == indices.end()) {
121
+ Part* part = p_list[n];
122
+ if (part->is(Part::SEAM) && part->size > 0 && !part->delayed) {
123
+ part->delayed = true;
124
+ result.clear();
125
+ result.push_back({nullptr});
126
+ return result;
127
+ }
128
+ if (last_n == (n - 1) && !result.empty()) {
129
+ std::vector<Point*> pts = part->to_vector();
130
+ result.back().insert(result.back().end(), pts.begin(), pts.end());
131
+ } else {
132
+ result.push_back(part->to_vector());
133
+ }
134
+ last_n = n;
135
+ }
136
+ }
137
+ return result;
138
+ };
139
+ auto left = collect_sequences(matching_part_indexes, this->parts_);
140
+ if (!left.empty() && !left[0].empty() && left[0][0] == nullptr) {
141
+ return std::nullopt;
101
142
  }
102
- std::vector<Part*> after_parts;
103
- for (int i = 0; i < other_matching_part_indexes.front(); ++i) {
104
- after_parts.push_back(other->parts_[i]);
143
+ auto right = collect_sequences(other_matching_part_indexes, other->parts_);
144
+ if (!right.empty() && !right[0].empty() && right[0][0] == nullptr) {
145
+ return std::nullopt;
105
146
  }
106
- Part* part_start = parts_[matching_part_indexes.front()];
107
- Part* part_end = parts_[matching_part_indexes.back()];
108
- // They are inverted since they traverse in opposite directions
109
- Sequence sequence;
110
- sequence.add(part_start->head);
111
- for (Part* p : before_parts) sequence.append(*p);
112
- for (Part* p : after_parts) sequence.append(*p);
113
- if (part_end->tail) sequence.add(part_end->tail);
114
- part_start->replace(sequence);
115
- part_start->type = Part::EXCLUSIVE;
116
- if (part_start != part_end) part_end->reset();
117
-
118
- std::vector<std::vector<Point*>> left;
119
-
120
- for (int n = matching_part_indexes.front() + 1;
121
- n <= matching_part_indexes.back() - 1;
122
- ++n)
123
- { if (std::find(matching_part_indexes.begin(),
124
- matching_part_indexes.end(),
125
- n) == matching_part_indexes.end())
126
- { auto pts = parts_[n]->to_vector();
127
- left.push_back(pts);
147
+
148
+ if (part_start != part_end) {
149
+ for (int n = end_idx - 1; n > start_idx; --n) {
150
+ Part* delete_part = parts_[n];
151
+ // Topological detachment of pointers
152
+ if (delete_part->prev) delete_part->prev->next = delete_part->next;
153
+ if (delete_part->next) delete_part->next->prev = delete_part->prev;
154
+ parts_.erase(parts_.begin() + n);
128
155
  }
129
156
  }
130
157
 
131
- // delete parts in reverse order
132
- for (int n = matching_part_indexes.back() - 1;
133
- n >= matching_part_indexes.front() + 1;
134
- --n)
135
- { Part* delete_part = parts_[n];
136
- if (delete_part->prev) delete_part->prev->next = delete_part->next;
137
- if (delete_part->next) delete_part->next->prev = delete_part->prev;
138
- parts_.erase(parts_.begin() + n);
158
+ std::vector<Part*> all_parts;
159
+ Polyline* polyline = dynamic_cast<Polyline*>(this);
160
+ all_parts.reserve(before_parts.size() + after_parts.size());
161
+ all_parts.insert(all_parts.end(), before_parts.begin(), before_parts.end());
162
+ all_parts.insert(all_parts.end(), after_parts.begin(), after_parts.end());
163
+ Part* will_be_last = all_parts.empty() ? nullptr : all_parts.back();
164
+ for (auto it = all_parts.rbegin(); it != all_parts.rend(); ++it) {
165
+ Part* p = *it;
166
+ this->insert_after(part_start, p);
167
+ auto& op = other->parts_;
168
+ op.erase(std::remove(op.begin(), op.end(), p), op.end());
169
+ p->set_polyline(polyline);
139
170
  }
140
171
 
141
- std::vector<std::vector<Point*>> right;
142
- for (int n = other_matching_part_indexes.front() + 1;
143
- n <= other_matching_part_indexes.back() - 1;
144
- ++n)
145
- { if (std::find(other_matching_part_indexes.begin(),
146
- other_matching_part_indexes.end(),
147
- n) == other_matching_part_indexes.end())
148
- { auto pts = other->parts_[n]->to_vector();
149
- right.push_back(pts);
172
+ part_start->type = Part::EXCLUSIVE;
173
+ PartPool& pool = polyline->tile->cluster->parts_pool;
174
+ Part* new_end_part = pool.acquire(Part::EXCLUSIVE, polyline);
175
+ new_end_part->add(part_end->tail);
176
+ part_start->singleton();
177
+
178
+ // deletes part_end
179
+ if (part_start != part_end) {
180
+ if (part_end->prev) part_end->prev->next = part_end->next;
181
+ if (part_end->next) part_end->next->prev = part_end->prev;
182
+ auto it = std::find(parts_.begin(), parts_.end(), part_end);
183
+ if (it != parts_.end()) {
184
+ parts_.erase(it);
150
185
  }
151
186
  }
152
- return { left, right };
187
+
188
+ Part* reference_part = (will_be_last != nullptr) ? will_be_last : part_start;
189
+ this->insert_after(reference_part, new_end_part);
190
+
191
+ polyline->reset_tracked_endpoints();
192
+
193
+ return std::make_pair(left, right);
153
194
  }
154
195
 
196
+
155
197
  void Partitionable::trasmute_parts()
156
198
  { std::vector<Part*> insides;
157
199
  for (Part* p : parts_) {
@@ -9,22 +9,24 @@
9
9
  #pragma once
10
10
  #include <vector>
11
11
  #include <utility>
12
+ #include <optional>
12
13
  #include "Part.h"
13
14
 
15
+ using SewReturnData = std::pair<std::vector<std::vector<Point*>>, std::vector<std::vector<Point*>>>;
16
+
14
17
  class Partitionable {
15
18
  public:
16
19
  explicit Partitionable() {}
17
20
  virtual ~Partitionable() = default;
18
21
  void partition();
19
22
  Part* find_first_part_by_position(Position* position);
20
- std::pair<
21
- std::vector<std::vector<Point*>>,
22
- std::vector<std::vector<Point*>>> sew(std::vector<Point*> intersection, Polyline* other);
23
+ std::optional<SewReturnData> sew(std::vector<std::pair<int, int>> intersection, Polyline* other);
23
24
 
24
25
  protected:
25
26
  std::vector<Part*> parts_;
26
27
 
27
28
  private:
28
29
  void add_part(Part* new_part);
30
+ void insert_after(Part* part, Part* new_part);
29
31
  void trasmute_parts();
30
32
  };
@@ -48,6 +48,10 @@ bool Polyline::boundary() {
48
48
  return( tile->tg_border(Point{min_x, 0}) || tile->tg_border(Point{max_x, 0}));
49
49
  }
50
50
 
51
+ void Polyline::reset_tracked_endpoints() {
52
+ tracked_endpoints.clear();
53
+ }
54
+
51
55
  void Polyline::find_boundary() {
52
56
  if (raw_.empty()) return;
53
57
  min_x = std::numeric_limits<int>::max();
@@ -65,40 +69,43 @@ void Polyline::find_boundary() {
65
69
  }
66
70
  }
67
71
 
68
- struct PointHash {
69
- size_t operator()(const Point* p) const {
70
- if (!p) return 0;
71
- std::hash<double> hasher;
72
- size_t h1 = hasher(p->x);
73
- size_t h2 = hasher(p->y);
74
- return h1 ^ (h2 << 1);
75
- }
76
- };
77
-
78
- struct PointEqual {
79
- bool operator()(const Point* p1, const Point* p2) const {
80
- if (!p1 || !p2) return p1 == p2;
81
- return *p1 == *p2;
72
+ std::vector<std::pair<int, int>> Polyline::intersection(const Polyline* other) const {
73
+ if (this->tracked_endpoints.empty()) {
74
+ for (int i = 0; i < parts_.size(); ++i) {
75
+ auto& part = parts_[i];
76
+ if (!part->is(Part::SEAM) && part->trasmuted) continue;
77
+ part->each([&](QNode<Point>* pos) -> bool {
78
+ Position *position = dynamic_cast<Position*>(pos);
79
+ if (position->end_point() != nullptr)
80
+ { this->tracked_endpoints[position->end_point()] = i;
81
+ }
82
+ return true;
83
+ });
84
+ }
82
85
  }
83
- };
84
86
 
85
- std::vector<Point*> Polyline::intersection(const Polyline* other) const {
86
- std::vector<Point*> result;
87
- if (!other) return result;
88
- std::unordered_set<Point*, PointHash, PointEqual> other_set;
89
- other_set.reserve(other->raw().size());
90
- for (Point* p : other->raw()) {
91
- if (p) other_set.insert(p);
92
- }
93
- for (Point* p : raw_) {
94
- if (!p) continue;
95
- if (other_set.count(p)) {
96
- result.push_back(p);
87
+ std::vector<std::pair<int, int>> matching_parts;
88
+ for (int j = 0; j < other->parts_.size(); ++j) {
89
+ auto& other_part = other->parts_[j];
90
+ if (!other_part->is(Part::SEAM) && other_part->trasmuted) {
91
+ continue;
97
92
  }
93
+ other_part->each([&](QNode<Point>* pos) -> bool {
94
+ Position *position = dynamic_cast<Position*>(pos);
95
+ auto it = this->tracked_endpoints.find(position->end_point());
96
+ if (it != this->tracked_endpoints.end()) {
97
+ int self_index = it->second;
98
+ matching_parts.push_back({self_index, j});
99
+ return false;
100
+ }
101
+ return true;
102
+ });
98
103
  }
99
- return result;
104
+
105
+ return matching_parts;
100
106
  }
101
107
 
108
+
102
109
  void Polyline::clear() {
103
110
  this->raw_.clear();
104
111
  }
@@ -10,7 +10,9 @@
10
10
  #include <list>
11
11
  #include <cstdint>
12
12
  #include <optional>
13
+ #include <utility>
13
14
  #include <vector>
15
+ #include <unordered_map>
14
16
  #include "Partitionable.h"
15
17
  #include "../RectBounds.h"
16
18
 
@@ -37,11 +39,12 @@ class Polyline : public Partitionable {
37
39
  std::vector<Point*> raw() const { return raw_; }
38
40
  const std::list<Shape*>& next_tile_eligible_shapes() const { return next_tile_eligible_shapes_; }
39
41
  const std::vector<Part*>& parts() const { return parts_; }
40
- std::vector<Point*> intersection(const Polyline* other) const;
42
+ std::vector<std::pair<int, int>> intersection(const Polyline* other) const;
41
43
  const int max_y() const { return max_y_; }
42
44
  void clear();
43
45
  bool is_empty();
44
46
  bool vert_intersect(Polyline& other);
47
+ void reset_tracked_endpoints();
45
48
 
46
49
  private:
47
50
  std::vector<Point*> raw_;
@@ -49,4 +52,5 @@ class Polyline : public Partitionable {
49
52
  void find_boundary();
50
53
  uint32_t flags_ = 0;
51
54
  std::list<Shape*> next_tile_eligible_shapes_;
55
+ mutable std::unordered_map<const EndPoint*, int> tracked_endpoints;
52
56
  };
@@ -11,21 +11,24 @@
11
11
 
12
12
  Position::Position(Hub* hub, Point* point)
13
13
  : QNode<Point>(point)
14
- { int key = point->y * hub->width() + point->x;
15
- EndPoint* existing_ep = hub->get(key);
16
- if (existing_ep == nullptr)
17
- { end_point_ = hub->spawn_end_point();
18
- hub->put(key, end_point_);
19
- } else {
20
- end_point_ = existing_ep;
14
+ { if (hub != nullptr) {
15
+ int key = point->y;
16
+ EndPoint* existing_ep = hub->get(key);
17
+ if (existing_ep == nullptr)
18
+ { end_point_ = hub->put(key, hub->spawn_end_point());
19
+ } else {
20
+ end_point_ = existing_ep;
21
+ }
21
22
  }
22
23
  }
23
24
 
24
25
  void Position::before_rem(Queueable<Point>* q) {
25
- auto& queues = this->end_point_->queues();
26
- queues.erase(std::remove(queues.begin(), queues.end(), q), queues.end());
26
+ if (this->end_point_ != nullptr) {
27
+ auto& queues = this->end_point_->queues();
28
+ queues.erase(std::remove(queues.begin(), queues.end(), q), queues.end());
29
+ }
27
30
  }
28
31
 
29
32
  void Position::after_add(Queueable<Point>* q) {
30
- this->end_point_->queues().push_back(q);
33
+ if (this->end_point_ != nullptr) this->end_point_->queues().push_back(q);
31
34
  }
@@ -21,5 +21,5 @@ class Position : public QNode<Point>{
21
21
  void before_rem(Queueable<Point>* q) override;
22
22
  void after_add(Queueable<Point>* q) override;
23
23
  private:
24
- EndPoint* end_point_;
24
+ EndPoint* end_point_ = nullptr;
25
25
  };
@@ -43,8 +43,7 @@ class Queueable {
43
43
 
44
44
  QNode<T>* rem(QNode<T>* node) {
45
45
  if (!node) return nullptr;
46
- if (node->owner != this)
47
- throw std::runtime_error("Not my node");
46
+ // if (node->owner != this) throw std::runtime_error("Not my node");
48
47
  node->before_rem(this);
49
48
  if (node->prev) node->prev->next = node->next;
50
49
  if (node->next) node->next->prev = node->prev;
@@ -79,9 +78,21 @@ class Queueable {
79
78
  head = nullptr;
80
79
  tail = nullptr;
81
80
  _iterator = nullptr;
81
+ _started = false;
82
82
  size = 0;
83
83
  }
84
84
 
85
+ void singleton()
86
+ { if (head && head->next) {
87
+ head->next->prev = nullptr;
88
+ head->next = nullptr;
89
+ }
90
+ tail = nullptr;
91
+ size = 1;
92
+ _iterator = nullptr;
93
+ _started = false;
94
+ }
95
+
85
96
  void replace(Queueable<T>& q) {
86
97
  reset();
87
98
  append(q);
@@ -130,8 +141,8 @@ class Queueable {
130
141
  }
131
142
 
132
143
  void next_of(QNode<T>* node) {
133
- if (!node) throw std::runtime_error("nil node");
134
- if (node->owner != this) throw std::runtime_error("wrong node");
144
+ // if (!node) throw std::runtime_error("nil node");
145
+ // if (node->owner != this) throw std::runtime_error("wrong node");
135
146
  _iterator = node->next;
136
147
  _started = true;
137
148
  }
@@ -181,23 +192,6 @@ class Queueable {
181
192
  return out;
182
193
  }
183
194
 
184
- bool intersection_with_array(const std::vector<T*>& array) {
185
- if (array.empty() || size == 0) return false;
186
-
187
- QNode<T>* current = head;
188
- while (current) {
189
- if (current->payload) {
190
- for (T* item : array) {
191
- if (item && *item == *(current->payload)) {
192
- return true;
193
- }
194
- }
195
- }
196
- current = current->next;
197
- }
198
- return false;
199
- }
200
-
201
195
  QNode<T>* pop() {
202
196
  if (!tail) return nullptr;
203
197
  return rem(tail);
@@ -220,7 +214,7 @@ class Queueable {
220
214
 
221
215
  for (T* current : source) {
222
216
  if (!result.empty() && *result.back() == *current) {
223
- result.pop_back(); // "Annulla" la coppia invece di ricominciare
217
+ result.pop_back();
224
218
  } else {
225
219
  result.push_back(current);
226
220
  }
@@ -267,7 +267,7 @@ void Init_cpp_polygon_finder() {
267
267
 
268
268
  Data_Type<RGBNotMatcher> rb_cRGBNotMatcher =
269
269
  define_class<RGBNotMatcher, Matcher>("CPPRGBNotMatcher")
270
- .define_constructor(Constructor<RGBNotMatcher, int>())
270
+ .define_constructor(Constructor<RGBNotMatcher, unsigned int>())
271
271
  .define_method("match", &RGBNotMatcher::match);
272
272
 
273
273
  Data_Type<PolygonFinder> rb_cPolygonFinder =
@@ -3,23 +3,8 @@ module Contrek
3
3
  class RgbColor
4
4
  attr_reader :raw
5
5
  def initialize(r:, g:, b:, a: 255)
6
- @r = r
7
- @g = g
8
- @b = b
9
- @a = a
10
6
  @raw = (r << 24) + (g << 16) + (b << 8) + a
11
7
  end
12
-
13
- def to_rgb_raw
14
- @raw >> 8
15
- end
16
-
17
- def self.reverse_raw(raw)
18
- [:a, :b, :g, :r].each_with_object({}) do |c, h|
19
- h[c] = raw & 0xFF
20
- raw >>= 8
21
- end
22
- end
23
8
  end
24
9
  end
25
10
  end
@@ -0,0 +1,10 @@
1
+ module Contrek
2
+ module Bitmaps
3
+ class RgbCppColor
4
+ attr_reader :raw
5
+ def initialize(r:, g:, b:, a: 255)
6
+ @raw = (a << 24) | (b << 16) | (g << 8) | r
7
+ end
8
+ end
9
+ end
10
+ end
@@ -3,10 +3,10 @@ module Contrek
3
3
  class Cluster
4
4
  attr_reader :tiles, :hub
5
5
 
6
- def initialize(finder:, height:, width:)
6
+ def initialize(finder:, height:, start_x:, end_x:)
7
7
  @finder = finder
8
8
  @tiles = []
9
- @hub = Hub.new(height:, width:)
9
+ @hub = Hub.new(height:, start_x:, end_x:)
10
10
  end
11
11
 
12
12
  def add(tile)
@@ -54,34 +54,51 @@ module Contrek
54
54
  missing_shapes << shape
55
55
  end
56
56
  end
57
+ to_delay = connect_missings(missing_shapes)
58
+ while to_delay.any?
59
+ to_delay = connect_missings(to_delay)
60
+ end
61
+
62
+ retme = collect_inner_sequences(outer_seq)
63
+
64
+ @polylines_sequence.each do |polyline|
65
+ polyline.turn_on(Polyline::TRACKED_INNER)
66
+ end
67
+ retme
68
+ end
69
+
70
+ private
71
+
72
+ def connect_missings(missing_shapes)
73
+ delay_shapes = []
74
+
57
75
  @polylines_sequence.each do |polyline|
58
76
  missing_shapes.each do |missing_shape|
59
- outer_polyline = missing_shape.outer_polyline
60
- next unless polyline.vert_intersect?(outer_polyline)
61
- if (intersection = polyline.intersection(outer_polyline)).any?
62
- inject_sequences_left, inject_sequences_right = polyline.sew!(intersection, outer_polyline)
77
+ missing_outer_polyline = missing_shape.outer_polyline
78
+ next if missing_outer_polyline.on?(Polyline::TRACKED_OUTER) ||
79
+ !polyline.vert_intersect?(missing_outer_polyline)
80
+
81
+ if (intersection = polyline.intersection(missing_outer_polyline)).any?
82
+ inject_sequences_left, inject_sequences_right = polyline.sew!(intersection, missing_outer_polyline)
83
+ if inject_sequences_left.nil?
84
+ delay_shapes << missing_shape
85
+ next
86
+ end
63
87
  combine!(inject_sequences_right, inject_sequences_left).each do |sewn_sequence|
64
88
  sewn_sequence.uniq!
65
89
  @orphan_inners << sewn_sequence if sewn_sequence.size > 1 && sewn_sequence.map { |c| c[:x] }.uniq.size > 1 # segmenti non sono ammessi, solo aree
66
90
  end
67
- outer_polyline.clear!
68
- outer_polyline.turn_on(Polyline::TRACKED_OUTER)
69
- outer_polyline.turn_on(Polyline::TRACKED_INNER)
91
+ missing_outer_polyline.clear!
92
+ missing_outer_polyline.turn_on(Polyline::TRACKED_OUTER)
93
+ missing_outer_polyline.turn_on(Polyline::TRACKED_INNER)
70
94
  @orphan_inners += missing_shape.inner_polylines
71
95
  end
72
96
  end
73
97
  end
74
98
 
75
- retme = collect_inner_sequences(outer_seq)
76
-
77
- @polylines_sequence.each do |polyline|
78
- polyline.turn_on(Polyline::TRACKED_INNER)
79
- end
80
- retme
99
+ delay_shapes
81
100
  end
82
101
 
83
- private
84
-
85
102
  # rubocop:disable Lint/NonLocalExitFromIterator
86
103
  def traverse_outer(act_part, all_parts, polylines, shapes, outer_joined_polyline)
87
104
  all_parts << act_part if all_parts.last != act_part
@@ -165,7 +182,8 @@ module Contrek
165
182
  else
166
183
  act_part.polyline.next_tile_eligible_shapes.each do |shape|
167
184
  shape.outer_polyline.parts.each do |dest_part|
168
- next if dest_part.trasmuted
185
+ next if dest_part.trasmuted || dest_part.is?(Part::EXCLUSIVE)
186
+
169
187
  if dest_part.intersect_part?(act_part)
170
188
  link_seq = duplicates_intersection(dest_part, act_part)
171
189
  if link_seq.any?
@@ -98,7 +98,18 @@ module Contrek
98
98
  return
99
99
  end
100
100
  if (twin_tile = arriving_tiles.find { |b| (b.start_x == (tile.end_x - 1)) || ((b.end_x - 1) == tile.start_x) })
101
- cluster = Cluster.new(finder: self, height: bitmap.h, width: bitmap.w)
101
+
102
+ if twin_tile.start_x == (tile.end_x - 1)
103
+ start_x = tile.start_x
104
+ end_x = twin_tile.end_x
105
+ else
106
+ start_x = twin_tile.start_x
107
+ end_x = tile.end_x
108
+ end
109
+
110
+ # puts "start = #{start_x} end = #{end_x}"
111
+
112
+ cluster = Cluster.new(finder: self, height: bitmap.h, start_x:, end_x:)
102
113
  if twin_tile.start_x == (tile.end_x - 1)
103
114
  cluster.add(tile)
104
115
  cluster.add(twin_tile)
@@ -1,10 +1,9 @@
1
1
  module Contrek
2
2
  module Concurrent
3
3
  class Hub
4
- attr_reader :payloads, :width
5
- def initialize(height:, width:)
6
- @width = width
7
- # @payloads = Array.new(width * height)
4
+ attr_reader :payloads
5
+ def initialize(height:, start_x:, end_x:)
6
+ # @payloads = Array.new(height)
8
7
  @payloads = {}
9
8
  end
10
9
  end