rdp 0.0.3
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 +7 -0
- data/lib/rdp.rb +39 -0
- data/lib/rdp/line.rb +30 -0
- data/lib/rdp/point.rb +14 -0
- data/lib/rdp/polyline.rb +96 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c3464f0ee71582a92c167d6b64301c65af6385bd
|
4
|
+
data.tar.gz: 388a51185140363aa48cdcee500e4638e4e6ca93
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28bc20959e14b78198c9652ade68bcfe9dab7c376970d057b737f1be0da571901bb67f778d3126ded5eb1a71c4010fcb727fad93ffb17d461495655f6b88609f
|
7
|
+
data.tar.gz: c62c928007aa97e17938a11a47e2d17ca3973dce150e0020096604a7daa1aa4bbcb982cc696bf28ac8a7226935d56c4cf86dfbad3de94ebe370d2b8020652d1d
|
data/lib/rdp.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#vertix decimation using Ramer Douglas Peucker algorithm
|
2
|
+
class RDP
|
3
|
+
|
4
|
+
#Simplify an array using the Ramer Douglas Peucker algorithm.
|
5
|
+
#
|
6
|
+
#The actual algorithm is implemented in Polyline. This is just a simplier way to call it form arrays
|
7
|
+
#
|
8
|
+
#The array should read as simplify([x1,x2,x3...],[y1,y2,y3...])
|
9
|
+
def self.simplify(x,y,tol=nil)
|
10
|
+
p = if tol
|
11
|
+
Polyline.new(x.zip(y).map{|a,b| Point.new(a,b)}).simplify(tol).to_a
|
12
|
+
else
|
13
|
+
Polyline.new(x.zip(y).map{|a,b| Point.new(a,b)}).simplify.to_a
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#Merge an array of vectors that have different abcissa
|
18
|
+
#
|
19
|
+
#The array should read as [[[x1...],[y1...]], [[x2...],[y2...]],...]
|
20
|
+
def self.merge(*args)
|
21
|
+
Polyline::merge(
|
22
|
+
*args.map{|x,y| Polyline.new(x.zip(y).map{|a,b| Point.new(a,b)}) }
|
23
|
+
).to_a
|
24
|
+
end
|
25
|
+
|
26
|
+
# Define new x vector for a given [[x],[y]] vector
|
27
|
+
#
|
28
|
+
# usage : RDP.interpolate( [[x1,x2..],[y1,y2...]], [newx1,newx2...])
|
29
|
+
def self.interpolate(inline,abs)
|
30
|
+
pl = Polyline.new(
|
31
|
+
inline[0].zip(inline[1]).map{|x,y| Point.new(x,y)}
|
32
|
+
)
|
33
|
+
return pl.interpolate(abs).to_a
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
require 'rdp/point'
|
39
|
+
require 'rdp/polyline'
|
data/lib/rdp/line.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#Line in a plane, defined by the equation ax + by + c = 0
|
2
|
+
class RDP::Line
|
3
|
+
# ax + by + c = 0
|
4
|
+
attr_accessor :a, :b, :c
|
5
|
+
|
6
|
+
def initialize(a=0,b=0,c=0)
|
7
|
+
@a = a
|
8
|
+
@b = b
|
9
|
+
@c = c
|
10
|
+
end
|
11
|
+
|
12
|
+
#Construct the line from two points
|
13
|
+
def define_from_points(p,q)
|
14
|
+
@a = q.y - p.y
|
15
|
+
@b = p.x - q.x
|
16
|
+
@c = p.y*(q.x - p.x) - p.x*(q.y - p.y)
|
17
|
+
return self
|
18
|
+
end
|
19
|
+
|
20
|
+
#Euclidian distance from a point to the line
|
21
|
+
def distance_to_point(p)
|
22
|
+
( @a*p.x + @b*p.y + @c).abs/Math.sqrt(a**2 + b**2).to_f
|
23
|
+
end
|
24
|
+
|
25
|
+
#Log all
|
26
|
+
def show
|
27
|
+
puts "#{@a.round(2)}x + #{@b.round(2)}y +#{@c.round(2)} = 0"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/lib/rdp/point.rb
ADDED
data/lib/rdp/polyline.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#Polyline, represented as an array of points
|
2
|
+
class RDP::Polyline < Array
|
3
|
+
|
4
|
+
def initialize(ary=nil)
|
5
|
+
if ary
|
6
|
+
ary.each do |el|
|
7
|
+
self << el
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
#Automatically compute a tolerance level for the vertix decimation algorithm
|
13
|
+
def normalized_epsilon
|
14
|
+
ys = self.map{|point| point.y}
|
15
|
+
(ys.max - ys.min)**(0.01)
|
16
|
+
end
|
17
|
+
|
18
|
+
#vertix decimation using Ramer Douglas Peucker algorithm
|
19
|
+
def simplify(epsilon=normalized_epsilon)
|
20
|
+
l = RDP::Line.new.define_from_points(self.first, self.last)
|
21
|
+
dmax = 0.0
|
22
|
+
pmax = nil
|
23
|
+
imax = nil
|
24
|
+
|
25
|
+
#Look for the farthest point if any
|
26
|
+
(1..self.size-2).each do |i|
|
27
|
+
d = l.distance_to_point(self[i])
|
28
|
+
if d > dmax and d > epsilon
|
29
|
+
pmax = self[i]
|
30
|
+
imax = i
|
31
|
+
dmax = d
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if pmax # at least a point has to be taken into account
|
36
|
+
sub1 = RDP::Polyline.new(self[0..imax])
|
37
|
+
sub2 = RDP::Polyline.new(self[imax..-1])
|
38
|
+
return RDP::Polyline.new((sub1.simplify(epsilon) + sub2.simplify(epsilon)).uniq)
|
39
|
+
else
|
40
|
+
#no point is found
|
41
|
+
return RDP::Polyline.new([self.first, self.last])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#vertix decimation using Ramer Douglas Peucker algorithm
|
46
|
+
def simplify!(eps=normalized_epsilon)
|
47
|
+
self.replace self.simplify(eps)
|
48
|
+
end
|
49
|
+
|
50
|
+
#Print all the points to stdout
|
51
|
+
def show
|
52
|
+
self.each { |point| point.show }
|
53
|
+
end
|
54
|
+
|
55
|
+
#Export the points to a file
|
56
|
+
def export(file)
|
57
|
+
File.open(file,'w') do |f|
|
58
|
+
self.each {|point| f.puts "#{point.x}\t#{point.y}"}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#Interpolate the polyline to obtain a new polyline, using the given X vector.
|
63
|
+
def interpolate(abcisses)
|
64
|
+
res = RDP::Polyline.new
|
65
|
+
i = 0 # will go through all abcisses
|
66
|
+
(0..self.size-2).each do |j|
|
67
|
+
while i < abcisses.size and abcisses[i] <= self[j+1].x
|
68
|
+
l = RDP::Line.new.define_from_points(self[j],self[j+1])
|
69
|
+
y = abcisses[i] == self[j].x ? self[j].y : (-l.c - l.a*abcisses[i]).to_f/l.b
|
70
|
+
res << RDP::Point.new(abcisses[i], y)
|
71
|
+
i +=1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
return res
|
75
|
+
end
|
76
|
+
|
77
|
+
#Merge two polylines together
|
78
|
+
def self.merge(*args)
|
79
|
+
abs = args.reduce([]){|x,y| x += y.map{|el| el.x}}.uniq.sort
|
80
|
+
res = RDP::Polyline.new
|
81
|
+
(0..abs.size-1).each do |i|
|
82
|
+
res << RDP::Point.new( abs[i] , args.map{|line| line.interpolate(abs)}.inject(0){|y,line| y+= (line[i].y rescue 0)})
|
83
|
+
end
|
84
|
+
return res
|
85
|
+
end
|
86
|
+
|
87
|
+
#Convert a polyline (array of vectors) to a ruby array
|
88
|
+
def to_a
|
89
|
+
x = self.map{|p| p.x}
|
90
|
+
y = self.map{|p| p.y}
|
91
|
+
return [x,y]
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
require 'rdp/point'
|
96
|
+
require 'rdp/line'
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rdp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aurélien Hervé
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-05-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Ramer Douglas Peucker algorithm implementation to simplify a 2d curve
|
14
|
+
email: aurelien@adomik.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/rdp.rb
|
20
|
+
- lib/rdp/point.rb
|
21
|
+
- lib/rdp/line.rb
|
22
|
+
- lib/rdp/polyline.rb
|
23
|
+
homepage: http://rubygems.org/gems/rdp
|
24
|
+
licenses: []
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 2.0.0.rc.2
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: added interpolate method
|
46
|
+
test_files: []
|