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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +4 -1
- data/README.md +218 -38
- data/contrek.gemspec +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +52 -148
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp +12 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.cpp +46 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.h +29 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/GeoLocalization.h +32 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/PngSource.cpp +103 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/PngSource.h +40 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/RasterSource.h +22 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/RasterStreamer.h +92 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/TiffSource.cpp +301 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/TiffSource.h +51 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +6 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +7 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +3 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +6 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h +51 -6
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +83 -0
- data/ext/cpp_polygon_finder/extconf.rb +9 -0
- data/lib/contrek/bitmaps/bitmap.rb +2 -2
- data/lib/contrek/bitmaps/chunky_bitmap.rb +23 -8
- data/lib/contrek/bitmaps/png_bitmap.rb +4 -0
- data/lib/contrek/bitmaps/rgba_bitmap.rb +50 -0
- data/lib/contrek/bitmaps/streaming/raster_streamer.rb +66 -0
- data/lib/contrek/bitmaps/streaming/sources/ascii.rb +33 -0
- data/lib/contrek/bitmaps/streaming/sources/base.rb +27 -0
- data/lib/contrek/bitmaps/streaming/sources/png.rb +105 -0
- data/lib/contrek/bitmaps/streaming/sources/tiff.rb +349 -0
- data/lib/contrek/finder/concurrent/finder.rb +3 -2
- data/lib/contrek/finder/concurrent/geo_json_streaming_merger.rb +19 -2
- data/lib/contrek/finder/polygon_finder.rb +6 -3
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +6 -0
- 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 ==
|
|
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
|
|
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
|
-
@
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
@@ -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
|