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 //------------------------------------------------------------------------------