contrek 1.3.3 → 1.3.4

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/Gemfile.lock +3 -1
  4. data/README.md +28 -28
  5. data/contrek.gemspec +1 -0
  6. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +2 -0
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +0 -2
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +11 -5
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +8 -10
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +4 -1
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +114 -42
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +1 -1
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +2 -1
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +1 -1
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +66 -116
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +1 -1
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +1 -0
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +2 -87
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +1 -13
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp +0 -1
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +1 -57
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +1 -4
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +31 -17
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +0 -16
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +0 -9
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +1 -1
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.cpp +177 -0
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.h +52 -0
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.cpp +109 -0
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.h +32 -0
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +6 -1
  32. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +4 -0
  33. data/lib/contrek/bitmaps/painting.rb +27 -10
  34. data/lib/contrek/bitmaps/png_bitmap.rb +3 -0
  35. data/lib/contrek/bitmaps/raw_bitmap.rb +1 -0
  36. data/lib/contrek/bitmaps/rendering.rb +74 -0
  37. data/lib/contrek/finder/concurrent/cursor.rb +62 -84
  38. data/lib/contrek/finder/concurrent/finder.rb +2 -1
  39. data/lib/contrek/finder/concurrent/part.rb +4 -77
  40. data/lib/contrek/finder/concurrent/partitionable.rb +1 -58
  41. data/lib/contrek/finder/concurrent/queueable.rb +23 -5
  42. data/lib/contrek/finder/concurrent/sequence.rb +0 -15
  43. data/lib/contrek/finder/concurrent/tile.rb +1 -1
  44. data/lib/contrek/finder/node.rb +26 -8
  45. data/lib/contrek/finder/node_cluster.rb +91 -37
  46. data/lib/contrek/finder/polygon_finder.rb +1 -1
  47. data/lib/contrek/reducers/douglas_peucker_reducer.rb +191 -0
  48. data/lib/contrek/reducers/raster_reducer.rb +72 -0
  49. data/lib/contrek/version.rb +1 -1
  50. data/lib/contrek.rb +3 -0
  51. metadata +23 -2
@@ -6,6 +6,7 @@
6
6
  * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
7
  * See the LICENSE file in this directory for the full license text.
8
8
  */
9
+
9
10
  #include <algorithm>
10
11
  #include <vector>
11
12
  #include <utility>
@@ -18,8 +19,8 @@ Cursor::Cursor(Cluster& cluster, Shape* shape)
18
19
  : cluster(cluster), shape(shape) {
19
20
  }
20
21
 
21
- Sequence Cursor::join_outers()
22
- { Polyline* outer_polyline = shape->outer_polyline;
22
+ Sequence Cursor::join_outers() {
23
+ Polyline* outer_polyline = shape->outer_polyline;
23
24
  this->shapes_sequence_.push_back(this->shape);
24
25
  this->shapes_sequence_lookup.insert(this->shape);
25
26
  Sequence outer_joined_polyline;
@@ -47,42 +48,67 @@ Sequence Cursor::join_outers()
47
48
  return(outer_joined_polyline);
48
49
  }
49
50
 
50
- void Cursor::traverse_outer(Part* act_part,
51
+ std::vector<InnerPolyline*> Cursor::join_inners(bool treemap) {
52
+ std::vector<InnerPolyline*> return_inner_polylines;
53
+ std::vector<Shape*> processing_queue = shapes_sequence_;
54
+
55
+ for (size_t i = 0; i < shapes_sequence_.size(); ++i)
56
+ { Shape* shape = shapes_sequence_[i];
57
+ Polyline* polyline = shape->outer_polyline;
58
+ for (Part* part : polyline->parts())
59
+ { if (part->innerable())
60
+ { std::vector<Part*> all_parts;
61
+ std::vector<EndPoint*> tracked_end_points;
62
+ traverse_inner(part, all_parts, tracked_end_points);
63
+ Sequence retme_sequence;
64
+ for (Part* part : all_parts)
65
+ { part->touch();
66
+ retme_sequence.append(*part);
67
+ }
68
+ InnerPolyline* inner_polyline = polyline->tile->shapes_pool->acquire_inner_polyline(&retme_sequence);
69
+ return_inner_polylines.push_back(inner_polyline);
70
+ if (treemap) {
71
+ mark_children(tracked_end_points, polyline, inner_polyline);
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return(return_inner_polylines);
77
+ }
78
+
79
+ void Cursor::traverse_outer(Part* start_part,
51
80
  std::vector<Part*>& all_parts,
52
81
  std::vector<Shape*>& shapes_sequence,
53
82
  Sequence& outer_joined_polyline) {
83
+ Part* act_part = start_part;
84
+
54
85
  while (act_part != nullptr) {
55
86
  Part* last_part = (!all_parts.empty()) ? all_parts.back() : nullptr;
56
87
  if (all_parts.empty() || last_part != act_part) {
57
88
  all_parts.push_back(act_part);
58
89
  }
59
90
  bool jumped_to_new_part = false;
91
+
60
92
  if (act_part->is(Part::EXCLUSIVE)) {
61
93
  if (act_part->size == 0) return;
62
-
63
94
  while (Position *position = act_part->next_position(nullptr)) {
64
95
  outer_joined_polyline.add(position);
65
96
  }
66
97
  } else {
67
- if (act_part->dead_end &&
68
- all_parts.size() > 1 &&
69
- last_part->is(Part::SEAM) &&
70
- last_part->polyline() == act_part->polyline()) return;
71
98
  while (Position *new_position = static_cast<Position*>(act_part->iterator())) {
72
99
  if (outer_joined_polyline.size > 1 &&
73
- outer_joined_polyline.head->payload == new_position->payload &&
74
- act_part == all_parts.front()) {
100
+ outer_joined_polyline.head->payload == new_position->payload &&
101
+ act_part == all_parts.front()) {
75
102
  return;
76
103
  }
77
- this->cluster.positions_pool.emplace_back(this->cluster.hub(), new_position->payload);
78
- outer_joined_polyline.add(&this->cluster.positions_pool.back());
79
104
  new_position->end_point()->tracked_outer = true;
80
105
  int versus = act_part->versus();
81
106
  auto& q_set = new_position->end_point()->queues();
82
107
  auto it = std::find_if(q_set.begin(), q_set.end(), [&](Queueable<Point>* q) {
83
108
  Part* p = static_cast<Part*>(q);
84
- return (p->mirror || act_part->mirror || p->versus() == -versus) && p->polyline()->tile != act_part->polyline()->tile;
109
+ return (p->versus() == -versus) && p->polyline()->tile != act_part->polyline()->tile;
85
110
  });
111
+
86
112
  Part* part = nullptr;
87
113
  if (it != q_set.end()) {
88
114
  part = static_cast<Part*>(*it);
@@ -91,31 +117,16 @@ void Cursor::traverse_outer(Part* act_part,
91
117
  const auto n = all_parts.size();
92
118
  Part *last_last_part = n >= 2 ? all_parts[n - 2] : nullptr;
93
119
  if (last_last_part != part) {
94
- bool all_seam = false;
95
- if (n >= 2) {
96
- all_seam = true;
97
- for (std::size_t i = all_parts.size() - 2; i < all_parts.size(); ++i) {
98
- if (all_parts[i]->type != Part::SEAM) {
99
- all_seam = false;
100
- break;
101
- }
102
- }
103
- }
104
- if (!all_seam) {
105
- if (shapes_sequence_lookup.insert(part->polyline()->shape).second) {
106
- shapes_sequence.push_back(part->polyline()->shape);
107
- }
108
- part->next_position(new_position);
109
- part->dead_end = true;
110
- act_part = part;
111
- jumped_to_new_part = true;
112
- break;
120
+ if (shapes_sequence_lookup.insert(part->polyline()->shape).second) {
121
+ shapes_sequence.push_back(part->polyline()->shape);
113
122
  }
123
+ part->next_position(new_position);
124
+ act_part = part;
125
+ jumped_to_new_part = true;
126
+ break;
114
127
  }
115
128
  }
116
- if (!jumped_to_new_part) {
117
- act_part->next_position(nullptr);
118
- }
129
+ act_part->next_position(nullptr);
119
130
  }
120
131
  }
121
132
  if (jumped_to_new_part) continue;
@@ -125,79 +136,9 @@ void Cursor::traverse_outer(Part* act_part,
125
136
  }
126
137
  }
127
138
 
128
- std::vector<InnerPolyline*> Cursor::join_inners(bool treemap) {
129
- std::vector<InnerPolyline*> return_inner_polylines;
130
- std::vector<Shape*> processing_queue = shapes_sequence_;
131
- for (size_t i = 0; i < shapes_sequence_.size(); ++i)
132
- { Shape* shape = shapes_sequence_[i];
133
- Polyline* polyline = shape->outer_polyline;
134
- for (Part* part : polyline->parts())
135
- { if (part->innerable())
136
- { std::vector<Part*> all_parts;
137
- std::vector<EndPoint*> tracked_end_points;
138
- Bounds bounds{
139
- .min = polyline->max_y(),
140
- .max = 0
141
- };
142
- traverse_inner(part, all_parts, bounds, tracked_end_points);
143
- Sequence retme_sequence;
144
- for (Part* part : all_parts)
145
- { part->touch();
146
- retme_sequence.move_from(*part, [&](QNode<Point>* pos) -> bool {
147
- Position *position = static_cast<Position*>(pos);
148
- if (part->is(Part::ADDED) &&
149
- !(position->payload.y >= bounds.min &&
150
- position->payload.y <= bounds.max)) {
151
- return(false);
152
- }
153
- return(!(polyline->tile->tg_border(position->payload) && position->end_point()->tracked_outer));
154
- });
155
- }
156
- if (retme_sequence.is_not_vertical()) {
157
- InnerPolyline* inner_polyline = polyline->tile->shapes_pool->acquire_inner_polyline(&retme_sequence);
158
- return_inner_polylines.push_back(inner_polyline);
159
- if (treemap) {
160
- mark_children(tracked_end_points, polyline, inner_polyline);
161
- }
162
- }
163
- }
164
- }
165
- }
166
- return(return_inner_polylines);
167
- }
168
-
169
- void Cursor::mark_children(std::vector<EndPoint*>& end_points, const Polyline* outer_polyline, InnerPolyline* inner_polyline) {
170
- for (size_t i = 0; i + 1 < end_points.size(); i += 2) {
171
- const auto& a = end_points[i];
172
- const auto& b = end_points[i + 1];
173
- auto [y_min, y_max] = std::minmax(a->get_point().y, b->get_point().y);
174
- for (int y = y_min + 1; y < y_max; ++y) {
175
- EndPoint* end_point = this->cluster.hub()->get(y);
176
- if (end_point) {
177
- for (auto part_p : end_point->queues())
178
- { Part* part = static_cast<Part*>(part_p);
179
- if (part->polyline() != outer_polyline) {
180
- part->polyline()->inside_inner_polyline = inner_polyline;
181
- }
182
- }
183
- }
184
- }
185
- }
186
- }
187
-
188
- void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bounds& bounds, std::vector<EndPoint*>& tracked_end_points) {
189
- PartPool& pool = act_part->polyline()->tile->cluster->parts_pool;
139
+ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, std::vector<EndPoint*>& tracked_end_points) {
190
140
  while (act_part != nullptr) {
191
141
  if (!all_parts.empty() && act_part == all_parts.front()) return;
192
- if (act_part->size > 0) {
193
- auto points = act_part->to_vector();
194
- auto [min_it, max_it] = std::minmax_element(
195
- points.begin(),
196
- points.end(),
197
- [](const Point& a, const Point& b) { return a.y < b.y; });
198
- bounds.min = std::min(bounds.min, min_it->y);
199
- bounds.max = std::max(bounds.max, max_it->y);
200
- }
201
142
  if (act_part->innerable()) {
202
143
  all_parts.push_back(act_part);
203
144
  bool jumped = false;
@@ -216,16 +157,6 @@ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bound
216
157
  if (dest_part_versus != 0 && dest_part_versus == act_part->versus()) continue;
217
158
 
218
159
  tracked_end_points.push_back(current_end_point);
219
-
220
- std::vector<EndPoint*> link_seq = dest_part->continuum_to(*act_part);
221
- if (!link_seq.empty()) {
222
- Part* ins_part = pool.acquire(Part::ADDED, act_part->polyline());
223
- for (EndPoint* pos : link_seq) {
224
- this->cluster.positions_pool.emplace_back(pos);
225
- ins_part->add(&this->cluster.positions_pool.back());
226
- }
227
- all_parts.push_back(ins_part);
228
- }
229
160
  Shape* shape = dest_part->polyline()->shape;
230
161
  if (!dest_part->polyline()->is_on(Polyline::TRACKED_OUTER))
231
162
  { shapes_sequence_.push_back(shape);
@@ -260,3 +191,22 @@ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bound
260
191
  else break;
261
192
  }
262
193
  }
194
+
195
+ void Cursor::mark_children(std::vector<EndPoint*>& end_points, const Polyline* outer_polyline, InnerPolyline* inner_polyline) {
196
+ for (size_t i = 0; i + 1 < end_points.size(); i += 2) {
197
+ const auto& a = end_points[i];
198
+ const auto& b = end_points[i + 1];
199
+ auto [y_min, y_max] = std::minmax(a->get_point().y, b->get_point().y);
200
+ for (int y = y_min + 1; y < y_max; ++y) {
201
+ EndPoint* end_point = this->cluster.hub()->get(y);
202
+ if (end_point) {
203
+ for (auto part_p : end_point->queues())
204
+ { Part* part = static_cast<Part*>(part_p);
205
+ if (part->polyline() != outer_polyline) {
206
+ part->polyline()->inside_inner_polyline = inner_polyline;
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
@@ -35,7 +35,7 @@ class Cursor {
35
35
  std::vector<Part*>& all_parts,
36
36
  std::vector<Shape*>& shapes_sequence,
37
37
  Sequence& outer_joined_polyline);
38
- void traverse_inner(Part* act_part, std::vector<Part*> &all_parts, Bounds& bounds, std::vector<EndPoint*>& tracked_end_points);
38
+ void traverse_inner(Part* act_part, std::vector<Part*> &all_parts, std::vector<EndPoint*>& tracked_end_points);
39
39
  std::vector<Shape*> connect_missings(std::vector<Shape*> shapes_sequence, std::vector<Shape*> missing_shapes);
40
40
  void mark_children(std::vector<EndPoint*>& end_points, const Polyline* outer_polyline, InnerPolyline* inner_polyline);
41
41
  };
@@ -139,6 +139,7 @@ ProcessResult* Finder::process_info() {
139
139
  pr->width = this->maximum_width_;
140
140
  pr->height = this->height;
141
141
  pr->has_bounds = this->options_.bounds;
142
+ pr->versus = this->options_.versus;
142
143
  FakeCluster fake_cluster(pr->polygons, this->options_);
143
144
  cpu_timer.start();
144
145
  fake_cluster.compress_coords(pr->polygons, this->options_);
@@ -29,8 +29,8 @@ Position* Part::next_position(Position* force_position) {
29
29
  if (force_position != nullptr)
30
30
  { QNode<Point>* move_to_this = nullptr;
31
31
  this->reverse_each([&](QNode<Point>* pos) -> bool {
32
+ move_to_this = pos;
32
33
  if (pos->payload == force_position->payload) {
33
- move_to_this = pos;
34
34
  return false;
35
35
  }
36
36
  return true;
@@ -62,12 +62,11 @@ void Part::touch()
62
62
  }
63
63
 
64
64
  void Part::orient()
65
- { if (this->size <= 1 || (this->size == 2 && this->inverts)) {
65
+ { if (this->size <= 1) {
66
66
  this->versus_ = 0;
67
67
  } else {
68
68
  int diff = this->tail->payload.y - this->head->payload.y;
69
69
  if (diff == 0) {
70
- this->mirror = true;
71
70
  this->versus_ = 0;
72
71
  } else {
73
72
  this->versus_ = diff > 0 ? 1 : -1;
@@ -75,52 +74,10 @@ void Part::orient()
75
74
  }
76
75
  }
77
76
 
78
- void Part::try_transmutation() {
79
- auto& head_queues = static_cast<Position*>(this->head)->end_point()->queues();
80
- if (head_queues.size() == 1) {
81
- return;
82
- }
83
-
84
- auto other_head_it = std::find_if(head_queues.begin(), head_queues.end(), [this](auto* queueable_ptr) {
85
- Part* part = static_cast<Part*>(queueable_ptr);
86
- return part != this && part->polyline()->tile == this->polyline()->tile;
87
- });
88
-
89
- if (other_head_it != head_queues.end()) {
90
- Part* other_head_part = static_cast<Part*>(*other_head_it);
91
- auto& tail_queues = static_cast<Position*>(this->tail)->end_point()->queues();
92
- auto found_in_tail = std::find(tail_queues.begin(), tail_queues.end(), other_head_part);
93
- if (found_in_tail != tail_queues.end()) {
94
- if ( (other_head_part->tail->payload.y == tail->payload.y && other_head_part->head->payload.y == head->payload.y) ||
95
- (other_head_part->tail->payload.y == head->payload.y && other_head_part->head->payload.y == tail->payload.y)) {
96
- if (this->next == nullptr && other_head_part->prev == nullptr) {
97
- this->mirror = true;
98
- }
99
- } else {
100
- this->type = Part::EXCLUSIVE;
101
- this->trasmuted = true;
102
- other_head_part->transmutation_skip = true;
103
- }
104
- }
105
- }
106
- }
107
-
108
- bool Part::within(Part* other) {
109
- const auto [self_min, self_max] = std::minmax(this->head->payload.y, this->tail->payload.y);
110
- const auto [other_min, other_max] = std::minmax(other->head->payload.y, other->tail->payload.y);
111
- return (self_min >= other_min) && (self_max <= other_max);
112
- }
113
-
114
- bool Part::same_length(Part* other) {
115
- return( std::abs(this->head->payload.y - this->tail->payload.y) ==
116
- std::abs(other->head->payload.y - other->tail->payload.y));
117
- }
118
-
119
77
  constexpr std::string_view typeToString(Part::Types t) noexcept {
120
78
  switch (t) {
121
79
  case Part::SEAM: return "SEAM";
122
80
  case Part::EXCLUSIVE: return "EXCLUSIVE";
123
- case Part::ADDED: return "ADDED";
124
81
  default: return "UNKNOWN";
125
82
  }
126
83
  }
@@ -134,11 +91,7 @@ std::string Part::inspect() {
134
91
  std::stringstream ss;
135
92
  ss << "part " << part_index
136
93
  << " (versus=" << this->versus_
137
- << " mirror=" << this->mirror
138
- << " inv=" << this->inverts
139
- << " trm=" << this->trasmuted
140
94
  << " touched=" << this->touched_
141
- << " dead_end=" << this->dead_end
142
95
  << ", " << this->size << "x) of " << this->polyline()->tile->name() << " " << this->polyline()->named()
143
96
  << " (" << typeToString(type) << ") (";
144
97
  this->each([&](QNode<Point>* pos) -> bool {
@@ -148,41 +101,3 @@ std::string Part::inspect() {
148
101
  ss << ")";
149
102
  return ss.str();
150
103
  }
151
-
152
- std::vector<EndPoint*> Part::continuum_to(const Part& other_part) const {
153
- if (this->size <= 2 && this->inverts && other_part.size <= 2 && other_part.inverts) return {};
154
-
155
- const Point& target = other_part.head->payload;
156
- QNode<Point>* cursor = this->tail;
157
-
158
- while (cursor != nullptr) {
159
- if (cursor->payload == target) {
160
- QNode<Point>* s = cursor;
161
- QNode<Point>* o = other_part.head;
162
- bool match = true;
163
- int count = 0;
164
-
165
- while (s != nullptr && o != nullptr) {
166
- if (!(s->payload == o->payload)) {
167
- match = false;
168
- break;
169
- }
170
- s = s->next;
171
- o = o->next;
172
- count++;
173
- }
174
- if (match && s == nullptr) {
175
- std::vector<EndPoint*> res;
176
- res.reserve(count);
177
- s = cursor;
178
- for (int i = 0; i < count; ++i) {
179
- res.push_back(static_cast<Position*>(s)->end_point());
180
- s = s->next;
181
- }
182
- return res;
183
- }
184
- }
185
- cursor = cursor->prev;
186
- }
187
- return {};
188
- }
@@ -24,25 +24,17 @@ class Part : public Queueable<Point> {
24
24
  public:
25
25
  enum Types : uint32_t {
26
26
  SEAM = 1,
27
- EXCLUSIVE = 0,
28
- ADDED = 2
27
+ EXCLUSIVE = 0
29
28
  };
30
29
  explicit Part(Types type, Polyline* polyline);
31
30
  bool listable() const override { return true; }
32
31
  bool is(Types type);
33
- bool inverts = false;
34
- bool trasmuted = false;
35
- bool transmutation_skip = false;
36
- bool dead_end = false;
37
- bool mirror = false;
38
32
 
39
33
  private:
40
34
  bool touched_ = false;
41
35
 
42
36
  public:
43
37
  Part* next = nullptr;
44
- Part* next_seam = nullptr;
45
- Part* prev = nullptr;
46
38
  Part* circular_next = nullptr;
47
39
  std::string toString() const { return "Part type = " + std::to_string(static_cast<uint32_t>(type)); }
48
40
  Polyline* polyline() { return polyline_; }
@@ -55,10 +47,6 @@ class Part : public Queueable<Point> {
55
47
  void touch();
56
48
  void orient();
57
49
  std::string inspect();
58
- std::vector<EndPoint*> continuum_to(const Part& other_part) const;
59
- bool within(Part* other);
60
- bool same_length(Part* other);
61
- void try_transmutation();
62
50
 
63
51
  private:
64
52
  int versus_ = 0;
@@ -16,7 +16,6 @@ Part* PartPool::acquire(uint32_t type, Polyline* poly) {
16
16
 
17
17
  Part* p = &storage.back();
18
18
  p->next = nullptr;
19
- p->prev = nullptr;
20
19
  return p;
21
20
  }
22
21
 
@@ -29,31 +29,19 @@ void Partitionable::add_part(Part* new_part)
29
29
  if (last) {
30
30
  last->next = last->circular_next = new_part;
31
31
  }
32
- new_part->prev = last;
33
32
  new_part->circular_next = this->parts_.front();
34
33
 
35
34
  if (new_part->is(Part::SEAM)) {
36
- if (!this->first_seam) {
37
- this->first_seam = new_part;
38
- }
39
- if (this->last_seam) {
40
- this->last_seam->next_seam = new_part;
41
- }
42
- this->last_seam = new_part;
43
35
  new_part->orient();
44
36
  }
45
37
  }
46
38
 
47
39
  void Partitionable::partition()
48
40
  { this->parts_.clear();
49
- this->first_seam = nullptr;
50
- this->last_seam = nullptr;
51
-
52
41
  Polyline *polyline = static_cast<Polyline*>(this);
53
42
  PartPool& pool = polyline->tile->cluster->parts_pool;
54
43
  Part *current_part = nullptr;
55
- int n = 0;
56
- const Point* prev_position = nullptr;
44
+
57
45
  for (const Point& position : polyline->raw())
58
46
  { if (polyline->tile->tg_border(position))
59
47
  { if (current_part == nullptr) {
@@ -68,51 +56,7 @@ void Partitionable::partition()
68
56
  this->add_part(current_part);
69
57
  current_part = pool.acquire(Part::EXCLUSIVE, polyline);
70
58
  }
71
- if (n > 0 && *prev_position == position) {
72
- current_part->inverts = true;
73
- }
74
59
  current_part->add_position(position);
75
- n++;
76
- prev_position = &position;
77
60
  }
78
61
  this->add_part(current_part);
79
-
80
- this->transmute_parts();
81
- }
82
-
83
- void Partitionable::transmute_transposed_part(Part* part) {
84
- if (Part* current_seam = this->first_seam; current_seam != nullptr) {
85
- while (current_seam != nullptr) {
86
- if (current_seam != part) {
87
- if (part->within(current_seam)) {
88
- if (!part->same_length(current_seam)) {
89
- part->type = Part::EXCLUSIVE;
90
- part->trasmuted = true;
91
- std::vector<Queueable<Point>*>& a = static_cast<Position*>(part->head)->end_point()->queues();
92
- a.erase(std::remove(a.begin(), a.end(), part), a.end());
93
- std::vector<Queueable<Point>*>& b = static_cast<Position*>(part->tail)->end_point()->queues();
94
- b.erase(std::remove(b.begin(), b.end(), part), b.end());
95
- }
96
- }
97
- }
98
- current_seam = current_seam->next_seam;
99
- }
100
- }
101
- }
102
-
103
- void Partitionable::transmute_parts()
104
- { Polyline *polyline = static_cast<Polyline*>(this);
105
- bool transpose = polyline->tile->cluster->finder()->transpose();
106
- if (Part* current_seam = this->first_seam; current_seam != nullptr) {
107
- while (current_seam != nullptr) {
108
- if (transpose) {
109
- transmute_transposed_part(current_seam);
110
- } else {
111
- if (!current_seam->transmutation_skip) {
112
- current_seam->try_transmutation();
113
- }
114
- }
115
- current_seam = current_seam->next_seam;
116
- }
117
- }
118
62
  }
@@ -21,10 +21,7 @@ class Partitionable {
21
21
 
22
22
  protected:
23
23
  std::vector<Part*> parts_;
24
- Part* first_seam = nullptr;
25
- Part* last_seam = nullptr;
24
+
26
25
  private:
27
26
  void add_part(Part* new_part);
28
- void transmute_parts();
29
- void transmute_transposed_part(Part* part);
30
27
  };
@@ -120,15 +120,6 @@ class Queueable {
120
120
  }
121
121
  }
122
122
 
123
- template<typename Func>
124
- void move_from(Queueable<T>& queueable, Func func) {
125
- queueable.rewind();
126
- while (QNode<T>* node = queueable.iterator())
127
- { queueable.forward();
128
- if (func(node)) add(node);
129
- }
130
- }
131
-
132
123
  std::vector<T> to_vector() const {
133
124
  std::vector<T> out;
134
125
  out.reserve(this->size);
@@ -140,16 +131,39 @@ class Queueable {
140
131
  return out;
141
132
  }
142
133
 
143
- std::vector<T> map(std::function<T(QNode<T>*)> fn) {
144
- std::vector<T> out;
145
- each([&](QNode<T>* n){
146
- out.push_back(fn(n));
147
- });
148
- return out;
149
- }
150
-
151
134
  QNode<T>* pop() {
152
135
  if (!tail) return nullptr;
153
136
  return rem(tail);
154
137
  }
138
+
139
+ void reset() {
140
+ head = nullptr;
141
+ tail = nullptr;
142
+ _iterator = nullptr;
143
+ _started = false;
144
+ size = 0;
145
+ }
146
+
147
+ void append(Queueable<T>& q) {
148
+ if (q.size == 0) return;
149
+ QNode<T>* current = q.head;
150
+ while (current) {
151
+ current->before_rem(&q);
152
+ current->owner = this;
153
+ current = current->next;
154
+ }
155
+ if (tail) {
156
+ tail->next = q.head;
157
+ q.head->prev = tail;
158
+ } else {
159
+ head = q.head;
160
+ }
161
+ tail = q.tail;
162
+ size += q.size;
163
+ q.reset();
164
+ each([&](QNode<T>* n) -> bool {
165
+ n->after_add(this);
166
+ return(true);
167
+ });
168
+ }
155
169
  };
@@ -18,19 +18,3 @@ std::string Sequence::toString() {
18
18
  });
19
19
  return(retme);
20
20
  }
21
-
22
- bool Sequence::is_not_vertical()
23
- { if (this->size < 2) {
24
- return false;
25
- }
26
- int x0 = head->payload.x;
27
- this->rewind();
28
-
29
- while (QNode<Point>* position = this->iterator())
30
- { if (position->payload.x != x0) {
31
- return true;
32
- }
33
- this->forward();
34
- }
35
- return false;
36
- }
@@ -20,14 +20,5 @@ class Sequence : public Queueable<Point>{
20
20
  public:
21
21
  Sequence() {}
22
22
  std::string toString();
23
- bool is_not_vertical();
24
23
  Shape* shape = nullptr;
25
- const std::vector<Point>& get_vector_cache() {
26
- if (vector_cache.empty() && this->size > 0) {
27
- vector_cache = this->to_vector();
28
- }
29
- return vector_cache;
30
- }
31
- private:
32
- std::vector<Point> vector_cache;
33
24
  };
@@ -94,7 +94,7 @@ void Tile::assign_shapes(std::vector<Shape*>& shapes) {
94
94
  }
95
95
 
96
96
  bool Tile::tg_border(const Point& coord) {
97
- return( coord.x == (this->next == nullptr ? start_x_ : (end_x_ - 1)));
97
+ return( coord.x == (this->next == nullptr ? start_x_ : (end_x_)));
98
98
  }
99
99
 
100
100
  void Tile::info() {