Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

SphereIntersection.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00002 // Lamp : Open source game middleware
00003 // Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
00004 //
00005 // This library is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 //
00010 // This library is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this library; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 //------------------------------------------------------------------------------
00019 
00020 /** @file
00021  * 球交差実装
00022  * @author Junpee
00023  */
00024 
00025 #include "LampBasic.h"
00026 #include "Geometry/Intersection/SphereIntersection.h"
00027 #include "Geometry/System/Intersection.h"
00028 
00029 #include "Geometry/Primitive/Triangle.h"
00030 
00031 namespace Lamp{
00032 
00033 //------------------------------------------------------------------------------
00034 // 点
00035 //------------------------------------------------------------------------------
00036 // 点交差
00037 bool SphereIntersection::intersect(const Sphere& sphere, const Vector3& point){
00038     Assert(false);
00039     return false;
00040 }
00041 //------------------------------------------------------------------------------
00042 // 球
00043 //------------------------------------------------------------------------------
00044 // 球交差
00045 bool SphereIntersection::intersect(
00046     const Sphere& sphere0, const Sphere& sphere1){
00047     // 半径と距離を比較する
00048     float radius = sphere0.getRadius() + sphere1.getRadius();
00049     Vector3 direction = sphere1.getCenter() - sphere0.getCenter();
00050     if(direction.getSquaredLength() > (radius * radius)){ return false; }
00051     return true;
00052 }
00053 //------------------------------------------------------------------------------
00054 // 球交差
00055 bool SphereIntersection::intersect(Intersection* intersection,
00056     const Sphere& sphere0, const Sphere& sphere1){
00057     const Vector3& center0 = sphere0.getCenter();
00058     float radius0 = sphere0.getRadius();
00059     const Vector3& center1 = sphere1.getCenter();
00060     float radius1 = sphere1.getRadius();
00061     // 半径と距離を比較する
00062     float totalRadius = radius0 + radius1;
00063     Vector3 distance = center1 - center0;
00064     float squaredLength = distance.getSquaredLength();
00065     if(squaredLength > (totalRadius * totalRadius)){ return false; }
00066     // 交差位置と反射の設定
00067     if(distance.isZero()){ distance = Vector3::unitY; }
00068     else{ distance.normalize(); }
00069     intersection->set(center0 + (distance * radius0),
00070         distance * (totalRadius - Math::sqrt(squaredLength)));
00071     return true;
00072 }
00073 //------------------------------------------------------------------------------
00074 // 三角
00075 //------------------------------------------------------------------------------
00076 // 三角交差
00077 bool SphereIntersection::intersect(
00078     const Sphere& sphere, const Triangle& triangle){
00079     const Vector3& center = sphere.getCenter();
00080     float radius = sphere.getRadius();
00081     const Vector3& vertex0 = triangle.getVertex(0);
00082     const Vector3& vertex1 = triangle.getVertex(1);
00083     const Vector3& vertex2 = triangle.getVertex(2);
00084 
00085     // 面法線を求める
00086     Vector3 edge0 = vertex1 - vertex0;
00087     Vector3 edge1 = vertex2 - vertex1;
00088     Vector3 normal = edge0.crossProduct(edge1).normalize();
00089 
00090     // 平面と球の距離を求める
00091     float constant = -normal.dotProduct(vertex0);
00092     float distance = normal.dotProduct(center) + constant;
00093 
00094     // 球の中心が面に接しているか、負の方向にある場合は当たらない。
00095     if(distance <= 0.f){ return false; }
00096     // 半径以上はなれていれば当たらない
00097     if(distance > radius){ return false; }
00098 
00099     // 球が三角内部に存在するか
00100     Vector3 edge2 = vertex0 - vertex2;
00101     bool outside = false;
00102     Vector3 distance0 = center - vertex0;
00103     outside |= (normal.dotProduct(edge0.crossProduct(distance0)) < 0.f);
00104     Vector3 distance1 = center - vertex1;
00105     outside |= (normal.dotProduct(edge1.crossProduct(distance1)) < 0.f);
00106     Vector3 distance2 = center - vertex2;
00107     outside |= (normal.dotProduct(edge2.crossProduct(distance2)) < 0.f);
00108     // 三角の内側なので交差する
00109     if(!outside){
00110         // 交差位置は球中心から面法線の逆方向にdistance伸ばしたところ
00111         return true;
00112     }
00113 
00114     // セグメント0との比較
00115     float squaredRadius = radius * radius;
00116     float t0 = distance0.dotProduct(edge0);
00117     if(t0 > 0.f){
00118         float edgeSquaredLength = edge0.getSquaredLength();
00119         if(t0 >= edgeSquaredLength){
00120             // t0 = 1.f; // 接触点を求める場合は設定する
00121             distance0 -= edge0;
00122         }else{
00123             t0 /= edgeSquaredLength;
00124             distance0 -= t0 * edge0;
00125         }
00126     }
00127     // セグメントとの距離が半径以下
00128     if(distance0.getSquaredLength() <= squaredRadius){
00129         // 交差位置はvertex0 + t0 * edge0
00130         return true;
00131     }
00132 
00133     // セグメント1との比較
00134     float t1 = distance1.dotProduct(edge1);
00135     if(t1 > 0.f){
00136         float edgeSquaredLength = edge1.getSquaredLength();
00137         if(t1 >= edgeSquaredLength){
00138             // t1 = 1.f; // 接触点を求める場合は設定する
00139             distance1 -= edge1;
00140         }else{
00141             t1 /= edgeSquaredLength;
00142             distance1 -= t1 * edge1;
00143         }
00144     }
00145     // セグメントとの距離が半径以下
00146     if(distance1.getSquaredLength() <= squaredRadius){
00147         // 交差位置はvertex1 + t1 * edge1
00148         return true;
00149     }
00150 
00151     // セグメント2との比較
00152     float t2 = distance2.dotProduct(edge2);
00153     if(t2 > 0.f){
00154         float edgeSquaredLength = edge2.getSquaredLength();
00155         if(t2 >= edgeSquaredLength){
00156             // t2 = 1.f; // 接触点を求める場合は設定する
00157             distance2 -= edge2;
00158         }else{
00159             t2 /= edgeSquaredLength;
00160             distance2 -= t2 * edge2;
00161         }
00162     }
00163     // セグメントとの距離が半径以下
00164     if(distance2.getSquaredLength() <= squaredRadius){
00165         // 交差位置はvertex2 + t2 * edge2
00166         return true;
00167     }
00168 
00169     return false;
00170 }
00171 //------------------------------------------------------------------------------
00172 // 三角交差
00173 bool SphereIntersection::intersect(Intersection* intersection,
00174     const Sphere& sphere, const Triangle& triangle){
00175     const Vector3& center = sphere.getCenter();
00176     float radius = sphere.getRadius();
00177     const Vector3& vertex0 = triangle.getVertex(0);
00178     const Vector3& vertex1 = triangle.getVertex(1);
00179     const Vector3& vertex2 = triangle.getVertex(2);
00180 
00181     // 面法線を求める
00182     Vector3 edge0 = vertex1 - vertex0;
00183     Vector3 edge1 = vertex2 - vertex1;
00184     Vector3 normal = edge0.crossProduct(edge1).normalize();
00185 
00186     // 平面と球の距離を求める
00187     float constant = -normal.dotProduct(vertex0);
00188     float distance = normal.dotProduct(center) + constant;
00189 
00190     // 球の中心が面に接しているか、負の方向にある場合は当たらない。
00191     if(distance <= 0.f){ return false; }
00192     // 半径以上はなれていれば当たらない
00193     if(distance > radius){ return false; }
00194 
00195     // 球が三角内部に存在するか
00196     Vector3 edge2 = vertex0 - vertex2;
00197     bool outside = false;
00198     Vector3 distance0 = center - vertex0;
00199     outside |= (normal.dotProduct(edge0.crossProduct(distance0)) < 0.f);
00200     Vector3 distance1 = center - vertex1;
00201     outside |= (normal.dotProduct(edge1.crossProduct(distance1)) < 0.f);
00202     Vector3 distance2 = center - vertex2;
00203     outside |= (normal.dotProduct(edge2.crossProduct(distance2)) < 0.f);
00204     // 三角の内側なので交差する
00205     if(!outside){
00206         // 交差位置は球中心から面方向へ半径分移動した地点
00207         // 反射は面の逆方向で(半径-距離)の長さ
00208         Vector3 inverseNormal(-normal);
00209         intersection->set(center + inverseNormal * radius,
00210             inverseNormal * (radius - distance));
00211         return true;
00212     }
00213 
00214     // セグメント0との比較
00215     float squaredRadius = radius * radius;
00216     float t0 = distance0.dotProduct(edge0);
00217     if(t0 > 0.f){
00218         float edgeSquaredLength = edge0.getSquaredLength();
00219         if(t0 >= edgeSquaredLength){
00220             t0 = 1.f;
00221             distance0 -= edge0;
00222         }else{
00223             t0 /= edgeSquaredLength;
00224             distance0 -= t0 * edge0;
00225         }
00226     }
00227     // セグメント0との距離が半径以下
00228     float squaredLength0 = distance0.getSquaredLength();
00229     if(squaredLength0 <= squaredRadius){
00230         // 交差位置は球中心に(-distance0).setLength(radius)を足した位置
00231         // 反射は(-distance).setLength(radius - length0)
00232         Vector3 position0 = -distance0;
00233         float length0 = radius - Math::sqrt(squaredLength0);
00234         if(position0.isZero()){
00235             // エッジが球中心に重なっている
00236             position0 = Vector3::unitY * radius;
00237             intersection->set(center + position0, position0);
00238         }else if(length0 <= Math::epsilon){
00239             // エッジが球に接している
00240             intersection->set(center + position0.setLength(radius),
00241                 Vector3::zero);
00242         }else{
00243             // エッジが球にめり込んでいる
00244             position0.normalize();
00245             intersection->set(center + position0 * radius,
00246                 position0 * length0);
00247         }
00248         return true;
00249     }
00250 
00251     // セグメント1との比較
00252     float t1 = distance1.dotProduct(edge1);
00253     if(t1 > 0.f){
00254         float edgeSquaredLength = edge1.getSquaredLength();
00255         if(t1 >= edgeSquaredLength){
00256             t1 = 1.f;
00257             distance1 -= edge1;
00258         }else{
00259             t1 /= edgeSquaredLength;
00260             distance1 -= t1 * edge1;
00261         }
00262     }
00263     // セグメント1との距離が半径以下
00264     float squaredLength1 = distance1.getSquaredLength();
00265     if(squaredLength1 <= squaredRadius){
00266         // 交差位置は球中心に(-distance1).setLength(radius)を足した位置
00267         // 反射は(-distance).setLength(radius - length1)
00268         Vector3 position1 = -distance1;
00269         float length1 = radius - Math::sqrt(squaredLength1);
00270         if(position1.isZero()){
00271             // エッジが球中心に重なっている
00272             position1 = Vector3::unitY * radius;
00273             intersection->set(center + position1, position1);
00274         }else if(length1 <= Math::epsilon){
00275             // エッジが球に接している
00276             intersection->set(center + position1.setLength(radius),
00277                 Vector3::zero);
00278         }else{
00279             // エッジが球にめり込んでいる
00280             position1.normalize();
00281             intersection->set(center + position1 * radius,
00282                 position1 * length1);
00283         }
00284         return true;
00285     }
00286 
00287     // セグメント2との比較
00288     float t2 = distance2.dotProduct(edge2);
00289     if(t2 > 0.f){
00290         float edgeSquaredLength = edge2.getSquaredLength();
00291         if(t2 >= edgeSquaredLength){
00292             t2 = 1.f;
00293             distance2 -= edge2;
00294         }else{
00295             t2 /= edgeSquaredLength;
00296             distance2 -= t2 * edge2;
00297         }
00298     }
00299     // セグメント2との距離が半径以下
00300     float squaredLength2 = distance2.getSquaredLength();
00301     if(squaredLength2 <= squaredRadius){
00302         // 交差位置は球中心に(-distance2).setLength(radius)を足した位置
00303         // 反射は(-distance).setLength(radius - length2)
00304         Vector3 position2 = -distance2;
00305         float length2 = radius - Math::sqrt(squaredLength2);
00306         if(position2.isZero()){
00307             // エッジが球中心に重なっている
00308             position2 = Vector3::unitY * radius;
00309             intersection->set(center + position2, position2);
00310         }else if(length2 <= Math::epsilon){
00311             // エッジが球に接している
00312             intersection->set(center + position2.setLength(radius),
00313                 Vector3::zero);
00314         }else{
00315             // エッジが球にめり込んでいる
00316             position2.normalize();
00317             intersection->set(center + position2 * radius,
00318                 position2 * length2);
00319         }
00320         return true;
00321     }
00322 
00323     return false;
00324 }
00325 //------------------------------------------------------------------------------
00326 } // End of namespace Lamp
00327 //------------------------------------------------------------------------------

Generated on Wed Mar 16 10:29:36 2005 for Lamp by doxygen 1.3.2