From 8c2f0c6ef8ea624d8b642bf2710b31760d5dc9e7 Mon Sep 17 00:00:00 2001 From: Michael Uleysky Date: Tue, 3 Nov 2015 13:24:11 +1000 Subject: [PATCH] Gmt module: Add function Pen. --- modules/gmt/modgmt.cpp | 1 + modules/gmt/modgmt_func.cpp | 239 +++++++++++++++++++++++++++++++++++ modules/gmt/modgmt_func.h | 1 + modules/gmt/modgmt_structs.h | 94 +++++++++++++- 4 files changed, 333 insertions(+), 2 deletions(-) diff --git a/modules/gmt/modgmt.cpp b/modules/gmt/modgmt.cpp index 0982be7..222aa9c 100644 --- a/modules/gmt/modgmt.cpp +++ b/modules/gmt/modgmt.cpp @@ -36,5 +36,6 @@ int gmt_module_init(void* p) RegisterFunction("ColorRGB",GMT_ColorRGB); RegisterFunction("ColorHSV",GMT_ColorHSV); RegisterFunction("ColorCMYK",GMT_ColorCMYK); + RegisterFunction("Pen",GMT_Pen); return 0; } diff --git a/modules/gmt/modgmt_func.cpp b/modules/gmt/modgmt_func.cpp index 43dd00b..825caf1 100644 --- a/modules/gmt/modgmt_func.cpp +++ b/modules/gmt/modgmt_func.cpp @@ -1122,6 +1122,225 @@ class ColorConv } }; +// Helper types +typedef GetDouble,PDefaultVal<>> Base2Width; +typedef GetDouble,PMultiInputNames> BaseM2Width; + +// Converting String to GMTDash +template class DashConv +{ + public: + struct gmt_dash operator()(const O* o, bool* issuc, const double& w) const + { + struct gmt_dash d; + if(!d.Convert(o->Value(),w)) *issuc=false; + return d; + } +}; +// Special case is GMTDash +template<> +class DashConv +{ + public: + struct gmt_dash operator()(const ObjectGMTDash* o, bool* suc, const double& w) const {return o->Data();} +}; +typedef Base2Something Base2Dash; + +// Converting List to GMTPen +template class PenConv +{ + public: + struct gmt_pen operator()(const O* o, bool* issuc) const + { + struct gmt_pen p; + if(!p.Convert(o->Value())) *issuc=false; + return p; + } +}; +// Special case is GMTPen +template<> +class PenConv +{ + public: + struct gmt_pen operator()(const ObjectGMTPen* o, bool* suc) const {return o->Data();} +}; +typedef Base2Something Base2Pen; +// Conversion from List +template<> +class PenConv +{ + public: + // Cases see in description of GMT_Pen function + struct gmt_pen operator()(const ObjectList* input, bool* issuc) const + { + struct gmt_pen p; + auto size=input->Size(); + + if(1==size) // Cases 1, 2 and 4 + { + Base2Pen a(input,0); + bool suc=true; + p=a(&suc); + if(suc) return p; + goto fail; + } + + // Case 3 + { + bool upd=false; + bool casevalid=false; + + // Update case, arguments list contains parameter with type GMTPen. + for(ObjectList::ListValues::size_type i=0;i pen(input->At(i)); + if(pen) + { + if(upd) goto fail; // Only one pen in list allowed + p=pen->Data(); + upd=true; + } + } + + // Update case, arguments list contains parameter p or pen. + { + Base2Pen pshort(input,"p"); + Base2Pen plong(input,"pen"); + if(pshort.Exist() && plong.Exist()) goto fail; // Only one parameter allowed + if(pshort.Exist()) + { + if(upd) goto fail; // Already have pen to update + bool suc=true; + upd=true; + p=pshort(&suc); + if(!suc) goto fail; // Parse error + } + if(plong.Exist()) + { + if(upd) goto fail; // Already have pen to update + upd=true; + bool suc=true; + p=plong(&suc); + if(!suc) goto fail; // Parse error + } + } + if(!upd) + { + // default pen is solid black 1mm width + p.width=1; + p.color.Convert(0); + p.dash.Clear(); + } + + { + BaseM2Width w(input,"w","width"); + if(w.Exist()) + { + bool suc=true; + p.width=w(&suc); + if(!suc) goto fail; // Parsing error + casevalid=true; + } + } + + // Color + { + bool havec=false; + // Find parameter with type GMTColor. + for(ObjectList::ListValues::size_type i=0;i c(input->At(i)); + if(c) + { + if(havec) goto fail; // Only one color in list allowed + p.color=c->Data(); + havec=true; + } + } + Base2Color sh(input,"c"), lo(input,"color"); + if(sh.Exist() && lo.Exist()) goto fail; // Only one parameter allowed + if(sh.Exist()) + { + if(havec) goto fail; // Already have color + havec=true; + bool suc=true; + p.color=sh(&suc); + if(!suc) goto fail; // Parsing error + } + if(lo.Exist()) + { + if(havec) goto fail; // Already have color + havec=true; + bool suc=true; + p.color=lo(&suc); + if(!suc) goto fail; // Parsing error + } + if(havec) casevalid=true; + } + + // Dash + { + bool haved=false; + // Find parameter with type GMTDash. + for(ObjectList::ListValues::size_type i=0;i d(input->At(i)); + if(d) + { + if(haved) goto fail; // Only one color in list allowed + p.dash=d->Data(); + haved=true; + } + } + Base2Dash sh(input,"d"), lo(input,"dash"); + if(sh.Exist() && lo.Exist()) goto fail; // Only one parameter allowed + if(sh.Exist()) + { + if(haved) goto fail; // Already have color + haved=true; + bool suc=true; + p.dash=sh(&suc,p.width); + if(!suc) goto fail; // Parsing error + } + if(lo.Exist()) + { + if(haved) goto fail; // Already have color + haved=true; + bool suc=true; + p.dash=lo(&suc,p.width); + if(!suc) goto fail; // Parsing error + } + if(haved) casevalid=true; + } + + if(casevalid || upd) return p; // Pen created or updated + } + + // Case 5 and 6 + if(2==size || 3==size) + { + Base2Width w(input,0); + Base2Color c(input,1); + Base2Dash d(input,2); + bool suc=true; + if(w && c) + { + p.width=w(&suc); + p.color=c(&suc); + } + else goto fail; // Something wrong + if(d) p.dash=d(&suc,p.width); + if(!suc) goto fail; // Something wrong + return p; + } + + fail: + *issuc=false; + return p; // Something go wrong + } +}; + + /* Input is one argument, Int, Real, String or GMTCoord. ObjectString can be number or in form "dd:mm[:ss]", where dd is degrees from -360 to 360, mm is minutes from 0 to 59 @@ -1269,3 +1488,23 @@ ObjectBase* GMT_ColorCMYK(const ObjectList* input) if(suc) return new ObjectGMTColor(c); else return 0; } + +/* +Input: +1) One argument, Pen. Return copy of this argument. +2) One argument, list. Recursively calling GMT_Pen. +3) Pairs list. Names are width (w), color(c), dash(f). Default values is 1 for width, black for color and solid for dash. +If pair with name pen(p) exists in list, when recursively calling GMT_Line on the value of this parameter, when modify it with specified parameters. +If argument with type Pen exists in list, when copy it and modify with specified parameters. +Instead of color and dash unnamed parameters with Color and Dash types may be used. +4) One argument, interprets as width of black solid line. +5) Two arguments, interprets as width and color of solid line. +6) Three arguments, interprets as width, color and dash. +*/ +ObjectBase* GMT_Pen(const ObjectList* input) +{ + bool suc=true; + struct gmt_pen p=PenConv()(input,&suc); + if(suc) return new ObjectGMTPen(p); + else return 0; +} diff --git a/modules/gmt/modgmt_func.h b/modules/gmt/modgmt_func.h index 1cf31cd..2f34305 100644 --- a/modules/gmt/modgmt_func.h +++ b/modules/gmt/modgmt_func.h @@ -12,5 +12,6 @@ ObjectBase* GMT_ColorGray(const ObjectList* input); ObjectBase* GMT_ColorRGB(const ObjectList* input); ObjectBase* GMT_ColorHSV(const ObjectList* input); ObjectBase* GMT_ColorCMYK(const ObjectList* input); +ObjectBase* GMT_Pen(const ObjectList* input); #endif diff --git a/modules/gmt/modgmt_structs.h b/modules/gmt/modgmt_structs.h index fadfa4b..ecd2551 100644 --- a/modules/gmt/modgmt_structs.h +++ b/modules/gmt/modgmt_structs.h @@ -601,6 +601,8 @@ struct gmt_color #include "modgmt_colortransform.h" }; +// Helper types for pens +typedef GetDouble,PFromValue> Value2Width; // Dash struct gmt_dash @@ -611,12 +613,54 @@ struct gmt_dash { std::string ret; if(dash.empty()) return ret; - for(auto i:dash) ret+=std::to_string(i)+"_"; + for(auto i:dash) ret+=std::to_string(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;} + + bool Convert(const std::string& in, const double& w) + { + Clear(); + shift=0; + if(0==in.size()) return true; // No dash + if(std::string::npos==in.find_first_not_of(".-")) // dot-dash form + { + double width=(0==w)?1:w; + for(const auto& i:in) + { + if('.'==i) dash.push_back(width); // Dot + else dash.push_back(8*width); // Dash + dash.push_back(4*width); // 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; + } }; @@ -626,6 +670,52 @@ 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()):"");} + 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=1; + 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