commit
4bca65aeec
|
@ -1,5 +1,4 @@
|
||||||
require 'xml/libxml'
|
require './lib/gpx/gpx' # load this just to get GPX::VERSION
|
||||||
require 'lib/gpx/gpx' # load this and xml/libxml just to get GPX::VERSION
|
|
||||||
require 'rake' # For FileList
|
require 'rake' # For FileList
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = 'gpx'
|
s.name = 'gpx'
|
||||||
|
@ -13,4 +12,5 @@ Gem::Specification.new do |s|
|
||||||
s.email = "doug.fales@gmail.com"
|
s.email = "doug.fales@gmail.com"
|
||||||
s.homepage = "http://dougfales.github.com/gpx/"
|
s.homepage = "http://dougfales.github.com/gpx/"
|
||||||
s.rubyforge_project = "gpx"
|
s.rubyforge_project = "gpx"
|
||||||
|
s.add_dependency('hpricot')
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#++
|
#++
|
||||||
$:.unshift(File.dirname(__FILE__))
|
$:.unshift(File.dirname(__FILE__))
|
||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
require 'xml/libxml'
|
require 'hpricot'
|
||||||
require 'date'
|
require 'date'
|
||||||
require 'time'
|
require 'time'
|
||||||
require 'csv'
|
require 'csv'
|
||||||
|
|
|
@ -21,12 +21,11 @@
|
||||||
# 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.6"
|
VERSION = "0.7"
|
||||||
|
|
||||||
# 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
|
||||||
include XML
|
|
||||||
|
|
||||||
# This initializer can take an XML::Node and scrape out any text
|
# This initializer can take an XML::Node 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
|
||||||
|
@ -35,11 +34,11 @@ module GPX
|
||||||
# have to pick out individual text elements in each initializer of each
|
# have to pick out individual text elements in each initializer of each
|
||||||
# class (Route, TrackPoint, Track, etc). Just pass an array of possible
|
# class (Route, TrackPoint, Track, etc). Just pass an array of possible
|
||||||
# attributes to this method.
|
# attributes to this method.
|
||||||
def instantiate_with_text_elements(parent, text_elements, ns)
|
def instantiate_with_text_elements(parent, text_elements)
|
||||||
text_elements.each do |el|
|
text_elements.each do |el|
|
||||||
child_xpath = "gpx:#{el}"
|
child_xpath = "//#{el}"
|
||||||
unless parent.find(child_xpath, ns).empty?
|
unless parent.at(child_xpath).nil?
|
||||||
val = parent.find(child_xpath, ns).first.content
|
val = parent.at(child_xpath).inner_text
|
||||||
self.send("#{el}=", val)
|
self.send("#{el}=", val)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -52,20 +52,19 @@ module GPX
|
||||||
# gpx_file = File.open(gpx_file)
|
# gpx_file = File.open(gpx_file)
|
||||||
#end
|
#end
|
||||||
gpx_file = gpx_file.name if gpx_file.is_a?(File)
|
gpx_file = gpx_file.name if gpx_file.is_a?(File)
|
||||||
@xml = XML::Document.file(gpx_file)
|
@xml = Hpricot(File.open(gpx_file))
|
||||||
else
|
else
|
||||||
parser = XML::Parser.string(opts[:gpx_data])
|
@xml = Hpricot(opts[:gpx_data])
|
||||||
@xml = parser.parse
|
|
||||||
end
|
end
|
||||||
# set XML namespace for XML find
|
# set XML namespace for XML find
|
||||||
if @xml.root.namespaces.namespace
|
#if @xml.root.namespaces.namespace
|
||||||
@ns = 'gpx:' + @xml.root.namespaces.namespace.href
|
# @ns = 'gpx:' + @xml.root.namespaces.namespace.href
|
||||||
else
|
#else
|
||||||
@ns = 'gpx:http://www.topografix.com/GPX/1/1' # default to GPX 1.1
|
# @ns = 'gpx:http://www.topografix.com/GPX/1/1' # default to GPX 1.1
|
||||||
end
|
#end
|
||||||
|
|
||||||
reset_meta_data
|
reset_meta_data
|
||||||
bounds_element = (@xml.find("//gpx:gpx/gpx:metadata/gpx:bounds", @ns).to_a.first rescue nil)
|
bounds_element = (@xml.at("//metadata/bounds") 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 = 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.min_lon = get_bounds_attr_value(bounds_element, %w{ min_lon minlon minLon})
|
||||||
|
@ -75,20 +74,18 @@ module GPX
|
||||||
get_bounds = true
|
get_bounds = true
|
||||||
end
|
end
|
||||||
|
|
||||||
@time = Time.parse(@xml.find("//gpx:gpx/gpx:metadata/gpx:time", @ns).first.content) rescue nil
|
@time = Time.parse(@xml.at("//metadata/time").inner_text) rescue nil
|
||||||
@name = @xml.find("//gpx:gpx/gpx:metadata/gpx:name", @ns).first.content rescue nil
|
@name = @xml.at("//metadata/name").inner_text rescue nil
|
||||||
|
|
||||||
@tracks = []
|
@tracks = []
|
||||||
@xml.find("//gpx:gpx/gpx:trk", @ns).each do |trk|
|
@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
|
@tracks << trk
|
||||||
end
|
end
|
||||||
@waypoints = []
|
@waypoints = []
|
||||||
@xml.find("//gpx:gpx/gpx:wpt", @ns).each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) }
|
@xml.search("//wpt").each { |wpt| @waypoints << Waypoint.new(:element => wpt, :gpx_file => self) }
|
||||||
@routes = []
|
@routes = []
|
||||||
@xml.find("//gpx:gpx/gpx:rte", @ns).each { |rte| @routes << Route.new(:element => rte, :gpx_file => self) }
|
@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
|
||||||
|
@ -222,7 +219,7 @@ module GPX
|
||||||
doc = Document.new
|
doc = Document.new
|
||||||
doc.root = Node.new('gpx')
|
doc.root = Node.new('gpx')
|
||||||
gpx_elem = doc.root
|
gpx_elem = doc.root
|
||||||
gpx_elem['xmlns:xsi'] = "http://www.w3.org/2001/XMLSchema-instance"
|
gpx_elem['xsi'] = "http://www.w3.org/2001/XMLSchema-instance"
|
||||||
@version = '1.1' if (@version.nil? || !(['1.0', '1.1'].include?(@version))) # default to version 1.1 of the schema (only version 1.0 and 1.1 of the schema exist)
|
@version = '1.1' if (@version.nil? || !(['1.0', '1.1'].include?(@version))) # default to version 1.1 of the schema (only version 1.0 and 1.1 of the schema exist)
|
||||||
version_dir = @version.gsub('.','/')
|
version_dir = @version.gsub('.','/')
|
||||||
gpx_elem['xmlns'] = @ns || "http://www.topografix.com/GPX/#{version_dir}"
|
gpx_elem['xmlns'] = @ns || "http://www.topografix.com/GPX/#{version_dir}"
|
||||||
|
|
|
@ -60,11 +60,11 @@ module GPX
|
||||||
|
|
||||||
# Takes the name of a magellan file, converts the contents to GPX, and
|
# Takes the name of a magellan file, converts the contents to GPX, and
|
||||||
# writes the result to gpx_filename.
|
# writes the result to gpx_filename.
|
||||||
def convert_to_gpx(magellan_filename, gpx_filename)
|
def convert_to_gpx(magellan_filename, gpx_filename)
|
||||||
|
|
||||||
segment = Segment.new
|
segment = Segment.new
|
||||||
|
|
||||||
CSV.open(magellan_filename, "r") do |row|
|
CSV.open(magellan_filename, "r").each 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]
|
||||||
|
|
|
@ -38,9 +38,9 @@ module GPX
|
||||||
@lat, @lon = elem["lat"].to_f, elem["lon"].to_f
|
@lat, @lon = elem["lat"].to_f, elem["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.find("gpx:time", @gpx_file.ns).first.content) rescue nil)
|
@time = (Time.xmlschema(elem.at("time").inner_text) rescue nil)
|
||||||
@elevation = elem.find("gpx:ele", @gpx_file.ns).first.content.to_f unless elem.find("gpx:ele", @gpx_file.ns).empty?
|
@elevation = elem.at("ele").inner_text.to_f unless elem.at("ele").nil?
|
||||||
@speed = elem.find("gpx:speed", @gpx_file.ns).first.content.to_f unless elem.find("gpx:speed", @gpx_file.ns).empty?
|
@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]
|
||||||
|
|
|
@ -34,9 +34,9 @@ module GPX
|
||||||
if(opts[:gpx_file] and opts[:element])
|
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.find("child::gpx:name", @gpx_file.ns).first.content
|
@name = rte_element.at("//name").inner_text
|
||||||
@points = []
|
@points = []
|
||||||
rte_element.find("child::gpx:rtept", @gpx_file.ns).each do |point|
|
rte_element.search("//rtept").each do |point|
|
||||||
@points << Point.new(:element => point, :gpx_file => @gpx_file)
|
@points << Point.new(:element => point, :gpx_file => @gpx_file)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
@ -46,8 +46,8 @@ 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?(XML::Node)
|
if segment_element.is_a?(Hpricot::Elem)
|
||||||
segment_element.find("child::gpx:trkpt", @gpx_file.ns).each do |trkpt|
|
segment_element.search("//trkpt").each do |trkpt|
|
||||||
pt = TrackPoint.new(:element => trkpt, :segment => self, :gpx_file => @gpx_file)
|
pt = TrackPoint.new(:element => trkpt, :segment => self, :gpx_file => @gpx_file)
|
||||||
unless pt.time.nil?
|
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)
|
||||||
|
|
|
@ -41,8 +41,8 @@ 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.find("child::gpx:name", @gpx_file.ns).first.content rescue "")
|
@name = (trk_element.at("//name").inner_text rescue "")
|
||||||
trk_element.find("child::gpx:trkseg", @gpx_file.ns).each do |seg_element|
|
trk_element.search("//trkseg").each do |seg_element|
|
||||||
seg = Segment.new(:element => seg_element, :track => self, :gpx_file => @gpx_file)
|
seg = Segment.new(:element => seg_element, :track => self, :gpx_file => @gpx_file)
|
||||||
update_meta_data(seg)
|
update_meta_data(seg)
|
||||||
@segments << seg
|
@segments << seg
|
||||||
|
@ -69,8 +69,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.find { |s| s.contains_time?(time) }
|
segment = segments.select { |s| s.contains_time?(time) }
|
||||||
segment.closest_point(time)
|
segment.first
|
||||||
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.
|
||||||
|
@ -114,6 +114,7 @@ module GPX
|
||||||
|
|
||||||
# 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"
|
||||||
|
|
|
@ -46,7 +46,7 @@ module GPX
|
||||||
wpt_elem = opts[:element]
|
wpt_elem = opts[:element]
|
||||||
@gpx_file = opts[:gpx_file]
|
@gpx_file = opts[:gpx_file]
|
||||||
super(:element => wpt_elem, :gpx_file => @gpx_file)
|
super(:element => wpt_elem, :gpx_file => @gpx_file)
|
||||||
instantiate_with_text_elements(wpt_elem, SUB_ELEMENTS, @gpx_file.ns)
|
instantiate_with_text_elements(wpt_elem, SUB_ELEMENTS)
|
||||||
else
|
else
|
||||||
opts.each do |key, value|
|
opts.each do |key, value|
|
||||||
assignment_method = "#{key}="
|
assignment_method = "#{key}="
|
||||||
|
|
|
@ -12,11 +12,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("Fri Apr 07 18:12:05 UTC 2006", @segment.earliest_point.time.to_s)
|
assert_equal(1144433525, @segment.earliest_point.time.to_i)
|
||||||
assert_equal("Fri Apr 07 19:26:31 UTC 2006", @segment.latest_point.time.to_s)
|
assert_equal(1144437991, @segment.latest_point.time.to_i)
|
||||||
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_equal("6.98803359528853", @segment.distance.to_s)
|
assert_in_delta(6.98803359528853, @segment.distance, 0.001)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_segment_crop
|
def test_segment_crop
|
||||||
|
@ -27,9 +27,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_equal("4.11422061733046", @segment.distance.to_s)
|
assert_in_delta(4.11422061733046, @segment.distance, 0.001)
|
||||||
assert_equal("Fri Apr 07 18:37:21 UTC 2006", @segment.earliest_point.time.to_s)
|
assert_equal(1144435041, @segment.earliest_point.time.to_i)
|
||||||
assert_equal("Fri Apr 07 19:22:32 UTC 2006", @segment.latest_point.time.to_s)
|
assert_equal(1144437752, @segment.latest_point.time.to_i)
|
||||||
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 +45,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_equal("3.35967118153605", @segment.distance.to_s)
|
assert_in_delta(3.35967118153605, @segment.distance, 0.001)
|
||||||
assert_equal("Fri Apr 07 18:12:05 UTC 2006", @segment.earliest_point.time.to_s)
|
assert_equal(1144433525, @segment.earliest_point.time.to_i)
|
||||||
assert_equal("Fri Apr 07 19:26:31 UTC 2006", @segment.latest_point.time.to_s)
|
assert_equal(1144437991, @segment.latest_point.time.to_i)
|
||||||
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)
|
||||||
|
|
|
@ -13,7 +13,7 @@ class TrackTest < Test::Unit::TestCase
|
||||||
assert_equal("ACTIVE LOG", @track.name)
|
assert_equal("ACTIVE LOG", @track.name)
|
||||||
assert_equal( 182, @track.points.size)
|
assert_equal( 182, @track.points.size)
|
||||||
assert_equal(8, @track.segments.size)
|
assert_equal(8, @track.segments.size)
|
||||||
assert_equal("3.07249668492626", @track.distance.to_s)
|
assert_in_delta(3.07249668492626, @track.distance, 0.001)
|
||||||
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_equal("1.62136024923607", @track.distance.to_s)
|
assert_in_delta(1.62136024923607, @track.distance, 0.001)
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue