GDCM 2.0.17

gdcmElement.h

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Program: GDCM (Grassroots DICOM). A DICOM library
00004   Module:  $URL$
00005 
00006   Copyright (c) 2006-2010 Mathieu Malaterre
00007   All rights reserved.
00008   See Copyright.txt or http://gdcm.sourceforge.net/Copyright.html for details.
00009 
00010      This software is distributed WITHOUT ANY WARRANTY; without even
00011      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00012      PURPOSE.  See the above copyright notice for more information.
00013 
00014 =========================================================================*/
00015 #ifndef GDCMELEMENT_H
00016 #define GDCMELEMENT_H
00017 
00018 #include "gdcmTypes.h"
00019 #include "gdcmVR.h"
00020 #include "gdcmTag.h"
00021 #include "gdcmVM.h"
00022 #include "gdcmByteValue.h"
00023 #include "gdcmDataElement.h"
00024 #include "gdcmSwapper.h"
00025 
00026 #include <string>
00027 #include <vector>
00028 #include <sstream>
00029 #include <limits>
00030 #include <cmath>
00031 
00032 namespace gdcm
00033 {
00034 
00035 // Forward declaration
00041 template<int T> class EncodingImplementation;
00042 
00048 template<int TVR, int TVM>
00049 class Element
00050 {
00051 public:
00052   typename VRToType<TVR>::Type Internal[VMToLength<TVM>::Length];
00053   typedef typename VRToType<TVR>::Type Type;
00054 
00055   unsigned long GetLength() const {
00056     return VMToLength<TVM>::Length;
00057   }
00058   // Implementation of Print is common to all Mode (ASCII/Binary)
00059   // TODO: Can we print a \ when in ASCII...well I don't think so
00060   // it would mean we used a bad VM then, right ?
00061   void Print(std::ostream &_os) const {
00062     _os << Internal[0]; // VM is at least garantee to be one
00063     for(int i=1; i<VMToLength<TVM>::Length; ++i)
00064       _os << "," << Internal[i];
00065     }
00066 
00067   const typename VRToType<TVR>::Type *GetValues() const {
00068     return Internal;
00069   }
00070   const typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) const {
00071     assert( idx < VMToLength<TVM>::Length );
00072     return Internal[idx];
00073   }
00074   typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) {
00075     assert( idx < VMToLength<TVM>::Length );
00076     return Internal[idx];
00077   }
00078   typename VRToType<TVR>::Type operator[] (unsigned int idx) const {
00079     return GetValue(idx);
00080   }
00081   void SetValue(typename VRToType<TVR>::Type v, unsigned int idx = 0) {
00082     assert( idx < VMToLength<TVM>::Length );
00083     Internal[idx] = v;
00084   }
00085 
00086   void SetFromDataElement(DataElement const &de) {
00087     const ByteValue *bv = de.GetByteValue();
00088     if( !bv ) return;
00089 #ifdef GDCM_WORDS_BIGENDIAN
00090     if( de.GetVR() == VR::UN /*|| de.GetVR() == VR::INVALID*/ )
00091 #else
00092     if( de.GetVR() == VR::UN || de.GetVR() == VR::INVALID )
00093 #endif
00094       {
00095       Set(de.GetValue());
00096       }
00097     else
00098       {
00099       SetNoSwap(de.GetValue());
00100       }
00101   }
00102 
00103   void Read(std::istream &_is) {
00104     return EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
00105       GetLength(),_is);
00106     }
00107   void Write(std::ostream &_os) const {
00108     return EncodingImplementation<VRToEncoding<TVR>::Mode>::Write(Internal,
00109       GetLength(),_os);
00110     }
00111 
00112   // FIXME: remove this function
00113   // this is only used in gdcm::SplitMosaicFilter / to pass value of a CSAElement
00114   void Set(Value const &v) {
00115     const ByteValue *bv = dynamic_cast<const ByteValue*>(&v);
00116     if( bv ) {
00117       //memcpy(Internal, bv->GetPointer(), bv->GetLength());
00118       std::stringstream ss;
00119       std::string s = std::string( bv->GetPointer(), bv->GetLength() );
00120       ss.str( s );
00121       EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
00122         GetLength(),ss);
00123     }
00124   }
00125 protected:
00126   void SetNoSwap(Value const &v) {
00127     const ByteValue *bv = dynamic_cast<const ByteValue*>(&v);
00128     assert( bv ); // That would be bad...
00129     //memcpy(Internal, bv->GetPointer(), bv->GetLength());
00130     std::stringstream ss;
00131     std::string s = std::string( bv->GetPointer(), bv->GetLength() );
00132     ss.str( s );
00133     EncodingImplementation<VRToEncoding<TVR>::Mode>::ReadNoSwap(Internal,
00134       GetLength(),ss);
00135   }
00136 };
00137 
00138 struct ignore_char {
00139   ignore_char(char c): m_char(c) {}
00140   char m_char;
00141 };
00142 ignore_char const backslash('\\');
00143 
00144   inline std::istream& operator>> (std::istream& in, ignore_char const& ic) {
00145     if (!in.eof())
00146       in.clear(in.rdstate() & ~std::ios_base::failbit);
00147     if (in.get() != ic.m_char)
00148       in.setstate(std::ios_base::failbit);
00149     return in;
00150   }
00151 
00152 
00153 // Implementation to perform formatted read and write
00154 template<> class EncodingImplementation<VR::VRASCII> {
00155 public:
00156   template<typename T> // FIXME this should be VRToType<TVR>::Type
00157   static inline void ReadComputeLength(T* data, unsigned int &length,
00158                           std::istream &_is) {
00159     assert( data );
00160     //assert( length ); // != 0
00161     length = 0;
00162     assert( _is );
00163 #if 0
00164     char sep;
00165     while( _is >> data[length++] )
00166       {
00167       // Get the separator in between the values
00168       assert( _is );
00169       _is.get(sep);
00170       assert( sep == '\\' || sep == ' ' ); // FIXME: Bad use of assert
00171       if( sep == ' ' ) length--; // FIXME
00172       }
00173 #else
00174   while( _is >> std::ws >> data[length++] >> std::ws >> backslash )
00175     {
00176     }
00177 #endif
00178     }
00179 
00180   template<typename T> // FIXME this should be VRToType<TVR>::Type
00181   static inline void Read(T* data, unsigned long length,
00182                           std::istream &_is) {
00183     assert( data );
00184     assert( length ); // != 0
00185     assert( _is );
00186     // FIXME BUG: what if >> operation fails ?
00187     // gdcmData/MR00010001.dcm / SpacingBetweenSlices
00188     _is >> std::ws >> data[0];
00189     char sep;
00190     //std::cout << "GetLength: " << af->GetLength() << std::endl;
00191     for(unsigned long i=1; i<length;++i) {
00192       assert( _is );
00193       // Get the separator in between the values
00194       _is >> std::ws >> sep; //_is.get(sep);
00195       assert( sep == '\\' ); // FIXME: Bad use of assert
00196       _is >> std::ws >> data[i];
00197       }
00198     }
00199 
00200   template<typename T>
00201   static inline void ReadNoSwap(T* data, unsigned long length,
00202                           std::istream &_is) {
00203     Read(data,length,_is);
00204 }
00205   template<typename T>
00206   static inline void Write(const T* data, unsigned long length,
00207                            std::ostream &_os)  {
00208     assert( data );
00209     assert( length );
00210     assert( _os );
00211     _os << data[0];
00212     for(unsigned long i=1; i<length; ++i) {
00213       assert( _os );
00214       _os << "\\" << data[i];
00215       }
00216     }
00217 };
00218 
00219 template < typename Float >
00220 std::string to_string ( Float data ) {
00221   std::stringstream in;
00222   // in.imbue(std::locale::classic()); // This is not required AFAIK
00223   unsigned long const digits =
00224     static_cast< unsigned long >(
00225     - std::log( std::numeric_limits<Float>::epsilon() )
00226     / std::log( 10.0 ) );
00227   if ( in << std::dec << std::setprecision(/*2+*/digits) << data ) {
00228     return ( in.str() );
00229   } else {
00230     throw "Impossible Conversion"; // should not happen ...
00231   }
00232 }
00233 
00234 /* Writing VR::DS is not that easy after all */
00235 // http://groups.google.com/group/comp.lang.c++/browse_thread/thread/69ccd26f000a0802
00236 template<> inline void EncodingImplementation<VR::VRASCII>::Write(const float * data, unsigned long length, std::ostream &_os)  {
00237     assert( data );
00238     assert( length );
00239     assert( _os );
00240     _os << to_string(data[0]);
00241     for(unsigned long i=1; i<length; ++i) {
00242       assert( _os );
00243       _os << "\\" << to_string(data[i]);
00244       }
00245     }
00246 
00247 template<> inline void EncodingImplementation<VR::VRASCII>::Write(const double* data, unsigned long length, std::ostream &_os)  {
00248     assert( data );
00249     assert( length );
00250     assert( _os );
00251     _os << to_string(data[0]);
00252     for(unsigned long i=1; i<length; ++i) {
00253       assert( _os );
00254       _os << "\\" << to_string(data[i]);
00255       }
00256     }
00257 
00258 
00259 // Implementation to perform binary read and write
00260 // TODO rewrite operation so that either:
00261 // #1. dummy implementation use a pointer to Internal and do ++p (faster)
00262 // #2. Actually do some meta programming to unroll the loop
00263 // (no notion of order in VM ...)
00264 template<> class EncodingImplementation<VR::VRBINARY> {
00265 public:
00266   template<typename T> // FIXME this should be VRToType<TVR>::Type
00267     static inline void ReadComputeLength(T* data, unsigned int &length,
00268       std::istream &_is) {
00269     const unsigned int type_size = sizeof(T);
00270     assert( data ); // Can we read from pointer ?
00271     //assert( length );
00272     length /= type_size;
00273     assert( _is ); // Is stream valid ?
00274     _is.read( reinterpret_cast<char*>(data+0), type_size);
00275     for(unsigned long i=1; i<length; ++i) {
00276       assert( _is );
00277       _is.read( reinterpret_cast<char*>(data+i), type_size );
00278     }
00279     }
00280   template<typename T>
00281   static inline void ReadNoSwap(T* data, unsigned long length,
00282     std::istream &_is) {
00283     const unsigned int type_size = sizeof(T);
00284     assert( data ); // Can we read from pointer ?
00285     assert( length );
00286     assert( _is ); // Is stream valid ?
00287     _is.read( reinterpret_cast<char*>(data+0), type_size);
00288     for(unsigned long i=1; i<length; ++i) {
00289       assert( _is );
00290       _is.read( reinterpret_cast<char*>(data+i), type_size );
00291     }
00292     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem(data,
00293     //  _is.GetSwapCode(), length);
00294     //SwapperNoOp::SwapArray(data,length);
00295   }
00296   template<typename T>
00297   static inline void Read(T* data, unsigned long length,
00298     std::istream &_is) {
00299     const unsigned int type_size = sizeof(T);
00300     assert( data ); // Can we read from pointer ?
00301     assert( length );
00302     assert( _is ); // Is stream valid ?
00303     _is.read( reinterpret_cast<char*>(data+0), type_size);
00304     for(unsigned long i=1; i<length; ++i) {
00305       assert( _is );
00306       _is.read( reinterpret_cast<char*>(data+i), type_size );
00307     }
00308     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem(data,
00309     //  _is.GetSwapCode(), length);
00310     SwapperNoOp::SwapArray(data,length);
00311   }
00312   template<typename T>
00313   static inline void Write(const T* data, unsigned long length,
00314     std::ostream &_os) {
00315     const unsigned int type_size = sizeof(T);
00316     assert( data ); // Can we write into pointer ?
00317     assert( length );
00318     assert( _os ); // Is stream valid ?
00319     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem((T*)data,
00320     //  _os.GetSwapCode(), length);
00321     T swappedData = SwapperNoOp::Swap(data[0]);
00322     _os.write( reinterpret_cast<const char*>(&swappedData), type_size);
00323     for(unsigned long i=1; i<length;++i) {
00324       assert( _os );
00325       swappedData = SwapperNoOp::Swap(data[i]);
00326       _os.write( reinterpret_cast<const char*>(&swappedData), type_size );
00327     }
00328     //ByteSwap<T>::SwapRangeFromSwapCodeIntoSystem((T*)data,
00329     //  _os.GetSwapCode(), length);
00330   }
00331 };
00332 
00333 // For particular case for ASCII string
00334 // WARNING: This template explicitely instanciates a particular
00335 // EncodingImplementation THEREFORE it is required to be declared after the
00336 // EncodingImplementation is needs (doh!)
00337 #if 0
00338 template<int TVM>
00339 class Element<TVM>
00340 {
00341 public:
00342   Element(const char array[])
00343     {
00344     unsigned int i = 0;
00345     const char sep = '\\';
00346     std::string sarray = array;
00347     std::string::size_type pos1 = 0;
00348     std::string::size_type pos2 = sarray.find(sep, pos1+1);
00349     while(pos2 != std::string::npos)
00350       {
00351       Internal[i++] = sarray.substr(pos1, pos2-pos1);
00352       pos1 = pos2+1;
00353       pos2 = sarray.find(sep, pos1+1);
00354       }
00355     Internal[i] = sarray.substr(pos1, pos2-pos1);
00356     // Shouldn't we do the contrary, since we know how many separators
00357     // (and default behavior is to discard anything after the VM declared
00358     assert( GetLength()-1 == i );
00359     }
00360 
00361   unsigned long GetLength() const {
00362     return VMToLength<TVM>::Length;
00363   }
00364   // Implementation of Print is common to all Mode (ASCII/Binary)
00365   void Print(std::ostream &_os) const {
00366     _os << Internal[0]; // VM is at least garantee to be one
00367     for(int i=1; i<VMToLength<TVM>::Length; ++i)
00368       _os << "," << Internal[i];
00369     }
00370 
00371   void Read(std::istream &_is) {
00372     EncodingImplementation<VR::VRASCII>::Read(Internal, GetLength(),_is);
00373     }
00374   void Write(std::ostream &_os) const {
00375     EncodingImplementation<VR::VRASCII>::Write(Internal, GetLength(),_os);
00376     }
00377 private:
00378   typename String Internal[VMToLength<TVM>::Length];
00379 };
00380 
00381 template< int TVM>
00382 class Element<VR::PN, TVM> : public StringElement<TVM>
00383 {
00384 };
00385 #endif
00386 
00387 // Implementation for the undefined length (dynamically allocated array)
00388 template<int TVR>
00389 class Element<TVR, VM::VM1_n>
00390 {
00391 public:
00392   // This the way to prevent default initialization
00393   explicit Element() { Internal=0; Length=0; Save = false; }
00394   ~Element() {
00395     if( Save ) {
00396       delete[] Internal;
00397     }
00398     Internal = 0;
00399   }
00400 
00401   // Length manipulation
00402   // SetLength should really be protected anyway...all operation
00403   // should go through SetArray
00404   unsigned long GetLength() const { return Length; }
00405   typedef typename VRToType<TVR>::Type Type;
00406 
00407   void SetLength(unsigned long len) {
00408     const unsigned int size = sizeof(Type);
00409     if( len ) {
00410       if( len > Length ) {
00411         // perform realloc
00412         assert( (len / size) * size == len );
00413         Type *internal = new Type[len / size];
00414         assert( Save == false );
00415         Save = true; // ????
00416         if( Internal )
00417           {
00418           memcpy(internal, Internal, len);
00419           delete[] Internal;
00420           }
00421         Internal = internal;
00422         }
00423       }
00424     Length = len / size;
00425   }
00426 
00427   // If save is set to zero user should not delete the pointer
00428   //void SetArray(const typename VRToType<TVR>::Type *array, int len, bool save = false)
00429   void SetArray(const Type *array, unsigned long len,
00430     bool save = false) {
00431     if( save ) {
00432       SetLength(len); // realloc
00433       memcpy(Internal, array, len/*/sizeof(Type)*/);
00434       assert( Save == false );
00435       }
00436     else {
00437       // TODO rewrite this stupid code:
00438       assert( Length == 0 );
00439       assert( Internal == 0 );
00440       assert( Save == false );
00441       Length = len / sizeof(Type);
00442       //assert( (len / sizeof(Type)) * sizeof(Type) == len );
00443       // MR00010001.dcm is a tough kid: 0019,105a is supposed to be VR::FL, VM::VM3 but
00444       // length is 14 bytes instead of 12 bytes. Simply consider value is total garbage.
00445       if( (len / sizeof(Type)) * sizeof(Type) != len ) { Internal = 0; Length = 0; }
00446       else Internal = const_cast<Type*>(array);
00447       }
00448       Save = save;
00449   }
00450   void SetValue(typename VRToType<TVR>::Type v, unsigned int idx = 0) {
00451     assert( idx < Length );
00452     Internal[idx] = v;
00453   }
00454   const typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) const {
00455     assert( idx < Length );
00456     return Internal[idx];
00457   }
00458   typename VRToType<TVR>::Type &GetValue(unsigned int idx = 0) {
00459     assert( idx < Length );
00460     return Internal[idx];
00461   }
00462   typename VRToType<TVR>::Type operator[] (unsigned int idx) const {
00463     return GetValue(idx);
00464   }
00465   void Set(Value const &v) {
00466     const ByteValue *bv = dynamic_cast<const ByteValue*>(&v);
00467     assert( bv ); // That would be bad...
00468     if( (VR::VRType)(VRToEncoding<TVR>::Mode) == VR::VRBINARY )
00469       {
00470       const Type* array = (Type*)bv->GetPointer();
00471       if( array ) {
00472         assert( array ); // That would be bad...
00473         assert( Internal == 0 );
00474         SetArray(array, bv->GetLength() ); }
00475       }
00476     else
00477       {
00478       std::stringstream ss;
00479       std::string s = std::string( bv->GetPointer(), bv->GetLength() );
00480       ss.str( s );
00481       EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
00482         GetLength(),ss);
00483       }
00484   }
00485   void SetFromDataElement(DataElement const &de) {
00486     const ByteValue *bv = de.GetByteValue();
00487     if( !bv ) return;
00488 #ifdef GDCM_WORDS_BIGENDIAN
00489     if( de.GetVR() == VR::UN /*|| de.GetVR() == VR::INVALID*/ )
00490 #else
00491     if( de.GetVR() == VR::UN || de.GetVR() == VR::INVALID )
00492 #endif
00493       {
00494       Set(de.GetValue());
00495       }
00496     else
00497       {
00498       SetNoSwap(de.GetValue());
00499       }
00500   }
00501 
00502 
00503   // Need to be placed after definition of EncodingImplementation<VR::VRASCII>
00504   void WriteASCII(std::ostream &os) const {
00505     return EncodingImplementation<VR::VRASCII>::Write(Internal, GetLength(), os);
00506     }
00507 
00508   // Implementation of Print is common to all Mode (ASCII/Binary)
00509   void Print(std::ostream &_os) const {
00510     assert( Length );
00511     assert( Internal );
00512     _os << Internal[0]; // VM is at least garantee to be one
00513     const unsigned long length = GetLength() < 25 ? GetLength() : 25;
00514     for(unsigned long i=1; i<length; ++i)
00515       _os << "," << Internal[i];
00516     }
00517   void Read(std::istream &_is) {
00518     if( !Internal ) return;
00519     EncodingImplementation<VRToEncoding<TVR>::Mode>::Read(Internal,
00520       GetLength(),_is);
00521     }
00522   //void ReadComputeLength(std::istream &_is) {
00523   //  if( !Internal ) return;
00524   //  EncodingImplementation<VRToEncoding<TVR>::Mode>::ReadComputeLength(Internal,
00525   //    Length,_is);
00526   //  }
00527   void Write(std::ostream &_os) const {
00528     EncodingImplementation<VRToEncoding<TVR>::Mode>::Write(Internal,
00529       GetLength(),_os);
00530     }
00531 
00532   DataElement GetAsDataElement() const {
00533     DataElement ret;
00534     ret.SetVR( (VR::VRType)TVR );
00535     if( Internal )
00536       {
00537       std::ostringstream os;
00538       EncodingImplementation<VRToEncoding<TVR>::Mode>::Write(Internal,
00539         GetLength(),os);
00540       ret.SetByteValue( os.str().c_str(), os.str().size() );
00541       }
00542     return ret;
00543   }
00544 
00545   Element(const Element&_val) {
00546     if( this != &_val) {
00547       *this = _val;
00548       }
00549     }
00550 
00551   Element &operator=(const Element &_val) {
00552     Length = 0; // SYITF
00553     Internal = 0;
00554     SetArray(_val.Internal, _val.Length, true);
00555     return *this;
00556     }
00557 protected:
00558   void SetNoSwap(Value const &v) {
00559     const ByteValue *bv = dynamic_cast<const ByteValue*>(&v);
00560     assert( bv ); // That would be bad...
00561     if( (VR::VRType)(VRToEncoding<TVR>::Mode) == VR::VRBINARY )
00562       {
00563       const Type* array = (Type*)bv->GetPointer();
00564       if( array ) {
00565         assert( array ); // That would be bad...
00566         assert( Internal == 0 );
00567         SetArray(array, bv->GetLength() ); }
00568       }
00569     else
00570       {
00571       std::stringstream ss;
00572       std::string s = std::string( bv->GetPointer(), bv->GetLength() );
00573       ss.str( s );
00574       EncodingImplementation<VRToEncoding<TVR>::Mode>::ReadNoSwap(Internal,
00575         GetLength(),ss);
00576       }
00577   }
00578 
00579 private:
00580   typename VRToType<TVR>::Type *Internal;
00581   unsigned long Length; // unsigned int ??
00582   bool Save;
00583 };
00584 
00585 //template <int TVM = VM::VM1_n>
00586 //class Element<VR::OB, TVM > : public Element<VR::OB, VM::VM1_n> {};
00587 
00588 // Partial specialization for derivatives of 1-n : 2-n, 3-n ...
00589 template<int TVR>
00590 class Element<TVR, VM::VM2_n> : public Element<TVR, VM::VM1_n>
00591 {
00592 public:
00593   typedef Element<TVR, VM::VM1_n> Parent;
00594   void SetLength(int len) {
00595     if( len <= 1 ) return;
00596     Parent::SetLength(len);
00597   }
00598 };
00599 template<int TVR>
00600 class Element<TVR, VM::VM2_2n> : public Element<TVR, VM::VM2_n>
00601 {
00602 public:
00603   typedef Element<TVR, VM::VM2_n> Parent;
00604   void SetLength(int len) {
00605     if( len % 2 ) return;
00606     Parent::SetLength(len);
00607   }
00608 };
00609 template<int TVR>
00610 class Element<TVR, VM::VM3_n> : public Element<TVR, VM::VM1_n>
00611 {
00612 public:
00613   typedef Element<TVR, VM::VM1_n> Parent;
00614   void SetLength(int len) {
00615     if( len <= 2 ) return;
00616     Parent::SetLength(len);
00617   }
00618 };
00619 template<int TVR>
00620 class Element<TVR, VM::VM3_3n> : public Element<TVR, VM::VM3_n>
00621 {
00622 public:
00623   typedef Element<TVR, VM::VM3_n> Parent;
00624   void SetLength(int len) {
00625     if( len % 3 ) return;
00626     Parent::SetLength(len);
00627   }
00628 };
00629 
00630 
00631 //template<int T> struct VRToLength;
00632 //template <> struct VRToLength<VR::AS>
00633 //{ enum { Length  = VM::VM1 }; }
00634 //template<>
00635 //class Element<VR::AS> : public Element<VR::AS, VRToLength<VR::AS>::Length >
00636 
00637 // only 0010 1010 AS 1 Patient’s Age
00638 template<>
00639 class Element<VR::AS, VM::VM5>
00640 {
00641 public:
00642   char Internal[VMToLength<VM::VM5>::Length];
00643   void Print(std::ostream &_os) const {
00644     _os << Internal;
00645     }
00646   unsigned long GetLength() const {
00647     return VMToLength<VM::VM5>::Length;
00648   }
00649 };
00650 
00651 template <>
00652 class Element<VR::OB, VM::VM1> : public Element<VR::OB, VM::VM1_n> {};
00653 // Make it impossible to compile any other cases:
00654 template <int TVM> class Element<VR::OB, TVM>;
00655 
00656 // Same for OW:
00657 template <>
00658 class Element<VR::OW, VM::VM1> : public Element<VR::OW, VM::VM1_n> {};
00659 // Make it impossible to compile any other cases:
00660 template <int TVM> class Element<VR::OW, TVM>;
00661 
00662 } // namespace gdcm
00663 
00664 #endif //GDCMELEMENT_H

Generated on Tue Feb 1 2011 12:30:25 for GDCM by doxygen 1.7.3
SourceForge.net Logo