contrek 1.1.2 → 1.1.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +6 -1
  4. data/Gemfile.lock +1 -1
  5. data/LICENSE-MIT.md +9 -0
  6. data/README.md +41 -1
  7. data/contrek.gemspec +0 -1
  8. data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +14 -2
  9. data/ext/cpp_polygon_finder/PolygonFinder/LICENSE_AGPL.txt +661 -0
  10. data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +9 -7
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +9 -0
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +2 -0
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +13 -2
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +74 -82
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +12 -4
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +0 -10
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +0 -7
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +39 -39
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +10 -10
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +24 -39
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +5 -7
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +6 -4
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +4 -3
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +9 -3
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +1 -0
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +33 -0
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +5 -1
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +8 -8
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +2 -1
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +13 -0
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +2 -0
  32. data/ext/cpp_polygon_finder/extconf.rb +12 -2
  33. data/lib/contrek/bitmaps/painting.rb +1 -0
  34. data/lib/contrek/finder/concurrent/cursor.rb +5 -5
  35. data/lib/contrek/finder/concurrent/finder.rb +2 -1
  36. data/lib/contrek/finder/concurrent/part.rb +12 -3
  37. data/lib/contrek/finder/concurrent/partitionable.rb +7 -5
  38. data/lib/contrek/finder/node.rb +41 -29
  39. data/lib/contrek/finder/node_cluster.rb +18 -12
  40. data/lib/contrek/finder/polygon_finder.rb +4 -3
  41. data/lib/contrek/version.rb +1 -1
  42. metadata +8 -7
@@ -1,10 +1,11 @@
1
- //============================================================================
2
- // Name : example.cpp
3
- // Author : Emanuele Cesaroni
4
- // Version :
5
- // Copyright : 2025 Emanuele Cesaroni
6
- // Description :
7
- //============================================================================
1
+ /*
2
+ * example.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
+ */
8
9
 
9
10
  #include <iostream>
10
11
  #include "ContrekApi.h"
@@ -29,6 +30,7 @@ int main() {
29
30
  cfg.threads = 4;
30
31
  cfg.tiles = 4;
31
32
  cfg.compress_unique = true;
33
+ cfg.connectivity_mode = Contrek::Connectivity::OMNIDIRECTIONAL;
32
34
 
33
35
  CpuTimer cpu_timer;
34
36
  cpu_timer.start();
@@ -26,6 +26,11 @@ enum class MatchMode {
26
26
  EXACT_COLOR // Tracks border of what exactly matchs target color
27
27
  };
28
28
 
29
+ enum class Connectivity {
30
+ ORTHOGONAL = 4, // up, down, left, right 4 directions
31
+ OMNIDIRECTIONAL = 8 // 8 directions
32
+ };
33
+
29
34
  struct Config {
30
35
  int threads = 4;
31
36
  int tiles = 2;
@@ -35,6 +40,7 @@ struct Config {
35
40
  bool treemap = false;
36
41
  int32_t target_color = -1;
37
42
  MatchMode mode = MatchMode::NOT_COLOR;
43
+ Connectivity connectivity_mode = Connectivity::ORTHOGONAL;
38
44
  };
39
45
 
40
46
  inline std::unique_ptr<ProcessResult> trace(const std::string& image_path, const Config& cfg = Config()) {
@@ -64,6 +70,9 @@ inline std::unique_ptr<ProcessResult> trace(const std::string& image_path, const
64
70
  if (m.flag) internal_args.emplace_back(m.arg);
65
71
  }
66
72
  internal_args.push_back("--number_of_tiles=" + std::to_string(cfg.tiles));
73
+ if(cfg.connectivity_mode == Connectivity::OMNIDIRECTIONAL) {
74
+ internal_args.push_back("--connectivity=" + std::to_string(8));
75
+ }
67
76
 
68
77
  Finder finder(cfg.threads, bitmap.get(), matcher.get(), &internal_args);
69
78
 
@@ -7,6 +7,7 @@
7
7
  * See the LICENSE file in this directory for the full license text.
8
8
  */
9
9
 
10
+ #include <sys/mman.h>
10
11
  #include <iostream>
11
12
  #include <vector>
12
13
  #include <fstream>
@@ -38,6 +39,7 @@ FastPngBitmap::FastPngBitmap(std::string filename) : Bitmap("", 0) {
38
39
  size_t out_size;
39
40
  spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);
40
41
  this->image.resize(out_size);
42
+ madvise(this->image.data(), out_size, MADV_HUGEPAGE);
41
43
  int error = spng_decode_image(ctx, image.data(), out_size, SPNG_FMT_RGBA8, SPNG_DECODE_TRNS);
42
44
  spng_ctx_free(ctx);
43
45
  this->png_error = error;
@@ -22,7 +22,7 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
22
22
  char** argv = &argv0[0];
23
23
  int argc = argv0.size() -1;
24
24
 
25
- enum optionIndex { COMPRESS_UNIQ, VERSUS, COMPRESS_VISVALINGAM, COMPRESS_LINEAR, NUMBER_OF_TILES, COMPRESS_VISVALINGAM_TOLERANCE, TREEMAP, NAMED_SEQUENCES, BOUNDS};
25
+ enum optionIndex { COMPRESS_UNIQ, VERSUS, COMPRESS_VISVALINGAM, COMPRESS_LINEAR, NUMBER_OF_TILES, COMPRESS_VISVALINGAM_TOLERANCE, TREEMAP, NAMED_SEQUENCES, BOUNDS, CONNECTIVITY};
26
26
  const option::Descriptor usage[] = {
27
27
  // {UNKNOWN, 0,"" , "" ,option::Arg::None, 0},
28
28
  {COMPRESS_VISVALINGAM, 0, "" , "compress_visvalingam", option::Arg::None, 0},
@@ -34,6 +34,7 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
34
34
  {NAMED_SEQUENCES, 0, "", "named_sequences", option::Arg::None, 0},
35
35
  {BOUNDS, 0, "", "bounds", option::Arg::None, 0},
36
36
  {VERSUS, 0, "v", "versus", option::Arg::Optional, 0},
37
+ {CONNECTIVITY, 0, "c", "connectivity", option::Arg::Optional, 0},
37
38
  {0, 0, 0, 0, 0, 0}
38
39
  };
39
40
 
@@ -58,9 +59,19 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
58
59
  if (ioptions[NUMBER_OF_TILES].count() > 0)
59
60
  { try {
60
61
  options.number_of_tiles = std::stoi(ioptions[NUMBER_OF_TILES].arg);
62
+ if (options.number_of_tiles <= 0) options.number_of_tiles = 1;
61
63
  }
62
64
  catch (const std::invalid_argument&) {
63
- std::cerr << "Errore: --number_of_tiles richiede un numero (non una lettera)\n";
65
+ std::cerr << "Errore: --number_of_tiles requires a number\n";
66
+ }
67
+ }
68
+ // CONNECTIVITY
69
+ if (ioptions[CONNECTIVITY].count() > 0)
70
+ { try {
71
+ if (std::stoi(ioptions[CONNECTIVITY].arg) == 8) options.connectivity_offset = 1;
72
+ }
73
+ catch (const std::invalid_argument&) {
74
+ std::cerr << "Errore: --connectivity requires a number\n";
64
75
  }
65
76
  }
66
77
  // TREEMAP
@@ -10,109 +10,101 @@
10
10
  #include "List.h"
11
11
  #include <iostream>
12
12
 
13
- class Listable;
13
+ List::List(int id) : start(nullptr), end(nullptr), isize(0), idd(id) {}
14
14
 
15
- List::List(int id) {
16
- this->start = nullptr;
17
- this->end = nullptr;
18
- this->isize = 0;
19
- this->idd = id;
20
- }
21
-
22
- Listable *List::first() {
23
- return(this->start);
24
- }
25
- Listable *List::last() {
26
- return(this->end);
27
- }
15
+ Listable *List::first() { return this->start; }
16
+ Listable *List::last() { return this->end; }
17
+ int List::get_id() { return this->idd; }
18
+ int List::size() { return this->isize; }
28
19
 
29
20
  bool List::contains(Listable *entry) {
30
- return(entry->data_pointer[this->idd].inside);
31
- }
32
- int List::get_id() {
33
- return(this->idd);
21
+ return entry->data_pointer[this->idd].inside;
34
22
  }
35
23
 
36
- void List::grab(List *source_list) {
37
- if (source_list->size() == 0) return;
38
- int source_list_idd = source_list->get_id();
39
- Listable *source_list_start_entry = source_list->first();
40
-
41
- Listable *act = source_list->last();
42
- while (true)
43
- { if ((act = act->data_pointer[source_list_idd].prev) == nullptr) break;
44
- }
45
- Listable *source_entry = source_list->first();
46
- while (true)
47
- { source_entry->data_pointer[this->idd] = source_entry->data_pointer[source_list_idd];
48
- Listable *next_entry = source_entry->data_pointer[source_list_idd].next;
49
- source_entry->data_pointer[source_list_idd].inside = false;
50
- source_entry->data_pointer[source_list_idd].next = nullptr;
51
- source_entry->data_pointer[source_list_idd].prev = nullptr;
52
- if (next_entry == nullptr) break;
53
- source_entry = next_entry;
54
- }
55
- source_list_start_entry->data_pointer[this->idd].prev = this->end;
56
- if (this->end != nullptr) this->end->data_pointer[this->idd].next = source_list_start_entry;
57
- this->end = source_list->last();
58
- if (this->start == nullptr) this->start = source_list->first();
59
- this->isize += source_list->size();
60
- source_list->reset();
61
- }
62
-
63
- void List::reset() {
24
+ void List::reset() {
64
25
  this->end = nullptr;
65
26
  this->start = nullptr;
66
27
  this->isize = 0;
67
28
  }
68
29
 
69
- Listable *List::shift() {
70
- if (this->isize == 0) return(nullptr);
71
- Listable *retme = this->start;
72
- Listable *next_of_retme = retme->data_pointer[this->idd].next;
73
- this->start = next_of_retme;
74
- if (retme == this->end) this->end = nullptr;
75
- if (next_of_retme != nullptr) next_of_retme->data_pointer[this->idd].prev = nullptr;
76
- this->isize--;
77
- retme->data_pointer[this->idd].next = nullptr;
78
- retme->data_pointer[this->idd].prev = nullptr;
79
- retme->data_pointer[this->idd].inside = false;
80
- return (retme);
81
- }
82
-
83
30
  void List::push_back(Listable *entry) {
84
- if (entry->data_pointer[this->idd].inside) return;
85
- if (this->isize > 0)
86
- { this->end->data_pointer[this->idd].next = entry;
87
- entry->data_pointer[this->idd].prev = this->end;
31
+ auto& meta = entry->data_pointer[this->idd];
32
+ if (meta.inside) return;
33
+
34
+ if (this->isize > 0) {
35
+ this->end->data_pointer[this->idd].next = entry;
36
+ meta.prev = this->end;
88
37
  } else {
89
38
  this->start = entry;
39
+ meta.prev = nullptr;
90
40
  }
41
+
42
+ meta.next = nullptr;
91
43
  this->end = entry;
92
- entry->data_pointer[this->idd].inside = true;
44
+ meta.inside = true;
93
45
  this->isize++;
94
46
  }
95
- int List::size() {
96
- return(this->isize);
97
- }
98
47
 
99
48
  void List::remove(Listable *entry) {
100
- if (this->isize == 0) return;
101
- if (entry->data_pointer[this->idd].inside == false) return;
102
- Listable *next_of_entry = entry->data_pointer[this->idd].next;
103
- Listable *prev_of_entry = entry->data_pointer[this->idd].prev;
49
+ auto& meta = entry->data_pointer[this->idd];
50
+ if (this->isize == 0 || !meta.inside) return;
51
+
52
+ Listable *nxt = meta.next;
53
+ Listable *prv = meta.prev;
54
+
55
+ if (entry == this->start) this->start = nxt;
56
+ if (entry == this->end) this->end = prv;
57
+
58
+ if (nxt) nxt->data_pointer[this->idd].prev = prv;
59
+ if (prv) prv->data_pointer[this->idd].next = nxt;
60
+
61
+ meta.next = nullptr;
62
+ meta.prev = nullptr;
63
+ meta.inside = false;
64
+ this->isize--;
65
+ }
66
+
67
+ Listable *List::shift() {
68
+ if (this->isize == 0) return nullptr;
69
+ Listable *retme = this->start;
70
+ auto& meta = retme->data_pointer[this->idd];
71
+
72
+ this->start = meta.next;
73
+ if (retme == this->end) this->end = nullptr;
74
+ if (this->start) this->start->data_pointer[this->idd].prev = nullptr;
75
+
76
+ this->isize--;
77
+ meta.next = nullptr;
78
+ meta.prev = nullptr;
79
+ meta.inside = false;
80
+ return retme;
81
+ }
82
+
83
+ void List::grab(List *source_list) {
84
+ if (source_list->isize == 0) return;
104
85
 
105
- if (entry == this->start)
106
- { this->start = next_of_entry;
86
+ int src_idd = source_list->idd;
87
+ Listable *current = source_list->start;
88
+
89
+ while (current) {
90
+ auto& src_meta = current->data_pointer[src_idd];
91
+ auto& dst_meta = current->data_pointer[this->idd];
92
+ dst_meta = src_meta;
93
+ src_meta.inside = false;
94
+ src_meta.next = nullptr;
95
+ src_meta.prev = nullptr;
96
+ current = dst_meta.next;
107
97
  }
108
- if (entry == this->end)
109
- { this->end = prev_of_entry;
98
+
99
+ if (this->isize > 0) {
100
+ this->end->data_pointer[this->idd].next = source_list->start;
101
+ source_list->start->data_pointer[this->idd].prev = this->end;
102
+ this->end = source_list->end;
103
+ } else {
104
+ this->start = source_list->start;
105
+ this->end = source_list->end;
110
106
  }
111
107
 
112
- if (next_of_entry != nullptr) next_of_entry->data_pointer[this->idd].prev = prev_of_entry;
113
- if (prev_of_entry != nullptr) prev_of_entry->data_pointer[this->idd].next = next_of_entry;
114
- entry->data_pointer[this->idd].next = nullptr;
115
- entry->data_pointer[this->idd].prev = nullptr;
116
- this->isize--;
117
- entry->data_pointer[this->idd].inside = false;
108
+ this->isize += source_list->isize;
109
+ source_list->reset();
118
110
  }
@@ -8,13 +8,21 @@
8
8
  */
9
9
 
10
10
  #pragma once
11
+ #include <array>
12
+
13
+ // Forward declaration
14
+ class Listable;
15
+
16
+ // Definizione completa di Link (necessaria per std::array)
17
+ struct Link {
18
+ Listable* next = nullptr;
19
+ Listable* prev = nullptr;
20
+ bool inside = false;
21
+ };
11
22
 
12
- #include <vector>
13
- #include "Lists.h"
14
- struct Link;
15
23
  class Listable {
16
24
  public:
17
- std::vector<Link> data_pointer;
25
+ std::array<Link, 3> data_pointer;
18
26
  };
19
27
 
20
28
  class List {
@@ -25,13 +25,3 @@ List *Lists::add_list() {
25
25
  lists.push_back(list);
26
26
  return(list);
27
27
  }
28
-
29
- std::vector<Link> Lists::get_data_pointer() {
30
- std::vector<Link> data(this->lists.size());
31
- for (auto& dt : data) {
32
- dt.inside = false;
33
- dt.next = nullptr;
34
- dt.prev = nullptr;
35
- }
36
- return data;
37
- }
@@ -11,19 +11,12 @@
11
11
  #include <list>
12
12
  #include <vector>
13
13
  #include "List.h"
14
- class List;
15
- class Listable;
16
- struct Link {
17
- Listable *next, *prev;
18
- bool inside;
19
- };
20
14
 
21
15
  class Lists {
22
16
  public:
23
17
  Lists() {}
24
18
  virtual ~Lists();
25
19
  List *add_list();
26
- std::vector<Link> get_data_pointer();
27
20
  private:
28
21
  std::list<List*> lists;
29
22
  };
@@ -11,11 +11,15 @@
11
11
  #include <string>
12
12
  #include <iostream>
13
13
  #include <algorithm>
14
+ #include <limits>
14
15
  #include <vector>
15
16
  #include <list>
16
17
  #include "Node.h"
18
+ #include "NodeCluster.h"
17
19
 
18
- Node::Node(int min_x, int max_x, int y, char name) {
20
+ Node::Node(int min_x, int max_x, int y, char name)
21
+ : start_point(min_x, y),
22
+ end_point(max_x, y) {
19
23
  this->name = name;
20
24
  this->min_x = min_x;
21
25
  this->max_x = max_x;
@@ -32,64 +36,59 @@ Node::Node(int min_x, int max_x, int y, char name) {
32
36
  bool Node::get_trackmax() {
33
37
  return((this->track & OMAX) != 0);
34
38
  }
39
+
35
40
  bool Node::track_complete() {
36
41
  return((this->track & OCOMPLETE) == OCOMPLETE);
37
42
  }
43
+
38
44
  bool Node::track_uncomplete() {
39
45
  return((this->track & OCOMPLETE) != OCOMPLETE);
40
46
  }
41
47
 
42
- bool Node::tangs_with(Node *node) {
43
- return(this->min_x <= node->max_x && node->min_x <= this->max_x);
44
- }
45
-
46
- void Node::add_intersection(Node *other_node) {
47
- if (other_node->y < this->y) tangs[T_UP].push_back(other_node);
48
- else tangs[T_DOWN].push_back(other_node);
48
+ void Node::add_intersection(Node& other_node, int other_node_index) {
49
+ if (other_node.y < this->y) {
50
+ upper_start = std::min(upper_start, other_node_index);
51
+ upper_end = std::max(upper_end, other_node_index);
52
+ } else {
53
+ lower_start = std::min(lower_start, other_node_index);
54
+ lower_end = std::max(lower_end, other_node_index);
55
+ }
49
56
  }
50
57
 
51
- void Node::precalc_tangs_sequences(std::vector<Point>& points) {
58
+ void Node::precalc_tangs_sequences(NodeCluster& cluster) {
52
59
  this->tangs_sequence.clear();
53
- this->tangs_sequence.reserve(tangs[T_UP].size() + tangs[T_DOWN].size());
54
- std::vector<Node*> up_copy = tangs[T_UP];
55
- std::vector<Node*> down_copy = tangs[T_DOWN];
56
60
 
57
- // --- CLOCKWISE (UP) ---
58
- std::sort(up_copy.begin(), up_copy.end(), sort_min_x);
59
- if (!up_copy.empty()) {
60
- this->up_indexer = -up_copy.front()->abs_x_index;
61
+ int lower_size = this->lower_end >= 0 ? (this->lower_end - this->lower_start + 1) : 0;
62
+ int upper_size = this->upper_end >= 0 ? (this->upper_end - this->upper_start + 1) : 0;
63
+ this->tangs_sequence.reserve(lower_size + upper_size);
64
+
65
+ if (this->upper_end >= 0) {
66
+ this->up_indexer = -cluster.vert_nodes[y + T_UP][this->upper_start].abs_x_index;
61
67
  }
62
- for (Node* t_node : up_copy) {
63
- tangs_sequence.push_back(NodeDescriptor{
64
- t_node,
65
- Tangent{ &points.emplace_back(t_node->max_x, t_node->y), OMAX},
66
- Tangent{ &points.emplace_back(t_node->min_x, t_node->y), OMIN}
68
+ // --- CLOCKWISE (UP) ---
69
+ for (int upper_pos = this->upper_start; upper_pos <= this->upper_end; upper_pos++) {
70
+ Node& t_node = cluster.vert_nodes[y + T_UP][upper_pos];
71
+ tangs_sequence.emplace_back(NodeDescriptor{
72
+ &t_node,
73
+ Tangent{ &t_node.end_point, OMAX},
74
+ Tangent{ &t_node.start_point, OMIN}
67
75
  });
68
76
  }
69
-
70
- // --- COUNTER-CLOCKWISE (DOWN) ---
71
- std::sort(down_copy.begin(), down_copy.end(), sort_max_x);
72
- std::reverse(down_copy.begin(), down_copy.end());
73
- if (!down_copy.empty()) {
74
- this->down_indexer = (down_copy.back()->abs_x_index +
75
- tangs[T_UP].size() + tangs[T_DOWN].size() - 1);
77
+ if (this->lower_end >= 0) {
78
+ this->down_indexer = (cluster.vert_nodes[y + T_DOWN][this->lower_start].abs_x_index + lower_size + upper_size - 1);
76
79
  }
77
- for (Node* t_node : down_copy) {
78
- tangs_sequence.push_back(NodeDescriptor{
79
- t_node,
80
- Tangent{&points.emplace_back(t_node->min_x, t_node->y), OMIN},
81
- Tangent{&points.emplace_back(t_node->max_x, t_node->y), OMAX}
80
+ // --- COUNTER-CLOCKWISE (DOWN) ---
81
+ for (int lower_pos = this->lower_end; lower_pos >= this->lower_start; lower_pos--) {
82
+ Node& t_node = cluster.vert_nodes[y + T_DOWN][lower_pos];
83
+ tangs_sequence.emplace_back(NodeDescriptor{
84
+ &t_node,
85
+ Tangent{&t_node.start_point, OMIN},
86
+ Tangent{&t_node.end_point, OMAX}
82
87
  });
83
88
  }
84
89
  this->tangs_count = this->tangs_sequence.size();
85
90
  }
86
91
 
87
- bool Node::sort_min_x(Node *a, Node *b) {
88
- return(a->min_x <= b->min_x);
89
- }
90
- bool Node::sort_max_x(Node *a, Node *b) {
91
- return(a->max_x <= b->max_x);
92
- }
93
92
  Node* Node::my_next_inner(Node *last, int versus) {
94
93
  unsigned int last_node_index;
95
94
  if (last->y < this->y) last_node_index = last->abs_x_index + this->up_indexer;
@@ -98,6 +97,7 @@ Node* Node::my_next_inner(Node *last, int versus) {
98
97
  else last_node_index == this->tangs_sequence.size() - 1 ? last_node_index = 0 : last_node_index++;
99
98
  return((this->tangs_sequence)[last_node_index].node);
100
99
  }
100
+
101
101
  Node* Node::my_next_outer(Node *last, int versus) {
102
102
  unsigned int last_node_index;
103
103
  if (last->y < this->y) last_node_index = last->abs_x_index + this->up_indexer;
@@ -11,6 +11,8 @@
11
11
  #include <string>
12
12
  #include <vector>
13
13
  #include <list>
14
+ #include <limits>
15
+ #include <algorithm>
14
16
  #include <map>
15
17
  #include "List.h"
16
18
 
@@ -32,10 +34,9 @@ struct Tangent {
32
34
  };
33
35
  struct NodeDescriptor;
34
36
 
35
-
36
37
  class Node : public Listable {
37
38
  public:
38
- static const int T_UP = 0;
39
+ static const int T_UP = -1;
39
40
  static const int T_DOWN = 1;
40
41
  static const int O = 0;
41
42
  static const int A = 1;
@@ -50,7 +51,6 @@ class Node : public Listable {
50
51
  static const int OUTER = 0;
51
52
  static const int INNER = 1;
52
53
 
53
- std::vector<Node*> tangs[2];
54
54
  int y;
55
55
  int abs_x_index;
56
56
  int up_indexer, down_indexer;
@@ -58,8 +58,12 @@ class Node : public Listable {
58
58
  char name;
59
59
  int track;
60
60
  int outer_index, inner_index;
61
- bool tangs_with(Node *node);
62
- void add_intersection(Node *other_node);
61
+ int upper_start = std::numeric_limits<int>::max();
62
+ int upper_end = -1;
63
+ int lower_start = std::numeric_limits<int>::max();
64
+ int lower_end = -1;
65
+ Point start_point, end_point;
66
+ void add_intersection(Node& other_node, int other_node_index);
63
67
  std::vector<NodeDescriptor> tangs_sequence;
64
68
  Point* coords_entering_to(Node *enter_to, int mode, int tracking);
65
69
  Node* my_next_outer(Node *last, int versus);
@@ -68,14 +72,10 @@ class Node : public Listable {
68
72
  bool track_complete();
69
73
  bool get_trackmax();
70
74
 
71
- private:
72
- static bool sort_min_x(Node *a, Node *b);
73
- static bool sort_max_x(Node *a, Node *b);
74
-
75
75
  public:
76
76
  int min_x, max_x;
77
77
  Node(int min_x, int max_x, int y, char name);
78
- void precalc_tangs_sequences(std::vector<Point>& points);
78
+ void precalc_tangs_sequences(NodeCluster& cluster);
79
79
  bool processed = false;
80
80
  };
81
81
 
@@ -14,6 +14,7 @@
14
14
  #include <string>
15
15
  #include <vector>
16
16
  #include <utility>
17
+ #include <deque>
17
18
  #include "NodeCluster.h"
18
19
  #include "Node.h"
19
20
  #include "RectBounds.h"
@@ -30,15 +31,9 @@ NodeCluster::NodeCluster(int h, int w, pf_Options *options) {
30
31
  this->nodes = 0;
31
32
 
32
33
  this->vert_nodes.resize(h);
33
- for (int i = 0; i < h; ++i) {
34
- this->vert_nodes[i].reserve(w/2);
35
- }
36
-
37
34
  this->root_nodes = this->lists.add_list();
38
35
  this->inner_plot = this->lists.add_list();
39
36
  this->inner_new = this->lists.add_list();
40
-
41
- this->points.reserve(w * h);
42
37
  }
43
38
 
44
39
  NodeCluster::~NodeCluster() {
@@ -74,32 +69,33 @@ void NodeCluster::compress_coords(std::list<Polygon>& polygons, pf_Options optio
74
69
  void NodeCluster::build_tangs_sequence() {
75
70
  for (auto& line : vert_nodes) {
76
71
  for (Node& node : line) {
77
- node.precalc_tangs_sequences(this->points);
72
+ node.precalc_tangs_sequences(*this);
78
73
  }
79
74
  }
80
75
  }
81
76
 
82
- Node* NodeCluster::add_node(int min_x, int max_x, int y, char name) {
77
+ Node* NodeCluster::add_node(int min_x, int max_x, int y, char name, int offset) {
83
78
  vert_nodes[y].emplace_back(min_x, max_x, y, name);
84
79
 
85
80
  Node& node = vert_nodes[y].back();
86
- node.data_pointer = this->lists.get_data_pointer();
87
81
  node.abs_x_index = vert_nodes[y].size() - 1;
88
82
  this->nodes++;
89
83
 
90
84
  root_nodes->push_back(&node);
91
85
 
92
86
  if (y > 0) {
93
- std::vector<Node>& up_nodes = vert_nodes[y - 1];
87
+ std::deque<Node>& up_nodes = vert_nodes[y - 1];
94
88
  if (!up_nodes.empty()) {
95
89
  auto it = std::lower_bound(up_nodes.begin(), up_nodes.end(), node.min_x,
96
- [](const Node& a, int val) {
97
- return a.max_x < val;
90
+ [&](const Node& a, int val) {
91
+ return ((a.max_x + offset) < val);
98
92
  });
93
+
99
94
  while (it != up_nodes.end()) {
100
- if (it->min_x > node.max_x) break;
101
- node.add_intersection(&(*it));
102
- it->add_intersection(&node);
95
+ if ((it->min_x - offset) > node.max_x) break;
96
+ int current_index = std::distance(up_nodes.begin(), it);
97
+ node.add_intersection(*it, current_index);
98
+ it->add_intersection(node, node.abs_x_index);
103
99
  ++it;
104
100
  }
105
101
  }
@@ -159,13 +155,20 @@ void NodeCluster::plot(int versus) {
159
155
 
160
156
  first->inner_index = index_inner;
161
157
 
162
- Node *next_node;
163
- if (first->get_trackmax())
164
- { if (inner_v == Node::A) next_node = first->tangs[Node::T_UP].front();
165
- else next_node = first->tangs[Node::T_DOWN].front();
158
+ Node* next_node = nullptr;
159
+
160
+ if (first->get_trackmax()) {
161
+ if (inner_v == Node::A) {
162
+ if (first->upper_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_UP][first->upper_start];
163
+ } else {
164
+ if (first->lower_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_DOWN][first->lower_start];
165
+ }
166
166
  } else {
167
- if (inner_v == Node::A) next_node = first->tangs[Node::T_DOWN].back();
168
- else next_node = first->tangs[Node::T_UP].back();
167
+ if (inner_v == Node::A) {
168
+ if (first->lower_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_DOWN][first->lower_end];
169
+ } else {
170
+ if (first->upper_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_UP][first->upper_end];
171
+ }
169
172
  }
170
173
 
171
174
  if (next_node != nullptr)
@@ -309,21 +312,3 @@ void NodeCluster::plot_node(std::vector<Point*>& sequence_coords, Node *node, No
309
312
  current_node = next_node;
310
313
  }
311
314
  }
312
-
313
- void NodeCluster::list_track(Node *node, std::list<Node*> *list) {
314
- std::list<Node*>::iterator i = std::find(list->begin(), list->end(), node);
315
- if (i == list->end()) list->push_back(node);
316
- else list_delete(node, list);
317
- }
318
-
319
- void NodeCluster::list_delete(Node *node, std::list<Node*> *list) {
320
- std::list<Node*>::iterator i;
321
- while ((i = std::find(list->begin(), list->end(), node)) != list->end())
322
- { list->erase(i);
323
- }
324
- }
325
-
326
- bool NodeCluster::list_present(Node *node, std::list<Node*> *list) {
327
- std::list<Node*>::iterator i = std::find(list->begin(), list->end(), node);
328
- return(!(i == list->end()));
329
- }