geotree 1.1.1 → 1.1.2

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.
@@ -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