simplify_rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e13939f627822e4b0114f8d60c15a31788f0a03d
4
+ data.tar.gz: 41a9e75f2bd598f291849286f468b9bfd42b9829
5
+ SHA512:
6
+ metadata.gz: 3e4a59ca16d463d9b236add0318e1ebad3fe5907652001bd7a85b8c7e9a542168be5d1a5dc4c266cf13fa79f8216f5e327e778723ecfc5934addae64aefd7789
7
+ data.tar.gz: 1ccd9699ab4066cb5903191334ea39a21d2425aa9788934bce288f7204a8aceaae1f826c1f53c7cb2122f50ca31fed3469e097353f4b5600a76674e578fdecc4
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in simplify_rb.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 odlp
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # SimplifyRb - Polyline simplification
2
+
3
+ SimplifyRb is a Ruby port of [simplify.js](https://github.com/mourner/simplify-js) by Vladimir Agafonkin.
4
+
5
+ You can use this gem to reduce the number of points in a complex polyline / polygon, making use of an optimized Douglas-Peucker algorithm.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'simplify_rb'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install simplify_rb
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'simplify_rb'
25
+
26
+ SimplifyRb.simplify(points, tolerance, high_quality)
27
+ ```
28
+
29
+ ```points```: An array of hashes, containing x,y coordinates: ```{x: 51.5256, y: -0.0875}```
30
+
31
+ ```tolerance```: (optional, 1 by default): Affects the amount of simplification that occurs (the smaller, the less simplification)
32
+
33
+ ```highestQuality```: (optional, False by default): Flag to exclude the distance pre-processing. Produces higher quality results when true is passed, but runs slower
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,113 @@
1
+ require "simplify_rb/version"
2
+
3
+ class SimplifyRb
4
+ # Main method
5
+ def self.simplify (points, tolerance=1, highest_quality=false)
6
+ return points if points.length <= 1
7
+
8
+ points = symbolize_keys(points) unless keys_are_symbols?(points.map{|p| p.keys})
9
+
10
+ sq_tolerance = tolerance * tolerance
11
+
12
+ # Optimisation step 1
13
+ points = simplifyRadialDist(points, sq_tolerance) unless highest_quality
14
+
15
+ # Optimisation step 2
16
+ simplifyDouglasPeucker(points, sq_tolerance)
17
+ end
18
+
19
+ # Basic distance-based simplification
20
+ def self.simplifyRadialDist (points, sq_tolerance)
21
+ new_points = [points.first]
22
+
23
+ points.each do |point|
24
+ new_points << point if (getSqDist(point, new_points.last) > sq_tolerance)
25
+ end
26
+
27
+ new_points << points.last unless new_points.last == points.last
28
+
29
+ new_points
30
+ end
31
+
32
+ # Simplification using optimized Douglas-Peucker algorithm with recursion elimination
33
+ def self.simplifyDouglasPeucker (points, sq_tolerance)
34
+ length = points.length
35
+ first = 0
36
+ last = length - 1
37
+ index = nil
38
+ stack = []
39
+
40
+ points.first[:keep] = true
41
+ points.last[:keep] = true
42
+
43
+ while last do
44
+ max_sq_dist = 0
45
+
46
+ ((first + 1)...last).each do |i|
47
+ sq_dist = getSqSegDist(points[i], points[first], points[last])
48
+
49
+ if sq_dist > max_sq_dist
50
+ index = i
51
+ max_sq_dist = sq_dist
52
+ end
53
+ end
54
+
55
+ if max_sq_dist > sq_tolerance
56
+ points[index][:keep] = true
57
+
58
+ stack.push(first, index, index, last)
59
+ end
60
+
61
+ last = stack.pop
62
+ first = stack.pop
63
+
64
+ end # end while
65
+
66
+ points.keep_if { |p| p[:keep] && p.delete(:keep) }
67
+ end
68
+
69
+ # Square distance between two points
70
+ def self.getSqDist (point_1, point_2)
71
+ dx = point_1[:x] - point_2[:x]
72
+ dy = point_1[:y] - point_2[:y]
73
+
74
+ dx * dx + dy * dy
75
+ end
76
+
77
+ # Square distance from a point to a segment
78
+ def self.getSqSegDist (point, point_1, point_2)
79
+ x = point_1[:x]
80
+ y = point_1[:y]
81
+ dx = point_2[:x] - x
82
+ dy = point_2[:y] - y
83
+
84
+ if (dx != 0 || dy != 0)
85
+ t = ((point[:x] - x) * dx + (point[:y] - y) * dy) / (dx * dx + dy * dy)
86
+
87
+ if t > 1
88
+ x = point_2[:x]
89
+ y = point_2[:y]
90
+ elsif t > 0
91
+ x += dx * t
92
+ y += dy * t
93
+ end
94
+ end
95
+
96
+ dx = point[:x] - x
97
+ dy = point[:y] - y
98
+
99
+ dx * dx + dy * dy
100
+ end
101
+
102
+ # Check if keys are symbols
103
+ def self.keys_are_symbols? (keys)
104
+ keys.all? {|k| k.is_a? Symbol}
105
+ end
106
+
107
+ # Symbolize all the hash keys in an array of hashes
108
+ def self.symbolize_keys (collection)
109
+ collection.map do |item|
110
+ item.each_with_object({}) { |(k,v), memo| memo[k.to_sym] = v }
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,3 @@
1
+ class SimplifyRb
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'simplify_rb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "simplify_rb"
8
+ spec.version = SimplifyRb::VERSION
9
+ spec.authors = ["odlp"]
10
+ spec.description = "You can use this gem to reduce the number of points in a complex polyline / polygon, making use of an optimized Douglas-Peucker algorithm."
11
+ spec.summary = "Polyline simplification library. Ruby port of Simplify.js."
12
+ spec.homepage = "https://github.com/odlp/simplify_rb"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "rake", "~> 10"
22
+ spec.add_development_dependency "rspec", "~> 3"
23
+ end
@@ -0,0 +1,43 @@
1
+ require "spec_helper"
2
+
3
+ describe SimplifyRb do
4
+ context "simplifies points correctly with the given tolerance" do
5
+ before(:each) {@test_data = SimplifyTestData::points}
6
+
7
+ it "with the fast strategy (default)" do
8
+ expect(SimplifyRb.simplify(@test_data, 5)).to eq(SimplifyTestData::result_fast)
9
+ end
10
+
11
+ it "with the high quality strategy" do
12
+ expect(SimplifyRb.simplify(@test_data, 5, true)).to eq(SimplifyTestData::result_high_quality)
13
+ end
14
+ end
15
+
16
+ it "returns the points if it has only one point" do
17
+ data = [{x: 1, y: 2}]
18
+
19
+ expect(SimplifyRb.simplify(data)).to eq(data)
20
+ end
21
+
22
+ it "returns the array if it has no points" do
23
+ expect(SimplifyRb.simplify([])).to eq([])
24
+ end
25
+
26
+ context "#keys_are_symbols?" do
27
+ it "should return false if any key is not a Symbol" do
28
+ expect(SimplifyRb.keys_are_symbols? [:a, 'b', :c]).to equal(false)
29
+ end
30
+
31
+ it "should return true if all the keys are Symbols" do
32
+ expect(SimplifyRb.keys_are_symbols? [:a, :b, :c]).to equal(true)
33
+ end
34
+ end
35
+
36
+ context "#symbolize_keys" do
37
+ it "should convert all of the collection's keys to symbols" do
38
+ collection = [{'a' => 1, 'b' => 2}, {'c' => 3}]
39
+
40
+ expect(SimplifyRb.symbolize_keys(collection)).to eq([{a: 1, b: 2}, {c: 3}])
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ module SimplifyTestData
2
+ def self.points
3
+ [
4
+ {x:224.55,y:250.15},{x:226.91,y:244.19},{x:233.31,y:241.45},{x:234.98,y:236.06},
5
+ {x:244.21,y:232.76},{x:262.59,y:215.31},{x:267.76,y:213.81},{x:273.57,y:201.84},
6
+ {x:273.12,y:192.16},{x:277.62,y:189.03},{x:280.36,y:181.41},{x:286.51,y:177.74},
7
+ {x:292.41,y:159.37},{x:296.91,y:155.64},{x:314.95,y:151.37},{x:319.75,y:145.16},
8
+ {x:330.33,y:137.57},{x:341.48,y:139.96},{x:369.98,y:137.89},{x:387.39,y:142.51},
9
+ {x:391.28,y:139.39},{x:409.52,y:141.14},{x:414.82,y:139.75},{x:427.72,y:127.30},
10
+ {x:439.60,y:119.74},{x:474.93,y:107.87},{x:486.51,y:106.75},{x:489.20,y:109.45},
11
+ {x:493.79,y:108.63},{x:504.74,y:119.66},{x:512.96,y:122.35},{x:518.63,y:120.89},
12
+ {x:524.09,y:126.88},{x:529.57,y:127.86},{x:534.21,y:140.93},{x:539.27,y:147.24},
13
+ {x:567.69,y:148.91},{x:575.25,y:157.26},{x:580.62,y:158.15},{x:601.53,y:156.85},
14
+ {x:617.74,y:159.86},{x:622.00,y:167.04},{x:629.55,y:194.60},{x:638.90,y:195.61},
15
+ {x:641.26,y:200.81},{x:651.77,y:204.56},{x:671.55,y:222.55},{x:683.68,y:217.45},
16
+ {x:695.25,y:219.15},{x:700.64,y:217.98},{x:703.12,y:214.36},{x:712.26,y:215.87},
17
+ {x:721.49,y:212.81},{x:727.81,y:213.36},{x:729.98,y:208.73},{x:735.32,y:208.20},
18
+ {x:739.94,y:204.77},{x:769.98,y:208.42},{x:779.60,y:216.87},{x:784.20,y:218.16},
19
+ {x:800.24,y:214.62},{x:810.53,y:219.73},{x:817.19,y:226.82},{x:820.77,y:236.17},
20
+ {x:827.23,y:236.16},{x:829.89,y:239.89},{x:851.00,y:248.94},{x:859.88,y:255.49},
21
+ {x:865.21,y:268.53},{x:857.95,y:280.30},{x:865.48,y:291.45},{x:866.81,y:298.66},
22
+ {x:864.68,y:302.71},{x:867.79,y:306.17},{x:859.87,y:311.37},{x:860.08,y:314.35},
23
+ {x:858.29,y:314.94},{x:858.10,y:327.60},{x:854.54,y:335.40},{x:860.92,y:343.00},
24
+ {x:856.43,y:350.15},{x:851.42,y:352.96},{x:849.84,y:359.59},{x:854.56,y:365.53},
25
+ {x:849.74,y:370.38},{x:844.09,y:371.89},{x:844.75,y:380.44},{x:841.52,y:383.67},
26
+ {x:839.57,y:390.40},{x:845.59,y:399.05},{x:848.40,y:407.55},{x:843.71,y:411.30},
27
+ {x:844.09,y:419.88},{x:839.51,y:432.76},{x:841.33,y:441.04},{x:847.62,y:449.22},
28
+ {x:847.16,y:458.44},{x:851.38,y:462.79},{x:853.97,y:471.15},{x:866.36,y:480.77}
29
+ ]
30
+ end
31
+
32
+ def self.result_fast
33
+ [
34
+ {x:224.55,y:250.15},{x:267.76,y:213.81},{x:296.91,y:155.64},{x:330.33,y:137.57},
35
+ {x:409.52,y:141.14},{x:439.6,y:119.74},{x:486.51,y:106.75},{x:529.57,y:127.86},
36
+ {x:539.27,y:147.24},{x:617.74,y:159.86},{x:629.55,y:194.6},{x:671.55,y:222.55},
37
+ {x:727.81,y:213.36},{x:739.94,y:204.77},{x:769.98,y:208.42},{x:779.6,y:216.87},
38
+ {x:800.24,y:214.62},{x:820.77,y:236.17},{x:859.88,y:255.49},{x:865.21,y:268.53},
39
+ {x:857.95,y:280.3},{x:867.79,y:306.17},{x:859.87,y:311.37},{x:854.54,y:335.4},
40
+ {x:860.92,y:343},{x:849.84,y:359.59},{x:854.56,y:365.53},{x:844.09,y:371.89},
41
+ {x:839.57,y:390.4},{x:848.4,y:407.55},{x:839.51,y:432.76},{x:853.97,y:471.15},
42
+ {x:866.36,y:480.77}]
43
+ end
44
+
45
+ def self.result_high_quality
46
+ [{x:224.55,y:250.15},{x:267.76,y:213.81},{x:296.91,y:155.64},{x:330.33,y:137.57},
47
+ {x:409.52,y:141.14},{x:439.6,y:119.74},{x:486.51,y:106.75},{x:529.57,y:127.86},
48
+ {x:539.27,y:147.24},{x:617.74,y:159.86},{x:629.55,y:194.6},{x:671.55,y:222.55},
49
+ {x:727.81,y:213.36},{x:739.94,y:204.77},{x:769.98,y:208.42},{x:784.2,y:218.16},
50
+ {x:800.24,y:214.62},{x:820.77,y:236.17},{x:859.88,y:255.49},{x:865.21,y:268.53},
51
+ {x:857.95,y:280.3},{x:867.79,y:306.17},{x:858.29,y:314.94},{x:854.54,y:335.4},
52
+ {x:860.92,y:343},{x:849.84,y:359.59},{x:854.56,y:365.53},{x:844.09,y:371.89},
53
+ {x:839.57,y:390.4},{x:848.4,y:407.55},{x:839.51,y:432.76},{x:853.97,y:471.15},
54
+ {x:866.36,y:480.77}
55
+ ]
56
+ end
57
+ end
@@ -0,0 +1,6 @@
1
+ require 'bundler/setup'
2
+ require 'rspec'
3
+ require File.expand_path '../simplify_test_data.rb', __FILE__
4
+ require 'simplify_rb'
5
+
6
+ Bundler.setup
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simplify_rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - odlp
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
55
+ description: You can use this gem to reduce the number of points in a complex polyline
56
+ / polygon, making use of an optimized Douglas-Peucker algorithm.
57
+ email:
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/simplify_rb.rb
69
+ - lib/simplify_rb/version.rb
70
+ - simplify_rb.gemspec
71
+ - spec/simplify_rb_spec.rb
72
+ - spec/simplify_test_data.rb
73
+ - spec/spec_helper.rb
74
+ homepage: https://github.com/odlp/simplify_rb
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.2.2
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Polyline simplification library. Ruby port of Simplify.js.
98
+ test_files:
99
+ - spec/simplify_rb_spec.rb
100
+ - spec/simplify_test_data.rb
101
+ - spec/spec_helper.rb