Class: Mageo::Triangle
- Inherits:
-
Object
- Object
- Mageo::Triangle
- Defined in:
- lib/mageo/triangle.rb
Overview
3次元空間中の3角形を表現するクラス。
法線ベクトル( Mageo::Vector3D クラスインスタンス )を返すメソッドは定義しない。
法線ベクトルは2通りの方向を取りうるため。
initialize 時に点の指定の順序を決めることで定義はできるが、
そうすると簡潔性が損なわれる。
Defined Under Namespace
Classes: InitializeError, LinearException, NoIntersectionError, TypeError
Instance Attribute Summary collapse
-
#vertices ⇒ Object
readonly
Returns the value of attribute vertices.
Instance Method Summary collapse
-
#==(other) ⇒ Object
3つの頂点の座標が順序通りに対応すれば真を返す。.
- #edges ⇒ Object
-
#equivalent?(other, tolerance = 0.0) ⇒ Boolean
(also: #eql?)
3つの頂点の座標が順不同で対応すれば真を返す。 other が Mageo::Triangle クラス以外のインスタンスなら例外 Triangle::TypeError を投げる。 MEMO: 当初 eql? という名前を付けていたが、 これは hash メソッドと関連があるので危険。 よって別の名前の equivalent? というメソッド名にした。 しかし eql? に依存したコードが残っているので当面 alias を残す。 そのうち obsolete する。.
-
#include?(pos, tolerance) ⇒ Boolean
3点で張られる面上にあり、三角形の内側にあれば true を返す。 pos が Mageo::Vector3D クラスインスタンスでなければ例外。 ただし、面の法線方向には tolerance だけの許容値を設ける。 計算誤差の問題のため、これを設定しないと殆ど真とならない。.
-
#initialize(vertices) ⇒ Triangle
constructor
An argument ‘vertices’ can be Array of 3 items, Vector of 3 items, or Mageo::Vector3D class instance, which have [] and map methods.
-
#intersection(segment, tolerance) ⇒ Object
三角形を含む面と線分の交点を返す。 交点がない、無数にある、三角形の内側にない、という場合には 例外 NoIntersectionError を返す。.
-
#normal_vector ⇒ Object
法線ベクトルの1つを返す。 法線ベクトルは正反対の方向を示す 2つがあるが、 内部的には頂点の順が右ねじとなる方向(正確には外積の定義される方向) のものが選ばれる。 また、長さが1に規格化されたものが返される。.
-
#parallel_segment?(segment) ⇒ Boolean
線分と並行であることを判定する。 線分が三角形の面内の場合は false になる。.
-
#same_side?(pos0, pos1) ⇒ Boolean
引数で与えられた 2 つの座標が、三角形の面に対して同じ側にあれば true を返す。 どちらか、もしくは両方が、面上の点(当然頂点、辺上を含む)であれば必ず false を返す。.
Constructor Details
#initialize(vertices) ⇒ Triangle
An argument ‘vertices’ can be Array of 3 items, Vector of 3 items, or Mageo::Vector3D class instance, which have [] and map methods. 当面は Array を前提とする。 座標が整数で入っていたとしても内部的には Float に変換して使用する。 3点が1直線上に並んでいて三角形を囲まない場合は 例外 Mageo::Triangle::LinearException を投げる。
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/mageo/triangle.rb', line 25 def initialize( vertices ) raise InitializeError unless vertices.methods.include?( :size ) raise InitializeError if vertices.size != 3 vertices.each do |pos| raise InitializeError if pos.size != 3 raise InitializeError unless pos.methods.include?( :[] ) raise InitializeError unless pos.methods.include?( :map ) end @vertices = vertices.map do |pos| ( pos.map { |i| i.to_f }) . to_v3d end #Checking on linear. edge1 = @vertices[1] - @vertices[0] edge2 = @vertices[2] - @vertices[0] if ( Mageo::Vector3D[0.0, 0.0, 0.0] == Mageo::Vector3D.vector_product( edge1, edge2 )) raise LinearException end end |
Instance Attribute Details
#vertices ⇒ Object (readonly)
Returns the value of attribute vertices.
11 12 13 |
# File 'lib/mageo/triangle.rb', line 11 def vertices @vertices end |
Instance Method Details
#==(other) ⇒ Object
3つの頂点の座標が順序通りに対応すれば真を返す。
193 194 195 196 197 198 |
# File 'lib/mageo/triangle.rb', line 193 def ==(other) vertices.size.times do |i| return false unless @vertices[i] == other.vertices[i] end return true end |
#edges ⇒ Object
200 201 202 203 204 205 206 |
# File 'lib/mageo/triangle.rb', line 200 def edges results = [] results << Mageo::Segment.new(@vertices[0], @vertices[1]) results << Mageo::Segment.new(@vertices[1], @vertices[2]) results << Mageo::Segment.new(@vertices[2], @vertices[0]) return results end |
#equivalent?(other, tolerance = 0.0) ⇒ Boolean Also known as: eql?
3つの頂点の座標が順不同で対応すれば真を返す。 other が Mageo::Triangle クラス以外のインスタンスなら例外 Triangle::TypeError を投げる。 MEMO: 当初 eql? という名前を付けていたが、 これは hash メソッドと関連があるので危険。 よって別の名前の equivalent? というメソッド名にした。 しかし eql? に依存したコードが残っているので当面 alias を残す。 そのうち obsolete する。
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/mageo/triangle.rb', line 172 def equivalent?(other, tolerance = 0.0) raise TypeError unless other.class == Mageo::Triangle vertices.each do |v_self| if (other.vertices.find{|v_other| v_self.equal_in_delta?(v_other, tolerance) }) next else return false end end #return false unless other.vertices.include?(v) return true #vertices.each do |v| # return false unless other.vertices.include?(v) #end #return true end |
#include?(pos, tolerance) ⇒ Boolean
3点で張られる面上にあり、三角形の内側にあれば true を返す。 pos が Mageo::Vector3D クラスインスタンスでなければ例外。 ただし、面の法線方向には tolerance だけの許容値を設ける。 計算誤差の問題のため、これを設定しないと殆ど真とならない。
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/mageo/triangle.rb', line 70 def include?(pos, tolerance) raise TypeError if pos.class != Mageo::Vector3D axes = internal_axes #一次独立チェックは initialize 時にされている筈。 pos = (pos - @vertices[0]).to_v3d internal_pos = pos.internal_coordinates(axes) return false if internal_pos[2].abs > tolerance #面の外にあれば false return false if (internal_pos[0] < 0.0 ) return false if (1.0 < internal_pos[0]) return false if (internal_pos[1] < 0.0 ) return false if (1.0 < internal_pos[1]) return false if (1.0 < internal_pos[0] + internal_pos[1]) #たしざんで 1 いかとか。 return true end |
#intersection(segment, tolerance) ⇒ Object
三角形を含む面と線分の交点を返す。 交点がない、無数にある、三角形の内側にない、という場合には 例外 NoIntersectionError を返す。
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/mageo/triangle.rb', line 100 def intersection(segment, tolerance) # 平行のとき、例外。 raise NoIntersectionError if parallel_segment?(segment) # 面内の直線のとき、例外。 endpoints_v3di = segment.endpoints.map do |v| (v - @vertices[0]).internal_coordinates(internal_axes) end if ( (endpoints_v3di[0][2] == 0.0) && (endpoints_v3di[1][2] == 0.0) ) raise NoIntersectionError end # 面と直線の交点を求める。 # endpoints_v3di をベクトルと見たとき、 c 軸成分が 0 になるのは # ベクトルの何倍か? # ゼロ割りになる条件は、ここまでに弾いた条件に含まれる筈。 c_0 = endpoints_v3di[0][2] c_1 = endpoints_v3di[1][2] factor = c_0 / (c_0 - c_1) result = (segment.endpoints[0] + (segment.to_v3d) * factor) # 交点が線分上にあるか?すなわち両端点が面を挟んでいるか? raise NoIntersectionError if c_0 * c_1 > 0 # 交点が三角形の内側にあるか? if (! include?(result, tolerance)) raise NoIntersectionError end return result end |
#normal_vector ⇒ Object
法線ベクトルの1つを返す。 法線ベクトルは正反対の方向を示す 2つがあるが、 内部的には頂点の順が右ねじとなる方向(正確には外積の定義される方向) のものが選ばれる。 また、長さが1に規格化されたものが返される。
155 156 157 158 159 160 161 162 |
# File 'lib/mageo/triangle.rb', line 155 def normal_vector edge1 = (@vertices[1] - @vertices[0]) edge2 = (@vertices[2] - @vertices[1]) vec = edge1.exterior_product( edge2 ) normal = vec * (1.0/vec.r) return normal end |
#parallel_segment?(segment) ⇒ Boolean
線分と並行であることを判定する。 線分が三角形の面内の場合は false になる。
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/mageo/triangle.rb', line 134 def parallel_segment?(segment) #p segment.endpoints t = segment.endpoints.map{|v| v.internal_coordinates(internal_axes) } # 傾いてるときは常に false return false if t[0][2] != t[1][2] # 傾きがない場合、面に含まれていれば false return false if t[0][2] == 0.0 # 残った場合が true return true end |
#same_side?(pos0, pos1) ⇒ Boolean
引数で与えられた 2 つの座標が、三角形の面に対して同じ側にあれば true を返す。 どちらか、もしくは両方が、面上の点(当然頂点、辺上を含む)であれば必ず false を返す。
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/mageo/triangle.rb', line 48 def same_side?( pos0, pos1 ) raise TypeError if pos0.class != Mageo::Vector3D raise TypeError if pos1.class != Mageo::Vector3D edge1 = @vertices[1] - @vertices[0] edge2 = @vertices[2] - @vertices[0] pos0 = pos0.to_v3d - @vertices[0] pos1 = pos1.to_v3d - @vertices[0] triple_product_pos0 = Mageo::Vector3D.scalar_triple_product( edge1, edge2, pos0 ) triple_product_pos1 = Mageo::Vector3D.scalar_triple_product( edge1, edge2, pos1 ) if triple_product_pos0 * triple_product_pos1 > 0 return true else return false end end |