source: nanovis/trunk/Flow.cpp @ 5722

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

Set flags to update ranges when deleting objects

  • 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->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 (float)position->value;
110    }
111    switch (position->axis) {
112    case AXIS_X:
113        return (float)((position->value - _volume->xAxis.min()) /
114                       (_volume->xAxis.max() - _volume->xAxis.min()));
115    case AXIS_Y:
116        return (float)((position->value - _volume->yAxis.min()) /
117                       (_volume->yAxis.max() - _volume->yAxis.min()));
118    case AXIS_Z:
119        return (float)((position->value - _volume->zAxis.min()) /
120                       (_volume->zAxis.max() - _volume->zAxis.min()));
121    }
122    return 0.0f;
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
337void
338Flow::data(Unirect3d *unirect)
339{
340    float *vdata = getScaledVector(unirect);
341    _volume = makeVolume(unirect, vdata);
342    delete [] vdata;
343    delete unirect;
344    initVolume();
345    scaleVectorField();
346}
347
348void
349Flow::data(Volume *volume)
350{
351    _volume = volume;
352    initVolume();
353    scaleVectorField();
354}
355
356float *
357Flow::getScaledVector(Unirect3d *unirect)
358{
359    assert(unirect->nComponents() == 3);
360    size_t n = unirect->nValues() / unirect->nComponents() * 4;
361    float *data = new float[n];
362    memset(data, 0, sizeof(float) * n);
363    float *dest = data;
364    const float *values = unirect->values();
365    for (size_t iz = 0; iz < unirect->zNum(); iz++) {
366        for (size_t iy = 0; iy < unirect->yNum(); iy++) {
367            for (size_t ix = 0; ix < unirect->xNum(); ix++) {
368                double vx, vy, vz, vm;
369                vx = values[0];
370                vy = values[1];
371                vz = values[2];
372                vm = sqrt(vx*vx + vy*vy + vz*vz);
373                dest[0] = vm / unirect->magMax();
374                dest[1] = vx /(2.0 * unirect->magMax()) + 0.5;
375                dest[2] = vy /(2.0 * unirect->magMax()) + 0.5;
376                dest[3] = vz /(2.0 * unirect->magMax()) + 0.5;
377                values += 3;
378                dest += 4;
379            }
380        }
381    }
382    return data;
383}
384
385Volume *
386Flow::makeVolume(Unirect3d *unirect, float *data)
387{
388    Volume *volume =
389        NanoVis::loadVolume(_name.c_str(),
390                            unirect->xNum(),
391                            unirect->yNum(),
392                            unirect->zNum(),
393                            4, data,
394                            unirect->magMin(),
395                            unirect->magMax(),
396                            0);
397    volume->xAxis.setRange(unirect->xMin(), unirect->xMax());
398    volume->yAxis.setRange(unirect->yMin(), unirect->yMax());
399    volume->zAxis.setRange(unirect->zMin(), unirect->zMax());
400
401    TRACE("mag=%g %g", unirect->magMin(), unirect->magMax());
402
403    return volume;
404}
405
406void
407Flow::initVolume()
408{
409    _volume->disableCutplane(0);
410    _volume->disableCutplane(1);
411    _volume->disableCutplane(2);
412
413    /* Initialize the volume with the previously configured values. */
414    _volume->transferFunction(_sv.transferFunction);
415    _volume->dataEnabled(_sv.showVolume);
416    _volume->twoSidedLighting(_sv.twoSidedLighting);
417    _volume->outline(_sv.showOutline);
418    _volume->opacityScale(_sv.opacity);
419    _volume->ambient(_sv.ambient);
420    _volume->diffuse(_sv.diffuse);
421    _volume->specularLevel(_sv.specular);
422    _volume->specularExponent(_sv.specularExp);
423}
Note: See TracBrowser for help on using the repository browser.