gpx 0.9.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +36 -0
  3. data/.gitignore +4 -0
  4. data/.rubocop.yml +162 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +6 -5
  7. data/CHANGELOG.md +15 -0
  8. data/Gemfile +2 -0
  9. data/LICENSE.txt +1 -1
  10. data/README.md +20 -5
  11. data/Rakefile +22 -12
  12. data/bin/gpx_distance +5 -6
  13. data/bin/gpx_smooth +25 -26
  14. data/gpx.gemspec +13 -12
  15. data/lib/gpx/bounds.rb +13 -31
  16. data/lib/gpx/geo_json.rb +199 -0
  17. data/lib/gpx/gpx.rb +4 -26
  18. data/lib/gpx/gpx_file.rb +140 -134
  19. data/lib/gpx/magellan_track_log.rb +34 -66
  20. data/lib/gpx/point.rb +22 -35
  21. data/lib/gpx/route.rb +10 -31
  22. data/lib/gpx/segment.rb +63 -90
  23. data/lib/gpx/track.rb +38 -42
  24. data/lib/gpx/track_point.rb +32 -0
  25. data/lib/gpx/version.rb +3 -1
  26. data/lib/gpx/waypoint.rb +10 -34
  27. data/lib/gpx.rb +13 -34
  28. data/tests/geojson_files/combined_data.json +68 -0
  29. data/tests/geojson_files/line_string_data.json +83 -0
  30. data/tests/geojson_files/multi_line_string_data.json +74 -0
  31. data/tests/geojson_files/multi_point_data.json +14 -0
  32. data/tests/geojson_files/point_data.json +22 -0
  33. data/tests/geojson_test.rb +92 -0
  34. data/tests/gpx10_test.rb +7 -6
  35. data/tests/gpx_file_test.rb +31 -19
  36. data/tests/gpx_files/one_segment_mixed_times.gpx +884 -0
  37. data/tests/gpx_files/routes_without_names.gpx +29 -0
  38. data/tests/gpx_files/with_empty_tracks.gpx +72 -0
  39. data/tests/magellan_test.rb +12 -11
  40. data/tests/output_test.rb +93 -94
  41. data/tests/route_test.rb +75 -30
  42. data/tests/segment_test.rb +104 -93
  43. data/tests/track_file_test.rb +50 -70
  44. data/tests/track_point_test.rb +22 -11
  45. data/tests/track_test.rb +73 -61
  46. data/tests/waypoint_test.rb +46 -48
  47. metadata +47 -18
  48. data/lib/gpx/trackpoint.rb +0 -60
data/lib/gpx/track.rb CHANGED
@@ -1,25 +1,5 @@
1
- #--
2
- # Copyright (c) 2006 Doug Fales
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
1
+ # frozen_string_literal: true
2
+
23
3
  module GPX
24
4
  # In GPX, a single Track can hold multiple Segments, each of which hold
25
5
  # multiple points (in this library, those points are instances of
@@ -34,28 +14,45 @@ module GPX
34
14
  # Initialize a track from a XML::Node, or, if no :element option is
35
15
  # passed, initialize a blank Track object.
36
16
  def initialize(opts = {})
17
+ super()
37
18
  @gpx_file = opts[:gpx_file]
38
19
  @segments = []
39
20
  @points = []
40
21
  reset_meta_data
41
- if(opts[:element])
42
- trk_element = opts[:element]
43
- @name = (trk_element.at("name").inner_text rescue "")
44
- @comment = (trk_element.at('cmt').inner_text rescue '')
45
- @description = (trk_element.at('desc').inner_text rescue '')
46
- trk_element.search("trkseg").each do |seg_element|
47
- seg = Segment.new(:element => seg_element, :track => self, :gpx_file => @gpx_file)
48
- update_meta_data(seg)
49
- @segments << seg
50
- end
22
+
23
+ return unless opts[:element]
24
+
25
+ trk_element = opts[:element]
26
+ @name = (
27
+ begin
28
+ trk_element.at('name').inner_text
29
+ rescue StandardError
30
+ ''
31
+ end)
32
+ @comment = (
33
+ begin
34
+ trk_element.at('cmt').inner_text
35
+ rescue StandardError
36
+ ''
37
+ end)
38
+ @description = (
39
+ begin
40
+ trk_element.at('desc').inner_text
41
+ rescue StandardError
42
+ ''
43
+ end)
44
+ trk_element.search('trkseg').each do |seg_element|
45
+ seg = Segment.new(element: seg_element, track: self, gpx_file: @gpx_file)
46
+ append_segment(seg)
51
47
  end
52
48
  end
53
49
 
54
50
  # Append a segment to this track, updating its meta data along the way.
55
51
  def append_segment(seg)
52
+ return if seg.points.empty?
53
+
56
54
  update_meta_data(seg)
57
55
  @segments << seg
58
- @points.concat(seg.points) unless seg.nil?
59
56
  end
60
57
 
61
58
  # Returns true if the given time occurs within any of the segments of this track.
@@ -63,7 +60,7 @@ module GPX
63
60
  segments.each do |seg|
64
61
  return true if seg.contains_time?(time)
65
62
  end
66
- return false
63
+ false
67
64
  end
68
65
 
69
66
  # Finds the closest point (to "time") within this track. Useful for
@@ -82,7 +79,7 @@ module GPX
82
79
  seg.crop(area)
83
80
  update_meta_data(seg) unless seg.empty?
84
81
  end
85
- segments.delete_if { |seg| seg.empty? }
82
+ segments.delete_if(&:empty?)
86
83
  end
87
84
 
88
85
  # Deletes all points within a given area and updates the meta data.
@@ -92,13 +89,13 @@ module GPX
92
89
  seg.delete_area(area)
93
90
  update_meta_data(seg) unless seg.empty?
94
91
  end
95
- segments.delete_if { |seg| seg.empty? }
92
+ segments.delete_if(&:empty?)
96
93
  end
97
94
 
98
95
  # Returns true if this track has no points in it. This should return
99
96
  # true even when the track has empty segments.
100
97
  def empty?
101
- (points.nil? or points.size.zero?)
98
+ (points.nil? || points.empty?)
102
99
  end
103
100
 
104
101
  # Prints out a friendly summary of this track (sans points). Useful for
@@ -115,7 +112,7 @@ module GPX
115
112
  result << "\tMoving duration: #{moving_duration} km\n"
116
113
  result << "\tLowest Point: #{lowest_point.elevation} \n"
117
114
  result << "\tHighest Point: #{highest_point.elevation}\n "
118
- result << "\tBounds: #{bounds.to_s}"
115
+ result << "\tBounds: #{bounds}"
119
116
  result
120
117
  end
121
118
 
@@ -125,12 +122,12 @@ module GPX
125
122
  @distance += seg.distance
126
123
  end
127
124
  end
128
-
125
+
129
126
  protected
130
127
 
131
128
  def update_meta_data(seg)
132
- @lowest_point = seg.lowest_point if(@lowest_point.nil? or seg.lowest_point.elevation < @lowest_point.elevation)
133
- @highest_point = seg.highest_point if(@highest_point.nil? or seg.highest_point.elevation > @highest_point.elevation)
129
+ @lowest_point = seg.lowest_point if @lowest_point.nil? || (seg.lowest_point.elevation < @lowest_point.elevation)
130
+ @highest_point = seg.highest_point if @highest_point.nil? || (seg.highest_point.elevation > @highest_point.elevation)
134
131
  @bounds.add(seg.bounds)
135
132
  @distance += seg.distance
136
133
  @moving_duration += seg.duration
@@ -145,6 +142,5 @@ module GPX
145
142
  @moving_duration = 0.0
146
143
  @points = []
147
144
  end
148
-
149
145
  end
150
146
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GPX
4
+ # Basically the same as a point, the TrackPoint class is supposed to
5
+ # represent the points that are children of Segment elements. So, the only
6
+ # real difference is that TrackPoints hold a reference to their parent
7
+ # Segments.
8
+ class TrackPoint < Point
9
+ RADIUS = 6371 # earth's mean radius in km
10
+
11
+ attr_accessor :segment
12
+
13
+ def initialize(opts = {})
14
+ super(opts)
15
+ @segment = opts[:segment]
16
+ end
17
+
18
+ # Units are in km
19
+ def haversine_distance_from(p2)
20
+ d_lat = p2.latr - latr
21
+ d_lon = p2.lonr - lonr
22
+ a = Math.sin(d_lat / 2) * Math.sin(d_lat / 2) + Math.cos(latr) * Math.cos(p2.latr) * Math.sin(d_lon / 2) * Math.sin(d_lon / 2)
23
+ c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
24
+ RADIUS * c
25
+ end
26
+
27
+ # Units are in km
28
+ def law_of_cosines_distance_from(p2)
29
+ Math.acos(Math.sin(latr) * Math.sin(p2.latr) + Math.cos(latr) * Math.cos(p2.latr) * Math.cos(p2.lonr - lonr)) * RADIUS
30
+ end
31
+ end
32
+ end
data/lib/gpx/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GPX
2
- VERSION = "0.9.0"
4
+ VERSION = "1.1.0"
3
5
  end
data/lib/gpx/waypoint.rb CHANGED
@@ -1,56 +1,32 @@
1
- #--
2
- # Copyright (c) 2006 Doug Fales
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
1
+ # frozen_string_literal: true
2
+
23
3
  module GPX
24
4
  # This class supports the concept of a waypoint. Beware that this class has
25
5
  # not seen much use yet, since WalkingBoss does not use waypoints right now.
26
6
  class Waypoint < Point
27
-
28
- SUB_ELEMENTS = %w{ele magvar geoidheight name cmt desc src link sym type fix sat hdop vdop pdop ageofdgpsdata dgpsid extensions}
7
+ SUB_ELEMENTS = %w[ele magvar geoidheight name cmt desc src link sym type fix sat hdop vdop pdop ageofdgpsdata dgpsid extensions].freeze
29
8
 
30
9
  attr_reader :gpx_file
10
+
31
11
  SUB_ELEMENTS.each { |sub_el| attr_accessor sub_el.to_sym }
32
12
 
33
13
  # Not implemented
34
- def crop(area)
35
- end
14
+ def crop(area); end
36
15
 
37
16
  # Not implemented
38
- def delete_area(area)
39
- end
17
+ def delete_area(area); end
40
18
 
41
19
  # Initializes a waypoint from a XML::Node.
42
20
  def initialize(opts = {})
43
- if(opts[:element] and opts[:gpx_file])
21
+ if opts[:element] && opts[:gpx_file]
44
22
  wpt_elem = opts[:element]
45
23
  @gpx_file = opts[:gpx_file]
46
- super(:element => wpt_elem, :gpx_file => @gpx_file)
24
+ super(element: wpt_elem, gpx_file: @gpx_file)
47
25
  instantiate_with_text_elements(wpt_elem, SUB_ELEMENTS)
48
26
  else
49
27
  opts.each do |key, value|
50
28
  assignment_method = "#{key}="
51
- if self.respond_to?(assignment_method)
52
- self.send(assignment_method, value)
53
- end
29
+ send(assignment_method, value) if respond_to?(assignment_method)
54
30
  end
55
31
  end
56
32
  end
@@ -65,7 +41,7 @@ module GPX
65
41
  result << "\tElevation: #{elevation}\n "
66
42
  result << "\tTime: #{time}\n"
67
43
  SUB_ELEMENTS.each do |sub_element_attribute|
68
- val = self.send(sub_element_attribute)
44
+ val = send(sub_element_attribute)
69
45
  result << "\t#{sub_element_attribute}: #{val}\n" unless val.nil?
70
46
  end
71
47
  result
data/lib/gpx.rb CHANGED
@@ -1,38 +1,17 @@
1
- #--
2
- # Copyright (c) 2006 Doug Fales
3
- #
4
- # Permission is hereby granted, free of charge, to any person obtaining
5
- # a copy of this software and associated documentation files (the
6
- # "Software"), to deal in the Software without restriction, including
7
- # without limitation the rights to use, copy, modify, merge, publish,
8
- # distribute, sublicense, and/or sell copies of the Software, and to
9
- # permit persons to whom the Software is furnished to do so, subject to
10
- # the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be
13
- # included in all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #++
1
+ # frozen_string_literal: true
23
2
 
24
3
  require 'time'
25
4
  require 'nokogiri'
26
5
 
27
- require File.expand_path('../gpx/version', __FILE__)
28
-
29
- require File.expand_path('../gpx/gpx', __FILE__)
30
- require File.expand_path('../gpx/gpx_file', __FILE__)
31
- require File.expand_path('../gpx/bounds', __FILE__)
32
- require File.expand_path('../gpx/track', __FILE__)
33
- require File.expand_path('../gpx/route', __FILE__)
34
- require File.expand_path('../gpx/segment', __FILE__)
35
- require File.expand_path('../gpx/point', __FILE__)
36
- require File.expand_path('../gpx/trackpoint', __FILE__)
37
- require File.expand_path('../gpx/waypoint', __FILE__)
38
- require File.expand_path('../gpx/magellan_track_log', __FILE__)
6
+ require File.expand_path('gpx/version', __dir__)
7
+ require File.expand_path('gpx/gpx', __dir__)
8
+ require File.expand_path('gpx/gpx_file', __dir__)
9
+ require File.expand_path('gpx/bounds', __dir__)
10
+ require File.expand_path('gpx/track', __dir__)
11
+ require File.expand_path('gpx/route', __dir__)
12
+ require File.expand_path('gpx/segment', __dir__)
13
+ require File.expand_path('gpx/point', __dir__)
14
+ require File.expand_path('gpx/track_point', __dir__)
15
+ require File.expand_path('gpx/waypoint', __dir__)
16
+ require File.expand_path('gpx/magellan_track_log', __dir__)
17
+ require File.expand_path('gpx/geo_json', __dir__)
@@ -0,0 +1,68 @@
1
+ {
2
+ "type": "FeatureCollection",
3
+ "features": [{
4
+ "type": "Feature",
5
+ "geometry": {
6
+ "type": "LineString",
7
+ "coordinates": [
8
+ [-118.41511, 34.06298, 80],
9
+ [-118.41506, 34.06301, 80],
10
+ [-118.415, 34.06305, 80],
11
+ [-118.41494, 34.06309, 80]
12
+ ]
13
+ }
14
+ }, {
15
+ "type": "Feature",
16
+ "geometry": {
17
+ "type": "LineString",
18
+ "coordinates": [
19
+ [-118.3689, 34.05826, 40],
20
+ [-118.36894, 34.05818, 40],
21
+ [-118.369, 34.05806, 40]
22
+ ]
23
+ }
24
+ }, {
25
+ "type": "Feature",
26
+ "geometry": {
27
+ "type": "LineString",
28
+ "coordinates": [
29
+ [-118.35042, 34.03788, 30],
30
+ [-118.35046, 34.03779, 30]
31
+ ]
32
+ }
33
+ }, {
34
+ "type": "Feature",
35
+ "geometry": {
36
+ "type": "MultiLineString",
37
+ "coordinates": [
38
+ [
39
+ [-118.41511, 34.06298, 80],
40
+ [-118.41506, 34.06301, 80],
41
+ [-118.415, 34.06305, 80],
42
+ [-118.41494, 34.06309, 80]
43
+ ],
44
+ [
45
+ [-118.3689, 34.05826, 40],
46
+ [-118.36894, 34.05818, 40],
47
+ [-118.369, 34.05806, 40]
48
+ ]
49
+ ]
50
+ }
51
+ }, {
52
+ "type": "Feature",
53
+ "geometry": {
54
+ "type": "Point",
55
+ "coordinates": [-118.41585, 34.06253, 80]
56
+ }
57
+ }, {
58
+ "type": "Feature",
59
+ "geometry": {
60
+ "type": "MultiPoint",
61
+ "coordinates": [
62
+ [-118.41585, 34.06253, 80],
63
+ [-118.4158, 34.06256, 80],
64
+ [-118.41575, 34.06259, 80]
65
+ ]
66
+ }
67
+ }]
68
+ }
@@ -0,0 +1,83 @@
1
+ {
2
+ "type": "FeatureCollection",
3
+ "features": [{
4
+ "type": "Feature",
5
+ "geometry": {
6
+ "type": "LineString",
7
+ "coordinates": [
8
+ [-118.41585, 34.06253, 80],
9
+ [-118.4158, 34.06256, 80],
10
+ [-118.41575, 34.06259, 80],
11
+ [-118.4157, 34.06262, 80],
12
+ [-118.41566, 34.06265, 80],
13
+ [-118.41561, 34.06268, 80],
14
+ [-118.41556, 34.06271, 80],
15
+ [-118.41551, 34.06274, 80],
16
+ [-118.41546, 34.06277, 80],
17
+ [-118.41541, 34.0628, 80],
18
+ [-118.41536, 34.06283, 80],
19
+ [-118.41531, 34.06286, 80],
20
+ [-118.41526, 34.06289, 80],
21
+ [-118.41521, 34.06292, 80],
22
+ [-118.41516, 34.06295, 80],
23
+ [-118.41511, 34.06298, 80],
24
+ [-118.41506, 34.06301, 80],
25
+ [-118.415, 34.06305, 80],
26
+ [-118.41494, 34.06309, 80]
27
+ ]
28
+ }
29
+ }, {
30
+ "type": "Feature",
31
+ "geometry": {
32
+ "type": "LineString",
33
+ "coordinates": [
34
+ [-118.36855, 34.05844, 40],
35
+ [-118.36849, 34.05843, 40],
36
+ [-118.36843, 34.05842, 40],
37
+ [-118.36837, 34.05841, 40],
38
+ [-118.36906, 34.05878, 40],
39
+ [-118.36895, 34.05877, 40],
40
+ [-118.36884, 34.05876, 40],
41
+ [-118.36873, 34.05875, 40],
42
+ [-118.36866, 34.05874, 40],
43
+ [-118.3687, 34.05866, 40],
44
+ [-118.36874, 34.05858, 40],
45
+ [-118.36878, 34.0585, 40],
46
+ [-118.36882, 34.05842, 40],
47
+ [-118.36886, 34.05834, 40],
48
+ [-118.3689, 34.05826, 40],
49
+ [-118.36894, 34.05818, 40],
50
+ [-118.369, 34.05806, 40]
51
+ ]
52
+ }
53
+ }, {
54
+ "type": "Feature",
55
+ "geometry": {
56
+ "type": "LineString",
57
+ "coordinates": [
58
+ [-118.35043, 34.0392, 30],
59
+ [-118.35047, 34.03911, 30],
60
+ [-118.35051, 34.03902, 30],
61
+ [-118.35055, 34.03893, 30],
62
+ [-118.35057, 34.03887, 30],
63
+ [-118.35045, 34.03885, 30],
64
+ [-118.35033, 34.03883, 30],
65
+ [-118.35021, 34.03881, 30],
66
+ [-118.35009, 34.03879, 30],
67
+ [-118.35002, 34.03878, 30],
68
+ [-118.35006, 34.03869, 30],
69
+ [-118.3501, 34.0386, 30],
70
+ [-118.35014, 34.03851, 30],
71
+ [-118.35018, 34.03842, 30],
72
+ [-118.35022, 34.03833, 30],
73
+ [-118.35026, 34.03824, 30],
74
+ [-118.3503, 34.03815, 30],
75
+ [-118.35034, 34.03806, 30],
76
+ [-118.35038, 34.03797, 30],
77
+ [-118.35042, 34.03788, 30],
78
+ [-118.35046, 34.03779, 30],
79
+ [-118.3505, 34.03768, 30]
80
+ ]
81
+ }
82
+ }]
83
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "type": "FeatureCollection",
3
+ "features": [{
4
+ "type": "Feature",
5
+ "geometry": {
6
+ "type": "MultiLineString",
7
+ "coordinates": [
8
+ [
9
+ [-118.41585, 34.06253, 80],
10
+ [-118.4158, 34.06256, 80],
11
+ [-118.41575, 34.06259, 80],
12
+ [-118.4157, 34.06262, 80],
13
+ [-118.41566, 34.06265, 80],
14
+ [-118.41561, 34.06268, 80],
15
+ [-118.41556, 34.06271, 80],
16
+ [-118.41551, 34.06274, 80],
17
+ [-118.41546, 34.06277, 80],
18
+ [-118.41541, 34.0628, 80],
19
+ [-118.41536, 34.06283, 80],
20
+ [-118.41531, 34.06286, 80],
21
+ [-118.41526, 34.06289, 80],
22
+ [-118.41521, 34.06292, 80],
23
+ [-118.41516, 34.06295, 80],
24
+ [-118.41511, 34.06298, 80],
25
+ [-118.41506, 34.06301, 80],
26
+ [-118.415, 34.06305, 80],
27
+ [-118.41494, 34.06309, 80]
28
+ ],
29
+ [
30
+ [-118.36855, 34.05844, 40],
31
+ [-118.36849, 34.05843, 40],
32
+ [-118.36843, 34.05842, 40],
33
+ [-118.36837, 34.05841, 40],
34
+ [-118.36906, 34.05878, 40],
35
+ [-118.36895, 34.05877, 40],
36
+ [-118.36884, 34.05876, 40],
37
+ [-118.36873, 34.05875, 40],
38
+ [-118.36866, 34.05874, 40],
39
+ [-118.3687, 34.05866, 40],
40
+ [-118.36874, 34.05858, 40],
41
+ [-118.36878, 34.0585, 40],
42
+ [-118.36882, 34.05842, 40],
43
+ [-118.36886, 34.05834, 40],
44
+ [-118.3689, 34.05826, 40],
45
+ [-118.36894, 34.05818, 40],
46
+ [-118.369, 34.05806, 40]
47
+ ],
48
+ [
49
+ [-118.35043, 34.0392, 30],
50
+ [-118.35047, 34.03911, 30],
51
+ [-118.35051, 34.03902, 30],
52
+ [-118.35055, 34.03893, 30],
53
+ [-118.35057, 34.03887, 30],
54
+ [-118.35045, 34.03885, 30],
55
+ [-118.35033, 34.03883, 30],
56
+ [-118.35021, 34.03881, 30],
57
+ [-118.35009, 34.03879, 30],
58
+ [-118.35002, 34.03878, 30],
59
+ [-118.35006, 34.03869, 30],
60
+ [-118.3501, 34.0386, 30],
61
+ [-118.35014, 34.03851, 30],
62
+ [-118.35018, 34.03842, 30],
63
+ [-118.35022, 34.03833, 30],
64
+ [-118.35026, 34.03824, 30],
65
+ [-118.3503, 34.03815, 30],
66
+ [-118.35034, 34.03806, 30],
67
+ [-118.35038, 34.03797, 30],
68
+ [-118.35042, 34.03788, 30],
69
+ [-118.35046, 34.03779, 30],
70
+ [-118.3505, 34.03768, 30]
71
+ ]]
72
+ }
73
+ }]
74
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "type": "FeatureCollection",
3
+ "features": [{
4
+ "type": "Feature",
5
+ "geometry": {
6
+ "type": "MultiPoint",
7
+ "coordinates": [
8
+ [-118.41585, 34.06253, 80],
9
+ [-118.4158, 34.06256, 80],
10
+ [-118.41575, 34.06259, 80]
11
+ ]
12
+ }
13
+ }]
14
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "type": "FeatureCollection",
3
+ "features": [{
4
+ "type": "Feature",
5
+ "geometry": {
6
+ "type": "Point",
7
+ "coordinates": [-118.41585, 34.06253, 80]
8
+ }
9
+ }, {
10
+ "type": "Feature",
11
+ "geometry": {
12
+ "type": "Point",
13
+ "coordinates": [-118.36855, 34.05844, 40]
14
+ }
15
+ }, {
16
+ "type": "Feature",
17
+ "geometry": {
18
+ "type": "Point",
19
+ "coordinates": [-118.35043, 34.0392, 30]
20
+ }
21
+ }]
22
+ }
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'gpx'
5
+ require 'json'
6
+
7
+ class GeojsonTest < Minitest::Test
8
+ # Test passing a file name
9
+ def test_geojson_file_name_as_param
10
+ file_name = "#{File.dirname(__FILE__)}/geojson_files/line_string_data.json"
11
+ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file_name)
12
+ assert_equal(1, gpx_file.tracks.size)
13
+ end
14
+
15
+ # Test passing a file
16
+ def test_geojson_file_as_param
17
+ file_name = "#{File.dirname(__FILE__)}/geojson_files/line_string_data.json"
18
+ file = File.new(file_name, 'r')
19
+ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
20
+ assert_equal(1, gpx_file.tracks.size)
21
+ end
22
+
23
+ def test_raises_arg_error_when_no_params
24
+ assert_raises(ArgumentError) do
25
+ GPX::GeoJSON.convert_to_gpx
26
+ end
27
+ end
28
+
29
+ # Test that lat/lon allocated correctly
30
+ def test_point_to_waypoint
31
+ pt = [-118, 34]
32
+ waypoint = GPX::GeoJSON.send(:point_to_waypoint, pt, nil)
33
+ assert_equal(34, waypoint.lat)
34
+ assert_equal(-118, waypoint.lon)
35
+ end
36
+
37
+ # Test that lat/lon allocated correctly
38
+ def test_point_to_trackpoint
39
+ pt = [-118, 34]
40
+ waypoint = GPX::GeoJSON.send(:point_to_track_point, pt, nil)
41
+ assert_equal(34, waypoint.lat)
42
+ assert_equal(-118, waypoint.lon)
43
+ end
44
+
45
+ def test_line_string_functionality
46
+ file = File.join(File.dirname(__FILE__), 'geojson_files/line_string_data.json')
47
+ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
48
+
49
+ assert_equal(1, gpx_file.tracks.size)
50
+ assert_equal(3, gpx_file.tracks.first.segments.size)
51
+ pts_size = gpx_file.tracks.first.segments[0].points.size +
52
+ gpx_file.tracks.first.segments[1].points.size +
53
+ gpx_file.tracks.first.segments[2].points.size
54
+ assert_equal(58, pts_size)
55
+ end
56
+
57
+ def test_multi_line_string_functionality
58
+ file = File.join(File.dirname(__FILE__), 'geojson_files/multi_line_string_data.json')
59
+ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
60
+ assert_equal(1, gpx_file.tracks.size)
61
+ assert_equal(3, gpx_file.tracks.first.segments.size)
62
+ pts_size = gpx_file.tracks.first.segments[0].points.size +
63
+ gpx_file.tracks.first.segments[1].points.size +
64
+ gpx_file.tracks.first.segments[2].points.size
65
+ assert_equal(58, pts_size)
66
+ end
67
+
68
+ def test_point_functionality
69
+ file = File.join(File.dirname(__FILE__), 'geojson_files/point_data.json')
70
+ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
71
+ assert_equal(3, gpx_file.waypoints.size)
72
+ end
73
+
74
+ def test_multi_point_functionality
75
+ file = File.join(File.dirname(__FILE__), 'geojson_files/multi_point_data.json')
76
+ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
77
+ assert_equal(3, gpx_file.waypoints.size)
78
+ end
79
+
80
+ def test_combined_functionality
81
+ file = File.join(File.dirname(__FILE__), 'geojson_files/combined_data.json')
82
+ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
83
+
84
+ # 1 for all LineStrings, 1 for MultiLineString
85
+ assert_equal(2, gpx_file.tracks.size)
86
+ assert_equal(3, gpx_file.tracks.first.segments.size)
87
+ assert_equal(2, gpx_file.tracks.last.segments.size)
88
+ pt_sum = gpx_file.tracks.inject(0) { |sum, trk| sum + trk.points.size }
89
+ assert_equal(16, pt_sum)
90
+ assert_equal(4, gpx_file.waypoints.size)
91
+ end
92
+ end