source: nanovis/trunk/Flow.cpp @ 4903

Last change on this file since 4903 was 4056, checked in by ldelgass, 10 years ago

Use nv namespace for internal classes (not Rappture) to make it easier to find
dependencies on the Rappture libraries.

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