gmath3D 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/VERSION +1 -1
- data/gmath3D.gemspec +3 -3
- data/lib/box.rb +39 -4
- data/lib/ext.rb +82 -0
- data/lib/finite_line.rb +7 -7
- data/lib/gmath3D.rb +4 -2
- data/lib/line.rb +4 -4
- data/lib/plane.rb +4 -5
- data/lib/polyline.rb +1 -1
- data/lib/quat.rb +8 -8
- data/lib/rectangle.rb +7 -7
- data/lib/tri_mesh.rb +27 -11
- data/lib/triangle.rb +22 -8
- data/lib/util.rb +9 -36
- data/lib/vector3.rb +14 -15
- data/test/test_box.rb +48 -0
- data/test/test_tri_mesh.rb +10 -0
- data/test/test_triangle.rb +16 -0
- data/test/test_util.rb +9 -9
- metadata +8 -8
- data/lib/matrix_util.rb +0 -55
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.4
|
data/gmath3D.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{gmath3D}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Toshiyasu Shimizu"]
|
12
|
-
s.date = %q{2011-11-
|
12
|
+
s.date = %q{2011-11-26}
|
13
13
|
s.description = %q{This library defines 3D geometric elements(point, line, plane etc..). It can get two(or more) elements relation, like distance between two elements.}
|
14
14
|
s.email = %q{toshi0328@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -27,11 +27,11 @@ Gem::Specification.new do |s|
|
|
27
27
|
"gmath3D.gemspec",
|
28
28
|
"lib/box.rb",
|
29
29
|
"lib/ellipse.rb",
|
30
|
+
"lib/ext.rb",
|
30
31
|
"lib/finite_line.rb",
|
31
32
|
"lib/geom.rb",
|
32
33
|
"lib/gmath3D.rb",
|
33
34
|
"lib/line.rb",
|
34
|
-
"lib/matrix_util.rb",
|
35
35
|
"lib/plane.rb",
|
36
36
|
"lib/polyline.rb",
|
37
37
|
"lib/quat.rb",
|
data/lib/box.rb
CHANGED
@@ -5,7 +5,6 @@ module GMath3D
|
|
5
5
|
# Box represents an axitially aligned box on 3D space.
|
6
6
|
#
|
7
7
|
class Box < Geom
|
8
|
-
public
|
9
8
|
attr_reader :min_point
|
10
9
|
attr_reader :max_point
|
11
10
|
|
@@ -15,8 +14,8 @@ public
|
|
15
14
|
# [Output]
|
16
15
|
# return new instance of Box.
|
17
16
|
def initialize(point1 = Vector3.new(0,0,0), point2 = Vector3.new(1,1,1))
|
18
|
-
|
19
|
-
|
17
|
+
Util3D.check_arg_type(Vector3, point1)
|
18
|
+
Util3D.check_arg_type(Vector3, point2)
|
20
19
|
super()
|
21
20
|
@min_point = Vector3.new();
|
22
21
|
@max_point = Vector3.new();
|
@@ -75,6 +74,42 @@ public
|
|
75
74
|
return width*height*depth
|
76
75
|
end
|
77
76
|
|
77
|
+
# [Output]
|
78
|
+
# return all vertices of Box.
|
79
|
+
def vertices
|
80
|
+
verts = Array.new(8)
|
81
|
+
length_ary = self.length
|
82
|
+
verts[0] = @min_point.clone
|
83
|
+
verts[1] = @min_point + Vector3.new(length_ary[0], 0, 0 )
|
84
|
+
verts[2] = @min_point + Vector3.new(length_ary[0], length_ary[1], 0 )
|
85
|
+
verts[3] = @min_point + Vector3.new( 0, length_ary[1], 0 )
|
86
|
+
verts[4] = @min_point + Vector3.new( 0, 0, length_ary[2])
|
87
|
+
verts[5] = @min_point + Vector3.new(length_ary[0], 0, length_ary[2])
|
88
|
+
verts[6] = @min_point + Vector3.new(length_ary[0], length_ary[1], length_ary[2])
|
89
|
+
verts[7] = @min_point + Vector3.new( 0, length_ary[1], length_ary[2])
|
90
|
+
return verts
|
91
|
+
end
|
92
|
+
|
93
|
+
# [input]
|
94
|
+
# _vec_ should be Vector3.
|
95
|
+
# [Output]
|
96
|
+
# return translated box as Box.
|
97
|
+
def translate(vec)
|
98
|
+
return Box.new(min_point + vec, max_point + vec)
|
99
|
+
end
|
100
|
+
|
101
|
+
# [input]
|
102
|
+
# _quat_ should be Quat.
|
103
|
+
# [Output]
|
104
|
+
# return rotated box as Box.
|
105
|
+
# since Box is AABB, returned box might be bigger than original one.
|
106
|
+
def rotate(quat)
|
107
|
+
rot_matrix = Matrix.from_quat(quat)
|
108
|
+
verts = self.vertices
|
109
|
+
verts = verts.collect {|item| rot_matrix*item}
|
110
|
+
return Box.from_points(verts)
|
111
|
+
end
|
112
|
+
|
78
113
|
private
|
79
114
|
def equals_inner(rhs)
|
80
115
|
return false if( !rhs.kind_of?(Box) )
|
@@ -103,7 +138,7 @@ private
|
|
103
138
|
end
|
104
139
|
return added_box
|
105
140
|
end
|
106
|
-
|
141
|
+
Util3D.raise_argurment_error(rhs)
|
107
142
|
end
|
108
143
|
end
|
109
144
|
end
|
data/lib/ext.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'gmath3D'
|
2
|
+
require 'matrix'
|
3
|
+
|
4
|
+
module GMath3D
|
5
|
+
class ::Matrix
|
6
|
+
def self.from_axis(axis, angle)
|
7
|
+
Util3D::check_arg_type(Vector3, axis)
|
8
|
+
Util3D::check_arg_type(Numeric, angle)
|
9
|
+
|
10
|
+
return Matrix[
|
11
|
+
[axis.x*axis.x*(1 - Math.cos(angle)) + Math.cos(angle),
|
12
|
+
axis.x*axis.y*(1 - Math.cos(angle)) + axis.z*Math.sin(angle),
|
13
|
+
axis.x*axis.z*(1 - Math.cos(angle)) - axis.y*Math.sin(angle)],
|
14
|
+
[axis.x*axis.y*(1 - Math.cos(angle)) - axis.z*Math.sin(angle),
|
15
|
+
axis.y*axis.y*(1 - Math.cos(angle)) + Math.cos(angle),
|
16
|
+
axis.y*axis.z*(1 - Math.cos(angle)) + axis.x*Math.sin(angle)],
|
17
|
+
[axis.x*axis.z*(1 - Math.cos(angle)) + axis.y*Math.sin(angle),
|
18
|
+
axis.y*axis.z*(1 - Math.cos(angle)) - axis.x*Math.sin(angle),
|
19
|
+
axis.z*axis.z*(1 - Math.cos(angle)) + Math.cos(angle)]]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.from_quat(quat)
|
23
|
+
Util3D::check_arg_type(Quat, quat)
|
24
|
+
qw = quat.w
|
25
|
+
qx = quat.x
|
26
|
+
qy = quat.y
|
27
|
+
qz = quat.z
|
28
|
+
|
29
|
+
x2 = 2.0 * qx * qx;
|
30
|
+
y2 = 2.0 * qy * qy;
|
31
|
+
z2 = 2.0 * qz * qz;
|
32
|
+
xy = 2.0 * qx * qy;
|
33
|
+
yz = 2.0 * qy * qz;
|
34
|
+
zx = 2.0 * qz * qx;
|
35
|
+
wx = 2.0 * qw * qx;
|
36
|
+
wy = 2.0 * qw * qy;
|
37
|
+
wz = 2.0 * qw * qz;
|
38
|
+
|
39
|
+
return Matrix[
|
40
|
+
[ 1.0 - y2 - z2, xy + wz, zx - wy],
|
41
|
+
[ xy - wz, 1.0 - z2 - x2, yz + wx],
|
42
|
+
[ zx + wy, yz - wx, 1.0 - x2 - y2]]
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :multi_inner, :* # hold original multiply processing
|
46
|
+
def multi_new(rhs)
|
47
|
+
if(rhs.kind_of?(Vector3))
|
48
|
+
ans = self.multi_inner(rhs.to_column_vector)
|
49
|
+
return Vector3.new(ans[0,0], ans[1,0], ans[2,0])
|
50
|
+
end
|
51
|
+
multi_inner(rhs)
|
52
|
+
end
|
53
|
+
alias_method :*, :multi_new # overwrite new multiply processing
|
54
|
+
end
|
55
|
+
|
56
|
+
class ::Array
|
57
|
+
def sum
|
58
|
+
s, n = self.sum_with_number
|
59
|
+
return s
|
60
|
+
end
|
61
|
+
def avg
|
62
|
+
s, n = self.sum_with_number
|
63
|
+
return s / n
|
64
|
+
end
|
65
|
+
|
66
|
+
def sum_with_number
|
67
|
+
return nil, 0 if(self.size <= 0)
|
68
|
+
s = nil
|
69
|
+
n = 0
|
70
|
+
self.each do |v|
|
71
|
+
next if v.nil?
|
72
|
+
if(s==nil)
|
73
|
+
s = v
|
74
|
+
else
|
75
|
+
s += v
|
76
|
+
end
|
77
|
+
n += 1
|
78
|
+
end
|
79
|
+
return s, n
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/finite_line.rb
CHANGED
@@ -16,8 +16,8 @@ public
|
|
16
16
|
# [Output]
|
17
17
|
# return new instance as FiniteLine
|
18
18
|
def initialize(start_point = Vector3.new(0,0,0), end_point = Vector3.new(1,0,0))
|
19
|
-
|
20
|
-
|
19
|
+
Util3D.check_arg_type(Vector3, start_point)
|
20
|
+
Util3D.check_arg_type(Vector3, end_point)
|
21
21
|
super()
|
22
22
|
@start_point = start_point
|
23
23
|
@end_point = end_point
|
@@ -105,12 +105,12 @@ public
|
|
105
105
|
elsif(target.kind_of?(FiniteLine))
|
106
106
|
return distance_to_finite_line(target)
|
107
107
|
end
|
108
|
-
|
108
|
+
Util3D.raise_argurment_error(target)
|
109
109
|
end
|
110
110
|
|
111
111
|
def self.ary_distanc_to_point(finite_lines, target_point)
|
112
|
-
|
113
|
-
|
112
|
+
Util3D.check_arg_type(::Array, finite_lines)
|
113
|
+
Util3D.check_arg_type(Vector3, target_point)
|
114
114
|
distance_ary = Array.new(0)
|
115
115
|
points_ary = Array.new(0)
|
116
116
|
finite_lines.each do | item |
|
@@ -124,8 +124,8 @@ public
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def self.ary_distance_to_line(finite_lines, target_line)
|
127
|
-
|
128
|
-
|
127
|
+
Util3D.check_arg_type(::Array, finite_lines)
|
128
|
+
Util3D.check_arg_type(Line, target_line)
|
129
129
|
distance_ary = Array.new(0)
|
130
130
|
point_on_target_ary = Array.new(0)
|
131
131
|
point_on_finite_line_ary = Array.new(0)
|
data/lib/gmath3D.rb
CHANGED
data/lib/line.rb
CHANGED
@@ -18,8 +18,8 @@ module GMath3D
|
|
18
18
|
# [Output]
|
19
19
|
# return new instance of Line.
|
20
20
|
def initialize(point = Vector3.new(0.0,0.0,0.0), direction = Vector3.new(1.0,0.0,0.0))
|
21
|
-
|
22
|
-
|
21
|
+
Util3D.check_arg_type(Vector3, point)
|
22
|
+
Util3D.check_arg_type(Vector3, direction)
|
23
23
|
super()
|
24
24
|
@base_point = point
|
25
25
|
@direction = direction
|
@@ -47,7 +47,7 @@ module GMath3D
|
|
47
47
|
# [Output]
|
48
48
|
# return a point on line at input parameter position as Vector3
|
49
49
|
def point(parameter)
|
50
|
-
|
50
|
+
Util3D.check_arg_type(::Numeric, parameter)
|
51
51
|
@base_point + @direction*parameter
|
52
52
|
end
|
53
53
|
|
@@ -69,7 +69,7 @@ module GMath3D
|
|
69
69
|
elsif(target.kind_of?(Line))
|
70
70
|
return distance_to_line(target)
|
71
71
|
end
|
72
|
-
|
72
|
+
Util3D.raise_argurment_error(target)
|
73
73
|
end
|
74
74
|
|
75
75
|
private
|
data/lib/plane.rb
CHANGED
@@ -5,7 +5,6 @@ module GMath3D
|
|
5
5
|
# Plane represents a infinite plane on 3D space.
|
6
6
|
#
|
7
7
|
class Plane < Geom
|
8
|
-
public
|
9
8
|
attr_accessor:base_point
|
10
9
|
attr_accessor:normal
|
11
10
|
|
@@ -14,8 +13,8 @@ public
|
|
14
13
|
# [Output]
|
15
14
|
# returns new instance of Plane.
|
16
15
|
def initialize(base_point = Vector3.new(), normal = Vector3.new(0,0,1))
|
17
|
-
|
18
|
-
|
16
|
+
Util3D.check_arg_type(::Vector3, normal)
|
17
|
+
Util3D.check_arg_type(::Vector3, base_point)
|
19
18
|
super()
|
20
19
|
@base_point = base_point
|
21
20
|
@normal = normal.normalize()
|
@@ -70,7 +69,7 @@ public
|
|
70
69
|
elsif(target.kind_of?(Plane))
|
71
70
|
return distance_to_plane(target)
|
72
71
|
end
|
73
|
-
|
72
|
+
Util3D.raise_argurment_error(target)
|
74
73
|
end
|
75
74
|
|
76
75
|
# [Input]
|
@@ -78,7 +77,7 @@ public
|
|
78
77
|
# [Output]
|
79
78
|
# retrun projected point on plane as Vector3.
|
80
79
|
def project( target_point )
|
81
|
-
|
80
|
+
Util3D.check_arg_type(::Vector3, target_point)
|
82
81
|
distance, closest_point = self.distance( target_point )
|
83
82
|
return closest_point
|
84
83
|
end
|
data/lib/polyline.rb
CHANGED
data/lib/quat.rb
CHANGED
@@ -16,10 +16,10 @@ public
|
|
16
16
|
# [Output]
|
17
17
|
# return new instance of Quat.
|
18
18
|
def initialize(x=0.0,y=0.0,z=0.0,w=0.0)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
Util3D.check_arg_type(Numeric, x)
|
20
|
+
Util3D.check_arg_type(Numeric, y)
|
21
|
+
Util3D.check_arg_type(Numeric, z)
|
22
|
+
Util3D.check_arg_type(Numeric, w)
|
23
23
|
super()
|
24
24
|
@x = x
|
25
25
|
@y = y
|
@@ -32,8 +32,8 @@ public
|
|
32
32
|
# [Output]
|
33
33
|
# return new instance of Quat.
|
34
34
|
def self.from_axis(axis, angle)
|
35
|
-
|
36
|
-
|
35
|
+
Util3D.check_arg_type(Vector3, axis)
|
36
|
+
Util3D.check_arg_type(Numeric, angle)
|
37
37
|
s = Math.sin(0.5*angle)
|
38
38
|
x = s * axis.x
|
39
39
|
y = s * axis.y
|
@@ -134,7 +134,7 @@ public
|
|
134
134
|
# [Output]
|
135
135
|
# return added result as Quat.
|
136
136
|
def +(rhs)
|
137
|
-
|
137
|
+
Util3D.check_arg_type(Quat, rhs)
|
138
138
|
t1 = Vector3.new(self.x, self.y, self.z)
|
139
139
|
t2 = Vector3.new(rhs.x, rhs.y, rhs.z)
|
140
140
|
dot = t1.dot(t2)
|
@@ -154,7 +154,7 @@ public
|
|
154
154
|
# [Output]
|
155
155
|
# return (outer products) multiplyed result as Quat.
|
156
156
|
def *(rhs)
|
157
|
-
|
157
|
+
Util3D.check_arg_type(Quat, rhs)
|
158
158
|
|
159
159
|
pw = self.w; px = self.x; py = self.y; pz = self.z;
|
160
160
|
qw = rhs.w ; qx = rhs.x ; qy = rhs.y ; qz = rhs.z;
|
data/lib/rectangle.rb
CHANGED
@@ -20,9 +20,9 @@ public
|
|
20
20
|
# [Output]
|
21
21
|
# return new instance of Rectangle.
|
22
22
|
def initialize(base_point_arg = Vector3.new(), u_vector_arg = Vector3.new(1,0,0), v_vector_arg = Vector3.new(0,1,0))
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
Util3D.check_arg_type(::Vector3, base_point_arg)
|
24
|
+
Util3D.check_arg_type(::Vector3, u_vector_arg)
|
25
|
+
Util3D.check_arg_type(::Vector3, v_vector_arg)
|
26
26
|
super()
|
27
27
|
self.base_point = base_point_arg
|
28
28
|
self.u_vector = u_vector_arg
|
@@ -57,8 +57,8 @@ public
|
|
57
57
|
# [Output]
|
58
58
|
# return point on rectangle as Vector3.
|
59
59
|
def point(u, v)
|
60
|
-
|
61
|
-
|
60
|
+
Util3D.check_arg_type(::Numeric, u)
|
61
|
+
Util3D.check_arg_type(::Numeric, v)
|
62
62
|
return base_point + u_vector*u + v_vector*v
|
63
63
|
end
|
64
64
|
|
@@ -113,7 +113,7 @@ public
|
|
113
113
|
# [Output]
|
114
114
|
# return u, v parametes on check_point as [Numeric, Numeric].
|
115
115
|
def uv_parameter(check_point)
|
116
|
-
|
116
|
+
Util3D.check_arg_type(::Vector3, check_point)
|
117
117
|
mat = Matrix[[u_vector.x, u_vector.y, u_vector.z],
|
118
118
|
[v_vector.x, v_vector.y, v_vector.z],
|
119
119
|
[normal.x, normal.y, normal.z]]
|
@@ -134,7 +134,7 @@ public
|
|
134
134
|
#with Line
|
135
135
|
# return distance_to_line(target)
|
136
136
|
end
|
137
|
-
|
137
|
+
Util3D.raise_argurment_error(target)
|
138
138
|
end
|
139
139
|
|
140
140
|
private
|
data/lib/tri_mesh.rb
CHANGED
@@ -17,15 +17,15 @@ module GMath3D
|
|
17
17
|
# return new instance of TriMesh.
|
18
18
|
def initialize(vertices, tri_indices)
|
19
19
|
# check arg
|
20
|
-
|
21
|
-
|
20
|
+
Util3D.check_arg_type(Array, vertices)
|
21
|
+
Util3D.check_arg_type(Array, tri_indices)
|
22
22
|
vertices.each do |item|
|
23
|
-
|
23
|
+
Util3D.check_arg_type(Vector3, item)
|
24
24
|
end
|
25
25
|
tri_indices.each do |tri_index|
|
26
|
-
|
26
|
+
Util3D.check_arg_type(Array, tri_index)
|
27
27
|
tri_index.each do |item|
|
28
|
-
|
28
|
+
Util3D.check_arg_type(Integer, item)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
super()
|
@@ -49,7 +49,7 @@ module GMath3D
|
|
49
49
|
# [Output]
|
50
50
|
# return new instance of TriMesh.
|
51
51
|
def self.from_box(box)
|
52
|
-
|
52
|
+
Util3D.check_arg_type(Box, box)
|
53
53
|
width, height, depth = box.length()
|
54
54
|
vertices = Array.new(8)
|
55
55
|
vertices[0] = box.min_point
|
@@ -82,7 +82,7 @@ module GMath3D
|
|
82
82
|
# [Output]
|
83
83
|
# return new instance of TriMesh.
|
84
84
|
def self.from_rectangle(rect)
|
85
|
-
|
85
|
+
Util3D.check_arg_type(Rectangle, rect)
|
86
86
|
return TriMesh.new(rect.vertices, [[0,1,3], [1,2,3]])
|
87
87
|
end
|
88
88
|
|
@@ -91,19 +91,18 @@ module GMath3D
|
|
91
91
|
# [Output]
|
92
92
|
# return new instance of TriMesh
|
93
93
|
def self.from_triangles(tris)
|
94
|
-
|
94
|
+
Util3D.check_arg_type(Array, tris)
|
95
95
|
tris.each do | item |
|
96
|
-
|
96
|
+
Util3D.check_arg_type(Triangle, item)
|
97
97
|
end
|
98
98
|
|
99
99
|
tri_idx = 0
|
100
100
|
vert_tris_map = Hash.new(nil)
|
101
|
-
tris.
|
101
|
+
tris.each_with_index do | triangle, tri_idx |
|
102
102
|
triangle.vertices.each do | vertex |
|
103
103
|
vert_tris_map[vertex] = Array.new() if( !vert_tris_map.key?(vertex) )
|
104
104
|
vert_tris_map[vertex] = vert_tris_map[vertex].push(tri_idx)
|
105
105
|
end
|
106
|
-
tri_idx += 1
|
107
106
|
end
|
108
107
|
|
109
108
|
tri_indices = Array.new( tris.size )
|
@@ -237,6 +236,23 @@ module GMath3D
|
|
237
236
|
end
|
238
237
|
return area_sum
|
239
238
|
end
|
239
|
+
|
240
|
+
# [Output]
|
241
|
+
# return normal vector for each vertex as Hash{ Vector3 vertex => Vector3 normal_vector}.
|
242
|
+
def normals_for_each_vertices
|
243
|
+
normals_map = Hash.new(nil)
|
244
|
+
triangles.each_with_index do | tri, tri_idx |
|
245
|
+
tri.vertices.each_with_index do | vertex, ver_idx |
|
246
|
+
normals_map[vertex] = Vector3.new() if( !normals_map.key?(vertex) )
|
247
|
+
normals_map[vertex] += tri.normal*tri.angle(ver_idx)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
normals_map.each do |vertex, normal|
|
251
|
+
normals_map[vertex] = normal.normalize
|
252
|
+
end
|
253
|
+
return normals_map
|
254
|
+
end
|
255
|
+
|
240
256
|
end
|
241
257
|
end
|
242
258
|
|
data/lib/triangle.rb
CHANGED
@@ -15,9 +15,9 @@ public
|
|
15
15
|
# [Output]
|
16
16
|
# return new instance of Triangle.
|
17
17
|
def initialize(vertex1 = Vector3.new(), vertex2 = Vector3.new(1,0,0), vertex3 = Vector3.new(0,1,0))
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
Util3D.check_arg_type(::Vector3, vertex1)
|
19
|
+
Util3D.check_arg_type(::Vector3, vertex2)
|
20
|
+
Util3D.check_arg_type(::Vector3, vertex3)
|
21
21
|
super()
|
22
22
|
@vertices = Array.new([vertex1, vertex2, vertex3])
|
23
23
|
end
|
@@ -52,7 +52,7 @@ public
|
|
52
52
|
# [Output]
|
53
53
|
# return point on triangle at parameter position as Vector3.
|
54
54
|
def point( parameter )
|
55
|
-
|
55
|
+
Util3D.check_arg_type(::Array, parameter )
|
56
56
|
# TODO Argument check
|
57
57
|
return self.vertices[0]*parameter[0] + self.vertices[1]*parameter[1] + self.vertices[2]*parameter[2]
|
58
58
|
end
|
@@ -90,9 +90,23 @@ public
|
|
90
90
|
return (vec1.cross(vec2).normalize)
|
91
91
|
end
|
92
92
|
|
93
|
+
# [Input]
|
94
|
+
# _vertex_index_ should be 0..2.
|
95
|
+
# [Output]
|
96
|
+
# return angle as Numeric(radian).
|
97
|
+
def angle( vertex_index )
|
98
|
+
return nil if(vertex_index < 0 || vertex_index > 2)
|
99
|
+
vert1 = self.vertices[vertex_index]
|
100
|
+
vert2 = self.vertices[(vertex_index+1)%3]
|
101
|
+
vert3 = self.vertices[(vertex_index+2)%3]
|
102
|
+
vec1 = vert2 - vert1
|
103
|
+
vec2 = vert3 - vert1
|
104
|
+
vec1.angle(vec2)
|
105
|
+
end
|
106
|
+
|
93
107
|
# [Output]
|
94
108
|
# return normal vector reversed triangle
|
95
|
-
def reverse
|
109
|
+
def reverse
|
96
110
|
return Triangle.new(@vertices[0], @vertices[2], @vertices[1])
|
97
111
|
end
|
98
112
|
|
@@ -101,7 +115,7 @@ public
|
|
101
115
|
# [Output]
|
102
116
|
# return barycentric_coordinate on check_point as three element Array of Numeric.
|
103
117
|
def barycentric_coordinate( check_point )
|
104
|
-
|
118
|
+
Util3D.check_arg_type(::Vector3, check_point)
|
105
119
|
|
106
120
|
v0 = @vertices[0]
|
107
121
|
v1 = @vertices[1]
|
@@ -171,7 +185,7 @@ public
|
|
171
185
|
#with Plane
|
172
186
|
return distance_to_plane(target)
|
173
187
|
end
|
174
|
-
|
188
|
+
Util3D.raise_argurment_error(target)
|
175
189
|
end
|
176
190
|
|
177
191
|
# [Input]
|
@@ -179,7 +193,7 @@ public
|
|
179
193
|
# [Output]
|
180
194
|
# return true if triangle contains _check_point_.
|
181
195
|
def contains?( check_point )
|
182
|
-
|
196
|
+
Util3D.check_arg_type(Vector3, check_point )
|
183
197
|
plane = Plane.new( vertices[0], self.normal)
|
184
198
|
distance, projected_point = plane.distance(check_point)
|
185
199
|
return false if( distance > self.tolerance )
|
data/lib/util.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
raise(ArgumentError::new("type mismatch: #{instance.class} for #{type}"))
|
6
|
-
end
|
1
|
+
module Util3D
|
2
|
+
def self.check_arg_type(type, instance)
|
3
|
+
unless(instance.kind_of?(type))
|
4
|
+
raise(ArgumentError::new("type mismatch: #{instance.class} for #{type}"))
|
7
5
|
end
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
end
|
8
|
+
def self.raise_argurment_error(instance)
|
9
|
+
raise(ArgumentError::new("type mismatch: #{instance.class}"))
|
12
10
|
end
|
11
|
+
end
|
13
12
|
|
13
|
+
module GMath3D
|
14
14
|
# Including 'vertices' methodshould be implimented that gets geometry vertices as Array of Vector3.
|
15
15
|
module BoxAvailable
|
16
16
|
# [Output]
|
@@ -21,30 +21,3 @@ module GMath3D
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
class Array
|
25
|
-
public
|
26
|
-
def sum
|
27
|
-
s, n = self.sum_with_number
|
28
|
-
return s
|
29
|
-
end
|
30
|
-
def avg
|
31
|
-
s, n = self.sum_with_number
|
32
|
-
return s / n
|
33
|
-
end
|
34
|
-
|
35
|
-
def sum_with_number
|
36
|
-
return nil, 0 if(self.size <= 0)
|
37
|
-
s = nil
|
38
|
-
n = 0
|
39
|
-
self.each do |v|
|
40
|
-
next if v.nil?
|
41
|
-
if(s==nil)
|
42
|
-
s = v
|
43
|
-
else
|
44
|
-
s += v
|
45
|
-
end
|
46
|
-
n += 1
|
47
|
-
end
|
48
|
-
return s, n
|
49
|
-
end
|
50
|
-
end
|
data/lib/vector3.rb
CHANGED
@@ -6,7 +6,6 @@ module GMath3D
|
|
6
6
|
# Vector3 represents a point or a vector on 3D space.
|
7
7
|
#
|
8
8
|
class Vector3 < Geom
|
9
|
-
public
|
10
9
|
attr_accessor :x
|
11
10
|
attr_accessor :y
|
12
11
|
attr_accessor :z
|
@@ -16,9 +15,9 @@ public
|
|
16
15
|
# [Output]
|
17
16
|
# return new instance as Vector3.
|
18
17
|
def initialize(x=0.0,y=0.0,z=0.0)
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
Util3D.check_arg_type(Numeric, x)
|
19
|
+
Util3D.check_arg_type(Numeric, y)
|
20
|
+
Util3D.check_arg_type(Numeric, z)
|
22
21
|
super()
|
23
22
|
@x = x
|
24
23
|
@y = y
|
@@ -93,7 +92,7 @@ public
|
|
93
92
|
# [Output]
|
94
93
|
# return inner product as Numeric
|
95
94
|
def dot(rhs)
|
96
|
-
|
95
|
+
Util3D.check_arg_type(Vector3, rhs)
|
97
96
|
self.x*rhs.x + self.y*rhs.y + self.z*rhs.z
|
98
97
|
end
|
99
98
|
|
@@ -102,7 +101,7 @@ public
|
|
102
101
|
# [Output]
|
103
102
|
# return cross product as Vector3.
|
104
103
|
def cross(rhs)
|
105
|
-
|
104
|
+
Util3D.check_arg_type(Vector3, rhs)
|
106
105
|
Vector3.new(
|
107
106
|
self.y*rhs.z - self.z*rhs.y,
|
108
107
|
self.z*rhs.x - self.x*rhs.z,
|
@@ -137,7 +136,7 @@ public
|
|
137
136
|
# [Output]
|
138
137
|
# return distance between two points as Numeric.
|
139
138
|
def distance(rhs)
|
140
|
-
|
139
|
+
Util3D.check_arg_type(Vector3, rhs)
|
141
140
|
Math::sqrt((self.x - rhs.x)*(self.x - rhs.x) + (self.y - rhs.y)*(self.y - rhs.y) + (self.z - rhs.z)*(self.z - rhs.z))
|
142
141
|
end
|
143
142
|
|
@@ -146,7 +145,7 @@ public
|
|
146
145
|
# [Output]
|
147
146
|
# return two vectors angle as Numeric (rad).
|
148
147
|
def angle(rhs)
|
149
|
-
|
148
|
+
Util3D.check_arg_type(Vector3, rhs)
|
150
149
|
vec1Length = self.length ;
|
151
150
|
vec2Length = rhs.length ;
|
152
151
|
return 0.0 if(vec1Length*vec2Length < self.tolerance )
|
@@ -165,7 +164,7 @@ public
|
|
165
164
|
# [Output]
|
166
165
|
# return true if myself and rhs is parallel as boolean
|
167
166
|
def parallel?(rhs)
|
168
|
-
|
167
|
+
Util3D.check_arg_type(Vector3, rhs)
|
169
168
|
return false if(self.length < self.tolerance or rhs.length < rhs.tolerance)
|
170
169
|
return false if(self.cross(rhs).length > self.tolerance)
|
171
170
|
return true
|
@@ -176,7 +175,7 @@ public
|
|
176
175
|
# [Output]
|
177
176
|
# return true if myself and rhs have same direction as boolean.
|
178
177
|
def same_direction?(rhs)
|
179
|
-
|
178
|
+
Util3D.check_arg_type(Vector3, rhs)
|
180
179
|
return false if(!parallel?(rhs))
|
181
180
|
return false if(self.dot(rhs) < self.tolerance)
|
182
181
|
return true
|
@@ -188,7 +187,7 @@ public
|
|
188
187
|
# [Output]
|
189
188
|
# return projected result as Vector3.
|
190
189
|
def project_to(rhs)
|
191
|
-
|
190
|
+
Util3D.check_arg_type(Vector3, rhs)
|
192
191
|
return Vector3.new, 0.0 if( rhs.length < rhs.tolerance )
|
193
192
|
parameter = self.dot( rhs ) / ( rhs.x * rhs.x + rhs.y * rhs.y + rhs.z * rhs.z ).to_f
|
194
193
|
return rhs*parameter, parameter
|
@@ -208,19 +207,19 @@ public
|
|
208
207
|
true
|
209
208
|
end
|
210
209
|
def add(rhs)
|
211
|
-
|
210
|
+
Util3D.check_arg_type(Vector3, rhs)
|
212
211
|
Vector3.new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
|
213
212
|
end
|
214
213
|
def subtract(rhs)
|
215
|
-
|
214
|
+
Util3D.check_arg_type(Vector3, rhs)
|
216
215
|
Vector3.new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
|
217
216
|
end
|
218
217
|
def multiply(rhs)
|
219
|
-
|
218
|
+
Util3D.check_arg_type(::Numeric, rhs)
|
220
219
|
Vector3.new(self.x * rhs, self.y * rhs, self.z * rhs)
|
221
220
|
end
|
222
221
|
def divide(rhs)
|
223
|
-
|
222
|
+
Util3D.check_arg_type(::Numeric, rhs)
|
224
223
|
Vector3.new(self.x.to_f / rhs, self.y / rhs.to_f, self.z / rhs.to_f)
|
225
224
|
end
|
226
225
|
end
|
data/test/test_box.rb
CHANGED
@@ -116,4 +116,52 @@ class BoxTestCase < MiniTest::Unit::TestCase
|
|
116
116
|
assert_in_delta( 1.0, @box_default.volume, @box_default.tolerance )
|
117
117
|
assert_in_delta( 112.5, @box.volume, @box.tolerance )
|
118
118
|
end
|
119
|
+
|
120
|
+
def test_vertices
|
121
|
+
verts = @box_default.vertices
|
122
|
+
assert(verts.include?(Vector3.new(0,0,0)))
|
123
|
+
assert(verts.include?(Vector3.new(1,0,0)))
|
124
|
+
assert(verts.include?(Vector3.new(1,1,0)))
|
125
|
+
assert(verts.include?(Vector3.new(0,1,0)))
|
126
|
+
assert(verts.include?(Vector3.new(0,0,1)))
|
127
|
+
assert(verts.include?(Vector3.new(1,0,1)))
|
128
|
+
assert(verts.include?(Vector3.new(1,1,1)))
|
129
|
+
assert(verts.include?(Vector3.new(0,1,1)))
|
130
|
+
|
131
|
+
verts = @box.vertices #.new(-3,2,5), Vector3.new(2,-2.5, 0))
|
132
|
+
assert(verts.include?(Vector3.new(-3, -2.5, 0)))
|
133
|
+
assert(verts.include?(Vector3.new( 2, -2.5, 0)))
|
134
|
+
assert(verts.include?(Vector3.new( 2, 2.0, 0)))
|
135
|
+
assert(verts.include?(Vector3.new(-3, 2.0, 0)))
|
136
|
+
assert(verts.include?(Vector3.new(-3, -2.5, 5)))
|
137
|
+
assert(verts.include?(Vector3.new( 2, -2.5, 5)))
|
138
|
+
assert(verts.include?(Vector3.new( 2, 2.0, 5)))
|
139
|
+
assert(verts.include?(Vector3.new(-3, 2.0, 5)))
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_translate
|
143
|
+
trans = Vector3.new(1,2.5,-0.5)
|
144
|
+
translated = @box_default.translate(trans)
|
145
|
+
assert_equal(Box.new(Vector3.new(1,2.5,-0.5), Vector3.new(2,3.5,0.5)), translated)
|
146
|
+
|
147
|
+
# this procedure is not destructive
|
148
|
+
assert_equal(Box.new(Vector3.new(0,0,0), Vector3.new(1,1,1)), @box_default)
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_rotate
|
152
|
+
angle_90 = 90.0*Math::PI/180.0
|
153
|
+
angle_45 = 45.0*Math::PI/180.0
|
154
|
+
rotation1 = Quat.from_axis(Vector3.new(0,0,1), angle_90)
|
155
|
+
rotation2 = Quat.from_axis(Vector3.new(0,0,1), angle_45)
|
156
|
+
# rotation3 = Quat.from_axis(Vector3.new(1,1,1).normalize, angle_90)
|
157
|
+
rotated1 = @box_default.rotate(rotation1)
|
158
|
+
rotated2 = @box_default.rotate(rotation2)
|
159
|
+
assert_equal(Box.new(Vector3.new(0,-1,0), Vector3.new(1,0,1)), rotated1)
|
160
|
+
assert_equal(Box.new(
|
161
|
+
Vector3.new(0, -(Math.sqrt(2.0)/2) ,0),
|
162
|
+
Vector3.new(Math.sqrt(2.0), (Math.sqrt(2.0)/2) ,1)), rotated2)
|
163
|
+
|
164
|
+
# this procedure is not destructive
|
165
|
+
assert_equal(Box.new(Vector3.new(0,0,0), Vector3.new(1,1,1)), @box_default)
|
166
|
+
end
|
119
167
|
end
|
data/test/test_tri_mesh.rb
CHANGED
@@ -173,4 +173,14 @@ class TriMeshTestCase < MiniTest::Unit::TestCase
|
|
173
173
|
box_mesh = get_box_mesh()
|
174
174
|
assert_equal(94, box_mesh.area)
|
175
175
|
end
|
176
|
+
|
177
|
+
def test_normals_for_each_vertices
|
178
|
+
box = Box.new(Vector3.new(-1,-1,-1), Vector3.new(1,1,1))
|
179
|
+
box_mesh = TriMesh.from_box(box)
|
180
|
+
result = box_mesh.normals_for_each_vertices
|
181
|
+
assert_equal( box_mesh.vertices.size, result.size )
|
182
|
+
box_mesh.vertices.each do |vertex|
|
183
|
+
assert_equal(vertex.normalize, result[vertex])
|
184
|
+
end
|
185
|
+
end
|
176
186
|
end
|
data/test/test_triangle.rb
CHANGED
@@ -299,4 +299,20 @@ class TriangleTestCase < MiniTest::Unit::TestCase
|
|
299
299
|
assert_equal( nil, point_on_triangle )
|
300
300
|
assert_equal( nil, point_on_plane )
|
301
301
|
end
|
302
|
+
|
303
|
+
def test_angle
|
304
|
+
triangle1 = Triangle.new( Vector3.new(0,0,1), Vector3.new(Math.sqrt(3.0),0,1), Vector3.new(0,1,1))
|
305
|
+
triangle2 = Triangle.new( Vector3.new(1,0,0), Vector3.new(0,0,1), Vector3.new(1,1,1))
|
306
|
+
|
307
|
+
assert_equal(nil, triangle1.angle(-1))
|
308
|
+
assert_equal(nil, triangle1.angle(3))
|
309
|
+
|
310
|
+
assert_in_delta(90.0*Math::PI/180.0, triangle1.angle(0), triangle1.tolerance)
|
311
|
+
assert_in_delta(30.0*Math::PI/180.0, triangle1.angle(1), triangle1.tolerance)
|
312
|
+
assert_in_delta(60.0*Math::PI/180.0, triangle1.angle(2), triangle1.tolerance)
|
313
|
+
|
314
|
+
assert_in_delta(60.0*Math::PI/180.0, triangle2.angle(0), triangle1.tolerance)
|
315
|
+
assert_in_delta(60.0*Math::PI/180.0, triangle2.angle(1), triangle1.tolerance)
|
316
|
+
assert_in_delta(60.0*Math::PI/180.0, triangle2.angle(2), triangle1.tolerance)
|
317
|
+
end
|
302
318
|
end
|
data/test/test_util.rb
CHANGED
@@ -12,28 +12,28 @@ class UtilTestCase < MiniTest::Unit::TestCase
|
|
12
12
|
stringInstance = 'string'
|
13
13
|
|
14
14
|
# no exception raise
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
Util3D.check_arg_type(Integer, integerInstance)
|
16
|
+
Util3D.check_arg_type(Float, floatInstance)
|
17
|
+
Util3D.check_arg_type(String, stringInstance)
|
18
18
|
|
19
19
|
# exception raise
|
20
20
|
assert_raises ArgumentError do
|
21
|
-
|
21
|
+
Util3D.check_arg_type(Integer, floatInstance)
|
22
22
|
end
|
23
23
|
assert_raises ArgumentError do
|
24
|
-
|
24
|
+
Util3D.check_arg_type(Integer, stringInstance)
|
25
25
|
end
|
26
26
|
assert_raises ArgumentError do
|
27
|
-
|
27
|
+
Util3D.check_arg_type(Float, integerInstance)
|
28
28
|
end
|
29
29
|
assert_raises ArgumentError do
|
30
|
-
|
30
|
+
Util3D.check_arg_type(Float, stringInstance)
|
31
31
|
end
|
32
32
|
assert_raises ArgumentError do
|
33
|
-
|
33
|
+
Util3D.check_arg_type(String, integerInstance)
|
34
34
|
end
|
35
35
|
assert_raises ArgumentError do
|
36
|
-
|
36
|
+
Util3D.check_arg_type(String, floatInstance)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gmath3D
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-26 00:00:00.000000000 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
17
|
-
requirement: &
|
17
|
+
requirement: &2151937640 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 1.0.0
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2151937640
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: jeweler
|
28
|
-
requirement: &
|
28
|
+
requirement: &2151936740 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: 1.6.4
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2151936740
|
37
37
|
description: This library defines 3D geometric elements(point, line, plane etc..).
|
38
38
|
It can get two(or more) elements relation, like distance between two elements.
|
39
39
|
email: toshi0328@gmail.com
|
@@ -53,11 +53,11 @@ files:
|
|
53
53
|
- gmath3D.gemspec
|
54
54
|
- lib/box.rb
|
55
55
|
- lib/ellipse.rb
|
56
|
+
- lib/ext.rb
|
56
57
|
- lib/finite_line.rb
|
57
58
|
- lib/geom.rb
|
58
59
|
- lib/gmath3D.rb
|
59
60
|
- lib/line.rb
|
60
|
-
- lib/matrix_util.rb
|
61
61
|
- lib/plane.rb
|
62
62
|
- lib/polyline.rb
|
63
63
|
- lib/quat.rb
|
@@ -97,7 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
97
97
|
version: '0'
|
98
98
|
segments:
|
99
99
|
- 0
|
100
|
-
hash:
|
100
|
+
hash: -2832198732220705826
|
101
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
102
|
none: false
|
103
103
|
requirements:
|
data/lib/matrix_util.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'gmath3D'
|
2
|
-
require 'matrix'
|
3
|
-
|
4
|
-
|
5
|
-
class Matrix
|
6
|
-
def self.from_axis(axis, angle)
|
7
|
-
Util.check_arg_type(Vector3, axis)
|
8
|
-
Util.check_arg_type(Numeric, angle)
|
9
|
-
|
10
|
-
return Matrix[
|
11
|
-
[axis.x*axis.x*(1 - Math.cos(angle)) + Math.cos(angle),
|
12
|
-
axis.x*axis.y*(1 - Math.cos(angle)) + axis.z*Math.sin(angle),
|
13
|
-
axis.x*axis.z*(1 - Math.cos(angle)) - axis.y*Math.sin(angle)],
|
14
|
-
[axis.x*axis.y*(1 - Math.cos(angle)) - axis.z*Math.sin(angle),
|
15
|
-
axis.y*axis.y*(1 - Math.cos(angle)) + Math.cos(angle),
|
16
|
-
axis.y*axis.z*(1 - Math.cos(angle)) + axis.x*Math.sin(angle)],
|
17
|
-
[axis.x*axis.z*(1 - Math.cos(angle)) + axis.y*Math.sin(angle),
|
18
|
-
axis.y*axis.z*(1 - Math.cos(angle)) - axis.x*Math.sin(angle),
|
19
|
-
axis.z*axis.z*(1 - Math.cos(angle)) + Math.cos(angle)]]
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.from_quat(quat)
|
23
|
-
Util.check_arg_type(Quat, quat)
|
24
|
-
qw = quat.w
|
25
|
-
qx = quat.x
|
26
|
-
qy = quat.y
|
27
|
-
qz = quat.z
|
28
|
-
|
29
|
-
x2 = 2.0 * qx * qx;
|
30
|
-
y2 = 2.0 * qy * qy;
|
31
|
-
z2 = 2.0 * qz * qz;
|
32
|
-
xy = 2.0 * qx * qy;
|
33
|
-
yz = 2.0 * qy * qz;
|
34
|
-
zx = 2.0 * qz * qx;
|
35
|
-
wx = 2.0 * qw * qx;
|
36
|
-
wy = 2.0 * qw * qy;
|
37
|
-
wz = 2.0 * qw * qz;
|
38
|
-
|
39
|
-
return Matrix[
|
40
|
-
[ 1.0 - y2 - z2, xy + wz, zx - wy],
|
41
|
-
[ xy - wz, 1.0 - z2 - x2, yz + wx],
|
42
|
-
[ zx + wy, yz - wx, 1.0 - x2 - y2]]
|
43
|
-
end
|
44
|
-
|
45
|
-
alias_method :multi_inner, :* # hold original multiply processing
|
46
|
-
def multi_new(rhs)
|
47
|
-
if(rhs.kind_of?(Vector3))
|
48
|
-
ans = self.multi_inner(rhs.to_column_vector)
|
49
|
-
return Vector3.new(ans[0,0], ans[1,0], ans[2,0])
|
50
|
-
end
|
51
|
-
multi_inner(rhs)
|
52
|
-
end
|
53
|
-
alias_method :*, :multi_new # overwrite new multiply processing
|
54
|
-
end
|
55
|
-
|