extract_curves 0.0.1-mswin32
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.
- data/bin/ec_rect2polar.rb +22 -0
- data/bin/ec_rev_lines.rb +5 -0
- data/bin/ec_sph_area.rb +30 -0
- data/bin/extract_curves.rb +2145 -0
- data/ruby_ext/pav/extconf.rb +22 -0
- data/ruby_ext/pav/pav.dll +0 -0
- data/ruby_libs/pav/attr_cache.rb +211 -0
- data/ruby_libs/pav/attr_cache.t1.rb +32 -0
- data/ruby_libs/pav/cache.rb +31 -0
- data/ruby_libs/pav/dbg_log.rb +458 -0
- data/ruby_libs/pav/floatsio.rb +53 -0
- data/ruby_libs/pav/generator_cache.rb +165 -0
- data/ruby_libs/pav/gtk/button.rb +130 -0
- data/ruby_libs/pav/gtk/icons.rb +87 -0
- data/ruby_libs/pav/gtk/toolbar.rb +192 -0
- data/ruby_libs/pav/heap.rb +54 -0
- data/ruby_libs/pav/icons/alt_handle.xpm +3832 -0
- data/ruby_libs/pav/icons/alt_handle_hover.xpm +3368 -0
- data/ruby_libs/pav/icons/alt_handle_pressed.xpm +3828 -0
- data/ruby_libs/pav/icons/extract_curves/extract_curves-icon-rgb.ppm +14 -0
- data/ruby_libs/pav/icons/extract_curves/extract_curves-logo-rgb.gif +0 -0
- data/ruby_libs/pav/icons/extract_curves/trace_mark.xpm +38 -0
- data/ruby_libs/pav/icons/handle.xpm +213 -0
- data/ruby_libs/pav/icons/next.xpm +29 -0
- data/ruby_libs/pav/icons/next_hover.xpm +315 -0
- data/ruby_libs/pav/icons/next_pressed.xpm +144 -0
- data/ruby_libs/pav/icons/prev.xpm +29 -0
- data/ruby_libs/pav/icons/prev_hover.xpm +315 -0
- data/ruby_libs/pav/icons/prev_pressed.xpm +144 -0
- data/ruby_libs/pav/icons/vnext.xpm +29 -0
- data/ruby_libs/pav/icons/vprev.xpm +29 -0
- data/ruby_libs/pav/numeric/ext.rb +13 -0
- data/ruby_libs/pav/pav_find.rb +90 -0
- data/ruby_libs/pav/pix/aapix.rb +378 -0
- data/ruby_libs/pav/pix/blob.rb +543 -0
- data/ruby_libs/pav/pix/circle.rb +73 -0
- data/ruby_libs/pav/pix/contour/calc_situations.rb +9 -0
- data/ruby_libs/pav/pix/contour/carp_calc.rb +212 -0
- data/ruby_libs/pav/pix/contour/situations.dmp +0 -0
- data/ruby_libs/pav/pix/contour/situations.rb +21 -0
- data/ruby_libs/pav/pix/contour.rb +644 -0
- data/ruby_libs/pav/pix/curve.rb +1508 -0
- data/ruby_libs/pav/pix/img_obj.rb +751 -0
- data/ruby_libs/pav/pix/node.rb +712 -0
- data/ruby_libs/pav/pix/node_grp.rb +853 -0
- data/ruby_libs/pav/pix/shaved_core.rb +534 -0
- data/ruby_libs/pav/pix/subpix.rb +212 -0
- data/ruby_libs/pav/pix.rb +402 -0
- data/ruby_libs/pav/rand_accessible.rb +16 -0
- data/ruby_libs/pav/rangeset.rb +63 -0
- data/ruby_libs/pav/search.rb +210 -0
- data/ruby_libs/pav/set.rb +20 -0
- data/ruby_libs/pav/string/bits.rb +523 -0
- data/ruby_libs/pav/string/ext.rb +58 -0
- data/ruby_libs/pav/string/observable.rb +155 -0
- data/ruby_libs/pav/string/text.rb +79 -0
- data/ruby_libs/pav/string/words.rb +42 -0
- data/ruby_libs/pav/sub_arr.rb +55 -0
- data/ruby_libs/pav/traced_obj.rb +79 -0
- metadata +112 -0
@@ -0,0 +1,712 @@
|
|
1
|
+
require 'pav/pix'
|
2
|
+
require 'pav/heap'
|
3
|
+
require 'pav/pix/aapix'
|
4
|
+
|
5
|
+
module PPix
|
6
|
+
|
7
|
+
class NoReversePathwayError < RuntimeError
|
8
|
+
attr_accessor :pathway, :start_node
|
9
|
+
|
10
|
+
def initialize(pathway, start_node=nil)
|
11
|
+
@pathway = pathway
|
12
|
+
@start_node = start_node
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class NoReverseLinkError < NoReversePathwayError
|
17
|
+
end
|
18
|
+
|
19
|
+
class NoReverseConnError < NoReversePathwayError
|
20
|
+
end
|
21
|
+
|
22
|
+
class NodeLink
|
23
|
+
attr_reader :node, :conn_i, :c_reverse
|
24
|
+
|
25
|
+
def initialize(node, conn_i)
|
26
|
+
@node = node
|
27
|
+
@conn_i = conn_i
|
28
|
+
@c_reverse = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def ==(link)
|
32
|
+
@node.node_eql?(link.node) && @conn_i == link.conn_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def reverse
|
36
|
+
return @c_reverse if @c_reverse
|
37
|
+
conn = @node.conns[@conn_i]
|
38
|
+
exit = conn.exit
|
39
|
+
r_conn = conn.reverse(@node)
|
40
|
+
exit.conns.each_with_index { |cn, cn_i|
|
41
|
+
if cn == r_conn
|
42
|
+
return @c_reverse = NodeLink.new(exit, cn_i)
|
43
|
+
end
|
44
|
+
}
|
45
|
+
raise NoReverseLinkError.new(self, @node),
|
46
|
+
#"#{self.class.name}.reverse: No rev. link: " +
|
47
|
+
"#{self}; conn.: #{node.conns[@conn_i]}; r_conn: #{r_conn}" +
|
48
|
+
(exit.conns.length < 50 ? '; '+NodeConn.conns_to_s(
|
49
|
+
exit.conns) : '')
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def expand_to_xy_path
|
54
|
+
@node.conns[@conn_i].path.expand_to_xy_path
|
55
|
+
end
|
56
|
+
|
57
|
+
def exit
|
58
|
+
@node.conns[@conn_i].exit
|
59
|
+
end
|
60
|
+
|
61
|
+
def length
|
62
|
+
@node.conns[@conn_i].length
|
63
|
+
end
|
64
|
+
|
65
|
+
def path
|
66
|
+
@node.conns[@conn_i].path
|
67
|
+
end
|
68
|
+
|
69
|
+
def conn
|
70
|
+
@node.conns[@conn_i]
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_s(how=0)
|
74
|
+
"#{@node}-[#{@conn_i}]->" + (how >= 1 ?
|
75
|
+
@node.conns[@conn_i].exit.to_s : '')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class NodePath < Array
|
80
|
+
def ==(path2)
|
81
|
+
#$PDbgLog.sig_call(self.name + "#")
|
82
|
+
#$PDbgLog.puts_msg "self: #{self}; path2: #{path2}"
|
83
|
+
if self.length != path2.length
|
84
|
+
# $PDbgLog.sig_return
|
85
|
+
return false
|
86
|
+
end
|
87
|
+
self.each_with_index { |link, i|
|
88
|
+
return false if !link = path2.at(i) }
|
89
|
+
#$PDbgLog.sig_return
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
93
|
+
def +(path2)
|
94
|
+
self.dup.concat(path2)
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_length
|
98
|
+
res = 0
|
99
|
+
self.each { |link| res += link.length }
|
100
|
+
res
|
101
|
+
end
|
102
|
+
|
103
|
+
def entry
|
104
|
+
return nil if self.empty?
|
105
|
+
self.first.node
|
106
|
+
end
|
107
|
+
|
108
|
+
def exit
|
109
|
+
return nil if self.empty?
|
110
|
+
self.last.exit
|
111
|
+
end
|
112
|
+
|
113
|
+
alias_method :reverse_links, :reverse
|
114
|
+
alias_method :reverse_links!, :reverse!
|
115
|
+
|
116
|
+
def reverse
|
117
|
+
res = []
|
118
|
+
self.each_with_index { |link, i|
|
119
|
+
res[self.length-i] = link.reverse }
|
120
|
+
end
|
121
|
+
|
122
|
+
def reverse!
|
123
|
+
0.upto(self.length-1) { |i| self[i] = self[i].reverse }
|
124
|
+
super
|
125
|
+
end
|
126
|
+
|
127
|
+
def expand_to_xy_path
|
128
|
+
return [] if self.empty?
|
129
|
+
res = self.first.expand_to_xy_path
|
130
|
+
1.upto(self.length-1) { |i|
|
131
|
+
res.concat(self.at(i).expand_to_xy_path) }
|
132
|
+
res
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_s(how=1)
|
136
|
+
self.join(' ') << (how > 0 ? self.exit.to_s : '')
|
137
|
+
end
|
138
|
+
|
139
|
+
def each_node
|
140
|
+
for link in self
|
141
|
+
yield(link.node)
|
142
|
+
end
|
143
|
+
if (exit = self.exit)
|
144
|
+
yield(exit)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class XyPath < Array
|
150
|
+
def self.yx_path_to_s(path)
|
151
|
+
path.collect { |yx| "(#{yx[1]}, #{yx[0]})" }.join(" ")
|
152
|
+
end
|
153
|
+
|
154
|
+
def get_length
|
155
|
+
self.length - 1
|
156
|
+
end
|
157
|
+
|
158
|
+
alias_method :entry, :first
|
159
|
+
alias_method :exit, :last
|
160
|
+
|
161
|
+
def to_s
|
162
|
+
self.collect { |pix| pix.to_s }.join(" ")
|
163
|
+
end
|
164
|
+
|
165
|
+
def eql?(path2)
|
166
|
+
#$PDbgLog.sig_call(self.name + "#")
|
167
|
+
#$PDbgLog.puts_msg "path1: #{path1}; path2: #{path2}"
|
168
|
+
if self.length != path2.length
|
169
|
+
# $PDbgLog.sig_return
|
170
|
+
return false
|
171
|
+
end
|
172
|
+
self.each_with_index { |pix, i|
|
173
|
+
return false if pix.y != path2[i].y ||
|
174
|
+
pix.x != path2[i].x
|
175
|
+
}
|
176
|
+
#$PDbgLog.sig_return
|
177
|
+
true
|
178
|
+
end
|
179
|
+
|
180
|
+
def starts_with(pfx_path)
|
181
|
+
return false unless self.length >= pfx_path.length
|
182
|
+
pfx_path.each_with_index { |pix, i|
|
183
|
+
return false if pix.yx != self.at(i).yx }
|
184
|
+
true
|
185
|
+
end
|
186
|
+
|
187
|
+
def ends_with(sfx_path)
|
188
|
+
return false unless (ofs = self.length - sfx_path.length) >= 0
|
189
|
+
0.upto(sfx_path.length-1) { |i|
|
190
|
+
return false if sfx_path.at(i).yx != self.at(ofs+i).yx }
|
191
|
+
true
|
192
|
+
end
|
193
|
+
|
194
|
+
def a_eql?(path2)
|
195
|
+
#$PDbgLog.sig_call(self.name + "#")
|
196
|
+
#$PDbgLog.puts_msg "self: #{self}; path2: #{path2}"
|
197
|
+
if self.length != path2.length
|
198
|
+
# $PDbgLog.sig_return
|
199
|
+
return false
|
200
|
+
end
|
201
|
+
self.each_with_index { |pix, i|
|
202
|
+
return false if !pix.a_eql?(path2.at(i)) }
|
203
|
+
#$PDbgLog.sig_return
|
204
|
+
true
|
205
|
+
end
|
206
|
+
|
207
|
+
def node_eql?(path2)
|
208
|
+
#$PDbgLog.sig_call(self.name + "#")
|
209
|
+
#$PDbgLog.puts_msg "self: #{self}; path2: #{path2}"
|
210
|
+
if self.length != path2.length
|
211
|
+
# $PDbgLog.sig_return
|
212
|
+
return false
|
213
|
+
end
|
214
|
+
self.each_with_index { |node, i|
|
215
|
+
return false if !node.a_eql?(path2.at(i)) }
|
216
|
+
#$PDbgLog.sig_return
|
217
|
+
true
|
218
|
+
end
|
219
|
+
|
220
|
+
alias_method :==, :node_eql?
|
221
|
+
|
222
|
+
def a_starts_with(pfx_path)
|
223
|
+
return false unless self.length >= spath.length
|
224
|
+
self.each_with_index { |pix, i|
|
225
|
+
return false if !pix.a_eql?(pfx_path.at(i)) }
|
226
|
+
true
|
227
|
+
end
|
228
|
+
|
229
|
+
def a_ends_with(sfx_path)
|
230
|
+
return false unless (ofs = self.length - sfx_path.length) >= 0
|
231
|
+
0.upto(sfx_path.length-1) { |i|
|
232
|
+
return false if !sfx_path.at(i).a_eql?(self.at(ofs+i)) }
|
233
|
+
true
|
234
|
+
end
|
235
|
+
|
236
|
+
def dup
|
237
|
+
XyPath.new(self)
|
238
|
+
end
|
239
|
+
|
240
|
+
def concat(path)
|
241
|
+
super(path[1, path.length-1])
|
242
|
+
self
|
243
|
+
end
|
244
|
+
|
245
|
+
def +(path)
|
246
|
+
self.dup.concat(path[1, path.length-1])
|
247
|
+
end
|
248
|
+
|
249
|
+
alias_method :expand_to_xy_path, :dup
|
250
|
+
|
251
|
+
def xy_nodes
|
252
|
+
self[1, self.length-1]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class NodeConn
|
257
|
+
attr_reader :exit, :length
|
258
|
+
attr_accessor :path
|
259
|
+
|
260
|
+
def self.conns_to_s(conns)
|
261
|
+
conns.collect {|cn| cn.to_s}.join(', ')
|
262
|
+
end
|
263
|
+
|
264
|
+
def initialize(exit, length)
|
265
|
+
@exit = exit
|
266
|
+
@length = length
|
267
|
+
raise ArgumentError, "Conn.'s exit must be an AaXyNode!" unless
|
268
|
+
@exit.kind_of?(AaXyNode)
|
269
|
+
raise ArgumentError, "Conn.'s length must be numeric!" unless
|
270
|
+
@length.kind_of?(Numeric)
|
271
|
+
end
|
272
|
+
|
273
|
+
def reverse(conn_0)
|
274
|
+
res = NodeConn.new(conn_0, length)
|
275
|
+
res.path = path.reverse
|
276
|
+
res
|
277
|
+
end
|
278
|
+
|
279
|
+
def max_depth(to_parent_conn_i, visited={})
|
280
|
+
return @c_max_depth if @c_max_depth
|
281
|
+
@c_max_depth = @length +
|
282
|
+
@exit.dir_max_depth(to_parent_conn_i, visited)
|
283
|
+
end
|
284
|
+
|
285
|
+
def to_s(how=0)
|
286
|
+
"<-#{@length}->#{@exit}" + (how<1 ? '' : ': ' + self.path.to_s)
|
287
|
+
end
|
288
|
+
|
289
|
+
def eql?(conn)
|
290
|
+
@exit.node_eql?(conn.exit) && @length == conn.length &&
|
291
|
+
@path == conn.path
|
292
|
+
end
|
293
|
+
|
294
|
+
alias_method :==, :eql?
|
295
|
+
end
|
296
|
+
|
297
|
+
class AaXyNode < AaXy
|
298
|
+
attr_reader :conns, :c_rev_conns
|
299
|
+
|
300
|
+
def initialize(ax, ay, conns)
|
301
|
+
super(ax, ay)
|
302
|
+
@conns = conns
|
303
|
+
@c_rev_conns = []
|
304
|
+
end
|
305
|
+
|
306
|
+
def rev_conn_idx(conn_i)
|
307
|
+
if (tmp = @c_rev_conns[conn_i])
|
308
|
+
return tmp
|
309
|
+
end
|
310
|
+
conn = @conns[conn_i]
|
311
|
+
l = conn.exit
|
312
|
+
rev_conn = conn.reverse(self)
|
313
|
+
l.conns.each_with_index { |cn, cn_i|
|
314
|
+
return cn_i if cn == rev_conn }
|
315
|
+
raise NoReverseConnError.new(conn, self),
|
316
|
+
"#{self.coords_to_s} #{@conns[conn_i].to_s(2)}!"
|
317
|
+
nil
|
318
|
+
end
|
319
|
+
|
320
|
+
def to_parent_conn_idx(conn_i)
|
321
|
+
begin
|
322
|
+
self.rev_conn_idx(conn_i)
|
323
|
+
rescue NoReverseConnError
|
324
|
+
if self.node_eql?(@conns[conn_i].exit)
|
325
|
+
@c_rev_conns[conn_i] = conn_i
|
326
|
+
else
|
327
|
+
raise
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def clear_rev_conns_cache
|
333
|
+
@c_rev_conns.clear
|
334
|
+
end
|
335
|
+
|
336
|
+
def delete_conn(conn_i)
|
337
|
+
@conns.delete_at(conn_i)
|
338
|
+
@c_rev_conns.delete_at(conn_i)
|
339
|
+
end
|
340
|
+
|
341
|
+
def conns_to_s
|
342
|
+
NodeConn.conns_to_s(@conns)
|
343
|
+
end
|
344
|
+
|
345
|
+
alias_method :node_eql?, :a_eql?
|
346
|
+
|
347
|
+
def each_link
|
348
|
+
@conns.each_index { |conn_i| yield(NodeLink.new(self, conn_i)) }
|
349
|
+
end
|
350
|
+
|
351
|
+
def get_min_lp_n_len(max_len=1.0/0.0)
|
352
|
+
#$PDbgLog.sig_call(self)
|
353
|
+
#$PDbgLog.print_msg self.coords_to_s + ", max_len=#{max_len}: "
|
354
|
+
p1, p2, len = *PSearch.first_norep_loop(self, max_len, max_len,
|
355
|
+
proc { |p| p.a_yx }) { |node, lev|
|
356
|
+
res = []
|
357
|
+
node.conns.each_with_index { |cn, cn_i|
|
358
|
+
res << [cn.exit,NodeLink.new(node,cn_i),lev+cn.length] }
|
359
|
+
res
|
360
|
+
}
|
361
|
+
unless p1
|
362
|
+
#$PDbgLog.sig_return
|
363
|
+
return [nil, nil]
|
364
|
+
end
|
365
|
+
#$PDbgLog.puts_msg 'p1: ' + p1.collect { |link|
|
366
|
+
# link ? link.to_s(1) : link.inspect }.join(' ')
|
367
|
+
#$PDbgLog.puts_msg 'p2: ' + p2.collect { |link|
|
368
|
+
# link ? link.to_s(1) : link.inspect }.join(' ')
|
369
|
+
lp = NodePath.new
|
370
|
+
p2.reverse_each { |link| lp << link }
|
371
|
+
p1.each { |link| lp << link.reverse }
|
372
|
+
#$PDbgLog.sig_return(lp)
|
373
|
+
[lp, len]
|
374
|
+
end
|
375
|
+
|
376
|
+
def dup_with_map(map)
|
377
|
+
if (tmp = map[self])
|
378
|
+
return tmp
|
379
|
+
end
|
380
|
+
res = map[self] = AaXyNod.new(self.ax, self.ay, conns=[])
|
381
|
+
@conns.each { |conn|
|
382
|
+
new_conn = NodeConn.new(conn.exit.dup_with_map(map),
|
383
|
+
conn.length)
|
384
|
+
new_conn.path = conn.path
|
385
|
+
conns << new_conn
|
386
|
+
}
|
387
|
+
res
|
388
|
+
end
|
389
|
+
|
390
|
+
def dup_graph
|
391
|
+
self.dup_with_map({})
|
392
|
+
end
|
393
|
+
|
394
|
+
def conn_max_depth(conn_i)
|
395
|
+
begin
|
396
|
+
rev_conn_i = self.rev_conn_idx(conn_i)
|
397
|
+
rescue NoReversePathwayError
|
398
|
+
rev_conn_i = -1
|
399
|
+
end
|
400
|
+
@conns[conn_i].max_depth(rev_conn_i)
|
401
|
+
end
|
402
|
+
|
403
|
+
def dir_max_depth(to_parent_conn_i, visited)
|
404
|
+
#$PDbgLog.sig_call(self)
|
405
|
+
max_depth = 0
|
406
|
+
visited[self] = true
|
407
|
+
@conns.each_with_index { |conn, conn_i|
|
408
|
+
next if to_parent_conn_i == conn_i
|
409
|
+
if visited.include?(conn.exit)
|
410
|
+
max_depth = 1.0/0.0
|
411
|
+
break
|
412
|
+
end
|
413
|
+
tmp = conn.max_depth(self.rev_conn_idx(conn_i), visited)
|
414
|
+
max_depth = tmp if tmp > max_depth
|
415
|
+
}
|
416
|
+
#$PDbgLog.sig_return
|
417
|
+
max_depth
|
418
|
+
end
|
419
|
+
|
420
|
+
def graph_each_conn_i(visited={}, &block)
|
421
|
+
if visited.include?(self)
|
422
|
+
vis_conns = visited[self]
|
423
|
+
else
|
424
|
+
vis_conns = visited[self] = []
|
425
|
+
end
|
426
|
+
@conns.each_with_index { |conn, conn_i|
|
427
|
+
unless vis_conns[conn_i]
|
428
|
+
yield(self, conn_i)
|
429
|
+
vis_conns[conn_i] = true
|
430
|
+
begin
|
431
|
+
visited[conn.exit] = [] unless
|
432
|
+
visited.include?(conn.exit)
|
433
|
+
visited[conn.exit][self.rev_conn_idx(conn_i)] = true
|
434
|
+
rescue NoReversePathwayError
|
435
|
+
end
|
436
|
+
conn.exit.graph_each_conn_i(visited, &block)
|
437
|
+
end
|
438
|
+
}
|
439
|
+
end
|
440
|
+
|
441
|
+
def graph_each_node(visited={}, &block)
|
442
|
+
return if visited.include?(self)
|
443
|
+
visited[self] = true
|
444
|
+
yield(self)
|
445
|
+
@conns.each {|conn| conn.exit.graph_each_node(visited, &block) }
|
446
|
+
end
|
447
|
+
|
448
|
+
def to_s(how=0)
|
449
|
+
res = self.coords_to_s
|
450
|
+
return res if how < 1
|
451
|
+
res.concat('+conns: ')
|
452
|
+
@conns.each_with_index { |conn, conn_i|
|
453
|
+
res.concat("[#{conn_i}]#{conn.to_s(how-1)}; ")
|
454
|
+
}
|
455
|
+
res[-2,2] = ''
|
456
|
+
res
|
457
|
+
end
|
458
|
+
|
459
|
+
def graph_to_s
|
460
|
+
res = ''
|
461
|
+
self.graph_each_conn_i { |node, conn_i|
|
462
|
+
res.concat(node.to_s + ": [#{conn_i}]#{node.conns[
|
463
|
+
conn_i].to_s(2)}\n")
|
464
|
+
}
|
465
|
+
res
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
class NodeCalcPCachePathIter
|
470
|
+
attr_accessor :path_cache, :node
|
471
|
+
|
472
|
+
def initialize(path_cache=nil, node=nil)
|
473
|
+
@path_cache = path_cache
|
474
|
+
@node = node
|
475
|
+
end
|
476
|
+
|
477
|
+
def pop
|
478
|
+
to_link = path_cache[@node][1]
|
479
|
+
@node = to_link ? to_link.node : nil
|
480
|
+
to_link
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
class NodeCalc
|
485
|
+
attr_reader :node, :c_paths
|
486
|
+
attr_accessor :link_filter
|
487
|
+
|
488
|
+
def initialize(node)
|
489
|
+
@node = node
|
490
|
+
@c_paths = {}
|
491
|
+
@link_filter = nil
|
492
|
+
end
|
493
|
+
|
494
|
+
def find_shortest_path_to_node(dest, max_lev=1.0/0.0,
|
495
|
+
path_cache=@c_paths)
|
496
|
+
#$PDbgLog.sig_call(self)
|
497
|
+
if max_lev < 0
|
498
|
+
#$PDbgLog.sig_return("max_lev < 0: nil")
|
499
|
+
return nil
|
500
|
+
end
|
501
|
+
path_cache = {} unless path_cache
|
502
|
+
if @link_filter
|
503
|
+
#$PDbgLog.sig_return
|
504
|
+
return self.find_shortest_path_to_node_with_link_filter(
|
505
|
+
dest, max_lev, path_cache)
|
506
|
+
end
|
507
|
+
path_cache[@node] = [0, nil] unless path_cache.include?(@node)&&
|
508
|
+
path_cache[@node][0] <= 0 && path_cache[@node][1] == nil
|
509
|
+
tail = PMinHeap.new { |a,b| a[1] <=> b[1] }
|
510
|
+
path_cache.each_pair { |node, frm| tail.push([node, frm[0]]) }
|
511
|
+
while !tail.empty?
|
512
|
+
node, lev = *tail.pop
|
513
|
+
next if path_cache.include?(node) &&
|
514
|
+
path_cache[node][0] < lev
|
515
|
+
if path_cache.include?(dest)
|
516
|
+
res = NodePath.new; node = dest
|
517
|
+
to_link = path_cache[node][1]
|
518
|
+
while to_link
|
519
|
+
res << to_link
|
520
|
+
to_link = path_cache[to_link.node][1]
|
521
|
+
end
|
522
|
+
res.reverse_links!
|
523
|
+
#$PDbgLog.sig_return(res.inspect)
|
524
|
+
return res
|
525
|
+
end
|
526
|
+
node.conns.each_with_index { |conn,conn_i| l = conn.exit
|
527
|
+
if (l_lev = lev+conn.length) <= max_lev &&
|
528
|
+
(!path_cache.include?(l) || path_cache[l][0] > l_lev)
|
529
|
+
tail.push([l, l_lev])
|
530
|
+
path_cache[l]=[l_lev,NodeLink.new(node,conn_i)]
|
531
|
+
end
|
532
|
+
}
|
533
|
+
end
|
534
|
+
#$PDbgLog.sig_return("nil")
|
535
|
+
nil
|
536
|
+
end
|
537
|
+
|
538
|
+
def find_shortest_path_to_node_with_link_filter(dest, max_lev,
|
539
|
+
path_cache)
|
540
|
+
#$PDbgLog.sig_call(self)
|
541
|
+
path_cache[@node] = [0, nil] unless path_cache.include?(@node)&&
|
542
|
+
path_cache[@node][0] <= 0 && path_cache[@node][1] == nil
|
543
|
+
tail = PMinHeap.new { |a,b| a[1] <=> b[1] }
|
544
|
+
path_cache.each_pair { |node, frm| tail.push([node, frm[0]]) }
|
545
|
+
#$PDbgLog.print_msg "node#{@node.coords_to_s}, dest#{dest.
|
546
|
+
# coords_to_s}, max_lev=#{max_lev}: "
|
547
|
+
while !tail.empty?
|
548
|
+
node, lev = *tail.pop
|
549
|
+
# $PDbgLog.print_msg "node#{node.coords_to_s},lev=#{lev} "
|
550
|
+
next if path_cache.include?(node) &&
|
551
|
+
path_cache[node][0] < lev
|
552
|
+
if path_cache.include?(dest)
|
553
|
+
res = NodePath.new; node = dest
|
554
|
+
to_link = path_cache[node][1]
|
555
|
+
while to_link
|
556
|
+
res << to_link
|
557
|
+
to_link = path_cache[to_link.node][1]
|
558
|
+
end
|
559
|
+
res.reverse_links!
|
560
|
+
#$PDbgLog.sig_return('found ' + res.to_s + '.')
|
561
|
+
return res
|
562
|
+
end
|
563
|
+
node.conns.each_with_index { |conn,conn_i| l = conn.exit
|
564
|
+
#$PDbgLog.print_msg "conn #{conn_i}: #{conn} "
|
565
|
+
if (l_lev = lev+conn.length) <= max_lev &&
|
566
|
+
(!path_cache.include?(l) || path_cache[l][0]>l_lev) &&
|
567
|
+
@link_filter.call(link=NodeLink.new(node,conn_i))
|
568
|
+
tail.push([l, l_lev])
|
569
|
+
path_cache[l]=[l_lev, link]
|
570
|
+
end
|
571
|
+
}
|
572
|
+
end
|
573
|
+
#$PDbgLog.sig_return("no path found.")
|
574
|
+
nil
|
575
|
+
end
|
576
|
+
|
577
|
+
def self.path_cache_to_s(path_cache)
|
578
|
+
"{#{path_cache.keys.to_a.sort.collect{|k| k.to_s + "=>[#{
|
579
|
+
path_cache[k][0]}, " + (path_cache[k][1] ?
|
580
|
+
path_cache[k][1].to_s : 'nil') + "]"}.join(", ")}}"
|
581
|
+
end
|
582
|
+
|
583
|
+
def self.path_cache_get_path_to_self(node, path_cache)
|
584
|
+
to_link = path_cache[node][1]
|
585
|
+
res = NodePath.new
|
586
|
+
while !to_link.node.node_eql?(node)
|
587
|
+
res << to_link
|
588
|
+
to_link = path_cache[to_link.node]
|
589
|
+
end
|
590
|
+
res << to_link
|
591
|
+
res.reverse_links!
|
592
|
+
end
|
593
|
+
|
594
|
+
def self.path_cache_get_path(node, path_cache)
|
595
|
+
#$PDbgLog.sig_call(self)
|
596
|
+
#$PDbgLog.print_msg "node#{node}, path_cache: #{self.
|
597
|
+
# path_cache_to_s(path_cache)}: "
|
598
|
+
to_link = path_cache[node][1]
|
599
|
+
res = NodePath.new
|
600
|
+
while to_link
|
601
|
+
res << to_link
|
602
|
+
to_link = path_cache[to_link.node][1]
|
603
|
+
end
|
604
|
+
res.reverse_links!
|
605
|
+
#$PDbgLog.sig_return(res.to_s(1))
|
606
|
+
res
|
607
|
+
end
|
608
|
+
|
609
|
+
def find_first_path_to(dest, max_lev=1.0/0.0, path_cache=nil)
|
610
|
+
if max_lev < 0
|
611
|
+
return nil
|
612
|
+
end
|
613
|
+
if @link_filter
|
614
|
+
return self.find_first_path_to_with_link_filter(dest,
|
615
|
+
max_lev, path_cache)
|
616
|
+
end
|
617
|
+
if dest.kind_of?(Proc)
|
618
|
+
dest_proc = dest
|
619
|
+
else
|
620
|
+
dest_proc = proc {|node,lev| dest.node_eql?(node)}
|
621
|
+
end
|
622
|
+
tail = PMinHeap.new { |frm1,frm2| frm1[1] <=> frm2[1] }
|
623
|
+
unless path_cache
|
624
|
+
path_cache = @c_paths
|
625
|
+
unless dest.kind_of?(Proc)
|
626
|
+
return NodeCalc.path_cache_get_path(dest,
|
627
|
+
path_cache) if path_cache.include?(dest)
|
628
|
+
end
|
629
|
+
path_cache.each_pair { |node, frm|
|
630
|
+
tail.push([node, frm[0]]) }
|
631
|
+
end
|
632
|
+
path_cache[@node] = [0, nil]
|
633
|
+
tail.push([@node, 0])
|
634
|
+
while !tail.empty?
|
635
|
+
node, lev = *tail.pop
|
636
|
+
next if path_cache.include?(node) &&
|
637
|
+
path_cache[node][0] < lev
|
638
|
+
if dest_proc.call(node, lev)
|
639
|
+
res = NodeCalc.path_cache_get_path(node,
|
640
|
+
path_cache)
|
641
|
+
return res
|
642
|
+
end
|
643
|
+
node.conns.each_with_index { |conn,conn_i| l = conn.exit
|
644
|
+
if (l_lev = lev + conn.length) <= max_lev &&
|
645
|
+
(!path_cache.include?(l) || path_cache[l][0] > l_lev)
|
646
|
+
tail.push([l, l_lev])
|
647
|
+
path_cache[l]=[l_lev,NodeLink.new(node,conn_i)]
|
648
|
+
end
|
649
|
+
}
|
650
|
+
end
|
651
|
+
nil
|
652
|
+
end
|
653
|
+
|
654
|
+
def find_first_path_to_with_link_filter(dest, max_lev, path_cache=nil)
|
655
|
+
#$PDbgLog.sig_call(self)
|
656
|
+
#$PDbgLog.print_msg "dest:#{dest}, max_lev=#{max_lev}"
|
657
|
+
if dest.kind_of?(Proc)
|
658
|
+
dest_proc = dest
|
659
|
+
else
|
660
|
+
dest_proc = proc {|node,lev| dest.node_eql?(node)}
|
661
|
+
end
|
662
|
+
tail = PMinHeap.new { |frm1,frm2| frm1[1] <=> frm2[1] }
|
663
|
+
unless path_cache
|
664
|
+
path_cache = @c_paths
|
665
|
+
if !dest.kind_of?(Proc) && path_cache.include?(dest)
|
666
|
+
#$PDbgLog.sig_return(': cached.')
|
667
|
+
return NodeCalc.path_cache_get_path(dest,
|
668
|
+
path_cache)
|
669
|
+
end
|
670
|
+
path_cache.each_pair { |node, frm|
|
671
|
+
tail.push([node, frm[0]]) }
|
672
|
+
end
|
673
|
+
path_cache[@node] = [0, nil]
|
674
|
+
tail.push([@node, 0])
|
675
|
+
while !tail.empty?
|
676
|
+
node, lev = *tail.pop
|
677
|
+
next if path_cache.include?(node) &&
|
678
|
+
path_cache[node][0] < lev
|
679
|
+
#$PDbgLog.print_msg "node#{node},lev=#{lev} "
|
680
|
+
if dest_proc.call(node, lev)
|
681
|
+
res = NodeCalc.path_cache_get_path(node,
|
682
|
+
path_cache)
|
683
|
+
#$PDbgLog.sig_return('Done.')
|
684
|
+
return res
|
685
|
+
end
|
686
|
+
node.conns.each_with_index { |conn,conn_i| l = conn.exit
|
687
|
+
if (l_lev = lev + conn.length) <= max_lev &&
|
688
|
+
(!path_cache.include?(l) || path_cache[l][0]>l_lev) &&
|
689
|
+
@link_filter.call(link=NodeLink.new(node,conn_i))
|
690
|
+
tail.push([l, l_lev])
|
691
|
+
path_cache[l] = [l_lev, link]
|
692
|
+
end
|
693
|
+
}
|
694
|
+
end
|
695
|
+
#$PDbgLog.sig_return(': nil')
|
696
|
+
nil
|
697
|
+
end
|
698
|
+
|
699
|
+
def kill_path_cache!
|
700
|
+
@c_paths.clear
|
701
|
+
end
|
702
|
+
|
703
|
+
def path_cache_each_path
|
704
|
+
iter = NodeCalcPCachePathIter.new(@c_paths)
|
705
|
+
@c_paths.each_key { |node|
|
706
|
+
iter.node = node
|
707
|
+
yield(iter)
|
708
|
+
}
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
end
|