flexible_polyline 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7ced372812b9fc3a5e916c38b60ad07dca29c030dc036c8d7e8e504baab0be76
4
+ data.tar.gz: 43fa8c59dabda50728c32ac61d6ae3c563ad217079aedd147e394e4c1a89f2d4
5
+ SHA512:
6
+ metadata.gz: 7c7e93df6f86dfe2e056a41a1aee91579be46b163ba6d186b107f6ec9156c39a559340ff50d28375c13072af6087b4086ad1391675319e30bc1cb77415e7d328
7
+ data.tar.gz: 01a4a2b19f3ef4324b8e70b895ccd5654a7c3c50c3a796d92a25f669f5cb13ead5be5447f7b980143aa0ea36e516ae1de1b16437d6b3fa5246b45f3aebbba85f
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,567 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.7
6
+ SuggestExtensions: false
7
+
8
+ ########## MISC
9
+ Style/Documentation:
10
+ Enabled: false
11
+
12
+ Bundler/OrderedGems:
13
+ Enabled: false
14
+
15
+ Security/IoMethods: # new in 1.22
16
+ Enabled: true
17
+
18
+ ########## NAMING RELATED
19
+ # Renaming `has_something?` to `something?` obfuscates whether it is a "is-a" or
20
+ # a "has-a" relationship.
21
+ Naming/PredicateName:
22
+ Enabled: false
23
+
24
+ Naming/MethodParameterName:
25
+ Enabled: false
26
+
27
+ ########## LAYOUT RELATED
28
+ Layout/AccessModifierIndentation:
29
+ Enabled: true
30
+
31
+ Layout/EmptyLinesAroundModuleBody:
32
+ Enabled: false
33
+
34
+ Layout/EmptyLinesAroundClassBody:
35
+ Enabled: false
36
+
37
+ Layout/DotPosition:
38
+ EnforcedStyle: leading
39
+
40
+ Layout/MultilineMethodCallIndentation:
41
+ EnforcedStyle: indented
42
+
43
+ Layout/HashAlignment:
44
+ EnforcedColonStyle: table
45
+ EnforcedHashRocketStyle: table
46
+
47
+ Layout/FirstArrayElementIndentation:
48
+ EnforcedStyle: consistent
49
+
50
+ Layout/LineLength:
51
+ AutoCorrect: false
52
+ Max: 120
53
+ IgnoredPatterns: ['\A\s*#']
54
+ Exclude:
55
+ - "**/*_spec.rb"
56
+
57
+ Layout/BeginEndAlignment:
58
+ Enabled: true
59
+
60
+ Layout/EmptyLinesAroundAttributeAccessor:
61
+ Enabled: true
62
+
63
+ Layout/SpaceAroundMethodCallOperator:
64
+ Enabled: true
65
+
66
+ ########## STYLE RELATED
67
+ Style/EmptyElse:
68
+ EnforcedStyle: empty
69
+
70
+ Style/FrozenStringLiteralComment:
71
+ EnforcedStyle: always
72
+ Exclude:
73
+ - 'spec/**/*'
74
+
75
+ Style/IfUnlessModifier:
76
+ Enabled: false
77
+
78
+ Style/SymbolArray:
79
+ EnforcedStyle: brackets
80
+
81
+ Style/NumericPredicate:
82
+ EnforcedStyle: comparison
83
+
84
+ Style/ZeroLengthPredicate:
85
+ Enabled: false
86
+
87
+ Style/NegatedIf:
88
+ Enabled: false
89
+
90
+ Style/GuardClause:
91
+ Enabled: false
92
+
93
+ Style/EmptyMethod:
94
+ Enabled: false
95
+
96
+ Style/MultilineTernaryOperator:
97
+ Enabled: false
98
+
99
+ Style/DoubleNegation:
100
+ Enabled: false
101
+
102
+ Style/SingleLineBlockParams:
103
+ Enabled: false
104
+
105
+ Style/RedundantCondition:
106
+ Enabled: false
107
+
108
+ Style/TrailingUnderscoreVariable:
109
+ Enabled: false
110
+
111
+ Style/MultilineBlockChain:
112
+ Enabled: false
113
+
114
+ Style/AsciiComments:
115
+ Enabled: false
116
+
117
+ Style/RedundantReturn:
118
+ Enabled: false
119
+
120
+ Style/HashConversion: # (new in 1.10)
121
+ Enabled: true
122
+
123
+ Style/HashEachMethods:
124
+ Enabled: true
125
+
126
+ Style/HashTransformKeys:
127
+ Enabled: true
128
+
129
+ Style/HashTransformValues:
130
+ Enabled: true
131
+
132
+ Style/TernaryParentheses:
133
+ EnforcedStyle: require_parentheses_when_complex
134
+
135
+ Style/FloatDivision:
136
+ Enabled: false
137
+
138
+ Style/CommentAnnotation:
139
+ Enabled: true
140
+
141
+ Style/CommentedKeyword:
142
+ Enabled: false
143
+
144
+ Style/NumberedParameters: # new in 1.22
145
+ Enabled: true
146
+
147
+ Style/NumberedParametersLimit: # new in 1.22
148
+ Enabled: true
149
+
150
+ Style/OpenStructUse: # new in 1.23
151
+ Enabled: true
152
+ Exclude:
153
+ - 'spec/**/*'
154
+
155
+ Style/SelectByRegexp: # new in 1.22
156
+ Enabled: true
157
+
158
+ Lint/EmptyWhen:
159
+ Enabled: false
160
+
161
+ Lint/RaiseException:
162
+ Enabled: true
163
+
164
+ Lint/RequireRelativeSelfPath: # new in 1.22
165
+ Enabled: true
166
+
167
+ Lint/StructNewOverride:
168
+ Enabled: true
169
+
170
+ Lint/BinaryOperatorWithIdenticalOperands:
171
+ Enabled: true
172
+
173
+ Lint/ConstantDefinitionInBlock:
174
+ Enabled: true
175
+
176
+ Lint/DeprecatedOpenSSLConstant:
177
+ Enabled: true
178
+
179
+ Lint/DuplicateElsifCondition:
180
+ Enabled: false
181
+
182
+ Lint/DuplicateRequire:
183
+ Enabled: false
184
+
185
+ Lint/DuplicateRescueException:
186
+ Enabled: false
187
+
188
+ Lint/EmptyConditionalBody:
189
+ Enabled: false
190
+
191
+ Lint/EmptyFile:
192
+ Enabled: false
193
+
194
+ Lint/FloatComparison:
195
+ Enabled: false
196
+
197
+ Lint/HashCompareByIdentity:
198
+ Enabled: false
199
+
200
+ Lint/IdentityComparison:
201
+ Enabled: false
202
+
203
+ Lint/MissingSuper:
204
+ Enabled: false
205
+
206
+ Lint/MixedRegexpCaptureTypes:
207
+ Enabled: false
208
+
209
+ Lint/NumberedParameterAssignment: # (new in 1.9)
210
+ Enabled: true
211
+
212
+ Lint/OrAssignmentToConstant: # (new in 1.9)
213
+ Enabled: true
214
+
215
+ Lint/OutOfRangeRegexpRef:
216
+ Enabled: false
217
+
218
+ Lint/RedundantSafeNavigation:
219
+ Enabled: false
220
+
221
+ Lint/SelfAssignment:
222
+ Enabled: false
223
+
224
+ Lint/SymbolConversion: # (new in 1.9)
225
+ Enabled: true
226
+
227
+ Lint/TopLevelReturnWithArgument:
228
+ Enabled: false
229
+
230
+ Lint/TrailingCommaInAttributeDeclaration:
231
+ Enabled: false
232
+
233
+ Lint/TripleQuotes: # (new in 1.9)
234
+ Enabled: true
235
+
236
+ Lint/UnreachableLoop:
237
+ Enabled: false
238
+
239
+ Lint/UselessMethodDefinition:
240
+ Enabled: false
241
+
242
+ Lint/UselessRuby2Keywords: # new in 1.23
243
+ Enabled: true
244
+
245
+ Lint/UselessTimes:
246
+ Enabled: false
247
+
248
+ # Disabled as a suggestion from https://github.com/rubocop-hq/rubocop/issues/4222
249
+ Lint/AmbiguousBlockAssociation:
250
+ Exclude:
251
+ - "spec/**/*.rb"
252
+
253
+ Style/AccessorGrouping:
254
+ Enabled: false
255
+
256
+ Style/BisectedAttrAccessor:
257
+ Enabled: false
258
+
259
+ Style/CaseLikeIf:
260
+ Enabled: false
261
+
262
+ Style/ClassEqualityComparison:
263
+ Enabled: false
264
+
265
+ Style/CombinableLoops:
266
+ Enabled: false
267
+
268
+ Style/ExplicitBlockArgument:
269
+ Enabled: false
270
+
271
+ Style/ExponentialNotation:
272
+ Enabled: false
273
+
274
+ Style/GlobalStdStream:
275
+ Enabled: false
276
+
277
+ Style/HashAsLastArrayItem:
278
+ Enabled: false
279
+
280
+ Style/HashLikeCase:
281
+ Enabled: false
282
+
283
+ Style/IfWithBooleanLiteralBranches: # (new in 1.9)
284
+ Enabled: true
285
+
286
+ Style/KeywordParametersOrder:
287
+ Enabled: false
288
+
289
+ Style/OptionalBooleanParameter:
290
+ Enabled: false
291
+
292
+ Style/RedundantAssignment:
293
+ Enabled: false
294
+
295
+ Style/RedundantFetchBlock:
296
+ Enabled: false
297
+
298
+ Style/RedundantFileExtensionInRequire:
299
+ Enabled: false
300
+
301
+ Style/RedundantRegexpCharacterClass:
302
+ Enabled: false
303
+
304
+ Style/RedundantRegexpEscape:
305
+ Enabled: false
306
+
307
+ Style/RedundantSelfAssignment:
308
+ Enabled: false
309
+
310
+ Style/SingleArgumentDig:
311
+ Enabled: false
312
+
313
+ Style/SlicingWithRange:
314
+ Enabled: false
315
+
316
+ Style/SoleNestedConditional:
317
+ Enabled: false
318
+
319
+ Style/StringConcatenation:
320
+ Enabled: false
321
+
322
+ ########## METRICS RELATED
323
+ Metrics/AbcSize:
324
+ Enabled: false
325
+
326
+ Metrics/MethodLength:
327
+ Enabled: false
328
+
329
+ Metrics/ModuleLength:
330
+ Enabled: false
331
+
332
+ Metrics/ClassLength:
333
+ Enabled: false
334
+
335
+ Metrics/BlockLength:
336
+ Enabled: false
337
+
338
+ Metrics/CyclomaticComplexity:
339
+ Enabled: false
340
+
341
+ Metrics/PerceivedComplexity:
342
+ Enabled: false
343
+
344
+ # When running rubocop with autocorrect (-a)
345
+ # this changes our tests for failing operations
346
+ # it { is_expected.to fail.with_error(:foobar) }
347
+ # to
348
+ # it { is_expected.to raise.with_error(:foobar) }
349
+ #
350
+ # which of course does not work ...
351
+ Style/SignalException:
352
+ Exclude:
353
+ - "**/*_spec.rb"
354
+
355
+ Style/FormatString:
356
+ Enabled: true
357
+ Style/FormatStringToken:
358
+ Enabled: false
359
+
360
+ # Added when merging 1.4
361
+ Lint/DuplicateBranch: # (new in 1.3)
362
+ Enabled: true
363
+ Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1)
364
+ Enabled: true
365
+ Lint/EmptyBlock: # (new in 1.1)
366
+ Enabled: true
367
+ Exclude:
368
+ - "**/*_spec.rb"
369
+ Lint/EmptyClass: # (new in 1.3)
370
+ Enabled: true
371
+ Lint/NoReturnInBeginEndBlocks: # (new in 1.2)
372
+ Enabled: true
373
+ Lint/ToEnumArguments: # (new in 1.1)
374
+ Enabled: true
375
+ Lint/UnexpectedBlockArity: # (new in 1.5)
376
+ Enabled: true
377
+ Lint/UnmodifiedReduceAccumulator: # (new in 1.1)
378
+ Enabled: true
379
+
380
+ Style/ArgumentsForwarding: # (new in 1.1)
381
+ Enabled: true
382
+ Style/CollectionCompact: # (new in 1.2)
383
+ Enabled: true
384
+ Style/DocumentDynamicEvalDefinition: # (new in 1.1)
385
+ Enabled: true
386
+ Style/NegatedIfElseCondition: # (new in 1.2)
387
+ Enabled: true
388
+ Style/NilLambda: # (new in 1.3)
389
+ Enabled: true
390
+ Style/RedundantArgument: # (new in 1.4)
391
+ Enabled: false
392
+ Style/SwapValues: # (new in 1.1)
393
+ Enabled: true
394
+
395
+ Layout/SpaceBeforeBrackets: # (new in 1.7)
396
+ # We are using a lot of method calls without parentheses and use an array as an argument.
397
+ # Those calls would be broken
398
+ Enabled: false
399
+ Lint/AmbiguousAssignment: # (new in 1.7)
400
+ Enabled: true
401
+ Style/HashExcept: # (new in 1.7)
402
+ # Ruby 3.0.0 adds Hash#except, all ActiveSupport methods like Hash#reject, etc can be replaced with this native
403
+ # function, once we switch to Ruby 3.0.0. We can enable this cop when we upgrade.
404
+ # See: https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/HashExcept
405
+ Enabled: false
406
+
407
+
408
+ Lint/DeprecatedConstants: # (new in 1.8)
409
+ Enabled: true
410
+ Lint/LambdaWithoutLiteralBlock: # (new in 1.8)
411
+ Enabled: true
412
+ Lint/RedundantDirGlobSort: # (new in 1.8)
413
+ Enabled: true
414
+ Style/EndlessMethod: # (new in 1.8)
415
+ Enabled: true
416
+
417
+ Naming/VariableNumber:
418
+ Enabled: false
419
+
420
+ Gemspec/DateAssignment: # (new in 1.10)
421
+ Enabled: true
422
+
423
+ Gemspec/RequireMFA: # new in 1.23
424
+ Enabled: true
425
+
426
+ Style/StringChars: # (new in 1.12)
427
+ Enabled: true
428
+
429
+ Lint/EmptyInPattern: # (new in 1.16)
430
+ Enabled: true
431
+
432
+ Style/InPatternThen: # (new in 1.16)
433
+ Enabled: true
434
+
435
+ Style/MultilineInPatternThen: # (new in 1.16)
436
+ Enabled: true
437
+
438
+ Style/QuotedSymbols: # (new in 1.16)
439
+ Enabled: true
440
+
441
+ Layout/LineEndStringConcatenationIndentation: # (new in 1.18)
442
+ Enabled: true
443
+
444
+ Naming/InclusiveLanguage: # (new in 1.18)
445
+ Enabled: false
446
+ Severity: info
447
+
448
+ Lint/AmbiguousRange: # (new in 1.19)
449
+ Enabled: true
450
+
451
+ Style/RedundantSelfAssignmentBranch: # (new in 1.19)
452
+ Enabled: true
453
+
454
+ Lint/AmbiguousOperatorPrecedence: # new in 1.21
455
+ Enabled: true
456
+
457
+ Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
458
+ Enabled: true
459
+
460
+ Naming/BlockForwarding: # new in 1.24
461
+ Enabled: true
462
+
463
+ Style/FileRead: # new in 1.24
464
+ Enabled: true
465
+
466
+ Style/FileWrite: # new in 1.24
467
+ Enabled: true
468
+
469
+ Style/MapToHash: # new in 1.24
470
+ Enabled: true
471
+
472
+ # -----------------------------------------------------------------------------
473
+ # RuboCop RSpec Config
474
+
475
+ RSpec/NestedGroups:
476
+ Max: 4
477
+
478
+ RSpec/AnyInstance:
479
+ Enabled: false
480
+
481
+ RSpec/Be:
482
+ Enabled: true
483
+
484
+ RSpec/BeEql:
485
+ Enabled: false
486
+
487
+ RSpec/BeforeAfterAll:
488
+ Enabled: true
489
+
490
+ RSpec/Capybara/VisibilityMatcher:
491
+ Enabled: true
492
+
493
+ RSpec/ContextMethod:
494
+ Enabled: true
495
+
496
+ RSpec/ContextWording:
497
+ Enabled: false
498
+
499
+ RSpec/DescribeClass:
500
+ Enabled: true
501
+
502
+ RSpec/DescribedClass:
503
+ Enabled: true
504
+
505
+ RSpec/EmptyHook:
506
+ Enabled: true
507
+
508
+ RSpec/EmptyLineAfterExampleGroup:
509
+ Enabled: true
510
+
511
+ RSpec/ExampleLength:
512
+ Enabled: false
513
+
514
+ RSpec/ExampleWording:
515
+ Enabled: true
516
+
517
+ RSpec/ExpectChange:
518
+ Enabled: true
519
+
520
+ RSpec/InstanceVariable:
521
+ Enabled: true
522
+
523
+ RSpec/MessageSpies:
524
+ Enabled: true
525
+ EnforcedStyle: receive
526
+
527
+ RSpec/MultipleExpectations:
528
+ Enabled: false
529
+
530
+ RSpec/MultipleMemoizedHelpers:
531
+ Enabled: false
532
+
533
+ RSpec/NamedSubject:
534
+ Enabled: false
535
+
536
+ RSpec/ReceiveCounts:
537
+ Enabled: true
538
+
539
+ RSpec/RepeatedExample:
540
+ Enabled: true
541
+
542
+ RSpec/RepeatedDescription:
543
+ Enabled: true
544
+
545
+ RSpec/StubbedMock:
546
+ Enabled: false
547
+
548
+ RSpec/VariableName:
549
+ EnforcedStyle: snake_case
550
+
551
+ RSpec/VoidExpect:
552
+ Enabled: true
553
+
554
+ RSpec/IdenticalEqualityAssertion: # (new in 2.4)
555
+ Enabled: true
556
+
557
+ RSpec/Rails/AvoidSetupHook: # (new in 2.4)
558
+ Enabled: true
559
+
560
+ RSpec/ExcessiveDocstringSpacing: # new in 2.5
561
+ Enabled: true
562
+
563
+ RSpec/SubjectDeclaration: # new in 2.5
564
+ Enabled: true
565
+
566
+ RSpec/FactoryBot/SyntaxMethods: # new in 2.7
567
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in flexible_polyline.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "rspec", "~> 3.0"
10
+ gem "rubocop", "~> 1.21"
11
+ gem "bigdecimal", "~> 3.1.2"
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ flexible_polyline (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ bigdecimal (3.1.2)
11
+ diff-lcs (1.5.0)
12
+ parallel (1.22.1)
13
+ parser (3.1.2.0)
14
+ ast (~> 2.4.1)
15
+ rainbow (3.1.1)
16
+ rake (13.0.6)
17
+ regexp_parser (2.5.0)
18
+ rexml (3.2.5)
19
+ rspec (3.11.0)
20
+ rspec-core (~> 3.11.0)
21
+ rspec-expectations (~> 3.11.0)
22
+ rspec-mocks (~> 3.11.0)
23
+ rspec-core (3.11.0)
24
+ rspec-support (~> 3.11.0)
25
+ rspec-expectations (3.11.0)
26
+ diff-lcs (>= 1.2.0, < 2.0)
27
+ rspec-support (~> 3.11.0)
28
+ rspec-mocks (3.11.1)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.11.0)
31
+ rspec-support (3.11.0)
32
+ rubocop (1.30.1)
33
+ parallel (~> 1.10)
34
+ parser (>= 3.1.0.0)
35
+ rainbow (>= 2.2.2, < 4.0)
36
+ regexp_parser (>= 1.8, < 3.0)
37
+ rexml (>= 3.2.5, < 4.0)
38
+ rubocop-ast (>= 1.18.0, < 2.0)
39
+ ruby-progressbar (~> 1.7)
40
+ unicode-display_width (>= 1.4.0, < 3.0)
41
+ rubocop-ast (1.18.0)
42
+ parser (>= 3.1.1.0)
43
+ ruby-progressbar (1.11.0)
44
+ unicode-display_width (2.2.0)
45
+
46
+ PLATFORMS
47
+ arm64-darwin-21
48
+
49
+ DEPENDENCIES
50
+ bigdecimal (~> 3.1.2)
51
+ flexible_polyline!
52
+ rake (~> 13.0)
53
+ rspec (~> 3.0)
54
+ rubocop (~> 1.21)
55
+
56
+ BUNDLED WITH
57
+ 2.3.7
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Ozan Bahar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # FlexiblePolyline
2
+
3
+ The flexible polyline encoding from heremaps is a lossy compressed representation of a list of coordinate pairs or coordinate triples.
4
+
5
+ It achieves that by:
6
+
7
+ 1. Reducing the decimal digits of each value.
8
+ 2. Encoding only the offset from the previous point.
9
+ 3. Using variable length for each coordinate delta.
10
+ 4. Using 64 URL-safe characters to display the result.
11
+
12
+ For more information, visit: https://github.com/heremaps/flexible-polyline
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'flexible_polyline', github: 'ioki-mobility/ruby-flexible-polyline'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ $ bundle install
25
+
26
+ ## Usage
27
+
28
+ Encode:
29
+ ```ruby
30
+ FlexiblePolyline::Encoder.encode(third_dim: 1, precision: 8, third_dim_precision: 8, positions: [[-96.628241002595274, 34.155307026461529, 228.390420353746407]])
31
+ ```
32
+ =>
33
+ "B4gBnq_r-_R-suzyrGm_vgqxqB"
34
+
35
+ Decode:
36
+ ```ruby
37
+ FlexiblePolyline::Decoder.decode('B4gBnq_r-_R-suzyrGm_vgqxqB')
38
+ ```
39
+
40
+ =>
41
+ ```json
42
+ {"header": {"precision": 8, "third_dim": 1, "third_dim_precision": 8}, "positions": [[-96.628241, 34.15530703, 228.39042035]]}
43
+ ```
44
+
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
+
50
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
51
+
52
+ ## Contributing
53
+
54
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ioki-mobility/flexible_polyline.
55
+
56
+ ## License
57
+
58
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/flexible_polyline/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "flexible_polyline"
7
+ spec.version = FlexiblePolyline::VERSION
8
+ spec.authors = ["Ozan Bahar"]
9
+ spec.email = ["ozan.bahar@ioki.com"]
10
+
11
+ spec.summary = 'A ruby implementation of here`s flexible-polyline library.'
12
+ spec.description = <<~DESCRIPTION
13
+ The flexible polyline encoding from heremaps is a lossy compressed representation of a list of coordinate pairs or coordinate triples. It achieves that by:
14
+ 1. Reducing the decimal digits of each value.
15
+ 2. Encoding only the offset from the previous point.
16
+ 3. Using variable length for each coordinate delta.
17
+ 4. Using 64 URL-safe characters to display the result.
18
+
19
+ For more information, visit: https://github.com/heremaps/flexible-polyline
20
+ DESCRIPTION
21
+ spec.homepage = 'https://github.com/ioki-mobility/ruby-flexible-polyline'
22
+ spec.license = "MIT"
23
+ spec.required_ruby_version = ">= 2.6.0"
24
+
25
+ #spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
26
+
27
+ spec.metadata['homepage_uri'] = spec.homepage
28
+ spec.metadata['source_code_uri'] = 'https://github.com/ioki-mobility/ruby-flexible-polyline'
29
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/ioki-mobility/ruby-flexible-polyline/issues'
30
+ spec.metadata['changelog_uri'] = 'https://github.com/ioki-mobility/ruby-flexible-polyline/blob/main/CHANGELOG.md'
31
+
32
+ # Specify which files should be added to the gem when it is released.
33
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
34
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
35
+ `git ls-files -z`.split("\x0").reject do |f|
36
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
37
+ end
38
+ end
39
+ spec.bindir = "exe"
40
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
41
+ spec.require_paths = ["lib"]
42
+
43
+ # Uncomment to register a new dependency of your gem
44
+ # spec.add_dependency "example-gem", "~> 1.0"
45
+
46
+ # For more information and examples about making a new gem, check out our
47
+ # guide at: https://bundler.io/guides/creating_gem.html
48
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiblePolyline
4
+
5
+ class Decoder
6
+ DECODING_TABLE = [
7
+ 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1,
8
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
9
+ 22, 23, 24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
10
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
11
+ ].freeze
12
+ FORMAT_VERSION = 1
13
+
14
+ class << self
15
+
16
+ def decode(encoded)
17
+ decoder = decode_unsigned_values(encoded)
18
+ header = decode_header(decoder[0], decoder[1])
19
+
20
+ factor_degree = 10**header[:precision]
21
+ factor_z = 10**header[:third_dim_precision]
22
+ third_dim = header[:third_dim]
23
+
24
+ last_lat = 0
25
+ last_lng = 0
26
+ last_z = 0
27
+ res = []
28
+
29
+ cnt = 2
30
+ while cnt < decoder.size - 1
31
+ delta_lat = to_signed(decoder[cnt]) / factor_degree.to_f
32
+ delta_lng = to_signed(decoder[cnt + 1]) / factor_degree.to_f
33
+ last_lat += delta_lat
34
+ last_lng += delta_lng
35
+
36
+ if third_dim.zero?
37
+ res << [last_lat.round(header[:precision]), last_lng.round(header[:precision])]
38
+ cnt += 2
39
+ else
40
+ delta_z = to_signed(decoder[cnt + 2]) / factor_z.to_f
41
+ last_z += delta_z
42
+ res << [last_lat.round(header[:precision]),
43
+ last_lng.round(header[:precision]),
44
+ last_z.round(header[:third_dim_precision])]
45
+ cnt += 3
46
+ end
47
+ end
48
+
49
+ raise StandardError, 'Invalid encoding. Premature ending reached' if cnt != decoder.size
50
+ {
51
+ header: header,
52
+ positions: res
53
+ }
54
+ end
55
+
56
+ private
57
+
58
+ def decode_char(char)
59
+ DECODING_TABLE[char[0].ord - 45]
60
+ end
61
+
62
+ def decode_unsigned_values(encoded)
63
+ result = 0
64
+ shift = 0
65
+ result_list = []
66
+
67
+ encoded.chars.each do |char|
68
+ value = decode_char(char)
69
+ result |= (value & 0x1F) << shift
70
+ if (value & 0x20).zero?
71
+ result_list << result
72
+ result = 0
73
+ shift = 0
74
+ else
75
+ shift += 5
76
+ end
77
+ end
78
+
79
+ raise StandardError, 'Invalid encoding' if shift.positive?
80
+
81
+ result_list
82
+ end
83
+
84
+ def decode_header(version, encoded_header)
85
+ raise StandardError, 'Invalid format version' if to_numeric(version) != FORMAT_VERSION
86
+
87
+ header_number = to_numeric(encoded_header)
88
+ precision = header_number & 15
89
+ third_dim = (header_number >> 4) & 7
90
+ third_dim_precision = (header_number >> 7) & 15
91
+ {
92
+ precision: precision,
93
+ third_dim: third_dim,
94
+ third_dim_precision: third_dim_precision
95
+ }
96
+ end
97
+
98
+ def to_signed(val)
99
+ val = ~val unless (val & 1).zero?
100
+ to_numeric(val >> 1)
101
+ end
102
+
103
+ def to_numeric(value)
104
+ num = BigDecimal(value.to_s)
105
+ if num.frac.zero?
106
+ num.to_i
107
+ else
108
+ num.to_f
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiblePolyline
4
+
5
+ class Encoder
6
+
7
+ ENCODING_TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
8
+ PRECISION = 5
9
+ FORMAT_VERSION = 1
10
+
11
+ class << self
12
+
13
+ def encode(positions:, precision: nil, third_dim: nil, third_dim_precision: nil)
14
+ precision ||= PRECISION
15
+ third_dim ||= 0
16
+ third_dim_precision ||= 0
17
+ multiplier_degree = 10**precision
18
+ multiplier_z = 10**third_dim_precision
19
+ encoded_header_list = encode_header(precision, third_dim, third_dim_precision)
20
+ encoded_coords = []
21
+
22
+ last_lat = 0
23
+ last_lng = 0
24
+ last_z = 0
25
+ positions.each do |location|
26
+ lat = (location[0] * multiplier_degree).round
27
+ encoded_coords << encode_scaled_value(lat - last_lat)
28
+ last_lat = lat
29
+
30
+ lng = (location[1] * multiplier_degree).round
31
+ encoded_coords << encode_scaled_value(lng - last_lng)
32
+ last_lng = lng
33
+
34
+ next if third_dim.zero?
35
+
36
+ z = (location[2] * multiplier_z).round
37
+ encoded_coords << encode_scaled_value(z - last_z)
38
+ last_z = z
39
+ end
40
+ [encoded_header_list, encoded_coords].join('')
41
+ end
42
+
43
+ private
44
+
45
+ def encode_header(precision, third_dim, third_dim_precision)
46
+ if precision.negative? || precision > 15
47
+ raise StandardError, 'precision out of range. Should be between 0 and 15'
48
+ end
49
+ if third_dim_precision.negative? || third_dim_precision > 15
50
+ raise StandardError, 'third_dim_precision out of range. Should be between 0 and 15'
51
+ end
52
+ if third_dim.negative? || third_dim > 7 || third_dim == 4 || third_dim == 5
53
+ raise StandardError, 'third_dim should be between 0, 1, 2, 3, 6 or 7'
54
+ end
55
+
56
+ res = (third_dim_precision << 7) | (third_dim << 4) | precision
57
+ encode_unsigned_number(FORMAT_VERSION) + encode_unsigned_number(res)
58
+ end
59
+
60
+ def encode_unsigned_number(val)
61
+ res = String.new
62
+ val = Integer(val)
63
+ while val > 0x1F
64
+ pos = (val & 0x1F) | 0x20
65
+ res << (ENCODING_TABLE[pos]).to_s
66
+ val >>= 5
67
+ end
68
+ "#{res}#{ENCODING_TABLE[val]}"
69
+ end
70
+
71
+ def encode_scaled_value(value)
72
+ value = Integer(value)
73
+
74
+ negative = value.negative?
75
+ value <<= 1
76
+ if negative
77
+ value = ~value
78
+ end
79
+ encode_unsigned_number(value)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiblePolyline
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'flexible_polyline/version'
4
+ require 'bigdecimal'
5
+
6
+ module FlexiblePolyline
7
+ require 'flexible_polyline/encoder'
8
+ require 'flexible_polyline/decoder'
9
+ end
@@ -0,0 +1,4 @@
1
+ module FlexiblePolyline
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flexible_polyline
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ozan Bahar
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-06-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |
14
+ The flexible polyline encoding from heremaps is a lossy compressed representation of a list of coordinate pairs or coordinate triples. It achieves that by:
15
+ 1. Reducing the decimal digits of each value.
16
+ 2. Encoding only the offset from the previous point.
17
+ 3. Using variable length for each coordinate delta.
18
+ 4. Using 64 URL-safe characters to display the result.
19
+
20
+ For more information, visit: https://github.com/heremaps/flexible-polyline
21
+ email:
22
+ - ozan.bahar@ioki.com
23
+ executables: []
24
+ extensions: []
25
+ extra_rdoc_files: []
26
+ files:
27
+ - ".rspec"
28
+ - ".rubocop.yml"
29
+ - Gemfile
30
+ - Gemfile.lock
31
+ - LICENSE.txt
32
+ - README.md
33
+ - Rakefile
34
+ - flexible_polyline.gemspec
35
+ - lib/flexible_polyline.rb
36
+ - lib/flexible_polyline/decoder.rb
37
+ - lib/flexible_polyline/encoder.rb
38
+ - lib/flexible_polyline/version.rb
39
+ - sig/flexible_polyline.rbs
40
+ homepage: https://github.com/ioki-mobility/ruby-flexible-polyline
41
+ licenses:
42
+ - MIT
43
+ metadata:
44
+ homepage_uri: https://github.com/ioki-mobility/ruby-flexible-polyline
45
+ source_code_uri: https://github.com/ioki-mobility/ruby-flexible-polyline
46
+ bug_tracker_uri: https://github.com/ioki-mobility/ruby-flexible-polyline/issues
47
+ changelog_uri: https://github.com/ioki-mobility/ruby-flexible-polyline/blob/main/CHANGELOG.md
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.6.0
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubygems_version: 3.3.7
64
+ signing_key:
65
+ specification_version: 4
66
+ summary: A ruby implementation of here`s flexible-polyline library.
67
+ test_files: []