extract_curves 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) 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/cstr.c +82 -0
  18. data/ruby_ext/pav/cstr.h +17 -0
  19. data/ruby_ext/pav/extconf.rb +22 -0
  20. data/ruby_ext/pav/pav.c +162 -0
  21. data/ruby_ext/pav/pgtk.c +40 -0
  22. data/ruby_ext/pav/pgtk.h +14 -0
  23. data/ruby_ext/pav/pix.c +806 -0
  24. data/ruby_ext/pav/pix.h +236 -0
  25. data/ruby_ext/pav/t.rb +35 -0
  26. data/ruby_ext/pav/t1.rb +35 -0
  27. data/ruby_libs/CVS/Entries +1 -0
  28. data/ruby_libs/CVS/Repository +1 -0
  29. data/ruby_libs/CVS/Root +1 -0
  30. data/ruby_libs/pav/CVS/Entries +20 -0
  31. data/ruby_libs/pav/CVS/Repository +1 -0
  32. data/ruby_libs/pav/CVS/Root +1 -0
  33. data/ruby_libs/pav/attr_cache.rb +211 -0
  34. data/ruby_libs/pav/attr_cache.t1.rb +32 -0
  35. data/ruby_libs/pav/cache.rb +31 -0
  36. data/ruby_libs/pav/dbg_log.rb +458 -0
  37. data/ruby_libs/pav/floatsio.rb +53 -0
  38. data/ruby_libs/pav/generator_cache.rb +165 -0
  39. data/ruby_libs/pav/gtk/CVS/Entries +4 -0
  40. data/ruby_libs/pav/gtk/CVS/Repository +1 -0
  41. data/ruby_libs/pav/gtk/CVS/Root +1 -0
  42. data/ruby_libs/pav/gtk/button.rb +130 -0
  43. data/ruby_libs/pav/gtk/icons.rb +87 -0
  44. data/ruby_libs/pav/gtk/toolbar.rb +192 -0
  45. data/ruby_libs/pav/heap.rb +54 -0
  46. data/ruby_libs/pav/icons/CVS/Entries +17 -0
  47. data/ruby_libs/pav/icons/CVS/Repository +1 -0
  48. data/ruby_libs/pav/icons/CVS/Root +1 -0
  49. data/ruby_libs/pav/icons/alt_handle.xcf +0 -0
  50. data/ruby_libs/pav/icons/alt_handle.xpm +3832 -0
  51. data/ruby_libs/pav/icons/alt_handle_hover.xcf +0 -0
  52. data/ruby_libs/pav/icons/alt_handle_hover.xpm +3368 -0
  53. data/ruby_libs/pav/icons/alt_handle_pressed.xcf +0 -0
  54. data/ruby_libs/pav/icons/alt_handle_pressed.xpm +3828 -0
  55. data/ruby_libs/pav/icons/extract_curves/CVS/Entries +6 -0
  56. data/ruby_libs/pav/icons/extract_curves/CVS/Repository +1 -0
  57. data/ruby_libs/pav/icons/extract_curves/CVS/Root +1 -0
  58. data/ruby_libs/pav/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
  59. data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
  60. data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.xcf +0 -0
  61. data/ruby_libs/pav/icons/extract_curves/trace_mark.xcf +0 -0
  62. data/ruby_libs/pav/icons/extract_curves/trace_mark.xpm +38 -0
  63. data/ruby_libs/pav/icons/handle.xcf +0 -0
  64. data/ruby_libs/pav/icons/handle.xpm +213 -0
  65. data/ruby_libs/pav/icons/next.xpm +29 -0
  66. data/ruby_libs/pav/icons/next_hover.xpm +315 -0
  67. data/ruby_libs/pav/icons/next_pressed.xpm +144 -0
  68. data/ruby_libs/pav/icons/prev.xpm +29 -0
  69. data/ruby_libs/pav/icons/prev_hover.xpm +315 -0
  70. data/ruby_libs/pav/icons/prev_pressed.xpm +144 -0
  71. data/ruby_libs/pav/icons/vnext.xpm +29 -0
  72. data/ruby_libs/pav/icons/vprev.xpm +29 -0
  73. data/ruby_libs/pav/numeric/CVS/Entries +2 -0
  74. data/ruby_libs/pav/numeric/CVS/Repository +1 -0
  75. data/ruby_libs/pav/numeric/CVS/Root +1 -0
  76. data/ruby_libs/pav/numeric/ext.rb +13 -0
  77. data/ruby_libs/pav/pav_find.rb +90 -0
  78. data/ruby_libs/pav/pix.rb +402 -0
  79. data/ruby_libs/pav/pix/CVS/Entries +11 -0
  80. data/ruby_libs/pav/pix/CVS/Repository +1 -0
  81. data/ruby_libs/pav/pix/CVS/Root +1 -0
  82. data/ruby_libs/pav/pix/aapix.rb +378 -0
  83. data/ruby_libs/pav/pix/blob.rb +543 -0
  84. data/ruby_libs/pav/pix/circle.rb +73 -0
  85. data/ruby_libs/pav/pix/contour.rb +644 -0
  86. data/ruby_libs/pav/pix/contour/CVS/Entries +5 -0
  87. data/ruby_libs/pav/pix/contour/CVS/Repository +1 -0
  88. data/ruby_libs/pav/pix/contour/CVS/Root +1 -0
  89. data/ruby_libs/pav/pix/contour/calc_situations.rb +9 -0
  90. data/ruby_libs/pav/pix/contour/carp_calc.rb +212 -0
  91. data/ruby_libs/pav/pix/contour/situations.dmp +0 -0
  92. data/ruby_libs/pav/pix/contour/situations.rb +21 -0
  93. data/ruby_libs/pav/pix/curve.rb +1508 -0
  94. data/ruby_libs/pav/pix/img_obj.rb +751 -0
  95. data/ruby_libs/pav/pix/node.rb +712 -0
  96. data/ruby_libs/pav/pix/node_grp.rb +853 -0
  97. data/ruby_libs/pav/pix/shaved_core.rb +534 -0
  98. data/ruby_libs/pav/pix/subpix.rb +212 -0
  99. data/ruby_libs/pav/rand_accessible.rb +16 -0
  100. data/ruby_libs/pav/rangeset.rb +63 -0
  101. data/ruby_libs/pav/search.rb +210 -0
  102. data/ruby_libs/pav/set.rb +20 -0
  103. data/ruby_libs/pav/string/CVS/Entries +6 -0
  104. data/ruby_libs/pav/string/CVS/Repository +1 -0
  105. data/ruby_libs/pav/string/CVS/Root +1 -0
  106. data/ruby_libs/pav/string/bits.rb +523 -0
  107. data/ruby_libs/pav/string/ext.rb +58 -0
  108. data/ruby_libs/pav/string/observable.rb +155 -0
  109. data/ruby_libs/pav/string/text.rb +79 -0
  110. data/ruby_libs/pav/string/words.rb +42 -0
  111. data/ruby_libs/pav/sub_arr.rb +55 -0
  112. data/ruby_libs/pav/traced_obj.rb +79 -0
  113. metadata +161 -0
@@ -0,0 +1,73 @@
1
+ module PPix
2
+
3
+ def self.AFilledCircle(x0, y0, r)
4
+ r2 = r*r
5
+ yield(x0, y0)
6
+ 1.upto(r) { |dx|
7
+ yield(x0 + dx, y0)
8
+ yield(x0 - dx, y0)
9
+ }
10
+ 1.upto(r) { |dy|
11
+ dy2 = dy*dy
12
+ yield(x0, y0+dy)
13
+ yield(x0, y0-dy)
14
+ dx = 1
15
+ while dx*dx + dy2 <= r2
16
+ yield(x0 + dx, y0+dy)
17
+ yield(x0 - dx, y0+dy)
18
+ yield(x0 + dx, y0-dy)
19
+ yield(x0 - dx, y0-dy)
20
+ dx += 1
21
+ end
22
+ }
23
+ end
24
+
25
+ =begin
26
+ def AaFilledCircle(x0, y0, r)
27
+ r2 = r*r
28
+ if r2 > 0.5
29
+ yield(x0, y0, 1.0)
30
+ else
31
+ if r <= 0.5
32
+ yield(x0, y0, Math::PI*r2)
33
+ else
34
+ phi = Math.acos(1.0 / r)
35
+ yield(x0, y0, (Math::PI-4.0*phi)*r2 + 4.0*Math.sqrt(r2-1.0))
36
+ end
37
+ return
38
+ end
39
+ dy = r.round
40
+ if r2 < (dy - 0.5)*(dy - 0.5) + 0.25
41
+ phi = Math.acos((dy-0.5) / r)
42
+ yield(x0, y+dy, f=phi*r2 - (dy-0.5)*r*Math.sin(phi))
43
+ yield(x0, y-dy, f)
44
+ dy -= 1
45
+ phi_0 = Math.atan2(dy-0.5, 0.5)
46
+ yield(x0, y+dy, f=r*(r*Math::PI/2.0 -
47
+ (dy-0.5)*2.0*Math.cos(phi_0)) - f)
48
+ yield(x0, y-dy, f)
49
+ dy -= 1
50
+ elsif r2 < (dy+0.5)*(dy+0.5) + 0.25
51
+ phi_0 = Math.atan2(dy-0.5, 0.5)
52
+ yield(x0, y+dy, f=r*(r*Math::PI/2.0 -
53
+ (dy-0.5)*2.0*Math.cos(phi_0)))
54
+ yield(x0, y-dy, f)
55
+ dy -= 1
56
+ end
57
+ 1.upto(r) { |dy|
58
+ dy2 = dy*dy
59
+ yield(x0, y0+dy)
60
+ yield(x0, y0-dy)
61
+ dx = 1
62
+ while dx*dx + dy2 < r2
63
+ yield(x0 + dx, y+dy)
64
+ yield(x0 - dx, y+dy)
65
+ yield(x0 + dx, y-dy)
66
+ yield(x0 - dx, y-dy)
67
+ dx += 1
68
+ end
69
+ }
70
+ end
71
+ =end
72
+
73
+ end
@@ -0,0 +1,644 @@
1
+ require 'set'
2
+ require 'pav/pix'
3
+ require 'pav/cache'
4
+ require 'pav/dbg_log'
5
+ require 'pav/pix/blob'
6
+ require 'pav/attr_cache'
7
+ require 'pav/pix/subpix'
8
+ require 'pav/pix/img_obj'
9
+ require 'pav/pix/contour/situations'
10
+
11
+ module PPix
12
+
13
+ class ContourLoop < ImageObject
14
+ attr_accessor :external, :contour_carpet, :vparities, :blob
15
+
16
+ self.img_obj_add_sub_obj :internal_blob
17
+
18
+ def initialize(contour_carpet=nil, external=nil)
19
+ @contour_carpet = contour_carpet
20
+ if external.nil?
21
+ @external = @contour_carpet.external if @contour_carpet
22
+ else
23
+ @external = external
24
+ end
25
+ @vparities = {}
26
+ super()
27
+ end
28
+
29
+ def merge_debris!(debris)
30
+ #$PDbgLog.sig_call(self)
31
+ debris.each { |pix|
32
+ ngbs = @contour_carpet.pix_neighbs(pix)
33
+ ngbs.each { |ngb|
34
+ if self.img_obj_yx_set.include?(ngb.yx)
35
+ j = self.index(ngb)
36
+ if ngbs.include?(self[i=j-1]) ||
37
+ ngbs.include?(self[((i=j)+1) % self.length])
38
+ #$PDbgLog.print_msg pix.coords_to_s+" @ #{i+1} "
39
+ #$PDbgLog.puts_msg PixbufPix.path_to_s(self)
40
+ self[i+1,0] = [pix]
41
+ self.img_obj_yx_set << pix.yx
42
+ #$PDbgLog.puts_msg PixbufPix.path_to_s(self)
43
+ break
44
+ end
45
+ end
46
+ }
47
+ }
48
+ #$PDbgLog.sig_return
49
+ end
50
+
51
+ def add(subpix)
52
+ if subpix.vertical?
53
+ if @vparities.include?(subpix.img_pix.yx)
54
+ @vparities.delete(subpix.img_pix.yx)
55
+ else
56
+ @vparities[subpix.img_pix.yx] = true
57
+ end
58
+ end
59
+ self << subpix.img_pix unless self[-1].yx==subpix.img_pix.yx
60
+ end
61
+
62
+ def add_pix(pix, horiz_cnt, vert_cnt)
63
+ if vert_cnt & 1 == 1
64
+ if @vparities.include?(pix.yx)
65
+ @vparities.delete(pix.yx)
66
+ else
67
+ @vparities[pix.yx] = true
68
+ end
69
+ end
70
+ self << pix
71
+ end
72
+
73
+ def internal_blob_each
74
+ return if self.empty?
75
+ #$PDbgLog.sig_call(self)
76
+ pix_scan = self.sort; pix_scan.uniq!
77
+ pixbuf = self.first.pixbuf
78
+ yield(pix_scan[0])
79
+ x0 = x = pix_scan[0].x
80
+ prev_y = y = pix_scan[0].y
81
+ parity = @vparities.include?(pix_scan[0].yx)
82
+ #$PDbgLog.puts_msg "pix_scan: #{PixbufPix.path_to_s(pix_scan)}"
83
+ #$PDbgLog.puts_msg "@vparities: " + PixbufPix.yx_path_to_s(
84
+ # @vparities.keys.to_a.sort)
85
+ if (i = 1) >= pix_scan.length
86
+ #$PDbgLog.sig_return
87
+ return
88
+ end
89
+ loop do
90
+ #$PDbgLog.print_msg "i=#{i}, x0=#{x0}, x=#{x}, y=#{y}: "
91
+ while pix_scan[i].y == y && pix_scan[i].x == x+1
92
+ #$PDbgLog.print_msg "."
93
+ x = pix_scan[i].x
94
+ parity ^= @vparities.include?(pix_scan[i].yx)
95
+ yield(pix_scan[i])
96
+ if (i += 1) >= pix_scan.length
97
+ #$PDbgLog.sig_return
98
+ return
99
+ end
100
+ end
101
+ #$PDbgLog.print_msg "; "
102
+ if pix_scan[i].y==y && parity
103
+ #$PDbgLog.print_msg "#{x}.upto(#{pix_scan[i].x
104
+ # }); "
105
+ (x+1).upto(pix_scan[i].x-1) { |tmp_x|
106
+ yield(pixbuf.get_pix(tmp_x, y)) }
107
+ end
108
+ x0 = x = pix_scan[i].x
109
+ y = pix_scan[i].y
110
+ parity ^= @vparities.include?(pix_scan[i].yx)
111
+ yield(pix_scan[i])
112
+ if (i += 1) >= pix_scan.length
113
+ #$PDbgLog.sig_return
114
+ return
115
+ end
116
+ end
117
+ #$PDbgLog.sig_return("Insanity!")
118
+ end
119
+
120
+ def internal_blob
121
+ $PDbgLog.sig_call(self)
122
+ res = ImageObject.new
123
+ self.internal_blob_each { |pix| res << pix }
124
+ $PDbgLog.sig_return
125
+ res.img_obj_freeze
126
+ res
127
+ end
128
+
129
+ def dup
130
+ res = self.class.new(contour_carpet, external)
131
+ res.replace(self)
132
+ res
133
+ end
134
+
135
+ cache_attr! :internal_blob
136
+ end
137
+
138
+ class ContourLoopCarpet < ContourLoop
139
+ self.img_obj_add_sub_obj()
140
+
141
+ def merge_new_loop!(lp)
142
+ if self.empty?
143
+ lp.each { |pix| self.img_obj_yx_set.add(pix.yx) }
144
+ self.replace(lp)
145
+ self.vparities.replace(lp.vparities)
146
+ return true
147
+ end
148
+ common_pix = common_pix_i = nil
149
+ lp.each_with_index { |pix, common_pix_i|
150
+ if self.img_obj_yx_set.include?(pix.yx)
151
+ common_pix = pix
152
+ break
153
+ end
154
+ }
155
+ if common_pix
156
+ lp.each { |pix| self.img_obj_yx_set.add(pix.yx) }
157
+ self[self.index(common_pix)+1,0] = lp[common_pix_i+
158
+ 1...lp.length] + lp[0..common_pix_i]
159
+ lp.vparities.each_key { |k|
160
+ if self.vparities.include?(k)
161
+ self.vparities.delete(k)
162
+ else self.vparities[k] = true; end }
163
+ return true
164
+ end
165
+ ngb = pix_i = nil
166
+ lp.each_with_index { |pix, pix_i|
167
+ self.contour_carpet.pix_neighbs(pix).each { |pngb|
168
+ if self.img_obj_yx_set.include?(pngb.yx)
169
+ ngb = pngb
170
+ break
171
+ end
172
+ }
173
+ break if ngb
174
+ }
175
+ return false unless ngb
176
+ lp.each { |pix| self.img_obj_yx_set.add(pix.yx) }
177
+ self[self.index(ngb)+1,0] = lp[pix_i...lp.length] +
178
+ lp[0..pix_i] + [ngb]
179
+ lp.vparities.each_key { |k|
180
+ if self.vparities.include?(k)
181
+ self.vparities.delete(k)
182
+ else self.vparities[k] = true; end }
183
+ end
184
+ end
185
+
186
+ class PixbufPix
187
+ attr_accessor :border_dirs8_id, :subpix_path_dir
188
+ end
189
+
190
+ class ContourCarpetCalc
191
+ attr_reader :contour_carpet, :geometry, :external, :block, :cpix,
192
+ :start_pix
193
+
194
+ def initialize(contour_carpet, geometry=8, external=nil, &block)
195
+ @contour_carpet = contour_carpet
196
+ @geometry = geometry
197
+ if external.nil?
198
+ @external = contour_carpet.external
199
+ else @external = external; end
200
+ if block_given?
201
+ @block = block
202
+ else
203
+ @block = nil
204
+ end
205
+ @start_pix = @contour_carpet.start_pix
206
+ @visited = {}
207
+ @pix_calcs = {}
208
+ end
209
+
210
+ def each_cpix(&block)
211
+ block = @block unless block_given?
212
+ block.call(@contour_carpet.start_pix)
213
+ @visited = { @contour_carpet.start_pix.yx => true }
214
+ @cpix = @contour_carpet.start_pix
215
+ tail = [@cpix]
216
+ while !tail.empty?
217
+ @contour_carpet.pix_neighbs(tail.pop).each { |cpix|
218
+ next if @visited.include?(cpix.yx)
219
+ block.call(cpix)
220
+ @visited[cpix.yx] = true
221
+ tail.push(cpix)
222
+ }
223
+ end
224
+ end
225
+
226
+ def loop_indexes(pix)
227
+ res = []
228
+ @loop.each_with_index { |p, i|
229
+ res << i if p.y == pix.y && p.x == pix.x }
230
+ res
231
+ end
232
+
233
+ def get_calc
234
+ @pix_calcs[@cpix.yx] = ImageObjectPixCalc.new(@cpix) unless
235
+ @pix_calcs.include?(@cpix.yx)
236
+ @pix_calcs[@cpix.yx]
237
+ end
238
+
239
+ def next_loop(start_subpix, id2lm, external)
240
+ #$PDbgLog.sig_call(self)
241
+ i_res = []
242
+ pix = start_subpix.img_pix
243
+ lm = id2lm.at(ContourCarpetCalc.subpix_situ8_pack(
244
+ @contour_carpet.pix_situ8_arr_into(pix, i_res))).at(
245
+ start_subpix.sub_n)
246
+ pix.border_dirs8_id = lm.border_dirs8_id
247
+ lp = ContourLoop.new(@contour_carpet, external)
248
+ lp.add_pix(pix, lm.path_horiz_cnt, lm.path_vert_cnt)
249
+ #$PDbgLog.puts_msg "start_subpix#{start_subpix}, external=#{
250
+ # external}, lm=#{lm.inspect}"
251
+ if external
252
+ next_lm = lm.entry
253
+ pix.subpix_path_dir = -1
254
+ else
255
+ next_lm = lm.exit
256
+ pix.subpix_path_dir = +1
257
+ end
258
+ if @visited.include?([pix.y, pix.x, lm.border_dirs8_id]) ||
259
+ !next_lm
260
+ #$PDbgLog.sig_return('debris.')
261
+ return lp
262
+ end
263
+ @visited[[pix.y,pix.x,lm.border_dirs8_id]] = true
264
+ pixbuf = pix.pixbuf
265
+ pix = pixbuf.get_pix(pix.x + next_lm.x, pix.y + next_lm.y)
266
+ lm = id2lm.at(ContourCarpetCalc.subpix_situ8_pack(
267
+ @contour_carpet.pix_situ8_arr_into(pix, i_res))).
268
+ at(next_lm.sub_n)
269
+ pix.border_dirs8_id = lm.border_dirs8_id
270
+ #$PDbgLog.new_progr
271
+ #$PDbgLog.progr.show_as = "/ visited"
272
+ while !@visited.include?([pix.y, pix.x, lm.border_dirs8_id])
273
+ #$PDbgLog.puts_msg "#{pix.coords_to_s}" +
274
+ # ",lm=#{lm} "
275
+ # ",dirs_id=#{"%b" % lm.border_dirs8_id}"
276
+ lp.add_pix(pix, lm.path_horiz_cnt, lm.path_vert_cnt)
277
+ @visited[[pix.y,pix.x,lm.border_dirs8_id]] = true
278
+ p_entry = pixbuf.get_pix(pix.x + lm.entry.x,
279
+ pix.y + lm.entry.y)
280
+ lm_entry = id2lm.at(ContourCarpetCalc.subpix_situ8_pack(
281
+ @contour_carpet.pix_situ8_arr_into(p_entry, i_res))).
282
+ at(lm.entry.sub_n)
283
+ p_exit = pixbuf.get_pix(pix.x + lm.exit.x,
284
+ pix.y + lm.exit.y)
285
+ lm_exit = id2lm.at(ContourCarpetCalc.subpix_situ8_pack(
286
+ @contour_carpet.pix_situ8_arr_into(p_exit, i_res))).
287
+ at(lm.exit.sub_n)
288
+ if @visited.include?([p_entry.y, p_entry.x,
289
+ lm_entry.border_dirs8_id])
290
+ pix.subpix_path_dir = +1
291
+ #$PDbgLog.print_msg ",next sub_n=#{lm.exit.sub_n
292
+ # }"
293
+ pix = p_exit; lm = lm_exit
294
+ else
295
+ # $PDbgLog.print_msg ",next sub_n=#{lm.entry.sub_n
296
+ # }"
297
+ pix.subpix_path_dir = -1
298
+ pix = p_entry; lm = lm_entry
299
+ end
300
+ #$PDbgLog.print_msg ",subpix_path_dir=" +
301
+ # lp.last.subpix_path_dir.inspect + " "
302
+ pix.border_dirs8_id = lm.border_dirs8_id
303
+ #$PDbgLog.progr.progr_units = @visited.length
304
+ end
305
+ #$PDbgLog.sig_return(".")
306
+ lp
307
+ end
308
+
309
+ def get_loops
310
+ return [ContourLoop.new(@contour_carpet).
311
+ replace(@contour_carpet)] if @contour_carpet.length < 3
312
+ #$PDbgLog.sig_call(self)
313
+ loops = []
314
+ @visited.clear
315
+ unvis_neighbs = []
316
+ vis_pix = {}
317
+ debris = Set.new
318
+ start_cpix = @contour_carpet.first
319
+ if @external
320
+ if @geometry == 8
321
+ get_start_subpix_proc = proc{|cpix| cpix.subpix8(16)}
322
+ id2lm = ContourCarpetCalc::CONTOUR_PATH_EXTERNAL_SITU8_ID2LM
323
+ else
324
+ get_start_subpix_proc = proc{|cpix| cpix.subpix4(8)}
325
+ id2lm = ContourCarpetCalc::CONTOUR_PATH_EXTERNAL_SITU4_ID2LM
326
+ end
327
+ else
328
+ if @geometry == 8
329
+ get_start_subpix_proc = proc{|cpix| cpix.subpix8(16)}
330
+ id2lm = ContourCarpetCalc::CONTOUR_PATH_INTERNAL_SITU8_ID2LM
331
+ else
332
+ get_start_subpix_proc = proc{|cpix| cpix.subpix4(8)}
333
+ id2lm = ContourCarpetCalc::CONTOUR_PATH_INTERNAL_SITU4_ID2LM
334
+ end
335
+ end
336
+ #$PDbgLog.print_msg "@external=#{@external.inspect} "
337
+ while start_cpix
338
+ #$PDbgLog.print_msg "start_cpix: #{start_cpix}: "
339
+ lp = self.next_loop(get_start_subpix_proc.call(
340
+ start_cpix), id2lm, @external)
341
+ #$PDbgLog.print_msg PixbufPix.path_to_s(lp) + " "
342
+ #$PDbgLog.puts_msg lp.inspect
343
+ #$PDbgLog.puts_msg "#{lp.length} pix "
344
+ if lp.length > 1
345
+ loops << lp
346
+ else
347
+ debris << start_cpix
348
+ end
349
+ lp.each { |pix| vis_pix[pix.yx] = true }
350
+ lp.each{|pix|@contour_carpet.pix_neighbs(pix).each{|ngb|
351
+ unvis_neighbs << ngb unless vis_pix.include?(ngb.yx)||
352
+ debris.include?(ngb) }}
353
+ start_cpix = unvis_neighbs.pop
354
+ while start_cpix && (vis_pix.include?(start_cpix.yx) ||
355
+ debris.include?(start_cpix))
356
+ start_cpix = unvis_neighbs.pop
357
+ end
358
+ end
359
+ loops.each { |lp| lp.merge_debris!(debris) }
360
+ #$PDbgLog.sig_return(".")
361
+ loops
362
+ end
363
+ end
364
+
365
+ class ContourCarpet < ImageObject
366
+ attr_reader :start_pix, :pix_neighbs_proc, :geometry, :external, :blob,
367
+ :min_loop_length, :subpix_class, :pix_neighbs_cache
368
+
369
+ self.img_obj_add_sub_obj :loops, :loop_carpet
370
+
371
+ def initialize(pix, blob, geometry=8, external=true, min_loop_length=0)
372
+ raise ArgumentError, "geometry must be 8 or 4" unless
373
+ [8, 4].include?(@geometry = geometry)
374
+ @external = external
375
+ @blob = blob
376
+ @min_loop_length = min_loop_length
377
+ @subpix_class = [Subpix4,Subpix8].at(@geometry/4 - 1)
378
+ @loops = nil
379
+ @loop_carpet = nil
380
+ if block_given?
381
+ @pix_neighbs_proc = Proc.new
382
+ else
383
+ if geometry == 8
384
+ @pix_neighbs_proc = proc{|ppix| ppix.adj8.find_all{|pix|
385
+ @blob.pixbuf.blob_id_at?(pix.x,pix.y,@blob.blob_id)&&
386
+ ((adj4 = pix.adj4).length < 4 ||
387
+ adj4.detect { |p|
388
+ !@blob.pixbuf.blob_id_at?(p.x,p.y,@blob.blob_id)})
389
+ }}
390
+ else
391
+ @pix_neighbs_proc = proc{|ppix| ppix.adj4.find_all{|pix|
392
+ @blob.pixbuf.blob_id_at?(pix.x,pix.y,@blob.blob_id)&&
393
+ ((adj8 = pix.adj8).length < 8 ||
394
+ adj8.detect { |p|
395
+ !@blob.pixbuf.blob_id_at?(p.x,p.y,@blob.blob_id)})
396
+ }}
397
+ end
398
+ end
399
+ super()
400
+ @start_pix = pix
401
+ @pix_rev_conn_idxs = {}
402
+ @pix_neighbs_cache = PCache.new
403
+ self.rebuild
404
+ end
405
+
406
+ def rebuild
407
+ $PDbgLog.sig_call(self)
408
+ self.clear
409
+ @loops = @loop_carpet = nil
410
+ $PDbgLog.print_msg "Getting #{@external ? "external": "internal"
411
+ } contour carpet from #{@start_pix.coords_to_s}: "
412
+ ContourCarpetCalc.new(self, @geometry, @external).each_cpix {
413
+ |cpix| self << cpix }
414
+ @pix_neighbs_cache.clear
415
+ $PDbgLog.sig_return("#{self.length} pixel#{self.length==1 ? "" :
416
+ "s"}.\n")
417
+ end
418
+
419
+ def loops
420
+ return @loops if @loops
421
+ @loops = ContourCarpetCalc.new(self, @geometry, @external).
422
+ get_loops.delete_if{ |lp| lp.length < @min_loop_length }
423
+ @loops.each { |lp| lp.blob = @blob }
424
+ @pix_neighbs_cache.clear
425
+ @loops
426
+ end
427
+
428
+ def loop_carpet
429
+ return @loop_carpet if @loop_carpet
430
+ $PDbgLog.sig_call(self)
431
+ $PDbgLog.print_msg "Getting #{@external ? "external": "internal"
432
+ } loop carpet: "
433
+ @loop_carpet = ContourLoopCarpet.new(self)
434
+ self.loops.each { |lp| @loop_carpet.merge_new_loop!(lp) }
435
+ @loop_carpet.blob = @blob
436
+ #$PDbgLog.print_msg PixbufPix.path_to_s(@loop_carpet) + ": "
437
+ @loop_carpet.img_obj_freeze
438
+ $PDbgLog.sig_return("#{@loop_carpet.length} pixel#{@loop_carpet.
439
+ length == 1 ? "" : "s"}.\n")
440
+ @loop_carpet
441
+ end
442
+
443
+ def to_s
444
+ "<PPix::ContourCarpet start_pix#{@start_pix.coords_to_s
445
+ }, geometry=#{@geometry} in pixbuf: #{@start_pix.pixbuf
446
+ }>"
447
+ end
448
+
449
+ alias_method :inspect, :to_s
450
+ end
451
+
452
+ class ContourCarpet
453
+ def pix_neighbs(pix)
454
+ if (tmp = @pix_neighbs_cache[pix.yx])
455
+ return tmp
456
+ end
457
+ @pix_neighbs_cache[pix.yx] = self.pix_neighbs_proc.call(pix)
458
+ end
459
+
460
+ def pix_connections(pix)
461
+ pix.connections { |cpix| self.pix_neighbs(cpix) }
462
+ end
463
+
464
+ def pix_rev_conn_idx(pix, conn_i)
465
+ #$PDbgLog.sig_call(self)
466
+ #$PDbgLog.puts_msg "(#{conn_i}) from (#{self.x}, #{self.y})."
467
+ if (rci = @pix_rev_conn_idxs[pix.yx])
468
+ return rci[conn_i] if rci[conn_i]
469
+ else
470
+ rci = @pix_rev_conn_idxs[pix.yx] = []
471
+ end
472
+ conns = self.pix_connections(pix)
473
+ #$PDbgLog.sig_return
474
+ rci[conn_i] = pix.rev_conn_idx(conns, conn_i,
475
+ self.pix_connections(conns[conn_i].last))
476
+ end
477
+
478
+ def pix_node?(pix)
479
+ self.pix_neighbs(pix).length > 2
480
+ end
481
+
482
+ def pix_transit_point?(pix)
483
+ self.pix_neighbs(pix).length == 2
484
+ end
485
+
486
+ def pix_end_point?(pix)
487
+ self.pix_neighbs(pix).length < 2
488
+ end
489
+
490
+ def pix_has_node_neighb?(pix)
491
+ self.pix_neighbs(pix).each { |neighb|
492
+ return true if self.pix_node?(neighb) }
493
+ false
494
+ end
495
+
496
+ def pix_has_nonnode_neighb?(pix)
497
+ self.pix_neighbs(pix).each { |neighb|
498
+ return true if !self.pix_node?(neighb) }
499
+ false
500
+ end
501
+
502
+ def pix_in_node_grp?(pix)
503
+ self.pix_node?(pix) && !self.pix_has_nonnode_neighb?(pix)
504
+ end
505
+ end
506
+
507
+ class ContourCarpet
508
+ def subpix_internal_neighbs(subpix)
509
+ #$PDbgLog.sig_call(self)
510
+ incl_yx=self.pix_neighbs(subpix.img_pix).collect{|cpix| cpix.yx}
511
+ incl_yx << subpix.img_pix.yx
512
+ yx_set = self.img_obj_yx_set
513
+ pixbuf = self.blob.pixbuf
514
+ blob_id = self.blob.blob_id
515
+ #$PDbgLog.puts_msg "yx_set: " + PixbufPix.yx_path_to_s(
516
+ # yx_set.to_a.sort)
517
+ #res =
518
+ subpix.neighbs.find_all { |ngb|
519
+ #$PDbgLog.print_msg ngb.to_s + " "
520
+ incl_yx.include?(ngb.img_pix.yx) &&
521
+ ngb.border.detect { |nn|
522
+ !yx_set.include?(nn.img_pix.yx) && (
523
+ nn.img_pix.virtual? ||
524
+ !pixbuf.blob_id_at?(nn.img_pix.x, nn.img_pix.y,
525
+ blob_id) )
526
+ }
527
+ }
528
+ #$PDbgLog.print_msg ". "
529
+ #$PDbgLog.sig_return(subpix.to_s + ": " + Subpix.path_to_s(res))
530
+ #res
531
+ end
532
+
533
+ def subpix_external_neighbs(subpix)
534
+ #$PDbgLog.sig_call(self)
535
+ incl_yx =self.pix_neighbs(subpix.img_pix).collect{|cpix|cpix.yx}
536
+ incl_yx << subpix.img_pix.yx
537
+ yx_set = self.img_obj_yx_set
538
+ pixbuf = self.blob.pixbuf
539
+ blob_id = self.blob.blob_id
540
+ #$PDbgLog.puts_msg "yx_set: " + PixbufPix.yx_path_to_s(
541
+ # yx_set.to_a.sort)
542
+ #res =
543
+ subpix.neighbs.find_all { |ngb|
544
+ #$PDbgLog.print_msg ngb.to_s + " "
545
+ incl_yx.include?(ngb.img_pix.yx) &&
546
+ ngb.border.detect { |nn|
547
+ !yx_set.include?(nn.img_pix.yx) && (
548
+ !nn.img_pix.virtual? &&
549
+ pixbuf.blob_id_at?(nn.img_pix.x, nn.img_pix.y,
550
+ blob_id) )
551
+ }
552
+ }
553
+ #$PDbgLog.print_msg ". "
554
+ #$PDbgLog.sig_return(subpix.to_s + ": " + Subpix.path_to_s(res))
555
+ #res
556
+ end
557
+
558
+ def subpix_internal_neighbs_into(subpix, res=[], incl_yx=[], neighbs=[],
559
+ bordr=[])
560
+ #$PDbgLog.sig_call(self)
561
+ incl_yx.clear
562
+ self.pix_neighbs(subpix.img_pix).each{|cpix| incl_yx << cpix.yx}
563
+ incl_yx << subpix.img_pix.yx
564
+ yx_set = self.img_obj_yx_set
565
+ pixbuf = self.blob.pixbuf
566
+ blob_id = self.blob.blob_id
567
+ #$PDbgLog.puts_msg "yx_set: " + PixbufPix.yx_path_to_s(
568
+ # yx_set.to_a.sort)
569
+ res.clear
570
+ subpix.neighbs_into(neighbs).each { |ngb|
571
+ #$PDbgLog.print_msg ngb.to_s + " "
572
+ if incl_yx.include?(ngb.img_pix.yx) &&
573
+ ngb.border_into(bordr).detect { |nn|
574
+ !yx_set.include?(nn.img_pix.yx) && (
575
+ nn.img_pix.virtual? ||
576
+ !pixbuf.blob_id_at?(nn.img_pix.x, nn.img_pix.y,
577
+ blob_id) )
578
+ }
579
+ res << ngb
580
+ end
581
+ }
582
+ #$PDbgLog.print_msg ". "
583
+ #$PDbgLog.sig_return(subpix.to_s + ": " + Subpix.path_to_s(res))
584
+ res
585
+ end
586
+
587
+ def subpix_external_neighbs_into(subpix, res=[], incl_yx=[], neighbs=[],
588
+ bordr=[])
589
+ #$PDbgLog.sig_call(self)
590
+ incl_yx.clear
591
+ self.pix_neighbs(subpix.img_pix).each{|cpix|incl_yx << cpix.yx}
592
+ incl_yx << subpix.img_pix.yx
593
+ yx_set = self.img_obj_yx_set
594
+ pixbuf = self.blob.pixbuf
595
+ blob_id = self.blob.blob_id
596
+ #$PDbgLog.puts_msg "yx_set: " + PixbufPix.yx_path_to_s(
597
+ # yx_set.to_a.sort)
598
+ res.clear
599
+ subpix.neighbs_into(neighbs).each { |ngb|
600
+ #$PDbgLog.print_msg ngb.to_s + " "
601
+ if incl_yx.include?(ngb.img_pix.yx) &&
602
+ ngb.border_into(bordr).detect { |nn|
603
+ !yx_set.include?(nn.img_pix.yx) && (
604
+ !nn.img_pix.virtual? &&
605
+ pixbuf.blob_id_at?(nn.img_pix.x, nn.img_pix.y,
606
+ blob_id) )
607
+ }
608
+ res << ngb
609
+ end
610
+ }
611
+ #$PDbgLog.print_msg ". "
612
+ #$PDbgLog.sig_return(subpix.to_s + ": " + Subpix.path_to_s(res))
613
+ res
614
+ end
615
+
616
+ def subpix_neighbs(subpix, external=true)
617
+ external ? self.subpix_external_neighbs(subpix) :
618
+ self.subpix_internal_neighbs(subpix)
619
+ end
620
+ end
621
+
622
+ class ContourCarpet
623
+ def pix_situ8_arr_into(pix, res=[])
624
+ res.clear
625
+ self.pix_neighbs(pix).each { |px| res[PixbufPix::ADJ8_ID2SPEC.
626
+ at(PixbufPix.adj8_xy_id(px.x-pix.x, px.y-pix.y)).at(1)] = 1 }
627
+ pixbuf = pix.pixbuf
628
+ blob_id = self.blob.blob_id
629
+ width = pixbuf.picture_width; height = pixbuf.picture_height
630
+ PixbufPix::ADJ8_CCW_ORDER.each_with_index { |a,a_i|
631
+ next if res.at(a_i)
632
+ x = pix.x + a.x; y = pix.y + a.y
633
+ if y >= 0 && y < height && x >= 0 && x < width &&
634
+ pixbuf.blob_id_at?(x, y, blob_id)
635
+ res[a_i] = 2
636
+ else
637
+ res[a_i] = 0
638
+ end
639
+ }
640
+ res
641
+ end
642
+ end
643
+
644
+ end