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
No related branches found
No related tags found
No related merge requests found
...@@ -16,6 +16,11 @@ ...@@ -16,6 +16,11 @@
// along with this library; if not, write to the Free Software Foundation, Inc., // along with this library; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
/*
Authors: Marco Biasini, Ansgar Philippsen
*/
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python; using namespace boost::python;
...@@ -76,15 +81,27 @@ namespace { ...@@ -76,15 +81,27 @@ namespace {
throw std::runtime_error("expected values of gfx.Color or float triplets"); throw std::runtime_error("expected values of gfx.Color or float triplets");
} }
try { 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 (...) { } 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); grad->SetColorAt(mark,col);
} }
return grad.release(); 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() void export_gradient()
...@@ -96,13 +113,16 @@ void export_gradient() ...@@ -96,13 +113,16 @@ void export_gradient()
.def("SetColorAt", &Gradient::SetColorAt) .def("SetColorAt", &Gradient::SetColorAt)
.def("GetColorAt", &Gradient::GetColorAt) .def("GetColorAt", &Gradient::GetColorAt)
.def("GetStops", &Gradient::GetStops) .def("GetStops", &Gradient::GetStops)
.add_property("stops", &Gradient::GetStops)
.def("GradientToInfo", &Gradient::GradientToInfo) .def("GradientToInfo", &Gradient::GradientToInfo)
.def("GradientFromInfo", &Gradient::GradientFromInfo).staticmethod("GradientFromInfo") .def("GradientFromInfo", &Gradient::GradientFromInfo).staticmethod("GradientFromInfo")
.add_property("hsv_mode",&Gradient::GetHSVMode,&Gradient::SetHSVMode)
; ;
implicitly_convertible<String, Gradient>(); implicitly_convertible<String, Gradient>();
class_<Gradient::StopList>("GradientStopList", init<>()) class_<Gradient::StopList>("GradientStopList", init<>())
.def(vector_indexing_suite<Gradient::StopList>()) .def(vector_indexing_suite<Gradient::StopList>())
.def("__repr__",sl_repr)
; ;
class_<Gradient::Stop>("GradientStop", init<>()) class_<Gradient::Stop>("GradientStop", init<>())
......
...@@ -62,7 +62,7 @@ namespace { ...@@ -62,7 +62,7 @@ namespace {
if(!PyArray_TYPE(na)==NPY_FLOAT) { if(!PyArray_TYPE(na)==NPY_FLOAT) {
throw std::runtime_error("expected normal array to be of dtype=float32"); 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"); throw std::runtime_error("expected normal array size to match vertex array size");
} }
np=reinterpret_cast<float*>(PyArray_DATA(na)); np=reinterpret_cast<float*>(PyArray_DATA(na));
...@@ -78,7 +78,7 @@ namespace { ...@@ -78,7 +78,7 @@ namespace {
if(!PyArray_TYPE(ca)==NPY_FLOAT) { if(!PyArray_TYPE(ca)==NPY_FLOAT) {
throw std::runtime_error("expected color array to be of dtype=float32"); 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"); throw std::runtime_error("expected color array size to equal vertex-count x 4");
} }
cp=reinterpret_cast<float*>(PyArray_DATA(ca)); cp=reinterpret_cast<float*>(PyArray_DATA(ca));
......
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
0.0615451 0.0313726 0.286275 0.501961 1 0.0615451 0.0313726 0.286275 0.501961 1
0.502146 1 1 1 1 0.502146 1 1 1 1
0.978541 0.890105 0.075639 0.0546578 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>
<Gradient Name="AUTUMN" >3 <Gradient Name="AUTUMN" >3
0.0615451 1 0.972015 0.0132753 1 0.0615451 1 0.972015 0.0132753 1
...@@ -61,6 +66,10 @@ ...@@ -61,6 +66,10 @@
0.748835 0 1 1 1 0.748835 0 1 1 1
0.857779 0 0.623529 1 1 0.857779 0 0.623529 1 1
0.97541 0 0.133333 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> </Gradient>
</Gradients> </Gradients>
</EMDataInfo> </EMDataInfo>
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#include "gradient.hh" #include "gradient.hh"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <algorithm>
#include <ost/log.hh>
#include <ost/info/info.hh> #include <ost/info/info.hh>
#include <ost/info/info_fw.hh> #include <ost/info/info_fw.hh>
...@@ -28,13 +31,18 @@ ...@@ -28,13 +31,18 @@
namespace ost { namespace gfx { namespace ost { namespace gfx {
Gradient::Gradient() Gradient::Gradient():
{ stops_(),
} hsv_mode_(false)
{}
Gradient::Gradient(const String& name) Gradient::Gradient(const String& name)
{ {
Gradient gradient = GradientManager::Instance().GetGradient(name); Gradient gradient = GradientManager::Instance().GetGradient(name);
// why doesn't this work:
// stops_=gradient.stops_
// or even better
// *this = gradient
StopList stops = gradient.GetStops(); StopList stops = gradient.GetStops();
for(unsigned int i = 0; i < stops.size(); i++){ for(unsigned int i = 0; i < stops.size(); i++){
Stop stop = stops[i]; Stop stop = stops[i];
...@@ -55,8 +63,11 @@ void Gradient::SetColorAt(float t, const Color& c) ...@@ -55,8 +63,11 @@ void Gradient::SetColorAt(float t, const Color& c)
Color Gradient::GetColorAt(float t) const Color Gradient::GetColorAt(float t) const
{ {
if (stops_.empty()) if (stops_.empty()) {
throw Error("Can not calculate color with 0 Stops set!"); return Color();
} else if(stops_.size()==1) {
return stops_[0].color;
}
uint c=0; uint c=0;
while (t>=stops_[c].t && c<stops_.size()) { while (t>=stops_[c].t && c<stops_.size()) {
...@@ -64,16 +75,17 @@ Color Gradient::GetColorAt(float t) const ...@@ -64,16 +75,17 @@ Color Gradient::GetColorAt(float t) const
} }
if (c==0) { if (c==0) {
return stops_.front().color; return stops_.front().color;
} } else if (c==stops_.size()) {
if (c==stops_.size()) {
return stops_.back().color; return stops_.back().color;
} }
float d=stops_[c].t-stops_[c-1].t; float d = stops_[c].t-stops_[c-1].t;
float tt=0.0; float tt = d>0.001 ? (t-stops_[c-1].t)/d : 0.0;
if (d>0.0001) { if(hsv_mode_) {
tt=(t-stops_[c-1].t)/d; 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]);
return stops_[c-1].color*(1.0-tt)+stops_[c].color*tt; } else {
return stops_[c-1].color*(1.0-tt)+stops_[c].color*tt;
}
} }
void Gradient::GradientToInfo(info::InfoGroup& group) const void Gradient::GradientToInfo(info::InfoGroup& group) const
...@@ -86,6 +98,7 @@ 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"; 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.SetTextData(ss.str());
group.SetAttribute("hsv_mode",hsv_mode_? "1" : "0");
} }
Gradient::StopList Gradient::GetStops() const{ Gradient::StopList Gradient::GetStops() const{
...@@ -95,6 +108,16 @@ Gradient::StopList Gradient::GetStops() const{ ...@@ -95,6 +108,16 @@ Gradient::StopList Gradient::GetStops() const{
Gradient Gradient::GradientFromInfo(const info::InfoGroup& group) Gradient Gradient::GradientFromInfo(const info::InfoGroup& group)
{ {
std::istringstream ss(group.GetTextData()); 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; Gradient grad;
StopList::size_type size = 0; StopList::size_type size = 0;
...@@ -102,10 +125,19 @@ Gradient Gradient::GradientFromInfo(const info::InfoGroup& group) ...@@ -102,10 +125,19 @@ Gradient Gradient::GradientFromInfo(const info::InfoGroup& group)
float t, r, g, b, a; float t, r, g, b, a;
for( StopList::size_type i = 0; i < size; i++ ) { for( StopList::size_type i = 0; i < size; i++ ) {
ss >> t >> r >> g >> b >> a; 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); 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; return grad;
} }
......
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
#define OST_GFX_GRADIENT_HH #define OST_GFX_GRADIENT_HH
/* /*
Author: Marco Biasini Authors: Marco Biasini, Ansgar Philippsen
*/ */
#include <vector> #include <vector>
...@@ -30,16 +30,32 @@ ...@@ -30,16 +30,32 @@
#include <ost/info/info.hh> #include <ost/info/info.hh>
#include <ost/info/info_fw.hh> #include <ost/info/info_fw.hh>
namespace ost { namespace gfx { namespace ost { namespace gfx {
/// \brief color gradient /*!
/// \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 Gradients map a scalar value in the range of 0 to 1 to a color. The
/// output of GetColorAt(). New stops can be added with SetColorAt(). 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"
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 { class DLLEXPORT_OST_GFX Gradient {
public: public:
struct Stop { struct Stop {
...@@ -49,14 +65,14 @@ public: ...@@ -49,14 +65,14 @@ public:
float t; float t;
Color color; Color color;
Color GetColor(){ Color GetColor() const {
return color; return color;
} }
float GetRel(){ float GetRel() const {
return t; return t;
} }
bool operator==(const Stop& ref) const bool operator==(const Stop& ref) const
{ {
return t==ref.t && color==ref.color; return t==ref.t && color==ref.color;
...@@ -85,16 +101,26 @@ public: ...@@ -85,16 +101,26 @@ public:
void SetColorAt(float t, const Color& color); void SetColorAt(float t, const Color& color);
/// \brief convert gradient to info /// \brief convert gradient to info
// TODO: rename to ToInfo
// TODO:: add stand-alone function named GradientToInfo(Gradient, InfoGroup)
void GradientToInfo(info::InfoGroup& group) const; void GradientToInfo(info::InfoGroup& group) const;
/// \brief get list of color stops /// \brief get list of color stops
StopList GetStops() const; StopList GetStops() const;
/// \brief create gradient from info /// \brief create gradient from info
// TODO: move outside
// TODO: add FromInfo member function that overwrites this
static gfx::Gradient GradientFromInfo(const info::InfoGroup& group); 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: private:
std::vector<Stop> stops_; 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