gpx 0.9.0 → 1.0.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.
@@ -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