Commit 84f8891d authored by Mathias Goldau's avatar Mathias Goldau

[CHANGE] WColor is now typedefed to osg::Vec4. All memberfunctions not...

[CHANGE] WColor is now typedefed to osg::Vec4. All memberfunctions not contained in Vec4 are outsourced as non member non friend functions in global namespace properly named and grouped via doxygen group "Color utils".
parent 6d90ac56
......@@ -23,84 +23,15 @@
//---------------------------------------------------------------------------
#include <cmath>
#include <cassert>
#include <string>
#include <vector>
#include <boost/lexical_cast.hpp>
#include "../common/WStringUtils.h"
#include "../common/exceptions/WOutOfBounds.h"
#include "../common/WStringUtils.h"
#include "WColor.h"
WColor::WColor( float red, float green, float blue, float alpha )
: m_red( red ),
m_green( green ),
m_blue( blue ),
m_alpha( alpha )
{
// check if the given values are correct in range
// TODO(lmath): reenable asserts to WAsserts as soon as LIC module doesn't procude invalid colors
// assert( m_green <= 1.0 && m_green >= 0.0 && "WColor comopnent out of range" );
// assert( m_blue <= 1.0 && m_blue >= 0.0 && "WColor comopnent out of range" );
// assert( m_red <= 1.0 && m_red >= 0.0 && "WColor comopnent out of range" );
// assert( m_alpha <= 1.0 && m_alpha >= 0.0 && "WColor comopnent out of range" );
}
void WColor::setGreen( float green )
{
// TODO(lmath): reenable asserts to WAsserts as soon as LIC module doesn't procude invalid colors
// assert( green <= 1.0 && green >= 0.0 );
m_green = green;
}
void WColor::setBlue( float blue )
{
// TODO(lmath): reenable asserts to WAsserts as soon as LIC module doesn't procude invalid colors
// assert( blue <= 1.0 && blue >= 0.0 );
m_blue = blue;
}
void WColor::setRed( float red )
{
// TODO(lmath): reenable asserts to WAsserts as soon as LIC module doesn't procude invalid colors
// assert( red <= 1.0 && red >= 0.0 );
m_red = red;
}
void WColor::setAlpha( float alpha )
{
// TODO(lmath): reenable asserts to WAsserts as soon as LIC module doesn't procude invalid colors
// assert( alpha <= 1.0 && alpha >= 0.0 );
m_alpha = alpha;
}
float WColor::getRed() const
{
return m_red;
}
float WColor::getGreen() const
{
return m_green;
}
float WColor::getBlue() const
{
return m_blue;
}
float WColor::getAlpha() const
{
return m_alpha;
}
void WColor::setRGB( double r, double g, double b )
{
setRed( r );
setGreen( g );
setBlue( b );
}
// This function is taken from VTK 5.4.2. Since its BSD licensed the license
// notice follows below. It is not taken from FAnToM since it seems more self
// documenting.
......@@ -129,7 +60,7 @@ void WColor::setRGB( double r, double g, double b )
// Contact: pppebay@sandia.gov,dcthomp@sandia.gov,
//
// =========================================================================*/
void WColor::setHSV( double h, double s, double v )
WColor convertHSVtoRGBA( double h, double s, double v )
{
const double onethird = 1.0 / 3.0;
const double onesixth = 1.0 / 6.0;
......@@ -182,63 +113,34 @@ void WColor::setHSV( double h, double s, double v )
g = ( s * g + ( 1.0 - s ) ) * v;
b = ( s * b + ( 1.0 - s ) ) * v;
setRGB( r, g, b );
return WColor( r, g, b, 1.0f );
}
std::ostream& operator<<( std::ostream& out, const WColor& c )
{
float r = c.getRed();
float g = c.getGreen();
float b = c.getBlue();
float a = c.getAlpha();
out << r << ";" << g << ";" << b << ";" << a;
return out;
return out << c[0] << ";" << c[1] << ";" << c[2] << ";" << c[3];
}
std::istream& operator>>( std::istream& in, WColor& c )
{
std::string str;
in >> str;
std::vector<std::string> tokens;
std::vector< std::string > tokens;
tokens = string_utils::tokenize( str, ";" );
assert( tokens.size() == 4 && "There weren't 4 color values for a WColor" );
if( tokens.size() != 4 )
{
throw WOutOfBounds( "Expected 4 color values for a WColor but got " + boost::lexical_cast< std::string >( tokens.size() ) );
}
c.setRed( boost::lexical_cast< float >( tokens[0] ) );
c.setGreen( boost::lexical_cast< float >( tokens[1] ) );
c.setBlue( boost::lexical_cast< float >( tokens[2] ) );
c.setAlpha( boost::lexical_cast< float >( tokens[3] ) );
c[0] = boost::lexical_cast< float >( tokens[0] );
c[1] = boost::lexical_cast< float >( tokens[1] );
c[2] = boost::lexical_cast< float >( tokens[2] );
c[3] = boost::lexical_cast< float >( tokens[3] );
return in;
}
bool WColor::operator==( const WColor &rhs ) const
{
return m_red == rhs.m_red &&
m_green == rhs.m_green &&
m_blue == rhs.m_blue &&
m_alpha == rhs.m_alpha;
}
bool WColor::operator!=( const WColor &rhs ) const
WColor inverseColor( const WColor& other )
{
return !( *this == rhs );
return WColor( std::abs( 1.0f - other[0] ), std::abs( 1.0f - other[1] ), std::abs( 1.0f - other[2] ), other[3] );
}
void WColor::inverse()
{
m_red = std::abs( 1. - m_red );
m_green = std::abs( 1. - m_green );
m_blue = std::abs( 1. - m_blue );
}
void WColor::average( const WColor& other )
{
m_red = ( m_red + other.getRed() ) / 2.0;
m_green = ( m_green + other.getGreen() ) / 2.0;
m_blue = ( m_blue + other.getBlue() ) / 2.0;
}
const WColor WColor::green( 0.0, 1.0, 0.0, 1.0 );
const WColor WColor::red( 1.0, 0.0, 0.0, 1.0 );
const WColor WColor::blue( 0.0, 0.0, 1.0, 1.0 );
......@@ -25,204 +25,46 @@
#ifndef WCOLOR_H
#define WCOLOR_H
#include <cassert>
#include <istream>
#include <ostream>
#include <string>
#include <vector>
#include <iostream>
#include <osg/Vec4>
#include "math/WVector3D.h"
#include "WExportCommon.h"
#include <osg/io_utils> // for the operator<< and operator>> for Vec4
/**
* Represents a RGBA Color
* Represents a RGBA Color.
*/
class OWCOMMON_EXPORT WColor
{
public:
/**
* Standard way of constructing colors, alpha is optional, and black is default
* \param red red value between [0,1]
* \param green green value between [0,1]
* \param blue blue value between [0,1]
* \param alpha opacity value between [0,1]
*/
WColor( float red = 0.0, float green = 0.0, float blue = 0.0, float alpha = 1.0 );
/**
* Casts a color to a vector comfortably.
*
* \return vector instance
*/
inline operator osg::Vec4f() const;
/**
* Casts a color to a vector comfortably. As the returned vector is three-dimensional, the alpha value is omitted.
*
* \return vector instance
*/
inline operator wmath::WVector3D() const;
/**
* Sets the green channel for this color
* \param green green value between [0,1]
*/
void setGreen( float green );
/**
* Sets the blue channel for this color
* \param blue blue value between [0,1]
*/
void setBlue( float blue );
/**
* Sets the red channel for this color
* \param red red value between [0,1]
*/
void setRed( float red );
/**
* Sets the alpha channel for this color
* \param alpha opacity value between [0,1]
*/
void setAlpha( float alpha );
/**
* \return red channel for this color
*/
float getRed() const;
/**
* \return green channel for this color
*/
float getGreen() const;
/**
* \return blue channel for this color
*/
float getBlue() const;
/**
* \return alpha channel for this color
*/
float getAlpha() const;
/**
* Reset this color via a given HSV color.
* \param h hue
* \param s saturation
* \param v value
*/
void setHSV( double h, double s, double v );
/**
* Reset all channels at once.
* \param r red value between [0,1]
* \param g green value between [0,1]
* \param b blue value between [0,1]
*/
void setRGB( double r, double g, double b );
/**
* Computes the inverse of this color in means of RGB space.
*/
void inverse();
/**
* Computes the arithmetic mean of this and the other color. This is done component wisely.
* For example red mixed with green will become yellow.
*
* \param other The other color to mix in here :D.
*/
void average( const WColor& other );
/**
* Compares two WColor instances on all four channels.
*
* \param rhs The other WColor instance
* \return True if they share the same values in all four channles:
* red, green, blue and alpha
*/
bool operator==( const WColor &rhs ) const;
/**
* Opposite of the operator==.
*
* \param rhs The other WColor instance
* \return True if they don't share the same values in all four channles:
* red, green, blue and alpha
*/
bool operator!=( const WColor &rhs ) const;
/**
* Divides each color and also the alpha channel by the given divisor.
*
* \param divisor The divisor used for division
*
* \return A divided copy of this.
*/
WColor operator/( double divisor ) const;
/**
* Accumulates this with another color channelwisely.
*
* \param other The other color to add to this.
*
* \return A reference to the modified this.
*/
WColor& operator+=( const WColor& other );
static const WColor green; //!< Default for green
static const WColor red; //!< Default for red
static const WColor blue; //!< Default for blue
protected:
private:
float m_red; //!< Red channel
float m_green; //!< Green channel
float m_blue; //!< Blue channel
float m_alpha; //!< Alpha channel
};
typedef osg::Vec4 WColor;
/**
* Write a color in string representation to the given output stream.
* Creates a color from a hue, saturation and value (HSV).
*
* \ingroup Color utils
*
* \param h hue
* \param s saturation
* \param v value
*
* \return The same color but in rgba format.
*/
std::ostream& operator<<( std::ostream& out, const WColor& c );
WColor convertHSVtoRGBA( double h, double s, double v );
/**
* Read a color in string representation from the given input stream.
* Computes the inverse of this color in means of RGB space. The alpha value is untouched.
*
* \ingroup Color utils
*
* \param other The color (RGBA) from which the inverse should be calculated.
*/
std::istream& operator>>( std::istream& in, WColor& c );
inline WColor::operator osg::Vec4f() const
{
return osg::Vec4f( static_cast< float >( m_red ),
static_cast< float >( m_green ),
static_cast< float >( m_blue ),
static_cast< float >( m_alpha ) );
}
inline WColor::operator wmath::WVector3D() const
{
return wmath::WVector3D( static_cast< float >( m_red ),
static_cast< float >( m_green ),
static_cast< float >( m_blue ) );
}
WColor inverseColor( const WColor& other );
inline WColor WColor::operator/( double divisor ) const
/**
* Some default colors.
*/
namespace defaultColor
{
return WColor( m_red / divisor, m_green / divisor, m_blue / divisor, m_alpha / divisor );
static const WColor GREEN( 0.0, 1.0, 0.0, 1.0 ); //!< Default for green
static const WColor RED( 1.0, 0.0, 0.0, 1.0 ); //!< Default for red
static const WColor BLUE( 0.0, 0.0, 1.0, 1.0 ); //!< Default for blue
}
inline WColor& WColor::operator+=( const WColor& other )
{
m_red += other.m_red;
m_green += other.m_green;
m_blue += other.m_blue;
m_alpha += other.m_alpha;
return *this;
}
#endif // WCOLOR_H
......@@ -53,7 +53,7 @@ public:
{
std::stringstream tmp;
tmp.precision( 16 );
tmp << "RGBA WColor( " << c.getRed() << " " << c.getGreen() << " " << c.getBlue() << " " << c.getAlpha() << " )";
tmp << "RGBA WColor( " << c[0] << " " << c[1] << " " << c[2] << " " << c[3] << " )";
m_s = tmp.str();
}
};
......
......@@ -34,77 +34,35 @@
#include "WColorTraits.h"
/**
* Unit tests the WColor class
* Unit tests the color helping functions
*/
class WColorTest : public CxxTest::TestSuite
{
public:
/**
* To write a WColor object to an output stream we must ensure that every
* component (red, green, blue and alpha) are written to that stream and
* that we have a special delimiter char.
*/
void testOutputOperator( void )
{
std::stringstream ss;
WColor c;
c.setBlue( 0.4711 );
ss << c;
std::string expected = "0;0;0.4711;1";
TS_ASSERT_EQUALS( ss.str(), expected );
}
/**
* When given a string separated by semicolons then it should be handled
* as red green blue and alpha values. There has to be 4 such values.
*/
void testInputOperator( void )
{
WColor c( 1.0, 0.5, 0.25 );
std::stringstream ss( "1.0;0.5;0.25;0.0" );
ss >> c;
TS_ASSERT_EQUALS( c.getRed(), 1.0 );
TS_ASSERT_EQUALS( c.getGreen(), 0.5 );
TS_ASSERT_EQUALS( c.getBlue(), 0.25 );
TS_ASSERT_EQUALS( c.getAlpha(), 0.0 );
}
/**
* Red in HSV is ( 0, 1, 1 ) and in RGB ( 1, 0, 0 )
* Green in HSV is ( 0.3, 1, 1 ) and in RGB ( 0, 1, 0 )
* and checks some dark green
*/
void testResetHSV( void )
{
WColor c;
c.setHSV( 0, 1, 1 );
TS_ASSERT_DELTA( c.getRed(), 1, 0.00001 );
TS_ASSERT_DELTA( c.getGreen(), 0, 0.00001 );
TS_ASSERT_DELTA( c.getBlue(), 0, 0.00001 );
c.setHSV( 1, 1, 1 ); // this is also red
TS_ASSERT_DELTA( c.getRed(), 1, 0.00001 );
TS_ASSERT_DELTA( c.getGreen(), 0, 0.00001 );
TS_ASSERT_DELTA( c.getBlue(), 0, 0.00001 );
c.setHSV( 1.0 / 3.0, 1, 1 );
TS_ASSERT_DELTA( c.getRed(), 0, 0.00001 );
TS_ASSERT_DELTA( c.getGreen(), 1, 0.00001 );
TS_ASSERT_DELTA( c.getBlue(), 0, 0.00001 );
c.setHSV( 0.3, 0.3, 0.3 ); // dark green
TS_ASSERT_DELTA( c.getRed(), 0.2280, 0.0001 );
TS_ASSERT_DELTA( c.getGreen(), 0.3, 0.0001 );
TS_ASSERT_DELTA( c.getBlue(), 0.2099, 0.0001 );
}
/**
* Two colors are equal if they share the same value in all four channels.
*/
void testEquality( void )
void testHSVConversion( void )
{
WColor foo( 0.1, 0.2, 0.3, 0.4 );
WColor bar( 0.10001, 0.2, 0.3, 0.4 );
TS_ASSERT_DIFFERS( foo, bar );
WColor pansen( 0.1, 0.2, 0.3, 0.4 );
TS_ASSERT_EQUALS( foo, pansen );
WColor c = convertHSVtoRGBA( 0, 1, 1 );
TS_ASSERT_DELTA( c[0], 1, 0.00001 );
TS_ASSERT_DELTA( c[1], 0, 0.00001 );
TS_ASSERT_DELTA( c[2], 0, 0.00001 );
c = convertHSVtoRGBA( 1, 1, 1 ); // this is also red
TS_ASSERT_DELTA( c[0], 1, 0.00001 );
TS_ASSERT_DELTA( c[1], 0, 0.00001 );
TS_ASSERT_DELTA( c[2], 0, 0.00001 );
c = convertHSVtoRGBA( 1.0 / 3.0, 1, 1 );
TS_ASSERT_DELTA( c[0], 0, 0.00001 );
TS_ASSERT_DELTA( c[1], 1, 0.00001 );
TS_ASSERT_DELTA( c[2], 0, 0.00001 );
c = convertHSVtoRGBA( 0.3, 0.3, 0.3 ); // dark green
TS_ASSERT_DELTA( c[0], 0.2280, 0.0001 );
TS_ASSERT_DELTA( c[1], 0.3, 0.0001 );
TS_ASSERT_DELTA( c[2], 0.2099, 0.0001 );
}
};
......
......@@ -74,7 +74,7 @@ osg::ref_ptr< osg::Geode > wge::generateBoundingBoxGeode( const WBoundingBox& bb
geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, vertices->size() - 6, 6 ) );
geometry->setVertexArray( vertices );
colors->push_back( wge::osgColor( color ) );
colors->push_back( color );
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
osg::ref_ptr< osg::Geode > geode = osg::ref_ptr< osg::Geode >( new osg::Geode );
......@@ -149,7 +149,7 @@ osg::ref_ptr< osg::Geometry > wge::createUnitCube( const WColor& color )
cube->setNormalBinding( osg::Geometry::BIND_PER_PRIMITIVE );
// finally, the colors
colors->push_back( wge::osgColor( color ) );
colors->push_back( color );
cube->setColorArray( colors );
cube->setColorBinding( osg::Geometry::BIND_OVERALL );
......@@ -170,7 +170,7 @@ osg::ref_ptr< osg::Node > wge::generateSolidBoundingBoxNode( const WBoundingBox&
else
{
osg::ref_ptr< osg::ShapeDrawable > cubeDrawable = new osg::ShapeDrawable( new osg::Box( osg::Vec3( 0.5, 0.5, 0.5 ), 1.0 ) );
cubeDrawable->setColor( wge::osgColor( color ) );
cubeDrawable->setColor( color );
cube->addDrawable( cubeDrawable );
}
......@@ -228,7 +228,7 @@ osg::ref_ptr< osg::Geode > wge::generateLineStripGeode( const wmath::WLine& line
for( size_t i = 1; i < line.size(); ++i )
{
vertices->push_back( osg::Vec3( line[i-1][0], line[i-1][1], line[i-1][2] ) );
colors->push_back( wge::osgColor( wge::getRGBAColorFromDirection( line[i-1], line[i] ) ) );
colors->push_back( wge::getRGBAColorFromDirection( line[i-1], line[i] ) );
}
vertices->push_back( osg::Vec3( line.back()[0], line.back()[1], line.back()[2] ) );
colors->push_back( colors->back() );
......@@ -239,7 +239,7 @@ osg::ref_ptr< osg::Geode > wge::generateLineStripGeode( const wmath::WLine& line
if( color != WColor( 0, 0, 0, 0 ) )
{
colors->clear();
colors->push_back( wge::osgColor( color ) );
colors->push_back( color );
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
}
......@@ -304,7 +304,7 @@ osg::ref_ptr< osg::Geode > wge::genFinitePlane( double xSize, double ySize, cons
ref_ptr< osg::Vec4Array > colors = ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
ref_ptr< osg::Geometry > geometry = ref_ptr< osg::Geometry >( new osg::Geometry );
colors->push_back( wge::osgColor( color ) );
colors->push_back( color );
vertices->push_back( p.getPointInPlane( xSize, ySize ) );
vertices->push_back( p.getPointInPlane( -xSize, ySize ) );
......@@ -330,9 +330,7 @@ osg::ref_ptr< osg::Geode > wge::genFinitePlane( double xSize, double ySize, cons
borderGeom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, 4 ) );
borderGeom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 3, 2 ) );
ref_ptr< osg::Vec4Array > colors = ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
WColor borderColor = color;
borderColor.inverse();
colors->push_back( wge::osgColor( borderColor ) );
colors->push_back( inverseColor( color ) );
borderGeom->setColorArray( colors );
borderGeom->setColorBinding( osg::Geometry::BIND_OVERALL );
borderGeom->setVertexArray( vertices );
......
......@@ -134,7 +134,7 @@ namespace wge
osg::ref_ptr< osg::Geode > WGE_EXPORT genFinitePlane( double xSize,
double ySize,
const WPlane& p,
const WColor& color = WColor( 0, 0.7, 0.7 ),
const WColor& color = WColor( 0.0, 0.7, 0.7, 1.0 ),
bool border = false );
/**
......@@ -171,7 +171,7 @@ namespace wge
*/
template< class Container > osg::ref_ptr< osg::Geode > genPointBlobs( boost::shared_ptr< Container > points,
double size,
const WColor& color = WColor( 1, 0, 0 ) );
const WColor& color = WColor( 1.0, 0.0, 0.0, 1.0 ) );
} // end of namespace wge
template< class Container > inline osg::ref_ptr< osg::Geode > wge::genPointBlobs( boost::shared_ptr< Container > points,
......@@ -206,7 +206,7 @@ template< class Container > inline osg::ref_ptr< osg::Geode > wge::genPointBlobs
}
geometry->setVertexArray( vertices );
colors->push_back( wge::osgColor( color ) );
colors->push_back( color );
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
geometry->setNormalArray( normals );
......
......@@ -60,7 +60,7 @@ WColor wge::createColorFromIndex( int index )
if ( index == 0 )
{
return WColor( 0.0, 0.0, 0.0 );
return WColor( 0.0, 0.0, 0.0, 1.0 );
}
if ( ( index & 1 ) == 1 )
......@@ -122,7 +122,7 @@ WColor wge::createColorFromIndex( int index )
g *= mult;
b *= mult;
return WColor( r, g, b );
return WColor( r, g, b, 1.0 );
}