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(
00105 std::vector<index_t> &IsoVertexEdge,
00106 std::vector<double> &IsoVertexWeight,
00107
00108
00109 std::vector<TriangleCell> &IsoSurfaceTriangles,
00110
00111
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
00125
00126
00127 int cubeindex = 0;
00128
00129 MultiIndex<3> VertexIndices[1<<3];
00130
00131 static const int VertexConvention[] =
00132 {
00133 0,
00134 1,
00135 3,
00136 2,
00137 4,
00138 5,
00139 7,
00140 6,
00141 };
00142
00143
00144
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
00154
00155 for(int i=0; i< (1<<3); i++)
00156 {
00157 MultiIndex<3> I = VertexIndices[i];
00158
00159
00160 if ( FE.isBelowThreshold( I ) )
00161 {
00162 cubeindex |= 1<<i;
00163 }
00164 }
00165
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
00196
00197
00198
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
00220
00221 int ntriang = 0;
00222 for (int i=0;triTable[cubeindex][i]!=-1; i+=3)
00223 {
00224
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
00271 const std::vector<index_t> &Edges,
00272 const std::vector<double> &Weights,
00273
00274
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
00314 MemCore::MemVector<index_t> IsoVertexEdge(0);
00315 MemCore::MemVector<double> IsoVertexWeight(0);
00316
00317
00318 MemCore::MemVector<TriangleCell> IsoSurfaceTriangles(0);
00319
00320
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
00362
00363 EvalVertexFieldOnEdges(IsoVertices.std_vector(),
00364
00365 IsoVertexEdge.std_vector(),
00366 IsoVertexWeight.std_vector(),
00367
00368
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 }
00387
00388 #endif