00001 #include "plistSpecialty.h"
00002 #include "string_util.h"
00003 #include <libxml/tree.h>
00004 #include <cmath>
00005 #include <cstdlib>
00006
00007 #ifdef PLATFORM_APERIOS
00008
00009 # define strtof strtod
00010 #endif
00011
00012
00013 using namespace std;
00014
00015 namespace plist {
00016
00017 void OutputSelector::bad_value::initMessage() {
00018 if(strValue.size()==0 && intValue==UNUSED) {
00019 message="plist specialty type OutputSelector was passed UNUSED, configured as invalid for this value";
00020 } else if(rangeError) {
00021 if(strValue.size()>0 && intValue!=UNUSED) {
00022 std::stringstream ss;
00023 ss << "plist specialty type OutputSelector was passed an out-of-range offset named " << strValue << " (" << intValue <<")";
00024 message=ss.str();
00025 } else if(strValue.size()>0) {
00026 message="plist specialty type OutputSelector was passed an out-of-range offset named '"+strValue+"'";
00027 } else {
00028 std::stringstream ss;
00029 ss << "plist specialty type OutputSelector was passed an out-of-range offset '" << intValue <<"'";
00030 message=ss.str();
00031 }
00032 } else {
00033 if(strValue.size()>0) {
00034 message="plist specialty type OutputSelector was passed '"+strValue+"', invalid for this robot model";
00035 } else {
00036 std::stringstream ss;
00037 ss << "plist specialty type OutputSelector was passed '" << intValue <<"', invalid for this robot model";
00038 message=ss.str();
00039 }
00040 }
00041 }
00042
00043 OutputSelector& OutputSelector::operator=(const unsigned int& v) {
00044 if(&prevVal==&val) std::swap(val,prevVal); else { prevVal=val; val=v; }
00045 if(val!=UNUSED && (val<rangeBegin || val>=rangeEnd || val>=capabilities.getNumFrames()) ) {
00046 val=UNUSED;
00047 if(throwInvalid) {
00048 fireValueChanged(prevVal==val);
00049 if(capabilities.getFrameName(v)!=NULL)
00050 throw bad_value(capabilities.getFrameName(v),v);
00051 else
00052 throw bad_value(v,true);
00053 }
00054 cerr << "Error: plist specialty type OutputSelector assigned an out-of-range ("<<rangeBegin<<','<<std::min(rangeEnd,capabilities.getNumFrames())<<"] offset "<<v<<" for model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00055 }
00056 if(throwUnused && val==UNUSED) {
00057 fireValueChanged(prevVal==val);
00058 throw bad_value(UNUSED);
00059 } else {
00060 fireValueChanged(prevVal==val);
00061 }
00062 return *this;
00063 }
00064
00065 void OutputSelector::loadXML(xmlNode* node) {
00066 if(node==NULL)
00067 return;
00068 xmlChar* cont=xmlNodeGetContent(node);
00069 try {
00070 if(xNodeHasName(node,"string")) {
00071 useNumeric=false;
00072 saveModel="";
00073 set((char*)cont);
00074 } else if(xNodeHasName(node,"integer") || xNodeHasName(node,"real")) {
00075 if(xNodeHasName(node,"real"))
00076 std::cerr << "Warning: plist specialty type OutputSelector should be either a string or integer, interpreting 'real' as 'integer'" << std::endl;
00077 useNumeric=true;
00078 saveModel="";
00079 prevVal=val;
00080 val=UNUSED;
00081 string strval = string_util::trim((const char*)cont);
00082 if(strval.size()>0) {
00083 char * endp=NULL;
00084 val = strtol(strval.c_str(),&endp,0);
00085 if(*endp!='\0') {
00086 throw bad_format(node,"Error: plist specialty type OutputSelector encountered malformed integer");
00087 } else if(defModel.size()!=0 && defModel!=capabilities.getRobotName()) {
00088
00089 const Capabilities * cap = getCapabilities(defModel);
00090 if(cap==NULL) {
00091 unsigned int badval=val;
00092 val=UNUSED;
00093 if(throwInvalid) {
00094 fireValueChanged(prevVal==val);
00095 std::stringstream ss;
00096 ss << defModel << '/' << badval;
00097 throw bad_value(ss.str());
00098 }
00099 cerr << "Error: plist specialty type OutputSelector has an invalid default model specifier "<<defModel<<", marking 'UNUSED'" << endl;
00100 } else {
00101 const char * name = cap->getFrameName(val);
00102 if(name==NULL) {
00103 unsigned int badval=val;
00104 val=UNUSED;
00105 if(throwInvalid) {
00106 fireValueChanged(prevVal==val);
00107 throw bad_value(badval);
00108 } else {
00109 cerr << "Error: plist specialty type OutputSelector attempted to set an invalid offset "<<badval<<" for model " << cap->getRobotName() << ", marking 'UNUSED'" << endl;
00110 }
00111 }
00112
00113 if(val!=UNUSED) {
00114 val=capabilities.findFrameOffset(name);
00115 if(val==-1U) {
00116 unsigned int badval=val;
00117 val=UNUSED;
00118 if(throwInvalid) {
00119 fireValueChanged(prevVal==val);
00120 throw bad_value(name);
00121 } else {
00122 cerr << "Error: plist specialty type OutputSelector could not map "<<name<<" ("<<defModel<<'/'<<badval<<") to model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00123 }
00124 }
00125 }
00126 }
00127 }
00128 if(val!=UNUSED && (val<rangeBegin || val>=rangeEnd || val>=capabilities.getNumFrames()) ) {
00129 unsigned int badval=val;
00130 val=UNUSED;
00131 if(throwInvalid) {
00132 fireValueChanged(prevVal==val);
00133 throw bad_value(strval,badval);
00134 }
00135 if(defModel.size()!=0 && defModel!=capabilities.getRobotName())
00136 cerr << "Error: plist specialty type OutputSelector loading an out-of-range ("<<rangeBegin<<','<<std::min(rangeEnd,capabilities.getNumFrames())<<"] offset "<<defModel<<'/'<<strval<<" ("<<badval<<") for model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00137 else
00138 cerr << "Error: plist specialty type OutputSelector loading an out-of-range ("<<rangeBegin<<','<<std::min(rangeEnd,capabilities.getNumFrames())<<"] offset "<<strval<<" for model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00139 }
00140 }
00141 if(throwUnused && val==UNUSED) {
00142 fireValueChanged(prevVal==val);
00143 throw bad_value(UNUSED);
00144 } else {
00145 fireValueChanged(prevVal==val);
00146 }
00147 } else {
00148 throw bad_format(node,"Error: plist specialty type OutputSelector must be either a string or integer");
00149 }
00150 } catch(const bad_format& err) {
00151 xmlFree(cont);
00152 throw err;
00153 } catch(...) {
00154 xmlFree(cont);
00155 throw;
00156 }
00157 xmlFree(cont);
00158 }
00159
00160 void OutputSelector::saveXML(xmlNode* node) const {
00161 if(node==NULL)
00162 return;
00163 if(val!=UNUSED && useNumeric && saveModel.size()==0) {
00164 xmlNodeSetName(node,(const xmlChar*)"integer");
00165 std::stringstream str;
00166 str << (int)val;
00167 xmlNodeSetContent(node,(const xmlChar*)str.str().c_str());
00168 } else {
00169 xmlNodeSetName(node,(const xmlChar*)"string");
00170 std::string str = get();
00171 if(str=="UNUSED")
00172 str.clear();
00173 xmlNodeSetContent(node,(const xmlChar*)str.c_str());
00174 }
00175 }
00176
00177 void OutputSelector::set(const std::string& str) {
00178 prevVal=val;
00179 val=UNUSED;
00180 string strval = string_util::trim(str);
00181 string model = defModel;
00182 string::size_type modelpos = str.find('/');
00183 if(modelpos!=string::npos) {
00184 model = saveModel = str.substr(0,modelpos);
00185 strval = str.substr(modelpos+1);
00186 }
00187 if(strval.size()==0 || strval=="UNUSED") {
00188 if(throwUnused) {
00189 fireValueChanged(prevVal==val);
00190 throw bad_value(UNUSED);
00191 }
00192 } else {
00193 if(model.size()==0 || model==capabilities.getRobotName()) {
00194
00195 char * endp=NULL;
00196 val = strtol(strval.c_str(),&endp,0);
00197 if(*endp!='\0') {
00198 val = capabilities.findFrameOffset(strval.c_str());
00199 if(val==-1U) {
00200 if(throwInvalid) {
00201 val=UNUSED;
00202 fireValueChanged(prevVal==val);
00203 throw bad_value(str);
00204 } else {
00205 val=UNUSED;
00206 cerr << "Error: plist specialty type OutputSelector attempted to set an invalid offset "<<strval<<" for model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00207 }
00208 }
00209 }
00210 } else {
00211 const Capabilities * cap = getCapabilities(model);
00212 if(cap==NULL) {
00213 if(throwInvalid) {
00214 fireValueChanged(prevVal==val);
00215 throw bad_value(str);
00216 }
00217 cerr << "Error: plist specialty type OutputSelector attempted to set a bad model specifier "<<model<<", marking 'UNUSED'" << endl;
00218 } else {
00219
00220 char * endp=NULL;
00221 val = strtol(strval.c_str(),&endp,0);
00222 if(*endp!='\0') {
00223 val = cap->findFrameOffset(strval.c_str());
00224 if(val!=-1U) {
00225
00226 val=capabilities.findFrameOffset(strval.c_str());
00227 if(val==-1U) {
00228 if(throwInvalid) {
00229 val=UNUSED;
00230 fireValueChanged(prevVal==val);
00231 throw bad_value(str);
00232 } else {
00233 val=UNUSED;
00234 cerr << "Error: plist specialty type OutputSelector could not map "<<str<<" to model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00235 }
00236 }
00237 } else {
00238
00239 val=capabilities.findFrameOffset(strval.c_str());
00240 if(val!=-1U) {
00241 cerr << "Warning: plist specialty type OutputSelector couldn't find "<<str<<" on model " << cap->getRobotName() << ", but it was found on current host model " << capabilities.getRobotName() << ", using that.." << endl;
00242 } else {
00243 if(throwInvalid) {
00244 val=UNUSED;
00245 fireValueChanged(prevVal==val);
00246 throw bad_value(str);
00247 } else {
00248 val=UNUSED;
00249 cerr << "Error: plist specialty type OutputSelector attempted to set an invalid offset "<<str<<" for model " << cap->getRobotName() << ", marking 'UNUSED'" << endl;
00250 }
00251 }
00252 }
00253 } else if(val!=UNUSED) {
00254 const char * name = cap->getFrameName(val);
00255 if(name==NULL) {
00256 val=UNUSED;
00257 if(throwInvalid) {
00258 fireValueChanged(prevVal==val);
00259 throw bad_value(str);
00260 } else {
00261 cerr << "Error: plist specialty type OutputSelector attempted to set an invalid offset "<<str<<" for model " << cap->getRobotName() << ", marking 'UNUSED'" << endl;
00262 }
00263 }
00264
00265 if(val!=UNUSED) {
00266 val=capabilities.findFrameOffset(name);
00267 if(val==-1U) {
00268 unsigned int badval=val;
00269 val=UNUSED;
00270 if(throwInvalid) {
00271 fireValueChanged(prevVal==val);
00272 throw bad_value(name);
00273 } else {
00274 cerr << "Error: plist specialty type OutputSelector could not map "<<name<<" ("<<model<<'/'<<badval<<") to model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00275 }
00276 }
00277 }
00278 }
00279 }
00280 }
00281 }
00282 if(val!=UNUSED && (val<rangeBegin || val>=rangeEnd || val>=capabilities.getNumFrames())) {
00283 unsigned int badval=val;
00284 val=UNUSED;
00285 if(throwInvalid) {
00286 fireValueChanged(prevVal==val);
00287 throw bad_value(strval,badval);
00288 }
00289 cerr << "Error: plist specialty type OutputSelector loading an out-of-range ("<<rangeBegin<<','<<std::min(rangeEnd,capabilities.getNumFrames())<<"] offset "<<str<<" ("<<badval<<") for model " << capabilities.getRobotName() << ", marking 'UNUSED'" << endl;
00290 }
00291 if(throwUnused && val==UNUSED) {
00292 fireValueChanged(prevVal==val);
00293 throw bad_value(UNUSED);
00294 } else {
00295 fireValueChanged(prevVal==val);
00296 }
00297 }
00298
00299 std::string OutputSelector::get() const {
00300 if(val==UNUSED)
00301 return "UNUSED";
00302 if(useNumeric) {
00303 unsigned int mappedValue=val;
00304 if(saveModel.size()==0) {
00305 std::stringstream sstr;
00306 sstr << (int)val;
00307 return sstr.str();
00308 } else {
00309 const Capabilities * cap = getCapabilities(saveModel);
00310 if(cap==NULL)
00311 throw bad_format(NULL,"Error: plist specialty type OutputSelector could not save due to bad saveModel "+saveModel);
00312 std::stringstream sstr;
00313 const char * name = capabilities.getFrameName(val);
00314 if(name==NULL) {
00315
00316 cerr << "Warning: plist specialty type OutputSelector does not have an for offset " << (int)val << " can't map to model " << cap->getRobotName() << endl;
00317 sstr << capabilities.getRobotName()<<'/'<<(int)val;
00318 return sstr.str();
00319 }
00320 mappedValue = (int)cap->findFrameOffset(name);
00321 if(mappedValue==-1U) {
00322
00323 cerr << "Warning: plist specialty type OutputSelector mapping to model " << saveModel << ", does not have " << name << endl;
00324 sstr << saveModel << '/' << name;
00325 return sstr.str();
00326 }
00327 sstr << saveModel << '/' << mappedValue;
00328 return sstr.str();
00329 }
00330 } else {
00331 const char * name = capabilities.getFrameName(val);
00332 if(name!=NULL) {
00333 return name;
00334 } else {
00335 std::stringstream sstr;
00336 if(saveModel.size()>0)
00337 sstr << saveModel << '/';
00338 else
00339 sstr << "INVALID" << '/';
00340 sstr << (int)val;
00341 return sstr.str();
00342 }
00343 }
00344 }
00345
00346 void OutputSelector::setRange(unsigned int begin, unsigned int end) {
00347 rangeBegin=begin;
00348 rangeEnd=end;
00349 if(val!=UNUSED && (val<rangeBegin || val>=rangeEnd || val>=capabilities.getNumFrames()) ) {
00350 prevVal=val;
00351 val=UNUSED;
00352 fireValueChanged(prevVal==val);
00353 if(throwInvalid) {
00354 if(capabilities.getFrameName(val)!=NULL)
00355 throw bad_value(capabilities.getFrameName(val),val);
00356 else
00357 throw bad_value(val,true);
00358 }
00359 cerr << "Error: plist specialty type OutputSelector value " << prevVal << " was invalidated by change to range (" << rangeBegin <<','<< std::min(rangeEnd,capabilities.getNumFrames()) << ']' << endl;
00360 }
00361 }
00362
00363
00364 PLIST_CLONE_IMP(OutputSelector,new OutputSelector);
00365
00366
00367
00368
00369
00370
00371 Angle::Format Angle::defaultFormat=Angle::FORMAT_DEGREE;
00372 Angle::Pedantic Angle::pedantic=Angle::PEDANTIC_FULL;
00373
00374 void Angle::loadXML(xmlNode* node) {
00375 if(node==NULL)
00376 return;
00377 xmlChar* cont=xmlNodeGetContent(node);
00378 xmlChar * att=NULL;
00379 try {
00380 if(xNodeHasName(node,"string") || xNodeHasName(node,"integer") || xNodeHasName(node,"real")) {
00381 att = xmlGetProp(node,(const xmlChar*)"unit");
00382 if(att==NULL) {
00383 set((char*)cont);
00384 } else {
00385 prevVal=val;
00386 if(xmlStrcasecmp(att,(const xmlChar*)"rad")==0 || xmlStrcasecmp(att,(const xmlChar*)"radian")==0 || xmlStrcasecmp(att,(const xmlChar*)"radians")==0) {
00387 char * endp=NULL;
00388 val=strtof((char*)cont,&endp);
00389 if(*endp!='\0') {
00390 val=prevVal;
00391 throw bad_format(node,"plist specialty type Angle expects a numeric value");
00392 }
00393 loadedFormat=FORMAT_RADIAN;
00394 } else if(xmlStrcasecmp(att,(const xmlChar*)"°")==0 || xmlStrcasecmp(att,(const xmlChar*)"deg")==0 || xmlStrcasecmp(att,(const xmlChar*)"degree")==0 || xmlStrcasecmp(att,(const xmlChar*)"degrees")==0) {
00395 char * endp=NULL;
00396 val=strtof((char*)cont,&endp);
00397 if(*endp!='\0') {
00398 val=prevVal;
00399 throw bad_format(node,"plist specialty type Angle expects a numeric value");
00400 }
00401 val=val*(decltype(val))M_PI/180;
00402 loadedFormat=FORMAT_DEGREE;
00403 } else if(xmlStrcasecmp(att,(const xmlChar*)"π")==0 || xmlStrcasecmp(att,(const xmlChar*)"pi")==0) {
00404 char * endp=NULL;
00405 val=strtof((char*)cont,&endp);
00406 if(*endp!='\0') {
00407 val=prevVal;
00408 throw bad_format(node,"plist specialty type Angle expects a numeric value");
00409 }
00410 val*=(decltype(val))M_PI;
00411 loadedFormat=FORMAT_PI;
00412 } else if(xmlStrcasecmp(att,(const xmlChar*)"%")==0 || xmlStrcasecmp(att,(const xmlChar*)"percent")==0) {
00413 char * endp=NULL;
00414 val=strtof((char*)cont,&endp);
00415 if(*endp!='\0') {
00416 val=prevVal;
00417 throw bad_format(node,"plist specialty type Angle expects a numeric value");
00418 }
00419 val=val*2*(decltype(val))M_PI/100;
00420 loadedFormat=FORMAT_PERCENT;
00421 } else {
00422 throw bad_format(node,"Error: plist specialty type Angle encountered unknown unit specification");
00423 }
00424 fireValueChanged(prevVal==val);
00425 }
00426 } else {
00427 throw bad_format(node,"Error: plist specialty type Angle must be either a string, real, or integer");
00428 }
00429 } catch(const bad_format& err) {
00430 xmlFree(att);
00431 xmlFree(cont);
00432 throw (err.getNode()!=NULL) ? err : bad_format(node,err.what());
00433 } catch(...) {
00434 xmlFree(att);
00435 xmlFree(cont);
00436 throw;
00437 }
00438 xmlFree(att);
00439 xmlFree(cont);
00440 }
00441
00442 void Angle::saveXML(xmlNode* node) const {
00443 if(node==NULL)
00444 return;
00445 Format fmt = saveFormat;
00446 if(fmt==FORMAT_SAME)
00447 fmt = (loadedFormat==FORMAT_AUTO) ? defaultFormat : loadedFormat;
00448 if(fmt==FORMAT_AUTO || fmt==FORMAT_SAME) {
00449 decltype(val) deg = val/(decltype(val))M_PI*180;
00450 if(std::abs(std::floor(deg)-deg)<1e-5)
00451 fmt=FORMAT_DEGREE;
00452 }
00453 switch(pedantic) {
00454 case PEDANTIC_FULL: {
00455 xmlUnsetProp(node,(const xmlChar*)"unit");
00456 if(fmt==FORMAT_RADIAN || fmt==FORMAT_NONE) {
00457 xmlNodeSetName(node,(const xmlChar*)"real");
00458 std::stringstream str;
00459 str << val;
00460 xmlNodeSetContent(node,(const xmlChar*)str.str().c_str());
00461 } else {
00462 xmlNodeSetName(node,(const xmlChar*)"string");
00463 xmlNodeSetContent(node,(const xmlChar*)get().c_str());
00464 }
00465 } break;
00466
00467 case PEDANTIC_VALID: {
00468 xmlNodeSetName(node,(const xmlChar*)"real");
00469 std::stringstream str;
00470 switch(fmt) {
00471 case FORMAT_NONE: {
00472 xmlUnsetProp(node,(const xmlChar*)"unit");
00473 str << val;
00474 } break;
00475 case FORMAT_RADIAN: {
00476 xmlSetProp(node,(const xmlChar*)"unit",(const xmlChar*)"rad");
00477 str << val;
00478 } break;
00479 case FORMAT_DEGREE: {
00480 xmlSetProp(node,(const xmlChar*)"unit",(const xmlChar*)"deg");
00481 str << (val/M_PI*180);
00482 } break;
00483 case FORMAT_PI: {
00484 xmlSetProp(node,(const xmlChar*)"unit",(const xmlChar*)"pi");
00485 str << (val/M_PI);
00486 } break;
00487 case FORMAT_PERCENT: {
00488 xmlSetProp(node,(const xmlChar*)"unit",(const xmlChar*)"%");
00489 str << (val/(2*M_PI)*100);
00490 } break;
00491 default: {
00492 throw std::logic_error("unhandled format");
00493 } break;
00494 }
00495 xmlNodeSetContent(node,(const xmlChar*)str.str().c_str());
00496 } break;
00497
00498 case PEDANTIC_CUTE: {
00499 xmlUnsetProp(node,(const xmlChar*)"unit");
00500 xmlNodeSetName(node,(const xmlChar*)"real");
00501 xmlNodeSetContent(node,(const xmlChar*)get().c_str());
00502 } break;
00503
00504 }
00505 }
00506
00507 void Angle::set(const std::string& str) {
00508 prevVal=val;
00509 string strval = string_util::trim(str);
00510 size_t p;
00511 if((p=strval.find("%"))!=string::npos) {
00512 string strnum = strval.substr(0,p);
00513 char * endp=NULL;
00514 val=strtof(strnum.c_str(),&endp);
00515 if(endp==strnum.c_str()) {
00516 val=prevVal;
00517 throw bad_format(NULL,"plist specialty type Angle expects a numeric value");
00518 }
00519 if(*endp!='\0')
00520 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters preceeding '%': " << endp << std::endl;
00521 if(p!=strval.size()-strlen("%"))
00522 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters following '%': " << strval.substr(p+strlen("%")) << std::endl;
00523 val=val*2*(decltype(val))M_PI/100;
00524 loadedFormat=FORMAT_PERCENT;
00525
00526 } else if((p=strval.find("π"))!=string::npos) {
00527 bool neg=false;
00528 if(strval[0]=='-') {
00529 neg=true;
00530 strval=strval.substr(1);
00531 p=strval.find("π");
00532 }
00533 float num,den=1;
00534 if(p==0)
00535 num=1;
00536 else {
00537 string strnum = strval.substr(0,p);
00538 char * endp=NULL;
00539 num=strtof(strnum.c_str(),&endp);
00540 if(endp==strnum.c_str())
00541 throw bad_format(NULL,"plist specialty type Angle expects a numeric value in π numerator");
00542 if(*endp!='\0')
00543 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters preceeding 'π': " << endp << std::endl;
00544 }
00545 strval=string_util::trim(strval.substr(p+strlen("π")));
00546 if(strval[0]=='/') {
00547 strval=strval.substr(1);
00548 if(strval.size()==0) {
00549 std::cerr << "WARNING: plist specialty type Angle ignoring trailing '/' following 'π'" << std::endl;
00550 } else {
00551 char * endp=NULL;
00552 den=strtof(strval.c_str(),&endp);
00553 if(endp==strval.c_str())
00554 throw bad_format(NULL,"plist specialty type Angle expects a numeric value in π denominator");
00555 if(*endp!='\0')
00556 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters following denominator: " << endp << std::endl;
00557 }
00558 } else if(strval.size()!=0) {
00559 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters following 'π': " << strval.substr(p+strlen("π")) << std::endl;
00560 }
00561 val = neg ? -num*(decltype(val))M_PI/den : num*(decltype(val))M_PI/den;
00562 loadedFormat=FORMAT_PI;
00563
00564 } else if((p=strval.find("°"))!=string::npos) {
00565 string strnum = strval.substr(0,p);
00566 char * endp=NULL;
00567 val=strtof(strnum.c_str(),&endp);
00568 if(endp==strnum.c_str()) {
00569 val=prevVal;
00570 throw bad_format(NULL,"plist specialty type Angle expects a numeric value");
00571 }
00572 if(*endp!='\0')
00573 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters preceeding '°': " << endp << std::endl;
00574 if(p!=strval.size()-strlen("°"))
00575 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters following '°': " << strval.substr(p+strlen("%")) << std::endl;
00576 val=val*(decltype(val))M_PI/180;
00577 loadedFormat=FORMAT_DEGREE;
00578
00579 } else {
00580 if(strval=="∞" && std::numeric_limits<PLISTREAL>::has_infinity) {
00581 val=std::numeric_limits<PLISTREAL>::infinity();
00582 } else {
00583 char * endp=NULL;
00584 val=strtof(strval.c_str(),&endp);
00585 if(endp==strval.c_str()) {
00586 val=prevVal;
00587 throw bad_format(NULL,"plist specialty type Angle expects a numeric value");
00588 }
00589 if(*endp!='\0')
00590 std::cerr << "WARNING: plist specialty type Angle ignoring extra characters following value: " << endp << std::endl;
00591 }
00592 loadedFormat=FORMAT_RADIAN;
00593
00594 }
00595 fireValueChanged(prevVal==val);
00596 }
00597
00598 std::string Angle::get() const {
00599 Format fmt = saveFormat;
00600 if(fmt==FORMAT_SAME)
00601 fmt = (loadedFormat==FORMAT_AUTO) ? defaultFormat : loadedFormat;
00602 if(fmt==FORMAT_AUTO || fmt==FORMAT_SAME) {
00603 decltype(val) deg = val*180/(decltype(val))M_PI;
00604 if(std::abs(std::floor(deg)-deg)<1e-5)
00605 fmt=FORMAT_DEGREE;
00606 }
00607 std::stringstream str;
00608 switch(fmt) {
00609 case FORMAT_NONE:
00610 case FORMAT_RADIAN: {
00611 str << val;
00612 } break;
00613 case FORMAT_DEGREE: {
00614 str << (val/M_PI*180) << "°";
00615 } break;
00616 case FORMAT_PI: {
00617 float x = val/(decltype(val))M_PI;
00618
00619 if(std::abs(rint(x)-x)<1e-5) {
00620 if(x==1)
00621 return "π";
00622 else if(x==-1)
00623 return "-π";
00624 else
00625 str << x << "π";
00626 } else for(int i=2; i<16; ++i) {
00627
00628 x = val/(decltype(val))M_PI*i;
00629 if(std::abs(rint(x)-x)<1e-5 && std::abs(x)>.9) {
00630 if(std::abs(rint(x)-1)<1e-5) {
00631 str << "π/" << i;
00632 } else if(std::abs(rint(x)+1)<1e-5) {
00633 str << "-π/" << i;
00634 } else {
00635 str << x << "π/" << i;
00636 }
00637 break;
00638 }
00639 }
00640 if(str.str().size()==0) {
00641
00642 str << val/M_PI << "π";
00643 }
00644 } break;
00645 case FORMAT_PERCENT: {
00646 str << (val/(2*M_PI)*100) << "%";
00647 } break;
00648 default: {
00649 throw std::logic_error("unhandled format");
00650 } break;
00651 }
00652 return str.str();
00653 }
00654
00655
00656 PLIST_CLONE_IMP(Angle,new Angle);
00657
00658 }
00659
00660
00661
00662
00663
00664