geotree 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,7 +16,7 @@ module GeoTreeModule
16
16
  # When querying a MultiTree, the user must specify which level of detail (i.e.,
17
17
  # which of the contained trees) is to be examined.
18
18
  #
19
- # {An animation of a MultiTree in action.}[link:../../doc/multi_tree.pdf]
19
+ # {An animation of a MultiTree in action.}[link:http://www.cs.ubc.ca/~jpsember/multi_tree.ps]
20
20
  #
21
21
  class MultiTree
22
22
 
@@ -123,9 +123,7 @@ module GeoTreeModule
123
123
  end
124
124
 
125
125
  def add_buffered_point(data_point)
126
- db = false
127
- # db = true
128
-
126
+
129
127
  # Determine which is the lowest detail level at which
130
128
  # this point is to be found
131
129
 
@@ -137,8 +135,6 @@ module GeoTreeModule
137
135
 
138
136
  randval = (wt + stretch*rf) / MAX_POINT_WEIGHT
139
137
 
140
- !db || pr("add pt#%4d wt%2d rf=%6.3f rand=%6.3f: ",data_point.name,wt,rf,randval)
141
-
142
138
  num_trees.times do |ti|
143
139
  di = num_trees - 1 - ti
144
140
 
@@ -146,10 +142,8 @@ module GeoTreeModule
146
142
  break
147
143
  end
148
144
 
149
- !db || pr(" ++ #{di} ")
150
145
  tree(di).add_buffered_point(data_point)
151
146
  end
152
- !db || pr("\n")
153
147
  end
154
148
 
155
149
  private
@@ -177,16 +171,3 @@ module GeoTreeModule
177
171
  end
178
172
  end
179
173
 
180
- if main?(__FILE__)
181
- include GeoTreeModule
182
- newdir = File.join(File.dirname(__FILE__),"../../test/workdir")
183
- assert!(File.directory?(newdir))
184
- Dir.chdir(newdir)
185
- remove_file_or_dir("_multitree_")
186
-
187
- mt = MultiTree.new("_multitree_",3)
188
-
189
- pts = DataPoint.rnd_many(100)
190
- pts.each{|x| mt.add(x)}
191
-
192
- end
@@ -1,6 +1,22 @@
1
1
  require_relative 'tools'
2
2
 
3
3
  module PS_Private
4
+ LT_SOLID_ = 1900
5
+ LT_DASHED_ = 1901
6
+ LT_DOTTED_ = 1902
7
+
8
+ LINEWIDTH_FACTOR_ = 3.0
9
+ LINETYPE_ = 1
10
+ LINEWIDTH_ = 2
11
+ TRANS_ = 3
12
+ RGB_ = 4
13
+ FONTHEIGHT_ = 5
14
+ SCALE_ = 6
15
+
16
+ S_START_ = 0
17
+ S_OPEN_ = 1
18
+ S_CLOSED_ = 2
19
+
4
20
  class SOper
5
21
  attr_reader :type
6
22
  def self.null
@@ -24,35 +40,40 @@ module PS_Private
24
40
  end
25
41
  end
26
42
 
27
- # A debugging / demonstration utility class that
43
+ # A debugging / demonstration utility class that
28
44
  # generates postscript images
29
45
  #
30
46
  class PSWriter
31
47
  include PS_Private
32
48
 
33
- LT_SOLID = 1900
34
- LT_DASHED = 1901
35
- LT_DOTTED = 1902
36
-
37
- LINEWIDTH_FACTOR = 3.0
38
- LINETYPE = 1
39
- LINEWIDTH = 2
40
- TRANS = 3
41
- RGB = 4
42
- FONTHEIGHT = 5
43
- SCALE = 6
44
-
45
- S_START = 0
46
- S_OPEN = 1
47
- S_CLOSED = 2
48
49
  # @param path path of file to write (e.g. xxx.ps)
49
50
  def initialize(path)
50
51
  @path = path
51
52
  @line_width = -1
52
53
  @rgb = [-1,0,0]
53
54
  @phys_size = [612,792]
54
- @state = S_START
55
+ @state = S_START_
55
56
  @stack = []
57
+ @buffer_stack = []
58
+ @dict = {}
59
+ @dict_keys = []
60
+
61
+ de("A","{arc} bind")
62
+ de("CP","{closepath} bind")
63
+ de('F','{fill} bind')
64
+ de('I','{index} bind')
65
+ de("L","{lineto} bind")
66
+ de("M","{moveto} bind")
67
+ de("NP","{newpath} bind")
68
+ de('SRGB','{setrgbcolor} bind')
69
+ de('SLW','{setlinewidth} bind')
70
+ de('P','{pop} bind')
71
+ de("R","{rmoveto} bind")
72
+ de("S","{stroke} bind")
73
+ de('SCL','{scale} bind')
74
+ de('TR','{translate} bind')
75
+ de("V","{rlineto} bind")
76
+ de("DSH","{setdash} bind")
56
77
 
57
78
  set_logical_page_size(1000,1200)
58
79
 
@@ -65,22 +86,45 @@ class PSWriter
65
86
  @s = ''
66
87
  end
67
88
 
89
+ def start_buffer
90
+ raise IllegalStateException if !@buffer_stack.empty?
91
+ @buffer_stack << @s
92
+ @s = ''
93
+ end
94
+
95
+ def stop_buffer
96
+ raise IllegalStateException if @buffer_stack.empty?
97
+ ret = @s
98
+ @s = @buffer_stack.pop
99
+ ret
100
+ end
101
+
102
+
68
103
  # Close document and write to disk
69
104
  def close
70
- if @state < S_CLOSED
105
+ if @state < S_CLOSED_
71
106
  if @stack.size != 0
72
107
  warn("state stack nonempty for #{@path}")
73
108
  end
109
+
74
110
  flush_page
75
- set_state(S_CLOSED)
76
- write_text_file(@path, @s)
111
+
112
+ # Construct file by combining header, dictionary, and
113
+ # the user text
114
+
115
+ s = get_doc_header
116
+ s << get_doc_dictionary
117
+ s << @s
118
+ set_state(S_CLOSED_)
119
+
120
+ write_text_file(@path, s)
77
121
  end
78
122
  end
79
123
 
80
124
  # Set logical page size. Subsequent drawing operations will be scaled
81
125
  # appropriately. Default logical page size is 1000 x 1200 units.
82
126
  def set_logical_page_size( width, height)
83
- raise IllegalStateException if @state != S_START
127
+ raise IllegalStateException if @state != S_START_
84
128
  @document_size = [width,height]
85
129
  end
86
130
 
@@ -91,83 +135,103 @@ class PSWriter
91
135
  # Draw a rectangle
92
136
  # @param inset distance to inset rectangle boundary (positive: shrink; negative:expand)
93
137
  def draw_rect(x,y,w,h,inset = 0)
138
+ de("RC","{3 I 3 I M 1 I 0 V 0 1 I V 1 I neg 0 V P P P P CP S }")
94
139
  a(x + inset)
95
140
  a(y + inset)
96
141
  a(w - 2 * inset);
97
142
  a(h - 2 * inset);
98
- a(" RECT\n");
143
+ a("RC");
144
+ cr
99
145
  end
100
146
 
101
147
  def set_font_size(height)
102
- raise IllegalStateException if @state != S_OPEN
148
+ raise IllegalStateException if @state != S_OPEN_
103
149
 
104
150
  ret = SOper.null
105
151
 
106
- if @font_height != height
107
- ret = SOper.new(FONTHEIGHT, @font_height)
152
+ if @font_height != height
153
+ ret = SOper.new(FONTHEIGHT_, @font_height)
108
154
  @font_height = height;
109
155
  @scaled_font_height = height / @scale;
110
156
  a("/Monaco findfont ");
111
157
  a(@scaled_font_height);
112
158
  a("scalefont setfont\n");
159
+ cr
113
160
  end
114
161
  ret
115
162
  end
116
163
 
117
164
  def draw_string(string, x, y)
165
+ if @font_height == 0
166
+ set_font_size(28)
167
+ end
168
+
169
+ # /TEXTL { currentpoint S M 0 0 R show } def
170
+ # % Right-justified text
171
+ # /TEXTR { currentpoint S M dup stringwidth pop neg 0 R show } def
172
+ # % Centered text
173
+ de("TX", "{currentpoint S M dup stringwidth pop -2 div 0 R show }")
174
+
118
175
  a(x)
119
176
  a(y - @scaled_font_height / 2);
120
- a("M ")
177
+ a("M")
121
178
  work = make_eps_safe(string)
122
179
  a(work)
123
- a(" TEXTC\n")
180
+ a("TX")
181
+ cr
124
182
  end
125
183
 
126
- def draw_disc(cx, cy, radius)
127
- a("NP");
184
+ def draw_disc(cx,cy,radius)
185
+ de("CF", "{NP 0 360 A CP F}")
128
186
  a(cx);
129
187
  a(cy);
130
188
  a(radius);
131
- a("0 360 A CP F\n");
189
+ a("CF")
190
+ cr
132
191
  end
133
192
 
134
193
  def draw_circle(cx, cy, radius)
194
+ de("CH", "{NP 0 360 A CP S}")
135
195
  a("NP");
136
196
  a(cx);
137
197
  a(cy);
138
198
  a(radius);
139
- a("0 360 A CP S\n");
199
+ a("CH");
200
+ cr
140
201
  end
141
202
 
142
203
  def draw_line(x1,y1,x2,y2)
143
- a("NP ");
204
+ de("LN", "{NP 4 2 roll M L CP S}")
205
+
206
+ # a("NP");
144
207
  a(x1);
145
208
  a(y1);
146
- a(" M ");
209
+ # a("M");
147
210
  a(x2);
148
211
  a(y2);
149
- a(" L CP S\n");
212
+ a("LN");
213
+ cr
150
214
  end
151
215
 
152
216
  def set_line_solid
153
- set_line_type(LT_SOLID)
217
+ set_line_type(LT_SOLID_)
154
218
  end
155
219
 
156
220
  def set_line_dashed
157
- set_line_type(LT_DASHED)
221
+ set_line_type(LT_DASHED_)
158
222
  end
159
223
 
160
224
  def set_line_dotted
161
- set_line_type(LT_DOTTED)
225
+ set_line_type(LT_DOTTED_)
162
226
  end
163
227
 
164
228
  def set_scale(f)
165
229
  ret = SOper.null
166
230
  if f != 1
167
- ret = SOper.new(SCALE, 1.0 / f)
231
+ ret = SOper.new(SCALE_, 1.0 / f)
168
232
  a(f);
169
233
  a(f);
170
- a("scale\n");
234
+ a("SCL");
171
235
  end
172
236
  ret
173
237
  end
@@ -175,24 +239,24 @@ class PSWriter
175
239
  def set_line_type(type)
176
240
  ret = SOper.null
177
241
  if @line_type != type
178
- ret = SOper.new(LINETYPE, @line_type)
242
+ ret = SOper.new(LINETYPE_, @line_type)
179
243
  @line_type = type
180
244
  case type
181
- when LT_DASHED
245
+ when LT_DASHED_
182
246
  n = (@scale * 30).to_i
183
247
  a("[");
184
248
  a(n);
185
249
  a(n);
186
- a("] 0 setdash\n");
187
- when LT_DOTTED
250
+ a("] 0 DSH");
251
+ when LT_DOTTED_
188
252
  int n = (@scale * 30).to_i
189
253
  n2 = n / 4
190
254
  a("[");
191
255
  a(n2);
192
256
  a(n);
193
- a("] 0 setdash\n");
194
- else # LT_SOLID
195
- a("[] 0 setdash\n");
257
+ a("] 0 DSH");
258
+ else # LT_SOLID_
259
+ a("[] 0 DSH");
196
260
  end
197
261
  end
198
262
  ret
@@ -203,38 +267,39 @@ class PSWriter
203
267
  # @param x translation to apply to coordinates
204
268
  # @param y
205
269
  def draw_polygon(polygon, x, y)
270
+
206
271
  push(translate(x, y))
207
- a("NP ")
272
+ a("NP")
208
273
  i = 0
209
274
  while i < polygon.size
210
275
  a(polygon[i])
211
- a(' ');
212
276
  a((polygon[i + 1]))
213
277
  if (i == 0)
214
- a(" M ");
278
+ a("M");
215
279
  else
216
- a(" L ");
280
+ a("L");
217
281
  end
218
282
  i += 2
219
283
  end
220
-
221
- a(" CP S\n")
284
+ a("CP S")
285
+ cr
222
286
  pop()
223
287
  end
224
288
 
225
289
  # Translate subsequent drawing operations
226
290
  def translate(tx,ty,neg=false)
291
+
227
292
  ret = SOper.null
228
293
  if (neg)
229
294
  tx = -tx;
230
295
  ty = -ty;
231
296
  end
232
297
  if (tx != 0 || ty != 0)
233
- ret = SOper.new(TRANS, -tx, -ty)
298
+ ret = SOper.new(TRANS_, -tx, -ty)
234
299
 
235
300
  a(tx);
236
301
  a(ty);
237
- a("TR\n");
302
+ a("TR");
238
303
  end
239
304
  ret
240
305
  end
@@ -242,10 +307,11 @@ class PSWriter
242
307
  def set_line_width(w)
243
308
  ret = SOper.null
244
309
  if @line_width != w
245
- ret = SOper.new(LINEWIDTH, @line_width)
310
+
311
+ ret = SOper.new(LINEWIDTH_, @line_width)
246
312
  @line_width = w
247
- a(LINEWIDTH_FACTOR * @scale * @line_width)
248
- a("SLW\n");
313
+ a(LINEWIDTH_FACTOR_ * @scale * @line_width)
314
+ a("SLW");
249
315
  end
250
316
  ret
251
317
  end
@@ -253,12 +319,13 @@ class PSWriter
253
319
  def set_rgb(r,g,b)
254
320
  ret = SOper.null
255
321
  if (r != @rgb[0] || g != @rgb[1] || b != @rgb[2])
256
- ret = SOper.new(RGB, @rgb[0], @rgb[1], @rgb[2])
322
+
323
+ ret = SOper.new(RGB_, @rgb[0], @rgb[1], @rgb[2])
257
324
  a(r)
258
325
  a(g)
259
326
  a(b)
260
327
  @rgb = [r,g,b]
261
- a("SRGB\n");
328
+ a("SRGB");
262
329
  end
263
330
  ret
264
331
  end
@@ -270,11 +337,11 @@ class PSWriter
270
337
  def set_state( s)
271
338
  if (@state != s)
272
339
  case s
273
- when S_OPEN
274
- raise IllegalStateException if @state != S_START
340
+ when S_OPEN_
341
+ raise IllegalStateException if @state != S_START_
275
342
  @state = s
276
- print_document_header
277
- when S_START
343
+ # print_document_header
344
+ when S_START_
278
345
  raise IllegalStateException
279
346
  end
280
347
  @state = s
@@ -284,7 +351,7 @@ class PSWriter
284
351
  # Start a new page
285
352
  # @param page_title title of new page
286
353
  def new_page(page_title)
287
- set_state(S_OPEN);
354
+ set_state(S_OPEN_);
288
355
  flush_page
289
356
 
290
357
  print_page_header(page_title);
@@ -303,39 +370,82 @@ class PSWriter
303
370
  n = @stack.size - 1
304
371
  op = @stack.pop
305
372
  case op.type
306
- when RGB
373
+ when RGB_
307
374
  set_rgb(op.arg(0),op.arg(1),op.arg(2))
308
- when LINETYPE
375
+ when LINETYPE_
309
376
  set_line_type(op.arg(0))
310
- when LINEWIDTH
377
+ when LINEWIDTH_
311
378
  set_line_width(op.arg(0))
312
- when TRANS
379
+ when TRANS_
313
380
  translate(op.arg(0),op.arg(1))
314
- when FONTHEIGHT
381
+ when FONTHEIGHT_
315
382
  set_font_size(op.arg(0))
316
- when SCALE
383
+ when SCALE_
317
384
  set_scale(op.arg(0))
318
385
  end
319
386
  end
320
387
  end
321
388
 
389
+ # Define an element by placing it in the dictionary
390
+ def add_element(key,val)
391
+ de(key,'{'+val+'}')
392
+ end
393
+
394
+ def draw_element(key)
395
+ val = @dict[key]
396
+ raise ArgumentError if !@dict.member?(key)
397
+ a(key)
398
+ end
399
+
322
400
  private
323
401
 
402
+ def cr
403
+ if true
404
+ if @sp_req
405
+ @s << ' '
406
+ @sp_req = false
407
+ end
408
+ else
409
+ @sp_req = false
410
+ @s << "\n"
411
+ end
412
+ end
413
+
324
414
  def a(obj)
415
+ if @sp_req
416
+ @s << ' '
417
+ end
325
418
  if obj.is_a? Numeric
326
419
  if obj.is_a? Float
327
- w = sprintf(" %.2f",obj)
328
- @s << w
420
+ w = sprintf("%.2f",obj)
421
+ # Trim extraneous leading/trailing zeros
422
+
423
+ if w[0,2] == '0.'
424
+ w = w[1.. -1]
425
+ elsif w[0,3] == '-0.'
426
+ w[1,1] = ''
427
+ end
428
+
429
+ j = w.index('.')
430
+ if j
431
+ while w[-1] == '0'
432
+ w = w[0..-2]
433
+ end
434
+ if w[-1] == '.'
435
+ w = w[0..-2]
436
+ end
437
+ end
438
+ @s << w
329
439
  else
330
- @s << " #{obj}"
440
+ @s << obj.to_s
331
441
  end
332
442
  else
333
- @s <<' ' << obj
443
+ @s << obj
334
444
  end
445
+ @sp_req = true
335
446
  end
336
447
 
337
448
  def print_page_header(page_title)
338
-
339
449
  # set up transformation
340
450
  lMargin = @phys_size[0] * 0.07
341
451
  lWorkX = @phys_size[0] - 2 * lMargin
@@ -348,10 +458,10 @@ class PSWriter
348
458
 
349
459
  a(lcx)
350
460
  a(lcy)
351
- a("TR\n");
461
+ a("TR");
352
462
  a(scl);
353
463
  a(scl);
354
- a("SCL\n\n");
464
+ a("SCL");
355
465
  set_line_width(1);
356
466
  set_gray(0);
357
467
 
@@ -366,46 +476,40 @@ class PSWriter
366
476
  end
367
477
  end
368
478
 
369
- def print_document_header
370
-
371
- a("%!PS\n");
372
-
373
- a("/Monaco findfont 28 scalefont setfont\n")
374
- a(<<"TXT"
375
- /A {arc} bind def
376
- /CP {closepath} bind def
377
- /NP {newpath} bind def
378
- /TR {translate} bind def
379
- /SCL {scale} bind def
380
- /SLW {setlinewidth} bind def
381
- /SRGB {setrgbcolor} bind def
382
- /S {stroke} bind def
383
- /F {fill} bind def
384
- /M {moveto} bind def
385
- /L {lineto} bind def
386
- /R {rmoveto} bind def
387
- /V {rlineto} bind def
388
- % Left-justified text
389
- /TEXTL { currentpoint S M 0 0 R show } def
390
- % Right-justified text
391
- /TEXTR { currentpoint S M dup stringwidth pop neg 0 R show } def
392
- % Centered text
393
- /TEXTC { currentpoint S M dup stringwidth pop -2 div 0 R show } def
394
-
395
- % Plot rectangle at x,y,w,h
396
- /RECT { 3 index 3 index M
397
- 1 index 0 V
398
- 0 1 index V
399
- 1 index neg 0 V
400
- pop pop pop pop CP
401
- S } def
402
- TXT
403
- )
479
+ def get_doc_header
480
+ h = "%!PS\n"
481
+ end
482
+
483
+ def get_doc_dictionary
484
+ s = ''
485
+ @dict_keys.each do |k|
486
+ v = @dict[k]
487
+ if v.size
488
+ s << '/' << k << ' ' << v << " def\n"
489
+ else
490
+ s2 << '/' << k << "\n"
491
+ end
492
+ end
493
+ s
404
494
  end
405
495
 
496
+ def de(key,val)
497
+ if !@dict.member? key
498
+ @dict_keys << key
499
+ @dict[key] = val
500
+ else
501
+ vexist = @dict[key]
502
+ if vexist != val
503
+ raise ArgumentError,"Attempt to change value for key #{key} to #{val}, was #{vexist}"
504
+ end
505
+
506
+ end
507
+ end
508
+
509
+
406
510
  def flush_page
407
511
  if @page_used
408
- @s << "showpage\n\n"
512
+ a("showpage")
409
513
  @page_used = false
410
514
  end
411
515
  end
@@ -432,40 +536,3 @@ TXT
432
536
 
433
537
  end
434
538
 
435
- if __FILE__ == $0
436
-
437
- poly = [ 0, 0, 50, 30, 30, 80]
438
-
439
- w = PSWriter.new("_jeff_.ps")
440
-
441
- w.set_logical_page_size(1000, 1000)
442
- 10.times do |i|
443
-
444
- w.new_page("example page #{i}" )
445
-
446
- w.draw_disc(200, 700, 200 - i * 18)
447
- w.draw_circle(700, 220, 10 + i * 5);
448
-
449
- w.push(w.set_gray(0.8));
450
- w.draw_disc(500, 500, 30 + i * 10);
451
- w.pop();
452
- w.push(w.set_line_width(3));
453
- w.push(w.set_line_dashed());
454
- w.draw_circle(500, 500, 30 + i * 10);
455
- w.pop(2);
456
-
457
- w.draw_line(20 + i * 10, 20, 980, 500 + i * 48);
458
- w.push(w.set_line_width(1.2 + 0.3 * i));
459
- w.push(w.translate(500 - i * 40, 500 - i * 40));
460
- w.push(w.set_scale(1 + i * 0.7));
461
- w.draw_polygon(poly, 0, 0);
462
- w.pop(3);
463
-
464
- w.push(w.set_rgb(1, 0.2, 0.2));
465
- w.push(w.set_font_size(10 + i * 3));
466
- w.draw_string("Hello", 10 + i * 30, 900 - i * 40);
467
- w.pop();
468
- w.pop();
469
- end
470
- w.close();
471
- end