contrek 1.1.7 → 1.1.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -1
  3. data/Gemfile.lock +1 -1
  4. data/README.md +50 -23
  5. data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +19 -11
  6. data/ext/cpp_polygon_finder/PolygonFinder/clean.sh +28 -0
  7. data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +4 -2
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +1 -1
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +2 -0
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +66 -61
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Primitives.h +14 -0
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.h +1 -1
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +86 -23
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +3 -0
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +24 -57
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +7 -13
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +12 -9
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +2 -1
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.cpp +55 -0
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.h +32 -0
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp +1 -1
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +38 -23
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +1 -2
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +21 -0
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +4 -0
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +1 -0
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +14 -0
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +14 -0
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +15 -6
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +11 -3
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp +42 -0
  32. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.h +34 -0
  33. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +72 -11
  34. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +9 -1
  35. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +4 -0
  36. data/lib/contrek/finder/concurrent/cluster.rb +58 -9
  37. data/lib/contrek/finder/concurrent/cursor.rb +11 -19
  38. data/lib/contrek/finder/concurrent/finder.rb +8 -2
  39. data/lib/contrek/finder/concurrent/inner_polyline.rb +49 -0
  40. data/lib/contrek/finder/concurrent/part.rb +26 -12
  41. data/lib/contrek/finder/concurrent/polyline.rb +46 -0
  42. data/lib/contrek/finder/concurrent/queueable.rb +0 -17
  43. data/lib/contrek/finder/concurrent/sequence.rb +21 -0
  44. data/lib/contrek/finder/concurrent/shape.rb +29 -2
  45. data/lib/contrek/finder/concurrent/tile.rb +36 -7
  46. data/lib/contrek/finder/node.rb +3 -1
  47. data/lib/contrek/finder/node_cluster.rb +56 -48
  48. data/lib/contrek/version.rb +1 -1
  49. data/lib/contrek.rb +1 -0
  50. 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->shapes_sequence.push_back(this->shape);
23
+ this->shapes_sequence_.push_back(this->shape);
29
24
  this->shapes_sequence_lookup.insert(this->shape);
30
- Sequence* outer_joined_polyline = new Sequence();
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->shapes_sequence,
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 : shapes_sequence) {
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<Sequence*> Cursor::join_inners(Sequence* outer_seq) {
131
- std::vector<Sequence*> retme;
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(shapes_sequence.begin(), shapes_sequence.end(), shape) != shapes_sequence.end()) {
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->shapes_sequence, missing_shapes);
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->shapes_sequence, to_delay_shapes);
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 : shapes_sequence) {
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
- orphan_inners_.end(),
218
- missing_shape->inner_polylines.begin(),
219
- missing_shape->inner_polylines.end());
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<Sequence*> Cursor::collect_inner_sequences(Sequence* outer_seq) {
228
- std::vector<Sequence*> return_sequences;
221
+ std::vector<InnerPolyline*> Cursor::collect_inner_sequences(Sequence* outer_seq) {
222
+ std::vector<InnerPolyline*> return_inner_polylines;
229
223
 
230
- for (Shape* shape : shapes_sequence)
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 = new 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()) return_sequences.push_back(retme_sequence);
255
- else delete retme_sequence;
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) {
@@ -286,7 +280,7 @@ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bound
286
280
  int dest_part_versus = dest_part->versus();
287
281
  if (dest_part_versus != 0 && dest_part_versus == act_part->versus()) continue;
288
282
  if (dest_part->intersect_part(act_part)) {
289
- std::vector<EndPoint*> link_seq = duplicates_intersection(*dest_part, *act_part);
283
+ std::vector<EndPoint*> link_seq = dest_part->continuum_to(*act_part);
290
284
  if (!link_seq.empty()) {
291
285
  Part* ins_part = pool.acquire(Part::ADDED, act_part->polyline());
292
286
  for (EndPoint* pos : link_seq) {
@@ -320,33 +314,6 @@ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bound
320
314
  }
321
315
  }
322
316
 
323
- template <typename T>
324
- std::vector<T*> difference_ptr(std::vector<T*>& a, std::vector<T*>& b)
325
- { std::vector<T*> result;
326
- for (T* item : a) {
327
- auto it = std::find_if(
328
- b.begin(), b.end(),
329
- [&](T* other) {
330
- return other == item;
331
- });
332
- if (it == b.end()) {
333
- result.push_back(item);
334
- }
335
- }
336
- return result;
337
- }
338
-
339
- std::vector<EndPoint*> Cursor::duplicates_intersection(Part& part_a, Part& part_b) {
340
- auto a1 = part_a.to_endpoints();
341
- auto b1 = part_b.to_endpoints();
342
- if (part_a.inverts) a1 = Part::remove_adjacent_pairs(a1);
343
- if (part_b.inverts) b1 = Part::remove_adjacent_pairs(b1);
344
- std::vector<EndPoint*> result = difference_ptr(a1, b1);
345
- std::vector<EndPoint*> temp = difference_ptr(b1, a1);
346
- result.insert(result.end(), temp.begin(), temp.end());
347
- return result;
348
- }
349
-
350
317
  std::vector<std::vector<Point*>> Cursor::combine(std::vector<std::vector<Point*>>& seqa, std::vector<std::vector<Point*>>& seqb)
351
318
  { std::vector<std::vector<Point*>> rets;
352
319
  size_t n = std::min(seqa.size(), seqb.size());
@@ -11,38 +11,32 @@
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<Sequence*> join_inners(Sequence* outer_seq);
30
- std::list<std::vector<Point*>> orphan_inners() { return orphan_inners_; }
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<Sequence*> allocated_sequences;
36
- std::vector<Shape*> shapes_sequence;
31
+ std::vector<Shape*> shapes_sequence_;
37
32
  std::unordered_set<Shape*> shapes_sequence_lookup;
38
- std::list<std::vector<Point*>> orphan_inners_;
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<Sequence*> collect_inner_sequences(Sequence* outer_seq);
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
- std::vector<EndPoint*> duplicates_intersection(Part& part_a, Part& part_b);
46
40
  std::vector<std::vector<Point*>> combine(std::vector<std::vector<Point*>>& seqa, std::vector<std::vector<Point*>>& seqb);
47
41
  std::vector<Shape*> connect_missings(std::vector<Shape*> shapes_sequence, std::vector<Shape*> missing_shapes);
48
42
  };
@@ -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->options, options);
33
+ if (options != nullptr) FinderUtils::sanitize_options(this->options_, options);
34
34
 
35
- double cw = static_cast<double>(this->maximum_width_) / this->options.number_of_tiles;
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->options.number_of_tiles; tile_index++)
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->options.get_alpha_versus()};
45
- if (this->options.connectivity_offset == 1) base_arguments.push_back("--connectivity=8");
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->options, options);
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->options);
149
+ FakeCluster fake_cluster(pr->polygons, this->options_);
149
150
  cpu_timer.start();
150
- fake_cluster.compress_coords(pr->polygons, this->options);
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 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;
@@ -74,29 +74,6 @@ bool Part::intersect_part(Part* other_part)
74
74
  return(intersect);
75
75
  }
76
76
 
77
- std::vector<EndPoint*> Part::to_endpoints() {
78
- std::vector<EndPoint*> out;
79
- QNode<Point>* current = head;
80
- while (current) {
81
- out.push_back((static_cast<Position*>(current))->end_point());
82
- current = current->next;
83
- }
84
- return out;
85
- }
86
-
87
- std::vector<EndPoint*> Part::remove_adjacent_pairs(const std::vector<EndPoint*>& input = {}) {
88
- std::vector<EndPoint*> result;
89
- result.reserve(input.size());
90
- for (EndPoint* current : input) {
91
- if (!result.empty() && result.back() == current) {
92
- result.pop_back();
93
- } else {
94
- result.push_back(current);
95
- }
96
- }
97
- return result;
98
- }
99
-
100
77
  void Part::orient()
101
78
  { if (this->size <= 1 || (this->size == 2 && this->inverts)) {
102
79
  this->versus_ = 0;
@@ -127,3 +104,41 @@ std::string Part::inspect() {
127
104
  ss << ")";
128
105
  return ss.str();
129
106
  }
107
+
108
+ std::vector<EndPoint*> Part::continuum_to(const Part& other_part) const {
109
+ if (this->size <= 2 && this->inverts && other_part.size <= 2 && other_part.inverts) return {};
110
+
111
+ Point* target = other_part.head->payload;
112
+ QNode<Point>* cursor = this->tail;
113
+
114
+ while (cursor != nullptr) {
115
+ if (*cursor->payload == *target) {
116
+ QNode<Point>* s = cursor;
117
+ QNode<Point>* o = other_part.head;
118
+ bool match = true;
119
+ int count = 0;
120
+
121
+ while (s != nullptr && o != nullptr) {
122
+ if (!(*s->payload == *o->payload)) {
123
+ match = false;
124
+ break;
125
+ }
126
+ s = s->next;
127
+ o = o->next;
128
+ count++;
129
+ }
130
+ if (match && s == nullptr) {
131
+ std::vector<EndPoint*> res;
132
+ res.reserve(count);
133
+ s = cursor;
134
+ for (int i = 0; i < count; ++i) {
135
+ res.push_back(static_cast<Position*>(s)->end_point());
136
+ s = s->next;
137
+ }
138
+ return res;
139
+ }
140
+ }
141
+ cursor = cursor->prev;
142
+ }
143
+ return {};
144
+ }
@@ -47,10 +47,9 @@ class Part : public Queueable<Point> {
47
47
  void touch();
48
48
  bool intersect_part(Part* other_part);
49
49
  void set_polyline(Polyline* polyline) { this->polyline_ = polyline; }
50
- std::vector<EndPoint*> to_endpoints();
51
- static std::vector<EndPoint*> remove_adjacent_pairs(const std::vector<EndPoint*>& input);
52
50
  void orient();
53
51
  std::string inspect();
52
+ std::vector<EndPoint*> continuum_to(const Part& other_part) const;
54
53
 
55
54
  private:
56
55
  int versus_ = 0;
@@ -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_;
@@ -177,6 +177,7 @@ class Queueable {
177
177
 
178
178
  std::vector<T*> to_vector() const {
179
179
  std::vector<T*> out;
180
+ out.reserve(this->size);
180
181
  QNode<T>* current = head;
181
182
  while (current) {
182
183
  out.push_back(current->payload);
@@ -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::list<std::vector<Point*>>& inner_polylines)
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::list<std::vector<Point*>>& inner_polylines);
20
- virtual ~Shape();
20
+ Shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines);
21
21
  Polyline* outer_polyline = nullptr;
22
- std::list<std::vector<Point*>> inner_polylines;
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
  };