contrek 1.2.1 → 1.2.3

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -1
  3. data/Gemfile.lock +1 -1
  4. data/PERFORMANCE.md +177 -0
  5. data/README.md +2 -1
  6. data/contrek.gemspec +5 -1
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +39 -16
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +4 -3
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +74 -3
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +32 -41
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +2 -1
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +33 -5
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +3 -2
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.cpp +1 -2
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.h +1 -3
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +16 -20
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +8 -3
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +5 -0
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +3 -1
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp +2 -2
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.h +1 -1
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +5 -3
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +4 -4
  24. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +2 -3
  25. data/lib/contrek/cpp/cpp_result.rb +2 -0
  26. data/lib/contrek/finder/concurrent/cluster.rb +30 -29
  27. data/lib/contrek/finder/concurrent/cursor.rb +35 -12
  28. data/lib/contrek/finder/concurrent/inner_polyline.rb +2 -3
  29. data/lib/contrek/finder/concurrent/polyline.rb +5 -7
  30. data/lib/contrek/finder/concurrent/shape.rb +7 -3
  31. data/lib/contrek/finder/concurrent/tile.rb +5 -4
  32. data/lib/contrek/finder/result.rb +2 -0
  33. data/lib/contrek/shared/result.rb +23 -0
  34. data/lib/contrek/version.rb +1 -1
  35. data/lib/contrek.rb +2 -1
  36. metadata +4 -6
  37. data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +0 -56
  38. data/ext/cpp_polygon_finder/PolygonFinder/images/graphs_1024x1024.png +0 -0
  39. data/ext/cpp_polygon_finder/PolygonFinder/images/labyrinth.png +0 -0
  40. data/ext/cpp_polygon_finder/PolygonFinder/images/sample_10240x10240.png +0 -0
@@ -129,7 +129,7 @@ void Cursor::traverse_outer(Part* act_part,
129
129
  }
130
130
  }
131
131
 
132
- std::vector<InnerPolyline*> Cursor::join_inners(Sequence* outer_seq) {
132
+ std::vector<InnerPolyline*> Cursor::join_inners(Sequence* outer_seq, bool treemap) {
133
133
  std::vector<InnerPolyline*> return_inner_polylines;
134
134
  std::vector<Shape*> processing_queue = shapes_sequence_;
135
135
  for (size_t i = 0; i < shapes_sequence_.size(); ++i)
@@ -138,11 +138,12 @@ std::vector<InnerPolyline*> Cursor::join_inners(Sequence* outer_seq) {
138
138
  for (Part* part : polyline->parts())
139
139
  { if (part->innerable())
140
140
  { std::vector<Part*> all_parts;
141
+ std::vector<EndPoint*> tracked_end_points;
141
142
  Bounds bounds{
142
143
  .min = polyline->max_y(),
143
144
  .max = 0
144
145
  };
145
- traverse_inner(part, all_parts, bounds);
146
+ traverse_inner(part, all_parts, bounds, tracked_end_points);
146
147
  Sequence* retme_sequence = shape->outer_polyline->tile->shapes_pool->acquire_sequence();
147
148
  for (Part* part : all_parts)
148
149
  { part->touch();
@@ -157,7 +158,11 @@ std::vector<InnerPolyline*> Cursor::join_inners(Sequence* outer_seq) {
157
158
  });
158
159
  }
159
160
  if (retme_sequence->is_not_vertical()) {
160
- return_inner_polylines.push_back(polyline->tile->shapes_pool->acquire_inner_polyline(retme_sequence));
161
+ InnerPolyline* inner_polyline = polyline->tile->shapes_pool->acquire_inner_polyline(retme_sequence);
162
+ return_inner_polylines.push_back(inner_polyline);
163
+ if (treemap) {
164
+ mark_children(tracked_end_points, polyline, inner_polyline);
165
+ }
161
166
  }
162
167
  }
163
168
  }
@@ -165,7 +170,26 @@ std::vector<InnerPolyline*> Cursor::join_inners(Sequence* outer_seq) {
165
170
  return(return_inner_polylines);
166
171
  }
167
172
 
168
- void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bounds& bounds) {
173
+ void Cursor::mark_children(std::vector<EndPoint*>& end_points, const Polyline* outer_polyline, InnerPolyline* inner_polyline) {
174
+ for (size_t i = 0; i + 1 < end_points.size(); i += 2) {
175
+ const auto& a = end_points[i];
176
+ const auto& b = end_points[i + 1];
177
+ auto [y_min, y_max] = std::minmax(a->get_point()->y, b->get_point()->y);
178
+ for (int y = y_min + 1; y < y_max; ++y) {
179
+ EndPoint* end_point = this->cluster.hub()->get(y);
180
+ if (end_point) {
181
+ for (auto part_p : end_point->queues())
182
+ { Part* part = static_cast<Part*>(part_p);
183
+ if (part->polyline() != outer_polyline) {
184
+ part->polyline()->inside_inner_polyline = inner_polyline;
185
+ }
186
+ }
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bounds& bounds, std::vector<EndPoint*>& tracked_end_points) {
169
193
  PartPool& pool = act_part->polyline()->tile->cluster->parts_pool;
170
194
  while (act_part != nullptr) {
171
195
  if (!all_parts.empty() && act_part == all_parts.front()) return;
@@ -186,13 +210,17 @@ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bound
186
210
  all_parts.push_back(act_part);
187
211
  } else {
188
212
  if (act_part->head)
189
- { for (auto dest_part_p : static_cast<Position*>(act_part->head)->end_point()->queues()) {
213
+ { EndPoint* current_end_point = static_cast<Position*>(act_part->head)->end_point();
214
+ for (auto dest_part_p : current_end_point->queues()) {
190
215
  Part* dest_part = static_cast<Part*>(dest_part_p);
191
216
  if (dest_part->polyline()->tile == act_part->polyline()->tile) {
192
217
  continue;
193
218
  }
194
219
  int dest_part_versus = dest_part->versus();
195
220
  if (dest_part_versus != 0 && dest_part_versus == act_part->versus()) continue;
221
+
222
+ tracked_end_points.push_back(current_end_point);
223
+
196
224
  std::vector<EndPoint*> link_seq = dest_part->continuum_to(*act_part);
197
225
  if (!link_seq.empty()) {
198
226
  Part* ins_part = pool.acquire(Part::ADDED, act_part->polyline());
@@ -21,7 +21,7 @@ class Cursor {
21
21
  public:
22
22
  Cursor(Cluster& cluster, Shape* shape);
23
23
  Sequence* join_outers();
24
- std::vector<InnerPolyline*> join_inners(Sequence* outer_seq);
24
+ std::vector<InnerPolyline*> join_inners(Sequence* outer_seq, bool treemap);
25
25
  std::list<InnerPolyline*> orphan_inners() { return orphan_inners_; }
26
26
  const std::vector<Shape*>& shapes_sequence() const { return shapes_sequence_; }
27
27
 
@@ -35,6 +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);
38
+ void traverse_inner(Part* act_part, std::vector<Part*> &all_parts, Bounds& bounds, std::vector<EndPoint*>& tracked_end_points);
39
39
  std::vector<Shape*> connect_missings(std::vector<Shape*> shapes_sequence, std::vector<Shape*> missing_shapes);
40
+ void mark_children(std::vector<EndPoint*>& end_points, const Polyline* outer_polyline, InnerPolyline* inner_polyline);
40
41
  };
@@ -11,9 +11,8 @@
11
11
  #include <vector>
12
12
  #include "InnerPolyline.h"
13
13
 
14
- InnerPolyline::InnerPolyline(std::vector<Point*> raw_coordinates, Shape* shape, bool recombined)
14
+ InnerPolyline::InnerPolyline(std::vector<Point*> raw_coordinates, Shape* shape)
15
15
  : raw_coordinates_(std::move(raw_coordinates)),
16
- recombined_(recombined),
17
16
  shape_(shape) {}
18
17
  InnerPolyline::InnerPolyline(Sequence* sequence)
19
18
  : sequence_(sequence) {
@@ -14,16 +14,14 @@
14
14
 
15
15
  class InnerPolyline {
16
16
  public:
17
- explicit InnerPolyline(std::vector<Point*> raw_coordinates, Shape* shape, bool recombined = false);
17
+ explicit InnerPolyline(std::vector<Point*> raw_coordinates, Shape* shape);
18
18
  explicit InnerPolyline(Sequence* sequence);
19
19
  std::vector<Point*>& raw();
20
20
  Sequence* sequence() { return this->sequence_; }
21
21
  Bounds& vertical_bounds();
22
- bool recombined() { return this->recombined_; }
23
22
  Shape* shape();
24
23
  Shape* assigned_shape = nullptr;
25
24
  private:
26
- bool recombined_ = false;
27
25
  std::vector<Point*> raw_coordinates_;
28
26
  Sequence* sequence_ = nullptr;
29
27
  Shape* shape_;
@@ -22,15 +22,12 @@ Polyline::Polyline(Tile* tile, const std::vector<Point*>& polygon, const std::op
22
22
  { if (bounds.has_value()) {
23
23
  min_x = bounds->min_x;
24
24
  max_x = bounds->max_x;
25
- min_y = bounds->min_y;
25
+ min_y_ = bounds->min_y;
26
26
  max_y_ = bounds->max_y;
27
27
  } else {
28
28
  this->find_boundary(); // TODO(ema): optimize when merging the bounds are the sum of the previouses
29
29
  }
30
- }
31
-
32
- bool Polyline::vert_intersect(Polyline& other) {
33
- return( !(this->max_y_ < other.min_y || other.max_y_ < this->min_y));
30
+ this->name = tile->shapes().size();
34
31
  }
35
32
 
36
33
  int Polyline::width() {
@@ -46,7 +43,7 @@ void Polyline::find_boundary() {
46
43
  if (raw_.empty()) return;
47
44
  min_x = std::numeric_limits<int>::max();
48
45
  max_x = -std::numeric_limits<int>::max();
49
- min_y = std::numeric_limits<int>::max();
46
+ min_y_ = std::numeric_limits<int>::max();
50
47
  max_y_ = -std::numeric_limits<int>::max();
51
48
  for (Point* p : raw_) {
52
49
  if (!p) continue;
@@ -54,7 +51,7 @@ void Polyline::find_boundary() {
54
51
  int y = p->y;
55
52
  if (x < min_x) min_x = x;
56
53
  if (x > max_x) max_x = x;
57
- if (y < min_y) min_y = y;
54
+ if (y < min_y_) min_y_ = y;
58
55
  if (y > max_y_) max_y_ = y;
59
56
  }
60
57
  }
@@ -67,20 +64,8 @@ bool Polyline::is_empty() {
67
64
  return raw_.empty();
68
65
  }
69
66
 
70
- std::string Polyline::info() {
71
- Shape* shape = this->shape;
72
- size_t part_index = 0;
73
- auto it = std::find(this->tile->shapes().begin(), this->tile->shapes().end(), shape);
74
- if (it != this->tile->shapes().end()) {
75
- part_index = std::distance(this->tile->shapes().begin(), it);
76
- }
77
- std::stringstream ss;
78
- ss << "b" << this->tile->name() << " S" << part_index;
79
- return ss.str();
80
- }
81
-
82
67
  bool Polyline::vert_bounds_intersect(Bounds& vertical_bounds)
83
- { return !(this->max_y_ < vertical_bounds.min || vertical_bounds.max < this->min_y);
68
+ { return !(this->max_y_ < vertical_bounds.min || vertical_bounds.max < this->min_y_);
84
69
  }
85
70
 
86
71
  bool Polyline::within(std::vector<Point*>& points) {
@@ -99,3 +84,14 @@ bool Polyline::within(std::vector<Point*>& points) {
99
84
  }
100
85
  return inside;
101
86
  }
87
+
88
+ std::string Polyline::named() {
89
+ if (this->named_.empty()) {
90
+ std::stringstream ss;
91
+ ss << "t" << this->tile->name() << "s" << this->name;
92
+ if (this->boundary()) ss << "B";
93
+ return ss.str();
94
+ } else {
95
+ return this->named_;
96
+ }
97
+ }
@@ -23,6 +23,7 @@
23
23
  class Tile;
24
24
  class Shape;
25
25
  class Point;
26
+ class InnerPolyline;
26
27
 
27
28
  class Polyline : public Partitionable {
28
29
  public:
@@ -42,17 +43,21 @@ class Polyline : public Partitionable {
42
43
  std::vector<Point*> raw() const { return raw_; }
43
44
  const std::vector<Part*>& parts() const { return parts_; }
44
45
  const int max_y() const { return max_y_; }
46
+ const int min_y() const { return min_y_; }
45
47
  void clear();
46
48
  bool is_empty();
47
- bool vert_intersect(Polyline& other);
48
49
  bool any_ancients = false;
49
- std::string info();
50
50
  bool vert_bounds_intersect(Bounds& vertical_bounds);
51
51
  bool within(std::vector<Point*>& points);
52
+ InnerPolyline* inside_inner_polyline = nullptr;
53
+ std::string named();
54
+ void set_named(std::string force_named) { this->named_ = force_named; }
52
55
 
53
56
  private:
54
57
  std::vector<Point*> raw_;
55
- int min_x, max_x, min_y, max_y_;
58
+ int min_x, max_x, min_y_, max_y_;
56
59
  void find_boundary();
57
60
  uint32_t flags_ = 0;
61
+ std::string named_;
62
+ int name;
58
63
  };
@@ -9,6 +9,7 @@
9
9
 
10
10
  #include <list>
11
11
  #include <vector>
12
+ #include <string>
12
13
  #include "Shape.h"
13
14
  #include "Polyline.h"
14
15
 
@@ -34,3 +35,7 @@ void Shape::set_parent_shape(Shape* shape) {
34
35
  { shape->children_shapes.push_back(this);
35
36
  }
36
37
  }
38
+
39
+ std::string Shape::name() {
40
+ return(this->outer_polyline->named());
41
+ }
@@ -11,6 +11,7 @@
11
11
  #include <list>
12
12
  #include <iostream>
13
13
  #include <vector>
14
+ #include <string>
14
15
  #include "InnerPolyline.h"
15
16
 
16
17
  class Point;
@@ -24,9 +25,10 @@ class Shape {
24
25
  InnerPolyline* parent_inner_polyline = nullptr;
25
26
  std::vector<Shape*> children_shapes;
26
27
  void clear_inner();
27
- bool reassociation_skip = false;
28
+ bool fixed = false;
28
29
  Shape* parent_shape() { return parent_shape_; }
29
30
  void set_parent_shape(Shape*);
31
+ std::string name();
30
32
  private:
31
33
  Shape* parent_shape_ = nullptr;
32
34
  };
@@ -17,8 +17,8 @@ Shape* ShapePool::acquire_shape(Polyline* outer_polyline, const std::vector<Inne
17
17
  return shape;
18
18
  }
19
19
 
20
- InnerPolyline* ShapePool::acquire_inner_polyline(std::vector<Point*> coords, Shape* shape, bool rec) {
21
- inner_polylines_storage.emplace_back(coords, shape, rec);
20
+ InnerPolyline* ShapePool::acquire_inner_polyline(std::vector<Point*> coords, Shape* shape) {
21
+ inner_polylines_storage.emplace_back(coords, shape);
22
22
  InnerPolyline* ip = &inner_polylines_storage.back();
23
23
  return ip;
24
24
  }
@@ -27,7 +27,7 @@ class ShapePool {
27
27
 
28
28
  public:
29
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);
30
+ InnerPolyline* acquire_inner_polyline(std::vector<Point*> coords, Shape* s);
31
31
  InnerPolyline* acquire_inner_polyline(Sequence* seq);
32
32
  Sequence* acquire_sequence();
33
33
  Polyline* acquire_polyline(Tile* tile, const std::vector<Point*>& polygon, const std::optional<RectBounds>& bounds);
@@ -61,7 +61,7 @@ void Tile::assign_raw_polygons(const std::list<Polygon>& raw_polylines, const st
61
61
  { Polyline* polyline = this->shapes_pool->acquire_polyline(this, raw_polyline.outer, raw_polyline.bounds);
62
62
  std::vector<InnerPolyline*> inner_polylines_list;
63
63
  for (auto& raw_points : raw_polyline.inner) {
64
- inner_polylines_list.push_back(this->shapes_pool->acquire_inner_polyline(raw_points, nullptr, false));
64
+ inner_polylines_list.push_back(this->shapes_pool->acquire_inner_polyline(raw_points, nullptr));
65
65
  }
66
66
  Shape* shape = this->shapes_pool->acquire_shape(polyline, inner_polylines_list);
67
67
  polyline->shape = shape;
@@ -75,6 +75,7 @@ void Tile::assign_raw_polygons(const std::list<Polygon>& raw_polylines, const st
75
75
  if (it != shapes_map.end()) {
76
76
  Shape* parent = it->second;
77
77
  shape->set_parent_shape(parent);
78
+ shape->fixed = true;
78
79
  shape->parent_inner_polyline = parent->inner_polylines[treemap_entry.second];
79
80
  }
80
81
  }
@@ -84,7 +85,7 @@ void Tile::assign_raw_polygons(const std::list<Polygon>& raw_polylines, const st
84
85
  }
85
86
  }
86
87
 
87
- void Tile::assign_shapes(std::list<Shape*>& shapes) {
88
+ void Tile::assign_shapes(std::vector<Shape*>& shapes) {
88
89
  for (Shape *shape : shapes) {
89
90
  shape->outer_polyline->tile = this;
90
91
  }
@@ -135,7 +136,8 @@ std::vector<std::pair<int, int>> Tile::compute_treemap()
135
136
  for (auto* shape : this->shapes_) {
136
137
  if (shape->outer_polyline->is_empty()) continue;
137
138
  if (shape->parent_shape() != nullptr) {
138
- int p_idx = shapes_map[shape->parent_shape()];
139
+ auto p_it = shapes_map.find(shape->parent_shape());
140
+ int p_idx = (p_it != shapes_map.end()) ? p_it->second : -1;
139
141
  const auto& inners = shape->parent_shape()->inner_polylines;
140
142
  auto it = std::find(inners.begin(), inners.end(), shape->parent_inner_polyline);
141
143
  int inner_idx = static_cast<int>(std::distance(inners.begin(), it));
@@ -30,7 +30,7 @@ class Tile {
30
30
  int start_x_;
31
31
  int end_x_;
32
32
  std::string name_;
33
- std::list<Shape*> shapes_;
33
+ std::vector<Shape*> shapes_;
34
34
 
35
35
  public:
36
36
  Tile(Finder *finder, int start_x, int end_x, std::string name, const Benchmarks& b);
@@ -42,15 +42,15 @@ class Tile {
42
42
  int start_x() const { return start_x_; }
43
43
  int end_x() const { return end_x_; }
44
44
  std::string name() const { return name_; }
45
- const std::list<Shape*>& shapes() const { return shapes_; }
46
- std::list<Shape*>& shapes() { return shapes_; }
45
+ const std::vector<Shape*>& shapes() const { return shapes_; }
46
+ std::vector<Shape*>& shapes() { return shapes_; }
47
47
  bool whole();
48
48
  bool left();
49
49
  bool right();
50
50
  void initial_process(ClippedPolygonFinder *finder);
51
51
  void info();
52
52
  bool tg_border(const Point& coord);
53
- void assign_shapes(std::list<Shape*>& shapes);
53
+ void assign_shapes(std::vector<Shape*>& shapes);
54
54
  void assign_raw_polygons(const std::list<Polygon>& raw_polylines, const std::vector<std::pair<int, int>>& treemap);
55
55
  std::list<Polygon> to_raw_polygons();
56
56
  std::vector<std::pair<int, int>> compute_treemap();
@@ -291,9 +291,8 @@ extern "C"
291
291
  void Init_cpp_polygon_finder() {
292
292
  #ifdef HAVE_TCMALLOC
293
293
  MallocExtension::instance()->SetNumericProperty(
294
- "tcmalloc.max_total_thread_cache_bytes",
295
- 1024 * 1024 * 1024
296
- );
294
+ "tcmalloc.max_total_thread_cache_bytes",
295
+ 1024 * 1024 * 1024);
297
296
  #endif
298
297
 
299
298
  Data_Type<Bitmap> rb_cBitmap =
@@ -1,6 +1,8 @@
1
1
  module Contrek
2
2
  module Cpp
3
3
  class CPPResult
4
+ include Shared::Result
5
+
4
6
  def polygons=(list)
5
7
  @polygons_storage = list
6
8
  end
@@ -6,7 +6,7 @@ module Contrek
6
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:)
10
10
  end
11
11
 
12
12
  def add(tile)
@@ -28,6 +28,7 @@ module Contrek
28
28
 
29
29
  new_shapes = []
30
30
  all_new_inner_polylines = []
31
+
31
32
  tot_outer += Benchmark.measure do
32
33
  @tiles.each do |tile|
33
34
  tile.shapes.each do |shape|
@@ -54,13 +55,12 @@ module Contrek
54
55
  new_inners = shape.inner_polylines
55
56
  new_inner_polylines = []
56
57
  tot_inner += Benchmark.measure do
57
- new_inner_polylines = cursor.join_inners!(new_outer)
58
+ new_inner_polylines = cursor.join_inners!(new_outer, treemap)
58
59
  new_inners += new_inner_polylines
59
60
  if treemap
60
- new_inner_polylines.each { |p| p.sequence.compute_vertical_bounds! }
61
- all_new_inner_polylines += new_inner_polylines
62
- cursor.orphan_inners.each do |orphan_inner|
63
- all_new_inner_polylines << orphan_inner if orphan_inner.recombined
61
+ new_inner_polylines.each do |inner_polyline|
62
+ inner_polyline.sequence.compute_vertical_bounds!
63
+ all_new_inner_polylines += new_inner_polylines
64
64
  end
65
65
  end
66
66
  new_inners += cursor.orphan_inners
@@ -70,7 +70,6 @@ module Contrek
70
70
  inserting_new_shape = Shape.init_by(polyline, new_inners)
71
71
  new_shapes << inserting_new_shape
72
72
  polyline.shape = inserting_new_shape
73
- inserting_new_shape.set_parent_shape(shape.parent_shape)
74
73
 
75
74
  new_inner_polylines.each { |inner_polyline| inner_polyline.sequence.shape = inserting_new_shape }
76
75
 
@@ -78,23 +77,20 @@ module Contrek
78
77
  cursor.shapes_sequence.each do |merged_shape|
79
78
  merged_shape.merged_to_shape = inserting_new_shape
80
79
  end
81
- assign_ancestry(inserting_new_shape, all_new_inner_polylines)
80
+ if shape.outer_polyline.inside_inner_polyline
81
+ assign_ancestry(inserting_new_shape, shape.outer_polyline.inside_inner_polyline)
82
+ end
82
83
  end
83
84
  else
84
- if treemap && !shape.reassociation_skip && shape.parent_shape.nil?
85
- assign_ancestry(shape, all_new_inner_polylines)
85
+ if treemap
86
+ if shape.fixed
87
+ shape.set_parent_shape(shape.parent_shape.merged_to_shape) if shape.parent_shape.merged_to_shape
88
+ else
89
+ is_children(shape, all_new_inner_polylines)
90
+ end
86
91
  end
87
- new_shapes << shape
88
- end
89
- end
90
- end
91
92
 
92
- if treemap
93
- @tiles.each do |tile|
94
- tile.shapes.each do |shape|
95
- if (merged_to_shape = shape.parent_shape&.merged_to_shape)
96
- shape.set_parent_shape(merged_to_shape)
97
- end
93
+ new_shapes << shape
98
94
  end
99
95
  end
100
96
  end
@@ -116,16 +112,21 @@ module Contrek
116
112
 
117
113
  private
118
114
 
119
- def assign_ancestry(shape, inner_polylines)
115
+ def assign_ancestry(shape, inner_polyline)
116
+ shape.set_parent_shape(inner_polyline.sequence.shape)
117
+ shape.parent_inner_polyline = inner_polyline
118
+ shape.fixed = true
119
+ end
120
+
121
+ def is_children(shape, inner_polylines)
120
122
  inner_polylines.each do |inner_polyline|
121
- if shape.outer_polyline.vert_bounds_intersect?(inner_polyline.vertical_bounds)
122
- if shape.outer_polyline.within?(inner_polyline.raw)
123
- shape.set_parent_shape(inner_polyline.shape)
124
- shape.parent_inner_polyline = inner_polyline
125
- shape.children_shapes.each do |children_shape|
126
- children_shape.reassociation_skip = true
127
- end
128
- end
123
+ bounds = inner_polyline.vertical_bounds
124
+ min_y = bounds[:min]
125
+ max_y = bounds[:max]
126
+ next if shape.outer_polyline.get_bounds[:max_y] < min_y ||
127
+ shape.outer_polyline.get_bounds[:min_y] > max_y
128
+ if shape.outer_polyline.within?(inner_polyline.raw)
129
+ assign_ancestry(shape, inner_polyline)
129
130
  end
130
131
  end
131
132
  end
@@ -4,7 +4,7 @@ module Contrek
4
4
  attr_reader :orphan_inners, :shapes_sequence
5
5
 
6
6
  def initialize(cluster:, shape:)
7
- @shapes_sequence = Set.new([shape])
7
+ @shapes_sequence = [shape]
8
8
  @cluster = cluster
9
9
  @outer_polyline = shape.outer_polyline
10
10
  @orphan_inners = []
@@ -38,18 +38,19 @@ module Contrek
38
38
  outer_joined_polyline
39
39
  end
40
40
 
41
- def join_inners!(outer_seq)
41
+ def join_inners!(outer_seq, treemap)
42
42
  return_inner_polylines = []
43
+ shape_index = 0
43
44
 
44
- @processing_shapes = @shapes_sequence.to_a
45
-
46
- @processing_shapes.each do |shape|
45
+ while shape_index < @shapes_sequence.size
46
+ shape = @shapes_sequence[shape_index]
47
47
  polyline = shape.outer_polyline
48
48
  polyline.parts.each do |part|
49
49
  if part.innerable?
50
50
  all_parts = []
51
+ tracked_end_points = []
51
52
  bounds = {min: polyline.max_y, max: 0}
52
- traverse_inner(part, all_parts, bounds)
53
+ traverse_inner(part, all_parts, bounds, tracked_end_points)
53
54
  range_of_bounds = (bounds[:min]..bounds[:max])
54
55
 
55
56
  retme_sequence = Sequence.new
@@ -62,16 +63,36 @@ module Contrek
62
63
  end
63
64
  end
64
65
  if retme_sequence.is_not_vertical
65
- return_inner_polylines << InnerPolyline.new(sequence: retme_sequence)
66
+ inner_polyline = InnerPolyline.new(sequence: retme_sequence)
67
+ return_inner_polylines << inner_polyline
68
+ mark_children(tracked_end_points, polyline, inner_polyline) if treemap
66
69
  end
67
70
  end
68
71
  end
72
+ shape_index += 1
69
73
  end
70
74
  return_inner_polylines
71
75
  end
72
76
 
73
77
  private
74
78
 
79
+ # finds each part (and relative polyline) inscribed between two end_points and sets the
80
+ # founded inner_polyline which be later used to define in which parent hole is placed.
81
+ def mark_children(end_points, outer_polyline, inner_polyline)
82
+ end_points.each_slice(2) do |a, b|
83
+ range = [a.position[:y], b.position[:y]].sort
84
+ (range[0] + 1).upto(range[1] - 1) do |y|
85
+ if (end_point = @cluster.hub.payloads[y])
86
+ end_point.queues.each do |part|
87
+ if part.polyline != outer_polyline
88
+ part.polyline.inside_inner_polyline = inner_polyline
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+
75
96
  # rubocop:disable Lint/NonLocalExitFromIterator
76
97
  def traverse_outer(act_part, all_parts, shapes_sequence, outer_joined_polyline)
77
98
  last_part = all_parts.last
@@ -104,7 +125,7 @@ module Contrek
104
125
  cont = false if map.size == 1 && map.first == Part::SEAM
105
126
  end
106
127
  if cont
107
- shapes_sequence.add(part.polyline.shape)
128
+ shapes_sequence << part.polyline.shape if !shapes_sequence.include?(part.polyline.shape)
108
129
  part.next_position(new_position)
109
130
  part.dead_end = true
110
131
  traverse_outer(part, all_parts, shapes_sequence, outer_joined_polyline)
@@ -120,7 +141,7 @@ module Contrek
120
141
  traverse_outer(act_part.circular_next, all_parts, shapes_sequence, outer_joined_polyline)
121
142
  end
122
143
 
123
- def traverse_inner(act_part, all_parts, bounds)
144
+ def traverse_inner(act_part, all_parts, bounds, tracked_end_points)
124
145
  return if act_part == all_parts.first
125
146
 
126
147
  if act_part.size > 0
@@ -140,6 +161,8 @@ module Contrek
140
161
  dest_part_versus = dest_part.versus
141
162
  next if dest_part_versus != 0 && dest_part_versus == act_part.versus
142
163
 
164
+ tracked_end_points << act_part.head.end_point
165
+
143
166
  link_seq = dest_part.continuum_to?(act_part)
144
167
  if link_seq.any?
145
168
  ins_part = Part.new(Part::ADDED, act_part.polyline)
@@ -150,13 +173,13 @@ module Contrek
150
173
  end
151
174
  shape = dest_part.polyline.shape
152
175
  if !dest_part.polyline.on?(Polyline::TRACKED_OUTER)
153
- @processing_shapes << shape
176
+ @shapes_sequence << shape
154
177
  @orphan_inners += shape.inner_polylines
155
178
  end
156
179
  dest_part.polyline.turn_on(Polyline::TRACKED_OUTER)
157
180
  if !dest_part.touched
158
181
  dest_part.touch!
159
- traverse_inner(dest_part.circular_next, all_parts, bounds)
182
+ traverse_inner(dest_part.circular_next, all_parts, bounds, tracked_end_points)
160
183
  return
161
184
  end
162
185
  end
@@ -165,7 +188,7 @@ module Contrek
165
188
  end
166
189
  end
167
190
  elsif act_part.next
168
- traverse_inner(act_part.next, all_parts, bounds)
191
+ traverse_inner(act_part.next, all_parts, bounds, tracked_end_points)
169
192
  end
170
193
  end
171
194
  # rubocop:enable Lint/NonLocalExitFromIterator
@@ -1,12 +1,11 @@
1
1
  module Contrek
2
2
  module Concurrent
3
3
  class InnerPolyline
4
- attr_reader :sequence, :recombined
4
+ attr_reader :sequence
5
5
 
6
- def initialize(shape: nil, raw_coordinates: [], sequence: nil, recombined: false)
6
+ def initialize(shape: nil, raw_coordinates: [], sequence: nil)
7
7
  @raw = raw_coordinates if raw_coordinates
8
8
  @sequence = sequence if sequence
9
- @recombined = recombined
10
9
  @shape = shape
11
10
  end
12
11
 
@@ -6,15 +6,17 @@ module Contrek
6
6
  TRACKED_OUTER = 1 << 0
7
7
 
8
8
  attr_reader :raw, :name, :min_y, :max_y
9
- attr_accessor :shape, :tile, :any_ancients
9
+ attr_accessor :shape, :tile, :any_ancients, :inside_inner_polyline
10
10
 
11
- def initialize(tile:, polygon:, shape: nil, bounds: nil)
11
+ def initialize(tile:, polygon:, shape: nil, bounds: nil, force_named: nil)
12
12
  @tile = tile
13
13
  @name = tile.shapes.count
14
+ @named = force_named
14
15
  @raw = polygon
15
16
  @shape = shape
16
17
  @flags = 0
17
18
  @any_ancients = false
19
+ @inside_inner_polyline = nil
18
20
 
19
21
  if bounds.nil?
20
22
  find_boundary
@@ -31,17 +33,13 @@ module Contrek
31
33
  end
32
34
 
33
35
  def named
34
- "[b#{@tile.name} S#{@name} #{"B" if boundary?}]"
36
+ @named || "t#{@tile.name}s#{@name}#{"B" if boundary?}"
35
37
  end
36
38
 
37
39
  def numpy_raw
38
40
  raw.flat_map { |p| [p[:x], p[:y]] }
39
41
  end
40
42
 
41
- def info
42
- "w#{@tile.name} S#{@name}"
43
- end
44
-
45
43
  def turn_on(flag)
46
44
  @flags |= flag
47
45
  end