Fix rubocop lint issues
[rails.git] / lib / gpx.rb
1 module GPX
2   class File
3     require "libxml"
4
5     include LibXML
6
7     attr_reader :possible_points
8     attr_reader :actual_points
9     attr_reader :tracksegs
10
11     def initialize(file)
12       @file = file
13     end
14
15     def points
16       @possible_points = 0
17       @actual_points = 0
18       @tracksegs = 0
19
20       @file.rewind
21
22       reader = XML::Reader.io(@file)
23
24       point = nil
25
26       while reader.read
27         if reader.node_type == XML::Reader::TYPE_ELEMENT
28           if reader.name == "trkpt"
29             point = TrkPt.new(@tracksegs, reader["lat"].to_f, reader["lon"].to_f)
30             @possible_points += 1
31           elsif reader.name == "ele" && point
32             point.altitude = reader.read_string.to_f
33           elsif reader.name == "time" && point
34             point.timestamp = DateTime.parse(reader.read_string)
35           end
36         elsif reader.node_type == XML::Reader::TYPE_END_ELEMENT
37           if reader.name == "trkpt" && point && point.valid?
38             point.altitude ||= 0
39             yield point
40             @actual_points += 1
41           elsif reader.name == "trkseg"
42             @tracksegs += 1
43           end
44         end
45       end
46     end
47
48     def picture(min_lat, min_lon, max_lat, max_lon, num_points)
49       frames = 10
50       width = 250
51       height = 250
52       proj = OSM::Mercator.new(min_lat, min_lon, max_lat, max_lon, width, height)
53
54       linegc = Magick::Draw.new
55       linegc.stroke_linejoin('miter')
56       linegc.stroke_width(1)
57       linegc.stroke('#BBBBBB')
58       linegc.fill('#BBBBBB')
59
60       highlightgc = Magick::Draw.new
61       highlightgc.stroke_linejoin('miter')
62       highlightgc.stroke_width(3)
63       highlightgc.stroke('#000000')
64       highlightgc.fill('#000000')
65
66       images = frames.times.collect do
67         Magick::Image.new(width, height) do |image|
68           image.background_color = 'white'
69           image.format = 'GIF'
70         end
71       end
72
73       oldpx = 0.0
74       oldpy = 0.0
75
76       m = 0
77       mm = 0
78       points do |p|
79         px = proj.x(p.longitude)
80         py = proj.y(p.latitude)
81
82         if m > 0
83           frames.times do |n|
84             if n == mm
85               gc = highlightgc.dup
86             else
87               gc = linegc.dup
88             end
89
90             gc.line(px, py, oldpx, oldpy)
91
92             gc.draw(images[n])
93           end
94         end
95
96         m += 1
97         if m > num_points.to_f / frames.to_f * (mm + 1)
98           mm += 1
99         end
100
101         oldpy = py
102         oldpx = px
103       end
104
105       il = Magick::ImageList.new
106
107       images.each do |f|
108         il << f
109       end
110
111       il.delay = 50
112       il.format = 'GIF'
113
114       il.to_blob
115     end
116
117     def icon(min_lat, min_lon, max_lat, max_lon)
118       width = 50
119       height = 50
120       proj = OSM::Mercator.new(min_lat, min_lon, max_lat, max_lon, width, height)
121
122       gc = Magick::Draw.new
123       gc.stroke_linejoin('miter')
124       gc.stroke_width(1)
125       gc.stroke('#000000')
126       gc.fill('#000000')
127
128       image = Magick::Image.new(width, height) do |i|
129         i.background_color = 'white'
130         i.format = 'GIF'
131       end
132
133       oldpx = 0.0
134       oldpy = 0.0
135
136       first = true
137
138       points do |p|
139         px = proj.x(p.longitude)
140         py = proj.y(p.latitude)
141
142         gc.dup.line(px, py, oldpx, oldpy).draw(image) unless first
143
144         first = false
145         oldpy = py
146         oldpx = px
147       end
148
149       image.to_blob
150     end
151   end
152
153   private
154
155   class TrkPt < Struct.new(:segment, :latitude, :longitude, :altitude, :timestamp)
156     def valid?
157       latitude && longitude && timestamp &&
158         latitude >= -90 && latitude <= 90 &&
159         longitude >= -180 && longitude <= 180
160     end
161   end
162 end