ifmapper 2.0.9 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -72,8 +72,7 @@ class IFMWriter
72
72
 
73
73
  tag = t.dup
74
74
 
75
- version = RUBY_VERSION.split('.').map { |x| x.to_i }
76
- if (version <=> [1,9,0]) < 0
75
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.0')
77
76
  utf = Iconv.new( 'iso-8859-1', 'utf-8' )
78
77
  tag = utf.iconv( tag )
79
78
  else
@@ -211,7 +211,7 @@ class Inform7Writer
211
211
  tag = str.dup
212
212
 
213
213
  # Take text from Unicode utf-8 to iso-8859-1
214
- if RUBY_VERSION < 1.9
214
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.0')
215
215
  utf = Iconv.new( 'iso-8859-1', 'utf-8' )
216
216
  tag = utf.iconv( tag )
217
217
  else
@@ -322,7 +322,7 @@ class Inform7Writer
322
322
  str = text.dup
323
323
 
324
324
  # Take text from Unicode utf-8 to iso-8859-1859-1
325
- if RUBY_VERSION < 1.9
325
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.0')
326
326
  utf = Iconv.new( 'iso-8859-1', 'utf-8' )
327
327
  str = utf.iconv( str )
328
328
  else
@@ -35,7 +35,7 @@ class InformWriter
35
35
 
36
36
  def new_tag(elem, str)
37
37
  tag = str.dup
38
- if RUBY_VERSION < 1.9
38
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.0')
39
39
  utf = Iconv.new( 'iso-8859-1', 'utf-8' )
40
40
  tag = utf.iconv( tag )
41
41
  else
@@ -112,7 +112,7 @@ class InformWriter
112
112
  str = text.dup
113
113
 
114
114
  # Take text from Unicode utf-8 to iso-8859-1
115
- if RUBY_VERSION < 1.9
115
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('1.9.0')
116
116
  utf = Iconv.new( 'iso-8859-1', 'utf-8' )
117
117
  str = utf.iconv( str )
118
118
  else
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rexml/document"
4
+
5
+ file="#{File.dirname($0)}/FXConnection.rb"
6
+ File.readlines(file).each do |line|
7
+ case line
8
+ when /H = /
9
+ H = line.delete("^0-9")
10
+ when /HS = /
11
+ HS = line.delete("^0-9")
12
+ end
13
+ end
14
+ sectiongap = (H.to_i + HS.to_i) * 2
15
+
16
+ mainfile = nil
17
+ otherfiles = []
18
+
19
+ ARGV.each_with_index { |item, index|
20
+ if index == 0
21
+ mainfile = item
22
+ else
23
+ otherfiles.push(item)
24
+ end
25
+ }
26
+
27
+ if mainfile == nil
28
+ $stderr.puts "--- #{File.basename($0)} ---\n\n"
29
+ $stderr.puts "Usage: #{$0} <first map section svg file> [other map section svg files] > outputfile.svg"
30
+ $stderr.puts "If other map section files are omitted then the directory containing the first map section file is searched for suitable matching section files."
31
+ exit(1)
32
+
33
+ end
34
+
35
+ if File.exist?(mainfile) && File.file?(mainfile)
36
+ mainxml = File.new( mainfile )
37
+ $stderr.puts "Info: successfully opened first map section file: #{mainfile}"
38
+ else
39
+ $stderr.puts "Error: first map section file [#{mainfile}] does not exist or is not a file."
40
+ exit(2)
41
+ end
42
+
43
+ if otherfiles.length == 0
44
+ $stderr.puts "Info: other map section files not specified, searching for suitable matches"
45
+ $stderr.puts "Info: first map section path: #{mainxml.path}"
46
+ $stderr.puts "Info: first map section basename: #{File.basename(mainxml.path)}"
47
+
48
+ filename = File.basename(mainxml.path);
49
+ searchdir = File.dirname(mainxml.path);
50
+
51
+ $stderr.puts "Info: searching for section files in directory: #{searchdir}"
52
+ Dir.chdir(searchdir);
53
+
54
+ # Remove section number from filename if exists.
55
+ cleanfilename = nil
56
+
57
+ sectionrindex = filename.rindex("-section");
58
+ if sectionrindex == nil
59
+ # If section number not part of filename then just remove the .svg extension.
60
+ cleanfilename = File.basename(filename, ".*")
61
+ else
62
+ cleanfilename = filename[0, filename.rindex("-section")];
63
+ end
64
+
65
+ Dir.glob(cleanfilename + "-section*") { |match|
66
+ if match != filename
67
+ $stderr.puts "Info: found potential matching section file: #{match}"
68
+ otherfiles.push(File.join(Dir.pwd, match))
69
+ end
70
+ }
71
+
72
+ otherfiles = otherfiles.sort
73
+
74
+ else
75
+ $stderr.puts "Info: other map section files specified as arguments: #{otherfiles}"
76
+ end
77
+
78
+ $stderr.puts "---"
79
+ $stderr.puts "Info: first map section file: #{File.absolute_path(mainxml.path)}"
80
+ $stderr.puts "Info: other map section files: #{otherfiles}"
81
+ $stderr.puts "---"
82
+
83
+ maindoc = REXML::Document.new mainxml
84
+
85
+ maindocsectionypos = maindoc.elements["svg/use"].attributes["y"];
86
+ maindocdefs = maindoc.elements["svg/defs"];
87
+ maindocsvg = maindoc.elements["svg"];
88
+ maindocsvg.attributes["height"] = maindocsvg.attributes["height"].to_i + sectiongap;
89
+
90
+ $stderr.puts "Info: extracted section vertical offset: #{maindocsectionypos}"
91
+
92
+ otherfiles.each { |otherfile |
93
+ $stderr.puts "Info: processing other section file: #{otherfile}"
94
+
95
+ if File.exist?(otherfile) && File.file?(otherfile)
96
+
97
+ otherfilexml = File.new( otherfile )
98
+ otherfiledoc = REXML::Document.new otherfilexml
99
+
100
+ otherfiledocheight = otherfiledoc.elements["svg"].attributes["height"];
101
+ otherfiledocwidth = otherfiledoc.elements["svg"].attributes["width"];
102
+
103
+ $stderr.puts "Info: -- section full height: #{otherfiledocheight}"
104
+
105
+ otherfilesectionid = otherfiledoc.elements["svg/use"].attributes["xlink:href"];
106
+
107
+ $stderr.puts "Info: -- section identifier: #{otherfilesectionid}"
108
+ otherfilesectionx = otherfiledoc.elements["svg/use"].attributes["x"];
109
+ otherfiledefid = otherfilesectionid[1, otherfilesectionid.length];
110
+
111
+ otherfilesectiondef = otherfiledoc.elements["svg/defs/g[@id='" + otherfiledefid + "']"];
112
+
113
+ maindocdefs.add_element otherfilesectiondef;
114
+
115
+ maindocheight = maindocsvg.attributes["height"];
116
+ maindocwidth = maindocsvg.attributes["width"];
117
+
118
+ maindocsvg.add_element "use", { "xlink:href" => otherfilesectionid, "x" => otherfilesectionx, "y" => maindocheight.to_i }
119
+
120
+ maindocheight = maindocheight.to_i + (otherfiledocheight.to_i - maindocsectionypos.to_i) + sectiongap;
121
+ maindocsvg.attributes["height"] = maindocheight;
122
+ $stderr.puts "Info: -- updated document height: #{maindocsvg.attributes['height']}"
123
+
124
+ if otherfiledocwidth.to_i > maindocwidth.to_i
125
+ maindocsvg.attributes["width"] = otherfiledocwidth;
126
+ $stderr.puts "Info: -- updated document width: #{maindocsvg.attributes['width']}"
127
+ end
128
+
129
+ else
130
+
131
+ $stderr.puts "Warn: -- other map section file [#{otherfile}] does not exist or is not a file. Ignoring this file!"
132
+ end
133
+ }
134
+ maindocheight = maindocsvg.attributes["height"];
135
+ maindocwidth = maindocsvg.attributes["width"];
136
+ maindocdefs.elements["pattern"].attributes["height"] = maindocheight;
137
+ maindocdefs.elements["pattern"].elements["image"].attributes["height"] = maindocheight;
138
+ maindocsvg.elements["path"].attributes["d"] = "'M5,5 l0," + maindocheight.to_s + " l" + maindocwidth + ",0 l0,-" + maindocheight.to_s + " l-" + maindocwidth + ",0'" unless maindocsvg.elements["path"].nil?;
139
+
140
+ dattrstr = "'M5,5 l0," + maindocheight + " l" + maindocwidth + ",0 l0,-" + maindocheight + " l-" + maindocwidth + ",0'"
141
+ REXML::XPath::each(maindocsvg, '//comment()') do |comment|
142
+ case comment.string
143
+ when /path/
144
+ comment.string = "<path d=" + dattrstr + " fill='url(#backgroundimg)'/>"
145
+ end
146
+ end
147
+
148
+ $stderr.puts "Info: outputting combined svg file..."
149
+
150
+ formatter = REXML::Formatters::Pretty.new(2)
151
+ formatter.compact = true
152
+ formatter.width = 99999999
153
+ formatter.write(maindoc, $stdout)
154
+
155
+ $stderr.puts "Info: done"
@@ -1,1091 +1,1303 @@
1
- require 'IFMapper/MapPrinting'
2
- require 'rexml/document'
3
- require 'rexml/cdata'
4
-
5
- DEBUG_OUTPUT = false
6
- SVG_ZOOM = 1
7
- SVG_ROOM_WIDTH = W * SVG_ZOOM
8
- SVG_ROOM_HEIGHT = H * SVG_ZOOM
9
- SVG_ROOM_WS = WS * SVG_ZOOM
10
- SVG_ROOM_HS = HS * SVG_ZOOM
11
-
12
- class SVGUtilities
13
-
14
- def self.new_svg_doc ( width, height)
15
- svg = REXML::Document.new
16
- svg << REXML::XMLDecl.new
17
-
18
- svg.add_element "svg", {
19
- "width" => width,
20
- "height" => height,
21
- "version" => "1.1",
22
- "xmlns" => "http://www.w3.org/2000/svg",
23
- "xmlns:xlink" => "http://www.w3.org/1999/xlink"}
24
- return svg
25
-
26
- end
27
-
28
- def self.add_text( svg, x, y, font_size, text, opts, fill_colour )
29
- if DEBUG_OUTPUT; puts "svg::FXMap::svg_draw_name_text:" end
30
- y = y + font_size
31
-
32
- t = svg.root.add_element "text", {
33
- "x" => x,
34
- "y" => y,
35
- "style" => "font-size:" + font_size.to_s() + "pt;fill:#" + fill_colour.to_s()}
36
-
37
- t.text = text
38
-
39
- return [svg, x, y]
40
- end
41
-
42
- def self.num_text_lines ( text, maxlinelength )
43
- if text and not text == ''
44
- return SVGUtilities::break_text_lines(text.chomp().strip(), maxlinelength).length
45
- else
46
- return 0
47
- end
48
- end
49
-
50
- def self.break_text_lines( text, maxlinelength )
51
- if DEBUG_OUTPUT; printf("SVGUtilities::break_text_lines:text=%s\r\n", text) end
52
-
53
- out = Array.new
54
-
55
- max_chars = maxlinelength
56
- words = text.split(" ")
57
- cur_str = ""
58
-
59
- words.each { |word|
60
- new_len = cur_str.length + word.length
61
- if DEBUG_OUTPUT; printf("SVGUtilities::break_text_lines:current word: %s :: new_len: %d\r\n", word, new_len) end
62
- new_len = cur_str.length + word.length
63
- if new_len <= max_chars
64
- cur_str = cur_str + word + " "
65
- else
66
- out << cur_str
67
- cur_str = "" + word + " "
68
- end
69
- }
70
- out << cur_str
71
-
72
- return out
73
- end
74
-
75
- def self.get_compass_svg_group()
76
-
77
- file = File.new( "icons/compass.svg" )
78
- doc = REXML::Document.new file
79
-
80
- newgroup = REXML::Element.new "g"
81
- newgroup.attributes["id"] = "compass"
82
-
83
- doc.root.elements.each {|elem|
84
- newgroup.add_element(elem)
85
- }
86
-
87
- return newgroup
88
-
89
- end
90
-
91
- def self.add_compass(svg)
92
- compassgroup = SVGUtilities::get_compass_svg_group()
93
-
94
- defs = svg.root.add_element "defs"
95
-
96
- defs.add_element compassgroup
97
-
98
- return svg
99
- end
100
-
101
-
102
- def self.svg_add_script( svg, opts )
103
- svg.root.attributes["onload"] = "Init(evt)"
104
-
105
- script = svg.root.add_element "script", {
106
- "type" => "text/ecmascript" }
107
-
108
- script.add( REXML::CData.new("
109
- var SVGDocument = null;
110
- var SVGRoot = null;
111
-
112
- function Init(evt)
113
- {
114
- SVGDocument = evt.target.ownerDocument;
115
- SVGRoot = SVGDocument.documentElement;
116
- }
117
-
118
- function ToggleOpacity(evt, targetId)
119
- {
120
- var newTarget = evt.target;
121
- if (targetId)
122
- {
123
- newTarget = SVGDocument.getElementById(targetId);
124
- }
125
- var newValue = newTarget.getAttributeNS(null, 'opacity')
126
-
127
- if ('0' != newValue)
128
- {
129
- newValue = '0';
130
- }
131
- else
132
- {
133
- newValue = '1';
134
- }
135
- newTarget.setAttributeNS(null, 'opacity', newValue);
136
-
137
- if (targetId)
138
- {
139
- SVGDocument.getElementById(targetId + 'Exception').setAttributeNS(null, 'opacity', '1');
140
- }
141
- }
142
- "))
143
-
144
- return svg;
145
- end
146
-
147
- def self.add_titles( svg, opts, x, y, font_size, mapname, mapcreator )
148
- if DEBUG_OUTPUT; puts "svg::SVGUtilities::add_titles" end
149
-
150
- if opts['print_title'] == true
151
- if not mapname or mapname == ''
152
- if DEBUG_OUTPUT; puts "svg::SVGUtilities::add_titles:name is empty, not printing" end
153
- else
154
- svg, x, y = SVGUtilities::add_text(svg, x, y, font_size*1.5, mapname, opts, '000000')
155
- y = y + (opts['name_line_spacing'] * 4)
156
- end
157
- end
158
-
159
- if opts['print_creator'] == true
160
- if not mapcreator or mapcreator == ''
161
- if DEBUG_OUTPUT; puts "svg::SVGUtilities::add_titles:creator is empty, not printing" end
162
- else
163
- svg, x, y = SVGUtilities::add_text(svg, x, y, font_size*0.85, 'Map ' + opts['creator_prefix'] + mapcreator, opts, '000000')
164
- y = y + (opts['name_line_spacing'] * 4)
165
- end
166
- end
167
-
168
- return [svg, x, y]
169
- end
170
-
171
- end
172
- #
173
- # Open all the map class and add all SVG methods there
174
- # Gotta love Ruby's flexibility to just inject in new methods.
175
- #
176
- class FXConnection
177
- def _cvt_pt(p, opts)
178
- if DEBUG_OUTPUT; puts "svg::FXConnection::_cvt_pt" end
179
- x = (p[0] - WW / 2.0) / WW.to_f
180
- y = (p[1] - HH / 2.0) / HH.to_f
181
- x = x * opts['ww'] + opts['margin'] + opts['w'] / 2.0
182
- y = y * opts['hh'] + opts['margin'] + opts['hs'] - 2
183
- return [x, y]
184
- end
185
-
186
- def svg_draw_arrow(svg, opts, x1, y1, x2, y2)
187
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_arrow:#{x1},#{y1},#{x2},#{y2}" end
188
- return if @dir == BOTH
189
-
190
- pt1, d = _arrow_info( x1, y1, x2, y2, 0.5 )
191
-
192
- if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: pt1[0]=%0.01f,pt1[1]=%0.01f,d[0]=%0.01f,d[1]=%0.01f\r\n", pt1[0], pt1[1], d[0], d[1]) end
193
-
194
- mx = pt1[0];
195
- my = pt1[1];
196
-
197
- if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: mx=%0.01f,my=%0.01f\r\n",mx,my) end
198
-
199
- lx1 = pt1[0] + d[0]
200
- ly1 = pt1[1] + d[1]
201
-
202
- if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: lx1=%0.01f,ly1=%0.01f\r\n",lx1,ly1) end
203
-
204
- lx2 = pt1[0] + d[1]
205
- ly2 = pt1[1] - d[0]
206
-
207
- if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: lx2=%0.01f,ly2=%0.01f\r\n",lx2,ly2) end
208
-
209
- points = sprintf("%0.01f", mx) + "," + sprintf("%0.01f", my) + " "
210
- points << sprintf("%0.01f", lx1) + "," + sprintf("%0.01f", ly1) + " "
211
- points << sprintf("%0.01f", lx2) + "," + sprintf("%0.01f", ly2) + " "
212
-
213
- svg.root.add_element "polygon", {
214
- "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s",opts['arrow_line_colour'],opts['arrow_line_width'],opts['arrow_fill_colour']),
215
- "points" => points }
216
-
217
- end
218
-
219
- def svg_draw_complex_as_bspline( svg, opts )
220
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_complex_as_bspline" end
221
- p = []
222
- p << _cvt_pt(@pts[0], opts)
223
- p << p[0]
224
- p << p[0]
225
- @pts.each { |pt|
226
- p << _cvt_pt(pt, opts)
227
- }
228
- p << p[-1]
229
- p << p[-1]
230
- p << p[-1]
231
- return FXSpline::bspline(p)
232
- end
233
-
234
- def svg_draw_complex_as_lines( svg, opts )
235
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_complex_as_lines" end
236
- p = []
237
- @pts.each { |pt|
238
- p << _cvt_pt(pt, opts)
239
- }
240
- return p
241
- end
242
-
243
- def svg_draw_door( svg, x1, y1, x2, y2 , opts)
244
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_arrow:#{x1},#{y1},#{x2},#{y2}" end
245
- v = [ (x2-x1), (y2-y1) ]
246
- t = 10 / Math.sqrt(v[0]*v[0]+v[1]*v[1])
247
- v = [ v[0]*t, v[1]*t ]
248
- m = [ (x2+x1)/2, (y2+y1)/2 ]
249
- x1, y1 = [m[0] + v[1], m[1] - v[0]]
250
- x2, y2 = [m[0] - v[1], m[1] + v[0]]
251
-
252
- v = [ v[0] / 3, v[1] / 3]
253
-
254
- poly = svg.root.add_element "polygon", {
255
- "style" => sprintf("stroke:%s;stroke-width:%s", opts['door_line_colour'],opts['door_line_width']),
256
- "points" => sprintf("%0.01f,%0.01f %0.01f,%0.01f %0.01f,%0.01f %0.01f,%0.01f",
257
- x1-v[0], y1-v[1], x1+v[0], y1+v[1], x2+v[0], y2+v[1], x2-v[0], y2-v[1]) }
258
-
259
- if @type == LOCKED_DOOR
260
- poly.attributes["style"] << sprintf(";fill:%s", opts['door_line_colour'])
261
- else
262
- poly.attributes["style"] << ";fill:none"
263
- end
264
- end
265
-
266
- def svg_draw_complex( svg, opts, sx ,sy )
267
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_complex" end
268
- if opts['Paths as Curves']
269
- if @room[0] == @room[1]
270
- dirA, dirB = dirs
271
- if dirA == dirB
272
- p = svg_draw_complex_as_lines( svg, opts )
273
- else
274
- p = svg_draw_complex_as_bspline( svg, opts )
275
- end
276
- else
277
- p = svg_draw_complex_as_bspline( svg, opts )
278
- end
279
- else
280
- p = svg_draw_complex_as_lines( svg, opts )
281
- end
282
-
283
- p.each { |pt|
284
- pt[0] = pt[0] + sx
285
- pt[1] = pt[1] + sy }
286
-
287
- d = "M" + sprintf("%0.01f", p[0][0]) + "," + sprintf("%0.01f", p[0][1]) + " "
288
-
289
- p.each { |pt|
290
- d = d + "L" + sprintf("%0.01f", pt[0]) + "," + sprintf("%0.01f", pt[1]) + " " }
291
-
292
- path = svg.root.add_element "path", {
293
- "style" => sprintf("stroke:%s;stroke-width:%s;fill:none",opts['conn_line_colour'],opts['conn_line_width']),
294
- "d" => d }
295
-
296
- if @type == SPECIAL
297
- path.attributes["style"] << ";stroke-dasharray:9,5"
298
- end
299
-
300
- x1, y1 = [p[0][0], p[0][1]]
301
- x2, y2 = [p[-1][0], p[-1][1]]
302
-
303
- svg_draw_arrow(svg, opts, x1, y1, x2, y2)
304
-
305
- if @type == LOCKED_DOOR or @type == CLOSED_DOOR
306
- t = p.size / 2
307
- x1, y1 = [ p[t][0], p[t][1] ]
308
- x2, y2 = [ p[t-2][0], p[t-2][1] ]
309
-
310
- svg_draw_door(svg, x1, y1, x2, y2, opts)
311
- end
312
- end
313
-
314
- def svg_draw_simple(svg, opts, sx, sy)
315
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_simple" end
316
- return if not @room[1]
317
-
318
- dir = @room[0].exits.index(self)
319
- x1, y1 = @room[0].svg_corner(opts, self, dir)
320
- x2, y2 = @room[1].svg_corner(opts, self)
321
-
322
- x1 = x1 + sx;
323
- x2 = x2 + sx;
324
- y1 = y1 + sy;
325
- y2 = y2 + sy;
326
-
327
- line = svg.root.add_element "line", {
328
- "x1" => x1,
329
- "y1" => y1,
330
- "x2" => x2,
331
- "y2" => y2,
332
- "style" => sprintf("stroke:%s;stroke-width:%s", opts['conn_line_colour'],opts['conn_line_width']) }
333
-
334
- if @type == SPECIAL
335
- line.attributes["style"] << ";stroke-dasharray:9,5"
336
- end
337
-
338
- svg_draw_arrow(svg, opts, x1, y1, x2, y2)
339
- if @type == LOCKED_DOOR or @type == CLOSED_DOOR
340
- svg_draw_door(svg, x1, y1, x2, y2, opts)
341
- end
342
- end
343
-
344
- #
345
- # Draw the connection text next to the arrow ('I', 'O', etc)
346
- #
347
- def svg_draw_text(svg, x, y, dir, text, arrow)
348
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_text:#{x},#{y},#{text}" end
349
- if dir == 7 or dir < 6 and dir != 1
350
- if arrow and (dir == 0 or dir == 4)
351
- x += 5
352
- end
353
- x += 2.5
354
- elsif dir == 6 or dir == 1
355
- x -= 7.5
356
- end
357
-
358
- if dir > 5 or dir < 4
359
- if arrow and (dir == 6 or dir == 2)
360
- y -= 5
361
- end
362
- y -= 2.5
363
- elsif dir == 4 or dir == 5
364
- y += 7.5
365
- end
366
-
367
- font_size = 6
368
-
369
- t = svg.root.add_element "text", {
370
- "x" => x,
371
- "y" => y,
372
- "style" => "font-size:" + font_size.to_s() + "pt"}
373
-
374
- t.text = text;
375
- end
376
-
377
- def svg_draw_exit_text(pdf, opts, sx, sy)
378
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_exit_text" end
379
- if @exitText[0] != 0
380
- dir = @room[0].exits.index(self)
381
- x, y = @room[0].svg_corner(opts, self, dir)
382
- x = x + sx
383
- y = y + sy
384
- svg_draw_text( pdf, x, y, dir,
385
- EXIT_TEXT[@exitText[0]], @dir == BtoA)
386
- end
387
-
388
- if @exitText[1] != 0
389
- dir = @room[1].exits.rindex(self)
390
- x, y = @room[1].svg_corner(opts, self, dir)
391
- x = x + sx
392
- y = y + sy
393
- svg_draw_text( pdf, x, y, dir,
394
- EXIT_TEXT[@exitText[1]], @dir == AtoB)
395
- end
396
- end
397
-
398
- def svg_draw(svg, opts, x, y)
399
- if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw:draw_connections=%s\r\n", opts['draw_connections'].to_s()) end
400
- if opts['draw_connections'] == true
401
- if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw" end
402
-
403
- svg_draw_exit_text(svg, opts, x, y)
404
-
405
- if @pts.size > 0
406
- svg_draw_complex(svg, opts, x, y)
407
- else
408
- svg_draw_simple(svg, opts, x, y)
409
- end
410
- end
411
- end
412
- end
413
-
414
-
415
- class FXRoom
416
- def svg_corner( opts, c, idx = nil )
417
- if DEBUG_OUTPUT; puts "svg::FXRoom::svg_corner" end
418
- x, y = _corner(c, idx)
419
-
420
- ww = opts['ww']
421
- hh = opts['hh']
422
- w = opts['w']
423
- h = opts['h']
424
-
425
- x = @x * ww + x * w + opts['margin']
426
- y = @y * hh + y * h + opts['margin']
427
-
428
- return [x, y]
429
- end
430
-
431
- def svg_draw_box( svg, opts, idx, sx, sy )
432
- if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_box" end
433
- x = sx + (@x * opts['ww']) + opts['margin']
434
- y = sy + (@y * opts['hh']) + opts['margin']
435
-
436
- if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_box[x=%s,y=%s,w=%s,h=%s]\r\n", x,y,opts['w'],opts['h']) end
437
-
438
- roomrect = svg.root.add_element "rect", {
439
- "x" => x,
440
- "y" => y,
441
- "width" => opts['w'],
442
- "height" => opts['h'],
443
- "style" => sprintf("stroke:%s;stroke-width:%s", opts['room_line_colour'],opts['room_line_width'])}
444
-
445
- if @darkness
446
- if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_box:DARKNESS" end
447
- roomrect.attributes["style"] << ";fill:gray"
448
- else
449
- if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_box:not darkness" end
450
- roomrect.attributes["style"] << ";fill:none"
451
- end
452
-
453
- if opts['print_room_nums'] == true
454
-
455
- # Add the room number to the bottom right hand corner!
456
-
457
- pad = 2
458
- font_size = 8
459
- numbox_width = (pad*2) + (3*font_size)
460
- numbox_height = (pad*2)+font_size
461
- numbox_x = (x + opts['w']) - numbox_width
462
- numbox_y = (y + opts['h']) - numbox_height
463
-
464
- numbox_rect = svg.root.add_element "rect", {
465
- "x" => numbox_x,
466
- "y" => numbox_y,
467
- "width" => numbox_width,
468
- "height" => numbox_height,
469
- "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s", opts['num_line_colour'],opts['num_line_width'],opts['num_fill_colour']) }
470
-
471
- numtext_x = numbox_x + pad
472
- numtext_y = numbox_y + font_size + pad
473
-
474
- if idx < 100
475
- numtext_x += font_size
476
- end
477
-
478
- if idx < 10
479
- numtext_x += font_size
480
- end
481
-
482
- numtext = svg.root.add_element "text", {
483
- "x" => numtext_x,
484
- "y" => numtext_y,
485
- "style" => "font-size:" + font_size.to_s() + "pt" }
486
-
487
- numtext.text = (idx+1).to_s()
488
-
489
- end
490
- end
491
-
492
- def svg_draw_text( svg, opts, x, y, text, font_size )
493
- if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_text:text=%s\r\n", text) end
494
-
495
- t = svg.root.add_element "text", {
496
- "x" => x,
497
- "y" => y,
498
- "style" => "font-size:" + font_size.to_s() + "pt"}
499
-
500
- max_chars = opts['text_max_chars']
501
- words = text.split(" ")
502
- dy = 0
503
- ypos = 0
504
- lasty = opts['h'] - opts['text_margin']
505
- cur_str = ""
506
-
507
- words.each { |word|
508
- new_len = cur_str.length + word.length
509
- if DEBUG_OUTPUT; printf("current word: %s :: new_len: %d\r\n", word, new_len) end
510
- new_len = cur_str.length + word.length
511
- if new_len <= max_chars
512
- cur_str = cur_str + word + " "
513
- else
514
- ypos = ypos + font_size + opts['text_line_spacing']
515
- if ypos >= lasty
516
- break
517
- end
518
- tspan = t.add_element "tspan", {
519
- "x" => x,
520
- "dy" => dy }
521
- tspan.text = cur_str
522
- if dy == 0
523
- dy = font_size + opts['text_line_spacing']
524
- end
525
- cur_str = "" + word + " "
526
- end
527
- }
528
-
529
- if ypos < lasty
530
- tspan = t.add_element "tspan", {
531
- "x" => x,
532
- "dy" => dy }
533
- tspan.text = cur_str
534
- end
535
-
536
- return [x, y+ypos]
537
- end
538
-
539
- def svg_draw_objects(svg, opts, x, y)
540
- if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_objects" end
541
- font_size = 6
542
- objs = @objects.split("\n")
543
- objs = objs.join(', ')
544
- return svg_draw_text( svg, opts, x, y, objs, font_size )
545
- end
546
-
547
- def svg_draw_name(svg, opts, sx, sy)
548
- if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_name:name=%s\r\n", @name) end
549
-
550
- x = sx + (@x * opts['ww']) + opts['margin'] + opts['text_margin']
551
- y = sy + (@y * opts['hh']) + opts['margin'] + opts['text_margin']
552
- font_size = 8
553
- y = y + font_size
554
-
555
- return svg_draw_text( svg, opts, x, y, @name, font_size )
556
- end
557
-
558
- def svg_draw_interactive( svg, opts, idx, sx, sy, section_idx )
559
- if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_interactive" end
560
-
561
- if (@objects and not @objects == '') or (@tasks and not @tasks == '') or (@comment and not @comment == '')
562
-
563
- x = sx + (@x * opts['ww']) + opts['margin'] + opts['w']
564
- y = sy + (@y * opts['hh']) + opts['margin']
565
-
566
- x1 = x - opts['corner_size']
567
- y1 = y
568
-
569
- x2 = x
570
- y2 = y + opts['corner_size']
571
-
572
- poly = svg.root.add_element "polygon", {
573
- "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s", opts['corner_line_colour'],opts['corner_line_width'],opts['corner_fill_colour']),
574
- "points" => sprintf("%0.01f,%0.01f %0.01f,%0.01f %0.01f,%0.01f", x, y, x1, y1, x2, y2),
575
- "onclick" => "ToggleOpacity(evt, \"section"+section_idx.to_s()+"room"+idx.to_s()+"\")" }
576
-
577
- objs_font_size = opts['objects_font_size']
578
- num_chars_per_line = opts['objects_width'] / (objs_font_size)
579
-
580
- numObjsLines = 0
581
- numTaskLines = 0
582
- numCommLines = 0
583
-
584
- if(@objects)
585
- numObjsLines = SVGUtilities::num_text_lines(@objects, num_chars_per_line);
586
- end
587
-
588
- if(@tasks)
589
- numTaskLines = SVGUtilities::num_text_lines(@tasks, num_chars_per_line);
590
- end
591
-
592
- if(@comment)
593
- numCommLines = SVGUtilities::num_text_lines(@comment, num_chars_per_line);
594
- end
595
-
596
- if(numObjsLines > 0)
597
- numObjsLines = numObjsLines + 2
598
- end
599
-
600
- if(numTaskLines > 0)
601
- numTaskLines = numTaskLines + 2
602
- end
603
-
604
- if(numCommLines > 0)
605
- numCommLines = numCommLines + 2
606
- end
607
-
608
- lines = numObjsLines + numTaskLines + numCommLines
609
-
610
- objs_height = (lines+1) * (objs_font_size + opts['text_line_spacing'])
611
-
612
- g = svg.root.add_element "g", {
613
- "id" => "section"+section_idx.to_s()+"room"+idx.to_s(),
614
- "opacity" => "0" }
615
-
616
- rect_x = x - opts['objects_width'] - opts['corner_size']
617
- rect_y = y + opts['corner_size']
618
-
619
- g.add_element "rect", {
620
- "x" => rect_x,
621
- "y" => rect_y,
622
- "width" => opts['objects_width'],
623
- "height" => objs_height,
624
- "z-index" => "1",
625
- "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s", opts['objs_line_colour'],opts['objs_line_width'],opts['objs_fill_colour']) }
626
-
627
- text_x = rect_x + opts['text_margin']
628
- text_y = rect_y + opts['text_margin'] + objs_font_size
629
-
630
- if @objects and not @objects == ''
631
- t1 = g.add_element "text", {
632
- "x" => text_x,
633
- "y" => text_y,
634
- "style" => "font-size:" + objs_font_size.to_s() + "pt;font-weight:bold" }
635
- t1.text = "Objects:"
636
-
637
- text_y = text_y + objs_font_size + opts['text_line_spacing']
638
- objs_lines = SVGUtilities::break_text_lines(@objects, num_chars_per_line)
639
- text_x, text_y = svg_draw_interactive_objects( g, opts, text_x, text_y, objs_font_size, objs_lines)
640
- text_y = text_y + objs_font_size + opts['text_line_spacing']
641
- end
642
-
643
- if @tasks and not @tasks == ''
644
- t2 = g.add_element "text", {
645
- "x" => text_x,
646
- "y" => text_y,
647
- "style" => "font-size:" + objs_font_size.to_s() + "pt;font-weight:bold" }
648
- t2.text = "Tasks:"
649
-
650
- text_y = text_y + objs_font_size + opts['text_line_spacing']
651
- tasks_lines = SVGUtilities::break_text_lines(@tasks, num_chars_per_line)
652
- text_x, text_y = svg_draw_interactive_objects( g, opts, text_x, text_y, objs_font_size, tasks_lines)
653
- text_y = text_y + objs_font_size + opts['text_line_spacing']
654
- end
655
-
656
- if @comment and not @comment == ''
657
- t2 = g.add_element "text", {
658
- "x" => text_x,
659
- "y" => text_y,
660
- "style" => "font-size:" + objs_font_size.to_s() + "pt;font-weight:bold" }
661
- t2.text = "Comments:"
662
-
663
- text_y = text_y + objs_font_size + opts['text_line_spacing']
664
- comments_lines = SVGUtilities::break_text_lines(@comment, num_chars_per_line)
665
- text_x, text_y = svg_draw_interactive_objects( g, opts, text_x, text_y, objs_font_size, comments_lines)
666
- text_y = text_y + objs_font_size + opts['text_line_spacing']
667
- end
668
- end
669
- end
670
-
671
-
672
- def svg_draw_interactive_objects( group, opts, x, y, font_size, lines)
673
- if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_interactive_objects\r\n") end
674
-
675
- t = group.add_element "text", {
676
- "x" => x,
677
- "y" => y,
678
- "style" => "font-size:" + font_size.to_s() + "pt"}
679
-
680
- dy = 0
681
- ypos = 0
682
-
683
- lines.each { |obj|
684
-
685
- ypos = ypos + font_size + opts['text_line_spacing']
686
- tspan = t.add_element "tspan", {
687
- "x" => x,
688
- "dy" => dy }
689
- tspan.text = obj
690
- if dy == 0
691
- dy = font_size + opts['text_line_spacing']
692
- end
693
- }
694
-
695
- return [x, y+ypos]
696
- end
697
-
698
- def svg_draw( svg, opts, idx, x, y )
699
- if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw" end
700
-
701
- if (!((opts['draw_connections'] == false) && (@name =~ /Shortcut to.*/i)))
702
- svg_draw_box( svg, opts, idx, x, y )
703
-
704
- if ((opts['draw_roomnames'] == true) || (@name =~ /Shortcut to.*/i) || (idx == 0))
705
-
706
- # Even if we're not printing location names, print the "Shortcut to"
707
- # part of any locations which start with that text. This convention of
708
- # a room named "Shortcut to <another location>" is for the sole purpose
709
- # of allowing additional connections to be collected which are then fwd'd
710
- # to the named location, because currently IFMapper can only provide
711
- # support for up to eight cardinal / ordinal directions which can be a
712
- # problem for large locations.
713
- if ((opts['draw_roomnames'] == false) && (@name =~ /(Shortcut to).*/i))
714
- @name = $1
715
- end
716
-
717
- x, y = svg_draw_name( svg, opts, x, y )
718
- end
719
- end
720
- end
721
-
722
- end
723
-
724
-
725
-
726
- class FXSection
727
-
728
- def svg_draw_grid(pdf, opts, w, h )
729
- if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw_grid" end
730
- (0...w).each { |xx|
731
- (0...h).each { |yy|
732
- x = xx * opts['ww'] + opts['ws_2'] + opts['margin_2']
733
- y = yy * opts['hh'] + opts['hs_2'] + opts['margin_2']
734
- }
735
- }
736
- end
737
-
738
-
739
- def svg_draw_section_name( svg, opts, x, y )
740
- return [x,y] if not @name or @name == ''
741
-
742
- font_size = opts['name_font_size']
743
-
744
- if opts['print_section_names'] == true
745
- svg, x, y = SVGUtilities::add_text( svg, x, y, font_size, @name, opts, '2F4F4F' )
746
- y = y + opts['name_line_spacing']
747
- end
748
-
749
- if opts['draw_sectioncomments'] == true
750
-
751
- if not @comments or @comments == ''
752
- if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw_section_name:section comments is empty, not printing" end
753
- else
754
- num_chars_per_line = svg.root.attributes["width"].to_i() / (font_size*0.75)
755
-
756
- brokenlines = @comments.split(/\r?\n/);
757
-
758
- brokenlines.each {|brokenline|
759
-
760
- lines = SVGUtilities::break_text_lines(brokenline, num_chars_per_line);
761
- lines.each {|line|
762
- svg, x, y = SVGUtilities::add_text( svg, x, y, font_size*0.75, line, opts, '000000' )
763
- y = y + (opts['name_line_spacing'])
764
- }
765
-
766
- y = y + (opts['name_line_spacing'])
767
- }
768
-
769
- end
770
-
771
- end
772
-
773
- y = y + (opts['name_line_spacing'] * 8)
774
-
775
- return [x,y]
776
- end
777
-
778
- def svg_width( opts )
779
- minmaxxy = min_max_rooms
780
- maxx = minmaxxy[1][0]
781
-
782
- sect_width = (maxx+4) * opts['ww']
783
- return sect_width
784
- end
785
-
786
- def svg_height( opts )
787
- minmaxxy = min_max_rooms
788
- maxy = minmaxxy[1][1]
789
-
790
- sect_height = (maxy+2) * opts['hh']
791
- return sect_height
792
- end
793
-
794
- def svg_draw(svg, opts, x, y, mapname, section_idx )
795
- if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw" end
796
-
797
- x, y = svg_draw_section_name( svg, opts, x, y )
798
-
799
- origx = x
800
- origy = y
801
-
802
- @connections.each { |c|
803
- a = c.roomA
804
- b = c.roomB
805
- next if a.y < 0 and b and b.y < 0
806
- c.svg_draw( svg, opts, x, y )
807
- }
808
-
809
- @rooms.each_with_index { |r, idx|
810
- next if r.y < 0
811
- r.svg_draw( svg, opts, idx, x, y)
812
- }
813
-
814
-
815
- # Add the compass displaying code in here so that it
816
- # is displayed beneath the interactive display items when
817
- # they are switched on.
818
-
819
- compass_scale_factor = opts['compass_size'];
820
-
821
- if(compass_scale_factor > 0)
822
-
823
- compassx = (x + opts['margin'] + (opts['w'] / 2))/compass_scale_factor
824
- compassy = ((y + svg_height(opts)) - opts['h'])/compass_scale_factor
825
-
826
- svg.root.add_element "use", {
827
- "x" => compassx,
828
- "y" => compassy,
829
- "xlink:href" => "#compass",
830
- "transform" => "scale(" + compass_scale_factor.to_s() + ")"
831
- }
832
-
833
- y = y + (64 * compass_scale_factor)
834
-
835
- end
836
-
837
- #
838
- # Iterate through the list of rooms a second time to
839
- # add the interactive elements (list of objects/tasks).
840
- # We do this as a second pass so that these objects a displayed
841
- # on top of the basic room objects.
842
- #
843
-
844
- if opts['draw_interactive'] == true
845
- if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw::draw_interactive == true" end
846
- @rooms.each_with_index { |r, idx|
847
- if (!((opts['draw_connections'] == false) && (r.name =~ /Shortcut to.*/i)))
848
-
849
- r.svg_draw_interactive( svg, opts, idx, origx, origy, section_idx)
850
- end
851
- }
852
- end
853
-
854
- y = y + svg_height( opts )
855
-
856
- return [x,y]
857
-
858
- end
859
-
860
- def svg_draw_separate(opts, svgfile, section_idx, mapname, mapcreator)
861
- if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw_separate" end
862
-
863
- svg = SVGUtilities::new_svg_doc(svg_width(opts), svg_height(opts))
864
- svg = SVGUtilities::add_compass(svg)
865
-
866
- if DEBUG_OUTPUT; printf("svg_draw_separate: section_idx = %s\r\n", section_idx.to_s()) end
867
-
868
- if opts['draw_interactive'] == true
869
- svg = SVGUtilities::svg_add_script(svg, opts)
870
- end
871
-
872
- x = opts['name_x'] + opts['margin']
873
- y = opts['name_y'] + opts['margin']
874
- font_size = opts['name_font_size']
875
-
876
- svg, x, y = SVGUtilities::add_titles(svg, opts, x, y, font_size, mapname, mapcreator)
877
-
878
- x, y = svg_draw(svg, opts, x, y, svgfile, section_idx)
879
-
880
- svg.root.attributes["height"] = y
881
-
882
- formatter = REXML::Formatters::Pretty.new(2)
883
- formatter.compact = true
884
-
885
- file = File.open(svgfile, "w")
886
- file.puts formatter.write(svg, "")
887
- file.close
888
-
889
- if DEBUG_OUTPUT; printf("\r\n") end
890
-
891
- end
892
- end
893
-
894
-
895
- class FXMap
896
-
897
- def svg_draw_sections_separate( opts, svgfile )
898
-
899
- @sections.each_with_index { |sect, idx|
900
-
901
- svgfilename = String::new(str=svgfile)
902
-
903
- @section = idx
904
- create_pathmap
905
-
906
- if DEBUG_OUTPUT; printf("svg_draw_sections_separate: filename = %s\r\n", svgfilename.to_s()) end
907
-
908
- # Remove .svg from end of filename if it is there.
909
- if svgfilename =~ /\.svg$/
910
- svgfilename = svgfilename[0..-5];
911
- end
912
-
913
- # Append the section number.
914
- svgfilename << "-section" << (idx + 1).to_s()
915
-
916
- if DEBUG_OUTPUT; printf("svg_draw_separate: filename = %s\r\n", svgfilename.to_s()) end
917
-
918
- # Add .svg back onto the end of the filename.
919
- svgfilename << ".svg"
920
-
921
- if DEBUG_OUTPUT; printf("svg_draw_separate: filename = %s\r\n", svgfilename.to_s()) end
922
-
923
- status "Exporting SVG file '#{svgfilename}'"
924
-
925
- sect.svg_draw_separate( opts, svgfilename, idx, @name, @creator)
926
- }
927
-
928
- status "Exporting SVG Completed"
929
- end
930
-
931
- def svg_draw_sections( opts, svgfile )
932
- if DEBUG_OUTPUT; puts "svg::FXMap::svg_draw_sections" end
933
- if DEBUG_OUTPUT; printf("svg::FXMap::svg_draw_sections:@section=%s\r\n", @section) end
934
-
935
- x = opts['name_x'] + opts['margin']
936
- y = opts['name_y'] + opts['margin']
937
- font_size = opts['name_font_size']
938
-
939
- svg = SVGUtilities::new_svg_doc(max_width(opts), total_height(opts))
940
- svg = SVGUtilities::add_compass(svg)
941
-
942
- if opts['draw_interactive'] == true
943
- svg = SVGUtilities::svg_add_script(svg, opts)
944
- end
945
-
946
- svg, x, y = SVGUtilities::add_titles(svg, opts, x, y, font_size, @name, @creator)
947
-
948
- @sections.each_with_index { |sect, idx|
949
-
950
- @section = idx
951
- # For each page, we need to regenerate the pathmap so that complex
952
- # paths will come out ok.
953
- create_pathmap
954
- # Now, we draw it
955
-
956
- x, y = sect.svg_draw(svg, opts, x, y, @name, idx)
957
-
958
- y = y + (opts['hh'] * 2)
959
-
960
- }
961
-
962
- create_pathmap
963
- svg.root.attributes["height"] = y
964
-
965
- if svgfile !~ /\.svg$/
966
- svgfile << ".svg"
967
- end
968
-
969
- status "Exporting SVG file '#{svgfile}'"
970
-
971
- formatter = REXML::Formatters::Pretty.new(2)
972
- formatter.compact = true
973
-
974
- file = File.open(svgfile, "w")
975
- file.puts formatter.write(svg, "")
976
- file.close
977
-
978
- status "Exporting SVG Completed"
979
-
980
- end
981
-
982
- def max_width(opts)
983
- max_width=0
984
- @sections.each_with_index{ |sect, idx|
985
- maxx = sect.svg_width(opts)
986
- if(maxx > max_width)
987
- max_width = maxx
988
- end
989
- if DEBUG_OUTPUT; puts("section=" + idx.to_s + ":maxx=" + maxx.to_s) end
990
- }
991
- return max_width
992
- end
993
-
994
- def total_height(opts)
995
- total_height=0
996
- @sections.each_with_index{ |sect, idx|
997
- maxy = sect.svg_height(opts)
998
- total_height = total_height + maxy
999
- }
1000
- return total_height
1001
- end
1002
-
1003
- def num_sections()
1004
- return @sections.length
1005
- end
1006
-
1007
- def svg_export(svgfile, printer = nil)
1008
-
1009
- if DEBUG_OUTPUT; puts "svg::FXMap::svg_export" end
1010
-
1011
- map_options = @options.dup
1012
-
1013
- ww = SVG_ROOM_WIDTH + SVG_ROOM_WS
1014
- hh = SVG_ROOM_HEIGHT + SVG_ROOM_HS
1015
-
1016
- svg_options = {
1017
- 'ww' => ww,
1018
- 'hh' => hh,
1019
- 'w' => SVG_ROOM_WIDTH,
1020
- 'h' => SVG_ROOM_HEIGHT,
1021
- 'ws' => SVG_ROOM_WS,
1022
- 'hs' => SVG_ROOM_HS,
1023
- 'ws_2' => SVG_ROOM_WS / 2.0,
1024
- 'hs_2' => SVG_ROOM_HS / 2.0,
1025
- 'margin' => 10,
1026
- 'margin_2' => 5,
1027
- # 'width' => map_width,
1028
- # 'height' => map_height,
1029
- 'text_max_chars' => 20,
1030
- 'text_line_spacing' => 2,
1031
- 'text_margin' => 5,
1032
- 'room_line_width' => 2,
1033
- 'room_line_colour' => "black",
1034
- 'room_font_size' => 8,
1035
- 'objects_font_size' => 6,
1036
- 'objects_width' => 140,
1037
- 'room_num_font_size' => 6,
1038
- 'print_room_nums' => true,
1039
- 'num_line_width' => 1,
1040
- 'num_line_colour' => "black",
1041
- 'num_fill_colour' => "lightgreen",
1042
- 'conn_line_width' => 2,
1043
- 'conn_line_colour' => "black",
1044
- 'door_line_width' => 2,
1045
- 'door_line_colour' => "forestgreen",
1046
- 'arrow_line_width' => 1,
1047
- 'arrow_line_colour' => "black",
1048
- 'arrow_fill_colour' => "black",
1049
- 'name_font_size' => 18,
1050
- 'name_x' => 0,
1051
- 'name_y' => 0,
1052
- 'name_line_spacing' => 4,
1053
- 'print_title' => true,
1054
- 'print_creator' => true,
1055
- 'print_date' => true,
1056
- 'creator_prefix' => "Creator: ",
1057
- 'date_prefix' => "Date: ",
1058
- 'draw_interactive' => true,
1059
- 'draw_roomnames' => true,
1060
- 'draw_connections' => true,
1061
- 'corner_size' => 15,
1062
- 'corner_line_colour' => "black",
1063
- 'corner_line_width' => 1,
1064
- 'corner_fill_colour' => "lightgreen",
1065
- 'objs_line_colour' => "black",
1066
- 'objs_line_width' => 1,
1067
- 'objs_fill_colour' => "lightgreen",
1068
- 'print_section_names' => true,
1069
- 'section_name_prefix' => "Section: ",
1070
- 'split_sections' => false,
1071
- 'draw_sectioncomments' => true,
1072
- 'compass_size' => 3
1073
- }
1074
-
1075
- svg_options.merge!(map_options)
1076
-
1077
- begin
1078
-
1079
- if svg_options['split_sections'] == false
1080
- svg_draw_sections(svg_options, svgfile)
1081
- else
1082
- svg_draw_sections_separate(svg_options, svgfile)
1083
- end
1084
-
1085
- rescue => e
1086
- p e
1087
- p e.backtrace
1088
- raise e
1089
- end
1090
- end
1091
- end
1
+ require 'IFMapper/MapPrinting'
2
+ require 'rexml/document'
3
+ require 'rexml/cdata'
4
+
5
+ DEBUG_OUTPUT = false
6
+ SVG_ZOOM = 1
7
+ SVG_ROOM_WIDTH = W * SVG_ZOOM
8
+ SVG_ROOM_HEIGHT = H * SVG_ZOOM
9
+ SVG_ROOM_WS = WS * SVG_ZOOM
10
+ SVG_ROOM_HS = HS * SVG_ZOOM
11
+ DEFAULT_BGROUND_IMAGE_FORMAT = '.jpg'
12
+
13
+ class SVGUtilities
14
+
15
+ def self.should_draw_interactive(opts)
16
+ if opts['draw_tasks'] or opts['draw_objects'] or opts['draw_comments'] or opts['draw_description']
17
+ return true
18
+ else
19
+ return false
20
+ end
21
+ end
22
+
23
+ def self.new_svg_doc ( width, height)
24
+ svg = REXML::Document.new
25
+ svg << REXML::XMLDecl.new( version=1.0, encoding=REXML::XMLDecl::DEFAULT_ENCODING )
26
+ svg << REXML::DocType.new( 'svg', REXML::DocType::PUBLIC + ' "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"' )
27
+ svg << REXML::Comment.new(" #{MSG_SVG_GENERATOR} ")
28
+ svg << REXML::Comment.new(" #{MSG_SVG_GENERATION_DATE} " + Time.now.utc.to_s + ' ')
29
+ svg << REXML::Comment.new(" #{HOMEPAGE} ")
30
+
31
+ svg.add_element "svg", {
32
+ "width" => width,
33
+ "height" => height,
34
+ "version" => "1.1",
35
+ "xmlns" => "http://www.w3.org/2000/svg",
36
+ "xmlns:xlink" => "http://www.w3.org/1999/xlink"}
37
+ return svg
38
+
39
+ end
40
+
41
+ def self.add_text( svg, x, y, font_size, text, opts, fill_colour )
42
+ if DEBUG_OUTPUT; puts "svg::FXMap::svg_draw_name_text:" end
43
+ y = y + font_size
44
+
45
+ t = svg.root.add_element "text", {
46
+ "x" => x,
47
+ "y" => y,
48
+ "style" => "font-size:" + font_size.to_s() + "pt;fill:#" + fill_colour.to_s()}
49
+
50
+ t.text = text
51
+
52
+ return [svg, x, y]
53
+ end
54
+
55
+ def self.num_text_lines ( text, maxlinelength )
56
+ if text and not text == ''
57
+ return SVGUtilities::break_text_lines(text.chomp().strip(), maxlinelength).length
58
+ else
59
+ return 0
60
+ end
61
+ end
62
+
63
+ def self.break_text_lines( text, maxlinelength )
64
+ if DEBUG_OUTPUT; printf("SVGUtilities::break_text_lines:text=%s\r\n", text) end
65
+
66
+ out = Array.new
67
+
68
+ max_chars = maxlinelength
69
+ lines = text.split("\n")
70
+ if DEBUG_OUTPUT; printf("SVGUtilities::break_text_lines:lines=%s\r\n", lines) end
71
+ words = text.split(" ")
72
+ if DEBUG_OUTPUT; printf("SVGUtilities::break_text_lines:words=%s\r\n", words) end
73
+ cur_str = ""
74
+
75
+ lines.each { |line|
76
+ words = line.split(" ");
77
+ words.each { |word|
78
+ new_len = cur_str.length + word.length
79
+ if DEBUG_OUTPUT; printf("SVGUtilities::break_text_lines:current word: %s :: new_len: %d\r\n", word, new_len) end
80
+ new_len = cur_str.length + word.length
81
+ if new_len <= max_chars
82
+ cur_str = cur_str + word + " "
83
+ else
84
+ out << cur_str
85
+ cur_str = "" + word + " "
86
+ end
87
+ }
88
+ out << cur_str
89
+ cur_str = ""
90
+ }
91
+
92
+ return out
93
+ end
94
+
95
+ def self.get_compass_svg_group()
96
+
97
+ file = File.new( "icons/compass.svg" )
98
+ doc = REXML::Document.new file
99
+
100
+ newgroup = REXML::Element.new "g"
101
+ newgroup.attributes["id"] = "compass"
102
+
103
+ doc.root.elements.each {|elem|
104
+ if elem.elements['tspan'] != nil
105
+ if elem.elements['tspan'].text =~ /^N$/
106
+ elem.elements['tspan'].text = Room::DIRECTIONS[0].upcase
107
+ elsif elem.elements['tspan'].text =~ /^E$/
108
+ elem.elements['tspan'].text = Room::DIRECTIONS[2].upcase
109
+ elsif elem.elements['tspan'].text =~ /^S$/
110
+ elem.elements['tspan'].text = Room::DIRECTIONS[4].upcase
111
+ elsif elem.elements['tspan'].text =~ /^W$/
112
+ elem.elements['tspan'].text = Room::DIRECTIONS[6].upcase
113
+ end
114
+ if DEBUG_OUTPUT; puts "svg::SVGUtilities::get_compass_svg_group:translated_compass_dir:#{elem.elements['tspan'].text}" end
115
+ end
116
+
117
+ newgroup.add_element(elem)
118
+ }
119
+
120
+ return newgroup
121
+
122
+ end
123
+
124
+ def self.add_compass(svg)
125
+ compassgroup = SVGUtilities::get_compass_svg_group()
126
+
127
+ defs = svg.root.add_element "defs"
128
+
129
+ defs.add_element compassgroup
130
+
131
+ return svg
132
+ end
133
+
134
+
135
+ def self.svg_add_script( svg, opts )
136
+ svg.root.attributes["onload"] = "Init(evt)"
137
+
138
+ script = svg.root.add_element "script", {
139
+ "type" => "text/ecmascript" }
140
+
141
+ script.add( REXML::CData.new("
142
+ var SVGDocument = null;
143
+ var SVGRoot = null;
144
+
145
+ function Init(evt)
146
+ {
147
+ SVGDocument = evt.target.ownerDocument;
148
+ SVGRoot = SVGDocument.documentElement;
149
+ }
150
+
151
+ function ToggleOpacity(evt, targetId)
152
+ {
153
+ var newTarget = evt.target;
154
+ if (targetId)
155
+ {
156
+ newTarget = SVGDocument.getElementById(targetId);
157
+ }
158
+ var newValue = newTarget.getAttributeNS(null, 'opacity')
159
+
160
+ if ('0' != newValue)
161
+ {
162
+ newValue = '0';
163
+ }
164
+ else
165
+ {
166
+ newValue = '1';
167
+ }
168
+ newTarget.setAttributeNS(null, 'opacity', newValue);
169
+
170
+ if (targetId)
171
+ {
172
+ SVGDocument.getElementById(targetId + 'Exception').setAttributeNS(null, 'opacity', '1');
173
+ }
174
+ }
175
+ "))
176
+
177
+ return svg;
178
+ end
179
+
180
+ def self.add_titles( svg, opts, x, y, font_size, mapname, mapcreator )
181
+ if DEBUG_OUTPUT; puts "svg::SVGUtilities::add_titles" end
182
+
183
+ if opts['print_title'] == true
184
+ if not mapname or mapname == ''
185
+ if DEBUG_OUTPUT; puts "svg::SVGUtilities::add_titles:name is empty, not printing" end
186
+ else
187
+ svg, x, y = SVGUtilities::add_text(svg, x, y, (font_size*1.5).to_i, mapname, opts, '000000')
188
+ y = y + (opts['name_line_spacing'] * 4)
189
+ end
190
+ end
191
+
192
+ if opts['print_creator'] == true
193
+ if not mapcreator or mapcreator == ''
194
+ if DEBUG_OUTPUT; puts "svg::SVGUtilities::add_titles:creator is empty, not printing" end
195
+ else
196
+ svg, x, y = SVGUtilities::add_text(svg, x, y, (font_size*0.85).to_i, 'Map ' + opts['creator_prefix'] + mapcreator, opts, '000000')
197
+ y = y + (opts['name_line_spacing'] * 4)
198
+ end
199
+ end
200
+
201
+ return [svg, x, y]
202
+ end
203
+
204
+ def self.add_background(svg, width, height, svgfilename)
205
+ if DEBUG_OUTPUT; puts "svg::SVGUtilities::add_background" end
206
+
207
+ svgbgroundimagefilename = "#{svgfilename}#{DEFAULT_BGROUND_IMAGE_FORMAT}"
208
+
209
+ if svg.root.elements["defs"] == nil
210
+ svg.root.add_element "defs"
211
+ end
212
+
213
+ defs = svg.root.elements["defs"]
214
+
215
+ defs[0,0] = REXML::Comment.new(" #{MSG_SVG_BGROUND_IMAGE_SECT_BEGINS} ")
216
+
217
+ bgpattern = REXML::Element.new('pattern')
218
+ bgpattern.add_attributes({
219
+ 'id' => 'backgroundimg',
220
+ 'patternUnits' => 'userSpaceOnUse',
221
+ 'x' => '0',
222
+ 'y' => '0',
223
+ 'height' => height,
224
+ 'width' => width
225
+ })
226
+ bgpattern.add_element 'image', {
227
+ 'xlink:href' => svgbgroundimagefilename,
228
+ 'height' => height,
229
+ 'width' => width
230
+ }
231
+ defs[1,0] = bgpattern
232
+
233
+ defs[2,0] = REXML::Comment.new(" #{MSG_SVG_BGROUND_IMAGE_SECT_ENDS} ")
234
+
235
+ bgpath = REXML::Comment.new(" #{MSG_SVG_BGROUND_IMAGE_ENABLE_COMMENT_START} #{svgbgroundimagefilename} #{MSG_SVG_BGROUND_IMAGE_ENABLE_COMMENT_END} -->\n"\
236
+ " <!--<path"\
237
+ " d='M5,5 l0," + height + " l" + width + ",0 l0,-" + height + " l-" + width + ",0" + "'"\
238
+ " fill='url(#backgroundimg)'/>"
239
+ )
240
+ svg.root.insert_after(defs, bgpath)
241
+
242
+ return svg
243
+ end
244
+
245
+ end
246
+ #
247
+ # Open all the map class and add all SVG methods there
248
+ # Gotta love Ruby's flexibility to just inject in new methods.
249
+ #
250
+ class FXConnection
251
+ def _svg_cvt_pt(p, opts)
252
+ if DEBUG_OUTPUT; puts "svg::FXConnection::_svg_cvt_pt" end
253
+ x = (p[0] - WW / 2.0) / WW.to_f
254
+ y = (p[1] - HH / 2.0) / HH.to_f
255
+ x = x * opts['ww'] + opts['margin'] + opts['w'] / 2.0
256
+ y = y * opts['hh'] + opts['margin'] + opts['hs'] - 2
257
+ return [x, y]
258
+ end
259
+
260
+ def svg_draw_arrow(svg, opts, x1, y1, x2, y2)
261
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_arrow:#{x1},#{y1},#{x2},#{y2}" end
262
+ return if @dir == BOTH
263
+
264
+ pt1, d = _arrow_info( x1, y1, x2, y2, 0.5 )
265
+
266
+ if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: pt1[0]=%0.01f,pt1[1]=%0.01f,d[0]=%0.01f,d[1]=%0.01f\r\n", pt1[0], pt1[1], d[0], d[1]) end
267
+
268
+ mx = pt1[0];
269
+ my = pt1[1];
270
+
271
+ if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: mx=%0.01f,my=%0.01f\r\n",mx,my) end
272
+
273
+ lx1 = pt1[0] + d[0]
274
+ ly1 = pt1[1] + d[1]
275
+
276
+ if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: lx1=%0.01f,ly1=%0.01f\r\n",lx1,ly1) end
277
+
278
+ lx2 = pt1[0] + d[1]
279
+ ly2 = pt1[1] - d[0]
280
+
281
+ if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw_arrow: lx2=%0.01f,ly2=%0.01f\r\n",lx2,ly2) end
282
+
283
+ points = sprintf("%0.01f", mx) + "," + sprintf("%0.01f", my) + " "
284
+ points << sprintf("%0.01f", lx1) + "," + sprintf("%0.01f", ly1) + " "
285
+ points << sprintf("%0.01f", lx2) + "," + sprintf("%0.01f", ly2) + " "
286
+
287
+ svg.root.add_element "polygon", {
288
+ "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s",opts['arrow_line_colour'],opts['arrow_line_width'],opts['arrow_fill_colour']),
289
+ "points" => points }
290
+
291
+ end
292
+
293
+ def svg_draw_complex_as_bspline( svg, opts )
294
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_complex_as_bspline" end
295
+ p = []
296
+ p << _svg_cvt_pt(@pts[0], opts)
297
+ p << p[0]
298
+ p << p[0]
299
+ @pts.each { |pt|
300
+ p << _svg_cvt_pt(pt, opts)
301
+ }
302
+ p << p[-1]
303
+ p << p[-1]
304
+ p << p[-1]
305
+ return FXSpline::bspline(p)
306
+ end
307
+
308
+ def svg_draw_complex_as_lines( svg, opts )
309
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_complex_as_lines" end
310
+ p = []
311
+ @pts.each { |pt|
312
+ p << _svg_cvt_pt(pt, opts)
313
+ }
314
+ return p
315
+ end
316
+
317
+ def svg_draw_door( svg, x1, y1, x2, y2 , opts)
318
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_arrow:#{x1},#{y1},#{x2},#{y2}" end
319
+ v = [ (x2-x1), (y2-y1) ]
320
+ t = 10 / Math.sqrt(v[0]*v[0]+v[1]*v[1])
321
+ v = [ v[0]*t, v[1]*t ]
322
+ m = [ (x2+x1)/2, (y2+y1)/2 ]
323
+ x1, y1 = [m[0] + v[1], m[1] - v[0]]
324
+ x2, y2 = [m[0] - v[1], m[1] + v[0]]
325
+
326
+ v = [ v[0] / 3, v[1] / 3]
327
+
328
+ poly = svg.root.add_element "polygon", {
329
+ "style" => sprintf("stroke:%s;stroke-width:%s", opts['door_line_colour'],opts['door_line_width']),
330
+ "points" => sprintf("%0.01f,%0.01f %0.01f,%0.01f %0.01f,%0.01f %0.01f,%0.01f",
331
+ x1-v[0], y1-v[1], x1+v[0], y1+v[1], x2+v[0], y2+v[1], x2-v[0], y2-v[1]) }
332
+
333
+ if @type == LOCKED_DOOR
334
+ poly.attributes["style"] << sprintf(";fill:%s", opts['door_line_colour'])
335
+ else
336
+ poly.attributes["style"] << ";fill:none"
337
+ end
338
+ end
339
+
340
+ def svg_draw_complex( svg, opts, sx ,sy )
341
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_complex" end
342
+ if opts['Paths as Curves']
343
+ if @room[0] == @room[1]
344
+ dirA, dirB = dirs
345
+ if dirA == dirB
346
+ p = svg_draw_complex_as_lines( svg, opts )
347
+ else
348
+ p = svg_draw_complex_as_bspline( svg, opts )
349
+ end
350
+ else
351
+ p = svg_draw_complex_as_bspline( svg, opts )
352
+ end
353
+ else
354
+ p = svg_draw_complex_as_lines( svg, opts )
355
+ end
356
+
357
+ p.each { |pt|
358
+ pt[0] = pt[0] + sx
359
+ pt[1] = pt[1] + sy }
360
+
361
+ d = "M" + sprintf("%0.01f", p[0][0]) + "," + sprintf("%0.01f", p[0][1]) + " "
362
+
363
+ p.each { |pt|
364
+ d = d + "L" + sprintf("%0.01f", pt[0]) + "," + sprintf("%0.01f", pt[1]) + " " }
365
+
366
+ path = svg.root.add_element "path", {
367
+ "style" => sprintf("stroke:%s;stroke-width:%s;fill:none",opts['conn_line_colour'],opts['conn_line_width']),
368
+ "d" => d }
369
+
370
+ if @type == SPECIAL
371
+ path.attributes["style"] << ";stroke-dasharray:9,5"
372
+ end
373
+
374
+ x1, y1 = [p[0][0], p[0][1]]
375
+ x2, y2 = [p[-1][0], p[-1][1]]
376
+
377
+ svg_draw_arrow(svg, opts, x1, y1, x2, y2)
378
+
379
+ if @type == LOCKED_DOOR or @type == CLOSED_DOOR
380
+ t = p.size / 2
381
+ x1, y1 = [ p[t][0], p[t][1] ]
382
+ x2, y2 = [ p[t-2][0], p[t-2][1] ]
383
+
384
+ svg_draw_door(svg, x1, y1, x2, y2, opts)
385
+ end
386
+ end
387
+
388
+ def svg_draw_simple(svg, opts, sx, sy)
389
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_simple" end
390
+ return if not @room[1]
391
+
392
+ dir = @room[0].exits.index(self)
393
+ x1, y1 = @room[0].svg_corner(opts, self, dir)
394
+ x2, y2 = @room[1].svg_corner(opts, self)
395
+
396
+ x1 = x1 + sx;
397
+ x2 = x2 + sx;
398
+ y1 = y1 + sy;
399
+ y2 = y2 + sy;
400
+
401
+ line = svg.root.add_element "line", {
402
+ "x1" => x1,
403
+ "y1" => y1,
404
+ "x2" => x2,
405
+ "y2" => y2,
406
+ "style" => sprintf("stroke:%s;stroke-width:%s", opts['conn_line_colour'],opts['conn_line_width']) }
407
+
408
+ if @type == SPECIAL
409
+ line.attributes["style"] << ";stroke-dasharray:9,5"
410
+ end
411
+
412
+ svg_draw_arrow(svg, opts, x1, y1, x2, y2)
413
+ if @type == LOCKED_DOOR or @type == CLOSED_DOOR
414
+ svg_draw_door(svg, x1, y1, x2, y2, opts)
415
+ end
416
+ end
417
+
418
+ #
419
+ # Draw the connection text next to the arrow ('I', 'O', etc)
420
+ #
421
+ def svg_draw_text(svg, x, y, dir, text, arrow)
422
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_text:#{x},#{y},#{text}" end
423
+ if dir == 7 or dir < 6 and dir != 1
424
+ if arrow and (dir == 0 or dir == 4)
425
+ x += 5
426
+ end
427
+ x += 2.5
428
+ elsif dir == 6 or dir == 1
429
+ x -= 7.5
430
+ end
431
+
432
+ if dir > 5 or dir < 4
433
+ if arrow and (dir == 6 or dir == 2)
434
+ y -= 5
435
+ end
436
+ y -= 2.5
437
+ elsif dir == 4 or dir == 5
438
+ y += 7.5
439
+ end
440
+
441
+ font_size = 6
442
+
443
+ t = svg.root.add_element "text", {
444
+ "x" => x,
445
+ "y" => y,
446
+ "style" => "font-size:" + font_size.to_s() + "pt"}
447
+
448
+ t.text = text;
449
+ end
450
+
451
+ def svg_draw_exit_text(pdf, opts, sx, sy)
452
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw_exit_text" end
453
+ if @exitText[0] != 0
454
+ dir = @room[0].exits.index(self)
455
+ x, y = @room[0].svg_corner(opts, self, dir)
456
+ x = x + sx
457
+ y = y + sy
458
+ svg_draw_text( pdf, x, y, dir,
459
+ EXIT_TEXT[@exitText[0]], @dir == BtoA)
460
+ end
461
+
462
+ if @exitText[1] != 0
463
+ dir = @room[1].exits.rindex(self)
464
+ x, y = @room[1].svg_corner(opts, self, dir)
465
+ x = x + sx
466
+ y = y + sy
467
+ svg_draw_text( pdf, x, y, dir,
468
+ EXIT_TEXT[@exitText[1]], @dir == AtoB)
469
+ end
470
+ end
471
+
472
+ def svg_draw(svg, opts, x, y)
473
+ if DEBUG_OUTPUT; printf("svg::FXConnection::svg_draw:draw_connections=%s\r\n", opts['draw_connections'].to_s()) end
474
+ if opts['draw_connections'] == true
475
+ if DEBUG_OUTPUT; puts "svg::FXConnection::svg_draw" end
476
+
477
+ svg_draw_exit_text(svg, opts, x, y)
478
+
479
+ if @pts.size > 0
480
+ svg_draw_complex(svg, opts, x, y)
481
+ else
482
+ svg_draw_simple(svg, opts, x, y)
483
+ end
484
+ end
485
+ end
486
+ end
487
+
488
+
489
+ class FXRoom
490
+
491
+ def hasTasks()
492
+ return (@tasks and not @tasks == '')
493
+ end
494
+
495
+ def hasObjects()
496
+ return (@objects and not @objects == '')
497
+ end
498
+
499
+ def hasComments()
500
+ return (@comment and not @comment == '')
501
+ end
502
+
503
+ def hasDescription()
504
+ return (@desc and not @desc == '')
505
+ end
506
+
507
+ def svg_corner( opts, c, idx = nil )
508
+ if DEBUG_OUTPUT; puts "svg::FXRoom::svg_corner" end
509
+ x, y = _corner(c, idx)
510
+
511
+ ww = opts['ww']
512
+ hh = opts['hh']
513
+ w = opts['w']
514
+ h = opts['h']
515
+
516
+ x = @x * ww + x * w + opts['margin']
517
+ y = @y * hh + y * h + opts['margin']
518
+
519
+ return [x, y]
520
+ end
521
+
522
+ def svg_draw_box( svg, opts, idx, sx, sy )
523
+ if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_box" end
524
+ x = sx + (@x * opts['ww']) + opts['margin']
525
+ y = sy + (@y * opts['hh']) + opts['margin']
526
+
527
+ if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_box[x=%s,y=%s,w=%s,h=%s]\r\n", x,y,opts['w'],opts['h']) end
528
+
529
+ roomrect = svg.root.add_element "rect", {
530
+ "x" => x,
531
+ "y" => y,
532
+ "width" => opts['w'],
533
+ "height" => opts['h'],
534
+ "style" => sprintf("stroke:%s;stroke-width:%s", opts['room_line_colour'],opts['room_line_width'])}
535
+
536
+ if @darkness
537
+ if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_box:DARKNESS" end
538
+ roomrect.attributes["style"] << ";fill:gray"
539
+ else
540
+ if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_box:not darkness" end
541
+ roomrect.attributes["style"] << ";fill:none"
542
+ end
543
+
544
+ if opts['print_room_nums'] == true
545
+
546
+ # Add the room number to the bottom right hand corner!
547
+
548
+ pad = 2
549
+ font_size = 8
550
+ numbox_width = (pad*2) + (3*font_size)
551
+ numbox_height = (pad*2)+font_size
552
+ numbox_x = (x + opts['w']) - numbox_width
553
+ numbox_y = (y + opts['h']) - numbox_height
554
+
555
+ numbox_rect = svg.root.add_element "rect", {
556
+ "x" => numbox_x,
557
+ "y" => numbox_y,
558
+ "width" => numbox_width,
559
+ "height" => numbox_height,
560
+ "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s", opts['num_line_colour'],opts['num_line_width'],opts['num_fill_colour']) }
561
+
562
+ numtext_x = numbox_x + pad
563
+ numtext_y = numbox_y + font_size + pad
564
+
565
+ idx += 1
566
+
567
+ if idx < 100
568
+ numtext_x += font_size
569
+ end
570
+
571
+ if idx < 10
572
+ numtext_x += font_size
573
+ end
574
+
575
+ numtext = svg.root.add_element "text", {
576
+ "x" => numtext_x,
577
+ "y" => numtext_y,
578
+ "style" => "font-size:" + font_size.to_s() + "pt" }
579
+
580
+ numtext.text = idx.to_s()
581
+
582
+ end
583
+ end
584
+
585
+ def svg_draw_text( svg, opts, x, y, text, font_size )
586
+ if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_text:text=%s\r\n", text) end
587
+
588
+ t = svg.root.add_element "text", {
589
+ "x" => x,
590
+ "y" => y,
591
+ "style" => "font-size:" + font_size.to_s() + "pt"}
592
+
593
+ max_chars = opts['text_max_chars']
594
+ words = text.split(" ")
595
+ dy = 0
596
+ ypos = 0
597
+ lasty = opts['h'] - opts['text_margin']
598
+ cur_str = ""
599
+
600
+ words.each { |word|
601
+ new_len = cur_str.length + word.length
602
+ if DEBUG_OUTPUT; printf("current word: %s :: new_len: %d\r\n", word, new_len) end
603
+ new_len = cur_str.length + word.length
604
+ if new_len <= max_chars
605
+ cur_str = cur_str + word + " "
606
+ else
607
+ ypos = ypos + font_size + opts['text_line_spacing']
608
+ if ypos >= lasty
609
+ break
610
+ end
611
+ tspan = t.add_element "tspan", {
612
+ "x" => x,
613
+ "dy" => dy }
614
+ tspan.text = cur_str
615
+ if dy == 0
616
+ dy = font_size + opts['text_line_spacing']
617
+ end
618
+ cur_str = "" + word + " "
619
+ end
620
+ }
621
+
622
+ if ypos < lasty
623
+ tspan = t.add_element "tspan", {
624
+ "x" => x,
625
+ "dy" => dy }
626
+ tspan.text = cur_str
627
+ end
628
+
629
+ return [x, y+ypos]
630
+ end
631
+
632
+ def svg_draw_objects(svg, opts, x, y)
633
+ if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_objects" end
634
+ font_size = 6
635
+ objs = @objects.split("\n")
636
+ objs = objs.join(', ')
637
+ return svg_draw_text( svg, opts, x, y, objs, font_size )
638
+ end
639
+
640
+ def svg_draw_name(svg, opts, sx, sy, roomname)
641
+ if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_name:name=%s\r\n", roomname) end
642
+
643
+ x = sx + (@x * opts['ww']) + opts['margin'] + opts['text_margin']
644
+ y = sy + (@y * opts['hh']) + opts['margin'] + opts['text_margin']
645
+ font_size = 8
646
+ y = y + font_size
647
+
648
+ return svg_draw_text( svg, opts, x, y, roomname, font_size )
649
+ end
650
+
651
+ def svg_draw_interactive( svg, opts, idx, sx, sy, section_idx )
652
+ if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw_interactive" end
653
+
654
+ if (hasObjects() and opts['draw_objects']) or (hasTasks() and opts['draw_tasks']) or (hasComments() and opts['draw_comments']) or (hasDescription() and opts['draw_description'])
655
+
656
+ x = sx + (@x * opts['ww']) + opts['margin'] + opts['w']
657
+ y = sy + (@y * opts['hh']) + opts['margin']
658
+
659
+ x1 = x - opts['corner_size']
660
+ y1 = y
661
+
662
+ x2 = x
663
+ y2 = y + opts['corner_size']
664
+
665
+ poly = svg.root.add_element "polygon", {
666
+ "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s", opts['corner_line_colour'],opts['corner_line_width'],opts['corner_fill_colour']),
667
+ "points" => sprintf("%0.01f,%0.01f %0.01f,%0.01f %0.01f,%0.01f", x, y, x1, y1, x2, y2),
668
+ "onclick" => "ToggleOpacity(evt, \"section"+section_idx.to_s()+"room"+idx.to_s()+"\")" }
669
+
670
+ objs_font_size = opts['objects_font_size']
671
+ num_chars_per_line = ((opts['objects_width'] / (objs_font_size)) * opts['font_width_fiddle']).floor
672
+
673
+ numObjsLines = 0
674
+ numTaskLines = 0
675
+ numCommLines = 0
676
+ numDescLines = 0
677
+
678
+ if(hasObjects() and opts['draw_objects'])
679
+ numObjsLines = SVGUtilities::num_text_lines(@objects, num_chars_per_line);
680
+ end
681
+
682
+ if(hasTasks() and opts['draw_tasks'])
683
+ numTaskLines = SVGUtilities::num_text_lines(@tasks, num_chars_per_line);
684
+ end
685
+
686
+ if(hasComments() and opts['draw_comments'])
687
+ numCommLines = SVGUtilities::num_text_lines(@comment, num_chars_per_line);
688
+ end
689
+
690
+ if(hasDescription() and opts['draw_description'])
691
+ numDescLines = SVGUtilities::num_text_lines(@desc, num_chars_per_line);
692
+ end
693
+
694
+ if(numObjsLines > 0)
695
+ numObjsLines = numObjsLines + 2
696
+ end
697
+
698
+ if(numTaskLines > 0)
699
+ numTaskLines = numTaskLines + 2
700
+ end
701
+
702
+ if(numCommLines > 0)
703
+ numCommLines = numCommLines + 2
704
+ end
705
+
706
+ if(numDescLines > 0)
707
+ numDescLines = numDescLines + 2
708
+ end
709
+
710
+ lines = numObjsLines + numTaskLines + numCommLines + numDescLines
711
+
712
+ objs_height = (lines+1) * (objs_font_size + opts['text_line_spacing'])
713
+
714
+ g = svg.root.add_element "g", {
715
+ "id" => "section"+section_idx.to_s()+"room"+idx.to_s(),
716
+ "opacity" => "0" }
717
+
718
+ rect_x = x - opts['objects_width'] - opts['corner_size']
719
+ rect_y = y + opts['corner_size']
720
+
721
+ g.add_element "rect", {
722
+ "x" => rect_x,
723
+ "y" => rect_y,
724
+ "width" => opts['objects_width'],
725
+ "height" => objs_height,
726
+ "style" => sprintf("stroke:%s;stroke-width:%s;fill:%s", opts['objs_line_colour'],opts['objs_line_width'],opts['objs_fill_colour']) }
727
+
728
+ text_x = rect_x + opts['text_margin']
729
+ text_y = rect_y + opts['text_margin'] + objs_font_size
730
+
731
+ if hasObjects() and opts['draw_objects']
732
+ t1 = g.add_element "text", {
733
+ "x" => text_x,
734
+ "y" => text_y,
735
+ "style" => "font-size:" + objs_font_size.to_s() + "pt;font-weight:bold" }
736
+ t1.text = "Objects:"
737
+
738
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
739
+ objs_lines = SVGUtilities::break_text_lines(@objects, num_chars_per_line)
740
+ text_x, text_y = svg_draw_interactive_objects( g, opts, text_x, text_y, objs_font_size, objs_lines)
741
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
742
+ end
743
+
744
+ if hasTasks() and opts['draw_tasks']
745
+ t2 = g.add_element "text", {
746
+ "x" => text_x,
747
+ "y" => text_y,
748
+ "style" => "font-size:" + objs_font_size.to_s() + "pt;font-weight:bold" }
749
+ t2.text = "Tasks:"
750
+
751
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
752
+ tasks_lines = SVGUtilities::break_text_lines(@tasks, num_chars_per_line)
753
+ text_x, text_y = svg_draw_interactive_objects( g, opts, text_x, text_y, objs_font_size, tasks_lines)
754
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
755
+ end
756
+
757
+ if hasComments() and opts['draw_comments']
758
+ t2 = g.add_element "text", {
759
+ "x" => text_x,
760
+ "y" => text_y,
761
+ "style" => "font-size:" + objs_font_size.to_s() + "pt;font-weight:bold" }
762
+ t2.text = "Comments:"
763
+
764
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
765
+ comments_lines = SVGUtilities::break_text_lines(@comment, num_chars_per_line)
766
+ text_x, text_y = svg_draw_interactive_objects( g, opts, text_x, text_y, objs_font_size, comments_lines)
767
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
768
+ end
769
+
770
+ if hasDescription() and opts['draw_description']
771
+ t2 = g.add_element "text", {
772
+ "x" => text_x,
773
+ "y" => text_y,
774
+ "style" => "font-size:" + objs_font_size.to_s() + "pt;font-weight:bold" }
775
+ t2.text = "Description:"
776
+
777
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
778
+ desc_lines = SVGUtilities::break_text_lines(@desc, num_chars_per_line)
779
+ text_x, text_y = svg_draw_interactive_objects( g, opts, text_x, text_y, objs_font_size, desc_lines)
780
+ text_y = text_y + objs_font_size + opts['text_line_spacing']
781
+ end
782
+
783
+ end
784
+ end
785
+
786
+
787
+ def svg_draw_interactive_objects( group, opts, x, y, font_size, lines)
788
+ if DEBUG_OUTPUT; printf("svg::FXRoom::svg_draw_interactive_objects\r\n") end
789
+
790
+ t = group.add_element "text", {
791
+ "x" => x,
792
+ "y" => y,
793
+ "style" => "font-size:" + font_size.to_s() + "pt"}
794
+
795
+ dy = 0
796
+ ypos = 0
797
+
798
+ lines.each { |obj|
799
+
800
+ ypos = ypos + font_size + opts['text_line_spacing']
801
+ tspan = t.add_element "tspan", {
802
+ "x" => x,
803
+ "dy" => dy }
804
+ tspan.text = obj
805
+ if dy == 0
806
+ dy = font_size + opts['text_line_spacing']
807
+ end
808
+ }
809
+
810
+ return [x, y+ypos]
811
+ end
812
+
813
+ def svg_draw( svg, opts, idx, x, y )
814
+ if DEBUG_OUTPUT; puts "svg::FXRoom::svg_draw" end
815
+
816
+ if (!((opts['draw_connections'] == false) && (@name =~ /#{MSG_SVG_SHORTCUT_TO}.*/i)))
817
+ svg_draw_box( svg, opts, idx, x, y )
818
+
819
+ if ((opts['draw_roomnames'] == true) ||
820
+ (opts['current_section_only'] && opts['text_for_selected_only'] && @selected == true) ||
821
+ (@name =~ /#{MSG_SVG_SHORTCUT_TO}.*/i) ||
822
+ (idx == 0))
823
+
824
+ # Even if we're not printing location names, print the "Shortcut to"
825
+ # part of any locations which start with that text. This convention of
826
+ # a room named "Shortcut to <another location>" is for the sole purpose
827
+ # of allowing additional connections to be collected which are then fwd'd
828
+ # to the named location, because currently IFMapper can only provide
829
+ # support for up to eight cardinal / ordinal directions which can be a
830
+ # problem for large locations.
831
+ roomname = @name
832
+ if ((opts['draw_roomnames'] == false) && (@name =~ /(#{MSG_SVG_SHORTCUT_TO}).*/i))
833
+ roomname = $1
834
+ end
835
+
836
+ x, y = svg_draw_name( svg, opts, x, y, roomname )
837
+ end
838
+ end
839
+ end
840
+
841
+ end
842
+
843
+
844
+
845
+ class FXSection
846
+
847
+ def svg_draw_grid(pdf, opts, w, h )
848
+ if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw_grid" end
849
+ (0...w).each { |xx|
850
+ (0...h).each { |yy|
851
+ x = xx * opts['ww'] + opts['ws_2'] + opts['margin_2']
852
+ y = yy * opts['hh'] + opts['hs_2'] + opts['margin_2']
853
+ }
854
+ }
855
+ end
856
+
857
+
858
+ def svg_draw_section_name( svg, opts, x, y, available_width )
859
+ return [x,y] if not @name or @name == ''
860
+
861
+ font_size = opts['name_font_size']
862
+
863
+ if opts['print_section_names'] == true
864
+ svg, x, y = SVGUtilities::add_text( svg, x, y, font_size, @name, opts, '2F4F4F' )
865
+ y = y + opts['name_line_spacing']
866
+ end
867
+
868
+ if opts['draw_sectioncomments'] == true
869
+
870
+ if not @comments or @comments == ''
871
+ if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw_section_name:section comments is empty, not printing" end
872
+ else
873
+ num_chars_per_line = (available_width.to_i / font_size*0.75).floor
874
+
875
+ brokenlines = @comments.split(/\r?\n/);
876
+
877
+ brokenlines.each {|brokenline|
878
+
879
+ lines = SVGUtilities::break_text_lines(brokenline, num_chars_per_line);
880
+ lines.each {|line|
881
+ svg, x, y = SVGUtilities::add_text( svg, x, y, (font_size*0.75).to_i, line, opts, '000000' )
882
+ y = y + (opts['name_line_spacing'])
883
+ }
884
+
885
+ y = y + (opts['name_line_spacing'])
886
+ }
887
+
888
+ end
889
+
890
+ end
891
+
892
+ y = y + (opts['name_line_spacing'] * 8)
893
+
894
+ return [x,y]
895
+ end
896
+
897
+ def svg_width( opts )
898
+ minmaxxy = min_max_rooms
899
+ maxx = minmaxxy[1][0]
900
+
901
+ sect_width = (maxx+4) * opts['ww']
902
+ return sect_width
903
+ end
904
+
905
+ def svg_height( opts )
906
+ minmaxxy = min_max_rooms
907
+ maxy = minmaxxy[1][1]
908
+
909
+ sect_height = (maxy+2) * opts['hh']
910
+ return sect_height
911
+ end
912
+
913
+ def svg_draw(svg, opts, x, y, mapname, section_idx )
914
+ if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw" end
915
+ if DEBUG_OUTPUT; printf(" current section: x=%f, y=%f\r\n", x, y) end
916
+
917
+ sectionid = "section" + (section_idx + 1).to_s()
918
+
919
+ if svg.root.elements["defs"] == nil
920
+ svg.root.add_element "defs"
921
+ end
922
+
923
+ defs = svg.root.elements["defs"]
924
+ defs << REXML::Comment.new(" #{MSG_SVG_MAP_SECT_BEGINS} (#{sectionid}) ")
925
+
926
+ sectiongroup = REXML::Element.new "g"
927
+ sectiongroup.attributes["id"] = sectionid
928
+
929
+ sectionx = x;
930
+ sectiony = y;
931
+
932
+ x, y = svg_draw_section_name( sectiongroup, opts, 0, 0, svg.root.attributes["width"] )
933
+
934
+ origx = x
935
+ origy = y
936
+
937
+ @connections.each { |c|
938
+ a = c.roomA
939
+ b = c.roomB
940
+ next if a.y < 0 and b and b.y < 0
941
+ if opts['current_section_only'] && (opts['selected_elements_only'] || opts['text_for_selected_only'])
942
+ if c.selected
943
+ c.svg_draw( sectiongroup, opts, x, y )
944
+ end
945
+ else
946
+ c.svg_draw( sectiongroup, opts, x, y )
947
+ end
948
+ }
949
+
950
+ @rooms.each_with_index { |r, idx|
951
+ next if r.y < 0
952
+ if opts['current_section_only'] && opts['selected_elements_only']
953
+ if r.selected or idx == 0
954
+ r.svg_draw( sectiongroup, opts, idx, x, y)
955
+ end
956
+ else
957
+ r.svg_draw( sectiongroup, opts, idx, x, y)
958
+ end
959
+ }
960
+
961
+
962
+ # Add the compass displaying code in here so that it
963
+ # is displayed beneath the interactive display items when
964
+ # they are switched on.
965
+
966
+ compass_scale_factor = opts['compass_size'];
967
+
968
+ if(compass_scale_factor > 0)
969
+
970
+ compassx = (x + opts['margin'] + (opts['w'] / 2))/compass_scale_factor
971
+ compassy = ((y + svg_height(opts)) - opts['h'])/compass_scale_factor
972
+
973
+ sectiongroup.add_element "use", {
974
+ "x" => compassx,
975
+ "y" => compassy,
976
+ "xlink:href" => "#compass",
977
+ "transform" => "scale(" + compass_scale_factor.to_s() + ")"
978
+ }
979
+
980
+ y = y + (72 * compass_scale_factor)
981
+
982
+ end
983
+
984
+ #
985
+ # Iterate through the list of rooms a second time to
986
+ # add the interactive elements (list of objects/tasks).
987
+ # We do this as a second pass so that these objects a displayed
988
+ # on top of the basic room objects.
989
+ #
990
+
991
+ if SVGUtilities::should_draw_interactive(opts) == true
992
+ if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw::draw_interactive == true" end
993
+ @rooms.each_with_index { |r, idx|
994
+ if (!((opts['draw_connections'] == false) && (r.name =~ /#{MSG_SVG_SHORTCUT_TO}.*/i)))
995
+ if opts['current_section_only'] && opts['selected_elements_only']
996
+ if r.selected
997
+ r.svg_draw_interactive( sectiongroup, opts, idx, origx, origy, section_idx)
998
+ end
999
+ else
1000
+ r.svg_draw_interactive( sectiongroup, opts, idx, origx, origy, section_idx)
1001
+ end
1002
+ end
1003
+ }
1004
+ end
1005
+
1006
+ y = y + svg_height( opts )
1007
+
1008
+ svg.root.elements["defs"] << sectiongroup
1009
+
1010
+ defs << REXML::Comment.new(" #{MSG_SVG_MAP_SECT_ENDS} (#{sectionid}) ")
1011
+
1012
+ svg.root.add_element "use", {
1013
+ "x" => sectionx,
1014
+ "y" => sectiony,
1015
+ "xlink:href" => "#section" + (section_idx + 1).to_s()
1016
+ }
1017
+
1018
+ return [x,y]
1019
+
1020
+ end
1021
+
1022
+ def svg_draw_separate(opts, svgfile, section_idx, mapname, mapcreator, maxwidth)
1023
+
1024
+ # Called from both:
1025
+ # Draw current section only to individual file
1026
+ # Draw all sections into individual files
1027
+
1028
+ if DEBUG_OUTPUT; puts "svg::FXSection::svg_draw_separate" end
1029
+
1030
+ svg = SVGUtilities::new_svg_doc(maxwidth, svg_height(opts))
1031
+ if opts['compass_size'] > 0
1032
+ svg = SVGUtilities::add_compass(svg)
1033
+ end
1034
+
1035
+ if DEBUG_OUTPUT; printf("svg_draw_separate: section_idx = %s\r\n", section_idx.to_s()) end
1036
+
1037
+ if SVGUtilities::should_draw_interactive(opts) == true
1038
+ svg = SVGUtilities::svg_add_script(svg, opts)
1039
+ end
1040
+
1041
+ x = opts['name_x'] + opts['margin']
1042
+ y = opts['name_y'] + opts['margin']
1043
+ font_size = opts['name_font_size']
1044
+
1045
+ svg, x, y = SVGUtilities::add_titles(svg, opts, x, y, font_size, mapname, mapcreator)
1046
+
1047
+ outx, outy = svg_draw(svg, opts, x, y, svgfile, section_idx)
1048
+ y = y + outy;
1049
+ svg.root.attributes["height"] = y
1050
+
1051
+ svg = SVGUtilities::add_background(svg, svg_width(opts).to_s, y.to_s, File.basename(svgfile, ".*"))
1052
+
1053
+ formatter = REXML::Formatters::Pretty.new(2)
1054
+ formatter.compact = true
1055
+
1056
+ file = File.open(svgfile, "w")
1057
+ formatter.write(svg, file)
1058
+ file.close
1059
+
1060
+ if DEBUG_OUTPUT; printf("\r\n") end
1061
+
1062
+ end
1063
+ end
1064
+
1065
+
1066
+ class FXMap
1067
+
1068
+ def svg_draw_section_separate( opts, idx, svgfile )
1069
+
1070
+ # Called from both:
1071
+ # Draw current section only to individual file
1072
+ # Draw all sections into individual files
1073
+
1074
+ svgfilename = String::new(str=svgfile)
1075
+
1076
+ @section = idx
1077
+ create_pathmap
1078
+
1079
+ if DEBUG_OUTPUT; printf("svg_draw_sections_separate: filename = %s\r\n", svgfilename.to_s()) end
1080
+
1081
+ # Remove .svg from end of filename if it is there.
1082
+ if svgfilename =~ /\.svg$/
1083
+ svgfilename = svgfilename[0..-5];
1084
+ end
1085
+
1086
+ # Append the section number.
1087
+ svgfilename << "-section" << (idx + 1).to_s()
1088
+
1089
+ if DEBUG_OUTPUT; printf("svg_draw_separate: filename = %s\r\n", svgfilename.to_s()) end
1090
+
1091
+ # Add .svg back onto the end of the filename.
1092
+ svgfilename << ".svg"
1093
+
1094
+ if DEBUG_OUTPUT; printf("svg_draw_separate: filename = %s\r\n", svgfilename.to_s()) end
1095
+
1096
+ status "#{MSG_SVG_EXPORTING} '#{svgfilename}'"
1097
+
1098
+ @sections[idx].svg_draw_separate( opts, svgfilename, idx, @name, @creator, max_width(opts))
1099
+
1100
+ end
1101
+
1102
+ def svg_draw_current_section( opts, svgfile )
1103
+
1104
+ # Draw current section only to individual file
1105
+
1106
+ svg_draw_section_separate(opts, @section, svgfile)
1107
+ status MSG_SVG_EXPORT_COMPLETED
1108
+
1109
+ end
1110
+
1111
+ def svg_draw_sections_separate( opts, svgfile )
1112
+
1113
+ # Draw all sections into individual files
1114
+
1115
+ @sections.each_with_index { |sect, idx|
1116
+ svg_draw_section_separate(opts, idx, svgfile)
1117
+ }
1118
+
1119
+ status MSG_SVG_EXPORT_COMPLETED
1120
+ end
1121
+
1122
+ def svg_draw_sections( opts, svgfile )
1123
+
1124
+ # Draw all sections in one SVG file
1125
+
1126
+ if DEBUG_OUTPUT; puts "svg::FXMap::svg_draw_sections" end
1127
+ if DEBUG_OUTPUT; printf("svg::FXMap::svg_draw_sections:@section=%s\r\n", @section) end
1128
+
1129
+ x = opts['name_x'] + opts['margin']
1130
+ y = opts['name_y'] + opts['margin']
1131
+ font_size = opts['name_font_size']
1132
+
1133
+ svg = SVGUtilities::new_svg_doc(max_width(opts), total_height(opts))
1134
+ if opts['compass_size'] > 0
1135
+ svg = SVGUtilities::add_compass(svg)
1136
+ end
1137
+
1138
+ if SVGUtilities::should_draw_interactive(opts) == true
1139
+ svg = SVGUtilities::svg_add_script(svg, opts)
1140
+ end
1141
+
1142
+ svg, x, y = SVGUtilities::add_titles(svg, opts, x, y, font_size, @name, @creator)
1143
+
1144
+ @sections.each_with_index { |sect, idx|
1145
+
1146
+ @section = idx
1147
+ # For each page, we need to regenerate the pathmap so that complex
1148
+ # paths will come out ok.
1149
+ create_pathmap
1150
+ # Now, we draw it
1151
+
1152
+ outx, outy = sect.svg_draw(svg, opts, x, y, @name, idx)
1153
+
1154
+ if DEBUG_OUTPUT; puts "svg_draw_sections: section gap (hh*2) = #{opts['hh'] * 2}" end
1155
+ y = y + outy + (opts['hh'] * 2)
1156
+
1157
+ }
1158
+
1159
+ create_pathmap
1160
+ svg.root.attributes["height"] = y
1161
+
1162
+ svg = SVGUtilities::add_background(svg, max_width(opts).to_s, y.to_s, File.basename(svgfile, ".*"))
1163
+
1164
+ if svgfile !~ /\.svg$/
1165
+ svgfile << ".svg"
1166
+ end
1167
+
1168
+ status "#{MSG_SVG_EXPORTING} '#{svgfile}'"
1169
+
1170
+ formatter = REXML::Formatters::Pretty.new(2)
1171
+ formatter.compact = true
1172
+ formatter.width = 99999999
1173
+
1174
+ file = File.open(svgfile, "w")
1175
+ formatter.write(svg, file)
1176
+ file.close
1177
+
1178
+ status MSG_SVG_EXPORT_COMPLETED
1179
+
1180
+ end
1181
+
1182
+ def max_width(opts)
1183
+ max_width=0
1184
+ @sections.each_with_index{ |sect, idx|
1185
+ maxx = sect.svg_width(opts)
1186
+ if(maxx > max_width)
1187
+ max_width = maxx
1188
+ end
1189
+ if DEBUG_OUTPUT; puts("section=" + idx.to_s + ":maxx=" + maxx.to_s) end
1190
+ }
1191
+ return max_width
1192
+ end
1193
+
1194
+ def total_height(opts)
1195
+ total_height=0
1196
+ @sections.each_with_index{ |sect, idx|
1197
+ maxy = sect.svg_height(opts)
1198
+ total_height = total_height + maxy
1199
+ }
1200
+ return total_height
1201
+ end
1202
+
1203
+ def num_sections()
1204
+ return @sections.length
1205
+ end
1206
+
1207
+ def svg_export(svgfile, printer = nil)
1208
+
1209
+ if DEBUG_OUTPUT; puts "svg::FXMap::svg_export" end
1210
+
1211
+ map_options = @options.dup
1212
+
1213
+ ww = SVG_ROOM_WIDTH + SVG_ROOM_WS
1214
+ hh = SVG_ROOM_HEIGHT + SVG_ROOM_HS
1215
+
1216
+ svg_options = {
1217
+ 'ww' => ww,
1218
+ 'hh' => hh,
1219
+ 'w' => SVG_ROOM_WIDTH,
1220
+ 'h' => SVG_ROOM_HEIGHT,
1221
+ 'ws' => SVG_ROOM_WS,
1222
+ 'hs' => SVG_ROOM_HS,
1223
+ 'ws_2' => SVG_ROOM_WS / 2.0,
1224
+ 'hs_2' => SVG_ROOM_HS / 2.0,
1225
+ 'margin' => 10,
1226
+ 'margin_2' => 5,
1227
+ 'text_max_chars' => 20,
1228
+ 'text_line_spacing' => 2,
1229
+ 'text_margin' => 5,
1230
+ 'room_line_width' => 2,
1231
+ 'room_line_colour' => "black",
1232
+ 'room_font_size' => 8,
1233
+ 'objects_font_size' => 6,
1234
+ 'objects_width' => 140,
1235
+ 'room_num_font_size' => 6,
1236
+ 'print_room_nums' => true,
1237
+ 'num_line_width' => 1,
1238
+ 'num_line_colour' => "black",
1239
+ 'num_fill_colour' => "lightgreen",
1240
+ 'conn_line_width' => 2,
1241
+ 'conn_line_colour' => "black",
1242
+ 'door_line_width' => 2,
1243
+ 'door_line_colour' => "forestgreen",
1244
+ 'arrow_line_width' => 1,
1245
+ 'arrow_line_colour' => "black",
1246
+ 'arrow_fill_colour' => "black",
1247
+ 'name_font_size' => 18,
1248
+ 'name_x' => 0,
1249
+ 'name_y' => 0,
1250
+ 'name_line_spacing' => 4,
1251
+ 'print_title' => true,
1252
+ 'print_creator' => true,
1253
+ 'print_date' => true,
1254
+ 'creator_prefix' => MSG_SVG_CREATOR_PREFIX,
1255
+ 'draw_objects' => true,
1256
+ 'draw_tasks' => true,
1257
+ 'draw_comments' => true,
1258
+ 'draw_description' => true,
1259
+ 'draw_roomnames' => true,
1260
+ 'draw_connections' => true,
1261
+ 'corner_size' => 15,
1262
+ 'corner_line_colour' => "black",
1263
+ 'corner_line_width' => 1,
1264
+ 'corner_fill_colour' => "lightgreen",
1265
+ 'objs_line_colour' => "black",
1266
+ 'objs_line_width' => 1,
1267
+ 'objs_fill_colour' => "lightgreen",
1268
+ 'print_section_names' => true,
1269
+ 'section_name_prefix' => "Section: ",
1270
+ 'split_sections' => false,
1271
+ 'draw_sectioncomments' => true,
1272
+ 'compass_size' => 3,
1273
+ 'font_width_fiddle' => 1.5,
1274
+ 'selected_elements_only' => false,
1275
+ 'text_for_selected_only' => false,
1276
+ 'current_section_only' => false
1277
+ }
1278
+
1279
+ svg_options.merge!(map_options)
1280
+
1281
+ begin
1282
+
1283
+
1284
+ if svg_options['current_section_only'] == true
1285
+ # Draw current section only to individual file
1286
+ svg_draw_current_section(svg_options, svgfile)
1287
+ else
1288
+ if svg_options['split_sections'] == false
1289
+ # Draw all sections in one SVG file
1290
+ svg_draw_sections(svg_options, svgfile)
1291
+ else
1292
+ # Draw all sections into individual files
1293
+ svg_draw_sections_separate(svg_options, svgfile)
1294
+ end
1295
+ end
1296
+
1297
+ rescue => e
1298
+ p e
1299
+ p e.backtrace
1300
+ raise e
1301
+ end
1302
+ end
1303
+ end