diff --git a/modules/gmt/colortransform.h b/modules/gmt/colortransform.h new file mode 100644 index 0000000..b49dd20 --- /dev/null +++ b/modules/gmt/colortransform.h @@ -0,0 +1,135 @@ +// From grayscale +struct gmt_color Gray2RGB() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=RGB; + color.r=color.g=color.b=gray; + return color; +} +struct gmt_color Gray2HSV() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=HSV; + color.hue=0; + color.saturation=0; + color.value=gray/255.0; + return color; +} +struct gmt_color Gray2CMYK() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=CMYK; + color.cyan=color.magenta=color.yellow=0; + color.black=(1.0-gray/255.0)*100.0; + return color; +} + +// From RGB +struct gmt_color RGB2Gray() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=GRAY; + color.gray=0.2126*r+0.7152*g+0.0722*b; + return color; +} +struct gmt_color RGB2HSV() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=HSV; + double rr=r/255.0,gg=g/255.0,bb=b/255.0; + double cmax=std::max(rr,std::max(gg,bb)); + double cmin=std::min(rr,std::min(gg,bb)); + double delta=cmax-cmin; + + if(0==delta) color.hue=0; + else if(cmax==rr) + { + double x=(gg-bb)/delta; + color.hue=x-floor(x/6.0)*6.0; + } + else if(cmax==gg) color.hue=(bb-rr)/delta+2.0; + else if(cmax==bb) color.hue=(rr-gg)/delta+4.0; + color.hue*=60.0; + color.saturation=(0==cmax)?0:(delta/cmax); + color.value=cmax; + + return color; +} +struct gmt_color RGB2CMYK() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=CMYK; + double rr=r/255.0,gg=g/255.0,bb=b/255.0; + double k=1.0-std::max(rr,std::max(gg,bb)); + + color.black=k; + color.cyan=(1.0-rr-k)/(1.0-k); + color.magenta=(1.0-gg-k)/(1.0-k); + color.yellow=(1.0-bb-k)/(1.0-k); + if(0.0==1.0-k) color.cyan=color.magenta=color.yellow=0.0; + color.black*=100.0; + color.cyan*=100.0; + color.magenta*=100.0; + color.yellow*=100.0; + + return color; +} + +// From HSV +struct gmt_color HSV2Gray() const +{ + return HSV2RGB().RGB2Gray(); +} +struct gmt_color HSV2RGB() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=RGB; + double c=saturation*value; + double x=c*(1.0-fabs((hue/60.0)-floor((hue/60.0)/2.0)*2.0-1.0)); + double m=value-c; + + if(0.0 <=hue && 60.0 >hue) {color.r=c; color.g=x; color.b=0;} + if(60.0 <=hue && 120.0>hue) {color.r=x; color.g=c; color.b=0;} + if(120.0<=hue && 180.0>hue) {color.r=0; color.g=c; color.b=x;} + if(180.0<=hue && 240.0>hue) {color.r=0; color.g=x; color.b=c;} + if(240.0<=hue && 300.0>hue) {color.r=x; color.g=0; color.b=c;} + if(300.0<=hue &&360.0>=hue) {color.r=c; color.g=0; color.b=x;} + color.r+=m; color.g+=m; color.b+=m; + color.r*=255; color.g*=255; color.b*=255; + + return color; +} +struct gmt_color HSV2CMYK() const +{ + return HSV2RGB().RGB2CMYK(); +} + +// From CMYK +struct gmt_color CMYK2Gray() const +{ + return CMYK2RGB().RGB2Gray(); +} +struct gmt_color CMYK2RGB() const +{ + struct gmt_color color; + color.transparency=transparency; + color.model=RGB; + double cc=cyan/100.0,mm=magenta/100.0,yy=yellow/100.0,kk=black/100.0; + + color.r=255.0*(1.0-cc)*(1.0-kk); + color.g=255.0*(1.0-mm)*(1.0-kk); + color.b=255.0*(1.0-yy)*(1.0-kk); + + return color; +} +struct gmt_color CMYK2HSV() const +{ + return CMYK2RGB().RGB2HSV(); +} diff --git a/modules/gmt/modgmt_structs.h b/modules/gmt/modgmt_structs.h new file mode 100644 index 0000000..21c5b68 --- /dev/null +++ b/modules/gmt/modgmt_structs.h @@ -0,0 +1,382 @@ +#ifndef MODGMT_STRUCT_H +#define MODGMT_STRUCT_H +#include + +// Coordinate +struct gmt_coord +{ + 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) + { + size_t bpos=0,pos=str.find(':'); + if(std::string::npos==pos) + { + isdeg=false; + return str2double(str,&r); + } + + isdeg=true; + int64_t res; + + // degrees + if(! str2int(std::string(str.c_str(),str.c_str()+pos),&res) ) return false; + if(res>360 || res<-360) res%=360; + sign=(std::string::npos==str.find('-')); + d=static_cast(sign?res:-res); + // minutes + bpos=pos+1; + pos=str.find(':',bpos); + if(std::string::npos==pos) + { + if(!str2int(str.substr(bpos),&res)) return false; + if(res<0 || res>=60) return false; + m=static_cast(res); + s=0; + return true; + } + if(! str2int(std::string(str.c_str()+bpos,str.c_str()+pos),&res) ) return false; + if(res<0 || res>=60) return false; + m=static_cast(res); + // seconds + if(! str2double(str.substr(pos+1),&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 +{ + 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 +{ + // OBLIQMERCATOR types + enum class OType {A,B,C}; + // No UTM (-Ju) + enum projection {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 + + union // other projection parameters + { + // XY + struct {double height;} x; + // Cylindrical projections + // CYL_EQU (Cylindrical Equidistant -Jq) + struct {double stpar,cmer;} q; + // MERCATOR (-Jm) + struct {double stpar,cmer;} m; + // TRANSMERCATOR (-Jt) + struct {double cmer,orlat,scale;} t; + // OBLIQMERCATOR (-Jo) + struct + { + OType type; + double clon,clat; + union + { + double azimuth; // A + struct {double eqlon,eqlat;}; // B + struct {double polelon,polelat;}; // C + }; + } o; + // CASSINI (-Jc) + struct {double clon,clat;} c; + // CYL_EQA (Cylindrical equal-area -Jy) + struct {double stpar,cmer;} y; + // MILLER (-Jj) + struct {double cmer;} j; + // CYL_STERE (Cylindrical stereographic -Jcyl_stere) + struct {double stpar,cmer;} cyl_stere; + }; + std::string Value() const + { + switch(proj) + { + case(XY): return "-JX"+std::to_string(width)+"c/"+std::to_string(x.height)+"c"; + case(CYL_EQU): return "-JQ"+std::to_string(q.cmer)+"/"+std::to_string(q.stpar)+"/"+std::to_string(width)+"c"; + case(MERCATOR): return "-JM"+std::to_string(m.cmer)+"/"+std::to_string(m.stpar)+"/"+std::to_string(width)+"c"; + case(TRANSMERCATOR): return "-JT"+std::to_string(t.cmer)+"/"+std::to_string(t.orlat)+"/"+std::to_string(width)+"c --PROJ_SCALE_FACTOR="+std::to_string(t.scale); + case(OBLIQMERCATOR): + { + switch(o.type) + { + case(OType::A): return "-JOa"+std::to_string(o.clon)+"/"+std::to_string(o.clat)+"/"+std::to_string(o.azimuth)+"/"+std::to_string(width)+"c"; + case(OType::B): return "-JOb"+std::to_string(o.clon)+"/"+std::to_string(o.clat)+"/"+std::to_string(o.eqlon)+"/"+std::to_string(o.eqlat)+"/"+std::to_string(width)+"c"; + case(OType::C): return "-JOb"+std::to_string(o.clon)+"/"+std::to_string(o.clat)+"/"+std::to_string(o.polelon)+"/"+std::to_string(o.polelat)+"/"+std::to_string(width)+"c"; + } + } + case(CASSINI): return "-JC"+std::to_string(c.clon)+"/"+std::to_string(c.clat)+"/"+std::to_string(width)+"c"; + case(CYL_EQA): return "-JY"+std::to_string(y.stpar)+"/"+std::to_string(y.cmer)+"/"+std::to_string(width)+"c"; + case(MILLER): return "-JJ"+std::to_string(j.cmer)+"/"+std::to_string(width)+"c"; + case(CYL_STERE): return "-JCyl_stere"+std::to_string(cyl_stere.stpar)+"/"+std::to_string(cyl_stere.cmer)+"/"+std::to_string(width)+"c"; + } + return ""; + } +}; + + +// Color +struct gmt_color +{ + 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; + } + + 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; + } + + 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; + } + + 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; + } + // Transformation functions + private: +#include "colortransform.h" +}; + + +// Dash +struct gmt_dash +{ + std::vector dash; + double shift; + std::string Value() const + { + std::string ret; + if(dash.empty()) return ret; + for(auto i:dash) ret+=std::to_string(i)+"_"; + ret.back()=':'; + ret+=std::to_string(shift)+"c"; + return ret; + } + operator bool() const {return !dash.empty();} +}; + + +// Pen +struct gmt_pen +{ + double width; + struct gmt_color color; + struct gmt_dash dash; + std::string Value() const {return std::to_string(width)+","+color.Value()+(dash?(","+dash.Value()):"");} +}; +#endif