eigen 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ require "mkmf-rice"
2
+
3
+ RbConfig::CONFIG['CXXFLAGS'].gsub! "-Wdeclaration-after-statement", ''
4
+ RbConfig::CONFIG['CXXFLAGS'].gsub! "-Wimplicit-function-declaration", ''
5
+
6
+ if !pkg_config('eigen3')
7
+ raise "cannot find the eigen3 pkg-config package in #{ENV['PKG_CONFIG_PATH']}"
8
+ end
9
+
10
+ create_makefile("eigen/eigen")
@@ -0,0 +1,15 @@
1
+ # Ruby bindings for the Eigen C++ linear algebra library
2
+ module Eigen
3
+ end
4
+
5
+ require 'eigen/eigen'
6
+
7
+ require 'eigen/affine3'
8
+ require 'eigen/angle_axis'
9
+ require 'eigen/isometry3'
10
+ require 'eigen/matrix4'
11
+ require 'eigen/matrixx'
12
+ require 'eigen/quaternion'
13
+ require 'eigen/vector3'
14
+ require 'eigen/vectorx'
15
+ require 'eigen/version'
@@ -0,0 +1,35 @@
1
+ module Eigen
2
+ class Affine3
3
+ def self.Identity
4
+ Affine3.new
5
+ end
6
+
7
+ def self.from_position_orientation( v, q )
8
+ i = Affine3.Identity
9
+ i.prerotate( q )
10
+ i.pretranslate( v )
11
+ i
12
+ end
13
+
14
+ def dup
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def ==(q)
19
+ q.kind_of?(self.class) &&
20
+ __equal__(q)
21
+ end
22
+
23
+ def *(obj)
24
+ if obj.kind_of?(Affine3)
25
+ concatenate(obj)
26
+ else
27
+ transform(obj)
28
+ end
29
+ end
30
+
31
+ def to_s
32
+ matrix.to_s
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,90 @@
1
+ module Eigen
2
+ # Representation and manipulation of an angle axis
3
+ class AngleAxis
4
+ def dup
5
+ AngleAxis.new(angle, axis)
6
+ end
7
+
8
+ # Returns the angle axis as [angle, x, y, z]
9
+ def to_a; [angle, axis.to_a] end
10
+
11
+ def from_a (array)
12
+ aa = AngleAxis.new(array[0], Eigen::Vector3.new(array[1][0], array[1][1], array[1][2]))
13
+ aa
14
+ end
15
+
16
+ # Returns the identity unit quaternion (identity rotation)
17
+ def self.Identity
18
+ AngleAxis.new(0, Eigen::Vector3.new(1, 0, 0))
19
+ end
20
+
21
+ # Creates a angle axis from a quaternion
22
+ def self.from_quaternion(*args)
23
+ aa = new(0, Eigen::Vector3.new(1, 0, 0))
24
+ aa.from_quaternion(*args)
25
+ aa
26
+ end
27
+
28
+ # Creates a quaternion from a set of euler angles.
29
+ #
30
+ # See Quaternion#from_euler for details
31
+ def self.from_euler(*args)
32
+ aa = new(0, Eigen::Vector3.new(1, 0, 0))
33
+ aa.from_euler(*args)
34
+ aa
35
+ end
36
+
37
+ # Creates a quaternion from a rotation matrix
38
+ def self.from_matrix(m)
39
+ aa = new(0, Eigen::Vector3.new(1, 0, 0))
40
+ aa.from_matrix(m)
41
+ aa
42
+ end
43
+
44
+ # Returns a scaled axis representation that is equivalent to this
45
+ # quaternion
46
+ #
47
+ # @param [Float] eps see {#to_angle_axis}
48
+ # @return [Vector3]
49
+ def to_scaled_axis(eps = 1e-12)
50
+ return axis * angle
51
+ end
52
+
53
+ # Concatenates with another angle axis or transforms a vector
54
+ def *(obj)
55
+ if obj.kind_of?(AngleAxis)
56
+ concatenate(obj)
57
+ else
58
+ transform(obj)
59
+ end
60
+ end
61
+
62
+ def _dump(level) # :nodoc:
63
+ Marshal.dump(to_a)
64
+ end
65
+
66
+ def self._load(coordinates) # :nodoc:
67
+ aa = new(0, Eigen::Vector3.new(1, 0, 0))
68
+ aa.from_a(Marshal.load(coordinates))
69
+ aa
70
+ end
71
+
72
+ def to_s # :nodoc:
73
+ "AngleAxis( angle #{angle}, axis(#{axis.x}, #{axis.y}, #{axis.z}))"
74
+ end
75
+
76
+ # Tests for equality
77
+ #
78
+ # Since Quaternion stores the coordinates as floating-point values, this is
79
+ # a bad test. Use
80
+ #
81
+ # (v - other_v).norm < threshold
82
+ #
83
+ # instead
84
+ def ==(q)
85
+ q.kind_of?(self.class) &&
86
+ __equal__(q)
87
+ end
88
+ end
89
+ end
90
+
@@ -0,0 +1,36 @@
1
+ module Eigen
2
+ class Isometry3
3
+ def self.Identity
4
+ Isometry3.new
5
+ end
6
+
7
+ def self.from_position_orientation( v, q )
8
+ i = Isometry3.Identity
9
+ i.prerotate( q )
10
+ i.pretranslate( v )
11
+ i
12
+ end
13
+
14
+ def dup
15
+ raise NotImplementedError
16
+ end
17
+
18
+ def ==(q)
19
+ q.kind_of?(self.class) &&
20
+ __equal__(q)
21
+ end
22
+
23
+ def *(obj)
24
+ if obj.kind_of?(Isometry3)
25
+ concatenate(obj)
26
+ else
27
+ transform(obj)
28
+ end
29
+ end
30
+
31
+ def to_s
32
+ matrix.to_s
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,96 @@
1
+ module Eigen
2
+ # Matrix 4x4
3
+ class Matrix4
4
+ # @!method [](row, col)
5
+ # @param [Integer] row the row index
6
+ # @param [Integer] col the column index
7
+
8
+ # Create a new matrix from the content of an array
9
+ #
10
+ # @param [Array<Numeric>] the values. It must be of size at most 16.
11
+ # If smaller than 16, the rest is filled with zeroes
12
+ #
13
+ # @return [Matrix4]
14
+ def self.from_a(*args)
15
+ m = new
16
+ m.from_a(*args)
17
+ m
18
+ end
19
+
20
+ # Returns the values flattened in a ruby array
21
+ #
22
+ # @param [Boolean] column_major if true, the values of a column will be
23
+ # adjacent in the resulting array, if not the values of a row will
24
+ # @return [Array<Numeric>]
25
+ #
26
+ # @example column-major ordering
27
+ # matrix.to_s => Matrix4(1 2 3 4
28
+ # 5 6 7 8
29
+ # 9 10 11 12
30
+ # 13 14 15 16)
31
+ # matrix.to_a(true) => [1 5 9 13 2 6 10 14 ...]
32
+ def to_a(column_major=true)
33
+ a = []
34
+ if column_major
35
+ for j in 0..3
36
+ for i in 0..3
37
+ a << self[i,j]
38
+ end
39
+ end
40
+ else
41
+ for i in 0..3
42
+ for j in 0..3
43
+ a << self[i,j]
44
+ end
45
+ end
46
+ end
47
+ a
48
+ end
49
+
50
+ # sets matrix from a 1d array
51
+ def from_a(array, column_major=true)
52
+ if array.size > 16
53
+ raise ArgumentError, "array should be of size maximum 16"
54
+ end
55
+
56
+ 16.times do |i|
57
+ v = array[i] || 0
58
+ if column_major
59
+ self[i%4,i/4] = v
60
+ else
61
+ self[i/4,i%4] = v
62
+ end
63
+ end
64
+ end
65
+
66
+ def ==(m)
67
+ m.kind_of?(self.class) &&
68
+ __equal__(m)
69
+ end
70
+
71
+ def to_s(line_format = "%g %g %g %g") # :nodoc:
72
+ lines = to_a.each_slice(3).to_s
73
+ <<-EOSTRING
74
+ Matrix4(#{line_format % lines[0]}"
75
+ #{line_format % lines[1]}"
76
+ #{line_format % lines[2]}"
77
+ #{line_format % lines[3]})"
78
+ EOSTRING
79
+ end
80
+
81
+ def _dump(level)
82
+ to_a.pack("E*")
83
+ end
84
+
85
+ def self._load(elements) # :nodoc:
86
+ m = new
87
+ if elements.size == 8 * 16
88
+ m.from_a(elements.unpack("E*"))
89
+ else
90
+ m.from_a(Marshal.load(elements)['data'])
91
+ end
92
+ m
93
+ end
94
+ end
95
+ end
96
+
@@ -0,0 +1,105 @@
1
+ module Eigen
2
+ # Abritary size vector
3
+ class MatrixX
4
+ def dup
5
+ MatrixX.from_a(to_a, rows, cols)
6
+ end
7
+
8
+ def self.Zero(rows, cols)
9
+ m = new(rows, cols)
10
+ rows.times do |r|
11
+ cols.times do |c|
12
+ m[r, c] = 0
13
+ end
14
+ end
15
+ m
16
+ end
17
+
18
+ def self.from_a(*args)
19
+ m = new
20
+ m.from_a(*args)
21
+ m
22
+ end
23
+
24
+ # Returns the array value in a vector
25
+ def to_a(column_major=true)
26
+ a = []
27
+ if column_major
28
+ for j in 0..cols()-1
29
+ for i in 0..rows()-1
30
+ a << self[i,j]
31
+ end
32
+ end
33
+ else
34
+ for i in 0..rows()-1
35
+ for j in 0..cols()-1
36
+ a << self[i,j]
37
+ end
38
+ end
39
+ end
40
+ a
41
+ end
42
+
43
+ # sets matrix from a 1d array
44
+ def from_a(array,nrows=-1,ncols=-1,column_major=true)
45
+ if nrows == -1 && ncols == -1
46
+ nrows = rows
47
+ ncols = cols
48
+ elsif nrows == -1
49
+ nrows = array.size / ncols
50
+ elsif ncols == -1
51
+ ncols = array.size / nrows
52
+ end
53
+ resize(nrows,ncols)
54
+ array.each_index do |i|
55
+ v = array[i]
56
+ if !v
57
+ v = 0.0
58
+ end
59
+ if column_major
60
+ self[i%nrows,i/nrows] = v
61
+ else
62
+ self[i/ncols,i%ncols] = v
63
+ end
64
+ end
65
+ end
66
+
67
+ def pretty_print(pp)
68
+ for i in 0..rows()-1
69
+ for j in 0..cols()-1
70
+ pp.text " #{self[i,j]}"
71
+ end
72
+ pp.text "\n"
73
+ end
74
+ end
75
+
76
+ def ==(m)
77
+ m.kind_of?(self.class) &&
78
+ __equal__(m)
79
+ end
80
+
81
+ def to_s # :nodoc:
82
+ str = "MatrixX(\n"
83
+ for i in 0..rows()-1
84
+ for j in 0..cols()-1
85
+ str += "#{self[i,j]} "
86
+ end
87
+ str[-1] = "\n"
88
+ end
89
+ str += ")"
90
+ str
91
+ end
92
+
93
+ def _dump(level) # :nodoc:
94
+ Marshal.dump({'rows' => rows, 'cols' => cols, 'data' => to_a})
95
+ end
96
+
97
+ def self._load(coordinates) # :nodoc:
98
+ o = Marshal.load(coordinates)
99
+ m = new(o['rows'],o['cols'])
100
+ m.from_a(o['data'],o['rows'],o['cols'])
101
+ m
102
+ end
103
+ end
104
+ end
105
+
@@ -0,0 +1,253 @@
1
+ module Eigen
2
+ # Representation and manipulation of a quaternion
3
+ class Quaternion
4
+ def dup
5
+ Quaternion.new(w, x, y, z)
6
+ end
7
+
8
+ # Returns the quaternion as [w, x, y, z]
9
+ def to_a; [w, x, y, z] end
10
+
11
+ # Returns the identity unit quaternion (identity rotation)
12
+ def self.Identity
13
+ Quaternion.new(1, 0, 0, 0)
14
+ end
15
+
16
+ # DEPRECATED: please use identity instead. Returns the unit quaternion (identity rotation)
17
+ def self.Unit
18
+ warn "[DEPRECATED] Quaternion.unit, please use Quaternion.identity."
19
+ self.Identity
20
+ end
21
+
22
+ # Creates a quaternion from an angle and axis description
23
+ def self.from_angle_axis(*args)
24
+ q = new(1, 0, 0, 0)
25
+ q.from_angle_axis(*args)
26
+ q
27
+ end
28
+
29
+ # Returns an angle,axis representation equivalent to this quaternion
30
+ #
31
+ # If the angle turns out to be PI, there are two solutions and the one
32
+ # with positive Z component is chosen.
33
+ #
34
+ # @param [Float] eps if the angle turns out to be closer to zero than eps, the
35
+ # rotation axis is undefined and chosen to be the Z axis.
36
+ #
37
+ # @return [(Float,Vector3)] the angle and axis. The angle is in [0, PI]
38
+ def to_angle_axis(eps = 1e-12)
39
+ w, x, y, z = to_a
40
+ norm = Math.sqrt(x*x+y*y+z*z);
41
+ if norm < eps
42
+ return 0, Eigen::Vector3.new(0,0,1);
43
+ end
44
+
45
+ angle = 2.0 * Math.atan2(norm, w);
46
+ axis = Eigen::Vector3.new(x, y, z) / norm
47
+ return angle, axis
48
+ end
49
+
50
+ # Returns a scaled axis representation that is equivalent to this
51
+ # quaternion
52
+ #
53
+ # @param [Float] eps see {#to_angle_axis}
54
+ # @return [Vector3]
55
+ def to_scaled_axis(eps = 1e-12)
56
+ angle, axis = to_angle_axis(eps)
57
+ return axis * angle
58
+ end
59
+
60
+ # Creates a quaternion from a set of euler angles.
61
+ #
62
+ # See Quaternion#from_euler for details
63
+ def self.from_euler(*args)
64
+ q = new(1, 0, 0, 0)
65
+ q.from_euler(*args)
66
+ q
67
+ end
68
+
69
+ # Creates a quaternion from a rotation matrix
70
+ def self.from_matrix(m)
71
+ q = new(1, 0, 0, 0)
72
+ q.from_matrix(m)
73
+ q
74
+ end
75
+
76
+ # Extracts the yaw angle from this quaternion
77
+ #
78
+ # It decomposes the quaternion in euler angles using to_euler
79
+ # and returns the first element. See #to_euler for details.
80
+ def yaw
81
+ to_euler[0]
82
+ end
83
+
84
+ def pitch
85
+ to_euler[1]
86
+ end
87
+
88
+ def roll
89
+ to_euler[2]
90
+ end
91
+
92
+ # The inverse of #yaw
93
+ def self.from_yaw(yaw)
94
+ from_euler(Eigen::Vector3.new(yaw, 0, 0), 2, 1, 0)
95
+ end
96
+
97
+ # Concatenates with another quaternion or transforms a vector
98
+ def *(obj)
99
+ if obj.kind_of?(Quaternion)
100
+ concatenate(obj)
101
+ else
102
+ transform(obj)
103
+ end
104
+ end
105
+
106
+ def _dump(level) # :nodoc:
107
+ Marshal.dump(to_a)
108
+ end
109
+
110
+ def self._load(coordinates) # :nodoc:
111
+ new(*Marshal.load(coordinates))
112
+ end
113
+
114
+ def to_s # :nodoc:
115
+ "Quaternion(#{w}, (#{x}, #{y}, #{z}))"
116
+ end
117
+
118
+ # Tests for equality
119
+ #
120
+ # Since Quaternion stores the coordinates as floating-point values, this is
121
+ # a bad test. Use
122
+ #
123
+ # (v - other_v).norm < threshold
124
+ #
125
+ # instead
126
+ def ==(q)
127
+ q.kind_of?(self.class) &&
128
+ __equal__(q)
129
+ end
130
+
131
+ def re
132
+ w
133
+ end
134
+
135
+ def re=(value)
136
+ self.w = value
137
+ end
138
+
139
+ def im
140
+ [x,y,z]
141
+ end
142
+
143
+ def im=(value)
144
+ self.x, self.y, self.z = *value
145
+ end
146
+
147
+ ##
148
+ # :method: w
149
+
150
+ ##
151
+ # :method: x
152
+
153
+ ##
154
+ # :method: y
155
+
156
+ ##
157
+ # :method: z
158
+
159
+ ##
160
+ # :method: w=
161
+
162
+ ##
163
+ # :method: x=
164
+
165
+ ##
166
+ # :method: y=
167
+
168
+ ##
169
+ # :method: z=
170
+
171
+ ##
172
+ # :method: concatenate
173
+ # :call-seq:
174
+ # concatenate(q)
175
+ #
176
+ # Returns the rotation in which +q+ is applied first and +self+ second
177
+
178
+ ##
179
+ # :method: transform
180
+ # :call-seq:
181
+ # transform(v)
182
+ #
183
+ # Transforms the given Eigen::Vector3 by the rotation represented with
184
+ # this quaternion
185
+
186
+ ##
187
+ # :method: normalize!
188
+ #
189
+ # Normalizes this quaternion
190
+
191
+ ##
192
+ # :method: normalize
193
+ #
194
+ # Returns a quaternion that is a normalized version of +self+
195
+
196
+ ##
197
+ # :method: approx?
198
+ # :call-seq:
199
+ # approx?(q, tolerance)
200
+ #
201
+ # Returns true if +self+ and +q+ do not differ from more than
202
+ # +tolerance+. The comparison is done on a coordinate basis.
203
+
204
+ ##
205
+ # :method: to_euler
206
+ # :call-seq:
207
+ # to_euler => Eigen::Vector3(a0, a1, a2)
208
+ #
209
+ # Decomposes this quaternion in euler angles so that +self+ can be
210
+ # obtained by applying the following rotations in order:
211
+ #
212
+ # rotation of a2 around x-axis
213
+ # rotation of a1 around y-axis
214
+ # rotation of a0 around z-axis
215
+ #
216
+ # assuming angles in range of: a0:(-pi,pi), a1:(-pi/2,pi/2), a2:(-pi/2,pi/2)
217
+ #
218
+ # note that
219
+ #
220
+ # self == Quaternion.from_euler(to_euler, axis0, axis1, axis2)
221
+
222
+ ##
223
+ # :method: from_euler
224
+ # :call-seq:
225
+ # from_euler(Eigen::Vector3(a0, a1, a2), axis0, axis1, axis2)
226
+ #
227
+ # Resets this quaternion so that it represents the rotation obtained by
228
+ # applying the following rotations in order:
229
+ #
230
+ # rotation of a2 around axis2
231
+ # rotation of a1 around axis1
232
+ # rotation of a0 around axis0
233
+ #
234
+ # note that
235
+ #
236
+ # self == Quaternion.from_euler(to_euler, axis0, axis1, axis2)
237
+
238
+ ##
239
+ # :method: inverse
240
+ # :call-seq:
241
+ # inverse => quaternion
242
+ #
243
+ # Computes the quaternion that is inverse of this one
244
+
245
+
246
+ # @return [Qt::Quaternion] the Qt quaternion that is identical to this
247
+ # one
248
+ def to_qt
249
+ Qt::Quaternion.new(w, x, y, z)
250
+ end
251
+ end
252
+ end
253
+