SyFi
0.3
|
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