contrek 1.4.1 → 1.4.3

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile.lock +4 -1
  4. data/README.md +218 -38
  5. data/contrek.gemspec +1 -0
  6. data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +2 -2
  7. data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +52 -148
  8. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp +12 -4
  9. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.h +1 -0
  10. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.cpp +46 -0
  11. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.h +29 -0
  12. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/GeoLocalization.h +32 -0
  13. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/PngSource.cpp +103 -0
  14. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/PngSource.h +40 -0
  15. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/RasterSource.h +22 -0
  16. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/RasterStreamer.h +92 -0
  17. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/TiffSource.cpp +301 -0
  18. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/TiffSource.h +51 -0
  19. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +6 -8
  20. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +7 -2
  21. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +3 -1
  22. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +6 -0
  23. data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h +51 -6
  24. data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +83 -0
  25. data/ext/cpp_polygon_finder/extconf.rb +9 -0
  26. data/lib/contrek/bitmaps/bitmap.rb +2 -2
  27. data/lib/contrek/bitmaps/chunky_bitmap.rb +23 -8
  28. data/lib/contrek/bitmaps/png_bitmap.rb +4 -0
  29. data/lib/contrek/bitmaps/rgba_bitmap.rb +50 -0
  30. data/lib/contrek/bitmaps/streaming/raster_streamer.rb +66 -0
  31. data/lib/contrek/bitmaps/streaming/sources/ascii.rb +33 -0
  32. data/lib/contrek/bitmaps/streaming/sources/base.rb +27 -0
  33. data/lib/contrek/bitmaps/streaming/sources/png.rb +105 -0
  34. data/lib/contrek/bitmaps/streaming/sources/tiff.rb +349 -0
  35. data/lib/contrek/finder/concurrent/finder.rb +3 -2
  36. data/lib/contrek/finder/concurrent/geo_json_streaming_merger.rb +19 -2
  37. data/lib/contrek/finder/polygon_finder.rb +6 -3
  38. data/lib/contrek/version.rb +1 -1
  39. data/lib/contrek.rb +6 -0
  40. metadata +30 -1
@@ -7,18 +7,26 @@
7
7
  * See the LICENSE file in this directory for the full license text.
8
8
  */
9
9
 
10
+ #include "RawBitmap.h"
11
+ #include "spng.h"
10
12
  #include <memory>
11
13
  #include <cstdio>
12
14
  #include <iostream>
13
15
  #include <cstring>
14
16
  #include <cerrno>
15
17
  #include <string>
16
- #include "spng.h"
17
- #include "RawBitmap.h"
18
18
 
19
19
  RawBitmap::RawBitmap() : Bitmap("", 0),
20
20
  width(0),
21
- height(0) {
21
+ height(0),
22
+ bpp(0) {
23
+ }
24
+
25
+ RawBitmap::RawBitmap(uint width, uint height) : Bitmap("", 0),
26
+ width(0),
27
+ height(0),
28
+ bpp(0) {
29
+ define(width, height, 4, false);
22
30
  }
23
31
 
24
32
  int RawBitmap::w() {
@@ -34,7 +42,7 @@ char RawBitmap::value_at(int, int) {
34
42
  }
35
43
 
36
44
  const unsigned char* RawBitmap::get_row_ptr(int y) const {
37
- return image.get() + (static_cast<size_t>(y) * static_cast<size_t>(width) * 4);
45
+ return image.get() + (static_cast<std::size_t>(y) * static_cast<std::size_t>(width) * static_cast<std::size_t>(bpp));
38
46
  }
39
47
 
40
48
  int RawBitmap::get_bytes_per_pixel() const {
@@ -19,6 +19,7 @@ class RGBMatcher;
19
19
  class RawBitmap : public Bitmap {
20
20
  public:
21
21
  explicit RawBitmap();
22
+ RawBitmap(uint width, uint height);
22
23
  int h();
23
24
  int w();
24
25
  char value_at(int x, int y);
@@ -0,0 +1,46 @@
1
+ /*
2
+ * AsciiSource.cpp
3
+ *
4
+ * Copyright (c) 2025-2026 Emanuele Cesaroni
5
+ *
6
+ * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
+ * See the LICENSE file in this directory for the full license text.
8
+ */
9
+
10
+ #include "AsciiSource.h"
11
+ #include <cstring>
12
+ #include <stdexcept>
13
+
14
+ AsciiSource::AsciiSource(Bitmap& bitmap)
15
+ : bitmap_(bitmap),
16
+ current_row_(0) {
17
+ }
18
+
19
+ uint32_t AsciiSource::width() const {
20
+ return static_cast<uint32_t>(bitmap_.w());
21
+ }
22
+
23
+ uint32_t AsciiSource::height() const {
24
+ return static_cast<uint32_t>(bitmap_.h());
25
+ }
26
+
27
+ uint32_t AsciiSource::get_bytes_per_pixel() const {
28
+ return static_cast<uint32_t>(bitmap_.get_bytes_per_pixel());
29
+ }
30
+
31
+ bool AsciiSource::read_next_row(unsigned char* destination, std::size_t row_size)
32
+ { if (current_row_ >= height()) {
33
+ return false;
34
+ }
35
+
36
+ const unsigned char* row = bitmap_.get_row_ptr(current_row_);
37
+ const std::size_t expected_row_size = static_cast<std::size_t>(width()) * static_cast<std::size_t>(get_bytes_per_pixel());
38
+
39
+ if (expected_row_size != row_size) {
40
+ throw std::runtime_error("Invalid row size");
41
+ }
42
+ std::memcpy(destination, row, row_size);
43
+ ++current_row_;
44
+
45
+ return true;
46
+ }
@@ -0,0 +1,29 @@
1
+ /*
2
+ * AsciiSource.h
3
+ *
4
+ * Copyright (c) 2025-2026 Emanuele Cesaroni
5
+ *
6
+ * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
+ * See the LICENSE file in this directory for the full license text.
8
+ */
9
+
10
+ #pragma once
11
+
12
+ #include <cstddef>
13
+ #include <cstdint>
14
+
15
+ #include "RasterSource.h"
16
+ #include "../Bitmap.h"
17
+
18
+ class AsciiSource : public RasterSource {
19
+ public:
20
+ explicit AsciiSource(Bitmap& bitmap);
21
+ uint32_t width() const override;
22
+ uint32_t height() const override;
23
+ uint32_t get_bytes_per_pixel() const override;
24
+ bool read_next_row(unsigned char* destination, std::size_t row_size) override;
25
+
26
+ private:
27
+ Bitmap& bitmap_;
28
+ uint32_t current_row_;
29
+ };
@@ -0,0 +1,32 @@
1
+ /*
2
+ * GeoLocalization.h
3
+ *
4
+ * Copyright (c) 2025-2026 Emanuele Cesaroni
5
+ *
6
+ * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
+ * See the LICENSE file in this directory for the full license text.
8
+ */
9
+
10
+ #pragma once
11
+
12
+ #include <string>
13
+
14
+ struct GeoTransform {
15
+ double x_origin = 0.0;
16
+ double y_origin = 0.0;
17
+ double x_pixel_size = 1.0;
18
+ double y_pixel_size = 1.0;
19
+ double x_row_offset = 0.0;
20
+ double y_column_offset = 0.0;
21
+ };
22
+
23
+ struct GeoCrs {
24
+ std::string authority;
25
+ int code = 0;
26
+ };
27
+
28
+ struct GeoLocalization {
29
+ bool valid = false;
30
+ GeoTransform transform;
31
+ GeoCrs crs;
32
+ };
@@ -0,0 +1,103 @@
1
+ /*
2
+ * PngSource.cpp
3
+ *
4
+ * Copyright (c) 2025-2026 Emanuele Cesaroni
5
+ *
6
+ * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
+ * See the LICENSE file in this directory for the full license text.
8
+ */
9
+
10
+ #include "PngSource.h"
11
+
12
+ #include <stdexcept>
13
+ #include <string>
14
+ #include <cstdio>
15
+
16
+ PngSource::PngSource(const std::string& filepath)
17
+ : fp_(nullptr),
18
+ ctx_(nullptr),
19
+ width_(0),
20
+ height_(0),
21
+ current_row_(0) {
22
+ fp_ = std::fopen(filepath.c_str(), "rb");
23
+ if (!fp_) {
24
+ throw std::runtime_error("Unable to open PNG file");
25
+ }
26
+
27
+ ctx_ = spng_ctx_new(0);
28
+ if (!ctx_) {
29
+ std::fclose(fp_);
30
+ fp_ = nullptr;
31
+ throw std::runtime_error("Unable to create spng context");
32
+ }
33
+
34
+ int ret = spng_set_png_file(ctx_, fp_);
35
+ if (ret != 0) {
36
+ spng_ctx_free(ctx_);
37
+ ctx_ = nullptr;
38
+ std::fclose(fp_);
39
+ fp_ = nullptr;
40
+ throw std::runtime_error(std::string("spng_set_png_file failed: ") + spng_strerror(ret));
41
+ }
42
+
43
+ spng_ihdr ihdr{};
44
+ ret = spng_get_ihdr(ctx_, &ihdr);
45
+
46
+ if (ret != 0) {
47
+ spng_ctx_free(ctx_);
48
+ ctx_ = nullptr;
49
+ std::fclose(fp_);
50
+ fp_ = nullptr;
51
+ throw std::runtime_error(std::string("spng_get_ihdr failed: ") + spng_strerror(ret));
52
+ }
53
+
54
+ width_ = static_cast<uint32_t>(ihdr.width);
55
+ height_ = static_cast<uint32_t>(ihdr.height);
56
+ ret = spng_decode_image(ctx_, nullptr, 0, SPNG_FMT_RGBA8, SPNG_DECODE_PROGRESSIVE);
57
+
58
+ if (ret != 0) {
59
+ spng_ctx_free(ctx_);
60
+ ctx_ = nullptr;
61
+ std::fclose(fp_);
62
+ fp_ = nullptr;
63
+ throw std::runtime_error(std::string("spng_decode_image failed: ") + spng_strerror(ret));
64
+ }
65
+ }
66
+
67
+ PngSource::~PngSource()
68
+ { if (ctx_) {
69
+ spng_ctx_free(ctx_);
70
+ }
71
+ if (fp_) {
72
+ std::fclose(fp_);
73
+ }
74
+ }
75
+
76
+ uint32_t PngSource::width() const {
77
+ return width_;
78
+ }
79
+
80
+ uint32_t PngSource::height() const {
81
+ return height_;
82
+ }
83
+
84
+ uint32_t PngSource::get_bytes_per_pixel() const {
85
+ return 4;
86
+ }
87
+
88
+ bool PngSource::read_next_row(unsigned char* destination, std::size_t row_size) {
89
+ if (current_row_ >= height_) {
90
+ return false;
91
+ }
92
+ const std::size_t expected_row_size = static_cast<std::size_t>(width_) * 4;
93
+ if (row_size != expected_row_size) {
94
+ throw std::runtime_error("Invalid row size");
95
+ }
96
+ const int ret = spng_decode_row(ctx_, destination, row_size);
97
+
98
+ if (ret != 0 && ret != SPNG_EOI) {
99
+ throw std::runtime_error(std::string("spng_decode_row failed: ") + spng_strerror(ret));
100
+ }
101
+ ++current_row_;
102
+ return true;
103
+ }
@@ -0,0 +1,40 @@
1
+ /*
2
+ * PngSource.h
3
+ *
4
+ * Copyright (c) 2025-2026 Emanuele Cesaroni
5
+ *
6
+ * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
+ * See the LICENSE file in this directory for the full license text.
8
+ */
9
+
10
+ #pragma once
11
+
12
+ #include <cstddef>
13
+ #include <cstdint>
14
+ #include <cstdio>
15
+ #include <string>
16
+
17
+ extern "C" {
18
+ #include "../spng.h"
19
+ }
20
+
21
+ #include "RasterSource.h"
22
+
23
+ class PngSource : public RasterSource {
24
+ public:
25
+ explicit PngSource(const std::string& filepath);
26
+ ~PngSource() override;
27
+
28
+ uint32_t width() const override;
29
+ uint32_t height() const override;
30
+ uint32_t get_bytes_per_pixel() const override;
31
+ bool read_next_row(unsigned char* destination, std::size_t row_size) override;
32
+
33
+ private:
34
+ FILE* fp_;
35
+ spng_ctx* ctx_;
36
+
37
+ uint32_t width_;
38
+ uint32_t height_;
39
+ uint32_t current_row_;
40
+ };
@@ -0,0 +1,22 @@
1
+ /*
2
+ * RasterSource.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
+
12
+ #include <cstddef>
13
+ #include <cstdint>
14
+
15
+ class RasterSource {
16
+ public:
17
+ virtual ~RasterSource() = default;
18
+ virtual uint32_t width() const = 0;
19
+ virtual uint32_t height() const = 0;
20
+ virtual uint32_t get_bytes_per_pixel() const = 0;
21
+ virtual bool read_next_row(unsigned char* destination, std::size_t row_size) = 0;
22
+ };
@@ -0,0 +1,92 @@
1
+ /*
2
+ * RasterStreamer.h
3
+ *
4
+ * Copyright (c) 2025-2026 Emanuele Cesaroni
5
+ *
6
+ * Licensed under the GNU Affero General Public License v3 (AGPLv3).
7
+ * See the LICENSE file in this directory for the full license text.
8
+ */
9
+
10
+ #pragma once
11
+
12
+ #include <algorithm>
13
+ #include <cstddef>
14
+ #include <cstdint>
15
+ #include <cstring>
16
+ #include <stdexcept>
17
+ #include <utility>
18
+ #include <vector>
19
+
20
+ #include "RasterSource.h"
21
+ #include "../RawBitmap.h"
22
+
23
+ class RasterStreamer {
24
+ public:
25
+ static constexpr uint32_t OVERLAP = 1;
26
+
27
+ RasterStreamer(RasterSource& source, uint32_t stripe_height)
28
+ : source_(source),
29
+ stripe_height_(stripe_height) {
30
+ if (stripe_height_ <= OVERLAP) {
31
+ throw std::invalid_argument("stripe_height must be greater than 1");
32
+ }
33
+ }
34
+ uint32_t stripe_height() const { return stripe_height_; }
35
+
36
+ template <typename Callback>
37
+ void each(Bitmap& buffer, Callback&& callback)
38
+ { const uint32_t width = source_.width();
39
+ const uint32_t height = source_.height();
40
+ const uint32_t bytes_per_pixel = source_.get_bytes_per_pixel();
41
+ const std::size_t row_size = static_cast<std::size_t>(width) * static_cast<std::size_t>(bytes_per_pixel);
42
+ uint32_t source_row = 0;
43
+ uint32_t previous_buffer_rows = 0;
44
+ bool first_stripe = true;
45
+
46
+ while (source_row < height) {
47
+ std::vector<unsigned char> overlap_row;
48
+ if (!first_stripe) {
49
+ overlap_row.resize(row_size);
50
+ const unsigned char* previous_last_row = buffer.get_row_ptr(previous_buffer_rows - 1);
51
+ std::memcpy(overlap_row.data(), previous_last_row, row_size);
52
+ }
53
+
54
+ const uint32_t overlap_rows = first_stripe ? 0 : OVERLAP;
55
+ const uint32_t available_rows = stripe_height_ - overlap_rows;
56
+ const uint32_t remaining_rows = height - source_row;
57
+ const uint32_t rows_to_read = std::min(available_rows, remaining_rows);
58
+ const uint32_t buffer_rows = overlap_rows + rows_to_read;
59
+
60
+ if (!first_stripe) {
61
+ unsigned char* first_row = const_cast<unsigned char*>(buffer.get_row_ptr(0));
62
+ std::memcpy(first_row, overlap_row.data(), row_size);
63
+ }
64
+ uint32_t rows_read = 0;
65
+ for (uint32_t i = 0; i < rows_to_read; ++i) {
66
+ const uint32_t buffer_y = overlap_rows + i;
67
+ unsigned char* destination = const_cast<unsigned char*>(buffer.get_row_ptr(buffer_y));
68
+ if (!source_.read_next_row(destination, row_size)) {
69
+ break;
70
+ }
71
+ ++source_row;
72
+ ++rows_read;
73
+ }
74
+ if (rows_read == 0) {
75
+ break;
76
+ }
77
+ const uint32_t actual_buffer_rows = overlap_rows + rows_read;
78
+ if (actual_buffer_rows != buffer_rows) {
79
+ throw std::runtime_error("Raster source ended before expected image height!");
80
+ }
81
+ const std::size_t buffer_size = static_cast<std::size_t>(buffer_rows) * row_size;
82
+
83
+ std::forward<Callback>(callback)(buffer, buffer_rows, buffer_size, rows_read);
84
+ previous_buffer_rows = buffer_rows;
85
+ first_stripe = false;
86
+ }
87
+ }
88
+
89
+ private:
90
+ RasterSource& source_;
91
+ uint32_t stripe_height_;
92
+ };