contrek 1.0.2 → 1.0.4

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.
@@ -0,0 +1,204 @@
1
+ module Contrek
2
+ module Concurrent
3
+ module Queueable
4
+ attr_reader :head, :tail, :size
5
+ def initialize(*args, **kwargs, &block)
6
+ super
7
+ @head = nil
8
+ @tail = nil
9
+ @iterator = 0
10
+ @size = 0
11
+ end
12
+
13
+ def rem(node)
14
+ Raise "Not my node" if node.owner != self
15
+
16
+ node.before_rem(self)
17
+
18
+ node.prev&.next = node.next
19
+ node.next&.prev = node.prev
20
+
21
+ @head = node.next if node == @head
22
+ @tail = node.prev if node == @tail
23
+
24
+ node.next = node.prev = node.owner = nil
25
+ @size -= 1
26
+
27
+ node
28
+ end
29
+
30
+ def add(node)
31
+ node.owner&.rem(node) # verifies owner presence
32
+
33
+ if @tail
34
+ @tail.next = node
35
+ node.prev = @tail
36
+ else
37
+ @head = node
38
+ node.prev = nil
39
+ end
40
+ @tail = node
41
+ node.next = nil
42
+ node.owner = self
43
+ @size += 1
44
+
45
+ node.after_add(self)
46
+ end
47
+
48
+ def replace!(queueable)
49
+ reset!
50
+ append(queueable)
51
+ end
52
+
53
+ def append(queueable)
54
+ return if queueable.size.zero?
55
+ queueable.each do |node|
56
+ node.before_rem(queueable)
57
+ node.owner = self
58
+ end
59
+ if @tail
60
+ @tail.next = queueable.head
61
+ queueable.head.prev = @tail
62
+ else
63
+ @head = queueable.head
64
+ end
65
+ @tail = queueable.tail
66
+ @size += queueable.size
67
+ queueable.reset!
68
+
69
+ each { |node| node.after_add(self) }
70
+ end
71
+
72
+ def move_from(queueable, &block)
73
+ queueable.rewind!
74
+ while (node = queueable.iterator)
75
+ queueable.forward!
76
+ add(node) if yield(node)
77
+ end
78
+ end
79
+
80
+ def reset!
81
+ @head = nil
82
+ @tail = nil
83
+ @size = 0
84
+ @iterator = 0
85
+ end
86
+
87
+ def each(&block)
88
+ last = nil
89
+ unless @head.nil?
90
+ pointer = @head
91
+ loop do
92
+ yield(pointer)
93
+ last = pointer
94
+ break unless (pointer = pointer.next)
95
+ end
96
+ end
97
+ last
98
+ end
99
+
100
+ def map(&block)
101
+ ret_array = []
102
+ each { |node| ret_array << yield(node) }
103
+ ret_array
104
+ end
105
+
106
+ def reverse_each(&block)
107
+ last = nil
108
+ unless @tail.nil?
109
+ pointer = @tail
110
+ loop do
111
+ yield(pointer)
112
+ last = pointer
113
+ break unless (pointer = pointer.prev)
114
+ end
115
+ end
116
+ last
117
+ end
118
+
119
+ def to_a
120
+ map(&:payload)
121
+ end
122
+
123
+ def forward!
124
+ @iterator = iterator.next unless iterator.nil?
125
+ end
126
+
127
+ def iterator
128
+ (@iterator == 0) ? @head : @iterator
129
+ end
130
+
131
+ def rewind!
132
+ @iterator = 0
133
+ end
134
+
135
+ def next_of!(node)
136
+ raise "nil node" if node.nil?
137
+ raise "wrong node" if node.owner != self
138
+ @iterator = node.next
139
+ end
140
+
141
+ def pop!
142
+ rem(@tail)
143
+ end
144
+
145
+ def intersection_with(queueable)
146
+ int = []
147
+ each do |node|
148
+ int += queueable.map do |e|
149
+ break [e.payload] if e.payload == node.payload
150
+ end.compact
151
+ end
152
+ int
153
+ end
154
+
155
+ def intersection_with_array?(array)
156
+ each { |node| return true if array.index(node.payload) }
157
+ false
158
+ end
159
+
160
+ def intersect_with?(queueable)
161
+ intersection_with(queueable).any?
162
+ end
163
+
164
+ def remove_adjacent_pairs(array = nil)
165
+ array = to_a if array.nil?
166
+ n = array.size
167
+ (0...(n - 1)).each do |i|
168
+ if array[i] == array[i + 1]
169
+ # Remove the pair and call recursively
170
+ new_array = array[0...i] + array[(i + 2)..]
171
+ return remove_adjacent_pairs(new_array)
172
+ end
173
+ end
174
+ array
175
+ end
176
+
177
+ def remove_adjacent_pairs!
178
+ unless @tail.nil?
179
+ pointer = @tail
180
+ loop do
181
+ break if pointer == @head
182
+ if pointer.payload == pointer.prev&.payload
183
+ later = pointer.next
184
+ rem pointer.prev
185
+ rem pointer
186
+ pointer = later.nil? ? @tail : later
187
+ redo
188
+ end
189
+ break unless (pointer = pointer.prev)
190
+ end
191
+ end
192
+ end
193
+
194
+ # def index(node)
195
+ # index = 0
196
+ # each do |loop_node|
197
+ # return index if node == loop_node
198
+ # index += 1
199
+ # end
200
+ # -1
201
+ # end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,7 @@
1
+ module Contrek
2
+ module Concurrent
3
+ class Sequence
4
+ prepend Queueable
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Contrek
2
+ module Concurrent
3
+ class Shape
4
+ attr_accessor :outer_polyline, :inner_polylines
5
+
6
+ def clear_inner!
7
+ @inner_polylines = []
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,91 @@
1
+ module Contrek
2
+ module Concurrent
3
+ class Tile
4
+ attr_reader :start_x, :end_x, :benchmarks, :shapes, :name
5
+ attr_accessor :prev, :next, :circular_next, :cluster
6
+
7
+ def initialize(finder:, start_x:, end_x:, name:, benchmarks: {})
8
+ @finder = finder
9
+ @start_x = start_x
10
+ @end_x = end_x
11
+ @name = name
12
+ @prev = nil
13
+ @next = nil
14
+ @benchmarks = {outer: 0, inner: 0}.merge(benchmarks)
15
+ end
16
+
17
+ def whole?
18
+ @start_x == 0 && @end_x == @finder.maximum_width
19
+ end
20
+
21
+ def left?
22
+ @start_x == 0
23
+ end
24
+
25
+ def right?
26
+ @end_x == @finder.maximum_width
27
+ end
28
+
29
+ def initial_process!(finder)
30
+ result = finder.process_info
31
+ assign_raw_polygons!(result[:polygons])
32
+ end
33
+
34
+ def boundary_shapes
35
+ @bbs ||= shapes.select { |s| s.outer_polyline.boundary? }
36
+ end
37
+
38
+ def iterate
39
+ @shapes.each do |shape|
40
+ shape.outer_polyline.raw.each do |position|
41
+ yield(position, "O")
42
+ end
43
+ shape.inner_polylines.each do |inner|
44
+ inner.each do |position|
45
+ yield(position, "I")
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ def assign_shapes!(shapes)
52
+ shapes.each { |s| s.outer_polyline.tile = self }
53
+ @shapes = shapes
54
+ end
55
+
56
+ def to_raw_polygons
57
+ @shapes.filter_map do |shape|
58
+ unless shape.outer_polyline.empty?
59
+ {outer: shape.outer_polyline.raw,
60
+ inner: shape.inner_polylines}
61
+ end
62
+ end
63
+ end
64
+
65
+ def info
66
+ {name: @name, start_x: @start_x, end_x: @end_x}
67
+ end
68
+
69
+ def tg_border?(coord)
70
+ coord[:x] == (@next.nil? ? @start_x : (@end_x - 1))
71
+ end
72
+
73
+ def inspect
74
+ "#{self.class}[#{@name}]"
75
+ end
76
+
77
+ private
78
+
79
+ def assign_raw_polygons!(raw_polylines)
80
+ @shapes = []
81
+ raw_polylines.each do |raw_polyline|
82
+ @shapes << Shape.new.tap do |shape|
83
+ shape.outer_polyline = Polyline.new(tile: self, polygon: raw_polyline[:outer], shape: shape)
84
+ shape.inner_polylines = raw_polyline[:inner]
85
+ end.then { _1.outer_polyline.width.zero? ? nil : _1 }
86
+ @shapes.compact!
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -2,6 +2,7 @@ module Contrek
2
2
  module Finder
3
3
  class Node
4
4
  include Listable
5
+
5
6
  attr_reader :min_x, :max_x, :y, :name, :tangs, :tangs_sequence, :tangs_count, :data_pointer
6
7
  attr_accessor :track, :abs_x_index, :outer_index, :inner_index
7
8
 
@@ -76,20 +76,33 @@ module Contrek
76
76
  end
77
77
  end
78
78
 
79
+ def inspect
80
+ ""
81
+ end
82
+
83
+ def start_x
84
+ 0
85
+ end
86
+
87
+ def end_x
88
+ @source_bitmap.w
89
+ end
90
+
79
91
  private
80
92
 
81
93
  # image scan
82
94
  def scan
83
95
  last_color = nil
84
96
  matching = false
85
- min_x = 0
86
- max_x = 0
87
- @source_bitmap.scan do |x, y, color|
97
+ min_x = start_x
98
+ max_x = start_x
99
+ @source_bitmap.scan(start_x: start_x, end_x: end_x) do |x, y, color|
100
+ # puts "#{x} #{y}"
88
101
  if @matcher.match?(color) && matching == false
89
102
  min_x = x
90
103
  last_color = color
91
104
  matching = true
92
- if x == (@source_bitmap.w - 1)
105
+ if x == (end_x - 1)
93
106
  max_x = x
94
107
  Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color)
95
108
  matching = false
@@ -98,7 +111,7 @@ module Contrek
98
111
  max_x = x - 1
99
112
  Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color)
100
113
  matching = false
101
- elsif x == (@source_bitmap.w - 1) && matching == true
114
+ elsif x == (end_x - 1) && matching == true
102
115
  max_x = x
103
116
  Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color)
104
117
  matching = false
@@ -1,3 +1,3 @@
1
1
  module Contrek
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.4"
3
3
  end
data/lib/contrek.rb CHANGED
@@ -3,6 +3,7 @@ require "contrek/bitmaps/painting"
3
3
  require "contrek/bitmaps/bitmap"
4
4
  require "contrek/bitmaps/chunky_bitmap"
5
5
  require "contrek/bitmaps/png_bitmap"
6
+ require "contrek/bitmaps/custom_bitmap"
6
7
  require "contrek/bitmaps/rgb_color"
7
8
  require "contrek/finder/list"
8
9
  require "contrek/finder/list_entry"
@@ -10,7 +11,24 @@ require "contrek/finder/listable"
10
11
  require "contrek/finder/lists"
11
12
  require "contrek/finder/node"
12
13
  require "contrek/finder/node_cluster"
14
+ require "contrek/finder/concurrent/fake_cluster"
13
15
  require "contrek/finder/polygon_finder"
16
+ require "contrek/finder/concurrent/clipped_polygon_finder"
17
+ require "contrek/finder/concurrent/hub"
18
+ require "contrek/finder/concurrent/end_point"
19
+ require "contrek/finder/concurrent/queueable"
20
+ require "contrek/finder/concurrent/part"
21
+ require "contrek/finder/concurrent/partitionable"
22
+ require "contrek/finder/concurrent/listable"
23
+ require "contrek/finder/concurrent/poolable"
24
+ require "contrek/finder/concurrent/position"
25
+ require "contrek/finder/concurrent/sequence"
26
+ require "contrek/finder/concurrent/shape"
27
+ require "contrek/finder/concurrent/tile"
28
+ require "contrek/finder/concurrent/polyline"
29
+ require "contrek/finder/concurrent/cluster"
30
+ require "contrek/finder/concurrent/finder"
31
+ require "contrek/finder/concurrent/cursor"
14
32
  require "contrek/map/mercator_projection"
15
33
  require "contrek/matchers/matcher"
16
34
  require "contrek/matchers/matcher_hsb"
@@ -35,20 +53,33 @@ module Contrek
35
53
  png_bitmap = CPPPngBitMap.new(png_file_path)
36
54
  rgb_matcher_klass = (options[:class] == "value_not_matcher") ? CPPRGBNotMatcher : CPPRGBMatcher
37
55
  rgb_matcher = rgb_matcher_klass.new(color.to_rgb_raw)
38
- CPPPolygonFinder.new(png_bitmap,
39
- rgb_matcher,
40
- nil,
41
- {versus: :a, compress: {uniq: true, linear: true}}).process_info
56
+ if options.key?(:number_of_threads) || options[:finder]&.key?(:number_of_tiles)
57
+ raise "Multithreading on native cpp code is not supported yet. Will be ASAP!"
58
+ else
59
+ CPPPolygonFinder.new(png_bitmap,
60
+ rgb_matcher,
61
+ nil,
62
+ {versus: :a}.merge(options[:finder] || {})).process_info
63
+ end
42
64
  end
43
65
 
44
66
  def compute_ruby_pure(png_file_path, options)
45
67
  color = Bitmaps::RgbColor.new(**options[:color])
46
68
  png_bitmap = Bitmaps::PngBitmap.new(png_file_path)
47
69
  rgb_matcher = const_get("Contrek::Matchers::" + camelize("value_not_matcher")).new(color.raw)
48
- Contrek::Finder::PolygonFinder.new(png_bitmap,
49
- rgb_matcher,
50
- nil,
51
- {versus: :a, compress: {uniq: true, linear: true}}).process_info
70
+ if options.key?(:number_of_threads) || options[:finder]&.key?(:number_of_tiles)
71
+ Contrek::Concurrent::Finder.new(
72
+ number_of_threads: options.key?(:threads),
73
+ bitmap: png_bitmap,
74
+ matcher: rgb_matcher,
75
+ options: {versus: :a}.merge(options[:finder] || {})
76
+ ).process_info
77
+ else
78
+ Contrek::Finder::PolygonFinder.new(png_bitmap,
79
+ rgb_matcher,
80
+ nil,
81
+ {versus: :a}.merge(options[:finder] || {})).process_info
82
+ end
52
83
  end
53
84
 
54
85
  def camelize(str)
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.2
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emanuele Cesaroni
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-19 00:00:00.000000000 Z
11
+ date: 2025-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -16,28 +16,68 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.10'
19
+ version: '3.12'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '3.10'
26
+ version: '3.12'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: standard
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.49'
33
+ version: '1.51'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.49'
40
+ version: '1.51'
41
+ - !ruby/object:Gem::Dependency
42
+ name: curses
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 1.5.3
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.5'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.5.3
61
+ - !ruby/object:Gem::Dependency
62
+ name: ruby-prof
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.7'
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 1.7.2
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '1.7'
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 1.7.2
41
81
  - !ruby/object:Gem::Dependency
42
82
  name: chunky_png
43
83
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +92,20 @@ dependencies:
52
92
  - - "~>"
53
93
  - !ruby/object:Gem::Version
54
94
  version: '1.4'
95
+ - !ruby/object:Gem::Dependency
96
+ name: concurrent-ruby
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: 1.3.5
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: 1.3.5
55
109
  - !ruby/object:Gem::Dependency
56
110
  name: rice
57
111
  requirement: !ruby/object:Gem::Requirement
@@ -130,9 +184,27 @@ files:
130
184
  - lib/contrek.rb
131
185
  - lib/contrek/bitmaps/bitmap.rb
132
186
  - lib/contrek/bitmaps/chunky_bitmap.rb
187
+ - lib/contrek/bitmaps/custom_bitmap.rb
133
188
  - lib/contrek/bitmaps/painting.rb
134
189
  - lib/contrek/bitmaps/png_bitmap.rb
135
190
  - lib/contrek/bitmaps/rgb_color.rb
191
+ - lib/contrek/finder/concurrent/clipped_polygon_finder.rb
192
+ - lib/contrek/finder/concurrent/cluster.rb
193
+ - lib/contrek/finder/concurrent/cursor.rb
194
+ - lib/contrek/finder/concurrent/end_point.rb
195
+ - lib/contrek/finder/concurrent/fake_cluster.rb
196
+ - lib/contrek/finder/concurrent/finder.rb
197
+ - lib/contrek/finder/concurrent/hub.rb
198
+ - lib/contrek/finder/concurrent/listable.rb
199
+ - lib/contrek/finder/concurrent/part.rb
200
+ - lib/contrek/finder/concurrent/partitionable.rb
201
+ - lib/contrek/finder/concurrent/polyline.rb
202
+ - lib/contrek/finder/concurrent/poolable.rb
203
+ - lib/contrek/finder/concurrent/position.rb
204
+ - lib/contrek/finder/concurrent/queueable.rb
205
+ - lib/contrek/finder/concurrent/sequence.rb
206
+ - lib/contrek/finder/concurrent/shape.rb
207
+ - lib/contrek/finder/concurrent/tile.rb
136
208
  - lib/contrek/finder/list.rb
137
209
  - lib/contrek/finder/list_entry.rb
138
210
  - lib/contrek/finder/listable.rb
@@ -154,7 +226,7 @@ licenses:
154
226
  - MIT
155
227
  metadata:
156
228
  homepage_uri: https://github.com/runout77/contrek
157
- post_install_message:
229
+ post_install_message:
158
230
  rdoc_options: []
159
231
  require_paths:
160
232
  - lib
@@ -170,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
242
  version: '0'
171
243
  requirements: []
172
244
  rubygems_version: 3.5.22
173
- signing_key:
245
+ signing_key:
174
246
  specification_version: 4
175
247
  summary: Png image shapes contour finder
176
248
  test_files: []