ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
vtkContext2DScalarBarActor.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
9 
10 #include <limits>
11 #include <map>
12 
14 #include "vtkAxis.h"
15 #include "vtkBrush.h"
16 #include "vtkColorTransferFunction.h"
17 #include "vtkContext2D.h"
18 #include "vtkContextActor.h"
19 #include "vtkContextDevice2D.h"
20 #include "vtkContextItem.h"
21 #include "vtkContextScene.h"
22 #include "vtkDiscretizableColorTransferFunction.h"
23 #include "vtkDoubleArray.h"
24 #include "vtkFloatArray.h"
25 #include "vtkImageData.h"
26 #include "vtkLookupTable.h"
27 #include "vtkMath.h"
28 #include "vtkNew.h"
29 #include "vtkObjectFactory.h"
30 #include "vtkOpenGLContextDevice2D.h"
31 #include "vtkOpenGLRenderWindow.h"
32 #include "vtkPen.h"
33 #include "vtkPointData.h"
34 #include "vtkPoints2D.h"
35 #include "vtkRenderWindow.h"
36 #include "vtkRenderer.h"
37 #include "vtkScalarsToColors.h"
38 #include "vtkTextProperty.h"
39 #include "vtkTransform2D.h"
40 #include "vtkUnsignedCharArray.h"
41 #include "vtkViewport.h"
42 
43 #if defined(_WIN32) && !defined(__CYGWIN__)
44 #define SNPRINTF _snprintf
45 #else
46 #define SNPRINTF snprintf
47 #endif
48 
49 // NOTE FOR DEVELOPERS
50 // The color bar is defined so that the origin (0, 0) is the bottom left
51 // corner of the region that contains the scalar bar, the out-of-range
52 // color swatches, and the NaN color swatches. This is true for both
53 // horizontal and vertical orientations.
54 //
55 // The layout of the color bar for both orientations is as follows:
56 //
57 // VERTICAL HORIZONTAL
58 //
59 // +-+ Below Range Above Range NaN Color
60 // | | Above Range +-+-------------------+-+ +-+
61 // +-+ | | | | | |
62 // | | +-+-------------------+-+-+-+
63 // | | (0, 0) Scalar Bar
64 // | |
65 // | | Scalar Bar
66 // | |
67 // +-+
68 // | | Below Range
69 // +-+
70 //
71 // +-+
72 // | | Nan Color
73 // + +
74 // (0, 0)
75 
76 // This class is a vtkContextItem that can be added to a vtkContextScene.
77 //----------------------------------------------------------------------------
78 class vtkContext2DScalarBarActor::vtkScalarBarItem : public vtkContextItem {
79 public:
80  vtkTypeMacro(vtkScalarBarItem, vtkContextItem);
81 
82  static vtkScalarBarItem* New() {
83  VTK_OBJECT_FACTORY_NEW_BODY(vtkScalarBarItem);
84  }
85 
86  // Forward calls to vtkContextItem::Paint to vtkContext2DScalarBarActor
87  bool Paint(vtkContext2D* painter) override {
88  bool somethingRendered = false;
89  if (this->Actor) {
90  somethingRendered = this->Actor->Paint(painter);
91  }
92 
93  return somethingRendered && this->Superclass::Paint(painter);
94  }
95 
96  // Reference to the Actor.
98 
99 protected:
101  ~vtkScalarBarItem() override {}
102 };
103 
104 //----------------------------------------------------------------------------
105 // Hide use of std::map from public interface
107  : public std::map<double, std::string> {};
108 
109 //----------------------------------------------------------------------------
111 
112 //----------------------------------------------------------------------------
114  this->ActorDelegate = vtkContextActor::New();
115 
116  this->TitleJustification = VTK_TEXT_LEFT;
117  this->ForceHorizontalTitle = false;
118 
119  this->ScalarBarThickness = 16;
120  this->ScalarBarLength = 0.33;
121 
122  this->AutomaticLabelFormat = 1;
123 
124  this->AddRangeLabels = 1;
125  this->AutomaticAnnotations = 0;
126  this->AddRangeAnnotations = 0;
127  this->RangeLabelFormat = NULL;
128  this->SetRangeLabelFormat("%g");
129 
130  this->OutlineScalarBar = 0;
131 
132  this->Spacer = 4.0;
133  this->NumberOfTicks = -1;
134 
135  this->DrawTickMarks = true;
136 
137  this->UseCustomLabels = false;
138  this->CustomLabels = vtkSmartPointer<vtkDoubleArray>::New();
139 
140  this->ReverseLegend = false;
141 
142  this->ScalarBarItem = vtkScalarBarItem::New();
143  this->ScalarBarItem->Actor = this;
144 
145  vtkContextScene* localScene = vtkContextScene::New();
146  this->ActorDelegate->SetScene(localScene);
147  localScene->AddItem(this->ScalarBarItem);
148  localScene->Delete();
149 
150  this->CurrentViewport = NULL;
151 
152  this->Axis = vtkAxis::New();
153  this->Axis->SetScene(localScene);
154 }
155 
156 //----------------------------------------------------------------------------
158  this->SetLookupTable(NULL);
159  this->ActorDelegate->Delete();
160  this->SetTitle(NULL);
161  this->SetComponentTitle(NULL);
162  this->ScalarBarItem->Delete();
163  this->SetTitleTextProperty(NULL);
164  this->SetLabelTextProperty(NULL);
165  this->Axis->Delete();
166  this->SetRangeLabelFormat(nullptr);
167 }
168 
169 //----------------------------------------------------------------------------
171  if (useLabels != this->UseCustomLabels) {
172  this->UseCustomLabels = useLabels;
173  this->Modified();
174  }
175 }
176 
177 //----------------------------------------------------------------------------
179  this->CustomLabels->SetNumberOfTuples(numLabels);
180 }
181 
182 //----------------------------------------------------------------------------
184  return this->CustomLabels->GetNumberOfTuples();
185 }
186 
187 //----------------------------------------------------------------------------
188 void vtkContext2DScalarBarActor::SetCustomLabel(vtkIdType index, double value) {
189  if (index < 0 || index >= this->CustomLabels->GetNumberOfTuples()) {
190  vtkErrorMacro(<< "Index out of range");
191  return;
192  }
193 
194  this->CustomLabels->SetTypedTuple(index, &value);
195 }
196 
197 //----------------------------------------------------------------------------
198 int vtkContext2DScalarBarActor::RenderOverlay(vtkViewport* viewport) {
199  this->CurrentViewport = viewport;
200 
201  int returnValue = 0;
202  if (this->ActorDelegate) {
203  returnValue = this->ActorDelegate->RenderOverlay(viewport);
204  }
205 
206  return returnValue;
207 }
208 
209 //----------------------------------------------------------------------------
211  this->CurrentViewport = viewport;
212 
213  return 1;
214 }
215 
216 //----------------------------------------------------------------------------
218  if (!this->ActorDelegate || !this->ActorDelegate->GetScene() ||
219  !this->ActorDelegate->GetScene()->GetLastPainter()) {
220  return;
221  }
222 
223  vtkContextDevice2D* device =
224  this->ActorDelegate->GetScene()->GetLastPainter()->GetDevice();
225 
226  // Downcast is needed because the context device superclass does
227  // not define this method (but probably should).
228  vtkOpenGLContextDevice2D* oglDevice =
229  vtkOpenGLContextDevice2D::SafeDownCast(device);
230  if (oglDevice) {
231  oglDevice->ReleaseGraphicsResources(window);
232  }
233 }
234 
235 //----------------------------------------------------------------------------
236 void vtkContext2DScalarBarActor::UpdateScalarBarTexture(vtkImageData* image) {
237  if (this->Orientation == VTK_ORIENT_VERTICAL) {
238  image->SetDimensions(1, 256, 1);
239  } else {
240  image->SetDimensions(256, 1, 1);
241  }
242  image->AllocateScalars(VTK_UNSIGNED_CHAR, 4);
243 
244  vtkUnsignedCharArray* colors = vtkUnsignedCharArray::SafeDownCast(
245  image->GetPointData()->GetArray(0));
246 
247  vtkDiscretizableColorTransferFunction* ctf =
248  vtkDiscretizableColorTransferFunction::SafeDownCast(
249  this->LookupTable);
250  if (!ctf) {
251  return;
252  }
253 
254  double* lutRange = ctf->GetRange();
255  const int numColors = 256;
256  unsigned char color[4];
257  for (int i = 0; i < numColors; ++i) {
258  // Probably use MapScalarsThroughTable2 here instead.
259  // Update only when LUT changes
260  double originalValue =
261  (((double)i / numColors) * (lutRange[1] - lutRange[0])) +
262  lutRange[0];
263  double value = originalValue;
264  if (this->LookupTable->UsingLogScale()) {
265  value = log10(lutRange[0]) +
266  i * (log10(lutRange[1]) - log10(lutRange[0])) / numColors;
267  value = pow(10.0, value);
268  }
269 
270  const unsigned char* colorTmp = ctf->MapValue(value);
271 
272  // The opacity function does not take into account the logarithmic
273  // mapping, so we use the original value here.
274  color[0] = colorTmp[0];
275  color[1] = colorTmp[1];
276  color[2] = colorTmp[2];
277  color[3] = static_cast<unsigned char>(
278  255.0 * ctf->GetOpacity(originalValue) + 0.5);
279  if (this->ReverseLegend) {
280  colors->SetTypedTuple(numColors - i - 1, color);
281  } else {
282  colors->SetTypedTuple(i, color);
283  }
284  }
285 }
286 
287 //----------------------------------------------------------------------------
288 void vtkContext2DScalarBarActor::GetSize(double size[2],
289  vtkContext2D* painter) {
290  if (!this->CurrentViewport) {
291  return;
292  }
293 
294  // Convert scalar bar length from normalized viewport coordinates to pixels
295  vtkNew<vtkCoordinate> lengthCoord;
296  lengthCoord->SetCoordinateSystemToNormalizedViewport();
297  lengthCoord->SetValue(
298  this->Orientation == VTK_ORIENT_VERTICAL ? 0.0
299  : this->ScalarBarLength,
300  this->Orientation == VTK_ORIENT_VERTICAL ? this->ScalarBarLength
301  : 0.0);
302  int* lengthOffset =
303  lengthCoord->GetComputedDisplayValue(this->CurrentViewport);
304 
305  // The scalar bar thickness is defined in terms of points. That is,
306  // if the thickness size is 12, that matches the height of a "|"
307  // character in a 12 point font.
308  vtkNew<vtkTextProperty> textProp;
309  textProp->SetFontSize(this->ScalarBarThickness);
310  painter->ApplyTextProp(textProp.Get());
311 
312  float bounds[4];
313  painter->ComputeStringBounds("|", bounds);
314  double thickness = bounds[3];
315 
316  if (this->Orientation == VTK_ORIENT_VERTICAL) {
317  size[0] = thickness;
318  size[1] = lengthOffset[1];
319  } else {
320  size[0] = lengthOffset[0];
321  size[1] = thickness;
322  }
323 }
324 
325 //----------------------------------------------------------------------------
326 vtkRectf vtkContext2DScalarBarActor::GetColorBarRect(double size[2]) {
327  vtkRectf rect = vtkRectf(0, 0, size[0], size[1]);
328 
329  // Color swatches are squares with sides equal to the width of the
330  // color bar when in vertical orientation and equal to the height
331  // when in horizontal orientation.
332  double swatchSize =
333  this->Orientation == VTK_ORIENT_VERTICAL ? size[0] : size[1];
334 
335  // Count up the swatches
336  double shift = 0;
337  double sizeReduction = 0;
338  if (this->DrawNanAnnotation) {
339  if (this->Orientation == VTK_ORIENT_VERTICAL) {
340  shift += swatchSize + this->Spacer;
341  }
342  sizeReduction += swatchSize + this->Spacer;
343  }
344 
345  vtkDiscretizableColorTransferFunction* ctf =
346  vtkDiscretizableColorTransferFunction::SafeDownCast(
347  this->LookupTable);
348  if (ctf && ctf->GetUseAboveRangeColor()) {
349  sizeReduction += swatchSize;
350  }
351 
352  if (ctf && ctf->GetUseBelowRangeColor()) {
353  shift += swatchSize;
354  sizeReduction += swatchSize;
355  }
356 
357  if (this->Orientation == VTK_ORIENT_VERTICAL) {
358  rect.SetY(rect.GetY() + shift);
359  rect.SetHeight(rect.GetHeight() - sizeReduction);
360  } else {
361  rect.SetX(rect.GetX() + shift);
362  rect.SetWidth(rect.GetWidth() - sizeReduction);
363  }
364 
365  return rect;
366 }
367 
368 //----------------------------------------------------------------------------
369 vtkRectf vtkContext2DScalarBarActor::GetFullColorBarRect(double size[2]) {
370  // This will end up with the full color bar rect
371  vtkRectf fullRect = this->GetColorBarRect(size);
372 
373  // Add these rects in if they have non-zero size
374  vtkRectf aboveRect = this->GetAboveRangeColorRect(size);
375  if (aboveRect.GetWidth() > 0 && aboveRect.GetHeight() > 0) {
376  fullRect.AddRect(aboveRect);
377  }
378 
379  vtkRectf belowRect = this->GetBelowRangeColorRect(size);
380  if (belowRect.GetWidth() > 0 && belowRect.GetHeight() > 0) {
381  fullRect.AddRect(belowRect);
382  }
383 
384  return fullRect;
385 }
386 
387 //----------------------------------------------------------------------------
388 vtkRectf vtkContext2DScalarBarActor::GetAboveRangeColorRect(double size[2]) {
389  vtkRectf rect(0, 0, 0, 0);
390 
391  vtkDiscretizableColorTransferFunction* ctf =
392  vtkDiscretizableColorTransferFunction::SafeDownCast(
393  this->LookupTable);
394  if (!ctf) {
395  if (this->LookupTable) {
396  vtkErrorMacro(<< "Lookup table should be a "
397  "vtkDiscretizableColorTransferFunction but was a "
398  << this->LookupTable->GetClassName());
399  } else {
400  vtkErrorMacro(<< "Lookup table was NULL");
401  }
402  return rect;
403  }
404 
405  if (ctf->GetUseAboveRangeColor()) {
406  rect = this->GetOutOfRangeColorRectInternal(
408  }
409  return rect;
410 }
411 
412 //----------------------------------------------------------------------------
413 vtkRectf vtkContext2DScalarBarActor::GetBelowRangeColorRect(double size[2]) {
414  vtkRectf rect(0, 0, 0, 0);
415 
416  vtkDiscretizableColorTransferFunction* ctf =
417  vtkDiscretizableColorTransferFunction::SafeDownCast(
418  this->LookupTable);
419  if (!ctf) {
420  if (this->LookupTable) {
421  vtkErrorMacro(<< "Lookup table should be a "
422  "vtkDiscretizableColorTransferFunction but was a "
423  << this->LookupTable->GetClassName());
424  } else {
425  vtkErrorMacro(<< "Lookup table was NULL");
426  }
427  return rect;
428  }
429 
430  if (ctf->GetUseBelowRangeColor()) {
431  rect = this->GetOutOfRangeColorRectInternal(
433  }
434  return rect;
435 }
436 
437 //----------------------------------------------------------------------------
438 vtkRectf vtkContext2DScalarBarActor::GetOutOfRangeColorRectInternal(
440  vtkRectf rect(0, 0, 0, 0);
441  bool graphicallyAbove = type == vtkContext2DScalarBarActor::ABOVE_RANGE &&
442  !this->ReverseLegend;
443  if (graphicallyAbove) {
444  if (this->Orientation == VTK_ORIENT_VERTICAL) {
445  double width = size[0];
446  rect = vtkRectf(0, size[1] - width, width, width);
447  } else {
448  // Horizontal
449  double nanSpace = this->GetNaNColorRect(size).GetWidth();
450  if (nanSpace > 0) {
451  nanSpace += this->Spacer;
452  }
453  double height = size[1];
454 
455  // Move it all the way to the right, minus the NaN swatch
456  rect = vtkRectf(size[0] - nanSpace - height, 0, height, height);
457  }
458  } else {
459  if (this->Orientation == VTK_ORIENT_VERTICAL) {
460  double nanSpace = this->GetNaNColorRect(size).GetHeight();
461  if (nanSpace > 0) {
462  nanSpace += this->Spacer;
463  }
464 
465  double height = size[0];
466  rect = vtkRectf(0, nanSpace, height, height);
467  } else {
468  double width = size[1];
469  rect = vtkRectf(0, 0, width, width);
470  }
471  }
472  return rect;
473 }
474 
475 //----------------------------------------------------------------------------
476 vtkRectf vtkContext2DScalarBarActor::GetNaNColorRect(double size[2]) {
477  // Initialize to 0 width, 0 height
478  vtkRectf rect(0, 0, 0, 0);
479 
480  if (this->DrawNanAnnotation) {
481  if (this->Orientation == VTK_ORIENT_VERTICAL) {
482  double width = size[0];
483  rect = vtkRectf(0, 0, width, width);
484  } else {
485  // Horizontal
486  double height = size[1];
487  rect = vtkRectf(size[0] - height, 0, height, height);
488  }
489  }
490 
491  return rect;
492 }
493 
494 //----------------------------------------------------------------------------
495 void vtkContext2DScalarBarActor::UpdateTextProperties() {
496  // We can't just ShallowCopy the LabelTextProperty to axisTextProperty
497  // because it will clobber the orientation and justification settings.
498  vtkTextProperty* axisLabelProperty = this->Axis->GetLabelProperties();
499  axisLabelProperty->SetColor(this->LabelTextProperty->GetColor());
500  axisLabelProperty->SetOpacity(this->LabelTextProperty->GetOpacity());
501  axisLabelProperty->SetBackgroundColor(
502  this->LabelTextProperty->GetBackgroundColor());
503  axisLabelProperty->SetBackgroundOpacity(
504  this->LabelTextProperty->GetBackgroundOpacity());
505  axisLabelProperty->SetFontFamilyAsString(
506  this->LabelTextProperty->GetFontFamilyAsString());
507  axisLabelProperty->SetFontFile(this->LabelTextProperty->GetFontFile());
508  axisLabelProperty->SetFontSize(this->LabelTextProperty->GetFontSize());
509 
510  axisLabelProperty->SetBold(this->LabelTextProperty->GetBold());
511  axisLabelProperty->SetItalic(this->LabelTextProperty->GetItalic());
512  axisLabelProperty->SetShadow(this->LabelTextProperty->GetShadow());
513  axisLabelProperty->SetShadowOffset(
514  this->LabelTextProperty->GetShadowOffset());
515 
516  vtkTextProperty* axisTitleProperty = this->Axis->GetTitleProperties();
517  axisTitleProperty->SetColor(this->TitleTextProperty->GetColor());
518  axisTitleProperty->SetOpacity(this->TitleTextProperty->GetOpacity());
519  axisTitleProperty->SetBackgroundColor(
520  this->TitleTextProperty->GetBackgroundColor());
521  axisTitleProperty->SetBackgroundOpacity(
522  this->TitleTextProperty->GetBackgroundOpacity());
523  axisTitleProperty->SetFontFamilyAsString(
524  this->TitleTextProperty->GetFontFamilyAsString());
525  axisTitleProperty->SetFontFile(this->TitleTextProperty->GetFontFile());
526  axisTitleProperty->SetFontSize(this->TitleTextProperty->GetFontSize());
527 
528  axisTitleProperty->SetBold(this->TitleTextProperty->GetBold());
529  axisTitleProperty->SetItalic(this->TitleTextProperty->GetItalic());
530  axisTitleProperty->SetShadow(this->TitleTextProperty->GetShadow());
531  axisTitleProperty->SetShadowOffset(
532  this->TitleTextProperty->GetShadowOffset());
533 }
534 
535 //----------------------------------------------------------------------------
536 void vtkContext2DScalarBarActor::PaintColorBar(vtkContext2D* painter,
537  double size[2]) {
538  vtkRectf barRect = this->GetColorBarRect(size);
539 
540  vtkBrush* brush = painter->GetBrush();
541 
542  //-----------------------------
543  // Draw scalar bar itself
544  vtkDiscretizableColorTransferFunction* ctf =
545  vtkDiscretizableColorTransferFunction::SafeDownCast(
546  this->LookupTable);
547  if (!ctf) {
548  return;
549  }
550 
551  // Disable pen to prevent an outline around the color swatches
552  vtkPen* pen = painter->GetPen();
553  pen->SetLineType(vtkPen::NO_PEN);
554 
555  // Create a map from anchor values to annotations. Since maps sort by key,
556  // when we iterate over the annotations later on, we will be doing it from
557  // smallest to greatest annotation value.
558  vtkAnnotationMap annotationAnchors;
559 
560  if (ctf->GetIndexedLookup()) {
561  // Divide up the color bar rect into the number of indexed colors
562  int numIndexedColors = ctf->GetNumberOfAnnotatedValues();
563  double indexedColorSwatchLength =
564  this->Orientation == VTK_ORIENT_VERTICAL ? barRect.GetHeight()
565  : barRect.GetWidth();
566 
567  // Subtract spaces between swatches
568  if (numIndexedColors > 0) {
569  indexedColorSwatchLength -= (numIndexedColors - 1) * this->Spacer;
570  indexedColorSwatchLength /= numIndexedColors;
571  }
572 
573  // Now loop over indexed colors and draw swatches
574  double x, y;
575  for (int i = 0; i < numIndexedColors; ++i) {
576  double shift = i * (indexedColorSwatchLength + this->Spacer);
577  double indexedColor[4];
578  vtkVariant annotatedValue = ctf->GetAnnotatedValue(i);
579  ctf->GetIndexedColor(i, indexedColor);
580  std::string annotation = ctf->GetAnnotation(i);
581  brush->SetColorF(indexedColor);
582  if (this->Orientation == VTK_ORIENT_VERTICAL) {
583  x = barRect.GetX();
584  if (this->ReverseLegend) {
585  y = barRect.GetY() + shift;
586  } else {
587  y = barRect.GetY() + barRect.GetHeight() - shift -
588  indexedColorSwatchLength;
589  }
590  painter->DrawRect(x, y, barRect.GetWidth(),
591  indexedColorSwatchLength);
592  annotationAnchors[y + 0.5 * indexedColorSwatchLength] =
593  annotation;
594  } else {
595  // Horizontal
596  if (this->ReverseLegend) {
597  x = barRect.GetX() + barRect.GetWidth() - shift -
598  indexedColorSwatchLength;
599  } else {
600  x = barRect.GetX() + shift;
601  }
602  y = barRect.GetY();
603  painter->DrawRect(x, y, indexedColorSwatchLength,
604  barRect.GetHeight());
605  annotationAnchors[x + 0.5 * indexedColorSwatchLength] =
606  annotation;
607  }
608  }
609  } else
610  // Continuous color map
611  {
612  vtkNew<vtkImageData> image;
613  this->UpdateScalarBarTexture(image.GetPointer());
614 
615  painter->DrawImage(barRect, image.GetPointer());
616 
617  // Draw the out-of-range colors if enabled
618  // pen->SetLineType(vtkPen::NO_PEN);
619  if (ctf->GetUseAboveRangeColor()) {
620  vtkRectf rect = this->GetAboveRangeColorRect(size);
621  brush->SetColorF(ctf->GetAboveRangeColor());
622  pen->SetLineType(vtkPen::NO_PEN);
623  painter->DrawRect(rect.GetX(), rect.GetY(), rect.GetWidth(),
624  rect.GetHeight());
625  }
626 
627  if (ctf->GetUseBelowRangeColor()) {
628  vtkRectf rect = this->GetBelowRangeColorRect(size);
629  brush->SetColorF(ctf->GetBelowRangeColor());
630  pen->SetLineType(vtkPen::NO_PEN);
631  painter->DrawRect(rect.GetX(), rect.GetY(), rect.GetWidth(),
632  rect.GetHeight());
633  }
634 
635  // Finally, draw a rect around the scalar bar and out-of-range
636  // colors, if they are enabled. We should probably draw four
637  // lines instead.
638  if (this->OutlineScalarBar) {
639  vtkRectf outlineRect = this->GetFullColorBarRect(size);
640 
641  brush->SetOpacity(0);
642  pen->SetLineType(vtkPen::SOLID_LINE);
643  painter->DrawRect(outlineRect.GetX(), outlineRect.GetY(),
644  outlineRect.GetWidth(), outlineRect.GetHeight());
645  }
646 
647  // Now set up annotation anchor point map
648  double lutRange[2];
649  lutRange[0] = this->LookupTable->GetRange()[0];
650  lutRange[1] = this->LookupTable->GetRange()[1];
651  if (this->LookupTable->UsingLogScale()) {
652  lutRange[0] = log10(lutRange[0]);
653  lutRange[1] = log10(lutRange[1]);
654  }
655 
656  double low = barRect.GetX();
657  double high = low + barRect.GetWidth();
658  if (this->Orientation == VTK_ORIENT_VERTICAL) {
659  low = barRect.GetY();
660  high = low + barRect.GetHeight();
661  }
662  if (this->ReverseLegend) {
663  std::swap(high, low);
664  }
665 
666  if (this->GetAutomaticAnnotations()) {
667  // How many annotations should there be?
668  vtkIdType numValues = ctf->GetNumberOfAvailableColors();
669  if (ctf && ctf->GetDiscretize() && this->AutomaticAnnotations &&
670  numValues) {
671  double step = (lutRange[1] - lutRange[0]) / numValues;
672  for (vtkIdType i = 0; i <= numValues; i++) {
673  double annotatedValue = lutRange[0] + step * i;
674 
675  double normalizedValue = (annotatedValue - lutRange[0]) /
676  (lutRange[1] - lutRange[0]);
677 
678  double barPosition = normalizedValue * (high - low) + low;
679  if (normalizedValue >=
680  0.0 - std::numeric_limits<double>::epsilon() &&
681  normalizedValue <=
682  1.0 + std::numeric_limits<double>::epsilon() &&
683  !vtkMath::IsNan(barPosition)) {
684  char annotation[1024];
685  if (this->LookupTable->UsingLogScale()) {
686  annotatedValue = pow(10.0, annotatedValue);
687  }
688  SNPRINTF(annotation, 1023, this->LabelFormat,
689  annotatedValue);
690  annotationAnchors[barPosition] = annotation;
691  }
692  }
693  }
694  } else // Manual annotations
695  {
696  int numAnnotations = ctf->GetNumberOfAnnotatedValues();
697  for (int i = 0; i < numAnnotations; ++i) {
698  // Figure out placement of annotation value along color bar.
699  double annotatedValue = ctf->GetAnnotatedValue(i).ToDouble();
700  if (this->LookupTable->UsingLogScale()) {
701  // Scale in log space
702  annotatedValue = log10(annotatedValue);
703  }
704 
705  double normalizedValue = (annotatedValue - lutRange[0]) /
706  (lutRange[1] - lutRange[0]);
707 
708  double barPosition = normalizedValue * (high - low) + low;
709  if (normalizedValue >= 0.0 && normalizedValue <= 1.0 &&
710  !vtkMath::IsNan(barPosition)) {
711  std::string annotation = ctf->GetAnnotation(i);
712  annotationAnchors[barPosition] = annotation;
713  }
714  }
715  }
716 
717  if (this->AddRangeAnnotations) {
718  char annotation[1024];
719 
720  SNPRINTF(annotation, 1023, this->RangeLabelFormat, lutRange[0]);
721  annotationAnchors[low] = annotation;
722 
723  SNPRINTF(annotation, 1023, this->RangeLabelFormat, lutRange[1]);
724  annotationAnchors[high] = annotation;
725  }
726 
727  } // Continuous color map
728 
729  // For all types of color maps, draw the NaN annotation.
730  if (this->DrawNanAnnotation) {
731  // Paint NaN color swatch
732  vtkRectf rect = this->GetNaNColorRect(size);
733  brush->SetOpacity(255);
734  brush->SetColorF(ctf->GetNanColor());
735  pen->SetLineType(vtkPen::NO_PEN);
736  painter->DrawRect(rect.GetX(), rect.GetY(), rect.GetWidth(),
737  rect.GetHeight());
738 
739  // Add NaN annotation
740  double nanAnchor = rect.GetY() + 0.5 * rect.GetHeight();
741  if (this->Orientation == VTK_ORIENT_HORIZONTAL) {
742  nanAnchor = rect.GetX() + 0.5 * rect.GetWidth();
743  }
744  annotationAnchors[nanAnchor] = this->GetNanAnnotation();
745  }
746 
747  // Draw the annotations
748  if (this->GetDrawAnnotations()) {
749  this->PaintAnnotations(painter, size, annotationAnchors);
750  }
751 }
752 
753 //----------------------------------------------------------------------------
754 void vtkContext2DScalarBarActor::PaintAxis(vtkContext2D* painter,
755  double size[2]) {
756  vtkRectf rect = this->GetColorBarRect(size);
757 
758  // Use the length of the character "|" at the label font size for various
759  // measurements.
760  float bounds[4];
761  painter->ApplyTextProp(this->LabelTextProperty);
762  painter->ComputeStringBounds("|", bounds);
763  float pipeHeight = bounds[3];
764 
765  // Note that at this point the font size is already scaled by the tile
766  // scale factor. Later on, vtkAxis will scale the tick length and label
767  // offset by the tile scale factor again, so we need to divide by the tile
768  // scale factor here to take that into account.
769  vtkWindow* renWin = this->CurrentViewport->GetVTKWindow();
770  int tileScale[2];
771  renWin->GetTileScale(tileScale);
772  pipeHeight /= tileScale[1];
773 
774  // Compute a shift amount for tick marks.
775  float axisShift = 0.25 * pipeHeight;
776 
777  // Compute tick lengths and label offsets based on the label font size
778  float tickLength = 0.75 * pipeHeight;
779  if (this->Orientation == VTK_ORIENT_VERTICAL) {
780  this->Axis->SetTickLength(tickLength);
781 
782  // Offset the labels from the tick marks a bit
783  float labelOffset = tickLength + (0.5 * tickLength);
784  this->Axis->SetLabelOffset(labelOffset);
785  } else {
786  this->Axis->SetTickLength(tickLength);
787 
788  float labelOffset = tickLength + (0.3 * tickLength);
789  this->Axis->SetLabelOffset(labelOffset);
790  }
791 
792  // Position the axis
793  if (this->TextPosition == PrecedeScalarBar) {
794  // Left
795  if (this->Orientation == VTK_ORIENT_VERTICAL) {
796  this->Axis->SetPoint1(rect.GetX() + axisShift, rect.GetY());
797  this->Axis->SetPoint2(rect.GetX() + axisShift,
798  rect.GetY() + rect.GetHeight());
799  this->Axis->SetPosition(vtkAxis::LEFT);
800  } else {
801  // Bottom
802  this->Axis->SetPoint1(rect.GetX(), rect.GetY() + axisShift);
803  this->Axis->SetPoint2(rect.GetX() + rect.GetWidth(),
804  rect.GetY() + axisShift);
805  this->Axis->SetPosition(vtkAxis::BOTTOM);
806  }
807  } else {
808  // Right
809  if (this->Orientation == VTK_ORIENT_VERTICAL) {
810  this->Axis->SetPoint1(rect.GetX() + rect.GetWidth() - axisShift,
811  rect.GetY());
812  this->Axis->SetPoint2(rect.GetX() + rect.GetWidth() - axisShift,
813  rect.GetY() + rect.GetHeight());
814  this->Axis->SetPosition(vtkAxis::RIGHT);
815  } else {
816  // Top
817  this->Axis->SetPoint1(rect.GetX(),
818  rect.GetY() + rect.GetHeight() - axisShift);
819  this->Axis->SetPoint2(rect.GetX() + rect.GetWidth(),
820  rect.GetY() + rect.GetHeight() - axisShift);
821  this->Axis->SetPosition(vtkAxis::TOP);
822  }
823  }
824 
825  //-----------------------------
826  // Get the range of the lut
827  const double* lutRange = this->LookupTable->GetRange();
828  double range[2];
829  range[0] = lutRange[0];
830  range[1] = lutRange[1];
831 
832  if (this->ReverseLegend) {
833  std::swap(range[0], range[1]);
834  }
835 
836  vtkPen* axisPen = this->Axis->GetPen();
837  axisPen->SetColorF(this->LabelTextProperty->GetColor());
838 
839  bool indexedMode = this->LookupTable->GetIndexedLookup() == 1;
840 
841  // NOTE: the order of calls to this->Axis is important and should be
842  // changed only with extreme care.
843  this->Axis->SetTickLabelAlgorithm(vtkAxis::TICK_SIMPLE);
844  this->Axis->SetUnscaledMinimumLimit(std::numeric_limits<double>::max() *
845  -1.0);
846  this->Axis->SetUnscaledMaximumLimit(std::numeric_limits<double>::max());
847  this->Axis->SetUnscaledRange(range);
848  this->Axis->SetAxisVisible(false);
849  this->Axis->SetLabelsVisible(!indexedMode && this->DrawTickLabels == 1);
850  this->Axis->SetTicksVisible(!indexedMode && this->DrawTickMarks);
851  this->Axis->SetGridVisible(false);
852 
853  if (this->AutomaticLabelFormat) {
854  this->Axis->SetNotation(vtkAxis::STANDARD_NOTATION);
855  } else {
856  this->Axis->SetNotation(vtkAxis::PRINTF_NOTATION);
857  }
858  this->Axis->SetLabelFormat(std::string(this->LabelFormat));
859  this->Axis->SetLogScale(this->LookupTable->UsingLogScale() == 1);
860  this->Axis->AutoScale();
861  this->Axis->SetRangeLabelsVisible(!indexedMode &&
862  this->AddRangeLabels == 1);
863  this->Axis->SetRangeLabelFormat(std::string(this->RangeLabelFormat));
864  this->Axis->SetNumberOfTicks(this->NumberOfTicks);
865 
866  if (this->UseCustomLabels) {
867  if (this->Axis->GetLogScale()) {
868  // Take log of label positions
869  vtkNew<vtkDoubleArray> logCustomLabels;
870  logCustomLabels->SetNumberOfTuples(
871  this->CustomLabels->GetNumberOfTuples());
872  for (vtkIdType id = 0; id < logCustomLabels->GetNumberOfTuples();
873  ++id) {
874  double d = this->CustomLabels->GetValue(id);
875  d = log10(d);
876  logCustomLabels->SetValue(id, d);
877  }
878  this->Axis->SetCustomTickPositions(logCustomLabels.GetPointer());
879  } else {
880  this->Axis->SetCustomTickPositions(this->CustomLabels);
881  }
882  } else {
883  this->Axis->SetCustomTickPositions(NULL);
884  }
885 
886  this->Axis->SetUnscaledRange(range);
887  this->Axis->RecalculateTickSpacing();
888 
889  this->Axis->Update();
890  this->Axis->Paint(painter);
891 }
892 
893 //----------------------------------------------------------------------------
894 void vtkContext2DScalarBarActor::PaintTitle(vtkContext2D* painter,
895  double size[2]) {
896  std::string combinedTitle(this->Title);
897  if (this->ComponentTitle && strlen(this->ComponentTitle) > 0) {
898  combinedTitle.append(" ");
899  combinedTitle.append(this->ComponentTitle);
900  }
901  // Apply the text property so that title size is up to date.
902  double titleOrientation = 0.0;
903  if (this->GetOrientation() == VTK_ORIENT_VERTICAL &&
904  !this->GetForceHorizontalTitle()) {
905  titleOrientation = 90.0;
906  }
907  this->TitleTextProperty->SetOrientation(titleOrientation);
908  this->TitleTextProperty->SetJustification(this->GetTitleJustification());
909  painter->ApplyTextProp(this->TitleTextProperty);
910 
911  // Get title size
912  float titleBounds[4];
913  painter->ComputeStringBounds(combinedTitle, titleBounds);
914  float titleWidth = titleBounds[2];
915  float titleHeight = titleBounds[3];
916 
917  // vtkAxis::GetBoundingRect() is not accurate. Compute it ourselves.
918  // All the code in this section is needed to get the actual bounds of
919  // the axis including any offsets applied in PaintAxis().
920  vtkNew<vtkBoundingRectContextDevice2D> boundingDevice;
921  vtkNew<vtkContextDevice2D> contextDevice;
922  boundingDevice->SetDelegateDevice(contextDevice.Get());
923  boundingDevice->Begin(this->CurrentViewport);
924  vtkNew<vtkContext2D> context;
925  context->Begin(boundingDevice);
926  this->PaintAxis(context, size);
927  context->End();
928  boundingDevice->End();
929 
930  vtkRectf axisRect = boundingDevice->GetBoundingRect();
931 
932  vtkRectf barAndAxisRect = axisRect;
933  vtkRectf colorBarRect = this->GetColorBarRect(size);
934  barAndAxisRect.AddRect(colorBarRect);
935 
936  float titleX = barAndAxisRect.GetX() + 0.5 * barAndAxisRect.GetWidth();
937  float titleY = colorBarRect.GetY() + 0.5 * colorBarRect.GetHeight();
938  if (this->GetOrientation() == VTK_ORIENT_HORIZONTAL ||
939  this->ForceHorizontalTitle) {
940  if (this->GetTitleJustification() == VTK_TEXT_LEFT) {
941  titleX = barAndAxisRect.GetX();
942  } else if (this->GetTitleJustification() == VTK_TEXT_RIGHT) {
943  titleX = barAndAxisRect.GetX() + barAndAxisRect.GetWidth();
944  }
945  if (this->GetTextPosition() ==
947  titleY = axisRect.GetY() - titleHeight - 0.25 * titleHeight;
948  } else {
949  // Handle zero-height axis.
950  if (axisRect.GetHeight() < 1.0) {
951  axisRect.SetHeight(colorBarRect.GetHeight());
952  }
953  titleY =
954  axisRect.GetY() + axisRect.GetHeight() + 0.25 * titleHeight;
955  }
956 
957  // Move title to the top if the title is forced horizontal
958  if (this->ForceHorizontalTitle &&
959  this->GetOrientation() != VTK_ORIENT_HORIZONTAL) {
960  titleY = barAndAxisRect.GetY() + barAndAxisRect.GetHeight() +
961  0.25 * titleHeight;
962  }
963  } else // Vertical orientation
964  {
965  // Handle zero-width axis.
966  if (axisRect.GetWidth() < 1.0) {
967  axisRect.SetWidth(0.25 * colorBarRect.GetWidth());
968  }
969  if (this->GetTitleJustification() == VTK_TEXT_LEFT) {
970  titleY = barAndAxisRect.GetY();
971  } else if (this->GetTitleJustification() == VTK_TEXT_RIGHT) {
972  titleY = barAndAxisRect.GetY() + barAndAxisRect.GetHeight();
973  }
974  if (this->GetTextPosition() ==
976  titleX = colorBarRect.GetX() - axisRect.GetWidth();
977  } else {
978  titleX = colorBarRect.GetX() + colorBarRect.GetWidth() +
979  axisRect.GetWidth() + titleWidth;
980  }
981  }
982 
983  painter->ApplyTextProp(this->TitleTextProperty);
984  painter->DrawString(titleX, titleY, combinedTitle);
985 }
986 
987 //----------------------------------------------------------------------------
988 bool vtkContext2DScalarBarActor::Paint(vtkContext2D* painter) {
989  if (!this->Visibility) {
990  return false;
991  }
992 
993  this->UpdateTextProperties();
994 
995  vtkPen* pen = painter->GetPen();
996  vtkBrush* brush = painter->GetBrush();
997 
998  // Save previous settings
999  vtkNew<vtkPen> savePen;
1000  savePen->DeepCopy(pen);
1001  vtkNew<vtkBrush> saveBrush;
1002  saveBrush->DeepCopy(brush);
1003 
1004  pen->SetColorF(1, 1, 1);
1005  brush->SetColorF(1, 0, 0);
1006 
1007  vtkNew<vtkPoints2D> rect;
1008  rect->InsertNextPoint(0, 00);
1009  rect->InsertNextPoint(200, 40);
1010 
1011  int* displayPosition = this->PositionCoordinate->GetComputedDisplayValue(
1012  this->CurrentViewport);
1013 
1014  // Ensure that the scene held by the Axis is the current renderer
1015  // so that things like tile scale and DPI are correct.
1016  this->Axis->GetScene()->SetRenderer(
1017  vtkRenderer::SafeDownCast(this->CurrentViewport));
1018 
1019  double size[2];
1020  this->GetSize(size, painter);
1021 
1022  // Paint the various components
1023  vtkNew<vtkTransform2D> tform;
1024  tform->Translate(displayPosition[0], displayPosition[1]);
1025  painter->PushMatrix();
1026  painter->AppendTransform(tform.GetPointer());
1027 
1028  this->PaintColorBar(painter, size);
1029  this->PaintAxis(painter, size);
1030  // IMPORTANT: this needs to be done *after* this->Axis->Update() is called
1031  // in PaintAxis() so that we get an accurate axis bounding rectangle.
1032  this->PaintTitle(painter, size);
1033 
1034  // Restore settings
1035  pen->DeepCopy(savePen.GetPointer());
1036  brush->DeepCopy(saveBrush.GetPointer());
1037 
1038  painter->PopMatrix();
1039 
1040  return false;
1041 }
1042 
1043 //----------------------------------------------------------------------------
1046  this->ScalarBarItem, this->CurrentViewport);
1047 }
1048 
1049 //----------------------------------------------------------------------------
1050 void vtkContext2DScalarBarActor::PaintAnnotations(
1051  vtkContext2D* painter,
1052  double size[2],
1053  const vtkAnnotationMap& annotationAnchors) {
1054  // Set the annotation text properties
1055  painter->ApplyTextProp(this->Axis->GetLabelProperties());
1056 
1057  if (this->Orientation == VTK_ORIENT_VERTICAL) {
1058  this->PaintAnnotationsVertically(painter, size, annotationAnchors);
1059  } else {
1060  this->PaintAnnotationsHorizontally(painter, size, annotationAnchors);
1061  }
1062 }
1063 
1064 namespace {
1065 
1066 //----------------------------------------------------------------------------
1067 typedef struct AI {
1068  double Anchor;
1069  double Position;
1070  std::string Annotation;
1071  double Span;
1072 } AnnotationInfo;
1073 
1074 //----------------------------------------------------------------------------
1075 void DistributeAnnotations(std::vector<AnnotationInfo>& annotations,
1076  float spacer) {
1077  // Look for clusters of overlapping annotations. We'll space these
1078  // annotations about the center of mass of each cluster. This winds
1079  // up looking nice.
1080 
1081  // Process clusters.
1082  // 1. Find centroid of cluster.
1083  // 2. Compute lower and upper bounds of cluster.
1084  // 3. Layout the labels.
1085  bool overlapDetected = false;
1086  int tries = 0;
1087  int maxTries = 20;
1088 
1089  // Keep track of adjacent annotations that overlap at any point in
1090  // the placement process. This is to prevent annotations from
1091  // potentially jumping from cluster to cluster during the layout
1092  // process. overlaps[j] == true means that annotations j and j+1
1093  // overlapped at some point.
1094  std::vector<bool> overlaps(annotations.size(), false);
1095 
1096  // Iterate repeatedely in case repositioning of clustered
1097  // annotations causes new overlap.
1098  do {
1099  overlapDetected = false;
1100  double clusterWidth = 0.0;
1101  size_t clusterCount = 0;
1102  for (size_t j = 0; j < annotations.size(); ++j) {
1103  // Check for overlap with neighbors
1104  bool overlapsNext = false;
1105  double lowerMax = 0.0;
1106  double upperMin = 0.0;
1107 
1108  if (j < annotations.size() - 1) {
1109  lowerMax = annotations[j].Position + 0.5 * annotations[j].Span +
1110  0.5 * spacer;
1111  upperMin = annotations[j + 1].Position -
1112  0.5 * annotations[j + 1].Span - 0.5 * spacer;
1113  overlapsNext = lowerMax > upperMin;
1114  overlapDetected = overlapDetected || overlapsNext;
1115  }
1116 
1117  if (overlapDetected) {
1118  clusterWidth += annotations[j].Span;
1119  clusterCount++;
1120  }
1121 
1122  if (overlapsNext) {
1123  overlaps[j] = true;
1124  }
1125 
1126  if (!overlaps[j]) {
1127  // Cluster ended. Go back and change the annotation positions
1128  // based on the cluster centroid.
1129  if (clusterCount > 0) {
1130  // Weight centers of each label by width
1131  double clusterCenter = 0.0;
1132  for (size_t k = j - clusterCount + 1; k <= j; ++k) {
1133  double weight = annotations[k].Span / clusterWidth;
1134  clusterCenter += annotations[k].Anchor * weight;
1135  }
1136 
1137  double accumWidth = 0.0;
1138  clusterWidth +=
1139  spacer * (clusterCount - 1); // Add in spacer width
1140  for (size_t k = 0; k < clusterCount; ++k) {
1141  // Start from the right (bigger coordinate) side and
1142  // work toward the left.
1143  annotations[j - k].Position =
1144  clusterCenter + 0.5 * clusterWidth -
1145  accumWidth - 0.5 * annotations[j - k].Span;
1146  accumWidth += annotations[j - k].Span + spacer;
1147  }
1148  }
1149 
1150  // reset cluster stats
1151  clusterWidth = 0.0;
1152  clusterCount = 0;
1153  }
1154  }
1155 
1156  ++tries;
1157  } while (overlapDetected && tries < maxTries);
1158 }
1159 
1160 } // end anonymous namespace
1161 
1162 //----------------------------------------------------------------------------
1163 void vtkContext2DScalarBarActor::PaintAnnotationsVertically(
1164  vtkContext2D* painter,
1165  double size[2],
1166  const vtkAnnotationMap& annotationAnchors) {
1167  vtkRectf barRect = this->GetColorBarRect(size);
1168 
1169  // Copy annotations and position info into a vector.
1170  std::vector<AnnotationInfo> annotations;
1171  annotations.reserve(annotationAnchors.size());
1172  vtkAnnotationMap::const_iterator annotationMapIter;
1173  for (annotationMapIter = annotationAnchors.begin();
1174  annotationMapIter != annotationAnchors.end(); ++annotationMapIter) {
1175  float bounds[4]; // bounds contains x, y, width, height
1176  painter->ComputeStringBounds(annotationMapIter->second, bounds);
1177 
1178  AnnotationInfo p;
1179  p.Anchor = annotationMapIter->first;
1180  p.Position = annotationMapIter->first;
1181  p.Annotation = annotationMapIter->second;
1182  p.Span = bounds[3]; // height
1183  annotations.push_back(p);
1184  }
1185 
1186  vtkWindow* renWin = this->CurrentViewport->GetVTKWindow();
1187  int tileScale[2];
1188  renWin->GetTileScale(tileScale);
1189 
1190  // Calculate the annotation labels
1191  const float spacer =
1192  1 * tileScale[0]; // vertical space between annotations
1193  DistributeAnnotations(annotations, spacer);
1194 
1195  // Iterate over anchors and draw annotations
1196  std::vector<AnnotationInfo>::iterator vectorIter;
1197  for (vectorIter = annotations.begin(); vectorIter != annotations.end();
1198  ++vectorIter) {
1199  const int annotationLeader = 8 * tileScale[0];
1200  double anchorPt[2] = {barRect.GetX(), vectorIter->Anchor};
1201  double labelPt[2] = {anchorPt[0] - annotationLeader,
1202  vectorIter->Position};
1203 
1204  painter->GetTextProp()->SetJustification(VTK_TEXT_RIGHT);
1205 
1206  if (this->TextPosition == PrecedeScalarBar) {
1207  anchorPt[0] = barRect.GetX() + barRect.GetWidth();
1208  labelPt[0] = anchorPt[0] + annotationLeader;
1209 
1210  painter->GetTextProp()->SetJustification(VTK_TEXT_LEFT);
1211  }
1212 
1213  vtkPen* pen = painter->GetPen();
1214  pen->SetOpacity(255);
1215  pen->SetLineType(vtkPen::SOLID_LINE);
1216  pen->SetColorF(this->Axis->GetLabelProperties()->GetColor());
1217 
1218  painter->DrawLine(anchorPt[0], anchorPt[1], labelPt[0], labelPt[1]);
1219  painter->GetTextProp()->SetVerticalJustification(VTK_TEXT_CENTERED);
1220  painter->DrawString(labelPt[0], labelPt[1], vectorIter->Annotation);
1221  }
1222 }
1223 
1224 //----------------------------------------------------------------------------
1225 void vtkContext2DScalarBarActor::PaintAnnotationsHorizontally(
1226  vtkContext2D* painter,
1227  double size[2],
1228  const vtkAnnotationMap& annotationAnchors) {
1229  vtkRectf barRect = this->GetColorBarRect(size);
1230 
1231  // Copy annotations and position info into a vector.
1232  std::vector<AnnotationInfo> annotations;
1233  annotations.reserve(annotationAnchors.size());
1234  vtkAnnotationMap::const_iterator annotationMapIter;
1235  for (annotationMapIter = annotationAnchors.begin();
1236  annotationMapIter != annotationAnchors.end(); ++annotationMapIter) {
1237  float bounds[4]; // bounds contains x, y, width, height
1238  painter->ComputeStringBounds(annotationMapIter->second, bounds);
1239  AnnotationInfo p;
1240  p.Anchor = annotationMapIter->first;
1241  p.Position = annotationMapIter->first;
1242  p.Annotation = annotationMapIter->second;
1243  p.Span = bounds[2]; // width
1244  annotations.push_back(p);
1245  }
1246 
1247  vtkWindow* renWin = this->CurrentViewport->GetVTKWindow();
1248  int tileScale[2];
1249  renWin->GetTileScale(tileScale);
1250 
1251  // Get horizontal spacing distance as a function of the font
1252  // properties. Use width of '-' as spacing between annotations.
1253  float bounds[4];
1254  painter->ComputeStringBounds("-", bounds);
1255  const float spacer = bounds[2] * tileScale[0];
1256 
1257  // Calculate the annotation labels
1258  DistributeAnnotations(annotations, spacer);
1259 
1260  // Iterate over anchors and draw annotations
1261  std::vector<AnnotationInfo>::iterator vectorIter;
1262  for (vectorIter = annotations.begin(); vectorIter != annotations.end();
1263  ++vectorIter) {
1264  const int annotationLeader = 8 * tileScale[0];
1265  double anchorPt[2] = {vectorIter->Anchor, barRect.GetY()};
1266  double labelPt[2] = {vectorIter->Position,
1267  anchorPt[1] - annotationLeader};
1268  double labelOffset = 3;
1269 
1270  painter->GetTextProp()->SetJustification(VTK_TEXT_CENTERED);
1271  painter->GetTextProp()->SetVerticalJustification(VTK_TEXT_TOP);
1272  if (this->TextPosition == PrecedeScalarBar) {
1273  anchorPt[1] = barRect.GetY() + barRect.GetHeight();
1274  labelPt[1] = anchorPt[1] + annotationLeader;
1275  labelOffset *= -1.0;
1276 
1277  painter->GetTextProp()->SetVerticalJustification(VTK_TEXT_BOTTOM);
1278  }
1279  painter->DrawString(labelPt[0], labelPt[1] - labelOffset,
1280  vectorIter->Annotation);
1281 
1282  vtkPen* pen = painter->GetPen();
1283  pen->SetOpacity(255);
1284  pen->SetLineType(vtkPen::SOLID_LINE);
1285  pen->SetColorF(this->Axis->GetLabelProperties()->GetColor());
1286 
1287  painter->DrawLine(anchorPt[0], anchorPt[1], labelPt[0], labelPt[1]);
1288  }
1289 }
1290 
1291 //----------------------------------------------------------------------------
1292 void vtkContext2DScalarBarActor::PrintSelf(ostream& os, vtkIndent indent) {
1293  this->Superclass::PrintSelf(os, indent);
1294 }
1295 
1296 //----------------------------------------------------------------------------
1298  vtkDiscretizableColorTransferFunction* ctf =
1299  vtkDiscretizableColorTransferFunction::SafeDownCast(
1300  this->LookupTable);
1301  if (!ctf) {
1302  return 0;
1303  }
1304  if (this->GetAutomaticAnnotations() && !ctf->GetIndexedLookup()) {
1305  // How many annotations should there be?
1306  return ctf->GetNumberOfAvailableColors();
1307  } else // Manual annotations
1308  {
1309  return ctf->GetNumberOfAnnotatedValues();
1310  }
1311 }
std::shared_ptr< core::Tensor > image
int width
int size
int height
char type
math::float4 color
#define NULL
vtkTypeMacro(vtkScalarBarItem, vtkContextItem)
virtual bool Paint(vtkContext2D *painter)
void SetCustomLabel(vtkIdType index, double value)
void SetNumberOfCustomLabels(vtkIdType numLabels)
void ReleaseGraphicsResources(vtkWindow *window) override
int RenderOverlay(vtkViewport *viewport) override
int RenderOpaqueGeometry(vtkViewport *viewport) override
void PrintSelf(ostream &os, vtkIndent indent) override
double colors[3]
ImGuiContext * context
Definition: Window.cpp:76
normal_z y
normal_z x
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Definition: SmallVector.h:1370
#define SNPRINTF
vtkStandardNewMacro(vtkContext2DScalarBarActor)