gpx 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,58 +1,38 @@
1
- #--
2
- # Copyright (c) 2006 Doug Fales
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
23
1
  module GPX
24
2
  class Bounds < Base
25
- attr_accessor :min_lat, :max_lat, :max_lon, :min_lon, :center_lat, :center_lon
3
+ attr_accessor :min_lat, :max_lat, :max_lon, :min_lon
26
4
 
27
5
  # Creates a new bounds object with the passed-in min and max longitudes
28
6
  # and latitudes.
29
- def initialize(opts = { :min_lat => 90.0, :max_lat => -90.0, :min_lon => 180.0, :max_lon => -180.0})
30
- @min_lat, @max_lat = opts[:min_lat].to_f, opts[:max_lat].to_f
31
- @min_lon, @max_lon = opts[:min_lon].to_f, opts[:max_lon].to_f
7
+ def initialize(opts = { min_lat: 90.0, max_lat: -90.0, min_lon: 180.0, max_lon: -180.0 })
8
+ @min_lat = opts[:min_lat].to_f
9
+ @max_lat = opts[:max_lat].to_f
10
+ @min_lon = opts[:min_lon].to_f
11
+ @max_lon = opts[:max_lon].to_f
32
12
  end
33
13
 
34
14
  # Returns the middle latitude.
35
15
  def center_lat
36
- distance = (max_lat - min_lat)/2.0
16
+ distance = (max_lat - min_lat) / 2.0
37
17
  (min_lat + distance)
38
18
  end
39
19
 
40
20
  # Returns the middle longitude.
41
21
  def center_lon
42
- distance = (max_lon - min_lon)/2.0
22
+ distance = (max_lon - min_lon) / 2.0
43
23
  (min_lon + distance)
44
24
  end
45
25
 
46
26
  # Returns true if the pt is within these bounds.
47
27
  def contains?(pt)
48
- (pt.lat >= min_lat and pt.lat <= max_lat and pt.lon >= min_lon and pt.lon <= max_lon)
28
+ ((pt.lat >= min_lat) && (pt.lat <= max_lat) && (pt.lon >= min_lon) && (pt.lon <= max_lon))
49
29
  end
50
30
 
51
31
  # Adds an item to itself, expanding its min/max lat/lon as needed to
52
32
  # contain the given item. The item can be either another instance of
53
33
  # Bounds or a Point.
54
34
  def add(item)
55
- if(item.respond_to?(:lat) and item.respond_to?(:lon))
35
+ if item.respond_to?(:lat) && item.respond_to?(:lon)
56
36
  @min_lat = item.lat if item.lat < @min_lat
57
37
  @min_lon = item.lon if item.lon < @min_lon
58
38
  @max_lat = item.lat if item.lat > @max_lat
@@ -69,6 +49,5 @@ module GPX
69
49
  def to_s
70
50
  "min_lat: #{min_lat} min_lon: #{min_lon} max_lat: #{max_lat} max_lon: #{max_lon}"
71
51
  end
72
-
73
52
  end
74
53
  end
@@ -1,25 +1,3 @@
1
- #--
2
- # Copyright (c) 2006 Doug Fales
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
23
1
  module GPX
24
2
  # A common base class which provides a useful initializer method to many
25
3
  # class in the GPX library.
@@ -33,14 +11,12 @@ module GPX
33
11
  # attributes to this method.
34
12
  def instantiate_with_text_elements(parent, text_elements)
35
13
  text_elements.each do |el|
36
- child_xpath = "#{el}"
14
+ child_xpath = el.to_s
37
15
  unless parent.at(child_xpath).nil?
38
16
  val = parent.at(child_xpath).inner_text
39
- self.send("#{el}=", val)
17
+ send("#{el}=", val)
40
18
  end
41
19
  end
42
-
43
20
  end
44
-
45
21
  end
46
22
  end
@@ -1,28 +1,7 @@
1
- #--
2
- # Copyright (c) 2006 Doug Fales
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
23
1
  module GPX
24
2
  class GPXFile < Base
25
- attr_accessor :tracks, :routes, :waypoints, :bounds, :lowest_point, :highest_point, :duration, :ns, :time, :name, :version, :creator, :description, :moving_duration
3
+ attr_accessor :tracks,
4
+ :routes, :waypoints, :bounds, :lowest_point, :highest_point, :duration, :ns, :time, :name, :version, :creator, :description, :moving_duration
26
5
 
27
6
  DEFAULT_CREATOR = "GPX RubyGem #{GPX::VERSION} -- http://dougfales.github.io/gpx/".freeze
28
7
 
@@ -47,7 +26,10 @@ module GPX
47
26
  @duration = 0
48
27
  @attributes = {}
49
28
  @namespace_defs = []
50
- if(opts[:gpx_file] or opts[:gpx_data])
29
+ @tracks = []
30
+ @time = nil
31
+
32
+ if opts[:gpx_file] || opts[:gpx_data]
51
33
  if opts[:gpx_file]
52
34
  gpx_file = opts[:gpx_file]
53
35
  gpx_file = File.open(gpx_file) unless gpx_file.is_a?(File)
@@ -59,41 +41,53 @@ module GPX
59
41
  gpx_element = @xml.at('gpx')
60
42
  @attributes = gpx_element.attributes
61
43
  @namespace_defs = gpx_element.namespace_definitions
62
- #$stderr.puts gpx_element.attributes.sort.inspect
63
- #$stderr.puts @xmlns.inspect
64
- #$stderr.puts @xsi.inspect
65
44
  @version = gpx_element['version']
66
45
  reset_meta_data
67
- bounds_element = (@xml.at("metadata/bounds") rescue nil)
46
+ bounds_element = (begin
47
+ @xml.at('metadata/bounds')
48
+ rescue StandardError
49
+ nil
50
+ end)
68
51
  if bounds_element
69
- @bounds.min_lat = get_bounds_attr_value(bounds_element, %w{ min_lat minlat minLat })
70
- @bounds.min_lon = get_bounds_attr_value(bounds_element, %w{ min_lon minlon minLon})
71
- @bounds.max_lat = get_bounds_attr_value(bounds_element, %w{ max_lat maxlat maxLat})
72
- @bounds.max_lon = get_bounds_attr_value(bounds_element, %w{ max_lon maxlon maxLon})
52
+ @bounds.min_lat = get_bounds_attr_value(bounds_element, %w[min_lat minlat minLat])
53
+ @bounds.min_lon = get_bounds_attr_value(bounds_element, %w[min_lon minlon minLon])
54
+ @bounds.max_lat = get_bounds_attr_value(bounds_element, %w[max_lat maxlat maxLat])
55
+ @bounds.max_lon = get_bounds_attr_value(bounds_element, %w[max_lon maxlon maxLon])
73
56
  else
74
57
  get_bounds = true
75
58
  end
76
59
 
77
- @time = Time.parse(@xml.at("metadata/time").inner_text) rescue nil
78
- @name = @xml.at("metadata/name").inner_text rescue nil
79
- @description = @xml.at('metadata/desc').inner_text rescue nil
80
- @tracks = []
81
- @xml.search("trk").each do |trk|
82
- trk = Track.new(:element => trk, :gpx_file => self)
60
+ @time = begin
61
+ Time.parse(@xml.at('metadata/time').inner_text)
62
+ rescue StandardError
63
+ nil
64
+ end
65
+ @name = begin
66
+ @xml.at('metadata/name').inner_text
67
+ rescue StandardError
68
+ nil
69
+ end
70
+ @description = begin
71
+ @xml.at('metadata/desc').inner_text
72
+ rescue StandardError
73
+ nil
74
+ end
75
+ @xml.search('trk').each do |trk|
76
+ trk = Track.new(element: trk, gpx_file: self)
83
77
  update_meta_data(trk, get_bounds)
84
78
  @tracks << trk
85
79
  end
86
80
  @waypoints = []
87
- @xml.search("wpt").each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) }
81
+ @xml.search('wpt').each { |wpt| @waypoints << Waypoint.new(element: wpt, gpx_file: self) }
88
82
  @routes = []
89
- @xml.search("rte").each { |rte| @routes << Route.new(:element => rte, :gpx_file => self) }
90
- @tracks.delete_if { |t| t.empty? }
83
+ @xml.search('rte').each { |rte| @routes << Route.new(element: rte, gpx_file: self) }
84
+ @tracks.delete_if(&:empty?)
91
85
 
92
86
  calculate_duration
93
87
  else
94
88
  reset_meta_data
95
- opts.each { |attr_name, value| instance_variable_set("@#{attr_name.to_s}", value) }
96
- unless(@tracks.nil? or @tracks.size.zero?)
89
+ opts.each { |attr_name, value| instance_variable_set("@#{attr_name}", value) }
90
+ unless @tracks.nil? || @tracks.size.zero?
97
91
  @tracks.each { |trk| update_meta_data(trk) }
98
92
  calculate_duration
99
93
  end
@@ -109,19 +103,23 @@ module GPX
109
103
  result = el[name]
110
104
  break unless result.nil?
111
105
  end
112
- return (result.to_f rescue nil)
106
+ (begin
107
+ result.to_f
108
+ rescue StandardError
109
+ nil
110
+ end)
113
111
  end
114
112
 
115
113
  # Returns the distance, in kilometers, meters, or miles, of all of the
116
114
  # tracks and segments contained in this GPXFile.
117
- def distance(opts = { :units => 'kilometers' })
115
+ def distance(opts = { units: 'kilometers' })
118
116
  case opts[:units]
119
117
  when /kilometers/i
120
- return @distance
118
+ @distance
121
119
  when /meters/i
122
- return (@distance * 1000)
120
+ (@distance * 1000)
123
121
  when /miles/i
124
- return (@distance * 0.62)
122
+ (@distance * 0.62)
125
123
  end
126
124
  end
127
125
 
@@ -129,14 +127,14 @@ module GPX
129
127
  # GPXFile. The calculation is based on the total distance divided by the
130
128
  # sum of duration of all segments of all tracks
131
129
  # (not taking into accounting pause time).
132
- def average_speed(opts = { :units => 'kilometers' })
130
+ def average_speed(opts = { units: 'kilometers' })
133
131
  case opts[:units]
134
132
  when /kilometers/i
135
- return distance / (moving_duration/3600.0)
133
+ distance / (moving_duration / 3600.0)
136
134
  when /meters/i
137
- return (distance * 1000) / (moving_duration/3600.0)
135
+ (distance * 1000) / (moving_duration / 3600.0)
138
136
  when /miles/i
139
- return (distance * 0.62) / (moving_duration/3600.0)
137
+ (distance * 0.62) / (moving_duration / 3600.0)
140
138
  end
141
139
  end
142
140
 
@@ -176,7 +174,7 @@ module GPX
176
174
  keep_tracks << trk
177
175
  end
178
176
  end
179
- @tracks = keep_tracks
177
+ @tracks = keep_tracks
180
178
  routes.each { |rte| rte.delete_area(area) }
181
179
  waypoints.each { |wpt| wpt.delete_area(area) }
182
180
  end
@@ -196,8 +194,8 @@ module GPX
196
194
  # you modify the GPX data (i.e. by adding or deleting points) and you
197
195
  # want the meta data to accurately reflect the new data.
198
196
  def update_meta_data(trk, get_bounds = true)
199
- @lowest_point = trk.lowest_point if(@lowest_point.nil? or (!trk.lowest_point.nil? and trk.lowest_point.elevation < @lowest_point.elevation))
200
- @highest_point = trk.highest_point if(@highest_point.nil? or (!trk.highest_point.nil? and trk.highest_point.elevation > @highest_point.elevation))
197
+ @lowest_point = trk.lowest_point if @lowest_point.nil? || (!trk.lowest_point.nil? && (trk.lowest_point.elevation < @lowest_point.elevation))
198
+ @highest_point = trk.highest_point if @highest_point.nil? || (!trk.highest_point.nil? && (trk.highest_point.elevation > @highest_point.elevation))
201
199
  @bounds.add(trk.bounds) if get_bounds
202
200
  @distance += trk.distance
203
201
  @moving_duration += trk.moving_duration
@@ -206,14 +204,14 @@ module GPX
206
204
  # Serialize the current GPXFile to a gpx file named <filename>.
207
205
  # If the file does not exist, it is created. If it does exist, it is overwritten.
208
206
  def write(filename, update_time = true)
209
- @time = Time.now if(@time.nil? or update_time)
207
+ @time = Time.now if @time.nil? || update_time
210
208
  @name ||= File.basename(filename)
211
209
  doc = generate_xml_doc
212
210
  File.open(filename, 'w+') { |f| f.write(doc.to_xml) }
213
211
  end
214
212
 
215
213
  def to_s(update_time = true)
216
- @time = Time.now if(@time.nil? or update_time)
214
+ @time = Time.now if @time.nil? || update_time
217
215
  doc = generate_xml_doc
218
216
  doc.to_xml
219
217
  end
@@ -231,117 +229,123 @@ module GPX
231
229
  end
232
230
 
233
231
  private
232
+
234
233
  def attributes_and_nsdefs_as_gpx_attributes
235
- #$stderr.puts @namespace_defs.inspect
234
+ # $stderr.puts @namespace_defs.inspect
236
235
  gpx_header = {}
237
- @attributes.each do |k,v|
236
+ @attributes.each do |k, v|
238
237
  k = v.namespace.prefix + ':' + k if v.namespace
239
238
  gpx_header[k] = v.value
240
- end
239
+ end
241
240
 
242
241
  @namespace_defs.each do |nsd|
243
242
  tag = 'xmlns'
244
- if nsd.prefix
245
- tag += ':' + nsd.prefix
246
- end
243
+ tag += ':' + nsd.prefix if nsd.prefix
247
244
  gpx_header[tag] = nsd.href
248
245
  end
249
- return gpx_header
246
+ gpx_header
250
247
  end
251
-
248
+
252
249
  def generate_xml_doc
253
250
  @version ||= '1.1'
254
- version_dir = version.gsub('.','/')
251
+ version_dir = version.tr('.', '/')
255
252
 
256
253
  gpx_header = attributes_and_nsdefs_as_gpx_attributes
257
-
258
- gpx_header['version'] = @version.to_s if !gpx_header['version']
259
- gpx_header['creator'] = DEFAULT_CREATOR if !gpx_header['creator']
260
- gpx_header['xsi:schemaLocation'] = "http://www.topografix.com/GPX/#{version_dir} http://www.topografix.com/GPX/#{version_dir}/gpx.xsd" if !gpx_header['xsi:schemaLocation']
261
- gpx_header['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance" if !gpx_header['xsi'] and !gpx_header['xmlns:xsi']
262
-
263
- #$stderr.puts gpx_header.keys.inspect
264
254
 
255
+ gpx_header['version'] = @version.to_s unless gpx_header['version']
256
+ gpx_header['creator'] = DEFAULT_CREATOR unless gpx_header['creator']
257
+ gpx_header['xsi:schemaLocation'] = "http://www.topografix.com/GPX/#{version_dir} http://www.topografix.com/GPX/#{version_dir}/gpx.xsd" unless gpx_header['xsi:schemaLocation']
258
+ gpx_header['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance' if !gpx_header['xsi'] && !gpx_header['xmlns:xsi']
259
+
260
+ # $stderr.puts gpx_header.keys.inspect
261
+
262
+ # rubocop:disable Metrics/BlockLength
265
263
  doc = Nokogiri::XML::Builder.new do |xml|
266
- xml.gpx(gpx_header) \
267
- {
268
- # version 1.0 of the schema doesn't support the metadata element, so push them straight to the root 'gpx' element
269
- if (@version == '1.0') then
264
+ xml.gpx(gpx_header) do
265
+ # version 1.0 of the schema doesn't support the metadata element, so push them straight to the root 'gpx' element
266
+ if @version == '1.0'
267
+ xml.name @name
268
+ xml.time @time.xmlschema
269
+ xml.bound(
270
+ minlat: bounds.min_lat,
271
+ minlon: bounds.min_lon,
272
+ maxlat: bounds.max_lat,
273
+ maxlon: bounds.max_lon
274
+ )
275
+ else
276
+ xml.metadata do
270
277
  xml.name @name
271
278
  xml.time @time.xmlschema
272
279
  xml.bound(
273
280
  minlat: bounds.min_lat,
274
281
  minlon: bounds.min_lon,
275
282
  maxlat: bounds.max_lat,
276
- maxlon: bounds.max_lon,
283
+ maxlon: bounds.max_lon
277
284
  )
278
- else
279
- xml.metadata {
280
- xml.name @name
281
- xml.time @time.xmlschema
282
- xml.bound(
283
- minlat: bounds.min_lat,
284
- minlon: bounds.min_lon,
285
- maxlat: bounds.max_lat,
286
- maxlon: bounds.max_lon,
287
- )
288
- }
289
285
  end
286
+ end
290
287
 
288
+ unless tracks.nil?
291
289
  tracks.each do |t|
292
- xml.trk {
290
+ xml.trk do
293
291
  xml.name t.name
294
292
 
295
293
  t.segments.each do |seg|
296
- xml.trkseg {
294
+ xml.trkseg do
297
295
  seg.points.each do |p|
298
- xml.trkpt(lat: p.lat, lon: p.lon) {
296
+ xml.trkpt(lat: p.lat, lon: p.lon) do
299
297
  xml.time p.time.xmlschema unless p.time.nil?
300
298
  xml.ele p.elevation unless p.elevation.nil?
301
299
  xml << p.extensions.to_xml unless p.extensions.nil?
302
- }
300
+ end
303
301
  end
304
- }
302
+ end
305
303
  end
306
- }
307
- end unless tracks.nil?
304
+ end
305
+ end
306
+ end
308
307
 
308
+ unless waypoints.nil?
309
309
  waypoints.each do |w|
310
- xml.wpt(lat: w.lat, lon: w.lon) {
310
+ xml.wpt(lat: w.lat, lon: w.lon) do
311
311
  xml.time w.time.xmlschema unless w.time.nil?
312
312
  Waypoint::SUB_ELEMENTS.each do |sub_elem|
313
313
  xml.send(sub_elem, w.send(sub_elem)) if w.respond_to?(sub_elem) && !w.send(sub_elem).nil?
314
314
  end
315
- }
316
- end unless waypoints.nil?
315
+ end
316
+ end
317
+ end
317
318
 
319
+ unless routes.nil?
318
320
  routes.each do |r|
319
- xml.rte {
321
+ xml.rte do
320
322
  xml.name r.name
321
323
 
322
324
  r.points.each do |p|
323
- xml.rtept(lat: p.lat, lon: p.lon) {
325
+ xml.rtept(lat: p.lat, lon: p.lon) do
324
326
  xml.time p.time.xmlschema unless p.time.nil?
325
327
  xml.ele p.elevation unless p.elevation.nil?
326
- }
328
+ end
327
329
  end
328
- }
329
- end unless routes.nil?
330
- }
330
+ end
331
+ end
332
+ end
333
+ end
331
334
  end
335
+ # rubocop:enable Metrics/BlockLength
332
336
 
333
- return doc
337
+ doc
334
338
  end
335
339
 
336
340
  # Calculates and sets the duration attribute by subtracting the time on
337
341
  # the very first point from the time on the very last point.
338
342
  def calculate_duration
339
343
  @duration = 0
340
- if(@tracks.nil? or @tracks.size.zero? or @tracks[0].segments.nil? or @tracks[0].segments.size.zero?)
344
+ if @tracks.nil? || @tracks.size.zero? || @tracks[0].segments.nil? || @tracks[0].segments.size.zero?
341
345
  return @duration
342
346
  end
343
347
  @duration = (@tracks[-1].segments[-1].points[-1].time - @tracks.first.segments.first.points.first.time)
344
- rescue
348
+ rescue StandardError
345
349
  @duration = 0
346
350
  end
347
351
  end