OpenWalnut  1.4.0
WGEGeometryUtils.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <map>
00026 #include <string>
00027 #include <vector>
00028 
00029 #include <osg/Array>
00030 #include <osgUtil/DelaunayTriangulator>
00031 
00032 #include "WGEGeometryUtils.h"
00033 #include "WGEUtils.h"
00034 #include "WTriangleMesh.h"
00035 #include "exceptions/WGEException.h"
00036 
00037 osg::ref_ptr< osg::Vec3Array > wge::generateCuboidQuads( const std::vector< WPosition >& corners )
00038 {
00039     osg::ref_ptr< osg::Vec3Array > vertices = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array );
00040 
00041     // Surfaces
00042     vertices->push_back( corners[0] );
00043     vertices->push_back( corners[1] );
00044     vertices->push_back( corners[2] );
00045     vertices->push_back( corners[3] );
00046 
00047     vertices->push_back( corners[1] );
00048     vertices->push_back( corners[5] );
00049     vertices->push_back( corners[6] );
00050     vertices->push_back( corners[2] );
00051 
00052     vertices->push_back( corners[5] );
00053     vertices->push_back( corners[4] );
00054     vertices->push_back( corners[7] );
00055     vertices->push_back( corners[6] );
00056 
00057     vertices->push_back( corners[4] );
00058     vertices->push_back( corners[0] );
00059     vertices->push_back( corners[3] );
00060     vertices->push_back( corners[7] );
00061 
00062     vertices->push_back( corners[3] );
00063     vertices->push_back( corners[2] );
00064     vertices->push_back( corners[6] );
00065     vertices->push_back( corners[7] );
00066 
00067     vertices->push_back( corners[0] );
00068     vertices->push_back( corners[1] );
00069     vertices->push_back( corners[5] );
00070     vertices->push_back( corners[4] );
00071     return vertices;
00072 }
00073 
00074 osg::Vec3 wge::getQuadNormal( const WPosition& a,
00075                               const WPosition& b,
00076                               const WPosition& c )
00077 {
00078     WVector3d vec1 = a - b;
00079     WVector3d vec2 = c - b;
00080     WVector3d normal = cross( vec2, vec1 );
00081     return normalize( normal );
00082 }
00083 
00084 osg::ref_ptr< osg::Vec3Array > wge::generateCuboidQuadNormals( const std::vector< WPosition >& corners )
00085 {
00086     osg::ref_ptr< osg::Vec3Array > vertices = osg::ref_ptr< osg::Vec3Array >( new osg::Vec3Array );
00087 
00088     vertices->push_back( getQuadNormal( corners[0], corners[1], corners[2] ) );
00089     vertices->push_back( getQuadNormal( corners[1], corners[5], corners[6] ) );
00090     vertices->push_back( getQuadNormal( corners[5], corners[4], corners[7] ) );
00091     vertices->push_back( getQuadNormal( corners[4], corners[0], corners[3] ) );
00092     vertices->push_back( getQuadNormal( corners[3], corners[2], corners[6] ) );
00093     vertices->push_back( getQuadNormal( corners[0], corners[1], corners[5] ) );
00094     return vertices;
00095 }
00096 
00097 WTriangleMesh::SPtr wge::triangulate( const std::vector< WPosition >& points, double transformationFactor )
00098 {
00099     WAssert( points.size() > 2, "The Delaunay triangulation needs at least 3 vertices!" );
00100 
00101     osg::ref_ptr< osg::Vec3Array > osgPoints = wge::osgVec3Array( points );
00102 
00103     if( transformationFactor != 0.0 )
00104     {
00105         // Transform the points as described in the Doxygen description of
00106         // this function.
00107         osg::Vec3 centroid;
00108         for( std::size_t pointID = 0; pointID < osgPoints->size(); ++pointID )
00109         {
00110             centroid += (*osgPoints)[pointID];
00111         }
00112         centroid /= osgPoints->size();
00113 
00114         for( std::size_t pointID = 0; pointID < osgPoints->size(); ++pointID )
00115         {
00116             const double factor = ( (*osgPoints)[pointID].z() - centroid.z() ) * transformationFactor + 1.0;
00117             (*osgPoints)[pointID].x() = ( (*osgPoints)[pointID].x() - centroid.x() ) * factor + centroid.x();
00118             (*osgPoints)[pointID].y() = ( (*osgPoints)[pointID].y() - centroid.y() ) * factor + centroid.y();
00119         }
00120     }
00121 
00122     // The osg triangulator sorts the points and returns the triangles with
00123     // the indizes of the sorted points. Since we don't want to change the
00124     // sequence of the points, we have to save the original index of each
00125     // point.
00126     std::map< osg::Vec3, size_t > map;
00127     for( size_t index = 0; index < osgPoints->size(); ++index )
00128     {
00129         map[ (*osgPoints)[index] ] = index;
00130     }
00131 
00132     osg::ref_ptr< osgUtil::DelaunayTriangulator > triangulator( new osgUtil::DelaunayTriangulator( osgPoints ) );
00133 
00134     bool triangulationResult = triangulator->triangulate();
00135 
00136     WAssert( triangulationResult, "Something went wrong in triangulation." );
00137 
00138     osg::ref_ptr< const osg::DrawElementsUInt > osgTriangles( triangulator->getTriangles() );
00139     size_t nbTriangles = osgTriangles->size() / 3;
00140     std::vector<  size_t > triangles( osgTriangles->size()  );
00141     for( size_t triangleID = 0; triangleID < nbTriangles; ++triangleID )
00142     {
00143         // Convert the new index of the osgTriangle to the original
00144         // index stored in map.
00145         size_t vertID = triangleID * 3;
00146         triangles[vertID + 0] = map[ (*osgPoints)[ (*osgTriangles)[vertID + 0] ] ];
00147         triangles[vertID + 1] = map[ (*osgPoints)[ (*osgTriangles)[vertID + 1] ] ];
00148         triangles[vertID + 2] = map[ (*osgPoints)[ (*osgTriangles)[vertID + 2] ] ];
00149     }
00150 
00151     // I needed this reconversion using osgVec3Array because the triangulator changed my positions somehow.
00152     return WTriangleMesh::SPtr( new WTriangleMesh( wge::osgVec3Array( points ), triangles ) );
00153 }