contrek 1.2.6 → 1.2.8
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 +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +12 -0
- data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +4 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +4 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +297 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +4 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +7 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +4 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp +1 -1
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +9 -6
- data/lib/contrek/cpp/cpp_result.rb +3 -2
- data/lib/contrek/finder/concurrent/tile.rb +3 -2
- data/lib/contrek/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d6702682d1ddd30acbdc45a4344b1d761473afc336b7c07734f169739228f855
|
|
4
|
+
data.tar.gz: 8fde7e85a08f0e8037b7711b303fefb0d4edcff1f7c9725a767ff09f815445a6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f498831ee81c1ff533ce412b39efdfe9c9dc42ff40679749600a2e2cf833cd8193b1f3ca8bf00e8ff98ae3a3798f9670380274d3cf63e485bad4428200256af4
|
|
7
|
+
data.tar.gz: 4fd128cf5cd14d929f2baaf9c611708cd9bd8ce01550e267f1d93252f5f23a9012b6f66bb59a4ab4390cb02c38b31a37f3fc6fd56d22478cf046359834a3bf0d
|
data/CHANGELOG.md
CHANGED
|
@@ -112,3 +112,7 @@ All notable changes to this project will be documented in this file.
|
|
|
112
112
|
- **Refactored `spng.c` function `rgb8_row_to_rgba8`:** Extended a loop counter to `size_t` (previously limited to `uint32_t`), which was causing segmentation faults when reading massive images (e.g., 81920x81920).
|
|
113
113
|
- **Refactored `RawBitmap.define` function:** Updated area and size calculations to use full 64-bit integers.
|
|
114
114
|
- **Refactored `PolygonFinder.to_svg_stream()` function:** Optimized performance to efficiently handle massive SVG streams of 2 GB and beyond.
|
|
115
|
+
|
|
116
|
+
## [1.2.7] - 2026-06-02
|
|
117
|
+
### Changed
|
|
118
|
+
- **Refactored `bounds` option:** Starting from this release, precalculated bounds for each polygon can now be requested in concurrent mode as well, in addition to single-threaded mode.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -286,6 +286,18 @@ result.points
|
|
|
286
286
|
For pure Ruby implementations (`{ native: false }`), coordinates are always expressed as points.
|
|
287
287
|
In this case, both `polygons` and `points` return the same data, represented as hashes with `x` and `y` keys.
|
|
288
288
|
|
|
289
|
+
For each returned polygon, it is possible to get its bounding box. You just need to request it as an option (`bounds`), for example:
|
|
290
|
+
```ruby
|
|
291
|
+
{named_sequences: true, bounds: true, compress: {uniq: true, linear: true}}
|
|
292
|
+
```
|
|
293
|
+
Each entry will contain the precalculated bounds key:
|
|
294
|
+
```ruby
|
|
295
|
+
[{:bounds=>{:min_x=>3, :max_x=>11, :min_y=>1, :max_y=>3},
|
|
296
|
+
:outer=>[{:x=>3, :y=>1}, {:x=>3, :y=>3}, {:x=>11, :y=>3}, {:x=>11, :y=>1}],
|
|
297
|
+
:inner=>[]}]
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
|
|
289
301
|
## Metadata
|
|
290
302
|
|
|
291
303
|
Metadata associated with the result can be accessed via:
|
|
@@ -11,8 +11,10 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
|
11
11
|
list(FILTER CMAKE_CXX_FLAGS EXCLUDE REGEX "-DNDEBUG")
|
|
12
12
|
list(FILTER CMAKE_C_FLAGS EXCLUDE REGEX "-DNDEBUG")
|
|
13
13
|
else()
|
|
14
|
-
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread -march=native -DNDEBUG -Ofast -flto")
|
|
15
|
-
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -march=native -fPIC -DNDEBUG")
|
|
14
|
+
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread -march=native -DNDEBUG -Ofast -flto")
|
|
15
|
+
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -march=native -fPIC -DNDEBUG")
|
|
16
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread -march=native -DNDEBUG -Ofast -flto -fopenmp-simd -ftree-vectorize")
|
|
17
|
+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pthread -march=native -DNDEBUG -Ofast -flto -fopenmp-simd -ftree-vectorize")
|
|
16
18
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread -flto=auto -Wl,--no-as-needed")
|
|
17
19
|
find_library(TCMALLOC_LIB tcmalloc)
|
|
18
20
|
if(TCMALLOC_LIB)
|
|
@@ -108,12 +108,13 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
|
|
|
108
108
|
break;
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
/*std::cout << "-----------" << std::endl;
|
|
111
|
+
/* std::cout << "-----------" << std::endl;
|
|
112
112
|
std::cout << "versus " << options.versus << std::endl;
|
|
113
|
+
std::cout << "bounds " << options.bounds << std::endl;
|
|
113
114
|
std::cout << "number_of_tiles " << options.number_of_tiles << std::endl;
|
|
114
115
|
std::cout << "uniq " << options.compress_uniq << std::endl;
|
|
115
116
|
std::cout << "linear " << options.compress_linear << std::endl;
|
|
116
117
|
std::cout << "visvalingam " << options.compress_visvalingam << std::endl;
|
|
117
|
-
std::cout << options.compress_visvalingam_tolerance << std::endl;
|
|
118
|
-
std::cout << "-----------" << std::endl
|
|
118
|
+
std::cout << "visvalingam tolernace " << options.compress_visvalingam_tolerance << std::endl;
|
|
119
|
+
std::cout << "-----------" << std::endl; */
|
|
119
120
|
}
|
|
@@ -46,6 +46,7 @@ PolygonFinder::PolygonFinder(Bitmap *bitmap,
|
|
|
46
46
|
cpu_timer.start();
|
|
47
47
|
scan();
|
|
48
48
|
reports["scan"] = cpu_timer.stop();
|
|
49
|
+
//std::cout << "scan " << reports["scan"] << std::endl;
|
|
49
50
|
//=====================//
|
|
50
51
|
|
|
51
52
|
//= BUILD_TANGS_SEQUENCE ===//
|
|
@@ -107,6 +108,7 @@ ProcessResult* PolygonFinder::process_info() {
|
|
|
107
108
|
pr->treemap = this->node_cluster->treemap;
|
|
108
109
|
pr->width = this->source_bitmap->w();
|
|
109
110
|
pr->height = this->source_bitmap->h();
|
|
111
|
+
pr->has_bounds = this->node_cluster->options->bounds;
|
|
110
112
|
|
|
111
113
|
if (this->node_cluster->options->named_sequences && typeid(*this->source_bitmap) == typeid(Bitmap))
|
|
112
114
|
{ std::string sequence;
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
#include <sstream>
|
|
21
21
|
#include <stdexcept>
|
|
22
22
|
#include <limits>
|
|
23
|
+
#include <cstdint>
|
|
24
|
+
|
|
23
25
|
#include "../bitmaps/Bitmap.h"
|
|
24
26
|
#include "NodeCluster.h"
|
|
25
27
|
#include "Node.h"
|
|
@@ -59,6 +61,7 @@ struct pf_Options {
|
|
|
59
61
|
struct ProcessResult {
|
|
60
62
|
int groups;
|
|
61
63
|
int width, height;
|
|
64
|
+
bool has_bounds = false;
|
|
62
65
|
std::map<std::string, double> benchmarks;
|
|
63
66
|
std::list<Polygon> polygons;
|
|
64
67
|
std::string named_sequence;
|
|
@@ -204,7 +207,7 @@ class PolygonFinder {
|
|
|
204
207
|
std::map<std::string, double> reports;
|
|
205
208
|
void scan();
|
|
206
209
|
CpuTimer cpu_timer;
|
|
207
|
-
|
|
210
|
+
/*
|
|
208
211
|
template <typename M, typename F>
|
|
209
212
|
void run_loop(M* specific_matcher, F&& fetch_color, int offset) {
|
|
210
213
|
int img_h = this->source_bitmap->h();
|
|
@@ -235,7 +238,299 @@ class PolygonFinder {
|
|
|
235
238
|
}
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
|
-
}
|
|
241
|
+
}*/
|
|
242
|
+
|
|
243
|
+
template <typename M, typename F>
|
|
244
|
+
void run_loop(M* specific_matcher, F&& fetch_color, int offset) {
|
|
245
|
+
int img_h = this->source_bitmap->h();
|
|
246
|
+
int bpp = this->source_bitmap->get_bytes_per_pixel();
|
|
247
|
+
|
|
248
|
+
for (int y = 0; y < img_h; y++) {
|
|
249
|
+
const unsigned char* row_ptr = this->source_bitmap->get_row_ptr(y);
|
|
250
|
+
const unsigned char* p = row_ptr + (this->start_x * bpp);
|
|
251
|
+
|
|
252
|
+
int min_x = 0;
|
|
253
|
+
bool matching = false;
|
|
254
|
+
unsigned char last_red_value = 0;
|
|
255
|
+
|
|
256
|
+
int x = this->start_x;
|
|
257
|
+
|
|
258
|
+
if (bpp == 4) {
|
|
259
|
+
for (; x <= this->end_x - 4; x += 4) {
|
|
260
|
+
// 1. Unico accesso alla RAM per pixel: leggiamo i 4 byte completi
|
|
261
|
+
unsigned int c0 = fetch_color(p);
|
|
262
|
+
unsigned int c1 = fetch_color(p + 4);
|
|
263
|
+
unsigned int c2 = fetch_color(p + 8);
|
|
264
|
+
unsigned int c3 = fetch_color(p + 12);
|
|
265
|
+
|
|
266
|
+
// 2. Estrazione a costo zero dai registri della CPU (Operazione bitwise, NO RAM)
|
|
267
|
+
// Se fetch_color ritorna il mascheramento standard, il primo byte si prende con il cast o lo shift
|
|
268
|
+
unsigned char v0 = static_cast<unsigned char>(c0);
|
|
269
|
+
unsigned char v1 = static_cast<unsigned char>(c1);
|
|
270
|
+
unsigned char v2 = static_cast<unsigned char>(c2);
|
|
271
|
+
unsigned char v3 = static_cast<unsigned char>(c3);
|
|
272
|
+
|
|
273
|
+
p += 16;
|
|
274
|
+
|
|
275
|
+
bool m0 = specific_matcher->match(c0);
|
|
276
|
+
bool m1 = specific_matcher->match(c1);
|
|
277
|
+
bool m2 = specific_matcher->match(c2);
|
|
278
|
+
bool m3 = specific_matcher->match(c3);
|
|
279
|
+
|
|
280
|
+
// [Resto della logica dei pixel 0, 1, 2, 3 invariata...]
|
|
281
|
+
if (m0) {
|
|
282
|
+
if (!matching) { min_x = x; last_red_value = v0; matching = true; }
|
|
283
|
+
} else if (matching) {
|
|
284
|
+
this->node_cluster->add_node(min_x, x - 1, y, last_red_value, offset);
|
|
285
|
+
matching = false;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (m1) {
|
|
289
|
+
if (!matching) { min_x = x + 1; last_red_value = v1; matching = true; }
|
|
290
|
+
} else if (matching) {
|
|
291
|
+
this->node_cluster->add_node(min_x, x, y, last_red_value, offset);
|
|
292
|
+
matching = false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (m2) {
|
|
296
|
+
if (!matching) { min_x = x + 2; last_red_value = v2; matching = true; }
|
|
297
|
+
} else if (matching) {
|
|
298
|
+
this->node_cluster->add_node(min_x, x + 1, y, last_red_value, offset);
|
|
299
|
+
matching = false;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (m3) {
|
|
303
|
+
if (!matching) { min_x = x + 3; last_red_value = v3; matching = true; }
|
|
304
|
+
} else if (matching) {
|
|
305
|
+
this->node_cluster->add_node(min_x, x + 2, y, last_red_value, offset);
|
|
306
|
+
matching = false;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// --- CLEANUP SCALARE ---
|
|
312
|
+
for (; x < this->end_x; x++) {
|
|
313
|
+
unsigned int color = fetch_color(p);
|
|
314
|
+
// Applichiamo la stessa ottimizzazione anche qui
|
|
315
|
+
unsigned char current_val = static_cast<unsigned char>(color);
|
|
316
|
+
p += bpp;
|
|
317
|
+
|
|
318
|
+
if (specific_matcher->match(color)) {
|
|
319
|
+
if (!matching) {
|
|
320
|
+
min_x = x;
|
|
321
|
+
last_red_value = current_val;
|
|
322
|
+
matching = true;
|
|
323
|
+
}
|
|
324
|
+
} else if (matching) {
|
|
325
|
+
this->node_cluster->add_node(min_x, x - 1, y, last_red_value, offset);
|
|
326
|
+
matching = false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (matching) {
|
|
331
|
+
this->node_cluster->add_node(min_x, this->end_x - 1, y, last_red_value, offset);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/*template <typename M, typename F>
|
|
337
|
+
void run_loop(M* specific_matcher, F&& fetch_color, int offset) {
|
|
338
|
+
int img_h = this->source_bitmap->h();
|
|
339
|
+
int bpp = this->source_bitmap->get_bytes_per_pixel();
|
|
340
|
+
|
|
341
|
+
for (int y = 0; y < img_h; y++) {
|
|
342
|
+
const unsigned char* row_ptr = this->source_bitmap->get_row_ptr(y);
|
|
343
|
+
const unsigned char* p = row_ptr + (this->start_x * bpp);
|
|
344
|
+
|
|
345
|
+
int min_x = 0;
|
|
346
|
+
bool matching = false;
|
|
347
|
+
unsigned char last_red_value = 0;
|
|
348
|
+
|
|
349
|
+
int x = this->start_x;
|
|
350
|
+
|
|
351
|
+
// --- IL TUO SWEET SPOT: UNROLLING A 4 VIE RIFINITO ---
|
|
352
|
+
if (bpp == 4) {
|
|
353
|
+
for (; x <= this->end_x - 4; x += 4) {
|
|
354
|
+
// Leggiamo in sequenza stretta per ottimizzare i register e la cache L1
|
|
355
|
+
unsigned int c0 = fetch_color(p);
|
|
356
|
+
unsigned char v0 = p[0];
|
|
357
|
+
|
|
358
|
+
unsigned int c1 = fetch_color(p + 4);
|
|
359
|
+
unsigned char v1 = p[4];
|
|
360
|
+
|
|
361
|
+
unsigned int c2 = fetch_color(p + 8);
|
|
362
|
+
unsigned char v2 = p[8];
|
|
363
|
+
|
|
364
|
+
unsigned int c3 = fetch_color(p + 12);
|
|
365
|
+
unsigned char v3 = p[12];
|
|
366
|
+
|
|
367
|
+
p += 16; // Spostato qui: avanza di 4 pixel RGBA precisi
|
|
368
|
+
|
|
369
|
+
bool m0 = specific_matcher->match(c0);
|
|
370
|
+
bool m1 = specific_matcher->match(c1);
|
|
371
|
+
bool m2 = specific_matcher->match(c2);
|
|
372
|
+
bool m3 = specific_matcher->match(c3);
|
|
373
|
+
|
|
374
|
+
// Pixel 0
|
|
375
|
+
if (m0) {
|
|
376
|
+
if (!matching) { min_x = x; last_red_value = v0; matching = true; }
|
|
377
|
+
} else if (matching) {
|
|
378
|
+
this->node_cluster->add_node(min_x, x - 1, y, last_red_value, offset);
|
|
379
|
+
matching = false;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Pixel 1
|
|
383
|
+
if (m1) {
|
|
384
|
+
if (!matching) { min_x = x + 1; last_red_value = v1; matching = true; }
|
|
385
|
+
} else if (matching) {
|
|
386
|
+
this->node_cluster->add_node(min_x, x, y, last_red_value, offset);
|
|
387
|
+
matching = false;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Pixel 2
|
|
391
|
+
if (m2) {
|
|
392
|
+
if (!matching) { min_x = x + 2; last_red_value = v2; matching = true; }
|
|
393
|
+
} else if (matching) {
|
|
394
|
+
this->node_cluster->add_node(min_x, x + 1, y, last_red_value, offset);
|
|
395
|
+
matching = false;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Pixel 3
|
|
399
|
+
if (m3) {
|
|
400
|
+
if (!matching) { min_x = x + 3; last_red_value = v3; matching = true; }
|
|
401
|
+
} else if (matching) {
|
|
402
|
+
this->node_cluster->add_node(min_x, x + 2, y, last_red_value, offset);
|
|
403
|
+
matching = false;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// --- CLEANUP SCALARE PER I RIMANENTI ---
|
|
409
|
+
for (; x < this->end_x; x++) {
|
|
410
|
+
unsigned int color = fetch_color(p);
|
|
411
|
+
unsigned char current_val = p[0];
|
|
412
|
+
p += bpp;
|
|
413
|
+
|
|
414
|
+
if (specific_matcher->match(color)) {
|
|
415
|
+
if (!matching) {
|
|
416
|
+
min_x = x;
|
|
417
|
+
last_red_value = current_val;
|
|
418
|
+
matching = true;
|
|
419
|
+
}
|
|
420
|
+
} else if (matching) {
|
|
421
|
+
this->node_cluster->add_node(min_x, x - 1, y, last_red_value, offset);
|
|
422
|
+
matching = false;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// --- CHIUSURA DI SICUREZZA FINE RIGA ---
|
|
427
|
+
if (matching) {
|
|
428
|
+
this->node_cluster->add_node(min_x, this->end_x - 1, y, last_red_value, offset);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}*/
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
/*
|
|
436
|
+
|
|
437
|
+
#include <cstdint>
|
|
438
|
+
|
|
439
|
+
template <typename M, typename F>
|
|
440
|
+
void run_loop(M* specific_matcher, F&& fetch_color, int offset) {
|
|
441
|
+
int img_h = this->source_bitmap->h();
|
|
442
|
+
int bpp = this->source_bitmap->get_bytes_per_pixel();
|
|
443
|
+
|
|
444
|
+
for (int y = 0; y < img_h; y++) {
|
|
445
|
+
const unsigned char* row_ptr = this->source_bitmap->get_row_ptr(y);
|
|
446
|
+
const unsigned char* p = row_ptr + (this->start_x * bpp);
|
|
447
|
+
|
|
448
|
+
int min_x = 0;
|
|
449
|
+
bool matching = false;
|
|
450
|
+
unsigned char last_red_value = 0;
|
|
451
|
+
|
|
452
|
+
int x = this->start_x;
|
|
453
|
+
|
|
454
|
+
// --- LINEA 1: UNROLLING A 4 VIE (SIMD FRIENDLY, NO DEPENDENCY) ---
|
|
455
|
+
if (bpp == 4) {
|
|
456
|
+
for (; x <= this->end_x - 4; x += 4) {
|
|
457
|
+
// Carichiamo 4 pixel in variabili separate (zero dipendenze tra loro)
|
|
458
|
+
unsigned int c0 = fetch_color(p);
|
|
459
|
+
unsigned int c1 = fetch_color(p + 4);
|
|
460
|
+
unsigned int c2 = fetch_color(p + 8);
|
|
461
|
+
unsigned int c3 = fetch_color(p + 12);
|
|
462
|
+
|
|
463
|
+
unsigned char v0 = p[0];
|
|
464
|
+
unsigned char v1 = p[4];
|
|
465
|
+
unsigned char v2 = p[8];
|
|
466
|
+
unsigned char v3 = p[12];
|
|
467
|
+
|
|
468
|
+
p += 16; // Avanza di 4 pixel (4 * 4 byte)
|
|
469
|
+
|
|
470
|
+
// Eseguiamo il match in parallelo. Il compilatore trasforma questo in istruzioni vettoriali
|
|
471
|
+
bool m0 = specific_matcher->match(c0);
|
|
472
|
+
bool m1 = specific_matcher->match(c1);
|
|
473
|
+
bool m2 = specific_matcher->match(c2);
|
|
474
|
+
bool m3 = specific_matcher->match(c3);
|
|
475
|
+
|
|
476
|
+
// Pixel 0
|
|
477
|
+
if (m0) {
|
|
478
|
+
if (!matching) { min_x = x; last_red_value = v0; matching = true; }
|
|
479
|
+
} else if (matching) {
|
|
480
|
+
this->node_cluster->add_node(min_x, x - 1, y, last_red_value, offset);
|
|
481
|
+
matching = false;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Pixel 1
|
|
485
|
+
if (m1) {
|
|
486
|
+
if (!matching) { min_x = x + 1; last_red_value = v1; matching = true; }
|
|
487
|
+
} else if (matching) {
|
|
488
|
+
this->node_cluster->add_node(min_x, x, y, last_red_value, offset);
|
|
489
|
+
matching = false;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Pixel 2
|
|
493
|
+
if (m2) {
|
|
494
|
+
if (!matching) { min_x = x + 2; last_red_value = v2; matching = true; }
|
|
495
|
+
} else if (matching) {
|
|
496
|
+
this->node_cluster->add_node(min_x, x + 1, y, last_red_value, offset);
|
|
497
|
+
matching = false;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Pixel 3
|
|
501
|
+
if (m3) {
|
|
502
|
+
if (!matching) { min_x = x + 3; last_red_value = v3; matching = true; }
|
|
503
|
+
} else if (matching) {
|
|
504
|
+
this->node_cluster->add_node(min_x, x + 2, y, last_red_value, offset);
|
|
505
|
+
matching = false;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// --- LINEA 2: SCALAR CLEANUP ---
|
|
511
|
+
for (; x < this->end_x; x++) {
|
|
512
|
+
unsigned int color = fetch_color(p);
|
|
513
|
+
unsigned char current_val = p[0];
|
|
514
|
+
p += bpp;
|
|
515
|
+
|
|
516
|
+
if (specific_matcher->match(color)) {
|
|
517
|
+
if (!matching) {
|
|
518
|
+
min_x = x;
|
|
519
|
+
last_red_value = current_val;
|
|
520
|
+
matching = true;
|
|
521
|
+
}
|
|
522
|
+
} else if (matching) {
|
|
523
|
+
this->node_cluster->add_node(min_x, x - 1, y, last_red_value, offset);
|
|
524
|
+
matching = false;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// --- CHIUSURA DI SICUREZZA ---
|
|
529
|
+
if (matching) {
|
|
530
|
+
this->node_cluster->add_node(min_x, this->end_x - 1, y, last_red_value, offset);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}*/
|
|
239
534
|
|
|
240
535
|
public:
|
|
241
536
|
PolygonFinder(Bitmap *bitmap,
|
|
@@ -60,7 +60,7 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
|
|
|
60
60
|
Tile* tile = new Tile(this, payload.tile_start_x, payload.tile_end_x,
|
|
61
61
|
std::to_string(payload.tile_index), Benchmarks {0, 0});
|
|
62
62
|
tile->initial_process(finder);
|
|
63
|
-
|
|
63
|
+
tiles_.queue_push(tile);
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
x = tile_end_x - 1;
|
|
@@ -79,7 +79,7 @@ void Finder::process_tiles() {
|
|
|
79
79
|
std::vector<Tile*> arriving_tiles;
|
|
80
80
|
|
|
81
81
|
while (true) {
|
|
82
|
-
Tile* tile =
|
|
82
|
+
Tile* tile = tiles_.queue_pop();
|
|
83
83
|
|
|
84
84
|
if (tile->whole()) {
|
|
85
85
|
this->whole_tile = tile;
|
|
@@ -116,7 +116,7 @@ void Finder::process_tiles() {
|
|
|
116
116
|
arriving_tiles.erase(it);
|
|
117
117
|
enqueue(cluster, [this](Cluster* c) {
|
|
118
118
|
Tile* merged_tile = c->merge_tiles();
|
|
119
|
-
|
|
119
|
+
tiles_.queue_push(merged_tile);
|
|
120
120
|
delete c;
|
|
121
121
|
});
|
|
122
122
|
} else {
|
|
@@ -146,6 +146,7 @@ ProcessResult* Finder::process_info() {
|
|
|
146
146
|
pr->groups = pr->polygons.size();
|
|
147
147
|
pr->width = this->maximum_width_;
|
|
148
148
|
pr->height = this->height;
|
|
149
|
+
pr->has_bounds = this->options_.bounds;
|
|
149
150
|
FakeCluster fake_cluster(pr->polygons, this->options_);
|
|
150
151
|
cpu_timer.start();
|
|
151
152
|
fake_cluster.compress_coords(pr->polygons, this->options_);
|
|
@@ -42,7 +42,7 @@ class Finder : public Poolable {
|
|
|
42
42
|
CpuTimer cpu_timer;
|
|
43
43
|
|
|
44
44
|
protected:
|
|
45
|
-
Queue<Tile*>
|
|
45
|
+
Queue<Tile*> tiles_;
|
|
46
46
|
int maximum_width_;
|
|
47
47
|
int height = 0;
|
|
48
48
|
void process_tiles();
|
|
@@ -55,4 +55,5 @@ class Finder : public Poolable {
|
|
|
55
55
|
int maximum_width() const { return maximum_width_; }
|
|
56
56
|
virtual ProcessResult* process_info();
|
|
57
57
|
const pf_Options& options() const { return options_; }
|
|
58
|
+
Queue<Tile*>& tiles() { return tiles_; }
|
|
58
59
|
};
|
|
@@ -21,9 +21,9 @@ void Merger::add_tile(ProcessResult& result)
|
|
|
21
21
|
this->height = result.height;
|
|
22
22
|
}
|
|
23
23
|
int end_x = this->current_x + result.width;
|
|
24
|
-
Tile* tile = new Tile(this, this->current_x, end_x, std::to_string(
|
|
24
|
+
Tile* tile = new Tile(this, this->current_x, end_x, std::to_string(tiles_.size()), Benchmarks {0, 0});
|
|
25
25
|
tile->assign_raw_polygons(result.polygons, result.treemap);
|
|
26
|
-
|
|
26
|
+
tiles_.queue_push(tile);
|
|
27
27
|
|
|
28
28
|
this->maximum_width_ = end_x;
|
|
29
29
|
this->current_x = end_x - 1;
|
|
@@ -95,3 +95,10 @@ std::string Polyline::named() {
|
|
|
95
95
|
return this->named_;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
|
|
99
|
+
void Polyline::fill_bounds(RectBounds& target_bounds) const {
|
|
100
|
+
target_bounds.min_x = this->min_x;
|
|
101
|
+
target_bounds.max_x = this->max_x;
|
|
102
|
+
target_bounds.min_y = this->min_y_;
|
|
103
|
+
target_bounds.max_y = this->max_y_;
|
|
104
|
+
}
|
|
@@ -52,6 +52,7 @@ class Polyline : public Partitionable {
|
|
|
52
52
|
InnerPolyline* inside_inner_polyline = nullptr;
|
|
53
53
|
std::string named();
|
|
54
54
|
void set_named(std::string force_named) { this->named_ = force_named; }
|
|
55
|
+
void fill_bounds(RectBounds& target_bounds) const;
|
|
55
56
|
|
|
56
57
|
private:
|
|
57
58
|
std::vector<Point*> raw_;
|
|
@@ -107,10 +107,14 @@ std::string Tile::toString() {
|
|
|
107
107
|
|
|
108
108
|
std::list<Polygon> Tile::to_raw_polygons()
|
|
109
109
|
{ std::list<Polygon> retme;
|
|
110
|
+
bool bounds = this->finder->options().bounds;
|
|
110
111
|
for (Shape* s : shapes_)
|
|
111
112
|
{ if (s->outer_polyline && !s->outer_polyline->is_empty())
|
|
112
113
|
{ Polygon poly;
|
|
113
114
|
poly.outer = s->outer_polyline->raw();
|
|
115
|
+
if (bounds) {
|
|
116
|
+
s->outer_polyline->fill_bounds(poly.bounds);
|
|
117
|
+
}
|
|
114
118
|
if (!s->inner_polylines.empty()) {
|
|
115
119
|
for (auto inner : s->inner_polylines) {
|
|
116
120
|
poly.inner.push_back(inner->raw());
|
|
@@ -21,7 +21,7 @@ VerticalMerger::VerticalMerger(int number_of_threads, std::vector<std::string> *
|
|
|
21
21
|
|
|
22
22
|
void VerticalMerger::add_tile(ProcessResult& result)
|
|
23
23
|
{ transpose(result);
|
|
24
|
-
if (this->
|
|
24
|
+
if (this->tiles_.size() > 0) {
|
|
25
25
|
translate(result, this->current_x);
|
|
26
26
|
}
|
|
27
27
|
adjust(result);
|
|
@@ -172,6 +172,7 @@ class To_Ruby<ProcessResult*>
|
|
|
172
172
|
}
|
|
173
173
|
RubyResult* rr = new RubyResult();
|
|
174
174
|
Rice::Data_Object<RubyResult> rb_result(rr);
|
|
175
|
+
bool inject_bounds = pr->has_bounds;
|
|
175
176
|
|
|
176
177
|
Rice::Hash return_me = Rice::Hash();
|
|
177
178
|
Rice::Hash benchmarks_rb;
|
|
@@ -206,12 +207,14 @@ class To_Ruby<ProcessResult*>
|
|
|
206
207
|
}
|
|
207
208
|
poly_hash[Symbol("inner")] = inner_collection;
|
|
208
209
|
// BOUNDS
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
210
|
+
if (inject_bounds) {
|
|
211
|
+
Rice::Hash bounds_hash = Rice::Hash();
|
|
212
|
+
bounds_hash[Symbol("min_x")] = x.bounds.min_x;
|
|
213
|
+
bounds_hash[Symbol("max_x")] = x.bounds.max_x;
|
|
214
|
+
bounds_hash[Symbol("min_y")] = x.bounds.min_y;
|
|
215
|
+
bounds_hash[Symbol("max_y")] = x.bounds.max_y;
|
|
216
|
+
poly_hash[Symbol("bounds")] = bounds_hash;
|
|
217
|
+
}
|
|
215
218
|
|
|
216
219
|
out.push(poly_hash);
|
|
217
220
|
}
|
|
@@ -19,8 +19,9 @@ module Contrek
|
|
|
19
19
|
def points
|
|
20
20
|
raw_list = polygons.to_a
|
|
21
21
|
@to_points ||= raw_list.map do |polygon|
|
|
22
|
-
{
|
|
23
|
-
|
|
22
|
+
{bounds: (polygon[:bounds] if polygon.key?(:bounds)),
|
|
23
|
+
outer: self.class.to_points(polygon[:outer]),
|
|
24
|
+
inner: polygon[:inner].map { |s| self.class.to_points(s) }}.compact
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
27
|
|
|
@@ -54,8 +54,9 @@ module Contrek
|
|
|
54
54
|
def to_raw_polygons
|
|
55
55
|
@shapes.filter_map do |shape|
|
|
56
56
|
unless shape.outer_polyline.empty?
|
|
57
|
-
{
|
|
58
|
-
|
|
57
|
+
{bounds: (shape.outer_polyline.get_bounds if @finder.options[:bounds]),
|
|
58
|
+
outer: shape.outer_polyline.raw,
|
|
59
|
+
inner: shape.inner_polylines.map(&:raw)}.compact
|
|
59
60
|
end
|
|
60
61
|
end
|
|
61
62
|
end
|
data/lib/contrek/version.rb
CHANGED
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.2.
|
|
4
|
+
version: 1.2.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emanuele Cesaroni
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -301,7 +301,7 @@ metadata:
|
|
|
301
301
|
homepage_uri: https://github.com/runout77/contrek
|
|
302
302
|
documentation_uri: https://github.com/runout77/contrek#readme
|
|
303
303
|
changelog_uri: https://github.com/runout77/contrek/blob/main/CHANGELOG.md
|
|
304
|
-
post_install_message:
|
|
304
|
+
post_install_message:
|
|
305
305
|
rdoc_options: []
|
|
306
306
|
require_paths:
|
|
307
307
|
- lib
|
|
@@ -317,7 +317,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
317
317
|
version: '0'
|
|
318
318
|
requirements: []
|
|
319
319
|
rubygems_version: 3.5.22
|
|
320
|
-
signing_key:
|
|
320
|
+
signing_key:
|
|
321
321
|
specification_version: 4
|
|
322
322
|
summary: Fast PNG contour tracing and shape detection for Ruby
|
|
323
323
|
test_files: []
|