source: Swollen/swwreader/swwreader.cpp @ 44

Last change on this file since 44 was 44, checked in by darran, 20 years ago
  • terrible destruction of Swollen moving towards changes Robert suggests
File size: 13.9 KB
Line 
1/*
2    SWWReader
3
4    Reader of SWW files from within OpenSceneGraph.
5
6    An SWW file is the visualization output of the pyVolution
7    Shallow Water Wave equation solver.  SWW files contain bedslope
8    geometry and a sequence of stages at known timesteps.  The
9    internal format is NetCDF:
10
11    netcdf demo.sww {
12        dimensions:
13            number_of_volumes = <integer> ;
14            number_of_vertices = 3 ;
15            number_of_points = <integer> ;
16            number_of_timesteps = UNLIMITED ;
17        variables:
18            float x(number_of_points) ;
19            float y(number_of_points) ;
20            float z(number_of_points) ;
21            int volumes(number_of_volumes, number_of_vertices) ;
22            float time(number_of_timesteps) ;
23            float stage(number_of_timesteps, number_of_points) ;
24
25    copyright (C) 2004 Geoscience Australia
26*/
27
28#include <SWWReader.h>
29#include <string>
30#include <fstream>
31#include <netcdf.h>
32#include <osg/Notify>
33
34#include <stdlib.h>
35#include <stdio.h>
36
37#define DEF_CULLNEARZERO    0.001
38#define DEF_CULLSTEEPANGLE  0.9
39#define DEF_CULLSTART       CULLNONE
40
41#define MIN(a, b) (a < b ? a : b)
42#define MAX(a, b) (a > b ? a : b)
43
44
45// only constructor, requires netcdf file
46SWWReader::SWWReader(const std::string& filename)
47{
48    // assume failure until end of constructor
49    _valid = false;
50
51    // netcdf filename
52    _filename = new std::string(filename);
53
54    // netcdf open
55    _status.push_back( nc_open(_filename->c_str(), NC_NOWRITE, &_ncid) );
56    if (this->_statusHasError()) return;
57
58    // dimension ids
59    _status.push_back( nc_inq_dimid(_ncid, "number_of_volumes", &_nvolumesid) );
60    _status.push_back( nc_inq_dimid(_ncid, "number_of_vertices", &_nverticesid) );
61    _status.push_back( nc_inq_dimid(_ncid, "number_of_points", &_npointsid) );
62    _status.push_back( nc_inq_dimid(_ncid, "number_of_timesteps", &_ntimestepsid) );
63    if (this->_statusHasError()) return;
64
65    // dimension values
66    _status.push_back( nc_inq_dimlen(_ncid, _nvolumesid, &_nvolumes) );
67    _status.push_back( nc_inq_dimlen(_ncid, _nverticesid, &_nvertices) );
68    _status.push_back( nc_inq_dimlen(_ncid, _npointsid, &_npoints) );
69    _status.push_back( nc_inq_dimlen(_ncid, _ntimestepsid, &_ntimesteps) );
70    if (this->_statusHasError()) return;
71
72    // variable ids
73    _status.push_back( nc_inq_varid (_ncid, "x", &_xid) );
74    _status.push_back( nc_inq_varid (_ncid, "y", &_yid) );
75    _status.push_back( nc_inq_varid (_ncid, "z", &_zid) );
76    _status.push_back( nc_inq_varid (_ncid, "volumes", &_volumesid) );
77    _status.push_back( nc_inq_varid (_ncid, "time", &_timeid) );
78    _status.push_back( nc_inq_varid (_ncid, "stage", &_stageid) );
79    if (this->_statusHasError()) return;
80
81    // allocation of variable arrays, destructor responsible for cleanup
82    _px = new float[_npoints];
83    _py = new float[_npoints];
84    _pz = new float[_npoints];
85    _ptime = new float[_ntimesteps];
86    _pvolumes = new unsigned int[_nvertices * _nvolumes];
87    _pstage = new float[_npoints];
88
89    // loading variables from netcdf file
90    _status.push_back( nc_get_var_float (_ncid, _xid, _px) );  // x vertices
91    _status.push_back( nc_get_var_float (_ncid, _yid, _py) );  // y vertices
92    _status.push_back( nc_get_var_float (_ncid, _zid, _pz) );  // bedslope heights
93    _status.push_back( nc_get_var_float (_ncid, _timeid, _ptime) );  // time array
94    _status.push_back( nc_get_var_int (_ncid, _volumesid, (int *) _pvolumes) );  // triangle indices
95    if (this->_statusHasError()) return;
96
97    // loop index
98    size_t iv;
99
100    // vertex indices
101    unsigned int v1index, v2index, v3index;
102
103    // bedslope extents and resultant scale factors
104    float xmin, xmax, xrange;
105    float ymin, ymax, yrange;
106    float zmin, zmax, zrange;
107    float aspect_ratio;
108    xmin = _px[0]; xmax = _px[0];
109    ymin = _py[0]; ymax = _py[0];
110    zmin = _pz[0]; zmax = _pz[0];
111    for( iv=1; iv < _npoints; iv++ )
112    {
113      if( _px[iv] < xmin ) xmin = _px[iv];
114      if( _px[iv] > xmax ) xmax = _px[iv];
115      if( _py[iv] < ymin ) ymin = _py[iv];
116      if( _py[iv] > ymax ) ymax = _py[iv];
117      if( _pz[iv] < zmin ) zmin = _pz[iv];
118      if( _pz[iv] > zmax ) zmax = _pz[iv];
119    }
120
121    xrange = xmax - xmin;
122    yrange = ymax - ymin;
123    aspect_ratio = xrange/yrange;
124    if( aspect_ratio > 1.0 )
125    {
126            _xscale = 1.0 / xrange;
127            _xoffset = xmin;
128            _xcenter = 0.5;
129
130            _yscale = _xscale;
131            _yoffset = ymin;
132            _ycenter = 0.5 / aspect_ratio;
133
134            _zscale = _xscale;
135            _zoffset = zmin;
136            _zcenter = 0.0;
137    }
138    else
139    {
140            _yscale = 1.0 / yrange;
141            _yoffset = ymin;
142            _ycenter = 0.5;
143
144            _xscale = _yscale;
145            _xoffset = xmin;
146            _xcenter = 0.5 / aspect_ratio;
147
148            _zscale = _yscale;
149            _zoffset = zmin;
150            _zcenter = 0.0;
151    }
152
153    osg::notify(osg::INFO) << "[SWWReader] xmin: " << xmin <<  std::endl;
154    osg::notify(osg::INFO) << "[SWWReader] xmax: " << xmax <<  std::endl;
155    osg::notify(osg::INFO) << "[SWWReader] xscale: " << _xscale <<  std::endl;
156    osg::notify(osg::INFO) << "[SWWReader] ymin: " << ymin <<  std::endl;
157    osg::notify(osg::INFO) << "[SWWReader] ymax: " << ymax <<  std::endl;
158    osg::notify(osg::INFO) << "[SWWReader] yscale: " << _yscale <<  std::endl;
159    osg::notify(osg::INFO) << "[SWWReader] zmin: " << zmin <<  std::endl;
160    osg::notify(osg::INFO) << "[SWWReader] zmax: " << zmax <<  std::endl;
161    osg::notify(osg::INFO) << "[SWWReader] zscale: " << _zscale <<  std::endl;
162
163
164    // culling defaults
165    _cullsetting = DEF_CULLSTART;
166    _cullnearzero = DEF_CULLNEARZERO;
167    _cullsteepangle = DEF_CULLSTEEPANGLE;
168
169    // compute triangle connectivity, a list (indexed by vertex number)
170    // of lists (indices of triangles sharing this vertex)
171    _connectivity = std::vector<triangle_list>(_npoints);
172    for (iv=0; iv < _nvolumes; iv++)
173    {
174        v1index = _pvolumes[3*iv+0];
175        v2index = _pvolumes[3*iv+1];
176        v3index = _pvolumes[3*iv+2];
177        _connectivity.at(v1index).push_back(iv);
178        _connectivity.at(v2index).push_back(iv);
179        _connectivity.at(v3index).push_back(iv);
180    }
181
182    // load bedslope vertex array, shifting and scaling vertices to unit cube
183    // centred about the origin
184    _bedslopevertices = new osg::Vec3Array;
185    for (iv=0; iv < _npoints; iv++)
186      _bedslopevertices->push_back( osg::Vec3( (_px[iv]-_xoffset)*_xscale - _xcenter, 
187                                               (_py[iv]-_yoffset)*_yscale - _ycenter, 
188                                               (_pz[iv]-_zoffset)*_zscale - _zcenter) );
189
190    // load bedslope index array, pvolumes array indexes into x, y and z
191    _bedslopeindices = new osg::UIntArray;
192    for (iv=0; iv < _nvolumes*_nvertices; iv++)
193        _bedslopeindices->push_back( _pvolumes[iv] );
194
195    // calculate bedslope primitive normal and centroid arrays
196    _bedslopenormals = new osg::Vec3Array;
197    _bedslopecentroids = new osg::Vec3Array;
198    osg::Vec3 v1, v2, v3, side1, side2, nrm;
199    for (iv=0; iv < _nvolumes; iv++)
200    {
201        v1index = _pvolumes[3*iv+0];
202        v2index = _pvolumes[3*iv+1];
203        v3index = _pvolumes[3*iv+2];
204
205        v1 = _bedslopevertices->at(v1index);
206        v2 = _bedslopevertices->at(v2index);
207        v3 = _bedslopevertices->at(v3index);
208
209        side1 = v2 - v1;
210        side2 = v3 - v2;
211        nrm = side1^side2;
212        nrm.normalize();
213
214        _bedslopenormals->push_back( nrm );
215        _bedslopecentroids->push_back( (v1+v2+v3)/3.0 );
216    }
217
218    // success!
219    _valid = true;
220
221}
222
223
224
225SWWReader::~SWWReader()
226{
227    _status.push_back( nc_close(_ncid) );
228    delete[]( _px, _py, _pz, _ptime, _pvolumes, _pstage );
229}
230
231
232
233osg::ref_ptr<osg::Vec3Array> SWWReader::getStageVertexArray(unsigned int index)
234{
235    size_t start[2], count[2], iv;
236    const ptrdiff_t stride[2] = {1,1};
237    start[0] = index;
238    start[1] = 0;
239    count[0] = 1;
240    count[1] = _npoints;
241
242    // stage heights from netcdf file (x and y are same as bedslope)
243    int status = nc_get_vars_float (_ncid, _stageid, start, count, stride, _pstage);
244
245    // load stage vertex array, scaling and shifting vertices to lie in the unit cube
246    _stagevertices = new osg::Vec3Array;
247    for (iv=0; iv < _npoints; iv++)
248        _stagevertices->push_back( osg::Vec3(
249                                             (_px[iv]-_xoffset)*_xscale - _xcenter, 
250                                             (_py[iv]-_yoffset)*_yscale - _ycenter, 
251                                             (_pstage[iv]-_zoffset)*_zscale - _zcenter) );
252
253    // stage index and per primitive normal and centroid arrays
254    _stageprimitivenormals = new osg::Vec3Array;
255    _stagecentroids = new osg::Vec3Array;
256    _stageindices = new osg::UIntArray;
257    _stagecolors = new osg::Vec4Array;
258    osg::Vec3 v1b, v2b, v3b;
259    osg::Vec3 v1s, v2s, v3s;
260    osg::Vec3 side1, side2, nrm;
261    unsigned int v1index, v2index, v3index;
262    osg::ref_ptr<osg::UIntArray> culledlist = new osg::UIntArray;
263    std::vector<triangle_list> stageconnectivity = std::vector<triangle_list>(_npoints);
264
265    // over all stage triangles
266    unsigned int nonculled = 0;
267    float alphamin = 1.0;
268    float alphamax = 0.0;
269    for (iv=0; iv < _nvolumes; iv++){
270
271        v1index = _pvolumes[3*iv+0];
272        v2index = _pvolumes[3*iv+1];
273        v3index = _pvolumes[3*iv+2];
274
275        v1s = _stagevertices->at(v1index);
276        v2s = _stagevertices->at(v2index);
277        v3s = _stagevertices->at(v3index);
278        v1b = _bedslopevertices->at(v1index);
279        v2b = _bedslopevertices->at(v2index);
280        v3b = _bedslopevertices->at(v3index);
281
282        // shallow water depth culling test
283        if( (_cullsetting == CULLALL || _cullsetting == CULLNEARZERO) && 
284            ((v1s.z()+v2s.z()+v3s.z())/3.0 - _bedslopecentroids->at(iv).z()) < _cullnearzero )
285        {
286            culledlist->push_back( iv );
287            continue;
288        }
289
290        // steep bedslope culling test
291        if( _cullsetting == CULLALL || _cullsetting == CULLSTEEPANGLE ) 
292        {
293            if( _bedslopenormals->at(iv) * osg::Vec3f(0,0,1) < _cullsteepangle )
294            {
295                culledlist->push_back( iv );
296                continue;
297            }
298        }
299
300        // pass through, current triangle is visible (not culled)
301        _stageindices->push_back( v1index );
302        _stageindices->push_back( v2index );
303        _stageindices->push_back( v3index );
304
305        // alpha value based on stage-bedslope height difference
306        float alpha1 = ( v1s.z()-v1b.z() )*10.0;
307        float alpha2 = ( v2s.z()-v2b.z() )*10.0;
308        float alpha3 = ( v3s.z()-v3b.z() )*10.0;
309        alphamax = MAX( alphamax, alpha1 );
310        alphamax = MAX( alphamax, alpha2 );
311        alphamax = MAX( alphamax, alpha3 );
312        alphamin = MIN( alphamin, alpha1 );
313        alphamin = MIN( alphamin, alpha2 );
314        alphamin = MIN( alphamin, alpha3 );
315
316        osg::Vec4 color1, color2, color3;
317        color1.set( alpha1,alpha1,alpha1, 1.0 );
318        color2.set( alpha2,alpha2,alpha2, 1.0 );
319        color3.set( alpha3,alpha3,alpha3, 1.0 );
320        //color1.set( alpha1,alpha1,alpha1, alpha1 );
321        //color2.set( alpha2,alpha2,alpha2, alpha2 );
322        //color3.set( alpha3,alpha3,alpha3, alpha3 );
323        _stagecolors->push_back( color1 );
324        _stagecolors->push_back( color2 );
325        _stagecolors->push_back( color3 );
326
327        // current triangle primitive normal
328        side1 = v2s - v1s;
329        side2 = v3s - v2s;
330        nrm = side1^side2;
331        nrm.normalize();
332
333        // stage triangle connectivity, a list (indexed by vertex number)
334        // of lists (indices of non-culled triangles sharing this vertex)
335        stageconnectivity.at(v1index).push_back(nonculled);
336        stageconnectivity.at(v2index).push_back(nonculled);
337        stageconnectivity.at(v3index).push_back(nonculled);
338
339        // store centroid and primitive normal (both needed to visualize vectors)
340        _stagecentroids->push_back( (v1s+v2s+v3s)/3.0 );
341        _stageprimitivenormals->push_back( nrm );
342
343        // non-culled triangle count
344        nonculled++;
345
346    }
347
348    std::cout << "index: " << index << "    AlphaMax: " << alphamax << std::endl;
349    std::cout << "index: " << index << "    AlphaMin: " << alphamin << std::endl;
350
351    // per-vertex normals
352    _stagevertexnormals = new osg::Vec3Array;
353    int num_shared_triangles, triangle_index;
354    for (iv=0; iv < _npoints; iv++)
355    {
356        nrm.set(0,0,0);
357        num_shared_triangles = stageconnectivity.at(iv).size();
358        for (int i=0; i<num_shared_triangles; i++ )
359        {
360            triangle_index = stageconnectivity.at(iv).at(i);
361
362            // summing of contributing primitive normals
363            nrm += _stageprimitivenormals->at(triangle_index);
364        }
365
366        // FIXME: Length of this list has to match vertex list length.
367        // We have vertices and normals that aren't being referenced.
368        if( 1 || num_shared_triangles )  // avoid vertices belonging only to culled triangles
369        {
370            nrm = nrm / num_shared_triangles;  // average
371            nrm.normalize();
372            _stagevertexnormals->push_back(nrm);
373        }
374    }
375
376    return _stagevertices;
377}
378
379
380
381void SWWReader::toggleCullSetting()
382{
383
384  switch( _cullsetting )
385    {
386
387    case CULLALL:
388      _cullsetting = CULLNEARZERO;
389      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLNEARZERO" <<  std::endl;
390      break;
391
392    case CULLNEARZERO:
393      _cullsetting = CULLSTEEPANGLE;
394      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLSTEEPANGLE" <<  std::endl;
395      break;
396
397    case CULLSTEEPANGLE:
398      _cullsetting = CULLNONE;
399      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLNONE" <<  std::endl;
400      break;
401
402    case CULLNONE:
403      _cullsetting = CULLALL;
404      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLALL" <<  std::endl;
405      break;
406
407    }
408}
409
410
411
412bool SWWReader::_statusHasError()
413{
414    bool haserror = false;  // assume success, trap failure
415
416    std::vector<int>::iterator iter;
417    for (iter=_status.begin(); iter != _status.end(); iter++)
418    {
419        if (*iter != NC_NOERR)
420        {
421            osg::notify(osg::WARN) << nc_strerror(*iter) <<  std::endl;
422            haserror = true;
423            nc_close(_ncid);
424            break;
425        }
426    }
427
428    // on return start gathering result values afresh
429    _status.clear();
430
431    return haserror;
432}
Note: See TracBrowser for help on using the repository browser.