$treeview $search $mathjax
Palabos  Version 1.1
$projectbrief
$projectbrief
$searchbox

triangularSurfaceMesh.hh

Go to the documentation of this file.
00001 /* This file is part of the Palabos library.
00002  *
00003  * Copyright (C) 2011 FlowKit Sarl
00004  * Avenue de Chailly 23
00005  * 1012 Lausanne, Switzerland
00006  * E-mail contact: contact@flowkit.com
00007  *
00008  * The most recent release of Palabos can be downloaded at 
00009  * <http://www.palabos.org/>
00010  *
00011  * The library Palabos is free software: you can redistribute it and/or
00012  * modify it under the terms of the GNU Affero General Public License as
00013  * published by the Free Software Foundation, either version 3 of the
00014  * License, or (at your option) any later version.
00015  *
00016  * The library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU Affero General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Affero General Public License
00022  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023 */
00024 
00025 /* Main author: Dimitrios Kontaxakis */
00026 
00027 #ifndef TRIANGULAR_SURFACE_MESH_HH
00028 #define TRIANGULAR_SURFACE_MESH_HH
00029 
00030 #include <algorithm>
00031 #include <limits>
00032 #include <cmath>
00033 #include <cstdio>
00034 #include <cstdlib>
00035 #include <cstring>
00036 #include "offLattice/triangularSurfaceMesh.h"
00037 #include "latticeBoltzmann/geometricOperationTemplates.h"
00038 #include "core/globalDefs.h"
00039 #include "core/plbDebug.h"
00040 #include "parallelism/mpiManager.h"
00041 #include "core/util.h"
00042 #include "io/parallelIO.h"
00043 
00044 #define FPEQUAL_ABS(x, y, eps) (fabs((x)-(y)) <= (eps)) // Macro definition for the function
00045                                                         // util::fpequal_abs<T>(T x, T y, T eps)
00046 
00047 namespace plb {
00048 
00049 template<typename T>
00050 const T TriangularSurfaceMesh<T>::eps0 = std::numeric_limits<T>::epsilon();
00051 
00052 template<typename T>
00053 const T TriangularSurfaceMesh<T>::eps1 =
00054         (sizeof(T) == sizeof(float)) ?
00055              std::numeric_limits<float>::epsilon() :
00056              100.0 * std::numeric_limits<T>::epsilon();
00057 
00058 template<typename T>
00059 TriangularSurfaceMesh<T>::TriangularSurfaceMesh (
00060             std::vector<Array<T,3> >& vertexList_,
00061             std::vector<plint>& emanatingEdgeList_,
00062             std::vector<typename TriangularSurfaceMesh<T>::Edge>& edgeList_,
00063             plint numVertices_ )
00064       : vertexList(&vertexList_),
00065         emanatingEdgeList(&emanatingEdgeList_),
00066         edgeList(&edgeList_),
00067         numTriangles((plint)edges().size()/(plint)3),
00068         numVertices(numVertices_>=0 ? numVertices_ : ( (plint)vertices().size() ) )
00069 {
00070     avoidIntegerPositions();
00071 }
00072 
00073 template<typename T>
00074 void TriangularSurfaceMesh<T>::replaceVertex(plint iVertex, Array<T,3> const& newPosition)
00075 {
00076     PLB_PRECONDITION( iVertex<getNumVertices() );
00077     (*vertexList)[iVertex] = newPosition;
00078     // avoidIntegerPosition(iVertex);
00079 }
00080 
00081 template<typename T>
00082 void TriangularSurfaceMesh<T>::resetVertices(Array<T,3> const& defaultVertex)
00083 {
00084     for (plint iVertex=0; iVertex<getNumVertices(); ++iVertex) {
00085         vertices()[iVertex] = defaultVertex;
00086     }
00087 }
00088 
00089 template<typename T>
00090 inline void TriangularSurfaceMesh<T>::assertVertex(Array<T,3> const& vertex) const
00091 {
00092 #ifdef PLB_DEBUG
00093     if (global::IOpolicy().stlFilesHaveLowerBound()) {
00094         double bound = global::IOpolicy().getLowerBoundForStlFiles();
00095         PLB_ASSERT( !(vertex[0]<bound && vertex[1]<bound && vertex[2]<bound) );
00096     }
00097 #endif // PLB_DEBUG
00098 }
00099 
00100 template<typename T>
00101 inline Array<T,3> const& TriangularSurfaceMesh<T>::getVertex (
00102         plint iTriangle, int localVertex) const
00103 {
00104     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles &&
00105                (localVertex == 0 || localVertex == 1 || localVertex == 2));
00106     Array<T,3> const& vertex (
00107             vertices()[ edges()[ 3*iTriangle + ((localVertex == 0) ? 2 : localVertex-1) ].pv ] );
00108     assertVertex(vertex);
00109     return vertex;
00110 }
00111 
00112 template<typename T>
00113 inline Array<T,3>& TriangularSurfaceMesh<T>::getVertex (
00114         plint iTriangle, int localVertex )
00115 {
00116     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles &&
00117                (localVertex == 0 || localVertex == 1 || localVertex == 2));
00118     Array<T,3>& vertex (
00119             vertices()[ edges()[ 3*iTriangle + ((localVertex == 0) ? 2 : localVertex-1) ].pv ] );
00120     assertVertex(vertex);
00121     return vertex;
00122 }
00123 
00124 template<typename T>
00125 bool TriangularSurfaceMesh<T>::isValidVertex (
00126         plint iTriangle, int localVertex) const
00127 {
00128     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles &&
00129                (localVertex == 0 || localVertex == 1 || localVertex == 2));
00130     if (global::IOpolicy().stlFilesHaveLowerBound()) {
00131         double bound = global::IOpolicy().getLowerBoundForStlFiles();
00132         Array<T,3> const& vertex (
00133                 vertices()[ edges()[ 3*iTriangle + ((localVertex == 0) ? 2 : localVertex-1) ].pv ] );
00134         return !(vertex[0]<bound && vertex[1]<bound && vertex[2]<bound);
00135     }
00136     else {
00137         return true;
00138     }
00139 }
00140 
00141 template<typename T>
00142 inline Array<T,3> const& TriangularSurfaceMesh<T>::getVertex (
00143         plint iVertex) const
00144 {
00145     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices);
00146     Array<T,3> const& vertex(vertices()[iVertex]);
00147     assertVertex(vertex);
00148     return vertex;
00149 }
00150 
00151 template<typename T>
00152 inline Array<T,3>& TriangularSurfaceMesh<T>::getVertex (
00153         plint iVertex)
00154 {
00155     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices);
00156     Array<T,3>& vertex(vertices()[iVertex]);
00157     assertVertex(vertex);
00158     return vertex;
00159 }
00160 
00161 template<typename T>
00162 inline bool TriangularSurfaceMesh<T>::isValidVertex (
00163         plint iVertex) const
00164 {
00165     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices);
00166     if (global::IOpolicy().stlFilesHaveLowerBound()) {
00167         Array<T,3> const& vertex(vertices()[iVertex]);
00168         double bound = global::IOpolicy().getLowerBoundForStlFiles();
00169         return !(vertex[0]<bound && vertex[1]<bound && vertex[2]<bound);
00170     }
00171     else {
00172         return true;
00173     }
00174 }
00175 
00176 template<typename T>
00177 void TriangularSurfaceMesh<T>::computeBoundingBox (
00178         Array<T,2>& xRange, Array<T,2>& yRange, Array<T,2>& zRange ) const
00179 {
00180     T minVal = std::numeric_limits<T>::min();
00181     T maxVal = std::numeric_limits<T>::max();
00182     xRange = Array<T,2>(maxVal, minVal);
00183     yRange = Array<T,2>(maxVal, minVal);
00184     zRange = Array<T,2>(maxVal, minVal);
00185     for (plint iVertex=0; iVertex<getNumVertices(); ++iVertex) {
00186         Array<T,3> const& vertex = getVertex(iVertex);
00187         xRange[0] = std::min(xRange[0], vertex[0]);
00188         xRange[1] = std::max(xRange[1], vertex[0]);
00189         yRange[0] = std::min(yRange[0], vertex[1]);
00190         yRange[1] = std::max(yRange[1], vertex[1]);
00191         zRange[0] = std::min(zRange[0], vertex[2]);
00192         zRange[1] = std::max(zRange[1], vertex[2]);
00193     }
00194 }
00195 
00196 template<typename T>
00197 void TriangularSurfaceMesh<T>::translate(Array<T,3> const& vector)
00198 {
00199     if (util::fpequal(norm(vector), T(), eps0))
00200         return;
00201 
00202     for (plint i = 0; i < numVertices; i++)
00203         getVertex(i) += vector;
00204 }
00205 
00206 template<typename T>
00207 void TriangularSurfaceMesh<T>::scale(T alpha)
00208 {
00209 
00210     PLB_ASSERT(! util::fpequal(alpha, T(), eps0));
00211     if (util::fpequal(alpha, (T) 1.0, eps0))
00212         return;
00213 
00214     for (plint i = 0; i < numVertices; i++)
00215         getVertex(i) *= alpha;
00216 }
00217 
00218 template<typename T>
00219 void TriangularSurfaceMesh<T>::rotate(T phi, T theta, T psi)
00220 {
00221     static const T pi = acos(-1.0);
00222 
00223     PLB_ASSERT((theta > T() || util::fpequal(theta, T(), eps0)) &&
00224                (theta < pi  || util::fpequal(theta, pi, eps0)));
00225 
00226     T a[3][3];
00227     a[0][0] =  1.0;
00228     a[0][1] =  0.0;
00229     a[0][2] =  0.0;
00230     a[1][0] =  0.0;
00231     a[1][1] =  cos(theta);
00232     a[1][2] =  sin(theta);
00233     a[2][0] =  0.0;
00234     a[2][1] = -sin(theta);
00235     a[2][2] =  cos(theta);
00236 
00237     T b[3][3];
00238     b[0][0] =  cos(phi);
00239     b[0][1] =  sin(phi);
00240     b[0][2] =  0.0;
00241     b[1][0] = -sin(phi);
00242     b[1][1] =  cos(phi);
00243     b[1][2] =  0.0;
00244     b[2][0] =  0.0;
00245     b[2][1] =  0.0;
00246     b[2][2] =  1.0;
00247 
00248     T c[3][3];
00249     for (int i = 0; i < 3; i++) {
00250         for (int j = 0; j < 3; j++) {
00251             c[i][j] = 0.0;
00252             for (int k = 0; k < 3; k++) {
00253                 c[i][j] += a[i][k]*b[k][j];
00254             }
00255         }
00256     }
00257 
00258     b[0][0] =  cos(psi);
00259     b[0][1] =  sin(psi);
00260     b[0][2] =  0.0;
00261     b[1][0] = -sin(psi);
00262     b[1][1] =  cos(psi);
00263     b[1][2] =  0.0;
00264     b[2][0] =  0.0;
00265     b[2][1] =  0.0;
00266     b[2][2] =  1.0;
00267 
00268     for (int i = 0; i < 3; i++) {
00269         for (int j = 0; j < 3; j++) {
00270             a[i][j] = 0.0;
00271             for (int k = 0; k < 3; k++) {
00272                 a[i][j] += b[i][k]*c[k][j];
00273             }
00274         }
00275     }
00276 
00277     for (plint iVertex = 0; iVertex < numVertices; iVertex++) {
00278         Array<T,3> x = getVertex(iVertex);
00279         for (int i = 0; i < 3; i++) {
00280             getVertex(iVertex)[i] = 0.0;
00281             for (int j = 0; j < 3; j++) {
00282                 getVertex(iVertex)[i] += a[i][j]*x[j];
00283             }
00284         }
00285     }
00286 }
00287 
00288 template<typename T>
00289 void TriangularSurfaceMesh<T>::smooth(plint maxiter, T relax, bool isMeasureWeighted)
00290 {
00291     PLB_ASSERT(maxiter >= 0);
00292     PLB_ASSERT((relax > (T) 0.0 || fabs(relax) <= eps0) &&
00293                (relax < (T) 1.0 || fabs(relax - 1.0) <= eps0));
00294 
00295     if (maxiter <= 0)
00296         return;
00297 
00298     std::vector<Array<T,3> > *bp0;
00299     bp0 = vertexList;
00300 
00301     std::vector<Array<T,3> > buf;
00302     buf.resize(numVertices);
00303 
00304     std::vector<Array<T,3> > *bp1;
00305     bp1 = &buf;
00306 
00307     if (isMeasureWeighted) {
00308         for (plint iter = 0; iter < maxiter; iter++) {
00309             for (plint iVertex = 0; iVertex < numVertices; iVertex++) {
00310                 Array<T,3> iVertexPos = (*bp0)[iVertex];
00311                 std::vector<plint> neighborVertexIds = getNeighborVertexIds(iVertex);
00312 
00313                 if (isInteriorVertex(iVertex)) {
00314                     pluint sizeIds = neighborVertexIds.size();
00315                     T area = (T) 0.0;
00316                     Array<T,3> tmp((T) 0.0, (T) 0.0, (T) 0.0);
00317                     for (pluint i = 0; i < sizeIds; i++) {
00318                         plint jVertex = neighborVertexIds[i];
00319                         plint kVertex = (i + 1 < sizeIds) ? neighborVertexIds[i + 1] : neighborVertexIds[0];
00320 
00321                         Array<T,3> jVertexPos = (*bp0)[jVertex];
00322                         Array<T,3> kVertexPos = (*bp0)[kVertex];
00323 
00324                         Array<T,3> middleVertexPos = (iVertexPos + jVertexPos + kVertexPos) / (T) 3.0;
00325 
00326                         Array<T,3> eij = jVertexPos - iVertexPos;
00327                         Array<T,3> eik = kVertexPos - iVertexPos;
00328                         Array<T,3> n;
00329                         crossProduct(eij, eik, n);
00330                         T locArea = (T) 0.5 * norm(n);
00331 
00332                         area += locArea;
00333                         tmp += middleVertexPos * locArea;
00334                     }
00335                     (*bp1)[iVertex] = (1.0 - relax) * (*bp0)[iVertex] + relax * tmp / area;
00336                 } else {
00337                     plint jVertex = -1, kVertex = -1;
00338                     int counter = 0;
00339                     for (pluint i = 0; i < neighborVertexIds.size(); i++) {
00340                         plint vertexId = neighborVertexIds[i];
00341                         if (isBoundaryVertex(vertexId)) {
00342                             if (isBoundaryEdge(iVertex, vertexId)) {
00343                                 counter++;
00344                                 if (counter == 1) {
00345                                     jVertex = vertexId;
00346                                 } else if (counter == 2) {
00347                                     kVertex = vertexId;
00348                                 } else {
00349                                     PLB_ASSERT(false); // Problem with the boundary of the surface mesh.
00350                                 }
00351                             }
00352                         }
00353                     }
00354 
00355                     PLB_ASSERT(counter == 2); // Problem with the boundary of the surface mesh.
00356 
00357                     Array<T,3> jVertexPos = (*bp0)[jVertex];
00358                     Array<T,3> kVertexPos = (*bp0)[kVertex];
00359 
00360                     Array<T,3> middleVertexPos0 = (iVertexPos + jVertexPos) / (T) 2.0;
00361                     Array<T,3> middleVertexPos1 = (iVertexPos + kVertexPos) / (T) 2.0;
00362 
00363                     T length0 = norm(jVertexPos - iVertexPos);
00364                     T length1 = norm(kVertexPos - iVertexPos);
00365 
00366                     (*bp1)[iVertex] = (1.0 - relax) * (*bp0)[iVertex] +
00367                                       relax * (middleVertexPos0*length0 + middleVertexPos1*length1) / (length0 + length1);
00368                 }
00369             }
00370             // Swap buffers.
00371             std::vector<Array<T,3> > *tmp = bp0;
00372             bp0 = bp1;
00373             bp1 = tmp;
00374         }
00375     } else {
00376         for (plint iter = 0; iter < maxiter; iter++) {
00377             for (plint iVertex = 0; iVertex < numVertices; iVertex++) {
00378                 Array<T,3> iVertexPos = (*bp0)[iVertex];
00379                 std::vector<plint> neighborVertexIds = getNeighborVertexIds(iVertex);
00380 
00381                 if (isInteriorVertex(iVertex)) {
00382                     pluint sizeIds = neighborVertexIds.size();
00383                     Array<T,3> tmp((T) 0.0, (T) 0.0, (T) 0.0);
00384                     for (pluint i = 0; i < sizeIds; i++) {
00385                         tmp += (*bp0)[neighborVertexIds[i]];
00386                     }
00387                     (*bp1)[iVertex] = (1.0 - relax) * (*bp0)[iVertex] + relax * tmp / (T) sizeIds;
00388                 } else {
00389                     plint jVertex = -1, kVertex = -1;
00390                     int counter = 0;
00391                     for (pluint i = 0; i < neighborVertexIds.size(); i++) {
00392                         plint vertexId = neighborVertexIds[i];
00393                         if (isBoundaryVertex(vertexId)) {
00394                             if (isBoundaryEdge(iVertex, vertexId)) {
00395                                 counter++;
00396                                 if (counter == 1) {
00397                                     jVertex = vertexId;
00398                                 } else if (counter == 2) {
00399                                     kVertex = vertexId;
00400                                 } else {
00401                                     PLB_ASSERT(false); // Problem with the boundary of the surface mesh.
00402                                 }
00403                             }
00404                         }
00405                     }
00406 
00407                     PLB_ASSERT(counter == 2); // Problem with the boundary of the surface mesh.
00408 
00409                     (*bp1)[iVertex] = (1.0 - relax) * (*bp0)[iVertex] +
00410                                       relax * ((*bp0)[jVertex] + (*bp0)[kVertex]) / (T) 2.0;
00411                 }
00412             }
00413             // Swap buffers.
00414             std::vector<Array<T,3> > *tmp = bp0;
00415             bp0 = bp1;
00416             bp1 = tmp;
00417         }
00418     }
00419 
00420     // Final copy of vertex positions.
00421     if (vertexList != bp0)
00422         for (plint iVertex = 0; iVertex < numVertices; iVertex++)
00423            (*vertexList)[iVertex] = (*bp0)[iVertex];
00424 }
00425 
00426 template<typename T>
00427 inline plint TriangularSurfaceMesh<T>::getVertexId(plint iTriangle, plint localVertex) const {
00428     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles &&
00429                (localVertex == 0 || localVertex == 1 || localVertex == 2));
00430     return edges() [ 3*iTriangle + ((localVertex == 0) ? 2 : localVertex-1) ].pv;
00431 }
00432 
00433 template<typename T>
00434 std::vector<plint> TriangularSurfaceMesh<T>::getNeighborVertexIds(
00435     plint iVertex) const
00436 {
00437     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices);
00438 
00439     std::vector<plint> neighborVertexIds;
00440 
00441     plint ee = emanatingEdges()[iVertex];
00442     neighborVertexIds.push_back(edges()[ee].pv);
00443 
00444     plint pe = prev(ee);
00445     plint e = pe;
00446     if ((e = edges()[e].ne) < 0) {
00447         neighborVertexIds.push_back(edges()[prev(pe)].pv);
00448         e = ee;
00449     }
00450 
00451     while (e != ee) {
00452         neighborVertexIds.push_back(edges()[e].pv);
00453 
00454         e = pe = prev(e);
00455         if ((e = edges()[e].ne) < 0) {
00456             neighborVertexIds.push_back(edges()[prev(pe)].pv);
00457             e = ee;
00458         }
00459     }
00460 
00461     PLB_ASSERT(neighborVertexIds.size() > 1); // Problem with the topology of the surface mesh.
00462 
00463     return neighborVertexIds;
00464 }
00465 
00466 template<typename T>
00467 std::vector<plint> TriangularSurfaceMesh<T>::getNeighborVertexIds(
00468     plint iVertex, plint jVertex) const
00469 {
00470     std::vector<plint> neighborVertexIds;
00471     std::vector<plint> adjacentTriangleIds = getAdjacentTriangleIds(iVertex, jVertex);
00472     std::vector<plint>::iterator tit = adjacentTriangleIds.begin();
00473     for (; tit != adjacentTriangleIds.end(); ++tit) {
00474         plint iTriangle = *tit;
00475         plint id0 = getVertexId(iTriangle, 0);
00476         plint id1 = getVertexId(iTriangle, 1);
00477         plint id2 = getVertexId(iTriangle, 2);
00478         plint kVertex =  (iVertex != id0 && jVertex != id0) ? id0 :
00479                         ((iVertex != id1 && jVertex != id1) ? id1 : id2);
00480         neighborVertexIds.push_back(kVertex);
00481     }
00482 
00483     plint size = neighborVertexIds.size();
00484     PLB_ASSERT(size == 1 || size == 2); // Problem with the topology of the surface mesh.
00485 
00486     return neighborVertexIds;
00487 }
00488 
00489 template<typename T>
00490 std::vector<plint> TriangularSurfaceMesh<T>::getNeighborTriangleIds(
00491     plint iVertex ) const
00492 {
00493     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices);
00494 
00495     std::vector<plint> neighborTriangleIds;
00496 
00497     plint ee = emanatingEdges()[iVertex];
00498     neighborTriangleIds.push_back(ee/3);
00499 
00500     plint e = prev(ee);
00501     if ((e = edges()[e].ne) < 0)
00502         e = ee;
00503 
00504     while (e != ee) {
00505         neighborTriangleIds.push_back(e/3);
00506 
00507         e = prev(e);
00508         if ((e = edges()[e].ne) < 0)
00509             e = ee;
00510     }
00511 
00512     PLB_ASSERT(neighborTriangleIds.size() != 0); // Problem with the topology of the surface mesh.
00513 
00514     return neighborTriangleIds;
00515 }
00516 
00517 template<typename T>
00518 std::vector<plint> TriangularSurfaceMesh<T>::getAdjacentTriangleIds(
00519     plint iTriangle) const
00520 {
00521     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles);
00522 
00523     std::vector<plint> adjacentTriangleIds;
00524     for (int localEdge = 0; localEdge < 3; localEdge++) {
00525         plint e = edges()[3*iTriangle + localEdge].ne;
00526         if (e >= 0)
00527             adjacentTriangleIds.push_back(e/3);
00528     }
00529     return adjacentTriangleIds;
00530 }
00531 
00532 template<typename T>
00533 std::vector<plint> TriangularSurfaceMesh<T>::getAdjacentTriangleIds(
00534     plint iVertex, plint jVertex) const
00535 {
00536     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices &&
00537                jVertex >= 0 && jVertex < numVertices &&
00538                iVertex != jVertex);
00539 
00540 #ifdef PLB_DEBUG
00541     std::vector<plint> neighborVertexIds = getNeighborVertexIds(iVertex);
00542     std::vector<plint>::iterator vit;
00543     vit = find(neighborVertexIds.begin(), neighborVertexIds.end(), jVertex);
00544     PLB_ASSERT(vit != neighborVertexIds.end()); // Vertices do not belong to the same edge.
00545 #endif // PLB_DEBUG
00546 
00547     std::vector<plint> adjacentTriangleIds;
00548     std::vector<plint> neighborTriangleIds = getNeighborTriangleIds(iVertex);
00549     std::vector<plint>::iterator tit = neighborTriangleIds.begin();
00550     for (; tit != neighborTriangleIds.end(); ++tit) {
00551         plint iTriangle = *tit;
00552         plint id0 = getVertexId(iTriangle, 0);
00553         plint id1 = getVertexId(iTriangle, 1);
00554         plint id2 = getVertexId(iTriangle, 2);
00555         if ((iVertex == id0 || iVertex == id1 || iVertex == id2) &&
00556             (jVertex == id0 || jVertex == id1 || jVertex == id2))
00557             adjacentTriangleIds.push_back(iTriangle);
00558     }
00559 
00560     plint size = adjacentTriangleIds.size();
00561     PLB_ASSERT(size == 1 || size == 2); // Problem with the topology of the surface mesh.
00562 
00563     return adjacentTriangleIds;
00564 }
00565 
00566 template<typename T>
00567 Array<T,3> TriangularSurfaceMesh<T>::computeTriangleNormal(
00568     plint iTriangle, bool isAreaWeighted) const
00569 {
00570     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles);
00571 
00572     Array<T,3> v0 = getVertex(iTriangle, 0);
00573     Array<T,3> v1 = getVertex(iTriangle, 1);
00574     Array<T,3> v2 = getVertex(iTriangle, 2);
00575 
00576     Array<T,3> e01 = v1 - v0;
00577     Array<T,3> e02 = v2 - v0;
00578 
00579     Array<T,3> n;
00580     crossProduct(e01, e02, n);
00581     if (!isAreaWeighted)
00582         n /= norm(n);
00583 
00584     return n;
00585 }
00586 
00587 template<typename T>
00588 Array<T,3> TriangularSurfaceMesh<T>::computeTriangleNormal(
00589     plint iVertex, plint jVertex, plint kVertex, bool isAreaWeighted) const
00590 {
00591     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices &&
00592                jVertex >= 0 && jVertex < numVertices &&
00593                kVertex >= 0 && kVertex < numVertices &&
00594                iVertex != jVertex && iVertex != kVertex &&
00595                jVertex != kVertex);
00596 
00597     plint id0 = iVertex;
00598     plint id1, id2;
00599 
00600     std::vector<plint> neighborVertexIds = getNeighborVertexIds(iVertex);
00601     std::vector<plint>::iterator it;
00602     it = find(neighborVertexIds.begin(), neighborVertexIds.end(), jVertex);
00603     PLB_ASSERT(it != neighborVertexIds.end()); // Vertices do not belong to the same triangle.
00604 
00605     plint prevVertex, nextVertex;
00606     if (jVertex == neighborVertexIds[0]) {
00607         prevVertex = neighborVertexIds[neighborVertexIds.size()-1];
00608         nextVertex = neighborVertexIds[1];
00609     }
00610     else if (jVertex == neighborVertexIds[neighborVertexIds.size()-1]) {
00611         prevVertex = neighborVertexIds[neighborVertexIds.size()-2];
00612         nextVertex = neighborVertexIds[0];
00613     }
00614     else {
00615         prevVertex = *(it - 1);
00616         nextVertex = *(it + 1);
00617     }
00618 
00619     if (kVertex == prevVertex) {
00620         id1 = kVertex;
00621         id2 = jVertex;
00622     }
00623     else if (kVertex == nextVertex) {
00624         id1 = jVertex;
00625         id2 = kVertex;
00626     }
00627     else {
00628         PLB_ASSERT(false); // Vertices do not belong to the same triangle.
00629     }
00630 
00631     Array<T,3> v0 = getVertex(id0);
00632     Array<T,3> v1 = getVertex(id1);
00633     Array<T,3> v2 = getVertex(id2);
00634 
00635     Array<T,3> e01 = v1 - v0;
00636     Array<T,3> e02 = v2 - v0;
00637 
00638     Array<T,3> n;
00639     crossProduct(e01, e02, n);
00640     if (!isAreaWeighted)
00641         n /= norm(n);
00642 
00643     return n;
00644 }
00645 
00646 template<typename T>
00647 Array<T,3> TriangularSurfaceMesh<T>::computeEdgeNormal(
00648     plint iVertex, plint jVertex, bool isAreaWeighted) const
00649 {
00650     Array<T,3> n;
00651     std::vector<plint> adjacentTriangleIds = getAdjacentTriangleIds(iVertex, jVertex);
00652     std::vector<plint>::iterator tit = adjacentTriangleIds.begin();
00653     for (n.resetToZero(); tit != adjacentTriangleIds.end(); ++tit)
00654         n += computeTriangleNormal(*tit, isAreaWeighted);
00655 
00656     n /= norm(n);
00657     return n;
00658 }
00659 
00660 template<typename T>
00661 Array<T,3> TriangularSurfaceMesh<T>::computeVertexNormal(
00662     plint iVertex, bool isAreaWeighted) const
00663 {
00664     std::vector<plint> neighborTriangleIds = getNeighborTriangleIds(iVertex);
00665     Array<T,3> n;
00666     std::vector<plint>::iterator it = neighborTriangleIds.begin();
00667     for (n.resetToZero(); it != neighborTriangleIds.end(); ++it)
00668         n += computeTriangleNormal(*it, isAreaWeighted);
00669 
00670     n /= norm(n);
00671     return n;
00672 }
00673 
00674 template<typename T>
00675 Array<T,3> TriangularSurfaceMesh<T>::computeContinuousNormal(
00676     Array<T,3> const& p, plint iTriangle, bool isAreaWeighted) const
00677 {
00678     plint id0 = getVertexId(iTriangle, 0);
00679     plint id1 = getVertexId(iTriangle, 1);
00680     plint id2 = getVertexId(iTriangle, 2);
00681 
00682     Array<T,3> v0 = getVertex(id0);
00683     Array<T,3> v1 = getVertex(id1);
00684     Array<T,3> v2 = getVertex(id2);
00685 
00686     Array<T,3> ep0 = v0 - p;
00687     Array<T,3> ep1 = v1 - p;
00688     Array<T,3> ep2 = v2 - p;
00689 
00690     Array<T,3> n;
00691     crossProduct(ep1, ep2, n);
00692     T area0 = 0.5 * norm(n);
00693     crossProduct(ep2, ep0, n);
00694     T area1 = 0.5 * norm(n);
00695 
00696     T area = computeTriangleArea(iTriangle);
00697 
00698     T u = area0 / area;
00699     T v = area1 / area;
00700 
00701     Array<T,3> n0 = computeVertexNormal(id0, isAreaWeighted);
00702     Array<T,3> n1 = computeVertexNormal(id1, isAreaWeighted);
00703     Array<T,3> n2 = computeVertexNormal(id2, isAreaWeighted);
00704 
00705     n = u * n0 + v * n1 + ((T)1. - u - v) * n2;
00706     n /= norm(n);
00707     return n;
00708 }
00709 
00710 template<typename T>
00711 T TriangularSurfaceMesh<T>::computeTriangleArea(plint iTriangle) const
00712 {
00713     Array<T,3> v0 = getVertex(iTriangle, 0);
00714     Array<T,3> v1 = getVertex(iTriangle, 1);
00715     Array<T,3> v2 = getVertex(iTriangle, 2);
00716 
00717     Array<T,3> e01 = v1 - v0;
00718     Array<T,3> e02 = v2 - v0;
00719 
00720     Array<T,3> n;
00721     crossProduct(e01, e02, n);
00722     return 0.5 * norm(n);
00723 }
00724 
00725 template<typename T>
00726 T TriangularSurfaceMesh<T>::computeTriangleArea(
00727     plint iVertex, plint jVertex, plint kVertex) const
00728 {
00729     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices &&
00730                jVertex >= 0 && jVertex < numVertices &&
00731                kVertex >= 0 && kVertex < numVertices &&
00732                iVertex != jVertex && iVertex != kVertex &&
00733                jVertex != kVertex);
00734 
00735 #ifdef PLB_DEBUG
00736     std::vector<plint> neighborVertexIds = getNeighborVertexIds(iVertex);
00737     std::vector<plint>::iterator it;
00738     it = find(neighborVertexIds.begin(), neighborVertexIds.end(), jVertex);
00739     PLB_ASSERT(it != neighborVertexIds.end()); // Vertices do not belong to the same triangle.
00740 
00741     plint prevVertex, nextVertex;
00742     if (jVertex == neighborVertexIds[0]) {
00743         prevVertex = neighborVertexIds[neighborVertexIds.size()-1];
00744         nextVertex = neighborVertexIds[1];
00745     }
00746     else if (jVertex == neighborVertexIds[neighborVertexIds.size()-1]) {
00747         prevVertex = neighborVertexIds[neighborVertexIds.size()-2];
00748         nextVertex = neighborVertexIds[0];
00749     }
00750     else {
00751         prevVertex = *(it - 1);
00752         nextVertex = *(it + 1);
00753     }
00754 
00755     PLB_ASSERT(kVertex == prevVertex || kVertex == nextVertex); // Vertices do not belong to the same triangle.
00756 #endif // PLB_DEBUG
00757 
00758     Array<T,3> v0 = getVertex(iVertex);
00759     Array<T,3> v1 = getVertex(jVertex);
00760     Array<T,3> v2 = getVertex(kVertex);
00761 
00762     return plb::computeTriangleArea(v0,v1,v2);
00763 }
00764 
00765 template<typename T>
00766 T TriangularSurfaceMesh<T>::computeEdgeArea(plint iVertex, plint jVertex) const
00767 {
00768     T area = T();
00769     std::vector<plint> adjacentTriangleIds = getAdjacentTriangleIds(iVertex, jVertex);
00770     std::vector<plint>::iterator tit = adjacentTriangleIds.begin();
00771     for (; tit != adjacentTriangleIds.end(); ++tit)
00772         area += computeTriangleArea(*tit);
00773 
00774     return area/3.0;
00775 }
00776 
00777 template<typename T>
00778 T TriangularSurfaceMesh<T>::computeVertexArea(plint iVertex) const
00779 {
00780     std::vector<plint> neighborTriangleIds = getNeighborTriangleIds(iVertex);
00781     T area = T();
00782     std::vector<plint>::iterator it = neighborTriangleIds.begin();
00783     for (; it != neighborTriangleIds.end(); ++it)
00784     {
00785         area += computeTriangleArea(*it);
00786     }
00787 
00788     return area/3.0;
00789 }
00790 
00791 template<typename T>
00792 T TriangularSurfaceMesh<T>::computeEdgeLength(plint iVertex, plint jVertex) const
00793 {
00794 #ifdef PLB_DEBUG
00795     std::vector<plint> neighborVertexIds = getNeighborVertexIds(iVertex);
00796     std::vector<plint>::iterator it;
00797     it = find(neighborVertexIds.begin(), neighborVertexIds.end(), jVertex);
00798     PLB_ASSERT(it != neighborVertexIds.end()); // Vertices do not belong to the same edge.
00799 #endif // PLB_DEBUG
00800 
00801     return norm(getVertex(iVertex) - getVertex(jVertex));
00802 }
00803 
00804 template<typename T>
00805 T TriangularSurfaceMesh<T>::computeDihedralAngle(plint iVertex, plint jVertex) const
00806 {
00807     std::vector<plint> adjacentTriangleIds = getAdjacentTriangleIds(iVertex, jVertex);
00808     if (adjacentTriangleIds.size() == 1)
00809         return T();
00810 
00811     return angleBetweenVectors(computeTriangleNormal(adjacentTriangleIds[0]),
00812                                computeTriangleNormal(adjacentTriangleIds[1]));
00813 }
00814 
00815 template<typename T>
00816 T TriangularSurfaceMesh<T>::computeEdgeTileSpan(plint iVertex, plint jVertex) const
00817 {
00818     std::vector<plint> neighborVertexIds = getNeighborVertexIds(iVertex, jVertex);
00819 
00820     Array<T,3> v0 = getVertex(neighborVertexIds[0]);
00821     Array<T,3> v1 = getVertex(iVertex);
00822     Array<T,3> v2 = getVertex(jVertex);
00823 
00824     Array<T,3> v01 = v1 - v0;
00825     Array<T,3> v21 = v1 - v2;
00826     T angle_012 = angleBetweenVectors(v21, v01);
00827 
00828     T span = fabs(sin(angle_012)) * norm(v01);
00829 
00830     if (neighborVertexIds.size() == 1)
00831         return span/6.0;
00832 
00833     Array<T,3> v3 = getVertex(neighborVertexIds[1]);
00834 
00835     Array<T,3> v32 = v2 - v3;
00836     Array<T,3> v12 = -v21;
00837     T angle_321 = angleBetweenVectors(v12, v32);
00838     
00839     span += fabs(sin(angle_321)) * norm(v32);
00840 
00841     return span/6.0;
00842 }
00843 
00844 template<typename T>
00845 void TriangularSurfaceMesh<T>::writeAsciiSTL(std::string fname) const
00846 {
00847     // Output only from one MPI process.
00848     if (!global::mpi().isMainProcessor()) {
00849         return;
00850     }
00851     FILE *fp = fopen(fname.c_str(), "w");
00852     PLB_ASSERT(fp != NULL);
00853 
00854     char fmt1[64] = "  facet normal ";
00855     char fmt2[64] = "      vertex ";
00856     if (sizeof(T) == sizeof(long double)) {
00857         strcat(fmt1, "% Le % Le % Le\n");
00858         strcat(fmt2, "% Le % Le % Le\n");
00859     }
00860     else if (sizeof(T) == sizeof(float) ||
00861              sizeof(T) == sizeof(double)) {
00862         strcat(fmt1, "% e % e % e\n");
00863         strcat(fmt2, "% e % e % e\n");
00864     }
00865     else {
00866         PLB_ASSERT(false);
00867     }
00868 
00869     fprintf(fp, "solid surface\n");
00870     for (plint i = 0; i < numTriangles; i++) {
00871         Array<T,3> n = computeTriangleNormal(i);
00872         Array<T,3> v;
00873         fprintf(fp, fmt1, n[0], n[1], n[2]);
00874         fprintf(fp, "    outer loop\n");
00875         v = getVertex(i, 0);
00876         fprintf(fp, fmt2, v[0], v[1], v[2]);
00877         v = getVertex(i, 1);
00878         fprintf(fp, fmt2, v[0], v[1], v[2]);
00879         v = getVertex(i, 2);
00880         fprintf(fp, fmt2, v[0], v[1], v[2]);
00881         fprintf(fp, "    endloop\n");
00882         fprintf(fp, "  endfacet\n");
00883     }
00884     fprintf(fp, "endsolid surface\n");
00885 
00886     fclose(fp);
00887 }
00888 
00889 template<typename T>
00890 void TriangularSurfaceMesh<T>::writeBinarySTL(std::string fname) const
00891 {
00892     // Output only from one MPI process.
00893     if (!global::mpi().isMainProcessor()) {
00894         return;
00895     }
00896     FILE *fp = fopen(fname.c_str(), "wb");
00897     PLB_ASSERT(fp != NULL);
00898 
00899     unsigned int nt = (unsigned int) numTriangles;
00900     unsigned short abc = 0;
00901     char buf[80];
00902 
00903     for (int i = 0; i < 80; i++)
00904         buf[i] = '\0';
00905 
00906     fwrite(buf, sizeof(char), 80, fp);
00907     fwrite(&nt, sizeof(unsigned int), 1, fp);
00908     for (plint i = 0; i < numTriangles; i++) {
00909         Array<T,3> vertex;
00910         Array<T,3> normal = computeTriangleNormal(i);
00911         float n[3];
00912         n[0] = normal[0];
00913         n[1] = normal[1];
00914         n[2] = normal[2];
00915         fwrite((void *) n, sizeof(float), 3, fp);
00916         vertex = getVertex(i, 0);
00917         float v[3];
00918         v[0] = vertex[0];
00919         v[1] = vertex[1];
00920         v[2] = vertex[2];
00921         fwrite((void *) v, sizeof(float), 3, fp);
00922         vertex = getVertex(i, 1);
00923         v[0] = vertex[0];
00924         v[1] = vertex[1];
00925         v[2] = vertex[2];
00926         fwrite((void *) v, sizeof(float), 3, fp);
00927         vertex = getVertex(i, 2);
00928         v[0] = vertex[0];
00929         v[1] = vertex[1];
00930         v[2] = vertex[2];
00931         fwrite((void *) v, sizeof(float), 3, fp);
00932         fwrite(&abc, sizeof(unsigned short), 1, fp);
00933     }
00934 
00935     fclose(fp);
00936 }
00937 
00938 template<typename T>
00939 inline bool TriangularSurfaceMesh<T>::isBoundaryVertex(plint iVertex) const
00940 {
00941     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices);
00942     if ( edges()[ emanatingEdges()[iVertex] ].ne < 0)
00943         return true;
00944     return false;
00945 }
00946 
00947 template<typename T>
00948 inline bool TriangularSurfaceMesh<T>::isInteriorVertex(plint iVertex) const
00949 {
00950     PLB_ASSERT(iVertex >= 0 && iVertex < numVertices);
00951     if ( edges()[ emanatingEdges()[iVertex] ].ne >= 0)
00952         return true;
00953     return false;
00954 }
00955 
00956 template<typename T>
00957 inline bool TriangularSurfaceMesh<T>::isBoundaryEdge(plint iVertex, plint jVertex) const
00958 {
00959     if (getAdjacentTriangleIds(iVertex, jVertex).size() == 2)
00960         return false;
00961 
00962     return true;
00963 }
00964 
00965 template<typename T>
00966 inline bool TriangularSurfaceMesh<T>::isInteriorEdge(plint iVertex, plint jVertex) const
00967 {
00968     return !isBoundaryEdge(iVertex, jVertex);
00969 }
00970 
00971 template<typename T>
00972 int TriangularSurfaceMesh<T>::pointOnTriangle (
00973     Array<T,3> const& point1, Array<T,3> const& point2, int flag,
00974     plint iTriangle, Array<T,3>& intersection, Array<T,3>& normal,
00975     T& distance) const
00976 {
00977     if(!((flag == 0 || flag == 1 || flag == 2) &&iTriangle >= 0 && iTriangle < numTriangles)) {
00978         pcout << "iTriangle=" << iTriangle << std::endl;
00979         pcout << "numTriangles=" << numTriangles << std::endl;
00980         pcout << "flag=" << flag << std::endl;
00981     }
00982     PLB_ASSERT((flag == 0 || flag == 1 || flag == 2) &&
00983                 iTriangle >= 0 && iTriangle < numTriangles);
00984 
00985     Array<T,3> v0 = getVertex(iTriangle, 0); // Triangle vertex coordinates
00986     Array<T,3> v1 = getVertex(iTriangle, 1);
00987     Array<T,3> v2 = getVertex(iTriangle, 2);
00988 
00989     Array<T,3> e0 = v1 - v0;  // Triangle edge vectors starting at v0
00990     Array<T,3> e1 = v2 - v0;
00991 
00992     crossProduct(e0, e1, normal); // Triangle unit normal
00993     normal /= norm(normal);
00994 
00995     Array<T,3> direction = point2 - point1;
00996 
00997     T num = dot(v0, normal) - dot(point1, normal);
00998     T denom = dot(direction, normal);
00999 
01000     T t = num / denom;
01001 
01002     // The function pointOnTriangle is essentially to verify crossings
01003     //   through the surface from inside to outside or vice versa. When
01004     //   one of the end-points of a segment is right on top of the surface
01005     //   this creates an awkward ambiguity. To remove this ambiguity, the
01006     //   triangle is slightly shifted in direction of its normal vector.
01007     if (    ( (flag==0||flag==1) && util::fpequal_abs(t, T(), eps1) )
01008          || ( (flag==0) && util::fpequal_abs(t, (T) 1.0, eps1) )
01009        )
01010     {
01011         // Shift the vertex, and recompute everything that needs to be
01012         //   recomputed. v1 and v2 are not used any more, so there is no
01013         //   need to recompute them.
01014         v0 += (T)2*eps1*normal;
01015         num = dot(v0, normal) - dot(point1, normal);
01016         t = num / denom;
01017     }
01018 
01019     if (util::fpequal_abs(denom, T(), eps1)) {
01020         if (util::fpequal_abs(num, T(), eps1)) {
01021             return -1; // Line belongs to the plane
01022         }
01023         else {
01024             return 0; // Line does not intersect the plane
01025         }
01026     }
01027 
01028     if (flag == 0) { // For intersection with a line segment
01029         if ((t < 0.0 && !util::fpequal_abs(t, T(), eps1)) ||
01030             (t > 1.0 && !util::fpequal_abs(t, (T) 1.0, eps1))) {
01031             return 0;
01032         }
01033     }
01034     else if (flag == 1) { // For intersection with a half-line
01035         if (t < 0.0 && !util::fpequal_abs(t, T(), eps1)) {
01036             return 0;
01037         }
01038     }
01039 
01040     intersection = point1 + direction*t; // Intersection point with the plane
01041 
01042     T a[2][2];
01043     a[0][0] = dot(e0, e0);
01044     a[0][1] = dot(e0, e1);
01045     a[1][0] = a[0][1];
01046     a[1][1] = dot(e1, e1);
01047 
01048     T tmp[3];
01049     tmp[0] = intersection[0] - v0[0];
01050     tmp[1] = intersection[1] - v0[1];
01051     tmp[2] = intersection[2] - v0[2];
01052 
01053     T b[2];
01054     b[0] = dot(tmp, e0);
01055     b[1] = dot(tmp, e1);
01056 
01057     T det = a[0][0]*a[1][1] - a[0][1]*a[1][0];
01058 
01059     T u = (a[1][1]*b[0] - a[0][1]*b[1]) / det;
01060     T v = (a[0][0]*b[1] - a[1][0]*b[0]) / det;
01061 
01062     T upv = u + v;
01063 
01064     int ueq0   = util::fpequal_abs(u,   T(), eps1);
01065     int ueq1   = util::fpequal_abs(u,   (T) 1.0, eps1);
01066     int veq0   = util::fpequal_abs(v,   T(), eps1);
01067     int veq1   = util::fpequal_abs(v,   (T) 1.0, eps1);
01068     int upveq1 = util::fpequal_abs(upv, (T) 1.0, eps1);
01069 
01070     int is_vertex = -1;
01071     int is_in_edge = -1;
01072 
01073     if ((u < 0.0 && !ueq0) || (u > 1.0 && !ueq1) ||
01074         (v < 0.0 && !veq0) || (v > 1.0 && !veq1) ||
01075         (upv > 1.0 && !upveq1))
01076         return 0; // The point does not belong to the triangle
01077     else { // The point belongs to the triangle (boundary or interior)
01078         distance = fabs(t) * norm(direction);
01079                     // Distance between intersection and point1
01080 
01081         if (!ueq0 && !veq0 && !upveq1)
01082             return 1; // Point is in the triangle interior
01083         else if (ueq0 && veq0)
01084             is_vertex = 0;
01085         else if (ueq1 && veq0)
01086             is_vertex = 1;
01087         else if (ueq0 && veq1)
01088             is_vertex = 2;
01089         else if (veq0 && !ueq0 && !ueq1)
01090             is_in_edge = 0;
01091         else if (ueq0 && !veq0 && !veq1)
01092             is_in_edge = 2;
01093         else if (upveq1 && !ueq1 && !veq1)
01094             is_in_edge = 1;
01095     }
01096 
01097     if (is_in_edge != -1) { // The point belongs to an edge
01098         plint iVertex = getVertexId(iTriangle, is_in_edge);
01099         plint jVertex = (is_in_edge == 2) ? getVertexId(iTriangle, 0) :
01100                                             getVertexId(iTriangle, is_in_edge+1);
01101 
01102         normal = computeEdgeNormal(iVertex, jVertex);
01103     } else if (is_vertex != -1) { // The point is a vertex
01104         normal = computeVertexNormal(getVertexId(iTriangle, is_vertex));
01105     }
01106 
01107     return 1;
01108 }
01109 
01110 template<typename T>
01111 bool TriangularSurfaceMesh<T>::segmentIntersectsTriangle (
01112     Array<T,3> const& point1, Array<T,3> const& point2, plint iTriangle ) const
01113 {
01114     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles);
01115 
01116     T v0[3], v1[3], v2[3]; // Triangle vertex coordinates
01117 
01118     Array<T,3> tv0 = getVertex(iTriangle, 0); tv0.to_cArray(v0);
01119     Array<T,3> tv1 = getVertex(iTriangle, 1); tv1.to_cArray(v1);
01120     Array<T,3> tv2 = getVertex(iTriangle, 2); tv2.to_cArray(v2);
01121 
01122     T e0[3], e1[3]; // Triangle edge vectors starting at v0
01123 
01124     e0[0] = v1[0] - v0[0];
01125     e0[1] = v1[1] - v0[1];
01126     e0[2] = v1[2] - v0[2];
01127 
01128     e1[0] = v2[0] - v0[0];
01129     e1[1] = v2[1] - v0[1];
01130     e1[2] = v2[2] - v0[2];
01131 
01132     T normal[3]; // Triangle normal
01133 
01134     normal[0] = e0[1]*e1[2] - e0[2]*e1[1];
01135     normal[1] = e0[2]*e1[0] - e0[0]*e1[2];
01136     normal[2] = e0[0]*e1[1] - e0[1]*e1[0];
01137 
01138     T direction[3], p1[3], p2[3];
01139 
01140     point1.to_cArray(p1);
01141     point2.to_cArray(p2);
01142 
01143     direction[0] = p2[0] - p1[0];
01144     direction[1] = p2[1] - p1[1];
01145     direction[2] = p2[2] - p1[2];
01146 
01147     T denom = direction[0]*normal[0] + direction[1]*normal[1] + direction[2]*normal[2];
01148 
01149     if (FPEQUAL_ABS(denom, T(), eps1))
01150         return false; // The segment belongs to the plane or it is parallel to it
01151                       //   and does not intersect it.
01152 
01153     T num = (v0[0]-p1[0])*normal[0] + (v0[1]-p1[1])*normal[1] + (v0[2]-p1[2])*normal[2];
01154 
01155     T t = num / denom;
01156 
01157     // The function segmentIntersectsTriangle is essentially to verify crossings
01158     //   through the surface from inside to outside or vice versa. When
01159     //   one of the end-points of a segment is right on top of the surface
01160     //   this creates an awkward ambiguity. To remove this ambiguity, the
01161     //   triangle is slightly shifted in direction of its normal vector.
01162     if (    ( FPEQUAL_ABS(t, T(),     eps1) )
01163          || ( FPEQUAL_ABS(t, (T) 1.0, eps1) )
01164        )
01165     {
01166         T norm_normal = sqrt(util::sqr(normal[0])+util::sqr(normal[1])+util::sqr(normal[2]));
01167         normal[0] /= norm_normal;
01168         normal[1] /= norm_normal;
01169         normal[2] /= norm_normal;
01170         // Shift the vertex, and recompute everything that needs to be
01171         //   recomputed. v1 and v2 are not used any more, so there is no
01172         //   need to recompute them.
01173         T tmp = (T)2*eps1;
01174         v0[0] += tmp*normal[0];
01175         v0[1] += tmp*normal[1];
01176         v0[2] += tmp*normal[2];
01177         num = (v0[0]-p1[0])*normal[0] + (v0[1]-p1[1])*normal[1] + (v0[2]-p1[2])*normal[2];
01178         t = num / denom;
01179     }
01180 
01181     if ((t < 0.0 && !FPEQUAL_ABS(t, T(), eps1)) ||
01182         (t > 1.0 && !FPEQUAL_ABS(t, (T) 1.0, eps1)))
01183         return false;
01184 
01185     T intersection[3];
01186 
01187     intersection[0] = p1[0] + direction[0]*t; // Intersection point with the plane
01188     intersection[1] = p1[1] + direction[1]*t;
01189     intersection[2] = p1[2] + direction[2]*t;
01190 
01191     T a[2][2];
01192     a[0][0] = e0[0]*e0[0] + e0[1]*e0[1] + e0[2]*e0[2];
01193     a[0][1] = e0[0]*e1[0] + e0[1]*e1[1] + e0[2]*e1[2];
01194     a[1][0] = a[0][1];
01195     a[1][1] = e1[0]*e1[0] + e1[1]*e1[1] + e1[2]*e1[2];
01196 
01197     T tmp[3];
01198     tmp[0] = intersection[0] - v0[0];
01199     tmp[1] = intersection[1] - v0[1];
01200     tmp[2] = intersection[2] - v0[2];
01201 
01202     T b[2];
01203     b[0] = tmp[0]*e0[0] + tmp[1]*e0[1] + tmp[2]*e0[2];
01204     b[1] = tmp[0]*e1[0] + tmp[1]*e1[1] + tmp[2]*e1[2];
01205 
01206     T det = a[0][0]*a[1][1] - a[0][1]*a[1][0];
01207 
01208     T u = (a[1][1]*b[0] - a[0][1]*b[1])/det;
01209     T v = (a[0][0]*b[1] - a[1][0]*b[0])/det;
01210 
01211     T upv = u + v;
01212 
01213     if ((u   < 0.0 && !FPEQUAL_ABS(u,   T(),     eps1)) ||
01214         (u   > 1.0 && !FPEQUAL_ABS(u,   (T) 1.0, eps1)) ||
01215         (v   < 0.0 && !FPEQUAL_ABS(v,   T(),     eps1)) ||
01216         (v   > 1.0 && !FPEQUAL_ABS(v,   (T) 1.0, eps1)) ||
01217         (upv > 1.0 && !FPEQUAL_ABS(upv, (T) 1.0, eps1)))
01218         return false; // The point does not belong to the triangle
01219 
01220     return true;
01221 }
01222 
01223 template<typename T>
01224 void TriangularSurfaceMesh<T>::distanceToEdgeLine (
01225         Array<T,3> const& point, plint iTriangle, plint whichEdge,
01226         T& distance, bool& intersectionIsInside ) const
01227 {
01228     PLB_ASSERT(iTriangle >= 0 && iTriangle < numTriangles &&
01229                (whichEdge == 0 || whichEdge == 1 || whichEdge == 2));
01230 
01231     plint iVertex1 = edges()[3*iTriangle+((whichEdge==0) ? 2:whichEdge-1)].pv;
01232     plint iVertex2 = edges()[3*iTriangle+whichEdge].pv;
01233     Array<T,3> vertex1 = getVertex(iVertex1);
01234     Array<T,3> vertex2 = getVertex(iVertex2);
01235     Array<T,3> pv = point-vertex1;
01236     Array<T,3> e = vertex2-vertex1;
01237 
01238     T u = dot(pv,e) / dot(e,e);
01239     Array<T,3> x = vertex1+u*e;
01240     distance = norm(point-x);
01241 
01242     int ueq0 = util::fpequal_abs(u, T(), eps1);
01243     int ueq1 = util::fpequal_abs(u, (T) 1.0, eps1);
01244     intersectionIsInside = (u >= 0.0 || ueq0) && (u <= 1.0 || ueq1);
01245 }
01246 
01247 template<typename T>
01248 void TriangularSurfaceMesh<T>::distanceToTrianglePlane (
01249         Array<T,3> const& point, plint iTriangle,
01250         T& distance, bool& intersectionIsInside, bool& pointIsBehind ) const
01251 {
01252     Array<T,3> normal = computeTriangleNormal(iTriangle);
01253     Array<T,3> intersection;
01254     int flag = 2; // Line.
01255     intersectionIsInside =
01256         pointOnTriangle( point, point+normal, flag, iTriangle,
01257                          intersection, normal, distance ) == 1;
01258     T projection = dot(normal, point-intersection);
01259 
01260     pointIsBehind = projection <= (T)0. ||
01261                     util::fpequal_abs(projection, (T)0., eps1);
01262 }
01263 
01264 template<typename T>
01265 void TriangularSurfaceMesh<T>::distanceToTriangle (
01266         Array<T,3> const& point, plint iTriangle,
01267         T& distance, bool& pointIsBehind ) const
01268 {
01269     bool intersectionIsInside;
01270     // First possibility: The projection of the point is inside the triangle.
01271     distanceToTrianglePlane( point, iTriangle, distance,
01272                              intersectionIsInside, pointIsBehind );
01273     if (intersectionIsInside) {
01274         return;
01275     }
01276     // Second possibility: The projection of the point is inside an edge.
01277     bool intersectsWithEdge = false;
01278     for (plint iEdge=0; iEdge<=2; ++iEdge) {
01279         T newDistance;
01280         distanceToEdgeLine(point, iTriangle, iEdge, newDistance, intersectionIsInside);
01281         if (iEdge==0 || newDistance<distance) {
01282             distance = newDistance;
01283             // The edge-line to which the point is closest should be selected if
01284             //   and only if the intersection is inside the edge. Otherwise
01285             //   the closest distance to the triangle is on one of the vertices
01286             //   which is selected further down.
01287             intersectsWithEdge = intersectionIsInside;
01288         }
01289     }
01290     if (intersectsWithEdge) {
01291         return;
01292     }
01293     // Default: Compute the closest distance to one of the vertices.
01294     T d0Sqr = normSqr(point-getVertex(iTriangle, 0));
01295     T d1Sqr = normSqr(point-getVertex(iTriangle, 1));
01296     T d2Sqr = normSqr(point-getVertex(iTriangle, 2));
01297     T minDistSqr = std::min(d0Sqr, std::min(d1Sqr,d2Sqr));
01298     distance = sqrt(minDistSqr);
01299 }
01300 
01301 template<typename T>
01302 void TriangularSurfaceMesh<T>::reverseOrientation()
01303 {
01304     // Rearrange the emanating edge list.
01305     for (plint iVertex = 0; iVertex < numVertices; iVertex++)
01306         if (isInteriorVertex(iVertex)) {
01307             emanatingEdges()[iVertex] = changeEdgeId(edges()[emanatingEdges()[iVertex]].ne);
01308         }
01309         else {
01310             plint ee = emanatingEdges()[iVertex];
01311             plint pe = prev(ee);
01312             plint e = pe;
01313             if ((e = edges()[e].ne) < 0) {
01314                 emanatingEdges()[iVertex] = changeEdgeId(pe);
01315                 e = ee;
01316             }
01317             while (e != ee) {
01318                 e = pe = prev(e);
01319                 if ((e = edges()[e].ne) < 0) {
01320                     emanatingEdges()[iVertex] = changeEdgeId(pe);
01321                     e = ee;
01322                 }
01323             }
01324         }
01325 
01326     // Rearrange the neighboring edge list.
01327     std::vector<Edge> tmp = edges();
01328     for (plint iEdge = 0; iEdge < 3*numTriangles; iEdge++)
01329         if (edges()[iEdge].ne < 0) {
01330             tmp[changeEdgeId(iEdge)].ne = -1;
01331         }
01332         else {
01333             tmp[changeEdgeId(iEdge)].ne = changeEdgeId(edges()[iEdge].ne);
01334         }
01335 
01336     edges().swap(tmp);
01337 
01338     // Rearrange the pointing vertex list.
01339     for (plint iTriangle = 0; iTriangle < numTriangles; iTriangle++) {
01340         plint id0 = getVertexId(iTriangle, 0);
01341         plint id1 = getVertexId(iTriangle, 1);
01342         plint id2 = getVertexId(iTriangle, 2);
01343 
01344         edges()[3*iTriangle].pv     = id2;
01345         edges()[3*iTriangle + 1].pv = id1;
01346         edges()[3*iTriangle + 2].pv = id0;
01347     }
01348 }
01349 
01350 template<typename T>
01351 std::vector<typename TriangularSurfaceMesh<T>::Lid> TriangularSurfaceMesh<T>::closeHoles() {
01352     std::vector<std::vector<plint> > holes = detectHoles();
01353     std::vector<Lid> lids(holes.size());
01354     for (pluint iHole=0; iHole<holes.size(); ++iHole) {
01355         lids[iHole] = closeHole(holes[iHole]);
01356     }
01357     return lids;
01358 }
01359 
01360 template<typename T>
01361 void TriangularSurfaceMesh<T>::avoidIntegerPositions() {
01362     for (plint iVertex=0; iVertex<getNumVertices(); ++iVertex) {
01363         avoidIntegerPosition(iVertex);
01364     }
01365 }
01366 
01367 template<typename T>
01368 void TriangularSurfaceMesh<T>::avoidIntegerPosition(plint iVertex) {
01369     Array<T,3>& vertex = getVertex(iVertex);
01370     Array<T,3> normal = computeVertexNormal(iVertex);
01371     if ( vertex[0]-(plint)vertex[0] < 1.e-12 ||
01372          vertex[1]-(plint)vertex[1] < 1.e-12 ||
01373          vertex[2]-(plint)vertex[2] < 1.e-12 )
01374     {
01375         vertex += (T)1.e-12 * normal;
01376     }
01377 }
01378 
01379 template<typename T>
01380 void TriangularSurfaceMesh<T>::inflate(T amount) {
01381     for (plint iVertex=0; iVertex<getNumVertices(); ++iVertex) {
01382         Array<T,3>& vertex = getVertex(iVertex);
01383         Array<T,3> normal = computeVertexNormal(iVertex);
01384         vertex += amount * normal;
01385     }
01386 }
01387 
01388 template<typename T>
01389 inline plint TriangularSurfaceMesh<T>::prev(plint iEdge) const
01390 {
01391     PLB_ASSERT(iEdge >= 0 && iEdge < 3*numTriangles);
01392     return (iEdge%3 == 0) ? iEdge+2 : iEdge-1;
01393 }
01394 
01395 template<typename T>
01396 inline plint TriangularSurfaceMesh<T>::next(plint iEdge) const
01397 {
01398     PLB_ASSERT(iEdge >= 0 && iEdge < 3*numTriangles);
01399     return (iEdge%3 == 2) ? iEdge-2 : iEdge+1;
01400 }
01401 
01402 template<typename T>
01403 inline plint TriangularSurfaceMesh<T>::changeEdgeId(plint iEdge) const
01404 {
01405     plint iTriangle = iEdge/3;
01406     plint mod = iEdge%3;
01407     return (mod == 0) ? 3*iTriangle+2 : ((mod == 1) ? iEdge : 3*iTriangle);
01408 }
01409 
01410 template<typename T>
01411 std::vector<std::vector<plint> >
01412     TriangularSurfaceMesh<T>::detectHoles()
01413 {
01414     std::vector<std::vector<plint> > holes;
01415     std::vector<bool> check(getNumVertices());
01416     // Whenever a vertex is identified as part of a given hole boundary, it is
01417     //   opted out in the "check" array to avoid that it is mistakingly
01418     //   identified later on as the starting vertex for a new hole.
01419     std::fill(check.begin(), check.end(), false);
01420     // Check all vertices ...
01421     for(plint iVertex=0; iVertex<numVertices; ++iVertex) {
01422         //                               ... unless they've been previously opted out.
01423         if (isBoundaryVertex(iVertex) && !check[iVertex]) {
01424             check[iVertex] = true;
01425             std::vector<plint> newHole;
01426             newHole.push_back(iVertex);
01427             Edge nextEdge = edges()[emanatingEdges()[iVertex]];
01428             // Loop around the hole, until we're back to the first vertex.
01429             while (nextEdge.pv != iVertex) {
01430                 plint nextVertex = nextEdge.pv;
01431                 check[nextVertex] = true;
01432                 newHole.push_back(nextVertex);
01433                 nextEdge = edges()[emanatingEdges()[nextVertex]];
01434             }
01435             holes.push_back(newHole);
01436         }
01437     }
01438     return holes;
01439 }
01440 
01441 template<typename T>
01442 typename TriangularSurfaceMesh<T>::Lid TriangularSurfaceMesh<T>::closeHole(
01443     std::vector<plint> const& hole)
01444 {
01445     plint numHoleVertices = (plint) hole.size();
01446 
01447     // 1. Create a new vertex, corresponding to the barycenter.
01448     Array<T,3> baryCenter; baryCenter.resetToZero();
01449     for (plint iHole=0; iHole<numHoleVertices; ++iHole) {
01450         plint iVertex = hole[iHole];
01451         baryCenter += getVertex(iVertex);
01452     }
01453     baryCenter /= (T)numHoleVertices;
01454     vertices().push_back(baryCenter);
01455     plint iCenter = numVertices;
01456     ++numVertices; // Don't forget to update this class variable.
01457 
01458     // 2. Create the new triangles.
01459     plint edgeIndex = edges().size()-1;
01460     plint firstAddedEdge = edgeIndex+1;
01461     // There is exactly one new triangle for each vertex along the hole.
01462     for (plint iTriangle=0; iTriangle<numHoleVertices; ++iTriangle) {
01463         plint iVertex = hole[iTriangle];
01464         plint nextVertex = hole[iTriangle==numHoleVertices-1 ? 0 : iTriangle+1];
01465 
01466         // a) Add the new edge which is horizontal to the hole boundary.
01467         Edge counterEdge; ++edgeIndex;
01468         counterEdge.pv = iVertex;
01469         counterEdge.ne = emanatingEdges()[iVertex];
01470         edges().push_back(counterEdge);
01471         // Convert this former boundary edge to a bulk edge.
01472         edges()[counterEdge.ne].ne = edgeIndex; 
01473 
01474         // b) Add the edge that goes from a boundary vertex to the barycenter.
01475         Edge firstEdge; ++edgeIndex;
01476         firstEdge.pv = iCenter;
01477         if (iTriangle>0) {
01478             firstEdge.ne = edgeIndex-2;
01479             // Convert this former boundary edge to a bulk edge.
01480             edges()[firstEdge.ne].ne = edgeIndex;
01481         }
01482         edges().push_back(firstEdge);
01483 
01484         // c) Add the edge that goes from the barycenter to a boundary vertex.
01485         Edge secondEdge; ++edgeIndex;
01486         secondEdge.pv = nextVertex;
01487         if (iTriangle==numHoleVertices-1) {
01488             secondEdge.ne = firstAddedEdge+1;
01489             // Convert this former boundary edge to a bulk edge.
01490             edges()[secondEdge.ne].ne = edgeIndex;
01491         }
01492         edges().push_back(secondEdge);
01493 
01494         ++numTriangles; // Don't forget to update this class variable.
01495     }
01496     // For the newly created barycenter, define the emanating edge to
01497     //   be the one corresponding to the first added triangle.
01498     emanatingEdges().push_back(firstAddedEdge+2);
01499 
01500     // 3. Make sure this will not become a degenerate case.
01501     avoidIntegerPosition(iCenter);
01502 
01503     // 4. Keep track of the newly created triangles with help of a "Lid" structure.
01504     Lid lid;
01505     lid.firstTriangle = firstAddedEdge/3;
01506     lid.numTriangles = numHoleVertices;
01507     lid.boundaryVertices = hole;
01508     lid.centerVertex = iCenter;
01509     return lid;
01510 }
01511 
01512 
01513 template<typename T>
01514 void toLatticeUnits (
01515         TriangularSurfaceMesh<T>& mesh,
01516         plint resolution, plint referenceDirection,
01517         Array<T,3>& location, T& dx)
01518 {
01519     PLB_ASSERT(referenceDirection>=0 && referenceDirection <=2);
01520     Array<T,2> xRange, yRange, zRange;
01521     mesh.computeBoundingBox(xRange, yRange, zRange);
01522     T deltaX = T();
01523     switch (referenceDirection) {
01524         case 0: deltaX = xRange[1] - xRange[0];
01525                 break;
01526         case 1: deltaX = yRange[1] - yRange[0];
01527                 break;
01528         case 2: deltaX = zRange[1] - zRange[0];
01529                 break;
01530     }
01531     
01532     T scalingFactor = (T)(resolution)/deltaX;
01533 
01534     // Transform mesh into the frame of coordinate of the multiScalarField.
01535     location = Array<T,3>(xRange[0],yRange[0],zRange[0]);
01536     mesh.translate(Array<T,3>(-location));
01537     mesh.scale(scalingFactor);
01538     dx = 1./scalingFactor;
01539 }
01540 
01541 
01542 /* ******* Lid operations ************************************************** */
01543 
01544 template<typename T>
01545 Array<T,3> computeBaryCenter (
01546         TriangularSurfaceMesh<T> const& mesh,
01547         typename TriangularSurfaceMesh<T>::Lid const& lid )
01548 {
01549     Array<T,3> baryCenter; baryCenter.resetToZero();
01550     for ( plint iBoundary=0;
01551           iBoundary<(plint)lid.boundaryVertices.size(); ++iBoundary)
01552     {
01553         plint iVertex = lid.boundaryVertices[iBoundary];
01554         baryCenter += mesh.getVertex(iVertex);
01555     }
01556     baryCenter /= (T)lid.boundaryVertices.size();
01557     return baryCenter;
01558 }
01559 
01560 template<typename T>
01561 Array<T,3> computeGeometricCenter (
01562         TriangularSurfaceMesh<T> const& mesh,
01563         typename TriangularSurfaceMesh<T>::Lid const& lid )
01564 {
01565     typedef typename TriangularSurfaceMesh<T>::Edge Edge;
01566     Array<T,3> center; center.resetToZero();
01567     T circumference = T();
01568     for ( plint iBoundary=0;
01569           iBoundary<(plint)lid.boundaryVertices.size(); ++iBoundary)
01570     {
01571         plint iVertex = lid.boundaryVertices[iBoundary];
01572         Edge edge = mesh.edges()[mesh.emanatingEdges()[iVertex]];
01573         plint iNextVertex = edge.pv;
01574         Array<T,3> v1 = mesh.getVertex(iVertex);
01575         Array<T,3> v2 = mesh.getVertex(iNextVertex);
01576         T l = norm(v2-v1);
01577         center += (v1+v2)*l;
01578         circumference += l;
01579     }
01580     center /= 2.*circumference;
01581     return center;
01582 }
01583 
01584 template<typename T>
01585 T computeGeometricRadius (
01586         TriangularSurfaceMesh<T> const& mesh,
01587         typename TriangularSurfaceMesh<T>::Lid const& lid )
01588 {
01589     typedef typename TriangularSurfaceMesh<T>::Edge Edge;
01590     Array<T,3> center= computeGeometricCenter(mesh, lid);
01591     T radius = T();
01592     T circumference = T();
01593     for ( plint iBoundary=0;
01594           iBoundary<(plint)lid.boundaryVertices.size(); ++iBoundary)
01595     {
01596         plint iVertex = lid.boundaryVertices[iBoundary];
01597         Edge edge = mesh.edges()[mesh.emanatingEdges()[iVertex]];
01598         plint iNextVertex = edge.pv;
01599         Array<T,3> v1 = mesh.getVertex(iVertex);
01600         Array<T,3> v2 = mesh.getVertex(iNextVertex);
01601         T l = norm(v2-v1);
01602         radius += norm(v1-center)*l;
01603         circumference += l;
01604     }
01605     radius /= circumference;
01606     return radius;
01607 }
01608 
01609 template<typename T>
01610 void computeBoundingBox (
01611         TriangularSurfaceMesh<T> const& mesh,
01612         typename TriangularSurfaceMesh<T>::Lid const& lid,
01613         Array<T,2>& xLim, Array<T,2>& yLim, Array<T,2>& zLim )
01614 {
01615     xLim[0] = yLim[0] = zLim[0] = std::numeric_limits<T>::max();
01616     xLim[1] = yLim[1] = zLim[1] = std::numeric_limits<T>::min();
01617     for ( plint iBoundary=0;
01618           iBoundary<(plint)lid.boundaryVertices.size(); ++iBoundary )
01619     {
01620         plint iVertex = lid.boundaryVertices[iBoundary];
01621         Array<T,3> const& vertex = mesh.getVertex(iVertex);
01622         xLim[0] = std::min(xLim[0], vertex[0]);
01623         xLim[1] = std::max(xLim[1], vertex[0]);
01624         yLim[0] = std::min(yLim[0], vertex[1]);
01625         yLim[1] = std::max(yLim[1], vertex[1]);
01626         zLim[0] = std::min(zLim[0], vertex[2]);
01627         zLim[1] = std::max(zLim[1], vertex[2]);
01628     }
01629 }
01630 
01631 template<typename T>
01632 T computeInnerRadius (
01633         TriangularSurfaceMesh<T> const& mesh,
01634         typename TriangularSurfaceMesh<T>::Lid const& lid )
01635 {
01636     if (lid.boundaryVertices.empty()) {
01637         return T();
01638     }
01639     else {
01640         T innerRadius = mesh.computeEdgeLength (
01641                 lid.centerVertex, lid.boundaryVertices[0] );
01642         for ( plint iBoundary=1;
01643               iBoundary<(plint)lid.boundaryVertices.size(); ++iBoundary)
01644         {
01645             T nextLength = mesh.computeEdgeLength (
01646                     lid.centerVertex, lid.boundaryVertices[iBoundary] );
01647             innerRadius = std::min(innerRadius, nextLength);
01648         }
01649         return innerRadius;
01650     }
01651 }
01652 
01653 template<typename T>
01654 T computeOuterRadius (
01655         TriangularSurfaceMesh<T> const& mesh,
01656         typename TriangularSurfaceMesh<T>::Lid const& lid )
01657 {
01658     if (lid.boundaryVertices.empty()) {
01659         return T();
01660     }
01661     else {
01662         T innerRadius = mesh.computeEdgeLength (
01663                 lid.centerVertex, lid.boundaryVertices[0] );
01664         for ( plint iBoundary=1;
01665               iBoundary<(plint)lid.boundaryVertices.size(); ++iBoundary)
01666         {
01667             T nextLength = mesh.computeEdgeLength (
01668                     lid.centerVertex, lid.boundaryVertices[iBoundary] );
01669             innerRadius = std::max(innerRadius, nextLength);
01670         }
01671         return innerRadius;
01672     }
01673 }
01674 
01675 template<typename T>
01676 T computeArea (
01677         TriangularSurfaceMesh<T> const& mesh,
01678         typename TriangularSurfaceMesh<T>::Lid const& lid )
01679 {
01680     T area = T();
01681     plint numVertices = (plint)lid.boundaryVertices.size();
01682     plint centerVertex = lid.centerVertex;
01683     for ( plint iBoundary=0; iBoundary<numVertices; ++iBoundary)
01684     {
01685         plint vertex1 = lid.boundaryVertices[iBoundary];
01686         plint vertex2 = lid.boundaryVertices[(iBoundary+1)%numVertices];
01687         area += mesh.computeTriangleArea(centerVertex, vertex1, vertex2);
01688     }
01689     return area;
01690 }
01691 
01692 template<typename T>
01693 Array<T,3> computeNormal (
01694         TriangularSurfaceMesh<T> const& mesh,
01695         typename TriangularSurfaceMesh<T>::Lid const& lid )
01696 {
01697     return mesh.computeVertexNormal(lid.centerVertex);
01698 }
01699 
01700 
01701 template<typename T>
01702 void reCenter (
01703         TriangularSurfaceMesh<T>& mesh,
01704         typename TriangularSurfaceMesh<T>::Lid const& lid )
01705 {
01706     Array<T,3> newCenter = computeBaryCenter(mesh,lid);
01707     mesh.replaceVertex(lid.centerVertex, newCenter);
01708 }
01709 
01710 } // namespace plb
01711 
01712 #endif  // TRIANGULAR_SURFACE_MESH_HH