contrek 1.3.5 → 1.3.6

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +5 -2
  5. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +13 -17
  6. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +78 -33
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +31 -101
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.h +2 -1
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +1 -2
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/OptionValue.h +91 -0
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Options.h +123 -0
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +4 -3
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +14 -6
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.cpp +1 -1
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.h +2 -1
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +19 -11
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +5 -4
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h +4 -5
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.cpp +1 -1
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.h +1 -1
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp +28 -2
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.h +3 -1
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +12 -0
  24. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +2 -0
  25. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp +16 -6
  26. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h +2 -2
  27. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/SvgStreamingMerger.h +1 -1
  28. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +1 -13
  29. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp +1 -1
  30. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.h +1 -1
  31. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +66 -24
  32. data/lib/contrek/finder/concurrent/finder.rb +2 -2
  33. data/lib/contrek/finder/concurrent/geo_json_streaming_merger.rb +3 -3
  34. data/lib/contrek/finder/concurrent/merger.rb +17 -1
  35. data/lib/contrek/finder/concurrent/shape.rb +6 -0
  36. data/lib/contrek/finder/concurrent/streaming_merger.rb +8 -4
  37. data/lib/contrek/finder/concurrent/tile.rb +2 -7
  38. data/lib/contrek/finder/node_cluster.rb +1 -1
  39. data/lib/contrek/finder/polygon_finder.rb +2 -0
  40. data/lib/contrek/reducers/visvalingam_reducer.rb +2 -1
  41. data/lib/contrek/version.rb +1 -1
  42. metadata +4 -3
  43. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/optionparser.h +0 -2858
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea7475a8d469db6be267562a802b7b8f09480774e6d3085a35a428f569d2f113
4
- data.tar.gz: 20370119576e765342797caad9778b7d808f9b6be154eca4e5a744f988d532f6
3
+ metadata.gz: 6e79871127e3d6aff04c8bd1e6ea9765d47542249a188b0cf151ce8a005ea29a
4
+ data.tar.gz: '055817b3638fcf582584e45e0ffef001305961321f8a05beb5998399b0be7bc6'
5
5
  SHA512:
6
- metadata.gz: b09fddc2bc46bb644f3024de98aa2db5155856981aaf3ce3a5dfaf5a8ef5449f36ad4fb784654bb12368fc8d2b2c0741a492c1f70ec4e620b4282d28268d770e
7
- data.tar.gz: 6240cd18e6145a3f47504decfab3d74decce51c0ddc91084d7ac7cf95e020cc7165bfca4d8d7831c760ca3ee3aaa63ae3b50fa1c75b5ed60ed13ae87544b9d36
6
+ metadata.gz: e3007307485a1ce6902f4f95b452b3ef2622fd2c59a0a27d8ee2564e0d8b512bdf8acc15ad5fac30b472b8d14263800324ac19ad74932eb220366860ad7ec60b
7
+ data.tar.gz: 38289075bb92eb56229f1206ff595a0ea65d6bcbbf271dcdc035d60ef8b1c7609cbae687367803ff3d2cb39eae9f8fe670fb893afdcff87df77d8c0ce7b1c928
data/CHANGELOG.md CHANGED
@@ -138,3 +138,9 @@ All notable changes to this project will be documented in this file.
138
138
 
139
139
  ## [1.3.4] - 2026-07-19
140
140
  - Refactored core topology from a top-left point model to a 4-vertex pixel-cell model, natively eliminating diagonal ambiguities and rewriting part of the stripe-merging algorithm to ensure perfect geometric stitching on shared nodes. Removed Strict Bounds mode. Added a Douglas-Peucker and a custom raster-compression algorithm that shifts top/right pixel boundaries by 1px to ensure flawless surface rendering as bitmap image.
141
+
142
+ ## [1.3.6] - 2026-07-26
143
+ - Removed optionparser.h and the legacy options argument mechanism, replacing them with the new OptionValue.h and Options.h
144
+ - Added polygon compression to the progressive streaming pipeline (StreamingMerger).
145
+ - Added strict validation in progressive streaming. Results passed to add_tile() are now validated to ensure they contain compatible settings (such as versus conventions and compression options).
146
+ - Added unsafe_mode flag to streaming mergers. This allows bypassing compatibility checks when using custom or arbitrary input data.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- contrek (1.3.4)
4
+ contrek (1.3.6)
5
5
  chunky_png (~> 1.4)
6
6
  concurrent-ruby (~> 1.3.5)
7
7
  rice (= 4.5.0)
data/README.md CHANGED
@@ -128,7 +128,7 @@ rgb_matcher = CPPRGBNotMatcher.new(png_bitmap.rgb_value_at(0, 0))
128
128
  polygonfinder = CPPPolygonFinder.new(png_bitmap,
129
129
  rgb_matcher,
130
130
  nil,
131
- {versus: :a, compress: {visvalingam: {tolerance: 1.5}}})
131
+ {versus: :a, compress: {visvalingam: true, visvalingam_tolerance: 1.5}})
132
132
  result = polygonfinder.process_info
133
133
  # draws the polygons found
134
134
  Contrek::Bitmaps::Painting.direct_draw_polygons(result.points, png_image)
@@ -312,8 +312,11 @@ result.metadata
312
312
  "total"=>0.05208},
313
313
  :groups=>1,
314
314
  :named_sequence=>"AFEDCBA",
315
- :treemap=>[]}
315
+ :treemap=>[],
316
+ :options=>{versus: :a, compress: {visvalingam: true, visvalingam_tolerance: 1.5}}
317
+ }
316
318
  ```
319
+ The options are the original options passed by user.
317
320
 
318
321
  ## Treemap
319
322
 
@@ -8,17 +8,16 @@
8
8
  */
9
9
 
10
10
  #pragma once
11
-
12
11
  #include <string>
13
12
  #include <vector>
14
13
  #include <memory>
15
14
  #include <cstdint>
16
15
  #include <string_view>
17
-
18
16
  #include "Finder.h"
19
17
  #include "FastPngBitmap.h"
20
18
  #include "RGBNotMatcher.h"
21
19
  #include "RGBMatcher.h"
20
+ #include "Options.h"
22
21
 
23
22
  namespace Contrek {
24
23
 
@@ -49,7 +48,7 @@ struct Config {
49
48
  struct TraceContext {
50
49
  std::unique_ptr<FastPngBitmap> bitmap;
51
50
  std::unique_ptr<Matcher> matcher;
52
- std::vector<std::string> internal_args;
51
+ Options internal_args;
53
52
  std::unique_ptr<Finder> finder;
54
53
  std::unique_ptr<ProcessResult> result;
55
54
 
@@ -82,23 +81,20 @@ inline TraceContext trace(const std::string& image_path, const Config& cfg = Con
82
81
  ctx.matcher = std::make_unique<RGBMatcher>(color_to_match);
83
82
  }
84
83
 
85
- ctx.internal_args = {"--versus=a"};
86
-
87
- struct Mapping { bool flag; std::string_view arg; };
88
- const Mapping mappings[] = {
89
- {cfg.compress_unique, "--compress_uniq"},
90
- {cfg.compress_linear, "--compress_linear"},
91
- {cfg.compress_visvalingam, "--compress_visvalingam"},
92
- {cfg.treemap, "--treemap"}
84
+ ctx.internal_args = {
85
+ {"versus", Identifier{"a"}},
93
86
  };
94
- for (const auto& m : mappings) {
95
- if (m.flag) ctx.internal_args.emplace_back(m.arg);
96
- }
97
- ctx.internal_args.push_back("--number_of_tiles=" + std::to_string(cfg.tiles));
87
+ Options compression_opts;
88
+
89
+ if (cfg.compress_unique) compression_opts["uniq"] = true;
90
+ if (cfg.compress_linear) compression_opts["linear"] = true;
91
+ if (cfg.compress_visvalingam) compression_opts["visvalingam"] = true;
92
+ if (cfg.compress_unique || cfg.compress_linear || cfg.compress_visvalingam) ctx.internal_args["compression"] = compression_opts;
93
+ ctx.internal_args["number_of_tiles"] = cfg.tiles;
98
94
  if (cfg.connectivity_mode == Connectivity::OMNIDIRECTIONAL) {
99
- ctx.internal_args.push_back("--connectivity=" + std::to_string(8));
95
+ ctx.internal_args["connectivity"] = 8;
100
96
  }
101
- ctx.finder = std::make_unique<Finder>(cfg.threads, ctx.bitmap.get(), ctx.matcher.get(), &ctx.internal_args);
97
+ ctx.finder = std::make_unique<Finder>(cfg.threads, ctx.bitmap.get(), ctx.matcher.get(), ctx.internal_args);
102
98
  ctx.result = std::unique_ptr<ProcessResult>(ctx.finder->process_info());
103
99
 
104
100
  return ctx;
@@ -32,7 +32,7 @@
32
32
  #include "polygon/matchers/RGBMatcher.h"
33
33
  #include "polygon/matchers/RGBNotMatcher.h"
34
34
  #include "polygon/matchers/ValueNotMatcher.h"
35
- #include "polygon/finder/optionparser.h"
35
+ #include "polygon/finder/Options.h"
36
36
  #include "polygon/finder/concurrent/Finder.h"
37
37
  #include "polygon/finder/concurrent/HorizontalMerger.h"
38
38
  #include "polygon/finder/concurrent/VerticalMerger.h"
@@ -53,14 +53,22 @@ void Tests::test_a()
53
53
  "000000DDDDDD0000"\
54
54
  "0000000000000000";
55
55
 
56
- std::vector<std::string> arguments = {"--versus=a", "--compress_uniq", "--treemap"};
56
+ Options options = {
57
+ {"versus", Identifier{"a"}},
58
+ {"compress", Options{
59
+ {"uniq", true},
60
+ {"linear", true},
61
+ }},
62
+ {"treemap", true}
63
+ };
64
+
57
65
  ValueNotMatcher matcher('0');
58
66
  Bitmap b(chunk, 16);
59
- PolygonFinder pl(&b, &matcher, nullptr, &arguments);
67
+ PolygonFinder pl(&b, &matcher, nullptr, options);
60
68
  ProcessResult *o = pl.process_info();
61
69
  // o->print_polygons();
62
- std::vector<int> outer_array{11, 1, 6, 2, 6, 3, 6, 4, 6, 5, 11, 5, 11, 4, 11, 3, 11, 2, 11, 1};
63
- std::vector<int> inner_array{7, 3, 10, 3, 10, 4, 7, 4};
70
+ std::vector<int> outer_array{11, 1, 11, 2, 6, 2, 6, 6, 12, 6, 12, 1 };
71
+ std::vector<int> inner_array{8, 3, 10, 3, 10, 5, 8, 5, 8, 4};
64
72
  std::vector<int> array_compare;
65
73
 
66
74
  for (const auto& x : o->polygons)
@@ -90,10 +98,19 @@ void Tests::test_b()
90
98
  " XX XX "\
91
99
  " XXXXXXXXXXX ";
92
100
 
93
- std::vector<std::string> arguments = {"--versus=o", "--number_of_tiles=2", "--compress_uniq", "--compress_linear", "--treemap"};
101
+ Options options = {
102
+ {"versus", Identifier{"o"}},
103
+ {"number_of_tiles",2},
104
+ {"compress", Options{
105
+ {"uniq", true},
106
+ {"linear", true},
107
+ }},
108
+ {"treemap", true}
109
+ };
110
+
94
111
  ValueNotMatcher matcher(' ');
95
112
  Bitmap b(chunk, 16);
96
- Finder concurrentFinder(2, &b, &matcher, &arguments);
113
+ Finder concurrentFinder(2, &b, &matcher, options);
97
114
  ProcessResult *pro = concurrentFinder.process_info();
98
115
  pro->print_polygons();
99
116
  delete pro;
@@ -152,14 +169,21 @@ void Tests::test_d()
152
169
  FastPngBitmap png_bitmap("../images/sample_10240x10240.png");
153
170
  // FastPngBitmap png_bitmap("images/labyrinth.png");
154
171
  std::cout << "image_w=" << png_bitmap.w() << " image_h=" << png_bitmap.h() << std::endl;
155
- std::cout << "image reading time =" << cpu_timer.stop() << std::endl;
172
+ std::cout << "image reading time=" << cpu_timer.stop() << std::endl;
156
173
 
157
174
  int color = png_bitmap.value_at(0, 0);
158
- std::cout << "color =" << color << std::endl;
175
+ std::cout << "color = " << color << std::endl;
159
176
  RGBNotMatcher not_matcher(color);
160
177
 
161
- std::vector<std::string> arguments = {"--versus=a", "--compress_uniq", "--treemap"};
162
- PolygonFinder pl(&png_bitmap, &not_matcher, nullptr, &arguments);
178
+ Options options = {
179
+ {"versus", Identifier{"a"}},
180
+ {"compress", Options{
181
+ {"uniq", true},
182
+ }},
183
+ {"treemap", true}
184
+ };
185
+
186
+ PolygonFinder pl(&png_bitmap, &not_matcher, nullptr, options);
163
187
  ProcessResult *o = pl.process_info();
164
188
  o->print_info();
165
189
  delete o;
@@ -176,8 +200,14 @@ void Tests::test_e()
176
200
  std::cout << "color = " << color << std::endl;
177
201
  RGBNotMatcher not_matcher(color);
178
202
 
179
- std::vector<std::string> arguments = {"--versus=a", "--compress_uniq", "--number_of_tiles=2"};
180
- Finder pl(2, &png_bitmap, &not_matcher, &arguments);
203
+ Options options = {
204
+ {"versus", Identifier{"a"}},
205
+ {"number_of_tiles",2},
206
+ {"compress", Options{
207
+ {"uniq", true},
208
+ }},
209
+ };
210
+ Finder pl(2, &png_bitmap, &not_matcher, options);
181
211
  ProcessResult *o = pl.process_info();
182
212
  o->print_info();
183
213
  std::cout << "polygons = " << o->groups << std::endl;
@@ -211,8 +241,14 @@ void Tests::test_g()
211
241
  std::cout << "color = " << color << std::endl;
212
242
  RGBNotMatcher not_matcher(color);
213
243
 
214
- std::vector<std::string> arguments = {"--versus=a", "--compress_uniq", "--number_of_tiles=2"};
215
- Finder pl(2, &raw_bitmap, &not_matcher, &arguments);
244
+ Options options = {
245
+ {"versus", Identifier{"a"}},
246
+ {"number_of_tiles",2},
247
+ {"compress", Options{
248
+ {"uniq", true},
249
+ }},
250
+ };
251
+ Finder pl(2, &raw_bitmap, &not_matcher, options);
216
252
  ProcessResult *o = pl.process_info();
217
253
  // o->print_info();
218
254
  // o->print_polygons();
@@ -231,10 +267,15 @@ void Tests::test_h()
231
267
  "00 " \
232
268
  "0000000000" \
233
269
  "0000000000";
234
- std::vector<std::string> arguments = {"--versus=a", "--compress_uniq"};
270
+ Options options = {
271
+ {"versus", Identifier{"a"}},
272
+ {"compress", Options{
273
+ {"uniq", true},
274
+ }},
275
+ };
235
276
  ValueNotMatcher matcher(' ');
236
277
  Bitmap b_left(left, 10);
237
- PolygonFinder pl_left(&b_left, &matcher, nullptr, &arguments);
278
+ PolygonFinder pl_left(&b_left, &matcher, nullptr, options);
238
279
  ProcessResult *left_result = pl_left.process_info();
239
280
 
240
281
  std::string right =
@@ -248,11 +289,11 @@ void Tests::test_h()
248
289
  "0000000000" \
249
290
  "0000000000";
250
291
  Bitmap b_right(right, 10);
251
- PolygonFinder pl_right(&b_right, &matcher, nullptr, &arguments);
292
+ PolygonFinder pl_right(&b_right, &matcher, nullptr, options);
252
293
  ProcessResult *right_result = pl_right.process_info();
253
294
 
254
- std::vector<std::string> merger_arguments = {};
255
- HorizontalMerger hmerger(1, &arguments);
295
+ Options merger_options = {};
296
+ HorizontalMerger hmerger(1, merger_options);
256
297
  hmerger.add_tile(*left_result);
257
298
  hmerger.add_tile(*right_result);
258
299
  ProcessResult *merged_result = hmerger.process_info();
@@ -282,8 +323,8 @@ double get_peak_rss() {
282
323
  */
283
324
  void stream_png_image(const std::string& filepath, uint32_t stripe_height, bool generate_svg = false, bool generate_png = false) {
284
325
  std::vector<ProcessResult*> result_clones;
285
- std::vector<std::string> varguments = {};
286
- VerticalMerger vmerger(0, &varguments);
326
+ Options options = {};
327
+ VerticalMerger vmerger(0, options);
287
328
 
288
329
  // opens image to stream
289
330
  FILE* fp = fopen(filepath.c_str(), "rb");
@@ -340,10 +381,10 @@ void stream_png_image(const std::string& filepath, uint32_t stripe_height, bool
340
381
  if (ret != 0 && ret != SPNG_EOI) break;
341
382
  }
342
383
  // stripe contour tracing
343
- std::vector<std::string> finder_arguments = {
344
- "--versus=a",
384
+ Options options = {
385
+ {"versus", Identifier{"a"}},
345
386
  };
346
- PolygonFinder polygon_finder(&stripe_bitmap, &not_matcher, nullptr, &finder_arguments);
387
+ PolygonFinder polygon_finder(&stripe_bitmap, &not_matcher, nullptr, options);
347
388
  ProcessResult *result = polygon_finder.process_info();
348
389
  if (result) {
349
390
  std::cout << "stripe " << stripe_count << ": found polygons " << result->groups << std::endl;
@@ -400,7 +441,9 @@ double get_current_rss_mb() {
400
441
 
401
442
  void stream_progressive_png_image(const std::string& filepath, uint32_t stripe_height) {
402
443
  std::vector<ProcessResult*> result_clones;
403
- std::vector<std::string> varguments = {"--bounds"};
444
+ Options voptions = {
445
+ {"bounds", true},
446
+ };
404
447
  // opens image to stream
405
448
  FILE* fp = fopen(filepath.c_str(), "rb");
406
449
  if (!fp) {
@@ -439,7 +482,7 @@ void stream_progressive_png_image(const std::string& filepath, uint32_t stripe_h
439
482
  std::vector<char> buffer(4 * 1024 * 1024); // Buffer (4MB)
440
483
  shared_stream.rdbuf()->pubsetbuf(buffer.data(), buffer.size());
441
484
 
442
- SvgStreamingMerger vmerger(0, &varguments, &shared_stream, total_width, total_height);
485
+ SvgStreamingMerger vmerger(0, voptions, &shared_stream, total_width, total_height);
443
486
  // GeoJsonStreamingMerger vmerger(0, &varguments, &shared_stream, 4294901760);
444
487
  try {
445
488
  size_t row_size = static_cast<size_t>(total_width) * 4;
@@ -466,14 +509,16 @@ void stream_progressive_png_image(const std::string& filepath, uint32_t stripe_h
466
509
  if (ret != 0 && ret != SPNG_EOI) break;
467
510
  }
468
511
  // stripe contour tracing
469
- std::vector<std::string> finder_arguments = {
470
- "--versus=a",
471
- "--bounds",
472
- "--compress_uniq",
473
- "--compress_linear"
512
+ Options options = {
513
+ {"versus", Identifier{"a"}},
514
+ {"bounds", true},
515
+ {"compress", Options{
516
+ {"uniq", true},
517
+ {"linear", true},
518
+ }},
474
519
  };
475
520
 
476
- PolygonFinder polygon_finder(&stripe_bitmap, &not_matcher, nullptr, &finder_arguments);
521
+ PolygonFinder polygon_finder(&stripe_bitmap, &not_matcher, nullptr, options);
477
522
  ProcessResult *result = polygon_finder.process_info();
478
523
  if (result) {
479
524
  std::cout << "stripe " << stripe_count << ": found polygons " << result->groups << std::endl;
@@ -9,118 +9,48 @@
9
9
 
10
10
  #include <iostream>
11
11
  #include <string>
12
- #include <vector>
12
+ #include <algorithm>
13
13
  #include "PolygonFinder.h"
14
14
  #include "FinderUtils.h"
15
- #include "optionparser.h"
16
15
 
17
- void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string> *incoming_options) {
18
- std::vector<char*> argv0;
19
- for (const auto& arg : *incoming_options)
20
- argv0.push_back(const_cast<char*>(arg.data()));
21
- argv0.push_back(nullptr);
22
- char** argv = &argv0[0];
23
- int argc = argv0.size() -1;
16
+ void FinderUtils::sanitize_options(pf_Options& options, const Options& incoming_options) {
17
+ const Identifier versus = incoming_options.get<Identifier>("versus", options.versus == Node::A ? "a" : "o");
18
+ options.versus = versus == "a" ? Node::A : Node::O;
19
+ options.number_of_tiles = std::max(1, static_cast<int>(incoming_options.get<std::int64_t>(
20
+ "number_of_tiles",
21
+ options.number_of_tiles)));
22
+ options.connectivity_offset = incoming_options.get<std::int64_t>(
23
+ "connectivity",
24
+ options.connectivity_offset == 1 ? 8 : 4) == 8;
25
+ options.treemap = incoming_options.get<bool>("treemap", options.treemap);
26
+ options.named_sequences = incoming_options.get<bool>(
27
+ "named_sequences",
28
+ options.named_sequences);
29
+ options.bounds = incoming_options.get<bool>("bounds", options.bounds);
30
+ options.unsafe_mode = incoming_options.get<bool>("unsafe_mode", options.unsafe_mode);
24
31
 
25
- enum optionIndex { COMPRESS_UNIQ, VERSUS, COMPRESS_VISVALINGAM, COMPRESS_LINEAR, NUMBER_OF_TILES,
26
- COMPRESS_VISVALINGAM_TOLERANCE, TREEMAP, NAMED_SEQUENCES, BOUNDS, CONNECTIVITY,
27
- COMPRESS_RASTER, COMPRESS_DOUGLAS_PEUCKER };
28
- const option::Descriptor usage[] = {
29
- // {UNKNOWN, 0,"" , "" ,option::Arg::None, 0},
30
- {COMPRESS_VISVALINGAM, 0, "" , "compress_visvalingam", option::Arg::None, 0},
31
- {COMPRESS_LINEAR, 0, "" , "compress_linear", option::Arg::None, 0},
32
- {COMPRESS_VISVALINGAM_TOLERANCE, 0, "" , "compress_visvalingam_tolerance", option::Arg::Optional, 0},
33
- {COMPRESS_UNIQ, 0, "", "compress_uniq", option::Arg::None, 0},
34
- {COMPRESS_RASTER, 0, "", "compress_raster", option::Arg::None, 0},
35
- {COMPRESS_DOUGLAS_PEUCKER, 0, "", "compress_douglas_peucker", option::Arg::None, 0},
36
- {NUMBER_OF_TILES, 0, "", "number_of_tiles", option::Arg::Optional, 0},
37
- {TREEMAP, 0, "", "treemap", option::Arg::None, 0},
38
- {NAMED_SEQUENCES, 0, "", "named_sequences", option::Arg::None, 0},
39
- {BOUNDS, 0, "", "bounds", option::Arg::None, 0},
40
- {VERSUS, 0, "v", "versus", option::Arg::Optional, 0},
41
- {CONNECTIVITY, 0, "c", "connectivity", option::Arg::Optional, 0},
42
- {0, 0, 0, 0, 0, 0}
43
- };
44
-
45
- option::Stats stats(usage, argc, argv);
46
- option::Option ioptions[stats.options_max], buffer[stats.buffer_max];
47
- option::Parser parse(usage, argc, argv, ioptions, buffer);
48
-
49
- if (parse.error()) return;
50
- // VERSUS
51
- if (ioptions[VERSUS].count() > 0)
52
- { for (option::Option* opt = ioptions[VERSUS]; opt; opt = opt->next())
53
- { std::string opts = opt->arg;
54
- options.versus = (opts.compare("a") == 0 ? Node::A : Node::O);
55
- break;
56
- }
57
- }
58
- // COMPRESS UNIQ
59
- if (ioptions[COMPRESS_UNIQ].count() > 0)
60
- { options.compress_uniq = true;
61
- }
62
- // NUMBER_OF_TILES
63
- if (ioptions[NUMBER_OF_TILES].count() > 0)
64
- { try {
65
- options.number_of_tiles = std::stoi(ioptions[NUMBER_OF_TILES].arg);
66
- if (options.number_of_tiles <= 0) options.number_of_tiles = 1;
32
+ if (const Options* compress = incoming_options.get_options("compress")) {
33
+ options.compress_uniq = compress->get<bool>("uniq", options.compress_uniq);
34
+ options.compress_linear = compress->get<bool>("linear", options.compress_linear);
35
+ options.compress_raster = compress->get<bool>("raster", options.compress_raster);
36
+ options.compress_douglas_peucker = compress->get<bool>("douglas_peucker", options.compress_douglas_peucker);
37
+ options.compress_visvalingam = compress->get<bool>("visvalingam", options.compress_visvalingam);
38
+ if (compress->contains("visvalingam_tolerance")) {
39
+ options.compress_visvalingam = true;
40
+ options.compress_visvalingam_tolerance = static_cast<float>(compress->get<double>(
41
+ "visvalingam_tolerance",
42
+ options.compress_visvalingam_tolerance));
67
43
  }
68
- catch (const std::invalid_argument&) {
69
- std::cerr << "Errore: --number_of_tiles requires a number\n";
70
- }
71
- }
72
- // CONNECTIVITY
73
- if (ioptions[CONNECTIVITY].count() > 0)
74
- { try {
75
- if (std::stoi(ioptions[CONNECTIVITY].arg) == 8) options.connectivity_offset = 1;
76
- }
77
- catch (const std::invalid_argument&) {
78
- std::cerr << "Errore: --connectivity requires a number\n";
79
- }
80
- }
81
- // TREEMAP
82
- if (ioptions[TREEMAP].count() > 0)
83
- { options.treemap = true;
84
44
  }
85
- // NAMED_SEQUENCES
86
- if (ioptions[NAMED_SEQUENCES].count() > 0)
87
- { options.named_sequences = true;
88
- }
89
- // BOUNDS
90
- if (ioptions[BOUNDS].count() > 0)
91
- { options.bounds = true;
92
- }
93
- // COMPRESS LINEAR
94
- if (ioptions[COMPRESS_LINEAR].count() > 0)
95
- { options.compress_linear = true;
96
- }
97
- // COMPRESS UNIQ
98
- if (ioptions[COMPRESS_VISVALINGAM].count() > 0)
99
- { options.compress_visvalingam = true;
100
- }
101
- if (ioptions[COMPRESS_VISVALINGAM_TOLERANCE].count() > 0)
102
- { options.compress_visvalingam = true;
103
- for (option::Option* opt = ioptions[COMPRESS_VISVALINGAM_TOLERANCE]; opt; opt = opt->next())
104
- { std::string opts = opt->arg;
105
- options.compress_visvalingam_tolerance = strtof(opt->arg, 0);
106
- break;
107
- }
108
- }
109
- // COMPRESS RASTER
110
- if (ioptions[COMPRESS_RASTER].count() > 0)
111
- { options.compress_raster = true;
112
- }
113
- // COMPRESS DOUGLAS PEUCKER
114
- if (ioptions[COMPRESS_DOUGLAS_PEUCKER].count() > 0)
115
- { options.compress_douglas_peucker = true;
116
- }
117
- /* std::cout << "-----------" << std::endl;
45
+
46
+ /*std::cout << "-----------" << std::endl;
118
47
  std::cout << "versus " << options.versus << std::endl;
119
48
  std::cout << "bounds " << options.bounds << std::endl;
120
49
  std::cout << "number_of_tiles " << options.number_of_tiles << std::endl;
121
50
  std::cout << "uniq " << options.compress_uniq << std::endl;
122
51
  std::cout << "linear " << options.compress_linear << std::endl;
52
+ std::cout << "treemap " << options.treemap << std::endl;
123
53
  std::cout << "visvalingam " << options.compress_visvalingam << std::endl;
124
- std::cout << "visvalingam tolernace " << options.compress_visvalingam_tolerance << std::endl;
54
+ std::cout << "visvalingam tolerance " << options.compress_visvalingam_tolerance << std::endl;
125
55
  std::cout << "-----------" << std::endl; */
126
56
  }
@@ -10,8 +10,9 @@
10
10
  #pragma once
11
11
  #include <string>
12
12
  #include <vector>
13
+ #include "Options.h"
13
14
 
14
15
  class FinderUtils {
15
16
  public:
16
- static void sanitize_options(pf_Options& options, std::vector<std::string> *incoming_options);
17
+ static void sanitize_options(pf_Options& options, const Options& incoming_options);
17
18
  };
@@ -43,8 +43,7 @@ NodeCluster::~NodeCluster() {
43
43
  }
44
44
 
45
45
  void NodeCluster::compress_coords(std::list<Polygon>& polygons, pf_Options options) {
46
- if (!(options.compress_linear || options.compress_uniq || options.compress_raster ||
47
- options.compress_douglas_peucker || options.compress_visvalingam)) return;
46
+ if (!(options.any_compression())) return;
48
47
 
49
48
  auto compress_sequence = [&](std::vector<Point>& points_vec) {
50
49
  if (points_vec.empty()) return;
@@ -0,0 +1,91 @@
1
+ /*
2
+ * OptionValue.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
+ #pragma once
11
+ #include <cstdint>
12
+ #include <memory>
13
+ #include <string>
14
+ #include <utility>
15
+ #include <variant>
16
+
17
+ class Options;
18
+
19
+ struct Identifier {
20
+ std::string value;
21
+ Identifier() = default;
22
+ Identifier(const char* v) : value(v) {}
23
+ Identifier(std::string v) : value(std::move(v)) {}
24
+ bool operator==(const Identifier& other) const {
25
+ return value == other.value;
26
+ }
27
+ bool operator!=(const Identifier& other) const {
28
+ return value != other.value;
29
+ }
30
+ };
31
+
32
+ class OptionValue {
33
+ public:
34
+ using NestedOptions = std::shared_ptr<Options>;
35
+
36
+ using Value = std::variant<
37
+ std::monostate,
38
+ bool,
39
+ std::int64_t,
40
+ double,
41
+ std::string,
42
+ Identifier,
43
+ NestedOptions>;
44
+
45
+ OptionValue() = default;
46
+ OptionValue(bool value) : value_(value) {}
47
+ OptionValue(int value) : value_(static_cast<std::int64_t>(value)) {}
48
+ OptionValue(std::int64_t value) : value_(value) {}
49
+ OptionValue(double value) : value_(value) {}
50
+ OptionValue(const char* value) : value_(std::string(value)) {}
51
+ OptionValue(std::string value) : value_(std::move(value)) {}
52
+ OptionValue(Identifier value) : value_(std::move(value)) {}
53
+ OptionValue(const Options& value);
54
+ OptionValue(Options&& value);
55
+ bool is_bool() const { return std::holds_alternative<bool>(value_); }
56
+ bool is_integer() const { return std::holds_alternative<std::int64_t>(value_); }
57
+ bool is_double() const {return std::holds_alternative<double>(value_);}
58
+ bool is_string() const { return std::holds_alternative<std::string>(value_); }
59
+ bool is_options() const { return std::holds_alternative<NestedOptions>(value_); }
60
+ bool is_identifier() const { return std::holds_alternative<Identifier>(value_); }
61
+ bool as_bool() const { return std::get<bool>(value_); }
62
+ std::int64_t as_integer() const { return std::get<std::int64_t>(value_); }
63
+ double as_double() const { return std::get<double>(value_); }
64
+ const std::string& as_string() const { return std::get<std::string>(value_); }
65
+ std::string& as_string() { return std::get<std::string>(value_); }
66
+ const Options& as_options() const;
67
+ Options& as_options();
68
+ const Identifier& as_identifier() const { return std::get<Identifier>(value_); }
69
+ Identifier& as_identifier() { return std::get<Identifier>(value_);}
70
+
71
+ template <typename T>
72
+ bool is() const { return std::holds_alternative<T>(value_); }
73
+
74
+ template <typename T>
75
+ const T& as() const { return std::get<T>(value_); }
76
+
77
+ template <typename T>
78
+ T& as() { return std::get<T>(value_);}
79
+
80
+ template <typename T>
81
+ const T* get_if() const { return std::get_if<T>(&value_); }
82
+
83
+ template <typename T>
84
+ T* get_if() {return std::get_if<T>(&value_); }
85
+
86
+ const Value& value() const { return value_; }
87
+ Value& value() {return value_;}
88
+
89
+ private:
90
+ Value value_;
91
+ };