source: Swollen/swwreader/swwreader.cpp @ 45

Last change on this file since 45 was 45, checked in by darran, 20 years ago

Major changes as per Robert's suggestions

  • removed all culling from swwreader
  • DrawElements? for primitive set improves speed
  • per vertex alpha (vec4 color)

Also,

  • initial view angle slightly above plane
File size: 11.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#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    zrange = zmax - zmin;
124    aspect_ratio = xrange/yrange;
125    _xscale = 1.0 / xrange;
126    _yscale = 1.0 / yrange;
127    _zscale = (zmax == 0.0) ? 1.0 : 1.0 / zrange;
128    _xoffset = xmin;
129    _yoffset = ymin;
130    _zoffset = zmin;
131    _xcenter = 0.5;
132    _ycenter = 0.5;
133    _zcenter = 0.0;
134
135    if( aspect_ratio > 1.0 )
136    {
137      _scale = 1.0 / xrange;
138      _ycenter /= aspect_ratio;
139    }
140    else
141    {
142      _scale = 1.0 / yrange;
143      _xcenter /= aspect_ratio;
144    }
145
146    osg::notify(osg::INFO) << "[SWWReader] xmin: " << xmin <<  std::endl;
147    osg::notify(osg::INFO) << "[SWWReader] xmax: " << xmax <<  std::endl;
148    osg::notify(osg::INFO) << "[SWWReader] xscale: " << _xscale <<  std::endl;
149    osg::notify(osg::INFO) << "[SWWReader] ymin: " << ymin <<  std::endl;
150    osg::notify(osg::INFO) << "[SWWReader] ymax: " << ymax <<  std::endl;
151    osg::notify(osg::INFO) << "[SWWReader] yscale: " << _yscale <<  std::endl;
152    osg::notify(osg::INFO) << "[SWWReader] zmin: " << zmin <<  std::endl;
153    osg::notify(osg::INFO) << "[SWWReader] zmax: " << zmax <<  std::endl;
154    osg::notify(osg::INFO) << "[SWWReader] zscale: " << _zscale <<  std::endl;
155
156
157    // culling defaults
158    _cullsetting = DEF_CULLSTART;
159    _cullnearzero = DEF_CULLNEARZERO;
160    _cullsteepangle = DEF_CULLSTEEPANGLE;
161
162    // compute triangle connectivity, a list (indexed by vertex number)
163    // of lists (indices of triangles sharing this vertex)
164    _connectivity = std::vector<triangle_list>(_npoints);
165    for (iv=0; iv < _nvolumes; iv++)
166    {
167        v1index = _pvolumes[3*iv+0];
168        v2index = _pvolumes[3*iv+1];
169        v3index = _pvolumes[3*iv+2];
170        _connectivity.at(v1index).push_back(iv);
171        _connectivity.at(v2index).push_back(iv);
172        _connectivity.at(v3index).push_back(iv);
173    }
174
175    // bedslope vertex array, shifting and scaling vertices to unit cube
176    // centred about the origin
177    _bedslopevertices = new osg::Vec3Array;
178    for (iv=0; iv < _npoints; iv++)
179      _bedslopevertices->push_back( osg::Vec3( (_px[iv]-_xoffset)*_scale - _xcenter, 
180                                               (_py[iv]-_yoffset)*_scale - _ycenter, 
181                                               (_pz[iv]-_zoffset)*_scale - _zcenter) );
182
183    // bedslope index array, pvolumes array indexes into x, y and z
184    _bedslopeindices = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, _nvolumes*_nvertices);
185    for (iv=0; iv < _nvolumes*_nvertices; iv++)
186      (*_bedslopeindices)[iv] = _pvolumes[iv];
187
188
189    // bedslope texture coords based on (x,y) locations scaled by extents into range [0,1]
190    _bedslopetexcoords = new osg::Vec2Array;
191    for( iv=0; iv < _npoints; iv++ )
192      _bedslopetexcoords->push_back( osg::Vec2( (_px[iv]-_xoffset)*_xscale, (_py[iv]-_yoffset)*_yscale ) );
193
194
195
196    // calculate bedslope primitive normal and centroid arrays
197    _bedslopenormals = new osg::Vec3Array;
198    _bedslopecentroids = new osg::Vec3Array;
199    osg::Vec3 v1, v2, v3, side1, side2, nrm;
200    for (iv=0; iv < _nvolumes; iv++)
201    {
202        v1index = _pvolumes[3*iv+0];
203        v2index = _pvolumes[3*iv+1];
204        v3index = _pvolumes[3*iv+2];
205
206        v1 = _bedslopevertices->at(v1index);
207        v2 = _bedslopevertices->at(v2index);
208        v3 = _bedslopevertices->at(v3index);
209
210        side1 = v2 - v1;
211        side2 = v3 - v2;
212        nrm = side1^side2;
213        nrm.normalize();
214
215        _bedslopenormals->push_back( nrm );
216        _bedslopecentroids->push_back( (v1+v2+v3)/3.0 );
217    }
218
219    // success!
220    _valid = true;
221
222}
223
224
225
226SWWReader::~SWWReader()
227{
228    _status.push_back( nc_close(_ncid) );
229    delete[]( _px, _py, _pz, _ptime, _pvolumes, _pstage );
230}
231
232
233
234osg::ref_ptr<osg::Vec3Array> SWWReader::getStageVertexArray(unsigned int index)
235{
236    size_t start[2], count[2], iv;
237    const ptrdiff_t stride[2] = {1,1};
238    start[0] = index;
239    start[1] = 0;
240    count[0] = 1;
241    count[1] = _npoints;
242
243    // stage heights from netcdf file (x and y are same as bedslope)
244    int status = nc_get_vars_float (_ncid, _stageid, start, count, stride, _pstage);
245
246    // load stage vertex array, scaling and shifting vertices to lie in the unit cube
247    _stagevertices = new osg::Vec3Array;
248    for (iv=0; iv < _npoints; iv++)
249        _stagevertices->push_back( osg::Vec3( (_px[iv]-_xoffset)*_scale - _xcenter, 
250                                              (_py[iv]-_yoffset)*_scale - _ycenter, 
251                                              (_pstage[iv]-_zoffset)*_scale - _zcenter) );
252
253
254    // stage index, per primitive normal and centroid arrays
255    _stageprimitivenormals = new osg::Vec3Array;
256    _stagecentroids = new osg::Vec3Array;
257    osg::Vec3 v1b, v2b, v3b;
258    osg::Vec3 v1s, v2s, v3s;
259    osg::Vec3 side1, side2, nrm;
260    unsigned int v1index, v2index, v3index;
261
262    // over all stage triangles
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        // current triangle primitive normal
277        side1 = v2s - v1s;
278        side2 = v3s - v2s;
279        nrm = side1^side2;
280        nrm.normalize();
281
282        // store centroid and primitive normal
283        _stagecentroids->push_back( (v1s+v2s+v3s)/3.0 );
284        _stageprimitivenormals->push_back( nrm );
285
286    }
287
288
289    float alpha;
290    _stagecolors = new osg::Vec4Array;
291    for (iv=0; iv < _npoints; iv++)
292    {
293      // FIXME: needs to be scaled appropriately
294        alpha = ( _stagevertices->at(iv).z() - _bedslopevertices->at(iv).z() ) * 100.0;
295        _stagecolors->push_back( osg::Vec4( 1.0, 1.0, 1.0, alpha ) );
296    }
297
298
299    // per-vertex normals calculated as average of primitive normals
300    // from contributing triangles
301    _stagevertexnormals = new osg::Vec3Array;
302    int num_shared_triangles, triangle_index;
303    for (iv=0; iv < _npoints; iv++)
304    {
305        nrm.set(0,0,0);
306        num_shared_triangles = _connectivity.at(iv).size();
307        for (int i=0; i<num_shared_triangles; i++ )
308        {
309            triangle_index = _connectivity.at(iv).at(i);
310            nrm += _stageprimitivenormals->at(triangle_index);
311        }
312
313        nrm = nrm / num_shared_triangles;  // average
314        nrm.normalize();
315        _stagevertexnormals->push_back(nrm);
316    }
317
318    return _stagevertices;
319}
320
321
322
323void SWWReader::toggleCullSetting()
324{
325
326  switch( _cullsetting )
327    {
328
329    case CULLALL:
330      _cullsetting = CULLNEARZERO;
331      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLNEARZERO" <<  std::endl;
332      break;
333
334    case CULLNEARZERO:
335      _cullsetting = CULLSTEEPANGLE;
336      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLSTEEPANGLE" <<  std::endl;
337      break;
338
339    case CULLSTEEPANGLE:
340      _cullsetting = CULLNONE;
341      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLNONE" <<  std::endl;
342      break;
343
344    case CULLNONE:
345      _cullsetting = CULLALL;
346      osg::notify(osg::INFO) << "[SWWReader::toggleCullSetting] CULLALL" <<  std::endl;
347      break;
348
349    }
350}
351
352
353
354bool SWWReader::_statusHasError()
355{
356    bool haserror = false;  // assume success, trap failure
357
358    std::vector<int>::iterator iter;
359    for (iter=_status.begin(); iter != _status.end(); iter++)
360    {
361        if (*iter != NC_NOERR)
362        {
363            osg::notify(osg::WARN) << nc_strerror(*iter) <<  std::endl;
364            haserror = true;
365            nc_close(_ncid);
366            break;
367        }
368    }
369
370    // on return start gathering result values afresh
371    _status.clear();
372
373    return haserror;
374}
Note: See TracBrowser for help on using the repository browser.