source: trunk/packages/vizservers/vtkvis/Glyphs.cpp @ 3769

Last change on this file since 3769 was 3769, checked in by ldelgass, 7 years ago

Tweak scaling for glyphs: don't apply dataset specific scale factor if not
normalizing scaling. When computing datset scale factor, mesh point clouds to
get cell size (this can fail however), fall back to fraction of bounding box.
Also, bump up scale factor (which controls max size) by two times. Add method
to mask glyph points to a maximum number (protocol to come).

  • Property svn:eol-style set to native
File size: 30.0 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2012  HUBzero Foundation, LLC
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <cstring>
9#include <cfloat>
10
11#include <vtkDataSet.h>
12#include <vtkPointData.h>
13#include <vtkCellData.h>
14#include <vtkCellDataToPointData.h>
15#include <vtkProp.h>
16#include <vtkActor.h>
17#include <vtkProperty.h>
18#include <vtkGlyph3D.h>
19#include <vtkLineSource.h>
20#include <vtkArrowSource.h>
21#include <vtkConeSource.h>
22#include <vtkCubeSource.h>
23#include <vtkCylinderSource.h>
24#include <vtkPlatonicSolidSource.h>
25#include <vtkPointSource.h>
26#include <vtkSphereSource.h>
27#include <vtkTransform.h>
28#include <vtkPolyDataMapper.h>
29#include <vtkTransformPolyDataFilter.h>
30#include <vtkPolyDataNormals.h>
31#include <vtkDelaunay2D.h>
32#include <vtkDelaunay3D.h>
33#include <vtkPolyData.h>
34#include <vtkUnstructuredGrid.h>
35
36#include "Glyphs.h"
37#include "Renderer.h"
38#include "Math.h"
39#include "Trace.h"
40
41using namespace VtkVis;
42
43Glyphs::Glyphs(GlyphShape shape) :
44    GraphicsObject(),
45    _glyphShape(shape),
46    _scalingMode(SCALE_BY_VECTOR_MAGNITUDE),
47    _dataScale(1.0),
48    _scaleFactor(1.0),
49    _normalizeScale(true),
50    _colorMap(NULL),
51    _colorMode(COLOR_BY_SCALAR)
52{
53    _faceCulling = true;
54    _scalingFieldRange[0] = DBL_MAX;
55    _scalingFieldRange[1] = -DBL_MAX;
56    _colorFieldRange[0] = DBL_MAX;
57    _colorFieldRange[1] = -DBL_MAX;
58}
59
60Glyphs::~Glyphs()
61{
62#ifdef WANT_TRACE
63    if (_dataSet != NULL)
64        TRACE("Deleting Glyphs for %s", _dataSet->getName().c_str());
65    else
66        TRACE("Deleting Glyphs with NULL DataSet");
67#endif
68}
69
70void Glyphs::setDataSet(DataSet *dataSet,
71                        Renderer *renderer)
72{
73    if (_dataSet != dataSet) {
74        _dataSet = dataSet;
75
76        _renderer = renderer;
77
78        if (renderer->getUseCumulativeRange()) {
79            renderer->getCumulativeDataRange(_dataRange,
80                                             _dataSet->getActiveScalarsName(),
81                                             1);
82            renderer->getCumulativeDataRange(_vectorMagnitudeRange,
83                                             _dataSet->getActiveVectorsName(),
84                                             3);
85            for (int i = 0; i < 3; i++) {
86                renderer->getCumulativeDataRange(_vectorComponentRange[i],
87                                                 _dataSet->getActiveVectorsName(),
88                                                 3, i);
89            }
90        } else {
91            _dataSet->getScalarRange(_dataRange);
92            _dataSet->getVectorRange(_vectorMagnitudeRange);
93            for (int i = 0; i < 3; i++) {
94                _dataSet->getVectorRange(_vectorComponentRange[i], i);
95            }
96        }
97
98        update();
99    }
100}
101
102/**
103 * \brief Set the shape of the glyphs
104 */
105void Glyphs::setGlyphShape(GlyphShape shape)
106{
107    _glyphShape = shape;
108
109    // Note: using vtkTransformPolyDataFilter instead of the vtkGlyph3D's
110    // SourceTransform because of a bug: vtkGlyph3D doesn't transform normals
111    // by the SourceTransform, so the lighting would be wrong
112
113    bool needsNormals = false;
114    double featureAngle = 90.;
115
116    switch (_glyphShape) {
117    case LINE:
118        // Length of 1, centered at origin
119        _glyphSource = vtkSmartPointer<vtkLineSource>::New();
120        break;
121    case ARROW: {
122        // Height of 1, Tip radius .1, tip length .35, shaft radius .03
123        _glyphSource = vtkSmartPointer<vtkArrowSource>::New();
124        vtkSmartPointer<vtkArrowSource> arrow = vtkArrowSource::SafeDownCast(_glyphSource);
125        arrow->SetTipResolution(8);
126        arrow->SetShaftResolution(8);
127        needsNormals = true;
128    }
129        break;
130    case CONE: {
131        // base length of 1, height 1, centered at origin
132        _glyphSource = vtkSmartPointer<vtkConeSource>::New();
133        vtkSmartPointer<vtkConeSource> cone = vtkConeSource::SafeDownCast(_glyphSource);
134        cone->SetResolution(8);
135        needsNormals = true;
136    }
137        break;
138    case CUBE:
139        // Sides of length 1
140        _glyphSource = vtkSmartPointer<vtkCubeSource>::New();
141        break;
142    case CYLINDER: {
143        // base length of 1, height 1, centered at origin
144        vtkSmartPointer<vtkCylinderSource> csource = vtkSmartPointer<vtkCylinderSource>::New();
145        csource->SetResolution(8);
146        _glyphSource = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
147        _glyphSource->SetInputConnection(csource->GetOutputPort());
148        vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
149        trans->RotateZ(-90.0);
150        vtkTransformPolyDataFilter::SafeDownCast(_glyphSource)->SetTransform(trans);
151      }
152        break;
153    case DODECAHEDRON:
154        // Radius of 1
155        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
156        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToDodecahedron();
157        needsNormals = true;
158        featureAngle = 30.;
159        break;
160    case ICOSAHEDRON:
161        // Radius of 1
162        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
163        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToIcosahedron();
164        needsNormals = true;
165        featureAngle = 30.;
166        break;
167    case OCTAHEDRON:
168        // Radius of 1
169        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
170        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToOctahedron();
171        needsNormals = true;
172        featureAngle = 30.;
173        break;
174    case POINT:
175        _glyphSource = vtkSmartPointer<vtkPointSource>::New();
176        vtkPointSource::SafeDownCast(_glyphSource)->SetNumberOfPoints(1);
177        vtkPointSource::SafeDownCast(_glyphSource)->SetCenter(0, 0, 0);
178        vtkPointSource::SafeDownCast(_glyphSource)->SetRadius(0);
179        vtkPointSource::SafeDownCast(_glyphSource)->SetDistributionToUniform();
180        break;
181    case SPHERE: {
182        // Default radius 0.5
183        _glyphSource = vtkSmartPointer<vtkSphereSource>::New();
184        vtkSmartPointer<vtkSphereSource> sphere = vtkSphereSource::SafeDownCast(_glyphSource);
185        sphere->SetThetaResolution(14);
186        sphere->SetPhiResolution(14);
187    }
188        break;
189    case TETRAHEDRON:
190        // Radius of 1
191        // FIXME: need to rotate inital orientation
192        _glyphSource = vtkSmartPointer<vtkPlatonicSolidSource>::New();
193        vtkPlatonicSolidSource::SafeDownCast(_glyphSource)->SetSolidTypeToTetrahedron();
194        needsNormals = true;
195        featureAngle = 30.;
196        break;
197    default:
198        ERROR("Unknown glyph shape: %d", _glyphShape);
199        return;
200    }
201
202    if (_glyphShape == ICOSAHEDRON ||
203        _glyphShape == TETRAHEDRON) {
204        // These shapes are created with front faces pointing inside
205        setCullFace(CULL_FRONT);
206    } else {
207        setCullFace(CULL_BACK);
208    }
209
210    if (needsNormals && _glyphMapper != NULL) {
211        vtkSmartPointer<vtkPolyDataNormals> normalFilter = vtkSmartPointer<vtkPolyDataNormals>::New();
212        normalFilter->SetFeatureAngle(featureAngle);
213        normalFilter->SetInputConnection(_glyphSource->GetOutputPort());
214        _glyphMapper->SetSourceConnection(normalFilter->GetOutputPort());
215    } else if (_glyphMapper != NULL) {
216        _glyphMapper->SetSourceConnection(_glyphSource->GetOutputPort());
217    }
218}
219
220void Glyphs::setQuality(double quality)
221{
222    if (quality > 10.0)
223        quality = 10.0;
224
225    switch (_glyphShape) {
226    case ARROW: {
227        vtkSmartPointer<vtkArrowSource> arrow = vtkArrowSource::SafeDownCast(_glyphSource);
228        int res = (int)(quality * 8.);
229        if (res < 3) res = 3;
230        arrow->SetTipResolution(res);
231        arrow->SetShaftResolution(res);
232    }
233        break;
234    case CONE: {
235        vtkSmartPointer<vtkConeSource> cone = vtkConeSource::SafeDownCast(_glyphSource);
236        int res = (int)(quality * 8.);
237        if (res < 3) res = 3;
238        cone->SetResolution(res);
239    }
240        break;
241    case CYLINDER: {
242        vtkSmartPointer<vtkCylinderSource> csource =
243            vtkCylinderSource::SafeDownCast(_glyphSource->GetInputAlgorithm(0, 0));
244        if (csource == NULL) {
245            ERROR("Can't get cylinder glyph source");
246            return;
247        }
248        int res = (int)(quality * 8.);
249        if (res < 3) res = 3;
250        csource->SetResolution(res);
251    }
252        break;
253    case SPHERE: {
254        vtkSmartPointer<vtkSphereSource> sphere = vtkSphereSource::SafeDownCast(_glyphSource);
255        int thetaRes = (int)(quality * 14.);
256        int phiRes = thetaRes;
257        if (thetaRes < 4) thetaRes = 4;
258        if (phiRes < 3) phiRes = 3;
259
260        sphere->SetThetaResolution(thetaRes);
261        sphere->SetPhiResolution(phiRes);
262    }
263        break;
264    default:
265        break;
266    }
267    if (_glyphMapper != NULL) {
268        _glyphMapper->Modified();
269        _glyphMapper->Update();
270    }
271}
272
273/**
274 * \brief Internal method to set up pipeline after a state change
275 */
276void Glyphs::update()
277{
278    if (_dataSet == NULL) {
279        return;
280    }
281
282    vtkDataSet *ds = _dataSet->getVtkDataSet();
283
284    if (_glyphMapper == NULL) {
285        _glyphMapper = vtkSmartPointer<vtkGlyph3DMapper>::New();
286        _glyphMapper->SetResolveCoincidentTopologyToPolygonOffset();
287        // If there are color scalars, use them without lookup table (if scalar visibility is on)
288        _glyphMapper->SetColorModeToDefault();
289        _glyphMapper->ScalarVisibilityOn();
290    }
291
292    initProp();
293
294    setGlyphShape(_glyphShape);
295
296    vtkSmartPointer<vtkCellDataToPointData> cellToPtData;
297
298    if (ds->GetPointData() == NULL ||
299        ds->GetPointData()->GetScalars() == NULL) {
300        if (ds->GetCellData() != NULL &&
301            ds->GetCellData()->GetScalars() != NULL) {
302            TRACE("Generating point data scalars from cell data for: %s", _dataSet->getName().c_str());
303            cellToPtData =
304                vtkSmartPointer<vtkCellDataToPointData>::New();
305#ifdef USE_VTK6
306            cellToPtData->SetInputData(ds);
307#else
308            cellToPtData->SetInput(ds);
309#endif
310            //cellToPtData->PassCellDataOn();
311            cellToPtData->Update();
312            ds = cellToPtData->GetOutput();
313        } else {
314            TRACE("No scalar data in dataset %s", _dataSet->getName().c_str());
315        }
316    }
317
318#ifdef USE_VTK6
319    _glyphMapper->SetInputData(ds);
320#else
321    _glyphMapper->SetInputConnection(ds->GetProducerPort());
322#endif
323
324    if (ds->GetPointData()->GetVectors() != NULL) {
325        TRACE("Setting scale mode to vector magnitude");
326        setScalingMode(SCALE_BY_VECTOR_MAGNITUDE);
327    } else {
328        TRACE("Setting scale mode to scalar");
329        setScalingMode(SCALE_BY_SCALAR);
330    }
331
332    if (_dataSet->isCloud()) {
333        PrincipalPlane plane;
334        double offset;
335        if (_dataSet->is2D(&plane, &offset)) {
336            // 2D cloud
337            vtkSmartPointer<vtkDelaunay2D> mesher = vtkSmartPointer<vtkDelaunay2D>::New();
338            if (plane == PLANE_ZY) {
339                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
340                trans->RotateWXYZ(90, 0, 1, 0);
341                if (offset != 0.0) {
342                    trans->Translate(-offset, 0, 0);
343                }
344                mesher->SetTransform(trans);
345            } else if (plane == PLANE_XZ) {
346                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
347                trans->RotateWXYZ(-90, 1, 0, 0);
348                if (offset != 0.0) {
349                    trans->Translate(0, -offset, 0);
350                }
351                mesher->SetTransform(trans);
352            } else if (offset != 0.0) {
353                // XY with Z offset
354                vtkSmartPointer<vtkTransform> trans = vtkSmartPointer<vtkTransform>::New();
355                trans->Translate(0, 0, -offset);
356                mesher->SetTransform(trans);
357            }
358#ifdef USE_VTK6
359            mesher->SetInputData(ds);
360#else
361            mesher->SetInput(ds);
362#endif
363            mesher->Update();
364            vtkPolyData *pd = mesher->GetOutput();
365            if (pd->GetNumberOfPolys() == 0) {
366                // Meshing failed, fall back to scale based on bounds
367                double bounds[6];
368                _dataSet->getBounds(bounds);
369                double xlen = bounds[1] - bounds[0];
370                double ylen = bounds[3] - bounds[2];
371                double zlen = bounds[5] - bounds[4];
372                double max = max3(xlen, ylen, zlen);
373                _dataScale = max / 64.0;
374            } else {
375                double cellSizeRange[2];
376                double avgSize;
377                DataSet::getCellSizeRange(pd, cellSizeRange, &avgSize);
378                _dataScale = avgSize * 2.0;
379            }
380        } else {
381            // 3D cloud
382            vtkSmartPointer<vtkDelaunay3D> mesher = vtkSmartPointer<vtkDelaunay3D>::New();
383#ifdef USE_VTK6
384            mesher->SetInputData(ds);
385#else
386            mesher->SetInput(ds);
387#endif
388            mesher->Update();
389            vtkUnstructuredGrid *ugrid = mesher->GetOutput();
390            if (ugrid->GetNumberOfCells() == 0) {
391                // Meshing failed, fall back to scale based on bounds
392                double bounds[6];
393                _dataSet->getBounds(bounds);
394                double xlen = bounds[1] - bounds[0];
395                double ylen = bounds[3] - bounds[2];
396                double zlen = bounds[5] - bounds[4];
397                double max = max3(xlen, ylen, zlen);
398                _dataScale = max / 64.0;
399            } else {
400                double cellSizeRange[2];
401                double avgSize;
402                DataSet::getCellSizeRange(ugrid, cellSizeRange, &avgSize);
403                _dataScale = avgSize * 2.0;
404            }
405        }
406    } else {
407        double cellSizeRange[2];
408        double avgSize;
409        _dataSet->getCellSizeRange(cellSizeRange, &avgSize);
410        _dataScale = avgSize * 2.0;
411    }
412
413    TRACE("Data scale factor: %g", _dataScale);
414
415    // Normalize sizes to [0,1] * ScaleFactor
416    _glyphMapper->SetClamping(_normalizeScale ? 1 : 0);
417    if (_normalizeScale) {
418        _glyphMapper->SetScaleFactor(_scaleFactor * _dataScale);
419        TRACE("Setting scale factor: %g", _scaleFactor * _dataScale);
420    } else {
421        _glyphMapper->SetScaleFactor(_scaleFactor);
422        TRACE("Setting scale factor: %g", _scaleFactor);
423    }
424    _glyphMapper->ScalingOn();
425
426    if (_lut == NULL) {
427        setColorMap(ColorMap::getDefault());
428    }
429
430    if (ds->GetPointData()->GetScalars() == NULL) {
431        TRACE("Setting color mode to vector magnitude");
432        setColorMode(COLOR_BY_VECTOR_MAGNITUDE);
433    } else {
434        TRACE("Setting color mode to scalar");
435        setColorMode(COLOR_BY_SCALAR);
436    }
437
438    getActor()->SetMapper(_glyphMapper);
439    _glyphMapper->Update();
440}
441
442/**
443 * \brief Control if field data range is normalized to [0,1] before
444 * applying scale factor
445 */
446void Glyphs::setNormalizeScale(bool normalize)
447{
448    if (_normalizeScale != normalize) {
449        _normalizeScale = normalize;
450        if (_glyphMapper != NULL) {
451            _glyphMapper->SetClamping(_normalizeScale ? 1 : 0);
452            if (_normalizeScale) {
453                _glyphMapper->SetScaleFactor(_scaleFactor * _dataScale);
454                TRACE("Setting scale factor: %g", _scaleFactor * _dataScale);
455            } else {
456                _glyphMapper->SetScaleFactor(_scaleFactor);
457                TRACE("Setting scale factor: %g", _scaleFactor);
458            }
459        }
460    }
461}
462
463/**
464 * \brief Turn on/off orienting glyphs from a vector field
465 */
466void Glyphs::setOrientMode(bool mode, const char *name)
467{
468    if (_glyphMapper != NULL) {
469        _glyphMapper->SetOrient(mode ? 1 : 0);
470        if (name != NULL && strlen(name) > 0) {
471            _glyphMapper->SetOrientationArray(name);
472        } else {
473            _glyphMapper->SetOrientationArray(vtkDataSetAttributes::VECTORS);
474        }
475    }
476}
477
478/**
479 * \brief Control how glyphs are scaled
480 */
481void Glyphs::setScalingMode(ScalingMode mode, const char *name, double range[2])
482{
483    _scalingMode = mode;
484
485    if (_dataSet == NULL || _glyphMapper == NULL)
486        return;
487
488    if (name != NULL && strlen(name) > 0) {
489        if (!_dataSet->hasField(name, DataSet::POINT_DATA)) {
490            ERROR("Field not found: %s", name);
491            return;
492        }
493        _scalingFieldName = name;
494    } else
495        _scalingFieldName.clear();
496    if (range == NULL) {
497        _scalingFieldRange[0] = DBL_MAX;
498        _scalingFieldRange[1] = -DBL_MAX;
499    } else {
500        memcpy(_scalingFieldRange, range, sizeof(double)*2);
501    }
502
503    if (name != NULL && strlen(name) > 0) {
504        _glyphMapper->SetScaleArray(name);
505    } else {
506        if (mode == SCALE_BY_SCALAR) {
507            _glyphMapper->SetScaleArray(vtkDataSetAttributes::SCALARS);
508        } else {
509            _glyphMapper->SetScaleArray(vtkDataSetAttributes::VECTORS);
510        }
511    }
512
513    if (range != NULL) {
514        TRACE("Setting size range to: %g,%g", range[0], range[1]);
515        _glyphMapper->SetRange(range);
516    } else if (name != NULL && strlen(name) > 0) {
517        double r[2];
518        DataSet::DataAttributeType type = DataSet::POINT_DATA;
519        int comp = -1;
520
521        if (_renderer->getUseCumulativeRange()) {
522            int numComponents;
523            if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
524                ERROR("Field not found: %s, type: %d", name, type);
525                return;
526            } else if (mode == SCALE_BY_VECTOR_COMPONENTS && numComponents < 3) {
527                ERROR("Field %s needs 3 components but has only %d components",
528                      name, numComponents);
529                return;
530            }
531            if (mode == SCALE_BY_VECTOR_COMPONENTS) {
532                double tmpR[2];
533                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 0);
534                r[0] = tmpR[0];
535                r[1] = tmpR[1];
536                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 1);
537                r[0] = min2(r[0], tmpR[0]);
538                r[1] = max2(r[1], tmpR[1]);
539                _renderer->getCumulativeDataRange(tmpR, name, type, numComponents, 2);
540                r[0] = min2(r[0], tmpR[0]);
541                r[1] = max2(r[1], tmpR[1]);
542            } else {
543                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
544            }
545        } else {
546            if (mode == SCALE_BY_VECTOR_COMPONENTS) {
547                double tmpR[2];
548                _dataSet->getDataRange(tmpR, name, type, 0);
549                r[0] = tmpR[0];
550                r[1] = tmpR[1];
551                _dataSet->getDataRange(tmpR, name, type, 1);
552                r[0] = min2(r[0], tmpR[0]);
553                r[1] = max2(r[1], tmpR[1]);
554                _dataSet->getDataRange(tmpR, name, type, 2);
555                r[0] = min2(r[0], tmpR[0]);
556                r[1] = max2(r[1], tmpR[1]);
557            } else {
558                _dataSet->getDataRange(r, name, type, comp);
559            }
560        }
561        TRACE("Setting size range to: %g,%g", r[0], r[1]);
562        _glyphMapper->SetRange(r);
563    } else {
564        switch (mode) {
565        case SCALE_BY_SCALAR:
566            TRACE("Setting size range to: %g,%g", _dataRange[0], _dataRange[1]);
567            _glyphMapper->SetRange(_dataRange);
568            break;
569        case SCALE_BY_VECTOR_MAGNITUDE:
570            TRACE("Setting size range to: %g,%g", _vectorMagnitudeRange[0], _vectorMagnitudeRange[1]);
571            _glyphMapper->SetRange(_vectorMagnitudeRange);
572            break;
573        case SCALE_BY_VECTOR_COMPONENTS: {
574            double sizeRange[2];
575            sizeRange[0] = _vectorComponentRange[0][0];
576            sizeRange[1] = _vectorComponentRange[0][1];
577            sizeRange[0] = min2(sizeRange[0], _vectorComponentRange[1][0]);
578            sizeRange[1] = max2(sizeRange[1], _vectorComponentRange[1][1]);
579            sizeRange[0] = min2(sizeRange[0], _vectorComponentRange[2][0]);
580            sizeRange[1] = max2(sizeRange[1], _vectorComponentRange[2][1]);
581            TRACE("Setting size range to: %g,%g", sizeRange[0], sizeRange[1]);
582            _glyphMapper->SetRange(sizeRange);
583        }
584            break;
585        case SCALING_OFF:
586        default:
587            ;
588        }
589    }
590
591    switch (mode) {
592    case SCALE_BY_SCALAR:
593    case SCALE_BY_VECTOR_MAGNITUDE:
594        _glyphMapper->SetScaleModeToScaleByMagnitude();
595        break;
596    case SCALE_BY_VECTOR_COMPONENTS:
597        _glyphMapper->SetScaleModeToScaleByVectorComponents();
598        break;
599    case SCALING_OFF:
600    default:
601        _glyphMapper->SetScaleModeToNoDataScaling();
602    }
603}
604
605void Glyphs::setScalingMode(ScalingMode mode)
606{
607    setScalingMode(mode, NULL, NULL);
608}
609
610void Glyphs::setColorMode(ColorMode mode,
611                          const char *name, double range[2])
612{
613    _colorMode = mode;
614    if (name == NULL)
615        _colorFieldName.clear();
616    else
617        _colorFieldName = name;
618    if (range == NULL) {
619        _colorFieldRange[0] = DBL_MAX;
620        _colorFieldRange[1] = -DBL_MAX;
621    } else {
622        memcpy(_colorFieldRange, range, sizeof(double)*2);
623    }
624
625    if (_dataSet == NULL || _glyphMapper == NULL)
626        return;
627
628    if (name != NULL && strlen(name) > 0) {
629        _glyphMapper->SetScalarModeToUsePointFieldData();
630        _glyphMapper->SelectColorArray(name);
631    } else {
632        _glyphMapper->SetScalarModeToDefault();
633    }
634
635    if (_lut != NULL) {
636        if (range != NULL) {
637            _lut->SetRange(range);
638        } else if (name != NULL && strlen(name) > 0) {
639            double r[2];
640            int comp = -1;
641            if (mode == COLOR_BY_VECTOR_X)
642                comp = 0;
643            else if (mode == COLOR_BY_VECTOR_Y)
644                comp = 1;
645            else if (mode == COLOR_BY_VECTOR_Z)
646                comp = 2;
647
648            DataSet::DataAttributeType type = DataSet::POINT_DATA;
649
650            if (_renderer->getUseCumulativeRange()) {
651                int numComponents;
652                if  (!_dataSet->getFieldInfo(name, type, &numComponents)) {
653                    ERROR("Field not found: %s, type: %d", name, type);
654                    return;
655                } else if (numComponents < comp+1) {
656                    ERROR("Request for component %d in field with %d components",
657                          comp, numComponents);
658                    return;
659                }
660                _renderer->getCumulativeDataRange(r, name, type, numComponents, comp);
661            } else {
662                _dataSet->getDataRange(r, name, type, comp);
663            }
664            TRACE("Setting lut range to: %g,%g", r[0], r[1]);
665            _lut->SetRange(r);
666        }
667    }
668
669    switch (mode) {
670    case COLOR_BY_SCALAR:
671        _glyphMapper->ScalarVisibilityOn();
672        break;
673    case COLOR_BY_VECTOR_MAGNITUDE:
674        _glyphMapper->ScalarVisibilityOn();
675        if (_lut != NULL) {
676            _lut->SetVectorModeToMagnitude();
677        }
678        break;
679    case COLOR_BY_VECTOR_X:
680        _glyphMapper->ScalarVisibilityOn();
681        if (_lut != NULL) {
682            _lut->SetVectorModeToComponent();
683            _lut->SetVectorComponent(0);
684        }
685        break;
686    case COLOR_BY_VECTOR_Y:
687        _glyphMapper->ScalarVisibilityOn();
688        if (_lut != NULL) {
689            _lut->SetVectorModeToComponent();
690            _lut->SetVectorComponent(1);
691        }
692        break;
693    case COLOR_BY_VECTOR_Z:
694        _glyphMapper->ScalarVisibilityOn();
695        if (_lut != NULL) {
696            _lut->SetVectorModeToComponent();
697            _lut->SetVectorComponent(2);
698        }
699        break;
700    case COLOR_CONSTANT:
701    default:
702        _glyphMapper->ScalarVisibilityOff();
703        break;
704    }
705}
706
707void Glyphs::setColorMode(ColorMode mode)
708{
709    _colorMode = mode;
710    if (_dataSet == NULL)
711        return;
712
713    switch (mode) {
714    case COLOR_BY_SCALAR:
715        setColorMode(mode,
716                     _dataSet->getActiveScalarsName(),
717                     _dataRange);
718        break;
719    case COLOR_BY_VECTOR_MAGNITUDE:
720        setColorMode(mode,
721                     _dataSet->getActiveVectorsName(),
722                     _vectorMagnitudeRange);
723        break;
724    case COLOR_BY_VECTOR_X:
725        setColorMode(mode,
726                     _dataSet->getActiveVectorsName(),
727                     _vectorComponentRange[0]);
728        break;
729    case COLOR_BY_VECTOR_Y:
730        setColorMode(mode,
731                     _dataSet->getActiveVectorsName(),
732                     _vectorComponentRange[1]);
733        break;
734    case COLOR_BY_VECTOR_Z:
735        setColorMode(mode,
736                     _dataSet->getActiveVectorsName(),
737                     _vectorComponentRange[2]);
738        break;
739    case COLOR_CONSTANT:
740    default:
741        setColorMode(mode, NULL, NULL);
742        break;
743    }
744}
745
746/**
747 * \brief Turn on/off orienting glyphs from a vector field
748 */
749void Glyphs::setOrient(bool state)
750{
751    if (_glyphMapper != NULL) {
752        _glyphMapper->SetOrient(state ? 1 : 0);
753    }
754}
755
756/**
757 * \brief Controls relative scaling of glyphs
758 */
759void Glyphs::setScaleFactor(double scale)
760{
761    _scaleFactor = scale;
762    if (_glyphMapper != NULL) {
763        if (_normalizeScale) {
764            _glyphMapper->SetScaleFactor(_scaleFactor * _dataScale);
765            TRACE("Setting scale factor: %g", _scaleFactor * _dataScale);
766        } else {
767            _glyphMapper->SetScaleFactor(_scaleFactor);
768            TRACE("Setting scale factor: %g", _scaleFactor);
769        }
770    }
771}
772
773void Glyphs::updateRanges(Renderer *renderer)
774{
775    if (_dataSet == NULL) {
776        ERROR("called before setDataSet");
777        return;
778    }
779
780    if (renderer->getUseCumulativeRange()) {
781        renderer->getCumulativeDataRange(_dataRange,
782                                         _dataSet->getActiveScalarsName(),
783                                         1);
784        renderer->getCumulativeDataRange(_vectorMagnitudeRange,
785                                         _dataSet->getActiveVectorsName(),
786                                         3);
787        for (int i = 0; i < 3; i++) {
788            renderer->getCumulativeDataRange(_vectorComponentRange[i],
789                                             _dataSet->getActiveVectorsName(),
790                                             3, i);
791        }
792    } else {
793        _dataSet->getScalarRange(_dataRange);
794        _dataSet->getVectorRange(_vectorMagnitudeRange);
795        for (int i = 0; i < 3; i++) {
796            _dataSet->getVectorRange(_vectorComponentRange[i], i);
797        }
798    }
799
800    // Need to update color map ranges and/or active vector field
801    double *rangePtr = _colorFieldRange;
802    if (_colorFieldRange[0] > _colorFieldRange[1]) {
803        rangePtr = NULL;
804    }
805    setColorMode(_colorMode, _colorFieldName.c_str(), rangePtr);
806
807    rangePtr = _scalingFieldRange;
808    if (_scalingFieldRange[0] > _scalingFieldRange[1]) {
809        rangePtr = NULL;
810    }
811    setScalingMode(_scalingMode, _scalingFieldName.c_str(), rangePtr);
812}
813
814/**
815 * \brief Called when the color map has been edited
816 */
817void Glyphs::updateColorMap()
818{
819    setColorMap(_colorMap);
820}
821
822/**
823 * \brief Associate a colormap lookup table with the DataSet
824 */
825void Glyphs::setColorMap(ColorMap *cmap)
826{
827    if (cmap == NULL)
828        return;
829
830    _colorMap = cmap;
831 
832    if (_lut == NULL) {
833        _lut = vtkSmartPointer<vtkLookupTable>::New();
834        if (_glyphMapper != NULL) {
835            _glyphMapper->UseLookupTableScalarRangeOn();
836            _glyphMapper->SetLookupTable(_lut);
837        }
838        _lut->DeepCopy(cmap->getLookupTable());
839        switch (_colorMode) {
840        case COLOR_CONSTANT:
841        case COLOR_BY_SCALAR:
842            _lut->SetRange(_dataRange);
843            break;
844        case COLOR_BY_VECTOR_MAGNITUDE:
845            _lut->SetRange(_vectorMagnitudeRange);
846            break;
847        case COLOR_BY_VECTOR_X:
848            _lut->SetRange(_vectorComponentRange[0]);
849            break;
850        case COLOR_BY_VECTOR_Y:
851            _lut->SetRange(_vectorComponentRange[1]);
852            break;
853        case COLOR_BY_VECTOR_Z:
854            _lut->SetRange(_vectorComponentRange[2]);
855            break;
856        default:
857            break;
858        }
859    } else {
860        double range[2];
861        _lut->GetTableRange(range);
862        _lut->DeepCopy(cmap->getLookupTable());
863        _lut->SetRange(range);
864        _lut->Modified();
865    }
866
867    switch (_colorMode) {
868    case COLOR_BY_VECTOR_MAGNITUDE:
869        _lut->SetVectorModeToMagnitude();
870        break;
871    case COLOR_BY_VECTOR_X:
872        _lut->SetVectorModeToComponent();
873        _lut->SetVectorComponent(0);
874        break;
875    case COLOR_BY_VECTOR_Y:
876        _lut->SetVectorModeToComponent();
877        _lut->SetVectorComponent(1);
878        break;
879    case COLOR_BY_VECTOR_Z:
880        _lut->SetVectorModeToComponent();
881        _lut->SetVectorComponent(2);
882        break;
883    default:
884        break;
885    }
886}
887
888/**
889 * \brief Limit the number of glyphs displayed
890 *
891 * The choice of glyphs to display can be based on sampling every
892 * n-th point (ratio) or by random sample
893 *
894 * \param max Maximum number of glyphs to display, negative means display all
895 * \param random Flag to enable/disable random sampling
896 * \param offset If random is false, this controls the first sample point
897 * \param ratio If random is false, this ratio controls every n-th point sampling
898 */
899void Glyphs::setMaximumNumberOfGlyphs(int max, bool random, int offset, int ratio)
900{
901    if (_dataSet == NULL || _glyphMapper == NULL)
902        return;
903
904    if (max < 0) {
905        if (_maskPoints != NULL) {
906#ifdef USE_VTK6
907            _glyphMapper->SetInputData(_dataSet->getVtkDataSet());
908#else
909            _glyphMapper->SetInputConnection(_dataSet->getVtkDataSet()->GetProducerPort());
910#endif
911            _maskPoints = NULL;
912        }
913    } else {
914        if (_maskPoints == NULL) {
915            _maskPoints = vtkSmartPointer<vtkMaskPoints>::New();
916        }
917#ifdef USE_VTK6
918        _maskPoints->SetInputData(_dataSet->getVtkDataSet());
919#else
920        _maskPoints->SetInput(_dataSet->getVtkDataSet());
921#endif
922        _maskPoints->SetMaximumNumberOfPoints(max);
923        _maskPoints->SetOffset(offset);
924        _maskPoints->SetOnRatio(ratio);
925        _maskPoints->SetRandomMode((random ? 1 : 0));
926        _maskPoints->GenerateVerticesOff();
927        _glyphMapper->SetInputConnection(_maskPoints->GetOutputPort());
928    }
929}
930
931/**
932 * \brief Set a group of world coordinate planes to clip rendering
933 *
934 * Passing NULL for planes will remove all cliping planes
935 */
936void Glyphs::setClippingPlanes(vtkPlaneCollection *planes)
937{
938    if (_glyphMapper != NULL) {
939        _glyphMapper->SetClippingPlanes(planes);
940    }
941}
Note: See TracBrowser for help on using the repository browser.