Compare commits

..

No commits in common. "master" and "release-0.1" have entirely different histories.

33 changed files with 930 additions and 1328 deletions

3
.gitignore vendored
View File

@ -1,3 +0,0 @@
tests/output/*
.*.swp
Gemfile.lock

View File

@ -1,60 +0,0 @@
2010-02-27 Doug Fales <doug@falesafeconsulting.com>
* Putting the gem building stuff into a gemspec.
* Fixing some tests since git does not believe in empty directories.
* Fixing README formatting.
2010-02-27 Doug Fales <doug@falesafeconsulting.com>
* README edits.
* More rdoc tweaks.
* Changing README to rdoc ext for github.
2009-10-13 Doug Fales <doug@falesafeconsulting.com>
* Adding the ability to write GPX to a string in addition to a file. Thanks to Douglas Robertson for the patch.
2009-09-27 Doug Fales <doug@falesafeconsulting.com>
* Adding a patch from Douglas Robertson that allows using version 1.0 of the schema for output.
2009-07-07 Doug Fales <doug@falesafeconsulting.com>
* Adding changelog.
* Revving to version 0.5.
* Changing my contact email address.
* Patches from Tom Verbeure (mtbguru.com) to work with libxml-ruby 1.x.
2009-06-17 Doug Fales <doug@falesafeconsulting.com>
* Patch from Kang-min Liu to support speed element.
2008-02-19 Doug Fales <doug@falesafeconsulting.com>
* Revving to 0.4.
* Adding some new unit tests and fixing several file export bugs reported by Jochen Topf. New unit tests also uncovered a bug where the number of trackpoints reported in a file was twice the actual number.
2008-02-11 Doug Fales <doug@falesafeconsulting.com>
* Going to version 0.3.
* Updating unit tests in light of recent fixes to routes and waypoints code.
2008-02-08 Doug Fales <doug@falesafeconsulting.com>
* Thanks to Mike Gauland for discovering some route- and waypoint-related bugs. I've fixed them and also added #to_s on Waypoint so it's easier to debug.
2007-12-04 Doug Fales <doug@falesafeconsulting.com>
* Thanks to Christian Koerner for finding and fixing these bugs in the waypoint code.
* Another patch from Gaku Ueda. This one allows you to pass in a string of GPX data using the :gpx_date => option. Thanks Gaku!
2007-11-30 Doug Fales <doug@falesafeconsulting.com>
* Updating the version #.
* Updates courtesy of Gaku Ueda: * Adding support for GPX 1.0 as well as 1.1 (since libxml namespace parsing was hard-coded to 1.1. previously). * Adding a GPX 1.0 unit test file. * Miscellaneous updates to make it work with Ruby 1.8.6.
2006-12-04 Doug Fales <doug@falesafeconsulting.com>
* First stab at using libxml-ruby instead of REXML. I'm seeing the unit tests finish in under 14 seconds. That is compared to 2 minutes using REXML.
2006-12-03 Doug Fales <doug@falesafeconsulting.com>
* Fixing more nil time exceptions.
* Fixing an exception in contains_time?.
2006-11-28 Doug Fales <doug@falesafeconsulting.com>
* A couple of fixes to make the library comply with the different attribute names possible on the bounds element.
2006-10-28 Doug Fales <doug@falesafeconsulting.com>
* Fixing nil time bug.
2006-10-14 Doug Fales <doug@falesafeconsulting.com>
* Initial import of gpx gem.

View File

@ -1,4 +0,0 @@
source 'https://rubygems.org'
# Specify your gem's dependencies in seryz.gemspec
gemspec

View File

@ -1,9 +1,8 @@
= GPX Gem = GPX Gem
Copyright (C) 2006 Doug Fales
Copyright (C) 2006 Doug Fales mailto:doug@falesafeconsulting.com Doug Fales mailto:doug.fales@gmail.com
== What It Does == What It Does
This library reads GPX files and provides an API for reading and manipulating This library reads GPX files and provides an API for reading and manipulating
the data as objects. For more info on the GPX format, see the data as objects. For more info on the GPX format, see
http://www.topografix.com/gpx.asp. http://www.topografix.com/gpx.asp.
@ -15,7 +14,6 @@ the tracks and points in a file (such as distance, duration, average speed,
etc). etc).
== Examples == Examples
Reading a GPX file, and cropping its contents to a given area: Reading a GPX file, and cropping its contents to a given area:
gpx = GPX::GPXFile.new(:gpx_file => filename) # Read GPX file gpx = GPX::GPXFile.new(:gpx_file => filename) # Read GPX file
bounds = GPX::Bounds.new(params) # Create a rectangular area to crop bounds = GPX::Bounds.new(params) # Create a rectangular area to crop
@ -29,14 +27,13 @@ Converting a Magellan track log to GPX:
== Notes == Notes
This library was written to bridge the gap between my Garmin Geko This library was written to bridge the gap between my Garmin Geko
and my website, WalkingBoss.org (RIP). For that reason, it has always been more of a and my website, WalkingBoss.org. For that reason, it has always been more of a
work-in-progress than an attempt at full GPX compliance. The track side of the work-in-progress than an attempt at full GPX compliance. The track side of the
library has seen much more use than the route/waypoint side, so if you're doing library has seen much more use than the route/waypoint side, so if you're doing
something with routes or waypoints, you may need to tweak some things. something with routes or waypoints, you may need to tweak some things.
Since this code uses XML to read an entire GPX file into memory, it is not Since this code uses REXML to read an entire GPX file into memory, it is not
the fastest possible solution for working with GPX data, especially if you are the fastest possible solution for working with GPX data, especially if you are
working with tracks from several days or weeks. working with tracks from several days or weeks.

View File

@ -1,6 +1,20 @@
require 'bundler/gem_tasks' require 'rubygems'
require 'rake'
require 'rake/testtask' require 'rake/testtask'
require 'rdoc/task' require 'rake/rdoctask'
require 'rake/gempackagetask'
require File.dirname(__FILE__) + '/lib/gpx'
PKG_VERSION = GPX::VERSION
PKG_NAME = "gpx"
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
RUBY_FORGE_PROJECT = "gpx"
RUBY_FORGE_USER = ENV['RUBY_FORGE_USER'] || "dougfales"
RELEASE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
PKG_FILES = FileList[
"lib/**/*", "bin/*", "tests/**/*", "[A-Z]*", "Rakefile", "doc/**/*"
]
desc "Default Task" desc "Default Task"
task :default => [ :test ] task :default => [ :test ]
@ -13,6 +27,12 @@ Rake::TestTask.new("test") { |t|
t.verbose = true t.verbose = true
} }
# Make a console, useful when working on tests
desc "Generate a test console"
task :console do
verbose( false ) { sh "irb -I lib/ -r 'gpx'" }
end
# Genereate the RDoc documentation # Genereate the RDoc documentation
desc "Create documentation" desc "Create documentation"
Rake::RDocTask.new("doc") { |rdoc| Rake::RDocTask.new("doc") { |rdoc|
@ -21,3 +41,51 @@ Rake::RDocTask.new("doc") { |rdoc|
rdoc.rdoc_files.include('README') rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb') rdoc.rdoc_files.include('lib/**/*.rb')
} }
# Genereate the package
spec = Gem::Specification.new do |s|
#### Basic information.
s.name = 'gpx'
s.version = PKG_VERSION
s.summary = <<-EOF
A basic API for reading and writing GPX files.
EOF
s.description = <<-EOF
A basic API for reading and writing GPX files.
EOF
#### Which files are to be included in this gem? Everything! (Except CVS directories.)
s.files = PKG_FILES
#### Load-time details: library and application (you will need one or both).
s.require_path = 'lib'
s.autorequire = 'gpx'
#### Documentation and testing.
s.has_rdoc = true
#### Author and project details.
s.author = "Doug Fales"
s.email = "doug.fales@gmail.com"
#s.homepage = "http://gpx.rubyforge.com/"
end
Rake::GemPackageTask.new(spec) do |pkg|
pkg.need_zip = true
pkg.need_tar = true
end
desc "Report code statistics (KLOCs, etc) from the application"
task :stats do
require 'code_statistics'
CodeStatistics.new(
["Library", "lib"],
["Units", "tests"]
).to_s
end

View File

@ -1,22 +0,0 @@
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'gpx/version'
Gem::Specification.new do |s|
s.name = 'gpx'
s.version = GPX::VERSION
s.authors = ["Guillaume Dott", "Doug Fales"]
s.email = ["guillaume+github@dott.fr", "doug.fales@gmail.com"]
s.summary = %q{A basic API for reading and writing GPX files.}
s.description = %q{A basic API for reading and writing GPX files.}
s.files = `git ls-files`.split($/)
s.test_files = s.files.grep(%r{^(test|spec|features)/})
s.require_paths = ["lib"]
s.has_rdoc = true
s.homepage = "http://dougfales.github.com/gpx/"
s.rubyforge_project = "gpx"
s.add_dependency 'nokogiri'
end

View File

@ -20,12 +20,11 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
$:.unshift(File.dirname(__FILE__))
require 'rexml/document'
require 'date'
require 'time' require 'time'
require 'nokogiri' require 'csv'
require 'gpx/version'
require 'gpx/gpx' require 'gpx/gpx'
require 'gpx/gpx_file' require 'gpx/gpx_file'
require 'gpx/bounds' require 'gpx/bounds'

View File

@ -43,6 +43,15 @@ module GPX
(min_lon + distance) (min_lon + distance)
end end
def to_xml
bnd = REXML::Element.new('bounds')
bnd.attributes['min_lat'] = min_lat
bnd.attributes['min_lon'] = min_lon
bnd.attributes['max_lat'] = max_lat
bnd.attributes['max_lon'] = max_lon
bnd
end
# Returns true if the pt is within these bounds. # Returns true if the pt is within these bounds.
def contains?(pt) def contains?(pt)
(pt.lat >= min_lat and pt.lat <= max_lat and pt.lon >= min_lon and pt.lon <= max_lon) (pt.lat >= min_lat and pt.lat <= max_lat and pt.lon >= min_lon and pt.lon <= max_lon)

View File

@ -21,10 +21,14 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
module GPX module GPX
VERSION = "0.1"
# A common base class which provides a useful initializer method to many # A common base class which provides a useful initializer method to many
# class in the GPX library. # class in the GPX library.
class Base class Base
# This initializer can take an XML::Node and scrape out any text include REXML
# This initializer can take a REXML::Element and scrape out any text
# elements with the names given in the "text_elements" array. Each # elements with the names given in the "text_elements" array. Each
# element found underneath "parent" with a name in "text_elements" causes # element found underneath "parent" with a name in "text_elements" causes
# an attribute to be initialized on the instance. This means you don't # an attribute to be initialized on the instance. This means you don't
@ -33,10 +37,13 @@ module GPX
# attributes to this method. # attributes to this method.
def instantiate_with_text_elements(parent, text_elements) def instantiate_with_text_elements(parent, text_elements)
text_elements.each do |el| text_elements.each do |el|
child_xpath = "#{el}" unless parent.elements[el].nil?
unless parent.at(child_xpath).nil? val = parent.elements[el].text
val = parent.at(child_xpath).inner_text code = <<-code
self.send("#{el}=", val) attr_accessor #{ el }
#{el}=#{val}
code
class_eval code
end end
end end

View File

@ -22,7 +22,8 @@
#++ #++
module GPX module GPX
class GPXFile < Base class GPXFile < Base
attr_accessor :tracks, :routes, :waypoints, :bounds, :lowest_point, :highest_point, :duration, :ns, :time, :name attr_reader :tracks, :routes, :waypoints, :bounds, :lowest_point, :highest_point, :distance, :duration, :average_speed
# This initializer can be used to create a new GPXFile from an existing # 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 # file or to create a new GPXFile instance with no data (so that you can
@ -33,8 +34,6 @@ module GPX
# puts "Duration: #{gpx_file.duration}" # puts "Duration: #{gpx_file.duration}"
# puts "Bounds: #{gpx_file.bounds}" # 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: # To create a new blank GPXFile instance:
# gpx_file = GPXFile.new # gpx_file = GPXFile.new
# Note that you can pass in any instance variables to this form of the initializer, including Tracks or Segments: # Note that you can pass in any instance variables to this form of the initializer, including Tracks or Segments:
@ -43,38 +42,33 @@ module GPX
# #
def initialize(opts = {}) def initialize(opts = {})
@duration = 0 @duration = 0
if(opts[:gpx_file] or opts[:gpx_data]) if(opts[:gpx_file])
if opts[:gpx_file]
gpx_file = opts[:gpx_file] gpx_file = opts[:gpx_file]
gpx_file = File.open(gpx_file) unless gpx_file.is_a?(File) case gpx_file
@xml = Nokogiri::XML(gpx_file) when String
else gpx_file = File.open(gpx_file)
@xml = Nokogiri::XML(opts[:gpx_data])
end end
reset_meta_data reset_meta_data
bounds_element = (@xml.at("metadata/bounds") rescue nil) @xml = Document.new(gpx_file, :ignore_whitespace_nodes => :all)
bounds_element = (XPath.match(@xml, "/gpx/metadata/bounds").first rescue nil)
if bounds_element if bounds_element
@bounds.min_lat = get_bounds_attr_value(bounds_element, %w{ min_lat minlat minLat }) @bounds.min_lat = bounds_element.attributes["min_lat"].to_f
@bounds.min_lon = get_bounds_attr_value(bounds_element, %w{ min_lon minlon minLon}) @bounds.min_lon = bounds_element.attributes["min_lon"].to_f
@bounds.max_lat = get_bounds_attr_value(bounds_element, %w{ max_lat maxlat maxLat}) @bounds.max_lat = bounds_element.attributes["max_lat"].to_f
@bounds.max_lon = get_bounds_attr_value(bounds_element, %w{ max_lon maxlon maxLon}) @bounds.max_lon = bounds_element.attributes["max_lon"].to_f
else else
get_bounds = true get_bounds = true
end end
@time = Time.parse(@xml.at("metadata/time").inner_text) rescue nil @tracks = XPath.match(@xml, "/gpx/trk").collect do |trk|
@name = @xml.at("metadata/name").inner_text rescue nil
@tracks = []
@xml.search("trk").each do |trk|
trk = Track.new(:element => trk, :gpx_file => self) trk = Track.new(:element => trk, :gpx_file => self)
update_meta_data(trk, get_bounds) update_meta_data(trk, get_bounds)
@tracks << trk trk
end end
@waypoints = [] @waypoints = XPath.match(@xml, "/gpx/wpt").collect { |wpt| Waypoint.new(:element => wpt, :gpx_file => self) }
@xml.search("wpt").each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) } @routes = XPath.match(@xml, "/gpx/rte").collect { |rte| Route.new(:element => rte, :gpx_file => self) }
@routes = []
@xml.search("rte").each { |rte| @routes << Route.new(:element => rte, :gpx_file => self) }
@tracks.delete_if { |t| t.empty? } @tracks.delete_if { |t| t.empty? }
calculate_duration calculate_duration
@ -86,18 +80,6 @@ module GPX
calculate_duration calculate_duration
end end
end end
@tracks ||= []
@routes ||= []
@waypoints ||= []
end
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 end
# Returns the distance, in kilometers, meters, or miles, of all of the # Returns the distance, in kilometers, meters, or miles, of all of the
@ -182,96 +164,46 @@ module GPX
# you modify the GPX data (i.e. by adding or deleting points) and you # you modify the GPX data (i.e. by adding or deleting points) and you
# want the meta data to accurately reflect the new data. # want the meta data to accurately reflect the new data.
def update_meta_data(trk, get_bounds = true) def update_meta_data(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)) @lowest_point = trk.lowest_point if(@lowest_point.nil? or 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)) @highest_point = trk.highest_point if(@highest_point.nil? or trk.highest_point.elevation > @highest_point.elevation)
@bounds.add(trk.bounds) if get_bounds @bounds.add(trk.bounds) if get_bounds
@distance += trk.distance @distance += trk.distance
end end
# Serialize the current GPXFile to a gpx file named <filename>. # 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. # If the file does not exist, it is created. If it does exist, it is overwritten.
def write(filename, update_time = true) def write(filename)
@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
def to_s(update_time = true) doc = Document.new
@time = Time.now if(@time.nil? or update_time) gpx_elem = Element.new('gpx')
doc = generate_xml_doc doc.add(gpx_elem)
doc.to_xml gpx_elem.attributes['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance"
end gpx_elem.attributes['xmlns'] = "http://www.topografix.com/GPX/1/1"
gpx_elem.attributes['version'] = "1.1"
gpx_elem.attributes['creator'] = "GPX RubyGem 0.1 Copyright 2006 Doug Fales -- http://walkingboss.com"
gpx_elem.attributes['xsi:schemaLocation'] = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
def inspect meta_data_elem = Element.new('metadata')
"<#{self.class.name}:...>" name_elem = Element.new('name')
name_elem.text = File.basename(filename)
meta_data_elem.elements << name_elem
time_elem = Element.new('time')
time_elem.text = Time.now.xmlschema
meta_data_elem.elements << time_elem
meta_data_elem.elements << bounds.to_xml
gpx_elem.elements << meta_data_elem
tracks.each { |t| gpx_elem.add_element t.to_xml } unless tracks.nil?
waypoints.each { |w| gpx_elem.add_element w.to_xml } unless waypoints.nil?
routes.each { |r| gpx_elem.add_element r.to_xml } unless routes.nil?
File.open(filename, 'w') { |f| doc.write(f) }
end end
private private
def generate_xml_doc
version = '1.1'
version_dir = version.gsub('.','/')
doc = Nokogiri::XML::Builder.new do |xml|
xml.gpx(
'xsi' => "http://www.w3.org/2001/XMLSchema-instance",
'version' => version.to_s,
'creator' => "GPX RubyGem #{GPX::VERSION}",
'xsi:schemaLocation' => "http://www.topografix.com/GPX/#{version_dir} http://www.topografix.com/GPX/#{version_dir}/gpx.xsd") \
{
xml.metadata {
xml.name @name
xml.time @time.xmlschema
xml.bound(
minlat: bounds.min_lat,
minlon: bounds.min_lon,
maxlat: bounds.max_lat,
maxlon: bounds.max_lon,
)
}
tracks.each do |t|
xml.trk {
xml.name t.name
t.segments.each do |seg|
xml.trkseg {
seg.points.each do |p|
xml.trkpt(lat: p.lat, lon: p.lon) {
xml.time p.time.xmlschema unless p.time.nil?
xml.ele p.elevation unless p.elevation.nil?
}
end
}
end
}
end unless tracks.nil?
waypoints.each do |w|
xml.wpt(lat: w.lat, lon: w.lon) {
Waypoint::SUB_ELEMENTS.each do |sub_elem|
xml.send(sub_elem, w.send(sub_elem)) if w.respond_to?(sub_elem) && !w.send(sub_elem).nil?
end
}
end unless waypoints.nil?
routes.each do |r|
xml.rte {
xml.name r.name
r.points.each do |p|
xml.rtept(lat: p.lat, lon: p.lon) {
xml.time p.time.xmlschema unless p.time.nil?
xml.ele p.elevation unless p.elevation.nil?
}
end
}
end unless routes.nil?
}
end
return doc
end
# Calculates and sets the duration attribute by subtracting the time on # Calculates and sets the duration attribute by subtracting the time on
# the very first point from the time on the very last point. # the very first point from the time on the very last point.
@ -284,5 +216,7 @@ module GPX
rescue rescue
@duration = 0 @duration = 0
end end
end end
end end

View File

@ -21,8 +21,10 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
module GPX module GPX
# This class will parse the lat/lon and time data from a Magellan track log, # This class will parse the lat/lon and time data from a Magellan track log,
# which is a NMEA formatted CSV list of points. # which is a NMEA formatted CSV list of points.
class MagellanTrackLog class MagellanTrackLog
#PMGNTRK #PMGNTRK
# This message is to be used to transmit Track information (basically a list of previous position fixes) # This message is to be used to transmit Track information (basically a list of previous position fixes)
@ -62,7 +64,7 @@ module GPX
segment = Segment.new segment = Segment.new
CSV.open(magellan_filename, "r").each do |row| CSV.open(magellan_filename, "r") do |row|
next if(row.size < 10 or row[INVALID_FLAG] == 'V') next if(row.size < 10 or row[INVALID_FLAG] == 'V')
lat_deg = row[LAT][0..1] lat_deg = row[LAT][0..1]

View File

@ -20,32 +20,30 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
include Math
module GPX module GPX
# The base class for all points. Trackpoint and Waypoint both descend from this base class. # The base class for all points. Trackpoint and Waypoint both descend from this base class.
class Point < Base class Point < Base
D_TO_R = Math::PI/180.0; D_TO_R = PI/180.0;
attr_accessor :lat, :lon, :time, :elevation, :gpx_file, :speed attr_accessor :lat, :lon, :time, :elevation
# When you need to manipulate individual points, you can create a Point # When you need to manipulate individual points, you can create a Point
# object with a latitude, a longitude, an elevation, and a time. In # object with a latitude, a longitude, an elevation, and a time. In
# addition, you can pass an XML element to this initializer, and the # addition, you can pass a REXML element to this initializer, and the
# relevant info will be parsed out. # relevant info will be parsed out.
def initialize(opts = {:lat => 0.0, :lon => 0.0, :elevation => 0.0, :time => Time.now } ) def initialize(opts = {:lat => 0.0, :lon => 0.0, :elevation => 0.0, :time => Time.now } )
@gpx_file = opts[:gpx_file]
if (opts[:element]) if (opts[:element])
elem = opts[:element] elem = opts[:element]
@lat, @lon = elem["lat"].to_f, elem["lon"].to_f @lat, @lon = elem.attributes["lat"].to_f, elem.attributes["lon"].to_f
@latr, @lonr = (D_TO_R * @lat), (D_TO_R * @lon) @latr, @lonr = (D_TO_R * @lat), (D_TO_R * @lon)
#'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)? #'-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
@time = (Time.xmlschema(elem.at("time").inner_text) rescue nil) @time = (Time.xmlschema(elem.elements["time"].text) rescue nil)
@elevation = elem.at("ele").inner_text.to_f unless elem.at("ele").nil? @elevation = elem.elements["ele"].text.to_f if elem.elements["ele"]
@speed = elem.at("speed").inner_text.to_f unless elem.at("speed").nil?
else else
@lat = opts[:lat] @lat = opts[:lat]
@lon = opts[:lon] @lon = opts[:lon]
@elevation = opts[:elevation] @elevation = opts[:elevation]
@time = opts[:time] @time = opts[:time]
@speed = opts[:speed]
end end
end end
@ -86,5 +84,20 @@ module GPX
@lonr = (longitude * D_TO_R) @lonr = (longitude * D_TO_R)
@lon = longitude @lon = longitude
end end
# Convert this point to a REXML::Element.
def to_xml(elem_name = 'trkpt')
pt = Element.new('trkpt')
pt.attributes['lat'] = lat
pt.attributes['lon'] = lon
time_elem = Element.new('time')
time_elem.text = time.xmlschema
pt.elements << time_elem
elev = Element.new('ele')
elev.text = elevation
pt.elements << elev
pt
end
end end
end end

View File

@ -21,26 +21,22 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
module GPX module GPX
# A Route in GPX is very similar to a Track, but it is created by a user # A Route in GPX is very similar to a Track, but it is created by a user
# from a series of Waypoints, whereas a Track is created by the GPS device # from a series of Waypoints, whereas a Track is created by the GPS device
# automatically logging your progress at regular intervals. # automatically logging your progress at regular intervals.
class Route < Base class Route < Base
attr_accessor :points, :name, :gpx_file attr_reader :points, :name, :gpx_file
# Initialize a Route from a XML::Node. # Initialize a Route from a REXML::Element.
def initialize(opts = {}) def initialize(opts = {})
if(opts[:gpx_file] and opts[:element])
rte_element = opts[:element] rte_element = opts[:element]
@gpx_file = opts[:gpx_file] @gpx_file = opts[:gpx_file]
@name = rte_element.at("name").inner_text @name = rte_element.elements["child::name"].text
@points = [] @points = []
rte_element.search("rtept").each do |point| XPath.each(rte_element, "child::rtept") do |point|
@points << Point.new(:element => point, :gpx_file => @gpx_file) @points << Point.new(:element => point)
end
else
@points = (opts[:points] or [])
@name = (opts[:name])
end end
end end
@ -54,5 +50,16 @@ module GPX
def delete_area(area) def delete_area(area)
points.delete_if{ |pt| area.contains? pt } points.delete_if{ |pt| area.contains? pt }
end end
# Convert this Route to a REXML::Element.
def to_xml
rte = Element.new('rte')
name_elem = Element.new('name')
name_elem.text = name
rte.elements << name_elem
points.each { |rte_pt| rte.elements << rte_pt.to_xml('rtept') }
rte
end
end end
end end

View File

@ -21,6 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
module GPX module GPX
# A segment is the basic container in a GPX file. A Segment contains points # A segment is the basic container in a GPX file. A Segment contains points
# (in this lib, they're called TrackPoints). A Track contains Segments. An # (in this lib, they're called TrackPoints). A Track contains Segments. An
# instance of Segment knows its highest point, lowest point, earliest and # instance of Segment knows its highest point, lowest point, earliest and
@ -30,10 +31,9 @@ module GPX
attr_reader :earliest_point, :latest_point, :bounds, :highest_point, :lowest_point, :distance attr_reader :earliest_point, :latest_point, :bounds, :highest_point, :lowest_point, :distance
attr_accessor :points, :track attr_accessor :points, :track
# If a XML::Node object is passed-in, this will initialize a new # If a REXML::Element object is passed-in, this will initialize a new
# Segment based on its contents. Otherwise, a blank Segment is created. # Segment based on its contents. Otherwise, a blank Segment is created.
def initialize(opts = {}) def initialize(opts = {})
@gpx_file = opts[:gpx_file]
@track = opts[:track] @track = opts[:track]
@points = [] @points = []
@earliest_point = nil @earliest_point = nil
@ -45,13 +45,11 @@ module GPX
if(opts[:element]) if(opts[:element])
segment_element = opts[:element] segment_element = opts[:element]
last_pt = nil last_pt = nil
if segment_element.is_a?(Nokogiri::XML::Node) unless segment_element.is_a?(Text)
segment_element.search("trkpt").each do |trkpt| XPath.each(segment_element, "child::trkpt") do |trkpt|
pt = TrackPoint.new(:element => trkpt, :segment => self, :gpx_file => @gpx_file) pt = TrackPoint.new(:element => trkpt, :segment => self)
unless pt.time.nil?
@earliest_point = pt if(@earliest_point.nil? or pt.time < @earliest_point.time) @earliest_point = pt if(@earliest_point.nil? or pt.time < @earliest_point.time)
@latest_point = pt if(@latest_point.nil? or pt.time > @latest_point.time) @latest_point = pt if(@latest_point.nil? or pt.time > @latest_point.time)
end
unless pt.elevation.nil? unless pt.elevation.nil?
@lowest_point = pt if(@lowest_point.nil? or pt.elevation < @lowest_point.elevation) @lowest_point = pt if(@lowest_point.nil? or pt.elevation < @lowest_point.elevation)
@highest_point = pt if(@highest_point.nil? or pt.elevation > @highest_point.elevation) @highest_point = pt if(@highest_point.nil? or pt.elevation > @highest_point.elevation)
@ -87,7 +85,7 @@ module GPX
# Returns true if the given time is within this Segment. # Returns true if the given time is within this Segment.
def contains_time?(time) def contains_time?(time)
(time >= @earliest_point.time and time <= @latest_point.time) rescue false (time >= @earliest_point.time and time <= @latest_point.time)
end end
# Finds the closest point in time to the passed-in time argument. Useful # Finds the closest point in time to the passed-in time argument. Useful
@ -131,6 +129,13 @@ module GPX
(points.nil? or (points.size == 0)) (points.nil? or (points.size == 0))
end end
# Converts this Segment to a REXML::Element object.
def to_xml
seg = Element.new('trkseg')
points.each { |pt| seg.elements << pt.to_xml }
seg
end
# Prints out a nice summary of this Segment. # Prints out a nice summary of this Segment.
def to_s def to_s
result = "Track Segment\n" result = "Track Segment\n"
@ -197,10 +202,8 @@ module GPX
end end
def update_meta_data(pt, last_pt) def update_meta_data(pt, last_pt)
unless pt.time.nil?
@earliest_point = pt if(@earliest_point.nil? or pt.time < @earliest_point.time) @earliest_point = pt if(@earliest_point.nil? or pt.time < @earliest_point.time)
@latest_point = pt if(@latest_point.nil? or pt.time > @latest_point.time) @latest_point = pt if(@latest_point.nil? or pt.time > @latest_point.time)
end
unless pt.elevation.nil? unless pt.elevation.nil?
@lowest_point = pt if(@lowest_point.nil? or pt.elevation < @lowest_point.elevation) @lowest_point = pt if(@lowest_point.nil? or pt.elevation < @lowest_point.elevation)
@highest_point = pt if(@highest_point.nil? or pt.elevation > @highest_point.elevation) @highest_point = pt if(@highest_point.nil? or pt.elevation > @highest_point.elevation)

View File

@ -21,6 +21,7 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
module GPX module GPX
# In GPX, a single Track can hold multiple Segments, each of which hold # In GPX, a single Track can hold multiple Segments, each of which hold
# multiple points (in this library, those points are instances of # multiple points (in this library, those points are instances of
# TrackPoint). Each instance of this class has its own meta-data, including # TrackPoint). Each instance of this class has its own meta-data, including
@ -31,7 +32,7 @@ module GPX
attr_reader :points, :bounds, :lowest_point, :highest_point, :distance attr_reader :points, :bounds, :lowest_point, :highest_point, :distance
attr_accessor :segments, :name, :gpx_file attr_accessor :segments, :name, :gpx_file
# Initialize a track from a XML::Node, or, if no :element option is # Initialize a track from a REXML::Element, or, if no :element option is
# passed, initialize a blank Track object. # passed, initialize a blank Track object.
def initialize(opts = {}) def initialize(opts = {})
@gpx_file = opts[:gpx_file] @gpx_file = opts[:gpx_file]
@ -40,11 +41,12 @@ module GPX
reset_meta_data reset_meta_data
if(opts[:element]) if(opts[:element])
trk_element = opts[:element] trk_element = opts[:element]
@name = (trk_element.at("name").inner_text rescue "") @name = (trk_element.elements["child::name"].text rescue "")
trk_element.search("trkseg").each do |seg_element| XPath.each(trk_element, "child::trkseg") do |seg_element|
seg = Segment.new(:element => seg_element, :track => self, :gpx_file => @gpx_file) seg = Segment.new(:element => seg_element, :track => self)
update_meta_data(seg) update_meta_data(seg)
@segments << seg @segments << seg
@points.concat(seg.points) unless seg.nil?
end end
end end
end end
@ -68,8 +70,8 @@ module GPX
# correlating things like pictures, video, and other events, if you are # correlating things like pictures, video, and other events, if you are
# working with a timestamp. # working with a timestamp.
def closest_point(time) def closest_point(time)
segment = segments.select { |s| s.contains_time?(time) } segment = segments.find { |s| s.contains_time?(time) }
segment.first segment.closest_point(time)
end end
# Removes all points outside of a given area and updates the meta data. # Removes all points outside of a given area and updates the meta data.
@ -99,9 +101,20 @@ module GPX
(points.nil? or points.size.zero?) (points.nil? or points.size.zero?)
end end
# Creates a new REXML::Element from the contents of this instance.
def to_xml
trk= Element.new('trk')
name_elem = Element.new('name')
name_elem.text = name
trk.elements << name_elem
segments.each do |seg|
trk.elements << seg.to_xml
end
trk
end
# Prints out a friendly summary of this track (sans points). Useful for # Prints out a friendly summary of this track (sans points). Useful for
# debugging and sanity checks. # debugging and sanity checks.
def to_s def to_s
result = "Track \n" result = "Track \n"
result << "\tName: #{name}\n" result << "\tName: #{name}\n"

View File

@ -1,3 +0,0 @@
module GPX
VERSION = "0.7"
end

View File

@ -20,15 +20,16 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++ #++
module GPX module GPX
# This class supports the concept of a waypoint. Beware that this class has # This class supports the concept of a waypoint. Beware that this class has
# not seen much use yet, since WalkingBoss does not use waypoints right now. # not seen much use yet, since WalkingBoss does not use waypoints right now.
class Waypoint < Point class Waypoint < Point
SUB_ELEMENTS = %w{ magvar geoidheight name cmt desc src link sym type fix sat hdop vdop pdop ageofdgpsdata dgpsid extensions ele} SUB_ELEMENTS = %q{ magvar geoidheight name cmt desc src link sym type fix sat hdop vdop pdop ageofdgpsdata dgpsid extensions }
attr_reader :gpx_file attr_reader :gpx_file
SUB_ELEMENTS.each { |sub_el| attr_accessor sub_el.to_sym }
# Not implemented # Not implemented
def crop(area) def crop(area)
@ -38,37 +39,35 @@ module GPX
def delete_area(area) def delete_area(area)
end end
# Initializes a waypoint from a XML::Node. # Initializes a waypoint from a REXML::Element.
def initialize(opts = {}) def initialize(opts = {})
if(opts[:element] and opts[:gpx_file])
wpt_elem = opts[:element] wpt_elem = opts[:element]
@gpx_file = opts[:gpx_file] super(:element => wpt_elem)
super(:element => wpt_elem, :gpx_file => @gpx_file)
instantiate_with_text_elements(wpt_elem, SUB_ELEMENTS) instantiate_with_text_elements(wpt_elem, SUB_ELEMENTS)
else @gpx_file = opts[:gpx_file]
opts.each do |key, value|
assignment_method = "#{key}="
if self.respond_to?(assignment_method)
self.send(assignment_method, value)
end
end
end
end end
# Prints out a friendly summary of this track (sans points). Useful for # Converts a waypoint to a REXML::Element.
# debugging and sanity checks. def to_xml
def to_s wpt = Element.new('wpt')
result = "Waypoint \n" wpt.attributes['lat'] = lat
result << "\tName: #{name}\n" wpt.attributes['lon'] = lon
result << "\tLatitude: #{lat} \n" if self.respond_to? :name
result << "\tLongitude: #{lon} \n" name_elem = Element.new('name')
result << "\tElevation: #{elevation}\n " name_elem.text = self.name
result << "\tTime: #{time}\n" wpt.elements << name_elem
SUB_ELEMENTS.each do |sub_element_attribute|
val = self.send(sub_element_attribute)
result << "\t#{sub_element_attribute}: #{val}\n" unless val.nil?
end end
result if self.respond_to? :sym
sym_elem = Element.new('sym')
sym_elem.text = self.sym
wpt.elements << sym_elem
end
if self.respond_to? :ele
elev_elem = Element.new('ele')
elev_elem.text = self.ele
wpt.elements << elev_elem
end
wpt
end end
end end
end end

View File

@ -1,12 +0,0 @@
require 'test/unit'
require 'gpx'
class GPX10Test < Test::Unit::TestCase
GPX_FILE = File.join(File.dirname(__FILE__), "gpx_files/gpx10.gpx")
def test_read
# make sure we can read a GPX 1.0 file
@gpx_file = GPX::GPXFile.new(:gpx_file => GPX_FILE)
end
end

View File

@ -1,48 +0,0 @@
require 'test/unit'
require 'gpx'
class GPXFileTest < Test::Unit::TestCase
ONE_TRACK_FILE = File.join(File.dirname(__FILE__), "gpx_files/one_track.gpx")
WITH_OR_WITHOUT_ELEV_FILE = File.join(File.dirname(__FILE__), "gpx_files/with_or_without_elev.gpx")
BIG_FILE = File.join(File.dirname(__FILE__), "gpx_files/big.gpx")
def test_load_data_from_string
gpx_file = GPX::GPXFile.new(:gpx_data => open(ONE_TRACK_FILE).read)
assert_equal(1, gpx_file.tracks.size)
assert_equal(8, gpx_file.tracks.first.segments.size)
assert_equal("ACTIVE LOG", gpx_file.tracks.first.name)
assert_equal("active_log.gpx", gpx_file.name)
assert_equal("2006-04-08T16:44:28Z", gpx_file.time.xmlschema)
assert_equal(38.681488, gpx_file.bounds.min_lat)
assert_equal(-109.606948, gpx_file.bounds.min_lon)
assert_equal(38.791759, gpx_file.bounds.max_lat)
assert_equal(-109.447045, gpx_file.bounds.max_lon)
end
def test_load_data_from_file
gpx_file = GPX::GPXFile.new(:gpx_file => ONE_TRACK_FILE)
assert_equal(1, gpx_file.tracks.size)
assert_equal(8, gpx_file.tracks.first.segments.size)
assert_equal("ACTIVE LOG", gpx_file.tracks.first.name)
assert_equal("active_log.gpx", gpx_file.name)
assert_equal("2006-04-08T16:44:28Z", gpx_file.time.xmlschema)
assert_equal(38.681488, gpx_file.bounds.min_lat)
assert_equal(-109.606948, gpx_file.bounds.min_lon)
assert_equal(38.791759, gpx_file.bounds.max_lat)
assert_equal(-109.447045, gpx_file.bounds.max_lon)
end
def test_big_file
gpx_file = GPX::GPXFile.new(:gpx_file => BIG_FILE)
assert_equal(1, gpx_file.tracks.size)
assert_equal(7968, gpx_file.tracks.first.points.size)
end
def test_with_or_with_elev
gpx_file = GPX::GPXFile.new(:gpx_file => WITH_OR_WITHOUT_ELEV_FILE)
assert_equal(2, gpx_file.tracks.size)
#assert_equal(7968, gpx_file.tracks.first.points.size)
end
end

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.0"
creator="GPSBabel - http://www.gpsbabel.org"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.topografix.com/GPX/1/0"
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<trk>
<name>ACTIVE LOG #74</name>
<number>82</number>
<trkseg>
<trkpt lat="37.378388923" lon="-122.063654875">
<ele>35.706055</ele>
<time>2007-11-23T23:49:43Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>

View File

@ -1,9 +1 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?><gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" version="1.1" creator="Link2GPS - 2.0.2 - http://www.hiketech.com" xsi:schemaLocation="ttp://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"><metadata><name><![CDATA[routes.gpx]]></name><time>2006-01-02T08:55:34Z</time><bounds min_lat="39.989739" min_lon="-105.295285" max_lat="39.999840" max_lon="-105.214696"/></metadata><extensions/><rte><name><![CDATA[GRG-CA-TO]]></name><rtept lat="39.997298" lon="-105.292674"><name><![CDATA[GRG-CA]]></name><sym>Waypoint</sym><ele>1766.535</ele></rtept><rtept lat="39.995700" lon="-105.292805"><name><![CDATA[AMPTHT]]></name><sym>Waypoint</sym><ele>1854.735</ele></rtept><rtept lat="39.989739" lon="-105.295285"><name><![CDATA[TO]]></name><sym>Waypoint</sym><ele>2163.556</ele></rtept></rte><rte><name><![CDATA[SBDR-SBDR]]></name><rtept lat="39.999840" lon="-105.214696"><name><![CDATA[SBDR]]></name><sym>Waypoint</sym><ele>1612.965</ele></rtept></rte></gpx>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" version="1.1" creator="Link2GPS - 2.0.2 - http://www.hiketech.com" xsi:schemaLocation="ttp://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"><metadata><name><![CDATA[routes.gpx]]></name><time>2006-01-02T08:55:34Z</time><bounds min_lat="39.989739" min_lon="-105.295285" max_lat="39.999840" max_lon="-105.214696"/></metadata><extensions/>
<rte><name><![CDATA[GRG-CA-TO]]></name>
<rtept lat="39.997298" lon="-105.292674"><name><![CDATA[GRG-CA]]></name><sym>Waypoint</sym><ele>1766.535</ele></rtept>
<rtept lat="39.995700" lon="-105.292805"><name><![CDATA[AMPTHT]]></name><sym>Waypoint</sym><ele>1854.735</ele></rtept>
<rtept lat="39.989739" lon="-105.295285"><name><![CDATA[TO]]></name><sym>Waypoint</sym><ele>2163.556</ele></rtept></rte>
<rte><name><![CDATA[SBDR-SBDR]]></name>
<rtept lat="39.999840" lon="-105.214696"><name><![CDATA[SBDR]]></name><sym>Waypoint</sym><ele>1612.965</ele></rtept></rte>
</gpx>

View File

@ -1,20 +1 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?><gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" version="1.1" creator="Link2GPS - 2.0.2 - http://www.hiketech.com" xsi:schemaLocation="ttp://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"><metadata><name><![CDATA[waypoints.gpx]]></name><time>2006-01-02T08:55:21Z</time><bounds min_lat="25.061783" min_lon="-111.946110" max_lat="50.982883" max_lon="121.640267"/></metadata><extensions/><wpt lat="40.035557" lon="-105.248268"><name><![CDATA[001]]></name><sym>Waypoint</sym><ele>1639.161</ele></wpt><wpt lat="39.993070" lon="-105.296588"><name><![CDATA[002]]></name><sym>Waypoint</sym><ele>1955.192</ele></wpt><wpt lat="39.990151" lon="-105.295680"><name><![CDATA[003]]></name><sym>Waypoint</sym><ele>2129.91</ele></wpt><wpt lat="39.990157" lon="-105.295686"><name><![CDATA[004]]></name><sym>Waypoint</sym><ele>2136.399</ele></wpt><wpt lat="39.990134" lon="-105.295251"><name><![CDATA[005]]></name><sym>Waypoint</sym><ele>2174.612</ele></wpt><wpt lat="39.990116" lon="-105.295147"><name><![CDATA[006]]></name><sym>Waypoint</sym><ele>2156.106</ele></wpt><wpt lat="39.990099" lon="-105.295207"><name><![CDATA[007]]></name><sym>Waypoint</sym><ele>2155.145</ele></wpt><wpt lat="39.990067" lon="-105.295185"><name><![CDATA[008]]></name><sym>Waypoint</sym><ele>2152.021</ele></wpt><wpt lat="39.995700" lon="-105.292805"><name><![CDATA[AMPTHT]]></name><sym>Waypoint</sym><ele>1854.735</ele></wpt><wpt lat="38.855550" lon="-94.799017"><name><![CDATA[GARMIN]]></name><sym>Waypoint</sym><ele>325.0491</ele></wpt><wpt lat="39.997298" lon="-105.292674"><name><![CDATA[GRG-CA]]></name><sym>Waypoint</sym><ele>1766.535</ele></wpt><wpt lat="50.982883" lon="-1.463900"><name><![CDATA[GRMEUR]]></name><sym>Waypoint</sym><ele>35.93469</ele></wpt><wpt lat="33.330190" lon="-111.946110"><name><![CDATA[GRMPHX]]></name><sym>Waypoint</sym><ele>361.0981</ele></wpt><wpt lat="25.061783" lon="121.640267"><name><![CDATA[GRMTWN]]></name><sym>Waypoint</sym><ele>38.09766</ele></wpt><wpt lat="39.999840" lon="-105.214696"><name><![CDATA[SBDR]]></name><sym>Waypoint</sym><ele>1612.965</ele></wpt><wpt lat="39.989739" lon="-105.295285"><name><![CDATA[TO]]></name><sym>Waypoint</sym><ele>2163.556</ele></wpt><wpt lat="40.035301" lon="-105.254443"><name><![CDATA[VICS]]></name><sym>Waypoint</sym><ele>1535.34</ele></wpt></gpx>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/1/1" version="1.1" creator="Link2GPS - 2.0.2 - http://www.hiketech.com" xsi:schemaLocation="ttp://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"><metadata><name><![CDATA[waypoints.gpx]]></name><time>2006-01-02T08:55:21Z</time><bounds min_lat="25.061783" min_lon="-111.946110" max_lat="50.982883" max_lon="121.640267"/></metadata><extensions/>
<wpt lat="40.035557" lon="-105.248268"><name><![CDATA[001]]></name><sym>Waypoint</sym><ele>1639.161</ele><cmt><![CDATA[001]]></cmt><desc><![CDATA[Just some waypoint...]]></desc></wpt>
<wpt lat="39.993070" lon="-105.296588"><name><![CDATA[002]]></name><sym>Waypoint</sym><ele>1955.192</ele></wpt>
<wpt lat="39.990151" lon="-105.295680"><name><![CDATA[003]]></name><sym>Waypoint</sym><ele>2129.91</ele></wpt>
<wpt lat="39.990157" lon="-105.295686"><name><![CDATA[004]]></name><sym>Waypoint</sym><ele>2136.399</ele></wpt>
<wpt lat="39.990134" lon="-105.295251"><name><![CDATA[005]]></name><sym>Waypoint</sym><ele>2174.612</ele></wpt>
<wpt lat="39.990116" lon="-105.295147"><name><![CDATA[006]]></name><sym>Waypoint</sym><ele>2156.106</ele></wpt>
<wpt lat="39.990099" lon="-105.295207"><name><![CDATA[007]]></name><sym>Waypoint</sym><ele>2155.145</ele></wpt>
<wpt lat="39.990067" lon="-105.295185"><name><![CDATA[008]]></name><sym>Waypoint</sym><ele>2152.021</ele></wpt>
<wpt lat="39.995700" lon="-105.292805"><name><![CDATA[AMPTHT]]></name><sym>Waypoint</sym><ele>1854.735</ele></wpt>
<wpt lat="38.855550" lon="-94.799017"><name><![CDATA[GARMIN]]></name><sym>Waypoint</sym><ele>325.0491</ele></wpt>
<wpt lat="39.997298" lon="-105.292674"><name><![CDATA[GRG-CA]]></name><sym>Waypoint</sym><ele>1766.535</ele></wpt>
<wpt lat="50.982883" lon="-1.463900"><name><![CDATA[GRMEUR]]></name><sym>Waypoint</sym><ele>35.93469</ele></wpt>
<wpt lat="33.330190" lon="-111.946110"><name><![CDATA[GRMPHX]]></name><sym>Waypoint</sym><ele>361.0981</ele></wpt>
<wpt lat="25.061783" lon="121.640267"><name><![CDATA[GRMTWN]]></name><sym>Waypoint</sym><ele>38.09766</ele></wpt>
<wpt lat="39.999840" lon="-105.214696"><name><![CDATA[SBDR]]></name><sym>Waypoint</sym><ele>1612.965</ele></wpt>
<wpt lat="39.989739" lon="-105.295285"><name><![CDATA[TO]]></name><sym>Waypoint</sym><ele>2163.556</ele></wpt>
<wpt lat="40.035301" lon="-105.254443"><name><![CDATA[VICS]]></name><sym>Waypoint</sym><ele>1535.34</ele></wpt>
</gpx>

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" creator="MapSource 6.5" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<metadata>
<link href="http://www.garmin.com">
<text>Garmin International</text>
</link>
<time>2007-04-16T18:11:47Z</time>
<bounds maxlat="40.207429" maxlon="116.670578" minlat="39.876895" minlon="101.636217"/>
</metadata>
<trk>
<name>ACTIVE LOG</name>
<trkseg>
<trkpt lat="40.079434" lon="116.295948">
<ele>50.606567</ele>
<time>2007-03-25T05:17:34Z</time>
</trkpt>
</trkseg>
</trk>
<trk>
<name>LINE-13</name>
<trkseg>
<trkpt lat="39.949744" lon="116.427398"/>
</trkseg>
</trk>
</gpx>

View File

@ -1,7 +1,7 @@
require 'test/unit' require 'test/unit'
require 'gpx' require File.dirname(__FILE__) + '/../lib/gpx'
class MagellanTest < Test::Unit::TestCase class TestMagellanTrackLog < Test::Unit::TestCase
MAGELLAN_TRACK_LOG = File.join(File.dirname(__FILE__), "gpx_files/magellan_track.log") MAGELLAN_TRACK_LOG = File.join(File.dirname(__FILE__), "gpx_files/magellan_track.log")
GPX_FILE = File.join(File.dirname(__FILE__), "gpx_files/one_segment.gpx") GPX_FILE = File.join(File.dirname(__FILE__), "gpx_files/one_segment.gpx")

View File

@ -1,115 +0,0 @@
require 'test/unit'
require 'fileutils'
require 'gpx'
class OutputTest < Test::Unit::TestCase
include GPX
def setup
FileUtils.mkdir_p(File.join(File.dirname(__FILE__), "output"))
end
def test_new_gpx_file_from_scratch
gpx_file = GPXFile.new
track = Track.new(:name => "My First Track")
segment = Segment.new
track_point_data = [
{:lat => 40.036926, :lon =>-105.253487, :time => Time.parse('2005-12-31T22:01:24Z'), :elevation => 1737.24},
{:lat => 40.036604, :lon =>-105.253487, :time => Time.parse("2005-12-31T22:02:01Z"), :elevation => 1738.682},
{:lat => 40.036347, :lon =>-105.253830, :time => Time.parse("2005-12-31T22:02:08Z"), :elevation => 1738.682},
{:lat => 40.035574, :lon =>-105.254045, :time => Time.parse("2005-12-31T22:02:20Z"), :elevation => 1737.24},
{:lat => 40.035467, :lon =>-105.254366, :time => Time.parse("2005-12-31T22:02:29Z"), :elevation => 1735.798},
{:lat => 40.035317, :lon =>-105.254388, :time => Time.parse("2005-12-31T22:02:33Z"), :elevation => 1735.798},
{:lat => 40.035274, :lon =>-105.254431, :time => Time.parse("2005-12-31T22:02:49Z"), :elevation => 1736.278},
{:lat => 40.035274, :lon =>-105.254431, :time => Time.parse("2005-12-31T22:02:54Z"), :elevation => 1739.643},
{:lat => 40.035317, :lon =>-105.254431, :time => Time.parse("2005-12-31T22:05:08Z"), :elevation => 1732.433},
{:lat => 40.035317, :lon =>-105.254431, :time => Time.parse("2005-12-31T22:05:09Z"), :elevation => 1726.665}]
track_point_data.each do |trk_pt_hash|
segment.points << TrackPoint.new(trk_pt_hash)
end
track.segments << segment
gpx_file.tracks << track
waypoint_data = [
{:lat => 39.997298, :lon => -105.292674, :name => 'GRG-CA', :sym => 'Waypoint', :ele => '1766.535'},
{:lat => 33.330190, :lon => -111.946110, :name => 'GRMPHX', :sym => 'Waypoint', :ele => '361.0981',
:cmt => "Hey here's a comment.", :desc => "Somewhere in my backyard.", :fix => '3d', :sat => "8", :hdop => "50.5", :vdop => "6.8", :pdop => "7.6"},
{:lat => 25.061783, :lon => 121.640267, :name => 'GRMTWN', :sym => 'Waypoint', :ele => '38.09766'},
{:lat => 39.999840, :lon => -105.214696, :name => 'SBDR', :sym => 'Waypoint', :ele => '1612.965'},
{:lat => 39.989739, :lon => -105.295285, :name => 'TO', :sym => 'Waypoint', :ele => '2163.556'},
{:lat => 40.035301, :lon => -105.254443, :name => 'VICS', :sym => 'Waypoint', :ele => '1535.34'}
]
waypoint_data.each do |wpt_hash|
gpx_file.waypoints << Waypoint.new(wpt_hash)
end
route_point_data = [
{:lat => 40.035467, :lon =>-105.254366, :time => Time.parse("2005-12-31T22:02:29Z"), :elevation => 1735.798},
{:lat => 40.035317, :lon =>-105.254388, :time => Time.parse("2005-12-31T22:02:33Z"), :elevation => 1735.798},
{:lat => 40.035274, :lon =>-105.254431, :time => Time.parse("2005-12-31T22:02:49Z"), :elevation => 1736.278} ]
route = Route.new()
route_point_data.each do |rte_pt_hash|
route.points << Point.new(rte_pt_hash)
end
gpx_file.routes << route
gpx_file.write(output_file(name_of_test))
written_gpx_file = GPXFile.new(:gpx_file => output_file(name_of_test))
assert_equal(File.basename(output_file(name_of_test)), written_gpx_file.name)
assert_equal(1, written_gpx_file.tracks.size)
assert_equal(1, written_gpx_file.tracks[0].segments.size)
assert_equal(track_point_data.size, written_gpx_file.tracks[0].segments[0].points.size)
assert_equal(track_point_data.size, written_gpx_file.tracks[0].points.size)
# Make sure each point in the segment has the attributes it was initialized with
written_segment = written_gpx_file.tracks[0].segments[0]
track_point_data.each_with_index do |trk_pt_hash, index|
trk_pt_hash.each do |key, value|
assert_equal(value, written_segment.points[index].send(key))
end
end
# Make sure the one route has the attributes we initialized it with
assert_equal(1, written_gpx_file.routes.size)
written_route = written_gpx_file.routes[0]
assert_equal(route_point_data.size, written_route.points.size)
route_point_data.each_with_index do |rte_pt_hash, index|
rte_pt_hash.each do |key, value|
assert_equal(value, written_route.points[index].send(key))
end
end
# Make sure the waypoints have all of the attributes we initialized them with
written_waypoints = written_gpx_file.waypoints
assert_equal(waypoint_data.size, written_waypoints.size)
waypoint_data.each_with_index do |wpt_hash, index|
wpt_hash.each do |key, value|
assert_equal(value, written_waypoints[index].send(key.to_s), key)
end
end
end
def name_of_test
caller[0] =~ /`test_([^']*)'/ and $1
end
def output_file(test_name)
File.join(File.dirname(__FILE__), "output/#{test_name}.gpx")
end
THE_WORKS = "<?xml version=\"1.0\"?>\n<gpx xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" version=\"1.1\" creator=\"GPX RubyGem #{GPX::VERSION} Copyright 2006-2009 Doug Fales -- http://gpx.rubyforge.org/\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n <metadata>\n <name>new_gpx_file_from_scratch.gpx</name>\n <time>%s</time>\n <bounds minlat=\"90.0\" minlon=\"180.0\" maxlat=\"-90.0\" maxlon=\"-180.0\"/>\n </metadata>\n <trk>\n <name/>\n <trkseg>\n <trkpt lat=\"40.036926\" lon=\"-105.253487\">\n <time>2005-12-31T22:01:24Z</time>\n <ele>1737.24</ele>\n </trkpt>\n <trkpt lat=\"40.036604\" lon=\"-105.253487\">\n <time>2005-12-31T22:02:01Z</time>\n <ele>1738.682</ele>\n </trkpt>\n <trkpt lat=\"40.036347\" lon=\"-105.25383\">\n <time>2005-12-31T22:02:08Z</time>\n <ele>1738.682</ele>\n </trkpt>\n <trkpt lat=\"40.035574\" lon=\"-105.254045\">\n <time>2005-12-31T22:02:20Z</time>\n <ele>1737.24</ele>\n </trkpt>\n <trkpt lat=\"40.035467\" lon=\"-105.254366\">\n <time>2005-12-31T22:02:29Z</time>\n <ele>1735.798</ele>\n </trkpt>\n <trkpt lat=\"40.035317\" lon=\"-105.254388\">\n <time>2005-12-31T22:02:33Z</time>\n <ele>1735.798</ele>\n </trkpt>\n <trkpt lat=\"40.035274\" lon=\"-105.254431\">\n <time>2005-12-31T22:02:49Z</time>\n <ele>1736.278</ele>\n </trkpt>\n <trkpt lat=\"40.035274\" lon=\"-105.254431\">\n <time>2005-12-31T22:02:54Z</time>\n <ele>1739.643</ele>\n </trkpt>\n <trkpt lat=\"40.035317\" lon=\"-105.254431\">\n <time>2005-12-31T22:05:08Z</time>\n <ele>1732.433</ele>\n </trkpt>\n <trkpt lat=\"40.035317\" lon=\"-105.254431\">\n <time>2005-12-31T22:05:09Z</time>\n <ele>1726.665</ele>\n </trkpt>\n </trkseg>\n </trk>\n <wpt lat=\"39.997298\" lon=\"-105.292674\">\n <name>GRG-CA</name>\n <sym>Waypoint</sym>\n <ele>1766.535</ele>\n </wpt>\n <wpt lat=\"33.33019\" lon=\"-111.94611\">\n <name>GRMPHX</name>\n <cmt>Hey here's a comment.</cmt>\n <desc>Somewhere in my backyard.</desc>\n <sym>Waypoint</sym>\n <fix>3d</fix>\n <sat>8</sat>\n <hdop>50.5</hdop>\n <vdop>6.8</vdop>\n <pdop>7.6</pdop>\n <ele>361.0981</ele>\n </wpt>\n <wpt lat=\"25.061783\" lon=\"121.640267\">\n <name>GRMTWN</name>\n <sym>Waypoint</sym>\n <ele>38.09766</ele>\n </wpt>\n <wpt lat=\"39.99984\" lon=\"-105.214696\">\n <name>SBDR</name>\n <sym>Waypoint</sym>\n <ele>1612.965</ele>\n </wpt>\n <wpt lat=\"39.989739\" lon=\"-105.295285\">\n <name>TO</name>\n <sym>Waypoint</sym>\n <ele>2163.556</ele>\n </wpt>\n <wpt lat=\"40.035301\" lon=\"-105.254443\">\n <name>VICS</name>\n <sym>Waypoint</sym>\n <ele>1535.34</ele>\n </wpt>\n <rte>\n <name/>\n <rtept lat=\"40.035467\" lon=\"-105.254366\">\n <time>2005-12-31T22:02:29Z</time>\n <ele>1735.798</ele>\n </rtept>\n <rtept lat=\"40.035317\" lon=\"-105.254388\">\n <time>2005-12-31T22:02:33Z</time>\n <ele>1735.798</ele>\n </rtept>\n <rtept lat=\"40.035274\" lon=\"-105.254431\">\n <time>2005-12-31T22:02:49Z</time>\n <ele>1736.278</ele>\n </rtept>\n </rte>\n</gpx>\n"
end

View File

@ -1,63 +0,0 @@
require 'test/unit'
require 'gpx'
class RouteTest < Test::Unit::TestCase
def test_read_routes
gpx = GPX::GPXFile.new(:gpx_file => File.join(File.dirname(__FILE__), "gpx_files/routes.gpx"))
assert_equal(2, gpx.routes.size)
first_route = gpx.routes.first
assert_equal(3, first_route.points.size)
assert_equal('GRG-CA-TO', first_route.name)
# Route 1, First Point
# <rtept lat="39.997298" lon="-105.292674">
# <name><![CDATA[GRG-CA]]></name>
# <sym>Waypoint</sym>
# <ele>1766.535</ele>
# </rtept>
assert_equal(39.997298, first_route.points[0].lat)
assert_equal(-105.292674, first_route.points[0].lon)
assert_equal(1766.535, first_route.points[0].elevation)
# Route 1, Second Point
# <rtept lat="39.995700" lon="-105.292805">
# <name><![CDATA[AMPTHT]]></name>
# <sym>Waypoint</sym>
# <ele>1854.735</ele>
# </rtept>
assert_equal(39.995700, first_route.points[1].lat)
assert_equal(-105.292805, first_route.points[1].lon)
assert_equal(1854.735, first_route.points[1].elevation)
# Route 1, Third Point
# <rtept lat="39.989739" lon="-105.295285">
# <name><![CDATA[TO]]></name>
# <sym>Waypoint</sym>
# <ele>2163.556</ele>
# </rtept>
assert_equal(39.989739, first_route.points[2].lat)
assert_equal(-105.295285, first_route.points[2].lon)
assert_equal(2163.556, first_route.points[2].elevation)
second_route = gpx.routes[1]
assert_equal(1, second_route.points.size)
assert_equal('SBDR-SBDR', second_route.name)
# Route 2, Only Point
# <rtept lat="39.999840" lon="-105.214696">
# <name><![CDATA[SBDR]]></name>
# <sym>Waypoint</sym>
# <ele>1612.965</ele>
# </rtept>
assert_equal(39.999840, second_route.points[0].lat)
assert_equal(-105.214696, second_route.points[0].lon)
assert_equal(1612.965, second_route.points[0].elevation)
end
end

View File

@ -1,8 +1,7 @@
require 'test/unit' require 'test/unit'
require 'yaml' require File.dirname(__FILE__) + '/../lib/gpx'
require 'gpx'
class SegmentTest < Test::Unit::TestCase class TestSegment < Test::Unit::TestCase
ONE_SEGMENT = File.join(File.dirname(__FILE__), "gpx_files/one_segment.gpx") ONE_SEGMENT = File.join(File.dirname(__FILE__), "gpx_files/one_segment.gpx")
def setup def setup
@ -12,11 +11,11 @@ class SegmentTest < Test::Unit::TestCase
def test_segment_read def test_segment_read
assert_equal(189, @segment.points.size) assert_equal(189, @segment.points.size)
assert_equal(1144433525, @segment.earliest_point.time.to_i) assert_equal("Fri Apr 07 18:12:05 UTC 2006", @segment.earliest_point.time.to_s)
assert_equal(1144437991, @segment.latest_point.time.to_i) assert_equal("Fri Apr 07 19:26:31 UTC 2006", @segment.latest_point.time.to_s)
assert_equal(1334.447, @segment.lowest_point.elevation) assert_equal(1334.447, @segment.lowest_point.elevation)
assert_equal(1480.087, @segment.highest_point.elevation) assert_equal(1480.087, @segment.highest_point.elevation)
assert_in_delta(6.98803359528853, @segment.distance, 0.001) assert_equal("6.98803359528853", @segment.distance.to_s)
end end
def test_segment_crop def test_segment_crop
@ -27,9 +26,9 @@ class SegmentTest < Test::Unit::TestCase
@segment.crop(crop_rectangle) @segment.crop(crop_rectangle)
assert_equal(106, @segment.points.size) assert_equal(106, @segment.points.size)
assert_in_delta(4.11422061733046, @segment.distance, 0.001) assert_equal("4.11422061733046", @segment.distance.to_s)
assert_equal(1144435041, @segment.earliest_point.time.to_i) assert_equal("Fri Apr 07 18:37:21 UTC 2006", @segment.earliest_point.time.to_s)
assert_equal(1144437752, @segment.latest_point.time.to_i) assert_equal("Fri Apr 07 19:22:32 UTC 2006", @segment.latest_point.time.to_s)
assert_equal(1407.027, @segment.lowest_point.elevation) assert_equal(1407.027, @segment.lowest_point.elevation)
assert_equal(1480.087, @segment.highest_point.elevation) assert_equal(1480.087, @segment.highest_point.elevation)
assert_equal(39.173834, @segment.bounds.min_lat) assert_equal(39.173834, @segment.bounds.min_lat)
@ -45,9 +44,9 @@ class SegmentTest < Test::Unit::TestCase
:max_lon=> -108.999000) :max_lon=> -108.999000)
@segment.delete_area(delete_rectangle) @segment.delete_area(delete_rectangle)
assert_equal(83, @segment.points.size) assert_equal(83, @segment.points.size)
assert_in_delta(3.35967118153605, @segment.distance, 0.001) assert_equal("3.35967118153605", @segment.distance.to_s)
assert_equal(1144433525, @segment.earliest_point.time.to_i) assert_equal("Fri Apr 07 18:12:05 UTC 2006", @segment.earliest_point.time.to_s)
assert_equal(1144437991, @segment.latest_point.time.to_i) assert_equal("Fri Apr 07 19:26:31 UTC 2006", @segment.latest_point.time.to_s)
assert_equal(1334.447, @segment.lowest_point.elevation) assert_equal(1334.447, @segment.lowest_point.elevation)
assert_equal(1428.176, @segment.highest_point.elevation) assert_equal(1428.176, @segment.highest_point.elevation)
assert_equal(39.180572, @segment.bounds.min_lat) assert_equal(39.180572, @segment.bounds.min_lat)

View File

@ -1,7 +1,7 @@
require 'test/unit' require 'test/unit'
require 'gpx' require File.dirname(__FILE__) + '/../lib/gpx'
class TrackFileTest < Test::Unit::TestCase class TestTrackFile < Test::Unit::TestCase
TRACK_FILE = File.join(File.dirname(__FILE__), "gpx_files/tracks.gpx") TRACK_FILE = File.join(File.dirname(__FILE__), "gpx_files/tracks.gpx")
OTHER_TRACK_FILE = File.join(File.dirname(__FILE__), "gpx_files/arches.gpx") OTHER_TRACK_FILE = File.join(File.dirname(__FILE__), "gpx_files/arches.gpx")
@ -69,7 +69,7 @@ class TrackFileTest < Test::Unit::TestCase
end end
def test_write def test_write
@other_track_file.write("tests/output/myoutput.gpx") @other_track_file.write("myoutput.gpx")
end end
end end

View File

@ -1,7 +1,7 @@
require 'test/unit' require 'test/unit'
require 'gpx' require File.dirname(__FILE__) + '/../lib/gpx'
class TrackTest < Test::Unit::TestCase class TestTrack < Test::Unit::TestCase
ONE_TRACK = File.join(File.dirname(__FILE__), "gpx_files/one_track.gpx") ONE_TRACK = File.join(File.dirname(__FILE__), "gpx_files/one_track.gpx")
def setup def setup
@ -11,9 +11,9 @@ class TrackTest < Test::Unit::TestCase
def test_track_read def test_track_read
assert_equal("ACTIVE LOG", @track.name) assert_equal("ACTIVE LOG", @track.name)
assert_equal( 182, @track.points.size) assert_equal( 364, @track.points.size)
assert_equal(8, @track.segments.size) assert_equal(8, @track.segments.size)
assert_in_delta(3.07249668492626, @track.distance, 0.001) assert_equal("3.07249668492626", @track.distance.to_s)
assert_equal(1267.155, @track.lowest_point.elevation) assert_equal(1267.155, @track.lowest_point.elevation)
assert_equal(1594.003, @track.highest_point.elevation) assert_equal(1594.003, @track.highest_point.elevation)
assert_equal(38.681488, @track.bounds.min_lat) assert_equal(38.681488, @track.bounds.min_lat)
@ -32,7 +32,7 @@ class TrackTest < Test::Unit::TestCase
assert_equal("ACTIVE LOG", @track.name) assert_equal("ACTIVE LOG", @track.name)
assert_equal( 111, @track.points.size) assert_equal( 111, @track.points.size)
assert_equal(4, @track.segments.size) assert_equal(4, @track.segments.size)
assert_in_delta(1.62136024923607, @track.distance, 0.001) assert_equal("1.62136024923607", @track.distance.to_s)
assert_equal(1557.954, @track.lowest_point.elevation) assert_equal(1557.954, @track.lowest_point.elevation)
assert_equal(1582.468, @track.highest_point.elevation) assert_equal(1582.468, @track.highest_point.elevation)
assert_equal(38.782511, @track.bounds.min_lat) assert_equal(38.782511, @track.bounds.min_lat)

View File

@ -1,44 +0,0 @@
require 'test/unit'
require 'gpx'
class WaypointTest < Test::Unit::TestCase
def test_read_waypoints
gpx = GPX::GPXFile.new(:gpx_file => File.join(File.dirname(__FILE__), "gpx_files/waypoints.gpx"))
assert_equal(17, gpx.waypoints.size)
# First Waypoint
# <wpt lat="40.035557" lon="-105.248268">
# <name><![CDATA[001]]></name>
# <sym>Waypoint</sym>
# <ele>1639.161</ele>
# <cmt><![CDATA[001]]></cmt>
# <desc><![CDATA[Just some waypoint...]]></desc>
# </wpt>
first_wpt = gpx.waypoints[0]
assert_equal(40.035557, first_wpt.lat)
assert_equal(-105.248268, first_wpt.lon)
assert_equal('001', first_wpt.name)
assert_equal('001', first_wpt.cmt)
assert_equal('Just some waypoint...', first_wpt.desc)
assert_equal('Waypoint', first_wpt.sym)
assert_equal(1639.161, first_wpt.elevation)
# Second Waypoint
# <wpt lat="39.993070" lon="-105.296588">
# <name><![CDATA[002]]></name>
# <sym>Waypoint</sym>
# <ele>1955.192</ele>
# </wpt>
second_wpt = gpx.waypoints[1]
assert_equal(39.993070, second_wpt.lat)
assert_equal(-105.296588, second_wpt.lon)
assert_equal('002', second_wpt.name)
assert_equal('Waypoint', second_wpt.sym)
assert_equal(1955.192, second_wpt.elevation)
end
end