contrek 1.1.2 → 1.1.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +11 -1
- data/Gemfile.lock +1 -1
- data/LICENSE-MIT.md +9 -0
- data/README.md +58 -17
- data/contrek.gemspec +0 -1
- data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +14 -2
- data/ext/cpp_polygon_finder/PolygonFinder/LICENSE_AGPL.txt +661 -0
- data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +9 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +9 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +4 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +13 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +74 -82
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +12 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +0 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +0 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +64 -46
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +14 -23
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +39 -44
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +5 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +6 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +4 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +12 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.h +3 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +35 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +5 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +11 -11
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +16 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +2 -5
- data/ext/cpp_polygon_finder/extconf.rb +12 -2
- data/lib/contrek/bitmaps/painting.rb +1 -0
- data/lib/contrek/finder/concurrent/cursor.rb +7 -5
- data/lib/contrek/finder/concurrent/finder.rb +2 -1
- data/lib/contrek/finder/concurrent/part.rb +12 -3
- data/lib/contrek/finder/concurrent/partitionable.rb +7 -5
- data/lib/contrek/finder/node.rb +61 -32
- data/lib/contrek/finder/node_cluster.rb +30 -27
- data/lib/contrek/finder/polygon_finder.rb +4 -4
- data/lib/contrek/version.rb +1 -1
- metadata +5 -4
|
@@ -106,8 +106,8 @@ module Contrek
|
|
|
106
106
|
|
|
107
107
|
# rubocop:disable Lint/NonLocalExitFromIterator
|
|
108
108
|
def traverse_outer(act_part, all_parts, shapes_sequence, outer_joined_polyline)
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
last_part = all_parts.last
|
|
110
|
+
all_parts << act_part if last_part != act_part
|
|
111
111
|
if act_part.is?(Part::EXCLUSIVE)
|
|
112
112
|
return if act_part.size == 0
|
|
113
113
|
while (position = act_part.next_position)
|
|
@@ -117,14 +117,14 @@ module Contrek
|
|
|
117
117
|
outer_joined_polyline.add(position)
|
|
118
118
|
end
|
|
119
119
|
else
|
|
120
|
+
return if act_part.dead_end && all_parts.size > 1 && last_part.is?(Part::SEAM) && last_part.polyline == act_part.polyline
|
|
120
121
|
while (new_position = act_part.iterator)
|
|
121
122
|
return if outer_joined_polyline.size > 1 &&
|
|
122
123
|
outer_joined_polyline.head.payload == new_position.payload &&
|
|
123
124
|
act_part == all_parts.first
|
|
124
125
|
outer_joined_polyline.add(Position.new(position: new_position.payload, hub: @cluster.hub))
|
|
125
|
-
|
|
126
126
|
act_part.polyline.next_tile_eligible_shapes.each do |shape|
|
|
127
|
-
if (part = shape.outer_polyline.find_first_part_by_position(new_position))
|
|
127
|
+
if (part = shape.outer_polyline.find_first_part_by_position(new_position, act_part.versus))
|
|
128
128
|
if all_parts[-2] != part
|
|
129
129
|
if all_parts.size >= 2
|
|
130
130
|
map = all_parts[-2..].map(&:type).uniq
|
|
@@ -132,12 +132,12 @@ module Contrek
|
|
|
132
132
|
end
|
|
133
133
|
shapes_sequence.add(part.polyline.shape)
|
|
134
134
|
part.next_position(new_position)
|
|
135
|
+
part.dead_end = true
|
|
135
136
|
traverse_outer(part, all_parts, shapes_sequence, outer_joined_polyline)
|
|
136
137
|
return
|
|
137
138
|
end
|
|
138
139
|
end
|
|
139
140
|
end
|
|
140
|
-
act_part.passes += 1
|
|
141
141
|
act_part.next_position
|
|
142
142
|
end
|
|
143
143
|
end
|
|
@@ -189,6 +189,8 @@ module Contrek
|
|
|
189
189
|
act_part.polyline.next_tile_eligible_shapes.each do |shape|
|
|
190
190
|
shape.outer_polyline.parts.each do |dest_part|
|
|
191
191
|
next if dest_part.trasmuted || dest_part.is?(Part::EXCLUSIVE)
|
|
192
|
+
dest_part_versus = dest_part.versus
|
|
193
|
+
next if dest_part_versus != 0 && dest_part_versus == act_part.versus
|
|
192
194
|
|
|
193
195
|
if dest_part.intersect_part?(act_part)
|
|
194
196
|
link_seq = duplicates_intersection(dest_part, act_part)
|
|
@@ -29,6 +29,7 @@ module Contrek
|
|
|
29
29
|
@clusters = []
|
|
30
30
|
@maximum_width = bitmap.w
|
|
31
31
|
@number_of_tiles = options[:number_of_tiles] || (raise "number_of_tiles params is needed!")
|
|
32
|
+
@number_of_tiles = 1 if @number_of_tiles <= 0
|
|
32
33
|
|
|
33
34
|
cw = @maximum_width.to_f / @number_of_tiles
|
|
34
35
|
raise "One pixel tile width minimum!" if cw < 1.0
|
|
@@ -45,7 +46,7 @@ module Contrek
|
|
|
45
46
|
finder = ClippedPolygonFinder.new(
|
|
46
47
|
bitmap: bitmap,
|
|
47
48
|
matcher: matcher,
|
|
48
|
-
options: {versus: current_versus, bounds: true},
|
|
49
|
+
options: {versus: current_versus, bounds: true, connectivity: @options[:connectivity]}.compact,
|
|
49
50
|
start_x: payload[:tile_start_x],
|
|
50
51
|
end_x: payload[:tile_end_x]
|
|
51
52
|
)
|
|
@@ -8,18 +8,19 @@ module Contrek
|
|
|
8
8
|
ADDED = 2
|
|
9
9
|
|
|
10
10
|
attr_reader :polyline, :index, :touched
|
|
11
|
-
attr_accessor :next, :circular_next, :prev, :type, :
|
|
11
|
+
attr_accessor :next, :circular_next, :prev, :type, :dead_end, :inverts, :trasmuted, :delayed, :versus
|
|
12
12
|
def initialize(type, polyline)
|
|
13
13
|
@type = type
|
|
14
14
|
@polyline = polyline
|
|
15
15
|
@next = nil
|
|
16
16
|
@circular_next = nil
|
|
17
17
|
@prev = nil
|
|
18
|
-
@
|
|
18
|
+
@dead_end = false
|
|
19
19
|
@touched = false
|
|
20
20
|
@inverts = false
|
|
21
21
|
@trasmuted = false
|
|
22
22
|
@delayed = false
|
|
23
|
+
@versus = 0
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
def is?(type)
|
|
@@ -60,7 +61,7 @@ module Contrek
|
|
|
60
61
|
end
|
|
61
62
|
|
|
62
63
|
def inspect
|
|
63
|
-
"part #{polyline.parts.index(self)} (inv=#{@inverts} trm=#{@trasmuted} touched=#{@touched}
|
|
64
|
+
"part #{polyline.parts.index(self)} (versus=#{@versus} inv=#{@inverts} trm=#{@trasmuted} touched=#{@touched} dead_end =#{@dead_end}, #{size}x) of #{polyline.info} (#{name}) (#{to_a.map { |e| "[#{e[:x]},#{e[:y]}]" }.join})"
|
|
64
65
|
end
|
|
65
66
|
|
|
66
67
|
def innerable?
|
|
@@ -78,6 +79,14 @@ module Contrek
|
|
|
78
79
|
map(&:end_point)
|
|
79
80
|
end
|
|
80
81
|
|
|
82
|
+
def orient!
|
|
83
|
+
@versus = if size <= 1
|
|
84
|
+
0
|
|
85
|
+
else
|
|
86
|
+
(tail.payload[:y] - head.payload[:y]).positive? ? 1 : -1
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
81
90
|
def self.remove_adjacent_pairs(array = nil)
|
|
82
91
|
n = array.size
|
|
83
92
|
(0...(n - 1)).each do |i|
|
|
@@ -14,6 +14,8 @@ module Contrek
|
|
|
14
14
|
last.next = last.circular_next = new_part if last
|
|
15
15
|
new_part.circular_next = @parts.first
|
|
16
16
|
new_part.prev = last
|
|
17
|
+
|
|
18
|
+
new_part.orient! if new_part.is?(Part::SEAM)
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def insert_after(part, new_part)
|
|
@@ -25,10 +27,10 @@ module Contrek
|
|
|
25
27
|
part.next = part.circular_next = new_part
|
|
26
28
|
end
|
|
27
29
|
|
|
28
|
-
def find_first_part_by_position(position)
|
|
30
|
+
def find_first_part_by_position(position, versus)
|
|
29
31
|
@parts.find do |part|
|
|
30
32
|
part.is?(Part::SEAM) &&
|
|
31
|
-
part.
|
|
33
|
+
part.versus == -versus &&
|
|
32
34
|
position.end_point.queues.include?(part)
|
|
33
35
|
end
|
|
34
36
|
end
|
|
@@ -144,10 +146,10 @@ module Contrek
|
|
|
144
146
|
|
|
145
147
|
count = 0
|
|
146
148
|
inside.each do |position|
|
|
147
|
-
|
|
148
|
-
count += 1
|
|
149
|
+
inclusion = position.end_point.queues.include?(inside_compare)
|
|
150
|
+
count += 1 if inclusion
|
|
149
151
|
end
|
|
150
|
-
if count == inside.size
|
|
152
|
+
if count == inside.size && count < inside_compare.size
|
|
151
153
|
inside.type = Part::EXCLUSIVE
|
|
152
154
|
inside.trasmuted = true
|
|
153
155
|
break
|
data/lib/contrek/finder/node.rb
CHANGED
|
@@ -3,7 +3,8 @@ module Contrek
|
|
|
3
3
|
class Node
|
|
4
4
|
include Listable
|
|
5
5
|
|
|
6
|
-
attr_reader :min_x, :max_x, :y, :name, :
|
|
6
|
+
attr_reader :min_x, :max_x, :y, :name, :tangs_sequence, :tangs_count, :data_pointer,
|
|
7
|
+
:upper_start, :upper_end, :lower_start, :lower_end, :start_point, :end_point
|
|
7
8
|
attr_accessor :track, :abs_x_index, :outer_index, :inner_index
|
|
8
9
|
|
|
9
10
|
T_UP = -1
|
|
@@ -24,12 +25,11 @@ module Contrek
|
|
|
24
25
|
OUTER = 0
|
|
25
26
|
INNER = 1
|
|
26
27
|
|
|
27
|
-
def initialize(cluster, min_x, max_x, y, name)
|
|
28
|
+
def initialize(cluster, min_x, max_x, y, name, connectivity_offset = 0)
|
|
28
29
|
@name = name
|
|
29
30
|
@min_x = min_x
|
|
30
31
|
@max_x = max_x
|
|
31
32
|
@y = y
|
|
32
|
-
@tangs = {T_UP => [], T_DOWN => []}
|
|
33
33
|
@tangs_sequence = nil
|
|
34
34
|
@tangs_count = 0
|
|
35
35
|
@track = 0
|
|
@@ -39,11 +39,23 @@ module Contrek
|
|
|
39
39
|
@down_indexer = 0
|
|
40
40
|
@outer_index = -1
|
|
41
41
|
@inner_index = -1
|
|
42
|
-
|
|
42
|
+
@upper_start = Float::INFINITY
|
|
43
|
+
@upper_end = -1
|
|
44
|
+
@lower_start = Float::INFINITY
|
|
45
|
+
@lower_end = -1
|
|
46
|
+
@start_point = {x: min_x, y: y}
|
|
47
|
+
@end_point = {x: max_x, y: y}
|
|
48
|
+
@cluster = cluster
|
|
49
|
+
cluster.add_node(self, connectivity_offset)
|
|
43
50
|
end
|
|
44
51
|
|
|
45
|
-
def
|
|
46
|
-
|
|
52
|
+
def get_tangent_node_by_virtual_index(virtual_index)
|
|
53
|
+
return nil if virtual_index.nil?
|
|
54
|
+
if virtual_index < 0
|
|
55
|
+
@cluster.vert_nodes[y + T_UP][-(virtual_index + 1)]
|
|
56
|
+
else
|
|
57
|
+
@cluster.vert_nodes[y + T_DOWN][virtual_index]
|
|
58
|
+
end
|
|
47
59
|
end
|
|
48
60
|
|
|
49
61
|
def my_next(last, versus, mode)
|
|
@@ -62,15 +74,13 @@ module Contrek
|
|
|
62
74
|
end
|
|
63
75
|
|
|
64
76
|
when :inner
|
|
65
|
-
|
|
66
77
|
if versus == :o
|
|
67
78
|
(last_node_index == 0) ? last_node_index = tangs_sequence.size - 1 : last_node_index -= 1
|
|
68
79
|
else
|
|
69
80
|
(last_node_index == tangs_sequence.size - 1) ? last_node_index = 0 : last_node_index += 1
|
|
70
81
|
end
|
|
71
|
-
|
|
72
82
|
end
|
|
73
|
-
tangs_sequence.at(last_node_index)
|
|
83
|
+
get_tangent_node_by_virtual_index(@tangs_sequence.at(last_node_index))
|
|
74
84
|
end
|
|
75
85
|
|
|
76
86
|
def coords_entering_to(enter_to, enter_mode, tracking)
|
|
@@ -79,14 +89,28 @@ module Contrek
|
|
|
79
89
|
else
|
|
80
90
|
@down_indexer - enter_to.abs_x_index
|
|
81
91
|
end
|
|
82
|
-
ds = tangs_sequence[enter_to_index]
|
|
83
|
-
coords_source = ds.send(enter_mode)
|
|
84
|
-
enter_to.track |= TURNER[tracking][coords_source[:m] - 1]
|
|
85
|
-
coords_source[:point]
|
|
86
|
-
end
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
tg_index = @tangs_sequence[enter_to_index]
|
|
94
|
+
if tg_index < 0
|
|
95
|
+
node_up = @cluster.vert_nodes[y + T_UP][-(tg_index + 1)]
|
|
96
|
+
if enter_mode == :a
|
|
97
|
+
enter_to.track |= TURNER[tracking][OMAX - 1]
|
|
98
|
+
point = node_up.end_point
|
|
99
|
+
else
|
|
100
|
+
enter_to.track |= TURNER[tracking][OMIN - 1]
|
|
101
|
+
point = node_up.start_point
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
node_down = @cluster.vert_nodes[y + T_DOWN][tg_index]
|
|
105
|
+
if enter_mode == :a
|
|
106
|
+
enter_to.track |= TURNER[tracking][OMIN - 1]
|
|
107
|
+
point = node_down.start_point
|
|
108
|
+
else
|
|
109
|
+
enter_to.track |= TURNER[tracking][OMAX - 1]
|
|
110
|
+
point = node_down.end_point
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
point
|
|
90
114
|
end
|
|
91
115
|
|
|
92
116
|
def track_uncomplete
|
|
@@ -97,28 +121,33 @@ module Contrek
|
|
|
97
121
|
(@track & OCOMPLETE) == OCOMPLETE
|
|
98
122
|
end
|
|
99
123
|
|
|
100
|
-
def add_intersection(other_node)
|
|
124
|
+
def add_intersection(other_node, other_node_index)
|
|
101
125
|
if other_node.y < y
|
|
102
|
-
@
|
|
126
|
+
@upper_start = other_node_index if other_node_index < @upper_start
|
|
127
|
+
@upper_end = other_node_index if other_node_index > @upper_end
|
|
103
128
|
else
|
|
104
|
-
@
|
|
129
|
+
@lower_start = other_node_index if other_node_index < @lower_start
|
|
130
|
+
@lower_end = other_node_index if other_node_index > @lower_end
|
|
105
131
|
end
|
|
106
132
|
end
|
|
107
133
|
|
|
108
|
-
def precalc_tangs_sequences
|
|
109
|
-
@tangs_sequence =
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
134
|
+
def precalc_tangs_sequences(cluster:)
|
|
135
|
+
@tangs_sequence = []
|
|
136
|
+
@up_indexer = -cluster.vert_nodes[@y + T_UP][@upper_start].abs_x_index if @upper_end >= 0
|
|
137
|
+
if @upper_end >= 0
|
|
138
|
+
(@upper_start..@upper_end).each do |upper_pos|
|
|
139
|
+
@tangs_sequence << -(upper_pos + 1)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
if @lower_end >= 0
|
|
143
|
+
lower_size = (@lower_end >= 0) ? (@lower_end - @lower_start + 1) : 0
|
|
144
|
+
upper_size = (@upper_end >= 0) ? (@upper_end - @upper_start + 1) : 0
|
|
145
|
+
@down_indexer = (cluster.vert_nodes[@y + T_DOWN][@lower_start].abs_x_index + lower_size + upper_size - 1)
|
|
116
146
|
end
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
tangs_sequence[n += 1] = nd
|
|
147
|
+
if @lower_end >= 0
|
|
148
|
+
@lower_end.downto(@lower_start).each do |lower_pos|
|
|
149
|
+
@tangs_sequence << lower_pos
|
|
150
|
+
end
|
|
122
151
|
end
|
|
123
152
|
@tangs_count = tangs_sequence.size
|
|
124
153
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Contrek
|
|
2
2
|
module Finder
|
|
3
3
|
class NodeCluster
|
|
4
|
-
attr_reader :root_nodes, :sequences, :polygons, :lists, :treemap, :vert_nodes
|
|
4
|
+
attr_reader :root_nodes, :sequences, :polygons, :lists, :treemap, :vert_nodes, :options
|
|
5
5
|
VERSUS_INVERTER = {a: :o, o: :a}
|
|
6
6
|
|
|
7
7
|
def initialize(h, options)
|
|
@@ -44,7 +44,7 @@ module Contrek
|
|
|
44
44
|
def build_tangs_sequence
|
|
45
45
|
@vert_nodes.each do |line|
|
|
46
46
|
line.each do |node|
|
|
47
|
-
node.precalc_tangs_sequences
|
|
47
|
+
node.precalc_tangs_sequences(cluster: self)
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -62,21 +62,18 @@ module Contrek
|
|
|
62
62
|
bounds = Bounds.empty
|
|
63
63
|
# external polygon
|
|
64
64
|
@plot_sequence << root_node
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
|
|
66
|
+
next_node = if versus == :a
|
|
67
|
+
root_node.get_tangent_node_by_virtual_index(root_node.tangs_sequence.last)
|
|
67
68
|
else
|
|
68
|
-
root_node.tangs_sequence.first
|
|
69
|
+
root_node.get_tangent_node_by_virtual_index(root_node.tangs_sequence.first)
|
|
69
70
|
end
|
|
70
|
-
|
|
71
|
-
if !next_node_nd.nil?
|
|
72
|
-
next_node = next_node_nd.node
|
|
71
|
+
if !next_node.nil?
|
|
73
72
|
coord = next_node.coords_entering_to(root_node, VERSUS_INVERTER[versus], Contrek::Finder::Node::OUTER)
|
|
74
73
|
@sequence_coords << coord
|
|
75
74
|
bounds.expand(x: coord[:x], y: coord[:y])
|
|
76
75
|
end
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
plot_node(next_node, root_node, bounds, versus) if @nodes > 0 && !next_node_nd.nil?
|
|
76
|
+
plot_node(next_node, root_node, bounds, versus) if @nodes > 0 && !next_node.nil?
|
|
80
77
|
|
|
81
78
|
draw_sequence(bitmap, "X") unless bitmap.nil?
|
|
82
79
|
@polygons << {outer: @sequence_coords, inner: [], bounds: (bounds.to_h if @options[:bounds])}.compact if @sequence_coords.size >= 2
|
|
@@ -103,9 +100,15 @@ module Contrek
|
|
|
103
100
|
# end
|
|
104
101
|
|
|
105
102
|
next_node = if (first.track & Contrek::Finder::Node::OMAX) != 0
|
|
106
|
-
|
|
103
|
+
if inner_v == :a
|
|
104
|
+
vert_nodes[first.y + Node::T_UP][first.upper_start]
|
|
105
|
+
else
|
|
106
|
+
vert_nodes[first.y + Node::T_DOWN][first.lower_start]
|
|
107
|
+
end
|
|
108
|
+
elsif inner_v == :a
|
|
109
|
+
vert_nodes[first.y + Node::T_DOWN][first.lower_end]
|
|
107
110
|
else
|
|
108
|
-
|
|
111
|
+
vert_nodes[first.y + Node::T_UP][first.upper_end]
|
|
109
112
|
end
|
|
110
113
|
|
|
111
114
|
if !next_node.nil?
|
|
@@ -192,13 +195,13 @@ module Contrek
|
|
|
192
195
|
@root_nodes.delete(node)
|
|
193
196
|
@inner_plot.delete(node)
|
|
194
197
|
last_node = @plot_sequence.last
|
|
195
|
-
|
|
196
|
-
next_node = next_node_nd.node
|
|
198
|
+
next_node = node.my_next(last_node, versus, :inner)
|
|
197
199
|
@plot_sequence << node
|
|
198
200
|
|
|
199
201
|
plot = true
|
|
200
202
|
if next_node.y == last_node.y
|
|
201
|
-
|
|
203
|
+
virtual_index = node.tangs_sequence.send((versus == :a) ? :first : :last)
|
|
204
|
+
plot = (node.get_tangent_node_by_virtual_index(virtual_index) == next_node)
|
|
202
205
|
end
|
|
203
206
|
if plot
|
|
204
207
|
@sequence_coords << last_node.coords_entering_to(node, VERSUS_INVERTER[versus], Contrek::Finder::Node::INNER)
|
|
@@ -225,14 +228,14 @@ module Contrek
|
|
|
225
228
|
|
|
226
229
|
node.outer_index = start_node.outer_index
|
|
227
230
|
last_node = @plot_sequence.last
|
|
228
|
-
|
|
229
|
-
next_node = next_node_nd.node
|
|
231
|
+
next_node = node.my_next(last_node, versus, :outer)
|
|
230
232
|
|
|
231
233
|
@plot_sequence << node
|
|
232
234
|
|
|
233
235
|
plot = true
|
|
234
236
|
if next_node.y == last_node.y
|
|
235
|
-
|
|
237
|
+
virtual_index = node.tangs_sequence.send((versus == :a) ? :last : :first)
|
|
238
|
+
plot = (node.get_tangent_node_by_virtual_index(virtual_index) == next_node)
|
|
236
239
|
end
|
|
237
240
|
|
|
238
241
|
# coord
|
|
@@ -258,7 +261,7 @@ module Contrek
|
|
|
258
261
|
plot_node(next_node, start_node, bounds, versus)
|
|
259
262
|
end
|
|
260
263
|
|
|
261
|
-
def add_node(node)
|
|
264
|
+
def add_node(node, offset)
|
|
262
265
|
@nodes += 1
|
|
263
266
|
node.abs_x_index = @vert_nodes[node.y].size
|
|
264
267
|
|
|
@@ -273,17 +276,17 @@ module Contrek
|
|
|
273
276
|
index = 0
|
|
274
277
|
loop do
|
|
275
278
|
up_node = up_nodes[index]
|
|
276
|
-
if up_node.max_x >= node.min_x
|
|
277
|
-
if up_node.min_x <= node.max_x
|
|
278
|
-
node.add_intersection(up_node)
|
|
279
|
-
up_node.add_intersection(node)
|
|
279
|
+
if (up_node.max_x + offset) >= node.min_x
|
|
280
|
+
if (up_node.min_x - offset) <= node.max_x
|
|
281
|
+
node.add_intersection(up_node, index)
|
|
282
|
+
up_node.add_intersection(node, node.abs_x_index)
|
|
280
283
|
end
|
|
281
284
|
return if (index += 1) == up_nodes_count
|
|
282
285
|
loop do
|
|
283
286
|
up_node = up_nodes[index]
|
|
284
|
-
if up_node.min_x <= node.max_x
|
|
285
|
-
node.add_intersection(up_node)
|
|
286
|
-
up_node.add_intersection(node)
|
|
287
|
+
if (up_node.min_x - offset) <= node.max_x
|
|
288
|
+
node.add_intersection(up_node, index)
|
|
289
|
+
up_node.add_intersection(node, node.abs_x_index)
|
|
287
290
|
else
|
|
288
291
|
return
|
|
289
292
|
end
|
|
@@ -3,7 +3,6 @@ require "benchmark"
|
|
|
3
3
|
module Contrek
|
|
4
4
|
module Finder
|
|
5
5
|
class PolygonFinder
|
|
6
|
-
NodeDescriptor = Struct.new(:node, :a, :o)
|
|
7
6
|
def initialize(bitmap, matcher, test_bitmap = nil, options = {})
|
|
8
7
|
@options = {versus: :a}.merge(options)
|
|
9
8
|
sanitize_options
|
|
@@ -91,6 +90,7 @@ module Contrek
|
|
|
91
90
|
|
|
92
91
|
# image scan
|
|
93
92
|
def scan
|
|
93
|
+
offset = (@node_cluster.options[:connectivity] == 8) ? 1 : 0
|
|
94
94
|
last_color = nil
|
|
95
95
|
matching = false
|
|
96
96
|
min_x = start_x
|
|
@@ -103,16 +103,16 @@ module Contrek
|
|
|
103
103
|
matching = true
|
|
104
104
|
if x == (end_x - 1)
|
|
105
105
|
max_x = x
|
|
106
|
-
Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color)
|
|
106
|
+
Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color, offset)
|
|
107
107
|
matching = false
|
|
108
108
|
end
|
|
109
109
|
elsif @matcher.unmatch?(color) && matching == true
|
|
110
110
|
max_x = x - 1
|
|
111
|
-
Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color)
|
|
111
|
+
Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color, offset)
|
|
112
112
|
matching = false
|
|
113
113
|
elsif x == (end_x - 1) && matching == true
|
|
114
114
|
max_x = x
|
|
115
|
-
Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color)
|
|
115
|
+
Contrek::Finder::Node.new(@node_cluster, min_x, max_x, y, last_color, offset)
|
|
116
116
|
matching = false
|
|
117
117
|
end
|
|
118
118
|
end
|
data/lib/contrek/version.rb
CHANGED
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.1.
|
|
4
|
+
version: 1.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emanuele Cesaroni
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -135,12 +135,14 @@ files:
|
|
|
135
135
|
- CHANGELOG.md
|
|
136
136
|
- Gemfile
|
|
137
137
|
- Gemfile.lock
|
|
138
|
+
- LICENSE-MIT.md
|
|
138
139
|
- LICENSE.md
|
|
139
140
|
- README.md
|
|
140
141
|
- Rakefile
|
|
141
142
|
- contrek.gemspec
|
|
142
143
|
- contrek.png
|
|
143
144
|
- ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt
|
|
145
|
+
- ext/cpp_polygon_finder/PolygonFinder/LICENSE_AGPL.txt
|
|
144
146
|
- ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp
|
|
145
147
|
- ext/cpp_polygon_finder/PolygonFinder/images/labyrinth.png
|
|
146
148
|
- ext/cpp_polygon_finder/PolygonFinder/images/sample_10240x10240.png
|
|
@@ -275,7 +277,6 @@ licenses:
|
|
|
275
277
|
- AGPL-3.0-only
|
|
276
278
|
metadata:
|
|
277
279
|
homepage_uri: https://github.com/runout77/contrek
|
|
278
|
-
source_code_uri: https://github.com/runout77/contrek
|
|
279
280
|
documentation_uri: https://github.com/runout77/contrek#readme
|
|
280
281
|
changelog_uri: https://github.com/runout77/contrek/blob/main/CHANGELOG.md
|
|
281
282
|
post_install_message:
|
|
@@ -293,7 +294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
293
294
|
- !ruby/object:Gem::Version
|
|
294
295
|
version: '0'
|
|
295
296
|
requirements: []
|
|
296
|
-
rubygems_version: 3.
|
|
297
|
+
rubygems_version: 3.5.22
|
|
297
298
|
signing_key:
|
|
298
299
|
specification_version: 4
|
|
299
300
|
summary: Fast PNG contour tracing and shape detection for Ruby
|