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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +1 -1
- data/README.md +80 -8
- data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +39 -0
- data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +43 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +72 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +19 -24
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +1 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +3 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +29 -9
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +11 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +6 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +12 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +108 -66
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +5 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +35 -28
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +5 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +13 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +16 -22
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +1 -1
- data/lib/contrek/bitmaps/rgb_color.rb +0 -15
- data/lib/contrek/bitmaps/rgb_cpp_color.rb +10 -0
- data/lib/contrek/finder/concurrent/cluster.rb +2 -2
- data/lib/contrek/finder/concurrent/cursor.rb +34 -16
- data/lib/contrek/finder/concurrent/finder.rb +12 -1
- data/lib/contrek/finder/concurrent/hub.rb +3 -4
- data/lib/contrek/finder/concurrent/part.rb +8 -2
- data/lib/contrek/finder/concurrent/partitionable.rb +61 -33
- data/lib/contrek/finder/concurrent/polyline.rb +45 -2
- data/lib/contrek/finder/concurrent/position.rb +3 -4
- data/lib/contrek/finder/concurrent/queueable.rb +12 -20
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +4 -3
- metadata +6 -4
- data/ext/cpp_polygon_finder/PolygonFinder/Makefile +0 -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<
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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::
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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<
|
|
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
|
-
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
hub->put(key,
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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
|
}
|
|
@@ -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();
|
|
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
|
|
@@ -3,10 +3,10 @@ module Contrek
|
|
|
3
3
|
class Cluster
|
|
4
4
|
attr_reader :tiles, :hub
|
|
5
5
|
|
|
6
|
-
def initialize(finder:, height:,
|
|
6
|
+
def initialize(finder:, height:, start_x:, end_x:)
|
|
7
7
|
@finder = finder
|
|
8
8
|
@tiles = []
|
|
9
|
-
@hub = Hub.new(height:,
|
|
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
|
-
|
|
60
|
-
next
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
5
|
-
def initialize(height:,
|
|
6
|
-
@
|
|
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
|