contrek 1.3.3 → 1.3.5
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 +3 -0
- data/Gemfile.lock +3 -1
- data/README.md +28 -28
- data/contrek.gemspec +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +0 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +11 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +8 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +4 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +114 -42
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +66 -116
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +1 -1
- 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 +2 -87
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +1 -13
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp +0 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +1 -57
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +1 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +31 -17
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +0 -16
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +0 -9
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.cpp +177 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.h +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.cpp +109 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.h +32 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +6 -1
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +4 -0
- data/lib/contrek/bitmaps/painting.rb +27 -10
- data/lib/contrek/bitmaps/png_bitmap.rb +3 -0
- data/lib/contrek/bitmaps/rendering.rb +75 -0
- data/lib/contrek/finder/concurrent/cursor.rb +62 -84
- data/lib/contrek/finder/concurrent/finder.rb +2 -1
- data/lib/contrek/finder/concurrent/part.rb +4 -77
- data/lib/contrek/finder/concurrent/partitionable.rb +1 -58
- data/lib/contrek/finder/concurrent/queueable.rb +23 -5
- data/lib/contrek/finder/concurrent/sequence.rb +0 -15
- data/lib/contrek/finder/concurrent/tile.rb +1 -1
- data/lib/contrek/finder/node.rb +26 -8
- data/lib/contrek/finder/node_cluster.rb +91 -37
- data/lib/contrek/finder/polygon_finder.rb +1 -1
- data/lib/contrek/reducers/douglas_peucker_reducer.rb +191 -0
- data/lib/contrek/reducers/raster_reducer.rb +72 -0
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +3 -0
- metadata +23 -2
|
@@ -32,7 +32,9 @@ module Contrek
|
|
|
32
32
|
path_sequences do |seq|
|
|
33
33
|
Contrek::Reducers::UniqReducer.new(points: seq).reduce! if @options[:compress].has_key?(:uniq)
|
|
34
34
|
Contrek::Reducers::LinearReducer.new(points: seq, options: @options[:compress][:linear]).reduce! if @options[:compress].has_key?(:linear)
|
|
35
|
+
Contrek::Reducers::RasterReducer.new(points: seq, options: @options).reduce! if @options[:compress].has_key?(:raster)
|
|
35
36
|
Contrek::Reducers::VisvalingamReducer.new(points: seq, options: @options[:compress][:visvalingam]).reduce! if @options[:compress].has_key?(:visvalingam)
|
|
37
|
+
Contrek::Reducers::DouglasPeuckerReducer.new(points: seq).reduce! if @options[:compress].has_key?(:douglas_peucker)
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
|
|
@@ -70,16 +72,44 @@ module Contrek
|
|
|
70
72
|
else
|
|
71
73
|
root_node.get_tangent_node_by_virtual_index(root_node.tangs_sequence.first)
|
|
72
74
|
end
|
|
73
|
-
|
|
75
|
+
|
|
76
|
+
if next_node
|
|
77
|
+
beginning_point = (versus == :a) ? root_node.nw_point : root_node.ne_point
|
|
78
|
+
@sequence_coords << beginning_point
|
|
79
|
+
bounds.expand(**beginning_point)
|
|
80
|
+
|
|
74
81
|
coord = next_node.coords_entering_to(root_node, VERSUS_INVERTER[versus], Contrek::Finder::Node::OUTER)
|
|
75
82
|
@sequence_coords << coord
|
|
76
|
-
bounds.expand(
|
|
83
|
+
bounds.expand(**coord)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
plot_node(next_node, root_node, bounds, versus) if @nodes > 0 && !next_node.nil?
|
|
87
|
+
|
|
88
|
+
if next_node.nil?
|
|
89
|
+
if versus == :a
|
|
90
|
+
nw_point = root_node.nw_point
|
|
91
|
+
@sequence_coords << nw_point
|
|
92
|
+
bounds.expand(**nw_point)
|
|
93
|
+
@sequence_coords << root_node.sw_point
|
|
94
|
+
se_point = root_node.se_point
|
|
95
|
+
@sequence_coords << se_point
|
|
96
|
+
bounds.expand(**se_point)
|
|
97
|
+
@sequence_coords << root_node.ne_point
|
|
98
|
+
else
|
|
99
|
+
ne_point = root_node.ne_point
|
|
100
|
+
@sequence_coords << ne_point
|
|
101
|
+
bounds.expand(**ne_point)
|
|
102
|
+
@sequence_coords << root_node.se_point
|
|
103
|
+
sw_point = root_node.sw_point
|
|
104
|
+
@sequence_coords << sw_point
|
|
105
|
+
bounds.expand(**sw_point)
|
|
106
|
+
@sequence_coords << root_node.nw_point
|
|
107
|
+
end
|
|
77
108
|
end
|
|
78
|
-
plot_node(next_node, root_node, bounds, versus, @options[:strict_bounds]) if @nodes > 0 && !next_node.nil?
|
|
79
109
|
|
|
80
110
|
draw_sequence(bitmap, "X") unless bitmap.nil?
|
|
81
111
|
|
|
82
|
-
if @sequence_coords.
|
|
112
|
+
if @sequence_coords.any?
|
|
83
113
|
@polygons << {outer: @sequence_coords, inner: [], bounds: (bounds.to_h if @options[:bounds])}.compact
|
|
84
114
|
@sequences << @plot_sequence
|
|
85
115
|
|
|
@@ -117,10 +147,11 @@ module Contrek
|
|
|
117
147
|
|
|
118
148
|
if !next_node.nil?
|
|
119
149
|
@sequence_coords << next_node.coords_entering_to(first, inner_v, Contrek::Finder::Node::INNER)
|
|
150
|
+
last_node = plot_inner_node(next_node, inner_v, first, root_node)
|
|
151
|
+
last_coord = last_node.coords_entering_to(first, VERSUS_INVERTER[inner_v], Contrek::Finder::Node::INNER)
|
|
152
|
+
@sequence_coords << last_coord if @sequence_coords.last != last_coord
|
|
120
153
|
end
|
|
121
154
|
|
|
122
|
-
plot_inner_node(next_node, inner_v, first, root_node, options[:strict_bounds]) if !next_node.nil?
|
|
123
|
-
|
|
124
155
|
draw_sequence(bitmap, "+") unless bitmap.nil?
|
|
125
156
|
|
|
126
157
|
@polygons.last[:inner] << @sequence_coords
|
|
@@ -194,7 +225,7 @@ module Contrek
|
|
|
194
225
|
# inner way
|
|
195
226
|
# nodes in @plot_sequence
|
|
196
227
|
# coordinates in @sequence_coords
|
|
197
|
-
def plot_inner_node(node, versus, stop_at, start_node
|
|
228
|
+
def plot_inner_node(node, versus, stop_at, start_node)
|
|
198
229
|
node.outer_index = start_node.outer_index
|
|
199
230
|
@root_nodes.delete(node)
|
|
200
231
|
@inner_plot.delete(node)
|
|
@@ -214,16 +245,25 @@ module Contrek
|
|
|
214
245
|
virtual_index = node.tangs_sequence.send((versus == :a) ? :first : :last)
|
|
215
246
|
plot = (node.get_tangent_node_by_virtual_index(virtual_index) == next_node)
|
|
216
247
|
end
|
|
248
|
+
|
|
217
249
|
if plot
|
|
218
|
-
|
|
219
|
-
if
|
|
220
|
-
|
|
221
|
-
|
|
250
|
+
first_point = last_node.coords_entering_to(node, VERSUS_INVERTER[versus], Contrek::Finder::Node::INNER)
|
|
251
|
+
@sequence_coords << first_point if @sequence_coords.last != first_point
|
|
252
|
+
if next_node.y == last_node.y
|
|
253
|
+
if next_node.y < node.y
|
|
254
|
+
pt_a, pt_b = node.sw_point, node.se_point
|
|
255
|
+
else
|
|
256
|
+
pt_a, pt_b = node.ne_point, node.nw_point
|
|
257
|
+
end
|
|
258
|
+
if versus == :o
|
|
259
|
+
@sequence_coords << pt_a
|
|
260
|
+
@sequence_coords << pt_b
|
|
261
|
+
else
|
|
262
|
+
@sequence_coords << pt_b
|
|
263
|
+
@sequence_coords << pt_a
|
|
222
264
|
end
|
|
223
265
|
end
|
|
224
|
-
|
|
225
|
-
@sequence_coords << {y: node.y, x: (first_is_max ? last_node.max_x : last_node.min_x)}
|
|
226
|
-
@sequence_coords << {y: node.y, x: (first_is_max ? next_node.min_x : next_node.max_x)}
|
|
266
|
+
@sequence_coords << next_node.coords_entering_to(node, versus, Contrek::Finder::Node::INNER)
|
|
227
267
|
end
|
|
228
268
|
|
|
229
269
|
if node.track_uncomplete
|
|
@@ -232,12 +272,12 @@ module Contrek
|
|
|
232
272
|
@inner_new.delete(node)
|
|
233
273
|
end
|
|
234
274
|
|
|
235
|
-
return if next_node == stop_at
|
|
236
|
-
plot_inner_node(next_node, versus, stop_at, start_node
|
|
275
|
+
return node if next_node == stop_at
|
|
276
|
+
plot_inner_node(next_node, versus, stop_at, start_node)
|
|
237
277
|
end
|
|
238
278
|
|
|
239
279
|
# contour tracing core logic loop
|
|
240
|
-
def plot_node(node, start_node, bounds, versus = :a
|
|
280
|
+
def plot_node(node, start_node, bounds, versus = :a)
|
|
241
281
|
@root_nodes.delete(node)
|
|
242
282
|
|
|
243
283
|
node.outer_index = start_node.outer_index
|
|
@@ -252,32 +292,47 @@ module Contrek
|
|
|
252
292
|
plot = (node.get_tangent_node_by_virtual_index(virtual_index) == next_node)
|
|
253
293
|
end
|
|
254
294
|
|
|
255
|
-
# coord
|
|
256
295
|
if plot
|
|
257
|
-
|
|
258
|
-
@sequence_coords
|
|
259
|
-
|
|
296
|
+
start_coord = last_node.coords_entering_to(node, versus, Contrek::Finder::Node::OUTER)
|
|
297
|
+
if @sequence_coords.last != start_coord
|
|
298
|
+
@sequence_coords << start_coord
|
|
299
|
+
bounds.expand(**start_coord)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
final_step = node == start_node && node.track_complete
|
|
303
|
+
if next_node.y == last_node.y
|
|
304
|
+
if next_node.y < node.y
|
|
305
|
+
pt_a, pt_b = node.se_point, node.sw_point
|
|
306
|
+
else
|
|
307
|
+
pt_a, pt_b = node.nw_point, node.ne_point
|
|
308
|
+
end
|
|
309
|
+
first = (versus == :o) ? pt_a : pt_b
|
|
310
|
+
second = (versus == :o) ? pt_b : pt_a
|
|
311
|
+
@sequence_coords << first
|
|
312
|
+
bounds.expand(**first)
|
|
313
|
+
unless final_step
|
|
314
|
+
@sequence_coords << second
|
|
315
|
+
bounds.expand(**second)
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
unless final_step
|
|
320
|
+
end_coord = next_node.coords_entering_to(node, VERSUS_INVERTER[versus], Contrek::Finder::Node::OUTER)
|
|
321
|
+
@sequence_coords << end_coord
|
|
322
|
+
bounds.expand(**end_coord)
|
|
323
|
+
end
|
|
324
|
+
|
|
260
325
|
if node != start_node
|
|
261
326
|
@inner_plot.contains(node) ? @inner_plot.delete(node) : @inner_plot << node
|
|
262
327
|
if last_node.y == next_node.y
|
|
263
|
-
c = next_node.coords_entering_to(node, VERSUS_INVERTER[versus], Contrek::Finder::Node::OUTER)
|
|
264
|
-
@sequence_coords << c
|
|
265
|
-
bounds.expand(x: c[:x], y: c[:y])
|
|
266
328
|
@inner_plot.contains(node) ? @inner_plot.delete(node) : @inner_plot << node
|
|
267
329
|
end
|
|
268
330
|
end
|
|
269
|
-
elsif strict_bounds
|
|
270
|
-
is_down = node.y > last_node.y
|
|
271
|
-
is_a = (versus == :a)
|
|
272
|
-
@sequence_coords << {y: node.y, x: ((is_down == is_a) ? last_node.min_x : last_node.max_x)}
|
|
273
|
-
@sequence_coords << {y: node.y, x: ((is_down == is_a) ? next_node.max_x : next_node.min_x)}
|
|
274
331
|
end
|
|
275
332
|
# exit if root_node
|
|
333
|
+
return if node == start_node && node.track_complete
|
|
276
334
|
|
|
277
|
-
|
|
278
|
-
return if node.track_complete
|
|
279
|
-
end
|
|
280
|
-
plot_node(next_node, start_node, bounds, versus, strict_bounds)
|
|
335
|
+
plot_node(next_node, start_node, bounds, versus)
|
|
281
336
|
end
|
|
282
337
|
|
|
283
338
|
def add_node(node, offset)
|
|
@@ -295,15 +350,15 @@ module Contrek
|
|
|
295
350
|
index = 0
|
|
296
351
|
loop do
|
|
297
352
|
up_node = up_nodes[index]
|
|
298
|
-
if (up_node.max_x + offset) >= node.min_x
|
|
299
|
-
if (up_node.min_x - offset) <= node.max_x
|
|
353
|
+
if ((up_node.max_x - 1) + offset) >= node.min_x
|
|
354
|
+
if (up_node.min_x - offset) <= (node.max_x - 1)
|
|
300
355
|
node.add_intersection(up_node, index)
|
|
301
356
|
up_node.add_intersection(node, node.abs_x_index)
|
|
302
357
|
end
|
|
303
358
|
return if (index += 1) == up_nodes_count
|
|
304
359
|
loop do
|
|
305
360
|
up_node = up_nodes[index]
|
|
306
|
-
if (up_node.min_x - offset) <= node.max_x
|
|
361
|
+
if (up_node.min_x - offset) <= (node.max_x - 1)
|
|
307
362
|
node.add_intersection(up_node, index)
|
|
308
363
|
up_node.add_intersection(node, node.abs_x_index)
|
|
309
364
|
else
|
|
@@ -316,7 +371,6 @@ module Contrek
|
|
|
316
371
|
break if (index += 1) == up_nodes_count
|
|
317
372
|
end
|
|
318
373
|
end
|
|
319
|
-
|
|
320
374
|
end
|
|
321
375
|
end
|
|
322
376
|
end
|
|
@@ -6,7 +6,7 @@ module Contrek
|
|
|
6
6
|
module Finder
|
|
7
7
|
class PolygonFinder
|
|
8
8
|
def initialize(bitmap, matcher, test_bitmap = nil, options = {})
|
|
9
|
-
@options = {versus: :a
|
|
9
|
+
@options = {versus: :a}.merge(options)
|
|
10
10
|
sanitize_options
|
|
11
11
|
@source_bitmap = bitmap
|
|
12
12
|
@matcher = matcher
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Contrek
|
|
4
|
+
module Reducers
|
|
5
|
+
class DouglasPeuckerReducer < Reducer
|
|
6
|
+
TOLERANCE_SQUARED = 1.0
|
|
7
|
+
|
|
8
|
+
def reduce!
|
|
9
|
+
count = @points.length
|
|
10
|
+
return @points if count < 4
|
|
11
|
+
|
|
12
|
+
first_index = extreme_index_by_x
|
|
13
|
+
second_index = farthest_index_from(first_index)
|
|
14
|
+
|
|
15
|
+
return @points if second_index == first_index
|
|
16
|
+
|
|
17
|
+
keep = Array.new(count, false)
|
|
18
|
+
keep[first_index] = true
|
|
19
|
+
keep[second_index] = true
|
|
20
|
+
|
|
21
|
+
simplify_arc!(first_index, second_index, keep)
|
|
22
|
+
simplify_arc!(second_index, first_index, keep)
|
|
23
|
+
|
|
24
|
+
compact_ring!(keep)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def extreme_index_by_x
|
|
30
|
+
points = @points
|
|
31
|
+
index = 0
|
|
32
|
+
best = 0
|
|
33
|
+
best_x = points[0][:x]
|
|
34
|
+
|
|
35
|
+
while (index += 1) < points.length
|
|
36
|
+
x = points[index][:x]
|
|
37
|
+
|
|
38
|
+
if x < best_x
|
|
39
|
+
best_x = x
|
|
40
|
+
best = index
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
best
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def farthest_index_from(origin_index)
|
|
48
|
+
points = @points
|
|
49
|
+
origin = points[origin_index]
|
|
50
|
+
|
|
51
|
+
ox = origin[:x]
|
|
52
|
+
oy = origin[:y]
|
|
53
|
+
|
|
54
|
+
best_index = origin_index
|
|
55
|
+
best_distance = -1
|
|
56
|
+
|
|
57
|
+
index = 0
|
|
58
|
+
|
|
59
|
+
while index < points.length
|
|
60
|
+
dx = points[index][:x] - ox
|
|
61
|
+
dy = points[index][:y] - oy
|
|
62
|
+
distance = dx * dx + dy * dy
|
|
63
|
+
|
|
64
|
+
if distance > best_distance
|
|
65
|
+
best_distance = distance
|
|
66
|
+
best_index = index
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
index += 1
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
best_index
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def simplify_arc!(first_index, last_index, keep)
|
|
76
|
+
count = @points.length
|
|
77
|
+
stack = [first_index, last_index]
|
|
78
|
+
|
|
79
|
+
until stack.empty?
|
|
80
|
+
last = stack.pop
|
|
81
|
+
first = stack.pop
|
|
82
|
+
|
|
83
|
+
split = farthest_on_arc(first, last, count)
|
|
84
|
+
next unless split
|
|
85
|
+
|
|
86
|
+
keep[split] = true
|
|
87
|
+
|
|
88
|
+
stack << first << split if next_index(first, count) != split
|
|
89
|
+
stack << split << last if next_index(split, count) != last
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def farthest_on_arc(first_index, last_index, count)
|
|
94
|
+
points = @points
|
|
95
|
+
|
|
96
|
+
first = points[first_index]
|
|
97
|
+
last = points[last_index]
|
|
98
|
+
|
|
99
|
+
ax = first[:x]
|
|
100
|
+
ay = first[:y]
|
|
101
|
+
bx = last[:x]
|
|
102
|
+
by = last[:y]
|
|
103
|
+
|
|
104
|
+
abx = bx - ax
|
|
105
|
+
aby = by - ay
|
|
106
|
+
length_squared = abx * abx + aby * aby
|
|
107
|
+
|
|
108
|
+
max_distance = TOLERANCE_SQUARED
|
|
109
|
+
split_index = nil
|
|
110
|
+
index = next_index(first_index, count)
|
|
111
|
+
|
|
112
|
+
while index != last_index
|
|
113
|
+
point = points[index]
|
|
114
|
+
|
|
115
|
+
distance = if length_squared.zero?
|
|
116
|
+
dx = point[:x] - ax
|
|
117
|
+
dy = point[:y] - ay
|
|
118
|
+
dx * dx + dy * dy
|
|
119
|
+
else
|
|
120
|
+
point_segment_distance_squared(
|
|
121
|
+
point[:x],
|
|
122
|
+
point[:y],
|
|
123
|
+
ax,
|
|
124
|
+
ay,
|
|
125
|
+
bx,
|
|
126
|
+
by,
|
|
127
|
+
abx,
|
|
128
|
+
aby,
|
|
129
|
+
length_squared
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
if distance > max_distance
|
|
134
|
+
max_distance = distance
|
|
135
|
+
split_index = index
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
index = next_index(index, count)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
split_index
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def point_segment_distance_squared(
|
|
145
|
+
px, py,
|
|
146
|
+
ax, ay,
|
|
147
|
+
bx, by,
|
|
148
|
+
abx, aby,
|
|
149
|
+
length_squared
|
|
150
|
+
)
|
|
151
|
+
apx = px - ax
|
|
152
|
+
apy = py - ay
|
|
153
|
+
|
|
154
|
+
dot = apx * abx + apy * aby
|
|
155
|
+
|
|
156
|
+
if dot <= 0
|
|
157
|
+
apx * apx + apy * apy
|
|
158
|
+
elsif dot >= length_squared
|
|
159
|
+
bpx = px - bx
|
|
160
|
+
bpy = py - by
|
|
161
|
+
bpx * bpx + bpy * bpy
|
|
162
|
+
else
|
|
163
|
+
cross = apx * aby - apy * abx
|
|
164
|
+
(cross * cross).fdiv(length_squared)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def next_index(index, count)
|
|
169
|
+
(index + 1 == count) ? 0 : index + 1
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def compact_ring!(keep)
|
|
173
|
+
points = @points
|
|
174
|
+
read_index = 0
|
|
175
|
+
write_index = 0
|
|
176
|
+
|
|
177
|
+
while read_index < points.length
|
|
178
|
+
if keep[read_index]
|
|
179
|
+
points[write_index] = points[read_index]
|
|
180
|
+
write_index += 1
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
read_index += 1
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
points.slice!(write_index, points.length - write_index)
|
|
187
|
+
points
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Contrek
|
|
4
|
+
module Reducers
|
|
5
|
+
class RasterReducer < Reducer
|
|
6
|
+
def reduce!
|
|
7
|
+
versus = @opts[:versus]
|
|
8
|
+
to_raster_polygon!(@points, versus)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def to_raster_polygon!(points, versus)
|
|
14
|
+
n = points.size
|
|
15
|
+
return points if n.zero?
|
|
16
|
+
|
|
17
|
+
outer = versus == :o
|
|
18
|
+
first_x = points[0][:x]
|
|
19
|
+
first_y = points[0][:y]
|
|
20
|
+
prev_x = points[-1][:x]
|
|
21
|
+
prev_y = points[-1][:y]
|
|
22
|
+
points.each_index do |i|
|
|
23
|
+
curr_x = points[i][:x]
|
|
24
|
+
curr_y = points[i][:y]
|
|
25
|
+
if i + 1 < n
|
|
26
|
+
next_x = points[i + 1][:x]
|
|
27
|
+
next_y = points[i + 1][:y]
|
|
28
|
+
else
|
|
29
|
+
next_x = first_x
|
|
30
|
+
next_y = first_y
|
|
31
|
+
end
|
|
32
|
+
in_side = segment_pole(
|
|
33
|
+
curr_x - prev_x,
|
|
34
|
+
curr_y - prev_y,
|
|
35
|
+
outer
|
|
36
|
+
)
|
|
37
|
+
out_side = segment_pole(
|
|
38
|
+
next_x - curr_x,
|
|
39
|
+
next_y - curr_y,
|
|
40
|
+
outer
|
|
41
|
+
)
|
|
42
|
+
x = curr_x
|
|
43
|
+
y = curr_y
|
|
44
|
+
[in_side, out_side].uniq.each do |side|
|
|
45
|
+
case side
|
|
46
|
+
when :south then y -= 1
|
|
47
|
+
when :east then x -= 1
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
points[i][:x] = x
|
|
51
|
+
points[i][:y] = y
|
|
52
|
+
prev_x = curr_x
|
|
53
|
+
prev_y = curr_y
|
|
54
|
+
end
|
|
55
|
+
points
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def segment_pole(dx, dy, clockwise)
|
|
59
|
+
sx = dx <=> 0
|
|
60
|
+
sy = dy <=> 0
|
|
61
|
+
case [sx, sy]
|
|
62
|
+
when [0, 1] then clockwise ? :east : :west
|
|
63
|
+
when [1, 0] then clockwise ? :north : :south
|
|
64
|
+
when [0, -1] then clockwise ? :west : :east
|
|
65
|
+
when [-1, 0] then clockwise ? :south : :north
|
|
66
|
+
else
|
|
67
|
+
raise ArgumentError, "Non-axial segment dx=#{dx} dy=#{dy}!"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/contrek/version.rb
CHANGED
data/lib/contrek.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "contrek/version"
|
|
4
4
|
require "contrek/bitmaps/painting"
|
|
5
|
+
require "contrek/bitmaps/rendering"
|
|
5
6
|
require "contrek/bitmaps/bitmap"
|
|
6
7
|
require "contrek/bitmaps/chunky_bitmap"
|
|
7
8
|
require "contrek/bitmaps/png_bitmap"
|
|
@@ -51,6 +52,8 @@ require "contrek/reducers/reducer"
|
|
|
51
52
|
require "contrek/reducers/linear_reducer"
|
|
52
53
|
require "contrek/reducers/uniq_reducer"
|
|
53
54
|
require "contrek/reducers/visvalingam_reducer"
|
|
55
|
+
require "contrek/reducers/douglas_peucker_reducer"
|
|
56
|
+
require "contrek/reducers/raster_reducer"
|
|
54
57
|
require "cpp_polygon_finder"
|
|
55
58
|
require "contrek/cpp/cpp_concurrent_finder"
|
|
56
59
|
require "contrek/cpp/cpp_concurrent_merger"
|
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.3.
|
|
4
|
+
version: 1.3.5
|
|
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-
|
|
11
|
+
date: 2026-07-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -78,6 +78,20 @@ dependencies:
|
|
|
78
78
|
- - ">="
|
|
79
79
|
- !ruby/object:Gem::Version
|
|
80
80
|
version: 1.7.2
|
|
81
|
+
- !ruby/object:Gem::Dependency
|
|
82
|
+
name: ruby2d
|
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - "~>"
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '0.12'
|
|
88
|
+
type: :development
|
|
89
|
+
prerelease: false
|
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - "~>"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '0.12'
|
|
81
95
|
- !ruby/object:Gem::Dependency
|
|
82
96
|
name: chunky_png
|
|
83
97
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -234,8 +248,12 @@ files:
|
|
|
234
248
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.h
|
|
235
249
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.cpp
|
|
236
250
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.h
|
|
251
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.cpp
|
|
252
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/DouglasPeuckerReducer.h
|
|
237
253
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.cpp
|
|
238
254
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.h
|
|
255
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.cpp
|
|
256
|
+
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/RasterReducer.h
|
|
239
257
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.cpp
|
|
240
258
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.h
|
|
241
259
|
- ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.cpp
|
|
@@ -251,6 +269,7 @@ files:
|
|
|
251
269
|
- lib/contrek/bitmaps/painting.rb
|
|
252
270
|
- lib/contrek/bitmaps/png_bitmap.rb
|
|
253
271
|
- lib/contrek/bitmaps/raw_bitmap.rb
|
|
272
|
+
- lib/contrek/bitmaps/rendering.rb
|
|
254
273
|
- lib/contrek/bitmaps/rgb_color.rb
|
|
255
274
|
- lib/contrek/bitmaps/rgb_cpp_color.rb
|
|
256
275
|
- lib/contrek/bitmaps/sample_generator.rb
|
|
@@ -299,7 +318,9 @@ files:
|
|
|
299
318
|
- lib/contrek/matchers/matcher.rb
|
|
300
319
|
- lib/contrek/matchers/matcher_hsb.rb
|
|
301
320
|
- lib/contrek/matchers/value_not_matcher.rb
|
|
321
|
+
- lib/contrek/reducers/douglas_peucker_reducer.rb
|
|
302
322
|
- lib/contrek/reducers/linear_reducer.rb
|
|
323
|
+
- lib/contrek/reducers/raster_reducer.rb
|
|
303
324
|
- lib/contrek/reducers/reducer.rb
|
|
304
325
|
- lib/contrek/reducers/uniq_reducer.rb
|
|
305
326
|
- lib/contrek/reducers/visvalingam_reducer.rb
|