google_static_maps_helper 1.3.3 → 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -97,7 +97,10 @@ Another thing you might want to do is to override the center point and zoom leve
97
97
 
98
98
 
99
99
  == Paths and Polygons
100
- It is also possible to create Paths and Polygons and to use them together with markers. To create a Path you need two Points and a Path object:
100
+ It is also possible to create Paths and Polygons and to use them together with markers.
101
+ Paths and Polygons will by default encode it's points with Google's encoding algorithm.
102
+
103
+ To create a Path you need two Points and a Path object:
101
104
  path = GoogleStaticMapsHelper::Path.new
102
105
  start_point = {:lat => 1, :lng => 2} # You can also use any object which responds to lat and lng here
103
106
  end_point = {:lat => 1, :lng => 2}
@@ -136,9 +139,6 @@ It also have a helper method called <tt>endpoints_for_circle_with_radius</tt> wh
136
139
  map << path
137
140
 
138
141
 
139
- == TODO
140
- * Add support for encoded polylines (http://code.google.com/apis/maps/documentation/staticmaps/#EncodedPolylines).
141
-
142
142
  == Copyright
143
143
 
144
144
  Copyright (c) 2009 Thorbjørn Hermansen. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.3
1
+ 1.3.4
data/changelog.txt CHANGED
@@ -1,4 +1,8 @@
1
- = v.1.3.3 (in git)
1
+ = v.1.3.4
2
+ * Paths are now as default encoding it's points with Google's encoding algorithm. Thanks to Joel Rosenberg for providing an easy class to use.
3
+ This will cut the length of the generated URL quite a bit; down to between 1/3 and 1/2 of the old size.
4
+
5
+ = v.1.3.3
2
6
  * We are now supporting ruby 1.9.1.
3
7
 
4
8
  = v.1.3.2
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{google_static_maps_helper}
8
- s.version = "1.3.3"
8
+ s.version = "1.3.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Thorbj\303\270rn Hermansen"]
12
- s.date = %q{2009-12-01}
11
+ s.authors = ["Thorbjørn Hermansen"]
12
+ s.date = %q{2009-12-03}
13
13
  s.description = %q{This gem provides a simple interface to the Google Static Maps V2 API.}
14
14
  s.email = %q{thhermansen@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
26
26
  "changelog.txt",
27
27
  "google_static_maps_helper.gemspec",
28
28
  "lib/google_static_maps_helper.rb",
29
+ "lib/google_static_maps_helper/gmap_polyline_encoder.rb",
29
30
  "lib/google_static_maps_helper/location.rb",
30
31
  "lib/google_static_maps_helper/map.rb",
31
32
  "lib/google_static_maps_helper/marker.rb",
@@ -4,6 +4,7 @@ require File.dirname(__FILE__) + '/google_static_maps_helper/map'
4
4
  require File.dirname(__FILE__) + '/google_static_maps_helper/location'
5
5
  require File.dirname(__FILE__) + '/google_static_maps_helper/marker'
6
6
  require File.dirname(__FILE__) + '/google_static_maps_helper/path'
7
+ require File.dirname(__FILE__) + '/google_static_maps_helper/gmap_polyline_encoder'
7
8
 
8
9
  #
9
10
  # The Google Static Map Helper provides a simple interface to the
@@ -0,0 +1,390 @@
1
+ #--
2
+ #
3
+ # Utility for creating Google Maps Encoded GPolylines
4
+ #
5
+ # License: You may distribute this code under the same terms as Ruby itself
6
+ #
7
+ # Author: Joel Rosenberg
8
+ #
9
+ # ( Drawing from the official example pages as well as Mark McClure's work )
10
+ #
11
+ # == Example
12
+ #
13
+ # data = [
14
+ # [ 37.4419, -122.1419],
15
+ # [ 37.4519, -122.1519],
16
+ # [ 37.4619, -122.1819],
17
+ # ]
18
+ #
19
+ # encoder = GMapPolylineEncoder.new()
20
+ # result = encoder.encode( data )
21
+ #
22
+ # javascript << " var myLine = new GPolyline.fromEncoded({\n"
23
+ # javascript << " color: \"#FF0000\",\n"
24
+ # javascript << " weight: 10,\n"
25
+ # javascript << " opacity: 0.5,\n"
26
+ # javascript << " zoomFactor: #{result[:zoomFactor]},\n"
27
+ # javascript << " numLevels: #{result[:numLevels]},\n"
28
+ # javascript << " points: \"#{result[:points]}\",\n"
29
+ # javascript << " levels: \"#{result[:levels]}\"\n"
30
+ # javascript << " });"
31
+ #
32
+ # == Methods
33
+ #
34
+ # Constructor args (all optional):
35
+ # :numLevels (default 18)
36
+ # :zoomFactor (default 2)
37
+ # :reduce: Reduce points (default true)
38
+ # :escape: Escape backslashes (default true)
39
+ #
40
+ # encode( points ) method
41
+ # points (required): array of longitude, latitude pairs
42
+ #
43
+ # returns hash with keys :points, :levels, :zoomFactor, :numLevels
44
+ #
45
+ # == Background
46
+ #
47
+ # Description: http://www.google.com/apis/maps/documentation/#Encoded_Polylines
48
+ # API: http://www.google.com/apis/maps/documentation/reference.html#GPolyline
49
+ # Hints: http://www.google.com/apis/maps/documentation/polylinealgorithm.html
50
+ #
51
+ # Example Javascript for instantiating an encoded polyline:
52
+ # var encodedPolyline = new GPolyline.fromEncoded({
53
+ # color: "#FF0000",
54
+ # weight: 10,
55
+ # points: "yzocFzynhVq}@n}@o}@nzD",
56
+ # levels: "BBB",
57
+ # zoomFactor: 32,
58
+ # numLevels: 4
59
+ # });
60
+ #
61
+ # == Changes
62
+ #
63
+ # 06.29.2007 - Release 0.1
64
+ # Profiling showed that distance() accounted for 50% of the time when
65
+ # processing McClure's British coast data. By moving the distance
66
+ # calculation into encode(), we can cache a few of the calculations
67
+ # (magnitude) and eliminate the overhead of the function call. This
68
+ # reduced the time to encode by ~ 30%
69
+ #
70
+ # 06.21.2007 Implementing the Doublas-Peucker algorithm for removing superflous
71
+ # points as per Mark McClure's design:
72
+ # http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/
73
+ #
74
+ # 10.14.2006 Cleaned up (and finally grasped) zoom levels
75
+ #
76
+ # 09.2006 First port of the official example's javascript. Ignoring zoom
77
+ # levels for now, showing points at all zoom levels
78
+ #
79
+ #++
80
+ module GoogleStaticMapsHelper
81
+ class GMapPolylineEncoder
82
+ attr_accessor :reduce, :escape #zoomFactor and numLevels need side effects
83
+ attr_reader :zoomFactor, :numLevels
84
+
85
+ # The minimum distance from the line that a point must exceed to avoid
86
+ # elimination under the DP Algorithm.
87
+ @@dp_threshold = 0.00001
88
+
89
+ def initialize(options = {})
90
+ # There are no required parameters
91
+
92
+ # Nice defaults
93
+ @numLevels = options.has_key?(:numLevels) ? options[:numLevels] : 18
94
+ @zoomFactor = options.has_key?(:zoomFactor) ? options[:zoomFactor] : 2
95
+
96
+ # Calculate the distance thresholds for each zoom level
97
+ calculate_zoom_breaks()
98
+
99
+ # By default we'll simplify the polyline unless told otherwise
100
+ @reduce = ! options.has_key?(:reduce) ? true : options[:reduce]
101
+
102
+ # Escape by default; most people are using this in a web context
103
+ @escape = ! options.has_key?(:escape) ? true : options[:escape]
104
+
105
+ end
106
+
107
+ def numLevels=( new_num_levels )
108
+ @numLevels = new_num_levels
109
+ # We need to recalculate our zoom breaks
110
+ calculate_zoom_breaks()
111
+ end
112
+
113
+ def zoomFactor=( new_zoom_factor )
114
+ @zoomFactor = new_zoom_factor
115
+ # We need to recalculate our zoom breaks
116
+ calculate_zoom_breaks()
117
+ end
118
+
119
+ def encode( points )
120
+
121
+ #
122
+ # This is an implementation of the Douglas-Peucker algorithm for simplifying
123
+ # a line. You can thing of it as an elimination of points that do not
124
+ # deviate enough from a vector. That threshold for point elimination is in
125
+ # @@dp_threshold. See
126
+ #
127
+ # http://everything2.com/index.pl?node_id=859282
128
+ #
129
+ # for an explanation of the algorithm
130
+ #
131
+
132
+ max_dist = 0 # Greatest distance we measured during the run
133
+ stack = []
134
+ distances = Array.new(points.size)
135
+
136
+ if(points.length > 2)
137
+ stack << [0, points.size-1]
138
+
139
+ while(stack.length > 0)
140
+ current_line = stack.pop()
141
+ p1_idx = current_line[0]
142
+ pn_idx = current_line[1]
143
+ pb_dist = 0
144
+ pb_idx = nil
145
+
146
+ x1 = points[p1_idx][0]
147
+ y1 = points[p1_idx][1]
148
+ x2 = points[pn_idx][0]
149
+ y2 = points[pn_idx][1]
150
+
151
+ # Caching the line's magnitude for performance
152
+ magnitude = Math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
153
+ magnitude_squared = magnitude ** 2
154
+
155
+ # Find the farthest point and its distance from the line between our pair
156
+ for i in (p1_idx+1)..(pn_idx-1)
157
+
158
+ # Refactoring distance computation inline for performance
159
+ #current_distance = compute_distance(points[i], points[p1_idx], points[pn_idx])
160
+
161
+ #
162
+ # This uses Euclidian geometry. It shouldn't be that big of a deal since
163
+ # we're using it as a rough comparison for line elimination and zoom
164
+ # calculation.
165
+ #
166
+ # TODO: Implement Haversine functions which would probably bring this to
167
+ # a snail's pace (ehhhh)
168
+ #
169
+
170
+ px = points[i][0]
171
+ py = points[i][1]
172
+
173
+ current_distance = nil
174
+
175
+ if( magnitude == 0 )
176
+ # The line is really just a point
177
+ current_distance = Math.sqrt((x2-px)**2 + (y2-py)**2)
178
+ else
179
+
180
+ u = (((px - x1) * (x2 - x1)) + ((py - y1) * (y2 - y1))) / magnitude_squared
181
+
182
+ if( u <= 0 || u > 1 )
183
+ # The point is closest to an endpoint. Find out which one
184
+ ix = Math.sqrt((x1 - px)**2 + (y1 - py)**2)
185
+ iy = Math.sqrt((x2 - px)**2 + (y2 - py)**2)
186
+ if( ix > iy )
187
+ current_distance = iy
188
+ else
189
+ current_distance = ix
190
+ end
191
+ else
192
+ # The perpendicular point intersects the line
193
+ ix = x1 + u * (x2 - x1)
194
+ iy = y1 + u * (y2 - y1)
195
+ current_distance = Math.sqrt((ix - px)**2 + (iy - py)**2)
196
+ end
197
+ end
198
+
199
+ # See if this distance is the greatest for this segment so far
200
+ if(current_distance > pb_dist)
201
+ pb_dist = current_distance
202
+ pb_idx = i
203
+ end
204
+ end
205
+
206
+ # See if this is the greatest distance for all points
207
+ if(pb_dist > max_dist)
208
+ max_dist = pb_dist
209
+ end
210
+
211
+ if(pb_dist > @@dp_threshold)
212
+ # Our point, Pb, that had the greatest distance from the line, is also
213
+ # greater than our threshold. Process again using Pb as a new
214
+ # start/end point. Record this distance - we'll use it later when
215
+ # creating zoom values
216
+ distances[pb_idx] = pb_dist
217
+ stack << [p1_idx, pb_idx]
218
+ stack << [pb_idx, pn_idx]
219
+ end
220
+
221
+ end
222
+ end
223
+
224
+ # Force line endpoints to be included (sloppy, but faster than checking for
225
+ # endpoints in encode_points())
226
+ distances[0] = max_dist
227
+ distances[distances.length-1] = max_dist
228
+
229
+ # Create Base64 encoded strings for our points and zoom levels
230
+ points_enc = encode_points( points, distances)
231
+ levels_enc = encode_levels( points, distances, max_dist)
232
+
233
+ # Make points_enc an escaped string if desired.
234
+ # We should escape the levels too, in case google pulls a switcheroo
235
+ @escape && points_enc && points_enc.gsub!( /\\/, '\\\\\\\\' )
236
+
237
+
238
+ # Returning a hash. Yes, I am a Perl programmer
239
+ return {
240
+ :points => points_enc,
241
+ :levels => levels_enc,
242
+ :zoomFactor => @zoomFactor,
243
+ :numLevels => @numLevels,
244
+ }
245
+
246
+ end
247
+
248
+ private
249
+
250
+ def calculate_zoom_breaks()
251
+ # Calculate the distance thresholds for each zoom level
252
+ @zoom_level_breaks = Array.new(@numLevels);
253
+
254
+ for i in 0..(@numLevels-1)
255
+ @zoom_level_breaks[i] = @@dp_threshold * (@zoomFactor ** ( @numLevels-i-1));
256
+ end
257
+
258
+ return
259
+ end
260
+
261
+ def encode_points( points, distances )
262
+ encoded = ""
263
+
264
+ plat = 0
265
+ plon = 0
266
+
267
+ #points.each do |point| # Gah, need the distances.
268
+ for i in 0..(points.size() - 1)
269
+ if(! @reduce || distances[i] != nil )
270
+ point = points[i]
271
+ late5 = (point[0] * 1e5).floor();
272
+ lone5 = (point[1] * 1e5).floor();
273
+
274
+ dlat = late5 - plat
275
+ dlon = lone5 - plon
276
+
277
+ plat = late5;
278
+ plon = lone5;
279
+
280
+ # I used to need this for some reason
281
+ #encoded << encodeSignedNumber(Fixnum.induced_from(dlat)).to_s
282
+ #encoded << encodeSignedNumber(Fixnum.induced_from(dlon)).to_s
283
+ encoded << encodeSignedNumber(dlat).to_s
284
+ encoded << encodeSignedNumber(dlon).to_s
285
+ end
286
+ end
287
+
288
+ return encoded
289
+
290
+ end
291
+
292
+ def encode_levels( points, distances, max_dist )
293
+
294
+ encoded = "";
295
+
296
+ # Force startpoint
297
+ encoded << encodeNumber(@numLevels - 1)
298
+
299
+ if( points.size() > 2 )
300
+ for i in 1..(points.size() - 2)
301
+ distance = distances[i]
302
+ if( ! @reduce || distance != nil)
303
+ computed_level = 0
304
+
305
+ while (distance < @zoom_level_breaks[computed_level]) do
306
+ computed_level += 1
307
+ end
308
+
309
+ encoded << encodeNumber( @numLevels - computed_level - 1 )
310
+ end
311
+ end
312
+ end
313
+
314
+ # Force endpoint
315
+ encoded << encodeNumber(@numLevels - 1)
316
+
317
+ return encoded;
318
+
319
+ end
320
+
321
+ def compute_distance( point, lineStart, lineEnd )
322
+
323
+ #
324
+ # Note: This has been refactored to encode() inline for performance and
325
+ # computation caching
326
+ #
327
+
328
+ px = point[0]
329
+ py = point[1]
330
+ x1 = lineStart[0]
331
+ y1 = lineStart[1]
332
+ x2 = lineEnd[0]
333
+ y2 = lineEnd[1]
334
+
335
+ distance = nil
336
+
337
+ magnitude = Math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
338
+
339
+ if( magnitude == 0 )
340
+ return Math.sqrt((x2-px)**2 + (y2-py)**2)
341
+ end
342
+
343
+ u = (((px - x1) * (x2 - x1)) + ((py - y1) * (y2 - y1))) / (magnitude**2)
344
+
345
+ if( u <= 0 || u > 1 )
346
+ # The point is closest to an endpoint. Find out which
347
+ ix = Math.sqrt((x1 - px)**2 + (y1 - py)**2)
348
+ iy = Math.sqrt((x2 - px)**2 + (y2 - py)**2)
349
+ if( ix > iy )
350
+ distance = iy
351
+ else
352
+ distance = ix
353
+ end
354
+ else
355
+ # The perpendicular point intersects the line
356
+ ix = x1 + u * (x2 - x1)
357
+ iy = y1 + u * (y2 - y1)
358
+ distance = Math.sqrt((ix - px)**2 + (iy - py)**2)
359
+ end
360
+
361
+ return distance
362
+ end
363
+
364
+ def encodeSignedNumber(num)
365
+ # Based on the official google example
366
+
367
+ sgn_num = num << 1
368
+
369
+ if( num < 0 )
370
+ sgn_num = ~(sgn_num)
371
+ end
372
+
373
+ return encodeNumber(sgn_num)
374
+ end
375
+
376
+ def encodeNumber(num)
377
+ # Based on the official google example
378
+
379
+ encoded = "";
380
+
381
+ while (num >= 0x20) do
382
+ encoded << ((0x20 | (num & 0x1f)) + 63).chr;
383
+ num = num >> 5;
384
+ end
385
+
386
+ encoded << (num + 63).chr;
387
+ return encoded;
388
+ end
389
+ end
390
+ end
@@ -9,7 +9,7 @@ module GoogleStaticMapsHelper
9
9
 
10
10
  OPTIONAL_OPTIONS = [:weight, :color, :fillcolor]
11
11
 
12
- attr_accessor :points, *OPTIONAL_OPTIONS
12
+ attr_accessor :encode_points, :points, *OPTIONAL_OPTIONS
13
13
 
14
14
  #
15
15
  # Creates a new Path which you can push points on to to make up lines or polygons
@@ -25,9 +25,11 @@ module GoogleStaticMapsHelper
25
25
  # as described in the <tt>:color</tt>. When used, the static map will automatically create
26
26
  # a closed shape.
27
27
  # <tt>:points</tt>:: An array of points. You can mix objects responding to lng and lat, and a Hash with lng and lat keys.
28
+ # <tt>:encode_points:: A flag which tells us if we should encode the points in this path or not. Defaults to <tt>true</tt>
28
29
  #
29
30
  def initialize(*args)
30
31
  @points = []
32
+ @encode_points = true
31
33
 
32
34
  extract_options!(args)
33
35
  add_points(args)
@@ -49,9 +51,9 @@ module GoogleStaticMapsHelper
49
51
 
50
52
  out += "#{path_params}|" unless path_params.empty?
51
53
 
52
- out += inject([]) do |point_params, point|
53
- point_params << point.to_url
54
- end.join('|')
54
+ out += encoded_url_points if encoding_points?
55
+ out += unencoded_url_points unless encoding_points?
56
+ out
55
57
  end
56
58
 
57
59
 
@@ -78,6 +80,10 @@ module GoogleStaticMapsHelper
78
80
  length == 0
79
81
  end
80
82
 
83
+ def clear
84
+ @points = []
85
+ end
86
+
81
87
  #
82
88
  # Pushes a new point into the Path
83
89
  #
@@ -91,6 +97,14 @@ module GoogleStaticMapsHelper
91
97
  self
92
98
  end
93
99
 
100
+ #
101
+ # Will answer the question if we are encoding the points or not when
102
+ # building the image URL.
103
+ #
104
+ def encoding_points?
105
+ return !!@encode_points
106
+ end
107
+
94
108
 
95
109
  private
96
110
  #
@@ -117,5 +131,19 @@ module GoogleStaticMapsHelper
117
131
  def add_points(points)
118
132
  points.each {|point| self << point}
119
133
  end
134
+
135
+ def encoded_url_points
136
+ encoder = GMapPolylineEncoder.new
137
+ points_as_array = points.map { |location| [location.lat, location.lng]}
138
+ result = encoder.encode(points_as_array)
139
+
140
+ "enc:#{result[:points]}"
141
+ end
142
+
143
+ def unencoded_url_points
144
+ inject([]) do |point_params, point|
145
+ point_params << point.to_url
146
+ end.join('|')
147
+ end
120
148
  end
121
149
  end
@@ -35,7 +35,7 @@ describe GoogleStaticMapsHelper do
35
35
  point2 = {:lat => 3, :lng => 4}
36
36
 
37
37
  out = GoogleStaticMapsHelper.url_for do
38
- path point, point2, :color => :red
38
+ path point, point2, :color => :red, :encode_points => false
39
39
  end
40
40
 
41
41
  out.should include('path=color:red|1,2|3,4')
data/spec/map_spec.rb CHANGED
@@ -357,7 +357,7 @@ describe GoogleStaticMapsHelper::Map do
357
357
 
358
358
  describe "paths" do
359
359
  before do
360
- @path = GoogleStaticMapsHelper::Path.new
360
+ @path = GoogleStaticMapsHelper::Path.new :encode_points => false
361
361
  @point = GoogleStaticMapsHelper::Location.new(:lat => 1, :lng => 2)
362
362
  @point2 = GoogleStaticMapsHelper::Location.new(:lat => 3, :lng => 4)
363
363
  @path << @point << @point2
data/spec/path_spec.rb CHANGED
@@ -21,6 +21,23 @@ describe GoogleStaticMapsHelper::Path do
21
21
  end
22
22
  end
23
23
 
24
+ describe "encoding points flag" do
25
+ it "should be able to set to false" do
26
+ path = GoogleStaticMapsHelper::Path.new(:encode_points => false)
27
+ path.should_not be_encoding_points
28
+ end
29
+
30
+ it "should be able to set to true" do
31
+ path = GoogleStaticMapsHelper::Path.new(:encode_points => true)
32
+ path.should be_encoding_points
33
+ end
34
+
35
+ it "should be true as default" do
36
+ path = GoogleStaticMapsHelper::Path.new
37
+ path.should be_encoding_points
38
+ end
39
+ end
40
+
24
41
  describe "points" do
25
42
  before do
26
43
  @point = GoogleStaticMapsHelper::Location.new(:lat => 1, :lng => 2)
@@ -50,6 +67,12 @@ describe GoogleStaticMapsHelper::Path do
50
67
  @path.points.should == []
51
68
  end
52
69
 
70
+ it "should be possible to clear points" do
71
+ @path << @point << @point2
72
+ @path.clear
73
+ @path.length.should == 0
74
+ end
75
+
53
76
  it "should be able to push points on to a path" do
54
77
  @path << @point
55
78
  @path.points.length.should == 1
@@ -102,7 +125,7 @@ describe GoogleStaticMapsHelper::Path do
102
125
 
103
126
  describe "url_params" do
104
127
  before do
105
- @path = GoogleStaticMapsHelper::Path.new
128
+ @path = GoogleStaticMapsHelper::Path.new :encode_points => false
106
129
  @point = GoogleStaticMapsHelper::Location.new(:lat => 1, :lng => 2)
107
130
  @point2 = GoogleStaticMapsHelper::Location.new(:lat => 3, :lng => 4)
108
131
  @path << @point << @point2
@@ -148,5 +171,19 @@ describe GoogleStaticMapsHelper::Path do
148
171
  it "should concat point locations without any path options" do
149
172
  @path.url_params.should == 'path=1,2|3,4'
150
173
  end
174
+
175
+ describe "encoded poly lines" do
176
+ before do
177
+ @path.encode_points = true
178
+ end
179
+
180
+ it "should include 'enc:'" do
181
+ @path.url_params.should include('enc:')
182
+ end
183
+
184
+ it "should include encoded version of lng and lat" do
185
+ @path.url_params.should include('_ibE_seK_seK_seK')
186
+ end
187
+ end
151
188
  end
152
189
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google_static_maps_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Thorbj\xC3\xB8rn Hermansen"
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-01 00:00:00 +01:00
12
+ date: 2009-12-03 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -41,6 +41,7 @@ files:
41
41
  - changelog.txt
42
42
  - google_static_maps_helper.gemspec
43
43
  - lib/google_static_maps_helper.rb
44
+ - lib/google_static_maps_helper/gmap_polyline_encoder.rb
44
45
  - lib/google_static_maps_helper/location.rb
45
46
  - lib/google_static_maps_helper/map.rb
46
47
  - lib/google_static_maps_helper/marker.rb