Compare commits

..

2 Commits

  1. 34
      dotests
  2. 3
      include/builtin.h
  3. 80
      include/common.h
  4. 34
      maketest
  5. 130
      modules/gmt/cmpstr.c++
  6. 287
      modules/gmt/cmpstr_alt.c++
  7. 1926
      modules/gmt/modgmt_colornames.cpp
  8. 54
      modules/gmt/modgmt_colornames.h
  9. 380
      modules/gmt/modgmt_func.cpp
  10. 1467
      modules/gmt/modgmt_func.h
  11. 5
      modules/gmt/modgmt_gsfuncs.cpp
  12. 4
      modules/gmt/modgmt_gsfuncs.h
  13. 5
      modules/gmt/modgmt_internals.cpp
  14. 345
      modules/gmt/modgmt_map.cpp
  15. 23
      modules/gmt/modgmt_map.h
  16. 40
      modules/gmt/modgmt_objects.cpp
  17. 297
      modules/gmt/modgmt_param.h
  18. 139
      modules/gmt/modgmt_strcomp.cpp
  19. 98
      modules/gmt/modgmt_strcomp.h
  20. 223
      modules/gmt/modgmt_structs.h
  21. 4
      src/globals.cpp
  22. 2
      src/object.cpp
  23. 11
      tests/GMTCoord
  24. 8
      tests/GMTCoord_e1
  25. 18
      tests/GMTProjection
  26. 10
      tests/GMTRegion1
  27. 9
      tests/GMTRegion2
  28. 13
      tests/GMTRegion3
  29. 8
      tests/GMTRegion_e1

34
dotests

@ -1,34 +0,0 @@
#!/bin/bash
MAKEMAP="${1:-/tmp/save/build/src/makemap}"
TPATH=tests
SCRW=`tput cols`
set -o pipefail
for n in "$TPATH"/*; do
status=`cat $n|grep "# Status: "|sed "s/# Status: //"`
desc=`cat $n|grep "# Description: "|sed "s/# Description: //"`
hash=`cat $n|grep "# Output hash: "|sed "s/.*: //"`
while [ ${#desc} -lt $((SCRW-5)) ]; do desc+=" "; done
echo -n "$desc"
t=`mktemp`
grep -v -E "# .*: " "$n">$t
thash=`$MAKEMAP "$t" 2>&1 | sha256sum|sed "s/ .*//"`
ret=$?
if [ "$status" == "ok" ]; then
if [ "$hash" == "$thash" -a "$ret" == "0" ]; then
echo -e "\033[32mOk \033[0m"
else
echo -e "\033[31mFail\033[0m"
fi
else
if [ "$hash" == "$thash" -a "$ret" != "0" ]; then
echo -e "\033[32mOk \033[0m"
else
echo -e "\033[31mFail\033[0m"
fi
fi
rm $t
done

3
include/builtin.h

@ -1,5 +1,3 @@
#ifndef BUILTIN_H
#define BUILTIN_H
#include <cmath> #include <cmath>
#include "object.h" #include "object.h"
@ -116,4 +114,3 @@ const ObjectBase* Arifm1(const ObjectList* input)
return new ObjectError("Arifmetic unary operator","unknown error"); // Impossible case return new ObjectError("Arifmetic unary operator","unknown error"); // Impossible case
} }
#endif

80
include/common.h

@ -7,10 +7,8 @@
#include <list> #include <list>
#include <memory> #include <memory>
#include <set> #include <set>
#include <stack>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <tuple>
#include <typeindex> #include <typeindex>
#include <typeinfo> #include <typeinfo>
@ -278,80 +276,13 @@ public:
// Class for objects list // Class for objects list
class EXPORT ObjectList: public ObjectBase class EXPORT ObjectList: public ObjectBase
{ {
private: public:
typedef std::deque<const ObjectBase*> ListValues; typedef std::deque<const ObjectBase*> ListValues;
public: private:
typedef ListValues::size_type IndexType;
private:
// Forward iterator for ObjectList (may be later be bidirectional)
class ObjectListIterator: public std::iterator<std::forward_iterator_tag, const ObjectBase*>
{
const ObjectList* list;
std::stack<std::tuple<const ObjectList*, IndexType> > st;
IndexType pos;
void Increment()
{
while(true)
{
OBType<ObjectList> islist(list->At(pos));
if(islist && islist->Size()>0)
{
st.emplace(std::make_tuple(list,pos));
list=islist;
pos=0;
}
else return;
}
}
public:
ObjectListIterator():list(nullptr),pos(0) {}
ObjectListIterator(const ObjectListIterator&) = default;
ObjectListIterator(ObjectListIterator&&) = default;
ObjectListIterator(const ObjectList* l):list(l),pos(0) {if(list) Increment();}
bool operator ==(const ObjectListIterator& i) const {return (list==i.list && pos==i.pos);}
bool operator !=(const ObjectListIterator& i) const {return !operator==(i);}
ObjectListIterator& operator++()
{
if(pos<list->Size()-1)
{
pos++;
Increment();
return *this;
}
while(st.size()>0)
{
std::tie(list,pos)=st.top();
st.pop();
if(pos<list->Size()-1)
{
pos++;
Increment();
return *this;
}
}
// This is the end
list=nullptr;
pos=0;
return *this;
}
ObjectListIterator operator++(int) {ObjectListIterator tmp(*this); operator++(); return tmp;}
const ObjectBase* operator*() const {return list->At(pos);}
const ObjectBase* operator->() const {return list->At(pos);}
};
std::shared_ptr<ListValues> vals; std::shared_ptr<ListValues> vals;
ObjectList(const ObjectList* o):vals(o->vals) {} ObjectList(const ObjectList* o):vals(o->vals) {}
public: public:
typedef ObjectListIterator iterator;
typedef ObjectListIterator const_iterator;
ObjectList() {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;});} ObjectList() {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;});}
ObjectList(const ObjectBase* o) {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;}); PushBack(o);} ObjectList(const ObjectBase* o) {vals.reset(new ListValues, [](ListValues* p){for(auto& i: *p) delete i; delete p;}); PushBack(o);}
// Pure virtual overrides // Pure virtual overrides
@ -374,7 +305,7 @@ public:
} }
// Own functions // Own functions
const ObjectBase* At(IndexType i) const {return (*vals)[i];} const ObjectBase* At(ListValues::size_type i) const {return (*vals)[i];}
const ObjectBase* Get(const std::string& gname) const const ObjectBase* Get(const std::string& gname) const
{ {
const ObjectBase* p=Find(gname); const ObjectBase* p=Find(gname);
@ -395,12 +326,9 @@ public:
} }
return nullptr; return nullptr;
} }
IndexType Size() const {return vals->size();} ListValues::size_type Size() const {return vals->size();}
ObjectList* PushBack(const ObjectBase* p) {vals->push_back(p); return this;} ObjectList* PushBack(const ObjectBase* p) {vals->push_back(p); return this;}
ObjectList* PushFront(const ObjectBase* p) {vals->push_front(p); return this;} ObjectList* PushFront(const ObjectBase* p) {vals->push_front(p); return this;}
// Iterator functions
const_iterator begin() const {return const_iterator(this);}
const_iterator end() const {return const_iterator();}
}; };
typedef const ObjectBase* (*Func)(const ObjectList*); typedef const ObjectBase* (*Func)(const ObjectList*);

34
maketest

@ -1,34 +0,0 @@
#!/bin/bash
name="$1"
desc="$2"
TLOC="${3:-/tmp/save/test}"
MAKEMAP="${4:-/tmp/save/build/src/makemap}"
if [ -f tests/"$name" ]; then
echo "Test $name already exist."
exit 1
fi
if [ ! -f "$TLOC" ]; then
echo "Configuration file $TLOC not found."
exit 2
fi
if [ ! -x "$MAKEMAP" ]; then
echo "Can't exec file $MAKEMAP."
exit 3
fi
echo "# Description: $desc" >tests/$name
if "$MAKEMAP" "$TLOC" &>/dev/null; then
hash=`"$MAKEMAP" "$TLOC" 2>/dev/null|sha256sum|sed "s/ .*//"`
status=ok
else
hash=`"$MAKEMAP" "$TLOC" 2>&1|sha256sum|sed "s/ .*//"`
status=fail
fi
echo "# Status: $status" >>tests/$name
echo "# Output hash: $hash" >>tests/$name
cat "$TLOC" >>tests/$name

130
modules/gmt/cmpstr.c++

@ -0,0 +1,130 @@
#include <iostream>
#include <set>
#include <string>
#include <vector>
bool CmpStrEx(const std::string& expr, const std::string& str)
{
if(expr.empty() || str.empty()) return false;
struct State
{
struct Block
{
const size_t b,len;
const bool optional;
Block(const size_t bb,const size_t ee,const bool o):b(bb),len(ee-bb),optional(o) {}
};
struct Cursor
{
size_t block,offset;
bool operator <(const struct Cursor& c) const
{
if(block<c.block) return true;
if(block>c.block) return false;
if(offset<c.offset) return true;
return false;
}
};
typedef std::set<struct Cursor> Cursors;
typedef std::set<struct Cursor>::iterator pCursor;
std::vector<struct Block> blockchain;
Cursors cursors;
const std::string& s;
Cursors InitCursors(size_t block) const
{
Cursors cs;
for(size_t i=block; i<blockchain.size(); ++i)
{
cs.insert({i,0});
if(!blockchain[i].optional) break;
}
return cs;
}
State(const std::string& str):s(str)
{
size_t cur=0;
size_t bpos=0;
// Parse blocks
while(cur<s.length())
{
if('['==s[cur] || ']'==s[cur])
{
// Add current block to blockchain
if(cur>bpos) blockchain.push_back(Block(bpos,cur,(']'==s[cur])));
cur++;
bpos=cur;
continue;
}
cur++;
}
// Add last block
if(bpos<s.length()) blockchain.push_back(Block(bpos,s.length(),false));
// Creating cursors for the first symbol
cursors=InitCursors(0);
}
bool CmpSmb(const char c)
{
pCursor p=cursors.begin();
bool res=false;
// Compare symbol with all cursors
while(p!=cursors.end())
{
const Block& bl=blockchain[p->block];
if(c==s[bl.b+p->offset]) {res=true; ++p;}
else p=cursors.erase(p);
}
// Increment cursors
Cursors upd; // New cursors
p=cursors.begin();
while(p!=cursors.end())
{
// Increment cursor on one position
if(p->offset+1>=blockchain[p->block].len) // Go to next block
{
Cursors cs=InitCursors(p->block+1); // Get cursors for next block
p=cursors.erase(p); // Erase current cursor
for(const auto& cur: cs) upd.insert(cur); // Copy cursors to new set
continue;
}
else upd.insert({p->block,p->offset+1});
if(blockchain[p->block].optional) // If current block is optional next symbol may be from next block
{
Cursors cs=InitCursors(p->block+1); // Get cursors for next blockchain
for(const auto& cur: cs) upd.insert(cur); // Copy cursors to new set
}
++p;
}
cursors=upd;
return res;
}
};
struct State st(expr);
for(size_t pos=0; pos<str.length(); ++pos)
{
if(!st.CmpSmb(str[pos])) return false;
}
return true;
}
int main(int argc, char** argv)
{
if(argc!=3) return 1;
std::cout<<"Compare "<<argv[1]<<" with template "<<argv[2]<<": "<<(CmpStrEx(argv[2],argv[1])?"match":"not match")<<std::endl;
return 0;
}

287
modules/gmt/cmpstr_alt.c++

@ -0,0 +1,287 @@
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <vector>
bool CmpStrEx(const std::string& expr, const std::string& str)
{
if(expr.empty() || str.empty()) return false;
struct State
{
struct Block
{
using pBlock=std::unique_ptr<struct Block>;
enum Type {NOTDEF,TEXT,OPTIONAL,VARIANTS,DELIM};
size_t b,e;
Type type;
const struct Block* parent;
pBlock next,child;
Block() = delete;
Block(const struct Block&) = delete;
Block(struct Block&&) = delete;
bool isText() const {return type==TEXT;}
Block(Type t, const struct Block* p=nullptr):b(0),e(0),type(t),parent(p),next(nullptr),child(nullptr) {}
Block(size_t bb, size_t ee, const struct Block* p=nullptr):b(bb),e(ee),type(TEXT),parent(p),next(nullptr),child(nullptr) {}
};
Block::pBlock Parse(const std::string& str)
{
size_t e=0;
struct Block* blk;
struct Block* root;
auto c=str[e];
bool init,next;
// First symbol
if('['==c || '('==c) blk=new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS);
else blk=new Block(e,e+1);
root=blk;
init=!root->isText();
next=!init;
e++;
while(e<str.length())
{
c=str[e];
switch(c)
{
case '[':
case '(':
{
(next?blk->next:blk->child).reset(new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS,(next?blk->parent:blk)));
blk=(next?blk->next:blk->child).get();
init=true;
next=false;
break;
}
case ']':
case ')':
{
blk=const_cast<struct Block*>(blk->parent);
init=true;
next=true;
break;
}
case '|': {blk->next.reset(new Block(Block::DELIM,blk->parent)); blk=blk->next.get(); init=next=true; break;}
default:
{
if(init)
{
(next?blk->next:blk->child).reset(new Block(e,e+1,(next?blk->parent:blk)));
blk=(next?blk->next:blk->child).get();
}
else blk->e=e+1;
init=false;
next=true;
}
}
e++;
}
return Block::pBlock(root);
}
struct Cursor
{
const struct Block* block;
size_t offset;
bool operator <(const struct Cursor& c) const {return block<c.block;}
bool compare(const std::string& str, const char c) const {return c==str[block->b+offset];}
Cursor(const struct Block* b, size_t o):block(b),offset(o) {}
};
using Cursors=std::set<struct Cursor>;
using pCursor=std::set<struct Cursor>::const_iterator;
Block::pBlock root;
Cursors cursors;
const std::string& s;
void InitCursors(const struct Block* blk)
{
switch(blk->type)
{
case Block::TEXT: {cursors.insert({blk,0}); break;}
case Block::OPTIONAL:
{
auto b=blk;
InitCursors(b->child.get());
while(true)
{
if(!b->next) break;
b=b->next.get();
InitCursors(b);
if(b->type!=Block::OPTIONAL) break;
}
break;
}
case Block::VARIANTS:
{
auto b=blk->child.get();
while(true)
{
InitCursors(b);
while(b->type!=Block::DELIM)
{
if(!b->next) break;
b=b->next.get();
}
if(!b->next) break;
b=b->next.get();
}
}
default: {}
}
}
State(const std::string& str):root(Parse(str)),s(str) {InitCursors(root.get());}
std::string Name() const
{
const struct Block* b=root.get();
std::string res;
while(true)
{
// Processing current block
switch(b->type)
{
case(Block::TEXT): {res+=s.substr(b->b,b->e-b->b); break;}
case(Block::OPTIONAL): {b=b->child.get(); goto next;}
case(Block::VARIANTS): {b=b->child.get(); goto next;}
case(Block::DELIM): {b=b->parent; break;}
default: {}
}
// Go to next block
while(true)
{
if(nullptr!=b->next) {b=b->next.get(); goto next;}
if(nullptr!=b->parent) b=b->parent;
else break;
}
if(nullptr==b->next && nullptr==b->parent) break;
next: ;
}
return res;
}
bool CmpSmb(const char c)
{
pCursor p=cursors.cbegin();
bool res=false;
// Compare symbol with all cursors
std::cout<<"--------------\n";
std::cout<<"Symbol: "<<c<<"\n";
while(p!=cursors.end())
{
std::cout<<p->block->b+p->offset<<" "<<s[p->block->b+p->offset]<<"\n";
if(p->compare(s,c)) {res=true; p++;}
else p=cursors.erase(p);
}
Cursors old(std::move(cursors));
for(const auto& p:old)
{
auto blk=p.block;
// Increment cursors
if(blk->b+p.offset+1<blk->e) cursors.insert({blk,p.offset+1}); // Advance in current block
else // Move to next block
{
if(!blk->next || blk->next->type==Block::DELIM) // End of chain, must go up
{
while(blk->parent!=nullptr)
{
blk=blk->parent;
if(!blk->next || blk->next->type==Block::DELIM) continue;
InitCursors(blk->next.get());
}
}
else InitCursors(blk->next.get()); // Next block in chain
}
// Try to leave optional blocks
blk=p.block;
while(blk->parent!=nullptr)
{
blk=blk->parent;
if(blk->type!=Block::OPTIONAL || !blk->next || blk->next->type==Block::DELIM) continue;
InitCursors(blk->next.get());
}
}
return res;
}
};
// Main function
struct State st(expr);
std::cout<<"Name is "<<st.Name()<<std::endl;
// Dump code
{
std::cerr<<"digraph main\n{\nrankdir=TB pack=\"true\" packmode=\"node\";\n";
std::cerr<<"node [fontsize=30, shape=rectangle, style=\"filled,rounded\", fillcolor=azure2, fixedsize=\"false\", margin=0.2, width=1, penwidth=3, fontname=\"Times New Roman\"];\n";
std::cerr<<"edge [arrowsize=1.5, penwidth=3];\n";
const struct State::Block* r=st.root.get();
std::set<const struct State::Block*> visited;
visited.insert(nullptr);
while(true)
{
if(visited.count(r)==0)
{
std::string label;
if(r->type==State::Block::OPTIONAL) label="[]";
if(r->type==State::Block::VARIANTS) label="()";
if(r->type==State::Block::DELIM) label="|";
if(r->type==State::Block::TEXT) label=expr.substr(r->b,r->e-r->b);
std::cerr<<"\""<<r<<"\" [label=\""<<label<<"\""<<((r->type==State::Block::TEXT)?",fontcolor=\"red\"":"")<<"];\n";
if(r->child) std::cerr<<"\""<<r<<"\" -> \""<<r->child.get()<<"\";\n";
if(r->next)
{
std::cerr<<"\""<<r<<"\" -> \""<<r->next.get()<<"\" [color=\"blue\"];\n";
std::cerr<<"{rank=same; "<<"\""<<r<<"\"; \""<<r->next.get()<<"\";}\n";
}
if(r->parent!=nullptr) std::cerr<<"\""<<r<<"\" -> \""<<r->parent<<"\" [color=\"green\", penwidth=1];\n";
visited.insert(r);
}
if(r->child && visited.count(r->child.get())==0) r=r->child.get();
else if(r->next) r=r->next.get();
else
{
while(r->parent!=nullptr)
{
r=r->parent;
if(r->next) {r=r->next.get(); break;}
}
}
if(visited.count(r)!=0 && r->parent==nullptr && visited.count(r->next.get())!=0 && visited.count(r->child.get())!=0) break;
}
std::cerr<<"}\n";
}
for(size_t pos=0; pos<str.length(); ++pos)
{
if(!st.CmpSmb(str[pos])) return false;
}
return true;
}
int main(int argc, char** argv)
{
if(argc!=3) return 1;
std::cout<<"Compare "<<argv[1]<<" with template "<<argv[2]<<": "<<(CmpStrEx(argv[2],argv[1])?"match":"not match")<<std::endl;
return 0;
}

1926
modules/gmt/modgmt_colornames.cpp

File diff suppressed because it is too large Load Diff

54
modules/gmt/modgmt_colornames.h

@ -13,36 +13,36 @@ public:
}; };
inline unsigned int inline unsigned int
ColorHash::colornamehash (const char *str, unsigned int len) ColorHash::colornamehash ( const char *str, unsigned int len)
{ {
static const unsigned short asso_values[] = static const unsigned short asso_values[] =
{ {
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 666, 27, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 800, 25,
26, 23, 22, 789, 588, 587, 501, 436, 2728, 2728, 20, 5, 0, 845, 785, 780, 640, 620, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 61, 96, 222, 98, 22, 4084, 4084, 4084, 4084, 4084, 80, 0, 686, 5, 0,
117, 22, 561, 559, 22, 708, 179, 301, 42, 101, 260, 0, 85, 770, 20, 950, 210, 95, 160, 195,
242, 46, 23, 22, 116, 171, 821, 809, 2728, 169, 995, 335, 0, 0, 135, 425, 55, 863, 4084, 60,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 61, 96, 222, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 80, 0, 686,
98, 22, 117, 22, 561, 559, 22, 708, 179, 301, 5, 0, 260, 0, 85, 770, 20, 950, 210, 95,
42, 101, 242, 46, 23, 22, 116, 171, 821, 809, 160, 195, 995, 335, 0, 0, 135, 425, 55, 863,
2728, 169, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 60, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 2728, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084, 4084,
2728, 2728, 2728, 2728, 2728, 2728 4084, 4084, 4084, 4084, 4084, 4084
}; };
int hval = len; int hval = len;

380
modules/gmt/modgmt_func.cpp

@ -24,111 +24,126 @@ const ObjectBase* GMT_Footer(const ObjectList* input)
const ObjectBase* GMT_ColorGray(const ObjectList* input) const ObjectBase* GMT_ColorGray(const ObjectList* input)
{ {
struct gmt_color c; struct gmt_color c;
RPosPar<Base2RGB> g("gray"); bool suc=true;
OPosPar<Base2TransD> t("transparency",0.0); Base2RGB g(input,0);
Base2Transp t(input,1);
ParsePositionalParameters params(input,g,t);
if(!params) return new ObjectError("ColorGray",params.Error());
c.model=gmt_color::GRAY; c.model=gmt_color::GRAY;
c.gray=g; c.transparency=t; c.gray=g(&suc);
c.transparency=t(&suc);
return new ObjectGMTColor(c); if(suc) return new ObjectGMTColor(c);
else return 0;
} }
const ObjectBase* GMT_ColorRGB(const ObjectList* input) const ObjectBase* GMT_ColorRGB(const ObjectList* input)
{ {
struct gmt_color c; struct gmt_color c;
bool suc=true;
RPosPar<Base2RGB> r("red"),g("green"),b("blue"); Base2RGB r(input,0),g(input,1),b(input,2);
OPosPar<Base2TransD> t("transparency",0.0); Base2Transp t(input,3);
ParsePositionalParameters params(input,r,g,b,t);
if(!params) return new ObjectError("ColorRGB",params.Error());
c.model=gmt_color::RGB; c.model=gmt_color::RGB;
c.r=r; c.g=g; c.b=b; c.transparency=t; c.r=r(&suc);
c.g=g(&suc);
c.b=b(&suc);
c.transparency=t(&suc);
return new ObjectGMTColor(c); if(suc) return new ObjectGMTColor(c);
else return 0;
} }
const ObjectBase* GMT_ColorHSV(const ObjectList* input) const ObjectBase* GMT_ColorHSV(const ObjectList* input)
{ {
struct gmt_color c; struct gmt_color c;
bool suc=true;
RPosPar<Base2Hue> h("hue"); Base2Hue h(input,0);
RPosPar<Base2SV> s("saturation"), v("value"); Base2SV s(input,1),v(input,2);
OPosPar<Base2TransD> t("transparency",0.0); Base2Transp t(input,3);
ParsePositionalParameters params(input,h,s,v,t);
if(!params) return new ObjectError("ColorHSV",params.Error());
c.model=gmt_color::HSV; c.model=gmt_color::HSV;
c.hue=h; c.saturation=s; c.value=v; c.transparency=t; c.hue=h(&suc);
c.saturation=s(&suc);
c.value=v(&suc);
c.transparency=t(&suc);
return new ObjectGMTColor(c); if(suc) return new ObjectGMTColor(c);
else return 0;
} }
const ObjectBase* GMT_ColorCMYK(const ObjectList* input) const ObjectBase* GMT_ColorCMYK(const ObjectList* input)
{ {
struct gmt_color C; struct gmt_color c;
bool suc=true;
RPosPar<Base2CMYK> c("cyan"),m("magenta"),y("yellow"),k("black"); Base2CMYK cyan(input,0),m(input,1),y(input,2),k(input,3);
OPosPar<Base2TransD> t("transparency",0.0); Base2Transp t(input,4);
ParsePositionalParameters params(input,c,m,y,k,t); c.model=gmt_color::CMYK;
if(!params) return new ObjectError("ColorCMYK",params.Error()); c.cyan=cyan(&suc);
c.magenta=m(&suc);
C.model=gmt_color::CMYK; c.yellow=y(&suc);
C.cyan=c; C.magenta=m; C.yellow=y; C.black=k; C.transparency=t; c.black=k(&suc);
c.transparency=t(&suc);
return new ObjectGMTColor(C);
if(suc) return new ObjectGMTColor(c);
else return 0;
} }
// Shifting layer // Shifting layer
/* /*
Input: Input:
1) Three arguments, first is Layer, second and third are double. Interprets as new absolute position in cm. 1) Three arguments, first is Layer, second and third are double. Interprets as new absolute position in cm.
2) Pairs list. Names are l (layer), x, y, relx (rx), rely (ry). Pair with name l may be absent, in this case search in list and using as layer object with ObjectGMTLayer type. x and y are absolute positions in cm, relx and rely are shift from current position. x (y) and relx (rely) are mutually exlusive, but x (y) and rely (relx) can be used simultaneously. If position for some axis is absent, then this position is unchanged. 2) Pairs list. Names are l (layer), x, y, xrel (xr), yrel (yr). Pair with name l may be absent, in this case search in list and using as layer object with ObjectGMTLayer type. x and y are absolute positions in cm, xrel and yrel are shift from current position. x (y) and xrel (yrel) are mutually exlusive, but x (y) and yrel (xrel) can be used simultaneously. If position for some axis is absent, then this position is unchanged.
*/ */
const ObjectBase* GMT_LayerShift(const ObjectList* input) const ObjectBase* GMT_LayerShift(const ObjectList* input)
{ {
auto size=input->Size();
struct gmt_layer layer; struct gmt_layer layer;
std::string err;
// Case 1 // Case 1
if(3==size)
{ {
RPosPar<Base2Layer> l("layer"); Base2Layer l(input,0);
OPosPar<Base2DoubleD> x("x",0.0), y("y",0.0); Base2Double x(input,1), y(input,2);
bool suc=true;
{ParsePositionalParameters params(input,l,x,y); if(!params) goto case2;} // Try case 2, if case 1 failed. layer=l(&suc);
layer=l; layer.shiftx=x; layer.shifty=y; if(!suc) goto case2;
layer.shiftx=x(&suc);
layer.shifty=y(&suc);
if(!suc) goto case2;
return new ObjectGMTLayer(layer); return new ObjectGMTLayer(layer);
} }
case2: case2:
{
RNPar<Base2Layer> l("layer");
ONPar<Base2Double> x("x"),y("y"),rx("r[el]x"),ry("r[el]y");
{ParseNamedParameters params(input,l,x,y); if(!params) {err=params.Error(); goto fail;}} // Parsing error
// Check duplicate parameters // Search layer for shifting
if(x.Exist() && rx.Exist()) {err="Only one of "+x.Name()+" or "+rx.Name()+" can be specified."; goto fail;} {
if(y.Exist() && ry.Exist()) {err="Only one of "+y.Name()+" or "+ry.Name()+" can be specified."; goto fail;} SearchParameter<struct gmt_layer> original(input,"layer","l");
bool suc=true;
layer=original(&suc);
if(!suc) goto fail; // Conversion failed or too many arguments
}
// Do shift // Do shift
if( x.Exist()) layer.shiftx=x; {
if( y.Exist()) layer.shifty=y; BaseM2Double xr(input,"xrel","xr"), yr(input,"yrel","yr");
if(rx.Exist()) layer.shiftx+=rx; Base2Double x(input,"x"), y(input,"y");
if(ry.Exist()) layer.shifty+=ry; bool suc=true;
// Check duplicate parameters
if( ( x.Exist() && xr.Exist() ) || ( y.Exist() && yr.Exist() ) ) goto fail;
if(x.Exist()) layer.shiftx=x(&suc);
if(y.Exist()) layer.shifty=y(&suc);
if(xr.Exist()) layer.shiftx+=x(&suc);
if(yr.Exist()) layer.shifty+=y(&suc);
if(!suc) goto fail;
} }
return new ObjectGMTLayer(layer); return new ObjectGMTLayer(layer);
fail: fail:
return new ObjectError("LayerShift",err); return 0;
} }
// Draw frame with tics // Draw frame with tics
/* /*
Input: pairs list. Input: pairs list.
@ -146,146 +161,169 @@ framepen - pen for drawing frame. Default is 0.35,black.
ticklen - lenght of tick-marks in cm. Default is 0.18. ticklen - lenght of tick-marks in cm. Default is 0.18.
tickpen - pen for drawing ticks. Default is 0.3,black. tickpen - pen for drawing ticks. Default is 0.3,black.
trans or transparency - transparency level, double from 0 to 100. Default is 0 (opaque). trans or transparency - transparency level, double from 0 to 100. Default is 0 (opaque).
model - transparency model, string. Choose from Color, ColorBurn, ColorDodge, Darken, Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, Overlay, Saturation, SoftLight, and Screen. Default is Normal. transpmodel - transparency model, string. Choose from Color, ColorBurn, ColorDodge, Darken, Difference, Exclusion, HardLight, Hue, Lighten, Luminosity, Multiply, Normal, Overlay, Saturation, SoftLight, and Screen. Default is Normal.
rx or relx - shift layer on x cm in horisontal direction. Default is 0. x, xr or xrel - shift layer on x cm in horisontal direction. Default is 0.
ry or rely - shift layer on y cm in vertical direction. Default is 0. y, yr or yrel - shift layer on y cm in vertical direction. Default is 0.
*/ */
template<class O>
using SConvertor=Convert2Struct<std::string, O>;
template<class O>
using DConvertor=Convert2Struct<double, O>;
const ObjectBase* GMT_DrawFrame(const ObjectList* input) const ObjectBase* GMT_DrawFrame(const ObjectList* input)
{ {
struct XYIntVal // Representing intervals for tics intervals std::string opts="-P -O -K ";
{ bool suc=true;
bool isauto; double val; struct gmt_layer layer;
XYIntVal():isauto(true),val(0.0) {} // Default is auto // Defaults
}; std::string defxtics="down", defytics="left", defint="auto", defdomain="pos", deftranspmodel="Normal";
bool defmark=false;
class Base2TInt // Custom convertor class for xy tics intervals gmt_font deffont; deffont.Convert("12,Times-Roman,black");
{ double defoffset=0.18, defframewidth=0.1, defticklen=0.18;
public: gmt_pen defframepen, deftickpen; defframepen.Convert("0.35,black"); deftickpen.Convert("0.3,black");
using ValueType=struct XYIntVal;
{ // Get projection
BaseMT2Projection proj(input,"proj","projection");
layer.proj=proj(&suc);
if(!suc) goto fail;
opts+=layer.proj.Value()+" ";
}
ValueType Convert(const ObjectBase* ob, bool* res, std::string& err) { // Get xint and yint
{ BaseMD2String xint(input,defint,"xint"), yint(input,defint,"yint");
ValueType ret; double dx,dy;
ret.isauto=false; std::string str;
OBTypeM<SConvertor,ObjectString> sp(ob); str=xint(&suc);
OBTypeM<DConvertor,ObjectReal,ObjectInt,ObjectString> dp(ob); if(suc && "auto"==str) dx=AutoStep(layer.proj.region.xb,layer.proj.region.xe);
// Check string "auto" else // No auto, get numeric value
if(sp.Error()==OBTypeErr::OK)
{ {
std::string s=sp(res,std::ref(err)); Base2Double xint(input,"xint");
if(!res) {err="Unknown error"; goto fail;} // Impossible case suc=true;
tolower(s); dx=xint(&suc);
if("auto"==s) {ret.isauto=true; return ret;} if(!suc) goto fail; // Parameter exists, but conversion failed
} }
// Check double value
switch(dp.Error()) str=yint(&suc);
{ if(suc && "auto"==str) dy=AutoStep(layer.proj.region.yb,layer.proj.region.ye);
case(OBTypeErr::OK): else // No auto, get numeric value
{ {
ret.val=dp(res,std::ref(err)); Base2Double yint(input,"yint");
if(ret.val<=0.0) {err="Tics interval must be greater the zero"; break;} suc=true;
return ret; dy=yint(&suc);
}; if(!suc) goto fail; // Parameter exists, but conversion failed
case(OBTypeErr::NULLPTR): {err="Can't convert zero ObjectBase pointer to something meaningfull"; break;}
case(OBTypeErr::TYPEMISMATCH): {err="Can't convert "+ob->Type()+" to double: type mismatch"; break;}
} }
fail: opts+="-Bx"+ToString(dx)+" -By"+ToString(dy)+" ";
*res=false;
return ret;
} }
};
std::string err,fakerr; { // Get xtics and ytics
std::string opts="-P -O -K "; BaseMD2String x(input,defxtics,"xtics"), y(input,defytics,"ytics");
std::string xtics,ytics;
std::string xaxis,yaxis;
struct gmt_layer layer; xtics=x(&suc);
if(!suc) goto fail; // Conversion failed
if("none"==xtics) xaxis="sn";
if("down"==xtics) xaxis="Sn";
if("up"==xtics) xaxis="sN";
if("both"==xtics) xaxis="SN";
struct gmt_font deffont; ytics=y(&suc);
struct gmt_pen defframepen,deftickpen; if(!suc) goto fail; // Conversion failed
deffont.Convert("12,Times-Roman,black",fakerr); if("none"==ytics) yaxis="we";
defframepen.Convert("0.35,black",fakerr); if("left"==ytics) yaxis="We";
deftickpen.Convert("0.3,black",fakerr); if("right"==ytics) yaxis="wE";
if("both"==ytics) yaxis="WE";
RNFPar<Base2Proj,ObjectGMTProjection> proj("projection");
ONPar<Base2TInt> xint("x[ ]interval"), yint("y[ ]interval");
ONPar<Base2StringD> xtics("x[ ]tics[ ]position","down"), ytics("y[ ]t[ics[ ]position","left");
ONPar<Base2StringD> domain("domain","pos");
ONPar<Base2BoolD> mark("mark",false);
ONPar<Base2FontD> font("font",deffont);
ONPar<Base2DoubleD> offset("offset",0.18);
ONPar<Base2NonNegD> framewidth("f[rame][ ]width",0.1);
ONPar<Base2PenD> framepen("f[rame][ ]pen",defframepen), tickpen("t[icks][ ]pen",deftickpen);
ONPar<Base2DoubleD> ticklen("t[icks][ ]length",0.18);
ONPar<Base2TransD> transp("transparency",0.0);
ONPar<Base2StringD> transpmodel("model","Normal");
ONPar<Base2DoubleD> rx("r[el]x",0.0),ry("r[el]y",0.0);
ParseNamedParameters params(input,proj,xint,yint,xtics,ytics,domain,mark,font,offset,framewidth,framepen,tickpen,ticklen,transp,transpmodel,rx,ry); if(!params) {err=params.Error(); goto fail;} // Error parsing parameters
layer.proj=proj; // Get projection
opts+=layer.proj.Value()+" ";
{ // Get tics intervals if(xaxis.empty() || yaxis.empty()) goto fail; // Unknown value of xtics and/or ytics
XYIntVal dx=xint,dy=yint;
opts+="-Bx"+ToString(dx.isauto?AutoStep(layer.proj.region.xb,layer.proj.region.xe):dx.val)+" -By"+ToString(dy.isauto?AutoStep(layer.proj.region.yb,layer.proj.region.ye):dy.val)+" ";
}
{ // Get xtics and ytics positions
std::string xt=xtics, yt=ytics;
std::string xaxis, yaxis;
TemplateComparator none("none"), both("both");
TemplateComparator up("up"), down("down");
TemplateComparator left("left"), right("right");
tolower(xt); tolower(yt);
if(none.Compare(xt)) xaxis="sn";
if(down.Compare(xt)) xaxis="Sn";
if( up.Compare(xt)) xaxis="sN";
if(both.Compare(xt)) xaxis="SN";
if( none.Compare(yt)) yaxis="we";
if( left.Compare(yt)) yaxis="We";
if(right.Compare(yt)) yaxis="wE";
if( both.Compare(yt)) yaxis="WE";
if(xaxis.empty()) {err="Incorrect xtics position "+xtics.Value(); goto fail;} // Unknown value of xtics
if(yaxis.empty()) {err="Incorrect xtics position "+ytics.Value(); goto fail;} // Unknown value of ytics
opts+="-B"+xaxis+yaxis+" "; opts+="-B"+xaxis+yaxis+" ";
} }
{ // Get domain and mark { // Get domain and mark
std::string dom=domain; BaseMD2String d(input,defdomain,"domain");
BaseMD2Bool m(input,defmark,"mark");
std::string format; std::string format;
TemplateComparator p("positive"),n("negative"),c("centered");
tolower(dom);
if(p.Compare(dom)) format="+ddd:mm:ss"; std::string domain=d(&suc);
if(n.Compare(dom)) format="-ddd:mm:ss"; if(!suc) goto fail; // Conversion failed
if(c.Compare(dom)) format="ddd:mm:ss"; if("pos"==domain) format="+ddd:mm:ss";
if(format.empty()) {err="Incorrect domain value "+domain.Value(); goto fail;} // Unknown domain if("neg"==domain) format="-ddd:mm:ss";
if("center"==domain) format="ddd:mm:ss";
if(format.empty()) goto fail; // Unknown domain
if(m(&suc)) format+="F";
if(!suc) goto fail; // Conversion failed
if(mark) format+="F";
opts+="--FORMAT_GEO_MAP="+format+" "; opts+="--FORMAT_GEO_MAP="+format+" ";
} }
opts+="--FONT_ANNOT_PRIMARY="+font.Value().Value()+" "; // Get font { // Get font
opts+="--MAP_ANNOT_OFFSET_PRIMARY="+ToString(offset.Value())+"c "; // Get offset BaseMD2Font f(input,deffont,"font");
opts+="--MAP_FRAME_WIDTH="+ToString(framewidth.Value())+"c "; // Get framewidth gmt_font font;
opts+="--MAP_FRAME_PEN="+framepen.Value().Value()+" "; // Get framepen font=f(&suc);
opts+="--MAP_TICK_LENGTH_PRIMARY="+ToString(ticklen.Value())+"c "; // Get ticklen if(!suc) goto fail; // Conversion failed
opts+="--MAP_TICK_PEN_PRIMARY="+tickpen.Value().Value()+" "; // Get tickpen opts+="--FONT_ANNOT_PRIMARY="+font.Value()+" ";
if(transp!=0) opts+="-t"+ToString(transp.Value())+" "; // Get transparency }
opts+="--PS_TRANSPARENCY="+transpmodel.Value()+" "; // Get transparency model
{ // Get offset
BaseMD2Double o(input,defoffset,"offset");
double offset;
offset=o(&suc);
if(!suc) goto fail; // Conversion failed
opts+="--MAP_ANNOT_OFFSET_PRIMARY="+ToString(offset)+"c ";
}
{ // Get framewidth
SearchParameterWDef<double,false,PMin<0> > f(input,defframewidth,"framewidth");
double framewidth;
framewidth=f(&suc);
if(!suc) goto fail; // Conversion failed
opts+="--MAP_FRAME_WIDTH="+ToString(framewidth)+"c ";
}
{ // Get framepen
BaseMD2Pen p(input,defframepen,"framepen");
gmt_pen framepen;
framepen=p(&suc);
if(!suc) goto fail; // Conversion failed
opts+="--MAP_FRAME_PEN="+framepen.Value()+" ";
}
// Get shift { // Get ticklen
layer.shiftx=rx; BaseMD2Double t(input,defticklen,"ticklen","ticklength");
layer.shifty=ry; double ticklen;
ticklen=t(&suc);
if(!suc) goto fail; // Conversion failed
opts+="--MAP_TICK_LENGTH_PRIMARY="+ToString(ticklen)+"c ";
}
{ // Get tickpen
BaseMD2Pen t(input,deftickpen,"tickpen");
gmt_pen tickpen;
tickpen=t(&suc);
if(!suc) goto fail; // Conversion failed
opts+="--MAP_TICK_PEN_PRIMARY="+tickpen.Value()+" ";
}
{ // Get transparency
Base2Transp t(input,"trans","transp","transparency");
double transp;
transp=t(&suc);
if(!suc) goto fail; // Conversion failed
if(transp!=0) opts+="-t"+ToString(transp)+" ";
}
{ // Get transpmodel
BaseMD2String tm(input,deftranspmodel,"transpmodel","transparencymodel");
std::string transpmodel;
transpmodel=tm(&suc);
if(!suc) goto fail; // Conversion failed
opts+="--PS_TRANSPARENCY="+transpmodel+" ";
}
{ // Get x, y
BaseMD2Double x(input,0.0,"x","xr","xrel"), y(input,0.0,"y","yr","yrel");
layer.shiftx=x(&suc);
layer.shifty=y(&suc);
if(!suc) goto fail; // Conversion failed
}
{ // Calling psbasemap { // Calling psbasemap
void* gmtapi; void* gmtapi;
@ -304,5 +342,5 @@ const ObjectBase* GMT_DrawFrame(const ObjectList* input)
return new ObjectGMTLayer(layer); return new ObjectGMTLayer(layer);
fail: fail:
return new ObjectError("DrawFrame",err); return 0;
} }

1467
modules/gmt/modgmt_func.h

File diff suppressed because it is too large Load Diff

5
modules/gmt/modgmt_gsfuncs.cpp

@ -82,7 +82,6 @@ static int GhostRun(const std::string& opts, struct gs_runtime* r, std::string*
{ {
struct gsworkthreadpars wp; struct gsworkthreadpars wp;
int* pret; int* pret;
int ret=0;
wp.r=r; wp.r=r;
wp.input_callback=input; wp.input_callback=input;
@ -97,7 +96,7 @@ static int GhostRun(const std::string& opts, struct gs_runtime* r, std::string*
ssize_t br; ssize_t br;
char buffer[4096]; char buffer[4096];
if(0!=pipe(pipefd)) {ret=-1; goto end;} pipe(pipefd);
wp.fd=pipefd[1]; wp.fd=pipefd[1];
out->erase(); out->erase();
@ -113,8 +112,6 @@ static int GhostRun(const std::string& opts, struct gs_runtime* r, std::string*
} }
else pret=reinterpret_cast<int*>(gsworkthread(&wp)); else pret=reinterpret_cast<int*>(gsworkthread(&wp));
end:
if(0!=ret) return ret;
return *pret; return *pret;
} }

4
modules/gmt/modgmt_gsfuncs.h

@ -4,10 +4,6 @@
#include <ghostscript/iapi.h> #include <ghostscript/iapi.h>
#include <ghostscript/ierrors.h> #include <ghostscript/ierrors.h>
#ifndef e_Quit
#define e_Quit (-101)
#endif
struct gs_abilities_struct struct gs_abilities_struct
{ {
bool havepngmono,havepngmonod,havepng16,havepng256,havepnggray,havepng16m; bool havepngmono,havepngmonod,havepng16,havepng256,havepnggray,havepng16m;

5
modules/gmt/modgmt_internals.cpp

@ -44,9 +44,8 @@ int callgmtmodule(void *api, const char *module, struct GMT_OPTION *opts, std::s
pthread_t wthr; pthread_t wthr;
struct gmtworkthreadpars p; struct gmtworkthreadpars p;
int *pret; int *pret;
int ret=0;
if(0!=pipe(pipefd)) {ret=-1; goto end;} pipe(pipefd);
p.api=api; p.api=api;
p.module=module; p.module=module;
p.opts=opts; p.opts=opts;
@ -60,8 +59,6 @@ int callgmtmodule(void *api, const char *module, struct GMT_OPTION *opts, std::s
res->shrink_to_fit(); res->shrink_to_fit();
pthread_join(wthr,reinterpret_cast<void**>(&pret)); pthread_join(wthr,reinterpret_cast<void**>(&pret));
end:
if(0!=ret) return ret;
return *pret; return *pret;
} }
// Overloaded variant with opts as std::string // Overloaded variant with opts as std::string

345
modules/gmt/modgmt_map.cpp

@ -61,9 +61,13 @@ Resulted shift is added to own shift of layer (setted by function LayerShift).
*/ */
const ObjectBase* GMT_Map(const ObjectList* input) const ObjectBase* GMT_Map(const ObjectList* input)
{ {
std::string err; const ObjectList* list=input;
auto size=list->Size();
if(0==size) return 0;
decltype(size) pos=0;
std::string title; std::string title;
std::stack<std::pair<const ObjectList*,decltype(pos)> > lstack;
bool first=true;
double xg,yg,x,y; double xg,yg,x,y;
bool xislocal=false, yislocal=false; bool xislocal=false, yislocal=false;
std::list<std::shared_ptr<std::string> > data; std::list<std::shared_ptr<std::string> > data;
@ -74,29 +78,45 @@ const ObjectBase* GMT_Map(const ObjectList* input)
// See http://bugs.ghostscript.com/show_bug.cgi?id=202735 // See http://bugs.ghostscript.com/show_bug.cgi?id=202735
data.emplace_back(new std::string("4000 4000 translate")); data.emplace_back(new std::string("4000 4000 translate"));
data.emplace_back(new std::string(header)); data.emplace_back(new std::string(header));
for(auto i=input->begin(); i!=input->end(); ++i) while(pos<size)
{
// Check if next argument is list
{
OBType<ObjectList> l(list->At(pos));
// Descending
if(l)
{ {
if(0==l->Size()) goto next;
lstack.push(std::make_pair(list,pos));
list=l;
pos=0;
size=l->Size();
continue;
}
}
// Check if first argument is string // Check if first argument is string
if(input->begin()==i) if(first)
{ {
OBType<ObjectString> s(*i); first=false;
OBType<ObjectString> s(list->At(pos));
if(s) if(s)
{ {
title=s->Value(); title=s->Value();
continue; goto next;
} }
} }
// Check if argument is pair // Check if argument is pair
{ {
OBType<ObjectPair> p(*i); OBType<ObjectPair> p(list->At(pos));
if(p) if(p)
{ {
std::string name=p->Name(); std::string name=p->Name();
tolower(name); tolower(name);
Base2Double d; Base2Double d(p->Value());
bool suc=true; bool suc=true;
double val=d.Convert(p->Value(),&suc,err); double val=d(&suc);
if(!suc) goto fail; // Conversion failed if(!suc) goto fail; // Conversion failed
suc=false; suc=false;
if("x"==name) {suc=true; xislocal=true; x=val;} if("x"==name) {suc=true; xislocal=true; x=val;}
@ -107,14 +127,14 @@ const ObjectBase* GMT_Map(const ObjectList* input)
if("yg"==name) {suc=true; yg=val;} if("yg"==name) {suc=true; yg=val;}
if("xgr"==name) {suc=true; xg+=val;} if("xgr"==name) {suc=true; xg+=val;}
if("ygr"==name) {suc=true; yg+=val;} if("ygr"==name) {suc=true; yg+=val;}
if(!suc) {err="Unknown parameter name: "+p->Name(); goto fail;} // Unknown name if(!suc) goto fail; // Unknown name
continue; goto next;
} }
} }
// Check if argument is layer // Check if argument is layer
{ {
OBType<ObjectGMTLayer> l(*i); OBType<ObjectGMTLayer> l(list->At(pos));
if(l) if(l)
{ {
struct gmt_layer layer=l->Data(); struct gmt_layer layer=l->Data();
@ -128,11 +148,22 @@ const ObjectBase* GMT_Map(const ObjectList* input)
data.emplace_back(new std::string(layer.EndShift())); data.emplace_back(new std::string(layer.EndShift()));
} }
else data.emplace_back(layer.data); else data.emplace_back(layer.data);
continue; goto next;
} }
} }
err="Unknown argument type: "+i->Type();
goto fail; // Unknown type of argument goto fail; // Unknown type of argument
next:
pos++;
// Ascending
if(pos==size && !lstack.empty())
{
list=lstack.top().first;
pos=lstack.top().second;
lstack.pop();
size=list->Size();
goto next;
}
} }
data.emplace_back(new std::string(footer)); data.emplace_back(new std::string(footer));
@ -144,7 +175,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
int ret; int ret;
ret=GhostRun("-sDEVICE=bbox",gs_bbox_callback,&in,0,&bboxes,0); // Bounding box is writed on stderr ret=GhostRun("-sDEVICE=bbox",gs_bbox_callback,&in,0,&bboxes,0); // Bounding box is writed on stderr
if(0!=ret) {err="Can't determine BoundingBox"; goto fail;} // Something wrong if(0!=ret) goto fail; // Something wrong
std::smatch m; std::smatch m;
std::smatch::const_iterator ci; std::smatch::const_iterator ci;
@ -152,7 +183,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
bool ok=true; bool ok=true;
std::regex_search(bboxes,m,r); std::regex_search(bboxes,m,r);
if(5!=m.size()) {err="Something go wrong, this is strange and scary"; goto fail; }// This is strange and scary if(5!=m.size()) goto fail; // This is strange and scary
ci=m.cbegin(); ci=m.cbegin();
ci++; // Skip full match ci++; // Skip full match
@ -160,7 +191,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
ok=ok && str2int(*ci++,&bbly); ok=ok && str2int(*ci++,&bbly);
ok=ok && str2int(*ci++,&bbrx); ok=ok && str2int(*ci++,&bbrx);
ok=ok && str2int(*ci++,&bbry); ok=ok && str2int(*ci++,&bbry);
if(!ok) {err="Unexpected error!"; goto fail;} // Unexpected! if(!ok) goto fail; // Unexpected!
// FIXME: Workaround ghostscript bug 202735 // FIXME: Workaround ghostscript bug 202735
// We add 5 points to each margin because ghostscript does'nt count linewidths when calculate bounding box // We add 5 points to each margin because ghostscript does'nt count linewidths when calculate bounding box
bblx-=4005; bblx-=4005;
@ -193,7 +224,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
} }
fail: fail:
return new ObjectError("Map",err); return 0;
} }
// Creating pdf from eps // Creating pdf from eps
@ -204,24 +235,39 @@ Optionally, resolution can be specified by pair with name resolution, res or r a
*/ */
const ObjectBase* GMT_Convert2PDF(const ObjectList* input) const ObjectBase* GMT_Convert2PDF(const ObjectList* input)
{ {
std::string err; if(!gs_abilities.havepdf) return 0; // No pdf support
RNFPar<SearchGMTMap,ObjectGMTMap> map("map"); double r;
ONPar<Base2PosD> r("resolution",720); bool suc=true;
ParseNamedParameters params(input,map,r); const ObjectGMTMap* map=0;
const ObjectGMTMap* m=map;
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support {
if(!params) {err=params.Error(); goto fail;} // Parsing error SearchParameterWDefO<double,DoubleDefaultVal<720>,false,PMin<1> > res(input,"r","res","resolution");
r=res(&suc);
if(!suc) goto fail; // Error
}
{
for(ObjectList::ListValues::size_type i=0;i<input->Size();i++)
{
OBType<ObjectGMTMap> m(input->At(i));
if(m)
{
if(0!=map) goto fail; // Duplicate
map=m;
}
}
if(0==map) goto fail; // Map not found
}
{ {
std::string* out=new std::string; std::string* out=new std::string;
int ret=eps2pdf(*(m->pValue()),out,r); int ret=eps2pdf(*(map->pValue()),out,r);
if(0!=ret) {err="Conversion of EPS to PDF failed"; delete out; goto fail; } // Something wrong if(0!=ret) { delete out; goto fail; } // Something wrong
return new ObjectGMTMapPDF(out,m->Bblx(),m->Bbly(),m->Bbrx(),m->Bbry()); return new ObjectGMTMapPDF(out,map->Bblx(),map->Bbly(),map->Bbrx(),map->Bbry());
} }
fail: fail:
return new ObjectError("EPS2PDF",err); return 0;
} }
@ -240,108 +286,112 @@ antialiasing or aa - can be used to set graphics and text antialiasing simultane
*/ */
const ObjectBase* GMT_Convert2PNG(const ObjectList* input) const ObjectBase* GMT_Convert2PNG(const ObjectList* input)
{ {
std::string gsdev,err; if(!gs_abilities.havepdf) return 0; // No pdf support, so, no png
double res; double r;
bool suc=true;
ONPar<Base2PosD> r("resolution",300),ds("d[own]scale",1.0); const GMTMap* map=0;
ONPar<Base2Pos> w("width"),h("height"); std::string gsdev("");
ONPar<Base2StringD> cs("c[olor][ ]space","color"),taa("t[ext]a[nti]aliasing","full"),gaa("g[raphics]a[nti]aliasing","full"),aa("a[nti]aliasing","full"); bool ispdf;
const ObjectGMTMap* me; uint aat=0,aag=0;
const ObjectGMTMapPDF* mp; std::string aats("full"),aags("full");
const GMTMap* m; uint dscale=0;
uint aat,aag;
uint dscale;
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support, so, no png // Map to convert
// Search map
{ {
RNFPar<SearchGMTMap,ObjectGMTMap> mapeps("map"); for(ObjectList::ListValues::size_type i=0;i<input->Size();i++)
RNFPar<SearchGMTMapPDF,ObjectGMTMap> mappdf("map"); {
ParseNamedParameters peps(input,mapeps); OBType<ObjectGMTMap> m(input->At(i));
ParseNamedParameters ppdf(input,mappdf); OBType<ObjectGMTMapPDF> p(input->At(i));
if(!(peps || ppdf)) {err="Error parsing map parameter"; goto fail;} if(m)
me=mapeps; mp=mappdf; {
if(nullptr==me && nullptr==mp) {err="Map parameter not specified"; goto fail;} // This must never happened if(0!=map) goto fail; // Duplicate
if(nullptr!=me) m=me; else m=mp; map=m;
ispdf=false;
} }
// Parse other parameters if(p)
{ {
ParseNamedParameters params(input,r,ds,w,h,cs,taa,gaa,aa); if(0!=map) goto fail; // Duplicate
if(!params) {err=params.Error(); goto fail;} map=p;
ispdf=true;
}
}
if(0==map) goto fail; // Map not found
} }
// Determine resolution // Determine resolution
{ {
SearchParameter<double,false,PMin<1> > res(input,"r","res","resolution");
BaseM2Double w(input,"width","w"), h(input,"height","h");
// Check existence // Check existence
if( ( r.Exist() && w.Exist() ) || ( r.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) {err="Only one of resolution, width or height may be specified"; goto fail;} // Only one parameter allowed if( ( res.Exist() && w.Exist() ) || ( res.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) goto fail; // Only one parameter allowed
if(r.Exist()) res=r; r=300; // Default value
if(w.Exist()) res=w*72.0/(m->Bbrx()-m->Bblx()); if(res.Exist()) r=res(&suc);
if(h.Exist()) res=h*72.0/(m->Bbry()-m->Bbly()); if(w.Exist()) r=w(&suc)*72.0/(map->Bbrx()-map->Bblx());
if(h.Exist()) r=h(&suc)*72.0/(map->Bbry()-map->Bbly());
if(!suc) goto fail; // Error
} }
// Color model // Color model
{ {
std::string cspace=cs; std::string cs;
tolower(cspace); BaseMD2String cspace(input,"8bit","colorspace","cspace","cs");
if(("mono" ==cspace || "monochrome" ==cspace ) && gs_abilities.havepngmono) gsdev="pngmono"; cs=cspace(&suc);
if(("monod"==cspace || "monodiffused"==cspace ) && gs_abilities.havepngmonod) gsdev="pngmonod"; if(!suc) goto fail; // Error
if(("16c" ==cspace || "16" ==cspace ) && gs_abilities.havepng16) gsdev="png16"; tolower(cs);
if(("256c" ==cspace || "256" ==cspace ) && gs_abilities.havepng256) gsdev="png256"; if(("mono"==cs || "monochrome"==cs) && gs_abilities.havepngmono) gsdev="pngmono";
if(("gray" ==cspace || "grey" ==cspace || "g" ==cspace) && gs_abilities.havepnggray) gsdev="pnggray"; if(("monod"==cs || "monodiffused"==cs) && gs_abilities.havepngmonod) gsdev="pngmonod";
if(("full" ==cspace || "8bit" ==cspace || "color"==cspace) && gs_abilities.havepng16m) gsdev="png16m"; if(("16c"==cs || "16"==cs) && gs_abilities.havepng16) gsdev="png16";
if(gsdev.empty()) {err="Colorspace "+cs.Value()+" is bad or unsupported"; goto fail;} // Incorrect value if(("256c"==cs || "256"==cs) && gs_abilities.havepng256) gsdev="png256";
if(("gray"==cs || "grey"==cs || "g"==cs) && gs_abilities.havepnggray) gsdev="pnggray";
if(("full"==cs || "8bit"==cs || "color"==cs) && gs_abilities.havepng16m) gsdev="png16m";
if(""==gsdev) goto fail; // Incorrect value
} }
// Antialiasing // Antialiasing
{ {
std::string aags=aa,aats=aa; BaseM2String aa(input,"antialiasing","aa"),taa(input,"textantialiasing","taa"),gaa(input,"graphicsantialiasing","gaa");
if(taa.Exist()) aats=taa; if(aa.Exist()) aags=aats=aa(&suc);
if(gaa.Exist()) aags=gaa; if(taa.Exist()) aats=taa(&suc);
if(gaa.Exist()) aags=gaa(&suc);
if(!suc) goto fail; // Error
tolower(aags); tolower(aats); tolower(aags); tolower(aats);
if("none"==aags || "no"==aags || "n"==aags) aag=1; if("none"==aats || "no"==aats || "n"==aats) aat=1;
if("none" ==aags || "no"==aags || "n"==aags) aag=1; if("small"==aags || "s"==aags) aag=2; if("small"==aats || "s"==aats) aat=2;
if("none" ==aats || "no"==aats || "n"==aats) aat=1; if("full"==aags || "f"==aags) aag=4; if("full"==aats || "f"==aats) aat=4;
if(0==aat || 0==aag) goto fail; // Incorrect value
if("small"==aags || "s" ==aags ) aag=2;
if("small"==aats || "s" ==aats ) aat=2;
if("full" ==aags || "f" ==aags ) aag=4;
if("full" ==aats || "f" ==aats ) aat=4;
if(0==aat) {err="Incorrect value for text antialiasing: "+aats; goto fail;}
if(0==aag) {err="Incorrect value for graphics antialiasing: "+aags; goto fail;}
} }
// Downscale // Downscale
if("pngmonod"==gsdev || "pnggray"==gsdev || "png16m"==gsdev) if("pngmonod"==gsdev || "pnggray"==gsdev || "png16m"==gsdev)
{ {
dscale=static_cast<uint>(ds); SearchParameterWDefO<double,DoubleDefaultVal<1>,false,PMin<1>,PMax<10>,PInt > ds(input,"downscale","dscale","ds");
if(dscale<1 || dscale>10) {err="Downscale must be in interval from 1 to 10"; goto fail;} dscale=static_cast<uint>(ds(&suc));
res*=dscale; if(!suc) goto fail; // Error
r*=dscale;
} }
// Go! // Go!
{ {
std::string* pdf=0; std::string* pdf=0;
int ret; int ret;
if(nullptr!=me) if(!ispdf)
{ {
pdf=new std::string; pdf=new std::string;
ret=eps2pdf(*(me->pValue()),pdf,r,aat,aag); ret=eps2pdf(*(map->pValue()),pdf,r,aat,aag);
if(0!=ret) {err="Can't convert EPS to PDF"; delete pdf; goto fail; } // Something wrong if(0!=ret) { delete pdf; goto fail; } // Something wrong
} }
{ {
std::string* out=new std::string; std::string* out=new std::string;
ret=GhostRun("-r"+ToString(res)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+((dscale>1)?(" -dDownScaleFactor="+ToString(dscale)):""),((0!=pdf)?*pdf:*(mp->pValue())),0,0,out); ret=GhostRun("-r"+ToString(r)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+((dscale>1)?(" -dDownScaleFactor="+ToString(dscale)):""),((0!=pdf)?*pdf:*(map->pValue())),0,0,out);
if(0!=pdf) delete pdf; if(0!=pdf) delete pdf;
if(0!=ret) {err="Can't convert PDF to PNG"; delete out; goto fail; } // Something wrong if(0!=ret) { delete out; goto fail; } // Something wrong
return new ObjectGMTImage(out); return new ObjectGMTImage(out);
} }
} }
fail: fail:
return new ObjectError("EPS2PNG",err); return 0;
} }
@ -360,101 +410,104 @@ antialiasing or aa - can be used to set graphics and text antialiasing simultane
*/ */
const ObjectBase* GMT_Convert2JPG(const ObjectList* input) const ObjectBase* GMT_Convert2JPG(const ObjectList* input)
{ {
std::string gsdev,err; if(!gs_abilities.havepdf) return 0; // No pdf support, so, no jpeg
double r;
ONPar<Base2PosD> r("resolution",300); bool suc=true;
ONPar<Base2Pos> w("width"),h("height"); const GMTMap* map=0;
ONPar<Base2StringD> cs("c[olor][ ]space","color"),taa("t[ext]a[nti]aliasing","full"),gaa("g[raphics]a[nti]aliasing","full"),aa("a[nti]aliasing","full"); std::string gsdev("");
ONPar<Base2NonNegD> q("quality",75); bool ispdf;
const ObjectGMTMap* me; uint aat=0,aag=0;
const ObjectGMTMapPDF* mp; std::string aats("full"),aags("full");
const GMTMap* m;
double res;
uint aat,aag;
uint qual; uint qual;
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support, so, no jpeg // Map to convert
// Search map {
for(ObjectList::ListValues::size_type i=0;i<input->Size();i++)
{ {
RNFPar<SearchGMTMap,ObjectGMTMap> mapeps("map"); OBType<ObjectGMTMap> m(input->At(i));
RNFPar<SearchGMTMapPDF,ObjectGMTMap> mappdf("map"); OBType<ObjectGMTMapPDF> p(input->At(i));
ParseNamedParameters peps(input,mapeps); if(m)
ParseNamedParameters ppdf(input,mappdf); {
if(!(peps || ppdf)) {err="Error parsing map parameter"; goto fail;} if(0!=map) goto fail; // Duplicate
me=mapeps; mp=mappdf; map=m;
if(nullptr==me && nullptr==mp) {err="Map parameter not specified"; goto fail;} // This must never happened ispdf=false;
if(nullptr!=me) m=me; else m=mp;
} }
// Parse other parameters if(p)
{ {
ParseNamedParameters params(input,r,q,w,h,cs,taa,gaa,aa); if(0!=map) goto fail; // Duplicate
if(!params) {err=params.Error(); goto fail;} map=p;
ispdf=true;
}
}
if(0==map) goto fail; // Map not found
} }
// Determine resolution // Determine resolution
{ {
SearchParameter<double,false,PMin<1> > res(input,"r","res","resolution");
BaseM2Double w(input,"width","w"), h(input,"height","h");
// Check existence // Check existence
if( ( r.Exist() && w.Exist() ) || ( r.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) {err="Only one of resolution, width or height may be specified"; goto fail;} // Only one parameter allowed if( ( res.Exist() && w.Exist() ) || ( res.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) goto fail; // Only one parameter allowed
if(r.Exist()) res=r; r=300; // Default value
if(w.Exist()) res=w*72.0/(m->Bbrx()-m->Bblx()); if(res.Exist()) r=res(&suc);
if(h.Exist()) res=h*72.0/(m->Bbry()-m->Bbly()); if(w.Exist()) r=w(&suc)*72.0/(map->Bbrx()-map->Bblx());
if(h.Exist()) r=h(&suc)*72.0/(map->Bbry()-map->Bbly());
if(!suc) goto fail; // Error
} }
// Color model // Color model
{ {
std::string cspace=cs; std::string cs;
tolower(cspace); BaseMD2String cspace(input,"8bit","colorspace","cspace","cs");
if(("gray"==cspace || "grey"==cspace || "g" ==cspace) && gs_abilities.havejpeggray) gsdev="jpeggray"; cs=cspace(&suc);
if(("full"==cspace || "8bit"==cspace || "color"==cspace) && gs_abilities.havejpeg) gsdev="jpeg"; if(!suc) goto fail; // Error
if(gsdev.empty()) {err="Colorspace "+cs.Value()+" is bad or unsupported"; goto fail;} // Incorrect value tolower(cs);
if(("gray"==cs || "grey"==cs || "g"==cs) && gs_abilities.havejpeggray) gsdev="jpeggray";
if(("full"==cs || "8bit"==cs || "color"==cs) && gs_abilities.havejpeg) gsdev="jpeg";
if(""==gsdev) goto fail; // Incorrect value
} }
// Antialiasing // Antialiasing
{ {
std::string aags=aa,aats=aa; BaseM2String aa(input,"antialiasing","aa"),taa(input,"textantialiasing","taa"),gaa(input,"graphicsantialiasing","gaa");
if(taa.Exist()) aats=taa; if(aa.Exist()) aags=aats=aa(&suc);
if(gaa.Exist()) aags=gaa; if(taa.Exist()) aats=taa(&suc);
if(gaa.Exist()) aags=gaa(&suc);
if(!suc) goto fail; // Error
tolower(aags); tolower(aats); tolower(aags); tolower(aats);
if("none"==aags || "no"==aags || "n"==aags) aag=1; if("none"==aats || "no"==aats || "n"==aats) aat=1;
if("none" ==aags || "no"==aags || "n"==aags) aag=1; if("small"==aags || "s"==aags) aag=2; if("small"==aats || "s"==aats) aat=2;
if("none" ==aats || "no"==aats || "n"==aats) aat=1; if("full"==aags || "f"==aags) aag=4; if("full"==aats || "f"==aats) aat=4;
if(0==aat || 0==aag) goto fail; // Incorrect value
if("small"==aags || "s" ==aags ) aag=2;
if("small"==aats || "s" ==aats ) aat=2;
if("full" ==aags || "f" ==aags ) aag=4;
if("full" ==aats || "f" ==aats ) aat=4;
if(0==aat) {err="Incorrect value for text antialiasing: "+aats; goto fail;}
if(0==aag) {err="Incorrect value for graphics antialiasing: "+aags; goto fail;}
} }
// Quality // Quality
{ {
qual=static_cast<uint>(q); SearchParameterWDefO<double,DoubleDefaultVal<75>,false,PMin<0>,PMax<100>,PInt > q(input,"quality","qual","q");
if(q>100) {err="JPEG quality must not exceed 100"; goto fail;} // Error qual=static_cast<uint>(q(&suc));
if(!suc) goto fail; // Error
} }
// Go! // Go!
{ {
std::string* pdf=0; std::string* pdf=0;
int ret; int ret;
if(nullptr!=me) if(!ispdf)
{ {
pdf=new std::string; pdf=new std::string;
ret=eps2pdf(*(me->pValue()),pdf,r,aat,aag); ret=eps2pdf(*(map->pValue()),pdf,r,aat,aag);
if(0!=ret) {err="Can't convert EPS to PDF"; delete pdf; goto fail; } // Something wrong if(0!=ret) { delete pdf; goto fail; } // Something wrong
} }
{ {
std::string* out=new std::string; std::string* out=new std::string;
ret=GhostRun("-r"+ToString(res)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+" -dJPEGQ="+ToString(qual),((0!=pdf)?*pdf:*(mp->pValue())),0,0,out); ret=GhostRun("-r"+ToString(r)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+" -dJPEGQ="+ToString(qual),((0!=pdf)?*pdf:*(map->pValue())),0,0,out);
if(0!=pdf) delete pdf; if(0!=pdf) delete pdf;
if(0!=ret) {err="Can't convert PDF to JPEG"; delete out; goto fail; } // Something wrong if(0!=ret) { delete out; goto fail; } // Something wrong
return new ObjectGMTImage(out); return new ObjectGMTImage(out);
} }
} }
fail: fail:
return new ObjectError("EPS2JPEG",err); return 0;
} }

23
modules/gmt/modgmt_map.h

@ -72,29 +72,12 @@ class ObjectGMTImage: public GMTBlob
std::string Type() const override {return "GMTImage";} std::string Type() const override {return "GMTImage";}
}; };
// Convertor to search object // Policy for get integer value
template<class Object> class PInt
class SearchObject
{ {
public: public:
using ValueType=const Object*; double operator()(double v, bool* suc) const {if(v!=floor(v)) *suc=false; return v;}
template<class... Args>
ValueType Convert(const ObjectBase* ob, bool* res, std::string& err, Args... args)
{
OBType<Object> gp(ob);
switch(gp.Error())
{
case(OBTypeErr::OK): return gp;
case(OBTypeErr::NULLPTR): {err="Can't convert zero ObjectBase pointer to something meaningfull"; break;}
case(OBTypeErr::TYPEMISMATCH): {err=ob->Type()+" is not correct: type mismatch"; break;}
}
*res=false;
return nullptr;
}
}; };
// Convertor to search GMTMap objects
using SearchGMTMap=SearchObject<ObjectGMTMap>;
using SearchGMTMapPDF=SearchObject<ObjectGMTMapPDF>;
// Creating eps map from set of layers // Creating eps map from set of layers
const ObjectBase* GMT_Map(const ObjectList* input); const ObjectBase* GMT_Map(const ObjectList* input);

40
modules/gmt/modgmt_objects.cpp

@ -36,15 +36,41 @@ std::map<std::string,gmt_projection::projection> gmt_projection::projnames;
void gmt_projection::FillProjNames() void gmt_projection::FillProjNames()
{ {
projnames["(xy|decart)"]=XY; projnames["x"]=XY;
projnames["c[ylindrical][( |_)]equidistant"]=CYL_EQU; projnames["xy"]=XY;
projnames["decart"]=XY;
projnames["q"]=CYL_EQU;
projnames["cyl_equid"]=CYL_EQU;
projnames["cylindrical equidistant"]=CYL_EQU;
projnames["m"]=MERCATOR;
projnames["merc"]=MERCATOR;
projnames["mercator"]=MERCATOR; projnames["mercator"]=MERCATOR;
projnames["t[ransverse][( |_)]mercator"]=TRANSMERCATOR;
projnames["o[blique][( |_)]mercator"]=OBLIQMERCATOR; projnames["t"]=TRANSMERCATOR;
projnames["tmerc"]=TRANSMERCATOR;
projnames["transverse mercator"]=TRANSMERCATOR;
projnames["o"]=OBLIQMERCATOR;
projnames["omerc"]=OBLIQMERCATOR;
projnames["oblique mercator"]=OBLIQMERCATOR;
projnames["c"]=CASSINI;
projnames["cassini"]=CASSINI; projnames["cassini"]=CASSINI;
projnames["c[ylindrical][( |_)]eq[ua(l|l-)]area"]=CYL_EQA;
projnames["[c[ylindrical][( |_)]]miller"]=MILLER; projnames["y"]=CYL_EQA;
projnames["c[ylindrical][( |_)]stereographic"]=CYL_STERE; projnames["cyl_equala"]=CYL_EQA;
projnames["cylindrical equal-area"]=CYL_EQA;
projnames["cylindrical equalarea"]=CYL_EQA;
projnames["j"]=MILLER;
projnames["cyl_miller"]=MILLER;
projnames["miller"]=MILLER;
projnames["cylindrical miller"]=MILLER;
projnames["cyl_stere"]=CYL_STERE;
projnames["cylindrical stereographic"]=CYL_STERE;
} }
bool gmt_font::FillFontNames() bool gmt_font::FillFontNames()

297
modules/gmt/modgmt_param.h

@ -1,297 +0,0 @@
#ifndef MODGMT_PARAM_H
#define MODGMT_PARAM_H
#include "modgmt_strcomp.h"
#include "common.h"
// Common ancestor for all parameters
template<class Converter, bool Optional>
class Parameter
{
using ValueType=typename Converter::ValueType;
std::string name; // Used for error reporting
bool initialised;
Converter conv;
ValueType val;
template<bool hasDefault, class Conv=Converter>
struct Adapter;
template<class Conv>
struct Adapter<true,Conv> {static const typename Conv::ValueType& Val(const Conv& cnv) {return cnv.Default();}};
template<class Conv>
struct Adapter<false,Conv> {static typename Conv::ValueType Val(const Conv& cnv) {return typename Conv::ValueType();}};
template<class C>
struct CheckDefault
{
private:
static void detect(...);
template<class T> static decltype(std::declval<T>().Default()) detect(T);
public:
static constexpr bool value=std::is_same<ValueType, typename std::decay<decltype(detect(std::declval<C>()))>::type>::value;
};
protected:
Parameter(Parameter&&) = delete;
Parameter(const Parameter&) = delete;
Parameter() = delete;
template<class... Args>
Parameter(std::string&& str, Args... args): name(std::move(str)), initialised(false), conv(args...)
{
val=Adapter<CheckDefault<Converter>::value>::Val(conv);
}
template<class... Args>
Parameter(const std::string& str, Args... args): name(str), initialised(false), conv(args...)
{
val=Adapter<CheckDefault<Converter>::value>::Val(conv);
}
void SetState(bool newini) {initialised=newini;}
public:
bool Init(const ObjectBase* p, std::string& err)
{
std::string cerr;
bool res=true;
ValueType tval=conv.Convert(p,&res,cerr);
SetState(res);
if(res) val=std::move(tval);
else err=std::move(cerr);
return res;
}
bool Initialised() const {return initialised;}
bool Exist() const {return initialised;}
const std::string& Name() const {return name;}
constexpr bool isOptional() const {return Optional;}
const ValueType& Value() {return val;}
const ValueType* operator->() const {return &val;}
operator const ValueType&() {return val;}
void Reset() {initialised=false; val=Adapter<CheckDefault<Converter>::value>::Val(conv);}
static constexpr bool optional=Optional;
using ConverterType=Converter;
};
// Class for parameter which must be in named pair
template <class Converter, bool O>
class NamedParameter: public TemplateComparator, public Parameter<Converter,O>
{
public:
using AcceptableObject=void;
template<class... Args>
NamedParameter(const std::string& t, Args... args):TemplateComparator(t),Parameter<Converter,O>(Template2Name(),args...) {}
};
// Class for parameter which can be in named pair or as object of type Object
template <class Converter, bool O, class Object>
class NamedFreeParameter: public NamedParameter<Converter,O>
{
public:
using AcceptableObject=Object;
template<class... Args>
NamedFreeParameter(Args... args):NamedParameter<Converter,O>(args...) {}
};
// Class for parameter which can be in some positions in list
template <class Converter, bool O>
class PositionalParameter: public Parameter<Converter,O>
{
public:
template<class... Args>
PositionalParameter(Args... args):Parameter<Converter,O>(args...) {}
};
// Base class for ParseNamedParameters and ParsePositionalParameters
class ParseParameters
{
protected:
std::string err;
ParseParameters():err() {}
ParseParameters(const ParseParameters&) = delete;
ParseParameters(ParseParameters&&) = delete;
public:
std::string Error() const {return err;}
bool Ok() const {return err.empty();}
operator bool() const {return Ok();}
};
// Parsing positional parameters
class ParsePositionalParameters: public ParseParameters
{
ParsePositionalParameters() = delete;
ParsePositionalParameters(const ParsePositionalParameters&) = delete;
ParsePositionalParameters(ParsePositionalParameters&&) = delete;
// Main parsing function
template <class Par, class... Args>
void Parse(ObjectList::IndexType i, ObjectList::IndexType max, const ObjectList* ol, Par& param, Args&... args)
{
// Check types of arguments
static_assert(std::is_same<PositionalParameter<typename Par::ConverterType, Par::optional>,Par>::value,"ParsePositionalParameters argument(s) must be PositionalParameter");
// Check if parameter already initialised. This is code error.
if(param.Initialised())
{
err="Parameter "+param.Name()+" already initialised. This is code error.";
return;
}
// List is ended
if(i>=max)
{
// Parameter is optional, skip it
if(Par::optional) Parse(i,max,ol,args...);
// Parameter is required, this is an error
else err="Parameter "+param.Name()+" is required, but can't be setted because list is ended";
}
// Initialise from some list element
else
{
bool res=param.Init(ol->At(i),err);
// All Ok, continue to next element in list
if(res) Parse(i+1,max,ol,args...);
else
{
// All Ok, optional parameter may be absent, try to initialise next parameter by same list element
if(Par::optional) Parse(i,max,ol,args...);
// Error, required parameter not initialised
else err="Can't initialise parameter "+param.Name()+" from list element number "+ToString(i)+": "+err;
}
}
}
// Bottom of recursion
void Parse(ObjectList::IndexType i, ObjectList::IndexType max, const ObjectList* ol) {if(i<max) err="There are excess elements in list";}
public:
template <class Converter, bool optional, class... Args>
ParsePositionalParameters(const ObjectList* ol, PositionalParameter<Converter,optional>& p1, Args&... args) {Parse(0,ol->Size(),ol,p1,args...);}
template <class Converter, bool optional, class... Args>
ParsePositionalParameters(const ObjectList* ol, ObjectList::IndexType min, ObjectList::IndexType max, PositionalParameter<Converter,optional>& p1, Args&... args) {Parse(min,std::min(max,ol->Size()),ol,p1,args...);}
};
// Parsing named parameters
class ParseNamedParameters: public ParseParameters
{
ParseNamedParameters() = delete;
ParseNamedParameters(const ParseNamedParameters&) = delete;
ParseNamedParameters(ParseNamedParameters&&) = delete;
// Parsing function for elements without names
// ob - object from which we initialise parameter param.
// init - is ob was already used for initialise something.
// args - other parameters
// Function try to initialise parameter param, if param accepted real type of ob for initialisation, else function try to initialise next parameter in args.
// Function return error if initialisation of parameter failed or if two parameters can be initialised from ob.
template <class Par, class... Args>
bool ParseSingle(const ObjectBase* ob, bool init, Par& param, Args&... args)
{
// Check types of arguments
static_assert(std::is_same<NamedParameter<typename Par::ConverterType, Par::optional>,Par>::value || std::is_same<NamedFreeParameter<typename Par::ConverterType, Par::optional, typename Par::AcceptableObject>,Par>::value,"ParseNamedParameters argument(s) must be NamedParameter or NamedFreeParameter");
OBType<typename Par::AcceptableObject> o(ob);
if(o && init)
{
err="Object of type "+ob->Type()+" used for initialisation of two parameters. This is code error.";
return false;
}
if(!o) return ParseSingle(ob,init,args...); // Type mismatch, goto next parameter
if(param.Initialised())
{
err="Parameter "+param.Name()+" can't be initialised from object of type "+ob->Type()+" because it already initialised.";
return false;
}
std::string ierr;
if(!param.Init(ob,ierr))
{
err="Parameter "+param.Name()+" can't be initialised from object of type "+ob->Type()+": "+ierr;
return false;
}
return ParseSingle(ob,true,args...);
}
// Bottom of recursion
bool ParseSingle(const ObjectBase* ob, bool init) const {return true;}
// Parsing function for elements in pairs
// op - pair from which we initialise parameter param.
// pname - name of parameter already initialised from op (or empty string).
// args - other parameters
// Function try to initialise parameter param, if pair name corresponding to param template, else function try to initialise next parameter in args.
// Function return error if initialisation of parameter failed or if two parameters can be initialised from op.
template <class Par, class... Args>
bool ParsePair(const ObjectPair* op, std::string& pname, Par& param, Args&... args)
{
// Check types of arguments
static_assert(std::is_same<NamedParameter<typename Par::ConverterType, Par::optional>,Par>::value || std::is_same<NamedFreeParameter<typename Par::ConverterType, Par::optional, typename Par::AcceptableObject>,Par>::value,"ParseNamedParameters argument(s) must be NamedParameter or NamedFreeParameter");
bool cmp=param.Compare(op->Name());
if(cmp && !pname.empty())
{
err="Element "+op->Name()+" can be used for initialisation of two parameters: "+pname+" and "+param.Name();
return false;
}
if(!cmp) return ParsePair(op,pname,args...); // Name mismatch, goto next parameter
pname=param.Name();
if(param.Initialised())
{
err="Parameter "+param.Name()+" can't be initialised from element "+op->Name()+" because it already initialised.";
return false;
}
std::string ierr;
if(!param.Init(op->Value(),ierr))
{
err="Parameter "+param.Name()+" can't be initialised from element "+op->Name()+": "+ierr;
return false;
}
return ParsePair(op,pname,args...);
}
// Bottom of recursion
bool ParsePair(const ObjectPair* op, std::string& pname) const {return true;}
template <class Par, class... Args>
void CheckRequired(const Par& param, Args&... args)
{
if((Par::optional || param.Initialised())) CheckRequired(args...);
else err="Parameter "+param.Name()+" is required, but not initialised";
}
// Bottom of recursion
void CheckRequired() const {}
public:
template <class... Args>
ParseNamedParameters(const ObjectList* ol, Args&... args)
{
// Initialisation
std::string pname;
for(ObjectList::const_iterator i=ol->begin();i!=ol->end();++i)
{
pname.erase();
OBType<ObjectPair> p(*i);
if( !(p?ParsePair(p,pname,args...):ParseSingle(*i,false,args...)) ) break;
}
if(!Ok()) return; // Error on initialisation phase
// Check if all required parameters are initialised
CheckRequired(args...);
}
};
template<class Converter>
using ONPar=NamedParameter<Converter,true>;
template<class Converter>
using RNPar=NamedParameter<Converter,false>;
template<class Converter, class Object>
using ONFPar=NamedFreeParameter<Converter,true,Object>;
template<class Converter, class Object>
using RNFPar=NamedFreeParameter<Converter,false,Object>;
template<class Converter>
using OPosPar=PositionalParameter<Converter,true>;
template<class Converter>
using RPosPar=PositionalParameter<Converter,false>;
#endif

139
modules/gmt/modgmt_strcomp.cpp

@ -1,139 +0,0 @@
#include "modgmt_strcomp.h"
TemplateComparator::Block::pBlock TemplateComparator::Parse()
{
size_t e=0;
struct Block* blk;
struct Block* root;
auto c=s[e];
bool init,next;
// First symbol
if('['==c || '('==c) blk=new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS);
else blk=new Block(e,e+1);
root=blk;
init=root->type!=Block::TEXT;
next=!init;
e++;
while(e<s.length())
{
c=s[e];
switch(c)
{
case '[':
case '(':
{
(next?blk->next:blk->child).reset(new Block(('['==c)?Block::OPTIONAL:Block::VARIANTS,(next?blk->parent:blk)));
blk=(next?blk->next:blk->child).get();
init=true;
next=false;
break;
}
case ']':
case ')':
{
blk=const_cast<struct Block*>(blk->parent);
init=true;
next=true;
break;
}
case '|': {blk->next.reset(new Block(Block::DELIM,blk->parent)); blk=blk->next.get(); init=next=true; break;}
default:
{
if(init)
{
(next?blk->next:blk->child).reset(new Block(e,e+1,(next?blk->parent:blk)));
blk=(next?blk->next:blk->child).get();
}
else blk->e=e+1;
init=false;
next=true;
}
}
e++;
}
return Block::pBlock(root);
}
void TemplateComparator::InitCursors(const struct TemplateComparator::Block* blk)
{
switch(blk->type)
{
case Block::TEXT: {cursors.insert({blk,0}); break;}
case Block::OPTIONAL:
{
auto b=blk;
InitCursors(b->child.get());
while(true)
{
if(!b->next) break;
b=b->next.get();
InitCursors(b);
if(b->type!=Block::OPTIONAL) break;
}
break;
}
case Block::VARIANTS:
{
auto b=blk->child.get();
while(true)
{
InitCursors(b);
while(b->type!=Block::DELIM)
{
if(!b->next) break;
b=b->next.get();
}
if(!b->next) break;
b=b->next.get();
}
}
default: {}
}
}
bool TemplateComparator::CmpSmb(const char c)
{
pCursor p=cursors.cbegin();
bool res=false;
// Compare symbol with all cursors
while(p!=cursors.end())
{
if(p->compare(s,c)) {res=true; p++;}
else p=cursors.erase(p);
}
Cursors old(std::move(cursors));
for(const auto& p:old)
{
auto blk=p.block;
// Increment cursors
if(blk->b+p.offset+1<blk->e) cursors.insert({blk,p.offset+1}); // Advance in current block
else // Move to next block
{
if(!blk->next || blk->next->type==Block::DELIM) // End of chain, must go up
{
while(blk->parent!=nullptr)
{
blk=blk->parent;
if(!blk->next || blk->next->type==Block::DELIM) continue;
InitCursors(blk->next.get());
}
}
else InitCursors(blk->next.get()); // Next block in chain
}
// Try to leave optional blocks
blk=p.block;
while(blk->parent!=nullptr)
{
blk=blk->parent;
if(blk->type!=Block::OPTIONAL || !blk->next || blk->next->type==Block::DELIM) continue;
InitCursors(blk->next.get());
}
}
return res;
}

98
modules/gmt/modgmt_strcomp.h

@ -1,98 +0,0 @@
#ifndef MODGMT_STRCOMP_H
#define MODGMT_STRCOMP_H
#include <memory>
#include <set>
#include <string>
// Compare string with template
class TemplateComparator
{
TemplateComparator() = delete;
TemplateComparator(const TemplateComparator&) = delete;
TemplateComparator(TemplateComparator&&) = delete;
struct Block
{
using pBlock=std::unique_ptr<struct Block>;
enum Type {NOTDEF,TEXT,OPTIONAL,VARIANTS,DELIM};
size_t b,e;
Type type;
const struct Block* parent;
pBlock next,child;
Block() = delete;
Block(const struct Block&) = delete;
Block(struct Block&&) = delete;
Block(Type t, const struct Block* p=nullptr):b(0),e(0),type(t),parent(p),next(nullptr),child(nullptr) {}
Block(size_t bb, size_t ee, const struct Block* p=nullptr):b(bb),e(ee),type(TEXT),parent(p),next(nullptr),child(nullptr) {}
};
struct Cursor
{
const struct Block* block;
size_t offset;
bool operator <(const struct Cursor& c) const {return block<c.block;}
bool compare(const std::string& str, const char c) const {return c==str[block->b+offset];}
Cursor(const struct Block* b, size_t o):block(b),offset(o) {}
};
using Cursors=std::set<struct Cursor>;
using pCursor=std::set<struct Cursor>::const_iterator;
Block::pBlock Parse();
void InitCursors(const struct Block* blk);
bool CmpSmb(const char c);
Block::pBlock root;
Cursors cursors;
const std::string s;
void Reset()
{
cursors.clear();
InitCursors(root.get());
}
public:
TemplateComparator(const char* str):s(str) {root=Parse();}
TemplateComparator(const std::string& str):s(str) {root=Parse();}
TemplateComparator(std::string&& str):s(std::move(str)) {root=Parse();}
bool Compare(const std::string& str)
{
Reset();
for(size_t pos=0; pos<str.length(); ++pos) if(!CmpSmb(str[pos])) return false;
return true;
}
std::string Template2Name() const
{
const struct Block* b=root.get();
std::string res;
while(true)
{
// Processing current block
switch(b->type)
{
case(Block::TEXT): {res+=s.substr(b->b,b->e-b->b); break;}
case(Block::OPTIONAL):
case(Block::VARIANTS): {b=b->child.get(); goto next;}
case(Block::DELIM): {b=b->parent; break;}
default: {}
}
// Go to next block
while(true)
{
if(nullptr!=b->next) {b=b->next.get(); goto next;}
if(nullptr!=b->parent) b=b->parent;
else break;
}
if(nullptr==b->next && nullptr==b->parent) break;
next: ;
}
return res;
}
};
#endif

223
modules/gmt/modgmt_structs.h

@ -6,7 +6,6 @@
#include <vector> #include <vector>
#include "common.h" #include "common.h"
#include "modgmt_colornames.h" #include "modgmt_colornames.h"
#include "modgmt_strcomp.h"
// Centimeters to GMT points scale factor // Centimeters to GMT points scale factor
// 1 inch = 72 pt = 2.54 cm --> 1 cm = 72/2.54 pt // 1 inch = 72 pt = 2.54 cm --> 1 cm = 72/2.54 pt
@ -32,7 +31,7 @@ class GetDouble<Source, Policy, Policies...>: public GetDouble<Source, Policies.
GetDouble(GetDouble&) = delete; GetDouble(GetDouble&) = delete;
template<class... Args> template<class... Args>
GetDouble(Args... args):GetDouble<Source,Policies...>(args...) {}; GetDouble(Args... args):GetDouble<Source,Policies...>(args...) {};
double operator()(bool* suc, std::string& err) const {return p(GetDouble<Source,Policies...>::operator()(suc,err),suc,err);} double operator()(bool* suc) const {return p(GetDouble<Source,Policies...>::operator()(suc),suc);}
}; };
// Bottom of recursion // Bottom of recursion
@ -45,57 +44,37 @@ class GetDouble<Source>: public Source
GetDouble() = delete; GetDouble() = delete;
template<class... Args> template<class... Args>
GetDouble(Args... args):Source(args...) {}; GetDouble(Args... args):Source(args...) {};
double operator()(bool* suc, std::string& err) const {return Source::operator()(suc, err);} 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 // 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 // Policy to check if value is greater or equal num/denum
template<int32_t num, uint32_t denum=1, bool equal=true> template<int32_t num, uint32_t denum=1>
class PMin class PMin
{ {
static bool Compare(double d1, double d2) {return equal?(d1<=d2):(d1<d2);}
public: public:
double operator()(double v, bool* suc, std::string& err) const double operator()(double v, bool* suc) const {if(v<static_cast<double>(num)/denum) *suc=false; return v;}
{
if(Compare(v,static_cast<double>(num)/denum))
{
*suc=false;
if(err.empty()) err="Value "+ToString(v)+" must be greater "+(equal?"or equal ":"")+"then "+ToString(num)+((denum==1)?"":("/"+ToString(denum)));
}
return v;
}
}; };
// Policy to check if value is lesser or equal num/denum // Policy to check if value is lesser or equal num/denum
template<int32_t num, uint32_t denum=1, bool equal=true> template<int32_t num, uint32_t denum=1>
class PMax class PMax
{ {
static bool Compare(double d1, double d2) {return equal?(d1>=d2):(d1>d2);}
public: public:
double operator()(double v, bool* suc, std::string& err) const double operator()(double v, bool* suc) const {if(v>static_cast<double>(num)/denum) *suc=false; return v;}
{
if(Compare(v,static_cast<double>(num)/denum))
{
*suc=false;
if(err.empty()) err="Value "+ToString(v)+" must be lesser "+(equal?"or equal ":"")+"then "+ToString(num)+((denum==1)?"":("/"+ToString(denum)));
}
return v;
}
}; };
// Get double value from string or number // Get double value from string or number
class SourceValue class SourceValue
{ {
double d; double d;
std::string err; bool ok;
public: public:
SourceValue(const std::string& s) {if(!str2double(s,&d)) err="Can't convert string \""+s+"\" to double value";} SourceValue(const std::string& s) {ok=str2double(s,&d);}
SourceValue(double s):d(s) {} SourceValue(double s):d(s),ok(true) {}
double operator()(bool* suc, std::string& ierr) const double operator()(bool* suc) const
{ {
if(!err.empty()) {*suc=false; ierr=err;} if(!ok) *suc=false;
return d; return d;
} }
}; };
@ -103,7 +82,7 @@ class SourceValue
// Helper types for colors // Helper types for colors
typedef GetDouble<SourceValue,PMin<0>,PMax<255> > Value2RGB; typedef GetDouble<SourceValue,PMin<0>,PMax<255> > Value2RGB;
typedef GetDouble<SourceValue,PMin<0>,PMax<360> > Value2Hue; typedef GetDouble<SourceValue,PMin<0>,PMax<360> > Value2Hue;
typedef GetDouble<SourceValue,PMin<0>,PMax< 1 > > Value2SV; typedef GetDouble<SourceValue,PMin<0>,PMax<1> > Value2SV;
typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2CMYK; typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2CMYK;
typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2Transp; typedef GetDouble<SourceValue,PMin<0>,PMax<100> > Value2Transp;
// Helper type for pens and dashes // Helper type for pens and dashes
@ -137,8 +116,7 @@ struct gmt_coord: public gmt_struct
if(isdeg) return (d+(m+s/60.0)/60.0)*(sign?1:-1); if(isdeg) return (d+(m+s/60.0)/60.0)*(sign?1:-1);
else return r; else return r;
} }
bool Convert(const std::string& str)
bool Convert(const std::string& str, std::string& err)
{ {
WordList wl; WordList wl;
WordList::const_iterator cw; WordList::const_iterator cw;
@ -146,37 +124,34 @@ struct gmt_coord: public gmt_struct
if(1==wl.size()) // No dd:mm if(1==wl.size()) // No dd:mm
{ {
isdeg=false; isdeg=false;
bool res=str2double(str,&r); return str2double(str,&r);
if(!res) err="Can't convert string "+str+" to double value";
return res;
} }
if(0==wl.size() || wl.size()>3) {err="String "+str+" have incorrect format for geographic coordinate, must be ddd[:mm[:ss[.fff]]]"; return false;} if(0==wl.size() || wl.size()>3) return false;
isdeg=true; isdeg=true;
int64_t res; int64_t res;
// degrees // degrees
cw=wl.begin(); cw=wl.begin();
if(!str2int(*cw,&res)) {err="Can't convert "+*cw+" to integer"; return false;} if(!str2int(*cw,&res)) return false;
if(res>360 || res<-360) res%=360; if(res>360 || res<-360) res%=360;
sign=(std::string::npos==cw->find('-')); sign=(std::string::npos==cw->find('-'));
d=static_cast<uint16_t>(sign?res:-res); d=static_cast<uint16_t>(sign?res:-res);
// minutes // minutes
cw++; cw++;
if(!str2int(*cw,&res)) {err="Can't convert "+*cw+" to integer"; return false;} if(!str2int(*cw,&res)) return false;
if(res<0 || res>=60) {err="Minutes must be not lesser then 0 and lesser then 60"; return false;} if(res<0 || res>=60) return false;
m=static_cast<uint8_t>(res); m=static_cast<uint8_t>(res);
s=0; s=0;
// seconds // seconds
cw++; cw++;
if(wl.end()==cw) return true; // No seconds if(wl.end()==cw) return true; // No seconds
if(!str2double(*cw,&s) ) {err="Can't convert "+*cw+" to double"; return false;} if(!str2double(*cw,&s) ) return false;
if(s<0.0 || s>=60.0) {err="Seconds must be not lesser then 0 and lesser then 60"; return false;} if(s<0.0 || s>=60.0) return false;
return true; return true;
} }
bool Convert(double num)
bool Convert(double num, std::string& err)
{ {
isdeg=false; isdeg=false;
r=num; r=num;
@ -206,25 +181,24 @@ struct gmt_region: public gmt_struct
// Only "global", "global180" and "global360" // Only "global", "global180" and "global360"
// TODO: add parsing of "-R" strings // TODO: add parsing of "-R" strings
bool Convert(const std::string& istr, std::string& err) bool Convert(const std::string& istr)
{ {
std::string str=istr; std::string str=istr;
tolower(str); tolower(str);
if("global180"==str) if("global180"==str)
{ {
type=GLOBAL180; type=GLOBAL180;
xb.Convert(-180.0,err); xe.Convert(180.0,err); xb.Convert(-180.0); xe.Convert(180.0);
yb.Convert(-90.0,err); ye.Convert(90.0,err); yb.Convert(-90.0); ye.Convert(90.0);
return true; return true;
} }
if("global360"==str || "global"==str) if("global360"==str || "global"==str)
{ {
type=GLOBAL360; type=GLOBAL360;
xb.Convert(0.0,err); xe.Convert(360.0,err); xb.Convert(0.0); xe.Convert(360.0);
yb.Convert(-90.0,err); ye.Convert(90.0,err); yb.Convert(-90.0); ye.Convert(90.0);
return true; return true;
} }
err="Can't convert "+istr+" to region.";
return false; return false;
} }
@ -303,58 +277,24 @@ struct gmt_projection: public gmt_struct
case(OType::C): {ret="-JOb"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.polelon.Value()+"/"+o.polelat.Value()+"/"+ToString(width)+"c"; break;} case(OType::C): {ret="-JOb"+o.clon.Value()+"/"+o.clat.Value()+"/"+o.polelon.Value()+"/"+o.polelat.Value()+"/"+ToString(width)+"c"; break;}
default: return ""; default: return "";
} }
break;
} }
case(CASSINI): {ret="-JC"+c.clon.Value()+"/"+c.clat.Value()+"/"+ToString(width)+"c"; break;} case(CASSINI): {ret="-JC"+c.clon.Value()+"/"+c.clat.Value()+"/"+ToString(width)+"c"; break;}
case(CYL_EQA): {ret="-JY"+y.cmer.Value()+"/"+y.stpar.Value()+"/"+ToString(width)+"c"; break;} case(CYL_EQA): {ret="-JY"+y.stpar.Value()+"/"+y.cmer.Value()+"/"+ToString(width)+"c"; break;}
case(MILLER): {ret="-JJ"+j.cmer.Value()+"/"+ToString(width)+"c"; break;} case(MILLER): {ret="-JJ"+j.cmer.Value()+"/"+ToString(width)+"c"; break;}
case(CYL_STERE): {ret="-JCyl_stere/"+cyl_stere.stpar.Value()+"/"+cyl_stere.cmer.Value()+"/"+ToString(width)+"c"; break;} case(CYL_STERE): {ret="-JCyl_stere"+cyl_stere.stpar.Value()+"/"+cyl_stere.cmer.Value()+"/"+ToString(width)+"c"; break;}
default: return ""; default: return "";
} }
ret+=" "+region.Value(); ret+=" "+region.Value();
return ret; return ret;
} }
bool SetType(const std::string& s, std::string& err) bool SetType(const std::string& s)
{ {
proj=NOTDEF; proj=NOTDEF;
std::string str=s; std::string str=s;
tolower(str); tolower(str);
if(projnames.end()==projnames.find(str)) return false;
// Handle one symbol cases proj=projnames[str];
if(str.size()==1) switch(str[0]) return true;
{
case('c'): {proj=CASSINI; return true;}
case('j'): {proj=MILLER; return true;}
case('m'): {proj=MERCATOR; return true;}
case('o'): {proj=OBLIQMERCATOR; return true;}
case('q'): {proj=CYL_EQU; return true;}
case('t'): {proj=TRANSMERCATOR; return true;}
case('x'): {proj=XY; return true;}
case('y'): {proj=CYL_EQA; return true;}
default: break;
}
// Handle long GMT names
if("cyl_stere"==str) {proj=CYL_STERE; return true;}
// Handle common names
std::string t1;
for(const auto& m: projnames)
{
TemplateComparator cmp(m.first);
bool res=cmp.Compare(str);
if(!res) continue;
if(NOTDEF!=proj) // Ambiguos string
{
err="Ambiguous projection definition: did you mean \""+t1+"\" or \""+cmp.Template2Name()+"\"?";
proj=NOTDEF;
return false;
}
t1=cmp.Template2Name();
proj=m.second;
}
if(NOTDEF!=proj) return true; // All Ok
err="Unknown projection: "+s;
return false;
} }
static void FillProjNames(); static void FillProjNames();
@ -565,29 +505,18 @@ struct gmt_color: public gmt_struct
cyan=cc.cyan; magenta=cc.magenta; yellow=cc.yellow; black=cc.black; cyan=cc.cyan; magenta=cc.magenta; yellow=cc.yellow; black=cc.black;
} }
void ToModel(ColorModel newmodel)
{
switch(newmodel)
{
case(RGB): ToRGB(); return;
case(GRAY): ToGray(); return;
case(HSV): ToHSV(); return;
case(CMYK): ToCMYK(); return;
}
}
// Interpret one numeric argument as gray value // Interpret one numeric argument as gray value
bool Convert(double gr, std::string& err) bool Convert(double gr)
{ {
Value2RGB g(gr); Value2RGB g(gr);
bool suc=true; bool suc=true;
model=GRAY; model=GRAY;
transparency=0.0; transparency=0.0;
gray=g(&suc,err); gray=g(&suc);
return suc; return suc;
} }
bool Convert(const std::string& istr, std::string& err) bool Convert(const std::string& istr)
{ {
std::string cstr=istr; std::string cstr=istr;
tolower(cstr); tolower(cstr);
@ -604,7 +533,7 @@ struct gmt_color: public gmt_struct
cstr=*ci; cstr=*ci;
ci++; ci++;
Value2Transp t(*ci); Value2Transp t(*ci);
transparency=t(&suc,err); transparency=t(&suc);
if(!suc) return false; // Parse error if(!suc) return false; // Parse error
} }
} }
@ -612,9 +541,9 @@ struct gmt_color: public gmt_struct
WordList wl_slash=Split(cstr,"/"),wl_hyphen=Split(cstr,"-"); WordList wl_slash=Split(cstr,"/"),wl_hyphen=Split(cstr,"-");
WordList::size_type slash_size=wl_slash.size(),hyphen_size=wl_hyphen.size(); WordList::size_type slash_size=wl_slash.size(),hyphen_size=wl_hyphen.size();
// Checks // Checks
if(slash_size>1 && hyphen_size>1) {err="Delimeter of color components must be \"/\" or \"-\", not both"; return false;} if(slash_size>1 && hyphen_size>1) return false; // Delimiter can be "/" or "-", not both
if(2==slash_size || slash_size>4) {err="Number of color components must be 1 for GRAY, 3 for RGB or 4 for CMYK"; return false;} 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) {err="There is 3 color components in HSV model"; return false;} if(2==hyphen_size || hyphen_size>3) return false; // Size can be 1 or 3 for hsv
// Gray or name // Gray or name
// TODO: Hex representation // TODO: Hex representation
if(1==slash_size && 1==hyphen_size) if(1==slash_size && 1==hyphen_size)
@ -623,8 +552,7 @@ struct gmt_color: public gmt_struct
Value2RGB g(cstr); Value2RGB g(cstr);
bool suc=true; bool suc=true;
model=GRAY; model=GRAY;
gray=g(&suc,err); gray=g(&suc);
err="Can't understand string "+cstr+", this is nor color name, nor gray value (0-255)";
return suc; return suc;
} }
// RGB // RGB
@ -635,9 +563,9 @@ struct gmt_color: public gmt_struct
Value2RGB blue(wl_slash.front()); Value2RGB blue(wl_slash.front());
bool suc=true; bool suc=true;
model=RGB; model=RGB;
r=red(&suc,err); if(!suc) return suc; r=red(&suc);
g=green(&suc,err);if(!suc) return suc; g=green(&suc);
b=blue(&suc,err); b=blue(&suc);
return suc; return suc;
} }
// HSV // HSV
@ -648,9 +576,9 @@ struct gmt_color: public gmt_struct
Value2SV v(wl_hyphen.front()); Value2SV v(wl_hyphen.front());
bool suc=true; bool suc=true;
model=HSV; model=HSV;
hue=h(&suc,err); if(!suc) return suc; hue=h(&suc);
saturation=s(&suc,err);if(!suc) return suc; saturation=s(&suc);
value=v(&suc,err); value=v(&suc);
return suc; return suc;
} }
// CMYK // CMYK
@ -662,10 +590,10 @@ struct gmt_color: public gmt_struct
Value2CMYK k(wl_slash.front()); Value2CMYK k(wl_slash.front());
bool suc=true; bool suc=true;
model=CMYK; model=CMYK;
cyan=c(&suc,err); if(!suc) return suc; cyan=c(&suc);
magenta=m(&suc,err);if(!suc) return suc; magenta=m(&suc);
yellow=y(&suc,err); if(!suc) return suc; yellow=y(&suc);
black=k(&suc,err); black=k(&suc);
return suc; return suc;
} }
} }
@ -710,7 +638,7 @@ struct gmt_dash: public gmt_struct
operator bool() const {return !dash.empty();} operator bool() const {return !dash.empty();}
void Clear() {dash.clear(); shift=0.0; wisrel=false;} void Clear() {dash.clear(); shift=0.0; wisrel=false;}
bool Convert(const std::string& in, std::string& err, double w=0.0) bool Convert(const std::string& in, double w=0.0)
{ {
Clear(); Clear();
shift=0; shift=0;
@ -731,12 +659,12 @@ struct gmt_dash: public gmt_struct
// Determine shift // Determine shift
{ {
WordList wl=Split(in,":"); WordList wl=Split(in,":");
if(wl.size()>2) {err="Incorrect dash format"; return false;} if(wl.size()>1) return false;
if(2==wl.size()) if(1==wl.size())
{ {
Value2Width s(wl.back()); Value2Width s(wl.back());
bool suc=true; bool suc=true;
shift=s(&suc,err); shift=s(&suc);
if(!suc) return false; // Parse error if(!suc) return false; // Parse error
dstr=wl.front(); dstr=wl.front();
} }
@ -746,7 +674,7 @@ struct gmt_dash: public gmt_struct
{ {
Value2Width d(i); Value2Width d(i);
bool suc=true; bool suc=true;
dash.push_back(d(&suc,err)); dash.push_back(d(&suc));
if(!suc) return false; // Parse error if(!suc) return false; // Parse error
} }
return true; return true;
@ -764,18 +692,18 @@ struct gmt_pen: public gmt_struct
std::string Value() const {return ToString(width/10.0)+"c,"+color.Value()+(dash?(","+dash.Value()):"");} std::string Value() const {return ToString(width/10.0)+"c,"+color.Value()+(dash?(","+dash.Value()):"");}
// Interpret one numeric argument as width value // Interpret one numeric argument as width value
bool Convert(double in, std::string& err) bool Convert(double in)
{ {
Value2Width w(in); Value2Width w(in);
bool suc=true; bool suc=true;
color.Convert(0,err); // Black color.Convert(0); // Black
dash.Clear(); dash.Clear();
width=w(&suc,err); width=w(&suc);
return suc; return suc;
} }
// Convert from string // Convert from string
bool Convert(const std::string& istr, std::string& err) bool Convert(const std::string& istr)
{ {
std::string str=istr; std::string str=istr;
WordList::const_iterator ci; WordList::const_iterator ci;
@ -784,7 +712,7 @@ struct gmt_pen: public gmt_struct
// Defaults // Defaults
width=default_width; width=default_width;
color.Convert(0,err); // Black color.Convert(0); // Black
dash.Clear(); dash.Clear();
if(wl.size()>3) return false; // String is [width][,color][,dash] if(wl.size()>3) return false; // String is [width][,color][,dash]
@ -793,18 +721,18 @@ struct gmt_pen: public gmt_struct
{ {
Value2Width w(*ci); Value2Width w(*ci);
bool suc=true; bool suc=true;
width=w(&suc,err); width=w(&suc);
if(!suc) return false; // Parse error if(!suc) return false; // Parse error
} }
if(wl.end()!=ci) ci++; if(wl.end()!=ci) ci++;
if(wl.end()!=ci && 0!=ci->size()) if(wl.end()!=ci && 0!=ci->size())
{ {
if(!color.Convert(*ci,err)) return false; // Parse error if(!color.Convert(*ci)) return false; // Parse error
} }
if(wl.end()!=ci) ci++; if(wl.end()!=ci) ci++;
if(wl.end()!=ci && 0!=ci->size()) if(wl.end()!=ci && 0!=ci->size())
{ {
if(!dash.Convert(*ci,err,width)) return false; // Parse error if(!dash.Convert(*ci,width)) return false; // Parse error
} }
return true; return true;
} }
@ -824,58 +752,53 @@ struct gmt_font: public gmt_struct
std::string Value() const {return ToString(size)+"p,"+family+","+color.Value();} std::string Value() const {return ToString(size)+"p,"+family+","+color.Value();}
// Interpret one numeric argument as size of default black font // Interpret one numeric argument as size of default black font
bool Convert(double in, std::string& err) bool Convert(double in)
{ {
Value2Width s(in); Value2Width s(in);
bool suc=true; bool suc=true;
color.Convert(0,err); // Black color.Convert(0); // Black
size=s(&suc,err); size=s(&suc);
family=default_family; family=default_family;
return suc; return suc;
} }
// Convert from string // Convert from string
bool Convert(const std::string& str, std::string& err) bool Convert(const std::string& str)
{ {
WordList::const_iterator ci; WordList::const_iterator ci;
WordList wl=Split(str,",",true); WordList wl=Split(str,",",true);
std::string fakeerr;
// Defaults // Defaults
size=default_size; size=default_size;
family=default_family; family=default_family;
color.Convert(0,fakeerr); // Black color.Convert(0); // Black
if(wl.size()>3) {err="String "+str+" is not font string"; return false;} // String is [size][,family][,color] or [family][,color] if(wl.size()>3) return false; // String is [size][,family][,color] or [family][,color]
ci=wl.begin(); ci=wl.begin();
if(wl.end()!=ci && 0!=ci->size()) if(wl.end()!=ci && 0!=ci->size())
{ {
Value2Width s(*ci); Value2Width s(*ci);
bool suc=true; bool suc=true;
{ size=s(&suc);
std::string fake;
double newsize=s(&suc,fake);
if(suc) size=newsize;
}
if(!suc) // Parse error. check if argument is font name if(!suc) // Parse error. check if argument is font name
{ {
if(0==families.count(*ci)) return false; // No, argument is not allowed font name if(0==families.count(*ci)) return false; // No, argument is not allowed font name
family=*ci; family=*ci;
if(wl.size()>2) {err="String "+str+" is not font string"; return false;} // If first word is font name, then words count is 1 or 2. if(wl.size()>2) return false; // If first word is font name, then words count is 1 or 2.
goto read_color; goto read_color;
} }
} }
if(wl.end()!=ci) ci++; if(wl.end()!=ci) ci++;
if(wl.end()!=ci && 0!=ci->size()) if(wl.end()!=ci && 0!=ci->size())
{ {
if(0==families.count(*ci)) {err="Unknown font family: "+(*ci); return false;} // Argument is not allowed font name if(0==families.count(*ci)) return false; // Argument is not allowed font name
family=*ci; family=*ci;
} }
read_color: read_color:
if(wl.end()!=ci) ci++; if(wl.end()!=ci) ci++;
if(wl.end()!=ci && 0!=ci->size()) if(wl.end()!=ci && 0!=ci->size())
{ {
if(!color.Convert(*ci,err)) return false; // Parse error if(!color.Convert(*ci)) return false; // Parse error
} }
return true; return true;
} }

4
src/globals.cpp

@ -92,7 +92,7 @@ void RegisterFunction(const std::string& name, Func func)
bool Save(const ObjectList* input) bool Save(const ObjectList* input)
{ {
ObjectList::IndexType sz=input->Size(), i; ObjectList::ListValues::size_type sz=input->Size(), i;
if(sz<2 || sz%2==1 ) if(sz<2 || sz%2==1 )
{ {
COUT(ERROR)<<"Number of save arguments must not be "<<sz<<std::endl; COUT(ERROR)<<"Number of save arguments must not be "<<sz<<std::endl;
@ -128,7 +128,7 @@ bool Save(const ObjectList* input)
bool Print(const ObjectList* input) bool Print(const ObjectList* input)
{ {
ObjectList::IndexType sz=input->Size(), i; ObjectList::ListValues::size_type sz=input->Size(), i;
if(sz==0) return true; if(sz==0) return true;
// Print // Print

2
src/object.cpp

@ -170,7 +170,7 @@ const ObjectBase* Evaluate(ExecExpr& exp, bool* err)
exp.erase(pr); exp.erase(pr);
// Error handling // Error handling
if( res==nullptr || res->isError() ) if(!errl.empty())
{ {
const struct grammatic_location& loc=cse->Location(); const struct grammatic_location& loc=cse->Location();
*err=true; // Raise error flag *err=true; // Raise error flag

11
tests/GMTCoord

@ -1,11 +0,0 @@
# Description: Coord tests. Must passed.
# Status: ok
# Output hash: 1a1ca4aba24d0fe39407eef250167aca5c21373722f5f2a9bd6495cee34abaf2
@use "gmt"
a=Coord("10:30:18");
b=Coord(10.5);
c=Coord(":10:10");
d=Coord("-0:15:18");
print(a,a.n,b,b.n,c,c.n,d,d.n);

8
tests/GMTCoord_e1

@ -1,8 +0,0 @@
# Description: Non-integer degrees in dd:mm:ss mode.
# Status: fail
# Output hash: 9469953f706df02349e019f8b47a499d169113b654aee46cacb966d01a27848c
@use "gmt"
a=Coord("1.0:10");
print(a);

18
tests/GMTProjection

@ -1,18 +0,0 @@
# Description: Projections test
# Status: ok
# Output hash: 18656de8c59c9a218b71dc730a3a1e8f1016179622392b11f052c64210f6fa2d
@use "gmt"
r=Region("130",150,30,50);
px=Projection("dec",10,(10,20,10,20),15);
p=Projection(r,type="cyl equid",h=10,stpar=0);
p1=Projection(p,type="m",w=10);
p2b=Projection("ob",10,r,"eq",(r.xe.n+r.xb.n)/2,(r.ye.n+r.yb.n)/2,140,15);
p2=Projection(p2b,he=10);
p3=Projection("cas",11,r);
p4=Projection(r,type="cequa",11);
p5=Projection(p4,type="j",centralm="130:30");
p6=Projection("cylstereo",10,r);
print(px,p,p1,p2,p3,p4,p5,p6);

10
tests/GMTRegion1

@ -1,10 +0,0 @@
# Description: Global regions test.
# Status: ok
# Output hash: e661246caef9b2a5fa5a96b9d75c0542d2e0e655de9d63d755aff01cd3b4ceba
@use "gmt"
r1=Region("global");
r2=Region("global360");
r3=Region("global180");
print(r1,r1.xb,r1.xe,r2,r2.xb,r2.xe,r3,r3.xb,r3.xe);

9
tests/GMTRegion2

@ -1,9 +0,0 @@
# Description: Test sequential form of Region.
# Status: ok
# Output hash: a8006abe2c42b9e34c692ab88cf2f869ad6a01d1f32e6da842c1320f0d253d1c
@use "gmt"
r1=Region("10:30",20.5,-10.5,100,"bbox");
r2=Region("10:30",-10.5,20.5,100);
print(r1,r2,r1.yb,r2.yb);

13
tests/GMTRegion3

@ -1,13 +0,0 @@
# Description: Check named pairs form of Region.
# Status: ok
# Output hash: cf4acbeb2da3156fe52f1f374d4dc83a1aa0ee129a8aa2b1975ec828dd23cabe
@use "gmt"
r=Region("10:30",-10.5,20.5,100);
r1=Region(r,type="bbox");
r2=Region(r,type="global180");
r3=Region(r,ye=80.5);
l=(xb=r.xb.n-0.5,(xe=20+r.xb.n-10,yb=-10),(ye="11:30:28"));
rr=Region(l, type="bbox");
print(r,r1,r2,r3,rr);

8
tests/GMTRegion_e1

@ -1,8 +0,0 @@
# Description: Check string argument in sequential form of Region.
# Status: fail
# Output hash: 8421e39ea376a83938c3d79d803749f038ecd493a490228add4b8d179d4e8f75
@use "gmt"
r=Region("10:30",-10.5,20.5,100,"global");
print(r);
Loading…
Cancel
Save