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
@@ -3,6 +3,8 @@
3
3
  require "mkmf-rice"
4
4
 
5
5
  has_tcmalloc = find_library("tcmalloc", "malloc")
6
+ has_tiff = have_library("tiff", "TIFFOpen", "tiffio.h")
7
+ has_geotiff = has_tiff && have_library("geotiff", "XTIFFOpen", "geotiff/xtiffio.h")
6
8
 
7
9
  # rubocop:disable Style/GlobalVars
8
10
 
@@ -16,6 +18,13 @@ else
16
18
  puts "tcmalloc not found; standard malloc will be used."
17
19
  end
18
20
 
21
+ if has_tiff && has_geotiff
22
+ $CXXFLAGS << " -DCONTREK_HAS_TIFF"
23
+ puts "TIFF/GeoTIFF support enabled."
24
+ else
25
+ puts "TIFF/GeoTIFF support disabled."
26
+ end
27
+
19
28
  $LDFLAGS << " -lz -lstdc++ -flto -pthread"
20
29
 
21
30
  $objs = [
@@ -5,7 +5,7 @@ module Contrek
5
5
  class Bitmap
6
6
  include Painting
7
7
 
8
- def scan(start_x: 0, end_x: w)
8
+ def scan(start_x: 0, end_x: w, end_y: h)
9
9
  x = start_x
10
10
  y = 0
11
11
  loop do
@@ -14,7 +14,7 @@ module Contrek
14
14
  if x == end_x
15
15
  x = start_x
16
16
  y += 1
17
- break if y == h
17
+ break if y == end_y
18
18
  end
19
19
  end
20
20
  end
@@ -1,15 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "ffi"
4
+
3
5
  module Contrek
4
6
  module Bitmaps
5
7
  class ChunkyBitmap < Bitmap
6
8
  def initialize(data, mod)
7
- @raw = data.dup
8
9
  @module = mod
10
+ @height = data.bytesize / @module
11
+ @raw = FFI::MemoryPointer.new(:uint8, data.bytesize)
12
+ @raw.put_bytes(0, data)
9
13
  end
10
14
 
11
15
  def clear(val = "0")
12
- @raw = val * @module * h
16
+ @raw.put_bytes(0, val * @module * h)
13
17
  end
14
18
 
15
19
  def w
@@ -17,22 +21,30 @@ module Contrek
17
21
  end
18
22
 
19
23
  def h
20
- @raw.size / @module
24
+ @height
25
+ end
26
+
27
+ def get_bytes_per_pixel
28
+ 1
29
+ end
30
+
31
+ def get_row_ptr(y)
32
+ @raw + (@module * y)
21
33
  end
22
34
 
23
35
  def value_at(x, y)
24
- @raw[y * @module + x]
36
+ @raw.get_uint8(y * @module + x).chr
25
37
  end
26
38
 
27
39
  def value_set(x, y, value)
28
40
  return if y >= h
29
41
  return if x >= w
30
42
 
31
- @raw[y * @module + x] = value
43
+ @raw.put_uint8(y * @module + x, value.ord)
32
44
  end
33
45
 
34
46
  def dup!
35
- ChunkyBitmap.new(@raw, @module)
47
+ ChunkyBitmap.new(@raw.read_bytes(@module * h), @module)
36
48
  end
37
49
 
38
50
  def draw_rect(x:, y:, width:, height:, color: "o", filled: true)
@@ -80,7 +92,7 @@ module Contrek
80
92
  puts label if label
81
93
  puts " " + (0...@module).map { |i| (i % 10).to_s }.join
82
94
  n = 0
83
- @raw.scan(/.{1,#{@module}}/).each do |line|
95
+ @raw.read_bytes(@module * h).scan(/.{1,#{@module}}/).each do |line|
84
96
  colored_line = line.chars.map { |c| colorize_char(c) }.join
85
97
  puts "#{n} #{colored_line}"
86
98
  n += 1
@@ -96,8 +108,11 @@ module Contrek
96
108
  transposed += value_at(x, y)
97
109
  end
98
110
  end
99
- @raw = transposed
111
+ old_width = w
100
112
  @module = h
113
+ @height = old_width
114
+ @raw = FFI::MemoryPointer.new(:uint8, transposed.bytesize)
115
+ @raw.put_bytes(0, transposed)
101
116
  end
102
117
 
103
118
  private
@@ -20,6 +20,10 @@ module Contrek
20
20
  @image.dimension.height
21
21
  end
22
22
 
23
+ def get_bytes_per_pixel
24
+ 4
25
+ end
26
+
23
27
  def draw_line(start_x, start_y, end_x, end_y, value)
24
28
  @image.line_xiaolin_wu(start_x, start_y, end_x, end_y, value)
25
29
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ module Contrek
6
+ module Bitmaps
7
+ class RgbaBitmap < Bitmap
8
+ BYTES_PER_PIXEL = 4
9
+
10
+ def initialize(width, height)
11
+ @width = width
12
+ @height = height
13
+ @raw = FFI::MemoryPointer.new(:uint8, @width * @height * BYTES_PER_PIXEL)
14
+ end
15
+
16
+ def w
17
+ @width
18
+ end
19
+
20
+ def h
21
+ @height
22
+ end
23
+
24
+ def get_bytes_per_pixel
25
+ BYTES_PER_PIXEL
26
+ end
27
+
28
+ def value_at(x, y)
29
+ rgb_value_at(x, y)
30
+ end
31
+
32
+ def get_row_ptr(y)
33
+ @raw + (y * @width * BYTES_PER_PIXEL)
34
+ end
35
+
36
+ def rgb_value_at(x, y)
37
+ index = (y * @width + x) * BYTES_PER_PIXEL
38
+ r = @raw.get_uint8(index)
39
+ g = @raw.get_uint8(index + 1)
40
+ b = @raw.get_uint8(index + 2)
41
+ a = @raw.get_uint8(index + 3)
42
+ r | (g << 8) | (b << 16) | (a << 24)
43
+ end
44
+
45
+ def read_bytes(size)
46
+ @raw.read_bytes(size)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ module Contrek
6
+ module Bitmaps
7
+ module Streaming
8
+ class RasterStreamer
9
+ OVERLAP = 1
10
+
11
+ attr_reader :stripe_height
12
+
13
+ def initialize(source, stripe_height:)
14
+ @source = source
15
+ @stripe_height = stripe_height
16
+
17
+ raise ArgumentError, "stripe_height must be greater than 1" if @stripe_height <= OVERLAP
18
+ end
19
+
20
+ def each(buffer)
21
+ return enum_for(:each, buffer) unless block_given?
22
+
23
+ width = @source.width
24
+ height = @source.height
25
+ bytes_per_pixel = @source.get_bytes_per_pixel
26
+
27
+ row_size = width * bytes_per_pixel
28
+
29
+ source_row = 0
30
+ buffer_rows = 0
31
+ first_stripe = true
32
+
33
+ while source_row < height
34
+ unless first_stripe
35
+ previous_last_row = buffer.get_row_ptr(buffer_rows - 1)
36
+ current_first_row = buffer.get_row_ptr(0)
37
+ current_first_row.put_bytes(0, previous_last_row.read_bytes(row_size))
38
+ end
39
+
40
+ overlap_rows = first_stripe ? 0 : OVERLAP
41
+ available_rows = @stripe_height - overlap_rows
42
+ remaining_rows = height - source_row
43
+ rows_to_read = [available_rows, remaining_rows].min
44
+
45
+ rows_read = 0
46
+ rows_to_read.times do |i|
47
+ buffer_y = overlap_rows + i
48
+ row_ptr = buffer.get_row_ptr(buffer_y)
49
+ break unless @source.read_next_row(row_ptr, row_size)
50
+
51
+ source_row += 1
52
+ rows_read += 1
53
+ end
54
+
55
+ buffer_rows = overlap_rows + rows_read
56
+ break if buffer_rows == 0
57
+
58
+ yield buffer, buffer_rows, buffer_rows * row_size, rows_read
59
+
60
+ first_stripe = false
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module Contrek
6
+ module Bitmaps
7
+ module Streaming
8
+ module Sources
9
+ class Ascii < Base
10
+ extend Forwardable
11
+
12
+ def_delegator :@bitmap, :w, :width
13
+ def_delegator :@bitmap, :h, :height
14
+ def_delegators :@bitmap, :get_bytes_per_pixel
15
+
16
+ def initialize(bitmap)
17
+ @current_row = 0
18
+ @bitmap = bitmap
19
+ end
20
+
21
+ def read_next_row(destination, row_size)
22
+ return false if @current_row >= height
23
+
24
+ row = @bitmap.get_row_ptr(@current_row)
25
+ destination.put_bytes(0, row.read_bytes(row_size))
26
+ @current_row += 1
27
+ true
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Contrek
4
+ module Bitmaps
5
+ module Streaming
6
+ module Sources
7
+ class Base
8
+ def width
9
+ raise NotImplementedError
10
+ end
11
+
12
+ def height
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def get_bytes_per_pixel
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def read_next_row(destination, row_size)
21
+ raise NotImplementedError
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+ require "cpp_polygon_finder"
5
+
6
+ module Contrek
7
+ module Bitmaps
8
+ module Streaming
9
+ module Sources
10
+ class Png
11
+ attr_reader :width, :height
12
+
13
+ module LibSpng
14
+ extend FFI::Library
15
+
16
+ ffi_lib FFI::Library::CURRENT_PROCESS
17
+
18
+ SPNG_FMT_RGBA8 = 1
19
+ SPNG_DECODE_PROGRESSIVE = 256
20
+ SPNG_EOI = 75
21
+
22
+ class Ihdr < FFI::Struct
23
+ layout(
24
+ :width, :uint32,
25
+ :height, :uint32,
26
+ :bit_depth, :uint8,
27
+ :color_type, :uint8,
28
+ :compression_method, :uint8,
29
+ :filter_method, :uint8,
30
+ :interlace_method, :uint8
31
+ )
32
+ end
33
+
34
+ attach_function :spng_ctx_new, [:int], :pointer
35
+ attach_function :spng_ctx_free, [:pointer], :void
36
+ attach_function :spng_set_png_file, [:pointer, :pointer], :int
37
+ attach_function :spng_get_ihdr, [:pointer, :pointer], :int
38
+ attach_function :spng_decode_image, [:pointer, :pointer, :size_t, :int, :int], :int
39
+ attach_function :spng_decode_row, [:pointer, :pointer, :size_t], :int
40
+ end
41
+
42
+ module LibC
43
+ extend FFI::Library
44
+
45
+ ffi_lib FFI::Library::LIBC
46
+
47
+ attach_function :fopen, [:string, :string], :pointer
48
+ attach_function :fclose, [:pointer], :int
49
+ end
50
+
51
+ def initialize(filepath)
52
+ @fp = LibC.fopen(filepath, "rb")
53
+ raise "Unable to open PNG: #{filepath}" if @fp.null?
54
+
55
+ @ctx = LibSpng.spng_ctx_new(0)
56
+ raise "Unable to create spng context" if @ctx.null?
57
+
58
+ ret = LibSpng.spng_set_png_file(@ctx, @fp)
59
+ raise "spng_set_png_file failed: #{ret}" unless ret == 0
60
+
61
+ ihdr = LibSpng::Ihdr.new
62
+
63
+ ret = LibSpng.spng_get_ihdr(@ctx, ihdr)
64
+ raise "spng_get_ihdr failed: #{ret}" unless ret == 0
65
+
66
+ @width = ihdr[:width]
67
+ @height = ihdr[:height]
68
+
69
+ ret = LibSpng.spng_decode_image(
70
+ @ctx,
71
+ nil,
72
+ 0,
73
+ LibSpng::SPNG_FMT_RGBA8,
74
+ LibSpng::SPNG_DECODE_PROGRESSIVE
75
+ )
76
+ raise "Unable to initialize progressive decoding: #{ret}" unless ret == 0
77
+ end
78
+
79
+ def get_bytes_per_pixel
80
+ 4
81
+ end
82
+
83
+ def read_next_row(destination, row_size)
84
+ ret = LibSpng.spng_decode_row(@ctx, destination, row_size)
85
+ unless ret == 0 || ret == LibSpng::SPNG_EOI
86
+ raise "spng_decode_row failed: #{ret}"
87
+ end
88
+ true
89
+ end
90
+
91
+ def close
92
+ unless @ctx.nil? || @ctx.null?
93
+ LibSpng.spng_ctx_free(@ctx)
94
+ @ctx = nil
95
+ end
96
+ unless @fp.nil? || @fp.null?
97
+ LibC.fclose(@fp)
98
+ @fp = nil
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end