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.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +36 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +162 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -5
- data/CHANGELOG.md +15 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +20 -5
- data/Rakefile +22 -12
- data/bin/gpx_distance +5 -6
- data/bin/gpx_smooth +25 -26
- data/gpx.gemspec +13 -12
- data/lib/gpx/bounds.rb +13 -31
- data/lib/gpx/geo_json.rb +199 -0
- data/lib/gpx/gpx.rb +4 -26
- data/lib/gpx/gpx_file.rb +140 -134
- data/lib/gpx/magellan_track_log.rb +34 -66
- data/lib/gpx/point.rb +22 -35
- data/lib/gpx/route.rb +10 -31
- data/lib/gpx/segment.rb +63 -90
- data/lib/gpx/track.rb +38 -42
- data/lib/gpx/track_point.rb +32 -0
- data/lib/gpx/version.rb +3 -1
- data/lib/gpx/waypoint.rb +10 -34
- data/lib/gpx.rb +13 -34
- data/tests/geojson_files/combined_data.json +68 -0
- data/tests/geojson_files/line_string_data.json +83 -0
- data/tests/geojson_files/multi_line_string_data.json +74 -0
- data/tests/geojson_files/multi_point_data.json +14 -0
- data/tests/geojson_files/point_data.json +22 -0
- data/tests/geojson_test.rb +92 -0
- data/tests/gpx10_test.rb +7 -6
- data/tests/gpx_file_test.rb +31 -19
- data/tests/gpx_files/one_segment_mixed_times.gpx +884 -0
- data/tests/gpx_files/routes_without_names.gpx +29 -0
- data/tests/gpx_files/with_empty_tracks.gpx +72 -0
- data/tests/magellan_test.rb +12 -11
- data/tests/output_test.rb +93 -94
- data/tests/route_test.rb +75 -30
- data/tests/segment_test.rb +104 -93
- data/tests/track_file_test.rb +50 -70
- data/tests/track_point_test.rb +22 -11
- data/tests/track_test.rb +73 -61
- data/tests/waypoint_test.rb +46 -48
- metadata +47 -18
- data/lib/gpx/trackpoint.rb +0 -60
data/lib/gpx/track.rb
CHANGED
@@ -1,25 +1,5 @@
|
|
1
|
-
|
2
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
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
|
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
|
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?
|
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
|
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
|
133
|
-
@highest_point
|
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
data/lib/gpx/waypoint.rb
CHANGED
@@ -1,56 +1,32 @@
|
|
1
|
-
|
2
|
-
|
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
|
21
|
+
if opts[:element] && opts[:gpx_file]
|
44
22
|
wpt_elem = opts[:element]
|
45
23
|
@gpx_file = opts[:gpx_file]
|
46
|
-
super(:
|
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
|
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 =
|
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('
|
28
|
-
|
29
|
-
require File.expand_path('
|
30
|
-
require File.expand_path('
|
31
|
-
require File.expand_path('
|
32
|
-
require File.expand_path('
|
33
|
-
require File.expand_path('
|
34
|
-
require File.expand_path('
|
35
|
-
require File.expand_path('
|
36
|
-
require File.expand_path('
|
37
|
-
require File.expand_path('
|
38
|
-
require File.expand_path('
|
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,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
|