00001
00002 #ifndef INCLUDED_plistSpecialty_h_
00003 #define INCLUDED_plistSpecialty_h_
00004
00005 #include "plist.h"
00006 #include "Shared/RobotInfo.h"
00007 #include "Shared/string_util.h"
00008 #include <limits>
00009
00010 namespace plist {
00011 #ifdef FMAT_DEFAULT_DOUBLE
00012 typedef double PLISTREAL;
00013 #else
00014 typedef float PLISTREAL;
00015 #endif
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 class OutputSelector : public Primitive<unsigned int> {
00029 public:
00030 enum { UNUSED=-1U };
00031 class bad_value : public std::exception {
00032 public:
00033
00034 explicit bad_value(const std::string& val, bool range=false) throw() : std::exception(), strValue(val), intValue(UNUSED), rangeError(range), message() { initMessage(); }
00035
00036 explicit bad_value(unsigned int val, bool range=false) throw() : std::exception(), strValue(), intValue(val), rangeError(range), message() { initMessage(); }
00037
00038 bad_value(const std::string& strVal, unsigned int intVal) throw() : std::exception(), strValue(strVal), intValue(intVal), rangeError(true), message() { initMessage(); }
00039
00040 virtual ~bad_value() throw() {}
00041
00042 virtual const char* what() const throw() { return message.c_str(); }
00043 void initMessage();
00044 std::string strValue;
00045 unsigned int intValue;
00046 bool rangeError;
00047 std::string message;
00048 };
00049
00050 OutputSelector() : Primitive<unsigned int>(UNUSED), useNumeric(false), defModel(), saveModel(capabilities.getRobotName()), rangeBegin(0), rangeEnd(capabilities.getNumOutputs()), throwInvalid(false), throwUnused(false) {}
00051 OutputSelector(unsigned int v, bool isNum=false) : Primitive<unsigned int>(v), useNumeric(isNum), defModel(), saveModel(capabilities.getRobotName()), rangeBegin(0), rangeEnd(capabilities.getNumOutputs()), throwInvalid(false), throwUnused(false) {}
00052 OutputSelector& operator=(const std::string& v) { set(v); return *this; }
00053 OutputSelector& operator=(const unsigned int& v);
00054 OutputSelector& operator=(const OutputSelector& v) { operator=(v.val); return *this; }
00055 using Primitive<unsigned int>::operator=;
00056
00057 void loadXML(xmlNode* node);
00058 void saveXML(xmlNode* node) const;
00059 void set(const std::string& str);
00060 using Primitive<unsigned int>::set;
00061 std::string get() const;
00062
00063 void setNumeric(bool isNum) { useNumeric=isNum; }
00064 bool getNumeric() const { return useNumeric; }
00065
00066 void setDefaultModel(const std::string& name) { defModel = name; }
00067 const std::string& getDefaultModel() const { return defModel; }
00068
00069 void setSaveModel(const std::string& name) { saveModel = name; }
00070 const std::string& getSaveModel() const { return saveModel; }
00071
00072
00073
00074
00075 void setRange(unsigned int begin, unsigned int end);
00076 unsigned int getRangeBegin() const { return rangeBegin; }
00077 unsigned int getRangeEnd() const { return rangeEnd; }
00078
00079 void throwOnInvalid(bool b) { throwInvalid=b; }
00080 bool throwOnInvalid() const { return throwInvalid; }
00081
00082
00083 PLIST_CLONE_DEF(OutputSelector,new OutputSelector(val));
00084 protected:
00085
00086 bool useNumeric;
00087
00088 std::string defModel;
00089
00090
00091 std::string saveModel;
00092
00093 unsigned int rangeBegin;
00094
00095 unsigned int rangeEnd;
00096
00097 bool throwInvalid;
00098
00099 bool throwUnused;
00100 };
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 class Angle : public Primitive<PLISTREAL> {
00115 public:
00116 enum Format {
00117 FORMAT_NONE,
00118 FORMAT_RADIAN,
00119 FORMAT_DEGREE,
00120 FORMAT_PI,
00121 FORMAT_PERCENT,
00122 FORMAT_SAME,
00123 FORMAT_AUTO
00124 };
00125
00126 enum Pedantic {
00127 PEDANTIC_FULL,
00128 PEDANTIC_VALID,
00129 PEDANTIC_CUTE
00130 };
00131
00132 Angle() : Primitive<PLISTREAL>(0), saveFormat(FORMAT_SAME), loadedFormat(FORMAT_AUTO) {}
00133 Angle(PLISTREAL v) : Primitive<PLISTREAL>(v), saveFormat(FORMAT_SAME), loadedFormat(FORMAT_AUTO) {}
00134 Angle& operator=(const std::string& v) { set(v); return *this; }
00135 using Primitive<PLISTREAL>::operator=;
00136
00137 void loadXML(xmlNode* node);
00138 void saveXML(xmlNode* node) const;
00139 void set(const std::string& str);
00140 using Primitive<PLISTREAL>::set;
00141 void setDegree(PLISTREAL v) { operator=(v/180*static_cast<PLISTREAL>(M_PI)); }
00142 PLISTREAL getDegree() const { return val/static_cast<PLISTREAL>(M_PI)*180; }
00143 std::string get() const;
00144
00145 void setFormat(Format fmt) { saveFormat=fmt; }
00146 Format getFormat() const { return saveFormat; }
00147 Format getLoadedFormat() const { return loadedFormat; }
00148
00149 static void setDefaultFormat(Format fmt) { defaultFormat = fmt; }
00150 static Format getDefaultFormat() { return defaultFormat; }
00151
00152 static void setPedantic(Pedantic p) { pedantic=p; }
00153 static Pedantic getPedantic() { return pedantic; }
00154
00155
00156 PLIST_CLONE_DEF(Angle,new Angle(val));
00157 protected:
00158 void parseRadian(const std::string& str);
00159
00160
00161 Format saveFormat;
00162
00163 Format loadedFormat;
00164
00165 static Format defaultFormat;
00166
00167 static Pedantic pedantic;
00168 };
00169
00170
00171 class Point : public virtual plist::ArrayOf<plist::Primitive<PLISTREAL> > {
00172 public:
00173 typedef PLISTREAL storage_t;
00174
00175
00176 Point() : x(0), y(0), z(0) { init(); }
00177
00178 Point(storage_t x_, storage_t y_, storage_t z_) : x(x_), y(y_), z(z_) { init(); }
00179
00180
00181
00182
00183 Point(const Point& p) : x(p[0]), y(p[1]), z(p[2]) { init(); }
00184
00185 template<class T> Point(const T& p) : x(p[0]), y(p[1]), z(p[2]) { init(); }
00186
00187
00188 template<typename T> Point& importFrom(const T& a) { x=a[0]; y=a[1]; z=a[2]; return *this; }
00189
00190 template<typename T> T construct() const { return T(x,y,z); }
00191
00192 template<typename T> T exportTo() const { T a; a[0]=x; a[1]=y; a[2]=z; return a; }
00193
00194 template<typename T> T& exportTo(T& a) const { a[0]=x; a[1]=y; a[2]=z; return a; }
00195
00196
00197 void set(storage_t x_, storage_t y_, storage_t z_) { x=x_; y=y_; z=z_; }
00198 using plist::ArrayOf<plist::Primitive<PLISTREAL> >::set;
00199
00200 void saveXML(xmlNode* node) const {
00201 if(node==NULL)
00202 return;
00203 if(x==y && y==z) {
00204 x.saveXML(node);
00205 } else {
00206 plist::ArrayOf<plist::Primitive<storage_t> >::saveXML(node);
00207 }
00208 }
00209 void loadXML(xmlNode* node) {
00210 if(node==NULL)
00211 return;
00212 if(xNodeHasName(node,"real")) {
00213 x.loadXML(node);
00214 z = y = x;
00215 } else {
00216 plist::ArrayOf<plist::Primitive<storage_t> >::loadXML(node);
00217 }
00218 }
00219
00220 plist::Primitive<storage_t> x;
00221 plist::Primitive<storage_t> y;
00222 plist::Primitive<storage_t> z;
00223
00224 protected:
00225
00226 void init() {
00227 addEntry(x);
00228 addEntry(y);
00229 addEntry(z);
00230 setLoadSavePolicy(FIXED,SYNC);
00231 setSaveInlineStyle(true);
00232 }
00233 };
00234
00235
00236 template<class T>
00237 class RGBColor : virtual public DictionaryOf<plist::Primitive<T> >, virtual public ArrayOf<plist::Primitive<T> > {
00238 public:
00239 RGBColor() : DictionaryOf<plist::Primitive<T> >(), ArrayOf<plist::Primitive<T> >(), red(0), green(0), blue(0), alpha(255) { init(); }
00240 RGBColor(T r, T g, T b, T a=getMax()) : DictionaryOf<plist::Primitive<T> >(), ArrayOf<plist::Primitive<T> >(), red(r), green(g), blue(b), alpha(a) { init(); }
00241
00242 plist::Primitive<T> red;
00243 plist::Primitive<T> green;
00244 plist::Primitive<T> blue;
00245 plist::Primitive<T> alpha;
00246
00247 virtual void loadXML(xmlNode * node);
00248 virtual void saveXML(xmlNode * node) const;
00249 using DictionaryOf<plist::Primitive<T> >::saveXML;
00250 virtual void set(const RGBColor<T>& x);
00251 virtual void set(const plist::ObjectBase& x);
00252 virtual void set(const std::string& str);
00253 using DictionaryOf<plist::Primitive<T> >::set;
00254 using ArrayOf<plist::Primitive<T> >::set;
00255 using DictionaryOf<plist::Primitive<T> >::operator[];
00256 using ArrayOf<plist::Primitive<T> >::operator[];
00257
00258 plist::Primitive<T>& operator[](int i) { return ArrayOf<plist::Primitive<T> >::operator[](i); }
00259 const plist::Primitive<T>& operator[](int i) const { return ArrayOf<plist::Primitive<T> >::operator[](i); }
00260
00261 virtual std::string toString() const;
00262
00263 virtual size_t size() const { return ArrayOf<plist::Primitive<T> >::size(); }
00264
00265 virtual void clear() {
00266 DictionaryOf<plist::Primitive<T> >::clear();
00267 ArrayOf<plist::Primitive<T> >::clear();
00268 init();
00269 }
00270
00271 ObjectBase* resolveEntry(const std::string& s) const {
00272 ObjectBase* obj = DictionaryOf<plist::Primitive<T> >::resolveEntry(s);
00273 return (obj!=NULL) ? obj : ArrayOf<plist::Primitive<T> >::resolveEntry(s);
00274 }
00275 unsigned int getLongestKeyLen(const regex_t* reg, unsigned int depth) const { return DictionaryOf<plist::Primitive<T> >::getLongestKeyLen(reg,depth); }
00276 virtual bool canContain(const ObjectBase& obj) { return DictionaryOf<plist::Primitive<T> >::canContain(obj); }
00277
00278 PLIST_CLONE_DEF(RGBColor,new RGBColor<T>(red,green,blue,alpha));
00279
00280 protected:
00281 virtual void fireEntryRemoved(ObjectBase& val);
00282
00283 static float makeFloat(const T& v) { return v/(float)getMax(); }
00284 static int makeInt(const T& v) { return static_cast<int>(makeFloat(v)*255 + 0.5); }
00285 static T fromByte(unsigned char x) { return static_cast<T>(x)<<(8*(sizeof(T)-sizeof(unsigned char))); }
00286 static T fromReal(double x) { return static_cast<T>(x*getMax()+.5); }
00287 static T getMax() { return std::numeric_limits<T>::max(); }
00288 static void setNumeric(plist::Primitive<T>&) {}
00289
00290 void init() {
00291 DictionaryOf<plist::Primitive<T> >::addEntry("Red",red);
00292 DictionaryOf<plist::Primitive<T> >::addEntry("Green",green);
00293 DictionaryOf<plist::Primitive<T> >::addEntry("Blue",blue);
00294 DictionaryOf<plist::Primitive<T> >::addEntry("Alpha",alpha);
00295 ArrayOf<plist::Primitive<T> >::addEntry(red);
00296 ArrayOf<plist::Primitive<T> >::addEntry(green);
00297 ArrayOf<plist::Primitive<T> >::addEntry(blue);
00298 ArrayOf<plist::Primitive<T> >::addEntry(alpha);
00299 setNumeric(red);
00300 setNumeric(green);
00301 setNumeric(blue);
00302 setNumeric(alpha);
00303 Collection::setLoadSavePolicy(Collection::FIXED,Collection::SYNC);
00304 ArrayOf<plist::Primitive<T> >::setSaveInlineStyle(true);
00305 }
00306 };
00307
00308 template<> inline float RGBColor<float>::getMax() { return 1; }
00309 template<> inline double RGBColor<double>::getMax() { return 1; }
00310
00311 template<> inline unsigned char RGBColor<unsigned char>::fromByte(unsigned char x) { return x; }
00312 template<> inline char RGBColor<char>::fromByte(unsigned char x) { return static_cast<int>(x)-128; }
00313 template<> inline float RGBColor<float>::fromByte(unsigned char x) { return x/255.f; }
00314 template<> inline double RGBColor<double>::fromByte(unsigned char x) { return x/255.0; }
00315
00316 template<> inline float RGBColor<float>::fromReal(double x) { return static_cast<float>(x); }
00317 template<> inline double RGBColor<double>::fromReal(double x) { return x; }
00318
00319 template<> inline void RGBColor<char>::setNumeric(plist::Primitive<char>& n) { n.setNumeric(true); }
00320 template<> inline void RGBColor<unsigned char>::setNumeric(plist::Primitive<unsigned char>& n) { n.setNumeric(true); }
00321
00322 template<class T> void RGBColor<T>::loadXML(xmlNode * node) {
00323 if(ObjectBase::xNodeHasName(node,"array")) {
00324 ArrayOf<plist::Primitive<T> >::loadXML(node);
00325 } else if(ObjectBase::xNodeHasName(node,"dict")) {
00326 DictionaryOf<plist::Primitive<T> >::loadXML(node);
00327 } else if(ObjectBase::xNodeHasName(node,"string")) {
00328 xmlChar * cont=xmlNodeGetContent(node);
00329 try {
00330 set(std::string((const char*)cont));
00331 } catch(const XMLLoadSave::bad_format& err) {
00332 xmlFree(cont);
00333 throw XMLLoadSave::bad_format(node,err.what());
00334 } catch(...) {
00335 xmlFree(cont);
00336 throw;
00337 }
00338 xmlFree(cont);
00339 } else {
00340 std::stringstream ss;
00341 ss << "plist::RGBColor can't accept value of type "<< ObjectBase::xNodeGetName(node);
00342 ss << ", (try CSS-style string or array of RGB values in range 0-" << getMax() << ")";
00343 throw XMLLoadSave::bad_format(node,ss.str());
00344 }
00345 }
00346
00347 template<class T> void RGBColor<T>::saveXML(xmlNode * node) const {
00348 if(ObjectBase::xNodeHasName(node,"array")) {
00349 ArrayOf<plist::Primitive<T> >::saveXML(node);
00350 } else if(ObjectBase::xNodeHasName(node,"dict")) {
00351 DictionaryOf<plist::Primitive<T> >::saveXML(node);
00352 } else {
00353 xmlNodeSetName(node,(const xmlChar*)"string");
00354 xmlNodeSetContent(node,(const xmlChar*)toString().c_str());
00355 }
00356 }
00357
00358 template<class T> void RGBColor<T>::set(const RGBColor<T>& v) {
00359 red=v.red;
00360 green=v.green;
00361 blue=v.blue;
00362 alpha=v.alpha;
00363 }
00364 template<class T> void RGBColor<T>::set(const plist::ObjectBase& x) {
00365 if(const RGBColor * v = dynamic_cast<const RGBColor*>(&x)) {
00366 set(*v);
00367 } else if(const DictionaryBase * d = dynamic_cast<const DictionaryBase*>(&x)) {
00368 DictionaryOf<plist::Primitive<T> >::set(*d);
00369 } else if(const ArrayBase * a = dynamic_cast<const ArrayBase*>(&x)) {
00370 ArrayOf<plist::Primitive<T> >::set(*a);
00371 }
00372 }
00373
00374 template<class T> void RGBColor<T>::set(const std::string& str) {
00375 std::string s = string_util::makeLower(string_util::trim(str));
00376 if(s[0]=='#') {
00377 if(s.size()==4) {
00378 for(unsigned int i=0; i<3; ++i) {
00379 unsigned char x=0;
00380 if('0'<=s[i+1] && s[i+1]<='9')
00381 x = s[i+1]-'0';
00382 else if('a'<=s[i+1] && s[i+1]<='f')
00383 x = s[i+1]-'a'+10;
00384 else
00385 throw XMLLoadSave::bad_format(NULL,"plist::RGBColor bad character in hex specification: "+str);
00386 ArrayOf<plist::Primitive<T> >::operator[](i)=fromByte(x*16+x);
00387 }
00388 alpha=getMax();
00389 } else if(s.size()==7) {
00390 for(unsigned int i=0; i<3; ++i) {
00391 char ca=s[i*2+1], cb=s[i*2+2];
00392 unsigned char xa=0, xb=0;
00393 if('0'<=ca && ca<='9')
00394 xa = ca-'0';
00395 else if('a'<=ca && ca<='f')
00396 xa = ca-'a'+10;
00397 else
00398 throw XMLLoadSave::bad_format(NULL,"plist::RGBColor bad character in hex specification: "+str);
00399 if('0'<=cb && cb<='9')
00400 xb = cb-'0';
00401 else if('a'<=cb && cb<='f')
00402 xb = cb-'a'+10;
00403 else
00404 throw XMLLoadSave::bad_format(NULL,"plist::RGBColor bad character in hex specification: "+str);
00405 ArrayOf<plist::Primitive<T> >::operator[](i)=fromByte(xa*16+xb);
00406 }
00407 alpha=getMax();
00408 } else {
00409 throw XMLLoadSave::bad_format(NULL,"plist::RGBColor wrong number of characters (3 or 6) in hex specification: "+str);
00410 }
00411 } else if(s.substr(0,4)=="rgb(") {
00412 std::vector<std::string> tok = string_util::tokenize(s.substr(4),",");
00413 if(tok.size()!=3)
00414 throw XMLLoadSave::bad_format(NULL,"plist::RGBColor expects three arguments for rgb() specification");
00415 for(unsigned int i=0; i<tok.size(); ++i) {
00416 std::string t = string_util::trim(tok[i]);
00417 if(t[t.size()-1]=='%') {
00418 float x;
00419 std::stringstream(t.substr(0,t.size()-1)) >> x;
00420 ArrayOf<plist::Primitive<T> >::operator[](i)=fromReal(x/100.0);
00421 } else {
00422 unsigned int x;
00423 std::stringstream(t) >> x;
00424 ArrayOf<plist::Primitive<T> >::operator[](i)=fromByte(x);
00425 }
00426 }
00427 alpha=getMax();
00428 } else if(s.substr(0,5)=="rgba(") {
00429 std::vector<std::string> tok = string_util::tokenize(s.substr(5),",");
00430 if(tok.size()!=4)
00431 throw XMLLoadSave::bad_format(NULL,"plist::RGBColor expects four arguments for rgba() specification");
00432 for(unsigned int i=0; i<3; ++i) {
00433 std::string t = string_util::trim(tok[i]);
00434 if(t[t.size()-1]=='%') {
00435 double x;
00436 std::stringstream(t.substr(0,t.size()-1)) >> x;
00437 ArrayOf<plist::Primitive<T> >::operator[](i)=fromReal(x/100.0);
00438 } else {
00439 unsigned int x;
00440 std::stringstream(t) >> x;
00441 ArrayOf<plist::Primitive<T> >::operator[](i)=fromByte(x);
00442 }
00443 }
00444 std::string t = string_util::trim(tok[3]);
00445 double x;
00446 std::stringstream(t) >> x;
00447 alpha=fromReal(x);
00448 } else {
00449 if(s=="black") {
00450 red=green=blue=0;
00451 } else if(s=="silver") {
00452 red=green=blue=fromByte(0xC0);
00453 } else if(s=="gray") {
00454 red=green=blue=fromByte(0x80);
00455 } else if(s=="white") {
00456 red=green=blue=fromByte(0xFF);
00457 } else if(s=="maroon") {
00458 red=fromByte(0x80); green=blue=0;
00459 } else if(s=="red") {
00460 red=fromByte(0xFF); green=blue=0;
00461 } else if(s=="purple") {
00462 red=blue=fromByte(0x80); green=0;
00463 } else if(s=="fuchsia") {
00464 red=blue=fromByte(0xFF); green=0;
00465 } else if(s=="green") {
00466 green=fromByte(0x80); red=blue=0;
00467 } else if(s=="lime") {
00468 green=fromByte(0xFF); red=blue=0;
00469 } else if(s=="olive") {
00470 red=green=fromByte(0x80); blue=0;
00471 } else if(s=="yellow") {
00472 red=green=fromByte(0xFF); blue=0;
00473 } else if(s=="navy") {
00474 blue=fromByte(0x80); red=green=0;
00475 } else if(s=="blue") {
00476 blue=fromByte(0xFF); red=green=0;
00477 } else if(s=="teal") {
00478 green=blue=fromByte(0x80); red=0;
00479 } else if(s=="aqua") {
00480 green=blue=fromByte(0xFF); red=0;
00481 } else {
00482 throw XMLLoadSave::bad_format(NULL,"plist::RGBColor unknown specification: "+str);
00483 }
00484 alpha=getMax();
00485 }
00486 }
00487
00488 template<class T> std::string RGBColor<T>::toString() const {
00489 std::stringstream ss;
00490 ss << (alpha!=getMax() ? "rgba(" : "rgb(");
00491 ss << makeInt(red) << ',' << makeInt(green) << ',' << makeInt(blue);
00492 if(alpha!=getMax())
00493 ss << ',' << makeFloat(alpha);
00494 ss <<')';
00495 return ss.str();
00496 }
00497
00498 PLIST_CLONE_IMPT(T,RGBColor,new RGBColor<T>(red,green,blue,alpha));
00499
00500 template<class T> void RGBColor<T>::fireEntryRemoved(ObjectBase& val) {
00501 Collection::fireEntryRemoved(val);
00502 std::set<ObjectBase*>::iterator it=DictionaryOf<plist::Primitive<T> >::myRef.find(&val);
00503 bool deleted=false;
00504 if(it!=DictionaryOf<plist::Primitive<T> >::myRef.end()) {
00505 DictionaryOf<plist::Primitive<T> >::myRef.erase(it);
00506 if(!deleted) {
00507 delete &val;
00508 deleted=true;
00509 }
00510 }
00511 it=ArrayOf<plist::Primitive<T> >::myRef.find(&val);
00512 if(it!=ArrayOf<plist::Primitive<T> >::myRef.end()) {
00513 ArrayOf<plist::Primitive<T> >::myRef.erase(it);
00514 if(!deleted) {
00515 delete &val;
00516 deleted=true;
00517 }
00518 }
00519 }
00520 }
00521
00522
00523
00524
00525
00526
00527 #endif