contrek 1.0.8 → 1.0.9
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 +80 -8
- data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +39 -0
- data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +43 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +72 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +14 -20
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +1 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +3 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +13 -9
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +1 -2
- data/lib/contrek/finder/concurrent/cluster.rb +1 -1
- data/lib/contrek/finder/concurrent/cursor.rb +2 -1
- data/lib/contrek/finder/concurrent/hub.rb +3 -4
- data/lib/contrek/finder/concurrent/part.rb +2 -1
- data/lib/contrek/finder/concurrent/polyline.rb +1 -0
- data/lib/contrek/finder/concurrent/position.rb +3 -4
- data/lib/contrek/version.rb +1 -1
- metadata +5 -4
- data/ext/cpp_polygon_finder/PolygonFinder/Makefile +0 -44
- data/ext/cpp_polygon_finder/PolygonFinder/src/Main.cpp +0 -50
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15c162c3876502f8e8710ce261825dfe7fa66e1b600db084763e02ef70876a37
|
|
4
|
+
data.tar.gz: 32203f85040726d71ac519aac811d4078474c85dcd7c7b08227f1cea7e3b485f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9f8d2a44f087f96cfeacc8df8dec0973bf301f770ae45e82e6bf7d01902546c280c0446ee9c281c850a8e7c8965309e20d1a723ec269e60a99d386c288af0e7
|
|
7
|
+
data.tar.gz: 4d2c5c834fca24731866d0a56cc64d4aeac12437fac11b78389c38f7fbed9e637c785eb2a3357fb5c90a5fc257b2d010fe36cac2f84db3888f2b311276c42895
|
data/CHANGELOG.md
CHANGED
|
@@ -29,3 +29,8 @@ All notable changes to this project will be documented in this file.
|
|
|
29
29
|
- Fixed ARGB/RGBA format discrepancies between Ruby and C++.
|
|
30
30
|
- Updated the multithreading-side algorithm for rejoining mono-connected orphan polygons to other orphan polygons. The algorithm can now identify them and defer their processing within the pipeline.
|
|
31
31
|
- Improved, on the multithreading side, the polygon intersection detection mechanism; the geometric approach has been dropped in favor of a purely topological one.
|
|
32
|
+
|
|
33
|
+
## [1.0.9] - 2026-01-31
|
|
34
|
+
### Added
|
|
35
|
+
- **CMake Integration**: The library is now fully modularized via CMake, enabling seamless integration as a dependency in external C++ projects.
|
|
36
|
+
- Multithreading Algorithm Optimization.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Contrek
|
|
2
|
-
Contrek is a Ruby gem
|
|
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.
|
|
3
3
|
|
|
4
4
|
## About Contrek library
|
|
5
5
|
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.
|
|
@@ -99,7 +99,7 @@ Regarding multithreading:
|
|
|
99
99
|
|
|
100
100
|
- The treemap option is currently ignored (multithreaded treemap support will be introduced in upcoming revisions).
|
|
101
101
|
|
|
102
|
-
By not declaring native option CPP Multithreading optimized code is used. In the above example a [105 MP image](spec/files/images/sample_10240x10240.png) is examined by 2 threads working on 2 tiles (total compute time about
|
|
102
|
+
By not declaring native option CPP Multithreading optimized code is used. In the above example a [105 MP image](spec/files/images/sample_10240x10240.png) is examined by 2 threads working on 2 tiles (total compute time about 1.66 secs with image load).
|
|
103
103
|
|
|
104
104
|
```ruby
|
|
105
105
|
result = Contrek.contour!(
|
|
@@ -113,11 +113,13 @@ result = Contrek.contour!(
|
|
|
113
113
|
)
|
|
114
114
|
puts result.metadata[:benchmarks].inspect
|
|
115
115
|
|
|
116
|
-
{"compress"=>
|
|
117
|
-
"init"=>
|
|
118
|
-
"inner"=>
|
|
119
|
-
"outer"=>
|
|
120
|
-
"total"=>
|
|
116
|
+
{ "compress"=>13.423765,
|
|
117
|
+
"init"=>612.654121,
|
|
118
|
+
"inner"=>14.8930669,
|
|
119
|
+
"outer"=>33.0693249,
|
|
120
|
+
"total"=>626.0778879
|
|
121
|
+
}
|
|
122
|
+
|
|
121
123
|
```
|
|
122
124
|
|
|
123
125
|
## Result
|
|
@@ -262,7 +264,77 @@ This the one for the native C++
|
|
|
262
264
|
}
|
|
263
265
|
```
|
|
264
266
|
|
|
265
|
-
About 75x faster. Times are in microseconds; system: AMD Ryzen 7 3700X 8-Core Processor (BogoMIPS: 7199,99) on Ubuntu distro.
|
|
267
|
+
About 75x faster. Times are in microseconds; system: AMD Ryzen 7 3700X 8-Core Processor (BogoMIPS: 7199,99) on Ubuntu distro.
|
|
268
|
+
|
|
269
|
+
## 🛠 C++ Standalone Library Usage
|
|
270
|
+
|
|
271
|
+
The core of **Contrek** is a high-performance `C++17` library. It is designed to be **standalone**, meaning it has zero dependencies on Ruby and can be integrated into any `C++` project.
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
### Prerequisites
|
|
275
|
+
* **CMake** (3.10+)
|
|
276
|
+
* **ZLIB** (Required for PNG processing)
|
|
277
|
+
* **C++17 Compiler**
|
|
278
|
+
|
|
279
|
+
### 1. Build & Run Examples
|
|
280
|
+
If you want to test the performances or see the library in action:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Navigate to the core folder
|
|
284
|
+
cd ext/cpp_polygon_finder/PolygonFinder
|
|
285
|
+
|
|
286
|
+
# Setup build directory
|
|
287
|
+
mkdir build && cd build
|
|
288
|
+
|
|
289
|
+
# Configure with examples enabled
|
|
290
|
+
cmake -DBUILD_EXAMPLES=ON ..
|
|
291
|
+
|
|
292
|
+
# Build and run
|
|
293
|
+
make
|
|
294
|
+
./contrek_test
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 2. How to integrate it into your project
|
|
298
|
+
|
|
299
|
+
To use Contrek's engine in your own C++ application without Ruby:
|
|
300
|
+
|
|
301
|
+
1. **Copy the core folder**: Take the `ext/cpp_polygon_finder/PolygonFinder` directory and place it inside your project (e.g., in a `libs/` or `third_party/` folder).
|
|
302
|
+
2. **Update your CMakeLists.txt**: Add these lines to link the library:
|
|
303
|
+
|
|
304
|
+
```cmake
|
|
305
|
+
# Tell CMake to include Contrek
|
|
306
|
+
add_subdirectory(libs/PolygonFinder)
|
|
307
|
+
|
|
308
|
+
# Link it to your executable
|
|
309
|
+
add_executable(my_app main.cpp)
|
|
310
|
+
target_link_libraries(my_app PRIVATE ContrekLib)
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 3. C++ API Quick Start
|
|
314
|
+
|
|
315
|
+
Contrek provides a high-level C++ API. Here is how you can use it in your standalone projects:
|
|
316
|
+
|
|
317
|
+
```cpp
|
|
318
|
+
#include "ContrekApi.h"
|
|
319
|
+
#include <iostream>
|
|
320
|
+
|
|
321
|
+
int main() {
|
|
322
|
+
// 1. Configure the engine
|
|
323
|
+
Contrek::Config cfg;
|
|
324
|
+
cfg.threads = 4;
|
|
325
|
+
cfg.tiles = 2;
|
|
326
|
+
|
|
327
|
+
// 2. Run the tracing process
|
|
328
|
+
// Supports PNG files via internal spng integration
|
|
329
|
+
auto result = Contrek::trace("path/to/image.png", cfg);
|
|
330
|
+
|
|
331
|
+
// 3. Access results
|
|
332
|
+
result->print_info(); // prints generic infos
|
|
333
|
+
std::cout << "Found polygons: " << result->groups << std::endl;
|
|
334
|
+
|
|
335
|
+
return 0;
|
|
336
|
+
}
|
|
337
|
+
```
|
|
266
338
|
|
|
267
339
|
## License
|
|
268
340
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.10)
|
|
2
|
+
project(ContrekCore C CXX)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
5
|
+
set(CMAKE_C_STANDARD 11)
|
|
6
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread -g -march=native -DNDEBUG -Ofast -flto")
|
|
7
|
+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -march=native -fPIC -DNDEBUG")
|
|
8
|
+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread -flto=auto -Wl,--no-as-needed")
|
|
9
|
+
|
|
10
|
+
find_package(ZLIB REQUIRED)
|
|
11
|
+
|
|
12
|
+
file(GLOB_RECURSE CPP_SOURCES "*.cpp")
|
|
13
|
+
file(GLOB_RECURSE C_SOURCES "*.c")
|
|
14
|
+
|
|
15
|
+
list(FILTER CPP_SOURCES EXCLUDE REGEX "examples/.*\\.cpp")
|
|
16
|
+
|
|
17
|
+
add_library(ContrekLib STATIC ${CPP_SOURCES} ${C_SOURCES})
|
|
18
|
+
|
|
19
|
+
file(GLOB_RECURSE ALL_HEADERS "*.h")
|
|
20
|
+
foreach(header_file ${ALL_HEADERS})
|
|
21
|
+
get_filename_component(header_dir ${header_file} DIRECTORY)
|
|
22
|
+
list(APPEND ALL_INCLUDE_DIRS ${header_dir})
|
|
23
|
+
endforeach()
|
|
24
|
+
list(REMOVE_DUPLICATES ALL_INCLUDE_DIRS)
|
|
25
|
+
|
|
26
|
+
target_include_directories(ContrekLib PUBLIC ${ALL_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS})
|
|
27
|
+
target_link_libraries(ContrekLib PRIVATE ${ZLIB_LIBRARIES} pthread)
|
|
28
|
+
|
|
29
|
+
option(BUILD_EXAMPLES "Build the example application" OFF)
|
|
30
|
+
|
|
31
|
+
if(BUILD_EXAMPLES)
|
|
32
|
+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples/example.cpp")
|
|
33
|
+
message(STATUS "Contrek: Compiling example option ON")
|
|
34
|
+
add_executable(contrek_test examples/example.cpp)
|
|
35
|
+
target_link_libraries(contrek_test PRIVATE ContrekLib)
|
|
36
|
+
else()
|
|
37
|
+
message(WARNING "Contrek: examples/example.cpp not found!")
|
|
38
|
+
endif()
|
|
39
|
+
endif()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//============================================================================
|
|
2
|
+
// Name : example.cpp
|
|
3
|
+
// Author : Emanuele Cesaroni
|
|
4
|
+
// Version :
|
|
5
|
+
// Copyright : 2025 Emanuele Cesaroni
|
|
6
|
+
// Description :
|
|
7
|
+
//============================================================================
|
|
8
|
+
|
|
9
|
+
#include <iostream>
|
|
10
|
+
#include "ContrekApi.h"
|
|
11
|
+
#include "Tests.h"
|
|
12
|
+
|
|
13
|
+
void run_test() {
|
|
14
|
+
CpuTimer cpu_timer;
|
|
15
|
+
Tests test_suite;
|
|
16
|
+
cpu_timer.start();
|
|
17
|
+
|
|
18
|
+
// test_suite.test_a();
|
|
19
|
+
// test_suite.test_b();
|
|
20
|
+
// test_suite.test_c();
|
|
21
|
+
// test_suite.test_d();
|
|
22
|
+
// test_suite.test_e();
|
|
23
|
+
test_suite.test_f();
|
|
24
|
+
std::cout << "compute time =" << cpu_timer.stop() << std::endl;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
int main() {
|
|
28
|
+
Contrek::Config cfg;
|
|
29
|
+
cfg.threads = 2;
|
|
30
|
+
cfg.tiles = 2;
|
|
31
|
+
cfg.compress_unique = true;
|
|
32
|
+
|
|
33
|
+
CpuTimer cpu_timer;
|
|
34
|
+
cpu_timer.start();
|
|
35
|
+
std::cout << "--- Start Native Benchmark ---" << std::endl;
|
|
36
|
+
auto result = Contrek::trace("../images/sample_10240x10240.png", cfg);
|
|
37
|
+
result->print_info();
|
|
38
|
+
std::cout << "Found polygons: " << result->groups << std::endl;
|
|
39
|
+
std::cout << "Time: " << cpu_timer.stop() << " ms" << std::endl;
|
|
40
|
+
|
|
41
|
+
// run_test();
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ContrekApi.h
|
|
3
|
+
*
|
|
4
|
+
* Created on: 25 gen 2026
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include <memory>
|
|
14
|
+
#include <cstdint>
|
|
15
|
+
|
|
16
|
+
#include "Finder.h"
|
|
17
|
+
#include "FastPngBitmap.h"
|
|
18
|
+
#include "RGBNotMatcher.h"
|
|
19
|
+
#include "RGBMatcher.h"
|
|
20
|
+
|
|
21
|
+
namespace Contrek {
|
|
22
|
+
|
|
23
|
+
enum class MatchMode {
|
|
24
|
+
NOT_COLOR, // Tracks border of what is not target color
|
|
25
|
+
EXACT_COLOR // Tracks border of what exactly matchs target color
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
struct Config {
|
|
29
|
+
int threads = 4;
|
|
30
|
+
int tiles = 2;
|
|
31
|
+
bool compress_unique = false;
|
|
32
|
+
bool compress_linear = false;
|
|
33
|
+
bool compress_visvalingam = false;
|
|
34
|
+
bool treemap = false;
|
|
35
|
+
int32_t target_color = -1;
|
|
36
|
+
MatchMode mode = MatchMode::NOT_COLOR;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
inline std::unique_ptr<ProcessResult> trace(const std::string& image_path, const Config& cfg = Config()) {
|
|
40
|
+
auto bitmap = std::make_unique<FastPngBitmap>(image_path);
|
|
41
|
+
|
|
42
|
+
int32_t color_to_match = (cfg.target_color == -1)
|
|
43
|
+
? bitmap->rgb_value_at(0, 0)
|
|
44
|
+
: cfg.target_color;
|
|
45
|
+
|
|
46
|
+
std::unique_ptr<Matcher> matcher;
|
|
47
|
+
if (cfg.mode == MatchMode::NOT_COLOR) {
|
|
48
|
+
matcher = std::make_unique<RGBNotMatcher>(color_to_match);
|
|
49
|
+
} else {
|
|
50
|
+
matcher = std::make_unique<RGBMatcher>(color_to_match);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
std::vector<std::string> internal_args = {"--versus=a"};
|
|
54
|
+
struct Mapping { bool flag; std::string_view arg; };
|
|
55
|
+
const Mapping mappings[] = {
|
|
56
|
+
{cfg.compress_unique, "--compress_uniq"},
|
|
57
|
+
{cfg.compress_linear, "--compress_linear"},
|
|
58
|
+
{cfg.compress_visvalingam, "--compress_visvalingam"},
|
|
59
|
+
{cfg.treemap, "--treemap"}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
for (auto& m : mappings) {
|
|
63
|
+
if (m.flag) internal_args.emplace_back(m.arg);
|
|
64
|
+
}
|
|
65
|
+
internal_args.push_back("--number_of_tiles=" + std::to_string(cfg.tiles));
|
|
66
|
+
|
|
67
|
+
Finder finder(cfg.threads, bitmap.get(), matcher.get(), &internal_args);
|
|
68
|
+
|
|
69
|
+
return std::unique_ptr<ProcessResult>(finder.process_info());
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
} // namespace Contrek
|
|
@@ -28,12 +28,6 @@
|
|
|
28
28
|
#include "polygon/finder/concurrent/Position.h"
|
|
29
29
|
#include "polygon/finder/Polygon.h"
|
|
30
30
|
|
|
31
|
-
Tests::Tests() {
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
Tests::~Tests() {
|
|
35
|
-
}
|
|
36
|
-
|
|
37
31
|
void Tests::test_a()
|
|
38
32
|
{ std::string chunk =
|
|
39
33
|
"0000000000000000"\
|
|
@@ -79,22 +73,10 @@ void Tests::test_b()
|
|
|
79
73
|
" XX XX "\
|
|
80
74
|
" XX XX "\
|
|
81
75
|
" XXXXXXXXXXX ";
|
|
82
|
-
// "0123456789012345"
|
|
83
|
-
/*chunk = " XXXXXXXXXXX "\
|
|
84
|
-
" XX XX XX "\
|
|
85
|
-
" XX XX XX "\
|
|
86
|
-
" XX XX XX "\
|
|
87
|
-
" XXXXXXXXXXX ";*/
|
|
88
76
|
|
|
89
77
|
std::vector<std::string> arguments = {"--versus=o", "--number_of_tiles=2", "--compress_uniq", "--compress_linear", "--treemap"};
|
|
90
78
|
ValueNotMatcher matcher(' ');
|
|
91
79
|
Bitmap b(chunk, 16);
|
|
92
|
-
|
|
93
|
-
/*ClippedPolygonFinder pl(&b, &matcher, 0, 16, &arguments);
|
|
94
|
-
ProcessResult *pr = pl.process_info();
|
|
95
|
-
pr->print_polygons();
|
|
96
|
-
delete pr;*/
|
|
97
|
-
|
|
98
80
|
Finder concurrentFinder(2, &b, &matcher, &arguments);
|
|
99
81
|
ProcessResult *pro = concurrentFinder.process_info();
|
|
100
82
|
pro->print_polygons();
|
|
@@ -155,7 +137,7 @@ void Tests::test_c()
|
|
|
155
137
|
void Tests::test_d()
|
|
156
138
|
{ CpuTimer cpu_timer;
|
|
157
139
|
cpu_timer.start();
|
|
158
|
-
FastPngBitmap png_bitmap("images/sample_10240x10240.png");
|
|
140
|
+
FastPngBitmap png_bitmap("../images/sample_10240x10240.png");
|
|
159
141
|
// FastPngBitmap png_bitmap("images/labyrinth.png");
|
|
160
142
|
std::cout << "image_w=" << png_bitmap.w() << " image_h=" << png_bitmap.h() << std::endl;
|
|
161
143
|
std::cout << "immagine =" << cpu_timer.stop() << std::endl;
|
|
@@ -174,7 +156,7 @@ void Tests::test_d()
|
|
|
174
156
|
void Tests::test_e()
|
|
175
157
|
{ CpuTimer cpu_timer;
|
|
176
158
|
cpu_timer.start();
|
|
177
|
-
FastPngBitmap png_bitmap("images/sample_10240x10240.png");
|
|
159
|
+
FastPngBitmap png_bitmap("../images/sample_10240x10240.png");
|
|
178
160
|
// FastPngBitmap png_bitmap("images/sample_1024x1024.png");
|
|
179
161
|
std::cout << "image reading time =" << cpu_timer.stop() << std::endl;
|
|
180
162
|
|
|
@@ -189,3 +171,15 @@ void Tests::test_e()
|
|
|
189
171
|
std::cout << "polygons =" << o->groups << std::endl;
|
|
190
172
|
delete o;
|
|
191
173
|
}
|
|
174
|
+
|
|
175
|
+
void Tests::test_f()
|
|
176
|
+
{ FastPngBitmap png_bitmap("../images/labyrinth.png");
|
|
177
|
+
std::cout << "image_w=" << png_bitmap.w() << " image_h=" << png_bitmap.h() << std::endl;
|
|
178
|
+
std::cout << "load_error=" << png_bitmap.error() << std::endl;
|
|
179
|
+
|
|
180
|
+
std::string data_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==";
|
|
181
|
+
data_url.erase(0, 22);
|
|
182
|
+
RemoteFastPngBitmap bitmap(&data_url);
|
|
183
|
+
std::cout << "image_w=" << bitmap.w() << " image_h=" << bitmap.h() << std::endl;
|
|
184
|
+
std::cout << "load_error=" << bitmap.error() << std::endl;
|
|
185
|
+
}
|
|
@@ -289,7 +289,7 @@ void Cursor::traverse_inner(Part* act_part, std::vector<Part*>& all_parts, Bound
|
|
|
289
289
|
} else {
|
|
290
290
|
for (Shape *shape : act_part->polyline()->next_tile_eligible_shapes()) {
|
|
291
291
|
for (Part* dest_part : shape->outer_polyline->parts()) {
|
|
292
|
-
if (dest_part->trasmuted) continue;
|
|
292
|
+
if (dest_part->trasmuted || dest_part->is(Part::EXCLUSIVE)) continue;
|
|
293
293
|
if (dest_part->intersect_part(act_part)) {
|
|
294
294
|
std::vector<Point*> link_seq = duplicates_intersection(*dest_part, *act_part);
|
|
295
295
|
if (!link_seq.empty()) {
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
Hub::Hub(int height, int start_x, int end_x)
|
|
13
13
|
: width_(end_x - start_x), height_(height), start_x_(start_x)
|
|
14
|
-
{ size_t total_pixels = static_cast<size_t>(
|
|
14
|
+
{ size_t total_pixels = static_cast<size_t>(height);
|
|
15
15
|
payloads_.resize(total_pixels);
|
|
16
16
|
bitset_.resize((total_pixels + 63) / 64, 0);
|
|
17
17
|
std::memset(bitset_.data(), 0, bitset_.size() * sizeof(uint64_t));
|
|
18
|
+
endpoint_pool_.resize(total_pixels);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
int Hub::spawn_end_point() {
|
|
@@ -44,7 +44,8 @@ Position* Part::next_position(Position* force_position) {
|
|
|
44
44
|
|
|
45
45
|
void Part::add_position(Point* point) {
|
|
46
46
|
Cluster* c = this->polyline_->tile->cluster;
|
|
47
|
-
|
|
47
|
+
Hub* hub = is(EXCLUSIVE) ? nullptr : c->hub();
|
|
48
|
+
c->positions_pool.emplace_back(hub, point);
|
|
48
49
|
this->add(&c->positions_pool.back());
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -76,7 +76,9 @@ std::vector<std::pair<int, int>> Polyline::intersection(const Polyline* other) c
|
|
|
76
76
|
if (!part->is(Part::SEAM) && part->trasmuted) continue;
|
|
77
77
|
part->each([&](QNode<Point>* pos) -> bool {
|
|
78
78
|
Position *position = dynamic_cast<Position*>(pos);
|
|
79
|
-
|
|
79
|
+
if (position->end_point() != nullptr)
|
|
80
|
+
{ this->tracked_endpoints[position->end_point()] = i;
|
|
81
|
+
}
|
|
80
82
|
return true;
|
|
81
83
|
});
|
|
82
84
|
}
|
|
@@ -11,20 +11,24 @@
|
|
|
11
11
|
|
|
12
12
|
Position::Position(Hub* hub, Point* point)
|
|
13
13
|
: QNode<Point>(point)
|
|
14
|
-
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
{ if (hub != nullptr) {
|
|
15
|
+
int key = point->y;
|
|
16
|
+
EndPoint* existing_ep = hub->get(key);
|
|
17
|
+
if (existing_ep == nullptr)
|
|
18
|
+
{ end_point_ = hub->put(key, hub->spawn_end_point());
|
|
19
|
+
} else {
|
|
20
|
+
end_point_ = existing_ep;
|
|
21
|
+
}
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
void Position::before_rem(Queueable<Point>* q) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
if (this->end_point_ != nullptr) {
|
|
27
|
+
auto& queues = this->end_point_->queues();
|
|
28
|
+
queues.erase(std::remove(queues.begin(), queues.end(), q), queues.end());
|
|
29
|
+
}
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
void Position::after_add(Queueable<Point>* q) {
|
|
29
|
-
this->end_point_->queues().push_back(q);
|
|
33
|
+
if (this->end_point_ != nullptr) this->end_point_->queues().push_back(q);
|
|
30
34
|
}
|
|
@@ -43,8 +43,7 @@ class Queueable {
|
|
|
43
43
|
|
|
44
44
|
QNode<T>* rem(QNode<T>* node) {
|
|
45
45
|
if (!node) return nullptr;
|
|
46
|
-
if (node->owner != this)
|
|
47
|
-
throw std::runtime_error("Not my node");
|
|
46
|
+
// if (node->owner != this) throw std::runtime_error("Not my node");
|
|
48
47
|
node->before_rem(this);
|
|
49
48
|
if (node->prev) node->prev->next = node->next;
|
|
50
49
|
if (node->next) node->next->prev = node->prev;
|
|
@@ -182,7 +182,8 @@ module Contrek
|
|
|
182
182
|
else
|
|
183
183
|
act_part.polyline.next_tile_eligible_shapes.each do |shape|
|
|
184
184
|
shape.outer_polyline.parts.each do |dest_part|
|
|
185
|
-
next if dest_part.trasmuted
|
|
185
|
+
next if dest_part.trasmuted || dest_part.is?(Part::EXCLUSIVE)
|
|
186
|
+
|
|
186
187
|
if dest_part.intersect_part?(act_part)
|
|
187
188
|
link_seq = duplicates_intersection(dest_part, act_part)
|
|
188
189
|
if link_seq.any?
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
module Contrek
|
|
2
2
|
module Concurrent
|
|
3
3
|
class Hub
|
|
4
|
-
attr_reader :payloads
|
|
5
|
-
def initialize(start_x:, end_x:)
|
|
6
|
-
@
|
|
7
|
-
# @payloads = Array.new(width * height)
|
|
4
|
+
attr_reader :payloads
|
|
5
|
+
def initialize(height:, start_x:, end_x:)
|
|
6
|
+
# @payloads = Array.new(height)
|
|
8
7
|
@payloads = {}
|
|
9
8
|
end
|
|
10
9
|
end
|
|
@@ -31,7 +31,8 @@ module Contrek
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def add_position(position)
|
|
34
|
-
|
|
34
|
+
hub = is?(EXCLUSIVE) ? nil : polyline.tile.cluster.hub
|
|
35
|
+
add(Position.new(position: position, hub: hub))
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
def next_position(force_position = nil)
|
|
@@ -6,8 +6,7 @@ module Contrek
|
|
|
6
6
|
attr_reader :end_point
|
|
7
7
|
|
|
8
8
|
def initialize(hub:, position:)
|
|
9
|
-
|
|
10
|
-
@end_point = hub.payloads[key] ||= EndPoint.new
|
|
9
|
+
@end_point = hub.payloads[position[:y]] ||= EndPoint.new if hub
|
|
11
10
|
@position = position
|
|
12
11
|
end
|
|
13
12
|
|
|
@@ -16,11 +15,11 @@ module Contrek
|
|
|
16
15
|
end
|
|
17
16
|
|
|
18
17
|
def after_add(new_queue)
|
|
19
|
-
@end_point.queues << new_queue
|
|
18
|
+
@end_point.queues << new_queue if @end_point
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
def before_rem(old_queue)
|
|
23
|
-
@end_point
|
|
22
|
+
@end_point&.queues&.delete(old_queue)
|
|
24
23
|
end
|
|
25
24
|
end
|
|
26
25
|
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.0.
|
|
4
|
+
version: 1.0.9
|
|
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-01-
|
|
11
|
+
date: 2026-01-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -140,10 +140,11 @@ files:
|
|
|
140
140
|
- Rakefile
|
|
141
141
|
- contrek.gemspec
|
|
142
142
|
- contrek.png
|
|
143
|
-
- ext/cpp_polygon_finder/PolygonFinder/
|
|
143
|
+
- ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt
|
|
144
|
+
- ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp
|
|
144
145
|
- ext/cpp_polygon_finder/PolygonFinder/images/labyrinth.png
|
|
145
146
|
- ext/cpp_polygon_finder/PolygonFinder/images/sample_10240x10240.png
|
|
146
|
-
- ext/cpp_polygon_finder/PolygonFinder/src/
|
|
147
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h
|
|
147
148
|
- ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp
|
|
148
149
|
- ext/cpp_polygon_finder/PolygonFinder/src/Tests.h
|
|
149
150
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/CpuTimer.h
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
CXX = g++
|
|
2
|
-
CXXFLAGS = -Wall -Wextra -std=c++17 -Isrc -MMD -MP -pthread -g \
|
|
3
|
-
-fno-omit-frame-pointer -fsanitize=address,undefined \
|
|
4
|
-
-O0
|
|
5
|
-
LDFLAGS = -pthread -lz -fsanitize=address,undefined
|
|
6
|
-
|
|
7
|
-
# valgrinf or perf setup
|
|
8
|
-
# CXXFLAGS = -Wall -Wextra -std=c++17 -Isrc -MMD -MP -pthread -g -fno-omit-frame-pointer -march=native -DNDEBUG -O3
|
|
9
|
-
# LDFLAGS = -lpng -pthread -lz
|
|
10
|
-
|
|
11
|
-
# best performances
|
|
12
|
-
CXXFLAGS = -Wall -Wextra -std=c++17 -Isrc -MMD -MP -pthread -g -march=native -DNDEBUG -Ofast -flto
|
|
13
|
-
LDFLAGS = -pthread -lz -flto=auto
|
|
14
|
-
|
|
15
|
-
SRC = $(shell find src -name '*.cpp')
|
|
16
|
-
C_SRC = $(shell find src -name 'spng.c')
|
|
17
|
-
|
|
18
|
-
OBJ = $(patsubst src/%.cpp, build/%.o, $(SRC))
|
|
19
|
-
OBJ += $(patsubst src/%.c, build/%.o, $(C_SRC))
|
|
20
|
-
|
|
21
|
-
DEPS = $(OBJ:.o=.d)
|
|
22
|
-
|
|
23
|
-
EXEC = contrek
|
|
24
|
-
|
|
25
|
-
all: $(EXEC)
|
|
26
|
-
|
|
27
|
-
$(EXEC): $(OBJ)
|
|
28
|
-
$(CXX) $(CXXFLAGS) $(OBJ) -o $@ -Wl,--no-as-needed $(LDFLAGS)
|
|
29
|
-
|
|
30
|
-
build/%.o: src/%.cpp
|
|
31
|
-
@mkdir -p $(dir $@)
|
|
32
|
-
$(CXX) $(CXXFLAGS) -c $< -o $@
|
|
33
|
-
|
|
34
|
-
build/%.o: src/%.c
|
|
35
|
-
@mkdir -p $(dir $@)
|
|
36
|
-
$(CC) -O3 -march=native -fPIC -c $< -o $@
|
|
37
|
-
|
|
38
|
-
-include $(DEPS)
|
|
39
|
-
|
|
40
|
-
clean:
|
|
41
|
-
rm -rf build $(EXEC)
|
|
42
|
-
|
|
43
|
-
run: all
|
|
44
|
-
./$(EXEC)
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
//============================================================================
|
|
2
|
-
// Name : PolygonFinder.cpp
|
|
3
|
-
// Author : Emanuele Cesaroni
|
|
4
|
-
// Version :
|
|
5
|
-
// Copyright : 2025 Emanuele Cesaroni
|
|
6
|
-
// Description :
|
|
7
|
-
//============================================================================
|
|
8
|
-
|
|
9
|
-
#include <string.h>
|
|
10
|
-
#include <iostream>
|
|
11
|
-
#include <list>
|
|
12
|
-
#include <map>
|
|
13
|
-
#include <string>
|
|
14
|
-
#include "polygon/finder/PolygonFinder.h"
|
|
15
|
-
#include "polygon/bitmaps/Bitmap.h"
|
|
16
|
-
#include "polygon/bitmaps/FastPngBitmap.h"
|
|
17
|
-
#include "polygon/bitmaps/RemoteFastPngBitmap.h"
|
|
18
|
-
#include "polygon/matchers/Matcher.h"
|
|
19
|
-
#include "polygon/matchers/RGBMatcher.h"
|
|
20
|
-
#include "polygon/matchers/RGBNotMatcher.h"
|
|
21
|
-
#include "polygon/matchers/ValueNotMatcher.h"
|
|
22
|
-
#include "polygon/finder/optionparser.h"
|
|
23
|
-
#include "Tests.h"
|
|
24
|
-
#include "polygon/CpuTimer.h"
|
|
25
|
-
|
|
26
|
-
int main() {
|
|
27
|
-
CpuTimer cpu_timer;
|
|
28
|
-
Tests test_suite;
|
|
29
|
-
cpu_timer.start();
|
|
30
|
-
|
|
31
|
-
// test_suite.test_a();
|
|
32
|
-
// test_suite.test_b();
|
|
33
|
-
// test_suite.test_c();
|
|
34
|
-
// test_suite.test_d();
|
|
35
|
-
test_suite.test_e();
|
|
36
|
-
std::cout << "compute time =" << cpu_timer.stop() << std::endl;
|
|
37
|
-
|
|
38
|
-
/*
|
|
39
|
-
FastPngBitmap png_bitmap("images/labyrinth.png");
|
|
40
|
-
std::cout << "image_w=" << png_bitmap.w() << " image_h=" << png_bitmap.h() << std::endl;
|
|
41
|
-
std::cout << "load_error=" << png_bitmap.error() << std::endl;
|
|
42
|
-
|
|
43
|
-
std::string data_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==";
|
|
44
|
-
data_url.erase(0, 22);
|
|
45
|
-
RemoteFastPngBitmap bitmap(&data_url);
|
|
46
|
-
std::cout << "image_w=" << bitmap.w() << " image_h=" << bitmap.h() << std::endl;
|
|
47
|
-
std::cout << "load_error=" << bitmap.error() << std::endl;
|
|
48
|
-
*/
|
|
49
|
-
return 0;
|
|
50
|
-
}
|