extract-curves 0.1.1-i586-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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.so +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,21 @@
1
+ extract-curves (0.1.1) unstable; urgency=medium
2
+ * Switched to shaving negligible-extent groups as though they were nodes.
3
+ * Added the 'View/Unmark all' function.
4
+ * Switched to dynamic addition of tooltips and blinking/highlighted segments
5
+ (e.g. after incorporation of subblobs).
6
+ * Improved method call synchronization by using pre-call, cancel-call and
7
+ post-call hooks and method disabling.
8
+
9
+ -- Pavel Penev <pavpen@berkeley.edu> Sun, 27 Nov 2005 18:58:21 -0500
10
+
11
+ extract-curves (0.1.0) unstable; urgency=medium
12
+ * New pre-release with a new and more bug-free GUI, based on PGuiObj
13
+ (autogenerated from the Ruby object structure), with the ability to save
14
+ image objects in image formats.
15
+
16
+ -- Pavel Penev <pavpen@berkeley.edu> Sat, 19 Nov 2005 23:57:31 -0500
17
+
18
+ extract-curves (0.0.1) unstable; urgency=medium
19
+ * Initial pre-release.
20
+
21
+ -- Pavel Penev <pavpen@berkeley.edu> Tue, 15 Nov 2005 13:36:21 -0500
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'complex'
4
+ require 'pav/floatsio'
5
+
6
+ x0, y0, kr, ktheta, format_str = *ARGV
7
+ unless x0 && y0
8
+ puts "Usage: #{File.basename($0)} x_0 y_0 [k_r [k_theta [format_str]]]"
9
+ puts " (x_0, y_0) = Projection of the zero pole."
10
+ puts " k_r, k_theta = Coefficients for the linear (r, theta) pixel " +
11
+ "coordinates."
12
+ exit 1
13
+ end
14
+ x0 = x0.to_f; y0 = y0.to_f
15
+ kr ? kr = kr.to_f : kr = 1.0
16
+ ktheta ? ktheta = ktheta.to_f : ktheta = 1.0
17
+ format_str = "%.29g\t%.29g" unless format_str
18
+
19
+ FloatsInp.new($stdin).each_rec { |rec| x, y = *rec
20
+ r, theta = *Complex(x-x0, y-y0).polar
21
+ puts format_str % [theta * ktheta, r * kr]
22
+ }
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'complex'
4
+ require 'pav/floatsio'
5
+
6
+ x0, y0, kr, ktheta, format_str = *ARGV
7
+ unless x0 && y0
8
+ puts "Usage: #{File.basename($0)} x_0 y_0 [k_r [k_theta [format_str]]]"
9
+ puts " (x_0, y_0) = Projection of the zero pole."
10
+ puts " k_r, k_theta = Coefficients for the linear (r, theta) pixel " +
11
+ "coordinates."
12
+ exit 1
13
+ end
14
+ x0 = x0.to_f; y0 = y0.to_f
15
+ kr ? kr = kr.to_f : kr = 1.0
16
+ ktheta ? ktheta = ktheta.to_f : ktheta = 1.0
17
+ format_str = "%.29g\t%.29g" unless format_str
18
+
19
+ FloatsInp.new($stdin).each_rec { |rec| x, y = *rec
20
+ r, theta = *Complex(x-x0, y-y0).polar
21
+ puts format_str % [theta * ktheta, r * kr]
22
+ }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ lns = $stdin.readlines
4
+ lns.reverse!
5
+ print lns
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ lns = $stdin.readlines
4
+ lns.reverse!
5
+ print lns
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'pav/floatsio'
4
+
5
+ format_str = *ARGV
6
+ if ARGV.include?("--usage") || ARGV.include?("--help")
7
+ puts "Usage: #{File.basename($0)} [format_str]"
8
+ puts " Calculates the area of a spherical polygon given by "
9
+ puts " (azimuth; angular distance from the pole) points in steradians."
10
+ exit 1
11
+ end
12
+ format_str = "%.30g" unless format_str
13
+
14
+ area = 0.0
15
+ EPS = 1e-300
16
+ inp = FloatsInp.new($stdin)
17
+ az0, d0 = inp.get_rec
18
+ inp.each_rec { |rec| az, d = *rec
19
+ #puts "d0=#{d0.inspect}, az0=#{az0.inspect}, d=#{d.inspect}, az=#{
20
+ # az.inspect}"
21
+ if (d - d0).abs < EPS
22
+ term = Math.cos( (d+d0)/2.0 )
23
+ else
24
+ term = (Math.sin(d) - Math.sin(d0)) / (d - d0)
25
+ end
26
+ area += (az - az0) * (1.0 - term)
27
+ d0 = d; az0 = az
28
+ }
29
+
30
+ puts format_str % area
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'pav/floatsio'
4
+
5
+ format_str = *ARGV
6
+ if ARGV.include?("--usage") || ARGV.include?("--help")
7
+ puts "Usage: #{File.basename($0)} [format_str]"
8
+ puts " Calculates the area of a spherical polygon given by "
9
+ puts " (azimuth; angular distance from the pole) points in steradians."
10
+ exit 1
11
+ end
12
+ format_str = "%.30g" unless format_str
13
+
14
+ area = 0.0
15
+ EPS = 1e-300
16
+ inp = FloatsInp.new($stdin)
17
+ az0, d0 = inp.get_rec
18
+ inp.each_rec { |rec| az, d = *rec
19
+ #puts "d0=#{d0.inspect}, az0=#{az0.inspect}, d=#{d.inspect}, az=#{
20
+ # az.inspect}"
21
+ if (d - d0).abs < EPS
22
+ term = Math.cos( (d+d0)/2.0 )
23
+ else
24
+ term = (Math.sin(d) - Math.sin(d0)) / (d - d0)
25
+ end
26
+ area += (az - az0) * (1.0 - term)
27
+ d0 = d; az0 = az
28
+ }
29
+
30
+ puts format_str % area
@@ -0,0 +1,1670 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'gtk2'
4
+
5
+ if str = Gtk.check_version(2, 6, 0)
6
+ puts "This program requires GTK+ 2.6.0 or later"
7
+ puts str
8
+ exit
9
+ end
10
+
11
+ Gtk.init
12
+
13
+ require 'thread'
14
+ require 'pav/pix'
15
+ require 'pav/set'
16
+ require 'pav/dbg_log'
17
+ require 'pav/floatsio'
18
+ require 'pav/pix/blob'
19
+ require 'pav/pix/curve'
20
+ require 'pav/gtk/icons'
21
+ require 'pav/attr_cache'
22
+ require 'pav/gtk/dialog'
23
+ require 'pav/gtk/guiobj'
24
+ require 'pav/guiobj/obj'
25
+ require 'pav/string/ext'
26
+ require 'pav/gtk/toolbar'
27
+ require 'pav/pix/contour'
28
+ require 'pav/pix/img_obj'
29
+ require 'pav/string/words'
30
+ require 'pav/guiobj/info_asm'
31
+ require 'pav/pix/shaved_core'
32
+
33
+ class ExtractCurvesApp < Gtk::Window
34
+ VERSION = [0, 1, 1]
35
+ VERSION_SUFFIX = "-beta"
36
+ MARK_WAYS = ["highlight", "blink", "trace"]
37
+ end
38
+
39
+ if ARGV[0]
40
+ case ARGV[0]
41
+ when '--version'
42
+ puts ExtractCurvesApp::VERSION.join('.')
43
+ exit 0
44
+ when '--file-path'
45
+ puts File.expand_path(__FILE__)
46
+ exit 0
47
+ end
48
+ end
49
+
50
+ class ECLogProgrBar < PLogProgrBar
51
+ attr_reader :progr_bar, :progr_box, :progr_label
52
+
53
+ def initialize(dbg_log, progr_bar, progr_label, progr_box)
54
+ super(dbg_log)
55
+ @progr_bar = progr_bar
56
+ @progr_label = progr_label
57
+ @progr_box = progr_box
58
+ @progr_label.text = ""
59
+ @progr_bar.orientation = @progr_bar_orientation = 0
60
+ @progr_bar.fraction = 0.0
61
+ @progr_bar.show_text = false
62
+ @progr_box.pack_start(@progr_bar)
63
+ @progr_box.pack_start(@progr_label, false, false)
64
+ @tot_progr_units = 100.0
65
+ i = -1
66
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
67
+ Gtk.events_pending?
68
+ end
69
+
70
+ def total_progr_units=(val)
71
+ super(val)
72
+ if val
73
+ @progr_bar.show_text = true
74
+ else
75
+ @progr_bar.show_text = false
76
+ end
77
+ i = -1
78
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
79
+ Gtk.events_pending?
80
+ end
81
+
82
+ def disp_progr(progr_units_change)
83
+ if self.total_progr_units
84
+ if self.show_as[0,1] == "%"
85
+ pct = self.fmt_str % (100.0*self.progr_units /
86
+ self.total_progr_units)
87
+ else
88
+ pct = "#{self.progr_units}/#{
89
+ self.total_progr_units}"
90
+ end
91
+ pct += self.show_as[1, self.show_as.length-1]
92
+ @progr_bar.fraction = Float(self.progr_units) /
93
+ self.total_progr_units
94
+ else
95
+ while self.progr_units > @tot_progr_units
96
+ @tot_progr_units *= 2
97
+ @progr_bar_orientation += 1
98
+ end
99
+ if self.show_as[0,1] == "%"
100
+ pct = ""
101
+ else
102
+ pct = "#{self.progr_units}" +
103
+ self.show_as[1,self.show_as.length-1]
104
+ end
105
+ @progr_bar.fraction = Float(self.progr_units) /
106
+ @tot_progr_units
107
+ @progr_bar.orientation = @progr_bar_orientation %= 2
108
+ end
109
+ @progr_label.text = pct
110
+ i = -1
111
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
112
+ Gtk.events_pending?
113
+ end
114
+
115
+ def finish
116
+ super
117
+ @progr_box.remove(@progr_label)
118
+ @progr_box.remove(@progr_bar)
119
+ i = -1
120
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
121
+ Gtk.events_pending?
122
+ end
123
+ end
124
+
125
+ class StatusbarIO < IO
126
+ attr_reader :dbg_log, :statusbar, :tee_to, :last_ln
127
+
128
+ def initialize(dbg_log, statusbar, tee_to=nil)
129
+ @dbg_log = dbg_log
130
+ @statusbar = statusbar
131
+ @tee_to = tee_to
132
+ @last_ln = ""
133
+ end
134
+
135
+ def print_to_statusbar(str)
136
+ (@last_ln + str).each_line { |ln| @last_ln = ln }
137
+ @last_ln.eval_backspace!(@dbg_log.backspc)
138
+ @statusbar.pop(0)
139
+ @statusbar.push(0, @last_ln.chomp)
140
+ i = -1
141
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
142
+ Gtk.events_pending?
143
+ end
144
+
145
+ def print(str)
146
+ @tee_to.print(str) if @tee_to
147
+ self.print_to_statusbar(str)
148
+ end
149
+
150
+ def puts(str)
151
+ @tee_to.puts(str) if @tee_to
152
+ self.print_to_statusbar(str)
153
+ end
154
+
155
+ def tty?
156
+ if @tee_to
157
+ @tee_to.tty?
158
+ else
159
+ true
160
+ end
161
+ end
162
+ end
163
+
164
+ module PGuiObj
165
+
166
+ module MObj
167
+ attr_accessor :extract_curves_path, :extract_curves_mark,
168
+ :extract_curves_processed
169
+ end
170
+
171
+ module PMMethod
172
+ attr_accessor :extract_curves_observed
173
+ end
174
+
175
+ end
176
+
177
+ class EcImgObjArgObserver
178
+ def initialize(ec_app, arg_idx, path)
179
+ @ec_app = ec_app
180
+ @arg_idx = arg_idx
181
+ @path = path
182
+ end
183
+
184
+ def update(arg)
185
+ unless (cfg = @ec_app.ec_path_cfg[@path])
186
+ cfg = @ec_app.ec_path_cfg[@path] =
187
+ ExtractCurvesApp::ImgObjMethInfo.new.new(nil, [])
188
+ end
189
+ cfg.arg_deflts[@arg_idx] = arg.value
190
+ end
191
+ end
192
+
193
+ class EcImgObjMarkArgObserver
194
+ def initialize(ec_app, meth, path)
195
+ @ec_app = ec_app
196
+ @meth = meth
197
+ @path = path
198
+ end
199
+
200
+ def update(arg)
201
+ return if @ec_app.arg_set_auto
202
+ unless (cfg = @ec_app.ec_path_cfg[@path])
203
+ cfg = @ec_app.ec_path_cfg[@path] =
204
+ ExtractCurvesApp::ImgObjMethInfo.new(nil, [])
205
+ end
206
+ cfg.mark = arg.value
207
+ @meth.call
208
+ end
209
+ end
210
+
211
+ class EcObjDeathObserver
212
+ attr_reader :ec_app
213
+
214
+ def initialize(ec_app)
215
+ @ec_app = ec_app
216
+ end
217
+
218
+ def update(impl_obj, obj)
219
+ @ec_app.img_obj_delete(impl_obj)
220
+ end
221
+ end
222
+
223
+ class EcImgObjChangeObserver
224
+ attr_reader :ec_app
225
+
226
+ def self.observe(impl_obj, ec_app)
227
+ impl_obj.pguiobj_changed_flag.add_observer(
228
+ res=self.new(ec_app))
229
+ res
230
+ end
231
+
232
+ def initialize(ec_app)
233
+ @ec_app = ec_app
234
+ end
235
+
236
+ def self.img_obj_length(obj)
237
+ if obj.kind_of?(PGuiObj::ObjCollection)
238
+ len = 0
239
+ obj.pguiobj_each_value{|s|len += self.img_obj_length(s)}
240
+ len
241
+ else
242
+ obj.length
243
+ end
244
+ end
245
+
246
+ def update(impl_obj, change)
247
+ obj=impl_obj.pguiobj_guiobj
248
+ obj.pguiobj_info_str_asm.set_attr(10, 'extract-curves-pix-size',
249
+ EcImgObjChangeObserver.img_obj_length(obj).to_s + ' pix')
250
+ if obj.kind_of?(PGuiObj::ObjCollection)
251
+ obj.pguiobj_info_str_asm.set_attr(9,
252
+ 'extract-curves-collection-length',
253
+ (len=obj.pguiobj_length).to_s + ' element' + (len == 1 ?
254
+ '' : 's'))
255
+ end
256
+ @ec_app.ec_mark_add_pixels[obj.extract_curves_mark].call(change)
257
+ end
258
+ end
259
+
260
+ class EcImgObjMethEndCallObserver
261
+ attr_reader :ec_app
262
+
263
+ def self.observe(meth, ec_app)
264
+ meth.pguiobj_cancel_call_flag.add_observer(obs=self.new(ec_app))
265
+ meth.pguiobj_post_call_flag.add_observer(obs)
266
+ end
267
+
268
+ def initialize(ec_app)
269
+ @ec_app = ec_app
270
+ end
271
+
272
+ def update(impl_obj, impl_meth, *args)
273
+ @ec_app.drw_area_in_procs = false
274
+ @ec_app.in_progr.unlock
275
+ impl_meth.enable
276
+ end
277
+ end
278
+
279
+ class EcImgObjMethStartCallObserver
280
+ attr_reader :ec_app
281
+
282
+ def self.observe(meth, ec_app)
283
+ meth.pguiobj_pre_call_flag.add_observer(self.new(ec_app))
284
+ end
285
+
286
+ def initialize(ec_app)
287
+ @ec_app = ec_app
288
+ end
289
+
290
+ def update(impl_obj, impl_meth)
291
+ #$PDbgLog.sig_call(self)
292
+ #$PDbgLog.puts_msg "#{impl_obj.inspect}.#{
293
+ # impl_meth.pguiobj_name.inspect}: pixbuf: #{@ec_app.
294
+ # pixbuf || 'nil'}; in_progr: #{@ec_app.in_progr}:#{
295
+ # @ec_app.in_progr.locked? ? '' : 'not '}locked"
296
+ unless @ec_app.pixbuf && @ec_app.in_progr.try_lock
297
+ #$PDbgLog.sig_return
298
+ raise PGuiObj::CancelCall
299
+ end
300
+ impl_meth.disable
301
+ @ec_app.drw_area_in_procs = true
302
+ EcImgObjMethEndCallObserver.observe(impl_meth, @ec_app)
303
+ #$PDbgLog.sig_return
304
+ end
305
+ end
306
+
307
+ class EcImgObjMethCallObserver
308
+ attr_reader :ec_app
309
+
310
+ args = []
311
+ ExtractCurvesApp::MARK_WAYS.each_with_index{ |way,i|
312
+ args << way.cap_first; args << i }
313
+ args << 'None'; args << ExtractCurvesApp::MARK_WAYS.length
314
+ @@markings_enum = PGuiObj::Enum.new(*args)
315
+
316
+ def self.observe(meth, ec_app)
317
+ #$PDbgLog.sig_call(self)
318
+ unless meth.extract_curves_observed
319
+ #$PDbgLog.puts_msg "Observing #{meth.pguiobj_name.inspect} (#{
320
+ # meth.object_id.mem_hex})."
321
+ meth.pguiobj_post_call_flag.add_observer(self.new(ec_app))
322
+ EcImgObjMethStartCallObserver.observe(meth, ec_app)
323
+ meth.extract_curves_observed = true
324
+ end
325
+ #$PDbgLog.sig_return
326
+ end
327
+
328
+ def initialize(ec_app)
329
+ @ec_app = ec_app
330
+ end
331
+
332
+ def procs_obj(obj, impl_obj, path)
333
+ #$PDbgLog.sig_call(self)
334
+ ecp = obj.extract_curves_processed = 0 unless
335
+ (ecp = obj.extract_curves_processed)
336
+ if (ecp & 0b10) != 0
337
+ #$PDbgLog.sig_return
338
+ return
339
+ end
340
+ obj.extract_curves_processed |= 0b10
341
+ #$PDbgLog.puts_msg "obj: #{obj}, impl_obj: #{impl_obj}, path=#{
342
+ # path.inspect}"
343
+ unless (cfg=@ec_app.ec_path_cfg[path])
344
+ cfg = @ec_app.ec_path_cfg[path] =
345
+ ExtractCurvesApp::ImgObjMethInfo.new(nil, [])
346
+ end
347
+ obj.extract_curves_path = path
348
+ obj.pguiobj_methods.each { |child|
349
+ EcImgObjMethCallObserver.observe(child, @ec_app)
350
+ c_cfg = @ec_app.ec_path_cfg[c_path = path + '/' +
351
+ child.pguiobj_name]
352
+ if c_cfg
353
+ child.pguiobj_args.each_with_index { |arg, arg_i|
354
+ arg.pguiobj_default = c_cfg.arg_deflts.at(arg_i)
355
+ arg.pguiobj_config.gtk_tooltips =
356
+ @ec_app.objs_ttips
357
+ arg.pguiobj_value_changed_flag.add_observer(
358
+ EcImgObjArgObserver.new(@ec_app,arg_i,c_path))
359
+ }
360
+ end
361
+ }
362
+ impl_obj.pguiobj_config.gtk_tooltips = @ec_app.objs_ttips
363
+ obj.pguiobj_info_str_asm = PGuiObj::ObjInfoStrAssembler.new(
364
+ impl_obj) unless obj.pguiobj_info_str_asm
365
+ # Mark method:
366
+ meth = impl_obj.pguiobj_add_method(PGuiObj::PMethod.new(
367
+ proc { |way| @ec_app.img_obj_mark(impl_obj, way) },
368
+ [arg=PGuiObj::Argument.new(PGuiObj::Enum, @@markings_enum,nil,
369
+ way=(cfg.mark || ExtractCurvesApp::MARK_WAYS.length),
370
+ 'marking')],'mark', nil,OpenStruct.new('no_res'=>true,
371
+ 'no_show_title'=>true)))
372
+ arg.pguiobj_value_changed_flag.add_observer(
373
+ EcImgObjMarkArgObserver.new(@ec_app, meth, path))
374
+ obj.extract_curves_mark = ExtractCurvesApp::MARK_WAYS.length
375
+ obj.pguiobj_post_destroy_flag.add_observer(
376
+ EcObjDeathObserver.new(@ec_app))
377
+ EcImgObjChangeObserver.observe(impl_obj, @ec_app).
378
+ update(impl_obj, [])
379
+ meth.call
380
+ # Save method:
381
+ meth = impl_obj.pguiobj_add_method(PGuiObj::PMethod.new(
382
+ proc { PPix::ImageObject.save_objs(@ec_app.pixbuf.
383
+ picture_width, @ec_app.pixbuf.picture_height, [obj]) },
384
+ [], 'save', nil, OpenStruct.new('no_res'=>true,
385
+ 'icon'=>Gtk::Stock::SAVE)))
386
+ if obj.kind_of?(PGuiObj::ObjCollection) ||
387
+ obj.class <= PGuiObj::MObjCollection
388
+ impl_obj.pguiobj_each_key_value { |k, vlu|
389
+ self.procs_obj(vlu.pguiobj_guiobj, vlu,
390
+ path+'/'+k.to_s)
391
+ }
392
+ end
393
+ #$PDbgLog.sig_return
394
+ end
395
+
396
+ def update(obj, meth, res, impl_res)
397
+ #$PDbgLog.sig_call(self)
398
+ #$PDbgLog.puts_msg "#{meth.pguiobj_name}: meth obj. path: #{
399
+ # obj.extract_curves_path}"
400
+ #$PDbgLog.puts_msg "meth: #{meth}; obj: #{impl_res}(#{res})"
401
+ if res
402
+ path = res.extract_curves_path = obj.extract_curves_path +
403
+ '/' + meth.pguiobj_name
404
+ #$PDbgLog.puts_msg "path=#{path.inspect}"
405
+ self.procs_obj(res, impl_res, path)
406
+ end
407
+ #$PDbgLog.sig_return
408
+ end
409
+ end
410
+
411
+ class ExtractCurvesApp
412
+ attr_reader :ec_path_cfg, :ec_mark_add_pixels, :pixbuf,
413
+ :extract_curves_path, :objs_ttips, :arg_set_auto, :in_progr,
414
+ :pguiobj_name
415
+
416
+ ImgObjMethInfo = Struct.new('ExtractCurvesApp_ImgObjMethInfo',
417
+ :mark, :arg_deflts)
418
+
419
+ def initialize
420
+ @job = nil
421
+ @in_progr = Mutex.new
422
+ @pixbuf = nil
423
+ @pixbuf_backing = @pixbuf_highlighted = @pixbuf_blinking = nil
424
+ @pixbuf_highlighted_objs = ObjIdSet.new
425
+ @pixbuf_blinking_objs = ObjIdSet.new
426
+ @pixbuf_traced_objs = ObjIdSetWithArr.new
427
+ @pixbuf_traced_obj_i = @pixbuf_traced_pix_i = 0
428
+ @blink_area = @blink_area_rect = nil
429
+ @drw_area_in_procs = false
430
+ @arg_set_auto = false
431
+ @ec_path_cfg = {'/detect blob' => ImgObjMethInfo.new(1, []),
432
+ '/load blob ...'=>ImgObjMethInfo.new(1, [])}
433
+ @mark_meths=MARK_WAYS.collect{|w| self.method('impl_obj_'+w)} <<
434
+ proc {|*args|}
435
+ @unmark_meths=MARK_WAYS.collect{|w|self.method('impl_obj_un'+w)
436
+ } << proc {|*args|}
437
+ @ec_mark_add_pixels = MARK_WAYS.collect { |w| self.method(
438
+ 'pixels_'+w) } << proc {|*args|}
439
+ @extract_curves_path = ''
440
+ @pguiobj_name = 'EcApp'
441
+ super(Gtk::Window::TOPLEVEL)
442
+ self.set_title("Extract Curves")
443
+ begin
444
+ icon = Gdk::Pixbuf.new(PGtk.find_icon_file(
445
+ 'pav/icons/extract_curves/extract_curves-icon-rgb.ppm').to_s)
446
+ self.set_icon(icon)
447
+ rescue IOError, Gdk::PixbufError
448
+ warn self.class.name + ".initialize: Error: Failed to load " +
449
+ "icon:\n" + $!.class.name + ": #{$!}\n\tfrom " +
450
+ $!.backtrace.join("\n\tfrom ")
451
+ end
452
+ @trace_mark = Gdk::Pixbuf.new(PGtk.find_icon_file(
453
+ 'pav/icons/extract_curves/trace_mark.xpm'))
454
+ quit_cb = proc { self.destroy; true }
455
+ signal_connect('delete_event', &quit_cb)
456
+ set_default_size(600, 600)
457
+
458
+ # Root container:
459
+ table = Gtk::Table.new(1, 4, false)
460
+ add(table)
461
+
462
+ # Menubar:
463
+ accel_group = Gtk::AccelGroup.new
464
+ add_accel_group(accel_group)
465
+ open_cb = self.method("open_cb").to_proc
466
+ load_blob_cb = self.method('load_blob_cb').to_proc
467
+ sc_mapf = proc { |impl_obj| impl_obj.pguiobj_guiobj }
468
+ save_cb = proc { |*args|
469
+ objs = @pixbuf_highlighted_objs.collect(&sc_mapf) +
470
+ @pixbuf_blinking_objs.collect(&sc_mapf) +
471
+ @pixbuf_traced_objs.collect(&sc_mapf)
472
+ return if objs.empty?
473
+ PPix::ImageObject.save_objs(@pixbuf.picture_width,
474
+ @pixbuf.picture_height, objs)
475
+ }
476
+ cancel_cb = proc { |*args| Thread.kill(@job) if @job }
477
+ #ctxt_cb = proc { |*args| self.img_pop_context_menu }
478
+ zoom_100_cb = proc { |widget, event|
479
+ win, x, y, state = @drw_area.window.pointer
480
+ width = @drw_area.allocation.width
481
+ height = @drw_area.allocation.height
482
+ if x >= 0 && x < width && y >= 0 && y < height
483
+ @scrl_win.window.cursor = Gdk::Cursor.new(
484
+ Gdk::Cursor::TARGET)
485
+ end
486
+ self.drw_area_in_procs = true
487
+ @spinbtn_x.value = 1
488
+ @spinbtn_y.value = 1
489
+ self.drw_area_in_procs = false
490
+ @scrl_win.window.cursor = nil }
491
+ zoom_fit_cb = proc { |widget, event|
492
+ if @pixbuf
493
+ win, x, y, state = @drw_area.window.pointer
494
+ width = @drw_area.allocation.width
495
+ height = @drw_area.allocation.height
496
+ if x >= 0 && x < width && y >= 0 && y < height
497
+ @scrl_win.window.cursor = Gdk::Cursor.new(
498
+ Gdk::Cursor::TARGET)
499
+ end
500
+ self.drw_area_in_procs = true
501
+ k = [Float(@scrl_win.allocation.width-10)/@pixbuf.width,
502
+ Float(@scrl_win.allocation.height-10)/@pixbuf.height].
503
+ min
504
+ @spinbtn_x.value = k
505
+ @spinbtn_y.value = k
506
+ self.drw_area_in_procs = false
507
+ @scrl_win.window.cursor = nil
508
+ end
509
+ }
510
+ zoom_in_cb = proc { |widget, event|
511
+ win, x, y, state = @drw_area.window.pointer
512
+ width = @drw_area.allocation.width
513
+ height = @drw_area.allocation.height
514
+ if x >= 0 && x < width && y >= 0 && y < height
515
+ @scrl_win.window.cursor = Gdk::Cursor.new(
516
+ Gdk::Cursor::TARGET)
517
+ end
518
+ self.drw_area_in_procs = true
519
+ @spinbtn_x.value = @kx*1.5
520
+ @spinbtn_y.value = @ky*1.5
521
+ self.drw_area_in_procs = false
522
+ @scrl_win.window.cursor = nil }
523
+ zoom_out_cb = proc { |wgt, ev|
524
+ win, x, y, state = @drw_area.window.pointer
525
+ width = @drw_area.allocation.width
526
+ height = @drw_area.allocation.height
527
+ if x >= 0 && x < width && y >= 0 && y < height
528
+ @scrl_win.window.cursor = Gdk::Cursor.new(
529
+ Gdk::Cursor::TARGET)
530
+ end
531
+ self.drw_area_in_procs = true
532
+ @spinbtn_x.value = @kx/1.5
533
+ @spinbtn_y.value = @ky/1.5
534
+ self.drw_area_in_procs = false
535
+ @scrl_win.window.cursor = nil }
536
+ unmark_all_cb = proc { |wgt, ev|
537
+ @arg_set_auto = true
538
+ self.img_mark_all(MARK_WAYS.length)
539
+ @arg_set_auto = false
540
+ }
541
+ toolbar_visibility_cb = proc { |data, wgt|
542
+ if wgt.active? then @toolbar.show else @toolbar.hide end
543
+ true
544
+ }
545
+ item_factory = Gtk::ItemFactory.new(
546
+ Gtk::ItemFactory::TYPE_MENU_BAR, '<main>', accel_group)
547
+ item_factory.create_items([
548
+ ["/_File"],
549
+ ["/File/_Open ...", "<StockItem>", "<control>O",
550
+ Gtk::Stock::OPEN, open_cb],
551
+ ["/File/_Load blob ...", "<StockItem>", "<control>L",
552
+ Gtk::Stock::OPEN, load_blob_cb],
553
+ ["/File/_Save ...", "<StockItem>", "<control>S",
554
+ Gtk::Stock::SAVE, save_cb],
555
+ ["/File/sep1", "<Separator>", nil, nil],
556
+ ["/File/_Quit", "<StockItem>", "<control>Q",
557
+ Gtk::Stock::QUIT, quit_cb],
558
+ #["/_Edit"],
559
+ #["/Edit/Cont_ext menu ...", "<Item>", "<control>E",
560
+ # nil, ctxt_cb],
561
+ ["/_View"],
562
+ ["/View/Center"],
563
+ ["/View/Center/_Selection", "<StockItem>", "c",
564
+ Gtk::Stock::FIND,
565
+ self.method('center_selection_cb').to_proc],
566
+ ["/View/Center/_Highlighted","<StockItem>","<control>H",
567
+ Gtk::Stock::FIND,self.method('center_objs_cb').to_proc,
568
+ @pixbuf_highlighted_objs],
569
+ ["/View/Center/_Blinking", "<StockItem>", "<control>B",
570
+ Gtk::Stock::FIND,self.method('center_objs_cb').to_proc,
571
+ @pixbuf_blinking_objs],
572
+ ["/View/Center/_Traced", "<StockItem>", "<control>T",
573
+ Gtk::Stock::FIND,self.method('center_objs_cb').to_proc,
574
+ @pixbuf_traced_objs],
575
+ ["/View/Zoom"],
576
+ ["/View/Zoom/_100", "<StockItem>", "equal",
577
+ Gtk::Stock::ZOOM_100, zoom_100_cb],
578
+ ["/View/Zoom/_Fit", "<StockItem>", "asterisk",
579
+ Gtk::Stock::ZOOM_FIT, zoom_fit_cb],
580
+ ["/View/Zoom/_In", "<StockItem>", "plus",
581
+ Gtk::Stock::ZOOM_IN, zoom_in_cb],
582
+ ["/View/Zoom/_Out", "<StockItem>", "minus",
583
+ Gtk::Stock::ZOOM_OUT, zoom_out_cb],
584
+ ["/View/Unmark all", "<StockItem>", "<control>0",
585
+ Gtk::Stock::CLEAR, unmark_all_cb],
586
+ ["/View/sep1", "<Separator>", nil, nil],
587
+ ["/View/_Toolbar", "<CheckItem>", nil, nil,
588
+ toolbar_visibility_cb],
589
+ ["/_Help"],
590
+ ["/Help/_About", "<StockItem>", nil, Gtk::Stock::ABOUT,
591
+ self.method("about_cb").to_proc],
592
+ ])
593
+ table.attach(item_factory.get_widget('<main>'),
594
+ # X direction # Y direction
595
+ 0, 1, 0, 1,
596
+ Gtk::EXPAND | Gtk::FILL, 0,
597
+ 0, 0)
598
+
599
+ # Toolbars:
600
+ @toolbar = PGtk::Toolbar.new
601
+ item_factory.get_widget('<main>/View/Toolbar').activate
602
+ @toolbar.append(Gtk::Stock::OPEN,
603
+ "Open image file for curve recognition (^O)", &open_cb)
604
+ @toolbar.append(Gtk::Stock::SAVE,
605
+ "Save all marked (highlighted, blinking and traced) image " +
606
+ "objects to a file (^S)",
607
+ &save_cb)
608
+ #toolbar.append(Gtk::Stock::CANCEL,
609
+ # "Cancel the last started operation (^C)", &cancel_cb)
610
+ @toolbar.append_space
611
+ @toolbar.append(Gtk::Stock::QUIT, "Quit program (^Q)", &quit_cb)
612
+ table.attach(@toolbar,
613
+ # X direction # Y direction
614
+ 0, 1, 1, 2,
615
+ Gtk::EXPAND | Gtk::FILL, 0,
616
+ 0, 0)
617
+
618
+ # Objects vbox:
619
+ table.attach(hpaned=Gtk::HPaned.new,
620
+ # X direction # Y direction
621
+ 0, 1, 2, 3,
622
+ Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL,
623
+ 0, 0)
624
+ hpaned.pack1(@scrl_win = Gtk::ScrolledWindow.new, false, true)
625
+ @scrl_win.set_policy(Gtk::POLICY_AUTOMATIC,
626
+ Gtk::POLICY_AUTOMATIC)
627
+ @scrl_win.add_with_viewport(@objs_vbox=Gtk::VBox.new(false, 0))
628
+ @scrl_win.set_size_request(200, -1)
629
+ @objs_ttips = Gtk::Tooltips.new
630
+
631
+ # Trace delay:
632
+ @trace_delay_arg = PGtk::GuiObj::Argument.create(
633
+ PGuiObj::Argument.new(Integer, OpenStruct.new('min'=>10,
634
+ 'max'=>84000), nil, 100, 'trace delay',
635
+ "Time in miliseconds spent by the tracing pixel at a given pixel position before moving to the next one when tracing an image object.",
636
+ OpenStruct.new('gtk_tooltips'=>@objs_ttips)))
637
+ @trace_delay_arg.pguiobj_value_changed_flag.add_observer(
638
+ PGuiObj::ObserverCallMeth.new(proc{
639
+ self.pix_trace_tm_out = @trace_delay_arg.value}))
640
+ @objs_vbox.pack_start(@trace_delay_arg, false, false, 0)
641
+
642
+ # Detect blob:
643
+ @detect_meth = PGuiObj::PMethod.new(self.method(:detect_blob), [
644
+ PGuiObj::Argument.new(PGuiObj::Enum,
645
+ PGuiObj::Enum.new('8', 8, '4', 4), nil, nil,
646
+ 'contour geometry'),
647
+ PGuiObj::Argument.new(PGuiObj::Bool, nil, nil, true,
648
+ 'external contours'),
649
+ PGuiObj::Argument.new(Integer, OpenStruct.new('min'=>0), nil,
650
+ 0, 'min. outer loop length',
651
+ "Drop loops from a blob's outer contour carpet of length less than this one.",
652
+ OpenStruct.new('page_step'=>100,
653
+ 'gtk_tooltips'=>@objs_ttips)),
654
+ PGuiObj::Argument.new(PPix::Blob::MkGetNeighbsProcMeth, nil,
655
+ nil, nil, 'strategy')], 'detect blob', nil,
656
+ OpenStruct.new('icon'=>Gtk::Stock::FIND))
657
+ @objs_vbox.pack_start(@detect_meth=PGtk::GuiObj::PMethod.create(
658
+ @detect_meth, self), false, false, 0)
659
+ EcImgObjMethCallObserver.observe(@detect_meth, self)
660
+ # Load blob:
661
+ @load_meth = PGuiObj::PMethod.new(proc{ @pixbuf.gui_open_blob },
662
+ [], 'load blob ...', nil, OpenStruct.new(
663
+ 'icon'=>Gtk::Stock::OPEN))
664
+ @objs_vbox.pack_start(@load_meth=PGtk::GuiObj::PMethod.create(
665
+ @load_meth, self), false, false, 0)
666
+ EcImgObjMethCallObserver.observe(@load_meth, self)
667
+
668
+ # Image display frame:
669
+ hpaned.pack2(@scrl_win = Gtk::ScrolledWindow.new, true, true)
670
+ @scrl_win.set_policy(Gtk::POLICY_AUTOMATIC,
671
+ Gtk::POLICY_AUTOMATIC)
672
+ @scrl_win.shadow_type = Gtk::SHADOW_IN
673
+ self.set_default_size(200, 200)
674
+ @drw_area = Gtk::DrawingArea.new
675
+ @scrl_win.add_with_viewport(@drw_area)
676
+ @scrl_win.set_size_request(450, 450)
677
+ img_expose_cb = self.method("img_expose_cb").to_proc
678
+ img_motion_notify_cb=self.method("img_motion_notify_cb").to_proc
679
+ img_button_press_cb = self.method("img_button_press_cb").to_proc
680
+ @drw_area.signal_connect('expose_event', &img_expose_cb)
681
+ @drw_area.signal_connect('motion_notify_event',
682
+ &img_motion_notify_cb)
683
+ @drw_area.signal_connect('button_press_event',
684
+ &img_button_press_cb)
685
+ @drw_area.events |= Gdk::Event::LEAVE_NOTIFY_MASK |
686
+ Gdk::Event::BUTTON_PRESS_MASK |
687
+ Gdk::Event::POINTER_MOTION_MASK |
688
+ Gdk::Event::POINTER_MOTION_HINT_MASK
689
+ @scrl_win.hadjustment.signal_connect('value_changed',
690
+ &img_motion_notify_cb)
691
+ @scrl_win.vadjustment.signal_connect('value_changed',
692
+ &img_motion_notify_cb)
693
+
694
+ # x, y, kx, ky, statusbar:
695
+ bottom_box = Gtk::VBox.new(false, 3)
696
+ @progr_bar = Gtk::ProgressBar.new
697
+ @progr_label = Gtk::Label.new
698
+ @progr_bar_box = Gtk::HBox.new(false, 0)
699
+ @progr_bar_box.pack_start(@progr_bar)
700
+ @progr_bar_box.pack_start(@progr_label, false, false)
701
+ bottom_box.pack_start(@progr_bar_box)
702
+ hbox = Gtk::HBox.new(false, 3)
703
+ bottom_box.pack_start(hbox)
704
+ table.attach(bottom_box,
705
+ # X direction # Y direction
706
+ 0, 1, 3, 4,
707
+ Gtk::EXPAND | Gtk::FILL, 0,
708
+ 0, 0)
709
+
710
+ label = Gtk::Label.new("x="); label.set_alignment(1, 0.5)
711
+ hbox.pack_start(label, false, false)
712
+ @label_x = Gtk::Label.new; @label_x.set_alignment(0,0.5)
713
+ hbox.pack_start(@label_x,false,false)
714
+ label = Gtk::Label.new("y="); label.set_alignment(1, 0.5)
715
+ hbox.pack_start(label, false, false)
716
+ @label_y = Gtk::Label.new; @label_y.set_alignment(0,0.5)
717
+ hbox.pack_start(@label_y, false, false)
718
+
719
+ # kx:
720
+ label = Gtk::Label.new("kx=")
721
+ label.set_alignment(1, 0.5)
722
+ hbox.pack_start(label, false, false)
723
+ adj = Gtk::Adjustment.new(1.0, 1.0e-10, 1000.0, 1.0, 5.0, 1.0)
724
+ @spinbtn_x = Gtk::SpinButton.new(adj, 0, 3)
725
+ adj.signal_connect("value_changed") { |wgt, ev|
726
+ self.kx=@spinbtn_x.value }
727
+ hbox.pack_start(@spinbtn_x, false, false)
728
+ #@scrl_win.hadjustment.step_increment =
729
+ @kx = 1
730
+
731
+ # ky:
732
+ label = Gtk::Label.new("ky=")
733
+ label.set_alignment(1, 0.5)
734
+ hbox.pack_start(label, false, false)
735
+ adj = Gtk::Adjustment.new(1.0, 1.0e-10, 1000.0, 1.0, 5.0, 1.0)
736
+ @spinbtn_y = Gtk::SpinButton.new(adj, 0, 3)
737
+ adj.signal_connect("value_changed") { |wgt, ev|
738
+ self.ky=@spinbtn_y.value }
739
+ hbox.pack_start(@spinbtn_y, false, false)
740
+ #@scrl_win.vadjustment.step_increment =
741
+ @ky = 1
742
+
743
+ # RGB/HSV:
744
+ show_clr_scheme_cb = proc { |data, wgt|
745
+ if Gtk::ItemFactory.path_from_widget(wgt).ends_with(
746
+ "RGB:")
747
+ @clr_show_scheme = "rgb"
748
+ else
749
+ @clr_show_scheme = "hsv"
750
+ end
751
+ }
752
+ optmenu = Gtk::OptionMenu.new
753
+ item_factory = Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU,
754
+ '<clr_scheme>', accel_group)
755
+ item_factory.create_items([
756
+ ["/RGB:","<Item>","<control>R",nil,show_clr_scheme_cb],
757
+ ["/HSV:","<Item>","<control>H",nil,show_clr_scheme_cb],
758
+ ])
759
+ optmenu.menu = item_factory.get_widget('<clr_scheme>')
760
+ hbox.pack_start(optmenu, false, false)
761
+ @label_clr = Gtk::Label.new
762
+ @label_clr.width_chars = 11
763
+ @label_clr.set_alignment(0, 0.5)
764
+ hbox.pack_start(@label_clr,false,false)
765
+
766
+ # Statusbar:
767
+ @statusbar = Gtk::Statusbar.new
768
+ hbox.pack_start(@statusbar, true, true)
769
+
770
+ # Timeout:
771
+ @prev_traced_x = @prev_traced_y = 0
772
+ @pix_trace_proc = proc {
773
+ tx = @prev_traced_x*@kx; ty = @prev_traced_y*@ky
774
+ if @kx >= @trace_mark.width
775
+ tw = @kx.ceil
776
+ else
777
+ tw = @trace_mark.width
778
+ tx = tx + @kx/2.0 - tw/2.0
779
+ end
780
+ if @ky >= @trace_mark.height
781
+ th = @ky.ceil
782
+ else
783
+ th = @trace_mark.height
784
+ ty = ty + @ky/2.0 - th/2.0
785
+ end
786
+ @drw_area.window.invalidate(Gdk::Rectangle.new(tx, ty,
787
+ tw+1, th+1), false)
788
+ if (obj = @pixbuf_traced_objs[@pixbuf_traced_obj_i])
789
+ if (@pixbuf_traced_pix_i+=1) >= obj.length
790
+ if (@pixbuf_traced_obj_i += 1) >=
791
+ @pixbuf_traced_objs.length
792
+ @pixbuf_traced_obj_i = 0
793
+ end
794
+ @pixbuf_traced_pix_i = 0
795
+ end
796
+ else
797
+ @pixbuf_traced_obj_i = 0
798
+ @pixbuf_traced_pix_i = 0
799
+ end
800
+ if (obj = @pixbuf_traced_objs[@pixbuf_traced_obj_i]) &&
801
+ (obj=obj.pguiobj_guiobj) &&
802
+ (pix=obj[@pixbuf_traced_pix_i])
803
+ @prev_traced_x = pix.x + @pixbuf.border_width
804
+ @prev_traced_y = pix.y + @pixbuf.border_width
805
+ tx = @prev_traced_x*@kx; ty = @prev_traced_y*@ky
806
+ if @kx >= @trace_mark.width
807
+ tw = @kx.ceil
808
+ else
809
+ tw = @trace_mark.width
810
+ tx = tx + @kx/2.0 - tw/2.0
811
+ end
812
+ if @ky >= @trace_mark.height
813
+ th = @ky.ceil
814
+ else
815
+ th = @trace_mark.height
816
+ ty = ty + @ky/2.0 - th/2.0
817
+ end
818
+ @drw_area.window.invalidate(Gdk::Rectangle.new(
819
+ tx, ty, tw+1, th+1), false)
820
+ end
821
+ true
822
+ }
823
+ self.add_timeouts
824
+
825
+ signal_connect('destroy'){ self.remove_timeouts; Gtk.main_quit }
826
+
827
+ self.show_all
828
+ Gtk.main_iteration
829
+ @progr_bar_box.remove(@progr_label)
830
+ @progr_bar_box.remove(@progr_bar)
831
+ Gtk.main_iteration
832
+ if $VERBOSE || $DEBUG
833
+ tee_to = $stdout
834
+ else
835
+ tee_to = nil
836
+ end
837
+ #$PDbgLog.outp = StatusbarIO.new($PDbgLog, @statusbar, tee_to)
838
+ $PDbgLog.progr_class = ECLogProgrBar
839
+ $PDbgLog.progr_init_args = [@progr_bar, @progr_label,
840
+ @progr_bar_box]
841
+ end
842
+
843
+ def add_timeouts
844
+ #$PDbgLog.sig_call(self)
845
+ #$PDbgLog.puts_msg caller(1).join("\t\n")
846
+ unless @blink_timeout_id
847
+ t = Gdk::Screen.default.get_setting("gtk-cursor-blink-time")
848
+ @blink_timeout_id = Gtk.timeout_add(t ? t.to_i : 1000) {
849
+ #return true if @job && @job.alive?
850
+ if @pixbuf_blinking
851
+ if @pixbuf_backing.equal?(@pixbuf_blinking)
852
+ @pixbuf_backing = @pixbuf_highlighted
853
+ else
854
+ @pixbuf_backing = @pixbuf_blinking
855
+ end
856
+ @drw_area.window.invalidate(@blink_area_rect,
857
+ false) if @blink_area_rect
858
+ end
859
+ true
860
+ }
861
+ end
862
+ unless @pix_trace_timeout_id
863
+ @pix_trace_timeout_id = Gtk.timeout_add(@trace_delay_arg.value,
864
+ &@pix_trace_proc)
865
+ end
866
+ #$PDbgLog.sig_return("Done.")
867
+ end
868
+
869
+ def remove_timeouts
870
+ #$PDbgLog.sig_call(self)
871
+ #$PDbgLog.puts_msg caller(1).join("\t\n")
872
+ if @blink_timeout_id
873
+ Gtk.timeout_remove(@blink_timeout_id)
874
+ @blink_timeout_id = nil
875
+ end
876
+ if @pix_trace_timeout_id
877
+ Gtk.timeout_remove(@pix_trace_timeout_id)
878
+ @pix_trace_timeout_id = nil
879
+ end
880
+ #$PDbgLog.sig_return("Done.")
881
+ end
882
+
883
+ def drw_area_in_procs=(val)
884
+ if val
885
+ return if @drw_area_in_procs
886
+ @drw_area_in_procs = true
887
+ @scrl_win.freeze_child_notify
888
+ else
889
+ return unless @drw_area_in_procs
890
+ @drw_area_in_procs = false
891
+ @scrl_win.thaw_child_notify
892
+ @drw_area.queue_draw
893
+ end
894
+ end
895
+
896
+ def pixbuf=(val)
897
+ @pixbuf_backing = @pixbuf_highlighted = @pixbuf_blinking = nil
898
+ @pixbuf = val
899
+ if @pixbuf.bits_per_sample != 8
900
+ raise NotImplementError,
901
+ "pixbuf with #{@pixbuf.bits_per_sample} bits/sample"
902
+ end
903
+ if @pixbuf.n_channels == 3
904
+ @pixbuf_drw_meth = Gdk::RGB.method("draw_rgb_image")
905
+ elsif @pixbuf.n_channels == 4
906
+ @pixbuf_drw_meth = Gdk::RGB.method("draw_rgb_32_image")
907
+ else
908
+ raise NotImplementError,
909
+ "pixbuf with #{@pixbuf.n_channels} channels"
910
+ end
911
+ @pixbuf = @pixbuf.add_border(1)
912
+ @pixbuf_blinking = nil
913
+ @pixbuf_backing = @pixbuf_highlighted = @pixbuf.dup
914
+ @blob = nil
915
+ @blink_area_rect = nil
916
+ @pixbuf_highlighted_objs.clear
917
+ @pixbuf_blinking_objs.clear
918
+ @pixbuf_traced_objs.clear
919
+ @drw_area.set_size_request(@pixbuf.width*@kx,@pixbuf.height*@ky)
920
+ @scrl_win.queue_draw
921
+ @label_x.width_chars = @pixbuf.width.to_s.length
922
+ @label_y.width_chars = @pixbuf.height.to_s.length
923
+ @detect_meth.pguiobj_clear_children
924
+ @load_meth.pguiobj_clear_children
925
+ end
926
+
927
+ def kx=(val)
928
+ return if val == @kx
929
+ #@scrl_win.hadjustment.step_increment =
930
+ dx = val - @kx
931
+ @kx = val
932
+ return unless @pixbuf
933
+ if @blink_area
934
+ @blink_area_rect = Gdk::Rectangle.new(
935
+ (@blink_area.x + @pixbuf.border_width)*@kx,
936
+ (@blink_area.y + @pixbuf.border_width)*@ky,
937
+ (@blink_area.width*@kx).ceil + 1,
938
+ (@blink_area.height*@ky).ceil + 1)
939
+ end
940
+ win, x, y, state = *@drw_area.window.pointer
941
+ @drw_area.set_size_request(@pixbuf.width*@kx,@pixbuf.height*@ky)
942
+ viewport = @scrl_win.children[0]
943
+ win, vx, vy, state = viewport.window.pointer
944
+ width = viewport.allocation.width
945
+ height = viewport.allocation.height
946
+ if @drw_area.allocation.width > width
947
+ if vx >= 0 && vx < width && vy >= 0 && vy < height
948
+ viewport.hadjustment.value += x*dx / (@kx-dx)
949
+ else
950
+ k_x = viewport.hadjustment.value + width/2
951
+ viewport.hadjustment.value += k_x*dx / (@kx-dx)
952
+ end
953
+ end
954
+ @scrl_win.queue_draw
955
+ end
956
+
957
+ def ky=(val)
958
+ return if val == @ky
959
+ #@scrl_win.vadjustment.step_increment =
960
+ dy = val - @ky
961
+ @ky = val
962
+ return unless @pixbuf
963
+ if @blink_area
964
+ @blink_area_rect = Gdk::Rectangle.new(
965
+ (@blink_area.x + @pixbuf.border_width)*@kx,
966
+ (@blink_area.y + @pixbuf.border_width)*@ky,
967
+ (@blink_area.width*@kx).ceil + 1,
968
+ (@blink_area.height*@ky).ceil + 1)
969
+ end
970
+ win, x, y, state = *@drw_area.window.pointer
971
+ @drw_area.set_size_request(@pixbuf.width*@kx,@pixbuf.height*@ky)
972
+ viewport = @scrl_win.children[0]
973
+ win, vx, vy, state = viewport.window.pointer
974
+ width = viewport.allocation.width
975
+ height = viewport.allocation.height
976
+ if @drw_area.allocation.height > height
977
+ if vx >= 0 && vx < width && vy >= 0 && vy < height
978
+ viewport.vadjustment.value += y*dy / (@ky-dy)
979
+ else
980
+ k_y = viewport.vadjustment.value + height/2
981
+ viewport.vadjustment.value += k_y*dy / (@ky-dy)
982
+ end
983
+ end
984
+ @scrl_win.queue_draw
985
+ end
986
+
987
+ def pix_trace_tm_out=(val)
988
+ return if val == @pix_trace_tm_out
989
+ @pix_trace_tm_out = val
990
+ if @pix_trace_timeout_id
991
+ Gtk.timeout_remove(@pix_trace_timeout_id)
992
+ @pix_trace_timeout_id = Gtk.timeout_add(
993
+ @pix_trace_tm_out, &@pix_trace_proc)
994
+ end
995
+ end
996
+
997
+ def center_selection_cb(*args)
998
+ min_x = min_y = 1.0/0.0
999
+ max_x = max_y = 0
1000
+ pr = proc { |obj|
1001
+ min_x = obj.img_obj_min_ax.floor if
1002
+ obj.img_obj_min_ax.floor < min_x
1003
+ max_x = obj.img_obj_max_ax.ceil if
1004
+ obj.img_obj_max_ax.ceil > max_x
1005
+ min_y = obj.img_obj_min_ay.floor if
1006
+ obj.img_obj_min_ay.floor < min_y
1007
+ max_y = obj.img_obj_max_ay.ceil if
1008
+ obj.img_obj_max_ay.ceil > max_y
1009
+ }
1010
+ @pixbuf_highlighted_objs.each(&pr)
1011
+ @pixbuf_blinking_objs.each(&pr)
1012
+ @pixbuf_traced_objs.each(&pr)
1013
+ c_x = (min_x + max_x) * @kx / 2
1014
+ c_y = (min_y + max_y) * @ky / 2
1015
+ alloc = @scrl_win.children[0].allocation
1016
+ tmp = c_x - alloc.width/2
1017
+ @scrl_win.hadjustment.value = tmp > 0 ? tmp : 0
1018
+ tmp = c_y - alloc.height/2
1019
+ @scrl_win.vadjustment.value = tmp > 0 ? tmp : 0
1020
+ end
1021
+
1022
+ def center_objs_cb(objs, widget)
1023
+ min_x = min_y = 1.0/0.0
1024
+ max_x = max_y = 0
1025
+ objs.each { |obj|
1026
+ min_x = obj.img_obj_min_ax.floor if
1027
+ obj.img_obj_min_ax.floor < min_x
1028
+ max_x = obj.img_obj_max_ax.ceil if
1029
+ obj.img_obj_max_ax.ceil > max_x
1030
+ min_y = obj.img_obj_min_ay.floor if
1031
+ obj.img_obj_min_ay.floor < min_y
1032
+ max_y = obj.img_obj_max_ay.ceil if
1033
+ obj.img_obj_max_ay.ceil > max_y
1034
+ }
1035
+ c_x = (min_x + max_x) * @kx / 2
1036
+ c_y = (min_y + max_y) * @ky / 2
1037
+ alloc = @scrl_win.children[0].allocation
1038
+ tmp = c_x - alloc.width/2
1039
+ @scrl_win.hadjustment.value = tmp > 0 ? tmp : 0
1040
+ tmp = c_y - alloc.height/2
1041
+ @scrl_win.vadjustment.value = tmp > 0 ? tmp : 0
1042
+ end
1043
+
1044
+ def open_imagef(fpath)
1045
+ begin
1046
+ self.pixbuf = PPix::Pixbuf.new(fpath)
1047
+ dir, name = *File.split(fpath)
1048
+ self.title = "#{name} #{@pixbuf.picture_width}x#{
1049
+ @pixbuf.picture_height} (#{dir}) -- Extract Curves"
1050
+ rescue IOError, Gdk::PixbufError
1051
+ PGtk.show_exc_dialog
1052
+ end
1053
+ end
1054
+
1055
+ def load_blob_cb(*args)
1056
+ @load_meth.call
1057
+ end
1058
+
1059
+ def open_cb(*args)
1060
+ return false unless @in_progr.try_lock
1061
+ dialog = Gtk::FileChooserDialog.new(
1062
+ "Open raster image file for curve extraction", nil,
1063
+ Gtk::FileChooser::ACTION_OPEN, "gnome-vfs",
1064
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT],
1065
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL])
1066
+
1067
+ # Preview:
1068
+ preview_w = preview_h = 150
1069
+ dialog.set_preview_widget(preview_img=Gtk::Image.new)
1070
+ dialog.signal_connect('update-preview') { |wgt, data|
1071
+ begin
1072
+ if fpath = wgt.preview_filename
1073
+ preview_img.pixbuf=Gdk::Pixbuf.new(fpath, preview_w,
1074
+ preview_h)
1075
+ dialog.preview_widget_active = true
1076
+ else
1077
+ dialog.preview_widget_active = false
1078
+ end
1079
+ rescue Gdk::PixbufError, GLib::FileError
1080
+ dialog.preview_widget_active = false
1081
+ end
1082
+ }
1083
+
1084
+ # Filters:
1085
+ filter_any = Gtk::FileFilter.new
1086
+ filter_any.name = "Recognized Images"
1087
+ filter_any.add_pixbuf_formats
1088
+ dialog.add_filter(filter_any)
1089
+ filter = Gtk::FileFilter.new; filter.name = "All files"
1090
+ filter.add_pattern("*")
1091
+ dialog.add_filter(filter)
1092
+ PPix::Pixbuf.formats.each { |fmt| filter = Gtk::FileFilter.new
1093
+ filter.name = "#{fmt.description} (.#{fmt.name})"
1094
+ filter.add_pattern("*.#{fmt.name}")
1095
+ if fmt.name == 'jpeg'
1096
+ filter.add_pattern('*.jpg')
1097
+ end
1098
+ dialog.add_filter(filter)
1099
+ }
1100
+
1101
+ dialog.add_shortcut_folder("/tmp") if File.directory?("/tmp")
1102
+ fpath = nil
1103
+ resp = dialog.run
1104
+ fpath = dialog.filename
1105
+ dialog.destroy
1106
+ i = -1
1107
+ Gtk.main_iteration_do(false) while (i += 1) < 10 &&
1108
+ Gtk.events_pending?
1109
+ if resp != Gtk::Dialog::RESPONSE_ACCEPT || !fpath
1110
+ @in_progr.unlock
1111
+ return
1112
+ end
1113
+ begin
1114
+ self.open_imagef(fpath)
1115
+ ensure
1116
+ @in_progr.unlock
1117
+ end
1118
+ end
1119
+
1120
+ def arr_del_obj(arr, which)
1121
+ #$PDbgLog.sig_call(self)
1122
+ obj_i = nil
1123
+ arr.each_with_index { |obj, idx|
1124
+ #$PDbgLog.print_msg " obj#{idx}:%x" % obj.object_id
1125
+ if obj.equal?(which)
1126
+ obj_i = idx
1127
+ break
1128
+ end
1129
+ }
1130
+ if obj_i
1131
+ #$PDbgLog.print_msg "; obj_i=#{obj_i}"
1132
+ arr[obj_i,1] = nil
1133
+ else
1134
+ warn "#{self.class.name}.arr_del_obj: Image object "+
1135
+ "to remove not found!"
1136
+ end
1137
+ #$PDbgLog.sig_return
1138
+ end
1139
+
1140
+ def xy_toggle_buf(buf, x, y, pix_done, rowstride, pix_length)
1141
+ unless pix_done[k=[y, x]]
1142
+ s = @pixbuf.ofs0 + y*rowstride + x*pix_length
1143
+ s.upto(s + pix_length - 1) { |i|
1144
+ buf[i] ^= 0xff
1145
+ }
1146
+ pix_done[k] = true
1147
+ end
1148
+ end
1149
+
1150
+ def xy_toggle_2bufs(buf1, buf2, x, y, pix_done, rowstride, pix_length)
1151
+ unless pix_done[k=[y, x]]
1152
+ s = @pixbuf.ofs0 + y*rowstride + x*pix_length
1153
+ s.upto(s + pix_length - 1) { |i|
1154
+ buf1[i] ^= 0xff
1155
+ buf2[i] ^= 0xff
1156
+ }
1157
+ pix_done[k] = true
1158
+ end
1159
+ end
1160
+
1161
+ def pixels_highlight_toggle(which)
1162
+ #$PDbgLog.sig_call(self)
1163
+ #$PDbgLog.puts_msg("#{which.length} pixel#{
1164
+ # which.length==1? "" : "s"}")
1165
+ pix_done = {}
1166
+ rowstride = @pixbuf.rowstride; pix_length = @pixbuf.pix_length
1167
+ highl_pix = @pixbuf_highlighted.pixels
1168
+ if @pixbuf_blinking
1169
+ blinking_pix = @pixbuf_blinking.pixels
1170
+ which.each { |pt| ax, ay = pt.ax, pt.ay
1171
+ x1 = ax.floor; y1 = ay.floor
1172
+ x2 = ax.ceil; y2 = ay.ceil
1173
+ self.xy_toggle_2bufs(highl_pix, blinking_pix,
1174
+ x1, y1, pix_done, rowstride, pix_length)
1175
+ if x1 != x2
1176
+ if y1 != y2
1177
+ self.xy_toggle_2bufs(highl_pix,
1178
+ blinking_pix, x2, y1, pix_done,
1179
+ rowstride, pix_length)
1180
+ self.xy_toggle_2bufs(highl_pix,
1181
+ blinking_pix, x1, y2, pix_done,
1182
+ rowstride, pix_length)
1183
+ self.xy_toggle_2bufs(highl_pix,
1184
+ blinking_pix, x2, y2, pix_done,
1185
+ rowstride, pix_length)
1186
+ else
1187
+ self.xy_toggle_2bufs(highl_pix,
1188
+ blinking_pix, x2, y1, pix_done,
1189
+ rowstride, pix_length)
1190
+ end
1191
+ elsif y1 != y2
1192
+ self.xy_toggle_2bufs(highl_pix,
1193
+ blinking_pix, x1, y2, pix_done,
1194
+ rowstride, pix_length)
1195
+ end
1196
+ }
1197
+ else
1198
+ which.each { |pt| ax, ay = pt.ax, pt.ay
1199
+ x1 = ax.floor; y1 = ay.floor
1200
+ x2 = ax.ceil; y2 = ay.ceil
1201
+ self.xy_toggle_buf(highl_pix, x1, y1, pix_done,
1202
+ rowstride, pix_length)
1203
+ if x1 != x2
1204
+ if y1 != y2
1205
+ self.xy_toggle_buf(highl_pix, x2, y1,
1206
+ pix_done, rowstride, pix_length)
1207
+ self.xy_toggle_buf(highl_pix, x1, y2,
1208
+ pix_done, rowstride, pix_length)
1209
+ self.xy_toggle_buf(highl_pix, x2, y2,
1210
+ pix_done, rowstride, pix_length)
1211
+ else
1212
+ self.xy_toggle_buf(highl_pix, x2, y1,
1213
+ pix_done, rowstride, pix_length)
1214
+ end
1215
+ elsif y1 != y2
1216
+ self.xy_toggle_buf(highl_pix, x1, y2,
1217
+ pix_done, rowstride, pix_length)
1218
+ end
1219
+ }
1220
+ end
1221
+ @drw_area.window.invalidate(Gdk::Rectangle.new(
1222
+ ((which.img_obj_min_ax.floor+@pixbuf.border_width)*@kx).floor,
1223
+ ((which.img_obj_min_ay.floor+@pixbuf.border_width)*@ky).floor,
1224
+ ((which.img_obj_max_ax.ceil+1-which.img_obj_min_x)*@kx).ceil+1,
1225
+ ((which.img_obj_max_ay.ceil+1-which.img_obj_min_y)*@ky).ceil+1
1226
+ ), false)
1227
+ #$PDbgLog.sig_return
1228
+ end
1229
+
1230
+ def pixels_blink_toggle(which)
1231
+ unless @pixbuf_blinking
1232
+ @pixbuf_blinking = @pixbuf_highlighted.dup
1233
+ end
1234
+ pix_done = {}
1235
+ rowstride = @pixbuf.rowstride; pix_length = @pixbuf.pix_length
1236
+ blinking_pix = @pixbuf_blinking.pixels
1237
+ which.each { |pt| ax, ay = pt.ax, pt.ay
1238
+ x1 = ax.floor; y1 = ay.floor
1239
+ x2 = ax.ceil; y2 = ay.ceil
1240
+ self.xy_toggle_buf(blinking_pix, x1, y1, pix_done,
1241
+ rowstride, pix_length)
1242
+ if x1 != x2
1243
+ if y1 != y2
1244
+ self.xy_toggle_buf(blinking_pix, x2, y1,
1245
+ pix_done, rowstride, pix_length)
1246
+ self.xy_toggle_buf(blinking_pix, x1, y2,
1247
+ pix_done, rowstride, pix_length)
1248
+ self.xy_toggle_buf(blinking_pix, x2, y2,
1249
+ pix_done, rowstride, pix_length)
1250
+ else
1251
+ self.xy_toggle_buf(blinking_pix, x2, y1,
1252
+ pix_done, rowstride, pix_length)
1253
+ end
1254
+ elsif y1 != y2
1255
+ self.xy_toggle_buf(blinking_pix, x1, y2,
1256
+ pix_done, rowstride, pix_length)
1257
+ end
1258
+ }
1259
+ @drw_area.window.invalidate(Gdk::Rectangle.new(
1260
+ (which.img_obj_min_ax.floor+@pixbuf.border_width)*@kx,
1261
+ (which.img_obj_min_ay.floor+@pixbuf.border_width)*@ky,
1262
+ 1+((which.img_obj_max_ax.ceil+1-which.img_obj_min_x)*@kx).ceil,
1263
+ 1+((which.img_obj_max_ay.ceil+1-which.img_obj_min_y)*@ky).ceil),
1264
+ false)
1265
+ end
1266
+
1267
+ alias_method :pixels_highlight, :pixels_highlight_toggle
1268
+
1269
+ def impl_obj_highlight(impl_obj)
1270
+ self.pixels_highlight(impl_obj.pguiobj_guiobj)
1271
+ @pixbuf_highlighted_objs.push(impl_obj)
1272
+ end
1273
+
1274
+ def impl_obj_unhighlight(impl_obj)
1275
+ self.pixels_highlight_toggle(impl_obj.pguiobj_guiobj)
1276
+ @pixbuf_highlighted_objs.pop_obj(impl_obj)
1277
+ end
1278
+
1279
+ def pixels_blink(which)
1280
+ self.pixels_blink_toggle(which)
1281
+ return if which.empty?
1282
+ @blink_area = Gdk::Rectangle.new(
1283
+ which.first.x, which.first.y, 0, 0) unless @blink_area
1284
+ end_x = [@blink_area.x + @blink_area.width-1,
1285
+ which.img_obj_max_ax.ceil].max
1286
+ end_y = [@blink_area.y + @blink_area.height-1,
1287
+ which.img_obj_max_ay.ceil].max
1288
+ @blink_area.x = [@blink_area.x, which.img_obj_min_ax.floor].min
1289
+ @blink_area.y = [@blink_area.y, which.img_obj_min_ay.floor].min
1290
+ @blink_area.width = end_x - @blink_area.x + 1
1291
+ @blink_area.height = end_y - @blink_area.y + 1
1292
+ if @blink_area_rect
1293
+ @blink_area_rect.x =
1294
+ (@blink_area.x + @pixbuf.border_width)*@kx
1295
+ @blink_area_rect.width = (@blink_area.width*@kx).ceil+1
1296
+ @blink_area_rect.y =
1297
+ (@blink_area.y + @pixbuf.border_width)*@ky
1298
+ @blink_area_rect.height =(@blink_area.height*@ky).ceil+1
1299
+ else
1300
+ @blink_area_rect = Gdk::Rectangle.new(
1301
+ (@blink_area.x + @pixbuf.border_width)*@kx,
1302
+ (@blink_area.y + @pixbuf.border_width)*@ky,
1303
+ (@blink_area.width*@kx).ceil + 1,
1304
+ (@blink_area.height*@ky).ceil + 1)
1305
+ end
1306
+ end
1307
+
1308
+ def impl_obj_blink(impl_obj)
1309
+ self.pixels_blink(impl_obj.pguiobj_guiobj)
1310
+ @pixbuf_blinking_objs.push(impl_obj)
1311
+ end
1312
+
1313
+ def impl_obj_unblink(impl_obj)
1314
+ which = impl_obj.pguiobj_guiobj
1315
+ self.pixels_blink_toggle(which) if @pixbuf_blinking
1316
+ @pixbuf_blinking_objs.pop_obj(impl_obj)
1317
+ return if which.empty?
1318
+ end_x = @blink_area.x + @blink_area.width - 1
1319
+ end_y = @blink_area.y + @blink_area.height - 1
1320
+ if which.img_obj_max_ax.ceil >= end_x ||
1321
+ which.img_obj_min_ax.floor <= @blink_area.x ||
1322
+ which.img_obj_max_ay.ceil >= end_y ||
1323
+ which.img_obj_min_ay.floor <= @blink_area.y
1324
+ if @pixbuf_blinking_objs.empty?
1325
+ @blink_area = nil
1326
+ @blink_area_rect = nil
1327
+ else
1328
+ end_x=@blink_area.x=@pixbuf_blinking_objs.first.first.x
1329
+ end_y=@blink_area.y=@pixbuf_blinking_objs.first.first.y
1330
+ @pixbuf_blinking_objs.each { |obj|
1331
+ @blink_area.x = [@blink_area.x,
1332
+ obj.img_obj_min_ax.floor].min
1333
+ end_x = [end_x, obj.img_obj_max_ax.ceil].max
1334
+ @blink_area.y = [@blink_area.y,
1335
+ obj.img_obj_min_ay.floor].min
1336
+ end_y = [end_y, obj.img_obj_max_ay.ceil].max
1337
+ }
1338
+ @blink_area.width = end_x - @blink_area.x + 1
1339
+ @blink_area.height = end_y - @blink_area.y + 1
1340
+ @blink_area_rect.x =
1341
+ (@blink_area.x + @pixbuf.border_width)*@kx
1342
+ @blink_area_rect.width = (@blink_area.width*@kx).ceil+1
1343
+ @blink_area_rect.y =
1344
+ (@blink_area.y + @pixbuf.border_width)*@ky
1345
+ @blink_area_rect.height =(@blink_area.height*@ky).ceil+1
1346
+ end
1347
+ end
1348
+ end
1349
+
1350
+ def pixels_trace(which)
1351
+ end
1352
+
1353
+ def impl_obj_trace(impl_obj)
1354
+ @pixbuf_traced_objs.push(impl_obj)
1355
+ end
1356
+
1357
+ def impl_obj_untrace(impl_obj)
1358
+ @pixbuf_traced_objs.pop_obj(impl_obj)
1359
+ end
1360
+
1361
+ def img_obj_mark(impl_obj, way)
1362
+ #$PDbgLog.sig_call(self)
1363
+ #$PDbgLog.puts_msg "impl_obj: #{impl_obj}, way=#{way.inspect}"
1364
+ obj = impl_obj.pguiobj_guiobj
1365
+ if obj.extract_curves_mark != way
1366
+ if obj.kind_of?(PGuiObj::ObjCollection) ||
1367
+ obj.class <= PGuiObj::MObjCollection
1368
+ impl_obj.pguiobj_each_value { |val|
1369
+ @unmark_meths[obj.extract_curves_mark].call(val)
1370
+ @mark_meths[way].call(val)
1371
+ }
1372
+ else
1373
+ @unmark_meths[obj.extract_curves_mark].call(impl_obj)
1374
+ @mark_meths[way].call(impl_obj)
1375
+ end
1376
+ obj.extract_curves_mark = way
1377
+ end
1378
+ #$PDbgLog.sig_return
1379
+ end
1380
+
1381
+ def img_obj_delete(impl_obj)
1382
+ #$PDbgLog.sig_call(self)
1383
+ #$PDbgLog.puts_msg "obj: #{obj.to_s}"
1384
+ self.img_obj_mark(impl_obj, MARK_WAYS.length)
1385
+ impl_obj.pguiobj_each_method { |meth| meth.pguiobj_each_child {
1386
+ |child| self.img_obj_delete(child) }}
1387
+ obj = impl_obj.pguiobj_guiobj
1388
+ if obj.kind_of?(PGuiObj::ObjCollection) ||
1389
+ obj.kind_of?(PGuiObj::MObjCollection)
1390
+ impl_obj.pguiobj_each_value{|m| self.img_obj_delete(m) }
1391
+ end
1392
+ #$PDbgLog.sig_return
1393
+ end
1394
+
1395
+ def img_mark_all(way)
1396
+ #$PDbgLog.sig_call(self)
1397
+ while !@pixbuf_highlighted_objs.empty?
1398
+ # $PDbgLog.puts_msg "unhighlight "+@pixbuf_highlighted_objs.
1399
+ # first.inspect
1400
+ self.img_obj_mark(
1401
+ impl_obj=@pixbuf_highlighted_objs.first, way)
1402
+ impl_obj.pguiobj_each_method { |meth|
1403
+ if meth.pguiobj_name == 'mark'
1404
+ meth.pguiobj_impl_args[0].set way
1405
+ break
1406
+ end
1407
+ }
1408
+ end
1409
+ while !@pixbuf_blinking_objs.empty?
1410
+ #$PDbgLog.puts_msg "unblink " +
1411
+ # @pixbuf_blinking_objs.first.inspect
1412
+ self.img_obj_mark(
1413
+ impl_obj = @pixbuf_blinking_objs.first, way)
1414
+ impl_obj.pguiobj_each_method { |meth|
1415
+ if meth.pguiobj_name == 'mark'
1416
+ meth.pguiobj_impl_args[0].set way
1417
+ break
1418
+ end
1419
+ }
1420
+ end
1421
+ while !@pixbuf_traced_objs.empty?
1422
+ # $PDbgLog.puts_msg "untrace "+@pixbuf_traced_objs.first.inspect
1423
+ self.img_obj_mark(
1424
+ impl_obj=@pixbuf_traced_objs.first, way)
1425
+ impl_obj.pguiobj_each_method { |meth|
1426
+ if meth.pguiobj_name == 'mark'
1427
+ meth.pguiobj_impl_args[0].set way
1428
+ break
1429
+ end
1430
+ }
1431
+ end
1432
+ #$PDbgLog.sig_call(self)
1433
+ end
1434
+
1435
+ def img_motion_notify_cb(*args)
1436
+ win, x, y, state = *@drw_area.window.pointer
1437
+ x = (x/@kx).to_i; y = (y/@ky).to_i
1438
+ if !@pixbuf || x < 0 || x >= @pixbuf.width || y < 0 ||
1439
+ y >= @pixbuf.height
1440
+ @label_x.text = " "
1441
+ @label_y.text = " "
1442
+ return
1443
+ end
1444
+ @label_x.text = "%-3d" % (rx=x - @pixbuf.border_width)
1445
+ @label_y.text = "%-3d" % (ry=y - @pixbuf.border_width)
1446
+ if rx >= 0 && rx < @pixbuf.picture_width &&
1447
+ ry >= 0 && ry < @pixbuf.picture_height
1448
+ rgb = *@pixbuf.get_pix(rx, ry).color_rgb
1449
+ if @clr_show_scheme == "rgb"
1450
+ clr_text = "%3d,%3d,%3d" % rgb
1451
+ else
1452
+ h, s, v = *@pixbuf.get_pix(rx,ry).color_hsv
1453
+ clr_text = "%3.0f,%3.0f,%3.0f" %
1454
+ [360.0*h, 100.0*s, 100.0*v]
1455
+ end
1456
+ bg = "\#%02x%02x%02x" % rgb
1457
+ fg = "\#%02x%02x%02x" % [rgb[0] > 127 ? 0 : 255,
1458
+ rgb[1] > 127 ? 0 : 255, rgb[2] > 127 ? 0 : 255]
1459
+ @label_clr.set_markup("<span foreground=\"#{fg
1460
+ }\" background=\"#{bg}\">#{clr_text}</span>")
1461
+ end
1462
+ true
1463
+ end
1464
+
1465
+ def img_expose_cb(drw_area, event)
1466
+ #$PDbgLog.sig_call(self)
1467
+ #$PDbgLog.print_msg "area: #{event.area.x}, #{event.area.y}, #{
1468
+ # event.area.width}, #{event.area.height}: "
1469
+ if !@pixbuf || !@pixbuf_backing || !@pixbuf_drw_meth ||
1470
+ (x0=event.area.x/@kx) >= @pixbuf.width ||
1471
+ (y0=event.area.y/@ky) >= @pixbuf.height || @drw_area_in_procs
1472
+ #$PDbgLog.sig_return(@drw_area_in_procs)
1473
+ return @drw_area_in_procs
1474
+ end
1475
+ #$PDbgLog.puts_msg "pb_pix_cnt=#{@pixbuf.width*@pixbuf.height}"
1476
+ pb = @pixbuf_backing
1477
+ pb_pix = pb.pixels
1478
+ end_x = (event.area.x + event.area.width-1)/@kx
1479
+ end_y = (event.area.y + event.area.height-1)/@ky
1480
+ end_x = @pixbuf.width-1 if end_x >= @pixbuf.width
1481
+ end_y = @pixbuf.height-1 if end_y >= @pixbuf.height
1482
+ rowstride = @pixbuf.rowstride; pix_length = @pixbuf.pix_length
1483
+ ofs = ofs0 = y0 * rowstride + x0 * pix_length
1484
+ end_ofs = end_y * rowstride + end_x * pix_length
1485
+ width = end_x-x0 + 1; width_stride = width * pix_length
1486
+ height = end_y-y0 + 1
1487
+ t_width_stride = width_stride - pix_length
1488
+ #sub_x0 = @kx - event.area.x % @kx
1489
+ #sub_y0 = @ky - event.area.y % @ky
1490
+ view_width = (width*@kx).ceil + 1
1491
+ view_height = (height*@ky).ceil + 1
1492
+ start_x = event.area.x; start_y = event.area.y
1493
+ #$PDbgLog.print_msg "x0=#{x0}, y0=#{y0}, sub_x0=#{sub_x0
1494
+ # }, sub_y0=#{sub_y0}, end_x=#{end_x}, end_y=#{end_y
1495
+ # }, rowstride=#{rowstride}, pix_length=#{pix_length} "
1496
+ if (trc_obj = @pixbuf_traced_objs[@pixbuf_traced_obj_i]) &&
1497
+ (trc_obj = trc_obj.pguiobj_guiobj) &&
1498
+ (trc_pix = trc_obj[@pixbuf_traced_pix_i]) && (trc_pix_ofs =
1499
+ @pixbuf.ofs0+rowstride*trc_pix.y+pix_length*trc_pix.x)>=ofs0 &&
1500
+ trc_pix_ofs <= end_ofs
1501
+ trc_pix_ofs.upto(trc_pix_ofs+pix_length-1) { |tmp_ofs|
1502
+ pb_pix[tmp_ofs] ^= 0xff
1503
+ }
1504
+ tw = @trace_mark.width
1505
+ tx = tx0 = (@kx*(trc_pix.x+@pixbuf.border_width+0.5) -
1506
+ tw/2 - start_x).to_i
1507
+ if tx < 0
1508
+ tw += tx
1509
+ tx = 0
1510
+ end
1511
+ e_x = view_width
1512
+ tw = e_x - tx if tx + tw >= e_x
1513
+ th = @trace_mark.height
1514
+ ty = ty0 = (@ky*(trc_pix.y+@pixbuf.border_width+0.5) -
1515
+ th/2 - start_y).to_i
1516
+ if ty < 0
1517
+ th += ty
1518
+ ty = 0
1519
+ end
1520
+ e_y = view_height
1521
+ th = e_y - ty if ty + th > e_y
1522
+ else
1523
+ trc_pix = nil
1524
+ end
1525
+ sc_pb = pb.gdk_scaled(@kx, @ky, start_x, start_y,
1526
+ view_width, view_height, @kx < 1 || @ky < 1 ?
1527
+ Gdk::Pixbuf::INTERP_BILINEAR : Gdk::Pixbuf::INTERP_NEAREST);
1528
+ if trc_pix
1529
+ sc_pb.composite!(@trace_mark,tx,ty, tw,th, tx0,ty0, 1,1,
1530
+ Gdk::Pixbuf::INTERP_NEAREST, 255)
1531
+ trc_pix_ofs.upto(trc_pix_ofs+pix_length-1) { |tmp_ofs|
1532
+ pb_pix[tmp_ofs] ^= 0xff
1533
+ }
1534
+ end
1535
+ #@pixbuf_drw_meth.call(drw_area.window,drw_area.style.black_gc,
1536
+ # event.area.x, event.area.y,
1537
+ # (width-1)*@kx + sub_x0,(height-1)*@ky + sub_y0,
1538
+ # Gdk::RGB::Dither::NORMAL, pixels, rowstride,
1539
+ # (width-1)*@kx + sub_x0, (height-1)*@ky + sub_y0)
1540
+ #@pixbuf_drw_meth.call(drw_area.window,drw_area.style.black_gc,
1541
+ # event.area.x, event.area.y,
1542
+ # event.area.width, event.area.height,
1543
+ # Gdk::RGB::Dither::NORMAL, pixels, rowstride,
1544
+ # event.area.width, event.area.height)
1545
+ @pixbuf_drw_meth.call(drw_area.window,drw_area.style.black_gc,
1546
+ start_x, start_y, view_width, view_height,
1547
+ Gdk::RGB::Dither::NORMAL, sc_pb.pixels, sc_pb.rowstride,
1548
+ view_width, view_height)
1549
+ #$PDbgLog.sig_return
1550
+ true
1551
+ end
1552
+
1553
+ def detect_blob(ctr_geom, external_ctrs, min_out_lp_len, get_ngbs_proc)
1554
+ #$PDbgLog.sig_call(self)
1555
+ #$PDbgLog.puts_msg "@pixbuf: #{@pixbuf}"
1556
+ unless @pixbuf.blob_id_at?(@x, @y, 0)
1557
+ #$PDbgLog.sig_return
1558
+ return nil
1559
+ end
1560
+ #$PDbgLog.puts_msg "(#{@x}, #{@y})"
1561
+ res = @pixbuf.get_pix(@x, @y).blob(ctr_geom, external_ctrs,
1562
+ min_out_lp_len, &get_ngbs_proc)
1563
+ #$PDbgLog.sig_return
1564
+ res
1565
+ end
1566
+
1567
+ def img_get_objs_at(drw_arr, event)
1568
+ return false unless @pixbuf
1569
+ ## Pop the motion event and allow the registering of the next:
1570
+ #win, x, y, state = event.window.pointer
1571
+ x, y = event.x.to_i, event.y.to_i
1572
+ x = (x/@kx).to_i - @pixbuf.border_width
1573
+ y = (y/@ky).to_i - @pixbuf.border_width
1574
+ return true if x < 0 || x >= @pixbuf.picture_width ||
1575
+ y < 0 || y >= @pixbuf.picture_height ||
1576
+ (@blob && @pixbuf.blob_id_at?(x, y, @blob.blob_id))
1577
+ @x = x
1578
+ @y = y
1579
+ @detect_meth.call
1580
+ true
1581
+ end
1582
+
1583
+ def img_pop_context_menu
1584
+ menu = nil
1585
+ #@job = Thread.new(Thread.current) {
1586
+ # Thread.stop
1587
+ # $PDbgLog.sig_call(self)
1588
+ #menu = self.img_get_context_menu
1589
+ # $PDbgLog.sig_return("OK")
1590
+ #}
1591
+ #@job.run
1592
+ #Thread.pass while @job.alive?
1593
+ return unless menu
1594
+ $PDbgLog.sig_call(self)
1595
+ #$PDbgLog.puts_msg "#{(menu.methods.sort - Object.methods).
1596
+ # join("\n")}"
1597
+ menu.visible = true
1598
+ menu.activate
1599
+ menu.parent.modal = true
1600
+ menu.parent.window_position = Gtk::Window::POS_MOUSE
1601
+ menu.parent.show_all
1602
+ menu.grab_focus
1603
+
1604
+ while menu.visible?
1605
+ Gtk.main_iteration
1606
+ end
1607
+ #menu.destroy
1608
+ @scrl_win.queue_draw
1609
+ $PDbgLog.sig_return("Done.")
1610
+ end
1611
+
1612
+ def img_button_press_cb(drw_area, event)
1613
+ #$PDbgLog.sig_call(self)
1614
+ case event.button
1615
+ when 1 then self.img_get_objs_at(drw_area, event)
1616
+ when 3 then self.img_pop_context_menu
1617
+ end
1618
+ #$PDbgLog.sig_return(true)
1619
+ return true
1620
+ end
1621
+
1622
+ def about_cb(*args)
1623
+ authors = ["Pavel Penev (author) <pavpen@berkeley.edu>"]
1624
+ documentors = []
1625
+ license = %Q[
1626
+ This program is free software; you can redistribute it and/or
1627
+ modify it under the terms of the GNU General Public License as
1628
+ published by the Free Software Foundation; either version 2 of the
1629
+ License, or (at your option) any later version.
1630
+
1631
+ This program is distributed in the hope that it will be useful,
1632
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1633
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1634
+ General Public License for more details.
1635
+
1636
+ You should have received a copy of the GNU General Public
1637
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
1638
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1639
+ Boston, MA 02111-1307, USA.
1640
+ ]
1641
+ transparent = Gdk::Pixbuf.new(PGtk.find_icon_file(
1642
+ "pav/icons/extract_curves/extract_curves-logo-rgb.gif"))
1643
+ #.add_alpha(true, 0xff, 0xff, 0xff)
1644
+
1645
+ Gtk::AboutDialog.set_email_hook {|about, link|
1646
+ puts "send mail to #{link}"
1647
+ }
1648
+ Gtk::AboutDialog.set_url_hook {|about, link|
1649
+ puts "show url #{link}"
1650
+ }
1651
+ Gtk::AboutDialog.show(self,
1652
+ :name => "Extract Curves",
1653
+ :version => VERSION.join(".") + VERSION_SUFFIX,
1654
+ :copyright => "(C) 2005 Pavel Minev Penev",
1655
+ :license => license,
1656
+ :website => "http://extract-curves.rubyforge.org",
1657
+ :comments => "Program to identify the specific " +
1658
+ "characteristics of a motion which produced a "+
1659
+ "geometric curve.",
1660
+ :authors => authors,
1661
+ #:documenters => documentors,
1662
+ :logo => transparent)
1663
+ end
1664
+ end
1665
+
1666
+ #PApp.new(ExtractCurvesApp).run
1667
+ app_win = ExtractCurvesApp.new
1668
+ app_win.show_all
1669
+ app_win.open_imagef(ARGV[0]) if ARGV[0]
1670
+ Gtk.main