source: trunk/packages/vizservers/nanovis/Flow.cpp @ 3630

Last change on this file since 3630 was 3630, checked in by ldelgass, 7 years ago

Nanovis refactoring to fix problems with scaling and multiple results.
Do rendering in world space to properly place and scale multiple data sets.
Also fix flows to reduce resets of animations. More work toward removing
Cg dependency. Fix panning to convert viewport coords to world coords.

  • Property svn:eol-style set to native
File size: 11.0 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (c) 2004-2013  HUBzero Foundation, LLC
4 *
5 * Authors:
6 *   Wei Qiao <qiaow@purdue.edu>
7 *   Insoo Woo <iwoo@purdue.edu>
8 *   George A. Howlett <gah@purdue.edu>
9 *   Leif Delgass <ldelgass@purdue.edu>
10 */
11
12#include <float.h>
13
14#include <tcl.h>
15
16#include <vrmath/BBox.h>
17#include <vrmath/Vector3f.h>
18
19#include "nanovis.h"
20#include "Flow.h"
21#include "FlowCmd.h"
22#include "FlowTypes.h"
23#include "FlowParticles.h"
24#include "FlowBox.h"
25#include "LIC.h"
26#include "VelocityArrowsSlice.h"
27#include "Switch.h"
28#include "Unirect.h"
29#include "Volume.h"
30#include "Trace.h"
31#include "TransferFunction.h"
32
33using namespace nv;
34using namespace vrmath;
35
36bool Flow::updatePending = false;
37double Flow::magMin = DBL_MAX;
38double Flow::magMax = -DBL_MAX;
39
40Flow::Flow(Tcl_Interp *interp, const char *name) :
41    _interp(interp),
42    _name(name),
43    _data(NULL),
44    _volume(NULL)
45{
46    memset(&_sv, 0, sizeof(FlowValues));
47    _sv.sliceVisible = 1;
48    _sv.transferFunction = NanoVis::getTransferFunction("default");
49
50    _cmdToken = Tcl_CreateObjCommand(_interp, (char *)name, 
51                                     (Tcl_ObjCmdProc *)FlowInstObjCmd,
52                                     this, FlowInstDeleteProc);
53}
54
55Flow::~Flow()
56{
57    TRACE("Enter");
58
59    Rappture::FreeSwitches(_switches, &_sv, 0);
60
61    if (_data != NULL) {
62        delete _data;
63    }
64    if (_volume != NULL) {
65        NanoVis::removeVolume(_volume);
66        _volume = NULL;
67    }
68    for (BoxHashmap::iterator itr = _boxTable.begin();
69         itr != _boxTable.end(); ++itr) {
70        delete itr->second;
71    }
72    _boxTable.clear();
73    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
74         itr != _particlesTable.end(); ++itr) {
75        delete itr->second;
76    }
77    _particlesTable.clear();
78}
79
80void
81Flow::getBounds(Vector3f& min,
82                Vector3f& max,
83                bool onlyVisible)
84{
85    TRACE("Enter");
86
87    if (onlyVisible && !visible())
88        return;
89
90    BBox allBounds;
91    if (isDataLoaded()) {
92        BBox bbox;
93        data()->getBounds(bbox.min, bbox.max);
94        allBounds.extend(bbox);
95    }
96    for (BoxHashmap::iterator itr = _boxTable.begin();
97         itr != _boxTable.end(); ++itr) {
98        FlowBox *box = itr->second;
99        if (!onlyVisible || box->visible()) {
100            BBox bbox;
101            box->getBounds(bbox.min, bbox.max);
102            allBounds.extend(bbox);
103        }
104    }
105    min = allBounds.min;
106    max = allBounds.max;
107}
108
109float
110Flow::getRelativePosition(FlowPosition *position)
111{
112    if (position->flags == RELPOS) {
113        return position->value;
114    }
115    switch (position->axis) {
116    case AXIS_X: 
117        return (position->value - _data->xMin()) / 
118            (_data->xMax() - _data->xMin()); 
119    case AXIS_Y: 
120        return (position->value - _data->yMin()) / 
121            (_data->yMax() - _data->yMin()); 
122    case AXIS_Z: 
123        return (position->value - _data->zMin()) / 
124            (_data->zMax() - _data->zMin()); 
125    }
126    return 0.0;
127}
128
129void
130Flow::resetParticles()
131{
132    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
133         itr != _particlesTable.end(); ++itr) {
134        itr->second->reset();
135    }
136}
137
138void
139Flow::advect()
140{
141    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
142         itr != _particlesTable.end(); ++itr) {
143        if (itr->second->visible()) {
144            itr->second->advect();
145        }
146    }
147}
148
149void
150Flow::render()
151{
152    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
153         itr != _particlesTable.end(); ++itr) {
154        if (itr->second->visible()) {
155            itr->second->render();
156        }
157    }
158    renderBoxes();
159}
160
161FlowParticles *
162Flow::createParticles(const char *particlesName)
163{
164    ParticlesHashmap::iterator itr = _particlesTable.find(particlesName);
165    if (itr != _particlesTable.end()) {
166        TRACE("Deleting existing particle injection plane '%s'", particlesName);
167        delete itr->second;
168        _particlesTable.erase(itr);
169    }
170    FlowParticles *particles = new FlowParticles(particlesName);
171    _particlesTable[particlesName] = particles;
172    return particles;
173}
174
175FlowParticles *
176Flow::getParticles(const char *particlesName)
177{
178    ParticlesHashmap::iterator itr;
179    itr = _particlesTable.find(particlesName);
180    if (itr == _particlesTable.end()) {
181        TRACE("Can't find particle injection plane '%s' in '%s'", particlesName, name());
182        return NULL;
183    }
184    return itr->second;
185}
186
187void
188Flow::deleteParticles(const char *particlesName)
189{
190    ParticlesHashmap::iterator itr = _particlesTable.find(particlesName);
191    if (itr == _particlesTable.end()) {
192        TRACE("Can't find particle injection plane '%s' in '%s'", particlesName, name());
193        return;
194    }
195    delete itr->second;
196    _particlesTable.erase(itr);
197}
198
199void
200Flow::getParticlesNames(std::vector<std::string>& names)
201{
202    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
203         itr != _particlesTable.end(); ++itr) {
204        names.push_back(std::string(itr->second->name()));
205    }
206}
207
208FlowBox *
209Flow::createBox(const char *boxName)
210{
211    BoxHashmap::iterator itr = _boxTable.find(boxName);
212    if (itr != _boxTable.end()) {
213        TRACE("Deleting existing box '%s'", boxName);
214        delete itr->second;
215        _boxTable.erase(itr);
216    }
217    FlowBox *box = new FlowBox(boxName);
218    _boxTable[boxName] = box;
219    return box;
220}
221
222FlowBox *
223Flow::getBox(const char *boxName)
224{
225    BoxHashmap::iterator itr = _boxTable.find(boxName);
226    if (itr == _boxTable.end()) {
227        TRACE("Can't find box '%s' in '%s'", boxName, name());
228        return NULL;
229    }
230    return itr->second;
231}
232
233void
234Flow::deleteBox(const char *boxName)
235{
236    BoxHashmap::iterator itr = _boxTable.find(boxName);
237    if (itr == _boxTable.end()) {
238        TRACE("Can't find box '%s' in '%s'", boxName, name());
239        return;
240    }
241    delete itr->second;
242    _boxTable.erase(itr);
243}
244
245void Flow::getBoxNames(std::vector<std::string>& names)
246{
247    for (BoxHashmap::iterator itr = _boxTable.begin();
248         itr != _boxTable.end(); ++itr) {
249        names.push_back(std::string(itr->second->name()));
250    }
251}
252
253void
254Flow::initializeParticles()
255{
256    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
257         itr != _particlesTable.end(); ++itr) {
258        itr->second->initialize();
259    }
260}
261
262bool
263Flow::configure()
264{
265    bool needReset = false;
266
267    if (_volume != NULL) {
268        _volume->transferFunction(_sv.transferFunction);
269        _volume->dataEnabled(_sv.showVolume);
270        _volume->twoSidedLighting(_sv.twoSidedLighting);
271        _volume->outline(_sv.showOutline);
272        _volume->opacityScale(_sv.opacity);
273        _volume->ambient(_sv.ambient);
274        _volume->diffuse(_sv.diffuse);
275        _volume->specularLevel(_sv.specular);
276        _volume->specularExponent(_sv.specularExp);
277    }
278
279    float slicePos = getRelativePosition(&_sv.slicePos);
280
281    // FIXME: LIC and arrows should be per-flow
282    if (NanoVis::licRenderer != NULL) {
283        if (NanoVis::licRenderer->getSliceAxis() != _sv.slicePos.axis) {
284            needReset = true;
285            NanoVis::licRenderer->setSliceAxis(_sv.slicePos.axis);
286        }
287        if (NanoVis::licRenderer->getSlicePosition() != slicePos) {
288            needReset = true;
289            NanoVis::licRenderer->setSlicePosition(slicePos);
290        }
291        NanoVis::licRenderer->visible(_sv.sliceVisible);
292    }
293    if (NanoVis::velocityArrowsSlice != NULL) {
294        NanoVis::velocityArrowsSlice->setSliceAxis(_sv.slicePos.axis);
295        NanoVis::velocityArrowsSlice->setSlicePosition(slicePos);
296        NanoVis::velocityArrowsSlice->visible(_sv.showArrows);
297    }
298
299    return needReset;
300}
301
302bool
303Flow::scaleVectorField()
304{
305    float *vdata = getScaledVector();
306    if (_volume != NULL) {
307        TRACE("Updating existing volume: %s", _volume->name());
308        _volume->setData(vdata, magMin, magMax, 0);
309    } else {
310        _volume = makeVolume(vdata);
311        if (_volume == NULL) {
312            return false;
313        }
314    }
315    delete [] vdata;
316    // FIXME: LIC and arrows should be per-flow
317    if (NanoVis::licRenderer != NULL) {
318        NanoVis::licRenderer->setVectorField(_volume);
319        NanoVis::licRenderer->setSliceAxis(_sv.slicePos.axis);
320        NanoVis::licRenderer->setSlicePosition(getRelativePosition(&_sv.slicePos));
321        NanoVis::licRenderer->visible(_sv.sliceVisible);
322    }
323    if (NanoVis::velocityArrowsSlice != NULL) {
324        NanoVis::velocityArrowsSlice->setVectorField(_volume);
325        NanoVis::velocityArrowsSlice->setSliceAxis(_sv.slicePos.axis);
326        NanoVis::velocityArrowsSlice->setSlicePosition(getRelativePosition(&_sv.slicePos));
327        NanoVis::velocityArrowsSlice->visible(_sv.showArrows);
328    }
329    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
330         itr != _particlesTable.end(); ++itr) {
331        itr->second->setVectorField(_volume);
332    }
333    return true;
334}
335
336void
337Flow::renderBoxes()
338{
339    for (BoxHashmap::iterator itr = _boxTable.begin();
340         itr != _boxTable.end(); ++itr) {
341        if (itr->second->visible()) {
342            itr->second->render(_volume);
343        }
344    }
345}
346
347float *
348Flow::getScaledVector()
349{
350    assert(_data->nComponents() == 3);
351    size_t n = _data->nValues() / _data->nComponents() * 4;
352    float *data = new float[n];
353    memset(data, 0, sizeof(float) * n);
354    float *dest = data;
355    const float *values = _data->values();
356    for (size_t iz = 0; iz < _data->zNum(); iz++) {
357        for (size_t iy = 0; iy < _data->yNum(); iy++) {
358            for (size_t ix = 0; ix < _data->xNum(); ix++) {
359                double vx, vy, vz, vm;
360                vx = values[0];
361                vy = values[1];
362                vz = values[2];
363                vm = sqrt(vx*vx + vy*vy + vz*vz);
364                dest[0] = vm / magMax;
365                dest[1] = vx /(2.0 * magMax) + 0.5;
366                dest[2] = vy /(2.0 * magMax) + 0.5;
367                dest[3] = vz /(2.0 * magMax) + 0.5;
368                values += 3;
369                dest += 4;
370            }
371        }
372    }
373    return data;
374}
375
376Volume *
377Flow::makeVolume(float *data)
378{
379    Volume *volume =
380        NanoVis::loadVolume(_name.c_str(),
381                            _data->xNum(),
382                            _data->yNum(), 
383                            _data->zNum(),
384                            4, data, 
385                            magMin, magMax, 0);
386    volume->xAxis.setRange(_data->xMin(), _data->xMax());
387    volume->yAxis.setRange(_data->yMin(), _data->yMax());
388    volume->zAxis.setRange(_data->zMin(), _data->zMax());
389
390    TRACE("mag=%g %g", magMin, magMax);
391
392    volume->disableCutplane(0);
393    volume->disableCutplane(1);
394    volume->disableCutplane(2);
395
396    /* Initialize the volume with the previously configured values. */
397    volume->transferFunction(_sv.transferFunction);
398    volume->dataEnabled(_sv.showVolume);
399    volume->twoSidedLighting(_sv.twoSidedLighting);
400    volume->outline(_sv.showOutline);
401    volume->opacityScale(_sv.opacity);
402    volume->ambient(_sv.ambient);
403    volume->diffuse(_sv.diffuse);
404    volume->specularLevel(_sv.specular);
405    volume->specularExponent(_sv.specularExp);
406
407    Volume::updatePending = true;
408    return volume;
409}
Note: See TracBrowser for help on using the repository browser.