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])


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
99
100
101
102
103
104
# File 'lib/gpx/gpx_file.rb', line 46

def initialize(opts = {})
  @duration = 0
  @attributes = {}
  @namespace_defs = []
  if(opts[:gpx_file] or 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
    #$stderr.puts gpx_element.attributes.sort.inspect
    #$stderr.puts @xmlns.inspect
    #$stderr.puts @xsi.inspect
    @version = gpx_element['version']
    
    bounds_element = (@xml.at("metadata/bounds") rescue nil)
    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 = Time.parse(@xml.at("metadata/time").inner_text) rescue nil
    @name = @xml.at("metadata/name").inner_text rescue nil
    @description = @xml.at('metadata/desc').inner_text rescue nil
    @tracks = []
    @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 { |t| t.empty? }

    calculate_duration
  else
    
    opts.each { |attr_name, value| instance_variable_set("@#{attr_name.to_s}", value) }
    unless(@tracks.nil? or @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.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def bounds
  @bounds
end

#creatorObject

Returns the value of attribute creator.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def creator
  @creator
end

#descriptionObject

Returns the value of attribute description.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def description
  @description
end

#durationObject

Returns the value of attribute duration.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def duration
  @duration
end

#highest_pointObject

Returns the value of attribute highest_point.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def highest_point
  @highest_point
end

#lowest_pointObject

Returns the value of attribute lowest_point.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def lowest_point
  @lowest_point
end

#moving_durationObject

Returns the value of attribute moving_duration.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def moving_duration
  @moving_duration
end

#nameObject

Returns the value of attribute name.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def name
  @name
end

#nsObject

Returns the value of attribute ns.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def ns
  @ns
end

#routesObject

Returns the value of attribute routes.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def routes
  @routes
end

#timeObject

Returns the value of attribute time.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def time
  @time
end

#tracksObject

Returns the value of attribute tracks.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def tracks
  @tracks
end

#versionObject

Returns the value of attribute version.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

def version
  @version
end

#waypointsObject

Returns the value of attribute waypoints.



25
26
27
# File 'lib/gpx/gpx_file.rb', line 25

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



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

def average_speed(opts = { :units => 'kilometers' })
  case opts[:units]
  when /kilometers/i
    return distance / (moving_duration/3600.0)
  when /meters/i
    return (distance * 1000) /  (moving_duration/3600.0)
  when /miles/i
    return (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.



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

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.



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

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.



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

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

#get_bounds_attr_value(el, possible_names) ⇒ Object



106
107
108
109
110
111
112
113
# File 'lib/gpx/gpx_file.rb', line 106

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

#inspectObject



221
222
223
# File 'lib/gpx/gpx_file.rb', line 221

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

#recalculate_distanceObject



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

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.



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

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

#to_s(update_time = true) ⇒ Object



215
216
217
218
219
# File 'lib/gpx/gpx_file.rb', line 215

def to_s(update_time = true)
  @time = Time.now if(@time.nil? or 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.



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

def (trk, get_bounds = true)
  @lowest_point   = trk.lowest_point if(@lowest_point.nil? or (!trk.lowest_point.nil? and trk.lowest_point.elevation < @lowest_point.elevation))
  @highest_point  = trk.highest_point if(@highest_point.nil? or (!trk.highest_point.nil? and 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.



208
209
210
211
212
213
# File 'lib/gpx/gpx_file.rb', line 208

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