ifmapper 2.0.9 → 2.2.0

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