You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1270 lines
38 KiB

#include "modgmt_internals.h"
#include "modgmt_func.h"
ObjectBase* GMT_Header(const ObjectList* input)
{
return new ObjectString(header);
}
ObjectBase* GMT_Footer(const ObjectList* input)
{
return new ObjectString(footer);
}
template<template<typename> class Func, class... O>
class Base2Something: public OBTypeM<Func,O...>
{
Base2Something() = delete;
Base2Something(Base2Something&&) = delete;
Base2Something(Base2Something&) = delete;
public:
Base2Something(const ObjectBase* arg):OBTypeM<Func,O...>(arg) {};
Base2Something(const ObjectList* input, const std::string& name):OBTypeM<Func,O...>(input->Get(name)){};
Base2Something(const ObjectList* input, const ObjectList::ListValues::size_type i):OBTypeM<Func,O...>((i<input->Size())?input->At(i):0){}; // Check index, because At is not safe
auto operator ()(bool* b) const -> decltype(this->OBTypeM<Func,O...>::template operator()<bool*>(b))
{
if(!OBTypeM<Func,O...>::operator bool()) *b=false;
return OBTypeM<Func,O...>::operator ()(b);
}
};
// Converting Int, Real or String to double
template<class O>
class DoubleConv
{
public:
double operator ()(const O* q, bool* suc) const {return q->Value();}
};
template<>
class DoubleConv<ObjectString>
{
public:
double operator ()(const ObjectString* q, bool* suc) const {double d=0; *suc=(*suc) && str2double(q->Value(),&d); return d;}
};
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
{
public:
struct gmt_coord operator()(const O* o, bool* suc) const
{
struct gmt_coord c; *suc=(*suc) && c.Convert(o->Value()); return c;
}
};
// Special case is GMTCoord
template<>
class CoordConv<ObjectGMTCoord>
{
public:
struct gmt_coord operator()(const ObjectGMTCoord* o, bool* suc) const {return o->Data();}
};
typedef Base2Something<CoordConv,ObjectReal,ObjectInt,ObjectString,ObjectGMTCoord> Base2Coord;
// Converting List or String to GMTRegion
template<class O> class RegionConv
{
public:
struct gmt_region operator()(const O* o, bool* suc) const {*suc=false; return gmt_region();} // Must never used
};
// Conversion from List
template<>
class RegionConv<ObjectList>
{
public:
// Cases see in description of GMT_Region function
struct gmt_region operator()(const ObjectList* input, bool* issuc) const
{
struct gmt_region r;
auto size=input->Size();
if(1==size) // Cases 1, 2 and 3
{
const ObjectBase *arg=input->At(0);
OBType<ObjectGMTRegion> region(arg);
if(region) return r=region->Data(); // Case 1
OBType<ObjectString> string(arg);
if(string && r.Convert(string->Value())) return r; // Case 2
OBType<ObjectList> list(arg);
if(list) return r=operator()(list,issuc); // Case 3
*issuc=false;
return r; // Conversion failed
}
// Case 4
{
bool upd=false;
// Update case, arguments list contains parameter with type GMTRegion.
for(ObjectList::ListValues::size_type i=0;i<size;i++)
{
OBType<ObjectGMTRegion> region(input->At(i));
if(region)
{
if(upd){*issuc=false; return r;} // We already have region to update
r=region->Data();
upd=true;
}
}
// Update case, arguments list contains parameter region.
if(0!=input->Get("region"))
{
if(upd) {*issuc=false; return r;} // We already have region to update
ObjectList* list=new ObjectList;
list->PushBack(input->Get("region"));
r=operator()(list,issuc);
delete list;
if(!*issuc) return r; // Fail to convert
upd=true;
}
OBType<ObjectString> type(input->Get("type"));
if(type && r.Convert(type->Value())) return r; // type is one of "global*" string, we can return, becuse upd is irrelevant
Base2Coord ixb(input,"xb"), ixe(input,"xe"), iyb(input,"yb"), iye(input,"ye");
bool suc=true;
struct gmt_coord xb=ixb(&suc),yb=iyb(&suc),xe=ixe(&suc),ye=iye(&suc);
bool isbbox=upd?(gmt_region::BBOX==r.type):false;
if(type)
{
std::string s=type->Value();
tolower(s);
if("bbox"==s) isbbox=true;
if("nobbox"==s) isbbox=false;
if("bbox"!=s && "nobbox"!=s) suc=false; // Unknown type
}
if(upd)
{
if(!ixb.Exist()) xb=r.xb;
if(!ixe.Exist()) xe=r.xe;
if(!iyb.Exist()) yb=r.yb;
if(!iye.Exist()) ye=r.ye;
}
else suc=suc && ixb && ixe && iyb && iye; // In "new" mode all parameters must exists and have correct type
if(ixb.Exist()) xb=ixb(&suc);
if(ixe.Exist()) xe=ixe(&suc);
if(iyb.Exist()) yb=iyb(&suc);
if(iye.Exist()) ye=iye(&suc);
if(suc)
{
if(!r.Convert(xb,xe,yb,ye,isbbox)) *issuc=false;
return r; // Case 3 with all parameters
}
}
// Case 5
if(4==size || 5==size)
{
bool isbbox=false;
if(5==size)
{
OBType<ObjectString> type(input->At(4));
if(!type) {*issuc=false; return r;} // Unknown fifth parameter
std::string str=type->Value();
tolower(str);
if("bbox"!=str || "nobbox"!=str) {*issuc=false; return r;} // Unknown fifth parameter
if("bbox"==str) isbbox=true;
}
Base2Coord ixb(input,0), ixe(input,(isbbox?2:1)), iyb(input,(isbbox?1:2)), iye(input,3);
bool suc=true;
struct gmt_coord xb=ixb(&suc),yb=iyb(&suc),xe=ixe(&suc),ye=iye(&suc);
if(ixb && ixe && iyb && iye && suc)
{
if(!r.Convert(xb,xe,yb,ye,isbbox)) *issuc=false;
return r; // Case 4 with all parameters
}
}
*issuc=false;
return r; // Something go wrong
}
};
// Conversion from String
template<>
class RegionConv<ObjectString>
{
public:
struct gmt_region operator()(const ObjectString* input, bool* issuc) const
{
struct gmt_region r;
if(!r.Convert(input->Value())) *issuc=false;
return r;
}
};
// Special case is GMTRegion
template<>
class RegionConv<ObjectGMTRegion>
{
public:
struct gmt_region operator()(const ObjectGMTRegion* o, bool* suc) const {return o->Data();}
};
typedef Base2Something<RegionConv,ObjectList,ObjectString,ObjectGMTRegion> Base2Region;
// Converting List to GMTProjection
template<class O> class ProjConv
{
public:
struct gmt_projection operator()(const O* o, bool* suc) const {*suc=false; return gmt_projection();} // Must never used
};
// Conversion from List
template<>
class ProjConv<ObjectList>
{
public:
// Cases see in description of GMT_Projection function
struct gmt_projection operator()(const ObjectList* input, bool* issuc) const
{
struct gmt_projection p;
auto size=input->Size();
if(1==size) // Cases 1, and 2
{
const ObjectBase *arg=input->At(0);
OBType<ObjectGMTProjection> proj(arg);
if(proj) return p=proj->Data(); // Case 1
OBType<ObjectList> list(arg);
if(list) return p=operator()(list,issuc); // Case 2
goto fail; // Conversion failed
}
// Case 3
{
bool upd=false;
bool longisproj=false; // "projection" is good defined projection
bool shortisproj=false; // "proj" is good defined projection
bool changetype=false; // Projection type was specified in update mode. If new type is same as old type parameters of projection reset to default for this type.
// Update case, arguments list contains parameter with type GMTProjection.
for(ObjectList::ListValues::size_type i=0;i<size;i++)
{
OBType<ObjectGMTProjection> proj(input->At(i));
if(proj)
{
if(upd) goto fail; // Only one projection in list allowed
p=proj->Data();
upd=true;
}
}
// Update case, arguments list contains parameter proj or projection and this parameter is projection.
{
const ObjectBase* prg;
prg=input->Get("projection");
if(0!=prg)
{
struct gmt_projection ps;
bool suc=true;
ObjectList* list=new ObjectList;
list->PushBack(prg->Copy());
ps=operator()(list,&suc);
delete list;
if(suc)
{
if(upd) goto fail; // Already have projection to update
upd=true;
longisproj=true;
p=ps;
}
}
prg=input->Get("proj");
if(0!=prg)
{
struct gmt_projection ps;
bool suc=true;
ObjectList* list=new ObjectList;
list->PushBack(prg->Copy());
ps=operator()(list,&suc);
delete list;
if(suc)
{
if(upd) goto fail; // Already have projection to update
upd=true;
shortisproj=true;
p=ps;
}
}
}
// Try to set type of projection
{
OBType<ObjectString> type1(input->Get("projtype"));
OBType<ObjectString> type2(input->Get("projection"));
OBType<ObjectString> type3(input->Get("proj"));
if(!(type1.Exist() || type2.Exist() || type3.Exist() || upd)) goto case4; // No named parameter, not update mode, go to case 4
// Check on redundant parameters
if(type1.Exist() && type2.Exist() && type3.Exist()) goto fail; // Too many variants
if(type1.Exist() && type2.Exist() && !type3.Exist() && !longisproj) goto fail; // "projtype" and "projection" exists, but "projection" is not parse to Projection
if(type1.Exist() && !type2.Exist() && type3.Exist() && !shortisproj) goto fail; // "projtype" and "proj" exists, but "proj" is not parse to Projection
if(!type1.Exist() && type2.Exist() && type3.Exist() && !(shortisproj || longisproj)) goto fail; // "projection" and "proj" exists, but no one is parse to Projection
// Check on type correctness
if(type1.Exist() && !type1) goto fail; // "projtype" is not String
if(type2.Exist() && !type2 && !longisproj) goto fail; // "projection" is not String or Projection
if(type3.Exist() && !type3 && !shortisproj) goto fail; // "proj" is not String or Projection
bool suc=false;
if(!(type1 || type2 || type3)) // No String parameter
{
if(!upd) goto fail; // No type - no projection
changetype=false;
}
else
{
changetype=true;
if(!suc && type1) suc=p.SetType(type1->Value());
if(!suc && type2) suc=p.SetType(type2->Value());
if(!suc && type3) suc=p.SetType(type3->Value());
if(!suc) goto fail; // Incorrect projection type
}
}
// We need the region
{
Base2Region reg(input,"region");
// Try to find named parameter
if(reg.Exist())
{
bool suc=true;
p.region=reg(&suc);
if(!suc) goto fail; // Conversion failed
}
else
{
bool suc=false;
for(ObjectList::ListValues::size_type i=0;i<input->Size();i++)
{
OBType<ObjectGMTRegion> reg(input->At(i));
if(reg)
{
if(suc) goto fail; // Too many regions
p.region=reg->Data();
suc=true;
}
}
if(!suc && !upd) goto fail; // No such objects found in "new" mode
}
}
// Get parameters of projection
switch(p.proj)
{
case(gmt_projection::XY): // x Parameter height (by default equal width)
{
Base2Double height(input,"height");
if(height.Exist())
{
bool suc=true;
p.x.height=height(&suc);
if(!suc) goto fail; // Parsing error
}
else
{
Base2Double width(input,"width");
if(!width && changetype) p.x.height=gmt_projection::default_width; // We ignore case when parameter width exists but have wrong type. It will be handled later.
else
{
bool suc=true;
p.x.height=width(&suc);
if(!suc) goto fail; // Parsing error
}
}
break;
}
case(gmt_projection::CYL_EQU): // q Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region)
{
Base2Coord cmer(input,"cmer"), stpar(input,"stpar");
if(cmer.Exist())
{
bool suc=true;
p.q.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.q.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.q.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.q.stpar.Convert((p.region.yb+p.region.ye)*0.5);
break;
}
case(gmt_projection::MERCATOR): // m Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region)
{
Base2Coord cmer(input,"cmer"), stpar(input,"stpar");
if(cmer.Exist())
{
bool suc=true;
p.m.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.m.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.m.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.m.stpar.Convert((p.region.yb+p.region.ye)*0.5);
break;
}
case(gmt_projection::TRANSMERCATOR): // t Parameters: central meridian (cmer, default is center of region), latitude of origin (orlat, default is 0.0), scale factor (scale, default is 1.0)
{
Base2Coord cmer(input,"cmer"), orlat(input,"orlat");
Base2Double scale(input,"scale");
if(cmer.Exist())
{
bool suc=true;
p.t.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.t.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(orlat.Exist())
{
bool suc=true;
p.t.orlat=orlat(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.t.orlat.Convert(0.0);
if(scale.Exist())
{
bool suc=true;
p.t.scale=scale(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.t.scale=1.0;
break;
}
case(gmt_projection::OBLIQMERCATOR): // o Parameters: longitude of projection center (clon, default is center of region), latitude of projection center (clat, default is center of region). Other parameters may form one of three combinations and doesn't have default values. 1) Azimuth of the oblique equator (azimuth). 2) Longitude and latitude of second point on oblique equator (eqlon, eqlat). 3) Longitude and latitude of projection pole (polelon, polelat).
{
Base2Coord clon(input,"clon"), clat(input,"clat");
Base2Coord azimuth(input,"azimuth"), eqlon(input,"eqlon"), eqlat(input,"eqlat"), polelon(input,"polelon"), polelat(input,"polelat");
if(changetype) p.o.type=gmt_projection::OType::NOTDEF;
if(clon.Exist())
{
bool suc=true;
p.o.clon=clon(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.o.clon.Convert((p.region.xb+p.region.xe)*0.5);
if(clat.Exist())
{
bool suc=true;
p.o.clat=clat(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.o.clat.Convert((p.region.yb+p.region.ye)*0.5);
// Variant 1
if(azimuth)
{
p.o.type=gmt_projection::OType::A;
bool suc=true;
p.o.azimuth=azimuth(&suc);
if(!suc) goto fail; // Parsing error
}
if(eqlon && eqlat)
{
p.o.type=gmt_projection::OType::B;
bool suc=true;
p.o.eqlon=eqlon(&suc);
p.o.eqlat=eqlat(&suc);
if(!suc) goto fail; // Parsing error
}
if(polelon && polelat)
{
p.o.type=gmt_projection::OType::C;
bool suc=true;
p.o.polelon=polelon(&suc);
p.o.polelat=polelat(&suc);
if(!suc) goto fail; // Parsing error
}
if(gmt_projection::OType::NOTDEF==p.o.type) goto fail; // Insufficient data for this projection
break;
}
case(gmt_projection::CASSINI): // c Parameters: longitude (clon, default is center of region) and latitude (clat, default is center of region) of central point.
{
Base2Coord clon(input,"clon"), clat(input,"clat");
if(clon.Exist())
{
bool suc=true;
p.c.clon=clon(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.c.clon.Convert((p.region.xb+p.region.xe)*0.5);
if(clat.Exist())
{
bool suc=true;
p.c.clat=clat(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.c.clat.Convert((p.region.yb+p.region.ye)*0.5);
break;
}
case(gmt_projection::CYL_EQA): // y Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region)
{
Base2Coord cmer(input,"cmer"), stpar(input,"stpar");
if(cmer.Exist())
{
bool suc=true;
p.y.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.y.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.y.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.y.stpar.Convert((p.region.yb+p.region.ye)*0.5);
break;
}
case(gmt_projection::MILLER): // j Parameters: central meridian (cmer, default is center of region)
{
Base2Coord cmer(input,"cmer");
if(cmer.Exist())
{
bool suc=true;
p.j.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.j.cmer.Convert((p.region.xb+p.region.xe)*0.5);
break;
}
case(gmt_projection::CYL_STERE): // cyl_stere Parameters: central meridian (cmer, default is center of region), standart parallel (stpar, default is center of region)
{
Base2Coord cmer(input,"cmer"), stpar(input,"stpar");
if(cmer.Exist())
{
bool suc=true;
p.cyl_stere.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.cyl_stere.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.cyl_stere.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else if(changetype) p.cyl_stere.stpar.Convert((p.region.yb+p.region.ye)*0.5);
break;
}
default: goto fail; // Unknown projection
}
// Try to find width parameter
if(!upd) p.width=p.default_width;
{
Base2Double w(input,"width"),h(input,"height");
bool suc=true;
if(w.Exist()) // width is present
{
p.width=w(&suc);
if(!suc) goto fail; // Parameter width exists, but can't be converted to double
if(!ProjectionRealSize(p)) goto fail; // Something go wrong with determining real dimensions
}
else if(h.Exist()) // width is not present, but height is present
{
double hval=h(&suc);
if(!suc) goto fail; // Parameter height exists, but can't be converted to double
if(gmt_projection::XY==p.proj) p.width=hval; // For decart projection we use height as width if width is not specified
if(!ProjectionRealSize(p,hval)) goto fail; // Something go wrong with determining real dimensions
}
else // No width, no height, using default or old width
if(!ProjectionRealSize(p)) goto fail; // Something go wrong with determining real dimensions
}
return p; // All parameters setted
}
case4:
// Case 4
if(size>=3)
{
// First argument, try to set type of projection
{
OBType<ObjectString> type(input->At(0));
if(!type) goto fail; // No type - no projection
if(!p.SetType(type->Value())) goto fail; // Unknown type - no projection
}
// Second argument, set up width
{
Base2Double w(input,1);
bool suc=true;
p.width=w(&suc);
if(!suc) goto fail; // Conversion failed, no width
}
// Third argument, set up region
{
Base2Region reg(input,2);
bool suc=true;
p.region=reg(&suc);
if(!suc) goto fail; // Conversion failed, no region
}
// Projection specific parameters
switch(p.proj)
{
case(gmt_projection::XY): // x Parameter 4 is height (by default equal width)
{
Base2Double height(input,3);
if(height.Exist())
{
bool suc=true;
p.x.height=height(&suc);
if(!suc) goto fail; // Parsing error
}
else p.x.height=p.width;
if(size>4) goto fail; // Unknown parameter(s)
break;
}
case(gmt_projection::CYL_EQU): // q Parameters: 4 is central meridian (default is center of region), 5 is standart parallel (default is center of region)
{
Base2Coord cmer(input,3), stpar(input,4);
if(cmer.Exist())
{
bool suc=true;
p.q.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else p.q.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.q.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else p.q.stpar.Convert((p.region.yb+p.region.ye)*0.5);
if(size>5) goto fail; // Unknown parameter(s)
break;
}
case(gmt_projection::MERCATOR): // m Parameters: 4 is central meridian (default is center of region), 5 is standart parallel (default is center of region)
{
Base2Coord cmer(input,3), stpar(input,4);
if(cmer.Exist())
{
bool suc=true;
p.m.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else p.m.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.m.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else p.m.stpar.Convert((p.region.yb+p.region.ye)*0.5);
if(size>5) goto fail; // Unknown parameter(s)
break;
}
case(gmt_projection::TRANSMERCATOR): // t Parameters: 4 is central meridian (default is center of region), 5 is latitude of origin (default is 0.0), 6 is scale factor (default is 1.0)
{
Base2Coord cmer(input,3), orlat(input,4);
Base2Double scale(input,5);
if(cmer.Exist())
{
bool suc=true;
p.t.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else p.t.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(orlat.Exist())
{
bool suc=true;
p.t.orlat=orlat(&suc);
if(!suc) goto fail; // Parsing error
}
else p.t.orlat.Convert(0.0);
if(scale.Exist())
{
bool suc=true;
p.t.scale=scale(&suc);
if(!suc) goto fail; // Parsing error
}
else p.t.scale=1.0;
if(size>6) goto fail; // Unknown parameter(s)
break;
}
case(gmt_projection::OBLIQMERCATOR): // o There is no default values for this projection. Parameters: 4 is subtype ("a" or "azimuth", "b" or "equator", "c" or "pole"), 5 is longitude of projection center, 6 is latitude of projection center. Other parameters may form one of three combinations. 1) 7 is azimuth of the oblique equator. 2) Longitude and latitude of second point on oblique equator (7, 8). 3) Longitude and latitude of projection pole (7, 8).
{
if(size<4) goto fail; // Insufficient data for this projection
OBType<ObjectString> stype(input->At(3));
if(!stype) goto fail; // Incorrect parameter type
std::string subtype=stype->Value();
tolower(subtype);
Base2Coord clon(input,4), clat(input,5);
Base2Coord azimuth(input,6), eqlon(input,6), eqlat(input,7), polelon(input,6), polelat(input,7);
p.o.type=gmt_projection::OType::NOTDEF;
{
bool suc=true;
p.o.clon=clon(&suc);
p.o.clat=clat(&suc);
if(!suc) goto fail; // Parsing error
}
// Variant 1
if("a"==subtype || "azimuth"==subtype)
{
p.o.type=gmt_projection::OType::A;
bool suc=true;
p.o.azimuth=azimuth(&suc);
if(!suc) goto fail; // Parsing error
if(size>7) goto fail; // Unknown parameter(s)
}
if("b"==subtype || "equator"==subtype)
{
p.o.type=gmt_projection::OType::B;
bool suc=true;
p.o.eqlon=eqlon(&suc);
p.o.eqlat=eqlat(&suc);
if(!suc) goto fail; // Parsing error
if(size>8) goto fail; // Unknown parameter(s)
}
if("c"==subtype || "pole"==subtype)
{
p.o.type=gmt_projection::OType::C;
bool suc=true;
p.o.polelon=polelon(&suc);
p.o.polelat=polelat(&suc);
if(!suc) goto fail; // Parsing error
if(size>8) goto fail; // Unknown parameter(s)
}
if(gmt_projection::OType::NOTDEF==p.o.type) goto fail; // Insufficient data for this projection
break;
}
case(gmt_projection::CASSINI): // c Parameters: longitude (4, default is center of region) and latitude (5, default is center of region) of central point.
{
Base2Coord clon(input,3), clat(input,4);
if(clon.Exist())
{
bool suc=true;
p.c.clon=clon(&suc);
if(!suc) goto fail; // Parsing error
}
else p.c.clon.Convert((p.region.xb+p.region.xe)*0.5);
if(clat.Exist())
{
bool suc=true;
p.c.clat=clat(&suc);
if(!suc) goto fail; // Parsing error
}
else p.c.clat.Convert((p.region.yb+p.region.ye)*0.5);
if(size>5) goto fail; // Unknown parameter(s)
break;
}
case(gmt_projection::CYL_EQA): // y Parameters: central meridian (4, default is center of region), standart parallel (5, default is center of region)
{
Base2Coord cmer(input,3), stpar(input,4);
if(cmer.Exist())
{
bool suc=true;
p.y.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else p.y.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.y.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else p.y.stpar.Convert((p.region.yb+p.region.ye)*0.5);
if(size>5) goto fail; // Unknown parameter(s)
break;
}
case(gmt_projection::MILLER): // j Parameters: central meridian (4, default is center of region)
{
Base2Coord cmer(input,3);
if(cmer.Exist())
{
bool suc=true;
p.j.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else p.j.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(size>4) goto fail; // Unknown parameter(s)
break;
}
case(gmt_projection::CYL_STERE): // cyl_stere Parameters: central meridian (3, default is center of region), standart parallel (4, default is center of region)
{
Base2Coord cmer(input,3), stpar(input,4);
if(cmer.Exist())
{
bool suc=true;
p.cyl_stere.cmer=cmer(&suc);
if(!suc) goto fail; // Parsing error
}
else p.cyl_stere.cmer.Convert((p.region.xb+p.region.xe)*0.5);
if(stpar.Exist())
{
bool suc=true;
p.cyl_stere.stpar=stpar(&suc);
if(!suc) goto fail; // Parsing error
}
else p.cyl_stere.stpar.Convert((p.region.yb+p.region.ye)*0.5);
if(size>5) goto fail; // Unknown parameter(s)
break;
}
default: goto fail; // Unknown projection
}
if(ProjectionRealSize(p)) return p;
}
fail:
*issuc=false;
return p; // Something go wrong
}
};
// Special case is GMTProjection
template<>
class ProjConv<ObjectGMTProjection>
{
public:
struct gmt_projection operator()(const ObjectGMTProjection* o, bool* suc) const {return o->Data();}
};
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.
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
*/
ObjectBase* GMT_Coord(const ObjectList* input)
{
if(input->Size()!=1) return 0;
Base2Coord a(input,0);
struct gmt_coord c;
bool suc=true;
c=a(&suc);
if(a && suc) return new ObjectGMTCoord(c);
else return 0;
}
/*
Input:
1) One argument, Region. Return copy of this argument.
2) One argument, case insensitive string "global180" (global domain -R-180/180/-90/90), "global360" (global domain -R0/360/-90/90) or "global" (synonym of "global360").
3) One argument, list. Recursively calling GMT_Region.
4) Pairs list. Names are xb, xe, yb, ye, and, optionally, type="bbox|nobbox|global180|global360|global". Names are case sensitive, values can be Int, Real, String or GMTCoord.
If pair with name region exists in list, when recursively calling GMT_Region on the value of this parameter, when modify it with specified parameters.
If argument with type Region exists in list, when copy it and modify with specified parameters.
5) 4 or 5 parameters. Fifth parameter can be "bbox" or "nobbox" (default). If fifth parameter is string "bbox", when first four parameters interprets as xb,yb,xe,ye, else as xb,xe,yb,ye.
*/
ObjectBase* GMT_Region(const ObjectList* input)
{
bool suc=true;
struct gmt_region r=RegionConv<ObjectList>()(input,&suc);
if(suc) return new ObjectGMTRegion(r);
else return 0;
}
/*
Input:
1) One argument, Projection. Return copy of this argument.
2) One argument, list. Recursively calling GMT_Projection.
3) Pairs list. Names are projtype (string), region (GMTRegion, string or list, which can be converted to GMTRegion),
width (or height) in centimeters (may be absent, default width is 10 cm) and projection-dependent parameters.
Pair with name region may absent, in this case search in list and using as region object with ObjectGMTRegion type.
If pair with name proj (or projection) exists in list, when recursively calling GMT_Projection on the value of this parameter, when modify it with specified parameters.
If argument with type Projection exists in list, when copy it and modify with specified parameters.
4) 3 or more parameters. First parameter is projection type (string), second - width in centimeters,
third - region (any type which can be converted to GMTRegion), other parameters are projection-dependent.
Height can be set only in form 3.
*/
ObjectBase* GMT_Projection(const ObjectList* input)
{
bool suc=true;
struct gmt_projection p=ProjConv<ObjectList>()(input,&suc);
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;
}