snark
colour.h
1 // This file is part of snark, a generic and flexible library
2 // for robotics research.
3 //
4 // Copyright (C) 2011 The University of Sydney
5 //
6 // snark is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 3 of the License, or (at your option) any later version.
10 //
11 // snark is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 // for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with snark. If not, see <http://www.gnu.org/licenses/>.
18 
19 #ifndef SNARK_GRAPHICS_COLOUR_HEADER_GUARD_
20 #define SNARK_GRAPHICS_COLOUR_HEADER_GUARD_
21 
22 #include <boost/lexical_cast.hpp>
23 #include <comma/base/exception.h>
24 #include <comma/math/compare.h>
25 #include <comma/Point/Point.h>
26 #include <comma/visiting/traits.h>
27 
28 namespace snark { namespace graphics {
29 
31 template < typename T >
33 {
34  typedef T numeric_type;
35  static numeric_type min() { return 0; }
36  static numeric_type max() { return 1; }
37 };
38 
40 template <>
41 struct colour_traits< unsigned char >
42 {
43  typedef unsigned int numeric_type;
44  static numeric_type min() { return 0; }
45  static numeric_type max() { return 255; }
46 };
47 
49 template < typename T >
50 class colour : public comma::Point< T, 4 >
51 {
52  public:
54  colour();
55 
56 // /// copy constructor
57 // colour( const colour& rhs );
58 
60  colour( T r, T g, T b, T a = colour_traits< T >::max() );
61 
62 // /// conversion constructor
63 // template < typename S >
64 // colour( const colour< S >& rhs );
65 //
66 // /// assignment
67 // const colour< T >& operator=( const colour& rhs );
68 //
69 // /// conversion assignment
70 // template < typename S >
71 // const colour< T >& operator=( const colour< S >& rhs );
72 
74  template < typename S >
75  S as() const;
76 
78  T red() const;
79 
81  T green() const;
82 
84  T blue() const;
85 
87  T alpha() const;
88 
90  T hue() const;
91 
93  T saturation() const;
94 
96  T brightness() const;
97 
99  colour< T >& red( T t );
100 
102  colour< T >& green( T t );
103 
105  colour< T >& blue( T t );
106 
108  colour< T >& alpha( T t );
109 
111  typedef comma::Point< T, 4 > Base;
112 
115  bool operator==( const colour& rhs ) const { return comma::Point< T, 4 >::operator==( rhs ); }
116  bool operator!=( const colour& rhs ) const { return !operator==( rhs ); }
117  colour operator-() const { return colour( colour_traits< T >::max() - red(), colour_traits< T >::max() - green(), colour_traits< T >::max() - blue() ); }
118  const colour& operator+=( const colour& rhs ) { red( red() + rhs.red() ); green( green() + rhs.green() ); blue( blue() + rhs.blue() ); alpha( ( alpha() + rhs.alpha() ) / 2 ); return *this; }
119  const colour& operator*=( double d );
120  const colour& operator-=( const colour& rhs ) { return operator+=( -rhs ); }
121  const colour& operator/=( double d ) { return operator*=( 1 / d ); }
122  colour operator+( const colour& rhs ) const { colour c( *this ); c += rhs; return c; }
123  colour operator-( const colour& rhs ) const { colour c( *this ); c -= rhs; return c; }
124  colour operator*( double d ) const { colour c( *this ); c *= d; return c; }
125  colour operator/( double d ) const { colour c( *this ); c /= d; return c; }
126 
128  static colour< T > fromString( const std::string& rgba );
129 
131  const T& operator[]( std::size_t i ) const { return comma::Point< T, 4 >::operator[]( i ); }
132 
133  private:
134  T& operator[]( std::size_t i ) { return comma::Point< T, 4 >::operator[]( i ); }
135 };
136 
137 namespace impl {
138 
139 template < typename T >
140 inline void validate( T t )
141 {
142  if( math::less( t, colour_traits< T >::min() ) || math::less( colour_traits< T >::max(), t ) )
143  {
144  COMMA_THROW( comma::exception, "expected value in [" << colour_traits< T >::min() << ", " << colour_traits< T >::max() << "], got " << t );
145  }
146 }
147 
148 template < typename T > T fromString( const std::string& s ) { return boost::lexical_cast< T >( s ); }
149 
150 template <>
151 inline unsigned char fromString< unsigned char >( const std::string& s ) // todo: check value
152 {
153  unsigned char high = static_cast< unsigned char >( s.at( 0 ) );
154  unsigned char low = static_cast< unsigned char >( s.at( 1 ) );
155  return 16 * ( '0' <= high && high <= '9' ? high - '0' : 'a' <= high && high <= 'f' ? high - 'a' - 10 : high - 'A' - 10 )
156  + '0' <= low && low <= '9' ? low - '0' : 'a' <= low && low <= 'f' ? low - 'a' - 10 : low - 'A' - 10;
157 }
158 
159 } // namespace impl {
160 
161 template <>
162 inline colour< unsigned char > colour< unsigned char >::fromString( const std::string& rgba )
163 {
164  if( ( rgba.length() != 8 && rgba.length() != 10 ) || rgba.at( 0 ) != '0' || ( rgba.at( 1 ) != 'x' && rgba.at( 1 ) != 'X' ) ) { COMMA_THROW( graphics::exception, "expected hex colour, got \"" << rgba << "\"" ); }
165  colour< unsigned char > c( impl::fromString< unsigned char >( rgba.substr( 2 ) )
166  , impl::fromString< unsigned char >( rgba.substr( 4 ) )
167  , impl::fromString< unsigned char >( rgba.substr( 6 ) ) );
168  if( rgba.length() == 10 ) { c.alpha( impl::fromString< unsigned char >( rgba.substr( 8 ) ) ); }
169  return c;
170 }
171 
172 template < typename T >
174 
175 // template < typename T >
176 // inline colour< T >::colour( const colour& rhs ) { operator=( rhs ); }
177 
178 template < typename T >
179 inline colour< T >::colour( T r, T g, T b, T a )
180 {
181  red( r );
182  green( g );
183  blue( b );
184  alpha( a );
185 }
186 
187 // template < typename T >
188 // template < typename S >
189 // inline colour< T >::colour( const colour< S >& rhs ) { operator=( rhs ); }
190 //
191 // template < typename T >
192 // inline const colour< T >& colour< T >::operator=( const colour& rhs )
193 // {
194 // this->comma::Point< T, 4 >::operator=( rhs );
195 // return *this;
196 // }
197 //
198 // template < typename T >
199 // template < typename S >
200 // inline const colour< T >& colour< T >::operator=( const colour< S >& rhs )
201 // {
202 // for( unsigned int i = 0; i < Base::Dimension; ++i )
203 // {
204 // this->operator[]( i ) = static_cast< T >( ( ( colour_traits< T >::max() - colour_traits< T >::min() ) * rhs.colour< S >::Base::operator[]( i ) ) / ( colour_traits< S >::max() - colour_traits< S >::min() ) );
205 // }
206 // return *this;
207 // }
208 
209 template < typename T >
210 template < typename S >
211 inline S colour< T >::as() const
212 {
213  typedef typename S::Type Type;
214  static const Type fs = colour_traits< Type >::max() - colour_traits< Type >::min();
215  static const Type ft = colour_traits< T >::max() - colour_traits< T >::min();
216  return S( static_cast< Type >( ( float( this->red() ) / ft ) * fs )
217  , static_cast< Type >( ( float( this->green() ) / ft ) * fs )
218  , static_cast< Type >( ( float( this->blue() ) / ft ) * fs )
219  , static_cast< Type >( ( float( this->alpha() ) / ft ) * fs ) );
220 }
221 
222 template < typename T >
223 inline T colour< T >::red() const { return const_cast< colour* >( this )->operator[]( 0 ); } // a quick fix
224 
225 template < typename T >
226 inline T colour< T >::green() const { return const_cast< colour* >( this )->operator[]( 1 ); }
227 
228 template < typename T >
229 inline T colour< T >::blue() const { return const_cast< colour* >( this )->operator[]( 2 ); }
230 
231 template < typename T >
232 inline T colour< T >::alpha() const { return const_cast< colour* >( this )->operator[]( 3 ); }
233 
234 template < typename T >
236 {
237  impl::validate( t );
238  this->operator[]( 0 ) = t;
239  return *this;
240 }
241 
242 template < typename T >
244 {
245  impl::validate( t );
246  this->operator[]( 1 ) = t;
247  return *this;
248 }
249 
250 template < typename T >
252 {
253  impl::validate( t );
254  this->operator[]( 2 ) = t;
255  return *this;
256 }
257 
258 template < typename T >
260 {
261  impl::validate( t );
262  this->operator[]( 3 ) = t;
263  return *this;
264 }
265 
266 template < typename T >
267 const colour< T >& colour< T >::operator*=( double d ) // todo: quick and dirty now
268 {
269  float f = static_cast< float> ( d );
270  red( red() * f );
271  green( green() * f );
272  blue( blue() * f );
273  alpha( alpha() * f );
274  return *this;
275 }
276 
277 template < typename T >
279 {
280  // todo
281 }
282 
283 template < typename T >
285 {
286  // todo
287 }
288 
289 template < typename T >
291 {
292  // todo
293 }
294 
295 } } // namespace snark { namespace graphics {
296 
297 namespace snark { namespace Visiting {
298 
300 template < typename T > struct traits< snark::graphics::colour< T > >
301 {
303  template < typename Key, class Visitor >
304  static void visit( const Key&, const snark::graphics::colour< T >& p, Visitor& v )
305  {
306  v.apply( "r", p.red() );
307  v.apply( "g", p.green() );
308  v.apply( "b", p.blue() );
309  v.apply( "a", p.alpha() );
310  }
311 
313  template < typename Key, class Visitor >
314  static void visit( Key, snark::graphics::colour< T >& p, Visitor& v )
315  {
316  T r = p.red();
317  T g = p.green();
318  T b = p.blue();
319  T a = p.alpha();
320  v.apply( "r", r );
321  v.apply( "g", g );
322  v.apply( "b", b );
323  v.apply( "a", a );
324  p = snark::graphics::colour< T >( r, g, b, a );
325  }
326 };
327 
328 } } // namespace snark { namespace Visiting {
329 
330 #endif /*SNARK_GRAPHICS_COLOUR_HEADER_GUARD_*/