extract_curves 0.0.1-i586-linux

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 (99) hide show
  1. data/CVS/Entries +4 -0
  2. data/CVS/Repository +1 -0
  3. data/CVS/Root +1 -0
  4. data/bin/CVS/Entries +5 -0
  5. data/bin/CVS/Repository +1 -0
  6. data/bin/CVS/Root +1 -0
  7. data/bin/ec_rect2polar.rb +22 -0
  8. data/bin/ec_rev_lines.rb +5 -0
  9. data/bin/ec_sph_area.rb +30 -0
  10. data/bin/extract_curves.rb +2145 -0
  11. data/ruby_ext/CVS/Entries +1 -0
  12. data/ruby_ext/CVS/Repository +1 -0
  13. data/ruby_ext/CVS/Root +1 -0
  14. data/ruby_ext/pav/CVS/Entries +14 -0
  15. data/ruby_ext/pav/CVS/Repository +1 -0
  16. data/ruby_ext/pav/CVS/Root +1 -0
  17. data/ruby_ext/pav/extconf.rb +22 -0
  18. data/ruby_ext/pav/pav.so +0 -0
  19. data/ruby_libs/CVS/Entries +1 -0
  20. data/ruby_libs/CVS/Repository +1 -0
  21. data/ruby_libs/CVS/Root +1 -0
  22. data/ruby_libs/pav/CVS/Entries +20 -0
  23. data/ruby_libs/pav/CVS/Repository +1 -0
  24. data/ruby_libs/pav/CVS/Root +1 -0
  25. data/ruby_libs/pav/attr_cache.rb +211 -0
  26. data/ruby_libs/pav/attr_cache.t1.rb +32 -0
  27. data/ruby_libs/pav/cache.rb +31 -0
  28. data/ruby_libs/pav/dbg_log.rb +458 -0
  29. data/ruby_libs/pav/floatsio.rb +53 -0
  30. data/ruby_libs/pav/generator_cache.rb +165 -0
  31. data/ruby_libs/pav/gtk/CVS/Entries +4 -0
  32. data/ruby_libs/pav/gtk/CVS/Repository +1 -0
  33. data/ruby_libs/pav/gtk/CVS/Root +1 -0
  34. data/ruby_libs/pav/gtk/button.rb +130 -0
  35. data/ruby_libs/pav/gtk/icons.rb +87 -0
  36. data/ruby_libs/pav/gtk/toolbar.rb +192 -0
  37. data/ruby_libs/pav/heap.rb +54 -0
  38. data/ruby_libs/pav/icons/CVS/Entries +17 -0
  39. data/ruby_libs/pav/icons/CVS/Repository +1 -0
  40. data/ruby_libs/pav/icons/CVS/Root +1 -0
  41. data/ruby_libs/pav/icons/alt_handle.xpm +3832 -0
  42. data/ruby_libs/pav/icons/alt_handle_hover.xpm +3368 -0
  43. data/ruby_libs/pav/icons/alt_handle_pressed.xpm +3828 -0
  44. data/ruby_libs/pav/icons/extract_curves/CVS/Entries +6 -0
  45. data/ruby_libs/pav/icons/extract_curves/CVS/Repository +1 -0
  46. data/ruby_libs/pav/icons/extract_curves/CVS/Root +1 -0
  47. data/ruby_libs/pav/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
  48. data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
  49. data/ruby_libs/pav/icons/extract_curves/trace_mark.xpm +38 -0
  50. data/ruby_libs/pav/icons/handle.xpm +213 -0
  51. data/ruby_libs/pav/icons/next.xpm +29 -0
  52. data/ruby_libs/pav/icons/next_hover.xpm +315 -0
  53. data/ruby_libs/pav/icons/next_pressed.xpm +144 -0
  54. data/ruby_libs/pav/icons/prev.xpm +29 -0
  55. data/ruby_libs/pav/icons/prev_hover.xpm +315 -0
  56. data/ruby_libs/pav/icons/prev_pressed.xpm +144 -0
  57. data/ruby_libs/pav/icons/vnext.xpm +29 -0
  58. data/ruby_libs/pav/icons/vprev.xpm +29 -0
  59. data/ruby_libs/pav/numeric/CVS/Entries +2 -0
  60. data/ruby_libs/pav/numeric/CVS/Repository +1 -0
  61. data/ruby_libs/pav/numeric/CVS/Root +1 -0
  62. data/ruby_libs/pav/numeric/ext.rb +13 -0
  63. data/ruby_libs/pav/pav_find.rb +90 -0
  64. data/ruby_libs/pav/pix/CVS/Entries +11 -0
  65. data/ruby_libs/pav/pix/CVS/Repository +1 -0
  66. data/ruby_libs/pav/pix/CVS/Root +1 -0
  67. data/ruby_libs/pav/pix/aapix.rb +378 -0
  68. data/ruby_libs/pav/pix/blob.rb +543 -0
  69. data/ruby_libs/pav/pix/circle.rb +73 -0
  70. data/ruby_libs/pav/pix/contour/CVS/Entries +5 -0
  71. data/ruby_libs/pav/pix/contour/CVS/Repository +1 -0
  72. data/ruby_libs/pav/pix/contour/CVS/Root +1 -0
  73. data/ruby_libs/pav/pix/contour/calc_situations.rb +9 -0
  74. data/ruby_libs/pav/pix/contour/carp_calc.rb +212 -0
  75. data/ruby_libs/pav/pix/contour/situations.dmp +0 -0
  76. data/ruby_libs/pav/pix/contour/situations.rb +21 -0
  77. data/ruby_libs/pav/pix/contour.rb +644 -0
  78. data/ruby_libs/pav/pix/curve.rb +1508 -0
  79. data/ruby_libs/pav/pix/img_obj.rb +751 -0
  80. data/ruby_libs/pav/pix/node.rb +712 -0
  81. data/ruby_libs/pav/pix/node_grp.rb +853 -0
  82. data/ruby_libs/pav/pix/shaved_core.rb +534 -0
  83. data/ruby_libs/pav/pix/subpix.rb +212 -0
  84. data/ruby_libs/pav/pix.rb +402 -0
  85. data/ruby_libs/pav/rand_accessible.rb +16 -0
  86. data/ruby_libs/pav/rangeset.rb +63 -0
  87. data/ruby_libs/pav/search.rb +210 -0
  88. data/ruby_libs/pav/set.rb +20 -0
  89. data/ruby_libs/pav/string/CVS/Entries +6 -0
  90. data/ruby_libs/pav/string/CVS/Repository +1 -0
  91. data/ruby_libs/pav/string/CVS/Root +1 -0
  92. data/ruby_libs/pav/string/bits.rb +523 -0
  93. data/ruby_libs/pav/string/ext.rb +58 -0
  94. data/ruby_libs/pav/string/observable.rb +155 -0
  95. data/ruby_libs/pav/string/text.rb +79 -0
  96. data/ruby_libs/pav/string/words.rb +42 -0
  97. data/ruby_libs/pav/sub_arr.rb +55 -0
  98. data/ruby_libs/pav/traced_obj.rb +79 -0
  99. metadata +147 -0
@@ -0,0 +1,1508 @@
1
+ require 'set'
2
+ require 'pav/pix'
3
+ require 'pav/set'
4
+ require 'pav/search'
5
+ require 'pav/sub_arr'
6
+ require 'pav/pix/aapix'
7
+ require 'pav/pix/subpix'
8
+ require 'pav/pix/contour'
9
+ require 'pav/pix/img_obj'
10
+ require 'pav/pix/node_grp'
11
+
12
+ module PPix
13
+
14
+ class Blob
15
+ self.img_obj_add_to_sub_objs :curve_carpet
16
+
17
+ def curve_carpet(multiple_curves=false)
18
+ return @curve_carp if @curve_carp
19
+ $PDbgLog.sig_call(self)
20
+ @curve_carp = CurveCarpet.new(self, multiple_curves)
21
+ $PDbgLog.sig_return
22
+ @curve_carp
23
+ end
24
+
25
+ def delete_curve_carpet
26
+ @curve_carp = nil
27
+ end
28
+ end
29
+
30
+ class LoopSegs < Array
31
+ attr_reader :lp, :prev_segs_i, :prev_lp_i
32
+
33
+ def initialize(lp)
34
+ @lp = lp
35
+ super()
36
+ self.rewind
37
+ end
38
+
39
+ def rewind
40
+ @prev_segs_i = 0
41
+ if self.empty?
42
+ @prev_lp_i = 0
43
+ else
44
+ @prev_lp_i = self[0][0]
45
+ end
46
+ end
47
+
48
+ def append_seg(ofs_from_last_start, len)
49
+ self << [ofs_from_last_start, len]
50
+ end
51
+
52
+ def extend_seg_to(seg_i, seg_start_i, end_i)
53
+ j = seg_i
54
+ j_i = seg_start_i
55
+ while j + 1 < self.length && j_i + self[j+1][0] <= end_i
56
+ j += 1
57
+ j_i += self[j][0]
58
+ end
59
+ if tmp = j_i + self[j][1] > end_i then end_i = tmp; end
60
+ self[seg_i][1] = end_i - seg_start_i
61
+ self[seg_i+1..j] = nil
62
+ end
63
+
64
+ def subtract_seg(start_i, end_i)
65
+ #$PDbgLog.sig_call(self)
66
+ seg_i, lp_i = *self.cpix_i_get_seg_i_start(start_i)
67
+ #$PDbgLog.print_msg "#{start_i}..#{end_i}: seg_i=#{seg_i
68
+ # }, lp_i=#{lp_i}; "
69
+ if seg_i >= 0
70
+ if start_i <= lp_i
71
+ if end_i+1 < lp_i + self[seg_i][1]
72
+ len_ch = end_i+1 - lp_i
73
+ self[seg_i][0] += len_ch
74
+ self[seg_i][1] -= len_ch
75
+ @prev_segs_i = seg_i
76
+ @prev_lp_i = end_i+1
77
+ #$PDbgLog.sig_return(".")
78
+ return
79
+ else
80
+ lp_i -= self[seg_i][0]
81
+ end
82
+ elsif end_i+1 < lp_i + self[seg_i][1]
83
+ self[seg_i+1, 0] = [[end_i+1 - lp_i,
84
+ lp_i + self[seg_i][1] - end_i]]
85
+ self[seg_i][1] = start_i-lp_i
86
+ @prev_segs_i = seg_i
87
+ @prev_lp_i = lp_i
88
+ #$PDbgLog.sig_return(".")
89
+ return
90
+ else
91
+ self[seg_i][1] = start_i-lp_i
92
+ seg_i += 1
93
+ end
94
+ else
95
+ seg_i = -seg_i-1
96
+ end
97
+ @prev_segs_i = seg_i-1
98
+ @prev_lp_i = lp_i
99
+ if (j = seg_i) >= self.length
100
+ #$PDbgLog.sig_return(".")
101
+ return
102
+ end
103
+ j_i = lp_i + self[seg_i][0]
104
+ #$PDbgLog.print_msg "j=#{j}, j_i=#{j_i}; "
105
+ while j+1 < self.length && j_i + self[j+1][0] < end_i
106
+ j += 1; j_i += self[j][0]
107
+ end
108
+ #$PDbgLog.print_msg "j=#{j}, j_i=#{j_i}; "
109
+ if j_i + self[j][1] > end_i+1
110
+ self[j][0] = end_i - lp_i
111
+ self[j][1] -= end_i - j_i
112
+ self[j+1][0] -= end_i - j_i if j+1 < self.length
113
+ else
114
+ j += 1
115
+ self[j][0] = j_i + self[j][0] - lp_i if j < self.length
116
+ end
117
+ self[seg_i...j] = nil
118
+ #$PDbgLog.sig_return(".")
119
+ end
120
+
121
+ def each_seg_with_index
122
+ lp_i = 0
123
+ self.each_with_index { |seg, seg_i| lp_i += seg[0]
124
+ yield(SubArr.new(@lp, lp_i, lp_i+seg[1]), seg_i)
125
+ }
126
+ end
127
+
128
+ def each_abs_seg
129
+ lp_i = 0
130
+ self.each { |seg| lp_i += seg[0]; yield(lp_i, lp_i + seg[1]) }
131
+ end
132
+
133
+ def map_cpix!(cpix_i, maps_to)
134
+ #$PDbgLog.sig_call(self)
135
+ len_ch = maps_to.length - 1
136
+ #$PDbgLog.puts_msg "(#{cpix_i}) len_ch=#{len_ch} in #{self.to_s(
137
+ # 0, true)}"
138
+ self.rewind if @prev_lp_i > cpix_i
139
+ if @prev_segs_i >= self.length || @prev_segs_i < 0
140
+ self.rewind
141
+ if @prev_segs_i >= self.length
142
+ warn "LoopSegs.map_cpix!: BUG: @prev_segs_i(=#{
143
+ @prev_segs_i}) >= self.length(=#{self.length})"
144
+ #$PDbgLog.sig_return
145
+ return
146
+ end
147
+ end
148
+ loop do
149
+ if @prev_lp_i > cpix_i
150
+ #$PDbgLog.puts_msg "Mapped pixel out of " +
151
+ # "LoopSegs: #{self.segs_to_s(2)}"
152
+ #$PDbgLog.sig_return
153
+ return
154
+ end
155
+ break if @prev_lp_i + self[@prev_segs_i][1] > cpix_i
156
+ @prev_segs_i += 1
157
+ if @prev_segs_i >= self.length
158
+ #$PDbgLog.puts_msg "Mapped pixel out of " +
159
+ # "LoopSegs: #{self.segs_to_s(2)}"
160
+ self.rewind
161
+ #$PDbgLog.sig_return
162
+ return
163
+ end
164
+ @prev_lp_i += self[@prev_segs_i][0]
165
+ end
166
+ lp_i = @prev_lp_i
167
+ segs_i = @prev_segs_i
168
+ while lp_i <= cpix_i
169
+ if lp_i + self[segs_i][1] > cpix_i &&
170
+ (self[segs_i][1] += len_ch) < 1
171
+ self[segs_i][0] -= 1 if lp_i >= @lp.length
172
+ self[segs_i][1] += 1
173
+ end
174
+ segs_i += 1
175
+ break if segs_i >= self.length
176
+ lp_i += self[segs_i][0]
177
+ end
178
+ self[segs_i][0] += len_ch if segs_i < self.length
179
+ #$PDbgLog.puts_msg "Segs: #{self.segs_to_s(2)}"
180
+ #$PDbgLog.sig_return
181
+ end
182
+
183
+ def cpix_i_get_seg_i_start(cpix_i)
184
+ #$PDbgLog.sig_call(self)
185
+ #$PDbgLog.puts_msg "(#{cpix_i}) in #{self.to_s(0, true)}"
186
+ if @prev_lp_i > cpix_i || @prev_segs_i >= self.length ||
187
+ @prev_segs_i < 0
188
+ self.rewind
189
+ if @prev_segs_i >= self.length || @prev_lp_i > cpix_i
190
+ #$PDbgLog.sig_return
191
+ return [-1, 0]
192
+ end
193
+ end
194
+ loop do
195
+ break if @prev_lp_i + self[@prev_segs_i][1] > cpix_i
196
+ if @prev_segs_i+1 >= self.length
197
+ #$PDbgLog.sig_return
198
+ return [-@prev_segs_i-2, @prev_lp_i]
199
+ end
200
+ if @prev_lp_i + self[@prev_segs_i+1][0] > cpix_i
201
+ #$PDbgLog.sig_return
202
+ return [-@prev_segs_i-2, @prev_lp_i]
203
+ end
204
+ @prev_segs_i += 1; @prev_lp_i += self[@prev_segs_i][0]
205
+ end
206
+ #$PDbgLog.sig_return
207
+ [@prev_segs_i, @prev_lp_i]
208
+ end
209
+
210
+ def segs_to_s(detail_lev=3)
211
+ case detail_lev
212
+ when 0 then self.length.to_s
213
+ when 1 then self.collect{|seg| seg.inspect}.join(" ")
214
+ when 2 then segs = ""
215
+ self.each_abs_seg { |s, e| segs << "#{s}...#{e}, " }
216
+ segs[-2,2] = "" if segs.length > 1
217
+ segs
218
+ when 3 then segs = ""
219
+ self.each_abs_seg { |s, e| segs << "#{s}..#{e-1}, " }
220
+ segs[-2,2] = "" if segs.length > 1
221
+ segs
222
+ else
223
+ segs = ""
224
+ self.each_seg_with_index { |pixs, seg_i|
225
+ segs << self[seg_i].inspect << ": " <<
226
+ PixbufPix.path_to_s(pixs) << "; "
227
+ }
228
+ segs[-2,2] = "" if segs.length > 1
229
+ segs
230
+ end
231
+ end
232
+
233
+ def lp_to_s(repr_id=1)
234
+ case repr_id
235
+ when 0 then idmem = @lp.object_id &
236
+ ( (1 << (8*@lp.object_id.size)) - 1 )
237
+ "0x%x" % idmem
238
+ when 1 then lp = "#{@lp.length} element"
239
+ lp += "s" if @lp.length != 1
240
+ lp
241
+ else
242
+ PixbufPix.path_to_s(@lp)
243
+ end
244
+ end
245
+
246
+ def to_s(expand_segs=3, expand_loop=1)
247
+ "<#{self.class.name}: @lp: #{self.lp_to_s(expand_loop)
248
+ }; segs: #{self.segs_to_s(expand_segs)}>"
249
+ end
250
+
251
+ def inspect(expand_segs=3, expand_loop=1)
252
+ "<#{self.class.name}: @lp: #{self.lp_to_s(expand_loop)
253
+ }, @prev_segs_i=#{@prev_segs_i}, @prev_lp_i=#{@prev_lp_i.
254
+ inspect}; segs: #{self.segs_to_s(expand_segs)}>"
255
+ end
256
+ end
257
+
258
+ class AaPix
259
+ attr_accessor :border_dirs8_id, :subpix_path_dir
260
+ end
261
+
262
+ class AaPixWithPrevs < AaPix
263
+ attr_reader :prevs
264
+
265
+ def initialize(pixbuf, ax, ay)
266
+ super(pixbuf, ax, ay)
267
+ @prevs = Set.new
268
+ end
269
+
270
+ def tree_to_pp_s(indent_str='', indent_step=' ')
271
+ next_indent_str = indent_str + indent_step
272
+ res = indent_str + self.coords_to_s + ':' +
273
+ (@prevs.to_a.first.kind_of?(AaPixWithPrevs) ? "\n" : ' ') +
274
+ @prevs.collect{|pix| pix.kind_of?(AaPixWithPrevs) ?
275
+ pix.tree_to_pp_s(next_indent_str, indent_step) :
276
+ pix.inspect + "\n"
277
+ }.to_s
278
+ end
279
+ end
280
+
281
+ class BlobLoopCalc
282
+ attr_accessor :map_loop_end_i, :excl_set, :start_lp
283
+ attr_reader :blob, :lp, :prevs, :loop_segs, :not_done_pix_segs,
284
+ :layer_set, :blob_id
285
+
286
+ def initialize(blob, lp)
287
+ @blob = blob
288
+ @lp = lp.class.new
289
+ lp.each_with_index { |pix, pix_i|
290
+ pp = AaPixWithPrevs.new(pix.pixbuf, pix.ax, pix.ay)
291
+ pp.subpix_path_dir = pix.subpix_path_dir
292
+ pp.border_dirs8_id = pix.border_dirs8_id
293
+ pp.prevs << pix_i
294
+ @lp << pp
295
+ }
296
+ @start_lp = @lp
297
+ @excl_set = {}
298
+ @layer_set = {}; @lp.each { |pix| @layer_set[pix] = true }
299
+ @path_cache = {}
300
+ @tail = []
301
+ @neighbs = []
302
+ @next_lp = lp.class.new
303
+ @next_prevs = []
304
+ @prev_layer_set = {}
305
+ @map_loop_meth = self.method("map_loop_without_segs!")
306
+ @pixbuf = @blob.pixbuf
307
+ @blob_id = @blob.blob_id
308
+ end
309
+
310
+ def pix_map_into(pix,res, excl_set, prev_cpix, next_cpix, path_cache={},
311
+ tail=[], neighbs=[])
312
+ #$PDbgLog.sig_call(self)
313
+ #$PDbgLog.print_msg "excl_set: #{PixbufPix.yx_path_to_s(
314
+ # excl_set.keys.sort)}; "
315
+ #$PDbgLog.print_msg "#{pix.coords_to_s} prev_cpix#{prev_cpix.
316
+ # coords_to_s}, next_cpix#{next_cpix.coords_to_s}: "
317
+ if prev_cpix.y == next_cpix.y && prev_cpix.x == next_cpix.x
318
+ # $PDbgLog.print_msg "blob neighbs.: #{PixbufPix.path_to_s(
319
+ # @blobpix.pix_neighbs(pix)}: "
320
+ if @blob.pix_neighbs(pix).detect { |p|
321
+ !excl_set.include?(p.yx) && p.y != prev_cpix.y &&
322
+ p.x != prev_cpix.x && p.y != next_cpix.y &&
323
+ p.x != next_cpix.x
324
+ }
325
+ #$PDbgLog.sig_return("")
326
+ return []
327
+ else
328
+ #$PDbgLog.sig_return("nil")
329
+ return nil
330
+ end
331
+ end
332
+ pixbuf = @blob.pixbuf
333
+ blob_id = @blob.blob_id
334
+ if prev_cpix.virtual? || next_cpix.virtual? ||
335
+ !pixbuf.blob_id_at?(prev_cpix.x, prev_cpix.y, blob_id) ||
336
+ !pixbuf.blob_id_at?(next_cpix.x, next_cpix.y, blob_id)
337
+ get_neighbs_proc = proc { |cpix, ngb_res|
338
+ #$PDbgLog.sig_call(self)
339
+ # $PDbgLog.print_msg "get ngbs proc #{cpix.coords_to_s}: "
340
+ ngb_res.clear
341
+ PixbufPix::ADJACENT8.each { |adj|
342
+ p = pixbuf.get_pix(cpix.x+adj.x, cpix.y+adj.y)
343
+ ngb_res << p if p.yx != pix.yx &&
344
+ !excl_set.include?(p.yx) &&
345
+ (p.yx == next_cpix.yx ||
346
+ (pixbuf.blob_id_at?(p.x, p.y, blob_id) &&
347
+ ((adj4 = p.adj4).length < 4 ||
348
+ adj4.detect { |px| excl_set.include?(px.yx) ||
349
+ px.yx == pix.yx ||
350
+ !pixbuf.blob_id_at?(px.x, px.y, blob_id)
351
+ }))
352
+ )
353
+ }
354
+ #$PDbgLog.sig_return(PixbufPix.path_to_s(ngb_res))
355
+ ngb_res
356
+ }
357
+ else
358
+ get_neighbs_proc = proc { |cpix, ngb_res|
359
+ #$PDbgLog.sig_call(self)
360
+ # $PDbgLog.print_msg "get ngbs proc #{cpix.coords_to_s}: "
361
+ ngb_res.clear
362
+ @blob.pix_neighbs(cpix).each { |p|
363
+ ngb_res << p if
364
+ p.yx != pix.yx && !excl_set.include?(p.yx) &&
365
+ ((adj4 = p.adj4).length < 4 ||
366
+ adj4.detect { |px| excl_set.include?(px.yx) ||
367
+ px.yx == pix.yx ||
368
+ !pixbuf.blob_id_at?(px.x, px.y, blob_id)
369
+ })
370
+ }
371
+ #$PDbgLog.sig_return(PixbufPix.path_to_s(ngb_res))
372
+ ngb_res
373
+ }
374
+ end
375
+ if (res=prev_cpix.find_shortest_pix_path_into(res, next_cpix, 7,
376
+ path_cache, tail, neighbs, &get_neighbs_proc))
377
+ res.pop
378
+ end
379
+ #$PDbgLog.sig_return(res ? PixbufPix.path_to_s(res) : "nil")
380
+ res
381
+ end
382
+
383
+ def add_loop_segs
384
+ @loop_segs = LoopSegs.new(@lp) unless @loop_segs
385
+ @map_loop_meth = self.method("map_loop_with_segs!")
386
+ end
387
+
388
+ def map_loop_without_segs!(start_i, end_i)
389
+ $PDbgLog.sig_call(self)
390
+ #$PDbgLog.puts_msg "start_i=#{start_i}, end_i=#{end_i} in #{
391
+ # @lp.length} pixel#{@lp.length==1 ? "" : "s"}: #{
392
+ # PixbufPix.path_to_s(@lp)}"
393
+ next_px = nil
394
+ mapped_a_pix = false
395
+ i = start_i - 1
396
+ #nil_seq_i0 = nil_seq_end_i = 0
397
+ to = []
398
+ while (i+=1) < end_i
399
+ cpix = @lp[i]
400
+ if next_px && cpix != next_px
401
+ $PDbgLog.print_msg "i=#{i}, cpix#{cpix.coords_to_s
402
+ }, next_px#{next_px.coords_to_s}, start_i=#{
403
+ start_i}, end_i=#{end_i}); @lp.length=#{@lp.
404
+ length}; "
405
+ $PDbgLog.print_msg "@lp: #{PixbufPix.path_to_s(@lp)} "
406
+ end
407
+ unless self.pix_map_into(cpix, to, @excl_set,
408
+ @lp.at(i-1), next_px=@lp.at((i+1) % @lp.length),
409
+ @path_cache, @tail, @neighbs)
410
+ #if i - nil_seq_end_i < 2
411
+ # nil_seq_end_i += 1
412
+ #elsif nil_seq_end_i - nil_seq_i0 > 25
413
+ # @not_done_pix_segs.subtract_seg(
414
+ # nil_seq_i0, nil_seq_end_i)
415
+ #else
416
+ # nil_seq_start_i = nil_seq_end_i = i
417
+ #end
418
+ next
419
+ end
420
+ @lp[i,1] = to
421
+ new_i = i + to.length - 1
422
+ end_i += to.length - 1
423
+ @excl_set[cpix.yx] = true
424
+ #@not_done_pix_segs.map_cpix!(i, to)
425
+ #map_proc.call(cpix, i, to)
426
+ if to.empty? && @lp.length > 1 &&
427
+ @lp[i-1].y == @lp[lp_i=i % @lp.length].y &&
428
+ @lp[i-1].x == @lp[lp_i].x
429
+ @lp[lp_i,1] = nil
430
+ #@not_done_pix_segs.map_cpix!(i, to)
431
+ #map_proc.call(@lp[lp_i-1], i, [])
432
+ end_i -= 1
433
+ next_px = @lp[i % @lp.length]
434
+ end
435
+ i = new_i
436
+ mapped_a_pix = true
437
+ end
438
+ #@not_done_pix_segs.subtract_seg(nil_seq_i0, nil_seq_end_i) if
439
+ # nil_seq_end_i - nil_seq_i0 > 25
440
+ $PDbgLog.sig_return
441
+ mapped_a_pix
442
+ end
443
+
444
+ def map_loop_with_segs!(start_i, end_i)
445
+ $PDbgLog.sig_call(self)
446
+ #$PDbgLog.puts_msg "start_i=#{start_i}, end_i=#{end_i} in #{
447
+ # @lp.length} pixel#{@lp.length==1 ? "" : "s"}: #{
448
+ # PixbufPix.path_to_s(@lp)}"
449
+ next_px = nil
450
+ mapped_a_pix = false
451
+ i = start_i - 1
452
+ #nil_seq_i0 = nil_seq_end_i = 0
453
+ to = []
454
+ while (i+=1) < end_i
455
+ cpix = @lp[i]
456
+ if next_px && cpix != next_px
457
+ $PDbgLog.print_msg "i=#{i}, cpix#{cpix.coords_to_s
458
+ }, next_px#{next_px.coords_to_s}, start_i=#{
459
+ start_i}, end_i=#{end_i}); @lp.length=#{@lp.
460
+ length}; "
461
+ $PDbgLog.print_msg "@lp: #{PixbufPix.path_to_s(@lp)} "
462
+ end
463
+ unless self.pix_map_into(cpix, to, @excl_set,
464
+ @lp.at(i-1), next_px=@lp.at((i+1) % @lp.length),
465
+ @path_cache, @tail, @neighbs)
466
+ #if i - nil_seq_end_i < 2
467
+ # nil_seq_end_i += 1
468
+ #elsif nil_seq_end_i - nil_seq_i0 > 25
469
+ # @not_done_pix_segs.subtract_seg(
470
+ # nil_seq_i0, nil_seq_end_i)
471
+ #else
472
+ # nil_seq_start_i = nil_seq_end_i = i
473
+ #end
474
+ next
475
+ end
476
+ @lp[i,1] = to
477
+ new_i = i + to.length - 1
478
+ end_i += to.length - 1
479
+ @excl_set[cpix.yx] = true
480
+ #@not_done_pix_segs.map_cpix!(i, to)
481
+ @loop_segs.map_cpix!(i, to)
482
+ if to.empty? && @lp.length > 1 &&
483
+ @lp[i-1].y == @lp[lp_i=i % @lp.length].y &&
484
+ @lp[i-1].x == @lp[lp_i].x
485
+ @lp[lp_i,1] = nil
486
+ #@not_done_pix_segs.map_cpix!(i, to)
487
+ @loop_segs.map_cpix!(i, [])
488
+ end_i -= 1
489
+ next_px = @lp[i % @lp.length]
490
+ end
491
+ i = new_i
492
+ mapped_a_pix = true
493
+ end
494
+ #@not_done_pix_segs.subtract_seg(nil_seq_i0, nil_seq_end_i) if
495
+ # nil_seq_end_i - nil_seq_i0 > 25
496
+ $PDbgLog.sig_return
497
+ mapped_a_pix
498
+ end
499
+
500
+ def map_loop!(start_i, end_i)
501
+ return @map_loop_meth.call(start_i, end_i)
502
+ #$PDbgLog.sig_call(self)
503
+ seg_i,lp_i = *@not_done_pix_segs.cpix_i_get_seg_i_start(start_i)
504
+ #$PDbgLog.print_msg "#{start_i}...#{end_i}: seg_i=#{seg_i
505
+ # }, lp_i=#{lp_i}. "
506
+ if seg_i < 0
507
+ seg_i = -seg_i-1
508
+ if seg_i >= @not_done_pix_segs.length
509
+ #$PDbgLog.sig_return
510
+ return
511
+ end
512
+ lp_i += @not_done_pix_segs[seg_i][0]
513
+ end
514
+ mapped_a_pix = false
515
+ while lp_i < end_i
516
+ start_i = lp_i if lp_i > start_i
517
+ mapped_a_pix = true if @map_loop_meth.call(start_i,
518
+ lp_i + @not_done_pix_segs[seg_i][1])
519
+ break if (seg_i += 1) >= @not_done_pix_segs.length
520
+ lp_i += @not_done_pix_segs[seg_i]
521
+ end
522
+ #$PDbgLog.sig_return
523
+ mapped_a_pix
524
+ end
525
+
526
+ def map_loop_segments!
527
+ $PDbgLog.sig_call(self)
528
+ $PDbgLog.print_msg "#{@loop_segs.length} segment#{@loop_segs.
529
+ length == 1 ? "" : "s"}: "
530
+ $PDbgLog.new_progr
531
+ $PDbgLog.progr.total_progr_units = @blob.length
532
+ if @blob.external_contours
533
+ $PDbgLog.progr.total_progr_units += @lp.length
534
+ end
535
+ $PDbgLog.progr.show_as = "/ pixel#{@blob.length==1 ? "" : "s"}"
536
+ mapped_a_pix = true
537
+ while mapped_a_pix
538
+ mapped_a_pix = false
539
+ lp_start_i = @loop_segs[0][0]
540
+ @loop_segs.each_abs_seg { |start_i, end_i|
541
+ #$PDbgLog.print_msg "lp_start_i=#{lp_start_i}; Segment [#{
542
+ # start_i}; #{end_i}) " #; @lp: #{PixbufPix.path_to_s(@lp)
543
+ #} -> "
544
+ if end_i > lp_start_i
545
+ mapped_a_pix = true if self.map_loop!(
546
+ [lp_start_i, start_i].max, end_i)
547
+ lp_start_i = end_i
548
+ end
549
+ #$PDbgLog.puts_msg "Segment [#{start_i}; #{end_i}); Loop: #{
550
+ # PixbufPix.path_to_s(@lp)}"
551
+ $PDbgLog.progr.progr_units = excl_set.length
552
+ }
553
+ end
554
+ $PDbgLog.sig_return(" done.")
555
+ end
556
+ end
557
+
558
+ class BlobLoopCalc
559
+ def self.situation8_id_lms(id)
560
+ [id & 0b111, (id>>3) & 0b111, id >> 6]
561
+ end
562
+
563
+ def self.situation8_path(start_p, end_p, adj8_s, dir=+1)
564
+ path = []
565
+ pos = start_p + dir
566
+ if dir == 1
567
+ i_ofs = -1
568
+ else
569
+ i_ofs = (start_p == end_p ? 7 : 6)
570
+ end
571
+ while (pos % 8) != end_p
572
+ if adj8_s[pos-start_p+i_ofs] == 0 && (pos % 2 == 1 ||
573
+ (!path.empty? && adj8_s[path[-1]-start_p+i_ofs] == 0))
574
+ if start_p == end_p
575
+ d = (start_p % 2 == 0 ? 1 : 2)
576
+ if (-d..d).detect { |i| adj8_s[i] == 1 }
577
+ return []
578
+ else
579
+ return nil
580
+ end
581
+ else
582
+ return nil
583
+ end
584
+ end
585
+ if path.length > 0 && path[-1] % 2 == 0
586
+ path[-1] = pos
587
+ else
588
+ path << pos
589
+ end
590
+ pos += dir
591
+ end
592
+ if !path.empty? && path[-1] % 2 == 0
593
+ if path.length > 1
594
+ path.pop
595
+ elsif adj8_s[path[-1]-start_p+i_ofs] == 0
596
+ return nil
597
+ end
598
+ end
599
+ path.collect{|i| PixbufPix::ADJ8_CCW_ORDER.at(i % 8)}
600
+ end
601
+
602
+ PIX_SITUS8_4_PATHS = (0...(1 << 13)).collect { |sit_id|
603
+ start_p, end_p, adj8_s = self.situation8_id_lms(sit_id)
604
+ i_path = self.situation8_path(start_p, end_p, adj8_s, +1)
605
+ d_path = self.situation8_path(start_p, end_p, adj8_s, -1)
606
+ if i_path
607
+ if d_path
608
+ [i_path, d_path]
609
+ else
610
+ i_path
611
+ end
612
+ elsif d_path
613
+ d_path
614
+ else
615
+ nil
616
+ end
617
+ }
618
+
619
+ def pix_adj8(pix)
620
+ pix.adj8.find_all { |px| !@excl_set.include?(px.a_yx) }
621
+ end
622
+
623
+ def pix_adj8_s(pix)
624
+ res = 0
625
+ width=pix.pixbuf.picture_width; height=pix.pixbuf.picture_height
626
+ b = 1
627
+ PixbufPix::ADJ8_CCW_ORDER.each { |adj|
628
+ x = pix.x + adj.x; y = pix.y + adj.y
629
+ if x >= 0 && x < width && y >= 0 && y < height
630
+ res |= b
631
+ end
632
+ b = (b << 1)
633
+ }
634
+ res
635
+ end
636
+
637
+ def xy_mappable_to(x, y)
638
+ #$PDbgLog.sig_call(self)
639
+ #res =
640
+ x >= 0 && x < @pixbuf.picture_width && y >= 0 &&
641
+ y < @pixbuf.picture_height && !@excl_set.include?(
642
+ AaPix.a_yx(x, y)) && @pixbuf.blob_id_at?(x, y, @blob_id)
643
+ #$PDbgLog.sig_return("(#{x}, #{y}): #{res.inspect}")
644
+ #res
645
+ end
646
+
647
+ def pix_prev_next_situation8_id(pix, prev_p, next_p)
648
+ #$PDbgLog.sig_call(self)
649
+ if !pix.a_neighb8?(prev_p,0.51) || !pix.a_neighb8?(next_p, 0.51)
650
+ warn("#{self.class.name}.pix_prev_next_situation8_id: "+
651
+ "BUG: Pixels not contiguous: pix#{pix.coords_to_s
652
+ }, prev_p#{prev_p.coords_to_s}, next_p#{next_p.
653
+ coords_to_s}")
654
+ end
655
+ x_p = (prev_p.ax - pix.ax).round; y_p = (prev_p.ay-pix.ay).round
656
+ x_n = (next_p.ax - pix.ax).round; y_n = (next_p.ay-pix.ay).round
657
+ if x_p > 1 then x_p = 1; elsif x_p < -1 then x_p = -1; end
658
+ if y_p > 1 then y_p = 1; elsif y_p < -1 then y_p = -1; end
659
+ if x_n > 1 then x_n = 1; elsif x_n < -1 then x_n = -1; end
660
+ if y_n > 1 then y_n = 1; elsif y_n < -1 then y_n = -1; end
661
+ if (x_p.abs < 1 && y_p.abs < 1) || (x_n.abs < 1 && y_n.abs < 1)
662
+ warn("#{self.class.name}.pix_prev_next_situation8_id: "+
663
+ "BUG: Two subsequent pix in loop are the same: pix#{
664
+ pix.coords_to_s}, prev_p#{prev_p.coords_to_s
665
+ }, next_p#{next_p.coords_to_s}")
666
+ end
667
+ # $PDbgLog.print_msg "pix#{pix.coords_to_s}, prev_p#{prev_p.
668
+ # coords_to_s}, next_p#{next_p.coords_to_s}"+#"; x_p=#{x_p
669
+ # }, y_p=#{y_p}; x_n=#{x_n}, y_n=#{y_n}"
670
+ #$PDbgLog.print_msg ": "
671
+ i_p = i_n = nil
672
+ b = 1
673
+ adj8_s = 0
674
+ Xy::ADJ8_CCW_ORDER.each_with_index{ |a,i|
675
+ if a.y == y_p && a.x == x_p
676
+ i_p = i
677
+ i_n = i if a.y == y_n && a.x == x_n
678
+ adj8_s <<= 6 - (i - (i_n ? 1 : 0))
679
+ b = 1
680
+ elsif a.y == y_n && a.x == x_n
681
+ i_n = i
682
+ else
683
+ x = pix.ax + a.x; y = pix.ay + a.y
684
+ if a.x < 0
685
+ x = x.ceil
686
+ if a.y < 0 then y = y.ceil
687
+ flag = self.xy_mappable_to(x, y)
688
+ elsif a.y > 0 then y = y.floor
689
+ flag = self.xy_mappable_to(x, y)
690
+ else
691
+ flag = self.xy_mappable_to(x, y.floor)&&
692
+ self.xy_mappable_to(x, y.ceil)
693
+ end
694
+ elsif a.x > 0
695
+ x = x.floor
696
+ if a.y < 0 then y = y.ceil
697
+ flag = self.xy_mappable_to(x, y)
698
+ elsif a.y > 0 then y = y.floor
699
+ flag = self.xy_mappable_to(x, y)
700
+ else
701
+ flag = self.xy_mappable_to(x, y.floor)&&
702
+ self.xy_mappable_to(x, y.ceil)
703
+ end
704
+ elsif a.y < 0
705
+ y = y.ceil
706
+ flag = self.xy_mappable_to(x.floor, y)&&
707
+ self.xy_mappable_to(x.ceil, y)
708
+ elsif a.y > 0
709
+ y = y.floor
710
+ flag = self.xy_mappable_to(x.floor, y)&&
711
+ self.xy_mappable_to(x.ceil, y)
712
+ elsif a.y == 0
713
+ flag = self.xy_mappable_to(x.floor,
714
+ y.floor) &&
715
+ self.xy_mappable_to(x.floor,y.ceil) &&
716
+ self.xy_mappable_to(x.ceil,y.floor) &&
717
+ self.xy_mappable_to(x.ceil,y.ceil)
718
+ end
719
+ adj8_s |= b if flag
720
+ #$PDbgLog.print_msg "(#{pix.ax+a.x}, #{
721
+ # pix.ay+a.y})[#{i}]: #{flag} "
722
+ b = (b << 1)
723
+ end
724
+ }
725
+ #$PDbgLog.print_msg "i_p=#{i_p.inspect}, i_n=#{i_n.inspect}: "
726
+ #res =
727
+ i_p | (i_n << 3) | (adj8_s << 6)
728
+ #$PDbgLog.sig_return("%b" % res)
729
+ #res
730
+ end
731
+
732
+ def pix_map8_4_into(pix, prev_p, next_p, res_prev_p, res=[[], []])
733
+ #$PDbgLog.sig_call(self)
734
+ #$PDbgLog.print_msg pix.coords_to_s + (pix.border_dirs8_id ?
735
+ # "+border_dirs8_id=%b" % pix.border_dirs8_id : '') +
736
+ # (pix.subpix_path_dir ? "+subpix_path_dir=" +
737
+ # pix.subpix_path_dir.inspect : '') +
738
+ # ", prev_p#{prev_p.coords_to_s}, next_p#{next_p.
739
+ # coords_to_s}: "
740
+ #$PDbgLog.print_msg "res_prev_p#{res_prev_p ?
741
+ # res_prev_p.coords_to_s : "=" + res_prev_p.inspect}: "
742
+ if pix.y != pix.ay || pix.x != pix.ax
743
+ res[0].clear
744
+ res[0] << pix
745
+ #$PDbgLog.sig_return('self')
746
+ return res[0]
747
+ end
748
+ situ_id = self.pix_prev_next_situation8_id(pix, prev_p, next_p)
749
+ #$PDbgLog.print_msg "situ.: %b " % situ_id
750
+ if (paths = BlobLoopCalc::PIX_SITUS8_4_PATHS.at(situ_id))
751
+ if paths[0].kind_of?(Array)
752
+ res[0].clear; res[1].clear
753
+ paths[0].each{|a| res[0] << AaPixWithPrevs.new(@pixbuf,
754
+ pix.x + a.x, pix.y + a.y) }
755
+ paths[1].each{|a| res[1] << AaPixWithPrevs.new(@pixbuf,
756
+ pix.x + a.x, pix.y + a.y) }
757
+ #$PDbgLog.puts_msg "paths: 0: #{PixbufPix.path_to_s(
758
+ # res[0])}, 1: #{PixbufPix.path_to_s(res[1])}"
759
+ if !res_prev_p
760
+ if pix.subpix_path_dir == -1
761
+ # $PDbgLog.sig_return("1: " + PixbufPix.path_to_s(
762
+ # res[1]))
763
+ res[1]
764
+ else
765
+ # $PDbgLog.sig_return("0: " + PixbufPix.path_to_s(
766
+ # res[0]))
767
+ res[0]
768
+ end
769
+ elsif !res[0].empty? &&
770
+ !res_prev_p.a_neighb8?(res[0][0])
771
+ if !(res[1]).empty? &&
772
+ !res_prev_p.neighb8?(res[1][0])
773
+ res[1].clear
774
+ res[1] << pix
775
+ end
776
+ # $PDbgLog.sig_return("1: " + PixbufPix.path_to_s(
777
+ # res[1]))
778
+ res[1]
779
+ elsif pix.subpix_path_dir == -1 &&
780
+ (res[1].empty? || res_prev_p.a_neighb8?(res[1][0]))
781
+ # $PDbgLog.sig_return("1: " + PixbufPix.path_to_s(
782
+ # res[1]))
783
+ res[1]
784
+ else
785
+ # $PDbgLog.sig_return("0: " + PixbufPix.path_to_s(
786
+ # res[0]))
787
+ res[0]
788
+ end
789
+ else
790
+ res[0].clear
791
+ paths.each{|a| res[0] << AaPixWithPrevs.new(@pixbuf,
792
+ pix.x + a.x, pix.y + a.y) }
793
+ if res_prev_p && !res[0].empty? &&
794
+ !res_prev_p.neighb8?(res[0][0])
795
+ res[0].clear
796
+ res[0] << pix
797
+ end
798
+ #$PDbgLog.sig_return(PixbufPix.path_to_s(res[0]))
799
+ res[0]
800
+ end
801
+ else
802
+ res[0].clear
803
+ res[0] << pix
804
+ #$PDbgLog.sig_return('self')
805
+ res[0]
806
+ end
807
+ end
808
+
809
+ def pix_trace_min_seg(pix)
810
+ #$PDbgLog.sig_call(self)
811
+ #$PDbgLog.print_msg "#{pix.coords_to_s}: "
812
+ while !(p_prevs = pix.prevs.to_a).detect{|p| !p.kind_of?(AaPix)}
813
+ ngbs_arr = pix.semi_neighbs8_contig_arr(p_prevs)
814
+ if (segs = AaXy.semi_neighbs8_contig_arr_get_segs(
815
+ ngbs_arr)).empty?
816
+ pix = p_prevs.first
817
+ next
818
+ end
819
+ p_next_i = ngbs_arr[segs[0][0]]
820
+ pix = p_prevs[p_next_i]
821
+ end
822
+ #$PDbgLog.sig_return(p_prevs)
823
+ p_prevs.detect { |p| p.kind_of?(Integer) }
824
+ end
825
+
826
+ def pix_trace_max_seg(pix)
827
+ #$PDbgLog.sig_call(self)
828
+ #$PDbgLog.print_msg "#{pix.coords_to_s}: "
829
+ while !(p_prevs = pix.prevs.to_a).detect{|p| !p.kind_of?(AaPix)}
830
+ ngbs_arr = pix.semi_neighbs8_contig_arr(p_prevs)
831
+ if (segs = AaXy.semi_neighbs8_contig_arr_get_segs(
832
+ ngbs_arr)).empty?
833
+ pix = p_prevs.first
834
+ next
835
+ end
836
+ p_next_i = ngbs_arr[segs.last[1] - 1]
837
+ pix = p_prevs[p_next_i]
838
+ end
839
+ #$PDbgLog.sig_return(p_prevs)
840
+ p_prevs.detect { |p| p.kind_of?(Integer) }
841
+ end
842
+
843
+ def pix_trace_mid_seg(pix, p_prevs, i_err)
844
+ #$PDbgLog.sig_call(self)
845
+ #$PDbgLog.print_msg "pix#{pix.coords_to_s} "
846
+ path = [pix]
847
+ i_mid = 0; seg = [0, 0]
848
+ pixbuf = pix.pixbuf
849
+ while !p_prevs.detect { |p| !p.kind_of?(AaPixWithPrevs) }
850
+ ngbs_arr = pix.semi_neighbs8_contig_arr(p_prevs)
851
+ #$PDbgLog.print_msg "prevs: #{Xy.path_to_s(
852
+ # p_prevs)}, i_err=#{i_err}; "
853
+ unless (segs=AaXy.semi_neighbs8_contig_arr_get_segs(
854
+ ngbs_arr)).empty?
855
+ seg = [segs.first[0], segs.last[1]]
856
+ p_i_mid = Float(seg[0] + seg[1]-1 - i_err) / 2.0
857
+ i_mid = p_i_mid.round
858
+ #$PDbgLog.print_msg "ngbs_arr=#{ngbs_arr.inspect
859
+ # }, segs=#{segs.inspect}, seg=#{seg.inspect
860
+ # }, p_i_mid=#{p_i_mid}, i_mid=#{i_mid}; "
861
+ if i_mid >= seg[1]
862
+ i_mid = seg[1]-1
863
+ elsif i_mid < seg[0]
864
+ i_mid = seg[0]
865
+ end
866
+ #$PDbgLog.print_msg "i_mid=#{i_mid}; "
867
+ i_err = p_i_mid - i_mid
868
+ a = AaXy::SEMI_ADJ8[16 + i_mid % 16]
869
+ pix = AaPix.new(pixbuf, pix.ax+a.ax,pix.ay+a.ay)
870
+ end
871
+ next_prevs = []
872
+ p_prevs.each { |px|
873
+ if pix.a_eql?(px)
874
+ next_prevs = px.prevs.to_a; break
875
+ elsif pix.a_close_neighb?(px) &&
876
+ !path[-1].a_close_neighb?(px)
877
+ next_prevs << px; next
878
+ end
879
+ px.prevs.each { |t_pix|
880
+ next unless t_pix.kind_of?(AaPixWithPrevs)
881
+ if pix.a_neighb8?(t_pix) && !path[-1].
882
+ semi_close_neighb?(t_pix)
883
+ next_prevs << t_pix
884
+ end
885
+ }
886
+ }
887
+ if next_prevs.empty?
888
+ if ngbs_arr[i_mid]
889
+ p_next_i = ngbs_arr[i_mid]
890
+ else
891
+ d = 1
892
+ loop do
893
+ if i_mid - d < seg[0]
894
+ p_next_i = ngbs_arr[i_mid = seg[0]]; break
895
+ elsif i_mid+d >= seg[1]
896
+ p_next_i = ngbs_arr[i_mid = seg[1]-1]; break
897
+ elsif i_mid - d >= seg[0] && ngbs_arr[i_mid-d]
898
+ p_next_i = ngbs_arr[i_mid = i_mid-d]; break
899
+ elsif ngbs_arr[i_mid+d]
900
+ p_next_i = ngbs_arr[i_mid = i_mid+d]; break
901
+ end
902
+ d += 1
903
+ end
904
+ end
905
+ p_next_i = 0 unless p_next_i
906
+ pix = p_prevs[p_next_i]
907
+ next_prevs = pix.prevs.to_a
908
+ end
909
+ p_prevs = next_prevs
910
+ if path.length > 1 && path[-2].a_neighb8?(pix)
911
+ path[-1] = pix
912
+ else
913
+ path << pix
914
+ end
915
+ #$PDbgLog.print_msg "pix#{pix.coords_to_s} "
916
+ end
917
+ #$PDbgLog.sig_return(p_prevs)
918
+ [p_prevs.detect {|p| p.kind_of?(Integer)}, path]
919
+ end
920
+
921
+ def pix_trace_seg(pix, pix_prevs, ngbs_arr, seg_i_0, seg_i_end)
922
+ #$PDbgLog.sig_call(self)
923
+ #$PDbgLog.puts_msg "pix#{pix.coords_to_s},pix_prevs: #{Xy.
924
+ # path_to_s(pix_prevs)}, seg_i_0=#{seg_i_0}, seg_i_end=#{
925
+ # seg_i_end}"
926
+ p_min_next_i = ngbs_arr[seg_i_0]
927
+ p_max_next_i = ngbs_arr[seg_i_end-1]
928
+ p_i_mid = Float(seg_i_0 + seg_i_end-1) / 2.0
929
+ i_mid = p_i_mid.round
930
+ if i_mid >= seg_i_end
931
+ i_mid = seg_i_end-1
932
+ elsif i_mid < seg_i_0
933
+ i_mid = seg_i_0
934
+ end
935
+ a = AaXy::SEMI_ADJ8[16 + i_mid % 16]
936
+ mid_pix = AaPix.new(pix.pixbuf, pix.ax+a.ax, pix.ay+a.ay)
937
+ # $PDbgLog.puts_msg "i_mid=#{i_mid},mid_pix#{mid_pix.coords_to_s}"
938
+ p_mid_next_prevs = []
939
+ pix_prevs.each { |px|
940
+ if mid_pix.a_eql?(px)
941
+ p_mid_next_prevs = px.prevs.to_a; break
942
+ elsif mid_pix.a_close_neighb?(px) &&
943
+ !pix.a_close_neighb?(px)
944
+ p_mid_next_prevs << px; next
945
+ end
946
+ #$PDbgLog.print_msg "px#{px.coords_to_s} "
947
+ px.prevs.each_with_index { |t_pix, t_i|
948
+ next unless t_pix.kind_of?(AaPixWithPrevs)
949
+ #$PDbgLog.print_msg "t_pix#{t_pix.coords_to_s} "
950
+ if mid_pix.a_neighb8?(t_pix) && !pix.
951
+ semi_close_neighb?(t_pix)
952
+ p_mid_next_prevs << t_pix
953
+ end
954
+ }
955
+ }
956
+ #$PDbgLog.puts_msg "p_mid_next_prevs: #{p_mid_next_prevs.
957
+ # join(' ')}"
958
+ if p_mid_next_prevs.empty?
959
+ if ngbs_arr[i_mid]
960
+ p_next_i = ngbs_arr[i_mid]
961
+ else
962
+ d = 1
963
+ loop do
964
+ if i_mid - d < seg_i_0
965
+ p_next_i = ngbs_arr[i_mid = seg[0]]; break
966
+ elsif i_mid+d >= seg_i_end
967
+ p_next_i = ngbs_arr[i_mid = seg[1]-1]; break
968
+ elsif i_mid - d >= seg_i_0 && ngbs_arr[i_mid-d]
969
+ p_next_i = ngbs_arr[i_mid = i_mid-d]; break
970
+ elsif ngbs_arr[i_mid+d]
971
+ p_next_i = ngbs_arr[i_mid = i_mid+d]; break
972
+ end
973
+ d += 1
974
+ end
975
+ end
976
+ p_next_i = 0 unless p_next_i
977
+ mid_pix = pix_prevs[p_next_i]
978
+ p_mid_next_prevs = pix_prevs[p_next_i].prevs.to_a
979
+ end
980
+ #$PDbgLog.sig_return
981
+ [self.pix_trace_min_seg(pix_prevs[p_min_next_i]),
982
+ self.pix_trace_mid_seg(mid_pix,p_mid_next_prevs,p_i_mid-i_mid),
983
+ self.pix_trace_max_seg(pix_prevs[p_max_next_i])]
984
+ end
985
+
986
+ def lp_add_pix(pix, old_pix, prev_lp_i)
987
+ #$PDbgLog.sig_call(self)
988
+ if pix != old_pix && @prev_layer_set.include?(pix)
989
+ new_pix = AaPixWithPrevs.new(pix.pixbuf,
990
+ (Float(pix.x)+old_pix.x)/2.0,
991
+ (Float(pix.y)+old_pix.y)/2.0)
992
+ else
993
+ new_pix = pix
994
+ end
995
+ #$PDbgLog.print_msg "pix#{pix.coords_to_s}, old_pix#{old_pix.
996
+ # coords_to_s}, prev_lp_i=#{prev_lp_i}, new_pix#{new_pix.
997
+ # coords_to_s}: " #+ "\n"
998
+ #$PDbgLog.puts_msg "@next_lp: #{PixbufPix.path_to_s(@next_lp)}"
999
+ if @next_lp[-1] && @next_lp[-1].a_eql?(new_pix)
1000
+ @layer_set[new_pix] = @next_lp.length-1
1001
+ if new_pix.a_eql?(old_pix)
1002
+ @next_lp[-1].prevs.merge(old_pix.prevs)
1003
+ else
1004
+ @next_lp[-1].prevs << old_pix
1005
+ end
1006
+ else
1007
+ if new_pix.a_eql?(old_pix)
1008
+ new_pix.prevs.merge(old_pix.prevs)
1009
+ else
1010
+ new_pix.prevs << old_pix
1011
+ end
1012
+ @layer_set[new_pix] = @next_lp.length
1013
+ @next_lp << new_pix
1014
+ end
1015
+ if @next_lp[-2] && !@next_lp[-2].neighb8?(@next_lp[-1])
1016
+ warn("#{self.class.name}.lp_add_pix: Uncontiguous loop: #{
1017
+ PixbufPix.path_to_s(@next_lp[-3,3])
1018
+ } from #{PixbufPix.path_to_s(@lp[prev_lp_i-3,6])}")
1019
+ end
1020
+ #$PDbgLog.sig_return
1021
+ new_pix
1022
+ end
1023
+
1024
+ def lp_optimize_out_4neighbs(lp)
1025
+ return lp if lp.length < 3
1026
+ #$PDbgLog.sig_call(self)
1027
+ #$PDbgLog.puts_msg "lp: #{Xy.path_to_s(lp)}"
1028
+ i = 0
1029
+ while i < lp.length
1030
+ p0 = lp.at(i-1)
1031
+ p1 = lp.at(i)
1032
+ p2 = lp.at((i+1) % lp.length)
1033
+ #$PDbgLog.print_msg "p0#{p0.coords_to_s}->p1#{
1034
+ # p1.coords_to_s}[#{i}],p2#{p2.coords_to_s}: "
1035
+ if p1.a_neighb4?(p0) && p1.a_neighb4?(p2) &&
1036
+ p0.a_neighb8?(p2) && !p0.a_close_neighb?(p2)
1037
+ #$PDbgLog.puts "delete #{i}"
1038
+ lp.delete_at(i)
1039
+ break if lp.length < 3
1040
+ else
1041
+ i += 1
1042
+ #$PDbgLog.puts "."
1043
+ end
1044
+ end
1045
+ #$PDbgLog.sig_return
1046
+ end
1047
+
1048
+ def next_layer!(i_p_map1=[[], []], i_p_map2=[[], []])
1049
+ #$PDbgLog.sig_call(self)
1050
+ #$PDbgLog.puts_msg "@lp (#{@lp.length}): #{Xy.path_to_s(@lp)}"
1051
+ #$PDbgLog.puts_msg "@lp (#{@lp.length}): #{@lp.inspect}"
1052
+ if @lp.length < 3
1053
+ #$PDbgLog.sig_return(false)
1054
+ return false
1055
+ end
1056
+ @next_lp.clear
1057
+ tmp = @layer_set
1058
+ @layer_set = @prev_layer_set
1059
+ @prev_layer_set = tmp
1060
+ @layer_set.clear
1061
+ mapped_a_pix = false
1062
+ p0 = @lp[-3]
1063
+ p1 = @lp[i1=-2]
1064
+ p2 = @lp[i2=-1]
1065
+ p3 = @lp[0]
1066
+ i3 = 0
1067
+ p1_map = self.pix_map8_4_into(p1, p0, p2, nil, i_p_map1)
1068
+ while i3 < @lp.length
1069
+ while (p2_map=self.pix_map8_4_into(p2,p1,p3, p1_map[-1],
1070
+ i_p_map2)).empty? && i3 + 1 < @lp.length
1071
+ #$PDbgLog.print_msg "Gobble p2: p0#{p0.coords_to_s
1072
+ # }, p1#{p1.coords_to_s}[#{i1}], p2#{p2.coords_to_s
1073
+ # }[#{i2}], p3#{p3.coords_to_s}[#{i3}]: "
1074
+ begin
1075
+ if i3 + 1 >= @lp.length
1076
+ break
1077
+ end
1078
+ if p1 == p2
1079
+ p1.prevs.merge(p2.prevs)
1080
+ else
1081
+ p1.prevs << p2
1082
+ end
1083
+ @lp.at(i3).prevs << p2
1084
+ i2 = i3; i3 += 1
1085
+ p2 = p3; p3 = @lp.at(i3)
1086
+ #$PDbgLog.print_msg "p2#{p2.coords_to_s}[#{i2
1087
+ # }], p3#{p3.coords_to_s}[#{i3}]; "
1088
+ end while p1==p2 || (p2_map=self.pix_map8_4_into(p2,
1089
+ p1, p3, p1_map[-1], i_p_map2)).empty?
1090
+ if p1 == p2
1091
+ p1_map.clear; break
1092
+ end
1093
+ p1_map << p1 if (p1_map = self.pix_map8_4_into(p1, p0,
1094
+ p2, @next_lp[-1], i_p_map1)).empty?
1095
+ mapped_a_pix = true
1096
+ end
1097
+ #$PDbgLog.puts_msg "p0#{p0.coords_to_s}->p1#{p1.
1098
+ # coords_to_s}[#{i1}]->p2#{p2.coords_to_s}[#{i2
1099
+ # }], p3#{p3.coords_to_s}[#{i3}]: #{Xy.path_to_s(
1100
+ # p1_map)}"
1101
+ p1_map.each { |pix| mapped_a_pix = true if
1102
+ !self.lp_add_pix(pix, p1, i1).a_eql?(p1)
1103
+ #$PDbgLog.print_msg @next_lp[-1].tree_to_pp_s
1104
+ }
1105
+ p1_map = p2_map
1106
+ tmp = i_p_map2; i_p_map2 = i_p_map1; i_p_map1 = tmp
1107
+ i1 = i2; i2 = i3; i3 += 1
1108
+ p0 = p1; p1 = p2; p2 = p3; p3 = @lp.at(i3)
1109
+ end
1110
+ if mapped_a_pix
1111
+ #$PDbgLog.puts_msg "@next_lp (#{@next_lp.length}): #{
1112
+ # Xy.path_to_s(@next_lp)}"
1113
+ while @next_lp.length > 1 &&
1114
+ @next_lp[-1].a_eql?(@next_lp[0])
1115
+ @next_lp[0].prevs.merge(@next_lp[-1].prevs)
1116
+ @next_lp.pop
1117
+ end
1118
+ tmp = @lp
1119
+ @lp = @next_lp
1120
+ @next_lp = tmp
1121
+ @prev_layer_set.each_key { |p_map|
1122
+ @excl_set[p_map.a_yx] = true unless
1123
+ @layer_set.include?(p_map) }
1124
+ #$PDbgLog.puts_msg "@layer_set: #{Xy.path_to_s(
1125
+ # @layer_set.keys.to_a.sort)}"
1126
+ #$PDbgLog.puts_msg "@excl_set (#{@excl_set.length}): #{
1127
+ # Xy.yx_path_to_s(@excl_set.keys.to_a.sort)}"
1128
+ #$PDbgLog.puts_msg "@lp (#{@lp.length}): #{Xy.path_to_s(
1129
+ # @lp)}"
1130
+ #$PDbgLog.sig_return(true)
1131
+ true
1132
+ else
1133
+ #$PDbgLog.puts_msg "@lp (#{@lp.length}): #{Xy.path_to_s(
1134
+ # @lp)}"
1135
+ # $PDbgLog.puts_msg @lp.collect {|pix| pix.tree_to_pp_s }.
1136
+ # join("\n")
1137
+ self.lp_optimize_out_4neighbs(@lp)
1138
+ #$PDbgLog.puts_msg "@excl_set (#{@excl_set.length}): #{
1139
+ # Xy.yx_path_to_s(@excl_set.keys.to_a.sort)}"
1140
+ #$PDbgLog.puts_msg "@lp (#{@lp.length}): #{Xy.path_to_s(
1141
+ # @lp)}"
1142
+ # $PDbgLog.puts_msg @lp.collect {|pix| pix.tree_to_pp_s }.
1143
+ # join("\n")
1144
+ #$PDbgLog.puts_msg @lp.collect {|pix| pix.inspect}.join(
1145
+ # "\n")
1146
+ #$PDbgLog.sig_return(false)
1147
+ false
1148
+ end
1149
+ end
1150
+
1151
+ def self.pix_in_curve_blob?(pix, blob_id)
1152
+ !pix.virtual? && (pix.a_yx != pix.yx || pix.pixbuf.blob_id_at?(
1153
+ pix.x, pix.y, blob_id))
1154
+ end
1155
+
1156
+ def self.pix_neighbs_add(pix_neighbs, pix, neighb, blob_id)
1157
+ #$PDbgLog.sig_call(self)
1158
+ #$PDbgLog.print_msg pix.coords_to_s + ": " + neighb.coords_to_s
1159
+ if pix_neighbs.include?(pix.a_yx)
1160
+ unless (dest=pix_neighbs[pix.a_yx]).
1161
+ detect { |m| m.a_eql?(neighb) }
1162
+ dest << neighb
1163
+ end
1164
+ else
1165
+ pix_neighbs[pix.a_yx] = [neighb]
1166
+ end
1167
+ # $PDbgLog.sig_return(' = ' + Xy.path_to_s(pix_neighbs[pix.a_yx]))
1168
+ end
1169
+
1170
+ def self.loop_calcs_mid_ln_segs!(calcs, pix_neighbs)
1171
+ $PDbgLog.sig_call(self)
1172
+ pixbuf = calcs[0].lp[0].pixbuf
1173
+ excl_set = calcs[0].excl_set
1174
+ calcs.each { |calc| calc.start_lp = calc.lp.dup
1175
+ calc.excl_set = excl_set }
1176
+ active_calcs = calcs.dup
1177
+ $PDbgLog.print_msg "Skeletonizing: "
1178
+ $PDbgLog.new_progr
1179
+ blob = calcs[0].blob
1180
+ $PDbgLog.progr.total_progr_units = blob.length
1181
+ if blob.external_contours
1182
+ calcs.each { |calc|
1183
+ $PDbgLog.progr.total_progr_units += calc.lp.length }
1184
+ end
1185
+ $PDbgLog.progr.show_as = "/ pixel#{$PDbgLog.progr.
1186
+ total_progr_units==1 ? "" : "s"}"
1187
+ i_p_map = [[], []]
1188
+ c_i = -1
1189
+ while !active_calcs.empty?
1190
+ c_i = 0
1191
+ while c_i < active_calcs.length
1192
+ if active_calcs[c_i].next_layer!(i_p_map)
1193
+ c_i += 1
1194
+ else
1195
+ active_calcs.delete_at(c_i)
1196
+ end
1197
+ $PDbgLog.progr.progr_units = excl_set.length
1198
+ end
1199
+ end
1200
+ $PDbgLog.puts_msg " done."
1201
+ core = Set.new
1202
+ core_debris = []
1203
+ prevs = {}
1204
+ blob_id = calcs[0].blob_id
1205
+ if pix_neighbs
1206
+ calcs.each { |calc| next if (lp = calc.lp).length < 2
1207
+ #$PDbgLog.puts_msg "lp: #{Xy.path_to_s(lp)}"
1208
+ if lp.length == 2
1209
+ p0, p1 = *lp
1210
+ self.pix_neighbs_add(pix_neighbs, p0.dup_aapix,
1211
+ p1.dup_aapix, blob_id)
1212
+ self.pix_neighbs_add(pix_neighbs, p1.dup_aapix,
1213
+ p0.dup_aapix, blob_id)
1214
+ next
1215
+ end
1216
+ p0 = lp[-2]; p1 = lp[-1]
1217
+ lp.each { |p2|
1218
+ self.pix_neighbs_add(pix_neighbs, p1.dup_aapix,
1219
+ p0.dup_aapix, blob_id)
1220
+ self.pix_neighbs_add(pix_neighbs, p1.dup_aapix,
1221
+ p2.dup_aapix, blob_id)
1222
+ p0 = p1; p1 = p2
1223
+ }
1224
+ }
1225
+ end
1226
+ calcs.each { |calc| calc.lp.each_with_index { |pix, pix_i|
1227
+ core << AaPix.new(pix.pixbuf, pix.ax, pix.ay) if
1228
+ self.pix_in_curve_blob?(pix, blob_id)
1229
+ if prevs.include?(pix.a_yx)
1230
+ known_calc = false
1231
+ prevs[pix.a_yx].each { |prc|
1232
+ next unless prc[1].equal?(calc)
1233
+ p_prevs = prc[0]
1234
+ p_prevs.merge(pix.prevs)
1235
+ known_calc = true
1236
+ break
1237
+ }
1238
+ prevs[pix.a_yx] << [pix.prevs.dup, calc] unless
1239
+ known_calc
1240
+ else
1241
+ prevs[pix.a_yx] = [[pix.prevs.dup, calc]]
1242
+ end
1243
+ }}
1244
+ #$PDbgLog.puts_msg "Core: #{Xy.path_to_s(core.to_a.sort)}"
1245
+ neg_segs = {}
1246
+ core.each { |pix|
1247
+ ngb = ngb_p = nil
1248
+ p_end_pt = true
1249
+ pix.semi_adj8_incl_set_each(core) { |t_ngb, s_adj8_i|
1250
+ if ngb
1251
+ p_end_pt = false; break
1252
+ else
1253
+ ngb = t_ngb; ngb_p = s_adj8_i
1254
+ end
1255
+ }
1256
+ if p_end_pt
1257
+ warn("#{self.class.name}.loop_calcs_mid_ln_segs!: End " +
1258
+ "point#{pix.coords_to_s} resulting from many loops!") if
1259
+ prevs[pix.a_yx].length > 1
1260
+ p_prevs, p_calc = *(prevs[pix.a_yx][0])
1261
+ $PDbgLog.puts_msg "End point #{pix.coords_to_s}: from #{
1262
+ Xy.path_to_s(p_prevs)}"
1263
+ ngbs_arr = pix.semi_neighbs8_contig_arr(p_prevs)
1264
+ if !(p_segs=AaXy.semi_neighbs8_contig_arr_get_segs(
1265
+ ngbs_arr)).empty? && (p_segs != [[0, 16]] || ngb )
1266
+ if p_segs == [[0, 16]]
1267
+ # $PDbgLog.puts_msg "ngb#{ngb.coords_to_s} ngb_p=#{ngb_p}"
1268
+ p_segs = [[ngb_p-15, ngb_p]]
1269
+ end
1270
+ p_segs.each { |seg|
1271
+ p_ends = p_calc.pix_trace_seg(pix,p_prevs.to_a,ngbs_arr,
1272
+ seg.first, seg.last)
1273
+ s_mid, mid_pix = *p_ends[1]
1274
+ neg_segs[p_calc.start_lp] = [] unless neg_segs.include?(
1275
+ p_calc.start_lp)
1276
+ s_0 = p_ends[0]
1277
+ s_0 -= p_calc.start_lp.length if s_0 > s_mid
1278
+ s_end = p_ends[2]
1279
+ s_end += p_calc.start_lp.length if s_end < s_mid
1280
+ neg_segs[p_calc.start_lp] << [(s_0+s_mid)/2,
1281
+ (s_end+s_mid)/2]
1282
+ i = 0
1283
+ while i < mid_pix.length
1284
+ break unless self.pix_in_curve_blob?(
1285
+ mid_pix.at(i), blob_id)
1286
+ i += 1
1287
+ end
1288
+ mid_pix[i, mid_pix.length-i] = nil
1289
+ core_debris.concat(mid_pix)
1290
+ # $PDbgLog.puts_msg "mid_pix left: "+Xy.path_to_s(mid_pix)
1291
+ if pix_neighbs && !mid_pix.empty?
1292
+ self.pix_neighbs_add(pix_neighbs,pix,mid_pix[0],
1293
+ blob_id)
1294
+ self.pix_neighbs_add(pix_neighbs,mid_pix[0],pix,
1295
+ blob_id)
1296
+ if mid_pix.length > 1
1297
+ self.pix_neighbs_add(pix_neighbs,mid_pix[-2],
1298
+ mid_pix[-1], blob_id)
1299
+ self.pix_neighbs_add(pix_neighbs,mid_pix[-1],
1300
+ mid_pix[-2], blob_id)
1301
+ p0 = pix; p1 = mid_pix[0]
1302
+ for i in 1...mid_pix.length
1303
+ p2 = mid_pix[i]
1304
+ self.pix_neighbs_add(pix_neighbs,p1,p0,blob_id)
1305
+ self.pix_neighbs_add(pix_neighbs,p1,p2,blob_id)
1306
+ p0 = p1; p1 = p2
1307
+ end
1308
+ end
1309
+ end
1310
+ }
1311
+ end
1312
+ end
1313
+ }
1314
+ core_debris.each { |pix| core << pix }
1315
+ segs = []
1316
+ neg_segs.each_pair { |lp, n_segs|
1317
+ n_segs.sort! { |a,b| (a[0] % lp.length) <=>
1318
+ (b[0] % lp.length) }
1319
+ for seg_i in 0...n_segs.length
1320
+ i_0 = n_segs[seg_i-1][1]
1321
+ i_end = n_segs[seg_i][0]
1322
+ i_0 -= lp.length while i_0 > i_end
1323
+ #$PDbgLog.print_msg "seg[#{i_0}; #{i_end}] "
1324
+ segs << ImageObject.new(lp, i_0, i_end)
1325
+ end
1326
+ }
1327
+ #$PDbgLog.puts_msg "pix_neighbs: {#{pix_neighbs.keys.to_a.sort.
1328
+ # collect{|k| "(#{k[1]}, #{k[0]}): [" + PixbufPix.path_to_s(
1329
+ # pix_neighbs[k].to_a)}.join("]; ")}}" if pix_neighbs # "
1330
+ $PDbgLog.sig_return
1331
+ [core, segs]
1332
+ end
1333
+ end
1334
+
1335
+ class ContourLoop
1336
+ attr_accessor :blob_lp_calc
1337
+
1338
+ self.img_obj_add_sub_obj :next_layer
1339
+
1340
+ def next_layer
1341
+ return nil unless self.blob
1342
+ self.blob_lp_calc = BlobLoopCalc.new(self.blob, self.dup) unless
1343
+ self.blob_lp_calc
1344
+ self.blob_lp_calc.next_layer!
1345
+ ctr_lp = self.blob_lp_calc.lp.dup
1346
+ ctr_lp.blob = self.blob
1347
+ ctr_lp.blob_lp_calc = self.blob_lp_calc
1348
+ ctr_lp
1349
+ end
1350
+ end
1351
+
1352
+ class ContourLoopCarpet
1353
+ self.img_obj_add_sub_obj :next_layer
1354
+ end
1355
+
1356
+ class Curve < ImageObject
1357
+ attr_reader :curve_carpet, :segments, :set, :min_lp_grps,
1358
+ :min_lp_grp_terminals, :pix_neighbs_proc
1359
+
1360
+ self.img_obj_add_sub_obj :segments
1361
+
1362
+ def initialize(curve_carp, segments, pix_neighbs=nil)
1363
+ @curve_carpet = curve_carp
1364
+ @segments = segments
1365
+ if pix_neighbs
1366
+ @pix_neighbs_proc = proc { |pix| pix_neighbs[pix.a_yx] }
1367
+ else
1368
+ @pix_neighbs_proc = proc { |pix| ngbs = []
1369
+ #$PDbgLog.sig_call(self)
1370
+ #$PDbgLog.print_msg "ngbs:"+pix.coords_to_s + ": "
1371
+ pix.adj8_semi_adj8_each { |ngb|
1372
+ #$PDbgLog.print_msg "ngb#{ngb.coords_to_s} "
1373
+ if self.set.include?(ngb)
1374
+ ngbs << ngb; true; else false; end }
1375
+ #$PDbgLog.sig_return(PixbufPix.path_to_s(ngbs))
1376
+ ngbs
1377
+ }
1378
+ end
1379
+ @set = SortedArrSet.new(self) { |a,b| a.a_yx <=> b.a_yx }
1380
+ @min_lp_grps = []
1381
+ @min_lp_grp_terminals = []
1382
+ @pix_mapping2end_pt = {}
1383
+ @pix_mapping2body_pt = {}
1384
+ @pix_nodes = {}
1385
+ super()
1386
+ end
1387
+
1388
+ def pixbuf
1389
+ @curve_carpet.blob.pixbuf
1390
+ end
1391
+ end
1392
+
1393
+ class CurveCarpet < ImageObject
1394
+ attr_reader :blob, :curves, :multiple_curves, :pix_neighbs_from_curve
1395
+
1396
+ self.img_obj_add_sub_obj :curves
1397
+
1398
+ def initialize(blob, multiple_curves=false, pix_neighbs_from_curve=true)
1399
+ $PDbgLog.sig_call(self)
1400
+ @blob = blob
1401
+ @multiple_curves = multiple_curves
1402
+ @pix_neighbs_from_curve = pix_neighbs_from_curve
1403
+ @curves = []
1404
+ super()
1405
+ self.rebuild
1406
+ $PDbgLog.sig_return
1407
+ end
1408
+
1409
+ def rebuild
1410
+ $PDbgLog.sig_call(self)
1411
+ loop_calcs = []
1412
+ pix_neighbs = @pix_neighbs_from_curve ? Hash.new([]) : nil
1413
+ @curves.clear
1414
+ if @multiple_curves
1415
+ @blob.contour_carpets.each { |ctr| ctr.loops.each { |lp|
1416
+ loop_calcs << BlobLoopCalc.new(@blob,lp[0,lp.length]) }}
1417
+ core, segs = *BlobLoopCalc.loop_calcs_mid_ln_segs!(loop_calcs,
1418
+ pix_neighbs)
1419
+ visited = Set.new
1420
+ tail = []
1421
+ while !core.empty?
1422
+ pix = nil; core.each { |pix| break }
1423
+ @curves << (curve=Curve.new(self,c_segs=[],pix_neighbs))
1424
+ curve << pix
1425
+ c_set = curve.img_obj_ayx_set
1426
+ tail << pix
1427
+ while !tail.empty?
1428
+ pix = tail.pop
1429
+ ngbs = pix.adj8.find_all{|px| core.include?(px)}
1430
+ for ngb in ngbs
1431
+ unless c_set.include?(ngb.a_yx)
1432
+ tail << ngb
1433
+ curve << ngb
1434
+ c_set << ngb.a_yx
1435
+ end
1436
+ end
1437
+ end
1438
+ curve.sort! { |a,b| a.a_leg(b) }
1439
+ curve.each { |pix| core.delete(pix) }
1440
+ i = 0
1441
+ while i < segs.length
1442
+ seg = segs.at(i)
1443
+ if c_set.include?(seg.first.a_yx)
1444
+ warn(self.class.name + ".rebuild: " +
1445
+ "Segment goes across curves!") unless
1446
+ c_set.include?(seg.last.a_yx)
1447
+ c_segs << seg
1448
+ segs.delete_at(i)
1449
+ else
1450
+ i += 1
1451
+ end
1452
+ end
1453
+ end
1454
+ warn(self.class.name + ".rebuild: Unclaimed segments (#{segs.
1455
+ length})!") unless segs.empty?
1456
+ else
1457
+ @blob.contour_carpets.each { |ctr| lp = ctr.loop_carpet
1458
+ loop_calcs << BlobLoopCalc.new(@blob, lp[0,lp.length]) }
1459
+ core, segs = *BlobLoopCalc.loop_calcs_mid_ln_segs!(loop_calcs,
1460
+ pix_neighbs)
1461
+ @curves << (curve = Curve.new(self, segs, pix_neighbs))
1462
+ core.each { |pix| curve << pix }
1463
+ curve.sort! { |a,b| a.a_leg(b) }
1464
+ end
1465
+ self.clear
1466
+ core.each { |pix| self << pix }
1467
+ $PDbgLog.sig_return("#{@curves.length} curve#{@curves.length ==
1468
+ 1 ? "" : "s" }")
1469
+ end
1470
+ end
1471
+
1472
+ class Curve
1473
+ def pix_maps_to_end_pt?(pix)
1474
+ @pix_mapping2end_pt[pix.a_yx]
1475
+ end
1476
+
1477
+ def pix_maps_to_end_pt(pix, val)
1478
+ @pix_mapping2end_pt[pix.a_yx] = val
1479
+ end
1480
+
1481
+ def pix_maps_to_body_pt?(pix)
1482
+ @pix_mapping2body_pt[pix.a_yx]
1483
+ end
1484
+
1485
+ def pix_maps_to_body_pt(pix, val)
1486
+ @pix_mapping2body_pt[pix.a_yx] = val
1487
+ end
1488
+
1489
+ def pix_end_pt?(pix, incl_set)
1490
+ pix.adj8.find_all { |px| incl_set.include?(px.yx) }.length < 2
1491
+ end
1492
+
1493
+ def pix_node(pix)
1494
+ tmp = @pix_nodes[pix.a_yx]
1495
+ return tmp if tmp
1496
+ pix_conns = pix.connections(&@pix_neighbs_proc)
1497
+ node = @pix_nodes[pix.a_yx] = AaXyNode.new(pix.ax, pix.ay,
1498
+ conns = [])
1499
+ pix_conns.each { |pixs|
1500
+ cn = NodeConn.new(self.pix_node(pixs.last), pixs.length)
1501
+ cn.path = XyPath.new([pix] + pixs)
1502
+ conns << cn
1503
+ }
1504
+ node
1505
+ end
1506
+ end
1507
+
1508
+ end