Class: GPX::GPXFile

Inherits:
Base
  • Object
show all
Defined in:
lib/gpx/gpx_file.rb

Constant Summary collapse

DEFAULT_CREATOR =
"GPX RubyGem #{GPX::VERSION} -- http://dougfales.github.io/gpx/".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#instantiate_with_text_elements

Constructor Details

#initialize(opts = {}) ⇒ GPXFile

This initializer can be used to create a new GPXFile from an existing file or to create a new GPXFile instance with no data (so that you can add tracks and points and write it out to a new file later). To read an existing GPX file, do this:

gpx_file = GPXFile.new(:gpx_file => 'mygpxfile.gpx')
puts "Speed: #{gpx_file.average_speed}"
puts "Duration: #{gpx_file.duration}"
puts "Bounds: #{gpx_file.bounds}"

To read a GPX file from a string, use :gpx_data.

gpx_file = GPXFile.new(:gpx_data => '<xml ...><gpx>...</gpx>)

To create a new blank GPXFile instance:

gpx_file = GPXFile.new

Note that you can pass in any instance variables to this form of the initializer, including Tracks or Segments:

some_track = get_track_from_csv('some_other_format.csv')
gpx_file = GPXFile.new(:tracks => [some_track])


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/gpx/gpx_file.rb', line 25

def initialize(opts = {})
  @duration = 0
  @attributes = {}
  @namespace_defs = []
  @tracks = []
  @time = nil

  if opts[:gpx_file] || opts[:gpx_data]
    if opts[:gpx_file]
      gpx_file = opts[:gpx_file]
      gpx_file = File.open(gpx_file) unless gpx_file.is_a?(File)
      @xml = Nokogiri::XML(gpx_file)
    else
      @xml = Nokogiri::XML(opts[:gpx_data])
    end

    gpx_element = @xml.at('gpx')
    @attributes = gpx_element.attributes
    @namespace_defs = gpx_element.namespace_definitions
    @version = gpx_element['version']
    
    bounds_element = (begin
      @xml.at('metadata/bounds')
    rescue StandardError
      nil
    end)
    if bounds_element
      @bounds.min_lat = get_bounds_attr_value(bounds_element, %w[min_lat minlat minLat])
      @bounds.min_lon = get_bounds_attr_value(bounds_element, %w[min_lon minlon minLon])
      @bounds.max_lat = get_bounds_attr_value(bounds_element, %w[max_lat maxlat maxLat])
      @bounds.max_lon = get_bounds_attr_value(bounds_element, %w[max_lon maxlon maxLon])
    else
      get_bounds = true
    end

    @time = begin
              Time.parse(@xml.at('metadata/time').inner_text)
            rescue StandardError
              nil
            end
    @name = begin
              @xml.at('metadata/name').inner_text
            rescue StandardError
              nil
            end
    @description = begin
                     @xml.at('metadata/desc').inner_text
                   rescue StandardError
                     nil
                   end
    @xml.search('trk').each do |trk|
      trk = Track.new(element: trk, gpx_file: self)
      (trk, get_bounds)
      @tracks << trk
    end
    @waypoints = []
    @xml.search('wpt').each { |wpt| @waypoints << Waypoint.new(element: wpt, gpx_file: self) }
    @routes = []
    @xml.search('rte').each { |rte| @routes << Route.new(element: rte, gpx_file: self) }
    @tracks.delete_if(&:empty?)

    calculate_duration
  else
    
    opts.each { |attr_name, value| instance_variable_set("@#{attr_name}", value) }
    unless @tracks.nil? || @tracks.size.zero?
      @tracks.each { |trk| (trk) }
      calculate_duration
    end
  end
  @tracks ||= []
  @routes ||= []
  @waypoints ||= []
end

Instance Attribute Details

#boundsObject

Returns the value of attribute bounds.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def bounds
  @bounds
end

#creatorObject

Returns the value of attribute creator.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def creator
  @creator
end

#descriptionObject

Returns the value of attribute description.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def description
  @description
end

#durationObject

Returns the value of attribute duration.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def duration
  @duration
end

#highest_pointObject

Returns the value of attribute highest_point.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def highest_point
  @highest_point
end

#lowest_pointObject

Returns the value of attribute lowest_point.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def lowest_point
  @lowest_point
end

#moving_durationObject

Returns the value of attribute moving_duration.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def moving_duration
  @moving_duration
end

#nameObject

Returns the value of attribute name.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def name
  @name
end

#nsObject

Returns the value of attribute ns.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def ns
  @ns
end

#routesObject

Returns the value of attribute routes.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def routes
  @routes
end

#timeObject

Returns the value of attribute time.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def time
  @time
end

#tracksObject

Returns the value of attribute tracks.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def tracks
  @tracks
end

#versionObject

Returns the value of attribute version.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def version
  @version
end

#waypointsObject

Returns the value of attribute waypoints.



3
4
5
# File 'lib/gpx/gpx_file.rb', line 3

def waypoints
  @waypoints
end

Instance Method Details

#average_speed(opts = { units: 'kilometers' }) ⇒ Object

Returns the average speed, in km/hr, meters/hr, or miles/hr, of this GPXFile. The calculation is based on the total distance divided by the sum of duration of all segments of all tracks (not taking into accounting pause time).



130
131
132
133
134
135
136
137
138
139
# File 'lib/gpx/gpx_file.rb', line 130

def average_speed(opts = { units: 'kilometers' })
  case opts[:units]
  when /kilometers/i
    distance / (moving_duration / 3600.0)
  when /meters/i
    (distance * 1000) / (moving_duration / 3600.0)
  when /miles/i
    (distance * 0.62) / (moving_duration / 3600.0)
  end
end

#crop(area) ⇒ Object

Crops any points falling within a rectangular area. Identical to the delete_area method in every respect except that the points outside of the given area are deleted. Note that this method automatically causes the meta data to be updated after deletion.



145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/gpx/gpx_file.rb', line 145

def crop(area)
  
  keep_tracks = []
  tracks.each do |trk|
    trk.crop(area)
    unless trk.empty?
      (trk)
      keep_tracks << trk
    end
  end
  @tracks = keep_tracks
  routes.each { |rte| rte.crop(area) }
  waypoints.each { |wpt| wpt.crop(area) }
end

#delete_area(area) ⇒ Object

Deletes any points falling within a rectangular area. The “area” parameter is usually an instance of the Bounds class. Note that this method cascades into similarly named methods of subordinate classes (i.e. Track, Segment), which means, if you want the deletion to apply to all the data, you only call this one (and not the one in Track or Segment classes). Note that this method automatically causes the meta data to be updated after deletion.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/gpx/gpx_file.rb', line 167

def delete_area(area)
  
  keep_tracks = []
  tracks.each do |trk|
    trk.delete_area(area)
    unless trk.empty?
      (trk)
      keep_tracks << trk
    end
  end
  @tracks = keep_tracks
  routes.each { |rte| rte.delete_area(area) }
  waypoints.each { |wpt| wpt.delete_area(area) }
end

#distance(opts = { units: 'kilometers' }) ⇒ Object

Returns the distance, in kilometers, meters, or miles, of all of the tracks and segments contained in this GPXFile.



115
116
117
118
119
120
121
122
123
124
# File 'lib/gpx/gpx_file.rb', line 115

def distance(opts = { units: 'kilometers' })
  case opts[:units]
  when /kilometers/i
    @distance
  when /meters/i
    (@distance * 1000)
  when /miles/i
    (@distance * 0.62)
  end
end

#get_bounds_attr_value(el, possible_names) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/gpx/gpx_file.rb', line 100

def get_bounds_attr_value(el, possible_names)
  result = nil
  possible_names.each do |name|
    result = el[name]
    break unless result.nil?
  end
  (begin
    result.to_f
  rescue StandardError
    nil
  end)
end

#inspectObject



219
220
221
# File 'lib/gpx/gpx_file.rb', line 219

def inspect
  "<#{self.class.name}:...>"
end

#recalculate_distanceObject



223
224
225
226
227
228
229
# File 'lib/gpx/gpx_file.rb', line 223

def recalculate_distance
  @distance = 0
  @tracks.each do |track|
    track.recalculate_distance
    @distance += track.distance
  end
end

#reset_meta_dataObject

Resets the meta data for this GPX file. Meta data includes the bounds, the high and low points, and the distance.



184
185
186
187
188
189
190
# File 'lib/gpx/gpx_file.rb', line 184

def 
  @bounds = Bounds.new
  @highest_point = nil
  @lowest_point = nil
  @distance = 0.0
  @moving_duration = 0.0
end

#to_s(update_time = true) ⇒ Object



213
214
215
216
217
# File 'lib/gpx/gpx_file.rb', line 213

def to_s(update_time = true)
  @time = Time.now if @time.nil? || update_time
  doc = generate_xml_doc
  doc.to_xml
end

#update_meta_data(trk, get_bounds = true) ⇒ Object

Updates the meta data for this GPX file. Meta data includes the bounds, the high and low points, and the distance. This is useful when you modify the GPX data (i.e. by adding or deleting points) and you want the meta data to accurately reflect the new data.



196
197
198
199
200
201
202
# File 'lib/gpx/gpx_file.rb', line 196

def (trk, get_bounds = true)
  @lowest_point = trk.lowest_point if @lowest_point.nil? || (!trk.lowest_point.nil? && (trk.lowest_point.elevation < @lowest_point.elevation))
  @highest_point = trk.highest_point if @highest_point.nil? || (!trk.highest_point.nil? && (trk.highest_point.elevation > @highest_point.elevation))
  @bounds.add(trk.bounds) if get_bounds
  @distance += trk.distance
  @moving_duration += trk.moving_duration
end

#write(filename, update_time = true) ⇒ Object

Serialize the current GPXFile to a gpx file named <filename>. If the file does not exist, it is created. If it does exist, it is overwritten.



206
207
208
209
210
211
# File 'lib/gpx/gpx_file.rb', line 206

def write(filename, update_time = true)
  @time = Time.now if @time.nil? || update_time
  @name ||= File.basename(filename)
  doc = generate_xml_doc
  File.open(filename, 'w+') { |f| f.write(doc.to_xml) }
end