extract-curves 0.1.1-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/Changelog +21 -0
  2. data/bin/ec_rect2polar +22 -0
  3. data/bin/ec_rect2polar.rb +22 -0
  4. data/bin/ec_rev_lines +5 -0
  5. data/bin/ec_rev_lines.rb +5 -0
  6. data/bin/ec_sph_area +30 -0
  7. data/bin/ec_sph_area.rb +30 -0
  8. data/bin/extract_curves +1670 -0
  9. data/bin/extract_curves.rb +1670 -0
  10. data/ruby_ext/pav/extconf.rb +22 -0
  11. data/ruby_ext/pav/pav.dll +0 -0
  12. data/ruby_libs/pav/attr_cache.rb +211 -0
  13. data/ruby_libs/pav/attr_cache.t1.rb +32 -0
  14. data/ruby_libs/pav/cache.rb +31 -0
  15. data/ruby_libs/pav/collection/std.rb +58 -0
  16. data/ruby_libs/pav/dbg_log.rb +458 -0
  17. data/ruby_libs/pav/floatsio.rb +53 -0
  18. data/ruby_libs/pav/generator_cache.rb +165 -0
  19. data/ruby_libs/pav/graph/node.rb +602 -0
  20. data/ruby_libs/pav/graph/node_grp.rb +865 -0
  21. data/ruby_libs/pav/gtk.rb +6 -0
  22. data/ruby_libs/pav/gtk/button.rb +118 -0
  23. data/ruby_libs/pav/gtk/dialog.rb +29 -0
  24. data/ruby_libs/pav/gtk/guiobj.rb +772 -0
  25. data/ruby_libs/pav/gtk/icons.rb +124 -0
  26. data/ruby_libs/pav/gtk/rulers.rb +264 -0
  27. data/ruby_libs/pav/gtk/toolbar.rb +189 -0
  28. data/ruby_libs/pav/guiobj.rb +2 -0
  29. data/ruby_libs/pav/guiobj/info_asm.rb +41 -0
  30. data/ruby_libs/pav/guiobj/method.rb +211 -0
  31. data/ruby_libs/pav/guiobj/obj.rb +134 -0
  32. data/ruby_libs/pav/guiobj/signals.rb +9 -0
  33. data/ruby_libs/pav/heap.rb +54 -0
  34. data/ruby_libs/pav/icons/alt_handle.xpm +3832 -0
  35. data/ruby_libs/pav/icons/alt_handle_hover.xpm +3368 -0
  36. data/ruby_libs/pav/icons/alt_handle_pressed.xpm +3828 -0
  37. data/ruby_libs/pav/icons/blob.gif +0 -0
  38. data/ruby_libs/pav/icons/contour.gif +0 -0
  39. data/ruby_libs/pav/icons/contour_carpet.gif +0 -0
  40. data/ruby_libs/pav/icons/curve.gif +0 -0
  41. data/ruby_libs/pav/icons/curve_carpet.gif +0 -0
  42. data/ruby_libs/pav/icons/expand_closed.xpm +1791 -0
  43. data/ruby_libs/pav/icons/expand_closed_hover.xpm +1775 -0
  44. data/ruby_libs/pav/icons/expand_open.xpm +1788 -0
  45. data/ruby_libs/pav/icons/expand_open_hover.xpm +1752 -0
  46. data/ruby_libs/pav/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
  47. data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
  48. data/ruby_libs/pav/icons/extract_curves/trace_mark.xpm +38 -0
  49. data/ruby_libs/pav/icons/handle.xpm +213 -0
  50. data/ruby_libs/pav/icons/loop.gif +0 -0
  51. data/ruby_libs/pav/icons/loop_carpet.gif +0 -0
  52. data/ruby_libs/pav/icons/next.xpm +29 -0
  53. data/ruby_libs/pav/icons/next_hover.xpm +315 -0
  54. data/ruby_libs/pav/icons/next_pressed.xpm +144 -0
  55. data/ruby_libs/pav/icons/prev.xpm +29 -0
  56. data/ruby_libs/pav/icons/prev_hover.xpm +315 -0
  57. data/ruby_libs/pav/icons/prev_pressed.xpm +144 -0
  58. data/ruby_libs/pav/icons/shaved-core.gif +0 -0
  59. data/ruby_libs/pav/icons/vnext.xpm +29 -0
  60. data/ruby_libs/pav/icons/vprev.xpm +29 -0
  61. data/ruby_libs/pav/numeric/ext.rb +21 -0
  62. data/ruby_libs/pav/patterns/hsep.gif +0 -0
  63. data/ruby_libs/pav/patterns/tnode.gif +0 -0
  64. data/ruby_libs/pav/patterns/tnode_w_link.gif +0 -0
  65. data/ruby_libs/pav/patterns/vlink.gif +0 -0
  66. data/ruby_libs/pav/patterns/vsep.gif +0 -0
  67. data/ruby_libs/pav/patterns/yg_hrope.xpm +492 -0
  68. data/ruby_libs/pav/patterns/yg_hrope_thick.xpm +1904 -0
  69. data/ruby_libs/pav/patterns/yg_hrope_thin.xpm +130 -0
  70. data/ruby_libs/pav/patterns/yg_tnode.xpm +180 -0
  71. data/ruby_libs/pav/patterns/yg_tnode_thick.xpm +615 -0
  72. data/ruby_libs/pav/patterns/yg_tnode_thin.xpm +55 -0
  73. data/ruby_libs/pav/patterns/yg_tnode_w_link.xpm +190 -0
  74. data/ruby_libs/pav/patterns/yg_tnode_w_link_thick.xpm +676 -0
  75. data/ruby_libs/pav/patterns/yg_tnode_w_link_thin.xpm +62 -0
  76. data/ruby_libs/pav/patterns/yg_vrope.xpm +563 -0
  77. data/ruby_libs/pav/patterns/yg_vrope_thick.xpm +2047 -0
  78. data/ruby_libs/pav/patterns/yg_vrope_thin.xpm +166 -0
  79. data/ruby_libs/pav/pav_find.rb +90 -0
  80. data/ruby_libs/pav/pix.rb +402 -0
  81. data/ruby_libs/pav/pix/aapix.rb +378 -0
  82. data/ruby_libs/pav/pix/blob.rb +678 -0
  83. data/ruby_libs/pav/pix/circle.rb +73 -0
  84. data/ruby_libs/pav/pix/contour.rb +676 -0
  85. data/ruby_libs/pav/pix/contour/calc_situations.rb +9 -0
  86. data/ruby_libs/pav/pix/contour/carp_calc.rb +212 -0
  87. data/ruby_libs/pav/pix/contour/situations.dmp +0 -0
  88. data/ruby_libs/pav/pix/contour/situations.rb +21 -0
  89. data/ruby_libs/pav/pix/curve.rb +1544 -0
  90. data/ruby_libs/pav/pix/img_obj.rb +865 -0
  91. data/ruby_libs/pav/pix/node.rb +159 -0
  92. data/ruby_libs/pav/pix/shaved_core.rb +697 -0
  93. data/ruby_libs/pav/pix/subpix.rb +212 -0
  94. data/ruby_libs/pav/rand_accessible.rb +16 -0
  95. data/ruby_libs/pav/rangeset.rb +63 -0
  96. data/ruby_libs/pav/search.rb +210 -0
  97. data/ruby_libs/pav/set.rb +130 -0
  98. data/ruby_libs/pav/string/bits.rb +523 -0
  99. data/ruby_libs/pav/string/ext.rb +58 -0
  100. data/ruby_libs/pav/string/observable.rb +155 -0
  101. data/ruby_libs/pav/string/text.rb +79 -0
  102. data/ruby_libs/pav/string/words.rb +42 -0
  103. data/ruby_libs/pav/sub_arr.rb +56 -0
  104. data/ruby_libs/pav/traced_obj.rb +79 -0
  105. data/web/index.html +280 -0
  106. data/web/media/icons/alt_handle.xpm +3832 -0
  107. data/web/media/icons/alt_handle_hover.xpm +3368 -0
  108. data/web/media/icons/alt_handle_pressed.xpm +3828 -0
  109. data/web/media/icons/blob.gif +0 -0
  110. data/web/media/icons/contour.gif +0 -0
  111. data/web/media/icons/contour_carpet.gif +0 -0
  112. data/web/media/icons/curve.gif +0 -0
  113. data/web/media/icons/curve_carpet.gif +0 -0
  114. data/web/media/icons/expand_closed.xpm +1791 -0
  115. data/web/media/icons/expand_closed_hover.xpm +1775 -0
  116. data/web/media/icons/expand_open.xpm +1788 -0
  117. data/web/media/icons/expand_open_hover.xpm +1752 -0
  118. data/web/media/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
  119. data/web/media/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
  120. data/web/media/icons/extract_curves/trace_mark.xpm +38 -0
  121. data/web/media/icons/handle.xpm +213 -0
  122. data/web/media/icons/loop.gif +0 -0
  123. data/web/media/icons/loop_carpet.gif +0 -0
  124. data/web/media/icons/next.xpm +29 -0
  125. data/web/media/icons/next_hover.xpm +315 -0
  126. data/web/media/icons/next_pressed.xpm +144 -0
  127. data/web/media/icons/prev.xpm +29 -0
  128. data/web/media/icons/prev_hover.xpm +315 -0
  129. data/web/media/icons/prev_pressed.xpm +144 -0
  130. data/web/media/icons/shaved-core.gif +0 -0
  131. data/web/media/icons/vnext.xpm +29 -0
  132. data/web/media/icons/vprev.xpm +29 -0
  133. data/web/media/title.jpeg +0 -0
  134. data/web/stylesheets/default.css +20 -0
  135. metadata +192 -0
@@ -0,0 +1,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