fast-polylines 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +29 -22
- data/ext/fast_polylines/extconf.rb +10 -0
- data/ext/fast_polylines/fast_polylines.c +7 -2
- data/lib/fast_polylines/version.rb +1 -1
- data/spec/fast_polylines_spec.rb +28 -5
- data/spec/spec_helper.rb +3 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b799fba2f53eb5a319d237b5460cfc20185bbe757108420ed4a2c95414ab3b5
|
4
|
+
data.tar.gz: 7853302b6843e13d4ce0161be04c4deb514a4bbd62e3c0f2fd334c00ef3b6d72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5381b5bcaa24e8dc5a6d397dc514fdeed8dc20c894a855385ba78af691e10bab8442b9d93329af658a6a8eba3a26716aff3fb3f9f2a238ca1cc1d5dea4a10243
|
7
|
+
data.tar.gz: '08733692f3f9e7ac461434f57b82b0c689e981eac015f57c92a7be94ae0195f72a283695e876120018f14aa8f8be6095640bf86631eb166701af17f601b624f4'
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Implementation of the [Google polyline algorithm][algorithm].
|
7
7
|
|
8
|
-
**BREAKING CHANGES:** The version 2
|
8
|
+
**BREAKING CHANGES:** The version 2 of FastPolylines includes breaking changes, see [Migrate from V1](#migrate-from-V1)
|
9
9
|
|
10
10
|
|
11
11
|
About **300x faster encoding and decoding** than [Joshua Clayton's gem][polylines].
|
@@ -16,35 +16,35 @@ About **300x faster encoding and decoding** than [Joshua Clayton's gem][polylin
|
|
16
16
|
——————————————————————————————— ENCODING ————————————————————————————————
|
17
17
|
|
18
18
|
Warming up --------------------------------------
|
19
|
-
Polylines
|
20
|
-
FastPolylinesV1 2.
|
21
|
-
FastPolylinesV2
|
19
|
+
Polylines 310.000 i/100ms
|
20
|
+
FastPolylinesV1 2.607k i/100ms
|
21
|
+
FastPolylinesV2 59.833k i/100ms
|
22
22
|
Calculating -------------------------------------
|
23
|
-
Polylines
|
24
|
-
FastPolylinesV1 25.
|
25
|
-
FastPolylinesV2
|
23
|
+
Polylines 2.957k (± 5.9%) i/s - 14.880k in 5.049867s
|
24
|
+
FastPolylinesV1 25.644k (± 5.8%) i/s - 127.743k in 4.999954s
|
25
|
+
FastPolylinesV2 682.981k (± 7.7%) i/s - 3.410M in 5.025952s
|
26
26
|
|
27
27
|
Comparison:
|
28
|
-
FastPolylinesV2:
|
29
|
-
FastPolylinesV1:
|
30
|
-
Polylines:
|
28
|
+
FastPolylinesV2: 682980.7 i/s
|
29
|
+
FastPolylinesV1: 25643.7 i/s - 26.63x slower
|
30
|
+
Polylines: 2957.1 i/s - 230.97x slower
|
31
31
|
|
32
32
|
|
33
33
|
——————————————————————————————— DECODING ————————————————————————————————
|
34
34
|
|
35
35
|
Warming up --------------------------------------
|
36
|
-
Polylines
|
37
|
-
FastPolylinesV1 1.
|
38
|
-
FastPolylinesV2
|
36
|
+
Polylines 127.000 i/100ms
|
37
|
+
FastPolylinesV1 1.225k i/100ms
|
38
|
+
FastPolylinesV2 40.667k i/100ms
|
39
39
|
Calculating -------------------------------------
|
40
|
-
Polylines 1.
|
41
|
-
FastPolylinesV1
|
42
|
-
FastPolylinesV2
|
40
|
+
Polylines 1.289k (± 6.1%) i/s - 6.477k in 5.046552s
|
41
|
+
FastPolylinesV1 15.445k (± 4.4%) i/s - 77.175k in 5.006896s
|
42
|
+
FastPolylinesV2 468.413k (± 7.8%) i/s - 2.359M in 5.068936s
|
43
43
|
|
44
44
|
Comparison:
|
45
|
-
FastPolylinesV2:
|
46
|
-
FastPolylinesV1:
|
47
|
-
Polylines:
|
45
|
+
FastPolylinesV2: 468412.8 i/s
|
46
|
+
FastPolylinesV1: 15445.4 i/s - 30.33x slower
|
47
|
+
Polylines: 1288.8 i/s - 363.46x slower
|
48
48
|
```
|
49
49
|
|
50
50
|
## Install
|
@@ -61,7 +61,7 @@ gem "fast-polylines", "~> 2.0.0"
|
|
61
61
|
## Usage
|
62
62
|
|
63
63
|
```ruby
|
64
|
-
require "
|
64
|
+
require "fast_polylines"
|
65
65
|
|
66
66
|
FastPolylines.encode([[38.5, -120.2], [40.7, -120.95], [43.252, -126.453]])
|
67
67
|
# "_p~iF~ps|U_ulLnnqC_mqNvxq`@"
|
@@ -74,7 +74,7 @@ FastPolylines.decode("_p~iF~ps|U_ulLnnqC_mqNvxq`@")
|
|
74
74
|
|
75
75
|
**Use a different precision**
|
76
76
|
|
77
|
-
Default precision is `5` decimals, to use a precision of `6
|
77
|
+
Default precision is `5` decimals, to use a precision of `6`:
|
78
78
|
```ruby
|
79
79
|
FastPolylines.encode([[38.5, -120.2], [40.7, -120.95], [43.252, -126.453]], 6)
|
80
80
|
# "_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI"
|
@@ -84,17 +84,21 @@ FastPolylines.decode("_izlhA~rlgdF_{geC~ywl@_kwzCn`{nI", 6)
|
|
84
84
|
```
|
85
85
|
The precision max is `13`.
|
86
86
|
|
87
|
-
##
|
87
|
+
## Migrate from V1
|
88
88
|
|
89
89
|
**TL;DR:**
|
90
90
|
|
91
91
|
```ruby
|
92
92
|
# before
|
93
|
+
require "fast-polylines"
|
93
94
|
FastPolylines::Encoder.encode([[1.2, 1.2], [2.4, 2.4]], 1e6)
|
94
95
|
# after
|
96
|
+
require "fast_polylines"
|
95
97
|
FastPolylines.encode([[1.2, 1.2], [2.4, 2.4]], 6)
|
96
98
|
```
|
97
99
|
|
100
|
+
**Detailled:**
|
101
|
+
|
98
102
|
The new version of `FastPolylines` doesn't support precision more than `1e13`,
|
99
103
|
you should not consider using it anyway since [it is way too precise][xkcd].
|
100
104
|
|
@@ -106,6 +110,9 @@ The precision is now an integer representing the number of decimals. It is
|
|
106
110
|
slightly smaller, and mostly this will avoid having any float value as
|
107
111
|
precision.
|
108
112
|
|
113
|
+
The file name to require is now snake_cased, you'll have to require
|
114
|
+
`fast_polylines`. The gem name stays the same however.
|
115
|
+
|
109
116
|
## Run the Benchmark
|
110
117
|
|
111
118
|
You can run the benchmark with `make benchmark`.
|
@@ -72,15 +72,18 @@ rb_FastPolylines__decode(int argc, VALUE *argv, VALUE self) {
|
|
72
72
|
|
73
73
|
static inline uint8_t
|
74
74
|
_polyline_encode_number(char *chunks, int64_t number) {
|
75
|
+
dbg("_polyline_encode_number(\"%s\", %lli)\n", chunks, number);
|
75
76
|
number = number < 0 ? ~(number << 1) : (number << 1);
|
76
77
|
uint8_t i = 0;
|
77
|
-
while (number
|
78
|
+
while (number >= 0x20) {
|
78
79
|
uint8_t chunk = number & 0x1f;
|
79
80
|
chunks[i++] = (0x20 | chunk) + 63;
|
80
81
|
number = number >> 5;
|
81
82
|
}
|
82
|
-
dbg("%u encoded chunks\n", i);
|
83
83
|
chunks[i++] = number + 63;
|
84
|
+
dbg("%u encoded chunks\n", i);
|
85
|
+
dbg("chunks: %s\n", chunks);
|
86
|
+
dbg("/_polyline_encode_number");
|
84
87
|
return i;
|
85
88
|
}
|
86
89
|
|
@@ -108,6 +111,7 @@ rb_FastPolylines__encode(int argc, VALUE *argv, VALUE self) {
|
|
108
111
|
for (i = 0; i < len; i++) {
|
109
112
|
current_pair = RARRAY_AREF(argv[0], i);
|
110
113
|
uint8_t j;
|
114
|
+
Check_Type(current_pair, T_ARRAY);
|
111
115
|
if (RARRAY_LEN(current_pair) != 2) {
|
112
116
|
free(chunks);
|
113
117
|
rb_raise(rb_eArgError, "wrong number of coordinates");
|
@@ -136,6 +140,7 @@ rb_FastPolylines__encode(int argc, VALUE *argv, VALUE self) {
|
|
136
140
|
// We pass a pointer to the current chunk that need to be filled. Doing so
|
137
141
|
// avoid having to copy the string every single iteration.
|
138
142
|
chunks_index += _polyline_encode_number(chunks + chunks_index * sizeof(char), delta);
|
143
|
+
dbg("%s\n", chunks);
|
139
144
|
}
|
140
145
|
}
|
141
146
|
dbg("final chunks_index: %zu\n", chunks_index);
|
data/spec/fast_polylines_spec.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
1
|
describe FastPolylines do
|
4
2
|
describe ".decode" do
|
5
3
|
let(:points) { [[38.5, -120.2], [40.7, -120.95], [43.252, -126.453]] }
|
4
|
+
let(:polyline) { "_p~iF~ps|U_ulLnnqC_mqNvxq`@" }
|
6
5
|
context "with default precision" do
|
7
|
-
let(:polyline) { "_p~iF~ps|U_ulLnnqC_mqNvxq`@" }
|
8
6
|
it "should decode a polyline correctly" do
|
9
7
|
expect(described_class.decode(polyline)).to eq points
|
10
8
|
end
|
@@ -47,9 +45,34 @@ describe FastPolylines do
|
|
47
45
|
end
|
48
46
|
|
49
47
|
describe ".encode" do
|
50
|
-
let(:points)
|
48
|
+
let(:points) { [[38.5, -120.2], [40.7, -120.95], [43.252, -126.453]] }
|
49
|
+
let(:polyline) { "_p~iF~ps|U_ulLnnqC_mqNvxq`@" }
|
50
|
+
it "should raise for invalid input" do
|
51
|
+
expect { described_class.encode(points[0]) }.to raise_error(
|
52
|
+
TypeError,
|
53
|
+
"wrong argument type Float (expected Array)"
|
54
|
+
)
|
55
|
+
expect { described_class.encode([points]) }.to raise_error(
|
56
|
+
ArgumentError,
|
57
|
+
"wrong number of coordinates"
|
58
|
+
)
|
59
|
+
expect { described_class.encode([points[0..1]]) }.to raise_error(
|
60
|
+
TypeError,
|
61
|
+
"no implicit conversion to Float from Array"
|
62
|
+
)
|
63
|
+
end
|
64
|
+
# The method `_polyline_encode_number("", 16)` will check for a chunk
|
65
|
+
# of the size 32, which is the chunk size limit. This was errored due to
|
66
|
+
# a bad sign.
|
67
|
+
# Reported in issue #15, closed in PR #16
|
68
|
+
context "with points close to the chunk size limit" do
|
69
|
+
let(:points) { [[0, 0.00016]] }
|
70
|
+
let(:polyline) { "?_@" }
|
71
|
+
it "should encode points correctly" do
|
72
|
+
expect(described_class.encode(points)).to eq polyline
|
73
|
+
end
|
74
|
+
end
|
51
75
|
context "with default precision" do
|
52
|
-
let(:polyline) { "_p~iF~ps|U_ulLnnqC_mqNvxq`@" }
|
53
76
|
it "should encode points correctly" do
|
54
77
|
expect(described_class.encode(points)).to eq polyline
|
55
78
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast-polylines
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyrille Courtière
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-04-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: benchmark-ips
|
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
requirements: []
|
91
|
-
rubygems_version: 3.0.
|
91
|
+
rubygems_version: 3.1.0.pre3
|
92
92
|
signing_key:
|
93
93
|
specification_version: 4
|
94
94
|
summary: Fast & easy Google polylines
|