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
18using namespace ROOT::Experimental;
19
20RPalette::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
39namespace {
40static 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
51RPalette::RPalette(bool interpolate, const std::vector<RColor> &points)
52 : RPalette(interpolate, true, AddOrdinals(points))
53{}
54
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
114namespace {
115using GlobalPalettes_t = std::unordered_map<std::string, RPalette>;
116static 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
130static 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}
uint8_t
Definition: Converters.cxx:858
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
#define e(i)
Definition: RSha256.hxx:103
char name[80]
Definition: TGX11.cxx:109
point * points
Definition: X3DBuffer.c:22
The color class.
Definition: RColor.hxx:34
static constexpr RGB_t kRed
Definition: RColor.hxx:219
void SetRGB(const RGB_t &rgb)
Set r/g/b components of color.
Definition: RColor.hxx:72
static constexpr RGB_t kWhite
Definition: RColor.hxx:221
static constexpr RGB_t kBlack
Definition: RColor.hxx:206
static constexpr RGB_t kBlue
Definition: RColor.hxx:214
void SetAlpha(uint8_t alpha)
Set alpha as value from range 0..255.
Definition: RColor.hxx:106
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
RColor GetColor(double ordinal)
Get the color associated with the ordinal value.
Definition: RPalette.cxx:55
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:142
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
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:617