ifmapper 0.5 → 0.6

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.
@@ -0,0 +1,161 @@
1
+
2
+ # Common printing add-ons
3
+ class FXSection
4
+ attr_accessor :xoff, :yoff, :page, :pxlen, :pylen, :rotate
5
+ end
6
+
7
+ class Page
8
+ attr_accessor :xlen, :ylen, :sections, :rotate
9
+ def initialize(xlen = 0, ylen = 0)
10
+ @xlen = xlen
11
+ @ylen = ylen
12
+ @rotate = false
13
+ @sections = []
14
+ end
15
+ end
16
+
17
+ class Map
18
+ #
19
+ # This code section is largely a copy of similar code used in
20
+ # IFM's C code.
21
+ # It tries to pack multiple map sections into a single page.
22
+ #
23
+ def pack_sections(xmax, ymax)
24
+ spacing = 0.0
25
+
26
+ # initialize -- one section per page
27
+ pages = []
28
+ @sections.each { |sect|
29
+ xlen, ylen = sect.rooms_width_height
30
+ sect.xoff = 0.0
31
+ sect.yoff = 0.0
32
+
33
+ page = Page.new(xlen+2, ylen+2)
34
+ pages.push page
35
+ page.sections << sect
36
+ }
37
+
38
+ ratio = xmax.to_f / ymax
39
+
40
+ packed = 1
41
+ while packed > 0
42
+ newpages = []
43
+ pos = packed = 0
44
+ while pos < pages.size
45
+ p1 = pages[pos]
46
+ x1 = p1.xlen
47
+ y1 = p1.ylen
48
+
49
+ # Check if it's better off rotated
50
+ p1.rotate = ((x1 < y1 and xmax > ymax) or
51
+ (x1 > y1 and xmax < ymax))
52
+
53
+ # Check if this is the last page
54
+ if pos + 1 == pages.size
55
+ newpages.push p1
56
+ break
57
+ end
58
+
59
+ # Get following page
60
+ p2 = pages[pos+1]
61
+ x2 = p2.xlen
62
+ y2 = p2.ylen
63
+
64
+ # Try combining pages in X direction
65
+ xc1 = x1 + x2 + spacing
66
+ yc1 = [y1, y2].max
67
+ v1 = (xc1 <= xmax and yc1 <= ymax)
68
+ r1 = xc1.to_f / yc1
69
+
70
+ # Try combining pages in Y direction
71
+ xc2 = [x1, x2].max
72
+ yc2 = y1 + y2 + spacing
73
+ v2 = (xc2 <= xmax and yc2 <= ymax)
74
+ r2 = xc2.to_f / yc2
75
+
76
+ # See which is best
77
+ if v1 and v2
78
+ if (ratio - r1).abs < (ratio - r2).abs
79
+ v2 = false
80
+ else
81
+ v1 = false
82
+ end
83
+ end
84
+
85
+ # Just copy page if nothing can be done
86
+ if not v1 and not v2
87
+ newpages.push(p1)
88
+ pos += 1
89
+ next
90
+ end
91
+
92
+ # Create merged page
93
+ page = Page.new
94
+ xo1 = yo1 = xo2 = yo2 = 0
95
+
96
+ if v1
97
+ page.xlen = xc1
98
+ page.ylen = yc1
99
+ xo2 = x1 + spacing
100
+
101
+ if y1 < y2
102
+ yo1 = (yc1 - y1) / 2
103
+ else
104
+ yo2 = (yc1 - y2) / 2
105
+ end
106
+ end
107
+
108
+ if v2
109
+ page.xlen = xc2
110
+ page.ylen = yc2
111
+ yo1 = y2 + spacing
112
+
113
+ if x1 < x2
114
+ xo1 = (xc2 - x1) / 2
115
+ else
116
+ xo2 = (xc2 - x2) / 2
117
+ end
118
+ end
119
+
120
+ # Copy sections to new page, updating offsets
121
+ opsects = p1.sections
122
+ opsects.each { |sect|
123
+ page.sections.push sect
124
+ sect.xoff += xo1
125
+ sect.yoff += yo1
126
+ }
127
+
128
+ opsects = p2.sections
129
+ opsects.each { |sect|
130
+ page.sections.push sect
131
+ sect.xoff += xo2
132
+ sect.yoff += yo2
133
+ }
134
+
135
+ # Add merged page to list and go to next page pair
136
+ newpages.push page
137
+ pos += 2
138
+ packed += 1
139
+ end
140
+ pages = newpages
141
+ end
142
+
143
+ # Give each section its page info and clean up
144
+ num = 0
145
+ pages.each { |page|
146
+ psects = page.sections
147
+ xlen = page.xlen
148
+ ylen = page.ylen
149
+ rflag = page.rotate
150
+
151
+ num += 1
152
+ psects.each { |sect|
153
+ sect.page = num
154
+ sect.pxlen = xlen
155
+ sect.pylen = ylen
156
+ sect.rotate = rflag
157
+ }
158
+ }
159
+ return num
160
+ end
161
+ end
@@ -11,6 +11,8 @@ rescue => e
11
11
  raise "Please install 'pdf writer' library for Acrobat PDF support."
12
12
  end
13
13
 
14
+ require 'IFMapper/MapPrinting'
15
+
14
16
  PDF_ZOOM = 0.5
15
17
  PDF_ROOM_WIDTH = W * PDF_ZOOM # 60
16
18
  PDF_ROOM_HEIGHT = H * PDF_ZOOM # 37.5
@@ -18,7 +20,6 @@ PDF_ROOM_WS = WS * PDF_ZOOM
18
20
  PDF_ROOM_HS = HS * PDF_ZOOM
19
21
  PDF_MARGIN = 20
20
22
 
21
-
22
23
  #
23
24
  # Open all the map class and add all pdf methods there
24
25
  # Gotta love Ruby's flexibility to just inject in new methods.
@@ -87,8 +88,8 @@ class FXConnection
87
88
  return if not @roomB # PDF does not print unfinished complex connections
88
89
 
89
90
  dir = @roomA.exits.index(self)
90
- x1, y1 = @roomA.pdf_corner(pdf, opts, self, dir)
91
- x2, y2 = @roomB.pdf_corner(pdf, opts, self)
91
+ x1, y1 = @roomA.pdf_corner(opts, self, dir)
92
+ x2, y2 = @roomB.pdf_corner(opts, self)
92
93
  pdf.move_to(x1, y1)
93
94
  pdf.line_to(x2, y2).stroke
94
95
  pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
@@ -102,8 +103,49 @@ class FXConnection
102
103
  end
103
104
  end
104
105
 
106
+ #
107
+ # Draw the connection text next to the arrow ('I', 'O', etc)
108
+ #
109
+ def pdf_draw_text(pdf, x, y, dir, text, arrow)
110
+ if dir == 7 or dir < 6 and dir != 1
111
+ if arrow and (dir == 0 or dir == 4)
112
+ x += 5
113
+ end
114
+ x += 2.5
115
+ elsif dir == 6 or dir == 1
116
+ x -= 7.5
117
+ end
118
+
119
+ if dir > 5 or dir < 4
120
+ if arrow and (dir == 6 or dir == 2)
121
+ y += 5
122
+ end
123
+ y += 2.5
124
+ elsif dir == 4 or dir == 5
125
+ y -= 7.5
126
+ end
127
+
128
+ font_size = 8
129
+ pdf.add_text(x, y, text, font_size)
130
+ end
131
+
132
+ def pdf_draw_exit_text(pdf, opts)
133
+ if @exitAtext != 0
134
+ dir = @roomA.exits.index(self)
135
+ x, y = @roomA.pdf_corner(opts, self, dir)
136
+ pdf_draw_text( pdf, x, y, dir,
137
+ EXIT_TEXT[@exitAtext], @dir == BtoA)
138
+ end
139
+ if @exitBtext != 0
140
+ dir = @roomB.exits.rindex(self)
141
+ x, y = @roomB.pdf_corner(opts, self, dir)
142
+ pdf_draw_text( pdf, x, y, dir,
143
+ EXIT_TEXT[@exitBtext], @dir == AtoB)
144
+ end
145
+ end
146
+
105
147
  def pdf_draw(pdf, opts)
106
- # pdf_draw_exit_text(pdf, opts)
148
+ pdf_draw_exit_text(pdf, opts)
107
149
  if @type == SPECIAL
108
150
  s = PDF::Writer::StrokeStyle.new(2, :dash => {
109
151
  :pattern => [2],
@@ -128,7 +170,7 @@ end
128
170
 
129
171
 
130
172
  class FXRoom
131
- def pdf_corner( pdf, opts, c, idx = nil )
173
+ def pdf_corner( opts, c, idx = nil )
132
174
  x, y = _corner(c, idx)
133
175
  y = -y
134
176
 
@@ -160,30 +202,46 @@ class FXRoom
160
202
  pdf.rectangle(x, y, opts['w'], opts['h']).fill_stroke
161
203
  end
162
204
 
205
+ def pdf_draw_text( pdf, opts, x, y, text, font_size )
206
+ miny = (opts['height'] - @y) * opts['hh'] + opts['hs_2'] +
207
+ opts['margin_2']
208
+ while text != ''
209
+ text = pdf.add_text_wrap(x, y, opts['w'] - 2, text, font_size)
210
+ y -= font_size
211
+ break if y <= miny
212
+ end
213
+ return [x, y]
214
+ end
215
+
216
+ def pdf_draw_objects(pdf, opts, x, y)
217
+ font_size = 6
218
+ objs = @objects.split("\n")
219
+ objs = objs.join(', ')
220
+ return pdf_draw_text( pdf, opts, x, y, objs, font_size )
221
+ end
222
+
163
223
  def pdf_draw_name(pdf, opts)
164
224
  # We could also use pdf_corner(7) here
165
225
  x = @x * opts['ww'] + opts['margin_2'] + opts['ws_2'] + 2
166
226
  y = opts['height'] - @y
167
- y = y * opts['hh'] + opts['margin_2'] + opts['hs_2'] + opts['h'] - 10
168
227
  font_size = 8
228
+ y = y * opts['hh'] + opts['margin_2'] + opts['hs_2'] + opts['h'] -
229
+ (font_size + 2)
169
230
  pdf.stroke_color(Color::RGB::Black)
170
231
  pdf.fill_color(Color::RGB::Black)
171
- text = @name
172
- while text != ''
173
- text = pdf.add_text_wrap(x, y, opts['w'], text, font_size)
174
- y -= font_size
175
- end
232
+ return pdf_draw_text( pdf, opts, x, y, @name, font_size )
176
233
  end
177
234
 
178
235
  def pdf_draw( pdf, opts, idx )
179
236
  pdf_draw_box( pdf, opts )
180
- pdf_draw_name( pdf, opts )
237
+ x, y = pdf_draw_name( pdf, opts )
238
+ pdf_draw_objects(pdf, opts, x, y)
181
239
  end
182
240
  end
183
241
 
184
242
 
185
243
 
186
- class FXPage
244
+ class FXSection
187
245
 
188
246
  def pdf_draw_grid(pdf, opts, w, h )
189
247
  (0...w).each { |xx|
@@ -195,68 +253,80 @@ class FXPage
195
253
  }
196
254
  end
197
255
 
198
- def pdf_draw_mapname( pdf, opts, mapname )
199
- return if not mapname or mapname == ''
200
- pdf.text( mapname,
201
- :font_size => 24,
202
- :justification => :center
203
- )
204
- end
205
256
 
206
- def pdf_draw_pagename( pdf, opts )
257
+ def pdf_draw_section_name( pdf, opts )
207
258
  return if not @name or @name == ''
208
- pdf.text( @name,
209
- :font_size => 16,
210
- :justification => :center
211
- )
259
+ y = (opts['height']) * opts['hh'] + 16
260
+ xymin, xymax = min_max_rooms
261
+ x = (xymax[0] + 2) * opts['ww'] / 2
262
+ pdf.add_text( x, y, @name, 16 )
212
263
  end
213
264
 
214
265
 
215
266
  def pdf_draw(pdf, opts, mapname )
216
- width, height = rooms_width_height
217
-
218
- #
219
- # Determine if better to print page in landscape mode
220
- #
221
- landscape = false
222
- if landscape
267
+ if rotate
223
268
  pdf.rotate_axis(90.0)
224
- pdf.translate_axis( 0, -pdf.page_width )
269
+ pdf.translate_axis( 0, -pdf.page_height )
225
270
  end
226
271
 
272
+ # Move section to its position in page
273
+ pack = [@xoff * opts['ww'], @yoff * -opts['hh']]
274
+ pdf.translate_axis( pack[0], pack[1] )
275
+
227
276
  # Use times-roman as font
228
277
  pdf.select_font 'Times-Roman'
229
278
  pdf.stroke_color(Color::RGB::Black)
230
279
  pdf.fill_color(Color::RGB::Black)
231
280
 
232
- pdf_draw_mapname( pdf, opts, mapname )
233
- pdf_draw_pagename( pdf, opts )
281
+ pdf_draw_section_name( pdf, opts )
282
+
283
+ xymin, = min_max_rooms
284
+
285
+ x = -(xymin[0]-1) * opts['ww']
286
+ y = (xymin[1]-1) * opts['hh']
287
+ pdf.translate_axis( x, y )
234
288
 
235
289
  # For testing purposes only, draw grid of boxes
236
290
  # pdf_draw_grid( pdf, opts, width, height )
237
-
238
291
  @connections.each { |c| c.pdf_draw( pdf, opts ) }
239
292
  @rooms.each_with_index { |r, idx| r.pdf_draw( pdf, opts, idx) }
293
+
294
+ # Reset axis
295
+ pdf.translate_axis(-x, -y)
296
+ pdf.translate_axis(-pack[0], -pack[1])
240
297
  end
241
298
  end
242
299
 
243
300
 
244
301
  class FXMap
245
302
 
246
- def pdf_draw_pages( pdf, opts )
247
- old_page = @page
248
- @pages.each_with_index { |p, idx|
249
- pdf.start_new_page if idx > 0
250
- @page = idx
303
+ def pdf_draw_mapname( pdf, opts )
304
+ return if not @name or @name == ''
305
+ pdf.text( @name,
306
+ :font_size => 24,
307
+ :justification => :center
308
+ )
309
+ end
310
+
311
+ def pdf_draw_sections( pdf, opts )
312
+ old_section = @section
313
+ page = -1
314
+ @sections.each_with_index { |sect, idx|
315
+ if page != sect.page
316
+ page = sect.page
317
+ pdf.start_new_page if page > 1
318
+ pdf_draw_mapname( pdf, opts )
319
+ end
320
+ @section = idx
251
321
  # For each page, we need to regenerate the pathmap so that complex
252
322
  # paths will come out ok.
253
323
  create_pathmap
254
324
  # Now, we draw it
255
- p.pdf_draw(pdf, opts, @name)
325
+ sect.pdf_draw(pdf, opts, @name)
256
326
  }
257
327
 
258
328
  # Restore original viewing page
259
- @page = old_page
329
+ @section = old_section
260
330
  create_pathmap
261
331
  end
262
332
 
@@ -265,6 +335,8 @@ class FXMap
265
335
  paper = 'LETTER'
266
336
  if printer
267
337
  case printer.mediasize
338
+ when FXPrinter::MEDIA_LETTER
339
+ paper = 'LETTER'
268
340
  when FXPrinter::MEDIA_LEGAL
269
341
  paper = 'LEGAL'
270
342
  when FXPrinter::MEDIA_A4
@@ -281,10 +353,14 @@ class FXMap
281
353
 
282
354
 
283
355
  pdf_options = @options.dup
356
+
357
+ ww = PDF_ROOM_WIDTH + PDF_ROOM_WS
358
+ hh = PDF_ROOM_HEIGHT + PDF_ROOM_HS
359
+
284
360
  pdf_options.merge!(
285
361
  {
286
- 'ww' => PDF_ROOM_WIDTH + PDF_ROOM_WS,
287
- 'hh' => PDF_ROOM_HEIGHT + PDF_ROOM_HS,
362
+ 'ww' => ww,
363
+ 'hh' => hh,
288
364
  'w' => PDF_ROOM_WIDTH,
289
365
  'h' => PDF_ROOM_HEIGHT,
290
366
  'ws' => PDF_ROOM_WS,
@@ -293,18 +369,19 @@ class FXMap
293
369
  'hs_2' => PDF_ROOM_HS / 2.0,
294
370
  'margin' => PDF_MARGIN,
295
371
  'margin_2' => PDF_MARGIN / 2.0,
296
- 'width' => @width - 1,
297
- 'height' => @height - 1,
372
+ 'width' => (pdf.page_width / ww).to_i - 1,
373
+ 'height' => (pdf.page_height / hh).to_i - 1,
298
374
  }
299
375
  )
300
376
 
301
377
 
302
378
  begin
303
- # See if it is possible to pack several map sections (pages) into
379
+ # See if it is possible to pack several map sections (sections) into
304
380
  # a single print page.
305
- # pack_sections
306
- pdf_draw_pages(pdf, pdf_options)
307
- p "Saving pdf to '#{pdffile}'..."
381
+ num = pack_sections( pdf_options['width'] + 2,
382
+ pdf_options['height'] + 2 )
383
+ pdf_draw_sections(pdf, pdf_options)
384
+ status "Exporting PDF file '#{pdffile}'"
308
385
  pdf.save_as(pdffile)
309
386
  rescue => e
310
387
  p e