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.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +80 -8
  5. data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +39 -0
  6. data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +43 -0
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +72 -0
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +14 -20
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +1 -2
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +1 -1
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +2 -1
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +1 -1
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +2 -1
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +3 -1
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +13 -9
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +1 -1
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +1 -2
  18. data/lib/contrek/finder/concurrent/cluster.rb +1 -1
  19. data/lib/contrek/finder/concurrent/cursor.rb +2 -1
  20. data/lib/contrek/finder/concurrent/hub.rb +3 -4
  21. data/lib/contrek/finder/concurrent/part.rb +2 -1
  22. data/lib/contrek/finder/concurrent/polyline.rb +1 -0
  23. data/lib/contrek/finder/concurrent/position.rb +3 -4
  24. data/lib/contrek/version.rb +1 -1
  25. metadata +5 -4
  26. data/ext/cpp_polygon_finder/PolygonFinder/Makefile +0 -44
  27. 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: 862b863c602031251fedc2dc18a59c9bd270d91acff25761c24164e34e8952e9
4
- data.tar.gz: 97f18e804accd2d6ae11f95223c95eebe198eafb07c745261d1110f5edf5eae4
3
+ metadata.gz: 15c162c3876502f8e8710ce261825dfe7fa66e1b600db084763e02ef70876a37
4
+ data.tar.gz: 32203f85040726d71ac519aac811d4078474c85dcd7c7b08227f1cea7e3b485f
5
5
  SHA512:
6
- metadata.gz: d3d9ce7c0b5ae1a3c62f91480d63856312d89334f181899ccc2ff304c3fef983578838484da18f865ce1d50ea3cb3c291ce49fef1b01dcfaf397ab688bed9e37
7
- data.tar.gz: c8f7aade05577e132829e7ffcc6af5e637aa879bb6972f4ba8566c8db7d11b641862e32a170c39db4b8ab57666996a4639ffd3f516ba85712266b7ffd82ac276
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- contrek (1.0.8)
4
+ contrek (1.0.9)
5
5
  chunky_png (~> 1.4)
6
6
  concurrent-ruby (~> 1.3.5)
7
7
  rice (= 4.5.0)
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Contrek
2
- Contrek is a Ruby gem with a C++ core for fast contour tracing and edge detection in PNG images. Unlike standard geometric tracers, 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. 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 2 secs).
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"=>14.596786999999999,
117
- "init"=>2078.745861,
118
- "inner"=>1183.143734,
119
- "outer"=>118.94489599999999,
120
- "total"=>2093.342648}
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
+ }
@@ -10,11 +10,10 @@
10
10
 
11
11
  class Tests {
12
12
  public:
13
- Tests();
14
- virtual ~Tests();
15
13
  virtual void test_a();
16
14
  virtual void test_b();
17
15
  virtual void test_c();
18
16
  virtual void test_d();
19
17
  virtual void test_e();
18
+ virtual void test_f();
20
19
  };
@@ -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>(width_) * height;
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() {
@@ -37,7 +37,7 @@ class Hub {
37
37
  int height_;
38
38
  int start_x_;
39
39
  std::vector<int> payloads_;
40
- std::deque<EndPoint> endpoint_pool_;
40
+ std::vector<EndPoint> endpoint_pool_;
41
41
  Hub(const Hub&) = delete;
42
42
  Hub& operator=(const Hub&) = delete;
43
43
  std::vector<uint64_t> bitset_;
@@ -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
- c->positions_pool.emplace_back(c->hub(), point);
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
- this->tracked_endpoints[position->end_point()] = i;
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
- { int key = point->y * hub->width() + (point->x - hub->start_x());
15
- EndPoint* existing_ep = hub->get(key);
16
- if (existing_ep == nullptr)
17
- { end_point_ = hub->put(key, hub->spawn_end_point());
18
- } else {
19
- end_point_ = existing_ep;
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
- auto& queues = this->end_point_->queues();
25
- queues.erase(std::remove(queues.begin(), queues.end(), q), queues.end());
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
  }
@@ -21,5 +21,5 @@ class Position : public QNode<Point>{
21
21
  void before_rem(Queueable<Point>* q) override;
22
22
  void after_add(Queueable<Point>* q) override;
23
23
  private:
24
- EndPoint* end_point_;
24
+ EndPoint* end_point_ = nullptr;
25
25
  };
@@ -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;
@@ -6,7 +6,7 @@ module Contrek
6
6
  def initialize(finder:, height:, start_x:, end_x:)
7
7
  @finder = finder
8
8
  @tiles = []
9
- @hub = Hub.new(start_x:, end_x:)
9
+ @hub = Hub.new(height:, start_x:, end_x:)
10
10
  end
11
11
 
12
12
  def add(tile)
@@ -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, :width
5
- def initialize(start_x:, end_x:)
6
- @width = end_x - start_x
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
- add(Position.new(position: position, hub: polyline.tile.cluster.hub))
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)
@@ -66,6 +66,7 @@ module Contrek
66
66
  parts.each_with_index do |part, part_index|
67
67
  next if !part.is?(Part::SEAM) && part.trasmuted
68
68
  part.each do |pos|
69
+ next if pos.end_point.nil?
69
70
  @tracked_endpoints[pos.end_point.object_id] = part_index
70
71
  end
71
72
  end
@@ -6,8 +6,7 @@ module Contrek
6
6
  attr_reader :end_point
7
7
 
8
8
  def initialize(hub:, position:)
9
- key = position[:y] * hub.width + position[:x]
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.queues.delete(old_queue)
22
+ @end_point&.queues&.delete(old_queue)
24
23
  end
25
24
  end
26
25
  end
@@ -1,3 +1,3 @@
1
1
  module Contrek
2
- VERSION = "1.0.8"
2
+ VERSION = "1.0.9"
3
3
  end
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.8
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-25 00:00:00.000000000 Z
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/Makefile
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/Main.cpp
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
- }