class GMath3D::Triangle

Triangle represents a three edged finite plane on 3D space.

Attributes

vertices[RW]

Public Class Methods

new(vertex1 = Vector3.new(), vertex2 = Vector3.new(1,0,0), vertex3 = Vector3.new(0,1,0)) click to toggle source
Input

vertex1, vertex2, vertex3 should be Vector3.

Output

return new instance of Triangle.

Calls superclass method 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

==(rhs) click to toggle source
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
angle( vertex_index ) click to toggle source
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
area() click to toggle source
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
barycentric_coordinate( check_point ) click to toggle source
Input

check_point should be Vector3.

Output

return barycentric_coordinate on check_point as three element Array 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
center() click to toggle source
Output

return center point as Vector3.

# File lib/triangle.rb, line 81
def center
  return vertices.avg
end
contains?( check_point ) click to toggle source
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
distance(target) click to toggle source
Input

target shold be Vector3 or Line or Plane.

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].

# 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
edges() click to toggle source
Output

return edges as three element Array of Vector3.

# 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
initialize_copy( original_obj ) click to toggle source
# 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
normal() click to toggle source
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
point( parameter ) click to toggle source
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
reverse() click to toggle source
Output

return normal vector reversed triangle

# File lib/triangle.rb, line 109
def reverse
  return Triangle.new(@vertices[0], @vertices[2], @vertices[1])
end
to_s() click to toggle source
# 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

distance_to_line(target_line) click to toggle source
# 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
distance_to_plane(target_plane) click to toggle source
# 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
distance_to_point(target_point) click to toggle source
# 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