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.
- checksums.yaml +4 -4
- data/.gitignore +4 -3
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +4 -4
- data/README.md +34 -30
- data/Rakefile +3 -0
- data/contrek.gemspec +7 -4
- data/ext/cpp_polygon_finder/PolygonFinder/Makefile +44 -0
- data/ext/cpp_polygon_finder/PolygonFinder/images/sample_10240x10240.png +0 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Main.cpp +14 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +136 -15
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +5 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/CpuTimer.h +44 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.cpp +8 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.h +3 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +63 -573
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h +17 -18
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +22 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h +4 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/spng.c +6980 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/spng.h +537 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +101 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.h +16 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +0 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +4 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +13 -13
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +5 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +47 -41
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +15 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +181 -178
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +19 -20
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Polygon.h +20 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +52 -137
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +85 -16
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/RectBounds.h +39 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.cpp +14 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.h +17 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +117 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +32 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +344 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +46 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.cpp +14 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.h +22 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/FakeCluster.cpp +13 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/FakeCluster.h +17 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +138 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +40 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +70 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +47 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp +24 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +182 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +30 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +108 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Poolable.cpp +59 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Poolable.h +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +31 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +25 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queue.h +36 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +230 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +35 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +20 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +26 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +105 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +56 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.cpp +3 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.h +5 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBMatcher.h +3 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.h +4 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.h +3 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.cpp +23 -15
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.h +6 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.cpp +2 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.h +4 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.cpp +9 -12
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.h +3 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.cpp +26 -27
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +76 -87
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +64 -32
- data/ext/cpp_polygon_finder/extconf.rb +14 -0
- data/lib/contrek/bitmaps/sample_generator.rb +56 -0
- data/lib/contrek/cpp/cpp_concurrent_finder.rb +9 -0
- data/lib/contrek/finder/bounds.rb +17 -0
- data/lib/contrek/finder/concurrent/cluster.rb +2 -2
- data/lib/contrek/finder/concurrent/cursor.rb +8 -8
- data/lib/contrek/finder/concurrent/finder.rb +10 -9
- data/lib/contrek/finder/concurrent/part.rb +2 -2
- data/lib/contrek/finder/concurrent/partitionable.rb +1 -1
- data/lib/contrek/finder/concurrent/polyline.rb +17 -15
- data/lib/contrek/finder/concurrent/sequence.rb +11 -0
- data/lib/contrek/finder/concurrent/tile.rb +3 -3
- data/lib/contrek/finder/node_cluster.rb +16 -8
- data/lib/contrek/finder/polygon_finder.rb +1 -4
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +9 -1
- metadata +62 -15
- data/ext/cpp_polygon_finder/PolygonFinder/.cproject +0 -136
- data/ext/cpp_polygon_finder/PolygonFinder/.project +0 -27
- data/ext/cpp_polygon_finder/PolygonFinder/.settings/org.eclipse.ltk.core.refactoring.prefs +0 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.cpp +0 -48
- 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
|
+
}
|