|
|
|
#ifndef MODGMT_STRUCT_H
|
|
|
|
#define MODGMT_STRUCT_H
|
|
|
|
#include <cinttypes>
|
|
|
|
#include <cmath>
|
|
|
|
#include <map>
|
|
|
|
#include "common.h"
|
|
|
|
#include "modgmt_colornames.h"
|
|
|
|
|
|
|
|
// Helper template for checking double numbers acquired from Source with some Policies.
|
|
|
|
// Main definition, never instantiated
|
|
|
|
template<class Source, class... Policies>
|
|
|
|
class GetDouble;
|
|
|
|
|
|
|
|
// Recursive definition
|
|
|
|
template<class Source, class Policy, class... Policies>
|
|
|
|
class GetDouble<Source, Policy, Policies...>: public GetDouble<Source, Policies...>
|
|
|
|
{
|
|
|
|
Policy p;
|
|
|
|
public:
|
|
|
|
GetDouble(GetDouble&&) = delete;
|
|
|
|
GetDouble(GetDouble&) = delete;
|
|
|
|
template<class... Args>
|
|
|
|
GetDouble(Args... args):GetDouble<Source,Policies...>(args...) {};
|
|
|
|
double operator()(bool* suc) const {return p(GetDouble<Source,Policies...>::operator()(suc),suc);}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Bottom of recursion
|
|
|
|
template<class Source>
|
|
|
|
class GetDouble<Source>: public Source
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
GetDouble(GetDouble&&) = delete;
|
|
|
|
GetDouble(GetDouble&) = delete;
|
|
|
|
GetDouble() = delete;
|
|
|
|
template<class... Args>
|
|
|
|
GetDouble(Args... args):Source(args...) {};
|
|
|
|
double operator()(bool* suc) const {return Source::operator()(suc);}
|
|
|
|
};
|
|
|
|
|
|
|
|
// We use rational representation of floating point number, because double type values not allowed as template parameter
|
|
|
|
// Policy to check if value is greater or equal num/denum
|
|
|
|
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;}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Policy to check if value is lesser or equal num/denum
|
|
|
|
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;}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Get double value from string or number
|
|
|
|
class SourceValue
|
|
|
|
{
|
|
|
|
double d;
|
|
|
|
bool ok;
|
|
|
|
public:
|
|
|
|
SourceValue(const std::string& s) {ok=str2double(s,&d);}
|
|
|
|
SourceValue(double s):d(s),ok(true) {}
|
|
|
|
double operator()(bool* suc) const
|
|
|
|
{
|
|
|
|
if(!ok) *suc=false;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Helper types for colors
|
|
|
|
typedef GetDouble<SourceValue,PMin<0>,PMax<255> > Value2RGB;
|
|
|
|
typedef GetDouble<SourceValue,PMin<0>,PMax<360> > Value2Hue;
|
|
|
|
typedef GetDouble<SourceValue,PMin<0>,PMax<1> > Value2SV;
|
|
|
|
typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2CMYK;
|
|
|
|
typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2Transp;
|
|
|
|
// Helper type for pens and dashes
|
|
|
|
typedef GetDouble<SourceValue,PMin<0> > Value2Width;
|
|
|
|
|
|
|
|
class gmt_struct {}; // Base type for all gmt structures
|
|
|
|
|
|
|
|
// Coordinate
|
|
|
|
struct gmt_coord: public gmt_struct
|
|
|
|
{
|
|
|
|
bool isdeg;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
double r;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
bool sign;
|
|
|
|
uint16_t d;
|
|
|
|
uint8_t m;
|
|
|
|
double s;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string Value() const
|
|
|
|
{
|
|
|
|
if(!isdeg) return std::to_string(r);
|
|
|
|
else return (sign?"":"-")+std::to_string(d)+":"+std::to_string(m)+(s==0?"":":"+std::to_string(s));
|
|
|
|
}
|
|
|
|
operator double() const
|
|
|
|
{
|
|
|
|
if(isdeg) return (d+(m+s/60.0)/60.0)*(sign?1:-1);
|
|
|
|
else return r;
|
|
|
|
}
|
|
|
|
bool Convert(const std::string& str)
|
|
|
|
{
|
|
|
|
WordList wl;
|
|
|
|
WordList::const_iterator cw;
|
|
|
|
wl=Split(str,":",true);
|
|
|
|
if(1==wl.size()) // No dd:mm
|
|
|
|
{
|
|
|
|
isdeg=false;
|
|
|
|
return str2double(str,&r);
|
|
|
|
}
|
|
|
|
if(0==wl.size() || wl.size()>3) return false;
|
|
|
|
|
|
|
|
isdeg=true;
|
|
|
|
int64_t res;
|
|
|
|
|
|
|
|
// degrees
|
|
|
|
cw=wl.begin();
|
|
|
|
if(!str2int(*cw,&res)) return false;
|
|
|
|
if(res>360 || res<-360) res%=360;
|
|
|
|
sign=(std::string::npos==cw->find('-'));
|
|
|
|
d=static_cast<uint16_t>(sign?res:-res);
|
|
|
|
// minutes
|
|
|
|
cw++;
|
|
|
|
if(!str2int(*cw,&res)) return false;
|
|
|
|
if(res<0 || res>=60) return false;
|
|
|
|
m=static_cast<uint8_t>(res);
|
|
|
|
s=0;
|
|
|
|
|
|
|
|
// seconds
|
|
|
|
cw++;
|
|
|
|
if(wl.end()==cw) return true; // No seconds
|
|
|
|
if(!str2double(*cw,&s) ) return false;
|
|
|
|
if(s<0.0 || s>=60.0) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool Convert(double num)
|
|
|
|
{
|
|
|
|
isdeg=false;
|
|
|
|
r=num;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Region
|
|
|
|
struct gmt_region: public gmt_struct
|
|
|
|
{
|
|
|
|
enum Type {NORMAL,BBOX,GLOBAL360,GLOBAL180};
|
|
|
|
Type type;
|
|
|
|
struct gmt_coord xb,xe,yb,ye;
|
|
|
|
|
|
|
|
std::string Value() const
|
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case(NORMAL): return std::string("-R")+xb.Value()+"/"+xe.Value()+"/"+yb.Value()+"/"+ye.Value();
|
|
|
|
case(BBOX): return std::string("-R")+xb.Value()+"/"+yb.Value()+"/"+xe.Value()+"/"+ye.Value()+"r";
|
|
|
|
case(GLOBAL360): return "-Rg";
|
|
|
|
case(GLOBAL180): return "-Rd";
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only "global", "global180" and "global360"
|
|
|
|
// TODO: add parsing of "-R" strings
|
|
|
|
bool Convert(const std::string& istr)
|
|
|
|
{
|
|
|
|
std::string str=istr;
|
|
|
|
tolower(str);
|
|
|
|
if("global180"==str)
|
|
|
|
{
|
|
|
|
type=GLOBAL180;
|
|
|
|
xb.Convert(-180.0); xe.Convert(180.0);
|
|
|
|
yb.Convert(-90.0); ye.Convert(90.0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if("global360"==str || "global"==str)
|
|
|
|
{
|
|
|
|
type=GLOBAL360;
|
|
|
|
xb.Convert(0.0); xe.Convert(360.0);
|
|
|
|
yb.Convert(-90.0); ye.Convert(90.0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make by coordinates
|
|
|
|
bool Convert(struct gmt_coord ixb, struct gmt_coord ixe, struct gmt_coord iyb, struct gmt_coord iye, bool isbbox=false)
|
|
|
|
{
|
|
|
|
type=isbbox?BBOX:NORMAL;
|
|
|
|
xb=ixb; yb=iyb; xe=ixe; ye=iye;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Projection
|
|
|
|
struct gmt_projection: public gmt_struct
|
|
|
|
{
|
|
|
|
// OBLIQMERCATOR types
|
|
|
|
enum class OType {NOTDEF,A,B,C};
|
|
|
|
// No UTM (-Ju)
|
|
|
|
enum projection {NOTDEF,XY,CYL_EQU,MERCATOR,TRANSMERCATOR,OBLIQMERCATOR,CASSINI,CYL_EQA,MILLER,CYL_STERE};
|
|
|
|
// Real size in cm of drawing area
|
|
|
|
double rwidth,rheight;
|
|
|
|
|
|
|
|
struct gmt_region region;
|
|
|
|
projection proj;
|
|
|
|
double width; // parameter of projection
|
|
|
|
static const double default_width;
|
|
|
|
|
|
|
|
union // other projection parameters
|
|
|
|
{
|
|
|
|
// XY
|
|
|
|
struct {double height;} x;
|
|
|
|
// Cylindrical projections
|
|
|
|
// CYL_EQU (Cylindrical Equidistant -Jq)
|
|
|
|
struct {struct gmt_coord stpar,cmer;} q;
|
|
|
|
// MERCATOR (-Jm)
|
|
|
|
struct {struct gmt_coord stpar,cmer;} m;
|
|
|
|
// TRANSMERCATOR (-Jt)
|
|
|
|
struct {struct gmt_coord cmer,orlat; double scale;} t;
|
|
|
|
// OBLIQMERCATOR (-Jo)
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
OType type;
|
|
|
|
struct gmt_coord clon,clat;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct gmt_coord azimuth; // A
|
|
|
|
struct {struct gmt_coord eqlon,eqlat;}; // B
|
|
|
|
struct {struct gmt_coord polelon,polelat;}; // C
|
|
|
|
};
|
|
|
|
} o;
|
|
|
|
// CASSINI (-Jc)
|
|
|
|
struct {struct gmt_coord clon,clat;} c;
|
|
|
|
// CYL_EQA (Cylindrical equal-area -Jy)
|
|
|
|
struct {struct gmt_coord stpar,cmer;} y;
|
|
|
|
// MILLER (-Jj)
|
|
|
|
struct {struct gmt_coord cmer;} j;
|
|
|
|
// CYL_STERE (Cylindrical stereographic -Jcyl_stere)
|
|
|
|
struct {struct gmt_coord stpar,cmer;} cyl_stere;
|
|
|
|
};
|
|
|
|
std::string Value() const
|
|
|
|
{
|
|
|
|
std::string ret;
|
|
|
|
switch(proj)
|
|
|
|
{
|
|
|
|
case(XY): {ret="-JX"+std::to_string(width)+"c/"+std::to_string(x.height)+"c"; break;}
|
|
|
|
case(CYL_EQU): {ret="-JQ"+q.cmer.Value()+"/"+q.stpar.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
case(MERCATOR): {ret="-JM"+m.cmer.Value()+"/"+m.stpar.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
case(TRANSMERCATOR): {ret="-JT"+t.cmer.Value()+"/"+t.orlat.Value()+"/"+std::to_string(width)+"c --PROJ_SCALE_FACTOR="+std::to_string(t.scale); break;}
|
|
|
|
case(OBLIQMERCATOR):
|
|
|
|
{
|
|
|
|
switch(o.type)
|
|
|
|
{
|
|
|
|
case(OType::A): {ret="-JOa"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.azimuth.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
case(OType::B): {ret="-JOb"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.eqlon.Value()+"/"+o.eqlat.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
case(OType::C): {ret="-JOb"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.polelon.Value()+"/"+o.polelat.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
default: return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case(CASSINI): {ret="-JC"+c.clon.Value()+"/"+c.clat.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
case(CYL_EQA): {ret="-JY"+y.stpar.Value()+"/"+y.cmer.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
case(MILLER): {ret="-JJ"+j.cmer.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
case(CYL_STERE): {ret="-JCyl_stere"+cyl_stere.stpar.Value()+"/"+cyl_stere.cmer.Value()+"/"+std::to_string(width)+"c"; break;}
|
|
|
|
default: return "";
|
|
|
|
}
|
|
|
|
ret+=" "+region.Value();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
bool SetType(const std::string& s)
|
|
|
|
{
|
|
|
|
proj=NOTDEF;
|
|
|
|
std::string str=s;
|
|
|
|
tolower(str);
|
|
|
|
if(projnames.end()==projnames.find(str)) return false;
|
|
|
|
proj=projnames[str];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FillProjNames();
|
|
|
|
|
|
|
|
private:
|
|
|
|
static std::map<std::string,projection> projnames;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Color
|
|
|
|
struct gmt_color: public gmt_struct
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
enum ColorModel {RGB,GRAY,HSV,CMYK};
|
|
|
|
ColorModel model;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
double gray; // 0-255
|
|
|
|
struct {double r,g,b;}; // 0-255
|
|
|
|
struct {double hue,saturation,value;}; // 0-360, 0-1, 0-1
|
|
|
|
struct {double cyan,magenta,yellow,black;}; // 0-100
|
|
|
|
};
|
|
|
|
double transparency;
|
|
|
|
std::string Value() const
|
|
|
|
{
|
|
|
|
std::string trans=(transparency!=0)?("@"+std::to_string(transparency)):"";
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return std::to_string(r)+"/"+std::to_string(g)+"/"+std::to_string(b)+trans;
|
|
|
|
case(GRAY): return std::to_string(gray)+trans;
|
|
|
|
case(HSV): return std::to_string(hue)+"-"+std::to_string(saturation)+"-"+std::to_string(value)+trans;
|
|
|
|
case(CMYK): return std::to_string(cyan)+"/"+std::to_string(magenta)+"/"+std::to_string(yellow)+"/"+std::to_string(black)+trans;
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
double Gray() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2Gray().gray;
|
|
|
|
case(GRAY): return gray;
|
|
|
|
case(HSV): return HSV2Gray().gray;
|
|
|
|
case(CMYK): return CMYK2Gray().gray;
|
|
|
|
}
|
|
|
|
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
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return r;
|
|
|
|
case(GRAY): return Gray2RGB().r;
|
|
|
|
case(HSV): return HSV2RGB().r;
|
|
|
|
case(CMYK): return CMYK2RGB().r;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
double G() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return g;
|
|
|
|
case(GRAY): return Gray2RGB().g;
|
|
|
|
case(HSV): return HSV2RGB().g;
|
|
|
|
case(CMYK): return CMYK2RGB().g;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
double B() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return b;
|
|
|
|
case(GRAY): return Gray2RGB().b;
|
|
|
|
case(HSV): return HSV2RGB().b;
|
|
|
|
case(CMYK): return CMYK2RGB().b;
|
|
|
|
}
|
|
|
|
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
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2HSV().hue;
|
|
|
|
case(GRAY): return Gray2HSV().hue;
|
|
|
|
case(HSV): return hue;
|
|
|
|
case(CMYK): return CMYK2HSV().hue;
|
|
|
|
}
|
|
|
|
return 0;// Own functions
|
|
|
|
}
|
|
|
|
double S() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2HSV().saturation;
|
|
|
|
case(GRAY): return Gray2HSV().saturation;
|
|
|
|
case(HSV): return saturation;
|
|
|
|
case(CMYK): return CMYK2HSV().saturation;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
double V() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2HSV().value;
|
|
|
|
case(GRAY): return Gray2HSV().value;
|
|
|
|
case(HSV): return value;
|
|
|
|
case(CMYK): return CMYK2HSV().value;
|
|
|
|
}
|
|
|
|
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
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2CMYK().cyan;
|
|
|
|
case(GRAY): return Gray2CMYK().cyan;
|
|
|
|
case(HSV): return HSV2CMYK().cyan;
|
|
|
|
case(CMYK): return cyan;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
double M() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2CMYK().magenta;
|
|
|
|
case(GRAY): return Gray2CMYK().magenta;
|
|
|
|
case(HSV): return HSV2CMYK().magenta;
|
|
|
|
case(CMYK): return magenta;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
double Y() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2CMYK().yellow;
|
|
|
|
case(GRAY): return Gray2CMYK().yellow;
|
|
|
|
case(HSV): return HSV2CMYK().yellow;
|
|
|
|
case(CMYK): return yellow;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
double K() const
|
|
|
|
{
|
|
|
|
switch(model)
|
|
|
|
{
|
|
|
|
case(RGB): return RGB2CMYK().black;
|
|
|
|
case(GRAY): return Gray2CMYK().black;
|
|
|
|
case(HSV): return HSV2CMYK().black;
|
|
|
|
case(CMYK): return black;
|
|
|
|
}
|
|
|
|
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 "modgmt_colortransform.h"
|
|
|
|
};
|
|
|
|
|
|
|
|
// Dash
|
|
|
|
struct gmt_dash: public gmt_struct
|
|
|
|
{
|
|
|
|
std::vector<double> dash;
|
|
|
|
double shift;
|
|
|
|
double width;
|
|
|
|
bool wisrel;
|
|
|
|
static const double default_width;
|
|
|
|
std::string Value() const
|
|
|
|
{
|
|
|
|
std::string ret;
|
|
|
|
if(dash.empty()) return ret;
|
|
|
|
for(auto i:dash) ret+=std::to_string((wisrel?width:1.0)*i/10.0)+"_";
|
|
|
|
ret.back()=':';
|
|
|
|
ret+=std::to_string(shift)+"c";
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
operator bool() const {return !dash.empty();}
|
|
|
|
void Clear() {dash.clear(); shift=0.0; wisrel=false;}
|
|
|
|
|
|
|
|
bool Convert(const std::string& in, double w=0.0)
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
shift=0;
|
|
|
|
if(0==in.size()) return true; // No dash
|
|
|
|
if(std::string::npos==in.find_first_not_of(".-")) // dot-dash form
|
|
|
|
{
|
|
|
|
width=(0==w)?default_width:w;
|
|
|
|
wisrel=true;
|
|
|
|
for(const auto& i:in)
|
|
|
|
{
|
|
|
|
if('.'==i) dash.push_back(1); // Dot
|
|
|
|
else dash.push_back(8); // Dash
|
|
|
|
dash.push_back(4); // Gap
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
std::string dstr=in;
|
|
|
|
// Determine shift
|
|
|
|
{
|
|
|
|
WordList wl=Split(in,":");
|
|
|
|
if(wl.size()>1) return false;
|
|
|
|
if(1==wl.size())
|
|
|
|
{
|
|
|
|
Value2Width s(wl.back());
|
|
|
|
bool suc=true;
|
|
|
|
shift=s(&suc);
|
|
|
|
if(!suc) return false; // Parse error
|
|
|
|
dstr=wl.front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WordList wl=Split(dstr,"_");
|
|
|
|
for(const auto& i:wl)
|
|
|
|
{
|
|
|
|
Value2Width d(i);
|
|
|
|
bool suc=true;
|
|
|
|
dash.push_back(d(&suc));
|
|
|
|
if(!suc) return false; // Parse error
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Pen
|
|
|
|
struct gmt_pen: public gmt_struct
|
|
|
|
{
|
|
|
|
double width;
|
|
|
|
struct gmt_color color;
|
|
|
|
struct gmt_dash dash;
|
|
|
|
static const double default_width;
|
|
|
|
std::string Value() const {return std::to_string(width/10.0)+"c,"+color.Value()+(dash?(","+dash.Value()):"");}
|
|
|
|
|
|
|
|
// Interpret one numeric argument as width value
|
|
|
|
bool Convert(double in)
|
|
|
|
{
|
|
|
|
Value2Width w(in);
|
|
|
|
bool suc=true;
|
|
|
|
color.Convert(0); // Black
|
|
|
|
dash.Clear();
|
|
|
|
width=w(&suc);
|
|
|
|
return suc;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert from string
|
|
|
|
bool Convert(const std::string& istr)
|
|
|
|
{
|
|
|
|
std::string str=istr;
|
|
|
|
WordList::const_iterator ci;
|
|
|
|
tolower(str);
|
|
|
|
WordList wl=Split(str,",",true);
|
|
|
|
|
|
|
|
// Defaults
|
|
|
|
width=default_width;
|
|
|
|
color.Convert(0); // Black
|
|
|
|
dash.Clear();
|
|
|
|
|
|
|
|
if(wl.size()>3) return false; // String is [width][,color][,dash]
|
|
|
|
ci=wl.begin();
|
|
|
|
if(wl.end()!=ci && 0!=ci->size())
|
|
|
|
{
|
|
|
|
Value2Width w(*ci);
|
|
|
|
bool suc=true;
|
|
|
|
width=w(&suc);
|
|
|
|
if(!suc) return false; // Parse error
|
|
|
|
}
|
|
|
|
if(wl.end()!=ci) ci++;
|
|
|
|
if(wl.end()!=ci && 0!=ci->size())
|
|
|
|
{
|
|
|
|
if(!color.Convert(*ci)) return false; // Parse error
|
|
|
|
}
|
|
|
|
if(wl.end()!=ci) ci++;
|
|
|
|
if(wl.end()!=ci && 0!=ci->size())
|
|
|
|
{
|
|
|
|
if(!dash.Convert(*ci,width)) return false; // Parse error
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|