gmath3D 0.2.4 → 0.2.5
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/.document +5 -5
- data/Gemfile +5 -11
- data/LICENSE.txt +20 -20
- data/README.rdoc +19 -19
- data/Rakefile +45 -45
- data/VERSION +1 -1
- data/gmath3D.gemspec +79 -80
- data/lib/box.rb +145 -145
- data/lib/ellipse.rb +11 -11
- data/lib/ext.rb +82 -82
- data/lib/finite_line.rb +244 -244
- data/lib/geom.rb +20 -20
- data/lib/gmath3D.rb +22 -22
- data/lib/line.rb +122 -122
- data/lib/plane.rb +131 -131
- data/lib/polyline.rb +73 -73
- data/lib/quat.rb +170 -170
- data/lib/rectangle.rb +155 -155
- data/lib/tri_mesh.rb +258 -258
- data/lib/triangle.rb +281 -281
- data/lib/util.rb +36 -23
- data/lib/vector3.rb +227 -227
- data/test/helper.rb +15 -15
- data/test/test_box.rb +167 -167
- data/test/test_ellipse.rb +55 -55
- data/test/test_finite_line.rb +306 -306
- data/test/test_geom.rb +17 -17
- data/test/test_line.rb +146 -146
- data/test/test_matrix_util.rb +84 -84
- data/test/test_plane.rb +200 -200
- data/test/test_polyline.rb +93 -93
- data/test/test_quat.rb +144 -144
- data/test/test_rectangle.rb +184 -184
- data/test/test_tri_mesh.rb +186 -186
- data/test/test_triangle.rb +318 -318
- data/test/test_util.rb +88 -57
- data/test/test_vector3.rb +439 -439
- metadata +8 -11
- data/Gemfile.lock +0 -16
data/lib/triangle.rb
CHANGED
@@ -1,281 +1,281 @@
|
|
1
|
-
require 'gmath3D'
|
2
|
-
|
3
|
-
module GMath3D
|
4
|
-
#
|
5
|
-
# Triangle represents a three edged finite plane on 3D space.
|
6
|
-
#
|
7
|
-
class Triangle < Geom
|
8
|
-
public
|
9
|
-
attr_accessor :vertices
|
10
|
-
|
11
|
-
include BoxAvailable
|
12
|
-
|
13
|
-
# [Input]
|
14
|
-
# _vertex1_, _vertex2_, _vertex3_ should be Vector3.
|
15
|
-
# [Output]
|
16
|
-
# return new instance of Triangle.
|
17
|
-
def initialize(vertex1 = Vector3.new(), vertex2 = Vector3.new(1,0,0), vertex3 = Vector3.new(0,1,0))
|
18
|
-
Util3D.check_arg_type(::Vector3, vertex1)
|
19
|
-
Util3D.check_arg_type(::Vector3, vertex2)
|
20
|
-
Util3D.check_arg_type(::Vector3, vertex3)
|
21
|
-
super()
|
22
|
-
@vertices = Array.new([vertex1, vertex2, vertex3])
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize_copy( original_obj )
|
26
|
-
@vertices = Array.new(original_obj.vertices.size)
|
27
|
-
for i in 0..@vertices.size-1
|
28
|
-
@vertices[i] = original_obj.vertices[i].dup
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# [Input]
|
33
|
-
# _rhs_ is Line.
|
34
|
-
# [Output]
|
35
|
-
# return true if rhs equals myself.
|
36
|
-
def ==(rhs)
|
37
|
-
return false if rhs == nil
|
38
|
-
return false if( !rhs.kind_of?(Triangle) )
|
39
|
-
return false if(@vertices.size != rhs.vertices.size)
|
40
|
-
for i in 0..@vertices.size-1
|
41
|
-
return false if(@vertices[i] != rhs.vertices[i])
|
42
|
-
end
|
43
|
-
return true
|
44
|
-
end
|
45
|
-
|
46
|
-
def to_s
|
47
|
-
"Triangle[#{@vertices[0].to_element_s}, #{@vertices[1].to_element_s}, #{@vertices[2].to_element_s}]"
|
48
|
-
end
|
49
|
-
|
50
|
-
# [Input]
|
51
|
-
# _parameter_ should be three element Array of Numeric.
|
52
|
-
# [Output]
|
53
|
-
# return point on triangle at parameter position as Vector3.
|
54
|
-
def point( parameter )
|
55
|
-
Util3D.check_arg_type(::Array, parameter )
|
56
|
-
# TODO Argument check
|
57
|
-
return self.vertices[0]*parameter[0] + self.vertices[1]*parameter[1] + self.vertices[2]*parameter[2]
|
58
|
-
end
|
59
|
-
|
60
|
-
# [Output]
|
61
|
-
# return edges as three element Array of Vector3.
|
62
|
-
def edges
|
63
|
-
return_edges = Array.new(3)
|
64
|
-
return_edges[0] = FiniteLine.new(self.vertices[0], self.vertices[1])
|
65
|
-
return_edges[1] = FiniteLine.new(self.vertices[1], self.vertices[2])
|
66
|
-
return_edges[2] = FiniteLine.new(self.vertices[2], self.vertices[0])
|
67
|
-
return return_edges
|
68
|
-
end
|
69
|
-
|
70
|
-
# [Output]
|
71
|
-
# return area as Numeric.
|
72
|
-
def area
|
73
|
-
vec1 = vertices[1] - vertices[0]
|
74
|
-
vec2 = vertices[2] - vertices[0]
|
75
|
-
outer_product = vec1.cross(vec2)
|
76
|
-
return outer_product.length / 2.0
|
77
|
-
end
|
78
|
-
|
79
|
-
# [Output]
|
80
|
-
# return center point as Vector3.
|
81
|
-
def center
|
82
|
-
return vertices.avg
|
83
|
-
end
|
84
|
-
|
85
|
-
# [Output]
|
86
|
-
# return normal vector as Vector3.
|
87
|
-
def normal
|
88
|
-
vec1 = self.vertices[1] - self.vertices[0]
|
89
|
-
vec2 = self.vertices[2] - self.vertices[0]
|
90
|
-
return (vec1.cross(vec2).normalize)
|
91
|
-
end
|
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
|
-
|
107
|
-
# [Output]
|
108
|
-
# return normal vector reversed triangle
|
109
|
-
def reverse
|
110
|
-
return Triangle.new(@vertices[0], @vertices[2], @vertices[1])
|
111
|
-
end
|
112
|
-
|
113
|
-
# [Input]
|
114
|
-
# _check_point_ should be Vector3.
|
115
|
-
# [Output]
|
116
|
-
# return barycentric_coordinate on check_point as three element Array of Numeric.
|
117
|
-
def barycentric_coordinate( check_point )
|
118
|
-
Util3D.check_arg_type(::Vector3, check_point)
|
119
|
-
|
120
|
-
v0 = @vertices[0]
|
121
|
-
v1 = @vertices[1]
|
122
|
-
v2 = @vertices[2]
|
123
|
-
|
124
|
-
d1 = v1 - v0
|
125
|
-
d2 = v2 - v1
|
126
|
-
n = d1.cross(d2);
|
127
|
-
if((n.x).abs >= (n.y).abs && (n.x).abs >= (n.z).abs)
|
128
|
-
uu1 = v0.y - v2.y;
|
129
|
-
uu2 = v1.y - v2.y;
|
130
|
-
uu3 = check_point.y - v0.y;
|
131
|
-
uu4 = check_point.y - v2.y;
|
132
|
-
vv1 = v0.z - v2.z;
|
133
|
-
vv2 = v1.z - v2.z;
|
134
|
-
vv3 = check_point.z - v0.z;
|
135
|
-
vv4 = check_point.z - v2.z;
|
136
|
-
elsif((n.y).abs >= (n.z).abs)
|
137
|
-
uu1 = v0.z - v2.z;
|
138
|
-
uu2 = v1.z - v2.z;
|
139
|
-
uu3 = check_point.z - v0.z;
|
140
|
-
uu4 = check_point.z - v2.z;
|
141
|
-
vv1 = v0.x - v2.x;
|
142
|
-
vv2 = v1.x - v2.x;
|
143
|
-
vv3 = check_point.x - v0.x;
|
144
|
-
vv4 = check_point.x - v2.x;
|
145
|
-
else
|
146
|
-
uu1 = v0.x - v2.x;
|
147
|
-
uu2 = v1.x - v2.x;
|
148
|
-
uu3 = check_point.x - v0.x;
|
149
|
-
uu4 = check_point.x - v2.x;
|
150
|
-
vv1 = v0.y - v2.y;
|
151
|
-
vv2 = v1.y - v2.y;
|
152
|
-
vv3 = check_point.y - v0.y;
|
153
|
-
vv4 = check_point.y - v2.y;
|
154
|
-
end
|
155
|
-
|
156
|
-
denom = vv1 * uu2 - vv2* uu1
|
157
|
-
if(denom == 0.0)
|
158
|
-
return nil
|
159
|
-
end
|
160
|
-
b = Array.new(3)
|
161
|
-
oneOverDenom = 1.0 / denom ;
|
162
|
-
b[0] = (vv4*uu2 - vv2*uu4) * oneOverDenom;
|
163
|
-
b[1] = (vv1*uu3 - vv3*uu1) * oneOverDenom;
|
164
|
-
b[2] = 1.0 - b[0] - b[1];
|
165
|
-
return b;
|
166
|
-
end
|
167
|
-
|
168
|
-
# [Input]
|
169
|
-
# _target_ shold be Vector3 or Line or Plane.
|
170
|
-
# [Output]
|
171
|
-
# [In case _target_ is Vector3]
|
172
|
-
# return "distance, point on triangle" as [Numeric, Vector3].
|
173
|
-
# [In case _target_ is Line]
|
174
|
-
# return "distance, point on tirangle, point on line, parameter on line" as [Numeric, Vector3, Vector3, Numeric].
|
175
|
-
# [In case _target_ is Plane]
|
176
|
-
# return "distance, intersect_line(or closet edge), point_on_triangle, point_on_plane" as [Numeric, Vector3, Vector3, Vector3].
|
177
|
-
def distance(target)
|
178
|
-
# with Point
|
179
|
-
if(target.kind_of?(Vector3))
|
180
|
-
return distance_to_point(target)
|
181
|
-
elsif(target.kind_of?(Line))
|
182
|
-
#with Line
|
183
|
-
return distance_to_line(target)
|
184
|
-
elsif(target.kind_of?(Plane))
|
185
|
-
#with Plane
|
186
|
-
return distance_to_plane(target)
|
187
|
-
end
|
188
|
-
Util3D.raise_argurment_error(target)
|
189
|
-
end
|
190
|
-
|
191
|
-
# [Input]
|
192
|
-
# _check_point_ shold be Vector3.
|
193
|
-
# [Output]
|
194
|
-
# return true if triangle contains _check_point_.
|
195
|
-
def contains?( check_point )
|
196
|
-
Util3D.check_arg_type(Vector3, check_point )
|
197
|
-
plane = Plane.new( vertices[0], self.normal)
|
198
|
-
distance, projected_point = plane.distance(check_point)
|
199
|
-
return false if( distance > self.tolerance )
|
200
|
-
g_coord = self.barycentric_coordinate(check_point)
|
201
|
-
g_coord.each do |item|
|
202
|
-
return false if( item < 0 or 1 < item)
|
203
|
-
end
|
204
|
-
return true
|
205
|
-
end
|
206
|
-
|
207
|
-
private
|
208
|
-
def distance_to_point(target_point)
|
209
|
-
plane = Plane.new( vertices[0], self.normal)
|
210
|
-
distance, projected_point = plane.distance(target_point)
|
211
|
-
if( self.contains?(projected_point))
|
212
|
-
return distance, projected_point
|
213
|
-
end
|
214
|
-
#check distance to FiniteLines
|
215
|
-
finite_lines = self.edges
|
216
|
-
return FiniteLine.ary_distanc_to_point(finite_lines, target_point)
|
217
|
-
end
|
218
|
-
|
219
|
-
def distance_to_line(target_line)
|
220
|
-
plane = Plane.new( vertices[0], self.normal )
|
221
|
-
distance, point_on_plane, parameter_on_line = plane.distance( target_line )
|
222
|
-
if( point_on_plane == nil)
|
223
|
-
# parallel case
|
224
|
-
# check distance to FiniteLines
|
225
|
-
finite_lines = self.edges
|
226
|
-
distance, point_on_edge, point_on_target, param_on_finiteline, param_on_target =
|
227
|
-
FiniteLine.ary_distance_to_line(finite_lines, target_line)
|
228
|
-
return distance, nil, nil, nil
|
229
|
-
end
|
230
|
-
if( self.contains?(point_on_plane) )
|
231
|
-
return distance, point_on_plane, point_on_plane, parameter_on_line
|
232
|
-
end
|
233
|
-
# check distance to FiniteLines
|
234
|
-
finite_lines = self.edges
|
235
|
-
distance, point_on_edge, point_on_target, param_on_finiteline, param_on_target =
|
236
|
-
FiniteLine.ary_distance_to_line(finite_lines, target_line)
|
237
|
-
return distance, point_on_edge, point_on_target, param_on_target
|
238
|
-
end
|
239
|
-
|
240
|
-
def distance_to_plane(target_plane)
|
241
|
-
triangle_plane = Plane.new( vertices[0], self.normal )
|
242
|
-
distance, intersect_line_each_plane = triangle_plane.distance( target_plane )
|
243
|
-
if( intersect_line_each_plane == nil )
|
244
|
-
return distance, nil, nil, nil
|
245
|
-
end
|
246
|
-
|
247
|
-
# check distance from intersection and each edge.
|
248
|
-
distance_zero_count = 0
|
249
|
-
distance_info = Array.new(0)
|
250
|
-
prallel_edge_ary = Array.new(0)
|
251
|
-
self.edges.each do |edge|
|
252
|
-
distance, point_on_edge, point_on_line = edge.distance( intersect_line_each_plane)
|
253
|
-
if point_on_edge != nil && point_on_line != nil
|
254
|
-
distance_info.push([distance, point_on_edge, point_on_line])
|
255
|
-
if distance <= self.tolerance
|
256
|
-
distance_zero_count += 1
|
257
|
-
end
|
258
|
-
else
|
259
|
-
prallel_edge_ary.push( edge )
|
260
|
-
end
|
261
|
-
end
|
262
|
-
distance_info.sort!{|a,b| a[0] <=> b[0]}
|
263
|
-
# distance, intersect_line(or closet edge), point_on_triangle, point_on_plan
|
264
|
-
if (distance_zero_count == 2)
|
265
|
-
point1 = distance_info[0][1]
|
266
|
-
point2 = distance_info[1][1]
|
267
|
-
if point1.distance(point2) > self.tolerance
|
268
|
-
return 0.0, FiniteLine.new(point1, point2), nil, nil
|
269
|
-
end
|
270
|
-
return 0.0, nil, point1, point1
|
271
|
-
elsif (distance_zero_count == 0)
|
272
|
-
distance, closest_point_on_plane = target_plane.distance(distance_info[0][1])
|
273
|
-
if(distance_info[0][1] != distance_info[1][1])
|
274
|
-
return distance, FiniteLine.new(distance_info[0][1], distance_info[1][1]), nil, nil
|
275
|
-
end
|
276
|
-
return distance, nil, distance_info[0][1], closest_point_on_plane
|
277
|
-
end
|
278
|
-
return 0.0, nil, nil, nil
|
279
|
-
end
|
280
|
-
end
|
281
|
-
end
|
1
|
+
require 'gmath3D'
|
2
|
+
|
3
|
+
module GMath3D
|
4
|
+
#
|
5
|
+
# Triangle represents a three edged finite plane on 3D space.
|
6
|
+
#
|
7
|
+
class Triangle < Geom
|
8
|
+
public
|
9
|
+
attr_accessor :vertices
|
10
|
+
|
11
|
+
include BoxAvailable
|
12
|
+
|
13
|
+
# [Input]
|
14
|
+
# _vertex1_, _vertex2_, _vertex3_ should be Vector3.
|
15
|
+
# [Output]
|
16
|
+
# return new instance of Triangle.
|
17
|
+
def initialize(vertex1 = Vector3.new(), vertex2 = Vector3.new(1,0,0), vertex3 = Vector3.new(0,1,0))
|
18
|
+
Util3D.check_arg_type(::Vector3, vertex1)
|
19
|
+
Util3D.check_arg_type(::Vector3, vertex2)
|
20
|
+
Util3D.check_arg_type(::Vector3, vertex3)
|
21
|
+
super()
|
22
|
+
@vertices = Array.new([vertex1, vertex2, vertex3])
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize_copy( original_obj )
|
26
|
+
@vertices = Array.new(original_obj.vertices.size)
|
27
|
+
for i in 0..@vertices.size-1
|
28
|
+
@vertices[i] = original_obj.vertices[i].dup
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# [Input]
|
33
|
+
# _rhs_ is Line.
|
34
|
+
# [Output]
|
35
|
+
# return true if rhs equals myself.
|
36
|
+
def ==(rhs)
|
37
|
+
return false if rhs == nil
|
38
|
+
return false if( !rhs.kind_of?(Triangle) )
|
39
|
+
return false if(@vertices.size != rhs.vertices.size)
|
40
|
+
for i in 0..@vertices.size-1
|
41
|
+
return false if(@vertices[i] != rhs.vertices[i])
|
42
|
+
end
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
"Triangle[#{@vertices[0].to_element_s}, #{@vertices[1].to_element_s}, #{@vertices[2].to_element_s}]"
|
48
|
+
end
|
49
|
+
|
50
|
+
# [Input]
|
51
|
+
# _parameter_ should be three element Array of Numeric.
|
52
|
+
# [Output]
|
53
|
+
# return point on triangle at parameter position as Vector3.
|
54
|
+
def point( parameter )
|
55
|
+
Util3D.check_arg_type(::Array, parameter )
|
56
|
+
# TODO Argument check
|
57
|
+
return self.vertices[0]*parameter[0] + self.vertices[1]*parameter[1] + self.vertices[2]*parameter[2]
|
58
|
+
end
|
59
|
+
|
60
|
+
# [Output]
|
61
|
+
# return edges as three element Array of Vector3.
|
62
|
+
def edges
|
63
|
+
return_edges = Array.new(3)
|
64
|
+
return_edges[0] = FiniteLine.new(self.vertices[0], self.vertices[1])
|
65
|
+
return_edges[1] = FiniteLine.new(self.vertices[1], self.vertices[2])
|
66
|
+
return_edges[2] = FiniteLine.new(self.vertices[2], self.vertices[0])
|
67
|
+
return return_edges
|
68
|
+
end
|
69
|
+
|
70
|
+
# [Output]
|
71
|
+
# return area as Numeric.
|
72
|
+
def area
|
73
|
+
vec1 = vertices[1] - vertices[0]
|
74
|
+
vec2 = vertices[2] - vertices[0]
|
75
|
+
outer_product = vec1.cross(vec2)
|
76
|
+
return outer_product.length / 2.0
|
77
|
+
end
|
78
|
+
|
79
|
+
# [Output]
|
80
|
+
# return center point as Vector3.
|
81
|
+
def center
|
82
|
+
return vertices.avg
|
83
|
+
end
|
84
|
+
|
85
|
+
# [Output]
|
86
|
+
# return normal vector as Vector3.
|
87
|
+
def normal
|
88
|
+
vec1 = self.vertices[1] - self.vertices[0]
|
89
|
+
vec2 = self.vertices[2] - self.vertices[0]
|
90
|
+
return (vec1.cross(vec2).normalize)
|
91
|
+
end
|
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
|
+
|
107
|
+
# [Output]
|
108
|
+
# return normal vector reversed triangle
|
109
|
+
def reverse
|
110
|
+
return Triangle.new(@vertices[0], @vertices[2], @vertices[1])
|
111
|
+
end
|
112
|
+
|
113
|
+
# [Input]
|
114
|
+
# _check_point_ should be Vector3.
|
115
|
+
# [Output]
|
116
|
+
# return barycentric_coordinate on check_point as three element Array of Numeric.
|
117
|
+
def barycentric_coordinate( check_point )
|
118
|
+
Util3D.check_arg_type(::Vector3, check_point)
|
119
|
+
|
120
|
+
v0 = @vertices[0]
|
121
|
+
v1 = @vertices[1]
|
122
|
+
v2 = @vertices[2]
|
123
|
+
|
124
|
+
d1 = v1 - v0
|
125
|
+
d2 = v2 - v1
|
126
|
+
n = d1.cross(d2);
|
127
|
+
if((n.x).abs >= (n.y).abs && (n.x).abs >= (n.z).abs)
|
128
|
+
uu1 = v0.y - v2.y;
|
129
|
+
uu2 = v1.y - v2.y;
|
130
|
+
uu3 = check_point.y - v0.y;
|
131
|
+
uu4 = check_point.y - v2.y;
|
132
|
+
vv1 = v0.z - v2.z;
|
133
|
+
vv2 = v1.z - v2.z;
|
134
|
+
vv3 = check_point.z - v0.z;
|
135
|
+
vv4 = check_point.z - v2.z;
|
136
|
+
elsif((n.y).abs >= (n.z).abs)
|
137
|
+
uu1 = v0.z - v2.z;
|
138
|
+
uu2 = v1.z - v2.z;
|
139
|
+
uu3 = check_point.z - v0.z;
|
140
|
+
uu4 = check_point.z - v2.z;
|
141
|
+
vv1 = v0.x - v2.x;
|
142
|
+
vv2 = v1.x - v2.x;
|
143
|
+
vv3 = check_point.x - v0.x;
|
144
|
+
vv4 = check_point.x - v2.x;
|
145
|
+
else
|
146
|
+
uu1 = v0.x - v2.x;
|
147
|
+
uu2 = v1.x - v2.x;
|
148
|
+
uu3 = check_point.x - v0.x;
|
149
|
+
uu4 = check_point.x - v2.x;
|
150
|
+
vv1 = v0.y - v2.y;
|
151
|
+
vv2 = v1.y - v2.y;
|
152
|
+
vv3 = check_point.y - v0.y;
|
153
|
+
vv4 = check_point.y - v2.y;
|
154
|
+
end
|
155
|
+
|
156
|
+
denom = vv1 * uu2 - vv2* uu1
|
157
|
+
if(denom == 0.0)
|
158
|
+
return nil
|
159
|
+
end
|
160
|
+
b = Array.new(3)
|
161
|
+
oneOverDenom = 1.0 / denom ;
|
162
|
+
b[0] = (vv4*uu2 - vv2*uu4) * oneOverDenom;
|
163
|
+
b[1] = (vv1*uu3 - vv3*uu1) * oneOverDenom;
|
164
|
+
b[2] = 1.0 - b[0] - b[1];
|
165
|
+
return b;
|
166
|
+
end
|
167
|
+
|
168
|
+
# [Input]
|
169
|
+
# _target_ shold be Vector3 or Line or Plane.
|
170
|
+
# [Output]
|
171
|
+
# [In case _target_ is Vector3]
|
172
|
+
# return "distance, point on triangle" as [Numeric, Vector3].
|
173
|
+
# [In case _target_ is Line]
|
174
|
+
# return "distance, point on tirangle, point on line, parameter on line" as [Numeric, Vector3, Vector3, Numeric].
|
175
|
+
# [In case _target_ is Plane]
|
176
|
+
# return "distance, intersect_line(or closet edge), point_on_triangle, point_on_plane" as [Numeric, Vector3, Vector3, Vector3].
|
177
|
+
def distance(target)
|
178
|
+
# with Point
|
179
|
+
if(target.kind_of?(Vector3))
|
180
|
+
return distance_to_point(target)
|
181
|
+
elsif(target.kind_of?(Line))
|
182
|
+
#with Line
|
183
|
+
return distance_to_line(target)
|
184
|
+
elsif(target.kind_of?(Plane))
|
185
|
+
#with Plane
|
186
|
+
return distance_to_plane(target)
|
187
|
+
end
|
188
|
+
Util3D.raise_argurment_error(target)
|
189
|
+
end
|
190
|
+
|
191
|
+
# [Input]
|
192
|
+
# _check_point_ shold be Vector3.
|
193
|
+
# [Output]
|
194
|
+
# return true if triangle contains _check_point_.
|
195
|
+
def contains?( check_point )
|
196
|
+
Util3D.check_arg_type(Vector3, check_point )
|
197
|
+
plane = Plane.new( vertices[0], self.normal)
|
198
|
+
distance, projected_point = plane.distance(check_point)
|
199
|
+
return false if( distance > self.tolerance )
|
200
|
+
g_coord = self.barycentric_coordinate(check_point)
|
201
|
+
g_coord.each do |item|
|
202
|
+
return false if( item < 0 or 1 < item)
|
203
|
+
end
|
204
|
+
return true
|
205
|
+
end
|
206
|
+
|
207
|
+
private
|
208
|
+
def distance_to_point(target_point)
|
209
|
+
plane = Plane.new( vertices[0], self.normal)
|
210
|
+
distance, projected_point = plane.distance(target_point)
|
211
|
+
if( self.contains?(projected_point))
|
212
|
+
return distance, projected_point
|
213
|
+
end
|
214
|
+
#check distance to FiniteLines
|
215
|
+
finite_lines = self.edges
|
216
|
+
return FiniteLine.ary_distanc_to_point(finite_lines, target_point)
|
217
|
+
end
|
218
|
+
|
219
|
+
def distance_to_line(target_line)
|
220
|
+
plane = Plane.new( vertices[0], self.normal )
|
221
|
+
distance, point_on_plane, parameter_on_line = plane.distance( target_line )
|
222
|
+
if( point_on_plane == nil)
|
223
|
+
# parallel case
|
224
|
+
# check distance to FiniteLines
|
225
|
+
finite_lines = self.edges
|
226
|
+
distance, point_on_edge, point_on_target, param_on_finiteline, param_on_target =
|
227
|
+
FiniteLine.ary_distance_to_line(finite_lines, target_line)
|
228
|
+
return distance, nil, nil, nil
|
229
|
+
end
|
230
|
+
if( self.contains?(point_on_plane) )
|
231
|
+
return distance, point_on_plane, point_on_plane, parameter_on_line
|
232
|
+
end
|
233
|
+
# check distance to FiniteLines
|
234
|
+
finite_lines = self.edges
|
235
|
+
distance, point_on_edge, point_on_target, param_on_finiteline, param_on_target =
|
236
|
+
FiniteLine.ary_distance_to_line(finite_lines, target_line)
|
237
|
+
return distance, point_on_edge, point_on_target, param_on_target
|
238
|
+
end
|
239
|
+
|
240
|
+
def distance_to_plane(target_plane)
|
241
|
+
triangle_plane = Plane.new( vertices[0], self.normal )
|
242
|
+
distance, intersect_line_each_plane = triangle_plane.distance( target_plane )
|
243
|
+
if( intersect_line_each_plane == nil )
|
244
|
+
return distance, nil, nil, nil
|
245
|
+
end
|
246
|
+
|
247
|
+
# check distance from intersection and each edge.
|
248
|
+
distance_zero_count = 0
|
249
|
+
distance_info = Array.new(0)
|
250
|
+
prallel_edge_ary = Array.new(0)
|
251
|
+
self.edges.each do |edge|
|
252
|
+
distance, point_on_edge, point_on_line = edge.distance( intersect_line_each_plane)
|
253
|
+
if point_on_edge != nil && point_on_line != nil
|
254
|
+
distance_info.push([distance, point_on_edge, point_on_line])
|
255
|
+
if distance <= self.tolerance
|
256
|
+
distance_zero_count += 1
|
257
|
+
end
|
258
|
+
else
|
259
|
+
prallel_edge_ary.push( edge )
|
260
|
+
end
|
261
|
+
end
|
262
|
+
distance_info.sort!{|a,b| a[0] <=> b[0]}
|
263
|
+
# distance, intersect_line(or closet edge), point_on_triangle, point_on_plan
|
264
|
+
if (distance_zero_count == 2)
|
265
|
+
point1 = distance_info[0][1]
|
266
|
+
point2 = distance_info[1][1]
|
267
|
+
if point1.distance(point2) > self.tolerance
|
268
|
+
return 0.0, FiniteLine.new(point1, point2), nil, nil
|
269
|
+
end
|
270
|
+
return 0.0, nil, point1, point1
|
271
|
+
elsif (distance_zero_count == 0)
|
272
|
+
distance, closest_point_on_plane = target_plane.distance(distance_info[0][1])
|
273
|
+
if(distance_info[0][1] != distance_info[1][1])
|
274
|
+
return distance, FiniteLine.new(distance_info[0][1], distance_info[1][1]), nil, nil
|
275
|
+
end
|
276
|
+
return distance, nil, distance_info[0][1], closest_point_on_plane
|
277
|
+
end
|
278
|
+
return 0.0, nil, nil, nil
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
data/lib/util.rb
CHANGED
@@ -1,23 +1,36 @@
|
|
1
|
-
module Util3D
|
2
|
-
def self.check_arg_type(type, instance)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
1
|
+
module Util3D
|
2
|
+
def self.check_arg_type(type, instance, nullable = false, array_check = false)
|
3
|
+
return if(nullable && instance.nil?)
|
4
|
+
if(array_check && instance.kind_of?(Array))
|
5
|
+
instance.each do |item|
|
6
|
+
check_arg_type(type, item, nullable, array_check)
|
7
|
+
end
|
8
|
+
else
|
9
|
+
unless(instance.kind_of?(type))
|
10
|
+
raise(ArgumentError::new("type mismatch: #{instance.class} for #{type}"))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.raise_argurment_error(instance)
|
16
|
+
raise(ArgumentError::new("type mismatch: #{instance.class}"))
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.check_key_arg(arg, key)
|
20
|
+
if(!arg.include?(key))
|
21
|
+
raise(ArgumentError::new("args should be contains: #{key}"))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module GMath3D
|
27
|
+
# Including 'vertices' methodshould be implimented that gets geometry vertices as Array of Vector3.
|
28
|
+
module BoxAvailable
|
29
|
+
# [Output]
|
30
|
+
# return axially aligned bounding box as Box.
|
31
|
+
def box
|
32
|
+
return Box.from_points( vertices )
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|