lib/geo_ruby/gpx.rb in georuby-2.3.0 vs lib/geo_ruby/gpx.rb in georuby-2.5.1
- old
+ new
@@ -1,112 +1,224 @@
-require 'geo_ruby/gpx4r/gpx'
+require 'nokogiri'
+
+module GeoRuby
+ module Gpx4r
+ # An interface to GPX files
+ class GpxFile
+ attr_reader :record_count, :file_root #:xmin, :ymin, :xmax, :ymax, :zmin, :zmax, :mmin, :mmax, :file_length
+
+ include Enumerable
+
+ # Opens a GPX file. Both "abc.shp" and "abc" are accepted.
+ def initialize(file, *opts) # with_z = true, with_m = true)
+ @file_root = file.gsub(/\.gpx$/i, '')
+ fail MalformedGpxException.new('Missing GPX File') unless
+ File.exist? @file_root + '.gpx'
+ @points, @envelope = [], nil
+ @gpx = File.open(@file_root + '.gpx', 'rb')
+ opt = opts.reduce({}) { |a, e| e.merge(a) }
+ parse_file(opt[:with_z], opt[:with_m])
+ end
+
+ # force the reopening of the files compsing the shp. Close before calling this.
+ def reload!
+ initialize(@file_root)
+ end
+
+ # opens a GPX "file". If a block is given, the GpxFile object is yielded to it and is closed upon return. Else a call to <tt>open</tt> is equivalent to <tt>GpxFile.new(...)</tt>.
+ def self.open(file, *opts)
+ gpxfile = GpxFile.new(file, *opts)
+ if block_given?
+ yield gpxfile
+ # gpxfile.close
+ else
+ gpxfile
+ end
+ end
+
+ # Closes a gpxfile
+ def close
+ @gpx.close
+ end
+
+ # Tests if the file has no record
+ def empty?
+ record_count == 0
+ end
+
+ # Goes through each record
+ def each
+ (0...record_count).each do |i|
+ yield get_record(i)
+ end
+ end
+ alias_method :each_record, :each
+
+ # Returns record +i+
+ def [](i)
+ get_record(i)
+ end
+
+ # Returns all the records
+ def records
+ @points
+ end
+
+ # Return the GPX file as LineString
+ def as_line_string
+ GeoRuby::SimpleFeatures::LineString.from_points(@points)
+ end
+ alias_method :as_polyline, :as_line_string
+
+ # Return the GPX file as a Polygon
+ # If the GPX isn't closed, a line from the first
+ # to the last point will be created to close it.
+ def as_polygon
+ GeoRuby::SimpleFeatures::Polygon.from_points([@points[0] == @points[-1] ? @points : @points.push(@points[0].clone)])
+ end
+
+ # Return GPX Envelope
+ def envelope
+ @envelope ||= as_polygon.envelope
+ end
+
+ private
+
+ def get_record(i)
+ @points[i]
+ end
+
+ # wpt => waypoint => TODO?
+ # rte(pt) => route
+ # trk(pt) => track /
+ def parse_file(with_z, with_m)
+ data = @gpx.read
+ @file_mode = data =~ /trkpt/ ? '//trkpt' : (data =~ /wpt/ ? '//wpt' : '//rtept')
+ Nokogiri.HTML(data).search(@file_mode).each do |tp|
+ z = z.inner_text.to_f if with_z && z = tp.at('ele')
+ m = m.inner_text if with_m && m = tp.at('time')
+ @points << GeoRuby::SimpleFeatures::Point.from_coordinates([tp['lon'].to_f, tp['lat'].to_f, z, m], 4326, with_z, with_m)
+ end
+ close
+ @record_count = @points.length
+ envelope
+ rescue => e
+ raise MalformedGpxException.new("Bad GPX. Error: #{e}")
+ # trackpoint.at("gpxdata:hr").nil? # heartrate
+ end
+ end
+
+ class MalformedGpxException < StandardError
+ end
+ end
+end