 /* ImLib3D
  * Copyright (c) 2001, ULP-IPB Strasbourg.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
  * 
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  * 
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #ifndef _Image3D_hpp
 #define _Image3D_hpp
 
 #include<imlib3dconfig.h>
 
 #include<ImLib3D/CppTools.hpp>
 #include<ImLib3D/RectZone3D.hpp>
 #include<ImLib3D/Vect3D.hpp>
 #include<ImLib3D/ImLib3DFile.hpp>
 #include<ImLib3D/Size3D.hpp>
 #include<ImLib3D/Properties.hpp>
 
 class Mask3D;
 
 // ********************** Image3D ********************
 
 class Image3D : public Streamable
 {
 protected:
     int width;
     int height;
     int depth;
     int nvoxels;
 
 public:
 
     virtual string GetTypeName() const;
 public:
     Properties properties;
 
     // **************************************************
     // ****************** accessors *********************
     // **************************************************
     inline const Mask3D &Mask() const {return *properties.mask;}
     inline Mask3D       &Mask()       {return *properties.mask;}
     inline bool   HasMask() const {return properties.mask!=NULL;}
     Mask3D       &AddMask(){properties.AddMask(Size());return Mask();}
     inline byte   Mask(const Vect3Di &P) const  ;
     inline byte  &Mask(const Vect3Di &P)        ;
     inline byte   Mask(int x,int y,int z) const ;
     inline byte  &Mask(int x,int y,int z)       ; 
     void          RemoveMask();
     
     bool Has(const string &propname) const {return properties.Has(propname);}
 
     template<class PType>       PType &Property(const string &name)       
     {return properties.template GetTemplatedProperty<PType>(name);}
     template<class PType> const PType &Property(const string &name) const 
     {return properties.template GetTemplatedProperty<PType>(name);}
 
     template<class PType> void AddProperty(const string &name,PType v) {properties.Add(name,v);}
     template<class PType> void SetProperty(const string &name,PType v) {properties.Add(name,v);}
     
 
     inline int     Width()   const {return width;}
     inline int     Height()  const {return height;}
     inline int     Depth()   const {return depth;}
     inline Size3D  Size()    const {return Size3D (width,height,depth);}
     inline Vect3Di SizeV()   const {return Vect3Di(width,height,depth);}
     RectZone3Di GetZone()   const {return RectZone3Di(0,0,0,width-1,height-1,depth-1);}
     inline int GetNVoxels() const {return nvoxels;}
     
     inline bool IsInside(float x,float y,float z) const {return x>=0 && y>=0 && z>=0 && x<Width() && y<Height() && z<Depth() ;}
     inline bool IsInside(int x,int y,int z) const {return x>=0 && y>=0 && z>=0 && x<Width() && y<Height() && z<Depth() ;}
     inline bool IsInside(const Vect3Di &P) const {return IsInside(P.x,P.y,P.z);}
     inline void AssertBounds(int x,int y,int z) const
     {
         if(nvoxels!=width*height*depth)
         {ThrowError("Image3D::AssertBounds: incoherence in sizes");}
         if(!IsInside(x,y,z)){ThrowError("Image3D::AssertBounds: pos:%d %d %d image size:%d %d %d\n",x,y,z,
                                       width,height,depth);}
     }
     inline void AssertBounds(int pos) const
     {
         if(nvoxels!=width*height*depth)
         {ThrowError("Image3D::AssertBounds: incoherence in sizes");}
         if(pos<0 || pos>=nvoxels){ThrowError("Image3D::AssertBounds: pos:%d image size:%d %d %d: \n",pos,
                                       width,height,depth);}
     }
 
     virtual float FloatValue(int x,int y,int z) const;
     float FloatValue(const Vect3Di &pos) const {return FloatValue(pos.x,pos.y,pos.z);}
 
 
     // **************************************************
     // ****************** methods   *********************
     // **************************************************
 protected:
     xmlpp::Element *CreateWriteNode(ImLib3DFile *file,xmlpp::Element *parentNode=NULL,xmlpp::Element *node=NULL) const
     {
         return Streamable::CreateWriteNode("ImLib3DImage",file,parentNode,node);
     }
     xmlpp::Element *CreateReadNode(ImLib3DFile *file,xmlpp::Element *parentNode=NULL,xmlpp::Element *node=NULL)
     {
         return Streamable::CreateReadNode("ImLib3DImage",file,parentNode,node);
     }
 public:
 
 
     virtual void Read( ImLib3DFile *file,xmlpp::Element *parentNode=NULL,xmlpp::Element *node=NULL)      ;
     virtual void Write(ImLib3DFile *file,xmlpp::Element *parentNode=NULL,xmlpp::Element *node=NULL) const;
 public:
     virtual void WriteToFile (const string &fname) const {Streamable::WriteToFile(fname);}
 
 private:
     void SetSize(const Size3D &newSize);
 public:
     virtual void Resize(const Size3D &newSize);
 
     Image3D& operator=(const Image3D & other);
     bool operator==(const Image3D & other) const;
     bool operator!=(const Image3D & other) const {return !(this->operator==(other));}
 
     // **************************************************
     // ****************** constructors/destructors*******
     // **************************************************
 
 public:
     virtual ~Image3D();
     Image3D();
     Image3D(int _width, int _height, int _depth);
 //      Image3D(const string& fname){ReadFromFile(fname);}
     Image3D(const Size3D &size);
     Image3D(const Image3D & other);
 
 };
 
 template<> inline string TypeName<Image3D>(){return "Image3D";}
 
 #include<ImLib3D/Container3D.hpp>
 
 #endif  // _Image3D_hpp
