contrek 1.0.0

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 (78) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +84 -0
  6. data/LICENSE.md +9 -0
  7. data/README.md +118 -0
  8. data/Rakefile +19 -0
  9. data/contrek.gemspec +23 -0
  10. data/contrek.png +0 -0
  11. data/ext/cpp_polygon_finder/PolygonFinder/.cproject +136 -0
  12. data/ext/cpp_polygon_finder/PolygonFinder/.project +27 -0
  13. data/ext/cpp_polygon_finder/PolygonFinder/.settings/org.eclipse.ltk.core.refactoring.prefs +2 -0
  14. data/ext/cpp_polygon_finder/PolygonFinder/images/labyrinth.png +0 -0
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/Main.cpp +41 -0
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +69 -0
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +19 -0
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.cpp +52 -0
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.h +32 -0
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +656 -0
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h +42 -0
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.cpp +48 -0
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.h +32 -0
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +30 -0
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h +26 -0
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/X_picopng.cpp +576 -0
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +120 -0
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +40 -0
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +36 -0
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +30 -0
  31. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +111 -0
  32. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +80 -0
  33. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +325 -0
  34. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +59 -0
  35. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +206 -0
  36. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +69 -0
  37. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/optionparser.h +2858 -0
  38. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.cpp +23 -0
  39. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.h +23 -0
  40. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBMatcher.cpp +20 -0
  41. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBMatcher.h +23 -0
  42. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.cpp +20 -0
  43. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.h +23 -0
  44. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.cpp +20 -0
  45. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.h +21 -0
  46. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.cpp +40 -0
  47. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.h +23 -0
  48. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.cpp +19 -0
  49. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.h +25 -0
  50. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.cpp +30 -0
  51. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.h +21 -0
  52. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.cpp +50 -0
  53. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +121 -0
  54. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +260 -0
  55. data/ext/cpp_polygon_finder/extconf.rb +2 -0
  56. data/lib/contrek/bitmaps/bitmap.rb +21 -0
  57. data/lib/contrek/bitmaps/chunky_bitmap.rb +33 -0
  58. data/lib/contrek/bitmaps/painting.rb +40 -0
  59. data/lib/contrek/bitmaps/png_bitmap.rb +62 -0
  60. data/lib/contrek/bitmaps/rgb_color.rb +25 -0
  61. data/lib/contrek/finder/list.rb +132 -0
  62. data/lib/contrek/finder/list_entry.rb +11 -0
  63. data/lib/contrek/finder/listable.rb +8 -0
  64. data/lib/contrek/finder/lists.rb +25 -0
  65. data/lib/contrek/finder/node.rb +126 -0
  66. data/lib/contrek/finder/node_cluster.rb +294 -0
  67. data/lib/contrek/finder/polygon_finder.rb +121 -0
  68. data/lib/contrek/map/mercator_projection.rb +76 -0
  69. data/lib/contrek/matchers/matcher.rb +20 -0
  70. data/lib/contrek/matchers/matcher_hsb.rb +24 -0
  71. data/lib/contrek/matchers/value_not_matcher.rb +9 -0
  72. data/lib/contrek/reducers/linear_reducer.rb +25 -0
  73. data/lib/contrek/reducers/reducer.rb +14 -0
  74. data/lib/contrek/reducers/uniq_reducer.rb +9 -0
  75. data/lib/contrek/reducers/visvalingam_reducer.rb +139 -0
  76. data/lib/contrek/version.rb +3 -0
  77. data/lib/contrek.rb +58 -0
  78. metadata +175 -0
@@ -0,0 +1,325 @@
1
+ /*
2
+ * NodeCluster.cpp
3
+ *
4
+ * Created on: 26 nov 2018
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #include "NodeCluster.h"
10
+ #include "Node.h"
11
+ #include "../reducers/UniqReducer.h"
12
+ #include "../reducers/LinearReducer.h"
13
+ #include "../reducers/VisvalingamReducer.h"
14
+ #include <iostream>
15
+ #include <list>
16
+ #include <algorithm>
17
+ #include <map>
18
+ #include <string>
19
+ #include <vector>
20
+
21
+ NodeCluster::NodeCluster(int h, pf_Options *options) {
22
+ this->vert_nodes = new std::vector<Node*>[h];
23
+ versus_inverter[Node::O] = Node::A;
24
+ versus_inverter[Node::A] = Node::O;
25
+ this->options = options;
26
+ this->height = h;
27
+ this->nodes = 0;
28
+ this->plot_sequence = nullptr;
29
+ this->sequence_coords = nullptr;
30
+ this->sequences = new std::list<std::list<Node*>*>();
31
+
32
+ this->root_nodes = this->lists.add_list();
33
+ this->inner_plot = this->lists.add_list();
34
+ this->inner_new = this->lists.add_list();
35
+ }
36
+
37
+ NodeCluster::~NodeCluster() {
38
+ }
39
+
40
+ void NodeCluster::compress_coords(pf_Options options) {
41
+ if (options.compress_linear || options.compress_uniq || options.compress_visvalingam)
42
+ { std::list<std::list<Point*>*> sequences;
43
+ for (std::list<std::map<std::string, std::list<std::list<Point*>*>>>::iterator x = this->polygons.begin(); x != this->polygons.end(); ++x)
44
+ { for (std::list<std::list<Point*>*>::iterator y = (*x)["outer"].begin(); y != (*x)["outer"].end(); ++y)
45
+ { sequences.push_back(*y);
46
+ }
47
+ for (std::list<std::list<Point*>*>::iterator y = (*x)["inner"].begin(); y != (*x)["inner"].end(); ++y)
48
+ { sequences.push_back(*y);
49
+ }
50
+ }
51
+ if (options.compress_uniq)
52
+ { for (std::list<std::list<Point*>*>::iterator it = sequences.begin(); it != sequences.end(); ++it)
53
+ { UniqReducer reducer(*it);
54
+ reducer.reduce();
55
+ }
56
+ }
57
+ if (options.compress_linear)
58
+ { for (std::list<std::list<Point*>*>::iterator it = sequences.begin(); it != sequences.end(); ++it)
59
+ { LinearReducer reducer(*it);
60
+ reducer.reduce();
61
+ }
62
+ }
63
+ if (options.compress_visvalingam)
64
+ { for (std::list<std::list<Point*>*>::iterator it = sequences.begin(); it != sequences.end(); ++it)
65
+ { VisvalingamReducer reducer(*it, options.compress_visvalingam_tolerance);
66
+ reducer.reduce();
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+
73
+ void NodeCluster::build_tangs_sequence() {
74
+ for (int line = 0; line < this->height; line++)
75
+ { for (std::vector<Node*>::iterator node = vert_nodes[line].begin(); node != vert_nodes[line].end(); ++node)
76
+ { (*node)->precalc_tangs_sequences();
77
+ }
78
+ }
79
+ }
80
+
81
+ void NodeCluster::add_node(Node *node) {
82
+ this->nodes++;
83
+ node->data_pointer = this->lists.get_data_pointer();
84
+ node->abs_x_index = vert_nodes[node->y].size();
85
+ vert_nodes[node->y].push_back(node);
86
+ root_nodes->push_back(node);
87
+
88
+ if (node->y > 0)
89
+ { std::vector<Node*> *up_nodes = &vert_nodes[node->y - 1];
90
+ int up_nodes_count = up_nodes->size();
91
+ Node *up_node;
92
+ if (up_nodes_count > 0)
93
+ { int index = 0;
94
+ do
95
+ { up_node = (*up_nodes)[index];
96
+ if (up_node->max_x >= node->min_x)
97
+ { if (up_node->min_x <= node->max_x)
98
+ { node->add_intersection(up_node);
99
+ (up_node)->add_intersection(node);
100
+ }
101
+ if (++index == up_nodes_count) return;
102
+ do
103
+ { up_node = (*up_nodes)[index];
104
+ if (up_node->min_x <= node->max_x)
105
+ { node->add_intersection(up_node);
106
+ (up_node)->add_intersection(node);
107
+ }
108
+ else return;
109
+ }while (++index != up_nodes_count);
110
+ return;
111
+ }
112
+ }while(++index != up_nodes_count);
113
+ }
114
+ }
115
+ }
116
+
117
+ std::list<Point*>* NodeCluster::get_coords() {
118
+ return(this->sequence_coords);
119
+ }
120
+
121
+ void NodeCluster::plot(int versus) {
122
+ int inner_v = versus_inverter[versus];
123
+ int index_order = 0;
124
+ Node *next_node;
125
+
126
+ while (root_nodes->size() > 0)
127
+ { Node *root_node = (Node*) root_nodes->shift();
128
+ root_node->outer_index = index_order;
129
+ this->plot_sequence = new std::list<Node*>();
130
+ this->sequence_coords = new std::list<Point*>();
131
+
132
+ plot_sequence->push_back(root_node);
133
+
134
+ if ((root_node)->tangs_sequence->size() > 0) // front() on empty list is undefined
135
+ { versus == Node::A ? next_node = root_node->tangs_sequence->back()->node : next_node = root_node->tangs_sequence->front()->node;
136
+ if (next_node != nullptr)
137
+ { sequence_coords->push_back(next_node->coords_entering_to(root_node, versus_inverter[versus], Node::OUTER));
138
+ }
139
+ if ((this->nodes > 0) && (next_node != nullptr))
140
+ { plot_node(next_node, root_node, versus);
141
+ }
142
+ this->sequences->push_back(plot_sequence);
143
+ std::list<std::list<Point*>*> outer_container, inner_container;
144
+ outer_container.push_back(sequence_coords);
145
+ std::list<Point*> pl_inner;
146
+ std::map<std::string, std::list<std::list<Point*>*>> poly;
147
+ poly["outer"] = outer_container;
148
+ poly["inner"] = inner_container;
149
+ if (sequence_coords->size() > 2) this->polygons.push_back(poly);
150
+
151
+ int index_inner = 0;
152
+ while (inner_plot->size() > 0)
153
+ { this->plot_sequence = new std::list<Node*>();
154
+ this->sequence_coords = new std::list<Point*>();
155
+ std::list<Node*>::iterator first_i;
156
+ Node *first = nullptr;
157
+
158
+ Listable *act = inner_plot->first();
159
+ do
160
+ { if (((Node*)act)->tangs_count <= 2)
161
+ { first = (Node*) act;
162
+ break;
163
+ }
164
+ }while((act = act->data_pointer[inner_plot->get_id()].next) != nullptr);
165
+
166
+ if (first == nullptr) first = (Node*) inner_plot->first();
167
+
168
+ plot_sequence->push_back(first);
169
+ inner_plot->remove(first);
170
+ root_nodes->remove(first);
171
+
172
+ first->inner_index = index_inner;
173
+
174
+ Node *next_node;
175
+ if (first->get_trackmax())
176
+ { if (inner_v == Node::A) next_node = first->tangs[Node::T_UP].front();
177
+ else next_node = first->tangs[Node::T_DOWN].front();
178
+ } else {
179
+ if (inner_v == Node::A) next_node = first->tangs[Node::T_DOWN].back();
180
+ else next_node = first->tangs[Node::T_UP].back();
181
+ }
182
+
183
+ if (next_node != nullptr)
184
+ { sequence_coords->push_back(next_node->coords_entering_to(first, inner_v, Node::INNER));
185
+ plot_inner_node(next_node, inner_v, first, root_node);
186
+ }
187
+
188
+ this->polygons.back()["inner"].push_back(sequence_coords);
189
+ this->inner_plot->grab(this->inner_new);
190
+ index_inner++;
191
+ }
192
+ } else {
193
+ this->sequences->push_back(plot_sequence);
194
+ }
195
+ // tree
196
+ if (this->options->treemap)
197
+ { this->treemap.push_back(versus == Node::A ? this->test_in_hole_a(root_node) : this->test_in_hole_o(root_node));
198
+ }
199
+ index_order++;
200
+ }
201
+ }
202
+
203
+ int *NodeCluster::test_in_hole_a(Node *node)
204
+ { if (node->outer_index > 0)
205
+ { int start_left = node->abs_x_index - 1;
206
+ do
207
+ { Node *prev = this->vert_nodes[node->y][start_left];
208
+ int cindex = prev->outer_index;
209
+ if ((cindex < node->outer_index) && ((prev->track & Node::IMAX) != 0))
210
+ { unsigned int start_right = node->abs_x_index;
211
+ unsigned int line_size = this->vert_nodes[node->y].size();
212
+ while (++start_right != line_size)
213
+ { Node *tnext = this->vert_nodes[node->y][start_right];
214
+ if (tnext->outer_index == cindex)
215
+ { if ((tnext->track & Node::IMIN) != 0) return(new int[2] {cindex, prev->inner_index});
216
+ else return(new int[2] {-1, -1});
217
+ }
218
+ }
219
+ }
220
+ }while(--start_left >= 0);
221
+ }
222
+ return(new int[2] {-1, -1});
223
+ }
224
+
225
+ int *NodeCluster::test_in_hole_o(Node *node)
226
+ { unsigned int line_size = this->vert_nodes[node->y].size();
227
+ if ((node->outer_index) > 0 && (vert_nodes[node->y].back() != node))
228
+ { unsigned int start_left = node->abs_x_index + 1;
229
+ do
230
+ { Node *prev = this->vert_nodes[node->y][start_left];
231
+ int cindex = prev->outer_index;
232
+ if ((cindex < node->outer_index) && ((prev->track & Node::IMIN) != 0))
233
+ { int start_right = node->abs_x_index;
234
+ while (--start_right >= 0)
235
+ { Node *tnext = this->vert_nodes[node->y][start_right];
236
+ if (tnext->outer_index == cindex)
237
+ { if ((tnext->track & Node::IMAX) != 0) return(new int[2] {cindex, prev->inner_index});
238
+ else return(new int[2] {-1, -1});
239
+ }
240
+ }
241
+ }
242
+ }while(++start_left != line_size);
243
+ }
244
+ return(new int[2] {-1, -1});
245
+ }
246
+
247
+ void NodeCluster::plot_inner_node(Node *node, int versus, Node *stop_at, Node *start_node) {
248
+ node->outer_index = start_node->outer_index;
249
+ node->inner_index = stop_at->inner_index;
250
+ root_nodes->remove(node);
251
+ inner_plot->remove(node);
252
+
253
+ Node *last_node = plot_sequence->back();
254
+ Node *next_node = node->my_next_inner(last_node, versus);
255
+
256
+ plot_sequence->push_back(node);
257
+
258
+ bool plot = true;
259
+ if (next_node -> y == last_node -> y)
260
+ { Node *n = (versus == Node::A ? node->tangs_sequence->front()->node : node->tangs_sequence->back()->node);
261
+ plot = (n == next_node);
262
+ }
263
+ if (plot)
264
+ { sequence_coords->push_back(last_node->coords_entering_to(node, versus_inverter[versus], Node::INNER));
265
+ if (node != start_node)
266
+ { if (last_node->y == next_node->y)
267
+ { sequence_coords->push_back(next_node->coords_entering_to(node, versus, Node::INNER));
268
+ }
269
+ }
270
+ }
271
+ if (node->track_uncomplete())
272
+ { this->inner_new->push_back(node);
273
+ } else {
274
+ inner_new->remove(node);
275
+ }
276
+ if (next_node == stop_at) return;
277
+ plot_inner_node(next_node, versus, stop_at, start_node);
278
+ }
279
+
280
+ void NodeCluster::plot_node(Node *node, Node *start_node, int versus) {
281
+ root_nodes->remove(node);
282
+ node->outer_index = start_node->outer_index;
283
+ Node *last_node = plot_sequence->back();
284
+ Node *next_node = node->my_next_outer(last_node, versus);
285
+
286
+ plot_sequence->push_back(node);
287
+ bool plot = true;
288
+ if (next_node -> y == last_node -> y)
289
+ { Node *n = (versus == Node::A ? node->tangs_sequence->back()->node : node->tangs_sequence->front()->node);
290
+ plot = (n == next_node);
291
+ }
292
+
293
+ if (plot)
294
+ { sequence_coords->push_back(last_node->coords_entering_to(node, versus, Node::OUTER));
295
+ if (node != start_node)
296
+ { inner_plot->contains(node) ? inner_plot->remove(node) : inner_plot->push_back(node);
297
+ if (last_node->y == next_node->y)
298
+ { sequence_coords->push_back(next_node->coords_entering_to(node, versus_inverter[versus], Node::OUTER));
299
+ inner_plot->contains(node) ? inner_plot->remove(node) : inner_plot->push_back(node);
300
+ }
301
+ }
302
+ }
303
+ if (node == start_node)
304
+ { if (node->track_complete()) return;
305
+ }
306
+ plot_node(next_node, start_node, versus);
307
+ }
308
+
309
+ void NodeCluster::list_track(Node *node, std::list<Node*> *list) {
310
+ std::list<Node*>::iterator i = std::find(list->begin(), list->end(), node);
311
+ if (i == list->end()) list->push_back(node);
312
+ else list_delete(node, list);
313
+ }
314
+
315
+ void NodeCluster::list_delete(Node *node, std::list<Node*> *list) {
316
+ std::list<Node*>::iterator i;
317
+ while ((i = std::find(list->begin(), list->end(), node)) != list->end())
318
+ { list->erase(i);
319
+ }
320
+ }
321
+
322
+ bool NodeCluster::list_present(Node *node, std::list<Node*> *list) {
323
+ std::list<Node*>::iterator i = std::find(list->begin(), list->end(), node);
324
+ return(!(i == list->end()));
325
+ }
@@ -0,0 +1,59 @@
1
+ /*
2
+ * NodeCluster.h
3
+ *
4
+ * Created on: 26 nov 2018
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #ifndef POLYGON_FINDER_NODECLUSTER_H_
10
+ #define POLYGON_FINDER_NODECLUSTER_H_
11
+ #include <list>
12
+ #include <vector>
13
+ #include <map>
14
+ #include <string>
15
+ #include "PolygonFinder.h"
16
+ #include "Lists.h"
17
+
18
+ class Node;
19
+ struct Point;
20
+ struct pf_Options;
21
+
22
+ class NodeCluster {
23
+ private:
24
+ void plot_node(Node *node, Node *start_node, int versus);
25
+ void plot_inner_node(Node *node, int versus, Node *stop_at, Node *start_node);
26
+ std::list<Node*> *plot_sequence;
27
+ List *inner_plot;
28
+ std::list<Point*> *sequence_coords;
29
+ List *inner_new;
30
+ int versus_inverter[2];
31
+ int count = 0;
32
+ int nodes;
33
+ pf_Options *options;
34
+
35
+ public:
36
+ std::list<int*> treemap;
37
+ int *test_in_hole_a(Node *node);
38
+ int *test_in_hole_o(Node *node);
39
+ std::vector<Node*> *vert_nodes;
40
+ void list_track(Node *node, std::list<Node*> *list);
41
+ void list_delete(Node *node, std::list<Node*> *list);
42
+ bool list_present(Node *node, std::list<Node*> *list);
43
+ void compress_coords(pf_Options options);
44
+ List *root_nodes;
45
+ int height;
46
+ std::list<std::map<std::string, std::list<std::list<Point*>*>>> polygons;
47
+ NodeCluster(int h, pf_Options *options);
48
+ virtual ~NodeCluster();
49
+ void add_node(Node *node);
50
+ void calc_root_nodes();
51
+ void build_tangs_sequence();
52
+ void plot(int versus);
53
+ Lists lists;
54
+ std::list<Node*>::iterator exam(std::list<Node*>::iterator inode, Node *node, Node *father, Node *root_node);
55
+ std::list<Point*>* get_coords();
56
+ std::list<std::list<Node*>*> *sequences;
57
+ };
58
+
59
+ #endif /* POLYGON_FINDER_NODECLUSTER_H_ */
@@ -0,0 +1,206 @@
1
+ /*
2
+ * PolygonFinder.cpp
3
+ *
4
+ * Created on: 24 nov 2018
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+
10
+ #include <iostream>
11
+ #include <list>
12
+ #include <map>
13
+ #include <ctime>
14
+ #include <typeinfo>
15
+ #include <string>
16
+ #include <ctime>
17
+ #include <vector>
18
+ #include "PolygonFinder.h"
19
+ #include "../bitmaps/Bitmap.h"
20
+ #include "../matchers/Matcher.h"
21
+ #include "../matchers/RGBMatcher.h"
22
+ #include "optionparser.h"
23
+ #include "NodeCluster.h"
24
+ #include "Node.h"
25
+
26
+ PolygonFinder::PolygonFinder(Bitmap *bitmap, Matcher *matcher, Bitmap *test_bitmap, std::vector<std::string> *options) {
27
+ source_bitmap = bitmap;
28
+ this->matcher = matcher;
29
+ if (options != nullptr) sanitize_options(options);
30
+ this->node_cluster = new NodeCluster(source_bitmap->h(), &this->options);
31
+
32
+ //= SCAN ==============//
33
+ start_timer();
34
+ scan();
35
+ reports["scan"] = end_timer();
36
+ //=====================//
37
+
38
+ //= BUILD_TANGS_SEQUENCE ===//
39
+ start_timer();
40
+ node_cluster->build_tangs_sequence();
41
+ reports["build_tangs_sequence"] = end_timer();
42
+ //=====================//
43
+
44
+ //= PLOT ===//
45
+ start_timer();
46
+ node_cluster->plot(this->options.versus);
47
+ reports["plot"] = end_timer();
48
+ //=====================//
49
+
50
+ //= COMPRESS_COORDS ===//
51
+ start_timer();
52
+ node_cluster->compress_coords(this->options);
53
+ reports["compress"] = end_timer();
54
+ //=====================//
55
+ reports["total"] = reports["scan"] + reports["build_tangs_sequence"] + reports["plot"] + reports["compress"];
56
+ }
57
+
58
+ std::list<ShapeLine*> *PolygonFinder::get_shapelines() {
59
+ std::list<ShapeLine*> *sll = new std::list<ShapeLine*>();
60
+ for (int line = 0; line < this->node_cluster->height; line++)
61
+ { for (std::vector<Node*>::iterator node = this->node_cluster->vert_nodes[line].begin(); node != this->node_cluster->vert_nodes[line].end(); ++node)
62
+ { ShapeLine *sl = new ShapeLine({(*node)->min_x, (*node)->max_x, (*node)->y});
63
+ sll->push_back(sl);
64
+ }
65
+ }
66
+ return(sll);
67
+ }
68
+
69
+ void PolygonFinder::sanitize_options(std::vector<std::string> *incoming_options)
70
+ { std::vector<char*> argv0;
71
+ for (const auto& arg : *incoming_options)
72
+ argv0.push_back((char*)arg.data());
73
+ argv0.push_back(nullptr);
74
+ char** argv = &argv0[0];
75
+ int argc = argv0.size() -1;
76
+
77
+ enum optionIndex { COMPRESS_UNIQ, VERSUS, COMPRESS_VISVALINGAM, COMPRESS_LINEAR, COMPRESS_VISVALINGAM_TOLERANCE, TREEMAP};
78
+ const option::Descriptor usage[] = {
79
+ // {UNKNOWN, 0,"" , "" ,option::Arg::None, 0},
80
+ {COMPRESS_VISVALINGAM, 0, "" , "compress_visvalingam", option::Arg::None, 0},
81
+ {COMPRESS_LINEAR, 0, "" , "compress_linear", option::Arg::None, 0},
82
+ {COMPRESS_VISVALINGAM_TOLERANCE, 0, "" , "compress_visvalingam_tolerance", option::Arg::Optional, 0},
83
+ {COMPRESS_UNIQ, 0, "", "compress_uniq", option::Arg::None, 0},
84
+ {TREEMAP, 0, "", "treemap", option::Arg::None, 0},
85
+ {VERSUS, 0, "v", "versus", option::Arg::Optional, 0},
86
+ {0, 0, 0, 0, 0, 0}
87
+ };
88
+
89
+ option::Stats stats(usage, argc, argv);
90
+ option::Option ioptions[stats.options_max], buffer[stats.buffer_max];
91
+ option::Parser parse(usage, argc, argv, ioptions, buffer);
92
+
93
+ if (parse.error()) return;
94
+ // VERSUS
95
+ if (ioptions[VERSUS].count() > 0)
96
+ { for (option::Option* opt = ioptions[VERSUS]; opt; opt = opt->next())
97
+ { std::string opts = opt->arg;
98
+ this->options.versus = (opts.compare("a") == 0 ? Node::A : Node::O);
99
+ break;
100
+ }
101
+ }
102
+ // COMPRESS UNIQ
103
+ if (ioptions[COMPRESS_UNIQ].count() > 0)
104
+ { this->options.compress_uniq = true;
105
+ }
106
+ // TREEMAP
107
+ if (ioptions[TREEMAP].count() > 0)
108
+ { this->options.treemap = true;
109
+ }
110
+ // COMPRESS LINEAR
111
+ if (ioptions[COMPRESS_LINEAR].count() > 0)
112
+ { this->options.compress_linear = true;
113
+ }
114
+ // COMPRESS UNIQ
115
+ if (ioptions[COMPRESS_VISVALINGAM].count() > 0)
116
+ { this->options.compress_visvalingam = true;
117
+ }
118
+ if (ioptions[COMPRESS_VISVALINGAM_TOLERANCE].count() > 0)
119
+ { this->options.compress_visvalingam = true;
120
+ for (option::Option* opt = ioptions[COMPRESS_VISVALINGAM_TOLERANCE]; opt; opt = opt->next())
121
+ { std::string opts = opt->arg;
122
+ this->options.compress_visvalingam_tolerance = strtof(opt->arg, 0);
123
+ break;
124
+ }
125
+ }
126
+ /*std::cout << "-----------" << std::endl;
127
+ std::cout << "versus" << this->options.versus << std::endl;
128
+ std::cout << "uniq" << this->options.compress_uniq << std::endl;
129
+ std::cout << "linear" << this->options.compress_linear << std::endl;
130
+ std::cout << "visvalingam" << this->options.compress_visvalingam << std::endl;
131
+ std::cout << this->options.compress_visvalingam_tolerance << std::endl;
132
+ std::cout << "-----------" << std::endl;*/
133
+ }
134
+
135
+ void PolygonFinder::start_timer() {
136
+ timer_start = std::clock();
137
+ }
138
+
139
+ double PolygonFinder::end_timer() {
140
+ std::clock_t c_end = std::clock();
141
+ return 1000.0 * (c_end - timer_start) / CLOCKS_PER_SEC;
142
+ }
143
+
144
+ PolygonFinder::~PolygonFinder() {
145
+ }
146
+
147
+ void PolygonFinder::scan() {
148
+ char last_color = 0, color = 0;
149
+ int min_x = 0;
150
+ int max_x = 0;
151
+ bool match;
152
+ bool matching = false;
153
+
154
+ for (int y = 0; y < this->source_bitmap->h(); y++)
155
+ { for (int x = 0; x < this->source_bitmap->w(); x++)
156
+ { color = this->source_bitmap->value_at(x, y);
157
+ match = this->source_bitmap->pixel_match(x, y, this->matcher);
158
+ if (match && matching == false)
159
+ { min_x = x;
160
+ last_color = color;
161
+ matching = true;
162
+ if (x == (this->source_bitmap->w() - 1) )
163
+ { max_x = x;
164
+ this->node_cluster->add_node(new Node(min_x, max_x, y, last_color));
165
+ matching = false;
166
+ }
167
+ } else {
168
+ if (!match && matching == true)
169
+ { max_x = x - 1;
170
+ this->node_cluster->add_node(new Node(min_x, max_x, y, last_color));
171
+ matching = false;
172
+ } else {
173
+ if (x == (this->source_bitmap->w()-1) && matching == true)
174
+ { max_x = x;
175
+ this->node_cluster->add_node(new Node(min_x, max_x, y, last_color));
176
+ matching = false;
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ }
183
+
184
+ ProcessResult* PolygonFinder::process_info() {
185
+ ProcessResult *pr = new ProcessResult();
186
+ pr->groups = this->node_cluster->sequences->size();
187
+ pr->polygons = this->node_cluster->polygons;
188
+ pr->benchmarks = this->reports;
189
+ pr->treemap = this->node_cluster->treemap;
190
+
191
+ if (typeid(*this->source_bitmap) == typeid(Bitmap))
192
+ { std::string sequence;
193
+ int n = 0;
194
+ for (std::list<std::list<Node*>*>::iterator list = this->node_cluster->sequences->begin(); list != this->node_cluster->sequences->end(); ++list, n++)
195
+ { std::string seq;
196
+ for (std::list<Node*>::iterator node = (*list)->begin(); node != (*list)->end(); ++node)
197
+ { seq += (*node)->name;
198
+ }
199
+ if (n != 0) sequence += '-';
200
+ sequence += seq;
201
+ }
202
+ pr->named_sequence = sequence;
203
+ }
204
+ else pr->named_sequence = "";
205
+ return(pr);
206
+ }
@@ -0,0 +1,69 @@
1
+ /*
2
+ * PolygonFinder.h
3
+ *
4
+ * Created on: 24 nov 2018
5
+ * Author: ema
6
+ * Copyright 2025 Emanuele Cesaroni
7
+ */
8
+
9
+ #ifndef POLYGONFINDER_H_
10
+ #define POLYGONFINDER_H_
11
+
12
+ #include <list>
13
+ #include <vector>
14
+ #include "Node.h"
15
+ #include <ctime>
16
+ #include <string>
17
+ #include <map>
18
+
19
+ class Bitmap;
20
+ class Matcher;
21
+ class RGBMatcher;
22
+ class NodeCluster;
23
+ class Node;
24
+ struct Point;
25
+
26
+ struct ShapeLine {
27
+ int start_x, end_x, y;
28
+ };
29
+
30
+ struct pf_Options {
31
+ int versus = Node::A;
32
+ bool treemap = false;
33
+ bool compress_uniq = false;
34
+ bool compress_linear = false;
35
+ bool compress_visvalingam = false;
36
+ float compress_visvalingam_tolerance = 10.0;
37
+ };
38
+ struct ProcessResult {
39
+ int groups;
40
+ std::map<std::string, double> benchmarks;
41
+ std::list<std::map<std::string, std::list<std::list<Point*>*>>> polygons;
42
+ std::string named_sequence;
43
+ std::list<int*> treemap;
44
+ };
45
+
46
+ class PolygonFinder {
47
+ private:
48
+ Bitmap *source_bitmap;
49
+ Matcher *matcher;
50
+ NodeCluster *node_cluster;
51
+ pf_Options options;
52
+ std::map<std::string, double> reports;
53
+ void start_timer();
54
+ double end_timer();
55
+ void scan();
56
+ std::clock_t timer_start, timer_end;
57
+ void sanitize_options(std::vector<std::string> *incoming_options);
58
+
59
+ public:
60
+ PolygonFinder(Bitmap *bitmap, Matcher *matcher, Bitmap *test_bitmap, std::vector<std::string> *options = nullptr);
61
+ ProcessResult* process_info();
62
+ std::list<ShapeLine*> *get_shapelines();
63
+ virtual ~PolygonFinder();
64
+ };
65
+
66
+
67
+
68
+
69
+ #endif /* POLYGONFINDER_H_ */