gps2map 1.0.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 +7 -0
- data/README.md +21 -0
- data/bin/gps2map +6 -0
- data/lib/core_ext/integer.rb +8 -0
- data/lib/gps2map/version.rb +5 -0
- data/lib/gps2map.rb +120 -0
- data/lib/map.erb +59 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3cc4350e15d0c62b55fb807c3a703fb0962d70f5077a6f016fe4cc5bee6be5f2
|
4
|
+
data.tar.gz: b5c53b6993f76aa8ed70fdeabc299afa03d1983520116ab8631e23cb889a2c83
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a3993f4856b452e7bfdc2d19eebf8a02a5c958c5c35a7fda2efb7e3d00ffcf2b26448528c17da9973474b1a41e44e376555357b62beca4fc4e3354a4c9d79679
|
7
|
+
data.tar.gz: f801917602ccee3872e8cff9862a65f60c8068f309a885c2b2e66c8a4bbe80084f73c01ce80304c6edf7ce1b043467d1e81166f2d232a44ef178d5c837b66328
|
data/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# GPS2Map
|
2
|
+
Creates a Google Map from an input file containing GPS co-ordinates ([GPX](https://en.wikipedia.org/wiki/GPS_Exchange_Format), [KML](https://en.wikipedia.org/wiki/Keyhole_Markup_Language) or [TCX](https://en.wikipedia.org/wiki/Training_Center_XML) format).
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
```
|
6
|
+
$ gem install gps2map
|
7
|
+
```
|
8
|
+
|
9
|
+
## Prerequisites
|
10
|
+
A [Google Maps JavaScript API key](https://developers.google.com/maps/documentation/javascript/get-api-key) is required and must be specified in an environment variable named `GOOGLE_MAPS_API_KEY`.
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
```
|
14
|
+
gps2map generate <input.gpx|.kml|.tcx> <output.html>
|
15
|
+
```
|
16
|
+
|
17
|
+
## Licence
|
18
|
+
The gem is available as open source under the terms of the [MIT Licence](https://opensource.org/licenses/MIT).
|
19
|
+
|
20
|
+
## Copyright
|
21
|
+
Copyright (C) 2018 John Topley.
|
data/bin/gps2map
ADDED
data/lib/gps2map.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'thor'
|
7
|
+
require 'erb'
|
8
|
+
require 'csv'
|
9
|
+
|
10
|
+
require_relative 'core_ext/integer'
|
11
|
+
require_relative 'gps2map/version'
|
12
|
+
|
13
|
+
# Namespace all the gem code.
|
14
|
+
module GPS2Map
|
15
|
+
DIGITS = 6
|
16
|
+
LATITUDE_OFFSET = 0.005000
|
17
|
+
MARKERS = 15
|
18
|
+
|
19
|
+
Coordinate = Struct.new(:latitude, :longitude)
|
20
|
+
Marker = Struct.new(:latitude, :longitude, :label)
|
21
|
+
|
22
|
+
# Class that takes an input file containing GPS co-ordinates and outputs an HTML file containing a
|
23
|
+
# Google Map of those co-ordinates.
|
24
|
+
class GPS2Map < Thor
|
25
|
+
desc 'generate <input.gpx|.kml|.tcx> <output.html>', 'Generates a Google Map from an input file'
|
26
|
+
option :markers, type: :numeric, default: MARKERS, desc: 'The number of markers to plot on the map'
|
27
|
+
def generate(input_file, output_file)
|
28
|
+
vars = {}
|
29
|
+
vars[:api_key] = ENV['GOOGLE_MAPS_API_KEY'] || abort('No GOOGLE_MAPS_API_KEY provided.')
|
30
|
+
vars[:title] = input_file
|
31
|
+
coordinates = []
|
32
|
+
markers = []
|
33
|
+
label = 0
|
34
|
+
latitudes, longitudes = parse_file(input_file)
|
35
|
+
interval = latitudes.length / options[:markers]
|
36
|
+
|
37
|
+
latitudes.each_with_index do |latitude, i|
|
38
|
+
longitude = longitudes[i]
|
39
|
+
coordinates << Coordinate.new(latitude, longitude)
|
40
|
+
markers << Marker.new(latitude, longitude, label += 1) if i > 1 && (i % interval).zero?
|
41
|
+
end
|
42
|
+
|
43
|
+
vars[:coordinates] = coordinates
|
44
|
+
vars[:markers] = markers
|
45
|
+
vars[:map_centre_lat] = mean_of(coordinates.map(&:latitude)) + LATITUDE_OFFSET
|
46
|
+
vars[:map_centre_long] = mean_of(coordinates.map(&:longitude))
|
47
|
+
vars[:map_start_lat] = coordinates.first.latitude
|
48
|
+
vars[:map_start_long] = coordinates.first.longitude
|
49
|
+
write_output_file(output_file, execute_template(vars))
|
50
|
+
puts "Plotted #{latitudes.length.to_comma_formatted} co-ordinates with #{markers.length} markers."
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def execute_template(variables)
|
56
|
+
template = File.join(__dir__, 'map.erb')
|
57
|
+
context = OpenStruct.new(variables).instance_eval { binding }
|
58
|
+
# Set the ERB trim mode to suppress newlines.
|
59
|
+
ERB.new(File.read(template), 0, '>').result(context)
|
60
|
+
end
|
61
|
+
|
62
|
+
def mean_of(coordinates)
|
63
|
+
coordinates.sum.fdiv(coordinates.length).round(DIGITS)
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_file(input_file)
|
67
|
+
case File.extname(input_file).downcase
|
68
|
+
when '.gpx'
|
69
|
+
parse_gpx(input_file)
|
70
|
+
when '.kml'
|
71
|
+
parse_kml(input_file)
|
72
|
+
when '.tcx'
|
73
|
+
parse_tcx(input_file)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse(input_file, selector)
|
78
|
+
File.open(input_file, 'r') do |fi|
|
79
|
+
doc = Nokogiri::XML(fi)
|
80
|
+
doc.css(selector).each { |el| yield(el) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_gpx(input_file)
|
85
|
+
latitudes = []
|
86
|
+
longitudes = []
|
87
|
+
parse(input_file, 'trkpt') do |el|
|
88
|
+
latitudes << el['lat'].to_f.round(DIGITS)
|
89
|
+
longitudes << el['lon'].to_f.round(DIGITS)
|
90
|
+
end
|
91
|
+
[latitudes, longitudes]
|
92
|
+
end
|
93
|
+
|
94
|
+
def parse_kml(input_file)
|
95
|
+
latitudes = []
|
96
|
+
longitudes = []
|
97
|
+
parse(input_file, 'Point coordinates') do |el|
|
98
|
+
# KML has longitude first.
|
99
|
+
longitudes << CSV.parse(el.text.strip).first.first.to_f.round(DIGITS)
|
100
|
+
latitudes << CSV.parse(el.text.strip).first[1].to_f.round(DIGITS)
|
101
|
+
end
|
102
|
+
[latitudes, longitudes]
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_tcx(input_file)
|
106
|
+
latitudes = []
|
107
|
+
longitudes = []
|
108
|
+
File.open(input_file, 'r') do |fi|
|
109
|
+
doc = Nokogiri::XML(fi)
|
110
|
+
doc.css('LatitudeDegrees').each { |el| latitudes << el.text.to_f.round(DIGITS) }
|
111
|
+
doc.css('LongitudeDegrees').each { |el| longitudes << el.text.to_f.round(DIGITS) }
|
112
|
+
end
|
113
|
+
[latitudes, longitudes]
|
114
|
+
end
|
115
|
+
|
116
|
+
def write_output_file(output_file, data)
|
117
|
+
File.open(output_file, 'w') { |fi| fi.write(data) }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/map.erb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= title %></title>
|
5
|
+
<meta name="viewport" content="initial-scale=1.0">
|
6
|
+
<meta charset="utf-8">
|
7
|
+
<style>
|
8
|
+
/* Always set the map height explicitly to define the size of the div
|
9
|
+
* element that contains the map. */
|
10
|
+
#map {
|
11
|
+
height: 100%;
|
12
|
+
}
|
13
|
+
/* Optional: Makes the sample page fill the window. */
|
14
|
+
html, body {
|
15
|
+
height: 100%;
|
16
|
+
margin: 0;
|
17
|
+
padding: 0;
|
18
|
+
}
|
19
|
+
</style>
|
20
|
+
</head>
|
21
|
+
<body>
|
22
|
+
<div id="map"></div>
|
23
|
+
<script>
|
24
|
+
var map;
|
25
|
+
function initMap() {
|
26
|
+
map = new google.maps.Map(document.getElementById('map'), {
|
27
|
+
center: { lat: <%= map_centre_lat %>, lng: <%= map_centre_long %> },
|
28
|
+
zoom: 12
|
29
|
+
});
|
30
|
+
var coordinates = [
|
31
|
+
<% coordinates.each do |coordinate| %>
|
32
|
+
{ lat: <%= coordinate.latitude %>, lng: <%= coordinate.longitude %> },
|
33
|
+
<% end %>
|
34
|
+
];
|
35
|
+
var polyline = new google.maps.Polyline({
|
36
|
+
path: coordinates,
|
37
|
+
geodesic: true,
|
38
|
+
strokeColor: '#0088FF',
|
39
|
+
strokeOpacity: 0.6,
|
40
|
+
strokeWeight: 6
|
41
|
+
});
|
42
|
+
polyline.setMap(map);
|
43
|
+
var flagMarker = new google.maps.Marker({
|
44
|
+
position: { lat: <%= map_start_lat %>, lng: <%= map_start_long %>},
|
45
|
+
map: map,
|
46
|
+
icon: 'https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png'
|
47
|
+
});
|
48
|
+
<% markers.each do |marker| %>
|
49
|
+
new google.maps.Marker({
|
50
|
+
position: { lat: <%= marker.latitude %>, lng: <%= marker.longitude %> },
|
51
|
+
map: map,
|
52
|
+
label: '<%= marker.label %>'
|
53
|
+
});
|
54
|
+
<% end %>
|
55
|
+
}
|
56
|
+
</script>
|
57
|
+
<script src="https://maps.googleapis.com/maps/api/js?key=<%= api_key %>&callback=initMap" async defer></script>
|
58
|
+
</body>
|
59
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gps2map
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Topley
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nokogiri
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.8.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.8.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.20.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.20.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.16'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.16'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.49.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.49.1
|
83
|
+
description: 'Creates a Google Map from an input file containing GPS co-ordinates
|
84
|
+
(GPX, KML or TCX format).
|
85
|
+
|
86
|
+
'
|
87
|
+
email: john@johntopley.com
|
88
|
+
executables:
|
89
|
+
- gps2map
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- README.md
|
94
|
+
- bin/gps2map
|
95
|
+
- lib/core_ext/integer.rb
|
96
|
+
- lib/gps2map.rb
|
97
|
+
- lib/gps2map/version.rb
|
98
|
+
- lib/map.erb
|
99
|
+
homepage: https://github.com/johntopley/gps2map
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata: {}
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.7.5
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Creates a Google Map from an input file
|
123
|
+
test_files: []
|