contrek 1.0.6 → 1.0.8

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +102 -6
  5. data/ext/cpp_polygon_finder/PolygonFinder/Makefile +4 -4
  6. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +5 -4
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +3 -5
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +1 -1
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +2 -2
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +1 -1
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +28 -8
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +1 -0
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +12 -1
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +5 -5
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +11 -7
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +2 -0
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +108 -66
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +5 -3
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +33 -28
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +5 -1
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +2 -3
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +15 -20
  23. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +128 -131
  24. data/lib/contrek/bitmaps/rgb_color.rb +0 -15
  25. data/lib/contrek/bitmaps/rgb_cpp_color.rb +10 -0
  26. data/lib/contrek/finder/concurrent/cluster.rb +2 -2
  27. data/lib/contrek/finder/concurrent/cursor.rb +32 -15
  28. data/lib/contrek/finder/concurrent/finder.rb +23 -9
  29. data/lib/contrek/finder/concurrent/hub.rb +2 -2
  30. data/lib/contrek/finder/concurrent/part.rb +6 -1
  31. data/lib/contrek/finder/concurrent/partitionable.rb +61 -33
  32. data/lib/contrek/finder/concurrent/polyline.rb +44 -2
  33. data/lib/contrek/finder/concurrent/queueable.rb +12 -20
  34. data/lib/contrek/finder/polygon_finder.rb +8 -6
  35. data/lib/contrek/finder/result.rb +13 -0
  36. data/lib/contrek/results/cpp_result.rb +21 -0
  37. data/lib/contrek/version.rb +1 -1
  38. data/lib/contrek.rb +6 -3
  39. metadata +5 -2
@@ -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,41 @@ 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
+ this->tracked_endpoints[position->end_point()] = i;
80
+ return true;
81
+ });
82
+ }
82
83
  }
83
- };
84
84
 
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);
85
+ std::vector<std::pair<int, int>> matching_parts;
86
+ for (int j = 0; j < other->parts_.size(); ++j) {
87
+ auto& other_part = other->parts_[j];
88
+ if (!other_part->is(Part::SEAM) && other_part->trasmuted) {
89
+ continue;
97
90
  }
91
+ other_part->each([&](QNode<Point>* pos) -> bool {
92
+ Position *position = dynamic_cast<Position*>(pos);
93
+ auto it = this->tracked_endpoints.find(position->end_point());
94
+ if (it != this->tracked_endpoints.end()) {
95
+ int self_index = it->second;
96
+ matching_parts.push_back({self_index, j});
97
+ return false;
98
+ }
99
+ return true;
100
+ });
98
101
  }
99
- return result;
102
+
103
+ return matching_parts;
100
104
  }
101
105
 
106
+
102
107
  void Polyline::clear() {
103
108
  this->raw_.clear();
104
109
  }
@@ -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,11 +11,10 @@
11
11
 
12
12
  Position::Position(Hub* hub, Point* point)
13
13
  : QNode<Point>(point)
14
- { int key = point->y * hub->width() + point->x;
14
+ { int key = point->y * hub->width() + (point->x - hub->start_x());
15
15
  EndPoint* existing_ep = hub->get(key);
16
16
  if (existing_ep == nullptr)
17
- { end_point_ = hub->spawn_end_point();
18
- hub->put(key, end_point_);
17
+ { end_point_ = hub->put(key, hub->spawn_end_point());
19
18
  } else {
20
19
  end_point_ = existing_ep;
21
20
  }
@@ -79,9 +79,21 @@ class Queueable {
79
79
  head = nullptr;
80
80
  tail = nullptr;
81
81
  _iterator = nullptr;
82
+ _started = false;
82
83
  size = 0;
83
84
  }
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
+
85
97
  void replace(Queueable<T>& q) {
86
98
  reset();
87
99
  append(q);
@@ -130,8 +142,8 @@ class Queueable {
130
142
  }
131
143
 
132
144
  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");
145
+ // if (!node) throw std::runtime_error("nil node");
146
+ // if (node->owner != this) throw std::runtime_error("wrong node");
135
147
  _iterator = node->next;
136
148
  _started = true;
137
149
  }
@@ -181,23 +193,6 @@ class Queueable {
181
193
  return out;
182
194
  }
183
195
 
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
196
  QNode<T>* pop() {
202
197
  if (!tail) return nullptr;
203
198
  return rem(tail);
@@ -220,7 +215,7 @@ class Queueable {
220
215
 
221
216
  for (T* current : source) {
222
217
  if (!result.empty() && *result.back() == *current) {
223
- result.pop_back(); // "Annulla" la coppia invece di ricominciare
218
+ result.pop_back();
224
219
  } else {
225
220
  result.push_back(current);
226
221
  }