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.
@@ -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
@@ -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'
@@ -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
+
@@ -0,0 +1,14 @@
1
+ #Simple point, with cartesian coordinates
2
+ class RDP::Point
3
+ attr_accessor :x, :y
4
+ def initialize(x=0,y=0)
5
+ @x = x
6
+ @y = y
7
+ end
8
+
9
+ #console log
10
+ def show
11
+ puts "#{@x}\t#{@y}"
12
+ end
13
+ end
14
+
@@ -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: []