extract-curves 0.1.1-mswin32

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