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