Cleaning of names and reordering of Color functions

This commit is contained in:
Paolo Cignoni 2012-10-19 11:52:57 +00:00
parent d81d14189c
commit 1918c53a09
2 changed files with 473 additions and 616 deletions

View File

@ -23,353 +23,332 @@
#ifndef __VCG_TRI_UPDATE_COLOR
#define __VCG_TRI_UPDATE_COLOR
#include <limits>
#include <math.h>
#include <time.h>
#include <vcg/space/color4.h>
#include <vcg/math/histogram.h>
#include <vcg/complex/algorithms/stat.h>
#include <vcg/math/perlin_noise.h>
#include <vcg/math/random_generator.h>
#include <vcg/complex/algorithms/clean.h>
#include <vcg/complex/algorithms/stat.h>
namespace vcg {
namespace tri {
/// \ingroup trimesh
/*!
\ingroup trimesh
/// \headerfile color.h vcg/complex/algorithms/update/color.h
\headerfile color.h vcg/complex/algorithms/update/color.h
/// \brief Generation of per-vertex and per-face colors according to various strategy.
/**
This class is used to compute per face or per vertex color with respect to for example Border (UpdateColor::VertexBorderFlag), Selection (UpdateColor::FaceSelected), Quality .
\brief Generation and processing of per-vertex and per-face colors according to various strategy.
This class is used to compute per face or per vertex color with respect to a number of algorithms.
There is a wide range of algorithms for processing vertex color in a \i photoshop-like mode (changing for example contrast, white balance, gamma)
Basic Tools for mapping quality into a color according to standard color ramps are here.
*/
template <class UpdateMeshType>
template <class MeshType>
class UpdateColor
{
public:
typedef UpdateMeshType MeshType;
typedef typename UpdateMeshType::VertexType VertexType;
typedef typename UpdateMeshType::VertexPointer VertexPointer;
typedef typename UpdateMeshType::VertexIterator VertexIterator;
typedef typename UpdateMeshType::FaceType FaceType;
typedef typename UpdateMeshType::FacePointer FacePointer;
typedef typename UpdateMeshType::FaceIterator FaceIterator;
typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::VertexPointer VertexPointer;
typedef typename MeshType::VertexIterator VertexIterator;
typedef typename MeshType::FaceType FaceType;
typedef typename MeshType::FacePointer FacePointer;
typedef typename MeshType::FaceIterator FaceIterator;
typedef typename MeshType::ScalarType ScalarType;
class ColorAvgInfo
{
public:
unsigned int r;
unsigned int g;
unsigned int b;
unsigned int a;
int cnt;
};
static void VertexFromFace( UpdateMeshType &m)
{
ColorAvgInfo csi;
csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
SimpleTempData<typename UpdateMeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
for(int j=0;j<3;++j)
{
TD[(*fi).V(j)].r+=(*fi).C()[0];
TD[(*fi).V(j)].g+=(*fi).C()[1];
TD[(*fi).V(j)].b+=(*fi).C()[2];
TD[(*fi).V(j)].a+=(*fi).C()[3];
++TD[(*fi).V(j)].cnt;
}
VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD() && TD[*vi].cnt>0 )
{
(*vi).C()[0] = TD[*vi].r / TD[*vi].cnt;
(*vi).C()[1] = TD[*vi].g / TD[*vi].cnt;
(*vi).C()[2] = TD[*vi].b / TD[*vi].cnt;
(*vi).C()[3] = TD[*vi].a / TD[*vi].cnt;
}
}
static void FaceFromVertex( UpdateMeshType &m)
{
FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
{
Color4f avg = (Color4f::Construct((*fi).V(0)->C()) +
Color4f::Construct((*fi).V(1)->C()) +
Color4f::Construct((*fi).V(2)->C()) )/ 3.0;
(*fi).C().Import(avg);
}
}
/// \brief Color the vertexes of the mesh that are on the border
/**
It uses the information in the Vertex flags, and not any topology.
So it just require that you have correctly computed the flags;
- vcg::tri::UpdateTopology<Mesh>::FaceFace(m.cm);
- vcg::tri::UpdateFlags<Mesh>::FaceBorderFromFF(m.cm);
- vcg::tri::UpdateFlags<Mesh>::VertexBorderFromFace (m.cm);
- vcg::tri::UpdateColor<Mesh>::VertexBorderFlag(m.cm);
*/
static void VertexBorderFlag( UpdateMeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
{
Color4b BaseColor = Color4b::Green;
VertexConstant(m,BaseColor);
typename UpdateMeshType::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
for(int j=0;j<3;++j)
if((*fi).IsB(j)){
if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = BorderColor;
if( (*fi).V(j)->C() == InternalColor) (*fi).V(j)->C() = MixColor;
if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = BorderColor;
if( (*fi).V1(j)->C() == InternalColor) (*fi).V1(j)->C() = MixColor;
} else
{
if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = InternalColor;
if( (*fi).V(j)->C() == BorderColor) (*fi).V(j)->C() = MixColor;
if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = InternalColor;
if( (*fi).V1(j)->C() == BorderColor) (*fi).V1(j)->C() = MixColor;
}
}
/// This function colores the face of a mesh randomly.
/// The faux bit is used to color polygonal faces uniformly
static void FaceRandomConnectedComponent( UpdateMeshType &m)
{
std::vector< std::pair<int, typename UpdateMeshType::FacePointer> > CCV;
int ScatterSize= std::min (100,tri::Clean<UpdateMeshType>::ConnectedComponents(m, CCV)); // number of random color to be used. Never use too many.
ConnectedIterator<MeshType> ci;
for(unsigned int i=0;i<CCV.size();++i)
class ColorAvgInfo
{
Color4b BaseColor = Color4b::Scatter(ScatterSize, i%ScatterSize,.4f,.7f);
std::vector<typename MeshType::FacePointer> FPV;
for(ci.start(m,CCV[i].second);!ci.completed();++ci)
(*ci)->C()=BaseColor;
public:
unsigned int r;
unsigned int g;
unsigned int b;
unsigned int a;
int cnt;
};
/*! \brief This function colores all (or the selected) the vertices of a mesh.
*/
static int PerVertexConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
{
int cnt=0;
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD()){
if(!selected || (*vi).IsS())
{
(*vi).C() = vs;
++cnt;
}
}
return cnt;
}
}
/// This function colores the face of a mesh randomly.
/// The faux bit is used to color polygonal faces uniformly
static void MultiFaceRandom( UpdateMeshType &m)
{
FaceIterator fi;
Color4b BaseColor = Color4b::Black;
FaceConstant(m,BaseColor);
int id_num=0;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
{
id_num++;
if((*fi).C() == BaseColor) (*fi).C() = Color4b::Scatter(50, id_num%50,.4f,.7f);
for(int j=0;j<3;++j)
if((*fi).IsF(j))
{
assert(!IsBorder((*fi),j));
(*fi).FFp(j)->C()= (*fi).C();
}
}
}
static void FaceBF( UpdateMeshType &m, Color4b vn=Color4b::White, Color4b vb=Color4b::Blue,
Color4b vc=Color4b::Red, Color4b vs=Color4b::LightBlue)
{
typename UpdateMeshType::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
(*fi).C() = vn;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
{
if((*fi).IsS())
(*fi).C() = vs;
else
{
for(int j=0;j<3;++j)
if(*fi.IsManifold(j)){
if((*fi).IsB(j)){
(*fi).C() = vb;
(*fi).C() = vb;
}
}
else
{
(*fi).C() = vc;
(*fi).C() = vc;
}
}
}
}
static int FaceSelected(UpdateMeshType &m, Color4b vs=Color4b::LightBlue)
{
int cnt=0;
typename UpdateMeshType::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()){
if((*fi).IsS()) { (*fi).C() = vs; ++cnt; }
else (*fi).C() = Color4b::White;
}
return cnt;
}
static int VertexSelected(UpdateMeshType &m, Color4b vs=Color4b::LightBlue)
{
int cnt=0;
typename UpdateMeshType::VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD()){
if((*vi).IsS()) {(*vi).C() = vs; ++cnt; }
else (*vi).C() = Color4b::White;
}
return cnt;
}
static void VertexConstant(UpdateMeshType &m, Color4b c=Color4b::White)
{
typename UpdateMeshType::VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
(*vi).C()=c;
}
static void FaceConstant(UpdateMeshType &m, Color4b c=Color4b::White)
{
typename UpdateMeshType::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi)
(*fi).C()=c;
}
static void VertexBorderManifoldFlag(UpdateMeshType &m, Color4b vn=Color4b::White, Color4b vb=Color4b::Blue, Color4b vc=Color4b::Red)
{
typename UpdateMeshType::VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
(*vi).C()=vn;
typename UpdateMeshType::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
for(int j=0;j<3;++j)
if((*fi).IsManifold(j)){
if((*fi).IsB(j)){
(*fi).V(j)->C()=vb;
(*fi).V1(j)->C()=vb;
}
}
else
{
(*fi).V(j)->C()=vc;
(*fi).V1(j)->C()=vc;
}
}
static void FaceQualityGray(UpdateMeshType &m, float minq, float maxq)
{
typename UpdateMeshType::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
(*fi).C().SetGrayShade( ((*fi).Q()-minq)/(maxq-minq));
}
static void FaceQualityGray(UpdateMeshType &m)
{
std::pair<float,float> minmax = Stat<UpdateMeshType>::ComputePerFaceQualityMinMax(m);
FaceQualityGray(m,minmax.first,minmax.second);
}
static void FaceQualityRamp(UpdateMeshType &m,bool selected=false)
{
// step 1: find the range
typename UpdateMeshType::FaceIterator fi;
float minq=std::numeric_limits<float>::max(),
maxq=-std::numeric_limits<float>::max();
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
if(!selected || (*fi).IsS())
{
minq=std::min(minq,(float)(*fi).Q());
maxq=std::max(maxq,(float)(*fi).Q());
}
FaceQualityRamp(m,minq,maxq,selected);
}
static void FaceQualityRamp(UpdateMeshType &m, float minq, float maxq,bool selected=false)
{
typename UpdateMeshType::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
if(!selected || (*fi).IsS())
(*fi).C().SetColorRamp(minq,maxq,(*fi).Q());
}
static void VertexQualityRamp(UpdateMeshType &m, float minq, float maxq)
{
typename UpdateMeshType::VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD())
(*vi).C().SetColorRamp(minq,maxq,(*vi).Q());
}
static void VertexQualityRamp(UpdateMeshType &m)
{
std::pair<float,float> minmax = Stat<UpdateMeshType>::ComputePerVertexQualityMinMax(m);
VertexQualityRamp(m,minmax.first,minmax.second);
}
static void VertexQualityGray(UpdateMeshType &m, const float minq, const float maxq)
{
typename UpdateMeshType::VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD())
(*vi).C().SetGrayShade( ((*vi).Q()-minq)/(maxq-minq));
}
static void VertexQualityGray(UpdateMeshType &m)
{
std::pair<float,float> minmax = Stat<UpdateMeshType>::ComputePerVertexQualityMinMax( m);
VertexQualityGray(m,minmax.first,minmax.second);
}
//Fill the mesh with the selected color.
static int Filling(UpdateMeshType &m, Color4b c, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
/*! \brief This function colores all (or the selected) faces of a mesh.
*/
static int PerFaceConstant(MeshType &m, Color4b vs=Color4b::White,bool selected=false)
{
if(!(*vi).IsD()) //if it has not been deleted...
{
if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
int cnt=0;
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()){
if(!selected || (*fi).IsS())
{
(*fi).C() = vs;
++cnt;
}
}
return cnt;
}
/** \brief Transfer face color onto vertex color
Plain average of the color of the faces incident on a given vertex.
No adjacency required.
*/
static void PerVertexFromFace( MeshType &m)
{
ColorAvgInfo csi;
csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
SimpleTempData<typename MeshType::VertContainer, ColorAvgInfo> TD(m.vert,csi);
FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
for(int j=0;j<3;++j)
{
TD[(*fi).V(j)].r+=(*fi).C()[0];
TD[(*fi).V(j)].g+=(*fi).C()[1];
TD[(*fi).V(j)].b+=(*fi).C()[2];
TD[(*fi).V(j)].a+=(*fi).C()[3];
++TD[(*fi).V(j)].cnt;
}
VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD() && TD[*vi].cnt>0 )
{
(*vi).C() = c;
++counter;
(*vi).C()[0] = TD[*vi].r / TD[*vi].cnt;
(*vi).C()[1] = TD[*vi].g / TD[*vi].cnt;
(*vi).C()[2] = TD[*vi].b / TD[*vi].cnt;
(*vi).C()[3] = TD[*vi].a / TD[*vi].cnt;
}
}
/*! \brief Transfer vertex color onto face color
Plain average of the color of the vertexes on a given face.
*/
static void PerFaceFromVertex( MeshType &m)
{
FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
{
Color4f avg = (Color4f::Construct((*fi).V(0)->C()) +
Color4f::Construct((*fi).V(1)->C()) +
Color4f::Construct((*fi).V(2)->C()) )/ 3.0;
(*fi).C().Import(avg);
}
}
/*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality.
If no range of quality is passed it is automatically computed.
*/
static void PerVertexQualityRamp(MeshType &m, float minq=0, float maxq=0)
{
if(!HasPerVertexQuality(m)) throw MissingComponentException("PerVertexQuality");
if(minq==maxq)
{
std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
minq=minmax.first;
maxq=minmax.second;
}
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD())
(*vi).C().SetColorRamp(minq,maxq,(*vi).Q());
}
/*! \brief This function colores all the faces of a mesh with a hue color shade dependent on the quality.
If no range of quality is passed it is automatically computed.
*/
static void PerFaceQualityRamp(MeshType &m, float minq=0, float maxq=0, bool selected=false)
{
if(!HasPerFaceQuality(m)) throw MissingComponentException("PerFaceQuality");
if(minq==maxq)
{
std::pair<float,float> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
minq=minmax.first;
maxq=minmax.second;
}
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
if(!selected || (*fi).IsS())
(*fi).C().SetColorRamp(minq,maxq,(*fi).Q());
}
/*! \brief This function colores all the vertices of a mesh with a gray shade dependent on the quality.
If no range of quality is passed it is automatically computed.
*/
static void PerVertexQualityGray(MeshType &m, float minq, float maxq)
{
if(!HasPerVertexQuality(m)) throw MissingComponentException("PerVertexQuality");
if(minq==maxq)
{
std::pair<float,float> minmax = Stat<MeshType>::ComputePerVertexQualityMinMax(m);
minq=minmax.first;
maxq=minmax.second;
}
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD())
(*vi).C().SetGrayShade( ((*vi).Q()-minq)/(maxq-minq));
}
/*! \brief This function colores all the faces of a mesh with a gray shade dependent on the quality.
If no range of quality is passed it is automatically computed.
*/
static void PerFaceQualityGray(MeshType &m, float minq=0, float maxq=0)
{
if(!HasPerFaceQuality(m)) throw MissingComponentException("PerFaceQuality");
if(minq==maxq)
{
std::pair<float,float> minmax = Stat<MeshType>::ComputePerFaceQualityMinMax(m);
minq=minmax.first;
maxq=minmax.second;
}
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
(*fi).C().SetGrayShade( ((*fi).Q()-minq)/(maxq-minq));
}
/** \brief Color the vertexes of the mesh that are on the border
It uses the information in the Vertex flags, and not necessarily any topology.
So it just require that you have correctly computed the flags; one way could be the following one:
\code
vcg::tri::UpdateTopology<Mesh>::FaceFace(m.cm);
vcg::tri::UpdateFlags<Mesh>::FaceBorderFromFF(m.cm);
vcg::tri::UpdateFlags<Mesh>::VertexBorderFromFace (m.cm);
vcg::tri::UpdateColor<Mesh>::PerVertexBorderFlag(m.cm);
\endcode
*/
static void PerVertexBorderFlag( MeshType &m, Color4b BorderColor=Color4b::Blue, Color4b InternalColor=Color4b::White, Color4b MixColor=Color4b::Cyan)
{
Color4b BaseColor = Color4b::Green;
VertexConstant(m,BaseColor);
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
for(int j=0;j<3;++j)
{
if((*fi).IsB(j)){
if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = BorderColor;
if( (*fi).V(j)->C() == InternalColor) (*fi).V(j)->C() = MixColor;
if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = BorderColor;
if( (*fi).V1(j)->C() == InternalColor) (*fi).V1(j)->C() = MixColor;
} else
{
if( (*fi).V(j)->C() == BaseColor) (*fi).V(j)->C() = InternalColor;
if( (*fi).V(j)->C() == BorderColor) (*fi).V(j)->C() = MixColor;
if( (*fi).V1(j)->C() == BaseColor) (*fi).V1(j)->C() = InternalColor;
if( (*fi).V1(j)->C() == BorderColor) (*fi).V1(j)->C() = MixColor;
}
}
}
/*! \brief This function colores the faces of connected components of a mesh randomly.
It require FaceFace Adjacency becouse it relies on the output of the ConnecteComponents();
*/
static void PerFaceRandomConnectedComponent( MeshType &m)
{
if(!HasFFAdjacency(m)) throw MissingComponentException("FFAdjacency");
std::vector< std::pair<int, typename MeshType::FacePointer> > CCV;
int ScatterSize= std::min (100,tri::Clean<MeshType>::ConnectedComponents(m, CCV)); // number of random color to be used. Never use too many.
ConnectedIterator<MeshType> ci;
for(unsigned int i=0;i<CCV.size();++i)
{
Color4b BaseColor = Color4b::Scatter(ScatterSize, i%ScatterSize,.4f,.7f);
std::vector<typename MeshType::FacePointer> FPV;
for(ci.start(m,CCV[i].second);!ci.completed();++ci)
(*ci)->C()=BaseColor;
}
}
/*! \brief This function colores the face of a mesh randomly.
Note: The faux bit is used to color polygonal faces uniformly
*/
static void PerFaceRandom(MeshType &m)
{
FaceIterator fi;
Color4b BaseColor = Color4b::Black;
PerFaceConstant(m,BaseColor);
int id_num=0;
for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
{
id_num++;
if((*fi).C() == BaseColor) (*fi).C() = Color4b::Scatter(50, id_num%50,.4f,.7f);
for(int j=0;j<3;++j)
if((*fi).IsF(j))
{
assert(!IsBorder((*fi),j));
(*fi).FFp(j)->C()= (*fi).C();
}
}
}
/*! \brief Perlin Noise.
\return the number of changed vertexes (the selected ones)
Simple Perlin noise. To make things weirder each color band can be offset.
*/
static void PerVertexPerlinNoise(MeshType& m, Box3f bbox, Matrix44<ScalarType> tr, float freq, Point3i channelOffsets=Point3i(0,0,0))
{
Point3<ScalarType> p;
for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
{
if(!(*vi).IsD()){
p = bbox.GlobalToLocal(tr * (*vi).P()); //actual vertex position scaled to bbox
(*vi).C() = Color4b( int(255*math::Perlin::Noise(channelOffsets[0]+p[0]*freq,channelOffsets[0]+p[1]*freq,channelOffsets[0]+p[2]*freq)),
int(255*math::Perlin::Noise(channelOffsets[1]+p[0]*freq,channelOffsets[1]+p[1]*freq,channelOffsets[1]+p[2]*freq)),
int(255*math::Perlin::Noise(channelOffsets[2]+p[0]*freq,channelOffsets[2]+p[1]*freq,channelOffsets[2]+p[2]*freq)),
255 );
}
}
}
return counter;
}
//Reduces the mesh to two colors according to a threshold.
static int Thresholding(UpdateMeshType &m, float threshold, Color4b c1 = Color4<unsigned char>::Black, Color4b c2 = Color4<unsigned char>::White, const bool ProcessSelected=false)
/*! \brief Simple Noise adding function.
It simply add signed noise to the color of the mesh. The noise has uniform distribution and the amplitude is +/-2^(noisebits-1).
*/
static void PerVertexAddNoise(MeshType& m, int noiseBits)
{
if(noiseBits>8) noiseBits = 8;
if(noiseBits<1) return;
math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(time(NULL));
for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
{
if(!(*vi).IsD()){
(*vi).C()[0] = math::Clamp<int>((*vi).C()[0] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
(*vi).C()[1] = math::Clamp<int>((*vi).C()[1] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
(*vi).C()[2] = math::Clamp<int>((*vi).C()[2] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
}
}
}
/*! \brief Reduces vertex color the mesh to two colors according to a threshold.
*/
static int PerVertexThresholding(MeshType &m, float threshold, Color4b c1 = Color4<unsigned char>::Black, Color4b c2 = Color4<unsigned char>::White, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
@ -390,7 +369,7 @@ static int Thresholding(UpdateMeshType &m, float threshold, Color4b c1 = Color4<
return counter;
}
//Computes the lightness value for a specified color. lightness = 0.5*(Max(R,G,B)+Min(R,G,B))
// Computes the lightness value for a specified color. lightness = 0.5*(Max(R,G,B)+Min(R,G,B))
static float ComputeLightness(Color4b c)
{
float min_rgb = (float)math::Min(c[0],c[1],c[2]);
@ -398,8 +377,9 @@ static float ComputeLightness(Color4b c)
return (max_rgb + min_rgb)/2;
}
//Apply the brightness filter, with the given amount, to the mesh.
static int Brighting(UpdateMeshType &m, float amount, const bool ProcessSelected=false)
/*! \brief Apply the brightness filter, with the given amount, to the mesh.
*/
static int PerVertexBrightness(MeshType &m, float amount, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
@ -421,8 +401,9 @@ static int Brighting(UpdateMeshType &m, float amount, const bool ProcessSelected
return counter;
}
//Apply Contrast filter to the mesh with the given contrast factor.
static int Contrast(UpdateMeshType &m, float factor, const bool ProcessSelected=false)
/*! \brief Apply Contrast filter to the mesh with the given contrast factor.
*/
static int PerVertexContrast(MeshType &m, float factor, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
@ -452,8 +433,15 @@ static int ValueMul(int value, float factor)
return math::Clamp<int>((int)((value - 128)*factor + 128), 0, 255);
}
//Apply Brightness and Contrast filter to the mesh, with the given contrast factor and brightness amount.
static int BrightnessContrast(UpdateMeshType &m, float brightness, float contrast, const bool ProcessSelected=false)
/*! \brief Apply Brightness and Contrast filter to the mesh, with the given contrast factor and brightness amount.
Performs contrast and brightness operations on color, i.e NewValue = (OldValue - 128) * contrast + 128 + amount
The result is clamped just one time after all computations; this get a more accurate result.
The formula used here is the one of GIMP.
*/
static int PerVertexBrightnessContrast(MeshType &m, float brightness, float contrast, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
@ -471,9 +459,6 @@ static int BrightnessContrast(UpdateMeshType &m, float brightness, float contras
return counter;
}
//Performs contrast and brightness operations on color, i.e NewValue = (OldValue - 128) ◊ contrast + 128 + amount
//The result is clamped just one time after all computations; this get a more accurate result.
// The formula used here is the one of GIMP.
static Color4b ColorBrightnessContrast(Color4b c, float brightness, float contrast)
{
return Color4b( ValueBrightnessContrast(c[0], brightness, contrast),
@ -490,18 +475,21 @@ static int ValueBrightnessContrast(unsigned char ivalue, float brightness, float
return math::Clamp<int>(255.0*value, 0, 255);
}
//Invert the colors of the mesh.
static int Invert(UpdateMeshType &m, const bool ProcessSelected=false)
/*! \brief Invert the colors of the mesh.
\return the number of changed vertexes (the selected ones)
*/
static int PerVertexInvert(MeshType &m, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
for(VertexIterator vi=m.vert.begin(); vi!=m.vert.end(); ++vi) //scan all the vertex...
{
if(!(*vi).IsD()) //if it has not been deleted...
{
if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected, do transormation
{
(*vi).C() = ColorInvert((*vi).C());
Color4b &c=(*vi).C();
c=Color4b( 255-c[0],255-c[1],255-c[2], 1);
++counter;
}
}
@ -509,18 +497,10 @@ static int Invert(UpdateMeshType &m, const bool ProcessSelected=false)
return counter;
}
//Invert the rgb component of the color
static Color4b ColorInvert(Color4b c)
{
return Color4b( ValueInvert(c[0]), ValueInvert(c[1]), ValueInvert(c[2]), 1);
}
static int ValueInvert(int value)
{
return 255-value;
}
//Apply the gamma correction filter, with the given gamma exponet, to the mesh.
static int Gamma(UpdateMeshType &m, float gamma, const bool ProcessSelected=false)
/*! \brief Apply the gamma correction filter, with the given gamma exponet, to the mesh.
\return the number of changed vertexes (the selected ones)
*/
static int PerVertexGamma(MeshType &m, float gamma, const bool ProcessSelected=false)
{
int counter=0;
@ -557,10 +537,15 @@ static float ValuePow(float value, float exponent)
//useful bit masks for RGB channels, used for Levels filter.
enum rgbChMask {ALL_CHANNELS = 7, RED_CHANNEL = 4, GREEN_CHANNEL = 2, BLUE_CHANNEL = 1, NO_CHANNELS = 0 };
//Adjusts color levels of the mesh. Filter can be applied to all RGB channels or to each channel separately.
//in_min, gamma and in_max are respectively the black point, the gray point and the white point.
//out_min and out_max are the output level for black and white respectively.
static int Levels(UpdateMeshType &m, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask, const bool ProcessSelected=false)
/*! \brief Adjusts color levels of the mesh
\return the number of changed vertexes (the selected ones)
Adjusts color levels of the mesh. Filter can be applied to all RGB channels or to each channel separately.
in_min, gamma and in_max are respectively the black point, the gray point and the white point.
out_min and out_max are the output level for black and white respectively.
*/
static int PerVertexLevels(MeshType &m, float gamma, float in_min, float in_max, float out_min, float out_max, unsigned char rgbMask, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
@ -602,12 +587,16 @@ static int ValueLevels(int value, float gamma, float in_min, float in_max, float
return math::Clamp<int>((int)(fvalue * 255), 0, 255);
}
//Colors the mesh. Color is blended to the mesh with the given intensity.
static int Colourisation(UpdateMeshType &m, Color4b c, float intensity, const bool ProcessSelected=false)
/*! \brief Colorize the mesh toward a given color.
\return the number of changed vertexes (the selected ones)
Colors the mesh. Color is blended to the mesh with the given intensity (0..1 ranged).
*/
static int PerVertexColourisation(MeshType &m, Color4b c, float intensity, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
{
if(!(*vi).IsD()) //if it has not been deleted...
{
@ -621,10 +610,14 @@ static int Colourisation(UpdateMeshType &m, Color4b c, float intensity, const bo
return counter;
}
//Perform colourisation operation. For each channel C: newC = origC + intensity * (newC - origC)
// Perform colourisation operation.
// For each channel C:
// newC = origC + intensity * (newC - origC)
static Color4b ColorApplyDiff(Color4b old_color, Color4b new_color, float intensity)
{
return Color4b( ValueApplyDiff(old_color[0],new_color[0],intensity), ValueApplyDiff(old_color[1],new_color[1],intensity), ValueApplyDiff(old_color[2], new_color[2],intensity), 255);
return Color4b( ValueApplyDiff(old_color[0], new_color[0], intensity),
ValueApplyDiff(old_color[1], new_color[1], intensity),
ValueApplyDiff(old_color[2], new_color[2], intensity), 255);
}
static int ValueApplyDiff(int old_value, int new_value, float intensity)
@ -635,8 +628,16 @@ static int ValueApplyDiff(int old_value, int new_value, float intensity)
//An useful ENUM to hold all desaturation methods.
enum DesaturationMethods {M_LIGHTNESS = 0, M_LUMINOSITY = 1, M_AVERAGE = 2};
//Desaturates the mesh according the selected method. Method belongs to DesaturationMethods's ENUM.
static int Desaturation(UpdateMeshType &m, int method, const bool ProcessSelected=false)
/*! \brief Desaturates the mesh according the a chosen desaturation method
\return the number of changed vertexes (the selected ones)
There are three possibilities
- \c M_LIGHTNESS where lightness = 0.5*(Max(R,G,B)+Min(R,G,B))
- \c M_LUMINOSITY where luminosity = 0.21*R+0.71*G+0.7*B
- \c M_AVERAGE Plain Average
*/
static int PerVertexDesaturation(MeshType &m, int method, const bool ProcessSelected=false)
{
int counter=0;
VertexIterator vi;
@ -686,14 +687,17 @@ static float ComputeLuminosity(Color4b c)
return float(0.2126f*c[0]+0.7152f*c[1]+0.0722f*c[2]);
}
//Equalize the histogram of colors. It can equalize any combination of rgb channels or
//it can work on lightness.
static int Equalize(UpdateMeshType &m, unsigned int rgbMask, const bool ProcessSelected=false)
/*! \brief Histogram Color Equalization.
\return the number of changed vertexes (the selected ones)
Equalize the histogram of colors. It can equalize any combination of rgb channels or it can work on lightness.
*/
static int PerVertexEqualize(MeshType &m, unsigned int rgbMask, const bool ProcessSelected=false)
{
//declares , resets and set up 4 histograms, for Red, Green, Blue and Lightness
Histogramf Hl, Hr, Hg, Hb;
Hl.Clear(); Hr.Clear(); Hg.Clear(); Hb.Clear();
Hl.SetRange(0, 255, 255); Hr.SetRange(0, 255, 255); Hg.SetRange(0, 255, 255); Hb.SetRange(0, 255, 255);
Hl.SetRange(0, 255, 255); Hr.SetRange(0, 255, 255); Hg.SetRange(0, 255, 255); Hb.SetRange(0, 255, 255);
int counter=0;
VertexIterator vi;
@ -757,35 +761,17 @@ static int ValueEqualize(int cdfValue, int cdfMin, int cdfMax)
return int(float((cdfValue - cdfMin)/float(cdfMax - cdfMin)) * 255.0f);
}
//applies the white balance filter. It may works with an auto regulation of white, or based on a user
//color that is supposed to be white.
static int WhiteBalance(UpdateMeshType &m, bool automatic, Color4b userColor, const bool ProcessSelected=false)
/*! \brief Simple white balancing filter.
\return the number of changed vertexes (the selected ones)
It applies a simple white balancing filter. It may works on a provided user color that is supposed to be white.
*/
static int PerVertexWhiteBalance(MeshType &m, Color4b userColor, const bool ProcessSelected=false)
{
Color4b unbalancedWhite;
float lightness = 0;
Color4b unbalancedWhite= userColor;
int counter=0;
VertexIterator vi;
if(!automatic) unbalancedWhite = userColor; //no auto regolation required, user has provided a color.
else //else, we need to scan the mesh and pick its lighter color...
{
for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
{
if(!(*vi).IsD()) //if it has not been deleted...
{
if(!ProcessSelected || (*vi).IsS()) //if this vertex has been selected...
{
//the lighter color is selected with an incremental approach...
float v = ComputeLightness((*vi).C());
if( v > lightness){
lightness = v; //save lightness
unbalancedWhite = (*vi).C(); //save the color
}
}
}
}
}
//in this loop the transformation is applied to the mesh
for(vi=m.vert.begin();vi!=m.vert.end();++vi) //scan all the vertex...
{
@ -816,39 +802,6 @@ static Color4b ColorWhiteBalance(Color4b c, Color4b unbalancedWhite)
255);
}
static void PerlinColor(MeshType& m, Box3f bbox, float freq, Point3i channelOffsets)
{
typedef typename MeshType::ScalarType ScalarType;
Point3<ScalarType> p;
for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
{
if(!(*vi).IsD()){
p = bbox.GlobalToLocal(m.Tr * (*vi).P()); //actual vertex position scaled to bbox
(*vi).C() = Color4b( int(255*math::Perlin::Noise(channelOffsets[0]+p[0]*freq,channelOffsets[0]+p[1]*freq,channelOffsets[0]+p[2]*freq)),
int(255*math::Perlin::Noise(channelOffsets[1]+p[0]*freq,channelOffsets[1]+p[1]*freq,channelOffsets[1]+p[2]*freq)),
int(255*math::Perlin::Noise(channelOffsets[2]+p[0]*freq,channelOffsets[2]+p[1]*freq,channelOffsets[2]+p[2]*freq)),
255 );
}
}
}
static void ColorNoise(MeshType& m, int noiseBits)
{
if(noiseBits>8) noiseBits = 8;
if(noiseBits<1) return;
math::SubtractiveRingRNG randomGen = math::SubtractiveRingRNG(time(NULL));
for(VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); ++vi)
{
if(!(*vi).IsD()){
(*vi).C()[0] = math::Clamp<int>((*vi).C()[0] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
(*vi).C()[1] = math::Clamp<int>((*vi).C()[1] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
(*vi).C()[2] = math::Clamp<int>((*vi).C()[2] + randomGen.generate(int(2*pow(2.0f,noiseBits))) - int(pow(2.0f,noiseBits)),0,255);
}
}
}
};
}// end namespace

View File

@ -19,56 +19,6 @@
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
Revision 1.15 2007/09/21 11:34:10 ponchio
Just a clarification comment
Revision 1.14 2006/06/08 08:52:02 zifnab1974
gcc 4 needs the extra template keyword
Revision 1.13 2005/06/24 12:21:48 ponchio
Fixed "lerp" function.
Revision 1.12 2005/04/14 11:35:09 ponchio
*** empty log message ***
Revision 1.11 2004/09/09 12:51:28 fasano
corrected ColorRamp code (template specialization)
Revision 1.10 2004/09/09 08:39:33 cignoni
added a 'template<>' to the specialized constructors from a enum
Revision 1.9 2004/09/03 13:58:48 fasano
Corretto errore sintattico nelle specializzazioni parziali (float e char) di due costruttori di Color4
Revision 1.8 2004/07/15 11:01:43 ganovelli
added inclusion of point3.h
Revision 1.7 2004/06/24 07:55:50 cignoni
Now color ramp can do reverse color ramp
Revision 1.6 2004/05/26 15:10:29 cignoni
Corrected bug in setgrayshade
Revision 1.5 2004/05/07 12:46:55 cignoni
added ifdef for gcc [Bug c++/14479]
Revision 1.4 2004/05/07 10:06:55 cignoni
Corrected template specialization syntax for gcc compiling
Revision 1.3 2004/03/10 21:38:40 cignoni
Written some documentation and added to the space module
Revision 1.2 2004/03/10 00:35:01 cignoni
Removed a wrong (?) copy constructor
Revision 1.1 2004/02/10 01:11:28 cignoni
Edited Comments and GPL license
****************************************************************************/
#ifndef __VCGLIB_COLOR4
@ -94,41 +44,33 @@ public:
/// Constant for storing standard colors.
/// Each color is stored in a simple in so that the bit pattern match with the one of Color4b.
enum ColorConstant {
Black =0xff000000,
Gray =0xff808080,
White =0xffffffff,
Black = 0xff000000,
Gray = 0xff808080,
White = 0xffffffff,
Red =0xff0000ff,
Green =0xff00ff00,
Blue =0xffff0000,
Red = 0xff0000ff,
Green = 0xff00ff00,
Blue = 0xffff0000,
Cyan =0xffffff00,
Yellow =0xff00ffff,
Magenta=0xffff00ff,
Cyan = 0xffffff00,
Yellow = 0xff00ffff,
Magenta = 0xffff00ff,
LightGray =0xffc0c0c0,
LightRed =0xff8080ff,
LightGreen =0xff80ff80,
LightBlue =0xffff8080,
LightGray =0xffc0c0c0,
LightRed =0xff8080ff,
LightGreen =0xff80ff80,
LightBlue =0xffff8080,
DarkGray =0xff404040,
DarkRed =0xff000040,
DarkGreen =0xff004000,
DarkBlue =0xff400000
DarkGray =0xff404040,
DarkRed =0xff000040,
DarkGreen =0xff004000,
DarkBlue =0xff400000
};
inline Color4 ( const T nx, const T ny, const T nz , const T nw ) :Point4<T>(nx,ny,nz,nw) {};
// inline Color4 ( Color4 &c) :Point4<T>(c) {};
inline Color4 ( const Point4<T> &c) :Point4<T>(c) {};
inline Color4 (){};
inline Color4 ( const T nx, const T ny, const T nz , const T nw ) :Point4<T>(nx,ny,nz,nw) {}
inline Color4 ( const Point4<T> &c) :Point4<T>(c) {}
inline Color4 (){}
inline Color4 (ColorConstant cc);
#ifdef VCG_USE_EIGEN
template<typename OtherDerived>
inline Color4 (const Eigen::MatrixBase<OtherDerived>& other) : Base(other)
{
// TODO make sure the types are the same
}
#endif
template <class Q>
inline void Import(const Color4<Q> & b )
@ -163,52 +105,82 @@ public:
}
inline void lerp(const Color4 &c0, const Color4 &c1, const float x);
inline void lerp(const Color4 &c0, const Color4 &c1, const Color4 &c2, const Point3f &ip);
/// given a float and a range set the corresponding color in the well known red->green->blue color ramp. To reverse the direction of the ramp just swap minf and maxf.
inline void SetColorRamp(const float &minf,const float &maxf ,float v );
inline void SetRGB( unsigned char r, unsigned char g, unsigned char b )
{
(*this)[0] = r;
(*this)[1] = g;
(*this)[2] = b;
(*this)[3] = 0;
}
inline void lerp(const Color4 &c0, const Color4 &c1, const float x)
{
assert(x>=0);
assert(x<=1);
void SetHSVColor( float h, float s, float v){
float r,g,b;
if(s==0.0){ // gray color
r = g = b = v;
(*this)[0]=(unsigned char)(255*r);
(*this)[1]=(unsigned char)(255*g);
(*this)[2]=(unsigned char)(255*b);
(*this)[3]=255;
return;
}
if(h==1.0) h = 0.0;
int i = int( floor(h*6.0) );
float f = float(h*6.0f - floor(h*6.0f));
float p = v*(1.0f-s);
float q = v*(1.0f-s*f);
float t = v*(1.0f-s*(1.0f-f));
switch(i){
case 0: r=v; g=t; b=p; break;
case 1: r=q; g=v; b=p; break;
case 2: r=p; g=v; b=t; break;
case 3: r=p; g=q; b=v; break;
case 4: r=t; g=p; b=v; break;
case 5: r=v; g=p; b=q; break;
default: r=0;g=0;b=0; assert(0);break;
(*this)[0]=(T)(c1.V()[0]*x + c0.V()[0]*(1.0f-x));
(*this)[1]=(T)(c1.V()[1]*x + c0.V()[1]*(1.0f-x));
(*this)[2]=(T)(c1.V()[2]*x + c0.V()[2]*(1.0f-x));
(*this)[3]=(T)(c1.V()[3]*x + c0.V()[3]*(1.0f-x));
}
(*this)[0]=(unsigned char)(255*r);
(*this)[1]=(unsigned char)(255*g);
(*this)[2]=(unsigned char)(255*b);
(*this)[3]=255;
// V()[0]=r*256;V()[1]=g*256;V()[2]=b*256;
}
inline void lerp(const Color4 &c0, const Color4 &c1, const Color4 &c2, const Point3f &ip)
{
assert(fabs(ip[0]+ip[1]+ip[2]-1)<0.00001);
(*this)[0]=(T)(c0[0]*ip[0] + c1[0]*ip[1]+ c2[0]*ip[2]);
(*this)[1]=(T)(c0[1]*ip[0] + c1[1]*ip[1]+ c2[1]*ip[2]);
(*this)[2]=(T)(c0[2]*ip[0] + c1[2]*ip[1]+ c2[2]*ip[2]);
(*this)[3]=(T)(c0[3]*ip[0] + c1[3]*ip[1]+ c2[3]*ip[2]);
}
/// given a float and a range set the corresponding color in the well known red->green->blue color ramp. To reverse the direction of the ramp just swap minf and maxf.
inline void SetColorRamp(const float &minf,const float &maxf ,float v )
{
if(minf>maxf) { SetColorRamp(maxf,minf,maxf+(minf-v)); return; }
float step=(maxf-minf)/4;
if(v < minf ) { *this=Color4<T>(Color4<T>::Red); return; }
v-=minf;
if(v<step) { lerp(Color4<T>(Color4<T>::Red), Color4<T>(Color4<T>::Yellow),v/step); return;}
v-=step;
if(v<step) { lerp(Color4<T>(Color4<T>::Yellow),Color4<T>(Color4<T>::Green), v/step); return;}
v-=step;
if(v<step) { lerp(Color4<T>(Color4<T>::Green), Color4<T>(Color4<T>::Cyan), v/step); return;}
v-=step;
if(v<step) { lerp(Color4<T>(Color4<T>::Cyan), Color4<T>(Color4<T>::Blue), v/step); return;}
*this= Color4<T>(Color4<T>::Blue);
}
void SetHSVColor( float h, float s, float v)
{
float r,g,b;
if(s==0.0){ // gray color
r = g = b = v;
(*this)[0]=(unsigned char)(255*r);
(*this)[1]=(unsigned char)(255*g);
(*this)[2]=(unsigned char)(255*b);
(*this)[3]=255;
return;
}
if(h==1.0) h = 0.0;
int i = int( floor(h*6.0) );
float f = float(h*6.0f - floor(h*6.0f));
float p = v*(1.0f-s);
float q = v*(1.0f-s*f);
float t = v*(1.0f-s*(1.0f-f));
switch(i)
{
case 0: r=v; g=t; b=p; break;
case 1: r=q; g=v; b=p; break;
case 2: r=p; g=v; b=t; break;
case 3: r=p; g=q; b=v; break;
case 4: r=t; g=p; b=v; break;
case 5: r=v; g=p; b=q; break;
default: r=0;g=0;b=0; assert(0);break;
}
(*this)[0]=(unsigned char)(255*r);
(*this)[1]=(unsigned char)(255*g);
(*this)[2]=(unsigned char)(255*b);
(*this)[3]=255;
}
inline static Color4 GrayShade(float f)
{
@ -255,55 +227,8 @@ inline static Color4 ColorRamp(const float &minf,const float &maxf ,float v )
return rc;
}
};
template <class T>
inline void Color4<T>::lerp(const Color4<T> &c0, const Color4<T> &c1, const float x)
{
assert(x>=0);
assert(x<=1);
(*this)[0]=(T)(c1.V()[0]*x + c0.V()[0]*(1.0f-x));
(*this)[1]=(T)(c1.V()[1]*x + c0.V()[1]*(1.0f-x));
(*this)[2]=(T)(c1.V()[2]*x + c0.V()[2]*(1.0f-x));
(*this)[3]=(T)(c1.V()[3]*x + c0.V()[3]*(1.0f-x));
}
template <class T>
inline void Color4<T>::lerp(const Color4<T> &c0, const Color4<T> &c1, const Color4<T> &c2, const Point3f &ip)
{
assert(fabs(ip[0]+ip[1]+ip[2]-1)<0.00001);
(*this)[0]=(T)(c0[0]*ip[0] + c1[0]*ip[1]+ c2[0]*ip[2]);
(*this)[1]=(T)(c0[1]*ip[0] + c1[1]*ip[1]+ c2[1]*ip[2]);
(*this)[2]=(T)(c0[2]*ip[0] + c1[2]*ip[1]+ c2[2]*ip[2]);
(*this)[3]=(T)(c0[3]*ip[0] + c1[3]*ip[1]+ c2[3]*ip[2]);
}
template <class T>
inline void Color4<T>::SetColorRamp(const float &minf,const float &maxf ,float v )
{
if(minf>maxf) { SetColorRamp(maxf,minf,maxf+(minf-v)); return; }
if(v < minf ) { *this=Color4<T>(Color4<T>::Red); return; }
//the case v > maxf is handled automatically at the end of the function
float step=(maxf-minf)/4;
v-=minf;
if(v<step) {lerp(Color4<T>(Color4<T>::Red), Color4<T>(Color4<T>::Yellow),v/step); return;}
v-=step;
if(v<step) {lerp(Color4<T>(Color4<T>::Yellow),Color4<T>(Color4<T>::Green),v/step);return;}
v-=step;
if(v<step) {lerp(Color4<T>(Color4<T>::Green),Color4<T>(Color4<T>::Cyan),v/step); return;}
v-=step;
if(v<step) {lerp(Color4<T>(Color4<T>::Cyan),Color4<T>(Color4<T>::Blue),v/step); return;}
*this= Color4<T>(Color4<T>::Blue);
}
#if !defined(__GNUC__) || (__GNUC__ > 3)
template <>
#endif
template <>
template <> template <>
inline void Color4<float>::Import(const Color4<unsigned char> &b)
{
(*this)[0]=b[0]/255.0f;
@ -312,10 +237,7 @@ inline void Color4<float>::Import(const Color4<unsigned char> &b)
(*this)[3]=b[3]/255.0f;
}
#if !defined(__GNUC__) || (__GNUC__ > 3)
template <> // [Bug c++/14479] enum definition in template class with template methods causes error.
#endif
template <>
template <> template <>
inline void Color4<unsigned char>::Import(const Color4<float> &b)
{
(*this)[0]=(unsigned char)(b[0]*255.0f);
@ -324,10 +246,7 @@ inline void Color4<unsigned char>::Import(const Color4<float> &b)
(*this)[3]=(unsigned char)(b[3]*255.0f);
}
#if !defined(__GNUC__) || (__GNUC__ > 3)
template <> // [Bug c++/14479] enum definition in template class with template methods causes error.
#endif
template <>
template <> template <>
inline void Color4<unsigned char>::Import(const Point4<float> &b)
{
(*this)[0]=(unsigned char)(b[0]*255.0f);
@ -336,10 +255,7 @@ inline void Color4<unsigned char>::Import(const Point4<float> &b)
(*this)[3]=(unsigned char)(b[3]*255.0f);
}
#if !defined(__GNUC__) || (__GNUC__ > 3)
template <>
#endif
template <>
template <> template <>
inline Color4<unsigned char> Color4<unsigned char>::Construct( const Color4<float> & b )
{
return Color4<unsigned char>(
@ -349,10 +265,7 @@ inline Color4<unsigned char> Color4<unsigned char>::Construct( const Color4<floa
(unsigned char)(b[3]*255.0f));
}
#if !defined(__GNUC__) || (__GNUC__ > 3)
template <>
#endif
template <>
template <> template <>
inline Color4<float> Color4<float>::Construct( const Color4<unsigned char> & b )
{
return Color4<float>(
@ -362,15 +275,6 @@ inline Color4<float> Color4<float>::Construct( const Color4<unsigned char> & b )
(float)(b[3])/255.0f);
}
//template <class T,class S>
//inline void Color4<T>::Import(const Color4<S> &b)
//{
// V()[0] = T(b[0]);
// V()[1] = T(b[1]);
// V()[2] = T(b[2]);
// V()[3] = T(b[3]);
//}
//
template<>
inline Color4<unsigned char>::Color4(Color4<unsigned char>::ColorConstant cc)
{
@ -405,8 +309,8 @@ inline Color4<unsigned char> Color4<unsigned char>::operator + ( const Color4<un
typedef Color4<unsigned char> Color4b;
typedef Color4<float> Color4f;
typedef Color4<double> Color4d;
typedef Color4<float> Color4f;
typedef Color4<double> Color4d;
/*@}*/