contrek 1.0.4 → 1.0.6

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -3
  3. data/CHANGELOG.md +21 -0
  4. data/Gemfile.lock +4 -4
  5. data/README.md +34 -30
  6. data/Rakefile +3 -0
  7. data/contrek.gemspec +7 -4
  8. data/ext/cpp_polygon_finder/PolygonFinder/Makefile +44 -0
  9. data/ext/cpp_polygon_finder/PolygonFinder/images/sample_10240x10240.png +0 -0
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/Main.cpp +14 -5
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +136 -15
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +5 -4
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/CpuTimer.h +44 -0
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.cpp +8 -0
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.h +3 -4
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +63 -573
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h +17 -18
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +22 -5
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h +4 -8
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/spng.c +6980 -0
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/spng.h +537 -0
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +101 -0
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.h +16 -0
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +0 -3
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +4 -7
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +13 -13
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +5 -7
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +47 -41
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +15 -10
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +181 -178
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +19 -20
  32. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Polygon.h +20 -0
  33. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +52 -137
  34. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +85 -16
  35. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/RectBounds.h +39 -0
  36. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.cpp +14 -0
  37. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.h +17 -0
  38. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +117 -0
  39. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +32 -0
  40. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +344 -0
  41. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +46 -0
  42. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.cpp +14 -0
  43. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.h +22 -0
  44. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/FakeCluster.cpp +13 -0
  45. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/FakeCluster.h +17 -0
  46. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +138 -0
  47. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +52 -0
  48. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +23 -0
  49. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +40 -0
  50. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +70 -0
  51. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +47 -0
  52. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp +24 -0
  53. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.h +23 -0
  54. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +182 -0
  55. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +30 -0
  56. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +108 -0
  57. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +52 -0
  58. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Poolable.cpp +59 -0
  59. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Poolable.h +52 -0
  60. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +31 -0
  61. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +25 -0
  62. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queue.h +36 -0
  63. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +230 -0
  64. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +35 -0
  65. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +20 -0
  66. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +26 -0
  67. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +23 -0
  68. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +105 -0
  69. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +56 -0
  70. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.cpp +3 -3
  71. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.h +5 -8
  72. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBMatcher.h +3 -7
  73. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.cpp +2 -2
  74. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.h +4 -8
  75. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.cpp +2 -2
  76. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.h +3 -7
  77. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.cpp +23 -15
  78. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.h +6 -8
  79. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.cpp +2 -5
  80. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.h +4 -8
  81. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.cpp +9 -12
  82. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.h +3 -7
  83. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.cpp +26 -27
  84. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +76 -87
  85. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +64 -32
  86. data/ext/cpp_polygon_finder/extconf.rb +14 -0
  87. data/lib/contrek/bitmaps/sample_generator.rb +56 -0
  88. data/lib/contrek/cpp/cpp_concurrent_finder.rb +9 -0
  89. data/lib/contrek/finder/bounds.rb +17 -0
  90. data/lib/contrek/finder/concurrent/cluster.rb +2 -2
  91. data/lib/contrek/finder/concurrent/cursor.rb +8 -8
  92. data/lib/contrek/finder/concurrent/finder.rb +10 -9
  93. data/lib/contrek/finder/concurrent/part.rb +2 -2
  94. data/lib/contrek/finder/concurrent/partitionable.rb +1 -1
  95. data/lib/contrek/finder/concurrent/polyline.rb +17 -15
  96. data/lib/contrek/finder/concurrent/sequence.rb +11 -0
  97. data/lib/contrek/finder/concurrent/tile.rb +3 -3
  98. data/lib/contrek/finder/node_cluster.rb +16 -8
  99. data/lib/contrek/finder/polygon_finder.rb +1 -4
  100. data/lib/contrek/version.rb +1 -1
  101. data/lib/contrek.rb +9 -1
  102. metadata +62 -15
  103. data/ext/cpp_polygon_finder/PolygonFinder/.cproject +0 -136
  104. data/ext/cpp_polygon_finder/PolygonFinder/.project +0 -27
  105. data/ext/cpp_polygon_finder/PolygonFinder/.settings/org.eclipse.ltk.core.refactoring.prefs +0 -2
  106. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.cpp +0 -48
  107. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.h +0 -32
@@ -0,0 +1,344 @@
1
+ /*
2
+ * Cursor.cpp
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+ #include <algorithm>
9
+ #include <vector>
10
+ #include <utility>
11
+ #include <unordered_set>
12
+ #include "Cursor.h"
13
+ #include "Polyline.h"
14
+
15
+ Cursor::Cursor(Cluster& cluster, Shape* shape)
16
+ : cluster(cluster), shape(shape) {
17
+ }
18
+
19
+ Cursor::~Cursor() {
20
+ for (Sequence* sequence : this->allocated_sequences) {
21
+ delete sequence;
22
+ }
23
+ }
24
+
25
+ Sequence* Cursor::join_outers()
26
+ { Polyline* outer_polyline = shape->outer_polyline;
27
+ this->polylines_sequence.push_back(outer_polyline);
28
+ Sequence* outer_joined_polyline = new Sequence();
29
+ this->allocated_sequences.push_back(outer_joined_polyline);
30
+ int counter = 0;
31
+ std::vector<Part*> all_parts;
32
+ std::vector<Shape*> shapes;
33
+ shapes.push_back(this->shape);
34
+ this->traverse_outer(outer_polyline->parts().front(),
35
+ all_parts,
36
+ this->polylines_sequence,
37
+ shapes,
38
+ outer_joined_polyline, counter);
39
+
40
+ if (*outer_joined_polyline->head->payload == *outer_joined_polyline->tail->payload &&
41
+ this->cluster.tiles().front()->left() &&
42
+ this->cluster.tiles().back()->right()) outer_joined_polyline->pop();
43
+
44
+ // TODO(ema): optimize
45
+ std::unordered_set<Polyline*> seen;
46
+ std::vector<Polyline*> result;
47
+ for (Polyline* x : polylines_sequence) {
48
+ if (seen.insert(x).second) {
49
+ result.push_back(x);
50
+ }
51
+ }
52
+ polylines_sequence = result;
53
+
54
+ for (Polyline* polyline : polylines_sequence) {
55
+ polyline->turn_on(Polyline::TRACKED_OUTER);
56
+ }
57
+
58
+ for (Shape *shape : shapes)
59
+ { if (shape == outer_polyline->shape) {
60
+ continue;
61
+ }
62
+ orphan_inners_.insert(
63
+ orphan_inners_.end(),
64
+ shape->inner_polylines.begin(),
65
+ shape->inner_polylines.end());
66
+ shape->clear_inner();
67
+ }
68
+ return(outer_joined_polyline);
69
+ }
70
+
71
+ void Cursor::traverse_outer(Part* act_part,
72
+ std::vector<Part*>& all_parts,
73
+ std::vector<Polyline*>& polylines,
74
+ std::vector<Shape*>& shapes,
75
+ Sequence* outer_joined_polyline,
76
+ int& counter) {
77
+ while (act_part != nullptr) {
78
+ counter += 1;
79
+
80
+ if (all_parts.empty() || all_parts.back() != act_part) {
81
+ all_parts.push_back(act_part);
82
+ }
83
+
84
+ Shape* target_shape = act_part->polyline()->shape;
85
+ if (std::find(shapes.begin(), shapes.end(), target_shape) == shapes.end()) {
86
+ shapes.push_back(target_shape);
87
+ }
88
+
89
+ bool jumped_to_new_part = false;
90
+ if (act_part->is(Part::EXCLUSIVE)) {
91
+ if (act_part->size == 0) return;
92
+
93
+ while (Position *position = act_part->next_position(nullptr)) {
94
+ if (outer_joined_polyline->size > 1 &&
95
+ outer_joined_polyline->head->payload == position->payload &&
96
+ act_part == all_parts.front()) {
97
+ return;
98
+ }
99
+ outer_joined_polyline->add(position);
100
+ }
101
+ } else {
102
+ while (Position *new_position = static_cast<Position*>(act_part->iterator())) {
103
+ if (outer_joined_polyline->size > 1 &&
104
+ outer_joined_polyline->head->payload == new_position->payload &&
105
+ act_part == all_parts.front()) {
106
+ return;
107
+ }
108
+ this->cluster.positions_pool.emplace_back(this->cluster.hub(), new_position->payload);
109
+ outer_joined_polyline->add(&this->cluster.positions_pool.back());
110
+ for (Shape *shape : act_part->polyline()->next_tile_eligible_shapes()) {
111
+ if (Part *part = shape->outer_polyline->find_first_part_by_position(new_position)) {
112
+ const auto n = all_parts.size();
113
+ Part *last_last_part = n >= 2 ? all_parts[n - 2] : nullptr;
114
+
115
+ if (last_last_part != part) {
116
+ if (n >= 2) {
117
+ bool all_seam = true;
118
+ for (std::size_t i = all_parts.size() - 2; i < all_parts.size(); ++i) {
119
+ if (all_parts[i]->type != Part::SEAM) {
120
+ all_seam = false;
121
+ break;
122
+ }
123
+ }
124
+ if (all_seam) break;
125
+ }
126
+ polylines.push_back(part->polyline()->shape->outer_polyline);
127
+ part->next_position(new_position);
128
+ act_part = part;
129
+ jumped_to_new_part = true;
130
+ break;
131
+ }
132
+ }
133
+ }
134
+ if (jumped_to_new_part) break;
135
+ act_part->passes += 1;
136
+ act_part->next_position(nullptr);
137
+ }
138
+ }
139
+ if (jumped_to_new_part) continue;
140
+ Part* next_part = act_part->circular_next;
141
+ next_part->rewind();
142
+ act_part = next_part;
143
+ }
144
+ }
145
+
146
+ std::vector<Sequence*> Cursor::join_inners(Sequence* outer_seq) {
147
+ std::vector<Sequence*> retme;
148
+ std::vector<Shape*> missing_shapes;
149
+
150
+ for (Tile *tile : this->cluster.tiles())
151
+ { for (Shape *shape : tile->shapes())
152
+ { if (shape->outer_polyline->is_on(Polyline::TRACKED_OUTER) ||
153
+ shape->outer_polyline->is_on(Polyline::TRACKED_INNER) ||
154
+ !shape->outer_polyline->boundary() ||
155
+ std::find(polylines_sequence.begin(), polylines_sequence.end(), shape->outer_polyline) != polylines_sequence.end()) {
156
+ continue;
157
+ }
158
+ missing_shapes.push_back(shape);
159
+ }
160
+ }
161
+
162
+ for (Polyline *polyline : polylines_sequence)
163
+ { for (Shape *missing_shape : missing_shapes)
164
+ { Polyline* outer_polyline = missing_shape->outer_polyline;
165
+ if (!polyline->vert_intersect(*outer_polyline)) continue;
166
+ std::vector<Point*> intersection = polyline->intersection(outer_polyline);
167
+ if (intersection.size() > 0)
168
+ { auto [inject_sequences_left, inject_sequences_right] = polyline->sew(intersection, outer_polyline);
169
+ auto combined = combine(inject_sequences_right, inject_sequences_left);
170
+ for (auto& sewn_sequence : combined) {
171
+ std::vector<Point*> unique;
172
+ unique.reserve(sewn_sequence.size());
173
+ for (Point* p : sewn_sequence) {
174
+ if (!p) continue;
175
+ auto it = std::find_if(
176
+ unique.begin(), unique.end(),
177
+ [&](Point* up) {
178
+ return up && *up == *p;
179
+ });
180
+ if (it == unique.end()) unique.push_back(p);
181
+ }
182
+ sewn_sequence.swap(unique);
183
+
184
+ if (sewn_sequence.size() <= 1) continue;
185
+
186
+ int first_x = sewn_sequence.front()->x;
187
+ bool different_x = false;
188
+ for (Point* p : sewn_sequence) {
189
+ if (p->x != first_x) {
190
+ different_x = true;
191
+ break;
192
+ }
193
+ }
194
+ if (different_x) {
195
+ orphan_inners_.push_back(sewn_sequence);
196
+ }
197
+ }
198
+ outer_polyline->clear();
199
+ outer_polyline->turn_on(Polyline::TRACKED_OUTER);
200
+ outer_polyline->turn_on(Polyline::TRACKED_INNER);
201
+ orphan_inners_.insert(
202
+ orphan_inners_.end(),
203
+ missing_shape->inner_polylines.begin(),
204
+ missing_shape->inner_polylines.end());
205
+ }
206
+ }
207
+ }
208
+ retme = collect_inner_sequences(outer_seq);
209
+ for (Polyline* polyline : polylines_sequence) {
210
+ polyline->turn_on(Polyline::TRACKED_INNER);
211
+ }
212
+ return(retme);
213
+ }
214
+
215
+ std::vector<Sequence*> Cursor::collect_inner_sequences(Sequence* outer_seq) {
216
+ std::vector<Sequence*> return_sequences;
217
+
218
+ for (Polyline* polyline : polylines_sequence)
219
+ { for (Part* part : polyline->parts())
220
+ { if (part->innerable())
221
+ { std::vector<Part*> all_parts;
222
+ Bounds bounds{
223
+ .min = polyline->max_y(),
224
+ .max = 0
225
+ };
226
+ traverse_inner(part, all_parts, bounds);
227
+ Sequence* retme_sequence = new Sequence();
228
+
229
+ for (Part* part : all_parts)
230
+ { part->touch();
231
+ retme_sequence->move_from(*part, [&](QNode<Point>* pos) -> bool {
232
+ Position *position = dynamic_cast<Position*>(pos);
233
+ if (part->is(Part::ADDED) &&
234
+ !(position->payload->y >= bounds.min &&
235
+ position->payload->y <= bounds.max)) {
236
+ return(false);
237
+ }
238
+ return(!(polyline->tile->tg_border(*position->payload) && position->end_point()->queues_include(outer_seq)));
239
+ });
240
+ }
241
+ if (retme_sequence->is_not_vertical()) return_sequences.push_back(retme_sequence);
242
+ else delete retme_sequence;
243
+ }
244
+ }
245
+ }
246
+
247
+ return(return_sequences);
248
+ }
249
+
250
+ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bounds& bounds) {
251
+ PartPool& pool = act_part->polyline()->tile->cluster->parts_pool;
252
+ while (act_part != nullptr) {
253
+ if (!all_parts.empty() && act_part == all_parts.front()) return;
254
+ if (act_part->size > 0) {
255
+ auto points = act_part->to_vector();
256
+ auto [min_it, max_it] = std::minmax_element(
257
+ points.begin(),
258
+ points.end(),
259
+ [](Point* a, Point* b) { return a->y < b->y; });
260
+ bounds.min = std::min(bounds.min, (*min_it)->y);
261
+ bounds.max = std::max(bounds.max, (*max_it)->y);
262
+ }
263
+ if (act_part->innerable()) {
264
+ all_parts.push_back(act_part);
265
+ bool jumped = false;
266
+ while (act_part = act_part->next) {
267
+ if (act_part->innerable()) {
268
+ all_parts.push_back(act_part);
269
+ } else {
270
+ for (Shape *shape : act_part->polyline()->next_tile_eligible_shapes()) {
271
+ for (Part* dest_part : shape->outer_polyline->parts()) {
272
+ if (dest_part->trasmuted) continue;
273
+ if (dest_part->intersect_part(act_part)) {
274
+ std::vector<Point*> link_seq = duplicates_intersection(*dest_part, *act_part);
275
+ if (!link_seq.empty()) {
276
+ Part* ins_part = pool.acquire(Part::ADDED, act_part->polyline());
277
+ for (Point* pos : link_seq) {
278
+ this->cluster.positions_pool.emplace_back(this->cluster.hub(), pos);
279
+ ins_part->add(&this->cluster.positions_pool.back());
280
+ }
281
+ all_parts.push_back(ins_part);
282
+ }
283
+ act_part = dest_part->circular_next;
284
+ jumped = true;
285
+ break;
286
+ }
287
+ }
288
+ if (jumped) break;
289
+ }
290
+ if (jumped) break;
291
+ if (act_part->is(Part::SEAM)) {
292
+ all_parts.push_back(act_part);
293
+ }
294
+ }
295
+ }
296
+ if (jumped) continue;
297
+ break;
298
+ } else if (act_part->next) {
299
+ act_part = act_part->next;
300
+ continue;
301
+ }
302
+ else break;
303
+ }
304
+ }
305
+
306
+ template <typename T>
307
+ std::vector<T*> difference_ptr(const std::vector<T*>& a, const std::vector<T*>& b)
308
+ { std::vector<T*> result;
309
+ for (T* item : a) {
310
+ if (!item) continue;
311
+ auto it = std::find_if(
312
+ b.begin(), b.end(),
313
+ [&](T* other) {
314
+ return other && *other == *item;
315
+ });
316
+ if (it == b.end()) {
317
+ result.push_back(item);
318
+ }
319
+ }
320
+ return result;
321
+ }
322
+
323
+ std::vector<Point*> Cursor::duplicates_intersection(const Part& part_a, const Part& part_b) {
324
+ std::vector<Point*> a1 = part_a.inverts ? part_a.remove_adjacent_pairs(part_a.to_vector()) : part_a.to_vector();
325
+ std::vector<Point*> b1 = part_b.inverts ? part_b.remove_adjacent_pairs(part_b.to_vector()) : part_b.to_vector();
326
+ std::vector<Point*> result = difference_ptr(a1, b1);
327
+ std::vector<Point*> temp = difference_ptr(b1, a1);
328
+ result.insert(result.end(), temp.begin(), temp.end());
329
+ return result;
330
+ }
331
+
332
+ std::vector<std::vector<Point*>> Cursor::combine(std::vector<std::vector<Point*>>& seqa, std::vector<std::vector<Point*>>& seqb)
333
+ { std::vector<std::vector<Point*>> rets;
334
+ size_t n = std::min(seqa.size(), seqb.size());
335
+ for (size_t i = 0; i < n; ++i) {
336
+ std::vector<Point*> last = std::move(seqa.back());
337
+ seqa.pop_back();
338
+ std::vector<Point*> first = std::move(seqb.front());
339
+ seqb.erase(seqb.begin());
340
+ first.insert(first.end(), last.begin(), last.end());
341
+ rets.push_back(std::move(first));
342
+ }
343
+ return rets;
344
+ }
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Cursor.h
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #pragma once
10
+ #include <list>
11
+ #include <vector>
12
+ #include "Sequence.h"
13
+ #include "Cluster.h"
14
+ #include "Shape.h"
15
+ #include "Part.h"
16
+
17
+ struct Bounds {
18
+ int min;
19
+ int max;
20
+ };
21
+
22
+ class Cursor {
23
+ public:
24
+ Cursor(Cluster& cluster, Shape* shape);
25
+ virtual ~Cursor();
26
+ Sequence* join_outers();
27
+ std::vector<Sequence*> join_inners(Sequence* outer_seq);
28
+ std::list<std::vector<Point*>> orphan_inners() { return orphan_inners_; }
29
+
30
+ private:
31
+ Cluster& cluster;
32
+ Shape* shape;
33
+ std::vector<Sequence*> allocated_sequences;
34
+ std::vector<Polyline*> polylines_sequence;
35
+ std::list<std::vector<Point*>> orphan_inners_;
36
+ void traverse_outer(Part* act_part,
37
+ std::vector<Part*>& all_parts,
38
+ std::vector<Polyline*>& polylines,
39
+ std::vector<Shape*>& shapes,
40
+ Sequence* outer_joined_polyline,
41
+ int& counter);
42
+ std::vector<Sequence*> collect_inner_sequences(Sequence* outer_seq);
43
+ void traverse_inner(Part* act_part, std::vector<Part*> &all_parts, Bounds& bounds);
44
+ std::vector<Point*> duplicates_intersection(const Part& part_a, const Part& part_b);
45
+ std::vector<std::vector<Point*>> combine(std::vector<std::vector<Point*>>& seqa, std::vector<std::vector<Point*>>& seqb);
46
+ };
@@ -0,0 +1,14 @@
1
+ /*
2
+ * EndPoint.cpp
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #include "EndPoint.h"
10
+ #include <iostream>
11
+
12
+ bool EndPoint::queues_include(Queueable<Point>* q) const {
13
+ return (std::find(queues_.begin(), queues_.end(), q) != queues_.end());
14
+ }
@@ -0,0 +1,22 @@
1
+ /*
2
+ * EndPoint.h
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #pragma once
10
+ #include <vector>
11
+ #include "Part.h"
12
+
13
+ class Part;
14
+
15
+ class EndPoint {
16
+ public:
17
+ EndPoint() {}
18
+ std::vector<Queueable<Point>*>& queues() { return queues_; }
19
+ bool queues_include(Queueable<Point>* q) const;
20
+ private:
21
+ std::vector<Queueable<Point>*> queues_;
22
+ };
@@ -0,0 +1,13 @@
1
+ /*
2
+ * FakeCluster.cpp
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #include "FakeCluster.h"
10
+
11
+ FakeCluster::FakeCluster(std::list<Polygon>& polygons, pf_Options options)
12
+ : NodeCluster(0, 0, &options), polygons(polygons) {
13
+ }
@@ -0,0 +1,17 @@
1
+ /*
2
+ * FakeCluster.h
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #pragma once
10
+ #include <list>
11
+ #include "../NodeCluster.h"
12
+
13
+ class FakeCluster : public NodeCluster {
14
+ public:
15
+ std::list<Polygon>& polygons;
16
+ FakeCluster(std::list<Polygon>& polygons, pf_Options options);
17
+ };
@@ -0,0 +1,138 @@
1
+ /*
2
+ * Finder.cpp
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #include <utility>
10
+ #include <vector>
11
+ #include <string>
12
+ #include "Finder.h"
13
+ #include "../../bitmaps/Bitmap.h"
14
+ #include "../../matchers/Matcher.h"
15
+ #include "../../matchers/RGBMatcher.h"
16
+ #include "../optionparser.h"
17
+ #include "../FinderUtils.h"
18
+ #include "ClippedPolygonFinder.h"
19
+ #include "Tile.h"
20
+ #include "Queue.h"
21
+ #include "Cluster.h"
22
+ #include "FakeCluster.h"
23
+
24
+ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vector<std::string> *options)
25
+ : Poolable(number_of_threads),
26
+ bitmap(bitmap),
27
+ matcher(matcher),
28
+ input_options(*options),
29
+ maximum_width_(bitmap->w())
30
+ { cpu_timer.start();
31
+ if (options != nullptr) FinderUtils::sanitize_options(this->options, options);
32
+
33
+ double cw = static_cast<double>(this->maximum_width_) / this->options.number_of_tiles;
34
+ if (cw < 1.0) {
35
+ throw std::runtime_error("One pixel tile width minimum!");
36
+ }
37
+ int x = 0;
38
+ for (int tile_index = 0; tile_index < this->options.number_of_tiles; tile_index++)
39
+ { int tile_end_x = static_cast<int>(cw * (tile_index + 1));
40
+ TilePayload p { tile_index, x, tile_end_x };
41
+ enqueue(p, [this](const TilePayload& payload) {
42
+ std::vector<std::string> base_arguments = {"--bounds", "--versus=" + this->options.get_alpha_versus()};
43
+ CpuTimer t;
44
+ t.start();
45
+ auto* finder = new ClippedPolygonFinder(
46
+ this->bitmap,
47
+ this->matcher,
48
+ payload.tile_start_x,
49
+ payload.tile_end_x,
50
+ &base_arguments);
51
+ {
52
+ std::lock_guard<std::mutex> lock(finders_mutex);
53
+ finders.push(finder);
54
+ }
55
+
56
+ Tile* tile = new Tile(this, payload.tile_start_x, payload.tile_end_x,
57
+ std::to_string(payload.tile_index), Benchmarks {0, 0});
58
+ tile->initial_process(finder);
59
+ tiles.queue_push(tile);
60
+ });
61
+
62
+ x = tile_end_x - 1;
63
+ }
64
+ this->process_tiles();
65
+ reports["init"] = cpu_timer.stop();
66
+ }
67
+
68
+
69
+ void Finder::process_tiles() {
70
+ std::vector<Tile*> arriving_tiles;
71
+
72
+ while (true) {
73
+ Tile* tile = tiles.queue_pop();
74
+
75
+ if (tile->whole()) {
76
+ this->whole_tile = tile;
77
+ break;
78
+ }
79
+
80
+ auto it = std::find_if(
81
+ arriving_tiles.begin(),
82
+ arriving_tiles.end(),
83
+ [&](Tile* t) {
84
+ return (t->start_x() == (tile->end_x() - 1)) || ((t->end_x() - 1) == tile->start_x());
85
+ });
86
+
87
+ if (it != arriving_tiles.end()) {
88
+ Tile* twin_tile = *it;
89
+ Cluster *cluster = new Cluster(this, this->bitmap->h(), this->bitmap->w());
90
+ if (twin_tile->start_x() == (tile->end_x() - 1)) {
91
+ cluster->add(tile);
92
+ cluster->add(twin_tile);
93
+ } else {
94
+ cluster->add(twin_tile);
95
+ cluster->add(tile);
96
+ }
97
+ arriving_tiles.erase(it);
98
+ enqueue(cluster, [this](Cluster* c) {
99
+ Tile* merged_tile = c->merge_tiles();
100
+ tiles.queue_push(merged_tile);
101
+ delete c;
102
+ });
103
+ } else {
104
+ arriving_tiles.push_back(tile);
105
+ }
106
+ }
107
+ }
108
+
109
+ Finder::~Finder() {
110
+ if (this->whole_tile) {
111
+ delete this->whole_tile; // last tile to be deleted (not owned by a cluster)
112
+ }
113
+
114
+ while (!finders.empty()) {
115
+ ClippedPolygonFinder* finder = nullptr;
116
+ { std::lock_guard<std::mutex> lock(finders_mutex);
117
+ finder = finders.front();
118
+ finders.pop();
119
+ }
120
+ delete finder;
121
+ }
122
+ }
123
+
124
+ ProcessResult* Finder::process_info() {
125
+ ProcessResult *pr = new ProcessResult();
126
+ pr->polygons = std::move(this->whole_tile->to_raw_polygons());
127
+ FakeCluster fake_cluster(pr->polygons, this->options);
128
+ cpu_timer.start();
129
+ fake_cluster.compress_coords(pr->polygons, this->options);
130
+ reports["compress"] = cpu_timer.stop();
131
+ reports["total"] = reports["compress"] + reports["init"];
132
+ reports["outer"] = this->whole_tile->benchmarks.outer;
133
+ reports["inner"] = this->whole_tile->benchmarks.inner;
134
+ pr->benchmarks = this->reports;
135
+ // TODO(ema): pr->treemap
136
+ // TODO(ema): pr->named_sequence
137
+ return(pr);
138
+ }
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Finder.h
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #pragma once
10
+ #include <queue>
11
+ #include <mutex>
12
+ #include <string>
13
+ #include <map>
14
+ #include <vector>
15
+ #include "Poolable.h"
16
+ #include "../PolygonFinder.h"
17
+ #include "Queue.h"
18
+ #include "Tile.h"
19
+
20
+ struct TilePayload {
21
+ int tile_index;
22
+ int tile_start_x;
23
+ int tile_end_x;
24
+ };
25
+
26
+ class Bitmap;
27
+ class Matcher;
28
+ class Tile;
29
+ class ClippedPolygonFinder;
30
+
31
+ class Finder : public Poolable {
32
+ private:
33
+ Bitmap *bitmap;
34
+ Matcher *matcher;
35
+ pf_Options options;
36
+ std::vector<std::string> input_options;
37
+ int maximum_width_;
38
+ Queue<Tile*> tiles;
39
+ Tile* whole_tile = nullptr;
40
+ void process_tiles();
41
+ std::queue<ClippedPolygonFinder*> finders;
42
+ std::mutex finders_mutex;
43
+ std::map<std::string, double> reports;
44
+ CpuTimer cpu_timer;
45
+
46
+ public:
47
+ using Poolable::Poolable;
48
+ Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vector<std::string> *options);
49
+ virtual ~Finder();
50
+ int maximum_width() const { return maximum_width_; }
51
+ ProcessResult* process_info();
52
+ };
@@ -0,0 +1,23 @@
1
+ /*
2
+ * Hub.cpp
3
+ *
4
+ * Created on: 23 nov 2025
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #include "Hub.h"
10
+ #include <cstring>
11
+
12
+ Hub::Hub(int height, int width)
13
+ : width_(width), height_(height)
14
+ { size_t total_pixels = static_cast<size_t>(width) * height;
15
+ payloads_.resize(total_pixels);
16
+ bitset_.resize((total_pixels + 63) / 64, 0);
17
+ std::memset(bitset_.data(), 0, bitset_.size() * sizeof(uint64_t));
18
+ }
19
+
20
+ EndPoint* Hub::spawn_end_point() {
21
+ endpoint_pool_.emplace_back();
22
+ return &endpoint_pool_.back();
23
+ }