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,5 @@
1
+ /calc_situations.rb/1.1.1.1/Tue Nov 15 17:32:16 2005//
2
+ /carp_calc.rb/1.1.1.1/Tue Nov 15 17:32:40 2005//
3
+ /situations.dmp/1.1.1.1/Tue Nov 15 17:32:40 2005//
4
+ /situations.rb/1.1.1.1/Tue Nov 15 17:32:40 2005//
5
+ D
@@ -0,0 +1 @@
1
+ extract-curves/ruby_libs/pav/pix/contour
@@ -0,0 +1 @@
1
+ :ext:pavpen@rubyforge.org:/var/cvs/extract-curves
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/ruby
2
+ require 'pav/pix/contour/carp_calc'
3
+
4
+ c_plms = {}
5
+ situations = [ PPix::ContourCarpetCalc.get_id2lm(PPix::Subpix8, true, c_plms),
6
+ PPix::ContourCarpetCalc.get_id2lm(PPix::Subpix8, false,c_plms),
7
+ PPix::ContourCarpetCalc.get_id2lm(PPix::Subpix4, true, c_plms),
8
+ PPix::ContourCarpetCalc.get_id2lm(PPix::Subpix4, false,c_plms)]
9
+ open('situations.dmp', 'w') { |file| Marshal.dump(situations, file) }
@@ -0,0 +1,212 @@
1
+ require 'pav/pix'
2
+ require 'pav/pix/subpix'
3
+
4
+ module PPix
5
+
6
+ class ContourCarpetCalc
7
+ def self.subpix_situ8_unpack(situ)
8
+ res = Array.new(8, 0)
9
+ pos = 0
10
+ while situ > 0
11
+ res[pos] = situ % 3
12
+ pos += 1
13
+ situ /= 3
14
+ end
15
+ res
16
+ end
17
+
18
+ def self.subpix_situ8p_unpack(situ)
19
+ res = Array.new(9, 0)
20
+ res[-1] = 1
21
+ pos = 0
22
+ while situ > 0
23
+ res[pos] = situ % 3
24
+ pos += 1
25
+ situ /= 3
26
+ end
27
+ res
28
+ end
29
+
30
+ def self.subpix_situ8_pack(situ_arr)
31
+ #$PDbgLog.sig_call(self)
32
+ res = 0; order = 1
33
+ for ngb_id in situ_arr
34
+ res += order * ngb_id
35
+ order *= 3
36
+ end
37
+ #$PDbgLog.sig_return(situ_arr.inspect + ": 0x%x" % res)
38
+ res
39
+ end
40
+
41
+ def self.situ_subpix_goable_to(situ, sub_n, subpix_class, border_id)
42
+ situ_arr = self.subpix_situ8p_unpack(situ)
43
+ subpix_class::SUB_N_BORDER[sub_n].detect { |bordn_spec|
44
+ situ_arr[Xy::ADJ8_ID2SPEC[PixbufPix.adj8_xy_id(
45
+ bordn_spec.x, bordn_spec.y)][1]] == border_id
46
+ }
47
+ end
48
+
49
+ def self.subpix_situ_neighbs(situ, sub_n, subpix_class, border_id)
50
+ #$PDbgLog.sig_call(self)
51
+ situ_arr = self.subpix_situ8p_unpack(situ)
52
+ #$PDbgLog.print_msg("situ=#{"0x%x" % situ}, sub_n=#{sub_n
53
+ # }, subpix_class=#{subpix_class.name}, border_id=#{border_id
54
+ # }; situ_arr=#{situ_arr.inspect}: ")
55
+ res = []
56
+ subpix_class::SUB_N_NEIGHBS[sub_n].each_with_index {|ngb_spec,i|
57
+ if situ_arr[Xy::ADJ8_ID2SPEC[PixbufPix.adj8_xy_id(
58
+ x=ngb_spec.x, y=ngb_spec.y)][1]] == 1 &&
59
+ subpix_class::SUB_N_BORDER[ngb_spec.sub_n].detect{|bordn_spec|
60
+ situ_arr[Xy::ADJ8_ID2SPEC[PixbufPix.adj8_xy_id(
61
+ x+bordn_spec.x, y+bordn_spec.y)][1]]==border_id
62
+ }
63
+ res[i/2] = ngb_spec
64
+ end
65
+ }
66
+ #$PDbgLog.sig_return(res.inspect)
67
+ res
68
+ end
69
+
70
+ def self.subpix_situ_path(situ, sub_n_0, subpix_class, external)
71
+ #$PDbgLog.sig_call(self)
72
+ # $PDbgLog.print_msg "situ=%x, sub_n_0=#{sub_n_0}, subpix_class=#{
73
+ # subpix_class.name}, external=#{external}: " % situ
74
+ border_id = external ? 2 : 0
75
+ if sub_n_0 >= subpix_class::SUB_N_NEIGHBS.length-1
76
+ ngbs = self.subpix_situ_neighbs(situ, sub_n_0,
77
+ subpix_class, border_id)
78
+ unless (n = ngbs.detect {|ngb| ngb})
79
+ #$PDbgLog.sig_return('Empty.')
80
+ return []
81
+ end
82
+ else
83
+ unless self.situ_subpix_goable_to(situ, sub_n_0,
84
+ subpix_class, border_id)
85
+ #$PDbgLog.sig_return('[]')
86
+ return []
87
+ end
88
+ n = SubXy.new(0, 0, sub_n_0)
89
+ end
90
+ res = [prev_n = n]
91
+ ngbs0 = self.subpix_situ_neighbs(situ, n.sub_n, subpix_class,
92
+ border_id)
93
+ n = ngbs0[0]
94
+ while n
95
+ res.unshift(n)
96
+ break if n.y != 0 || n.x != 0
97
+ ngbs = self.subpix_situ_neighbs(situ, n.sub_n,
98
+ subpix_class, border_id)
99
+ tmp = n
100
+ n = ngbs.first == prev_n ? ngbs.last : ngbs.first
101
+ if res.include?(n)
102
+ #$PDbgLog.sig_return(res.inspect)
103
+ return res
104
+ end
105
+ prev_n = tmp
106
+ end
107
+ prev_n = res.last
108
+ n = ngbs0[1]
109
+ #$PDbgLog.puts_msg "half1: " + res.inspect + ": "
110
+ #$PDbgLog.puts_msg "prev_n=#{prev_n}, n=#{n}: "
111
+ #$PDbgLog.puts_msg "res.include?(n): #{res.include?(n)}"
112
+ while n && !res.include?(n)
113
+ res << n
114
+ break if n.y != 0 || n.x != 0
115
+ ngbs = self.subpix_situ_neighbs(situ, n.sub_n,
116
+ subpix_class, border_id)
117
+ #$PDbgLog.puts_msg "ngbs: #{ngbs.inspect}"
118
+ tmp = n
119
+ n = ngbs.first == prev_n ? ngbs.last : ngbs.first
120
+ prev_n = tmp
121
+ end
122
+ #$PDbgLog.sig_return(res.inspect)
123
+ res
124
+ end
125
+
126
+ def self.subpix_path_border_dirs8_id(path, subpix_class)
127
+ res = 0
128
+ for ngb_spec in path
129
+ subpix_class::SUB_N_BORDER[ngb_spec.sub_n].each { |n|
130
+ res |= Xy::ADJ8_ID2SPEC.at(PixbufPix.
131
+ adj8_xy_id(n.x, n.y)).at(2) if n.y != 0 || n.x != 0
132
+ }
133
+ end
134
+ res
135
+ end
136
+
137
+ def self.subpix_pix_path_normalize(path, subpix_class)
138
+ res = path.collect { |spec| spec.sub_n }
139
+ cyc = subpix_class::SUB_N_NEIGHBS.length-1
140
+ if res.length > 1 && res.first == (res.last + 1) % cyc
141
+ i_min = min_sub_n = 1.0/0.0
142
+ res.each_with_index { |sub_n, i|
143
+ if sub_n < min_sub_n
144
+ min_sub_n = sub_n; i_min = i
145
+ end
146
+ }
147
+ tmp = []
148
+ res.each_index {|i| tmp << res[(i+i_min) % res.length] }
149
+ res = tmp
150
+ end
151
+ res
152
+ end
153
+
154
+ ContourPathLm = Struct.new("ContourPathLm", #:sub_n_path,
155
+ :entry, :exit, :border_dirs8_id, :path_horiz_cnt,
156
+ :path_vert_cnt)
157
+
158
+ def self.get_id2lm(subpix_class, external, c_path_lms={})
159
+ $PDbgLog.sig_call(self)
160
+ $PDbgLog.new_progr
161
+ $PDbgLog.progr.show_as = "/ situations"
162
+ $PDbgLog.progr.total_progr_units = 3**8
163
+ res =
164
+ (0...3**8).collect { |situ8|
165
+ $PDbgLog.progr.progr_units = situ8
166
+ sub_n_lms = Array.new(subpix_class::SUB_N_NEIGHBS.length, nil)
167
+ (0...subpix_class::SUB_N_NEIGHBS.length).each { |sub_n_0|
168
+ path = self.subpix_situ_path(situ8, sub_n_0, subpix_class,
169
+ external)
170
+ if path[0] && (path[0].y != 0 || path[0].x != 0)
171
+ p_entry = path.shift
172
+ else
173
+ p_entry = nil
174
+ end
175
+ if path.last && (path.last.y != 0 || path.last.x != 0)
176
+ p_exit = path.pop
177
+ else
178
+ p_exit = nil
179
+ end
180
+ path_lm = ContourPathLm.new(
181
+ #self.subpix_pix_path_normalize(path, subpix_class),
182
+ p_entry, p_exit,
183
+ self.subpix_path_border_dirs8_id(path, subpix_class),
184
+ path.find_all{|spec| subpix_class.horizontal?(spec.sub_n)}.
185
+ length,
186
+ path.find_all{|spec| subpix_class.vertical?(spec.sub_n)}.
187
+ length)
188
+ path_lm = c_path_lms.include?(path_lm) ? c_path_lms[path_lm] :
189
+ (c_path_lms[path_lm] = path_lm)
190
+ path.each { |spec| sub_n = spec.sub_n
191
+ if sub_n_lms[sub_n]
192
+ if sub_n_lms[sub_n] != path_lm
193
+ raise "Conflicting path elements for #{subpix_class.name
194
+ }, #{external ? 'ex' : 'in'}ternal, situ8=#{
195
+ situ8}, sub_n=#{sub_n} from sub_n_0=#{sub_n_0
196
+ }: #{sub_n_lms[sub_n]} vs. #{path_lm}!"
197
+ end
198
+ else
199
+ sub_n_lms[sub_n] = path_lm
200
+ end
201
+ }
202
+ sub_n_lms[sub_n_0] = path_lm
203
+ }
204
+ sub_n_lms
205
+ }
206
+ $PDbgLog.progr.progr_units += 1
207
+ $PDbgLog.sig_return(' done.')
208
+ res
209
+ end
210
+ end
211
+
212
+ end
@@ -0,0 +1,21 @@
1
+ require 'pav/pav_find'
2
+ require 'pav/string/ext'
3
+ require 'pav/pix/contour/carp_calc'
4
+
5
+ module PPix
6
+
7
+ class ContourCarpetCalc
8
+ PavFind.pfind($:) { |path|
9
+ if path.ends_with('pav/pix/contour/situations.dmp')
10
+ open(path, 'r') { |file|
11
+ CONTOUR_PATH_EXTERNAL_SITU8_ID2LM,
12
+ CONTOUR_PATH_INTERNAL_SITU8_ID2LM,
13
+ CONTOUR_PATH_EXTERNAL_SITU4_ID2LM,
14
+ CONTOUR_PATH_INTERNAL_SITU4_ID2LM = *Marshal.load(file)
15
+ }
16
+ break
17
+ end
18
+ }
19
+ end
20
+
21
+ end
@@ -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