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

Last change on this file since 3628 was 3611, checked in by ldelgass, 11 years ago

Use nv namespace for classes in nanovis rather than prefixing class names with
Nv (still need to convert shader classes).

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