Class: GPX::Segment
Overview
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 instance of Segment knows its highest point, lowest point, earliest and latest points, distance, and bounds.
Instance Attribute Summary collapse
-
#bounds ⇒ Object
readonly
Returns the value of attribute bounds.
-
#distance ⇒ Object
readonly
Returns the value of attribute distance.
-
#duration ⇒ Object
readonly
Returns the value of attribute duration.
-
#earliest_point ⇒ Object
readonly
Returns the value of attribute earliest_point.
-
#highest_point ⇒ Object
readonly
Returns the value of attribute highest_point.
-
#latest_point ⇒ Object
readonly
Returns the value of attribute latest_point.
-
#lowest_point ⇒ Object
readonly
Returns the value of attribute lowest_point.
-
#points ⇒ Object
Returns the value of attribute points.
-
#track ⇒ Object
Returns the value of attribute track.
Instance Method Summary collapse
-
#append_point(pt) ⇒ Object
Tack on a point to this Segment.
-
#closest_point(time) ⇒ Object
Finds the closest point in time to the passed-in time argument.
-
#contains_time?(time) ⇒ Boolean
Returns true if the given time is within this Segment.
-
#crop(area) ⇒ Object
Deletes all points within this Segment that lie outside of the given area (which should be a Bounds object).
-
#delete_area(area) ⇒ Object
Deletes all points in this Segment that lie within the given area.
-
#delete_if ⇒ Object
A handy method that deletes points based on a block that is passed in.
-
#empty? ⇒ Boolean
Returns true if this Segment has no points.
- #find_point_by_time_or_offset(indicator) ⇒ Object
-
#initialize(opts = {}) ⇒ Segment
constructor
If a XML::Node object is passed-in, this will initialize a new Segment based on its contents.
-
#smooth_location_by_average(opts = {}) ⇒ Object
smooths the location data in the segment (by recalculating the location as an average of 20 neighbouring points. Useful for removing noise from GPS traces..
-
#to_s ⇒ Object
Prints out a nice summary of this Segment.
Methods inherited from Base
#instantiate_with_text_elements
Constructor Details
#initialize(opts = {}) ⇒ Segment
If a XML::Node object is passed-in, this will initialize a new Segment based on its contents. Otherwise, a blank Segment is created.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/gpx/segment.rb', line 14 def initialize(opts = {}) super() @gpx_file = opts[:gpx_file] @track = opts[:track] @points = [] @earliest_point = nil @latest_point = nil @highest_point = nil @lowest_point = nil @distance = 0.0 @duration = 0.0 @bounds = Bounds.new segment_element = opts[:element] return unless segment_element.is_a?(Nokogiri::XML::Node) segment_element.search('trkpt').each do |trkpt| pt = TrackPoint.new(element: trkpt, segment: self, gpx_file: @gpx_file) append_point(pt) end end |
Instance Attribute Details
#bounds ⇒ Object (readonly)
Returns the value of attribute bounds.
9 10 11 |
# File 'lib/gpx/segment.rb', line 9 def bounds @bounds end |
#distance ⇒ Object (readonly)
Returns the value of attribute distance.
9 10 11 |
# File 'lib/gpx/segment.rb', line 9 def distance @distance end |
#duration ⇒ Object (readonly)
Returns the value of attribute duration.
9 10 11 |
# File 'lib/gpx/segment.rb', line 9 def duration @duration end |
#earliest_point ⇒ Object (readonly)
Returns the value of attribute earliest_point.
9 10 11 |
# File 'lib/gpx/segment.rb', line 9 def earliest_point @earliest_point end |
#highest_point ⇒ Object (readonly)
Returns the value of attribute highest_point.
9 10 11 |
# File 'lib/gpx/segment.rb', line 9 def highest_point @highest_point end |
#latest_point ⇒ Object (readonly)
Returns the value of attribute latest_point.
9 10 11 |
# File 'lib/gpx/segment.rb', line 9 def latest_point @latest_point end |
#lowest_point ⇒ Object (readonly)
Returns the value of attribute lowest_point.
9 10 11 |
# File 'lib/gpx/segment.rb', line 9 def lowest_point @lowest_point end |
#points ⇒ Object
Returns the value of attribute points.
10 11 12 |
# File 'lib/gpx/segment.rb', line 10 def points @points end |
#track ⇒ Object
Returns the value of attribute track.
10 11 12 |
# File 'lib/gpx/segment.rb', line 10 def track @track end |
Instance Method Details
#append_point(pt) ⇒ Object
Tack on a point to this Segment. All meta-data will be updated.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/gpx/segment.rb', line 37 def append_point(pt) last_pt = @points[-1] if pt.time @earliest_point = pt if @earliest_point.nil? || (@earliest_point.time && pt.time < @earliest_point.time) @latest_point = pt if @latest_point.nil? || (@latest_point.time && pt.time > @latest_point.time) else # when no time information in data, we consider the points are ordered @earliest_point = @points[0] @latest_point = pt end if pt.elevation @lowest_point = pt if @lowest_point.nil? || (pt.elevation < @lowest_point.elevation) @highest_point = pt if @highest_point.nil? || (pt.elevation > @highest_point.elevation) end @bounds.min_lat = pt.lat if pt.lat < @bounds.min_lat @bounds.min_lon = pt.lon if pt.lon < @bounds.min_lon @bounds.max_lat = pt.lat if pt.lat > @bounds.max_lat @bounds.max_lon = pt.lon if pt.lon > @bounds.max_lon if last_pt @distance += haversine_distance(last_pt, pt) @duration += pt.time - last_pt.time if pt.time && last_pt.time end @points << pt end |
#closest_point(time) ⇒ Object
Finds the closest point in time to the passed-in time argument. Useful for matching up time-based objects (photos, video, etc) with a geographic location.
73 74 75 |
# File 'lib/gpx/segment.rb', line 73 def closest_point(time) find_closest(points, time) end |
#contains_time?(time) ⇒ Boolean
Returns true if the given time is within this Segment.
64 65 66 67 68 |
# File 'lib/gpx/segment.rb', line 64 def contains_time?(time) (time >= @earliest_point.time) && (time <= @latest_point.time) rescue StandardError false end |
#crop(area) ⇒ Object
Deletes all points within this Segment that lie outside of the given area (which should be a Bounds object).
79 80 81 |
# File 'lib/gpx/segment.rb', line 79 def crop(area) delete_if { |pt| !area.contains?(pt) } end |
#delete_area(area) ⇒ Object
Deletes all points in this Segment that lie within the given area.
84 85 86 |
# File 'lib/gpx/segment.rb', line 84 def delete_area(area) delete_if { |pt| area.contains?(pt) } end |
#delete_if ⇒ Object
A handy method that deletes points based on a block that is passed in. If the passed-in block returns true when given a point, then that point is deleted. For example:
delete_if{ |pt| area.contains?(pt) }
92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/gpx/segment.rb', line 92 def delete_if keep_points = [] last_pt = nil points.each do |pt| next if yield(pt) keep_points << pt (pt, last_pt) last_pt = pt end @points = keep_points end |
#empty? ⇒ Boolean
Returns true if this Segment has no points.
107 108 109 |
# File 'lib/gpx/segment.rb', line 107 def empty? points.nil? || points.empty? end |
#find_point_by_time_or_offset(indicator) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/gpx/segment.rb', line 124 def find_point_by_time_or_offset(indicator) if indicator.nil? nil elsif indicator.is_a?(Integer) closest_point(@earliest_point.time + indicator) elsif indicator.is_a?(Time) closest_point(indicator) else raise ArgumentError, 'find_end_point_by_time_or_offset requires an argument of type Time or Integer' end end |
#smooth_location_by_average(opts = {}) ⇒ Object
smooths the location data in the segment (by recalculating the location as an average of 20 neighbouring points. Useful for removing noise from GPS traces.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/gpx/segment.rb', line 137 def smooth_location_by_average(opts = {}) seconds_either_side = opts[:averaging_window] || 20 # calculate the first and last points to which the smoothing should be applied earliest = (find_point_by_time_or_offset(opts[:start]) || @earliest_point).time latest = (find_point_by_time_or_offset(opts[:end]) || @latest_point).time tmp_points = [] @points.each do |point| if point.time > latest || point.time < earliest tmp_points.push point # add the point unaltered next end lat_av = 0.to_f lon_av = 0.to_f alt_av = 0.to_f n = 0 # k ranges from the time of the current point +/- 20s (-1 * seconds_either_side..seconds_either_side).each do |k| # find the point nearest to the time offset indicated by k contributing_point = closest_point(point.time + k) # sum up the contributions to the average lat_av += contributing_point.lat lon_av += contributing_point.lon alt_av += contributing_point.elevation n += 1 end # calculate the averages tmp_point = point.clone tmp_point.lon = (lon_av / n).round(7) tmp_point.elevation = (alt_av / n).round(2) tmp_point.lat = (lat_av / n).round(7) tmp_points.push tmp_point end @points.clear # now commit the averages back and recalculate the distances tmp_points.each do |point| append_point(point) end end |
#to_s ⇒ Object
Prints out a nice summary of this Segment.
112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/gpx/segment.rb', line 112 def to_s result = "Track Segment\n" result << "\tSize: #{points.size} points\n" result << "\tDistance: #{distance} km\n" result << "\tEarliest Point: #{earliest_point.time} \n" result << "\tLatest Point: #{latest_point.time} \n" result << "\tLowest Point: #{lowest_point.elevation} \n" result << "\tHighest Point: #{highest_point.elevation}\n " result << "\tBounds: #{bounds}" result end |