gpx 1.1.0 → 1.1.2
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 +4 -4
- data/.github/workflows/ruby.yml +4 -3
- data/.rubocop +1 -0
- data/.rubocop.yml +4 -1
- data/.ruby-version +1 -1
- data/.tool-versions +1 -0
- data/.travis.yml +1 -3
- data/CHANGELOG.md +14 -1
- data/README.md +34 -7
- data/UPGRADING.md +7 -0
- data/gpx.gemspec +1 -1
- data/lib/gpx/bounds.rb +1 -1
- data/lib/gpx/geo_json.rb +30 -16
- data/lib/gpx/gpx_file.rb +1 -4
- data/lib/gpx/magellan_track_log.rb +1 -1
- data/lib/gpx/route.rb +1 -1
- data/lib/gpx/segment.rb +3 -3
- data/lib/gpx/track.rb +1 -1
- data/lib/gpx/version.rb +1 -1
- data/tests/geojson_files/line_string_data.json +11 -2
- data/tests/geojson_files/multi_line_string_data.json +3 -0
- data/tests/geojson_files/multi_point_data.json +3 -0
- data/tests/geojson_files/point_data.json +9 -0
- data/tests/geojson_test.rb +63 -0
- data/tests/gpx_file_test.rb +34 -29
- metadata +7 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 94b41dda1f7722e6a90e261b66420e08074a953c866f7c4b32947ff41046bbcb
|
|
4
|
+
data.tar.gz: 8aec6ca78168bab0c9ec5dd1d8e689387cfe700aa4b3984639ba9d8f9bcf4095
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 96c15693a26a49344ffb7e552d352fc342ee033af8cf62219295e4b3a3334ee9a3ceb201c168a4fbd079647714e0e10dd8a5653842c5ac1c2ce5442946622063
|
|
7
|
+
data.tar.gz: 9e30c74ad0165287406fa0c322651fd8ab326bdf712f8563097c11451bb7601cc245acc4b74cc5d9d40e059126583ce421df0c4950183bc36833add6f5862db2
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -19,16 +19,17 @@ jobs:
|
|
|
19
19
|
|
|
20
20
|
runs-on: ubuntu-latest
|
|
21
21
|
strategy:
|
|
22
|
+
fail-fast: true
|
|
22
23
|
matrix:
|
|
23
|
-
ruby-version: ['2.7', '3.0', '3.1']
|
|
24
|
+
ruby-version: ['2.7', '3.0', '3.1', '3.2']
|
|
24
25
|
|
|
25
26
|
steps:
|
|
26
|
-
- uses: actions/checkout@
|
|
27
|
+
- uses: actions/checkout@v4
|
|
27
28
|
- name: Set up Ruby
|
|
28
29
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
|
29
30
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
|
30
31
|
# uses: ruby/setup-ruby@v1
|
|
31
|
-
uses: ruby/setup-ruby@
|
|
32
|
+
uses: ruby/setup-ruby@v1.159.0
|
|
32
33
|
with:
|
|
33
34
|
ruby-version: ${{ matrix.ruby-version }}
|
|
34
35
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
data/.rubocop
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--server
|
data/.rubocop.yml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
AllCops:
|
|
2
|
-
TargetRubyVersion: 2.
|
|
2
|
+
TargetRubyVersion: 2.7
|
|
3
3
|
|
|
4
4
|
Style/Alias:
|
|
5
5
|
Enabled: false
|
|
@@ -65,6 +65,9 @@ Style/NegatedWhile:
|
|
|
65
65
|
Enabled: false
|
|
66
66
|
StyleGuide: http://relaxed.ruby.style/#stylenegatedwhile
|
|
67
67
|
|
|
68
|
+
Style/OptionalBooleanParameter:
|
|
69
|
+
Enabled: false
|
|
70
|
+
|
|
68
71
|
Style/ParallelAssignment:
|
|
69
72
|
Enabled: false
|
|
70
73
|
StyleGuide: http://relaxed.ruby.style/#styleparallelassignment
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.2.2
|
data/.tool-versions
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ruby 3.2.2
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
## [1.1.
|
|
1
|
+
## [1.1.2] - 2024-07-26
|
|
2
|
+
|
|
3
|
+
* Adds ability to address various GeoJSON properties when performing GeoJSON to GPX conversion. (#53 via @niborg)
|
|
4
|
+
* Allow anything that responds to `read` for GPXFile input. (#55 via @hiroaki)
|
|
5
|
+
|
|
6
|
+
## [1.1.1] - 2023-05-19
|
|
7
|
+
|
|
8
|
+
* updates CI, minimal Ruby version now 2.7, updates tooling like rubocop and GitHub actions
|
|
9
|
+
* adds support for Ruby 3.2
|
|
10
|
+
* adds UPGRADING.md to document changes between versions
|
|
11
|
+
|
|
12
|
+
## [1.1.0] - 2023-05-18
|
|
13
|
+
|
|
2
14
|
* Specify UTF-8 encoding for XML encoding (#35 via @sh1nduu)
|
|
3
15
|
* Added GeoJSON conversion (#38 via @tyrauber and @niborg)
|
|
4
16
|
* Support Ruby 3 (#43 via @LocoDelAssembly)
|
|
5
17
|
* Fix nil-to-Time comparison (#46 via @frodrigo)
|
|
6
18
|
* Fix bug when <rte> GPX file does not specify <name> tag (#41 via @niborg)
|
|
7
19
|
* Drop Ruby 2.5 and 2.6 from CI (#50 via @niborg)
|
|
20
|
+
|
|
8
21
|
## [1.0.0] - 2018-03-06
|
|
9
22
|
|
|
10
23
|
* Fix duplication of points on appending segment to track (#20 via @niborg)
|
data/README.md
CHANGED
|
@@ -6,25 +6,37 @@
|
|
|
6
6
|
## What It Does
|
|
7
7
|
|
|
8
8
|
This library reads GPX files and provides an API for reading and manipulating
|
|
9
|
-
the data as objects.
|
|
9
|
+
the data as objects. For more info on the GPX format, see
|
|
10
10
|
http://www.topografix.com/gpx.asp.
|
|
11
11
|
|
|
12
12
|
In addition to parsing GPX files, this library is capable of converting
|
|
13
13
|
Magellan NMEA files to GPX, converting GeoJSON data to GPX, and writing
|
|
14
|
-
new GPX files.
|
|
14
|
+
new GPX files. It can crop and delete rectangular areas within a file,
|
|
15
15
|
and it also calculates some meta-data about the tracks and points in a file (such as distance, duration, average speed, etc).
|
|
16
16
|
|
|
17
17
|
## Requirements
|
|
18
18
|
|
|
19
|
-
As of `1.
|
|
19
|
+
- As of `1.1.1`, `gpx` requires at least Ruby 2.7 to run.
|
|
20
|
+
- As of `1.0.0`, `gpx` requires at least Ruby 2.2 to run.
|
|
20
21
|
|
|
21
22
|
## Installation
|
|
23
|
+
|
|
22
24
|
Add to your gemfile:
|
|
25
|
+
|
|
23
26
|
```
|
|
24
27
|
gem 'gpx'
|
|
25
28
|
```
|
|
29
|
+
|
|
26
30
|
## Examples
|
|
27
31
|
|
|
32
|
+
Initialize a `GPXFile` object with either a file-like object or a string representation:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
gpx = GPX::GPXFile.new(:gpx_file => string_io) # Anything that responds to `read`
|
|
36
|
+
gpx = GPX::GPXFile.new(:gpx_file => path_to_a_file)
|
|
37
|
+
gpx = GPX::GPXFile.new(:gpx_data => some_string)
|
|
38
|
+
```
|
|
39
|
+
|
|
28
40
|
Reading a GPX file, and cropping its contents to a given area:
|
|
29
41
|
|
|
30
42
|
```ruby
|
|
@@ -35,6 +47,7 @@ gpx.write(filename) # Save it
|
|
|
35
47
|
```
|
|
36
48
|
|
|
37
49
|
Converting a Magellan track log to GPX:
|
|
50
|
+
|
|
38
51
|
```ruby
|
|
39
52
|
if GPX::MagellanTrackLog::is_magellan_file?(filename)
|
|
40
53
|
GPX::MagellanTrackLog::convert_to_gpx(filename, "#{filename}.gpx")
|
|
@@ -43,6 +56,7 @@ end
|
|
|
43
56
|
|
|
44
57
|
Converting GeoJSON data to GPX can be achieved by providing a
|
|
45
58
|
file path, file, or the data in string format:
|
|
59
|
+
|
|
46
60
|
```ruby
|
|
47
61
|
# Converting from a file name
|
|
48
62
|
gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: 'mygeojsonfile.json')
|
|
@@ -50,9 +64,23 @@ gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: 'mygeojsonfile.json')
|
|
|
50
64
|
# Converting from a string
|
|
51
65
|
data = JSON.generate(my_geojson_hash)
|
|
52
66
|
gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_data: data)
|
|
67
|
+
|
|
68
|
+
# The above won't transfer anything but coordinate values. If you want to
|
|
69
|
+
# transfer ad hoc "properties" information, you can specify an object that
|
|
70
|
+
# responds to `call` to manipulate GPX data structures as follows:
|
|
71
|
+
gpx_file = GPX::GeoJSON.convert_to_gpx(
|
|
72
|
+
geojson_data: data,
|
|
73
|
+
line_string_feature_to_segment: ->(ls, seg) { seg.distance = ls["properties"]["distance"] },
|
|
74
|
+
multi_line_string_feature_to_track: lambda { |mls, track|
|
|
75
|
+
track.name = mls["properties"]["name"]
|
|
76
|
+
},
|
|
77
|
+
point_feature_to_waypoint: ->(pt, wpt) { wpt.name = pt["properties"]["name"] }
|
|
78
|
+
multi_point_feature_to_waypoint: ->(mpt, wpt) { wpt.sym = mpt["properties"]["icon"] }
|
|
79
|
+
)
|
|
53
80
|
```
|
|
54
81
|
|
|
55
82
|
Exporting an ActiveRecord to GPXFile (as Waypoints)
|
|
83
|
+
|
|
56
84
|
```ruby
|
|
57
85
|
#
|
|
58
86
|
# Our active record in this example is called stop
|
|
@@ -97,12 +125,11 @@ Mime::Type.register "application/gpx+xml", :gpx
|
|
|
97
125
|
|
|
98
126
|
You have a complete example on how to create a gpx file from scratch on `tests/output_text.rb`.
|
|
99
127
|
|
|
100
|
-
|
|
101
128
|
## Notes
|
|
102
129
|
|
|
103
130
|
This library was written to bridge the gap between my Garmin Geko
|
|
104
|
-
and my website, WalkingBoss.org (RIP).
|
|
105
|
-
work-in-progress than an attempt at full GPX compliance.
|
|
131
|
+
and my website, WalkingBoss.org (RIP). For that reason, it has always been more of a
|
|
132
|
+
work-in-progress than an attempt at full GPX compliance. The track side of the
|
|
106
133
|
library has seen much more use than the route/waypoint side, so if you're doing
|
|
107
134
|
something with routes or waypoints, you may need to tweak some things.
|
|
108
135
|
|
|
@@ -112,7 +139,7 @@ working with tracks from several days or weeks.
|
|
|
112
139
|
|
|
113
140
|
Finally, it should be noted that none of the distance/speed calculation or
|
|
114
141
|
crop/delete code has been tested under International Date Line-crossing
|
|
115
|
-
conditions.
|
|
142
|
+
conditions. That particular part of the code will likely be unreliable if
|
|
116
143
|
you're zig-zagging across 180 degrees longitude routinely.
|
|
117
144
|
|
|
118
145
|
## License
|
data/UPGRADING.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Upgrading
|
|
2
|
+
|
|
3
|
+
You will find all the information you need to upgrade from one version to another here.
|
|
4
|
+
|
|
5
|
+
## Version 1.0.0 to 1.1.1
|
|
6
|
+
|
|
7
|
+
Please make sure, that you need at least Ruby 2.7.0 to use this gem now. As support for Ruby versions below 2.7.0 has been dropped.
|
data/gpx.gemspec
CHANGED
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
|
12
12
|
s.summary = 'A basic API for reading and writing GPX files.'
|
|
13
13
|
s.description = 'A basic API for reading and writing GPX files.'
|
|
14
14
|
|
|
15
|
-
s.required_ruby_version = '>= 2.
|
|
15
|
+
s.required_ruby_version = '>= 2.7', '< 4'
|
|
16
16
|
|
|
17
17
|
s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
18
18
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
data/lib/gpx/bounds.rb
CHANGED
|
@@ -28,7 +28,7 @@ module GPX
|
|
|
28
28
|
|
|
29
29
|
# Returns true if the pt is within these bounds.
|
|
30
30
|
def contains?(pt)
|
|
31
|
-
(
|
|
31
|
+
(pt.lat >= min_lat) && (pt.lat <= max_lat) && (pt.lon >= min_lon) && (pt.lon <= max_lon)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Adds an item to itself, expanding its min/max lat/lon as needed to
|
data/lib/gpx/geo_json.rb
CHANGED
|
@@ -34,8 +34,8 @@ module GPX
|
|
|
34
34
|
def convert_to_gpx(opts = {})
|
|
35
35
|
geojson = geojson_data_from(opts)
|
|
36
36
|
gpx_file = GPX::GPXFile.new
|
|
37
|
-
add_tracks_to(gpx_file, geojson)
|
|
38
|
-
add_waypoints_to(gpx_file, geojson)
|
|
37
|
+
add_tracks_to(gpx_file, geojson, opts)
|
|
38
|
+
add_waypoints_to(gpx_file, geojson, opts)
|
|
39
39
|
gpx_file
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -61,32 +61,35 @@ module GPX
|
|
|
61
61
|
JSON.parse(data)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
def add_tracks_to(gpx_file, geojson)
|
|
65
|
-
tracks = [line_strings_to_track(geojson)] +
|
|
66
|
-
multi_line_strings_to_tracks(geojson)
|
|
64
|
+
def add_tracks_to(gpx_file, geojson, opts)
|
|
65
|
+
tracks = [line_strings_to_track(geojson, opts)] +
|
|
66
|
+
multi_line_strings_to_tracks(geojson, opts)
|
|
67
67
|
tracks.compact!
|
|
68
68
|
gpx_file.tracks += tracks
|
|
69
69
|
gpx_file.tracks.each { |t| gpx_file.update_meta_data(t) }
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
def add_waypoints_to(gpx_file, geojson)
|
|
72
|
+
def add_waypoints_to(gpx_file, geojson, opts)
|
|
73
73
|
gpx_file.waypoints +=
|
|
74
|
-
points_to_waypoints(geojson, gpx_file) +
|
|
75
|
-
multi_points_to_waypoints(geojson, gpx_file)
|
|
74
|
+
points_to_waypoints(geojson, gpx_file, opts) +
|
|
75
|
+
multi_points_to_waypoints(geojson, gpx_file, opts)
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
# Converts GeoJSON 'LineString' features.
|
|
79
79
|
# Current strategy is to convert each LineString into a
|
|
80
80
|
# Track Segment, returning a Track for all LineStrings.
|
|
81
81
|
#
|
|
82
|
-
def line_strings_to_track(geojson)
|
|
82
|
+
def line_strings_to_track(geojson, opts)
|
|
83
83
|
line_strings = line_strings_in(geojson)
|
|
84
84
|
return nil unless line_strings.any?
|
|
85
85
|
|
|
86
86
|
track = GPX::Track.new
|
|
87
87
|
line_strings.each do |ls|
|
|
88
88
|
coords = ls['geometry']['coordinates']
|
|
89
|
-
|
|
89
|
+
segment = coords_to_segment(coords)
|
|
90
|
+
|
|
91
|
+
opts[:line_string_feature_to_segment]&.call(ls, segment)
|
|
92
|
+
track.append_segment(segment)
|
|
90
93
|
end
|
|
91
94
|
track
|
|
92
95
|
end
|
|
@@ -96,15 +99,18 @@ module GPX
|
|
|
96
99
|
# into a Track, with each set of LineString coordinates
|
|
97
100
|
# within a MultiLineString a Track Segment.
|
|
98
101
|
#
|
|
99
|
-
def multi_line_strings_to_tracks(geojson)
|
|
102
|
+
def multi_line_strings_to_tracks(geojson, opts)
|
|
100
103
|
tracks = []
|
|
101
104
|
multi_line_strings_in(geojson).each do |mls|
|
|
102
105
|
track = GPX::Track.new
|
|
103
106
|
mls['geometry']['coordinates'].each do |coords|
|
|
104
107
|
seg = coords_to_segment(coords)
|
|
105
108
|
seg.track = track
|
|
109
|
+
|
|
106
110
|
track.append_segment(seg)
|
|
107
111
|
end
|
|
112
|
+
|
|
113
|
+
opts[:multi_line_string_feature_to_track]&.call(mls, track)
|
|
108
114
|
tracks << track
|
|
109
115
|
end
|
|
110
116
|
tracks
|
|
@@ -114,10 +120,14 @@ module GPX
|
|
|
114
120
|
# Current strategy is to convert each Point
|
|
115
121
|
# feature into a GPX waypoint.
|
|
116
122
|
#
|
|
117
|
-
def points_to_waypoints(geojson, gpx_file)
|
|
123
|
+
def points_to_waypoints(geojson, gpx_file, opts)
|
|
118
124
|
points_in(geojson).reduce([]) do |acc, pt|
|
|
119
125
|
coords = pt['geometry']['coordinates']
|
|
120
|
-
|
|
126
|
+
waypoint = point_to_waypoint(coords, gpx_file)
|
|
127
|
+
|
|
128
|
+
opts[:point_feature_to_waypoint]&.call(pt, waypoint)
|
|
129
|
+
|
|
130
|
+
acc << waypoint
|
|
121
131
|
end
|
|
122
132
|
end
|
|
123
133
|
|
|
@@ -132,10 +142,14 @@ module GPX
|
|
|
132
142
|
# series of turn points leading to a destination."
|
|
133
143
|
# See http://www.topografix.com/gpx/1/1/#type_rteType
|
|
134
144
|
#
|
|
135
|
-
def multi_points_to_waypoints(geojson, gpx_file)
|
|
136
|
-
multi_points_in(geojson).
|
|
145
|
+
def multi_points_to_waypoints(geojson, gpx_file, opts)
|
|
146
|
+
multi_points_in(geojson).each_with_object([]) do |mpt, acc|
|
|
137
147
|
mpt['geometry']['coordinates'].each do |coords|
|
|
138
|
-
|
|
148
|
+
waypoint = point_to_waypoint(coords, gpx_file)
|
|
149
|
+
|
|
150
|
+
opts[:multi_point_feature_to_waypoint]&.call(mpt, waypoint)
|
|
151
|
+
|
|
152
|
+
acc << waypoint
|
|
139
153
|
end
|
|
140
154
|
end
|
|
141
155
|
end
|
data/lib/gpx/gpx_file.rb
CHANGED
|
@@ -35,7 +35,7 @@ module GPX
|
|
|
35
35
|
if opts[:gpx_file] || opts[:gpx_data]
|
|
36
36
|
if opts[:gpx_file]
|
|
37
37
|
gpx_file = opts[:gpx_file]
|
|
38
|
-
gpx_file = File.open(gpx_file) unless gpx_file.
|
|
38
|
+
gpx_file = File.open(gpx_file) unless gpx_file.respond_to?(:read)
|
|
39
39
|
@xml = Nokogiri::XML(gpx_file)
|
|
40
40
|
else
|
|
41
41
|
@xml = Nokogiri::XML(opts[:gpx_data])
|
|
@@ -194,8 +194,6 @@ module GPX
|
|
|
194
194
|
@moving_duration = 0.0
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
-
# rubocop:disable Style/OptionalBooleanParameter
|
|
198
|
-
|
|
199
197
|
# Updates the meta data for this GPX file. Meta data includes the
|
|
200
198
|
# bounds, the high and low points, and the distance. This is useful when
|
|
201
199
|
# you modify the GPX data (i.e. by adding or deleting points) and you
|
|
@@ -222,7 +220,6 @@ module GPX
|
|
|
222
220
|
doc = generate_xml_doc
|
|
223
221
|
doc.to_xml
|
|
224
222
|
end
|
|
225
|
-
# rubocop:enable Style/OptionalBooleanParameter
|
|
226
223
|
|
|
227
224
|
def inspect
|
|
228
225
|
"<#{self.class.name}:...>"
|
data/lib/gpx/route.rb
CHANGED
data/lib/gpx/segment.rb
CHANGED
|
@@ -62,7 +62,7 @@ module GPX
|
|
|
62
62
|
|
|
63
63
|
# Returns true if the given time is within this Segment.
|
|
64
64
|
def contains_time?(time)
|
|
65
|
-
(
|
|
65
|
+
(time >= @earliest_point.time) && (time <= @latest_point.time)
|
|
66
66
|
rescue StandardError
|
|
67
67
|
false
|
|
68
68
|
end
|
|
@@ -105,7 +105,7 @@ module GPX
|
|
|
105
105
|
|
|
106
106
|
# Returns true if this Segment has no points.
|
|
107
107
|
def empty?
|
|
108
|
-
|
|
108
|
+
points.nil? || points.empty?
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
# Prints out a nice summary of this Segment.
|
|
@@ -193,7 +193,7 @@ module GPX
|
|
|
193
193
|
elsif time <= pts[midpoint].time
|
|
194
194
|
find_closest(pts[0..midpoint], time)
|
|
195
195
|
else
|
|
196
|
-
find_closest(pts[(midpoint + 1)
|
|
196
|
+
find_closest(pts[(midpoint + 1)..], time)
|
|
197
197
|
end
|
|
198
198
|
end
|
|
199
199
|
|
data/lib/gpx/track.rb
CHANGED
|
@@ -95,7 +95,7 @@ module GPX
|
|
|
95
95
|
# Returns true if this track has no points in it. This should return
|
|
96
96
|
# true even when the track has empty segments.
|
|
97
97
|
def empty?
|
|
98
|
-
|
|
98
|
+
points.nil? || points.empty?
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
# Prints out a friendly summary of this track (sans points). Useful for
|
data/lib/gpx/version.rb
CHANGED
|
@@ -24,8 +24,11 @@
|
|
|
24
24
|
[-118.41506, 34.06301, 80],
|
|
25
25
|
[-118.415, 34.06305, 80],
|
|
26
26
|
[-118.41494, 34.06309, 80]
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"properties": {
|
|
30
|
+
"distance": 10
|
|
31
|
+
}
|
|
29
32
|
}, {
|
|
30
33
|
"type": "Feature",
|
|
31
34
|
"geometry": {
|
|
@@ -49,6 +52,9 @@
|
|
|
49
52
|
[-118.36894, 34.05818, 40],
|
|
50
53
|
[-118.369, 34.05806, 40]
|
|
51
54
|
]
|
|
55
|
+
},
|
|
56
|
+
"properties": {
|
|
57
|
+
"distance": 100
|
|
52
58
|
}
|
|
53
59
|
}, {
|
|
54
60
|
"type": "Feature",
|
|
@@ -78,6 +84,9 @@
|
|
|
78
84
|
[-118.35046, 34.03779, 30],
|
|
79
85
|
[-118.3505, 34.03768, 30]
|
|
80
86
|
]
|
|
87
|
+
},
|
|
88
|
+
"properties": {
|
|
89
|
+
"distance": 1000
|
|
81
90
|
}
|
|
82
91
|
}]
|
|
83
92
|
}
|
|
@@ -5,18 +5,27 @@
|
|
|
5
5
|
"geometry": {
|
|
6
6
|
"type": "Point",
|
|
7
7
|
"coordinates": [-118.41585, 34.06253, 80]
|
|
8
|
+
},
|
|
9
|
+
"properties": {
|
|
10
|
+
"name": "Foo"
|
|
8
11
|
}
|
|
9
12
|
}, {
|
|
10
13
|
"type": "Feature",
|
|
11
14
|
"geometry": {
|
|
12
15
|
"type": "Point",
|
|
13
16
|
"coordinates": [-118.36855, 34.05844, 40]
|
|
17
|
+
},
|
|
18
|
+
"properties": {
|
|
19
|
+
"name": "Bar"
|
|
14
20
|
}
|
|
15
21
|
}, {
|
|
16
22
|
"type": "Feature",
|
|
17
23
|
"geometry": {
|
|
18
24
|
"type": "Point",
|
|
19
25
|
"coordinates": [-118.35043, 34.0392, 30]
|
|
26
|
+
},
|
|
27
|
+
"properties": {
|
|
28
|
+
"name": "Baz"
|
|
20
29
|
}
|
|
21
30
|
}]
|
|
22
31
|
}
|
data/tests/geojson_test.rb
CHANGED
|
@@ -54,6 +54,28 @@ class GeojsonTest < Minitest::Test
|
|
|
54
54
|
assert_equal(58, pts_size)
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
+
def test_line_string_functionality_with_lambda
|
|
58
|
+
file = File.join(File.dirname(__FILE__), 'geojson_files/line_string_data.json')
|
|
59
|
+
gpx_file = GPX::GeoJSON.convert_to_gpx(
|
|
60
|
+
geojson_file: file,
|
|
61
|
+
line_string_feature_to_segment: lambda { |line_string, segment|
|
|
62
|
+
segment.points << GPX::Point.new(
|
|
63
|
+
{
|
|
64
|
+
lat: line_string['geometry']['coordinates'][0][1],
|
|
65
|
+
lon: line_string['geometry']['coordinates'][0][0]
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
assert_equal(1, gpx_file.tracks.size)
|
|
72
|
+
assert_equal(3, gpx_file.tracks.first.segments.size)
|
|
73
|
+
pts_size = gpx_file.tracks.first.segments[0].points.size +
|
|
74
|
+
gpx_file.tracks.first.segments[1].points.size +
|
|
75
|
+
gpx_file.tracks.first.segments[2].points.size
|
|
76
|
+
assert_equal(61, pts_size)
|
|
77
|
+
end
|
|
78
|
+
|
|
57
79
|
def test_multi_line_string_functionality
|
|
58
80
|
file = File.join(File.dirname(__FILE__), 'geojson_files/multi_line_string_data.json')
|
|
59
81
|
gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
|
|
@@ -65,18 +87,59 @@ class GeojsonTest < Minitest::Test
|
|
|
65
87
|
assert_equal(58, pts_size)
|
|
66
88
|
end
|
|
67
89
|
|
|
90
|
+
def test_multi_line_string_functionality_with_lambda
|
|
91
|
+
file = File.join(File.dirname(__FILE__), 'geojson_files/multi_line_string_data.json')
|
|
92
|
+
gpx_file = GPX::GeoJSON.convert_to_gpx(
|
|
93
|
+
geojson_file: file,
|
|
94
|
+
multi_line_string_feature_to_track: lambda { |multi_line_string, segment|
|
|
95
|
+
segment.name = multi_line_string['properties']['name']
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
assert_equal(1, gpx_file.tracks.size)
|
|
99
|
+
assert_equal(3, gpx_file.tracks.first.segments.size)
|
|
100
|
+
pts_size = gpx_file.tracks.first.segments[0].points.size +
|
|
101
|
+
gpx_file.tracks.first.segments[1].points.size +
|
|
102
|
+
gpx_file.tracks.first.segments[2].points.size
|
|
103
|
+
assert_equal(58, pts_size)
|
|
104
|
+
assert_equal("Foo", gpx_file.tracks[0].name)
|
|
105
|
+
end
|
|
106
|
+
|
|
68
107
|
def test_point_functionality
|
|
69
108
|
file = File.join(File.dirname(__FILE__), 'geojson_files/point_data.json')
|
|
70
109
|
gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
|
|
71
110
|
assert_equal(3, gpx_file.waypoints.size)
|
|
72
111
|
end
|
|
73
112
|
|
|
113
|
+
def test_point_functionality_with_proc
|
|
114
|
+
file = File.join(File.dirname(__FILE__), 'geojson_files/point_data.json')
|
|
115
|
+
gpx_file = GPX::GeoJSON.convert_to_gpx(
|
|
116
|
+
geojson_file: file,
|
|
117
|
+
point_feature_to_waypoint: ->(point, waypoint) { waypoint.name = point['properties']['name'] }
|
|
118
|
+
)
|
|
119
|
+
assert_equal(3, gpx_file.waypoints.size)
|
|
120
|
+
assert_equal('Foo', gpx_file.waypoints[0].name)
|
|
121
|
+
assert_equal('Bar', gpx_file.waypoints[1].name)
|
|
122
|
+
assert_equal('Baz', gpx_file.waypoints[2].name)
|
|
123
|
+
end
|
|
124
|
+
|
|
74
125
|
def test_multi_point_functionality
|
|
75
126
|
file = File.join(File.dirname(__FILE__), 'geojson_files/multi_point_data.json')
|
|
76
127
|
gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
|
|
77
128
|
assert_equal(3, gpx_file.waypoints.size)
|
|
78
129
|
end
|
|
79
130
|
|
|
131
|
+
def test_multi_point_functionality_with_proc
|
|
132
|
+
file = File.join(File.dirname(__FILE__), 'geojson_files/multi_point_data.json')
|
|
133
|
+
gpx_file = GPX::GeoJSON.convert_to_gpx(
|
|
134
|
+
geojson_file: file,
|
|
135
|
+
multi_point_feature_to_waypoint: ->(multi_point, waypoint) { waypoint.name = multi_point['properties']['name'] }
|
|
136
|
+
)
|
|
137
|
+
assert_equal(3, gpx_file.waypoints.size)
|
|
138
|
+
assert_equal('Foo', gpx_file.waypoints[0].name)
|
|
139
|
+
assert_equal('Foo', gpx_file.waypoints[1].name)
|
|
140
|
+
assert_equal('Foo', gpx_file.waypoints[2].name)
|
|
141
|
+
end
|
|
142
|
+
|
|
80
143
|
def test_combined_functionality
|
|
81
144
|
file = File.join(File.dirname(__FILE__), 'geojson_files/combined_data.json')
|
|
82
145
|
gpx_file = GPX::GeoJSON.convert_to_gpx(geojson_file: file)
|
data/tests/gpx_file_test.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'minitest/autorun'
|
|
4
4
|
require 'gpx'
|
|
5
|
+
require 'stringio'
|
|
5
6
|
|
|
6
7
|
class GPXFileTest < Minitest::Test
|
|
7
8
|
ONE_TRACK_FILE = File.join(File.dirname(__FILE__), 'gpx_files/one_track.gpx')
|
|
@@ -11,39 +12,12 @@ class GPXFileTest < Minitest::Test
|
|
|
11
12
|
|
|
12
13
|
def test_load_data_from_string
|
|
13
14
|
gpx_file = GPX::GPXFile.new(gpx_data: File.open(ONE_TRACK_FILE).read)
|
|
14
|
-
|
|
15
|
-
assert_equal(8, gpx_file.tracks.first.segments.size)
|
|
16
|
-
assert_equal('ACTIVE LOG', gpx_file.tracks.first.name)
|
|
17
|
-
assert_equal('active_log.gpx', gpx_file.name)
|
|
18
|
-
assert_equal('2006-04-08T16:44:28Z', gpx_file.time.xmlschema)
|
|
19
|
-
assert_equal(38.681488, gpx_file.bounds.min_lat)
|
|
20
|
-
assert_equal(-109.606948, gpx_file.bounds.min_lon)
|
|
21
|
-
assert_equal(38.791759, gpx_file.bounds.max_lat)
|
|
22
|
-
assert_equal(-109.447045, gpx_file.bounds.max_lon)
|
|
23
|
-
assert_equal('description of my GPX file with special char like &, <, >', gpx_file.description)
|
|
24
|
-
assert_equal('description of my GPX file with special char like &, <, >', gpx_file.description)
|
|
25
|
-
assert_equal(3.0724966849262554, gpx_file.distance)
|
|
26
|
-
assert_equal(15_237.0, gpx_file.duration)
|
|
27
|
-
assert_equal(3036.0, gpx_file.moving_duration)
|
|
28
|
-
assert_equal(3.6432767014935834, gpx_file.average_speed)
|
|
15
|
+
shared_assertions_for_one_track_file(gpx_file)
|
|
29
16
|
end
|
|
30
17
|
|
|
31
18
|
def test_load_data_from_file
|
|
32
19
|
gpx_file = GPX::GPXFile.new(gpx_file: ONE_TRACK_FILE)
|
|
33
|
-
|
|
34
|
-
assert_equal(8, gpx_file.tracks.first.segments.size)
|
|
35
|
-
assert_equal('ACTIVE LOG', gpx_file.tracks.first.name)
|
|
36
|
-
assert_equal('active_log.gpx', gpx_file.name)
|
|
37
|
-
assert_equal('2006-04-08T16:44:28Z', gpx_file.time.xmlschema)
|
|
38
|
-
assert_equal(38.681488, gpx_file.bounds.min_lat)
|
|
39
|
-
assert_equal(-109.606948, gpx_file.bounds.min_lon)
|
|
40
|
-
assert_equal(38.791759, gpx_file.bounds.max_lat)
|
|
41
|
-
assert_equal(-109.447045, gpx_file.bounds.max_lon)
|
|
42
|
-
assert_equal('description of my GPX file with special char like &, <, >', gpx_file.description)
|
|
43
|
-
assert_equal(3.0724966849262554, gpx_file.distance)
|
|
44
|
-
assert_equal(15_237.0, gpx_file.duration)
|
|
45
|
-
assert_equal(3036.0, gpx_file.moving_duration)
|
|
46
|
-
assert_equal(3.6432767014935834, gpx_file.average_speed)
|
|
20
|
+
shared_assertions_for_one_track_file(gpx_file)
|
|
47
21
|
end
|
|
48
22
|
|
|
49
23
|
def test_big_file
|
|
@@ -74,4 +48,35 @@ class GPXFileTest < Minitest::Test
|
|
|
74
48
|
assert_equal(21.0, gpx_file.moving_duration)
|
|
75
49
|
assert_equal(6.674040636626879, gpx_file.average_speed)
|
|
76
50
|
end
|
|
51
|
+
|
|
52
|
+
def test_load_data_from_stringio_assigned_gpx_file
|
|
53
|
+
str = File.open(ONE_TRACK_FILE).read
|
|
54
|
+
io = StringIO.new(str, 'r+')
|
|
55
|
+
gpx_file = GPX::GPXFile.new(gpx_file: io)
|
|
56
|
+
shared_assertions_for_one_track_file(gpx_file)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_load_data_from_stringio_assigned_gpx_data
|
|
60
|
+
str = File.open(ONE_TRACK_FILE).read
|
|
61
|
+
io = StringIO.new(str, 'r+')
|
|
62
|
+
gpx_file = GPX::GPXFile.new(gpx_data: io)
|
|
63
|
+
shared_assertions_for_one_track_file(gpx_file)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def shared_assertions_for_one_track_file(gpx_file)
|
|
67
|
+
assert_equal(1, gpx_file.tracks.size)
|
|
68
|
+
assert_equal(8, gpx_file.tracks.first.segments.size)
|
|
69
|
+
assert_equal('ACTIVE LOG', gpx_file.tracks.first.name)
|
|
70
|
+
assert_equal('active_log.gpx', gpx_file.name)
|
|
71
|
+
assert_equal('2006-04-08T16:44:28Z', gpx_file.time.xmlschema)
|
|
72
|
+
assert_equal(38.681488, gpx_file.bounds.min_lat)
|
|
73
|
+
assert_equal(-109.606948, gpx_file.bounds.min_lon)
|
|
74
|
+
assert_equal(38.791759, gpx_file.bounds.max_lat)
|
|
75
|
+
assert_equal(-109.447045, gpx_file.bounds.max_lon)
|
|
76
|
+
assert_equal('description of my GPX file with special char like &, <, >', gpx_file.description)
|
|
77
|
+
assert_equal(3.0724966849262554, gpx_file.distance)
|
|
78
|
+
assert_equal(15_237.0, gpx_file.duration)
|
|
79
|
+
assert_equal(3036.0, gpx_file.moving_duration)
|
|
80
|
+
assert_equal(3.6432767014935834, gpx_file.average_speed)
|
|
81
|
+
end
|
|
77
82
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gpx
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Guillaume Dott
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2024-07-27 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: nokogiri
|
|
@@ -93,14 +93,17 @@ extra_rdoc_files: []
|
|
|
93
93
|
files:
|
|
94
94
|
- ".github/workflows/ruby.yml"
|
|
95
95
|
- ".gitignore"
|
|
96
|
+
- ".rubocop"
|
|
96
97
|
- ".rubocop.yml"
|
|
97
98
|
- ".ruby-version"
|
|
99
|
+
- ".tool-versions"
|
|
98
100
|
- ".travis.yml"
|
|
99
101
|
- CHANGELOG.md
|
|
100
102
|
- Gemfile
|
|
101
103
|
- LICENSE.txt
|
|
102
104
|
- README.md
|
|
103
105
|
- Rakefile
|
|
106
|
+
- UPGRADING.md
|
|
104
107
|
- bin/gpx_distance
|
|
105
108
|
- bin/gpx_smooth
|
|
106
109
|
- gpx.gemspec
|
|
@@ -158,7 +161,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
158
161
|
requirements:
|
|
159
162
|
- - ">="
|
|
160
163
|
- !ruby/object:Gem::Version
|
|
161
|
-
version: '2.
|
|
164
|
+
version: '2.7'
|
|
162
165
|
- - "<"
|
|
163
166
|
- !ruby/object:Gem::Version
|
|
164
167
|
version: '4'
|
|
@@ -168,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
168
171
|
- !ruby/object:Gem::Version
|
|
169
172
|
version: '0'
|
|
170
173
|
requirements: []
|
|
171
|
-
rubygems_version: 3.
|
|
174
|
+
rubygems_version: 3.4.10
|
|
172
175
|
signing_key:
|
|
173
176
|
specification_version: 4
|
|
174
177
|
summary: A basic API for reading and writing GPX files.
|