SyFi  0.3
Ptv_tools.cpp
Go to the documentation of this file.
00001 // Copyright (C) 2006-2009 Kent-Andre Mardal and Simula Research Laboratory
00002 //
00003 // This file is part of SyFi.
00004 //
00005 // SyFi is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 2 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // SyFi 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
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with SyFi. If not, see <http://www.gnu.org/licenses/>.
00017 
00018 #include "Ptv_tools.h"
00019 #include <iostream>
00020 #include <stdexcept>
00021 #include <math.h>
00022 #include <vector>
00023 #include <algorithm>
00024 
00025 using namespace std;
00026 
00027 namespace SyFi
00028 {
00029 
00030         void sort_vector(vector<Ptv>& a)
00031         {
00032                 sort(a.begin(), a.end(), Ptv_is_less());
00033         }
00034 
00035         void set_tolerance(double tolerance)
00036         {
00037                 Ptv::tol = tolerance;
00038         }
00039 
00040         double mul(const Ptv&a, const Ptv& b)
00041         {
00042                 if ( a.size() != b.size() )
00043                 {
00044                         throw(std::logic_error("Exception from mul(const Ptv&, const Ptv&):  The dimentions of a and b must be the same."));
00045                 }
00046 
00047                 double sum = 0;
00048                 for (unsigned int i=0; i< a.size(); i++)
00049                 {
00050                         sum += (a[i])*(b[i]);
00051                 }
00052                 return sum;
00053         }
00054 
00055         double norm(const Ptv& a)
00056         {
00057                 double sum = 0.0;
00058                 for (unsigned int i=0; i < a.size(); i++)
00059                 {
00060                         sum += a[i]*a[i];
00061                 }
00062 
00063                 sum = sqrt(sum);
00064                 return sum;
00065         }
00066 
00067         void normalize(Ptv& a)
00068         {
00069                 double invn = 1.0/norm(a);
00070                 for (unsigned int i=0; i< a.size(); i++)
00071                 {
00072                         a[i] *= invn;
00073                 }
00074         }
00075 
00076         void add(const Ptv&a, const Ptv& b, Ptv& c)
00077         {
00078                 if ( a.size() != b.size() )
00079                 {
00080                         throw(std::logic_error("Exception from add(const Ptv&, const Ptv&, Ptv&):  The dimentions of a and b must be the same."));
00081                 }
00082 
00083                 c.redim(a.size());
00084                 for (unsigned int i=0; i< c.size(); i++)
00085                 {
00086                         c[i] = a[i] + b[i];
00087                 }
00088         }
00089 
00090         void sub(const Ptv&a, const Ptv& b, Ptv& c)
00091         {
00092                 if ( a.size() != b.size() )
00093                 {
00094                         throw(std::logic_error("Exception from add(const Ptv&, const Ptv&, Ptv&):  The dimentions of a and b must be the same."));
00095                 }
00096 
00097                 c.redim(a.size());
00098                 for (unsigned int i=0; i< c.size(); i++)
00099                 {
00100                         c[i] = a[i] - b[i];
00101                 }
00102         }
00103 
00104         void cross(const Ptv& a, const Ptv& b, Ptv& c)
00105         {
00106                 if ( a.size() != b.size() )
00107                 {
00108                         throw(std::logic_error("Exception from cross (const Ptv&, const Ptv&, Ptv&): The dimentions of a and b must be the same."));
00109                 }
00110 
00111                 if ( a.size() == 2 )
00112                 {
00113                         c.redim(1);
00114                         c[0] = a[0]*b[1] - a[1]*b[0];
00115                 }
00116 
00117                 else if ( a.size() == 3 )
00118                 {
00119                         c.redim(3);
00120                         c[0] =   a[1]*b[2] - b[1]*a[2];
00121                         c[1] = - a[0]*b[2] + b[0]*a[2];
00122                         c[2] =   a[0]*b[1] - b[0]*a[1];
00123                 }
00124 
00125                 else
00126                 {
00127                         throw(std::logic_error("The cross product can only be computed in 2D and 3D."));
00128                 }
00129 
00130         }
00131 
00132         bool is_equal(Ptv& a, Ptv& b)
00133         {
00134                 if (a.size() != b.size()) return false;
00135 
00136                 for (unsigned int i=0; i < a.size(); i++ )
00137                 {
00138                         if ( fabs( a[i] - b[i]) > Ptv::tol )
00139                         {
00140                                 return false;
00141                         }
00142                 }
00143 
00144                 return true;
00145         }
00146 
00147         bool line_contains(Ptv& e0, Ptv& e1, Ptv& p)
00148         {
00149 
00150                 if ( is_equal(e0, p) || is_equal(e1, p) ) return true;
00151 
00152                 // vec0 = e1-e0
00153                 Ptv vec0;
00154                 sub(e1,e0, vec0);
00155                 // vec1 = e1-p
00156                 Ptv vec1;
00157                 sub(e1, p, vec1);
00158 
00159                 // check if the vec0 and vec1 are parallel
00160                 Ptv c;
00161                 cross(vec0, vec1, c);
00162                 if (norm(c) > Ptv::tol)
00163                 {
00164                         return false;
00165                 }
00166 
00167                 // check whether the edge (e0,e1) contains p .
00168                 if ( e0.less(p) && e1.less(p) ) return false;
00169                 if ( p.less(e0) && p.less(e1) ) return false;
00170 
00171                 return true;
00172         }
00173 
00174         bool is_inside_triangle(Ptv& e0, Ptv& e1, Ptv& e2, Ptv& p)
00175         {
00176 
00177                 Ptv n0;
00178                 sub(e0, p, n0);
00179                 normalize(n0);
00180 
00181                 Ptv n1;
00182                 sub(e1, p, n1);
00183                 normalize(n1);
00184 
00185                 Ptv n2;
00186                 sub(e2, p, n2);
00187                 normalize(n2);
00188 
00189                 double c0 = acos(mul(n0,n1));
00190                 double c1 = acos(mul(n1,n2));
00191                 double c2 = acos(mul(n2,n1));
00192 
00193                 if ( fabs(c0 + c1 + c2 - 2*3.1415926535897931) < Ptv::tol) return true;
00194 
00195                 return false;
00196         }
00197 
00198         // FIXME this code can be made more general and put in
00199         // a more appropriate place. For now it is only used by
00200         // the boundary function. It only works in 2D.
00201         bool contains2D(Ptv& e0, Ptv& e1, Ptv& p)
00202         {
00203 
00204                 if ( e0.size() != e1.size() || e0.size() != p.size()  )
00205                 {
00206                         throw(std::logic_error("Exception from contains2D(Ptv&, Ptv&, Ptv&): The dimentions of a and b must be the same."));
00207                 }
00208 
00209                 bool b = line_contains(e0, e1, p);
00210 
00211                 return b;
00212         }
00213 
00214         bool contains3D(Ptv& e0, Ptv& e1, Ptv& e2, Ptv& p)
00215         {
00216 
00217                 // check if p is either e0, e1, or e2
00218                 if ( is_equal(e0, p) )  return true;
00219                 else if ( is_equal(e1, p) )  return true;
00220                 else if ( is_equal(e2, p) )  return true;
00221 
00222                 // check if p is on the lines connecting e0, e1, and e2
00223                 if ( line_contains(e0, e1, p) ) return true;
00224                 else if ( line_contains(e1, e2, p) ) return true;
00225                 else if ( line_contains(e2, e1, p) ) return true;
00226 
00227                 // check if p is inside the triangle with verticies e0, e1, and e2
00228                 if ( is_inside_triangle(e0, e1, e2, p) ) return true;
00229 
00230                 return false;
00231 
00232         }
00233 
00234 }                                                                // namespace SyFi
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator