1 #include "vtkF3DRendererWithColoring.h"
2 
3 #include "F3DLog.h"
4 
5 #include <vtkColorTransferFunction.h>
6 #include <vtkDataSetAttributes.h>
7 #include <vtkFieldData.h>
8 #include <vtkObjectFactory.h>
9 #include <vtkPiecewiseFunction.h>
10 #include <vtkPolyData.h>
11 #include <vtkVolumeProperty.h>
12 
13 vtkStandardNewMacro(vtkF3DRendererWithColoring);
14 
15 //----------------------------------------------------------------------------
Initialize(const F3DOptions & options,const std::string & fileInfo)16 void vtkF3DRendererWithColoring::Initialize(const F3DOptions& options, const std::string& fileInfo)
17 {
18   this->Superclass::Initialize(options, fileInfo);
19 
20   this->SetScalarBarActor(nullptr);
21   this->SetGeometryActor(nullptr);
22   this->SetPointSpritesActor(nullptr);
23   this->SetVolumeProp(nullptr);
24   this->SetPolyDataMapper(nullptr);
25   this->SetPointGaussianMapper(nullptr);
26   this->SetVolumeMapper(nullptr);
27 
28   this->UsePointSprites = this->Options.PointSprites;
29   this->UseVolume = this->Options.Volume;
30   this->UseInverseOpacityFunction = this->Options.InverseOpacityFunction;
31   this->ScalarBarVisible = this->Options.Bar;
32 
33   this->PointDataForColoring = nullptr;
34   this->CellDataForColoring = nullptr;
35   this->DataForColoring = nullptr;
36   this->ArrayIndexForColoring = -1;
37   this->ComponentForColoring = -1;
38 
39   this->ColorTransferFunctionConfigured = false;
40   this->PolyDataMapperConfigured = false;
41   this->PointGaussianMapperConfigured = false;
42   this->VolumeConfigured = false;
43   this->ScalarBarActorConfigured = false;
44 
45   this->CheatSheetNeedUpdate = true;
46 }
47 
48 //----------------------------------------------------------------------------
GenerateMetaDataDescription()49 std::string vtkF3DRendererWithColoring::GenerateMetaDataDescription()
50 {
51   std::string description;
52   description += " \n";
53   if (this->PolyDataMapper)
54   {
55     vtkDataSet* dataset = this->PolyDataMapper->GetInput();
56     if (dataset)
57     {
58       description += " Number of points: ";
59       description += std::to_string(dataset->GetNumberOfPoints());
60       description += " \n Number of cells: ";
61       description += std::to_string(dataset->GetNumberOfCells());
62       description += " \n";
63 
64       // Field Data
65       vtkFieldData* fieldData = dataset->GetFieldData();
66       int nbArrays = fieldData->GetNumberOfArrays();
67       for (vtkIdType i = 0; i < nbArrays; i++)
68       {
69         vtkAbstractArray* array = fieldData->GetAbstractArray(i);
70         if (array)
71         {
72           vtkIdType nbTuples = array->GetNumberOfTuples();
73           if (nbTuples == 1)
74           {
75             description += " ";
76             description += array->GetName();
77             description += " = ";
78             description += array->GetVariantValue(0).ToString();
79             description += " \n";
80           }
81         }
82       }
83     }
84     else
85     {
86       description += " Unavailable\n";
87     }
88   }
89   else
90   {
91     description += " Unavailable\n";
92   }
93 
94   return description;
95 }
96 
97 //----------------------------------------------------------------------------
SetUsePointSprites(bool use)98 void vtkF3DRendererWithColoring::SetUsePointSprites(bool use)
99 {
100   this->UsePointSprites = use;
101   this->UpdateInternalActors();
102   this->SetupRenderPasses();
103   this->CheatSheetNeedUpdate = true;
104 }
105 
106 //----------------------------------------------------------------------------
UsingPointSprites()107 bool vtkF3DRendererWithColoring::UsingPointSprites()
108 {
109   return this->UsePointSprites;
110 }
111 
112 //----------------------------------------------------------------------------
SetUseVolume(bool use)113 void vtkF3DRendererWithColoring::SetUseVolume(bool use)
114 {
115   this->UseVolume = use;
116   this->UpdateInternalActors();
117   this->SetupRenderPasses();
118   this->CheatSheetNeedUpdate = true;
119 }
120 
121 //----------------------------------------------------------------------------
UsingVolume()122 bool vtkF3DRendererWithColoring::UsingVolume()
123 {
124   return this->UseVolume;
125 }
126 
127 //----------------------------------------------------------------------------
SetUseInverseOpacityFunction(bool use)128 void vtkF3DRendererWithColoring::SetUseInverseOpacityFunction(bool use)
129 {
130   this->UseInverseOpacityFunction = use;
131   if (this->VolumeProp)
132   {
133     vtkPiecewiseFunction* pwf = this->VolumeProp->GetProperty()->GetScalarOpacity();
134     if (pwf->GetSize() == 2)
135     {
136       double range[2];
137       pwf->GetRange(range);
138 
139       pwf->RemoveAllPoints();
140       pwf->AddPoint(range[0], this->UseInverseOpacityFunction ? 1.0 : 0.0);
141       pwf->AddPoint(range[1], this->UseInverseOpacityFunction ? 0.0 : 1.0);
142     }
143     this->SetupRenderPasses();
144   }
145   this->CheatSheetNeedUpdate = true;
146 }
147 
148 //----------------------------------------------------------------------------
UsingInverseOpacityFunction()149 bool vtkF3DRendererWithColoring::UsingInverseOpacityFunction()
150 {
151   return this->UseInverseOpacityFunction;
152 }
153 
154 //----------------------------------------------------------------------------
CycleArrayIndexForColoring()155 void vtkF3DRendererWithColoring::CycleArrayIndexForColoring()
156 {
157   if (this->UseVolume)
158   {
159     this->ArrayIndexForColoring =
160       (this->ArrayIndexForColoring + 1) % this->DataForColoring->GetNumberOfArrays();
161   }
162   else
163   {
164     // Cycle through arrays looping back to -1
165     // -1 0 1 2 -1 0 1 2 ...
166     this->ArrayIndexForColoring =
167       (this->ArrayIndexForColoring + 2) % (this->DataForColoring->GetNumberOfArrays() + 1) - 1;
168   }
169 }
170 
171 //----------------------------------------------------------------------------
CycleArrayForColoring(bool checkCurrent)172 void vtkF3DRendererWithColoring::CycleArrayForColoring(bool checkCurrent)
173 {
174   if (this->DataForColoring)
175   {
176     for (int i = 0; i < this->DataForColoring->GetNumberOfArrays(); i++)
177     {
178       if (checkCurrent)
179       {
180         // Decrement before incrementing to keep this loop as simple as possible
181         this->ArrayIndexForColoring--;
182       }
183       this->CycleArrayIndexForColoring();
184       this->ArrayForColoring = this->DataForColoring->GetArray(this->ArrayIndexForColoring);
185       if (this->ArrayForColoring || this->ArrayIndexForColoring == -1)
186       {
187         this->CheckCurrentComponentForColoring();
188         break;
189       }
190     }
191   }
192 }
193 
194 //----------------------------------------------------------------------------
CheckCurrentComponentForColoring()195 void vtkF3DRendererWithColoring::CheckCurrentComponentForColoring()
196 {
197   if (this->ArrayForColoring)
198   {
199     // Check direct scalars
200     if (this->ArrayForColoring->GetNumberOfComponents() > 4 && this->ComponentForColoring == -2)
201     {
202       this->ComponentForColoring = -1;
203     }
204     // Check number of comps
205     else if (this->ComponentForColoring >= this->ArrayForColoring->GetNumberOfComponents())
206     {
207       this->ComponentForColoring = this->ArrayForColoring->GetNumberOfComponents() - 1;
208     }
209   }
210 }
211 
212 //----------------------------------------------------------------------------
CycleComponentForColoring()213 void vtkF3DRendererWithColoring::CycleComponentForColoring()
214 {
215   if (this->ArrayForColoring)
216   {
217     if (this->ArrayForColoring->GetNumberOfComponents() > 4)
218     {
219       // -1 0 1 2 3 4 5 6
220       this->ComponentForColoring =
221         (this->ComponentForColoring + 2) % (this->ArrayForColoring->GetNumberOfComponents() + 1) -
222         1;
223     }
224     else
225     {
226       // -2 -1 0 1 2 3 4
227       this->ComponentForColoring =
228         (this->ComponentForColoring + 3) % (this->ArrayForColoring->GetNumberOfComponents() + 2) -
229         2;
230     }
231   }
232 }
233 
234 //----------------------------------------------------------------------------
CycleFieldForColoring()235 void vtkF3DRendererWithColoring::CycleFieldForColoring()
236 {
237   // A generic approach will be better when adding categorical field data coloring
238   if (this->DataForColoring == this->PointDataForColoring)
239   {
240     this->DataForColoring = this->CellDataForColoring;
241   }
242   else // if (this->DataForColoring == this->CellDataForColoring)
243   {
244     this->DataForColoring = this->PointDataForColoring;
245   }
246   // Check current index is a valid coloring index
247   // If not, find another one
248   this->CycleArrayForColoring(true);
249 }
250 
251 //----------------------------------------------------------------------------
PrintColoringInfo()252 void vtkF3DRendererWithColoring::PrintColoringInfo()
253 {
254   if (this->ArrayForColoring)
255   {
256     F3DLog::Print(F3DLog::Severity::Info, "Coloring using ",
257       (this->DataForColoring == this->PointDataForColoring ? "point" : "cell"), " array named ",
258       this->ArrayForColoring->GetName(), ", ",
259       vtkF3DRendererWithColoring::ComponentToString(this->ComponentForColoring), ".");
260   }
261   else
262   {
263     F3DLog::Print(F3DLog::Severity::Info, "Not coloring");
264   }
265 }
266 
267 //----------------------------------------------------------------------------
CycleScalars(int cycleType)268 void vtkF3DRendererWithColoring::CycleScalars(int cycleType)
269 {
270   switch (cycleType)
271   {
272     case (F3D_FIELD_CYCLE):
273       this->CycleFieldForColoring();
274       break;
275     case (F3D_ARRAY_CYCLE):
276       this->CycleArrayForColoring();
277       break;
278     case (F3D_COMPONENT_CYCLE):
279       this->CycleComponentForColoring();
280       break;
281     default:
282       break;
283   }
284 
285   this->ColorTransferFunctionConfigured = false;
286   this->PolyDataMapperConfigured = false;
287   this->PointGaussianMapperConfigured = false;
288   this->VolumeConfigured = false;
289   this->ScalarBarActorConfigured = false;
290 
291   this->UpdateInternalActors();
292   this->SetupRenderPasses();
293   this->CheatSheetNeedUpdate = true;
294 }
295 
296 //----------------------------------------------------------------------------
ShowScalarBar(bool show)297 void vtkF3DRendererWithColoring::ShowScalarBar(bool show)
298 {
299   this->ScalarBarVisible = show;
300   this->UpdateScalarBarVisibility();
301   this->SetupRenderPasses();
302   this->CheatSheetNeedUpdate = true;
303 }
304 
305 //----------------------------------------------------------------------------
IsScalarBarVisible()306 bool vtkF3DRendererWithColoring::IsScalarBarVisible()
307 {
308   return this->ScalarBarVisible;
309 }
310 
311 //----------------------------------------------------------------------------
FillCheatSheetHotkeys(std::stringstream & cheatSheetText)312 void vtkF3DRendererWithColoring::FillCheatSheetHotkeys(std::stringstream& cheatSheetText)
313 {
314   if (this->DataForColoring)
315   {
316     cheatSheetText << " C: Cell scalars coloring ["
317                    << (this->DataForColoring == this->CellDataForColoring ? "ON" : "OFF") << "]\n";
318     cheatSheetText << " S: Scalars coloring ["
319                    << (this->ArrayForColoring ? vtkF3DRendererWithColoring::ShortName(
320                                                   this->ArrayForColoring->GetName(), 19)
321                                               : "OFF")
322                    << "]\n";
323     cheatSheetText << " Y: Coloring compponent ["
324                    << vtkF3DRendererWithColoring::ComponentToString(this->ComponentForColoring)
325                    << "]\n";
326     cheatSheetText << " B: Scalar bar " << (this->ScalarBarVisible ? "[ON]" : "[OFF]") << "\n";
327   }
328 
329   if (this->VolumeProp)
330   {
331     cheatSheetText << " V: Volume representation " << (this->UseVolume ? "[ON]" : "[OFF]") << "\n";
332     cheatSheetText << " I: Inverse volume opacity "
333                    << (this->UseInverseOpacityFunction ? "[ON]" : "[OFF]") << "\n";
334   }
335 
336   if (this->PointGaussianMapper)
337   {
338     cheatSheetText << " O: Point sprites " << (this->UsePointSprites ? "[ON]" : "[OFF]") << "\n";
339   }
340   this->Superclass::FillCheatSheetHotkeys(cheatSheetText);
341 }
342 
343 //----------------------------------------------------------------------------
UpdateInternalActors()344 void vtkF3DRendererWithColoring::UpdateInternalActors()
345 {
346   // Make sure ArrayForColoring is pointing to the right array
347   if (this->DataForColoring)
348   {
349     this->ArrayForColoring = this->DataForColoring->GetArray(this->ArrayIndexForColoring);
350   }
351 
352   if (this->Options.Verbose)
353   {
354     this->PrintColoringInfo();
355   }
356 
357   bool volumeVisibility = !this->UseRaytracing && this->UseVolume;
358   if (this->ArrayForColoring || volumeVisibility)
359   {
360     // When showing volume, always try to find an array to color with
361     if (volumeVisibility && !this->ArrayForColoring)
362     {
363       this->CycleArrayForColoring();
364     }
365 
366     if (!this->ArrayForColoring)
367     {
368       F3DLog::Print(F3DLog::Severity::Warning, "No array to color with");
369     }
370     if (!this->ColorTransferFunctionConfigured)
371     {
372       this->ConfigureRangeAndCTFForColoring(this->ArrayForColoring, this->ComponentForColoring);
373       this->ColorTransferFunctionConfigured = true;
374     }
375   }
376 
377   if (this->GeometryActor)
378   {
379     bool visible = this->UseRaytracing || (!this->UseVolume && !this->UsePointSprites);
380     this->GeometryActor->SetVisibility(visible);
381     if (this->PolyDataMapper)
382     {
383       if (visible && this->ArrayForColoring)
384       {
385         if (!this->PolyDataMapperConfigured)
386         {
387           vtkF3DRendererWithColoring::ConfigureMapperForColoring(this->PolyDataMapper,
388             this->ArrayForColoring, this->ComponentForColoring, this->ColorTransferFunction,
389             this->ColorRange, this->DataForColoring == this->CellDataForColoring);
390           this->PolyDataMapperConfigured = true;
391         }
392         this->PolyDataMapper->ScalarVisibilityOn();
393       }
394       else
395       {
396         this->PolyDataMapper->ScalarVisibilityOff();
397       }
398     }
399   }
400   if (this->PointSpritesActor)
401   {
402     bool visible = !this->UseRaytracing && !this->UseVolume && this->UsePointSprites;
403     this->PointSpritesActor->SetVisibility(visible);
404     if (this->PointGaussianMapper)
405     {
406       if (visible && this->ArrayForColoring)
407       {
408         if (!this->PointGaussianMapperConfigured)
409         {
410           vtkF3DRendererWithColoring::ConfigureMapperForColoring(this->PointGaussianMapper,
411             this->ArrayForColoring, this->ComponentForColoring, this->ColorTransferFunction,
412             this->ColorRange, this->DataForColoring == this->CellDataForColoring);
413           this->PointGaussianMapperConfigured = true;
414         }
415         this->PointGaussianMapper->ScalarVisibilityOn();
416       }
417       else
418       {
419         this->PointGaussianMapper->ScalarVisibilityOff();
420       }
421     }
422   }
423   if (this->VolumeProp)
424   {
425     vtkSmartVolumeMapper* mapper =
426       vtkSmartVolumeMapper::SafeDownCast(this->VolumeProp->GetMapper());
427     if (volumeVisibility && (!mapper || !mapper->GetInput() || !this->ArrayForColoring))
428     {
429       F3DLog::Print(
430         F3DLog::Severity::Error, "Cannot use volume with this dataset or with the requested array");
431       volumeVisibility = false;
432     }
433     if (volumeVisibility && this->VolumeMapper && this->VolumeMapper->GetInput() &&
434       !this->VolumeConfigured)
435     {
436       vtkF3DRendererWithColoring::ConfigureVolumeForColoring(this->VolumeMapper, this->VolumeProp,
437         this->ArrayForColoring, this->ComponentForColoring, this->ColorTransferFunction,
438         this->ColorRange, this->DataForColoring == this->CellDataForColoring,
439         this->UseInverseOpacityFunction);
440       this->VolumeConfigured = true;
441     }
442     this->VolumeProp->SetVisibility(volumeVisibility);
443   }
444   this->UpdateScalarBarVisibility();
445 }
446 
447 //----------------------------------------------------------------------------
UpdateScalarBarVisibility()448 void vtkF3DRendererWithColoring::UpdateScalarBarVisibility()
449 {
450   if (this->ScalarBarActor)
451   {
452     bool visible =
453       this->ScalarBarVisible && this->ArrayForColoring && this->ComponentForColoring >= -1;
454     this->ScalarBarActor->SetVisibility(visible);
455 
456     if (visible && !this->ScalarBarActorConfigured)
457     {
458       vtkF3DRendererWithColoring::ConfigureScalarBarActorForColoring(this->ScalarBarActor,
459         this->ArrayForColoring, this->ComponentForColoring, this->ColorTransferFunction);
460       this->ScalarBarActorConfigured = true;
461     }
462   }
463 }
464 
465 //----------------------------------------------------------------------------
SetColoring(vtkDataSetAttributes * pointData,vtkDataSetAttributes * cellData,bool useCellData,int arrayIndex,int component)466 void vtkF3DRendererWithColoring::SetColoring(vtkDataSetAttributes* pointData,
467   vtkDataSetAttributes* cellData, bool useCellData, int arrayIndex, int component)
468 {
469   this->ArrayForColoring = nullptr;
470   this->PointDataForColoring = pointData;
471   this->CellDataForColoring = cellData;
472   this->DataForColoring = useCellData ? this->CellDataForColoring : this->PointDataForColoring;
473   this->ArrayIndexForColoring = arrayIndex;
474   this->ComponentForColoring = component;
475   if (!this->DataForColoring ||
476     this->ArrayIndexForColoring >= this->DataForColoring->GetNumberOfArrays() ||
477     this->ArrayIndexForColoring < -1)
478   {
479     F3DLog::Print(F3DLog::Severity::Error, "Invalid coloring values");
480     this->ArrayIndexForColoring = -1;
481   }
482 }
483 
484 //----------------------------------------------------------------------------
ConfigureVolumeForColoring(vtkSmartVolumeMapper * mapper,vtkVolume * volume,vtkDataArray * array,int component,vtkColorTransferFunction * ctf,double range[2],bool cellFlag,bool inverseOpacityFlag)485 void vtkF3DRendererWithColoring::ConfigureVolumeForColoring(vtkSmartVolumeMapper* mapper,
486   vtkVolume* volume, vtkDataArray* array, int component, vtkColorTransferFunction* ctf,
487   double range[2], bool cellFlag, bool inverseOpacityFlag)
488 {
489   if (!array)
490   {
491     return;
492   }
493 
494   mapper->SetScalarMode(
495     cellFlag ? VTK_SCALAR_MODE_USE_CELL_FIELD_DATA : VTK_SCALAR_MODE_USE_POINT_FIELD_DATA);
496   mapper->SelectScalarArray(array->GetName());
497 
498   if (component >= 0)
499   {
500     mapper->SetVectorMode(vtkSmartVolumeMapper::COMPONENT);
501     mapper->SetVectorComponent(component);
502   }
503   else if (component == -1)
504   {
505     mapper->SetVectorMode(vtkSmartVolumeMapper::MAGNITUDE);
506   }
507   else if (component == -2)
508   {
509     if (array->GetNumberOfComponents() > 4)
510     {
511       // comp > 4 is actually not supported and would fail with a vtk error
512       F3DLog::Print(F3DLog::Severity::Warning,
513         "Direct scalars rendering not supported by array with more than 4 components");
514     }
515     else
516     {
517       mapper->SetVectorMode(vtkSmartVolumeMapper::DISABLED);
518     }
519   }
520 
521   vtkNew<vtkPiecewiseFunction> otf;
522   otf->AddPoint(range[0], inverseOpacityFlag ? 1.0 : 0.0);
523   otf->AddPoint(range[1], inverseOpacityFlag ? 0.0 : 1.0);
524 
525   vtkNew<vtkVolumeProperty> property;
526   property->SetColor(ctf);
527   property->SetScalarOpacity(otf);
528   property->ShadeOff();
529   property->SetInterpolationTypeToLinear();
530 
531   volume->SetProperty(property);
532 }
533 
534 //----------------------------------------------------------------------------
ConfigureMapperForColoring(vtkPolyDataMapper * mapper,vtkDataArray * array,int component,vtkColorTransferFunction * ctf,double range[2],bool cellFlag)535 void vtkF3DRendererWithColoring::ConfigureMapperForColoring(vtkPolyDataMapper* mapper,
536   vtkDataArray* array, int component, vtkColorTransferFunction* ctf, double range[2], bool cellFlag)
537 {
538   if (!array)
539   {
540     return;
541   }
542 
543   mapper->SetColorModeToMapScalars();
544   mapper->SelectColorArray(array->GetName());
545   mapper->SetScalarMode(
546     cellFlag ? VTK_SCALAR_MODE_USE_CELL_FIELD_DATA : VTK_SCALAR_MODE_USE_POINT_FIELD_DATA);
547   mapper->ScalarVisibilityOn();
548 
549   if (component == -2)
550   {
551     if (array->GetNumberOfComponents() > 4)
552     {
553       // comp > 4 is actually not supported and would fail with a vtk error
554       F3DLog::Print(F3DLog::Severity::Warning,
555         "Direct scalars rendering not supported by array with more than 4 components");
556     }
557     else
558     {
559       mapper->SetColorModeToDirectScalars();
560     }
561   }
562   else
563   {
564     mapper->SetColorModeToMapScalars();
565     mapper->SetScalarRange(range);
566     mapper->SetLookupTable(ctf);
567   }
568 }
569 
570 //----------------------------------------------------------------------------
ConfigureRangeAndCTFForColoring(vtkDataArray * array,int component)571 void vtkF3DRendererWithColoring::ConfigureRangeAndCTFForColoring(vtkDataArray* array, int component)
572 {
573   if (!array || component == -2)
574   {
575     return;
576   }
577 
578   if (component >= array->GetNumberOfComponents())
579   {
580     F3DLog::Print(F3DLog::Severity::Warning, "Invalid component index: ", component);
581     return;
582   }
583 
584   // Get range
585   if (this->Options.Range.size() == 2)
586   {
587     this->ColorRange[0] = this->Options.Range[0];
588     this->ColorRange[1] = this->Options.Range[1];
589   }
590   else
591   {
592     if (this->Options.Range.size() > 0)
593     {
594       F3DLog::Print(F3DLog::Severity::Warning,
595         "The range specified does not have exactly 2 values, using automatic range.");
596     }
597     array->GetRange(this->ColorRange, component);
598   }
599 
600   // Create lookup table
601   this->ColorTransferFunction = vtkSmartPointer<vtkColorTransferFunction>::New();
602   if (this->Options.LookupPoints.size() > 0)
603   {
604     if (this->Options.LookupPoints.size() % 4 == 0)
605     {
606       for (size_t i = 0; i < this->Options.LookupPoints.size(); i += 4)
607       {
608         double val = this->Options.LookupPoints[i];
609         double r = this->Options.LookupPoints[i + 1];
610         double g = this->Options.LookupPoints[i + 2];
611         double b = this->Options.LookupPoints[i + 3];
612         this->ColorTransferFunction->AddRGBPoint(
613           this->ColorRange[0] + val * (this->ColorRange[1] - this->ColorRange[0]), r, g, b);
614       }
615     }
616     else
617     {
618       F3DLog::Print(F3DLog::Severity::Warning,
619         "Specified color map list count is not a multiple of 4, ignoring it.");
620     }
621   }
622 
623   if (component >= 0)
624   {
625     this->ColorTransferFunction->SetVectorModeToComponent();
626     this->ColorTransferFunction->SetVectorComponent(component);
627   }
628   else
629   {
630     this->ColorTransferFunction->SetVectorModeToMagnitude();
631   }
632 }
633 
634 //----------------------------------------------------------------------------
ConfigureScalarBarActorForColoring(vtkScalarBarActor * scalarBar,vtkDataArray * array,int component,vtkColorTransferFunction * ctf)635 void vtkF3DRendererWithColoring::ConfigureScalarBarActorForColoring(
636   vtkScalarBarActor* scalarBar, vtkDataArray* array, int component, vtkColorTransferFunction* ctf)
637 {
638   if (!array)
639   {
640     return;
641   }
642 
643   std::string title = array->GetName();
644   title += " (";
645   title += vtkF3DRendererWithColoring::ComponentToString(component);
646   title += ")";
647 
648   scalarBar->SetLookupTable(ctf);
649   scalarBar->SetTitle(title.c_str());
650   scalarBar->SetNumberOfLabels(4);
651   scalarBar->SetOrientationToHorizontal();
652   scalarBar->SetWidth(0.8);
653   scalarBar->SetHeight(0.07);
654   scalarBar->SetPosition(0.1, 0.01);
655 }
656 
657 //----------------------------------------------------------------------------
ComponentToString(int component)658 std::string vtkF3DRendererWithColoring::ComponentToString(int component)
659 {
660   if (component == -2)
661   {
662     return "Direct Scalars";
663   }
664   else if (component == -1)
665   {
666     return "Magnitude";
667   }
668   else
669   {
670     std::string ret = "Component #";
671     ret += std::to_string(component);
672     return ret;
673   }
674 }
675 
676 //----------------------------------------------------------------------------
ShortName(const std::string & name,int maxChar)677 std::string vtkF3DRendererWithColoring::ShortName(const std::string& name, int maxChar)
678 {
679   if (name.size() <= static_cast<size_t>(maxChar) || maxChar <= 3)
680   {
681     return name;
682   }
683   else
684   {
685     return name.substr(0, maxChar - 3) + "...";
686   }
687 }
688