Logo ROOT  
Reference Guide
RPalette.cxx
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. *
3  * All rights reserved. *
4  * *
5  * For the licensing terms see $ROOTSYS/LICENSE. *
6  * For the list of contributors see $ROOTSYS/README/CREDITS. *
7  *************************************************************************/
8 
9 #include "ROOT/RPalette.hxx"
10 
11 #include "ROOT/RLogger.hxx"
12 
13 #include <algorithm>
14 #include <cmath>
15 #include <exception>
16 #include <unordered_map>
17 
18 using namespace ROOT::Experimental;
19 
20 RPalette::RPalette(bool interpolate, bool knownNormalized, const std::vector<RPalette::OrdinalAndColor> &points)
21  : fColors(points), fInterpolate(interpolate), fNormalized(knownNormalized)
22 {
23  if (points.size() < 2)
24  throw std::runtime_error("Must have at least two points to build a palette!");
25 
26  std::sort(fColors.begin(), fColors.end());
27 
28  if (!knownNormalized) {
29  // Is this a normalized palette? I.e. are the first and last ordinals 0 and 1?
30  double high = fColors.back().fOrdinal;
31  double low = fColors.front().fOrdinal;
32  double prec = (high - low) * 1e-8;
33 
34  auto reasonablyEqual = [&](double val, double expected) -> bool { return std::fabs(val - expected) < prec; };
35  fNormalized = reasonablyEqual(low, 0.) && reasonablyEqual(high, 1.);
36  }
37 }
38 
39 namespace {
40 static std::vector<RPalette::OrdinalAndColor> AddOrdinals(const std::vector<RColor> &points)
41 {
42  std::vector<RPalette::OrdinalAndColor> ret(points.size());
43  auto addOneOrdinal = [&](const RColor &col) -> RPalette::OrdinalAndColor {
44  return {1. / (points.size() - 1) * (&col - points.data()), col};
45  };
46  std::transform(points.begin(), points.end(), ret.begin(), addOneOrdinal);
47  return ret;
48 }
49 } // unnamed namespace
50 
51 RPalette::RPalette(bool interpolate, const std::vector<RColor> &points)
52  : RPalette(interpolate, true, AddOrdinals(points))
53 {}
54 
55 RColor RPalette::GetColor(double ordinal)
56 {
57  if (fColors.size() == 0)
58  return RColor();
59 
60  if (fColors.size() == 1)
61  return fColors.front().fColor;
62 
63  constexpr float epsilon = 1e-8;
64  if (ordinal < fColors.front().fOrdinal + epsilon)
65  return fColors.front().fColor;
66 
67  if (ordinal > fColors.back().fOrdinal - epsilon)
68  return fColors.back().fColor;
69 
70  auto iColor2 = std::lower_bound(fColors.begin(), fColors.end(), ordinal);
71  auto iColor1 = iColor2 - 1;
72 
73  auto diff1 = ordinal - iColor1->fOrdinal;
74  auto diff2 = iColor2->fOrdinal - ordinal;
75 
76  if ((diff1 < -epsilon) || (diff2 < -epsilon)) {
77  R__ERROR_HERE("Gpad") << "Wrong palette settings";
78  return fColors.back().fColor;
79  }
80 
81  if (diff1 < epsilon)
82  return iColor1->fColor;
83 
84  if (diff2 < epsilon)
85  return iColor2->fColor;
86 
87  if (IsGradient()) {
88  auto dist = diff1 + diff2;
89  auto rgba1 = iColor1->fColor.AsRGBA();
90  auto rgba2 = iColor2->fColor.AsRGBA();
91  if ((dist > epsilon) && (rgba1.size() > 2) && (rgba2.size() > 2)) {
92  if (rgba1.size() == 4)
93  rgba2.resize(4, 0xff);
94  else if (rgba2.size() == 4)
95  rgba1.resize(4, 0xff);
96 
97  for (unsigned i = 0; i < rgba1.size(); ++i)
98  rgba1[i] = (uint8_t) std::lround( (diff2*rgba1[i] + diff1*rgba2[i]) / dist);
99 
100  RColor res;
101  res.SetRGB(rgba1[0], rgba1[1], rgba1[2]);
102  if (rgba1.size() == 4)
103  res.SetAlpha(rgba1[3]);
104 
105  return res;
106  }
107 
108  R__ERROR_HERE("Gpad") << "Fail to interpolate color";
109  }
110 
111  return (diff2 < diff1) ? iColor2->fColor : iColor1->fColor;
112 }
113 
114 namespace {
115 using GlobalPalettes_t = std::unordered_map<std::string, RPalette>;
116 static GlobalPalettes_t CreateDefaultPalettes()
117 {
118  GlobalPalettes_t ret;
119  ret["default"] = RPalette({RColor::kRed, RColor::kBlue});
120  ret["bw"] = RPalette({RColor::kBlack, RColor::kWhite});
121  ret["bird"] = RPalette({RColor(53,42, 135), RColor(15,92,221), RColor(20,129,214),
122  RColor(6,164,202), RColor(46,183, 164), RColor(135,191,119),
123  RColor(209,187,89), RColor(254,200,50), RColor(249,251,14)});
124  ret["rainbow"] = RPalette({RColor(0,0,99), RColor(5,48,142), RColor(15,124,198),
125  RColor(35,192,201), RColor(102,206,90), RColor(196,226,22),
126  RColor(208,97,13), RColor(199,16,8), RColor(110,0,2)});
127  return ret;
128 }
129 
130 static GlobalPalettes_t &GetGlobalPalettes()
131 {
132  static GlobalPalettes_t globalPalettes = CreateDefaultPalettes();
133  return globalPalettes;
134 }
135 } // unnamed namespace
136 
138 {
139  GetGlobalPalettes()[std::string(name)] = palette;
140 }
141 
143 {
144  static const RPalette sNoPaletteWithThatName;
145  if (name.empty()) name = "bird";
146  auto iGlobalPalette = GetGlobalPalettes().find(std::string(name));
147  if (iGlobalPalette == GetGlobalPalettes().end())
148  return sNoPaletteWithThatName;
149  return iGlobalPalette->second;
150 }
ROOT::Experimental::RPalette::GetColor
RColor GetColor(double ordinal)
Get the color associated with the ordinal value.
Definition: RPalette.cxx:55
ROOT::Experimental::RPalette::GetPalette
static const RPalette & GetPalette(std::string_view name="")
Get a global palette by name.
Definition: RPalette.cxx:142
e
#define e(i)
Definition: RSha256.hxx:103
ROOT::Experimental::RPalette::IsGradient
bool IsGradient() const
Whether the palette is a smooth gradient generated by interpolating between the color points.
Definition: RPalette.hxx:111
ROOT::Experimental::RColor::kBlack
static constexpr RGB_t kBlack
Definition: RColor.hxx:215
ROOT::Experimental::RColor::kWhite
static constexpr RGB_t kWhite
Definition: RColor.hxx:230
ROOT::Experimental::RPalette::fNormalized
bool fNormalized
Whether the palette's ordinal numbers are normalized.
Definition: RPalette.hxx:64
string_view
basic_string_view< char > string_view
Definition: libcpp_string_view.h:785
ROOT::Experimental::RColor
The color class.
Definition: RColor.hxx:34
uint8_t
uint8_t
Definition: Converters.cxx:858
ROOT::Experimental::RColor::kBlue
static constexpr RGB_t kBlue
Definition: RColor.hxx:223
ROOT::Experimental::RPalette::fColors
std::vector< OrdinalAndColor > fColors
Palette colors: the color points and their ordinal value.
Definition: RPalette.hxx:58
ROOT::Math::gv_detail::dist
double dist(Rotation3D const &r1, Rotation3D const &r2)
Definition: 3DDistances.cxx:48
RLogger.hxx
ROOT::Math::fabs
VecExpr< UnaryOp< Fabs< T >, VecExpr< A, T, D >, T >, T, D > fabs(const VecExpr< A, T, D > &rhs)
Definition: UnaryOperators.h:131
R__ERROR_HERE
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
RPalette.hxx
epsilon
REAL epsilon
Definition: triangle.c:617
ROOT::Experimental::RPalette::RegisterPalette
static void RegisterPalette(std::string_view name, const RPalette &palette)
Register a palette in the set of global palettes, making it available to GetPalette().
Definition: RPalette.cxx:137
ROOT::Experimental::RPalette::RPalette
RPalette()=default
points
point * points
Definition: X3DBuffer.c:22
ROOT::Experimental::RColor::SetRGB
void SetRGB(const RGB_t &rgb)
Set r/g/b components of color.
Definition: RColor.hxx:72
name
char name[80]
Definition: TGX11.cxx:110
ROOT::Experimental
Definition: RDirectory.hxx:30
ROOT::Experimental::RColor::SetAlpha
void SetAlpha(uint8_t alpha)
Set alpha as value from range 0..255.
Definition: RColor.hxx:115
ROOT::Experimental::RPalette
A set of colors.
Definition: RPalette.hxx:38
ROOT::Experimental::RPalette::OrdinalAndColor
An ordinal value and its associated color.
Definition: RPalette.hxx:41
ROOT::Experimental::RColor::kRed
static constexpr RGB_t kRed
Definition: RColor.hxx:228