eigen 0.1.0

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,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
+