gmath3D 0.2.3 → 0.2.4
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.
- 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
|
-
|