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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +84 -0
- data/LICENSE.md +9 -0
- data/README.md +118 -0
- data/Rakefile +19 -0
- data/contrek.gemspec +23 -0
- data/contrek.png +0 -0
- data/ext/cpp_polygon_finder/PolygonFinder/.cproject +136 -0
- data/ext/cpp_polygon_finder/PolygonFinder/.project +27 -0
- data/ext/cpp_polygon_finder/PolygonFinder/.settings/org.eclipse.ltk.core.refactoring.prefs +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/images/labyrinth.png +0 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Main.cpp +41 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +69 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +19 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.cpp +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.h +32 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +656 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h +42 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.cpp +48 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.h +32 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +30 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h +26 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/X_picopng.cpp +576 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +120 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +40 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +36 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +30 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +111 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +80 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +325 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +59 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +206 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +69 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/optionparser.h +2858 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.cpp +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBMatcher.cpp +20 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBMatcher.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.cpp +20 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.cpp +20 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.h +21 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.cpp +40 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.cpp +19 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.h +25 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.cpp +30 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.h +21 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.cpp +50 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +121 -0
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +260 -0
- data/ext/cpp_polygon_finder/extconf.rb +2 -0
- data/lib/contrek/bitmaps/bitmap.rb +21 -0
- data/lib/contrek/bitmaps/chunky_bitmap.rb +33 -0
- data/lib/contrek/bitmaps/painting.rb +40 -0
- data/lib/contrek/bitmaps/png_bitmap.rb +62 -0
- data/lib/contrek/bitmaps/rgb_color.rb +25 -0
- data/lib/contrek/finder/list.rb +132 -0
- data/lib/contrek/finder/list_entry.rb +11 -0
- data/lib/contrek/finder/listable.rb +8 -0
- data/lib/contrek/finder/lists.rb +25 -0
- data/lib/contrek/finder/node.rb +126 -0
- data/lib/contrek/finder/node_cluster.rb +294 -0
- data/lib/contrek/finder/polygon_finder.rb +121 -0
- data/lib/contrek/map/mercator_projection.rb +76 -0
- data/lib/contrek/matchers/matcher.rb +20 -0
- data/lib/contrek/matchers/matcher_hsb.rb +24 -0
- data/lib/contrek/matchers/value_not_matcher.rb +9 -0
- data/lib/contrek/reducers/linear_reducer.rb +25 -0
- data/lib/contrek/reducers/reducer.rb +14 -0
- data/lib/contrek/reducers/uniq_reducer.rb +9 -0
- data/lib/contrek/reducers/visvalingam_reducer.rb +139 -0
- data/lib/contrek/version.rb +3 -0
- data/lib/contrek.rb +58 -0
- 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_ */
|