Skip to content
Snippets Groups Projects
Commit 293f1a4a authored by Ansgar Philippsen's avatar Ansgar Philippsen
Browse files

added hsv mode to gradient

parent 1df42e84
Branches
Tags
No related merge requests found
......@@ -16,6 +16,11 @@
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//------------------------------------------------------------------------------
/*
Authors: Marco Biasini, Ansgar Philippsen
*/
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;
......@@ -76,15 +81,27 @@ namespace {
throw std::runtime_error("expected values of gfx.Color or float triplets");
}
try {
col=gfx::Color(extract<float>(val[0]),extract<float>(val[1]),extract<float>(val[2]));
col=gfx::RGB(extract<float>(val[0]),extract<float>(val[1]),extract<float>(val[2]));
} catch (...) {
throw std::runtime_error("expected values of gfx.Color or float triplets");
throw std::runtime_error("expected values of gfx.Color float triplets");
}
}
grad->SetColorAt(mark,col);
}
return grad.release();
}
std::string sl_repr(const Gradient::StopList& sl) {
std::ostringstream m;
m << "[";
for(size_t i=0;i<sl.size();++i) {
Color c = sl[i].color;
m << "(" << sl[i].t << "," << "gfx.RGB(" << c[0] << "," << c[1] << "," << c[2] << "))";
if(i<sl.size()-1) m << ",";
}
m << "]";
return m.str();
}
}
void export_gradient()
......@@ -96,13 +113,16 @@ void export_gradient()
.def("SetColorAt", &Gradient::SetColorAt)
.def("GetColorAt", &Gradient::GetColorAt)
.def("GetStops", &Gradient::GetStops)
.add_property("stops", &Gradient::GetStops)
.def("GradientToInfo", &Gradient::GradientToInfo)
.def("GradientFromInfo", &Gradient::GradientFromInfo).staticmethod("GradientFromInfo")
.add_property("hsv_mode",&Gradient::GetHSVMode,&Gradient::SetHSVMode)
;
implicitly_convertible<String, Gradient>();
class_<Gradient::StopList>("GradientStopList", init<>())
.def(vector_indexing_suite<Gradient::StopList>())
.def("__repr__",sl_repr)
;
class_<Gradient::Stop>("GradientStop", init<>())
......
......@@ -62,7 +62,7 @@ namespace {
if(!PyArray_TYPE(na)==NPY_FLOAT) {
throw std::runtime_error("expected normal array to be of dtype=float32");
}
if(PyArray_SIZE(na)!=v_size) {
if((size_t)PyArray_SIZE(na)!=v_size) {
throw std::runtime_error("expected normal array size to match vertex array size");
}
np=reinterpret_cast<float*>(PyArray_DATA(na));
......@@ -78,7 +78,7 @@ namespace {
if(!PyArray_TYPE(ca)==NPY_FLOAT) {
throw std::runtime_error("expected color array to be of dtype=float32");
}
if(PyArray_SIZE(ca)!=v_count*4) {
if((size_t)PyArray_SIZE(ca)!=v_count*4) {
throw std::runtime_error("expected color array size to equal vertex-count x 4");
}
cp=reinterpret_cast<float*>(PyArray_DATA(ca));
......
......@@ -17,6 +17,11 @@
0.0615451 0.0313726 0.286275 0.501961 1
0.502146 1 1 1 1
0.978541 0.890105 0.075639 0.0546578 1
</Gradient>
<Gradient hsv_color="1" hsv_mode="1" Name="HEAT_MAP_HSV" >3
0.0615451 0.576389 0.9375 0.501961 1
0.502146 0 0 1 1
0.978541 0.00418562 0.938594 0.890105 1
</Gradient>
<Gradient Name="AUTUMN" >3
0.0615451 1 0.972015 0.0132753 1
......@@ -61,6 +66,10 @@
0.748835 0 1 1 1
0.857779 0 0.623529 1 1
0.97541 0 0.133333 1 1
</Gradient>
<Gradient hsv_color="1" hsv_mode="1" Name="RED_TO_BLUE_HSV">2
0.0 1 1 1 1
1.0 0.66666667 1 1 1
</Gradient>
</Gradients>
</EMDataInfo>
......@@ -19,6 +19,9 @@
#include "gradient.hh"
#include <iostream>
#include <vector>
#include <algorithm>
#include <ost/log.hh>
#include <ost/info/info.hh>
#include <ost/info/info_fw.hh>
......@@ -28,13 +31,18 @@
namespace ost { namespace gfx {
Gradient::Gradient()
{
}
Gradient::Gradient():
stops_(),
hsv_mode_(false)
{}
Gradient::Gradient(const String& name)
{
Gradient gradient = GradientManager::Instance().GetGradient(name);
// why doesn't this work:
// stops_=gradient.stops_
// or even better
// *this = gradient
StopList stops = gradient.GetStops();
for(unsigned int i = 0; i < stops.size(); i++){
Stop stop = stops[i];
......@@ -55,8 +63,11 @@ void Gradient::SetColorAt(float t, const Color& c)
Color Gradient::GetColorAt(float t) const
{
if (stops_.empty())
throw Error("Can not calculate color with 0 Stops set!");
if (stops_.empty()) {
return Color();
} else if(stops_.size()==1) {
return stops_[0].color;
}
uint c=0;
while (t>=stops_[c].t && c<stops_.size()) {
......@@ -64,16 +75,17 @@ Color Gradient::GetColorAt(float t) const
}
if (c==0) {
return stops_.front().color;
}
if (c==stops_.size()) {
} else if (c==stops_.size()) {
return stops_.back().color;
}
float d=stops_[c].t-stops_[c-1].t;
float tt=0.0;
if (d>0.0001) {
tt=(t-stops_[c-1].t)/d;
}
return stops_[c-1].color*(1.0-tt)+stops_[c].color*tt;
float d = stops_[c].t-stops_[c-1].t;
float tt = d>0.001 ? (t-stops_[c-1].t)/d : 0.0;
if(hsv_mode_) {
geom::Vec4 v=stops_[c-1].color.GetHSVA()*(1.0-tt)+stops_[c].color.GetHSVA()*tt;
return HSVA(v[0],v[1],v[2],v[3]);
} else {
return stops_[c-1].color*(1.0-tt)+stops_[c].color*tt;
}
}
void Gradient::GradientToInfo(info::InfoGroup& group) const
......@@ -86,6 +98,7 @@ void Gradient::GradientToInfo(info::InfoGroup& group) const
ss << stops_[i].t << "\t" << stops_[i].color.Red() << "\t" << stops_[i].color.Green() << "\t" << stops_[i].color.Blue() << "\t" << stops_[i].color.Alpha() << "\n";
}
group.SetTextData(ss.str());
group.SetAttribute("hsv_mode",hsv_mode_? "1" : "0");
}
Gradient::StopList Gradient::GetStops() const{
......@@ -95,6 +108,16 @@ Gradient::StopList Gradient::GetStops() const{
Gradient Gradient::GradientFromInfo(const info::InfoGroup& group)
{
std::istringstream ss(group.GetTextData());
bool hsv_color=false;
if(group.HasAttribute("hsv_color")) {
String hsv_color_s = group.GetAttribute("hsv_color");
std::transform(hsv_color_s.begin(), hsv_color_s.end(), hsv_color_s.begin(), ::tolower);
if(hsv_color_s=="0" || hsv_color_s=="false" || hsv_color_s=="no" || hsv_color_s=="off") {
hsv_color=false;
} else {
hsv_color=true;
}
}
Gradient grad;
StopList::size_type size = 0;
......@@ -102,10 +125,19 @@ Gradient Gradient::GradientFromInfo(const info::InfoGroup& group)
float t, r, g, b, a;
for( StopList::size_type i = 0; i < size; i++ ) {
ss >> t >> r >> g >> b >> a;
Color c = Color(r,g,b,a);
Color c = hsv_color ? HSVA(r,g,b,a) : RGBA(r,g,b,a);
grad.SetColorAt(t, c);
}
if(group.HasAttribute("hsv_mode")) {
String hsv_mode_s = group.GetAttribute("hsv_mode");
std::transform(hsv_mode_s.begin(), hsv_mode_s.end(), hsv_mode_s.begin(), ::tolower);
if(hsv_mode_s=="0" || hsv_mode_s=="false" || hsv_mode_s=="no" || hsv_mode_s=="off") {
grad.SetHSVMode(false);
} else {
grad.SetHSVMode(true);
}
}
return grad;
}
......
......@@ -20,8 +20,8 @@
#define OST_GFX_GRADIENT_HH
/*
Author: Marco Biasini
*/
Authors: Marco Biasini, Ansgar Philippsen
*/
#include <vector>
......@@ -30,16 +30,32 @@
#include <ost/info/info.hh>
#include <ost/info/info_fw.hh>
namespace ost { namespace gfx {
/// \brief color gradient
///
/// Gradients map a scalar value in the range of 0 to 1 to a color. The
/// gradient consists of zero or more color stops. These stop points define the
/// output of GetColorAt(). New stops can be added with SetColorAt().
///
/// \sa \ref gradient.py "Gradient Example"
/*!
\brief color gradient
Gradients map a scalar value in the range of 0 to 1 to a color. The
gradient consists of zero or more color stops. These stop points define the
output of GetColorAt(). New stops can be added with SetColorAt().
Usually, the gradient operates in RGB colorspace, which means a linear
interpolation of each color component between stops. As an alternative,
interpolation can also be done in HSV colorspace, by setting HSV mode
to true with SetHSVMode(). However, carefully using HSV colorspace will
yield better results, if some potential caveats are taken into consideration.
The best example is a simple gradient from red to blue. The half-point in RGB
colorspace is (0.5,0.0,0.5), so a darkish purple. Converting to HSV one can see
that the saturation is at 50%, which is unfortunate. Using hsv mode can circument
this issue, but in the above example, naively using hsv mode will give green
at the half-point and not purple. Why? Because red translates to HSV(0,1,1) and blue to
HSV(2/3,1,1), which at the half-point is HSV(1/3,1,1), or green. To interpolate
on the hue in the other direction, use HSV and unwrapped hue values, e.g.
[HSV(0.0,1,1),HSV(-1/3,1,1)] or [HSV(1,1,1),HSV(2/3,1,1)] - both of these will
give a half-point or a nice purple with full saturation
\sa \ref gradient.py "Gradient Example"
*/
class DLLEXPORT_OST_GFX Gradient {
public:
struct Stop {
......@@ -49,14 +65,14 @@ public:
float t;
Color color;
Color GetColor(){
Color GetColor() const {
return color;
}
float GetRel(){
float GetRel() const {
return t;
}
bool operator==(const Stop& ref) const
{
return t==ref.t && color==ref.color;
......@@ -85,16 +101,26 @@ public:
void SetColorAt(float t, const Color& color);
/// \brief convert gradient to info
// TODO: rename to ToInfo
// TODO:: add stand-alone function named GradientToInfo(Gradient, InfoGroup)
void GradientToInfo(info::InfoGroup& group) const;
/// \brief get list of color stops
StopList GetStops() const;
/// \brief create gradient from info
// TODO: move outside
// TODO: add FromInfo member function that overwrites this
static gfx::Gradient GradientFromInfo(const info::InfoGroup& group);
/// \brief turn HSV interpolation mode on or off
void SetHSVMode(bool m) {hsv_mode_=m;}
/// \brief return the HSV interpolation mode flag
bool GetHSVMode() const {return hsv_mode_;}
private:
std::vector<Stop> stops_;
bool hsv_mode_;
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment