source: nanovis/trunk/Flow.cpp @ 5586

Last change on this file since 5586 was 5586, checked in by ldelgass, 9 years ago

whitespace

  • Property svn:eol-style set to native
File size: 11.1 KB
RevLine 
[3597]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
[3630]12#include <float.h>
13
[3597]14#include <tcl.h>
15
[3630]16#include <vrmath/BBox.h>
[3597]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"
[3611]25#include "LIC.h"
[3597]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
[3611]33using namespace nv;
[3597]34using namespace vrmath;
35
[3630]36bool Flow::updatePending = false;
37double Flow::magMin = DBL_MAX;
38double Flow::magMax = -DBL_MAX;
39
[3597]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
[4056]58    FreeSwitches(_switches, &_sv, 0);
[3597]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
[3630]86    BBox allBounds;
[3597]87    if (isDataLoaded()) {
[3630]88        BBox bbox;
[3935]89        _volume->getBounds(bbox.min, bbox.max);
[3630]90        allBounds.extend(bbox);
[3597]91    }
92    for (BoxHashmap::iterator itr = _boxTable.begin();
93         itr != _boxTable.end(); ++itr) {
94        FlowBox *box = itr->second;
95        if (!onlyVisible || box->visible()) {
[3630]96            BBox bbox;
97            box->getBounds(bbox.min, bbox.max);
98            allBounds.extend(bbox);
[3597]99        }
100    }
[3630]101    min = allBounds.min;
102    max = allBounds.max;
[3597]103}
104
105float
106Flow::getRelativePosition(FlowPosition *position)
107{
108    if (position->flags == RELPOS) {
[5399]109        return (float)position->value;
[3597]110    }
111    switch (position->axis) {
[5586]112    case AXIS_X:
[5399]113        return (float)((position->value - _volume->xAxis.min()) /
114                       (_volume->xAxis.max() - _volume->xAxis.min()));
[5586]115    case AXIS_Y:
[5399]116        return (float)((position->value - _volume->yAxis.min()) /
117                       (_volume->yAxis.max() - _volume->yAxis.min()));
[5586]118    case AXIS_Z:
[5399]119        return (float)((position->value - _volume->zAxis.min()) /
120                       (_volume->zAxis.max() - _volume->zAxis.min()));
[3597]121    }
[5399]122    return 0.0f;
[3597]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
[3630]259Flow::configure()
[3597]260{
[3630]261    bool needReset = false;
262
[3597]263    if (_volume != NULL) {
[3630]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);
[3597]273    }
[3630]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);
[3597]288    }
[3630]289    if (NanoVis::velocityArrowsSlice != NULL) {
290        NanoVis::velocityArrowsSlice->setSliceAxis(_sv.slicePos.axis);
291        NanoVis::velocityArrowsSlice->setSlicePosition(slicePos);
292        NanoVis::velocityArrowsSlice->visible(_sv.showArrows);
[3597]293    }
294
[3630]295    return needReset;
296}
[3597]297
[3630]298bool
299Flow::scaleVectorField()
300{
[3935]301    if (_volume == NULL) {
[3936]302        ERROR("Called with NULL _volume");
[3935]303        return false;
[3630]304    }
[3935]305
[3630]306    // FIXME: LIC and arrows should be per-flow
[3597]307    if (NanoVis::licRenderer != NULL) {
[3630]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);
[3597]312    }
313    if (NanoVis::velocityArrowsSlice != NULL) {
[3630]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);
[3597]318    }
319    for (ParticlesHashmap::iterator itr = _particlesTable.begin();
320         itr != _particlesTable.end(); ++itr) {
[3630]321        itr->second->setVectorField(_volume);
[3597]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 *
[4056]338Flow::getScaledVector(Unirect3d *unirect)
[3597]339{
[3935]340    assert(unirect->nComponents() == 3);
341    size_t n = unirect->nValues() / unirect->nComponents() * 4;
[3597]342    float *data = new float[n];
343    memset(data, 0, sizeof(float) * n);
344    float *dest = data;
[3935]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++) {
[3597]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);
[3935]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;
[3597]358                values += 3;
359                dest += 4;
360            }
361        }
362    }
363    return data;
364}
365
366Volume *
[4056]367Flow::makeVolume(Unirect3d *unirect, float *data)
[3597]368{
369    Volume *volume =
370        NanoVis::loadVolume(_name.c_str(),
[3935]371                            unirect->xNum(),
372                            unirect->yNum(),
373                            unirect->zNum(),
[3597]374                            4, data,
[3935]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());
[3597]381
[3935]382    TRACE("mag=%g %g", unirect->magMin(), unirect->magMax());
[3597]383
[3935]384    return volume;
385}
[3597]386
[3935]387void
388Flow::initVolume()
389{
390    _volume->disableCutplane(0);
391    _volume->disableCutplane(1);
392    _volume->disableCutplane(2);
393
[3597]394    /* Initialize the volume with the previously configured values. */
[3935]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);
[3597]404
405    Volume::updatePending = true;
406}
Note: See TracBrowser for help on using the repository browser.