00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <physics/HeightField>
00026
00027 #include <fstream>
00028
00029
00030 using std::valarray;
00031 using physics::HeightField;
00032
00033
00034 HeightField::HeightField()
00035 : _nx(10), _ny(10), _dx(0.5), _dy(0.5), hf(new valarray<Real>(_nx*_ny))
00036 {
00037 }
00038
00039
00040 HeightField::HeightField(const HeightField& heightfield)
00041 : _nx(heightfield._nx), _ny(heightfield._ny), _dx(heightfield._dx), _dy(heightfield._dy),
00042 hf(new valarray<Real>(*heightfield.hf))
00043 {
00044 }
00045
00046
00047 HeightField::HeightField(Int nx, Int ny, Real dx, Real dy) throw(std::invalid_argument)
00048 : _nx(nx), _ny(ny), _dx(dx), _dy(dy), hf(0)
00049 {
00050 if ((nx<2) || (ny<2) || (dx<=0.0) || (dy<=0.0))
00051 throw std::invalid_argument(Exception("Dimension or resolution arguments too small"));
00052
00053 hf = new valarray<Real>(nx*ny);
00054 }
00055
00056
00057 HeightField::HeightField(ref<base::VFile> file) throw(std::invalid_argument, base::io_error)
00058 : hf(0)
00059 {
00060 load(file);
00061 }
00062
00063
00064 HeightField::~HeightField()
00065 {
00066 if (hf!=0)
00067 delete hf;
00068 }
00069
00070
00071 Real& HeightField::height(Real x, Real y) throw(std::out_of_range)
00072 {
00073 Int offset = Int((y/_dy)*Real(_nx) + x/_dx);
00074 if (offset >= hf->size())
00075 throw std::out_of_range(Exception("x or y out of range"));
00076
00077 return (*hf)[offset];
00078 }
00079
00080 const Real& HeightField::height(Real x, Real y) const throw(std::out_of_range)
00081 {
00082 Int offset = Int((y/_dy)*Real(_nx) + x/_dx);
00083 if (offset >= hf->size())
00084 throw std::out_of_range(Exception("x or y out of range"));
00085
00086 return (*hf)[offset];
00087 }
00088
00089
00090 void HeightField::scale(Real s)
00091 {
00092 _dx *= s;
00093 _dy *= s;
00094 scaleHeights(s);
00095 }
00096
00097
00098 void HeightField::scaleHeights(Real s)
00099 {
00100 (*hf) *= s;
00101 }
00102
00103 Real HeightField::maxHeight()
00104 {
00105 return hf->max();
00106 }
00107
00108 Real HeightField::minHeight()
00109 {
00110 return hf->min();
00111 }
00112
00113
00114 void HeightField::setResolution(Real dx, Real dy) throw(std::invalid_argument)
00115 {
00116 if ((dx<=0.0) || (dy<=0.0))
00117 throw std::invalid_argument(Exception("Resolution parameters too small"));
00118
00119 _dx = dx;
00120 _dy = dy;
00121 }
00122
00123
00124 void HeightField::load(ref<base::VFile> file) throw(std::invalid_argument, base::io_error)
00125 {
00126 String extension = file->extension();
00127 std::istream& in = ((extension=="dat") || (extension=="thf"))?file->istream()
00128 :file->iostream(std::istream::in | std::istream::binary);
00129
00130 if (extension=="dat") {
00131 loadDATFile(in);
00132 return;
00133 }
00134 if (extension=="thf") {
00135 loadTHFFile(in);
00136 return;
00137 }
00138
00139 throw std::invalid_argument(Exception("unsupported/unknown image file extension"));
00140 }
00141
00142
00143 void HeightField::save(ref<base::VFile> file) throw(std::invalid_argument, base::io_error)
00144 {
00145 throw std::runtime_error(Exception("unimplemented"));
00146 }
00147
00148 void HeightField::loadDATFile(std::istream& in) throw(base::io_error)
00149 {
00150 throw base::io_error(Exception("DAT file loading not yet supported, sorry."));
00151 }
00152
00153
00154 void HeightField::loadTHFFile(std::istream& in) throw(base::io_error)
00155 {
00156 valarray<Real>* hf;
00157 Int nx, ny;
00158 Real dx,dy;
00159
00160
00161 String header, version;
00162 in >> header;
00163 if (header != "#TextHeightField")
00164 throw base::io_error(Exception("not a valid TextHeightField (.thf) file - doesn't have correct #TextHeightField header line"));
00165
00166 in >> version;
00167 if (version != "#version")
00168 throw base::io_error(Exception("not a valid TextHeightField (.thf) file - no #version directive"));
00169
00170 Real v;
00171 in >> v;
00172 if (v != 1.0)
00173 throw base::io_error(Exception(String("unknown/unsupported TextHeightField (.thf) version ")+base::realToString(v)));
00174
00175 String tag;
00176 in >> tag;
00177 if (tag=="xdim")
00178 in >> nx;
00179 else
00180 throw base::io_error(Exception(String(String("expected xdim got ")+tag)));
00181
00182 in >> tag;
00183 if (tag=="ydim")
00184 in >> ny;
00185 else
00186 throw base::io_error(Exception(String(String("expected ydim got ")+tag)));
00187
00188 in >> tag;
00189 if (tag=="xres")
00190 in >> dx;
00191 else
00192 throw base::io_error(Exception(String(String("expected xres got ")+tag)));
00193
00194 in >> tag;
00195 if (tag=="yres")
00196 in >> dy;
00197 else
00198 throw base::io_error(Exception(String(String("expected yres got ")+tag)));
00199
00200 if ((nx<2) || (ny<2) || (dx<=0.0) || (dy<=0.0))
00201 throw base::io_error(Exception("Dimension or resolution parameters too small"));
00202
00203 hf = new valarray<Real>(nx*ny);
00204
00205 Int i=0;
00206 while ( i<(nx*ny) && in>>(*hf)[i]) i++;
00207
00208 this->hf = hf;
00209 _nx = nx;
00210 _ny = ny;
00211 _dx = dx;
00212 _dy = dy;
00213 }
00214
00215