contrek 1.1.4 → 1.1.5
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 +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +20 -2
- data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +3 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +71 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +12 -48
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h +2 -11
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp +64 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.h +37 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +2 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +12 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +10 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +8 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.cpp +22 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.h +19 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp +46 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.h +24 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queue.h +5 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp +64 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.h +24 -0
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +91 -0
- data/lib/contrek/bitmaps/{custom_bitmap.rb → raw_bitmap.rb} +1 -1
- data/lib/contrek/cpp/cpp_concurrent_horizontal_merger.rb +9 -0
- data/lib/contrek/cpp/cpp_concurrent_merger.rb +9 -0
- data/lib/contrek/cpp/cpp_concurrent_vertical_merger.rb +9 -0
- data/lib/contrek/finder/concurrent/finder.rb +8 -5
- data/lib/contrek/finder/concurrent/horizontal_merger.rb +10 -0
- data/lib/contrek/finder/concurrent/merger.rb +52 -0
- data/lib/contrek/finder/concurrent/tile.rb +0 -2
- data/lib/contrek/finder/concurrent/vertical_merger.rb +44 -0
- data/lib/contrek/finder/polygon_finder.rb +2 -0
- data/lib/contrek/reducers/linear_reducer.rb +1 -1
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +7 -1
- metadata +17 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 22d05e676f5c4a0f22f02ec2e915257bf1f5da224d468cb0e2f46fc397360242
|
|
4
|
+
data.tar.gz: '0997b63d2839cc3ba613884eff2e3a565d96502e4606db0bb72d2aee228e514d'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 57bf5e08937ea8fb4cee39e383a8f760e3a36714643c583408af6d02c7fbb84515af8d3089c753319677b8d5223c7a6a07f505c4356e21cd10570abbec358210
|
|
7
|
+
data.tar.gz: 0ec4babf59251515b05857a459adfd7365b930feaf58b17ca2215ab4b534abe3ac41ae45e7643270ec8acba4c699fbcd311b12eb3ddab6789e5dd1b7275ad220
|
data/CHANGELOG.md
CHANGED
|
@@ -58,3 +58,8 @@ All notable changes to this project will be documented in this file.
|
|
|
58
58
|
### Changed
|
|
59
59
|
- Fixed an infinite loop bug in multithreading during inner sequence joining in Omnidirectional mode.
|
|
60
60
|
- Optimized C++ and Ruby algorithms for initial spatial tangential sequence determination.
|
|
61
|
+
|
|
62
|
+
## [1.1.5] - 2026-03-08
|
|
63
|
+
### Changed
|
|
64
|
+
- **RawBitmap Integration (Ruby/C++):** Introduced a native buffer class for direct contour extraction, bypassing PNG encoding to significantly reduce latency and memory overhead.
|
|
65
|
+
- **Tiled Polygon Merger:** Added a spatial merger for `Finder` outputs to stitch polygons from discrete sub-areas (requiring only a 1px overlap). This multi-phase workflow supports coordinate translation and eliminates monolithic buffer requirements, optimizing the peak memory footprint.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Contrek
|
|
2
|
-
Contrek is a Ruby gem powered by a <u>standalone C++17 core library</u> for fast contour tracing and edge detection in PNG images. It employs a **topological approach** to extract polygonal contours, representing shapes as a connected graph of shared endpoints. This ensures perfect adjacency and structural integrity for shape analysis and raster-to-vector workflows, such as PNG to SVG conversion, managed via libspng (0.7.4) with multithreading support.
|
|
2
|
+
Contrek is a Ruby gem powered by a <u>standalone C++17 core library</u> for fast contour tracing and edge detection in PNG images and raw memory streams. It employs a **topological approach** to extract polygonal contours, representing shapes as a connected graph of shared endpoints. This ensures perfect adjacency and structural integrity for shape analysis and raster-to-vector workflows, such as PNG to SVG conversion, managed via libspng (0.7.4) with multithreading support.
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
## About Contrek library
|
|
6
6
|
|
|
7
|
-
Contrek (**con**tour **trek**king) simply scans your png bitmap and returns shape contour as close polygonal lines, both for the external and internal sides. It can compute the nesting level of the polygons found with a tree structure. It supports various levels and modes of compression and approximation of the found coordinates. It is capable of multithreaded processing, splitting the image into vertical strips and recombining the coordinates in pairs.
|
|
7
|
+
Contrek (**con**tour **trek**king) simply scans your png/raw bitmap and returns shape contour as close polygonal lines, both for the external and internal sides. It can compute the nesting level of the polygons found with a tree structure. It supports various levels and modes of compression and approximation of the found coordinates. It is capable of multithreaded processing, splitting the image into vertical strips and recombining the coordinates in pairs.
|
|
8
8
|
|
|
9
9
|
In the following image all the non-white pixels have been examined and the result is the red polygon for the outer contour and the green one for the inner one
|
|
10
10
|

|
|
@@ -86,6 +86,24 @@ You can also read base64 png images
|
|
|
86
86
|
png_bitmap = CPPRemotePngBitMap.new("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==")
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
You can process from a raw stream
|
|
90
|
+
```ruby
|
|
91
|
+
raw_bitmap = CPPRawBitMap.new
|
|
92
|
+
# set 20 as width, 30 as height, 4 as bytes per pixel and clears the content (true)
|
|
93
|
+
raw_bitmap.define(20,30,4,true)
|
|
94
|
+
# draws a polygon
|
|
95
|
+
4.upto(5) do |y|
|
|
96
|
+
5.upto(8) do |x|
|
|
97
|
+
raw_bitmap.draw_pixel(x, y, 1, 0, 0, 0);
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
not_matcher = CPPRGBNotMatcher.new(raw_bitmap.rgb_value_at(0, 0))
|
|
101
|
+
result = CPPPolygonFinder.new(raw_bitmap, not_matcher, nil,{compress: {uniq: true, linear: true}}).process_info
|
|
102
|
+
puts result.points.inspect
|
|
103
|
+
=>
|
|
104
|
+
[{:outer=>[{:x=>5, :y=>4}, {:x=>5, :y=>5}, {:x=>8, :y=>5}, {:x=>8, :y=>4}], :inner=>[]}]
|
|
105
|
+
```
|
|
106
|
+
|
|
89
107
|
Multithreaded contour processing is supported. However, on Ruby MRI (the standard Ruby implementation, at least up to 3.x), the Global Interpreter Lock (GIL) prevents more than one thread from executing Ruby code simultaneously. As a consequence, execution remains effectively serialized even on multicore systems, unless the gem is used under JRuby or TruffleRuby (not tested).
|
|
90
108
|
|
|
91
109
|
```ruby
|
|
@@ -21,7 +21,9 @@ void run_test() {
|
|
|
21
21
|
// test_suite.test_c();
|
|
22
22
|
// test_suite.test_d();
|
|
23
23
|
// test_suite.test_e();
|
|
24
|
-
test_suite.test_f();
|
|
24
|
+
// test_suite.test_f();
|
|
25
|
+
// test_suite.test_g();
|
|
26
|
+
// test_suite.test_h();
|
|
25
27
|
std::cout << "compute time =" << cpu_timer.stop() << std::endl;
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
#include "polygon/finder/concurrent/ClippedPolygonFinder.h"
|
|
19
19
|
#include "polygon/bitmaps/Bitmap.h"
|
|
20
20
|
#include "polygon/bitmaps/FastPngBitmap.h"
|
|
21
|
+
#include "polygon/bitmaps/RawBitmap.h"
|
|
21
22
|
#include "polygon/bitmaps/RemoteFastPngBitmap.h"
|
|
22
23
|
#include "polygon/matchers/Matcher.h"
|
|
23
24
|
#include "polygon/matchers/RGBMatcher.h"
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
#include "polygon/matchers/ValueNotMatcher.h"
|
|
26
27
|
#include "polygon/finder/optionparser.h"
|
|
27
28
|
#include "polygon/finder/concurrent/Finder.h"
|
|
29
|
+
#include "polygon/finder/concurrent/HorizontalMerger.h"
|
|
28
30
|
#include "polygon/finder/concurrent/Sequence.h"
|
|
29
31
|
#include "polygon/finder/concurrent/Position.h"
|
|
30
32
|
#include "polygon/finder/Polygon.h"
|
|
@@ -141,7 +143,7 @@ void Tests::test_d()
|
|
|
141
143
|
FastPngBitmap png_bitmap("../images/sample_10240x10240.png");
|
|
142
144
|
// FastPngBitmap png_bitmap("images/labyrinth.png");
|
|
143
145
|
std::cout << "image_w=" << png_bitmap.w() << " image_h=" << png_bitmap.h() << std::endl;
|
|
144
|
-
std::cout << "
|
|
146
|
+
std::cout << "image reading time =" << cpu_timer.stop() << std::endl;
|
|
145
147
|
|
|
146
148
|
int color = png_bitmap.value_at(0, 0);
|
|
147
149
|
std::cout << "color =" << color << std::endl;
|
|
@@ -169,7 +171,7 @@ void Tests::test_e()
|
|
|
169
171
|
Finder pl(2, &png_bitmap, ¬_matcher, &arguments);
|
|
170
172
|
ProcessResult *o = pl.process_info();
|
|
171
173
|
o->print_info();
|
|
172
|
-
std::cout << "polygons =" << o->groups << std::endl;
|
|
174
|
+
std::cout << "polygons = " << o->groups << std::endl;
|
|
173
175
|
delete o;
|
|
174
176
|
}
|
|
175
177
|
|
|
@@ -184,3 +186,70 @@ void Tests::test_f()
|
|
|
184
186
|
std::cout << "image_w=" << bitmap.w() << " image_h=" << bitmap.h() << std::endl;
|
|
185
187
|
std::cout << "load_error=" << bitmap.error() << std::endl;
|
|
186
188
|
}
|
|
189
|
+
|
|
190
|
+
void Tests::test_g()
|
|
191
|
+
{ RawBitmap raw_bitmap;
|
|
192
|
+
raw_bitmap.define(50, 50, 4);
|
|
193
|
+
|
|
194
|
+
// draw a polygon start_x = 5, start_y = 4, end_x = 8, end_y = 5
|
|
195
|
+
for (int y : {4, 5}) {
|
|
196
|
+
for (int x = 5; x <= 8; ++x) {
|
|
197
|
+
raw_bitmap.draw_pixel(x, y, 1, 0, 0);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
int color = raw_bitmap.rgb_value_at(0, 0);
|
|
202
|
+
std::cout << "color = " << color << std::endl;
|
|
203
|
+
RGBNotMatcher not_matcher(color);
|
|
204
|
+
|
|
205
|
+
std::vector<std::string> arguments = {"--versus=a", "--compress_uniq", "--number_of_tiles=2"};
|
|
206
|
+
Finder pl(2, &raw_bitmap, ¬_matcher, &arguments);
|
|
207
|
+
ProcessResult *o = pl.process_info();
|
|
208
|
+
// o->print_info();
|
|
209
|
+
// o->print_polygons();
|
|
210
|
+
std::cout << "polygons = " << o->groups << std::endl;
|
|
211
|
+
delete o;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
void Tests::test_h()
|
|
215
|
+
{ std::string left =
|
|
216
|
+
"0000000000" \
|
|
217
|
+
"0000000000" \
|
|
218
|
+
"00 " \
|
|
219
|
+
"00 " \
|
|
220
|
+
"00 " \
|
|
221
|
+
"00 " \
|
|
222
|
+
"00 " \
|
|
223
|
+
"0000000000" \
|
|
224
|
+
"0000000000";
|
|
225
|
+
std::vector<std::string> arguments = {"--versus=a", "--compress_uniq"};
|
|
226
|
+
ValueNotMatcher matcher(' ');
|
|
227
|
+
Bitmap b_left(left, 10);
|
|
228
|
+
PolygonFinder pl_left(&b_left, &matcher, nullptr, &arguments);
|
|
229
|
+
ProcessResult *left_result = pl_left.process_info();
|
|
230
|
+
|
|
231
|
+
std::string right =
|
|
232
|
+
"0000000000" \
|
|
233
|
+
"0000000000" \
|
|
234
|
+
" 0000" \
|
|
235
|
+
" 0000" \
|
|
236
|
+
" 0000" \
|
|
237
|
+
" 0000" \
|
|
238
|
+
" 0000" \
|
|
239
|
+
"0000000000" \
|
|
240
|
+
"0000000000";
|
|
241
|
+
Bitmap b_right(right, 10);
|
|
242
|
+
PolygonFinder pl_right(&b_right, &matcher, nullptr, &arguments);
|
|
243
|
+
ProcessResult *right_result = pl_right.process_info();
|
|
244
|
+
|
|
245
|
+
std::vector<std::string> merger_arguments = {};
|
|
246
|
+
HorizontalMerger hmerger(1, &arguments);
|
|
247
|
+
hmerger.add_tile(*left_result);
|
|
248
|
+
hmerger.add_tile(*right_result);
|
|
249
|
+
ProcessResult *merged_result = hmerger.process_info();
|
|
250
|
+
merged_result->print_polygons();
|
|
251
|
+
|
|
252
|
+
delete merged_result;
|
|
253
|
+
delete left_result;
|
|
254
|
+
delete right_result;
|
|
255
|
+
}
|
|
@@ -20,74 +20,38 @@
|
|
|
20
20
|
#include "FastPngBitmap.h"
|
|
21
21
|
#include "spng.h"
|
|
22
22
|
|
|
23
|
-
FastPngBitmap::FastPngBitmap(std::string filename) :
|
|
24
|
-
if (filename.length() > 0)
|
|
25
|
-
|
|
26
|
-
if (file.is_open())
|
|
27
|
-
|
|
23
|
+
FastPngBitmap::FastPngBitmap(std::string filename) : RawBitmap() {
|
|
24
|
+
if (filename.length() > 0) {
|
|
25
|
+
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
|
26
|
+
if (file.is_open()) {
|
|
27
|
+
std::streamsize size = file.tellg();
|
|
28
28
|
file.seekg(0, std::ios::beg);
|
|
29
29
|
std::vector<unsigned char> file_buffer(size);
|
|
30
|
-
if (!file.read(reinterpret_cast<char*>(file_buffer.data()), size))
|
|
31
|
-
|
|
30
|
+
if (!file.read(reinterpret_cast<char*>(file_buffer.data()), size)) {
|
|
31
|
+
this->png_error = -1;
|
|
32
32
|
} else {
|
|
33
33
|
spng_ctx *ctx = spng_ctx_new(0);
|
|
34
34
|
spng_set_png_buffer(ctx, file_buffer.data(), file_buffer.size());
|
|
35
35
|
struct spng_ihdr ihdr;
|
|
36
36
|
spng_get_ihdr(ctx, &ihdr);
|
|
37
|
-
this->width = ihdr.width;
|
|
38
|
-
this->height = ihdr.height;
|
|
39
37
|
size_t out_size;
|
|
40
38
|
spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);
|
|
41
|
-
this->
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
this->define(ihdr.width, ihdr.height, 4, false);
|
|
40
|
+
unsigned char* raw_ptr = this->image.get();
|
|
41
|
+
madvise(raw_ptr, out_size, MADV_HUGEPAGE);
|
|
42
|
+
int error = spng_decode_image(ctx, raw_ptr, out_size, SPNG_FMT_RGBA8, SPNG_DECODE_TRNS);
|
|
44
43
|
spng_ctx_free(ctx);
|
|
45
44
|
this->png_error = error;
|
|
46
45
|
}
|
|
47
46
|
} else {
|
|
48
|
-
throw std::runtime_error("Unable open file: " + filename);
|
|
47
|
+
throw std::runtime_error("Unable to open file: " + filename);
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
bool FastPngBitmap::pixel_match(int x, int y, Matcher *matcher)
|
|
54
|
-
{ int32_t index = ((y * width) + x) * 4;
|
|
55
|
-
unsigned int color;
|
|
56
|
-
unsigned char *red = &image[index];
|
|
57
|
-
std::memcpy(&color, red, 3);
|
|
58
|
-
if (typeid(*matcher) == typeid(RGBMatcher)) return((reinterpret_cast<RGBMatcher*>(matcher))->match(color));
|
|
59
|
-
if (typeid(*matcher) == typeid(RGBNotMatcher)) return((reinterpret_cast<RGBNotMatcher*>(matcher))->match(color));
|
|
60
|
-
return(false);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
int FastPngBitmap::w() {
|
|
64
|
-
return this->width;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
int FastPngBitmap::h() {
|
|
68
|
-
return this->height;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
52
|
int FastPngBitmap::error() {
|
|
72
53
|
return this->png_error;
|
|
73
54
|
}
|
|
74
|
-
char FastPngBitmap::value_at(int x, int y) {
|
|
75
|
-
return(0);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// source image format RGBA => returning uint ABGR
|
|
79
|
-
unsigned int FastPngBitmap::rgb_value_at(int x, int y) {
|
|
80
|
-
uint32_t index = (uint32_t(y) * width + x) * 4;
|
|
81
|
-
return *reinterpret_cast<const uint32_t*>(&image[index]);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const unsigned char* FastPngBitmap::get_row_ptr(int y) const {
|
|
85
|
-
return image.data() + (static_cast<size_t>(y) * static_cast<size_t>(width) * 4);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
int FastPngBitmap::get_bytes_per_pixel() const {
|
|
89
|
-
return 4; // RGBA
|
|
90
|
-
}
|
|
91
55
|
|
|
92
56
|
void FastPngBitmap::loadFile(std::vector<unsigned char>& buffer, const std::string& filename) // designed for loading files from hard disk in an std::vector
|
|
93
57
|
{ std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
|
|
@@ -11,29 +11,20 @@
|
|
|
11
11
|
#include <vector>
|
|
12
12
|
#include <cstddef>
|
|
13
13
|
#include <string>
|
|
14
|
-
#include "
|
|
14
|
+
#include "RawBitmap.h"
|
|
15
15
|
|
|
16
16
|
class RGBMatcher;
|
|
17
17
|
|
|
18
18
|
static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
19
19
|
|
|
20
|
-
class FastPngBitmap : public
|
|
20
|
+
class FastPngBitmap : public RawBitmap {
|
|
21
21
|
public:
|
|
22
22
|
explicit FastPngBitmap(std::string filename);
|
|
23
|
-
bool pixel_match(int x, int y, Matcher *matcher);
|
|
24
|
-
int h();
|
|
25
|
-
int w();
|
|
26
23
|
virtual int error();
|
|
27
|
-
char value_at(int x, int y);
|
|
28
|
-
unsigned int rgb_value_at(int x, int y);
|
|
29
|
-
const unsigned char* get_row_ptr(int y) const;
|
|
30
|
-
int get_bytes_per_pixel() const;
|
|
31
24
|
|
|
32
25
|
protected:
|
|
33
26
|
std::vector<unsigned char> buffer;
|
|
34
27
|
std::vector<unsigned char> base64_decode(std::string &encoded_string);
|
|
35
|
-
std::vector<unsigned char> image;
|
|
36
|
-
unsigned int width, height;
|
|
37
28
|
int png_error;
|
|
38
29
|
int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
|
|
39
30
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* RawBitmap.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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include <memory>
|
|
11
|
+
#include "RawBitmap.h"
|
|
12
|
+
|
|
13
|
+
RawBitmap::RawBitmap() : Bitmap("", 0),
|
|
14
|
+
width(0),
|
|
15
|
+
height(0) {
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
int RawBitmap::w() {
|
|
19
|
+
return this->width;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
int RawBitmap::h() {
|
|
23
|
+
return this->height;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
char RawBitmap::value_at(int x, int y) {
|
|
27
|
+
return(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const unsigned char* RawBitmap::get_row_ptr(int y) const {
|
|
31
|
+
return image.get() + (static_cast<size_t>(y) * static_cast<size_t>(width) * 4);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
int RawBitmap::get_bytes_per_pixel() const {
|
|
35
|
+
return this->bpp;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// source image format RGBA => returning uint ABGR
|
|
39
|
+
unsigned int RawBitmap::rgb_value_at(int x, int y) {
|
|
40
|
+
uint32_t index = (static_cast<uint32_t>(y) * width + x) * 4;
|
|
41
|
+
return *reinterpret_cast<const uint32_t*>(&image[index]);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void RawBitmap::draw_pixel(int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
|
|
45
|
+
if (x >= width || y >= height) return;
|
|
46
|
+
unsigned char* p = &image[(static_cast<size_t>(y) * width + x) * bpp];
|
|
47
|
+
p[0] = r;
|
|
48
|
+
if (bpp > 1) p[1] = g;
|
|
49
|
+
if (bpp > 2) p[2] = b;
|
|
50
|
+
if (bpp > 3) p[3] = a;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
uint32_t RawBitmap::define(uint width, uint height, int bytes_per_pixel, bool clear)
|
|
54
|
+
{ this->width = width;
|
|
55
|
+
this->height = height;
|
|
56
|
+
this->bpp = bytes_per_pixel;
|
|
57
|
+
uint32_t dimension = (static_cast<uint32_t>(width) * static_cast<uint32_t>(height)) * bytes_per_pixel;
|
|
58
|
+
this->image = std::make_unique<unsigned char[]>(dimension);
|
|
59
|
+
if (clear) {
|
|
60
|
+
std::fill(image.get(), image.get() + dimension, 0);
|
|
61
|
+
}
|
|
62
|
+
return dimension;
|
|
63
|
+
}
|
|
64
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* RawBitmap.h
|
|
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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#include <vector>
|
|
12
|
+
#include <memory>
|
|
13
|
+
#include <cstddef>
|
|
14
|
+
#include <string>
|
|
15
|
+
#include "Bitmap.h"
|
|
16
|
+
|
|
17
|
+
class RGBMatcher;
|
|
18
|
+
|
|
19
|
+
class RawBitmap : public Bitmap {
|
|
20
|
+
public:
|
|
21
|
+
explicit RawBitmap();
|
|
22
|
+
int h();
|
|
23
|
+
int w();
|
|
24
|
+
char value_at(int x, int y);
|
|
25
|
+
unsigned int rgb_value_at(int x, int y);
|
|
26
|
+
const unsigned char* get_row_ptr(int y) const;
|
|
27
|
+
int get_bytes_per_pixel() const;
|
|
28
|
+
uint32_t define(uint width, uint height, int bytes_per_pixel, bool clear = false);
|
|
29
|
+
void draw_pixel(int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255);
|
|
30
|
+
|
|
31
|
+
protected:
|
|
32
|
+
std::unique_ptr<unsigned char[]> image;
|
|
33
|
+
unsigned int width, height;
|
|
34
|
+
|
|
35
|
+
private:
|
|
36
|
+
int bpp;
|
|
37
|
+
};
|
|
@@ -30,12 +30,10 @@ RemoteFastPngBitmap::RemoteFastPngBitmap(std::string *dataurl) : FastPngBitmap("
|
|
|
30
30
|
struct spng_ihdr ihdr;
|
|
31
31
|
int error = spng_get_ihdr(ctx, &ihdr);
|
|
32
32
|
if (!error) {
|
|
33
|
-
this->width = ihdr.width;
|
|
34
|
-
this->height = ihdr.height;
|
|
35
33
|
size_t out_size; // RGBA8 dimension
|
|
36
34
|
spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);
|
|
37
|
-
this->
|
|
38
|
-
error = spng_decode_image(ctx, image.
|
|
35
|
+
this->define(ihdr.width, ihdr.height, 4, false);
|
|
36
|
+
error = spng_decode_image(ctx, image.get(), out_size, SPNG_FMT_RGBA8, SPNG_DECODE_TRNS);
|
|
39
37
|
}
|
|
40
38
|
if (error != 0) {
|
|
41
39
|
std::cout << "spng error: " << spng_strerror(error) << std::endl;
|
|
@@ -104,6 +104,8 @@ ProcessResult* PolygonFinder::process_info() {
|
|
|
104
104
|
pr->polygons = std::move(this->node_cluster->polygons);
|
|
105
105
|
pr->benchmarks = std::move(this->reports);
|
|
106
106
|
pr->treemap = this->node_cluster->treemap;
|
|
107
|
+
pr->width = this->source_bitmap->w();
|
|
108
|
+
pr->height = this->source_bitmap->h();
|
|
107
109
|
|
|
108
110
|
if (this->node_cluster->options->named_sequences && typeid(*this->source_bitmap) == typeid(Bitmap))
|
|
109
111
|
{ std::string sequence;
|
|
@@ -50,6 +50,7 @@ struct pf_Options {
|
|
|
50
50
|
};
|
|
51
51
|
struct ProcessResult {
|
|
52
52
|
int groups;
|
|
53
|
+
int width, height;
|
|
53
54
|
std::map<std::string, double> benchmarks;
|
|
54
55
|
std::list<Polygon> polygons;
|
|
55
56
|
std::string named_sequence;
|
|
@@ -77,6 +78,17 @@ struct ProcessResult {
|
|
|
77
78
|
}
|
|
78
79
|
std::cout << std::endl;
|
|
79
80
|
}
|
|
81
|
+
|
|
82
|
+
void translate(int x) {
|
|
83
|
+
for (auto& polygon : polygons) {
|
|
84
|
+
for (Point* p : polygon.outer) p->x += x;
|
|
85
|
+
for (const auto& seq : polygon.inner) {
|
|
86
|
+
for (Point* p : seq) p->x += x;
|
|
87
|
+
}
|
|
88
|
+
polygon.bounds.min_x += x;
|
|
89
|
+
polygon.bounds.max_x += x;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
80
92
|
};
|
|
81
93
|
|
|
82
94
|
class PolygonFinder {
|
|
@@ -27,7 +27,8 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
|
|
|
27
27
|
bitmap(bitmap),
|
|
28
28
|
matcher(matcher),
|
|
29
29
|
input_options(*options),
|
|
30
|
-
maximum_width_(bitmap->w())
|
|
30
|
+
maximum_width_(bitmap->w()),
|
|
31
|
+
height(bitmap->h())
|
|
31
32
|
{ cpu_timer.start();
|
|
32
33
|
if (options != nullptr) FinderUtils::sanitize_options(this->options, options);
|
|
33
34
|
|
|
@@ -67,6 +68,11 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
|
|
|
67
68
|
reports["init"] = cpu_timer.stop();
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
Finder::Finder(int number_of_threads, std::vector<std::string> *options)
|
|
72
|
+
: Poolable(number_of_threads), bitmap(nullptr), matcher(nullptr), input_options(*options), maximum_width_(0) {
|
|
73
|
+
if (options != nullptr) FinderUtils::sanitize_options(this->options, options);
|
|
74
|
+
reports["init"] = 0;
|
|
75
|
+
}
|
|
70
76
|
|
|
71
77
|
void Finder::process_tiles() {
|
|
72
78
|
std::vector<Tile*> arriving_tiles;
|
|
@@ -97,7 +103,7 @@ void Finder::process_tiles() {
|
|
|
97
103
|
end_x = tile->end_x();
|
|
98
104
|
}
|
|
99
105
|
|
|
100
|
-
Cluster *cluster = new Cluster(this, this->
|
|
106
|
+
Cluster *cluster = new Cluster(this, this->height, start_x, end_x);
|
|
101
107
|
|
|
102
108
|
if (twin_tile->start_x() == (tile->end_x() - 1)) {
|
|
103
109
|
cluster->add(tile);
|
|
@@ -137,6 +143,8 @@ ProcessResult* Finder::process_info() {
|
|
|
137
143
|
ProcessResult *pr = new ProcessResult();
|
|
138
144
|
pr->polygons = std::move(this->whole_tile->to_raw_polygons());
|
|
139
145
|
pr->groups = pr->polygons.size();
|
|
146
|
+
pr->width = this->maximum_width_;
|
|
147
|
+
pr->height = this->height;
|
|
140
148
|
FakeCluster fake_cluster(pr->polygons, this->options);
|
|
141
149
|
cpu_timer.start();
|
|
142
150
|
fake_cluster.compress_coords(pr->polygons, this->options);
|
|
@@ -35,19 +35,23 @@ class Finder : public Poolable {
|
|
|
35
35
|
Matcher *matcher;
|
|
36
36
|
pf_Options options;
|
|
37
37
|
std::vector<std::string> input_options;
|
|
38
|
-
int maximum_width_;
|
|
39
|
-
Queue<Tile*> tiles;
|
|
40
38
|
Tile* whole_tile = nullptr;
|
|
41
|
-
void process_tiles();
|
|
42
39
|
std::queue<ClippedPolygonFinder*> finders;
|
|
43
40
|
std::mutex finders_mutex;
|
|
44
41
|
std::map<std::string, double> reports;
|
|
45
42
|
CpuTimer cpu_timer;
|
|
46
43
|
|
|
44
|
+
protected:
|
|
45
|
+
Queue<Tile*> tiles;
|
|
46
|
+
int maximum_width_;
|
|
47
|
+
int height = 0;
|
|
48
|
+
void process_tiles();
|
|
49
|
+
|
|
47
50
|
public:
|
|
48
51
|
using Poolable::Poolable;
|
|
49
52
|
Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vector<std::string> *options);
|
|
53
|
+
Finder(int number_of_threads, std::vector<std::string> *options);
|
|
50
54
|
virtual ~Finder();
|
|
51
55
|
int maximum_width() const { return maximum_width_; }
|
|
52
|
-
ProcessResult* process_info();
|
|
56
|
+
virtual ProcessResult* process_info();
|
|
53
57
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* HorizontalMerger.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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include <iostream>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include "HorizontalMerger.h"
|
|
14
|
+
|
|
15
|
+
HorizontalMerger::HorizontalMerger(int number_of_threads, std::vector<std::string> *options)
|
|
16
|
+
: Merger(number_of_threads, options) {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void HorizontalMerger::add_tile(ProcessResult& result)
|
|
20
|
+
{ translate(result, this->current_x);
|
|
21
|
+
Merger::add_tile(result);
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* HorizontalMerger.h
|
|
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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include "Merger.h"
|
|
14
|
+
|
|
15
|
+
class HorizontalMerger : public Merger {
|
|
16
|
+
public:
|
|
17
|
+
HorizontalMerger(int number_of_threads, std::vector<std::string> *options);
|
|
18
|
+
void add_tile(ProcessResult& result) override;
|
|
19
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Merger.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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include <iostream>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include "Merger.h"
|
|
14
|
+
|
|
15
|
+
Merger::Merger(int number_of_threads, std::vector<std::string> *options)
|
|
16
|
+
: Finder(number_of_threads, options) {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void Merger::add_tile(ProcessResult& result)
|
|
20
|
+
{ if (this->height == 0) {
|
|
21
|
+
this->height = result.height;
|
|
22
|
+
}
|
|
23
|
+
int end_x = this->current_x + result.width;
|
|
24
|
+
Tile* tile = new Tile(this, this->current_x, end_x, std::to_string(tiles.size()), Benchmarks {0, 0});
|
|
25
|
+
tile->assign_raw_polygons(result.polygons);
|
|
26
|
+
tiles.queue_push(tile);
|
|
27
|
+
|
|
28
|
+
this->maximum_width_ = end_x;
|
|
29
|
+
this->current_x = end_x - 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
ProcessResult* Merger::process_info() {
|
|
33
|
+
this->process_tiles();
|
|
34
|
+
return(Finder::process_info());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
void Merger::translate(ProcessResult& result, int offset) {
|
|
38
|
+
for (auto& polygon : result.polygons) {
|
|
39
|
+
for (Point* p : polygon.outer) p->x += offset;
|
|
40
|
+
for (const auto& seq : polygon.inner) {
|
|
41
|
+
for (Point* p : seq) p->x += offset;
|
|
42
|
+
}
|
|
43
|
+
polygon.bounds.min_x += offset;
|
|
44
|
+
polygon.bounds.max_x += offset;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Merger.h
|
|
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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include "Finder.h"
|
|
14
|
+
|
|
15
|
+
class Merger : public Finder {
|
|
16
|
+
public:
|
|
17
|
+
Merger(int number_of_threads, std::vector<std::string> *options);
|
|
18
|
+
virtual void add_tile(ProcessResult& result);
|
|
19
|
+
ProcessResult* process_info() override;
|
|
20
|
+
|
|
21
|
+
protected:
|
|
22
|
+
void translate(ProcessResult& result, int offset);
|
|
23
|
+
int current_x = 0;
|
|
24
|
+
};
|
|
@@ -20,6 +20,7 @@ class Queue {
|
|
|
20
20
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
21
21
|
queue_.push(value);
|
|
22
22
|
cond_.notify_one();
|
|
23
|
+
this->size_++;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
T queue_pop() {
|
|
@@ -27,10 +28,14 @@ class Queue {
|
|
|
27
28
|
cond_.wait(lock, [this]{ return !queue_.empty(); });
|
|
28
29
|
T value = queue_.front();
|
|
29
30
|
queue_.pop();
|
|
31
|
+
this->size_--;
|
|
30
32
|
return value;
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
int size() { return this->size_; }
|
|
36
|
+
|
|
33
37
|
private:
|
|
38
|
+
int size_ = 0;
|
|
34
39
|
std::queue<T> queue_;
|
|
35
40
|
std::mutex mutex_;
|
|
36
41
|
std::condition_variable cond_;
|
|
@@ -30,7 +30,6 @@ class Tile {
|
|
|
30
30
|
std::list<Shape*> shapes_;
|
|
31
31
|
std::list<Shape*> boundary_shapes_;
|
|
32
32
|
bool boundary_shapes_initialized_ = false;
|
|
33
|
-
void assign_raw_polygons(const std::list<Polygon>& raw_polylines);
|
|
34
33
|
|
|
35
34
|
public:
|
|
36
35
|
Tile(Finder *finder, int start_x, int end_x, std::string name, const Benchmarks& b);
|
|
@@ -52,6 +51,7 @@ class Tile {
|
|
|
52
51
|
void info();
|
|
53
52
|
bool tg_border(const Point& coord);
|
|
54
53
|
void assign_shapes(std::list<Shape*>& shapes);
|
|
54
|
+
void assign_raw_polygons(const std::list<Polygon>& raw_polylines);
|
|
55
55
|
std::list<Polygon> to_raw_polygons();
|
|
56
56
|
Benchmarks benchmarks;
|
|
57
57
|
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* VerticalMerger.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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include <iostream>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include <algorithm>
|
|
14
|
+
#include <utility>
|
|
15
|
+
#include "VerticalMerger.h"
|
|
16
|
+
|
|
17
|
+
VerticalMerger::VerticalMerger(int number_of_threads, std::vector<std::string> *options)
|
|
18
|
+
: Merger(number_of_threads, options) {
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
void VerticalMerger::add_tile(ProcessResult& result)
|
|
22
|
+
{ transpose(result);
|
|
23
|
+
if (this->tiles.size() > 0) {
|
|
24
|
+
translate(result, this->current_x);
|
|
25
|
+
adjust(result);
|
|
26
|
+
}
|
|
27
|
+
Merger::add_tile(result);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
ProcessResult* VerticalMerger::process_info() {
|
|
31
|
+
ProcessResult* result = Merger::process_info();
|
|
32
|
+
transpose(*result);
|
|
33
|
+
return(result);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
void VerticalMerger::transpose(ProcessResult& result) {
|
|
37
|
+
std::swap(result.width, result.height);
|
|
38
|
+
|
|
39
|
+
for (auto& polygon : result.polygons) {
|
|
40
|
+
for (Point* p : polygon.outer) {
|
|
41
|
+
if (p) std::swap(p->x, p->y);
|
|
42
|
+
}
|
|
43
|
+
for (auto& sequence : polygon.inner) {
|
|
44
|
+
for (Point* p : sequence) {
|
|
45
|
+
if (p) std::swap(p->x, p->y);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
std::swap(polygon.bounds.min_x, polygon.bounds.min_y);
|
|
49
|
+
std::swap(polygon.bounds.max_x, polygon.bounds.max_y);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
void VerticalMerger::adjust(ProcessResult& result) {
|
|
54
|
+
for (auto& polygon : result.polygons) {
|
|
55
|
+
if (!polygon.outer.empty()) {
|
|
56
|
+
std::rotate(polygon.outer.begin(), polygon.outer.begin() + 1, polygon.outer.end());
|
|
57
|
+
}
|
|
58
|
+
for (auto& sequence : polygon.inner) {
|
|
59
|
+
if (!sequence.empty()) {
|
|
60
|
+
std::rotate(sequence.begin(), sequence.begin() + 1, sequence.end());
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* VerticalMerger.h
|
|
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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include "Merger.h"
|
|
14
|
+
|
|
15
|
+
class VerticalMerger : public Merger {
|
|
16
|
+
public:
|
|
17
|
+
VerticalMerger(int number_of_threads, std::vector<std::string> *options);
|
|
18
|
+
void add_tile(ProcessResult& result) override;
|
|
19
|
+
ProcessResult* process_info() override;
|
|
20
|
+
|
|
21
|
+
private:
|
|
22
|
+
void transpose(ProcessResult& result);
|
|
23
|
+
void adjust(ProcessResult& result);
|
|
24
|
+
};
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
#include "PolygonFinder/src/polygon/finder/Polygon.h"
|
|
28
28
|
#include "PolygonFinder/src/polygon/bitmaps/Bitmap.h"
|
|
29
29
|
#include "PolygonFinder/src/polygon/bitmaps/Bitmap.cpp"
|
|
30
|
+
#include "PolygonFinder/src/polygon/bitmaps/RawBitmap.h"
|
|
31
|
+
#include "PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp"
|
|
30
32
|
#include "PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h"
|
|
31
33
|
#include "PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp"
|
|
32
34
|
#include "PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h"
|
|
@@ -81,6 +83,12 @@
|
|
|
81
83
|
#include "PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp"
|
|
82
84
|
#include "PolygonFinder/src/polygon/finder/concurrent/PartPool.h"
|
|
83
85
|
#include "PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp"
|
|
86
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/Merger.h"
|
|
87
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/Merger.cpp"
|
|
88
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.h"
|
|
89
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.cpp"
|
|
90
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.h"
|
|
91
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp"
|
|
84
92
|
extern "C" {
|
|
85
93
|
#include "PolygonFinder/src/polygon/bitmaps/spng.h"
|
|
86
94
|
}
|
|
@@ -164,6 +172,8 @@ class To_Ruby<ProcessResult*>
|
|
|
164
172
|
return_me[Symbol("benchmarks")] = benchmarks_rb;
|
|
165
173
|
return_me[Symbol("groups")] = pr->groups;
|
|
166
174
|
return_me[Symbol("named_sequence")] = pr->named_sequence;
|
|
175
|
+
return_me[Symbol("width")] = pr->width;
|
|
176
|
+
return_me[Symbol("height")] = pr->height;
|
|
167
177
|
|
|
168
178
|
Rice::Array out;
|
|
169
179
|
for (Polygon& x : pr->polygons)
|
|
@@ -186,6 +196,14 @@ class To_Ruby<ProcessResult*>
|
|
|
186
196
|
inner_collection.push(sequence_flat);
|
|
187
197
|
}
|
|
188
198
|
poly_hash[Symbol("inner")] = inner_collection;
|
|
199
|
+
// BOUNDS
|
|
200
|
+
Rice::Hash bounds_hash = Rice::Hash();
|
|
201
|
+
bounds_hash[Symbol("min_x")] = x.bounds.min_x;
|
|
202
|
+
bounds_hash[Symbol("max_x")] = x.bounds.max_x;
|
|
203
|
+
bounds_hash[Symbol("min_y")] = x.bounds.min_y;
|
|
204
|
+
bounds_hash[Symbol("max_y")] = x.bounds.max_y;
|
|
205
|
+
poly_hash[Symbol("bounds")] = bounds_hash;
|
|
206
|
+
|
|
189
207
|
out.push(poly_hash);
|
|
190
208
|
}
|
|
191
209
|
rr->polygons = out;
|
|
@@ -212,6 +230,53 @@ class To_Ruby<ProcessResult*>
|
|
|
212
230
|
}
|
|
213
231
|
};
|
|
214
232
|
|
|
233
|
+
// converts back ProcessResult
|
|
234
|
+
ProcessResult ruby_result_to_process_result(Rice::Object rb_result) {
|
|
235
|
+
ProcessResult pr;
|
|
236
|
+
|
|
237
|
+
Rice::Hash metadata = rb_result.iv_get("@metadata_storage");
|
|
238
|
+
pr.width = detail::From_Ruby<int>().convert(metadata[Symbol("width")].value());
|
|
239
|
+
pr.height = detail::From_Ruby<int>().convert(metadata[Symbol("height")].value());
|
|
240
|
+
|
|
241
|
+
Rice::Array rb_polygons = rb_result.iv_get("@polygons_storage");
|
|
242
|
+
for (size_t i = 0; i < rb_polygons.size(); ++i) {
|
|
243
|
+
// Cast esplicito a Rice::Hash per evitare il Proxy
|
|
244
|
+
Rice::Hash rb_poly = (Rice::Hash)rb_polygons[i];
|
|
245
|
+
Polygon poly;
|
|
246
|
+
// BOUNDS
|
|
247
|
+
Rice::Object rb_bounds_obj = rb_poly[Symbol("bounds")];
|
|
248
|
+
if (!rb_bounds_obj.is_nil()) {
|
|
249
|
+
Rice::Hash rb_bounds = (Rice::Hash)rb_bounds_obj;
|
|
250
|
+
poly.bounds.min_x = detail::From_Ruby<int>().convert(rb_bounds[Symbol("min_x")].value());
|
|
251
|
+
poly.bounds.max_x = detail::From_Ruby<int>().convert(rb_bounds[Symbol("max_x")].value());
|
|
252
|
+
poly.bounds.min_y = detail::From_Ruby<int>().convert(rb_bounds[Symbol("min_y")].value());
|
|
253
|
+
poly.bounds.max_y = detail::From_Ruby<int>().convert(rb_bounds[Symbol("max_y")].value());
|
|
254
|
+
}
|
|
255
|
+
// OUTER
|
|
256
|
+
Rice::Array outer_flat = (Rice::Array)rb_poly[Symbol("outer")];
|
|
257
|
+
for (size_t j = 0; j < outer_flat.size(); j += 2) {
|
|
258
|
+
int px = detail::From_Ruby<int>().convert(outer_flat[j].value());
|
|
259
|
+
int py = detail::From_Ruby<int>().convert(outer_flat[j+1].value());
|
|
260
|
+
poly.outer.push_back(new Point(px, py));
|
|
261
|
+
}
|
|
262
|
+
// INNER
|
|
263
|
+
Rice::Array inner_collection = (Rice::Array)rb_poly[Symbol("inner")];
|
|
264
|
+
for (size_t j = 0; j < inner_collection.size(); ++j) {
|
|
265
|
+
Rice::Array sequence_flat = (Rice::Array)inner_collection[j];
|
|
266
|
+
std::vector<Point*> hole;
|
|
267
|
+
for (size_t k = 0; k < sequence_flat.size(); k += 2) {
|
|
268
|
+
int px = detail::From_Ruby<int>().convert(sequence_flat[k].value());
|
|
269
|
+
int py = detail::From_Ruby<int>().convert(sequence_flat[k+1].value());
|
|
270
|
+
hole.push_back(new Point(px, py));
|
|
271
|
+
}
|
|
272
|
+
poly.inner.push_back(hole);
|
|
273
|
+
}
|
|
274
|
+
pr.polygons.push_back(poly);
|
|
275
|
+
}
|
|
276
|
+
return pr;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
|
|
215
280
|
} // namespace Rice::detail
|
|
216
281
|
|
|
217
282
|
extern "C"
|
|
@@ -227,6 +292,15 @@ void Init_cpp_polygon_finder() {
|
|
|
227
292
|
.define_method("clear", &Bitmap::clear)
|
|
228
293
|
.define_method("print", &Bitmap::print);
|
|
229
294
|
|
|
295
|
+
Data_Type<RawBitmap> rb_cRawBitmap =
|
|
296
|
+
define_class<RawBitmap, Bitmap>("CPPRawBitMap")
|
|
297
|
+
.define_constructor(Constructor<RawBitmap>())
|
|
298
|
+
.define_method("rgb_value_at", &RawBitmap::rgb_value_at)
|
|
299
|
+
.define_method("w", &RawBitmap::w)
|
|
300
|
+
.define_method("h", &RawBitmap::h)
|
|
301
|
+
.define_method("define", &RawBitmap::define)
|
|
302
|
+
.define_method("draw_pixel", &RawBitmap::draw_pixel);
|
|
303
|
+
|
|
230
304
|
Data_Type<RemoteFastPngBitmap> rb_cRemotePngBitmap =
|
|
231
305
|
define_class<RemoteFastPngBitmap, Bitmap>("CPPRemotePngBitMap")
|
|
232
306
|
.define_constructor(Constructor<RemoteFastPngBitmap, std::string*>(), Arg("url"))
|
|
@@ -280,6 +354,23 @@ void Init_cpp_polygon_finder() {
|
|
|
280
354
|
.define_constructor(Constructor<Finder, int, Bitmap*, Matcher*, std::vector<std::string>*>(), Arg("number_of_threads"), Arg("bitmap"), Arg("matcher"), Arg("options") = nullptr, Rice::Arg("yield_gvl") = true)
|
|
281
355
|
.define_method("process_info", &Finder::process_info, Rice::Arg("yield_gvl") = true);
|
|
282
356
|
|
|
357
|
+
Data_Type<Merger> rb_cMerger =
|
|
358
|
+
define_class<Merger, Finder>("CPPMerger")
|
|
359
|
+
.define_constructor(Constructor<Merger, int, std::vector<std::string>*>(), Arg("number_of_threads"), Arg("options") = nullptr, Rice::Arg("yield_gvl") = true)
|
|
360
|
+
.define_method("add_tile", [](Merger& self, Object rb_result) {
|
|
361
|
+
ProcessResult pr = Rice::detail::ruby_result_to_process_result(rb_result);
|
|
362
|
+
self.add_tile(pr);
|
|
363
|
+
})
|
|
364
|
+
.define_method("process_info", &Merger::process_info, Rice::Arg("yield_gvl") = true);
|
|
365
|
+
|
|
366
|
+
Data_Type<HorizontalMerger> rb_cHorizontalMerger =
|
|
367
|
+
define_class<HorizontalMerger, Merger>("CPPHorizontalMerger")
|
|
368
|
+
.define_constructor(Constructor<HorizontalMerger, int, std::vector<std::string>*>(), Arg("number_of_threads"), Arg("options") = nullptr, Arg("yield_gvl") = true);
|
|
369
|
+
|
|
370
|
+
Data_Type<VerticalMerger> rb_cVerticalMerger =
|
|
371
|
+
define_class<VerticalMerger, Merger>("CPPVerticalMerger")
|
|
372
|
+
.define_constructor(Constructor<VerticalMerger, int, std::vector<std::string>*>(), Arg("number_of_threads"), Arg("options") = nullptr, Arg("yield_gvl") = true);
|
|
373
|
+
|
|
283
374
|
Data_Type<RubyResult> rb_cResult =
|
|
284
375
|
define_class_under<RubyResult>(rb_cFinder, "Result")
|
|
285
376
|
.define_constructor(Constructor<RubyResult>())
|
|
@@ -28,6 +28,7 @@ module Contrek
|
|
|
28
28
|
@options = options
|
|
29
29
|
@clusters = []
|
|
30
30
|
@maximum_width = bitmap.w
|
|
31
|
+
@height = bitmap.h
|
|
31
32
|
@number_of_tiles = options[:number_of_tiles] || (raise "number_of_tiles params is needed!")
|
|
32
33
|
@number_of_tiles = 1 if @number_of_tiles <= 0
|
|
33
34
|
|
|
@@ -62,11 +63,11 @@ module Contrek
|
|
|
62
63
|
|
|
63
64
|
x = tile_end_x - 1
|
|
64
65
|
end
|
|
65
|
-
process_tiles!(bitmap)
|
|
66
|
+
process_tiles!(bitmap, height: bitmap.h)
|
|
66
67
|
end.real
|
|
67
68
|
end
|
|
68
69
|
|
|
69
|
-
def process_info
|
|
70
|
+
def process_info
|
|
70
71
|
raw_polygons = @whole_tile.to_raw_polygons
|
|
71
72
|
|
|
72
73
|
compress_time = Benchmark.measure do
|
|
@@ -83,14 +84,16 @@ module Contrek
|
|
|
83
84
|
outer: (@whole_tile.benchmarks[:outer] * 1000).round(3),
|
|
84
85
|
inner: (@whole_tile.benchmarks[:inner] * 1000).round(3),
|
|
85
86
|
compress: ((compress_time * 1000).round(3) if @options.has_key?(:compress))
|
|
86
|
-
}.compact
|
|
87
|
+
}.compact,
|
|
88
|
+
width: @maximum_width,
|
|
89
|
+
height: @height
|
|
87
90
|
}
|
|
88
91
|
Contrek::Finder::Result.new(raw_polygons, metadata)
|
|
89
92
|
end
|
|
90
93
|
|
|
91
94
|
private
|
|
92
95
|
|
|
93
|
-
def process_tiles!(bitmap)
|
|
96
|
+
def process_tiles!(bitmap, height:)
|
|
94
97
|
arriving_tiles = []
|
|
95
98
|
loop do
|
|
96
99
|
tile = @tiles.pop
|
|
@@ -110,7 +113,7 @@ module Contrek
|
|
|
110
113
|
|
|
111
114
|
# puts "start = #{start_x} end = #{end_x}"
|
|
112
115
|
|
|
113
|
-
cluster = Cluster.new(finder: self, height:
|
|
116
|
+
cluster = Cluster.new(finder: self, height: height, start_x:, end_x:)
|
|
114
117
|
if twin_tile.start_x == (tile.end_x - 1)
|
|
115
118
|
cluster.add(tile)
|
|
116
119
|
cluster.add(twin_tile)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Contrek
|
|
2
|
+
module Concurrent
|
|
3
|
+
class Merger < Finder
|
|
4
|
+
prepend Poolable
|
|
5
|
+
|
|
6
|
+
def initialize(options: {})
|
|
7
|
+
@initialize_time = 0
|
|
8
|
+
@current_x = 0
|
|
9
|
+
@tiles = Queue.new
|
|
10
|
+
@whole_tile = nil
|
|
11
|
+
@options = options
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def add_tile(result)
|
|
15
|
+
@height ||= result.metadata[:height]
|
|
16
|
+
end_x = @current_x + result.metadata[:width]
|
|
17
|
+
|
|
18
|
+
tile = Tile.new(
|
|
19
|
+
finder: self,
|
|
20
|
+
start_x: @current_x,
|
|
21
|
+
end_x: end_x,
|
|
22
|
+
name: @tiles.size.to_s
|
|
23
|
+
)
|
|
24
|
+
tile.assign_raw_polygons!(result[:polygons])
|
|
25
|
+
|
|
26
|
+
@tiles << tile
|
|
27
|
+
@maximum_width = end_x
|
|
28
|
+
@current_x = end_x - 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def process_info
|
|
32
|
+
process_tiles!(nil, height: @height)
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def translate(result, offset)
|
|
39
|
+
result.polygons.each do |polygon|
|
|
40
|
+
polygon[:outer].each { |p| p[:x] += offset }
|
|
41
|
+
polygon[:inner].each do |sequence|
|
|
42
|
+
sequence.each { |p| p[:x] += offset }
|
|
43
|
+
end
|
|
44
|
+
if polygon.key?(:bounds)
|
|
45
|
+
polygon[:bounds][:min_x] += offset
|
|
46
|
+
polygon[:bounds][:max_x] += offset
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Contrek
|
|
2
|
+
module Concurrent
|
|
3
|
+
class VerticalMerger < Merger
|
|
4
|
+
def add_tile(result)
|
|
5
|
+
transpose(result)
|
|
6
|
+
if @tiles.size > 0
|
|
7
|
+
translate(result, @current_x)
|
|
8
|
+
adjust(result)
|
|
9
|
+
end
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def process_info
|
|
14
|
+
transpose(super)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def adjust(result)
|
|
20
|
+
result.polygons.each do |polygon|
|
|
21
|
+
polygon[:outer].rotate!(1)
|
|
22
|
+
polygon[:inner].each do |sequence|
|
|
23
|
+
sequence.rotate!(1)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def transpose(result)
|
|
29
|
+
result.metadata_hash[:width], result.metadata_hash[:height] = result.metadata_hash[:height], result.metadata_hash[:width]
|
|
30
|
+
result.polygons.each do |polygon|
|
|
31
|
+
polygon[:outer].each { |p| p[:x], p[:y] = p[:y], p[:x] }
|
|
32
|
+
polygon[:inner].each do |sequence|
|
|
33
|
+
sequence.each { |p| p[:x], p[:y] = p[:y], p[:x] }
|
|
34
|
+
end
|
|
35
|
+
if polygon.key?(:bounds)
|
|
36
|
+
polygon[:bounds][:min_x], polygon[:bounds][:min_y] = polygon[:bounds][:min_y], polygon[:bounds][:min_x]
|
|
37
|
+
polygon[:bounds][:max_x], polygon[:bounds][:max_y] = polygon[:bounds][:max_y], polygon[:bounds][:max_x]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -47,6 +47,8 @@ module Contrek
|
|
|
47
47
|
groups: @node_cluster.sequences.size,
|
|
48
48
|
groups_names: @node_cluster.root_nodes.map(&:name).join,
|
|
49
49
|
benchmarks: format_benchmarks,
|
|
50
|
+
width: @source_bitmap.w,
|
|
51
|
+
height: @source_bitmap.h,
|
|
50
52
|
treemap: (@node_cluster.treemap if @options.has_key?(:treemap))
|
|
51
53
|
}
|
|
52
54
|
Result.new(@node_cluster.polygons, metadata)
|
|
@@ -5,7 +5,7 @@ module Contrek
|
|
|
5
5
|
start_p = @points[0]
|
|
6
6
|
end_p = @points[1]
|
|
7
7
|
dir = seq_dir(start_p, end_p)
|
|
8
|
-
@points[2..].
|
|
8
|
+
@points[2..].each.with_index do |point, i|
|
|
9
9
|
if (act_seq = seq_dir(end_p, point)) == dir
|
|
10
10
|
@points.delete_at(@points.index(end_p))
|
|
11
11
|
else
|
data/lib/contrek/version.rb
CHANGED
data/lib/contrek.rb
CHANGED
|
@@ -3,7 +3,7 @@ require "contrek/bitmaps/painting"
|
|
|
3
3
|
require "contrek/bitmaps/bitmap"
|
|
4
4
|
require "contrek/bitmaps/chunky_bitmap"
|
|
5
5
|
require "contrek/bitmaps/png_bitmap"
|
|
6
|
-
require "contrek/bitmaps/
|
|
6
|
+
require "contrek/bitmaps/raw_bitmap"
|
|
7
7
|
require "contrek/bitmaps/rgb_color"
|
|
8
8
|
require "contrek/bitmaps/rgb_cpp_color"
|
|
9
9
|
require "contrek/finder/bounds"
|
|
@@ -32,6 +32,9 @@ require "contrek/finder/concurrent/tile"
|
|
|
32
32
|
require "contrek/finder/concurrent/polyline"
|
|
33
33
|
require "contrek/finder/concurrent/cluster"
|
|
34
34
|
require "contrek/finder/concurrent/finder"
|
|
35
|
+
require "contrek/finder/concurrent/merger"
|
|
36
|
+
require "contrek/finder/concurrent/horizontal_merger"
|
|
37
|
+
require "contrek/finder/concurrent/vertical_merger"
|
|
35
38
|
require "contrek/finder/concurrent/cursor"
|
|
36
39
|
require "contrek/map/mercator_projection"
|
|
37
40
|
require "contrek/matchers/matcher"
|
|
@@ -43,6 +46,9 @@ require "contrek/reducers/uniq_reducer"
|
|
|
43
46
|
require "contrek/reducers/visvalingam_reducer"
|
|
44
47
|
require "cpp_polygon_finder"
|
|
45
48
|
require "contrek/cpp/cpp_concurrent_finder"
|
|
49
|
+
require "contrek/cpp/cpp_concurrent_merger"
|
|
50
|
+
require "contrek/cpp/cpp_concurrent_horizontal_merger"
|
|
51
|
+
require "contrek/cpp/cpp_concurrent_vertical_merger"
|
|
46
52
|
require "contrek/results/cpp_result"
|
|
47
53
|
|
|
48
54
|
module Contrek
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: contrek
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emanuele Cesaroni
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-03-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -154,6 +154,8 @@ files:
|
|
|
154
154
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.h
|
|
155
155
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp
|
|
156
156
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h
|
|
157
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp
|
|
158
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.h
|
|
157
159
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp
|
|
158
160
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h
|
|
159
161
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/spng.c
|
|
@@ -184,8 +186,12 @@ files:
|
|
|
184
186
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/FakeCluster.h
|
|
185
187
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp
|
|
186
188
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h
|
|
189
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.cpp
|
|
190
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.h
|
|
187
191
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp
|
|
188
192
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h
|
|
193
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp
|
|
194
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.h
|
|
189
195
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp
|
|
190
196
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h
|
|
191
197
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp
|
|
@@ -206,6 +212,8 @@ files:
|
|
|
206
212
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h
|
|
207
213
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp
|
|
208
214
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h
|
|
215
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp
|
|
216
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.h
|
|
209
217
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/optionparser.h
|
|
210
218
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.cpp
|
|
211
219
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.h
|
|
@@ -228,13 +236,16 @@ files:
|
|
|
228
236
|
- lib/contrek.rb
|
|
229
237
|
- lib/contrek/bitmaps/bitmap.rb
|
|
230
238
|
- lib/contrek/bitmaps/chunky_bitmap.rb
|
|
231
|
-
- lib/contrek/bitmaps/custom_bitmap.rb
|
|
232
239
|
- lib/contrek/bitmaps/painting.rb
|
|
233
240
|
- lib/contrek/bitmaps/png_bitmap.rb
|
|
241
|
+
- lib/contrek/bitmaps/raw_bitmap.rb
|
|
234
242
|
- lib/contrek/bitmaps/rgb_color.rb
|
|
235
243
|
- lib/contrek/bitmaps/rgb_cpp_color.rb
|
|
236
244
|
- lib/contrek/bitmaps/sample_generator.rb
|
|
237
245
|
- lib/contrek/cpp/cpp_concurrent_finder.rb
|
|
246
|
+
- lib/contrek/cpp/cpp_concurrent_horizontal_merger.rb
|
|
247
|
+
- lib/contrek/cpp/cpp_concurrent_merger.rb
|
|
248
|
+
- lib/contrek/cpp/cpp_concurrent_vertical_merger.rb
|
|
238
249
|
- lib/contrek/finder/bounds.rb
|
|
239
250
|
- lib/contrek/finder/concurrent/clipped_polygon_finder.rb
|
|
240
251
|
- lib/contrek/finder/concurrent/cluster.rb
|
|
@@ -242,8 +253,10 @@ files:
|
|
|
242
253
|
- lib/contrek/finder/concurrent/end_point.rb
|
|
243
254
|
- lib/contrek/finder/concurrent/fake_cluster.rb
|
|
244
255
|
- lib/contrek/finder/concurrent/finder.rb
|
|
256
|
+
- lib/contrek/finder/concurrent/horizontal_merger.rb
|
|
245
257
|
- lib/contrek/finder/concurrent/hub.rb
|
|
246
258
|
- lib/contrek/finder/concurrent/listable.rb
|
|
259
|
+
- lib/contrek/finder/concurrent/merger.rb
|
|
247
260
|
- lib/contrek/finder/concurrent/part.rb
|
|
248
261
|
- lib/contrek/finder/concurrent/partitionable.rb
|
|
249
262
|
- lib/contrek/finder/concurrent/polyline.rb
|
|
@@ -253,6 +266,7 @@ files:
|
|
|
253
266
|
- lib/contrek/finder/concurrent/sequence.rb
|
|
254
267
|
- lib/contrek/finder/concurrent/shape.rb
|
|
255
268
|
- lib/contrek/finder/concurrent/tile.rb
|
|
269
|
+
- lib/contrek/finder/concurrent/vertical_merger.rb
|
|
256
270
|
- lib/contrek/finder/list.rb
|
|
257
271
|
- lib/contrek/finder/list_entry.rb
|
|
258
272
|
- lib/contrek/finder/listable.rb
|