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

triangleSet.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 TRIANGLE_SET_HH
00028 #define TRIANGLE_SET_HH
00029 
00030 #include "triangleSet.h"
00031 #include "core/util.h"
00032 #include <algorithm>
00033 #include <limits>
00034 #include <cstdio>
00035 #include <cmath>
00036 
00037 namespace plb {
00038 
00039 template<typename T>
00040 TriangleSet<T>::TriangleSet(Precision precision_)
00041     : minEdgeLength(std::numeric_limits<T>::max()),
00042       maxEdgeLength(std::numeric_limits<T>::min())
00043 {
00044     PLB_ASSERT(precision_ == FLT || precision_ == DBL || precision_ == LDBL);
00045     precision = precision_;
00046 
00047     boundingCuboid.lowerLeftCorner  = Array<T,3>(0.0, 0.0, 0.0);
00048     boundingCuboid.upperRightCorner = Array<T,3>(0.0, 0.0, 0.0);
00049 }
00050 
00051 template<typename T>
00052 TriangleSet<T>::TriangleSet(std::vector<Triangle> const& triangles_, Precision precision_)
00053     : triangles(triangles_),
00054       minEdgeLength(std::numeric_limits<T>::max()),
00055       maxEdgeLength(std::numeric_limits<T>::min())
00056 {
00057     PLB_ASSERT(precision_ == FLT || precision_ == DBL || precision_ == LDBL);
00058     precision = precision_;
00059 
00060     computeMinMaxEdges();
00061     computeBoundingCuboid();
00062 }
00063 
00064 template<typename T>
00065 TriangleSet<T>::TriangleSet(std::string fname, Precision precision_, SurfaceGeometryFileFormat fformat)
00066     : minEdgeLength(std::numeric_limits<T>::max()),
00067       maxEdgeLength(std::numeric_limits<T>::min())
00068 {
00069     PLB_ASSERT(precision_ == FLT || precision_ == DBL || precision_ == LDBL);
00070     PLB_ASSERT(fformat == STL);
00071     precision = precision_;
00072 
00073     switch (fformat) {
00074     case STL: default:
00075         readSTL(fname);
00076         break;
00077     }
00078 
00079     // TODO: Check if the next call is actually needed, since the min and max edges are
00080     //       computed in the readAsciiSTL and readBinarySTL functions as well.
00081     computeMinMaxEdges();
00082 
00083     computeBoundingCuboid();
00084 }
00085 
00086 template<typename T>
00087 std::vector<typename TriangleSet<T>::Triangle> const&
00088     TriangleSet<T>::getTriangles() const
00089 {
00090     return triangles;
00091 }
00092 
00093 template<typename T>
00094 void TriangleSet<T>::setPrecision(Precision precision_)
00095 {
00096     PLB_ASSERT(precision_ == FLT || precision_ == DBL || precision_ == LDBL);
00097     precision = precision_;
00098 }
00099 
00100 template<typename T>
00101 void TriangleSet<T>::readSTL(std::string fname)
00102 {
00103     char buf[256];
00104     FILE *fp = fopen(fname.c_str(), "r");
00105     PLB_ASSERT(fp != NULL); // The input file cannot be read.
00106 
00107     char *sp = fgets(buf, 256, fp);
00108     PLB_ASSERT(sp != NULL); // The input file cannot be read.
00109     rewind(fp);
00110 
00111     if (strstr(buf, "solid") != NULL) {
00112         readAsciiSTL(fp);
00113     }
00114     else {
00115         readBinarySTL(fp);
00116     }
00117 }
00118 
00119 template<typename T>
00120 void TriangleSet<T>::readAsciiSTL(FILE* fp) {
00121     char buf[256];
00122     char *cp, *sp;
00123 
00124     sp = fgets(buf, 256, fp);
00125     PLB_ASSERT(sp != NULL); // The input file is badly structured.
00126 
00127     char fmt[32];
00128     bool failed = false;
00129     if (sizeof(T) == sizeof(float))
00130         strcpy(fmt, "%f%f%f");
00131     else if (sizeof(T) == sizeof(double))
00132         strcpy(fmt, "%lf%lf%lf");
00133     else if (sizeof(T) == sizeof(long double))
00134         strcpy(fmt, "%Lf%Lf%Lf");
00135     else
00136         failed = true;
00137 
00138     PLB_ASSERT(!failed); // The input file cannot be read.
00139 
00140     cp = strstr(buf, "solid");
00141     PLB_ASSERT(cp != NULL); // The input file is badly structured.
00142 
00143     while (cp != NULL && !failed) {
00144         if (fgets(buf, 256, fp) == NULL) {
00145             failed = true;
00146         }
00147 
00148         do {
00149             if ((cp = strstr(buf, "facet normal")) == NULL) {
00150                 failed = true;
00151             }
00152             cp += 12;
00153             Array<T,3> n;
00154             if (sscanf(cp, fmt, &n[0], &n[1], &n[2]) != 3) {
00155                 failed = true;
00156             }
00157 
00158             if (fgets(buf, 256, fp) == NULL || strstr(buf, "outer loop") == NULL)
00159             {
00160                 failed = true;
00161             }
00162 
00163             Triangle triangle;
00164             T nextMin, nextMax;
00165             for (int i = 0; i < 3; i++) {
00166                 if ( fgets(buf, 256, fp) == NULL ||
00167                      (cp = strstr(buf, "vertex")) == NULL )
00168                 {
00169                     failed = true;
00170                 }
00171                 cp += 6;
00172                 triangle[i][0] = T();
00173                 triangle[i][1] = T();
00174                 triangle[i][2] = T();
00175                 if (sscanf( cp, fmt,
00176                             &triangle[i][0],
00177                             &triangle[i][1],
00178                             &triangle[i][2] ) != 3)
00179                 {
00180                     failed = true;
00181                 }
00182             }
00183 
00184             if (fgets(buf, 256, fp) == NULL || strstr(buf, "endloop") == NULL) {
00185                 failed = true;
00186             }
00187 
00188             if (fgets(buf, 256, fp) == NULL || strstr(buf, "endfacet") == NULL) {
00189                 failed = true;
00190             }
00191 
00192             check(triangle, n);
00193             triangles.push_back(triangle);
00194 
00195             computeMinMaxEdge(triangles.size()-1, nextMin, nextMax);
00196             minEdgeLength = std::min(minEdgeLength, nextMin);
00197             maxEdgeLength = std::max(maxEdgeLength, nextMax);
00198 
00199             if (fgets(buf, 256, fp) == NULL) {
00200                 failed = true;
00201             }
00202             cp = strstr(buf, "endsolid");
00203         }
00204         while (cp == NULL && !failed);
00205 
00206         if (fgets(buf, 256, fp) == NULL)
00207             break;
00208 
00209         cp = strstr(buf, "solid");
00210     }
00211     PLB_ASSERT(!failed); // The input file is badly structured.
00212 }
00213 
00214 template<typename T>
00215 void TriangleSet<T>::readBinarySTL(FILE* fp)
00216 {
00217     char buf[256];
00218     unsigned int nt;
00219     float array[3];
00220     unsigned short abc;
00221     bool failed = false;
00222 
00223     int count = 0;
00224     while (fread(buf, sizeof(char), 80, fp) == 80 &&
00225            fread(&nt, sizeof(unsigned int), 1, fp) == 1 && !failed) {
00226         count++;
00227         T nextMin, nextMax;
00228         for (unsigned it = 0; it < nt && !failed; it++) {
00229             if (fread(array, sizeof(float), 3, fp) != 3) {
00230                 failed = true;
00231             }
00232             Array<T,3> n;
00233             n[0] = array[0];
00234             n[1] = array[1];
00235             n[2] = array[2];
00236 
00237             Triangle triangle;
00238             for (int i = 0; i < 3 && !failed; i++) {
00239                 if (fread(array, sizeof(float), 3, fp) != 3) {
00240                     failed = true;
00241                 }
00242                 triangle[i][0] = T();
00243                 triangle[i][1] = T();
00244                 triangle[i][2] = T();
00245                 triangle[i][0] = array[0];
00246                 triangle[i][1] = array[1];
00247                 triangle[i][2] = array[2];
00248             }
00249 
00250             if (fread(&abc, sizeof(unsigned short), 1, fp) != 1) {
00251                 failed = true;
00252             }
00253 
00254             check(triangle, n);
00255             triangles.push_back(triangle);
00256 
00257             computeMinMaxEdge(triangles.size()-1, nextMin, nextMax);
00258             minEdgeLength = std::min(minEdgeLength, nextMin);
00259             maxEdgeLength = std::max(maxEdgeLength, nextMax);
00260         }
00261     }
00262 
00263     if (count == 0) 
00264         failed = true;
00265 
00266     PLB_ASSERT(!failed); // The input file is badly structured.
00267 }
00268 
00270 template<typename T>
00271 void TriangleSet<T>::check(Triangle& triangle, Array<T,3> const& n)
00272 {
00273     T eps = getEpsilon<T>(precision);
00274 
00275     Array<T,3> v01 = triangle[1] - triangle[0];
00276     Array<T,3> v02 = triangle[2] - triangle[0];
00277     Array<T,3> v12 = triangle[2] - triangle[1];
00278 
00279     T norm01 = sqrt(VectorTemplateImpl<T,3>::normSqr(v01));
00280     T norm02 = sqrt(VectorTemplateImpl<T,3>::normSqr(v02));
00281     T norm12 = sqrt(VectorTemplateImpl<T,3>::normSqr(v12));
00282 
00283     if (util::fpequal(norm01, (T) 0.0, eps) || util::fpequal(norm02, (T) 0.0, eps) ||
00284         util::fpequal(norm12, (T) 0.0, eps))
00285     {
00286         PLB_ASSERT(false); // One of the triangles is degenerate.
00287     }
00288 
00289     Array<T,3> cn;
00290     crossProduct(v01, v02, cn);
00291 
00292     T norm_cn = sqrt(VectorTemplateImpl<T,3>::normSqr(cn));
00293 
00294     if (util::fpequal(norm_cn, (T) 0.0, eps))
00295     {
00296         PLB_ASSERT(false); // One of the triangles has zero area.
00297     }
00298 
00299     T dot = VectorTemplateImpl<T,3>::scalarProduct(cn,n);
00300 
00301     if (dot < 0.0) {
00302         std::swap(triangle[1],triangle[2]);
00303     }
00304 }
00305 
00306 template<typename T>
00307 void TriangleSet<T>::translate(Array<T,3> const& vector)
00308 {
00309     T eps = std::numeric_limits<T>::epsilon();
00310     if (util::fpequal((T) sqrt(VectorTemplateImpl<T,3>::normSqr(vector)), (T) 0.0, eps))
00311         return;
00312 
00313     plint size = triangles.size();
00314     if (size == 0)
00315         return;
00316 
00317     for (plint i = 0; i < size; i++) {
00318         for (int j = 0; j < 3; j++) {
00319             triangles[i][j] += vector;
00320         }
00321     }
00322 
00323     boundingCuboid.lowerLeftCorner  += vector;
00324     boundingCuboid.upperRightCorner += vector;
00325 }
00326 
00327 template<typename T>
00328 void TriangleSet<T>::scale(T alpha)
00329 {
00330     T eps = std::numeric_limits<T>::epsilon();
00331     if (util::fpequal(alpha, (T) 1.0, eps))
00332         return;
00333 
00334     plint size = triangles.size();
00335     if (size == 0)
00336         return;
00337 
00338     for (plint i = 0; i < size; i++) {
00339         for (int j = 0; j < 3; j++) {
00340             triangles[i][j] *= alpha;
00341         }
00342     }
00343     minEdgeLength *= alpha;
00344     maxEdgeLength *= alpha;
00345 
00346     boundingCuboid.lowerLeftCorner  *= alpha;
00347     boundingCuboid.upperRightCorner *= alpha;
00348 }
00349 
00350 template<typename T>
00351 void TriangleSet<T>::rotateAtOrigin(Array<T,3> const& normedAxis, T theta) {
00352     plint size = (plint)triangles.size();
00353     for (plint iTriangle = 0; iTriangle < size; iTriangle++) {
00354         for (int iVertex = 0; iVertex < 3; iVertex++) {
00355             triangles[iTriangle][iVertex] =
00356                 plb::rotateAtOrigin (
00357                     triangles[iTriangle][iVertex], normedAxis, theta );
00358         }
00359     }
00360 
00361     computeBoundingCuboid();
00362 }
00363 
00364 template<typename T>
00365 void TriangleSet<T>::rotate(T phi, T theta, T psi)
00366 {   
00367     T eps = std::numeric_limits<T>::epsilon();
00368     T pi = acos(-1.0);
00369 
00370     PLB_ASSERT((theta > 0.0 || util::fpequal(theta, (T) 0.0, eps)) &&
00371                (theta < pi  || util::fpequal(theta, pi, eps)));
00372 
00373     plint size = triangles.size();
00374     if (size == 0)
00375         return;
00376 
00377     T a[3][3];
00378     a[0][0] =  1.0;
00379     a[0][1] =  0.0;
00380     a[0][2] =  0.0;
00381     a[1][0] =  0.0;
00382     a[1][1] =  cos(theta);
00383     a[1][2] =  sin(theta);
00384     a[2][0] =  0.0;
00385     a[2][1] = -sin(theta);
00386     a[2][2] =  cos(theta);
00387 
00388     T b[3][3];
00389     b[0][0] =  cos(phi);
00390     b[0][1] =  sin(phi);
00391     b[0][2] =  0.0;
00392     b[1][0] = -sin(phi);
00393     b[1][1] =  cos(phi);
00394     b[1][2] =  0.0;
00395     b[2][0] =  0.0;
00396     b[2][1] =  0.0;
00397     b[2][2] =  1.0;
00398 
00399     T c[3][3];
00400     for (int i = 0; i < 3; i++) {
00401         for (int j = 0; j < 3; j++) {
00402             c[i][j] = 0.0;
00403             for (int k = 0; k < 3; k++) {
00404                 c[i][j] += a[i][k]*b[k][j];
00405             }
00406         }
00407     }
00408 
00409     b[0][0] =  cos(psi);
00410     b[0][1] =  sin(psi);
00411     b[0][2] =  0.0;
00412     b[1][0] = -sin(psi);
00413     b[1][1] =  cos(psi);
00414     b[1][2] =  0.0;
00415     b[2][0] =  0.0;
00416     b[2][1] =  0.0;
00417     b[2][2] =  1.0;
00418 
00419     for (int i = 0; i < 3; i++) {
00420         for (int j = 0; j < 3; j++) {
00421             a[i][j] = 0.0;
00422             for (int k = 0; k < 3; k++) {
00423                 a[i][j] += b[i][k]*c[k][j];
00424             }
00425         }
00426     }
00427 
00428     for (plint iTriangle = 0; iTriangle < size; iTriangle++) {
00429         for (int iVertex = 0; iVertex < 3; iVertex++) {
00430             Array<T,3> x = triangles[iTriangle][iVertex];
00431             for (int i = 0; i < 3; i++) {
00432                 triangles[iTriangle][iVertex][i] = 0.0;
00433                 for (int j = 0; j < 3; j++) {
00434                     triangles[iTriangle][iVertex][i] += a[i][j]*x[j];
00435                 }
00436             }
00437         }
00438     }
00439 
00440     computeBoundingCuboid();
00441 }
00442 
00443 template<typename T>
00444 void TriangleSet<T>::merge(std::vector<TriangleSet<T> > meshes)
00445 {
00446     PLB_ASSERT(meshes.size() != 0);
00447 
00448     triangles.assign(meshes[0].getTriangles().begin(), meshes[0].getTriangles().end());
00449     minEdgeLength = meshes[0].getMinEdgeLength();
00450     maxEdgeLength = meshes[0].getMaxEdgeLength();
00451     boundingCuboid = meshes[0].getBoundingCuboid();
00452     for (plint i = 1; i < meshes.size(); i++) {
00453         triangles.insert(triangles.end(), meshes[i].getTriangles().begin(), meshes[i].getTriangles().end());
00454         minEdgeLength = std::min(minEdgeLength, meshes[i].getMinEdgeLength());
00455         maxEdgeLength = std::max(maxEdgeLength, meshes[i].getMaxEdgeLength());
00456 
00457         Cuboid<T> bcuboid = meshes[i].getBoundingCuboid();
00458         for (plint j = 0; j < 3; j++) {
00459             boundingCuboid.lowerLeftCorner[j]  = std::min(boundingCuboid.lowerLeftCorner[j],
00460                                                           bcuboid.lowerLeftCorner[j]);
00461             boundingCuboid.upperRightCorner[j] = std::max(boundingCuboid.upperRightCorner[j],
00462                                                           bcuboid.upperRightCorner[j]);
00463         }
00464     }
00465 }
00466 
00467 template<typename T>
00468 void TriangleSet<T>::reverseOrientation()
00469 {
00470     plint size = triangles.size();
00471     for (plint i = 0; i < size; i++) 
00472         std::swap(triangles[i][1],triangles[i][2]);
00473 }
00474 
00475 template<typename T>
00476 void TriangleSet<T>::writeAsciiSTL(std::string fname) const
00477 {
00478     if (global::mpi().isMainProcessor()) {
00479         FILE *fp = fopen(fname.c_str(), "w");
00480         PLB_ASSERT(fp != NULL);
00481 
00482         plint size = triangles.size();
00483         fprintf(fp, "solid plb\n");
00484         for (plint i = 0; i < size; i++) {
00485             Array<T,3> v0 = triangles[i][0];
00486             Array<T,3> v1 = triangles[i][1];
00487             Array<T,3> v2 = triangles[i][2];
00488 
00489             Array<T,3> e01 = v1 - v0;
00490             Array<T,3> e02 = v2 - v0;
00491 
00492             Array<T,3> n;
00493             crossProduct(e01, e02, n);
00494             n /= sqrt(VectorTemplateImpl<T,3>::normSqr(n));
00495             fprintf(fp, "  facet normal % e % e % e\n", (double) n[0], (double) n[1], (double) n[2]);
00496             fprintf(fp, "    outer loop\n");
00497             fprintf(fp, "      vertex % e % e % e\n", (double) v0[0], (double) v0[1], (double) v0[2]);
00498             fprintf(fp, "      vertex % e % e % e\n", (double) v1[0], (double) v1[1], (double) v1[2]);
00499             fprintf(fp, "      vertex % e % e % e\n", (double) v2[0], (double) v2[1], (double) v2[2]);
00500             fprintf(fp, "    endloop\n");
00501             fprintf(fp, "  endfacet\n");
00502         }
00503         fprintf(fp, "endsolid plb\n");
00504         fclose(fp);
00505     }
00506 }
00507 
00508 template<typename T>
00509 void TriangleSet<T>::writeBinarySTL(std::string fname) const
00510 {
00511     if (global::mpi().isMainProcessor()) {
00512         FILE *fp = fopen(fname.c_str(), "wb");
00513         PLB_ASSERT(fp != NULL);
00514 
00515         unsigned int nt = triangles.size();
00516         unsigned short abc = 0;
00517         char buf[80];
00518 
00519         for (int i = 0; i < 80; i++)
00520             buf[i] = '\0';
00521 
00522         fwrite(buf, sizeof(char), 80, fp);
00523         fwrite(&nt, sizeof(unsigned int), 1, fp);
00524         for (plint i = 0; i < nt; i++) {
00525             Array<T,3> v0 = triangles[i][0];
00526             Array<T,3> v1 = triangles[i][1];
00527             Array<T,3> v2 = triangles[i][2];
00528 
00529             Array<T,3> e01 = v1 - v0;
00530             Array<T,3> e02 = v2 - v0;
00531 
00532             Array<T,3> nrml;
00533             crossProduct(e01, e02, nrml);
00534             nrml /= sqrt(VectorTemplateImpl<T,3>::normSqr(nrml));
00535 
00536             float n[3];
00537             n[0] = nrml[0];
00538             n[1] = nrml[1];
00539             n[2] = nrml[2];
00540             fwrite((void *) n, sizeof(float), 3, fp);
00541             float v[3];
00542             v[0] = v0[0];
00543             v[1] = v0[1];
00544             v[2] = v0[2];
00545             fwrite((void *) v, sizeof(float), 3, fp);
00546             v[0] = v1[0];
00547             v[1] = v1[1];
00548             v[2] = v1[2];
00549             fwrite((void *) v, sizeof(float), 3, fp);
00550             v[0] = v2[0];
00551             v[1] = v2[1];
00552             v[2] = v2[2];
00553             fwrite((void *) v, sizeof(float), 3, fp);
00554             fwrite(&abc, sizeof(unsigned short), 1, fp);
00555         }
00556 
00557         fclose(fp);
00558     }
00559 }
00560 
00561 template<typename T>
00562 int TriangleSet<T>::cutTriangleWithPlane(Plane<T> const& plane, Triangle const& triangle,
00563         TriangleSet<T>& newTriangleSet) const
00564 {
00565     T epsilon = getEpsilon<T>(precision);
00566 
00567     int vertexTags[3];
00568 
00569     // Tag the triangle vertices.
00570     for (int iVertex = 0; iVertex < 3; iVertex++) {
00571         Array<T,3> tmp = triangle[iVertex] - plane.point;
00572         T norm_tmp = norm(tmp);
00573         if (norm_tmp > epsilon) {
00574             tmp /= norm_tmp;
00575         } else {
00576             tmp[0] = tmp[1] = tmp[2] = 0.0;
00577         }
00578         T dotp = dot(tmp, plane.normal);
00579         if (fabs(dotp) <= epsilon) {
00580             vertexTags[iVertex] = 0;
00581         } else if (dotp > 0.0 && fabs(dotp) > epsilon) {
00582             vertexTags[iVertex] = -1;
00583         } else if (dotp < 0.0 && fabs(dotp) > epsilon) {
00584             vertexTags[iVertex] = 1;
00585         } else {
00586             return -1;
00587         }
00588     }
00589 
00590     // All three vertices belong to one side of the cut plane.
00591     if (vertexTags[0] == 1 && vertexTags[1] == 1 && vertexTags[2] == 1) {
00592         newTriangleSet.triangles.push_back(triangle);
00593         return 1;
00594     } else if (vertexTags[0] == -1 && vertexTags[1] == -1 && vertexTags[2] == -1) {
00595         return 0;
00596     }
00597 
00598     // One vertex belongs to one side of the cut plane and the other two vertices
00599     //   belong to the other side.
00600     for (int i = 0; i < 3; i++) {
00601         int j = (i + 1) != 3 ? (i + 1) : 0;
00602         int k = (j + 1) != 3 ? (j + 1) : 0;
00603 
00604         if (vertexTags[i] == 1 && vertexTags[j] == -1 && vertexTags[k] == -1) {
00605             Array<T,3> intersection_ij(0.0, 0.0, 0.0), intersection_ik(0.0, 0.0, 0.0);
00606             int rv = 0;
00607             rv = lineIntersectionWithPlane<T>(plane, triangle[i], triangle[j], precision, intersection_ij);
00608             if (rv != 1) {
00609                 return -1;
00610             }
00611             rv = lineIntersectionWithPlane<T>(plane, triangle[i], triangle[k], precision, intersection_ik);
00612             if (rv != 1) {
00613                 return -1;
00614             }
00615             Triangle newTriangle(triangle[i], intersection_ij, intersection_ik);
00616             newTriangleSet.triangles.push_back(newTriangle);
00617             return 1;
00618         } else if (vertexTags[i] == -1 && vertexTags[j] == 1 && vertexTags[k] == 1) {
00619             Array<T,3> intersection_ij(0.0, 0.0, 0.0), intersection_ik(0.0, 0.0, 0.0);
00620             int rv = 0;
00621             rv = lineIntersectionWithPlane<T>(plane, triangle[i], triangle[j], precision, intersection_ij);
00622             if (rv != 1) {
00623                 return -1;
00624             }
00625             rv = lineIntersectionWithPlane<T>(plane, triangle[i], triangle[k], precision, intersection_ik);
00626             if (rv != 1) {
00627                 return -1;
00628             }
00629             Triangle newTriangle_0(triangle[k], intersection_ij, triangle[j]);
00630             Triangle newTriangle_1(triangle[k], intersection_ik, intersection_ij);
00631             newTriangleSet.triangles.push_back(newTriangle_0);
00632             newTriangleSet.triangles.push_back(newTriangle_1);
00633             return 1;
00634         }
00635     }
00636 
00637     // Only one vertex belongs to the cut plane.
00638     for (int i = 0; i < 3; i++) {
00639         int j = (i + 1) != 3 ? (i + 1) : 0;
00640         int k = (j + 1) != 3 ? (j + 1) : 0;
00641 
00642         if (vertexTags[i] == 0) {
00643             if (vertexTags[j] == 1 && vertexTags[k] == 1) {
00644                 newTriangleSet.triangles.push_back(triangle);
00645                 return 1;
00646             } else if (vertexTags[j] == -1 && vertexTags[k] == -1) {
00647                 return 0;
00648             } else if (vertexTags[j] == 1 && vertexTags[k] == -1) {
00649                 Array<T,3> intersection(0.0, 0.0, 0.0);
00650                 int rv = 0;
00651                 rv = lineIntersectionWithPlane<T>(plane, triangle[j], triangle[k], precision, intersection);
00652                 if (rv != 1) {
00653                     return -1;
00654                 }
00655                 Triangle newTriangle(triangle[i], triangle[j], intersection);
00656                 newTriangleSet.triangles.push_back(newTriangle);
00657                 return 1;
00658             } else if (vertexTags[j] == -1 && vertexTags[k] == 1) {
00659                 Array<T,3> intersection(0.0, 0.0, 0.0);
00660                 int rv = 0;
00661                 rv = lineIntersectionWithPlane<T>(plane, triangle[j], triangle[k], precision, intersection);
00662                 if (rv != 1) {
00663                     return -1;
00664                 }
00665                 Triangle newTriangle(triangle[i], intersection, triangle[k]);
00666                 newTriangleSet.triangles.push_back(newTriangle);
00667                 return 1;
00668             }
00669         }
00670     }
00671 
00672     // Only two of the three vertices belong to the cut plane.
00673     for (int i = 0; i < 3; i++) {
00674         int j = (i + 1) != 3 ? (i + 1) : 0;
00675         int k = (j + 1) != 3 ? (j + 1) : 0;
00676 
00677         if (vertexTags[i] == 0 && vertexTags[j] == 0) {
00678             if (vertexTags[k] == 1) {
00679                 newTriangleSet.triangles.push_back(triangle);
00680                 return 1;
00681             } else if (vertexTags[k] == -1) {
00682                 return 0;
00683             }
00684         }
00685     }
00686 
00687     // All 3 vertices belong to the cut plane.
00688     if (vertexTags[0] == 0 && vertexTags[1] == 0 && vertexTags[2] == 0) {
00689         newTriangleSet.triangles.push_back(triangle);
00690         return 1;
00691     }
00692 
00693     return -1;
00694 }
00695 
00696 template<typename T>
00697 int TriangleSet<T>::cutWithPlane(Plane<T> const& plane, TriangleSet<T>& newTriangleSet) const
00698 {
00699     T epsilon = getEpsilon<T>(precision);
00700 
00701     T norm_normal = norm(plane.normal);
00702     PLB_ASSERT(norm_normal > epsilon); // The cut plane normal vector cannot have zero magnitude.
00703     Plane<T> newPlane;
00704     newPlane.point = plane.point;
00705     newPlane.normal = plane.normal / norm_normal;
00706 
00707     newTriangleSet.triangles.resize(0);
00708 
00709     newTriangleSet.precision = precision;
00710 
00711     for (pluint iTriangle = 0; iTriangle < triangles.size(); iTriangle++) {
00712         if (cutTriangleWithPlane(newPlane, triangles[iTriangle], newTriangleSet) == -1) {
00713             return -1;
00714         }
00715     }
00716 
00717     if (newTriangleSet.triangles.size() != 0) {
00718         newTriangleSet.computeMinMaxEdges();
00719         newTriangleSet.computeBoundingCuboid();
00720     }
00721 
00722     if (newTriangleSet.triangles.size() == 0 || newTriangleSet.triangles.size() == triangles.size()) {
00723         return 0;
00724     }
00725 
00726     return 1;
00727 }
00728 
00729 template<typename T>
00730 int TriangleSet<T>::cutWithPlane (
00731         Plane<T> const& plane, Cuboid<T> const& cuboid, TriangleSet<T>& newTriangleSet ) const
00732 {
00733     T epsilon = getEpsilon<T>(precision);
00734 
00735     T norm_normal = norm(plane.normal);
00736     PLB_ASSERT(norm_normal > epsilon); // The cut plane normal vector cannot have zero magnitude.
00737     Plane<T> newPlane;
00738     newPlane.point = plane.point;
00739     newPlane.normal = plane.normal / norm_normal;
00740 
00741     T norm_diagonal = norm(cuboid.upperRightCorner - cuboid.lowerLeftCorner);
00742     PLB_ASSERT(norm_diagonal > epsilon); // The diagonal of the cuboid cannot have zero length.
00743 
00744     newTriangleSet.triangles.resize(0);
00745 
00746     newTriangleSet.precision = precision;
00747 
00748     for (pluint iTriangle = 0; iTriangle < triangles.size(); iTriangle++) {
00749         Triangle const& triangle = triangles[iTriangle];
00750 
00751         Array<T,3> vertices[3];
00752         vertices[0] = triangle[0];
00753         vertices[1] = triangle[1];
00754         vertices[2] = triangle[2];
00755 
00756         // Check if the triangle is fully contained in the cuboid.
00757         int isNotFullyContained = 0;
00758         for (int iVertex = 0; iVertex < 3; iVertex++) {
00759             Array<T,3> diff_l;
00760             diff_l = vertices[iVertex] - cuboid.lowerLeftCorner;
00761 
00762             Array<T,3> diff_u;
00763             diff_u = vertices[iVertex] - cuboid.upperRightCorner;
00764 
00765             if ((diff_l[0] < 0.0 && fabs(diff_l[0]) > epsilon) ||
00766                 (diff_l[1] < 0.0 && fabs(diff_l[1]) > epsilon) ||
00767                 (diff_l[2] < 0.0 && fabs(diff_l[2]) > epsilon) ||
00768                 (diff_u[0] > 0.0 && fabs(diff_u[0]) > epsilon) ||
00769                 (diff_u[1] > 0.0 && fabs(diff_u[1]) > epsilon) ||
00770                 (diff_u[2] > 0.0 && fabs(diff_u[2]) > epsilon)) {
00771                 isNotFullyContained = 1;
00772                 break;
00773             }
00774         }
00775 
00776         if (isNotFullyContained) {
00777             newTriangleSet.triangles.push_back(triangle);
00778             continue;
00779         }
00780 
00781         if (cutTriangleWithPlane(newPlane, triangle, newTriangleSet) == -1)
00782             return -1;
00783     }
00784 
00785     if (newTriangleSet.triangles.size() != 0) {
00786         newTriangleSet.computeMinMaxEdges();
00787         newTriangleSet.computeBoundingCuboid();
00788     }
00789 
00790     if (newTriangleSet.triangles.size() == 0 || newTriangleSet.triangles.size() == triangles.size()) {
00791         return 0;
00792     }
00793 
00794     return 1;
00795 }
00796 
00797 template<typename T>
00798 void TriangleSet<T>::computeMinMaxEdges() {
00799     T nextMin, nextMax;
00800     for (pluint i=0; i<triangles.size(); ++i) {
00801         computeMinMaxEdge(i, nextMin, nextMax);
00802         minEdgeLength = std::min(minEdgeLength, nextMin);
00803         maxEdgeLength = std::max(maxEdgeLength, nextMax);
00804     }
00805 }
00806 
00807 template<typename T>
00808 void TriangleSet<T>::computeMinMaxEdge(pluint iTriangle, T& minEdge, T& maxEdge) const {
00809     PLB_ASSERT( iTriangle<triangles.size() );
00810     Triangle const& triangle = triangles[iTriangle];
00811     T edge1 = norm(triangle[1]-triangle[0]);
00812     T edge2 = norm(triangle[2]-triangle[1]);
00813     T edge3 = norm(triangle[0]-triangle[2]);
00814     minEdge = std::min(edge1, std::min(edge2, edge3));
00815     maxEdge = std::max(edge1, std::max(edge2, edge3));
00816 }
00817 
00818 template<typename T>
00819 void TriangleSet<T>::computeBoundingCuboid() {
00820     T xMin, yMin, zMin;
00821     T xMax, yMax, zMax;
00822 
00823     xMin = yMin = zMin =  std::numeric_limits<T>::max();
00824     xMax = yMax = zMax = -std::numeric_limits<T>::max();
00825     for (pluint i=0; i<triangles.size(); ++i) {
00826         Triangle const& triangle = triangles[i];
00827 
00828         xMin = std::min(xMin, std::min(triangle[0][0], std::min(triangle[1][0], triangle[2][0])));
00829         yMin = std::min(yMin, std::min(triangle[0][1], std::min(triangle[1][1], triangle[2][1])));
00830         zMin = std::min(zMin, std::min(triangle[0][2], std::min(triangle[1][2], triangle[2][2])));
00831 
00832         xMax = std::max(xMax, std::max(triangle[0][0], std::max(triangle[1][0], triangle[2][0])));
00833         yMax = std::max(yMax, std::max(triangle[0][1], std::max(triangle[1][1], triangle[2][1])));
00834         zMax = std::max(zMax, std::max(triangle[0][2], std::max(triangle[1][2], triangle[2][2])));
00835     }
00836     boundingCuboid.lowerLeftCorner  = Array<T,3>(xMin, yMin, zMin);
00837     boundingCuboid.upperRightCorner = Array<T,3>(xMax, yMax, zMax);
00838 }
00839 
00840 } // namespace plb
00841 
00842 #endif  // TRIANGLE_SET_HH