Browse Source

Gmt module: Functions Color, ColorGray, ColorRGB, ColorHSV, and ColorCMYK.

ObjPtr
Michael Uleysky 9 years ago
parent
commit
db9f8b1a93
  1. 5
      modules/gmt/modgmt.cpp
  2. 1471
      modules/gmt/modgmt_colornames.cpp
  3. 84
      modules/gmt/modgmt_colornames.h
  4. 382
      modules/gmt/modgmt_func.cpp
  5. 5
      modules/gmt/modgmt_func.h
  6. 228
      modules/gmt/modgmt_structs.h

5
modules/gmt/modgmt.cpp

@ -31,5 +31,10 @@ int gmt_module_init(void* p)
RegisterFunction("Coord",GMT_Coord);
RegisterFunction("Region",GMT_Region);
RegisterFunction("Projection",GMT_Projection);
RegisterFunction("Color",GMT_Color);
RegisterFunction("ColorGray",GMT_ColorGray);
RegisterFunction("ColorRGB",GMT_ColorRGB);
RegisterFunction("ColorHSV",GMT_ColorHSV);
RegisterFunction("ColorCMYK",GMT_ColorCMYK);
return 0;
}

1471
modules/gmt/modgmt_colornames.cpp

File diff suppressed because it is too large Load Diff

84
modules/gmt/modgmt_colornames.h

@ -0,0 +1,84 @@
#ifndef MODGMT_COLORNAMES_H
#define MODGMT_COLORNAMES_H
struct colorname {const char *name; double r; double g; double b; };
#include <string.h>
class ColorHash
{
private:
static inline unsigned int colornamehash (const char *str, unsigned int len);
public:
static const struct colorname *in_colors_set (const char *str, unsigned int len);
};
inline unsigned int
ColorHash::colornamehash ( const char *str, unsigned int len)
{
static const unsigned short asso_values[] =
{
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 800, 25,
20, 5, 0, 845, 785, 780, 640, 620, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 80, 0, 686, 5, 0,
260, 0, 85, 770, 20, 950, 210, 95, 160, 195,
995, 335, 0, 0, 135, 425, 55, 863, 4084, 60,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 80, 0, 686,
5, 0, 260, 0, 85, 770, 20, 950, 210, 95,
160, 195, 995, 335, 0, 0, 135, 425, 55, 863,
4084, 60, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
4084, 4084, 4084, 4084, 4084, 4084
};
int hval = len;
switch (hval)
{
default:
hval += asso_values[(unsigned char)str[12]];
/*FALLTHROUGH*/
case 12:
hval += asso_values[(unsigned char)str[11]];
/*FALLTHROUGH*/
case 11:
case 10:
case 9:
case 8:
hval += asso_values[(unsigned char)str[7]];
/*FALLTHROUGH*/
case 7:
hval += asso_values[(unsigned char)str[6]];
/*FALLTHROUGH*/
case 6:
hval += asso_values[(unsigned char)str[5]];
/*FALLTHROUGH*/
case 5:
hval += asso_values[(unsigned char)str[4]];
/*FALLTHROUGH*/
case 4:
case 3:
hval += asso_values[(unsigned char)str[2]];
/*FALLTHROUGH*/
case 2:
case 1:
hval += asso_values[(unsigned char)str[0]];
break;
}
return hval + asso_values[(unsigned char)str[len - 1]];
}
#endif

382
modules/gmt/modgmt_func.cpp

@ -44,6 +44,88 @@ class DoubleConv<ObjectString>
};
typedef Base2Something<DoubleConv,ObjectReal,ObjectInt,ObjectString> Base2Double;
// Additional policies to let GetDouble work with Base2Double
// We use rational representation of floating point number, because double type values not allowed as template parameter
template<int32_t num=0, uint32_t denum=1>
class PDefaultVal
{
public:
double operator()() const {return static_cast<double>(num)/denum;}
};
class PMultiInputNames {};
// Special case for default value policy. This policy mast be last in policies list.
template<int32_t num, uint32_t denum>
class GetDouble<PDefaultVal<num,denum> >: public Base2Double
{
PDefaultVal<num,denum> p;
public:
GetDouble(GetDouble&&) = delete;
GetDouble(GetDouble&) = delete;
GetDouble() = delete;
GetDouble(const ObjectBase* arg):Base2Double(arg) {};
GetDouble(const ObjectList* input, const std::string& name):Base2Double(input,name){};
GetDouble(const ObjectList* input, const ObjectList::ListValues::size_type i):Base2Double(input,i){};
double operator()(bool* suc) const
{
if(Exist()) return Base2Double::operator()(suc);
else return p();
}
};
// Special case for multiple input names policy. This policy mast be last in policies list.
template<>
class GetDouble<PMultiInputNames>
{
bool exist;
bool ok;
double val;
public:
GetDouble(GetDouble&&) = delete;
GetDouble(GetDouble&) = delete;
GetDouble() = delete;
template<class... Args>
GetDouble(const ObjectList* input, const std::string& name, Args... args):GetDouble(input,args...)
{
Base2Double a(input,name);
if(exist && a.Exist()) ok=false;
else if(a.Exist())
{
exist=true;
ok=true;
val=a(&ok);
}
}
GetDouble(const ObjectList* input, const std::string& name)
{
Base2Double a(input,name);
exist=a.Exist();
ok=true;
if(exist) val=a(&ok);
}
double operator()(bool* suc) const
{
if(!ok || !exist) *suc=false;
return val;
}
bool Exist() const {return exist;}
};
// Bottom of recursion
template<>
class GetDouble<>: public Base2Double
{
public:
GetDouble(GetDouble&&) = delete;
GetDouble(GetDouble&) = delete;
GetDouble() = delete;
GetDouble(const ObjectBase* arg):Base2Double(arg) {};
GetDouble(const ObjectList* input, const std::string& name):Base2Double(input,name){};
GetDouble(const ObjectList* input, const ObjectList::ListValues::size_type i):Base2Double(input,i){};
double operator()(bool* suc) const {return Base2Double::operator()(suc);}
};
// Converting Int, Real or String to GMTCoord
template<class O> class CoordConv
{
@ -829,6 +911,215 @@ class ProjConv<ObjectGMTProjection>
};
typedef Base2Something<ProjConv,ObjectList,ObjectGMTProjection> Base2Proj;
// Helper types
typedef GetDouble<PMin<0>,PMax<255>,PDefaultVal<>> Base2RGB;
typedef GetDouble<PMin<0>,PMax<360>,PDefaultVal<>> Base2Hue;
typedef GetDouble<PMin<0>,PMax<1>,PDefaultVal<>> Base2SV;
typedef GetDouble<PMin<0>,PMax<100>,PDefaultVal<>> Base2CMYK;
typedef GetDouble<PMin<0>,PMax<100>,PDefaultVal<>> Base2Transp;
typedef GetDouble<PMin<0>,PMax<255>,PMultiInputNames> BaseM2RGB;
typedef GetDouble<PMin<0>,PMax<360>,PMultiInputNames> BaseM2Hue;
typedef GetDouble<PMin<0>,PMax<1>,PMultiInputNames> BaseM2SV;
typedef GetDouble<PMin<0>,PMax<100>,PMultiInputNames> BaseM2CMYK;
typedef GetDouble<PMin<0>,PMax<100>,PMultiInputNames> BaseM2Transp;
// Converting List to GMTColor
template<class O> class ColorConv
{
public:
struct gmt_color operator()(const O* o, bool* issuc) const
{
struct gmt_color c;
if(!c.Convert(o->Value())) *issuc=false;
return c;
}
};
// Special case is GMTColor
template<>
class ColorConv<ObjectGMTColor>
{
public:
struct gmt_color operator()(const ObjectGMTColor* o, bool* suc) const {return o->Data();}
};
typedef Base2Something<ColorConv,ObjectList,ObjectString,ObjectReal,ObjectInt,ObjectGMTColor> Base2Color;
// Conversion from List
template<>
class ColorConv<ObjectList>
{
public:
// Cases see in description of GMT_Color function
struct gmt_color operator()(const ObjectList* input, bool* issuc) const
{
struct gmt_color c;
auto size=input->Size();
if(1==size) // Cases 1, 2 and 4
{
Base2Color a(input,0);
bool suc=true;
c=a(&suc);
if(suc) return c;
goto fail;
}
// Case 3
{
bool upd=false;
bool cmodset=false;
// Update case, arguments list contains parameter with type GMTColor.
for(ObjectList::ListValues::size_type i=0;i<size;i++)
{
OBType<ObjectGMTColor> color(input->At(i));
if(color)
{
if(upd) goto fail; // Only one color in list allowed
c=color->Data();
upd=true;
}
}
// Update case, arguments list contains parameter color and this parameter is color.
{
Base2Color col(input,"color");
if(col.Exist())
{
if(upd) goto fail; // Already have color to update
bool suc=true;
struct gmt_color cs=col(&suc);
if(suc)
{
upd=true;
c=cs;
}
else goto fail; // Parse error
}
}
if(!upd)
{
// default color is black
c.transparency=0;
c.model=gmt_color::GRAY;
c.gray=0.0;
}
{
BaseM2Transp t(input,"t","transp","transparency");
if(t.Exist())
{
bool suc=true;
c.transparency=t(&suc);
if(!suc) goto fail; // Parsing error
}
}
// GRAY
{
BaseM2RGB g(input,"gray","grey");
if(g.Exist())
{
if(cmodset) goto fail; // Model already set
bool suc=true;
c.model=gmt_color::GRAY;
c.gray=g(&suc); // Update mode ignored in this case
if(!suc) goto fail; // Parsing error
cmodset=true;
}
}
// RGB
{
BaseM2RGB r(input,"r","red"), g(input,"g","green"), b(input,"b","blue");
if(r.Exist() || g.Exist() || b.Exist())
{
if(cmodset) goto fail; // Model already set
bool suc=true;
c.ToRGB();
if(r.Exist()) c.r=r(&suc);
if(g.Exist()) c.g=g(&suc);
if(b.Exist()) c.b=b(&suc);
if(!suc) goto fail; // Parsing error
cmodset=true;
}
}
// HSV
{
BaseM2Hue h(input,"h","hue");
BaseM2SV s(input,"s","sat","saturation"), v(input,"v","val","value");
if(h.Exist() || s.Exist() || v.Exist())
{
if(cmodset) goto fail; // Model already set
bool suc=true;
c.ToHSV();
if(h.Exist()) c.hue=h(&suc);
if(s.Exist()) c.saturation=s(&suc);
if(v.Exist()) c.value=v(&suc);
if(!suc) goto fail; // Parsing error
cmodset=true;
}
}
// CMYK
{
BaseM2CMYK cc(input,"c","cyan"), m(input,"m","magenta"), y(input,"y","yellow"), k(input,"k","black");
if(cc.Exist() || m.Exist() || y.Exist() || k.Exist())
{
if(cmodset) goto fail; // Model already set
bool suc=true;
c.ToCMYK();
if(cc.Exist()) c.cyan=cc(&suc);
if(m.Exist()) c.magenta=m(&suc);
if(y.Exist()) c.yellow=y(&suc);
if(k.Exist()) c.black=k(&suc);
if(!suc) goto fail; // Parsing error
cmodset=true;
}
}
if(cmodset || upd) return c; // Color created or updated
}
// Case 5
if(3==size)
{
Base2RGB r(input,0), g(input,1), b(input,2);
c.model=gmt_color::RGB;
bool suc=true;
if(r && g && b)
{
c.r=r(&suc);
c.g=g(&suc);
c.b=b(&suc);
if(!suc) goto fail; // Parsing error
}
else goto fail; // Something wrong
return c;
}
// Case 6
if(4==size)
{
Base2CMYK cc(input,0), m(input,1), y(input,2), k(input,3);
c.model=gmt_color::CMYK;
bool suc=true;
if(cc && m && y && k)
{
c.cyan=cc(&suc);
c.magenta=m(&suc);
c.yellow=y(&suc);
c.black=k(&suc);
if(!suc) goto fail; // Parsing error
}
else goto fail; // Something wrong
return c;
}
fail:
*issuc=false;
return c; // Something go wrong
}
};
/*
Input is one argument, Int, Real, String or GMTCoord.
@ -886,3 +1177,94 @@ ObjectBase* GMT_Projection(const ObjectList* input)
if(suc) return new ObjectGMTProjection(p);
else return 0;
}
/*
Input:
1) One argument, Color. Return copy of this argument.
2) One argument, list. Recursively calling GMT_Color.
3) Pairs list. Names are gray (grey), r(red),g(green),b(blue), h(hue),s(sat,saturation),v(value), c(cyan),m(magenta),y(yellow),k(black) and t(transp,transparency).
The different color models can't be mixed.
Gray, r, g, b are doubles in the range 0-255, h is double in the range 0-360, s and v are doubles in the range 0-1 and c, m, y, k and transparency are doubles in the range 0-100. Default value for all parameters is 0.
If pair with name color exists in list, when recursively calling GMT_Color on the value of this parameter, when modify it with specified parameters.
If argument with type Color exists in list, when copy it and modify with specified parameters. In both cases color model changing as specified by parameters.
4) One argument, interprets as gray.
5) Three arguments, interprets as r, g, b.
6) Four arguments, interprets as c, m, y, k.
Transparency or HSV model can be set only in form 3.
*/
ObjectBase* GMT_Color(const ObjectList* input)
{
bool suc=true;
struct gmt_color c=ColorConv<ObjectList>()(input,&suc);
if(suc) return new ObjectGMTColor(c);
else return 0;
}
ObjectBase* GMT_ColorGray(const ObjectList* input)
{
struct gmt_color c;
bool suc=true;
Base2RGB g(input,0);
Base2Transp t(input,1);
c.model=gmt_color::GRAY;
c.gray=g(&suc);
c.transparency=t(&suc);
if(suc) return new ObjectGMTColor(c);
else return 0;
}
ObjectBase* GMT_ColorRGB(const ObjectList* input)
{
struct gmt_color c;
bool suc=true;
Base2RGB r(input,0),g(input,1),b(input,2);
Base2Transp t(input,3);
c.model=gmt_color::RGB;
c.r=r(&suc);
c.g=g(&suc);
c.b=b(&suc);
c.transparency=t(&suc);
if(suc) return new ObjectGMTColor(c);
else return 0;
}
ObjectBase* GMT_ColorHSV(const ObjectList* input)
{
struct gmt_color c;
bool suc=true;
Base2Hue h(input,0);
Base2SV s(input,1),v(input,2);
Base2Transp t(input,3);
c.model=gmt_color::HSV;
c.hue=h(&suc);
c.saturation=s(&suc);
c.value=v(&suc);
c.transparency=t(&suc);
if(suc) return new ObjectGMTColor(c);
else return 0;
}
ObjectBase* GMT_ColorCMYK(const ObjectList* input)
{
struct gmt_color c;
bool suc=true;
Base2CMYK cyan(input,0),m(input,1),y(input,2),k(input,3);
Base2Transp t(input,4);
c.model=gmt_color::CMYK;
c.cyan=cyan(&suc);
c.magenta=m(&suc);
c.yellow=y(&suc);
c.black=k(&suc);
c.transparency=t(&suc);
if(suc) return new ObjectGMTColor(c);
else return 0;
}

5
modules/gmt/modgmt_func.h

@ -7,5 +7,10 @@ ObjectBase* GMT_Footer(const ObjectList* input);
ObjectBase* GMT_Coord(const ObjectList* input);
ObjectBase* GMT_Region(const ObjectList* input);
ObjectBase* GMT_Projection(const ObjectList* input);
ObjectBase* GMT_Color(const ObjectList* input);
ObjectBase* GMT_ColorGray(const ObjectList* input);
ObjectBase* GMT_ColorRGB(const ObjectList* input);
ObjectBase* GMT_ColorHSV(const ObjectList* input);
ObjectBase* GMT_ColorCMYK(const ObjectList* input);
#endif

228
modules/gmt/modgmt_structs.h

@ -4,6 +4,68 @@
#include <cmath>
#include <map>
#include "common.h"
#include "modgmt_colornames.h"
// Helper classes for conversion of doubles from strings with varios checks
// We use rational representation of floating point number, because double type values not allowed as template parameter
template<int32_t num, uint32_t denum=1>
class PMin
{
public:
double operator()(double v, bool* suc) const {if(v<static_cast<double>(num)/denum) *suc=false; return v;}
};
template<int32_t num, uint32_t denum=1>
class PMax
{
public:
double operator()(double v, bool* suc) const {if(v>static_cast<double>(num)/denum) *suc=false; return v;}
};
class PFromValue
{
double d;
bool ok;
public:
PFromValue(const std::string& s) {ok=str2double(s,&d);}
PFromValue(double s):d(s),ok(true) {}
double operator()(bool* suc) const
{
if(!ok) *suc=false;
return d;
}
};
// Main definition, never instantiated
template<class... Policies>
class GetDouble;
// Recursive definition
template<class Policy, class... Policies>
class GetDouble<Policy, Policies...>: public GetDouble<Policies...>
{
Policy p;
public:
GetDouble(GetDouble&&) = delete;
GetDouble(GetDouble&) = delete;
template<class... Args>
GetDouble(Args... args):GetDouble<Policies...>(args...) {};
double operator()(bool* suc) const {return p(GetDouble<Policies...>::operator()(suc),suc);}
};
// Special case for PFromString policy. This policy mast be last in policies list.
template<>
class GetDouble<PFromValue>
{
PFromValue p;
public:
GetDouble(GetDouble&&) = delete;
GetDouble(GetDouble&) = delete;
GetDouble() = delete;
GetDouble(const std::string& str):p(str) {};
GetDouble(double d):p(d) {};
double operator()(bool* suc) const {return p(suc);}
};
// Coordinate
struct gmt_coord
@ -218,10 +280,17 @@ struct gmt_projection
static std::map<std::string,projection> projnames;
};
// Helper types for colors
typedef GetDouble<PMin<0>,PMax<255>,PFromValue> Value2RGB;
typedef GetDouble<PMin<0>,PMax<360>,PFromValue> Value2Hue;
typedef GetDouble<PMin<0>,PMax<1>,PFromValue> Value2SV;
typedef GetDouble<PMin<0>,PMax<100>,PFromValue> Value2CMYK;
typedef GetDouble<PMin<0>,PMax<100>,PFromValue> Value2Transp;
// Color
struct gmt_color
{
public:
enum ColorModel {RGB,GRAY,HSV,CMYK};
ColorModel model;
union
@ -255,6 +324,17 @@ struct gmt_color
}
return 0;
}
void ToGray()
{
switch(model)
{
case(RGB): gray=RGB2Gray().gray; break;
case(GRAY): return;
case(HSV): gray=HSV2Gray().gray; break;
case(CMYK): gray=CMYK2Gray().gray; break;
}
model=GRAY;
}
double R() const
{
@ -289,6 +369,19 @@ struct gmt_color
}
return 0;
}
void ToRGB()
{
gmt_color c;
switch(model)
{
case(RGB): return;
case(GRAY): c=Gray2RGB(); break;
case(HSV): c=HSV2RGB(); break;
case(CMYK): c=CMYK2RGB(); break;
}
model=RGB;
r=c.r; g=c.g; b=c.b;
}
double H() const
{
@ -323,6 +416,19 @@ struct gmt_color
}
return 0;
}
void ToHSV()
{
gmt_color c;
switch(model)
{
case(RGB): c=RGB2HSV(); break;
case(GRAY): c=Gray2HSV(); break;
case(HSV): return;
case(CMYK): c=CMYK2HSV(); break;
}
model=HSV;
hue=c.hue; saturation=c.saturation; value=c.value;
}
double C() const
{
@ -368,6 +474,128 @@ struct gmt_color
}
return 0;
}
void ToCMYK()
{
gmt_color cc;
switch(model)
{
case(RGB): cc=RGB2CMYK(); break;
case(GRAY): cc=Gray2CMYK(); break;
case(HSV): cc=HSV2CMYK(); break;
case(CMYK): return;
}
model=CMYK;
cyan=cc.cyan; magenta=cc.magenta; yellow=cc.yellow; black=cc.black;
}
// Interpret one numeric argument as gray value
bool Convert(double gr)
{
Value2RGB g(gr);
bool suc=true;
model=GRAY;
transparency=0.0;
gray=g(&suc);
return suc;
}
bool Convert(const std::string& istr)
{
std::string cstr=istr;
tolower(cstr);
transparency=0.0;
// Transparency check
{
WordList wl=Split(cstr,"@");
if(1!=wl.size() && 2!=wl.size()) return false;
if(2==wl.size())
{
WordList::const_iterator ci=wl.begin();
bool suc=true;
cstr=*ci;
ci++;
Value2Transp t(*ci);
transparency=t(&suc);
if(!suc) return false; // Parse error
}
}
{
WordList wl_slash=Split(cstr,"/"),wl_hyphen=Split(cstr,"-");
WordList::size_type slash_size=wl_slash.size(),hyphen_size=wl_hyphen.size();
// Checks
if(slash_size>1 && hyphen_size>1) return false; // Delimiter can be "/" or "-", not both
if(2==slash_size || slash_size>4) return false; // Size can be 1 or 3 for rgb or 4 for cmyk
if(2==hyphen_size || hyphen_size>3) return false; // Size can be 1 or 3 for hsv
// Gray or name
// TODO: Hex representation
if(1==slash_size && 1==hyphen_size)
{
if(SetByName(cstr)) return true; // Set color by name, all ok
Value2RGB g(cstr);
bool suc=true;
model=GRAY;
gray=g(&suc);
return suc;
}
// RGB
if(3==slash_size)
{
Value2RGB red(wl_slash.front()); wl_slash.pop_front();
Value2RGB green(wl_slash.front()); wl_slash.pop_front();
Value2RGB blue(wl_slash.front());
bool suc=true;
model=RGB;
r=red(&suc);
g=green(&suc);
b=blue(&suc);
return suc;
}
// HSV
if(3==hyphen_size)
{
Value2Hue h(wl_hyphen.front()); wl_hyphen.pop_front();
Value2SV s(wl_hyphen.front()); wl_hyphen.pop_front();
Value2SV v(wl_hyphen.front());
bool suc=true;
model=HSV;
hue=h(&suc);
saturation=s(&suc);
value=v(&suc);
return suc;
}
// CMYK
if(4==slash_size)
{
Value2CMYK c(wl_slash.front()); wl_slash.pop_front();
Value2CMYK m(wl_slash.front()); wl_slash.pop_front();
Value2CMYK y(wl_slash.front()); wl_slash.pop_front();
Value2CMYK k(wl_slash.front());
bool suc=true;
model=CMYK;
cyan=c(&suc);
magenta=m(&suc);
yellow=y(&suc);
black=k(&suc);
return suc;
}
}
return false;
}
bool SetByName(const std::string& name)
{
const struct colorname* cdata;
model=RGB;
cdata=ColorHash::in_colors_set(name.c_str(),name.length());
if(0==cdata) return false;
r=cdata->r;
g=cdata->g;
b=cdata->b;
return true;
}
// Transformation functions
private:
#include "colortransform.h"

Loading…
Cancel
Save