extract-curves 0.1.1

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 (172) 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/cstr.c +82 -0
  11. data/ruby_ext/pav/cstr.h +17 -0
  12. data/ruby_ext/pav/extconf.rb +22 -0
  13. data/ruby_ext/pav/pav.c +162 -0
  14. data/ruby_ext/pav/pgtk.c +40 -0
  15. data/ruby_ext/pav/pgtk.h +14 -0
  16. data/ruby_ext/pav/pix.c +806 -0
  17. data/ruby_ext/pav/pix.h +236 -0
  18. data/ruby_ext/pav/t.rb +35 -0
  19. data/ruby_ext/pav/t1.rb +35 -0
  20. data/ruby_libs/pav/attr_cache.rb +211 -0
  21. data/ruby_libs/pav/attr_cache.t1.rb +32 -0
  22. data/ruby_libs/pav/cache.rb +31 -0
  23. data/ruby_libs/pav/collection/std.rb +58 -0
  24. data/ruby_libs/pav/dbg_log.rb +458 -0
  25. data/ruby_libs/pav/floatsio.rb +53 -0
  26. data/ruby_libs/pav/generator_cache.rb +165 -0
  27. data/ruby_libs/pav/graph/node.rb +602 -0
  28. data/ruby_libs/pav/graph/node_grp.rb +865 -0
  29. data/ruby_libs/pav/gtk.rb +6 -0
  30. data/ruby_libs/pav/gtk/button.rb +118 -0
  31. data/ruby_libs/pav/gtk/dialog.rb +29 -0
  32. data/ruby_libs/pav/gtk/guiobj.rb +772 -0
  33. data/ruby_libs/pav/gtk/icons.rb +124 -0
  34. data/ruby_libs/pav/gtk/rulers.rb +264 -0
  35. data/ruby_libs/pav/gtk/toolbar.rb +189 -0
  36. data/ruby_libs/pav/guiobj.rb +2 -0
  37. data/ruby_libs/pav/guiobj/info_asm.rb +41 -0
  38. data/ruby_libs/pav/guiobj/method.rb +211 -0
  39. data/ruby_libs/pav/guiobj/obj.rb +134 -0
  40. data/ruby_libs/pav/guiobj/signals.rb +9 -0
  41. data/ruby_libs/pav/heap.rb +54 -0
  42. data/ruby_libs/pav/icons/alt_handle.xcf +0 -0
  43. data/ruby_libs/pav/icons/alt_handle.xpm +3832 -0
  44. data/ruby_libs/pav/icons/alt_handle_hover.xcf +0 -0
  45. data/ruby_libs/pav/icons/alt_handle_hover.xpm +3368 -0
  46. data/ruby_libs/pav/icons/alt_handle_pressed.xcf +0 -0
  47. data/ruby_libs/pav/icons/alt_handle_pressed.xpm +3828 -0
  48. data/ruby_libs/pav/icons/blob.gif +0 -0
  49. data/ruby_libs/pav/icons/clover_base.xcf +0 -0
  50. data/ruby_libs/pav/icons/contour.gif +0 -0
  51. data/ruby_libs/pav/icons/contour.xcf +0 -0
  52. data/ruby_libs/pav/icons/contour_carpet.gif +0 -0
  53. data/ruby_libs/pav/icons/contour_carpet.xcf +0 -0
  54. data/ruby_libs/pav/icons/curve.gif +0 -0
  55. data/ruby_libs/pav/icons/curve.xcf +0 -0
  56. data/ruby_libs/pav/icons/curve_carpet.gif +0 -0
  57. data/ruby_libs/pav/icons/curve_carpet.xcf +0 -0
  58. data/ruby_libs/pav/icons/expand_base.xcf +0 -0
  59. data/ruby_libs/pav/icons/expand_closed.xpm +1791 -0
  60. data/ruby_libs/pav/icons/expand_closed_hover.xpm +1775 -0
  61. data/ruby_libs/pav/icons/expand_open.xpm +1788 -0
  62. data/ruby_libs/pav/icons/expand_open_hover.xpm +1752 -0
  63. data/ruby_libs/pav/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
  64. data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
  65. data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.xcf +0 -0
  66. data/ruby_libs/pav/icons/extract_curves/trace_mark.xcf +0 -0
  67. data/ruby_libs/pav/icons/extract_curves/trace_mark.xpm +38 -0
  68. data/ruby_libs/pav/icons/handle.xcf +0 -0
  69. data/ruby_libs/pav/icons/handle.xpm +213 -0
  70. data/ruby_libs/pav/icons/loop.gif +0 -0
  71. data/ruby_libs/pav/icons/loop.xcf +0 -0
  72. data/ruby_libs/pav/icons/loop_carpet.gif +0 -0
  73. data/ruby_libs/pav/icons/loop_carpet.xcf +0 -0
  74. data/ruby_libs/pav/icons/next.xpm +29 -0
  75. data/ruby_libs/pav/icons/next_hover.xpm +315 -0
  76. data/ruby_libs/pav/icons/next_pressed.xpm +144 -0
  77. data/ruby_libs/pav/icons/prev.xpm +29 -0
  78. data/ruby_libs/pav/icons/prev_hover.xpm +315 -0
  79. data/ruby_libs/pav/icons/prev_pressed.xpm +144 -0
  80. data/ruby_libs/pav/icons/shaved-core.gif +0 -0
  81. data/ruby_libs/pav/icons/vnext.xpm +29 -0
  82. data/ruby_libs/pav/icons/vprev.xpm +29 -0
  83. data/ruby_libs/pav/numeric/ext.rb +21 -0
  84. data/ruby_libs/pav/patterns/hsep.gif +0 -0
  85. data/ruby_libs/pav/patterns/tnode.gif +0 -0
  86. data/ruby_libs/pav/patterns/tnode_w_link.gif +0 -0
  87. data/ruby_libs/pav/patterns/vlink.gif +0 -0
  88. data/ruby_libs/pav/patterns/vsep.gif +0 -0
  89. data/ruby_libs/pav/patterns/yg_hrope.xpm +492 -0
  90. data/ruby_libs/pav/patterns/yg_hrope_thick.xpm +1904 -0
  91. data/ruby_libs/pav/patterns/yg_hrope_thin.xpm +130 -0
  92. data/ruby_libs/pav/patterns/yg_tnode.xpm +180 -0
  93. data/ruby_libs/pav/patterns/yg_tnode_thick.xpm +615 -0
  94. data/ruby_libs/pav/patterns/yg_tnode_thin.xpm +55 -0
  95. data/ruby_libs/pav/patterns/yg_tnode_w_link.xpm +190 -0
  96. data/ruby_libs/pav/patterns/yg_tnode_w_link_thick.xpm +676 -0
  97. data/ruby_libs/pav/patterns/yg_tnode_w_link_thin.xpm +62 -0
  98. data/ruby_libs/pav/patterns/yg_vrope.xpm +563 -0
  99. data/ruby_libs/pav/patterns/yg_vrope_thick.xpm +2047 -0
  100. data/ruby_libs/pav/patterns/yg_vrope_thin.xpm +166 -0
  101. data/ruby_libs/pav/pav_find.rb +90 -0
  102. data/ruby_libs/pav/pix.rb +402 -0
  103. data/ruby_libs/pav/pix/aapix.rb +378 -0
  104. data/ruby_libs/pav/pix/blob.rb +678 -0
  105. data/ruby_libs/pav/pix/circle.rb +73 -0
  106. data/ruby_libs/pav/pix/contour.rb +676 -0
  107. data/ruby_libs/pav/pix/contour/calc_situations.rb +9 -0
  108. data/ruby_libs/pav/pix/contour/carp_calc.rb +212 -0
  109. data/ruby_libs/pav/pix/contour/situations.dmp +0 -0
  110. data/ruby_libs/pav/pix/contour/situations.rb +21 -0
  111. data/ruby_libs/pav/pix/curve.rb +1544 -0
  112. data/ruby_libs/pav/pix/img_obj.rb +865 -0
  113. data/ruby_libs/pav/pix/node.rb +159 -0
  114. data/ruby_libs/pav/pix/shaved_core.rb +697 -0
  115. data/ruby_libs/pav/pix/subpix.rb +212 -0
  116. data/ruby_libs/pav/rand_accessible.rb +16 -0
  117. data/ruby_libs/pav/rangeset.rb +63 -0
  118. data/ruby_libs/pav/search.rb +210 -0
  119. data/ruby_libs/pav/set.rb +130 -0
  120. data/ruby_libs/pav/string/bits.rb +523 -0
  121. data/ruby_libs/pav/string/ext.rb +58 -0
  122. data/ruby_libs/pav/string/observable.rb +155 -0
  123. data/ruby_libs/pav/string/text.rb +79 -0
  124. data/ruby_libs/pav/string/words.rb +42 -0
  125. data/ruby_libs/pav/sub_arr.rb +56 -0
  126. data/ruby_libs/pav/traced_obj.rb +79 -0
  127. data/web/index.html +280 -0
  128. data/web/media/icons/alt_handle.xcf +0 -0
  129. data/web/media/icons/alt_handle.xpm +3832 -0
  130. data/web/media/icons/alt_handle_hover.xcf +0 -0
  131. data/web/media/icons/alt_handle_hover.xpm +3368 -0
  132. data/web/media/icons/alt_handle_pressed.xcf +0 -0
  133. data/web/media/icons/alt_handle_pressed.xpm +3828 -0
  134. data/web/media/icons/blob.gif +0 -0
  135. data/web/media/icons/clover_base.xcf +0 -0
  136. data/web/media/icons/contour.gif +0 -0
  137. data/web/media/icons/contour.xcf +0 -0
  138. data/web/media/icons/contour_carpet.gif +0 -0
  139. data/web/media/icons/contour_carpet.xcf +0 -0
  140. data/web/media/icons/curve.gif +0 -0
  141. data/web/media/icons/curve.xcf +0 -0
  142. data/web/media/icons/curve_carpet.gif +0 -0
  143. data/web/media/icons/curve_carpet.xcf +0 -0
  144. data/web/media/icons/expand_base.xcf +0 -0
  145. data/web/media/icons/expand_closed.xpm +1791 -0
  146. data/web/media/icons/expand_closed_hover.xpm +1775 -0
  147. data/web/media/icons/expand_open.xpm +1788 -0
  148. data/web/media/icons/expand_open_hover.xpm +1752 -0
  149. data/web/media/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
  150. data/web/media/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
  151. data/web/media/icons/extract_curves/extract_curves-logo-rgb.xcf +0 -0
  152. data/web/media/icons/extract_curves/trace_mark.xcf +0 -0
  153. data/web/media/icons/extract_curves/trace_mark.xpm +38 -0
  154. data/web/media/icons/handle.xcf +0 -0
  155. data/web/media/icons/handle.xpm +213 -0
  156. data/web/media/icons/loop.gif +0 -0
  157. data/web/media/icons/loop.xcf +0 -0
  158. data/web/media/icons/loop_carpet.gif +0 -0
  159. data/web/media/icons/loop_carpet.xcf +0 -0
  160. data/web/media/icons/next.xpm +29 -0
  161. data/web/media/icons/next_hover.xpm +315 -0
  162. data/web/media/icons/next_pressed.xpm +144 -0
  163. data/web/media/icons/prev.xpm +29 -0
  164. data/web/media/icons/prev_hover.xpm +315 -0
  165. data/web/media/icons/prev_pressed.xpm +144 -0
  166. data/web/media/icons/shaved-core.gif +0 -0
  167. data/web/media/icons/vnext.xpm +29 -0
  168. data/web/media/icons/vprev.xpm +29 -0
  169. data/web/media/title.jpeg +0 -0
  170. data/web/media/title.xcf +0 -0
  171. data/web/stylesheets/default.css +20 -0
  172. metadata +229 -0
@@ -0,0 +1,159 @@
1
+ require 'pav/pix'
2
+ require 'pav/heap'
3
+ require 'pav/pix/aapix'
4
+ require 'pav/graph/node'
5
+ require 'pav/graph/node_grp'
6
+
7
+ module PPix
8
+
9
+ include PGraph
10
+
11
+ class PGraph::NodeLink
12
+ def expand_to_xy_path
13
+ self.node.conns[self.conn_k].path.expand_to_xy_path
14
+ end
15
+ end
16
+
17
+ class PGraph::NodePath
18
+ def expand_to_xy_path
19
+ return [] if self.empty?
20
+ res = self.first.expand_to_xy_path
21
+ 1.upto(self.length-1) { |i|
22
+ res.concat(self.at(i).expand_to_xy_path) }
23
+ res
24
+ end
25
+ end
26
+
27
+ class XyPath < Array
28
+ def self.yx_path_to_s(path)
29
+ path.collect { |yx| "(#{yx[1]}, #{yx[0]})" }.join(" ")
30
+ end
31
+
32
+ def get_length
33
+ self.length - 1
34
+ end
35
+
36
+ alias_method :entry, :first
37
+ alias_method :exit, :last
38
+
39
+ def to_s
40
+ self.collect { |pix| pix.to_s }.join(" ")
41
+ end
42
+
43
+ def eql?(path2)
44
+ #$PDbgLog.sig_call(self.name + "#")
45
+ #$PDbgLog.puts_msg "path1: #{path1}; path2: #{path2}"
46
+ if self.length != path2.length
47
+ # $PDbgLog.sig_return
48
+ return false
49
+ end
50
+ self.each_with_index { |pix, i|
51
+ return false if pix.y != path2[i].y ||
52
+ pix.x != path2[i].x
53
+ }
54
+ #$PDbgLog.sig_return
55
+ true
56
+ end
57
+
58
+ def starts_with(pfx_path)
59
+ return false unless self.length >= pfx_path.length
60
+ pfx_path.each_with_index { |pix, i|
61
+ return false if pix.yx != self.at(i).yx }
62
+ true
63
+ end
64
+
65
+ def ends_with(sfx_path)
66
+ return false unless (ofs = self.length - sfx_path.length) >= 0
67
+ 0.upto(sfx_path.length-1) { |i|
68
+ return false if sfx_path.at(i).yx != self.at(ofs+i).yx }
69
+ true
70
+ end
71
+
72
+ def a_eql?(path2)
73
+ #$PDbgLog.sig_call(self.name + "#")
74
+ #$PDbgLog.puts_msg "self: #{self}; path2: #{path2}"
75
+ if self.length != path2.length
76
+ # $PDbgLog.sig_return
77
+ return false
78
+ end
79
+ self.each_with_index { |pix, i|
80
+ return false if !pix.a_eql?(path2.at(i)) }
81
+ #$PDbgLog.sig_return
82
+ true
83
+ end
84
+
85
+ def node_eql?(path2)
86
+ #$PDbgLog.sig_call(self.name + "#")
87
+ #$PDbgLog.puts_msg "self: #{self}; path2: #{path2}"
88
+ if self.length != path2.length
89
+ # $PDbgLog.sig_return
90
+ return false
91
+ end
92
+ self.each_with_index { |node, i|
93
+ return false if !node.a_eql?(path2.at(i)) }
94
+ #$PDbgLog.sig_return
95
+ true
96
+ end
97
+
98
+ alias_method :==, :node_eql?
99
+
100
+ def a_starts_with(pfx_path)
101
+ return false unless self.length >= spath.length
102
+ self.each_with_index { |pix, i|
103
+ return false if !pix.a_eql?(pfx_path.at(i)) }
104
+ true
105
+ end
106
+
107
+ def a_ends_with(sfx_path)
108
+ return false unless (ofs = self.length - sfx_path.length) >= 0
109
+ 0.upto(sfx_path.length-1) { |i|
110
+ return false if !sfx_path.at(i).a_eql?(self.at(ofs+i)) }
111
+ true
112
+ end
113
+
114
+ def dup
115
+ XyPath.new(self)
116
+ end
117
+
118
+ def concat(path)
119
+ super(path[1, path.length-1])
120
+ self
121
+ end
122
+
123
+ def +(path)
124
+ self.dup.concat(path[1, path.length-1])
125
+ end
126
+
127
+ alias_method :expand_to_xy_path, :dup
128
+
129
+ def xy_nodes
130
+ self[1, self.length-1]
131
+ end
132
+ end
133
+
134
+ class AaXyNode < Node
135
+ def initialize(ax_axy, ay_conns, conns=nil)
136
+ if conns
137
+ super(AaXy.new(ax_axy, ay_conns), conns)
138
+ else
139
+ super(ax_axy, ay_conns)
140
+ end
141
+ end
142
+
143
+ def to_s(how=0)
144
+ res = self.data.coords_to_s
145
+ return res if how < 1
146
+ res.concat('+conns: ')
147
+ self.conns.each_key_value { |conn_k, conn|
148
+ res.concat("[#{conn_k}]#{conn.to_s(how-1)}; ")
149
+ }
150
+ res[-2,2] = ''
151
+ res
152
+ end
153
+
154
+ def method_missing(id, *args, &block)
155
+ self.data.send(id, *args, &block)
156
+ end
157
+ end
158
+
159
+ end
@@ -0,0 +1,697 @@
1
+ require 'set'
2
+ require 'pav/pix'
3
+ require 'pav/pix/node'
4
+ require 'pav/pix/curve'
5
+ require 'pav/attr_cache'
6
+ require 'pav/pix/contour'
7
+
8
+ module PPix
9
+
10
+ class ShavedCoreCalc
11
+ attr_accessor :shaved_core, :curve, :min_branch_len, :min_lp_len_min,
12
+ :visited, :node_map
13
+
14
+ def initialize(shaved_core)
15
+ @shaved_core = shaved_core
16
+ @curve = @shaved_core.curve
17
+ @min_branch_len = @shaved_core.min_branch_len
18
+ @min_lp_len_min = @shaved_core.min_lp_len_min
19
+ @visited = {}
20
+ @use_progr = false
21
+ @dup_grps = []
22
+ @orig_grps = []
23
+ @node2gid = {}
24
+ @node_conn_depths = {}
25
+ @node_map = {}
26
+ @grps_shaven = []
27
+ end
28
+
29
+ def node_dir_max_depth(node, to_parent_conn_keys, visited={})
30
+ #$PDbgLog.sig_call(self)
31
+ #$PDbgLog.print_msg "node#{node}, to_parent_conn_keys: #{
32
+ # to_parent_conn_keys.inspect}: "
33
+ if visited.include?(node)
34
+ #$PDbgLog.sig_return(1.0/0.0)
35
+ return 1.0/0.0
36
+ end
37
+ visited[node] = true
38
+ max_depth = 0
39
+ node.conns.each_key_value { |conn_k, conn|
40
+ next if to_parent_conn_keys.include?(conn_k)
41
+ depth = self.node_conn_max_depth(node, conn_k, visited)
42
+ max_depth = depth if depth > max_depth
43
+ }
44
+ visited.delete(node)
45
+ #$PDbgLog.sig_return#("#{node}: #{max_depth}")
46
+ max_depth
47
+ end
48
+
49
+ def node_conn_max_depth(node, conn_k, visited={})
50
+ #$PDbgLog.sig_call(self)
51
+ if (conn_depths = @node_conn_depths[node])
52
+ if (tmp = conn_depths[conn_k])
53
+ #$PDbgLog.sig_return
54
+ return tmp
55
+ end
56
+ else
57
+ conn_depths = @node_conn_depths[node] = []
58
+ end
59
+ exit = (conn = node.conns[conn_k]).exit
60
+ #$PDbgLog.print_msg "node#{node}, conn[#{conn_k}]: #{conn}: "
61
+ if (nd_gid = @node2gid[node]) && nd_gid == @node2gid[exit] &&
62
+ (path = conn.path).kind_of?(PPix::NodePath) &&
63
+ (nd_grp = @orig_grps[nd_gid]).include?(path.first)
64
+ rev_conn_keys = []
65
+ exit.conns.each_key_value { |r_conn_k, r_conn|
66
+ rev_conn_keys << r_conn_k if
67
+ (r_path=r_conn.path).kind_of?(PPix::NodePath) &&
68
+ nd_grp.include?(r_path.first)
69
+ }
70
+ else
71
+ rev_conn_keys = [node.to_parent_conn_key(conn_k)]
72
+ end
73
+ res =
74
+ conn_depths[conn_k] = conn.length +
75
+ self.node_dir_max_depth(exit, rev_conn_keys, visited)
76
+ #$PDbgLog.sig_return("#{node},conn[#{conn_k}]: #{conn}: #{res}")
77
+ res
78
+ end
79
+
80
+ def min_lp_get_grp(min_lp_path)
81
+ #$PDbgLog.sig_call(self)
82
+ #$PDbgLog.print_msg "min_lp_path: #{min_lp_path}: "
83
+ res = min_lp_path.undir_to_link_grp
84
+ tail = res.nodes_to_a
85
+ while !tail.empty?
86
+ node = tail.pop
87
+ node.conns.each_key_value { |conn_k, conn|
88
+ if conn.length <= @min_lp_len_min &&
89
+ !res.include?(link = PPix::NodeLink.new(node, conn_k))
90
+ begin
91
+ excl_link = link.reverse
92
+ rescue PGraph::NoReverseLinkError
93
+ res << link
94
+ next
95
+ end
96
+ #$PDbgLog.puts_msg "link(#{link.length}): #{link.
97
+ # to_s(1)}"
98
+ node_calc = PPix::NodeCalc.new(conn.exit)
99
+ node_calc.link_filter = proc {|lk| lk != excl_link }
100
+ if (path =node_calc.find_shortest_path_to_node(node,
101
+ @min_lp_len_min - conn.length))
102
+ #$PDbgLog.puts_msg "+=(#{path.get_length}) " +
103
+ # path.to_s
104
+ res << link; res << excl_link
105
+ res.add_undir_path!(path)
106
+ path.each { |lk| tail.push(lk.node) }
107
+ end
108
+ end
109
+ }
110
+ end
111
+ #$PDbgLog.sig_return('= ' + res.to_s)
112
+ res
113
+ end
114
+
115
+ def dup_node(node)
116
+ #$PDbgLog.sig_call(self)
117
+ if (tmp = @node_map[node])
118
+ #$PDbgLog.sig_return#(tmp.to_s + ' (cached).')
119
+ return tmp
120
+ end
121
+ #$PDbgLog.print_msg node.coords_to_s + ": "
122
+ #$PDbgLog.puts_msg "map: #{@node_map.to_s}, tmp=#{tmp.inspect}"
123
+ lp, len = *node.get_min_lp_n_len(@min_lp_len_min)
124
+ #$PDbgLog.print_msg "lp(#{len.inspect}): #{lp}: "
125
+ if lp
126
+ #$PDbgLog.puts_msg 'condensing group.'
127
+ grp = self.min_lp_get_grp(lp)
128
+ grp.each { |m|
129
+ if @node_map.include?(m)
130
+ raise "BUG: Group member #{m} already in " +
131
+ "visited: #{grp.node_cnt < 100 ?
132
+ "m's grp.: " + grp.to_s + '. ' : ''}#{
133
+ @node2gid.include?(m) ? (
134
+ @dup_grps[@node2gid[m]].length<100 ?
135
+ @dup_grps[@node2gid[m]].to_s : 'large') :
136
+ ''}!" #'
137
+ end
138
+ }
139
+ if (entries = grp.get_entries_grp).empty?
140
+ #$PDbgLog.puts_msg 'Whole graph is one group.'
141
+ entries = grp
142
+ l_len = @min_lp_len_min#Don't neglect grp.extent
143
+ else
144
+ #$PDbgLog.puts_msg 'Entries: ' + Xy.path_to_s(
145
+ # entries.to_a.sort)
146
+ end
147
+ if (l_path = grp.get_a_longest_path)
148
+ l_len = l_path.get_length
149
+ else
150
+ #$PDbgLog.puts_msg 'A one-node loop group.'
151
+ l_len = -1 # Neglect group's extent.
152
+ end
153
+ # $PDbgLog.print_msg "longest_path(#{l_len}): #{l_path}: "
154
+ if l_len < @min_lp_len_min
155
+ #$PDbgLog.puts_msg 'group extent negligible.'
156
+ gid = @dup_grps.length
157
+ @dup_grps << (new_grp = PPix::NodeGrp.new)
158
+ @orig_grps << grp
159
+ entries.each_node { |m|
160
+ raise "BUG: Group entry already duplicated: #{m
161
+ }!" if @node_map[m]
162
+ new_grp <<(@node_map[m]=AaXyNode.new(m.ax,m.ay,[]))}
163
+ new_grp.each { |m| @node2gid[m] = gid }
164
+ entries.each_node { |m| nd_conns = @node_map[m].conns
165
+ grp.get_node_paths_to_entries(m).each { |path|
166
+ raise "BUG: Group entry not duplicated: #{
167
+ path.exit}!" unless @node_map[path.exit]
168
+ cn = PPix::NodeConn.new(@node_map[path.exit],
169
+ path.get_length)
170
+ cn.path = path
171
+ #$PDbgLog.puts_msg "path_to_exterior: #{
172
+ # path.to_s(2)}, conn.: #{cn}"
173
+ nd_conns << cn
174
+ }
175
+ m.conns.each_key_value { |conn_k, conn|
176
+ if !grp.include?(PPix::NodeLink.new(m,conn_k))
177
+ #$PDbgLog.puts_msg "link to exterior: #{
178
+ #PPix::NodeLink.new(m, conn_k).to_s(1)}"
179
+ cn = PPix::NodeConn.new(self.dup_node(
180
+ conn.exit), conn.length)
181
+ cn.path = conn.path
182
+ nd_conns << cn
183
+ end
184
+ }
185
+ }
186
+ #dbg_nodes = entries.nodes_to_a
187
+ else
188
+ #$PDbgLog.puts_msg "group's extent non-negligible."
189
+ paths = [l_path]
190
+ dyke = l_path.to_node_grp.get_vicinity_grp_in_set(
191
+ @min_lp_len_min/2, grp.as_node_set)
192
+ #$PDbgLog.puts_msg "Dyke: #{Xy.path_to_s(dyke.to_a.
193
+ # sort)}"
194
+ grps = grp.get_link_islands(dyke)
195
+ #$PDbgLog.puts_msg "grps: #{grps.join("\n --:")}"
196
+ grps_left_idxs = (0...grps.length).to_a
197
+ while !grps_left_idxs.empty?
198
+ i = 0
199
+ while i < grps_left_idxs.length
200
+ t_grp = grps[grps_left_idxs.at(i)]
201
+ l_path = t_grp.get_a_longest_path
202
+ l_len = l_path.get_length
203
+ #$PDbgLog.puts_msg "l_path(#{l_len}): #{l_path}"
204
+ if l_len < @min_lp_len_min
205
+ grps_left_idxs.delete_at(i)
206
+ else
207
+ paths << l_path
208
+ dk = l_path.to_node_grp.get_vicinity(
209
+ @min_lp_len_min/2)
210
+ dk.each { |m| dyke << m }
211
+ islands = t_grp.get_link_islands(dyke)
212
+ if islands.empty?
213
+ grps_left_idxs.delete_at(i)
214
+ else
215
+ grps[grps_left_idxs.at(i)] = islands.first
216
+ 1.upto(islands.length-1).each { |j|
217
+ grps_left_idxs << grps.length
218
+ grps << islands[j]
219
+ }
220
+ end
221
+ end
222
+ end
223
+ end
224
+ #$PDbgLog.puts_msg "grps: #{grps.join("\n --:")}"
225
+ paths.concat(grp.get_islands_min_span_paths(grps))
226
+ paths_grp = PPix::NodeGrp.new
227
+ paths.each { |path|
228
+ path.each { |link| paths_grp << link.node }
229
+ paths_grp << path.exit
230
+ }
231
+ entries.each { |m|
232
+ unless paths_grp.include?(m)
233
+ node_calc = PPix::NodeCalc.new(m)
234
+ path =node_calc.find_first_path_to(proc{|nd,lev|
235
+ paths_grp.include?(nd) })
236
+ paths << path
237
+ #$PDbgLog.puts_msg "Path to an entry: path: #{
238
+ # path}"
239
+ path.each { |link| paths_grp << link.node }
240
+ paths_grp << path.exit
241
+ end
242
+ }
243
+ entries.each { |m| @node_map[m] =
244
+ AaXyNode.new(m.ax,m.ay,[]) }
245
+ #dbg_nodes = entries.to_a
246
+ paths.each { |path| path.each { |link| nd=link.node
247
+ @node_map[nd] = AaXyNode.new(nd.ax,nd.ay,[]
248
+ ) unless @node_map.include?(nd)
249
+ #dbg_nodes << nd unless @node_map.include?(nd)
250
+ }
251
+ nd = path.exit
252
+ @node_map[nd] = AaXyNode.new(nd.ax, nd.ay, []
253
+ ) unless @node_map.include?(nd)
254
+ #dbg_nodes << nd unless @node_map.include?(nd)
255
+ }
256
+ #$PDbgLog.print_msg "Adding links: "
257
+ paths.each { |path| path.each { |link|
258
+ #$PDbgLog.print_msg "#{link.to_s(1)} "
259
+ conn = link.conn
260
+ cn = PPix::NodeConn.new(@node_map[conn.exit],
261
+ conn.length)
262
+ cn.path = conn.path
263
+ @node_map[link.node].conns << cn
264
+ conn = (link=link.reverse).conn #<-- reverse --
265
+ cn = PPix::NodeConn.new(@node_map[conn.exit],
266
+ conn.length)
267
+ cn.path = conn.path
268
+ @node_map[link.node].conns << cn
269
+ } }
270
+ #$PDbgLog.puts_msg '.'
271
+ #$PDbgLog.puts_msg 'Adding conns.: '
272
+ entries.each { |m| nd_conns = @node_map[m].conns
273
+ m.conns.each_key_value { |conn_k, conn|
274
+ #$PDbgLog.print_msg "conn:#{conn.to_s(1)} "
275
+ unless grp.include?(PPix::NodeLink.new(m,
276
+ conn_k))
277
+ nd_conns << (cn=PPix::NodeConn.new(
278
+ self.dup_node(conn.exit),conn.length))
279
+ cn.path = conn.path
280
+ end
281
+ }
282
+ }
283
+ #$PDbgLog.puts_msg '.'
284
+ end
285
+ # $PDbgLog.sig_return("#{node.to_s} done: "+dbg_nodes.
286
+ # sort.collect{|nd| @node_map[nd].to_s(1) }.join('. ') +
287
+ # ": #{@node_map[node]}")
288
+ @node_map[node]
289
+ else
290
+ #$PDbgLog.print_msg 'copying node: '
291
+ res = @node_map[node] =
292
+ AaXyNode.new(node.ax, node.ay, conns=[])
293
+ node.conns.each { |conn|
294
+ cn =PPix::NodeConn.new(self.dup_node(conn.exit),
295
+ conn.length)
296
+ cn.path = conn.path
297
+ conns << cn
298
+ }
299
+ #$PDbgLog.sig_return(res.to_s(1))
300
+ res
301
+ end
302
+ end
303
+
304
+ def dup_graph(node)
305
+ self.dup_node(node)
306
+ end
307
+
308
+ def expand_path(node, exit, path)
309
+ #$PDbgLog.sig_call(self)
310
+ #$PDbgLog.print_msg "node#{node}, exit#{exit}, path: #{path}: "
311
+ node.clear_rev_conns_cache
312
+ node.conns.each { |conn| conn.exit.clear_rev_conns_cache }
313
+ #exit.clear_rev_conns_cache
314
+ #exit.conns.each { |conn| conn.exit.clear_rev_conns_cache }
315
+ path.each { |link|
316
+ unless @node_map.include?(l_nd = link.node)
317
+ @node_map[l_nd] = AaXyNode.new(l_nd.ax, l_nd.ay, [])
318
+ end
319
+ }
320
+ for link in path
321
+ l_exit = link.exit; l_len = link.length
322
+ #$PDbgLog.print_msg "link: #{link}-#{l_exit},node:#{@node_map[
323
+ # link.node].to_s(2)} "
324
+ unless (l_cns = @node_map[link.node].conns).detect_value {|cn|
325
+ l_exit.node_eql?(cn.exit) && cn.length == l_len }
326
+ l_cns << (new_conn = PPix::NodeConn.new(@node_map[l_exit],
327
+ l_len))
328
+ new_conn.path = link.path
329
+ #$PDbgLog.print_msg "new_conn: #{new_conn} "
330
+ end
331
+ end
332
+ #$PDbgLog.sig_return('done.')
333
+ end
334
+
335
+ def expand_proxy_paths
336
+ #$PDbgLog.sig_call(self)
337
+ @dup_grps.each { |grp|
338
+ #$PDbgLog.print_msg "Group: #{grp}: "
339
+ grp.each_node { |node|
340
+ #$PDbgLog.print_msg "node#{node}: "
341
+ conn_i = 0; conns = node.conns
342
+ while conn_i < conns.length
343
+ conn = conns.at(conn_i)
344
+ #$PDbgLog.print_msg "conn: #{conn.to_s(1)} "
345
+ if (path = conn.path).kind_of?(PPix::NodePath) &&
346
+ grp.includes_node?(conn.exit)
347
+ #$PDbgLog.print_msg "node#{node.to_s(2)}: "
348
+ #$PDbgLog.print_msg " => expanding path #{conn_i
349
+ # }: "
350
+ conns.delete_at(conn_i)
351
+ self.expand_path(node, conn.exit, path)
352
+ #$PDbgLog.puts_msg "node#{node.to_s(2)}: "
353
+ else
354
+ conn_i += 1
355
+ end
356
+ end
357
+ }
358
+ #$PDbgLog.puts_msg '.'
359
+ }
360
+ #$PDbgLog.sig_return
361
+ end
362
+
363
+ def expand_grp_paths
364
+ #$PDbgLog.sig_call(self)
365
+ @dup_grps.each { |grp|
366
+ #$PDbgLog.print_msg "Group: #{grp}: "
367
+ entries = PPix::NodeGrp.new
368
+ grp.each { |nd|
369
+ if nd.conns.detect {|conn| !(conn.path.kind_of?(
370
+ PPix::NodePath) && grp.includes_node?(conn.exit)) }
371
+ entries << nd
372
+ end
373
+ }
374
+ #$PDbgLog.print_msg "Entries: #{entries} "
375
+ if entries.empty?
376
+ #$PDbgLog.puts_msg 'One-group graph.'
377
+ next
378
+ end
379
+ entries.each { |nd| conns = nd.conns
380
+ i = 0
381
+ while i < conns.length
382
+ if (conn = conns.at(i)).path.kind_of?(
383
+ PPix::NodePath) && grp.includes_node?(conn.exit
384
+ ) && !entries.includes_node?(conn.exit)
385
+ conns.delete_at(i)
386
+ else
387
+ i += 1
388
+ end
389
+ end
390
+ }
391
+ spanned = Set.new
392
+ tail = PMinHeap.new { |a,b| a.length <=> b.length }
393
+ first_nd = nil
394
+ entries.each_node { |first_nd| break }
395
+ first_nd.each_link { |link|
396
+ tail.push(link) if link.path.kind_of?(PPix::NodePath) &&
397
+ entries.includes_node?(link.exit) }
398
+ spanned << first_nd
399
+ rev_link = nil
400
+ while spanned.length < entries.length
401
+ link = tail.pop
402
+ next if spanned.include?(link.exit)
403
+ expand_path(node=link.node, link.exit, link.path)
404
+ link.exit.each_link { |rev_link|
405
+ break if node.node_eql?(rev_link.exit) &&
406
+ rev_link.path.kind_of?(PPix::NodePath) &&
407
+ grp.includes_node?(rev_link.node) }
408
+ expand_path(rev_link.node, rev_link.exit, rev_link.path)
409
+ spanned << link.exit
410
+ link.exit.each_link { |link|
411
+ tail.push(link) if grp.include?(link) &&
412
+ entries.includes_node?(link.exit) &&
413
+ !spanned.include?(link.exit)
414
+ }
415
+ end
416
+ #$PDbgLog.puts_msg '.'
417
+ }
418
+ #$PDbgLog.sig_return
419
+ end
420
+
421
+ def shave_node!(node)
422
+ #$PDbgLog.sig_call(self)
423
+ conns = node.conns
424
+ i1 = i2 = nil
425
+ i1_depth = i2_depth = 0
426
+ i = -1
427
+ while (i += 1) < conns.length
428
+ depth = self.node_conn_max_depth(node, i)
429
+ #$PDbgLog.print_msg node.to_s + ": --" +
430
+ # "#{conns[i]}:#{depth}: "
431
+ if i2
432
+ if depth > i1_depth
433
+ i_min = i2; min_depth = i2_depth
434
+ i2 = i1; i2_depth = i1_depth
435
+ i1 = i; i1_depth = depth
436
+ elsif depth > i2_depth
437
+ i_min = i2; min_depth = i2_depth
438
+ i2 = i; i2_depth = depth
439
+ else
440
+ i_min = i; min_depth = depth
441
+ end
442
+ if min_depth < @min_branch_len
443
+ #$PDbgLog.print_msg "deleting at #{i_min
444
+ # }/#{conns.length}: #{conns[i_min]}"
445
+ conns.delete_at(i_min)
446
+ if (c_depths = @node_conn_depths[node])
447
+ c_depths.delete_at(i_min)
448
+ end
449
+ i1 -= 1 if i1 > i_min
450
+ i2 -= 1 if i2 > i_min
451
+ i -= 1
452
+ end
453
+ elsif i1
454
+ if depth > i1_depth
455
+ i2 = i1; i2_depth = i1_depth
456
+ i1 = i; i1_depth = depth
457
+ else
458
+ i2 = i; i2_depth = depth
459
+ end
460
+ else
461
+ i1 = i; i1_depth = depth
462
+ end
463
+ #$PDbgLog.puts_msg "."
464
+ end
465
+ #$PDbgLog.sig_return
466
+ end
467
+
468
+ def shave_grp!(node)
469
+ #$PDbgLog.sig_call(self)
470
+ if @grps_shaven[gid=@node2gid[node]]
471
+ #$PDbgLog.sig_return
472
+ return
473
+ end
474
+ @grps_shaven[gid] = true
475
+ entries = (grp=@dup_grps[gid])
476
+ nd1 = nd2 = nil
477
+ i1 = i2 = nil
478
+ i1_depth = i2_depth = 0
479
+ for node in entries
480
+ i = -1
481
+ conns = node.conns
482
+ while (i += 1) < conns.length
483
+ conn = conns.at(i)
484
+ next if (path = conn.path).kind_of?(PPix::NodePath) &&
485
+ grp.includes_node?(conn.exit)
486
+ depth = self.node_conn_max_depth(node, i)
487
+ #$PDbgLog.print_msg node.to_s + ": --" +
488
+ # "#{conns[i]}:#{depth}: "
489
+ if i2
490
+ if depth > i1_depth
491
+ i_min = i2; min_depth = i2_depth; nd_min = nd2
492
+ i2 = i1; i2_depth = i1_depth; nd2 = nd1
493
+ i1 = i; i1_depth = depth; nd1 = node
494
+ elsif depth > i2_depth
495
+ i_min = i2; min_depth = i2_depth; nd_min = nd2
496
+ i2 = i; i2_depth = depth; nd2 = node
497
+ else
498
+ i_min = i; min_depth = depth; nd_min = node
499
+ end
500
+ if min_depth < @min_branch_len
501
+ # $PDbgLog.print_msg "deleting at #{i_min
502
+ # }/#{nd_min.conns.length}: #{nd_min} #{
503
+ # nd_min.conns[i_min]}"
504
+ nd_min.conns.delete_at(i_min)
505
+ if (c_depths=@node_conn_depths[nd_min])
506
+ c_depths.delete_at(i_min)
507
+ end
508
+ i1-=1 if nd1.equal?(nd_min) && i1>i_min
509
+ i2-=1 if nd2.equal?(nd_min) && i2>i_min
510
+ i -= 1 if node.equal?(nd_min)
511
+ end
512
+ elsif i1
513
+ if depth > i1_depth
514
+ i2 = i1; i2_depth = i1_depth; nd2 = nd1
515
+ i1 = i; i1_depth = depth; nd1 = node
516
+ else
517
+ i2 = i; i2_depth = depth; nd2 = node
518
+ end
519
+ else
520
+ i1 = i; i1_depth = depth; nd1 = node
521
+ end
522
+ #$PDbgLog.puts_msg "."
523
+ end
524
+ end
525
+ #$PDbgLog.sig_return
526
+ end
527
+
528
+ def shave!(node)
529
+ #$PDbgLog.sig_call(self)
530
+ #$PDbgLog.print_msg node.coords_to_s + ", conns: #{node.conns.
531
+ # join('; ')}: "
532
+ node.conns.each { |conn|
533
+ next if @visited.include?(conn.exit.a_yx)
534
+ if @node2gid[conn.exit]
535
+ self.shave_grp!(conn.exit)
536
+ else
537
+ self.shave_node!(conn.exit)
538
+ end
539
+ @visited[conn.exit.a_yx] = true
540
+ unless conn.exit.conns.detect { |cn|
541
+ cn.exit.node_eql?(node) }
542
+ #$PDbgLog.sig_return(node.coords_to_s + ": " +
543
+ # (res = self.shave!(conn.last)).coords_to_s)
544
+ return self.shave!(conn.exit) #res
545
+ end
546
+ if !(tmp = self.shave!(conn.exit)).node_eql?(conn.exit)
547
+ #$PDbgLog.sig_return(node.coords_to_s + ": " +
548
+ # tmp.coords_to_s)
549
+ return tmp
550
+ end
551
+ }
552
+ $PDbgLog.progr.progr_units = @visited.length if @use_progr
553
+ #$PDbgLog.sig_return(node.coords_to_s + ": " + node.coords_to_s)
554
+ node
555
+ end
556
+
557
+ def shave_graph(node)
558
+ $PDbgLog.sig_call(self)
559
+ #$PDbgLog.print_msg "node#{node}: "
560
+ @node_map = {}
561
+ unless (wrk_node = self.dup_graph(node))
562
+ # node could have been a non-visitable node in a group.
563
+ @node_map.each_value { |wrk_node| break }
564
+ end
565
+ #$PDbgLog.print_msg "wrk_node#{wrk_node} "
566
+ $PDbgLog.new_progr
567
+ $PDbgLog.progr.total_progr_units = @node_map.length
568
+ $PDbgLog.progr.show_as = "/ node" + (@node_map.length == 1 ?
569
+ '' : 's')
570
+ @use_progr = true
571
+ #$PDbgLog.puts_msg "Duplicated graph: #{wrk_node.graph_to_s}"
572
+ res = self.shave!(wrk_node)
573
+ #$PDbgLog.puts_msg "Shaved graph: #{res.graph_to_s}"
574
+ self.expand_grp_paths
575
+ #$PDbgLog.print_msg "res#{res} "
576
+ @use_progr = false
577
+ $PDbgLog.sig_return
578
+ res
579
+ end
580
+ end
581
+
582
+ class Curve
583
+ def get_shaved_core(min_branch_len, min_lp_len_min)
584
+ ShavedCore.new(self, min_branch_len, min_lp_len_min)
585
+ end
586
+
587
+ self.img_obj_add_meths(PGuiObj::PMethod.new(:get_shaved_core, [
588
+ PGuiObj::Argument.new(Integer, OpenStruct.new('min'=>0), nil, 10,
589
+ 'min. branch length',
590
+ "Branches of the curve of length less than this one will be shaved off for curve's shaved core.",
591
+ OpenStruct.new('page_step'=>100)),
592
+ PGuiObj::Argument.new(Integer, OpenStruct.new('min'=>0), nil, 10,
593
+ 'min. loop length',
594
+ "Shortest loops of the curve of length less than this one will be deloopified for curve's shaved core.",
595
+ OpenStruct.new('page_step'=>100))],
596
+ 'shaved core'))
597
+
598
+ def c_shaved_core(min_hair_len, min_lp_len)
599
+ return @c_shaved_core if @c_shaved_core
600
+ #$PDbgLog.sig_call(self)
601
+ #$PDbgLog.print_msg @shaved_core.inspect
602
+ @c_shaved_core = self.get_shaved_core(min_hair_len, min_lp_len)
603
+ #$PDbgLog.sig_return(@shaved_core.object_id)
604
+ #@c_shaved_core
605
+ end
606
+
607
+ def c_delete_shaved_core
608
+ @c_shaved_core = nil
609
+ end
610
+ end
611
+
612
+ class ShavedCore < ImageObject
613
+ attr_reader :curve, :branches, :min_branch_len, :min_lp_len_min
614
+
615
+ def initialize(curve, min_branch_len, min_lp_len_min)
616
+ @curve = curve
617
+ @branches = []
618
+ @min_branch_len = min_branch_len
619
+ @min_lp_len_min = min_lp_len_min
620
+ super()
621
+ self.pguiobj_config.name = "<Shaved core>"
622
+ self.rebuild
623
+ end
624
+
625
+ def rebuild
626
+ self.clear
627
+ if @curve.length < 2
628
+ self.replace(@curve)
629
+ return
630
+ end
631
+ $PDbgLog.sig_call(self)
632
+ $PDbgLog.print_msg "@min_branch_len=#{@min_branch_len
633
+ }, @min_lp_len_min=#{@min_lp_len_min}; Shaving: "
634
+ calc = ShavedCoreCalc.new(self)
635
+ node = @curve.pix_node(@curve.first)
636
+ node = node.conns.first.exit unless node.conns.empty?
637
+ #$PDbgLog.puts_msg "Graph: #{node.graph_to_s}"
638
+ node = calc.shave_graph(node)
639
+ $PDbgLog.print_msg "done. Traversing: "
640
+ @branches.clear
641
+ branch_start_i = 0
642
+ if node.conns.length < 2
643
+ self << AaPix.new(@curve.pixbuf, node.ax, node.ay)
644
+ else
645
+ node.graph_each_node { |nd|
646
+ if nd.conns.length < 2
647
+ node = nd
648
+ self << AaPix.new(@curve.pixbuf,node.ax,node.ay)
649
+ break
650
+ end
651
+ }
652
+ end
653
+ next_node = node
654
+ #$PDbgLog.puts_msg "node#{node}"
655
+ #$PDbgLog.puts_msg "Final graph: #{node.graph_to_s}"
656
+ branch_lims = []
657
+ node.graph_each_conn_k { |node, conn_k|
658
+ #$PDbgLog.puts_msg "node#{node},conn_k[#{conn_k}]: #{
659
+ # node.conns[conn_k].to_s(2)}: #{node.
660
+ # conns[conn_k].path.expand_to_xy_path.xy_nodes}"
661
+ if !next_node.node_eql?(node) || node.conns.length > 2
662
+ #@branches << ImageObject.new(self,
663
+ # branch_start_i, self.length)
664
+ branch_lims << [branch_start_i, self.length]
665
+ #$PDbgLog.puts_msg "Branch #{@branches.length
666
+ # }: #{Xy.path_to_s(@branches.last)}"
667
+ branch_start_i = self.length
668
+ end
669
+ conn = node.conns[conn_k]
670
+ self.concat(conn.path.expand_to_xy_path.xy_nodes)
671
+ next_node = conn.exit
672
+ }
673
+ $PDbgLog.print_msg "done; adding branches: "
674
+ branch_lims.each { |b|
675
+ @branches << ImageObject.new(self, b[0], b[1]) }
676
+ @branches << ImageObject.new(self, branch_start_i,
677
+ self.length) unless branch_start_i >= self.length
678
+ #$PDbgLog.print_msg "@branches.length=#{@branches.length
679
+ # }; @branches: #{@branches} "
680
+ $PDbgLog.sig_return("done all.")
681
+ end
682
+
683
+ def img_obj_branches
684
+ (res=self.branches).each{|b| b.pguiobj_config.destroy_btn=false
685
+ b.pguiobj_config.name = '<Branch>' }
686
+ res = ImageObject.create_array(res)
687
+ res.pguiobj_config.name = '[Branches]'
688
+ res.pguiobj_config.destroy_btn = false
689
+ res
690
+ end
691
+
692
+ self.img_obj_add_meths(meth=PGuiObj::PMethod.new(:img_obj_branches, [],
693
+ 'branches'))
694
+ PGuiObj::MethObserverCachedAttr.observe(meth)
695
+ end
696
+
697
+ end