geotree 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.txt +3 -0
- data/README.txt +6 -0
- data/lib/geotree.rb +1 -0
- data/lib/geotree/blockfile.rb +453 -0
- data/lib/geotree/bounds.rb +81 -0
- data/lib/geotree/datapoint.rb +68 -0
- data/lib/geotree/diskblockfile.rb +64 -0
- data/lib/geotree/externalsort.rb +369 -0
- data/lib/geotree/geotree.rb +980 -0
- data/lib/geotree/loc.rb +76 -0
- data/lib/geotree/multitree.rb +190 -0
- data/lib/geotree/node.rb +252 -0
- data/lib/geotree/pswriter.rb +471 -0
- data/lib/geotree/ptbuffer.rb +120 -0
- data/lib/geotree/tools.rb +626 -0
- data/test/test_blockfile.rb +153 -0
- data/test/test_externalsort.rb +139 -0
- data/test/test_geotree.rb +432 -0
- data/test/test_ps.rb +56 -0
- metadata +76 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require_relative '../lib/geotree/tools.rb'
|
4
|
+
req('blockfile diskblockfile')
|
5
|
+
|
6
|
+
|
7
|
+
#SINGLETEST = "test_200_recover_with_incorrect_password"
|
8
|
+
if defined? SINGLETEST
|
9
|
+
if main?(__FILE__)
|
10
|
+
ARGV.concat("-n #{SINGLETEST}".split)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class TestBlockFile < Test::Unit::TestCase #< MyTestSuite
|
15
|
+
|
16
|
+
|
17
|
+
# include BlockFile
|
18
|
+
# include LEnc
|
19
|
+
|
20
|
+
# Make a directory, if it doesn't already exist
|
21
|
+
def mkdir(name)
|
22
|
+
if !File.directory?(name)
|
23
|
+
Dir::mkdir(name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def suite_setup
|
28
|
+
# pr("\n\n>>>> TestBlockFile setup\n\n")
|
29
|
+
|
30
|
+
# Make current directory = the one containing this script
|
31
|
+
main?(__FILE__)
|
32
|
+
|
33
|
+
@@testDir = "__temp_dirs__"
|
34
|
+
mkdir(@@testDir)
|
35
|
+
|
36
|
+
|
37
|
+
clean()
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def clean
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_bf
|
45
|
+
if !@bf
|
46
|
+
@bf = BlockFile.new(64)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def suite_teardown
|
51
|
+
# pr("\n\n<<<< TestBlockFile teardown\n\n")
|
52
|
+
end
|
53
|
+
|
54
|
+
def method_setup
|
55
|
+
# pr("\n\n\n")
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_teardown
|
59
|
+
@bf = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
def ex(args)
|
65
|
+
if args.is_a? String
|
66
|
+
args = args.split
|
67
|
+
end
|
68
|
+
args.concat(["-w", @@sourceDir, "-q"])
|
69
|
+
LEncApp.new().run(args)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
# --------------- tests --------------------------
|
74
|
+
|
75
|
+
def test_100_create_block_file
|
76
|
+
build_bf
|
77
|
+
assert(@bf && !@bf.open?)
|
78
|
+
end
|
79
|
+
def test_110_create_and_open_block_file
|
80
|
+
build_bf
|
81
|
+
@bf.open
|
82
|
+
assert(@bf && @bf.open?)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_120_user_values
|
86
|
+
build_bf
|
87
|
+
@bf.open
|
88
|
+
k = 42
|
89
|
+
@bf.write_user(2,k)
|
90
|
+
@bf.write_user(1,k/2)
|
91
|
+
assert(@bf.read_user(2) == k)
|
92
|
+
assert(@bf.read_user(1) == k/2)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_130_read_when_not_open
|
96
|
+
assert_raise(IllegalStateException) do
|
97
|
+
build_bf
|
98
|
+
@bf.write_user(2,42)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_140_private_constant_access
|
103
|
+
assert_raise(NameError) do
|
104
|
+
BlockFile::BLOCKTYPE_RECYCLE
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# def test_140_phony
|
109
|
+
# assert_raise(IllegalStateException) do
|
110
|
+
# puts "nothing"
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
if true && __FILE__ == $0
|
117
|
+
|
118
|
+
pth = '__foo__.bin'
|
119
|
+
remove_file_or_dir(pth)
|
120
|
+
|
121
|
+
bf = DiskBlockFile.new(64,pth)
|
122
|
+
bf.open
|
123
|
+
|
124
|
+
bnames = []
|
125
|
+
(20..40).each do |i|
|
126
|
+
by = bf.alloc_buffer
|
127
|
+
bf.block_size.times do |x|
|
128
|
+
by[x] = i.chr
|
129
|
+
end
|
130
|
+
# bf.write(n,by)
|
131
|
+
n = bf.alloc(by)
|
132
|
+
bnames << n
|
133
|
+
pr("i=#{i} n=#{n} block_size=%d\n",bf.block_size)
|
134
|
+
pr("alloc'd block #{n}:\n%s\n",n,bf.dump(n))
|
135
|
+
end
|
136
|
+
|
137
|
+
5.times do
|
138
|
+
q = bnames.pop
|
139
|
+
|
140
|
+
bf.free q
|
141
|
+
pr("\n\n\nafter freeing %d: %s\n",q,d(bf))
|
142
|
+
|
143
|
+
if (q % 3 == 2)
|
144
|
+
q2 = bf.alloc
|
145
|
+
pr(" alloc'd another page #{q2}\n")
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
puts bf
|
151
|
+
bf.close
|
152
|
+
end
|
153
|
+
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require_relative '../lib/geotree/tools.rb'
|
4
|
+
req('externalsort')
|
5
|
+
|
6
|
+
include ExternalSortModule
|
7
|
+
|
8
|
+
class TestExternalSort < MyTestSuite
|
9
|
+
include ExternalSortModule
|
10
|
+
|
11
|
+
ELEM_SIZE = 16
|
12
|
+
|
13
|
+
# Make a directory, if it doesn't already exist
|
14
|
+
def mkdir(name)
|
15
|
+
if !File.directory?(name)
|
16
|
+
Dir::mkdir(name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def suite_setup
|
21
|
+
|
22
|
+
# Make current directory = the one containing this script
|
23
|
+
main?(__FILE__)
|
24
|
+
|
25
|
+
@@test_dir = "workdir"
|
26
|
+
mkdir(@@test_dir)
|
27
|
+
|
28
|
+
@@path = File.join(@@test_dir,"_input_.dat")
|
29
|
+
raise Exception,"no test file found" if !File.file?(@@path)
|
30
|
+
|
31
|
+
@@path3 = File.join(@@test_dir,"_largefile_.dat")
|
32
|
+
end
|
33
|
+
|
34
|
+
def prepare_unsorted
|
35
|
+
@@path2 = File.join(@@test_dir,"_output_.dat")
|
36
|
+
remove_file_or_dir(@@path2)
|
37
|
+
FileUtils.cp(@@path,@@path2)
|
38
|
+
|
39
|
+
fs = File.size(@@path2)
|
40
|
+
File.truncate(@@path2, fs - fs % ELEM_SIZE)
|
41
|
+
end
|
42
|
+
|
43
|
+
def suite_teardown
|
44
|
+
# remove_file_or_dir(@@path3)
|
45
|
+
end
|
46
|
+
|
47
|
+
def method_setup
|
48
|
+
end
|
49
|
+
|
50
|
+
def method_teardown
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_chunk
|
54
|
+
db = false
|
55
|
+
|
56
|
+
prepare_unsorted
|
57
|
+
|
58
|
+
f = File.open(@@path,"rb")
|
59
|
+
f2 = File.open(@@path2,"wb")
|
60
|
+
|
61
|
+
fs = File.size(@@path)
|
62
|
+
fs -= fs % ELEM_SIZE
|
63
|
+
|
64
|
+
ch = ChunkReader.new(f, 0, fs, ELEM_SIZE, 73 )
|
65
|
+
|
66
|
+
ch2 = ChunkWriter.new(f2,0,fs,ELEM_SIZE, 300 )
|
67
|
+
|
68
|
+
while !ch.done
|
69
|
+
!db|| puts(ch.peek_dump)
|
70
|
+
|
71
|
+
buff, offset = ch.read()
|
72
|
+
!db||pr("Read: %s",hex_dump_to_string(buff[offset,ch.element_size]))
|
73
|
+
ch2.write(buff,offset)
|
74
|
+
end
|
75
|
+
!db || pr("%s\n%s\n",d(ch),d(ch2))
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_sort
|
80
|
+
|
81
|
+
db = false
|
82
|
+
|
83
|
+
prepare_unsorted
|
84
|
+
|
85
|
+
!db|| pr("before sorting:\n")
|
86
|
+
!db|| puts(hex_dump(read_text_file(@@path2)))
|
87
|
+
sr = Sorter.new(@@path2, ELEM_SIZE, nil, 90, 8)
|
88
|
+
|
89
|
+
sr.sort
|
90
|
+
!db|| pr("after sorting:\n")
|
91
|
+
!db|| puts(hex_dump(read_text_file(@@path2)))
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def test_sort_large
|
96
|
+
|
97
|
+
elem_size = 16
|
98
|
+
|
99
|
+
if !File.file?(@@path3)
|
100
|
+
pr("Constructing LARGE file for sort test...\n")
|
101
|
+
f = File.open(@@path3,"wb+")
|
102
|
+
srand(1965)
|
103
|
+
|
104
|
+
a = 'abcdefghijklmnopABCDEFGHIJKLMNOP'.chars
|
105
|
+
a = a[0...elem_size]
|
106
|
+
|
107
|
+
tot = 10_000_000 / 20
|
108
|
+
|
109
|
+
tot.times do |i|
|
110
|
+
s = a.shuffle.join
|
111
|
+
f.write(s)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
c1 = Proc.new do |x,y|
|
116
|
+
bx,ox = x
|
117
|
+
by,oy = y
|
118
|
+
bx[ox,elem_size] <=> by[oy,elem_size]
|
119
|
+
end
|
120
|
+
c2 = Proc.new do |x,y|
|
121
|
+
bx,ox = x
|
122
|
+
by,oy = y
|
123
|
+
bx[ox+1,elem_size-1] <=> by[oy+1,elem_size-1]
|
124
|
+
end
|
125
|
+
|
126
|
+
pr("Sorting file in one way...\n")
|
127
|
+
|
128
|
+
sr = Sorter.new(@@path3, elem_size, c2)
|
129
|
+
sr.sort
|
130
|
+
|
131
|
+
pr("Sorting file in another...\n")
|
132
|
+
|
133
|
+
sr = Sorter.new(@@path3, elem_size, c1)
|
134
|
+
sr.sort
|
135
|
+
pr("...done sorting\n")
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,432 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require_relative '../lib/geotree/tools.rb'
|
4
|
+
req('geotree pswriter multitree')
|
5
|
+
|
6
|
+
include GeoTreeModule
|
7
|
+
|
8
|
+
#SINGLETEST = "test_ps_output_multi"
|
9
|
+
if defined? SINGLETEST
|
10
|
+
if main?(__FILE__)
|
11
|
+
ARGV.concat("-n #{SINGLETEST}".split)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class TestGeoTree < MyTestSuite
|
16
|
+
# Make a directory, if it doesn't already exist
|
17
|
+
def mkdir(name)
|
18
|
+
if !File.directory?(name)
|
19
|
+
Dir::mkdir(name)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def rnd_subset(pts, frac = 0.3)
|
24
|
+
raise ArgumentError if pts.empty?
|
25
|
+
|
26
|
+
a = pts.dup
|
27
|
+
num = [(a.size * frac).to_i.ceil,a.size].min
|
28
|
+
srand(1977)
|
29
|
+
a.shuffle!
|
30
|
+
del = a.slice!(0..num)
|
31
|
+
rem = a
|
32
|
+
[del,rem]
|
33
|
+
end
|
34
|
+
|
35
|
+
def pt_set(set = 0)
|
36
|
+
assert(set < @@pts.size )
|
37
|
+
@@pts[set]
|
38
|
+
end
|
39
|
+
|
40
|
+
def rel_path(path)
|
41
|
+
File.join(@@test_dir,path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def suite_setup
|
45
|
+
n_pts = 3000
|
46
|
+
|
47
|
+
# Make current directory = the one containing this script
|
48
|
+
main?(__FILE__)
|
49
|
+
|
50
|
+
@@test_dir = "workdir"
|
51
|
+
mkdir(@@test_dir)
|
52
|
+
@@tree_path = rel_path("_mytree_.dat")
|
53
|
+
|
54
|
+
clean()
|
55
|
+
|
56
|
+
@@pts = []
|
57
|
+
srand(7)
|
58
|
+
|
59
|
+
@@pts << DataPoint.rnd_many(n_pts)
|
60
|
+
|
61
|
+
p2 = DataPoint.rnd_many(n_pts/4)
|
62
|
+
i = 0
|
63
|
+
while i < p2.size
|
64
|
+
n = [p2.size-i, 200].min
|
65
|
+
pi = p2[i]
|
66
|
+
(i...i+n).each do |j|
|
67
|
+
pj = p2[j]
|
68
|
+
pj.loc.set_to(pi.loc)
|
69
|
+
end
|
70
|
+
i += n
|
71
|
+
end
|
72
|
+
p2.shuffle!
|
73
|
+
|
74
|
+
@@pts << p2
|
75
|
+
|
76
|
+
p3 = DataPoint.rnd_many(n_pts)
|
77
|
+
p3.each_with_index do |pt,i|
|
78
|
+
pt.loc=Loc.new(i*5,i*5)
|
79
|
+
end
|
80
|
+
@@pts << p3
|
81
|
+
|
82
|
+
srand(2000)
|
83
|
+
@@rects = Bounds.rnd_many(20)
|
84
|
+
end
|
85
|
+
|
86
|
+
def tree
|
87
|
+
@@t ||= GeoTree.open(@@tree_path)
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_pts(set = 0, max_pts = 0)
|
91
|
+
ps = @@pts[set]
|
92
|
+
if max_pts > 0
|
93
|
+
ps = ps[0,max_pts]
|
94
|
+
end
|
95
|
+
ps.each{|dp| tree.add(dp)}
|
96
|
+
tree.buffering = false
|
97
|
+
end
|
98
|
+
|
99
|
+
def clean(delete_tree_file = true)
|
100
|
+
@@t = nil
|
101
|
+
return if !delete_tree_file
|
102
|
+
remove_file_or_dir(@@tree_path)
|
103
|
+
end
|
104
|
+
|
105
|
+
def suite_teardown
|
106
|
+
end
|
107
|
+
|
108
|
+
def method_setup
|
109
|
+
end
|
110
|
+
|
111
|
+
def method_teardown
|
112
|
+
end
|
113
|
+
|
114
|
+
# Construct list of data points lying within a rectangle
|
115
|
+
def pts_within_rect(pts,r)
|
116
|
+
names = pts.select{|pt| r.contains_point(pt.loc)}
|
117
|
+
end
|
118
|
+
|
119
|
+
def names(pt_list)
|
120
|
+
DataPoint.name_list(pt_list)
|
121
|
+
end
|
122
|
+
|
123
|
+
def query(tree, b, pts = nil)
|
124
|
+
pts ||= pt_set
|
125
|
+
|
126
|
+
db = false
|
127
|
+
!db || pr("query rect= #{b}\n")
|
128
|
+
|
129
|
+
!db || pr("tree find=#{tree.find(b)}\n")
|
130
|
+
|
131
|
+
f1 = names(tree.find(b))
|
132
|
+
f2 = names(pts_within_rect(pts,b))
|
133
|
+
!db || pr("Find #{b} returned:\n #{d(f1)}\n #{d(f2)}\n")
|
134
|
+
|
135
|
+
if (!(f1 == f2))
|
136
|
+
raise IllegalStateException, "Query tree, bounds #{b}, expected #{d(f2)}, got #{d(f1)}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_create_tree
|
141
|
+
clean
|
142
|
+
tree
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_add_points
|
146
|
+
clean
|
147
|
+
add_pts
|
148
|
+
# puts(tree.dump)
|
149
|
+
# puts("Tree stats:\n#{d2(tree.statistics)}\n")
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_queries
|
153
|
+
clean
|
154
|
+
add_pts
|
155
|
+
bn = @@rects
|
156
|
+
bn.each{|b| query(tree,b)}
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_remove
|
160
|
+
db = false
|
161
|
+
# db = true
|
162
|
+
|
163
|
+
@@pts.each_with_index do |pset,i|
|
164
|
+
clean
|
165
|
+
|
166
|
+
# Use buffering, since some point sets are very unbalanced
|
167
|
+
tree.buffering = true
|
168
|
+
add_pts(i)
|
169
|
+
|
170
|
+
pts = pset
|
171
|
+
while !pts.empty?
|
172
|
+
|
173
|
+
del, rem = rnd_subset(pts)
|
174
|
+
!db || pr("\nChose subset size #{del.size} of points #{pts.size}...\n")
|
175
|
+
|
176
|
+
# !db || puts(tree.dump)
|
177
|
+
|
178
|
+
if !del.empty?
|
179
|
+
# construct a copy of the first point to be removed, one with a slightly
|
180
|
+
# different location, to verify that it won't get removed
|
181
|
+
pt = del[0]
|
182
|
+
loc = pt.loc
|
183
|
+
while true
|
184
|
+
x = loc.x + rand(3)-1
|
185
|
+
y = loc.y + rand(3) - 1
|
186
|
+
break if x!=loc.x || y != loc.y
|
187
|
+
end
|
188
|
+
|
189
|
+
pt = DataPoint.new(pt.name, pt.weight, Loc.new(x,y))
|
190
|
+
!db || pr("Attempting to remove perturbed point #{pt}")
|
191
|
+
pt2 = tree.remove(pt)
|
192
|
+
assert(!pt2)
|
193
|
+
# !db || puts(tree.dump)
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
del.each do |pt|
|
198
|
+
!db || pr(" attempting to remove #{pt}\n")
|
199
|
+
# !db || puts(tree.dump)
|
200
|
+
|
201
|
+
dp = tree.remove(pt)
|
202
|
+
assert(dp,"failed to remove #{pt}")
|
203
|
+
end
|
204
|
+
|
205
|
+
# try removing each point again to verify we can't
|
206
|
+
del.each do |pt|
|
207
|
+
!db || pr(" attempting to remove #{pt} again\n")
|
208
|
+
dp = tree.remove(pt)
|
209
|
+
assert(!dp)
|
210
|
+
end
|
211
|
+
pts = rem
|
212
|
+
|
213
|
+
# !db || puts(tree.dump)
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_buffering
|
220
|
+
db = false
|
221
|
+
# db = true
|
222
|
+
|
223
|
+
return if !db
|
224
|
+
|
225
|
+
!db || pr("test buffering\n")
|
226
|
+
|
227
|
+
clean
|
228
|
+
tree
|
229
|
+
|
230
|
+
tree.buffering = true
|
231
|
+
add_pts(2) #2,2000)
|
232
|
+
stat1 = tree.statistics
|
233
|
+
assert(stat1['leaf_depth (avg)'] < 2.6)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Test using points expressed in terms of longitude(x) and latitude(y)
|
237
|
+
def test_latlong
|
238
|
+
db = false
|
239
|
+
|
240
|
+
clean
|
241
|
+
t = tree
|
242
|
+
|
243
|
+
pts = []
|
244
|
+
|
245
|
+
pts << Loc.new(57.9,-2.9) # Aberdeen
|
246
|
+
pts << Loc.new(19.26,-99.7) # Mexico City
|
247
|
+
pts << Loc.new(-26.12,28.4) # Johannesburg
|
248
|
+
|
249
|
+
pts.each_with_index do |pt,i|
|
250
|
+
t.add(DataPoint.new(1+i,0,pt))
|
251
|
+
end
|
252
|
+
|
253
|
+
!db||pr("pts:\n%s\n",d2(pts))
|
254
|
+
|
255
|
+
pts.each_with_index do |lc,i|
|
256
|
+
y,x = lc.latit, lc.longit
|
257
|
+
!db|| pr("y,x=#{y},#{x}\n")
|
258
|
+
b = Bounds.new(x-1,y-1,2,2)
|
259
|
+
|
260
|
+
r = t.find(b)
|
261
|
+
assert(r.size == 1)
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_latlong_range_error
|
267
|
+
assert_raise(ArgumentError) do
|
268
|
+
b = Bounds.new(175.0,50,10,10)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_open_and_close
|
273
|
+
|
274
|
+
clean
|
275
|
+
t = tree
|
276
|
+
ps = pt_set(0)
|
277
|
+
npts = ps.size
|
278
|
+
|
279
|
+
ps.each do |dp|
|
280
|
+
t.add(dp)
|
281
|
+
end
|
282
|
+
|
283
|
+
t.close
|
284
|
+
@@t = nil
|
285
|
+
|
286
|
+
t = tree
|
287
|
+
ps2 = t.find(GeoTree.max_bounds)
|
288
|
+
|
289
|
+
assert(ps2.size == ps.size)
|
290
|
+
end
|
291
|
+
|
292
|
+
def plot_pts(w,pts,gray=0)
|
293
|
+
w.push(w.set_gray(gray))
|
294
|
+
plot_pts_colored(w,pts)
|
295
|
+
w.pop
|
296
|
+
end
|
297
|
+
|
298
|
+
def plot_pts_colored(w,pts,scale=1)
|
299
|
+
pts.each do |pt|
|
300
|
+
w.draw_disc(pt.loc.x,pt.loc.y,scale*0.3*(pt.weight+4))
|
301
|
+
end
|
302
|
+
|
303
|
+
end
|
304
|
+
|
305
|
+
def pt_on_circle(cx,cy,ang,rad)
|
306
|
+
|
307
|
+
x = cx + Math.cos(ang) * rad
|
308
|
+
y = cy + Math.sin(ang) * rad
|
309
|
+
Loc.new(x.to_i,y.to_i)
|
310
|
+
end
|
311
|
+
|
312
|
+
def prepare_tree(tree)
|
313
|
+
|
314
|
+
ps1 = pt_set(0)
|
315
|
+
ps1 = ps1[0,120]
|
316
|
+
|
317
|
+
srand(42)
|
318
|
+
ps2 = DataPoint.rnd_many(400)
|
319
|
+
ps2.each do |pt|
|
320
|
+
rs = rand*rand*500
|
321
|
+
pc = pt_on_circle(820,620,rand * 2*3.1415,rs)
|
322
|
+
pt.loc = pc
|
323
|
+
end
|
324
|
+
ps1.concat(ps2)
|
325
|
+
|
326
|
+
ps1.each{|x| tree.add(x)}
|
327
|
+
ps1
|
328
|
+
end
|
329
|
+
|
330
|
+
def prepare_ws(path)
|
331
|
+
b = Bounds.new(0,0,1000,1000)
|
332
|
+
|
333
|
+
w = PSWriter.new(rel_path(path))
|
334
|
+
|
335
|
+
w.set_logical_page_size(b.w,b.h)
|
336
|
+
|
337
|
+
w
|
338
|
+
end
|
339
|
+
|
340
|
+
def test_ps_output
|
341
|
+
|
342
|
+
tree = GeoTree.new
|
343
|
+
ps1 = prepare_tree(tree)
|
344
|
+
w = prepare_ws("tree.ps")
|
345
|
+
# ps1,w = prepare_ws(tree,"tree.ps")
|
346
|
+
|
347
|
+
50.times do |i|
|
348
|
+
w.new_page("GeoTree")
|
349
|
+
|
350
|
+
a = i * 3.1415/18
|
351
|
+
rad = 30+i*8
|
352
|
+
|
353
|
+
pp = pt_on_circle(500,450,a,rad)
|
354
|
+
x = pp.x
|
355
|
+
y = pp.y
|
356
|
+
|
357
|
+
width = (200 * (20+i)) / 25
|
358
|
+
height = (width * 2)/3
|
359
|
+
r = Bounds.new(x-width/2,y-height/2,width,height)
|
360
|
+
pts = tree.find(r)
|
361
|
+
w.push(w.set_gray(0))
|
362
|
+
w.draw_rect(r.x,r.y,r.w,r.h )
|
363
|
+
w.pop
|
364
|
+
|
365
|
+
w.push(w.set_rgb(0.4,0.4,0.9))
|
366
|
+
plot_pts_colored(w,ps1)
|
367
|
+
w.pop
|
368
|
+
|
369
|
+
w.push(w.set_rgb(0.75,0,0))
|
370
|
+
plot_pts_colored(w,pts,1.5)
|
371
|
+
w.pop
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
w.close();
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_ps_output_multi
|
379
|
+
|
380
|
+
tree_path = rel_path("_multitree_")
|
381
|
+
|
382
|
+
# Perform two passes. On the first,
|
383
|
+
# create the multitree and the points;
|
384
|
+
# on the second, open the tree and
|
385
|
+
# construct a plot.
|
386
|
+
|
387
|
+
ps1 = nil
|
388
|
+
|
389
|
+
[0,1].each do |pass|
|
390
|
+
|
391
|
+
if pass == 0
|
392
|
+
remove_file_or_dir(tree_path)
|
393
|
+
else
|
394
|
+
assert(File.directory?(tree_path))
|
395
|
+
end
|
396
|
+
|
397
|
+
ndetails = 5
|
398
|
+
tree = MultiTree.new(tree_path,ndetails)
|
399
|
+
|
400
|
+
if pass == 0
|
401
|
+
ps1 = prepare_tree(tree)
|
402
|
+
tree.close
|
403
|
+
else
|
404
|
+
w = prepare_ws("multi_tree.ps")
|
405
|
+
|
406
|
+
steps = 4
|
407
|
+
(ndetails*steps).times do |i|
|
408
|
+
dt = i/steps
|
409
|
+
w.new_page("MultiTree detail=#{dt}")
|
410
|
+
|
411
|
+
r = Bounds.new(10+i*16,190+i*10,700,600)
|
412
|
+
|
413
|
+
pts = tree.find(r,dt)
|
414
|
+
|
415
|
+
w.push(w.set_gray(0))
|
416
|
+
w.draw_rect(r.x,r.y,r.w,r.h )
|
417
|
+
w.pop
|
418
|
+
|
419
|
+
plot_pts(w,ps1,0.8)
|
420
|
+
|
421
|
+
w.push(w.set_rgb(0.75,0,0))
|
422
|
+
plot_pts_colored(w,pts,1.2)
|
423
|
+
w.pop
|
424
|
+
|
425
|
+
end
|
426
|
+
w.close();
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
end
|
432
|
+
|