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,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