Isosurface.hpp

00001 #ifndef __BASEOP_ISOSURFACE_HPP
00002 #define __BASEOP_ISOSURFACE_HPP
00003 
00004 #include "gridopDllApi.h"
00005 
00006 #include <eagle/PhysicalSpace.hpp>
00007 
00008 #include <vector/MultiIndex.hpp>
00009 
00010 #include <field/Cell.hpp>
00011 
00012 #include <grid/Grid.hpp>
00013 #include <grid/CartesianChart.hpp>
00014 #include <grid/Topology.hpp>
00015 
00016 #include <bundle/Slice.hpp>
00017 
00018 namespace Fiber
00019 {
00020 
00021 template <class ArrayType>
00022 struct  FieldExplorer;
00023 
00024 template <int Dims, class ValueType>
00025 struct  FieldExplorer<MultiArray<Dims, ValueType> >
00026 {
00027         const MultiArray<Dims, ValueType>&Field;
00028         const ValueType                   Isolevel;
00029 
00030         FieldExplorer(const MultiArray<Dims, ValueType>&FieldData, const ValueType&Threshold)
00031         : Field(FieldData)
00032         , Isolevel(Threshold)
00033         {}
00034 
00035         bool    isBelowThreshold(const MultiIndex<Dims>&I) const
00036         {
00037                 return Field[ I ] < Isolevel;
00038         }
00039 
00040         template <class ResultType>
00041         ResultType InterpolationWeight(const MultiIndex<Dims>&FirstVertex, const MultiIndex<Dims>&SecondVertex,
00042                                        const ResultType&precision) const
00043         {
00044         const ValueType &P1 = Field[ FirstVertex  ],
00045                         &P2 = Field[ SecondVertex ]; 
00046 
00047                 if ( fabs(Isolevel - P1) < precision)
00048                         return 0.0; 
00049 
00050                 if ( fabs(Isolevel - P2) < precision)
00051                         return 1.0; 
00052 
00053                 ValueType dP = P2-P1; 
00054                         if ( fabs(dP) < precision)
00055                                 return 0.0; 
00056 
00057                 return (Isolevel - P1) / dP;
00058         }
00059 
00060 };
00061 
00066 template <class ValueType, int Dims, class ResultType>
00067 void    ComputeInterpolationEdgeAndWeight(index_t&EdgeID,
00068                                           int    &EdgeOrientation,
00069                                           ResultType&Weight,
00070                                           const FieldExplorer<MultiArray<Dims, ValueType> >&FE,
00071                                           const MultiIndex<Dims>&FirstVertex, const MultiIndex<Dims>&SecondVertex,
00072                                           const ResultType&precision)
00073 {
00074 MultiIndex<Dims> EdgeDir = SecondVertex - FirstVertex;
00075 MultiIndex<Dims> IndexDifference = distance(SecondVertex, FirstVertex); 
00076 
00077         EdgeOrientation =  FirstVertex.getSignedOrientation(SecondVertex);
00078         assert( EdgeOrientation != 0 ); 
00079 
00080         if (EdgeOrientation<0)
00081         {
00082                 EdgeOrientation = -EdgeOrientation;
00083                 EdgeID = ComputeEdgeIDfromVertexAndOrientation(SecondVertex, EdgeOrientation-1, FE.Field.Size() ); 
00084                 assert( EdgeID < NumberOfEdges( FE.Field.Size() ));
00085                 Weight = 1.0 - FE.InterpolationWeight(FirstVertex, SecondVertex, precision);
00086         } 
00087         else
00088         {
00089                 EdgeID = ComputeEdgeIDfromVertexAndOrientation(FirstVertex, EdgeOrientation -1, FE.Field.Size() ); 
00090                 assert( EdgeID < NumberOfEdges( FE.Field.Size() ));
00091                 Weight = FE.InterpolationWeight(FirstVertex, SecondVertex, precision);
00092         }
00093 }
00094 
00095 extern gridop_API const int edgeTable[256];
00096 extern gridop_API const int triTable[256][16];
00097 
00103 template <class ArrayType>
00104 inline int      Polygonize(// data given per iso vertex
00105                            std::vector<index_t>       &IsoVertexEdge,
00106                            std::vector<double>        &IsoVertexWeight,
00107 
00108                            // data given per iso triangle
00109                            std::vector<TriangleCell>    &IsoSurfaceTriangles,
00110 
00111                            // internal collector
00112                            map<index_t, index_t>        &IsosurfaceVerticesAsEdges,
00113 
00115                            const FieldExplorer<ArrayType>&FE,
00116 
00117                            const MultiIndex<3>&CellIndex,
00118                            double  precision,
00119                            index_t EdgeOffset = 0)
00120 {
00121 typedef map<index_t, index_t>   IsosurfaceVerticesAsEdges_t;
00122 
00123         /*
00124           Determine the index into the edge table which
00125           tells us which vertices are inside of the surface
00126         */
00127 int     cubeindex = 0;
00128 
00129 MultiIndex<3> VertexIndices[1<<3];
00130 
00131 static  const int VertexConvention[] =
00132 {
00133 0, // 0,0,0
00134 1, // 1,0,0
00135 3, // 0,1,0
00136 2, // 1,1,0
00137 4, // 0,0,1
00138 5, // 1,0,1
00139 7, // 1,1,0
00140 6, // 1,1,1
00141 }; 
00142 
00143 //
00144 // Build up mapping from vertex number (counted) to vertex index (computed) 
00145 //
00146         for(int i=0; i< (1<<3); i++)
00147         {
00148         MultiIndex<3> I = CellIndex + MultiIndex<3>::BitIndex(i); 
00149                 VertexIndices[ VertexConvention[i] ] = I;
00150         } 
00151 
00152 // 
00153 //  Compute edge bitmap 
00154 //
00155         for(int i=0; i< (1<<3); i++)
00156         {
00157         MultiIndex<3> I = VertexIndices[i]; 
00158 
00159 //              if ( ScalarField[ I ] < Isolevel )
00160                 if ( FE.isBelowThreshold( I ) )
00161                 {
00162                         cubeindex |= 1<<i;
00163                 }
00164         } 
00165         /* Cube is entirely in/out of the surface */
00166         if (edgeTable[cubeindex] == 0)
00167                 return 0; 
00168 
00169 index_t Edges[12] = { -1u, -1u, -1u, -1u,
00170                       -1u, -1u, -1u, -1u,
00171                       -1u, -1u, -1u, -1u };
00172 
00173 int     EdgeOrientations[12];
00174 double  Weights[12];
00175 
00176 static  int EdgeVertices[12][2] = {
00177 {0,1},
00178 {1,2},
00179 {2,3},
00180 {3,0},
00181 
00182 {4,5},
00183 {5,6},
00184 {6,7},
00185 {7,4},
00186 
00187 {0,4},
00188 {1,5},
00189 {2,6},
00190 {3,7}
00191 };
00192 
00193 int     Nints = 0; 
00194 
00195         // Compute Edges array 
00196 
00197         // 
00198         // Find the edges where the surface intersects the cube 
00199         //
00200         for(int E=0; E<12; E++)
00201         {
00202                 if (edgeTable[cubeindex] & (1<<E) )
00203                 {
00204                 int edge = E; 
00205 
00206                 MultiIndex<3> V0 = VertexIndices[ EdgeVertices[edge][0] ],
00207                               V1 = VertexIndices[ EdgeVertices[edge][1] ];
00208 
00209                         Nints++;
00210 
00211                         ComputeInterpolationEdgeAndWeight(Edges[edge], EdgeOrientations[edge], Weights[edge],
00212                                                           FE,
00213                                                           V0, V1,
00214                                                           precision);
00215                 }
00216         } 
00217 
00218         // 
00219         // Create and the triangles
00220         //
00221 int     ntriang = 0;
00222         for (int i=0;triTable[cubeindex][i]!=-1; i+=3) 
00223         {
00224                 // Indices in locale Edge/Weights table
00225         int     I[3] = { triTable[cubeindex][i  ],
00226                          triTable[cubeindex][i+1],
00227                          triTable[cubeindex][i+2] };
00228 
00229         TriangleCell Triangle;
00230                 for(int k=0; k<3; k++)
00231                 {
00232                 int     LocalEdge = I[k];
00233                         assert( LocalEdge <12 );
00234                 index_t edge = Edges[ LocalEdge ] + EdgeOffset;
00235 
00236                 index_t SurfaceVertexIndex;
00237         
00238                 IsosurfaceVerticesAsEdges_t::const_iterator it =
00239                         IsosurfaceVerticesAsEdges.find( edge ); 
00240                         if (it == IsosurfaceVerticesAsEdges.end() ) 
00241                         {
00242                                 SurfaceVertexIndex = IsoVertexEdge.size();
00243                                 IsosurfaceVerticesAsEdges[ edge ] = SurfaceVertexIndex;
00244 
00245                                 IsoVertexEdge           .push_back( edge );
00246 
00247                                 assert(EdgeOrientations[ LocalEdge ] > 0);
00248                                 IsoVertexWeight         .push_back( Weights[ LocalEdge ] ); 
00249                         }
00250                         else
00251                         {
00252                                 SurfaceVertexIndex = it->second;
00253                         }
00254                         Triangle[ k ] = SurfaceVertexIndex;
00255                 }
00256                 IsoSurfaceTriangles.push_back( Triangle );
00257 
00258                 ntriang++;
00259         }
00260         return ntriang;
00261 }
00262 
00268 template <class VertexFieldType>
00269 inline void     EvalVertexFieldOnEdges(std::vector<typename VertexFieldType::value_type>&EvaluatedField,
00270                                        // data given per vertex
00271                                        const std::vector<index_t>    &Edges,
00272                                        const std::vector<double>     &Weights,
00273 
00274                                        // original vertex field
00275                                        const VertexFieldType&RegularField,
00276                                        const MultiIndex<3>&FragmentSize,
00277                                        const MultiIndex<3>&FragmentOffset,
00278 
00279                                        index_t  StartEvaluationAtVertex = 0,
00280                                        index_t  EdgeOffset = 0)
00281 {
00282         enum { Dims = VertexFieldType::Dims };
00283         typedef typename VertexFieldType::value_type value_type;
00284 
00285         EvaluatedField.resize( Edges.size() );
00286 
00287         for(index_t i = StartEvaluationAtVertex; i<Edges.size(); i++)
00288         {
00289         index_t EdgeIndex = Edges[i] - EdgeOffset;
00290 
00291         std::pair<MultiIndex<3>, MultiIndex<3> > Edge =
00292                 ComputeEdgeVertices(EdgeIndex, FragmentSize );
00293 
00294         const   value_type&P0 = RegularField[ Edge.first  + FragmentOffset ], 
00295                           &P1 = RegularField[ Edge.second + FragmentOffset ];
00296 
00297         double  w = Weights[ i ];
00298 
00299                 EvaluatedField[ i ] = P0 + w*(P1-P0);
00300         }
00301 }
00302 
00303 
00304 
00305 typedef std::pair<RefPtr<MemArray<1, ::Eagle::PhysicalSpace::point> >, RefPtr<MemArray<1, TriangleCell> > > TriangleSurface_t;
00306 
00307 template <class VertexField_t, class ArrayType>
00308 inline gridop_API TriangleSurface_t
00309         ComputeIsosurfaceT(const FieldExplorer<ArrayType>&FE,
00310                            const VertexField_t&VertexField,
00311                            double precision)
00312 {
00313         // data given per iso vertex
00314 MemCore::MemVector<index_t>             IsoVertexEdge(0);
00315 MemCore::MemVector<double>              IsoVertexWeight(0);
00316 
00317         // data given per iso triangle 
00318 MemCore::MemVector<TriangleCell>        IsoSurfaceTriangles(0);
00319 
00320         // internal collector
00321 map<index_t, index_t>                   IsosurfaceVerticesAsEdges;
00322 
00323 MultiIndex<3> NumberOfCells = FE.Field.Size() - MIndex(1,1,1);
00324 MultiIndex<3> CellIndex;
00325 
00326         try
00327         {
00328                 do
00329                 {
00330                         Polygonize(IsoVertexEdge,
00331                                    IsoVertexWeight,
00332                                    IsoSurfaceTriangles,
00333         
00334                                    IsosurfaceVerticesAsEdges,
00335         
00336                                    FE,
00337                                    CellIndex,
00338                                    precision);
00339                 }
00340                 while(  CellIndex.inc( NumberOfCells ) );
00341         }
00342         catch(...)
00343         {
00344                 printf("ComputeIsosurfaceT(): INTERNAL ERROR\n"); fflush(stdout);
00345                 throw;
00346         } 
00347 
00348 MemBase::Creator_t Crec;
00349 
00350 RefPtr<MemBase>
00351         IsoVertexEdgeM = makeMemArray1D( IsoVertexEdge  , Crec ),
00352         IsoVertexEdgeW = makeMemArray1D( IsoVertexWeight, Crec ),
00353 
00354         IsoTriangleM   = makeMemArray1D( IsoSurfaceTriangles, Crec ); 
00355 
00357 
00358 MemCore::MemVector< ::Eagle::PhysicalSpace::point>
00359         IsoVertices( IsoVertexEdge.size() ); 
00360 
00361 //      ComputeVertices 
00362 
00363         EvalVertexFieldOnEdges(IsoVertices.std_vector(),
00364                         // data given per iso vertex
00365                                IsoVertexEdge.std_vector(),
00366                                IsoVertexWeight.std_vector(),
00367                                
00368                         // original vertex field
00369                                VertexField,
00370                                VertexField.Size(),
00371                                MIndex(0,0,0)      );
00372 
00373         return TriangleSurface_t( makeMemArray1D( IsoVertices, Crec ),
00374                                   IsoTriangleM);
00375 }
00376 
00377 
00378 
00379 extern gridop_API
00380 TriangleSurface_t ComputeIsosurface(double Isolevel,
00381                                     const MultiArray<3,double>&ScalarField,
00382                                     const MultiArray<3,::Eagle::PhysicalSpace::point>&VertexField,
00383                                     double precision);
00384 
00385 
00386 } // namespace Fiber
00387 
00388 #endif