A toolkit for working with phylogenetic data.
v0.18.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
utils/tools/color/functions.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
33 #include <algorithm>
34 #include <cassert>
35 #include <cmath>
36 #include <iomanip>
37 #include <ostream>
38 #include <sstream>
39 #include <stdexcept>
40 #include <string>
41 
44 
46 
47 namespace genesis {
48 namespace utils {
49 
50 // =================================================================================================
51 // Color Conversion
52 // =================================================================================================
53 
54 Color color_from_bytes( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
55 {
56  Color c;
57  c.r_byte(r);
58  c.g_byte(g);
59  c.b_byte(b);
60  c.a_byte(a);
61  return c;
62 }
63 
64 Color color_from_hex( std::string const& hex_color, std::string const& prefix )
65 {
66  // Check for correct prefix and trim it.
67  if (hex_color.substr(0, prefix.size()) != prefix) {
68  throw std::invalid_argument("String does not start with given prefix.");
69  }
70  auto const h = utils::trim( hex_color.substr( prefix.size() ));
71 
72  // Check for incorrect chars, as std::stoul (used later for the actual conversion)
73  // might just end parsing instead of throwing...
74  if( h.find_first_not_of("0123456789abcdefABCDEF") != std::string::npos ) {
75  throw std::invalid_argument("Expects string with six or eight hexadecimal digits.");
76  }
77 
78  // Take a two-byte position in h, range [0-3], and parse the to bytes into a double.
79  auto hex_parse = [&h] (size_t pos) {
80  // We select the two-digit substring at the given position,
81  // which resolves to one of the three two-hex-digit color substrings in h.
82  auto s = h.substr(pos * 2, 2);
83  auto v = std::stoul(s, nullptr, 16);
84 
85  // We just fed two chars with a hex value into the conversion, there cannot be a result out
86  // of char range from this.
87  assert(v < 256);
88  return static_cast<double>(v) / 255.0;
89  };
90 
91  // Check for correct input size, and convert accordingly.
92  if( h.size() == 6 ) {
93  return Color( hex_parse(0), hex_parse(1), hex_parse(2) );
94  } else if( h.size() == 8 ) {
95  return Color( hex_parse(0), hex_parse(1), hex_parse(2), hex_parse(3) );
96  } else {
97  throw std::invalid_argument("Expects string with six or eight hexadecimal digits.");
98  }
99 }
100 
101 std::string color_to_hex(
102  Color const& c , std::string const& prefix, bool uppercase, bool with_alpha
103 ) {
104  std::stringstream stream;
105  stream << prefix;
106 
107  auto hex_print = [&stream, uppercase] (unsigned char v) {
108  if (uppercase) {
109  stream << std::setfill ('0') << std::setw(2) << std::hex << std::uppercase
110  << static_cast<int>(v);
111  } else {
112  stream << std::setfill ('0') << std::setw(2) << std::hex << std::nouppercase
113  << static_cast<int>(v);
114  }
115  };
116  hex_print( c.r_byte() );
117  hex_print( c.g_byte() );
118  hex_print( c.b_byte() );
119  if( with_alpha ) {
120  hex_print( c.a_byte() );
121  }
122 
123  return stream.str();
124 }
125 
126 // =================================================================================================
127 // Color Operators
128 // =================================================================================================
129 
130 std::ostream& operator<< (std::ostream& os, Color const& color)
131 {
132  os << "( " << std::to_string( color.r() )
133  << ", " << std::to_string( color.g() )
134  << ", " << std::to_string( color.b() )
135  << ", " << std::to_string( color.a() ) << " )";
136  return os;
137 }
138 
139 // =================================================================================================
140 // Color Gradients
141 // =================================================================================================
142 
143 Color interpolate (Color const& color1, Color const& color2, double fraction)
144 {
145  // Helper function that linearily interpolates between two values.
146  auto interpolate_values = []( double d1, double d2, double fraction )
147  {
148  return (1.0 - fraction) * d1 + fraction * d2;
149  };
150 
151  fraction = std::min( std::max( 0.0, fraction ), 1.0 );
152  double r = interpolate_values( color1.r(), color2.r(), fraction );
153  double g = interpolate_values( color1.g(), color2.g(), fraction );
154  double b = interpolate_values( color1.b(), color2.b(), fraction );
155  double a = interpolate_values( color1.a(), color2.a(), fraction );
156  return Color( r, g, b, a );
157 }
158 
159 Color gradient ( std::map<double, Color> const& ranges, double value )
160 {
161  // Check range sanity.
162  if( ranges.size() < 2 ) {
163  throw std::invalid_argument("Gradient range needs to contain at least two colors.");
164  }
165 
166  // Get range boundaries.
167  double const min = ranges.begin()->first;
168  double const max = ranges.rbegin()->first;
169 
170  // Ensure the correct interval.
171  value = std::min( std::max( min, value ), max );
172 
173  // Set hi_bound to the next bigger item in ranges that comes after the value position.
174  // lo_bound then is the one before it. Now, the range between them includes value.
175  // In case value is exactly equal to a value in ranges, it will be stored in lo_bound.
176  auto hi_bound = ranges.upper_bound( value );
177  auto lo_bound = std::prev( hi_bound );
178  assert( lo_bound != ranges.end() );
179 
180  if( hi_bound == ranges.end() ) {
181  // This is the boundary case that occurs when value is max.
182  // Assert the case and return the last color of the range.
183  assert( value == max );
184  return ranges.rbegin()->second;
185  }
186 
187  // Adjust value to the new interval between lo and hi, and return the interpolated color.
188  value = ( value - lo_bound->first ) / ( hi_bound->first - lo_bound->first );
189  return interpolate( lo_bound->second, hi_bound->second, value );
190 }
191 
192 Color heat_gradient (double percentage)
193 {
194  Color red { 1.0, 0.0, 0.0 };
195  Color yellow { 1.0, 1.0, 0.0 };
196  Color green { 0.0, 1.0, 0.0 };
197 
198  percentage = std::min(std::max(0.0, percentage), 1.0);
199 
200  if (percentage < 0.5) {
201  return interpolate(green, yellow, percentage / 0.5);
202  }
203  return interpolate(yellow, red, (percentage - 0.5) / 0.5);
204 }
205 
206 } // namespace utils
207 } // namespace genesis
double g() const
Definition: color.hpp:108
std::string trim(std::string const &s, std::string const &delimiters)
Return a copy of the input string, with trimmed white spaces.
Definition: string.cpp:238
double r() const
Definition: color.hpp:103
Color color_from_bytes(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
Create a Color given three or four values in the range [ 0, 255 ] for each of the components red...
std::string to_string(T const &v)
Return a string representation of a given value.
Definition: string.hpp:300
Color color_from_hex(std::string const &hex_color, std::string const &prefix)
Create a Color given a hex color string in the format "#003366[ff]".
Header of Color class.
unsigned char b_byte() const
Definition: color.hpp:133
Color interpolate(Color const &color1, Color const &color2, double fraction)
Linearily interpolate between two Colors.
Provides some commonly used string utility functions.
Color heat_gradient(double percentage)
Return a Color that represents a heat gradient for a given percentage value.
unsigned char g_byte() const
Definition: color.hpp:128
Provides easy and fast logging functionality.
unsigned char a_byte() const
Definition: color.hpp:138
double b() const
Definition: color.hpp:113
unsigned char r_byte() const
Definition: color.hpp:123
Color gradient(std::map< double, Color > const &ranges, double value)
Returns a Color that is created using a color gradient.
std::ostream & operator<<(std::ostream &os, NexusBlock const &block)
Definition: block.hpp:80
Color operators and functions.
double a() const
Definition: color.hpp:118
std::string color_to_hex(Color const &c, std::string const &prefix, bool uppercase, bool with_alpha)
Return a hex string representation of a Color in the format "#003366[ff]".