source: Swollen/swwreader/swwreader.cpp @ 36

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