source: nanovis/branches/1.2/Flow.cpp @ 5588

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

Merge support for VTK vector fields in nanovis to release branch

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