class GMath3D::Triangle
Triangle
represents a three edged finite plane on 3D space.
Attributes
Public Class Methods
GMath3D::Geom::new
# File lib/triangle.rb, line 17 def initialize(vertex1 = Vector3.new(), vertex2 = Vector3.new(1,0,0), vertex3 = Vector3.new(0,1,0)) Util3D.check_arg_type(::Vector3, vertex1) Util3D.check_arg_type(::Vector3, vertex2) Util3D.check_arg_type(::Vector3, vertex3) super() @vertices = Array.new([vertex1, vertex2, vertex3]) end
Public Instance Methods
- Input
-
rhs is
Line
. - Output
-
return true if rhs equals myself.
# File lib/triangle.rb, line 36 def ==(rhs) return false if rhs == nil return false if( !rhs.kind_of?(Triangle) ) return false if(@vertices.size != rhs.vertices.size) for i in 0..@vertices.size-1 return false if(@vertices[i] != rhs.vertices[i]) end return true end
- Input
-
vertex_index should be 0..2.
- Output
-
return angle as Numeric(radian).
# File lib/triangle.rb, line 97 def angle( vertex_index ) return nil if(vertex_index < 0 || vertex_index > 2) vert1 = self.vertices[vertex_index] vert2 = self.vertices[(vertex_index+1)%3] vert3 = self.vertices[(vertex_index+2)%3] vec1 = vert2 - vert1 vec2 = vert3 - vert1 vec1.angle(vec2) end
- Output
-
return area as Numeric.
# File lib/triangle.rb, line 72 def area vec1 = vertices[1] - vertices[0] vec2 = vertices[2] - vertices[0] outer_product = vec1.cross(vec2) return outer_product.length / 2.0 end
- Input
-
check_point should be
Vector3
. - Output
-
return
barycentric_coordinate
on check_point as three elementArray
of Numeric.
# File lib/triangle.rb, line 117 def barycentric_coordinate( check_point ) Util3D.check_arg_type(::Vector3, check_point) v0 = @vertices[0] v1 = @vertices[1] v2 = @vertices[2] d1 = v1 - v0 d2 = v2 - v1 n = d1.cross(d2); if((n.x).abs >= (n.y).abs && (n.x).abs >= (n.z).abs) uu1 = v0.y - v2.y; uu2 = v1.y - v2.y; uu3 = check_point.y - v0.y; uu4 = check_point.y - v2.y; vv1 = v0.z - v2.z; vv2 = v1.z - v2.z; vv3 = check_point.z - v0.z; vv4 = check_point.z - v2.z; elsif((n.y).abs >= (n.z).abs) uu1 = v0.z - v2.z; uu2 = v1.z - v2.z; uu3 = check_point.z - v0.z; uu4 = check_point.z - v2.z; vv1 = v0.x - v2.x; vv2 = v1.x - v2.x; vv3 = check_point.x - v0.x; vv4 = check_point.x - v2.x; else uu1 = v0.x - v2.x; uu2 = v1.x - v2.x; uu3 = check_point.x - v0.x; uu4 = check_point.x - v2.x; vv1 = v0.y - v2.y; vv2 = v1.y - v2.y; vv3 = check_point.y - v0.y; vv4 = check_point.y - v2.y; end denom = vv1 * uu2 - vv2* uu1 if(denom == 0.0) return nil end b = Array.new(3) oneOverDenom = 1.0 / denom ; b[0] = (vv4*uu2 - vv2*uu4) * oneOverDenom; b[1] = (vv1*uu3 - vv3*uu1) * oneOverDenom; b[2] = 1.0 - b[0] - b[1]; return b; end
- Output
-
return center point as
Vector3
.
# File lib/triangle.rb, line 81 def center return vertices.avg end
- Input
-
check_point shold be
Vector3
. - Output
-
return true if triangle contains check_point.
# File lib/triangle.rb, line 195 def contains?( check_point ) Util3D.check_arg_type(Vector3, check_point ) plane = Plane.new( vertices[0], self.normal) distance, projected_point = plane.distance(check_point) return false if( distance > self.tolerance ) g_coord = self.barycentric_coordinate(check_point) g_coord.each do |item| return false if( item < 0 or 1 < item) end return true end
- Input
- Output
- In case target is
Vector3
-
return “distance, point on triangle” as [Numeric, Vector3].
- In case target is
Line
-
return “distance, point on tirangle, point on line, parameter on line” as [Numeric,
Vector3
,Vector3
, Numeric]. - In case target is
Plane
-
return “distance, intersect_line(or closet edge), point_on_triangle, point_on_plane” as [Numeric,
Vector3
,Vector3
, Vector3].
- In case target is
# File lib/triangle.rb, line 177 def distance(target) # with Point if(target.kind_of?(Vector3)) return distance_to_point(target) elsif(target.kind_of?(Line)) #with Line return distance_to_line(target) elsif(target.kind_of?(Plane)) #with Plane return distance_to_plane(target) end Util3D.raise_argurment_error(target) end
# File lib/triangle.rb, line 62 def edges return_edges = Array.new(3) return_edges[0] = FiniteLine.new(self.vertices[0], self.vertices[1]) return_edges[1] = FiniteLine.new(self.vertices[1], self.vertices[2]) return_edges[2] = FiniteLine.new(self.vertices[2], self.vertices[0]) return return_edges end
# File lib/triangle.rb, line 25 def initialize_copy( original_obj ) @vertices = Array.new(original_obj.vertices.size) for i in 0..@vertices.size-1 @vertices[i] = original_obj.vertices[i].dup end end
- Output
-
return normal vector as
Vector3
.
# File lib/triangle.rb, line 87 def normal vec1 = self.vertices[1] - self.vertices[0] vec2 = self.vertices[2] - self.vertices[0] return (vec1.cross(vec2).normalize) end
- Input
-
parameter should be three element
Array
of Numeric. - Output
-
return point on triangle at parameter position as
Vector3
.
# File lib/triangle.rb, line 54 def point( parameter ) Util3D.check_arg_type(::Array, parameter ) # TODO Argument check return self.vertices[0]*parameter[0] + self.vertices[1]*parameter[1] + self.vertices[2]*parameter[2] end
- Output
-
return normal vector reversed triangle
# File lib/triangle.rb, line 109 def reverse return Triangle.new(@vertices[0], @vertices[2], @vertices[1]) end
# File lib/triangle.rb, line 46 def to_s "Triangle[#{@vertices[0].to_element_s}, #{@vertices[1].to_element_s}, #{@vertices[2].to_element_s}]" end
Private Instance Methods
# File lib/triangle.rb, line 219 def distance_to_line(target_line) plane = Plane.new( vertices[0], self.normal ) distance, point_on_plane, parameter_on_line = plane.distance( target_line ) if( point_on_plane == nil) # parallel case # check distance to FiniteLines finite_lines = self.edges distance, point_on_edge, point_on_target, param_on_finiteline, param_on_target = FiniteLine.ary_distance_to_line(finite_lines, target_line) return distance, nil, nil, nil end if( self.contains?(point_on_plane) ) return distance, point_on_plane, point_on_plane, parameter_on_line end # check distance to FiniteLines finite_lines = self.edges distance, point_on_edge, point_on_target, param_on_finiteline, param_on_target = FiniteLine.ary_distance_to_line(finite_lines, target_line) return distance, point_on_edge, point_on_target, param_on_target end
# File lib/triangle.rb, line 240 def distance_to_plane(target_plane) triangle_plane = Plane.new( vertices[0], self.normal ) distance, intersect_line_each_plane = triangle_plane.distance( target_plane ) if( intersect_line_each_plane == nil ) return distance, nil, nil, nil end # check distance from intersection and each edge. distance_zero_count = 0 distance_info = Array.new(0) prallel_edge_ary = Array.new(0) self.edges.each do |edge| distance, point_on_edge, point_on_line = edge.distance( intersect_line_each_plane) if point_on_edge != nil && point_on_line != nil distance_info.push([distance, point_on_edge, point_on_line]) if distance <= self.tolerance distance_zero_count += 1 end else prallel_edge_ary.push( edge ) end end distance_info.sort!{|a,b| a[0] <=> b[0]} # distance, intersect_line(or closet edge), point_on_triangle, point_on_plan if (distance_zero_count == 2) point1 = distance_info[0][1] point2 = distance_info[1][1] if point1.distance(point2) > self.tolerance return 0.0, FiniteLine.new(point1, point2), nil, nil end return 0.0, nil, point1, point1 elsif (distance_zero_count == 0) distance, closest_point_on_plane = target_plane.distance(distance_info[0][1]) if(distance_info[0][1] != distance_info[1][1]) return distance, FiniteLine.new(distance_info[0][1], distance_info[1][1]), nil, nil end return distance, nil, distance_info[0][1], closest_point_on_plane end return 0.0, nil, nil, nil end
# File lib/triangle.rb, line 208 def distance_to_point(target_point) plane = Plane.new( vertices[0], self.normal) distance, projected_point = plane.distance(target_point) if( self.contains?(projected_point)) return distance, projected_point end #check distance to FiniteLines finite_lines = self.edges return FiniteLine.ary_distanc_to_point(finite_lines, target_point) end