contrek 1.1.7 → 1.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/README.md +50 -23
- data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +19 -11
- data/ext/cpp_polygon_finder/PolygonFinder/clean.sh +28 -0
- data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +4 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +66 -61
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Primitives.h +14 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +86 -23
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +3 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +23 -29
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +7 -12
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +12 -9
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.cpp +55 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.h +32 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +21 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +4 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +14 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +14 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +15 -6
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +11 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp +42 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.h +34 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +72 -11
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +9 -1
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +4 -0
- data/lib/contrek/finder/concurrent/cluster.rb +58 -9
- data/lib/contrek/finder/concurrent/cursor.rb +10 -6
- data/lib/contrek/finder/concurrent/finder.rb +8 -2
- data/lib/contrek/finder/concurrent/inner_polyline.rb +49 -0
- data/lib/contrek/finder/concurrent/polyline.rb +46 -0
- data/lib/contrek/finder/concurrent/sequence.rb +21 -0
- data/lib/contrek/finder/concurrent/shape.rb +29 -2
- data/lib/contrek/finder/concurrent/tile.rb +36 -7
- data/lib/contrek/finder/node.rb +3 -1
- data/lib/contrek/finder/node_cluster.rb +56 -48
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +1 -0
- metadata +9 -2
|
@@ -14,12 +14,15 @@
|
|
|
14
14
|
#include "Cluster.h"
|
|
15
15
|
#include "Hub.h"
|
|
16
16
|
#include "PartPool.h"
|
|
17
|
+
#include "InnerPolyline.h"
|
|
17
18
|
|
|
18
19
|
class Cluster {
|
|
19
20
|
private:
|
|
20
21
|
Finder *finder;
|
|
21
22
|
std::vector<Tile*> tiles_;
|
|
22
23
|
Hub *hub_ = nullptr;
|
|
24
|
+
void assign_ancestry(Shape *shape, std::vector<InnerPolyline*>& inner_polylines);
|
|
25
|
+
|
|
23
26
|
public:
|
|
24
27
|
Cluster(Finder *finder, int height, int start_x, int end_x);
|
|
25
28
|
virtual ~Cluster();
|
|
@@ -12,34 +12,28 @@
|
|
|
12
12
|
#include <unordered_set>
|
|
13
13
|
#include "Cursor.h"
|
|
14
14
|
#include "Polyline.h"
|
|
15
|
+
#include "InnerPolyline.h"
|
|
15
16
|
|
|
16
17
|
Cursor::Cursor(Cluster& cluster, Shape* shape)
|
|
17
18
|
: cluster(cluster), shape(shape) {
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
Cursor::~Cursor() {
|
|
21
|
-
for (Sequence* sequence : this->allocated_sequences) {
|
|
22
|
-
delete sequence;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
21
|
Sequence* Cursor::join_outers()
|
|
27
22
|
{ Polyline* outer_polyline = shape->outer_polyline;
|
|
28
|
-
this->
|
|
23
|
+
this->shapes_sequence_.push_back(this->shape);
|
|
29
24
|
this->shapes_sequence_lookup.insert(this->shape);
|
|
30
|
-
Sequence* outer_joined_polyline =
|
|
31
|
-
this->allocated_sequences.push_back(outer_joined_polyline);
|
|
25
|
+
Sequence* outer_joined_polyline = outer_polyline->tile->shapes_pool->acquire_sequence();
|
|
32
26
|
std::vector<Part*> all_parts;
|
|
33
27
|
this->traverse_outer(outer_polyline->parts().front(),
|
|
34
28
|
all_parts,
|
|
35
|
-
this->
|
|
29
|
+
this->shapes_sequence_,
|
|
36
30
|
outer_joined_polyline);
|
|
37
31
|
|
|
38
32
|
if (*outer_joined_polyline->head->payload == *outer_joined_polyline->tail->payload &&
|
|
39
33
|
this->cluster.tiles().front()->left() &&
|
|
40
34
|
this->cluster.tiles().back()->right()) outer_joined_polyline->pop();
|
|
41
35
|
|
|
42
|
-
for (Shape* shape :
|
|
36
|
+
for (Shape* shape : shapes_sequence_) {
|
|
43
37
|
shape->outer_polyline->turn_on(Polyline::TRACKED_OUTER);
|
|
44
38
|
if (shape == outer_polyline->shape) {
|
|
45
39
|
continue;
|
|
@@ -127,8 +121,8 @@ void Cursor::traverse_outer(Part* act_part,
|
|
|
127
121
|
}
|
|
128
122
|
}
|
|
129
123
|
|
|
130
|
-
std::vector<
|
|
131
|
-
std::vector<
|
|
124
|
+
std::vector<InnerPolyline*> Cursor::join_inners(Sequence* outer_seq) {
|
|
125
|
+
std::vector<InnerPolyline*> retme;
|
|
132
126
|
std::vector<Shape*> missing_shapes;
|
|
133
127
|
|
|
134
128
|
for (Tile *tile : this->cluster.tiles())
|
|
@@ -136,7 +130,7 @@ std::vector<Sequence*> Cursor::join_inners(Sequence* outer_seq) {
|
|
|
136
130
|
{ if (shape->outer_polyline->is_on(Polyline::TRACKED_OUTER) ||
|
|
137
131
|
shape->outer_polyline->is_on(Polyline::TRACKED_INNER) ||
|
|
138
132
|
!shape->outer_polyline->boundary() ||
|
|
139
|
-
std::find(
|
|
133
|
+
std::find(shapes_sequence_.begin(), shapes_sequence_.end(), shape) != shapes_sequence_.end()) {
|
|
140
134
|
continue;
|
|
141
135
|
}
|
|
142
136
|
missing_shapes.push_back(shape);
|
|
@@ -145,17 +139,17 @@ std::vector<Sequence*> Cursor::join_inners(Sequence* outer_seq) {
|
|
|
145
139
|
|
|
146
140
|
if (missing_shapes.size() > 0) {
|
|
147
141
|
std::vector<Shape*> to_delay_shapes;
|
|
148
|
-
to_delay_shapes = connect_missings(this->
|
|
142
|
+
to_delay_shapes = connect_missings(this->shapes_sequence_, missing_shapes);
|
|
149
143
|
if (!to_delay_shapes.empty())
|
|
150
144
|
{ connect_missings(to_delay_shapes, missing_shapes);
|
|
151
145
|
while (!to_delay_shapes.empty()) {
|
|
152
|
-
to_delay_shapes = connect_missings(this->
|
|
146
|
+
to_delay_shapes = connect_missings(this->shapes_sequence_, to_delay_shapes);
|
|
153
147
|
}
|
|
154
148
|
}
|
|
155
149
|
}
|
|
156
150
|
|
|
157
151
|
retme = collect_inner_sequences(outer_seq);
|
|
158
|
-
for (Shape* shape :
|
|
152
|
+
for (Shape* shape : shapes_sequence_) {
|
|
159
153
|
shape->outer_polyline->turn_on(Polyline::TRACKED_INNER);
|
|
160
154
|
}
|
|
161
155
|
return(retme);
|
|
@@ -206,7 +200,7 @@ std::vector<Shape*> Cursor::connect_missings(std::vector<Shape*> shapes_sequence
|
|
|
206
200
|
}
|
|
207
201
|
}
|
|
208
202
|
if (different_x) {
|
|
209
|
-
orphan_inners_.push_back(sewn_sequence);
|
|
203
|
+
orphan_inners_.push_back(outer_polyline->tile->shapes_pool->acquire_inner_polyline(sewn_sequence, shape, true));
|
|
210
204
|
}
|
|
211
205
|
}
|
|
212
206
|
polyline->mixed_tile_origin = true;
|
|
@@ -214,9 +208,9 @@ std::vector<Shape*> Cursor::connect_missings(std::vector<Shape*> shapes_sequence
|
|
|
214
208
|
outer_polyline->turn_on(Polyline::TRACKED_OUTER);
|
|
215
209
|
outer_polyline->turn_on(Polyline::TRACKED_INNER);
|
|
216
210
|
orphan_inners_.insert(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
211
|
+
orphan_inners_.end(),
|
|
212
|
+
missing_shape->inner_polylines.begin(),
|
|
213
|
+
missing_shape->inner_polylines.end());
|
|
220
214
|
}
|
|
221
215
|
}
|
|
222
216
|
}
|
|
@@ -224,10 +218,10 @@ std::vector<Shape*> Cursor::connect_missings(std::vector<Shape*> shapes_sequence
|
|
|
224
218
|
return(delay_shapes);
|
|
225
219
|
}
|
|
226
220
|
|
|
227
|
-
std::vector<
|
|
228
|
-
std::vector<
|
|
221
|
+
std::vector<InnerPolyline*> Cursor::collect_inner_sequences(Sequence* outer_seq) {
|
|
222
|
+
std::vector<InnerPolyline*> return_inner_polylines;
|
|
229
223
|
|
|
230
|
-
for (Shape* shape :
|
|
224
|
+
for (Shape* shape : shapes_sequence_)
|
|
231
225
|
{ Polyline* polyline = shape->outer_polyline;
|
|
232
226
|
for (Part* part : polyline->parts())
|
|
233
227
|
{ if (part->innerable())
|
|
@@ -237,7 +231,7 @@ std::vector<Sequence*> Cursor::collect_inner_sequences(Sequence* outer_seq) {
|
|
|
237
231
|
.max = 0
|
|
238
232
|
};
|
|
239
233
|
traverse_inner(part, all_parts, bounds);
|
|
240
|
-
Sequence* retme_sequence =
|
|
234
|
+
Sequence* retme_sequence = shape->outer_polyline->tile->shapes_pool->acquire_sequence();
|
|
241
235
|
|
|
242
236
|
for (Part* part : all_parts)
|
|
243
237
|
{ part->touch();
|
|
@@ -251,13 +245,13 @@ std::vector<Sequence*> Cursor::collect_inner_sequences(Sequence* outer_seq) {
|
|
|
251
245
|
return(!(polyline->tile->tg_border(*position->payload) && position->end_point()->queues_include(outer_seq)));
|
|
252
246
|
});
|
|
253
247
|
}
|
|
254
|
-
if (retme_sequence->is_not_vertical())
|
|
255
|
-
|
|
248
|
+
if (retme_sequence->is_not_vertical()) {
|
|
249
|
+
return_inner_polylines.push_back(polyline->tile->shapes_pool->acquire_inner_polyline(retme_sequence));
|
|
250
|
+
}
|
|
256
251
|
}
|
|
257
252
|
}
|
|
258
253
|
}
|
|
259
|
-
|
|
260
|
-
return(return_sequences);
|
|
254
|
+
return(return_inner_polylines);
|
|
261
255
|
}
|
|
262
256
|
|
|
263
257
|
void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bounds& bounds) {
|
|
@@ -11,36 +11,31 @@
|
|
|
11
11
|
#include <list>
|
|
12
12
|
#include <vector>
|
|
13
13
|
#include <unordered_set>
|
|
14
|
+
#include "../Primitives.h"
|
|
14
15
|
#include "Sequence.h"
|
|
15
16
|
#include "Cluster.h"
|
|
16
17
|
#include "Shape.h"
|
|
17
18
|
#include "Part.h"
|
|
18
19
|
|
|
19
|
-
struct Bounds {
|
|
20
|
-
int min;
|
|
21
|
-
int max;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
20
|
class Cursor {
|
|
25
21
|
public:
|
|
26
22
|
Cursor(Cluster& cluster, Shape* shape);
|
|
27
|
-
virtual ~Cursor();
|
|
28
23
|
Sequence* join_outers();
|
|
29
|
-
std::vector<
|
|
30
|
-
std::list<
|
|
24
|
+
std::vector<InnerPolyline*> join_inners(Sequence* outer_seq);
|
|
25
|
+
std::list<InnerPolyline*> orphan_inners() { return orphan_inners_; }
|
|
26
|
+
const std::vector<Shape*>& shapes_sequence() const { return shapes_sequence_; }
|
|
31
27
|
|
|
32
28
|
private:
|
|
33
29
|
Cluster& cluster;
|
|
34
30
|
Shape* shape;
|
|
35
|
-
std::vector<
|
|
36
|
-
std::vector<Shape*> shapes_sequence;
|
|
31
|
+
std::vector<Shape*> shapes_sequence_;
|
|
37
32
|
std::unordered_set<Shape*> shapes_sequence_lookup;
|
|
38
|
-
std::list<
|
|
33
|
+
std::list<InnerPolyline*> orphan_inners_;
|
|
39
34
|
void traverse_outer(Part* act_part,
|
|
40
35
|
std::vector<Part*>& all_parts,
|
|
41
36
|
std::vector<Shape*>& shapes_sequence,
|
|
42
37
|
Sequence* outer_joined_polyline);
|
|
43
|
-
std::vector<
|
|
38
|
+
std::vector<InnerPolyline*> collect_inner_sequences(Sequence* outer_seq);
|
|
44
39
|
void traverse_inner(Part* act_part, std::vector<Part*> &all_parts, Bounds& bounds);
|
|
45
40
|
std::vector<EndPoint*> duplicates_intersection(Part& part_a, Part& part_b);
|
|
46
41
|
std::vector<std::vector<Point*>> combine(std::vector<std::vector<Point*>>& seqa, std::vector<std::vector<Point*>>& seqb);
|
|
@@ -30,19 +30,20 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
|
|
|
30
30
|
maximum_width_(bitmap->w()),
|
|
31
31
|
height(bitmap->h())
|
|
32
32
|
{ cpu_timer.start();
|
|
33
|
-
if (options != nullptr) FinderUtils::sanitize_options(this->
|
|
33
|
+
if (options != nullptr) FinderUtils::sanitize_options(this->options_, options);
|
|
34
34
|
|
|
35
|
-
double cw = static_cast<double>(this->maximum_width_) / this->
|
|
35
|
+
double cw = static_cast<double>(this->maximum_width_) / this->options_.number_of_tiles;
|
|
36
36
|
if (cw < 1.0) {
|
|
37
37
|
throw std::runtime_error("One pixel tile width minimum!");
|
|
38
38
|
}
|
|
39
39
|
int x = 0;
|
|
40
|
-
for (int tile_index = 0; tile_index < this->
|
|
40
|
+
for (int tile_index = 0; tile_index < this->options_.number_of_tiles; tile_index++)
|
|
41
41
|
{ int tile_end_x = static_cast<int>(cw * (tile_index + 1));
|
|
42
42
|
TilePayload p { tile_index, x, tile_end_x };
|
|
43
43
|
enqueue(p, [this](const TilePayload& payload) {
|
|
44
|
-
std::vector<std::string> base_arguments = {"--bounds", "--versus=" + this->
|
|
45
|
-
if (this->
|
|
44
|
+
std::vector<std::string> base_arguments = {"--bounds", "--versus=" + this->options_.get_alpha_versus()};
|
|
45
|
+
if (this->options_.connectivity_offset == 1) base_arguments.push_back("--connectivity=8");
|
|
46
|
+
if (this->options_.treemap) base_arguments.push_back("--treemap");
|
|
46
47
|
CpuTimer t;
|
|
47
48
|
t.start();
|
|
48
49
|
auto* finder = new ClippedPolygonFinder(
|
|
@@ -70,7 +71,7 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
|
|
|
70
71
|
|
|
71
72
|
Finder::Finder(int number_of_threads, std::vector<std::string> *options)
|
|
72
73
|
: Poolable(number_of_threads), bitmap(nullptr), matcher(nullptr), input_options(*options), maximum_width_(0) {
|
|
73
|
-
if (options != nullptr) FinderUtils::sanitize_options(this->
|
|
74
|
+
if (options != nullptr) FinderUtils::sanitize_options(this->options_, options);
|
|
74
75
|
reports["init"] = 0;
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -145,15 +146,17 @@ ProcessResult* Finder::process_info() {
|
|
|
145
146
|
pr->groups = pr->polygons.size();
|
|
146
147
|
pr->width = this->maximum_width_;
|
|
147
148
|
pr->height = this->height;
|
|
148
|
-
FakeCluster fake_cluster(pr->polygons, this->
|
|
149
|
+
FakeCluster fake_cluster(pr->polygons, this->options_);
|
|
149
150
|
cpu_timer.start();
|
|
150
|
-
fake_cluster.compress_coords(pr->polygons, this->
|
|
151
|
+
fake_cluster.compress_coords(pr->polygons, this->options_);
|
|
151
152
|
reports["compress"] = cpu_timer.stop();
|
|
152
153
|
reports["total"] = reports["compress"] + reports["init"];
|
|
153
154
|
reports["outer"] = this->whole_tile->benchmarks.outer;
|
|
154
155
|
reports["inner"] = this->whole_tile->benchmarks.inner;
|
|
156
|
+
if (this->options_.treemap) {
|
|
157
|
+
pr->treemap = this->whole_tile->compute_treemap();
|
|
158
|
+
}
|
|
155
159
|
pr->benchmarks = this->reports;
|
|
156
|
-
// TODO(ema): pr->treemap
|
|
157
160
|
// TODO(ema): pr->named_sequence
|
|
158
161
|
return(pr);
|
|
159
162
|
}
|
|
@@ -33,7 +33,7 @@ class Finder : public Poolable {
|
|
|
33
33
|
private:
|
|
34
34
|
Bitmap *bitmap;
|
|
35
35
|
Matcher *matcher;
|
|
36
|
-
pf_Options
|
|
36
|
+
pf_Options options_;
|
|
37
37
|
std::vector<std::string> input_options;
|
|
38
38
|
Tile* whole_tile = nullptr;
|
|
39
39
|
std::queue<ClippedPolygonFinder*> finders;
|
|
@@ -54,4 +54,5 @@ class Finder : public Poolable {
|
|
|
54
54
|
virtual ~Finder();
|
|
55
55
|
int maximum_width() const { return maximum_width_; }
|
|
56
56
|
virtual ProcessResult* process_info();
|
|
57
|
+
const pf_Options& options() const { return options_; }
|
|
57
58
|
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* InnerPolyline.cpp
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include <utility>
|
|
11
|
+
#include <vector>
|
|
12
|
+
#include "InnerPolyline.h"
|
|
13
|
+
|
|
14
|
+
InnerPolyline::InnerPolyline(std::vector<Point*> raw_coordinates, Shape* shape, bool recombined)
|
|
15
|
+
: raw_coordinates_(std::move(raw_coordinates)),
|
|
16
|
+
recombined_(recombined),
|
|
17
|
+
shape_(shape) {}
|
|
18
|
+
InnerPolyline::InnerPolyline(Sequence* sequence)
|
|
19
|
+
: sequence_(sequence) {
|
|
20
|
+
this->raw_coordinates_ = sequence->to_vector();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
std::vector<Point*>& InnerPolyline::raw() {
|
|
24
|
+
return this->raw_coordinates_;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Bounds& InnerPolyline::vertical_bounds() {
|
|
28
|
+
if (sequence_ != nullptr) {
|
|
29
|
+
return(sequence_->vertical_bounds);
|
|
30
|
+
} else {
|
|
31
|
+
return(this->raw_vertical_bounds());
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Shape* InnerPolyline::shape() {
|
|
36
|
+
if (sequence_ != nullptr) {
|
|
37
|
+
return(sequence_->shape);
|
|
38
|
+
} else {
|
|
39
|
+
return(this->shape_ ? this->shape_ : this->assigned_shape);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Bounds& InnerPolyline::raw_vertical_bounds() {
|
|
44
|
+
if (!raw_coordinates_.empty()) {
|
|
45
|
+
int min_y = raw_coordinates_[0]->y;
|
|
46
|
+
int max_y = raw_coordinates_[0]->y;
|
|
47
|
+
for (const auto& pos : raw_coordinates_) {
|
|
48
|
+
if (pos->y < min_y) min_y = pos->y;
|
|
49
|
+
if (pos->y > max_y) max_y = pos->y;
|
|
50
|
+
}
|
|
51
|
+
vertical_bounds_.min = min_y;
|
|
52
|
+
vertical_bounds_.max = max_y;
|
|
53
|
+
}
|
|
54
|
+
return(vertical_bounds_);
|
|
55
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* InnerPolyline.h
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#include <vector>
|
|
12
|
+
#include <optional>
|
|
13
|
+
#include "Sequence.h"
|
|
14
|
+
|
|
15
|
+
class InnerPolyline {
|
|
16
|
+
public:
|
|
17
|
+
explicit InnerPolyline(std::vector<Point*> raw_coordinates, Shape* shape, bool recombined = false);
|
|
18
|
+
explicit InnerPolyline(Sequence* sequence);
|
|
19
|
+
std::vector<Point*>& raw();
|
|
20
|
+
Sequence* sequence() { return this->sequence_; }
|
|
21
|
+
Bounds& vertical_bounds();
|
|
22
|
+
bool recombined() { return this->recombined_; }
|
|
23
|
+
Shape* shape();
|
|
24
|
+
Shape* assigned_shape = nullptr;
|
|
25
|
+
private:
|
|
26
|
+
bool recombined_ = false;
|
|
27
|
+
std::vector<Point*> raw_coordinates_;
|
|
28
|
+
Sequence* sequence_ = nullptr;
|
|
29
|
+
Shape* shape_;
|
|
30
|
+
Bounds& raw_vertical_bounds();
|
|
31
|
+
Bounds vertical_bounds_;
|
|
32
|
+
};
|
|
@@ -22,7 +22,7 @@ void Merger::add_tile(ProcessResult& result)
|
|
|
22
22
|
}
|
|
23
23
|
int end_x = this->current_x + result.width;
|
|
24
24
|
Tile* tile = new Tile(this, this->current_x, end_x, std::to_string(tiles.size()), Benchmarks {0, 0});
|
|
25
|
-
tile->assign_raw_polygons(result.polygons);
|
|
25
|
+
tile->assign_raw_polygons(result.polygons, result.treemap);
|
|
26
26
|
tiles.queue_push(tile);
|
|
27
27
|
|
|
28
28
|
this->maximum_width_ = end_x;
|
|
@@ -128,3 +128,24 @@ std::string Polyline::info() {
|
|
|
128
128
|
ss << "b" << this->tile->name() << " S" << part_index;
|
|
129
129
|
return ss.str();
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
bool Polyline::vert_bounds_intersect(Bounds& vertical_bounds)
|
|
133
|
+
{ return !(this->max_y_ < vertical_bounds.min || vertical_bounds.max < this->min_y);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
bool Polyline::within(std::vector<Point*>& points) {
|
|
137
|
+
size_t n = points.size();
|
|
138
|
+
if (n < 3) return false;
|
|
139
|
+
const int tx = this->raw_[0]->x;
|
|
140
|
+
const int ty = this->raw_[0]->y;
|
|
141
|
+
bool inside = false;
|
|
142
|
+
for (size_t i = 0, j = n - 1; i < n; j = i++) {
|
|
143
|
+
const Point* pi = points[i];
|
|
144
|
+
const Point* pj = points[j];
|
|
145
|
+
if (((pi->y > ty) != (pj->y > ty)) &&
|
|
146
|
+
(tx < (pj->x - pi->x) * (ty - pi->y) / (pj->y - pi->y) + pi->x)) {
|
|
147
|
+
inside = !inside;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return inside;
|
|
151
|
+
}
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
#include <unordered_map>
|
|
17
17
|
#include <string>
|
|
18
18
|
#include "Partitionable.h"
|
|
19
|
+
#include "Sequence.h"
|
|
19
20
|
#include "../RectBounds.h"
|
|
21
|
+
#include "../Primitives.h"
|
|
20
22
|
|
|
21
23
|
class Tile;
|
|
22
24
|
class Shape;
|
|
@@ -49,6 +51,8 @@ class Polyline : public Partitionable {
|
|
|
49
51
|
void reset_tracked_endpoints();
|
|
50
52
|
bool mixed_tile_origin = false;
|
|
51
53
|
std::string info();
|
|
54
|
+
bool vert_bounds_intersect(Bounds& vertical_bounds);
|
|
55
|
+
bool within(std::vector<Point*>& points);
|
|
52
56
|
|
|
53
57
|
private:
|
|
54
58
|
std::vector<Point*> raw_;
|
|
@@ -34,3 +34,17 @@ bool Sequence::is_not_vertical()
|
|
|
34
34
|
}
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
void Sequence::compute_vertical_bounds()
|
|
39
|
+
{ const auto& cache = get_vector_cache();
|
|
40
|
+
if (!cache.empty()) {
|
|
41
|
+
int min_y = cache[0]->y;
|
|
42
|
+
int max_y = cache[0]->y;
|
|
43
|
+
for (const auto& pos : cache) {
|
|
44
|
+
if (pos->y < min_y) min_y = pos->y;
|
|
45
|
+
if (pos->y > max_y) max_y = pos->y;
|
|
46
|
+
}
|
|
47
|
+
vertical_bounds.min = min_y;
|
|
48
|
+
vertical_bounds.max = max_y;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -9,13 +9,27 @@
|
|
|
9
9
|
|
|
10
10
|
#pragma once
|
|
11
11
|
#include <string>
|
|
12
|
+
#include <vector>
|
|
12
13
|
#include "Queueable.h"
|
|
13
14
|
#include "../Node.h"
|
|
14
15
|
#include "Position.h"
|
|
16
|
+
#include "../Primitives.h"
|
|
15
17
|
|
|
18
|
+
class Shape;
|
|
16
19
|
class Sequence : public Queueable<Point>{
|
|
17
20
|
public:
|
|
18
21
|
Sequence() {}
|
|
19
22
|
std::string toString();
|
|
20
23
|
bool is_not_vertical();
|
|
24
|
+
Shape* shape = nullptr;
|
|
25
|
+
Bounds vertical_bounds;
|
|
26
|
+
void compute_vertical_bounds();
|
|
27
|
+
const std::vector<Point*>& get_vector_cache() {
|
|
28
|
+
if (vector_cache.empty() && this->size > 0) {
|
|
29
|
+
vector_cache = this->to_vector();
|
|
30
|
+
}
|
|
31
|
+
return vector_cache;
|
|
32
|
+
}
|
|
33
|
+
private:
|
|
34
|
+
std::vector<Point*> vector_cache;
|
|
21
35
|
};
|
|
@@ -8,20 +8,29 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
#include <list>
|
|
11
|
+
#include <vector>
|
|
11
12
|
#include "Shape.h"
|
|
12
13
|
#include "Polyline.h"
|
|
13
14
|
|
|
14
|
-
Shape::Shape(Polyline* outer_polyline, const std::
|
|
15
|
+
Shape::Shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines)
|
|
15
16
|
: outer_polyline(outer_polyline),
|
|
16
17
|
inner_polylines(inner_polylines) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Shape::~Shape() {
|
|
20
|
-
if (outer_polyline) {
|
|
21
|
-
delete outer_polyline;
|
|
18
|
+
for (InnerPolyline* ip : inner_polylines) {
|
|
19
|
+
ip->assigned_shape = this;
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
void Shape::clear_inner() {
|
|
26
24
|
inner_polylines.clear();
|
|
27
25
|
}
|
|
26
|
+
|
|
27
|
+
void Shape::set_parent_shape(Shape* shape) {
|
|
28
|
+
if (this->parent_shape_ != nullptr)
|
|
29
|
+
{ auto& v = this->parent_shape_->children_shapes;
|
|
30
|
+
v.erase(std::remove(v.begin(), v.end(), this), v.end());
|
|
31
|
+
}
|
|
32
|
+
this->parent_shape_ = shape;
|
|
33
|
+
if (shape != nullptr)
|
|
34
|
+
{ shape->children_shapes.push_back(this);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -11,14 +11,22 @@
|
|
|
11
11
|
#include <list>
|
|
12
12
|
#include <iostream>
|
|
13
13
|
#include <vector>
|
|
14
|
+
#include "InnerPolyline.h"
|
|
14
15
|
|
|
15
16
|
class Point;
|
|
16
17
|
class Polyline;
|
|
17
18
|
class Shape {
|
|
18
19
|
public:
|
|
19
|
-
Shape(Polyline* outer_polyline, const std::
|
|
20
|
-
virtual ~Shape();
|
|
20
|
+
Shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines);
|
|
21
21
|
Polyline* outer_polyline = nullptr;
|
|
22
|
-
std::
|
|
22
|
+
std::vector<InnerPolyline*> inner_polylines;
|
|
23
|
+
Shape* merged_to_shape = nullptr;
|
|
24
|
+
InnerPolyline* parent_inner_polyline = nullptr;
|
|
25
|
+
std::vector<Shape*> children_shapes;
|
|
23
26
|
void clear_inner();
|
|
27
|
+
bool reassociation_skip = false;
|
|
28
|
+
Shape* parent_shape() { return parent_shape_; }
|
|
29
|
+
void set_parent_shape(Shape*);
|
|
30
|
+
private:
|
|
31
|
+
Shape* parent_shape_ = nullptr;
|
|
24
32
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ShapePool.cpp
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include <vector>
|
|
11
|
+
#include "Shape.h"
|
|
12
|
+
#include "ShapePool.h"
|
|
13
|
+
|
|
14
|
+
Shape* ShapePool::acquire_shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines) {
|
|
15
|
+
shapes_storage.emplace_back(outer_polyline, inner_polylines);
|
|
16
|
+
Shape* shape = &shapes_storage.back();
|
|
17
|
+
return shape;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
InnerPolyline* ShapePool::acquire_inner_polyline(std::vector<Point*> coords, Shape* shape, bool rec) {
|
|
21
|
+
inner_polylines_storage.emplace_back(coords, shape, rec);
|
|
22
|
+
InnerPolyline* ip = &inner_polylines_storage.back();
|
|
23
|
+
return ip;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
InnerPolyline* ShapePool::acquire_inner_polyline(Sequence* seq) {
|
|
27
|
+
inner_polylines_storage.emplace_back(seq);
|
|
28
|
+
InnerPolyline* ip = &inner_polylines_storage.back();
|
|
29
|
+
return ip;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Sequence* ShapePool::acquire_sequence() {
|
|
33
|
+
sequences_storage.emplace_back();
|
|
34
|
+
Sequence* s = &sequences_storage.back();
|
|
35
|
+
return s;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Polyline* ShapePool::acquire_polyline(Tile* tile, const std::vector<Point*>& polygon, const std::optional<RectBounds>& bounds = std::nullopt) {
|
|
39
|
+
polylines_storage.emplace_back(tile, polygon, bounds);
|
|
40
|
+
Polyline* p = &polylines_storage.back();
|
|
41
|
+
return p;
|
|
42
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ShapePool.h
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#include <deque>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include "Shape.h"
|
|
14
|
+
#include "../RectBounds.h"
|
|
15
|
+
#include "Polyline.h"
|
|
16
|
+
|
|
17
|
+
class Shape;
|
|
18
|
+
class Tile;
|
|
19
|
+
class Polyline;
|
|
20
|
+
class InnerPolyline;
|
|
21
|
+
class ShapePool {
|
|
22
|
+
private:
|
|
23
|
+
std::deque<Shape> shapes_storage;
|
|
24
|
+
std::deque<InnerPolyline> inner_polylines_storage;
|
|
25
|
+
std::deque<Sequence> sequences_storage;
|
|
26
|
+
std::deque<Polyline> polylines_storage;
|
|
27
|
+
|
|
28
|
+
public:
|
|
29
|
+
Shape* acquire_shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines);
|
|
30
|
+
InnerPolyline* acquire_inner_polyline(std::vector<Point*> coords, Shape* s, bool rec);
|
|
31
|
+
InnerPolyline* acquire_inner_polyline(Sequence* seq);
|
|
32
|
+
Sequence* acquire_sequence();
|
|
33
|
+
Polyline* acquire_polyline(Tile* tile, const std::vector<Point*>& polygon, const std::optional<RectBounds>& bounds);
|
|
34
|
+
};
|