source: trunk/src/core/RpUnits.cc @ 525

Last change on this file since 525 was 525, checked in by dkearney, 18 years ago

added new pressure units pascal, bar, torr, mmHg, psi, atm. rewrote some of the test cases for units.

File size: 57.6 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpUnits.cc
4 *
5 *   Data Members and member functions for the RpUnits class
6 *
7 * ======================================================================
8 *  AUTHOR:  Derrick Kearney, Purdue University
9 *  Copyright (c) 2004-2005  Purdue Research Foundation
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15
16#include "RpUnits.h"
17
18// dict pointer
19RpDict<std::string,RpUnits*>* RpUnits::dict = new RpDict<std::string,RpUnits*>();
20
21// install predefined units
22static RpUnitsPreset loader;
23
24// convert function flags
25const int RpUnits::UNITS_OFF = 0;
26const int RpUnits::UNITS_ON  = 1;
27
28/**********************************************************************/
29// METHOD: define()
30/// Define a unit type to be stored as a Rappture Unit.
31/**
32 */
33
34RpUnits *
35RpUnits::define(    const std::string units,
36                    const RpUnits* basis,
37                    const std::string type  ) {
38
39    RpUnits* newRpUnit = NULL;
40
41    std::string searchStr = units;
42    std::string sendStr = "";
43    int len = searchStr.length();
44    int idx = len-1;
45    double exponent = 1;
46
47    if (units.empty()) {
48        // raise error, user sent null units!
49        return NULL;
50    }
51
52    // check to see if the user is trying to trick me!
53    if ( (basis) && (units == basis->getUnits()) ) {
54        // dont trick me!
55        return NULL;
56    }
57
58    // check to see if the said unit can already be found in the dictionary
59    if (RpUnits::find(units)) {
60        return NULL;
61    }
62
63    //default exponent
64    exponent = 1;
65
66    // check to see if there is an exponent at the end
67    // of the search string
68    idx = RpUnits::grabExponent(searchStr, &exponent);
69    searchStr.erase(idx);
70
71    // move idx pointer back to where last character was found
72    idx--;
73
74    if ( searchStr[0] == '/') {
75        // need to negate all of the previous exponents
76        exponent = -1*exponent;
77        sendStr = searchStr.c_str()+1;
78    }
79    else {
80        // sendStr = searchStr.substr(idx+1,);
81        // we have a unit string to parse
82        sendStr = searchStr;
83    }
84
85    newRpUnit = new RpUnits(sendStr, exponent, basis, type);
86    if (newRpUnit) {
87        insert(newRpUnit->getUnitsName(),newRpUnit);
88    }
89
90    // return a copy of the new object to user
91    return newRpUnit;
92}
93
94/**********************************************************************/
95// METHOD: grabExponent()
96/// Return exponent from a units string containing a unit name and exponent
97/**
98 */
99
100int
101RpUnits::grabExponent(const std::string& inStr, double* exp) {
102
103    int len = inStr.length();
104    int idx = len - 1;
105
106    *exp = 1;
107
108    while (isdigit(inStr[idx])) {
109        idx--;
110    }
111
112    if ( (inStr[idx] == '+') || (inStr[idx] == '-') ) {
113        idx--;
114    }
115
116    idx++;
117
118    if (idx != len) {
119        // process the exponent.
120        *exp = strtod(inStr.c_str()+idx,NULL);
121    }
122
123    return idx;
124}
125
126/**********************************************************************/
127// METHOD: grabUnitString()
128/// Return units name from a units string containing a unit name and exponent
129/**
130 */
131
132int
133RpUnits::grabUnitString ( const std::string& inStr ) {
134
135    int idx = inStr.length() - 1;
136
137    while ((idx >= 0) && isalpha(inStr[idx])) {
138        idx--;
139    }
140
141    // move the index forward one position to
142    // represent the start of the unit string
143    idx++;
144
145    return idx;
146}
147
148/**********************************************************************/
149// METHOD: grabUnits()
150/// Search for the provided units exponent pair in the dictionary.
151/**
152 */
153
154const RpUnits*
155RpUnits::grabUnits ( std::string inStr, int* offset) {
156
157    const RpUnits* unit = NULL;
158    int len = inStr.length();
159
160    while ( ! inStr.empty() ) {
161        unit = RpUnits::find(inStr);
162        if (unit) {
163            *offset = len - inStr.length();
164            break;
165        }
166        inStr.erase(0,1);
167    }
168
169    return unit;
170}
171
172
173/**********************************************************************/
174// METHOD: getType()
175/// Return the type of an RpUnits object.
176/**
177 */
178std::string
179RpUnits::getType() const {
180    return this->type;
181}
182
183/**********************************************************************/
184// METHOD: getCompatible()
185/// Return a list of units compatible with this RpUnits object.
186/**
187 */
188std::list<std::string>
189RpUnits::getCompatible(double expMultiplier) const {
190
191    std::list<std::string> compatList;
192    std::list<std::string> basisCompatList;
193    std::string myName          = getUnitsName();
194    // std::stringstream otherName;
195    std::string otherName       = "";
196    std::string otherBasisName  = "";
197    std::string blank           = "";
198    // double otherExp             = 1.0;
199    convEntry* myConversions    = this->convList;
200    const RpUnits * basis       = NULL;
201
202    if (this->basis) {
203        basisCompatList = this->basis->getCompatible();
204        compatList.merge(basisCompatList);
205    }
206    else {
207        // only basis units should be in here
208        //
209        // run through the conversion list
210        // for each entry, look at the name
211        // if the name is not equal to the name of this RpUnits object,
212        // store the fromPtr->getUnitsName() into compatList
213        // else store the toPtr->getUnitsName() into compatList
214        //
215        while (myConversions != NULL) {
216
217            otherName = myConversions->conv->toPtr->getUnitsName();
218            /*
219            otherName.str("");
220            otherName << myConversions->conv->toPtr->getUnitsName();
221            otherExp = myConversions->conv->fromPtr->getExponent();
222            if ( (otherExp != 1) && (expMultiplier != 1) ) {
223                otherName << otherExp * expMultiplier;
224            }
225            */
226            basis = myConversions->conv->toPtr->basis;
227
228            // if (myName == otherName.str()) {
229            if (myName == otherName) {
230                otherName = myConversions->conv->fromPtr->getUnitsName();
231                /*
232                otherName.str("");
233                otherName << myConversions->conv->fromPtr->getUnitsName();
234                if ( (otherExp != 1) && (expMultiplier != 1) ) {
235                    otherExp = myConversions->conv->fromPtr->getExponent();
236                    otherName << otherExp * expMultiplier;
237                }
238                */
239                basis = myConversions->conv->fromPtr->basis;
240            }
241
242            // check to see if they are the same basis,
243            // no need to list all of the metric conversions.
244            if (basis) {
245                if (basis->getUnitsName() == myName) {
246                    // do not add this unit to the conversion
247                    // because its a derived unit.
248                    myConversions = myConversions->next;
249                    continue;
250                }
251            }
252
253            // add the other unit's name to the list of compatible units
254            // compatList.push_back(otherName.str());
255            compatList.push_back(otherName);
256
257            // advance to the next conversion
258            myConversions = myConversions->next;
259        }
260    }
261
262    compatList.push_back(myName);
263    compatList.sort();
264    compatList.unique();
265    return compatList;
266
267}
268
269/**********************************************************************/
270// METHOD: define()
271/// Define a unit conversion with one arg double function pointers.
272/**
273 */
274
275RpUnits *
276RpUnits::define(  const RpUnits* from,
277                  const RpUnits* to,
278                  double (*convForwFxnPtr)(double),
279                  double (*convBackFxnPtr)(double)  ) {
280
281    // this is kinda the wrong way to get the job done...
282    // how do we only create 1 conversion object and share it between atleast two RpUnits
283    // objs so that when the RpUnits objs are deleted, we are not trying to delete already
284    // deleted memory.
285    // so for the sake of safety we get the following few lines of code.
286
287    conversion* conv1 = NULL;
288    conversion* conv2 = NULL;
289
290    if (from && to) {
291
292        conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
293        conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
294
295        from->connectConversion(conv1);
296        to->connectConversion(conv2);
297    }
298
299    return NULL;
300}
301
302/**********************************************************************/
303// METHOD: define()
304/// Define a unit conversion with two arg double function pointers.
305/**
306 */
307
308RpUnits *
309RpUnits::define(  const RpUnits* from,
310                  const RpUnits* to,
311                  double (*convForwFxnPtr)(double,double),
312                  double (*convBackFxnPtr)(double,double)) {
313
314    // this is kinda the wrong way to get the job done...
315    // how do we only create 1 conversion object and share it between
316    // atleast two RpUnits objs so that when the RpUnits objs are
317    // deleted, we are not trying to delete already deleted memory.
318    // so for the sake of safety we get the following few lines of code.
319
320    conversion* conv1 = NULL;
321    conversion* conv2 = NULL;
322
323    if (from && to) {
324        conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
325        conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
326
327        from->connectConversion(conv1);
328        to->connectConversion(conv2);
329    }
330
331    return NULL;
332}
333
334/**********************************************************************/
335// METHOD: define()
336/// Define a unit conversion with two arg void* function pointers.
337/**
338 */
339
340RpUnits *
341RpUnits::define(  const RpUnits* from,
342                  const RpUnits* to,
343                  void* (*convForwFxnPtr)(void*, void*),
344                  void* convForwData,
345                  void* (*convBackFxnPtr)(void*, void*),
346                  void* convBackData) {
347
348    // this is kinda the wrong way to get the job done...
349    // how do we only create 1 conversion object and share it between at
350    // least two RpUnits objs so that when the RpUnits objs are deleted,
351    // we are not trying to delete already deleted memory.
352    // so for the sake of safety we get the following few lines of code.
353
354    conversion* conv1 = NULL;
355    conversion* conv2 = NULL;
356
357    if (from && to) {
358        conv1 = new conversion ( from, to, convForwFxnPtr,convForwData,
359                                 convBackFxnPtr,convBackData);
360        conv2 = new conversion ( from,to,convForwFxnPtr,convForwData,
361                                 convBackFxnPtr,convBackData);
362
363        from->connectConversion(conv1);
364        to->connectConversion(conv2);
365    }
366
367    return NULL;
368}
369
370
371/**********************************************************************/
372// METHOD: getUnits()
373/// Report the text portion of the units of this object back to caller.
374/**
375 * \sa {getUnitsName}
376 */
377
378std::string
379RpUnits::getUnits() const {
380
381    return units;
382}
383
384/**********************************************************************/
385// METHOD: getUnitsName()
386/// Report the full name of the units of this object back to caller.
387/**
388 * Reports the full text and exponent of the units represented by this
389 * object, back to the caller. Note that if the exponent == 1, no
390 * exponent will be printed.
391 */
392
393std::string
394RpUnits::getUnitsName() const {
395
396    std::stringstream unitText;
397    double exponent;
398
399    exponent = getExponent();
400
401    if (exponent == 1) {
402        unitText << units;
403    }
404    else {
405        unitText << units << exponent;
406    }
407
408    return (std::string(unitText.str()));
409}
410
411/**********************************************************************/
412// METHOD: getExponent()
413/// Report the exponent of the units of this object back to caller.
414/**
415 * Reports the exponent of the units represented by this
416 * object, back to the caller. Note that if the exponent == 1, no
417 * exponent will be printed.
418 */
419
420double
421RpUnits::getExponent() const {
422
423    return exponent;
424}
425
426/**********************************************************************/
427// METHOD: getBasis()
428/// Retrieve the RpUnits object representing the basis of this object.
429/**
430 * Returns a pointer to a RpUnits object which, on success, points to the
431 * RpUnits object that is the basis of the calling object.
432 */
433
434const RpUnits *
435RpUnits::getBasis() const {
436
437    return basis;
438}
439
440/**********************************************************************/
441// METHOD: makeBasis()
442/// Convert a value into its RpUnits's basis.
443/**
444 *  convert the current unit to its basis units
445 *
446 *  Return Codes
447 *      0) no error (could also mean or no prefix was found)
448 *          in some cases, this means the value is in its basis format
449 *      1) the prefix found does not have a built in factor associated.
450 *
451 */
452
453double
454RpUnits::makeBasis(double value, int* result) const {
455
456    double retVal = value;
457
458    if (result) {
459        *result = 0;
460    }
461
462    if (basis == NULL) {
463        // this unit is a basis
464        // do nothing
465    }
466    else {
467        retVal = convert(basis,value,result);
468    }
469
470    return retVal;
471}
472
473/**********************************************************************/
474// METHOD: makeBasis()
475/// Convert a value into its RpUnits's basis.
476/**
477 *
478 */
479
480const RpUnits&
481RpUnits::makeBasis(double* value, int* result) const {
482    double retVal = *value;
483    int convResult = 1;
484
485    if (basis == NULL) {
486        // this unit is a basis
487        // do nothing
488    }
489    else {
490        retVal = convert(basis,retVal,&convResult);
491    }
492
493    if ( (convResult == 0) ) {
494        *value = retVal;
495    }
496
497    if (result) {
498        *result = convResult;
499    }
500
501    return *this;
502}
503
504/**********************************************************************/
505// METHOD: makeMetric()
506/// Define a unit type to be stored as a Rappture Unit.
507/**
508 *  static int makeMetric(RpUnits * basis);
509 *  create the metric attachments for the given basis.
510 *  should only be used if this unit is of metric type
511 */
512
513int
514RpUnits::makeMetric(const RpUnits* basis) {
515
516    if (!basis) {
517        return 0;
518    }
519
520    std::string basisName = basis->getUnitsName();
521    std::string name;
522
523    name = "c" + basisName;
524    RpUnits * centi = RpUnits::define(name, basis, basis->type);
525    RpUnits::define(centi, basis, centi2base, base2centi);
526
527    name = "m" + basisName;
528    RpUnits * milli = RpUnits::define(name, basis, basis->type);
529    RpUnits::define(milli, basis, milli2base, base2milli);
530
531    name = "u" + basisName;
532    RpUnits * micro = RpUnits::define(name, basis, basis->type);
533    RpUnits::define(micro, basis, micro2base, base2micro);
534
535    name = "n" + basisName;
536    RpUnits * nano  = RpUnits::define(name, basis, basis->type);
537    RpUnits::define(nano, basis, nano2base, base2nano);
538
539    name = "p" + basisName;
540    RpUnits * pico  = RpUnits::define(name, basis, basis->type);
541    RpUnits::define(pico, basis, pico2base, base2pico);
542
543    name = "f" + basisName;
544    RpUnits * femto = RpUnits::define(name, basis, basis->type);
545    RpUnits::define(femto, basis, femto2base, base2femto);
546
547    name = "a" + basisName;
548    RpUnits * atto  = RpUnits::define(name, basis, basis->type);
549    RpUnits::define(atto, basis, atto2base, base2atto);
550
551    name = "k" + basisName;
552    RpUnits * kilo  = RpUnits::define(name, basis, basis->type);
553    RpUnits::define(kilo, basis, kilo2base, base2kilo);
554
555    name = "M" + basisName;
556    RpUnits * mega  = RpUnits::define(name, basis, basis->type);
557    RpUnits::define(mega, basis, mega2base, base2mega);
558
559    name = "G" + basisName;
560    RpUnits * giga  = RpUnits::define(name, basis, basis->type);
561    RpUnits::define(giga, basis, giga2base, base2giga);
562
563    name = "T" + basisName;
564    RpUnits * tera  = RpUnits::define(name, basis, basis->type);
565    RpUnits::define(tera, basis, tera2base, base2tera);
566
567    name = "P" + basisName;
568    RpUnits * peta  = RpUnits::define(name, basis, basis->type);
569    RpUnits::define(peta, basis, peta2base, base2peta);
570
571    return (1);
572}
573
574
575/**********************************************************************/
576// METHOD: find()
577/// Find an RpUnits Object from the provided string.
578/**
579 */
580
581const RpUnits*
582RpUnits::find(std::string key) {
583
584    // dict pointer
585    const RpUnits* unitEntry = NULL;
586    double exponent = 1;
587    int idx = 0;
588    std::stringstream tmpKey;
589
590    if (key[0] == '/') {
591        // check to see if there is an exponent at the end
592        // of the search string
593        idx = RpUnits::grabExponent(key, &exponent);
594        tmpKey << key.substr(1,idx-1) << (-1*exponent);
595        key = tmpKey.str();
596    }
597
598    unitEntry = *(dict->find(key).getValue());
599
600    // dict pointer
601    if (unitEntry == *(dict->getNullEntry().getValue()) ) {
602        unitEntry = NULL;
603    }
604
605    return unitEntry;
606}
607
608/**********************************************************************/
609// METHOD: validate()
610/// Split a string of units and check that each unit is available as an object
611/**
612 * Splits a string of units like cm2/kVns into a list of units like
613 * cm2, kV1, ns1 where an exponent is provided for each list entry.
614 * It checks to see that each unit actually exists as a valid defined unit.
615 * If the unit exists or can be interpreted, the function keeps parsing the
616 * string until it reaches the end of the string. If the function comes
617 * across a unit that is unrecognized or can not be interpreted, then it
618 * returns error (a non-zero value).
619 *
620 * this code is very similar to units2list()
621 *
622 * if &compatList == NULL, no compatible list of units will be generated.
623 * this function does not do a good job of placing the available units
624 * back into the original formula. i still need to work on this.
625 */
626
627int
628RpUnits::validate ( const std::string& inUnits,
629                    std::string& type,
630                    std::list<std::string>* compatList ) {
631
632    std::string myInUnits   = inUnits;
633    std::string sendUnitStr = "";
634    double exponent         = 1;
635    int offset              = 0;
636    int idx                 = 0;
637    int last                = 0;
638    int err                 = 0; // did we come across an unrecognized unit
639    const RpUnits* unit     = NULL;
640    std::list<std::string> basisCompatList;
641    std::list<std::string>::iterator compatListIter;
642    std::stringstream unitWExp;
643
644
645    while ( !myInUnits.empty() ) {
646
647        // check to see if we came across a '/' character
648        last = myInUnits.length()-1;
649        if (myInUnits[last] == '/') {
650            type = myInUnits[last] + type;
651            myInUnits.erase(last);
652            continue;
653        }
654
655        // get the exponent
656        offset = RpUnits::grabExponent(myInUnits,&exponent);
657        myInUnits.erase(offset);
658        idx = offset - 1;
659
660        // grab the largest string we can find
661        offset = RpUnits::grabUnitString(myInUnits);
662        idx = offset;
663
664        // figure out if we have some defined units in that string
665        sendUnitStr = myInUnits.substr(offset,std::string::npos);
666        if ((unit = grabUnits(sendUnitStr,&offset))) {
667            // a unit was found
668            // erase the found unit's name from our search string
669            myInUnits.erase(idx+offset);
670
671            // add the type to the type string
672            type = unit->getType() + type;
673
674            // merge the compatible units
675            if (compatList) {
676                basisCompatList = unit->getCompatible(exponent);
677
678                // adjust exponents as necessary
679                if ( (exponent != 0) && (exponent != 1) ) {
680                    compatListIter = compatList->begin();
681                    while (compatListIter != compatList->end()) {
682                        unitWExp << *compatListIter << exponent;
683                        *compatListIter = unitWExp.str();
684                    }
685                }
686
687                compatList->merge(basisCompatList);
688            }
689        }
690        else {
691            // we came across a unit we did not recognize
692            // raise error and exit
693            err++;
694            break;
695        }
696
697        // reset our vars
698        idx = 0;
699        offset = 0;
700        exponent = 1;
701    }
702
703    // clean out any duplicate entries.
704    if (compatList) {
705        compatList->unique();
706    }
707
708    return err;
709}
710
711
712/**********************************************************************/
713// METHOD: negateListExponents()
714/// Negate the exponents on every element in unitsList
715/**
716 */
717
718int
719RpUnits::negateListExponents(RpUnitsList& unitsList) {
720    RpUnitsListIter iter = unitsList.begin();
721    int nodeCnt = unitsList.size();
722
723    if (nodeCnt > 0) {
724        for (; iter != unitsList.end(); iter++) {
725            iter->negateExponent();
726            nodeCnt--;
727        }
728    }
729
730    return nodeCnt;
731}
732
733/**********************************************************************/
734// METHOD: negateExponent()
735/// Negate the exponent on the current RpUnitsListEntry
736/**
737 */
738
739void
740RpUnitsListEntry::negateExponent() const {
741    exponent = exponent * -1;
742    return;
743}
744
745/**********************************************************************/
746// METHOD: name()
747/// Provide the caller with the name of this object
748/**
749 */
750
751std::string
752RpUnitsListEntry::name() const {
753    std::stringstream name;
754    name << unit->getUnits() << exponent;
755    return std::string(name.str());
756}
757
758/**********************************************************************/
759// METHOD: define()
760/// Provide the caller with the basis of the RpUnits object being stored
761/**
762 */
763
764const RpUnits*
765RpUnitsListEntry::getBasis() const {
766    return unit->getBasis();
767}
768
769/**********************************************************************/
770// METHOD: getUnitsObj()
771/// Return the RpUnits Object from a RpUnitsListEntry.
772/**
773 */
774
775const RpUnits*
776RpUnitsListEntry::getUnitsObj() const {
777    return unit;
778}
779
780/**********************************************************************/
781// METHOD: getExponent()
782/// Return the exponent of an RpUnitsListEntry.
783/**
784 */
785
786double
787RpUnitsListEntry::getExponent() const {
788    return exponent;
789}
790
791/**********************************************************************/
792// METHOD: printList()
793/// Traverse a RpUnitsList and print out the name of each element.
794/**
795 */
796
797int
798RpUnits::printList(RpUnitsList& unitsList) {
799    RpUnitsListIter iter = unitsList.begin();
800    int nodeCnt = unitsList.size();
801
802    if (nodeCnt > 0) {
803        for (; iter != unitsList.end(); iter++) {
804            std::cout << iter->name() << " ";
805            nodeCnt--;
806        }
807        std::cout << std::endl;
808    }
809
810    return nodeCnt;
811}
812
813/**********************************************************************/
814// METHOD: units2list()
815/// Split a string of units into a list of base units with exponents.
816/**
817 * Splits a string of units like cm2/kVns into a list of units like
818 * cm2, kV1, ns1 where an exponent is provided for each list entry.
819 * List entries are found by comparing units strings to the names
820 * in the dictionary.
821 */
822
823int
824RpUnits::units2list ( const std::string& inUnits,
825                      RpUnitsList& outList ) {
826
827    std::string myInUnits   = inUnits;
828    std::string sendUnitStr = "";
829    double exponent         = 1;
830    int offset              = 0;
831    int idx                 = 0;
832    int last                = 0;
833    const RpUnits* unit     = NULL;
834
835
836    while ( !myInUnits.empty() ) {
837
838        // check to see if we came across a '/' character
839        last = myInUnits.length()-1;
840        if (myInUnits[last] == '/') {
841            myInUnits.erase(last);
842            // multiply previous exponents by -1
843            if ( ! outList.empty() ) {
844                RpUnits::negateListExponents(outList);
845            }
846            continue;
847        }
848
849        // get the exponent
850        offset = RpUnits::grabExponent(myInUnits,&exponent);
851        myInUnits.erase(offset);
852        idx = offset - 1;
853
854        // grab the largest string we can find
855        offset = RpUnits::grabUnitString(myInUnits);
856        idx = offset;
857
858        // figure out if we have some defined units in that string
859        sendUnitStr = myInUnits.substr(offset,std::string::npos);
860        unit = grabUnits(sendUnitStr,&offset);
861        if (unit) {
862            // a unit was found
863            // add this unit to the list
864            // erase the found unit's name from our search string
865            outList.push_front(RpUnitsListEntry(unit,exponent));
866            myInUnits.erase(idx+offset);
867        }
868        else {
869            // we came across a unit we did not recognize
870            // raise error and delete character for now
871            myInUnits.erase(last);
872        }
873
874        // reset our vars
875        idx = 0;
876        offset = 0;
877        exponent = 1;
878    }
879
880    return 0;
881}
882
883/**********************************************************************/
884// METHOD: compareListEntryBasis()
885/// Compare two RpUnits objects to see if they are related by a basis
886/**
887 * One step in converting between Rappture Units Objects is to check
888 * to see if the conversion is an intra-basis conversion. Intra-basis
889 * conversions include those where all conversions are done within
890 * the same basis.
891 *
892 * Examples of intra-basis conversions include:
893 *     m -> cm  ( meters to centimeters )
894 *     cm -> m  ( centimeters to meters )
895 *     cm -> nm ( centimenters to nanometers )
896 */
897
898int RpUnits::compareListEntryBasis ( RpUnitsList& fromList,
899                                     RpUnitsListIter& fromIter,
900                                     RpUnitsListIter& toIter ) {
901
902    const RpUnits* toBasis = NULL;
903    const RpUnits* fromBasis = NULL;
904    int retVal = 1;
905    double fromExp = 0;
906    double toExp = 0;
907
908    fromIter = fromList.begin();
909
910    // get the basis of the object being stored
911    // if the basis is NULL, then we'll compare the object
912    // itself because the object is the basis.
913    toBasis = toIter->getBasis();
914    if (toBasis == NULL) {
915        toBasis = toIter->getUnitsObj();
916    }
917
918    toExp   = toIter->getExponent();
919
920    while ( fromIter != fromList.end() ) {
921
922        fromExp = fromIter->getExponent();
923
924        // in order to convert, exponents must be equal.
925        if (fromExp == toExp) {
926
927            // get the basis of the object being stored
928            // if the basis is NULL, then we'll compare the object
929            // itself because the object is the basis.
930            fromBasis = fromIter->getBasis();
931            if (fromBasis == NULL) {
932                fromBasis = fromIter->getUnitsObj();
933            }
934
935            if (toBasis == fromBasis) {
936                // conversion needed between 2 units of the same basis.
937                // these two units could actually be the same unit (m->m)
938                retVal = 0;
939                break;
940            }
941        }
942
943        fromIter++;
944    }
945
946    return retVal;
947}
948
949/**********************************************************************/
950// METHOD: compareListEntrySearch()
951/// this function will soon be removed.
952/**
953 */
954
955int RpUnits::compareListEntrySearch ( RpUnitsList& fromList,
956                                     RpUnitsListIter& fromIter,
957                                     RpUnitsListIter& toIter ) {
958
959    const RpUnits* toBasis = NULL;
960    const RpUnits* fromBasis = NULL;
961    int retVal = 1;
962
963    fromIter = fromList.begin();
964
965    // get the basis of the object being stored
966    // if the basis is NULL, then we'll compare the object
967    // itself because the object is the basis.
968    toBasis = toIter->getBasis();
969    if (toBasis == NULL) {
970        toBasis = toIter->getUnitsObj();
971    }
972
973    while ( fromIter != fromList.end() ) {
974
975        // get the basis of the object being stored
976        // if the basis is NULL, then we'll compare the object
977        // itself because the object is the basis.
978        fromBasis = fromIter->getBasis();
979        if (fromBasis == NULL) {
980            fromBasis = fromIter->getUnitsObj();
981        }
982
983        if (toBasis == fromBasis) {
984            // conversion needed between 2 units of the same basis.
985            // these two units could actually be the same unit (m->m)
986            retVal = 0;
987            break;
988        }
989
990        fromIter++;
991    }
992
993    return retVal;
994}
995
996/**********************************************************************/
997// METHOD: convert()
998/// Convert between RpUnits return a string value with or without units
999/**
1000 * Convert function so people can just send in two strings and
1001 * we'll see if the units exists and do a conversion
1002 * Example:
1003 *     strVal = RpUnits::convert("300K","C",1);
1004 *
1005 * Returns a string with or without units.
1006 */
1007
1008std::string
1009RpUnits::convert (  std::string val,
1010                    std::string toUnitsName,
1011                    int showUnits,
1012                    int* result ) {
1013
1014    RpUnitsList toUnitsList;
1015    RpUnitsList fromUnitsList;
1016
1017    RpUnitsListIter toIter;
1018    RpUnitsListIter fromIter;
1019    RpUnitsListIter tempIter;
1020
1021    const RpUnits* toUnits = NULL;
1022    const RpUnits* fromUnits = NULL;
1023
1024    std::string tmpNumVal = "";
1025    std::string fromUnitsName = "";
1026    std::string convVal = "";
1027    double origNumVal = 0;
1028    double numVal = 0;
1029    double toExp = 0;
1030    double fromExp = 0;
1031    int convResult = 0;
1032    char* endptr = NULL;
1033    std::stringstream outVal;
1034
1035    int rv = 0;
1036    double factor = 1;
1037
1038
1039    // set  default result flag/error code
1040    if (result) {
1041        *result = 0;
1042    }
1043
1044    // search our string to see where the numeric part stops
1045    // and the units part starts
1046    //
1047    //  convert("5J", "neV") => 3.12075e+28neV
1048    //  convert("3.12075e+28neV", "J") => 4.99999J
1049    // now we can actually get the scientific notation portion of the string.
1050    //
1051
1052    numVal = strtod(val.c_str(),&endptr);
1053    origNumVal = numVal;
1054
1055    if ( (numVal == 0) && (endptr == val.c_str()) ) {
1056        // no conversion was done.
1057        // number in incorrect format probably.
1058        if (result) {
1059            *result = 1;
1060        }
1061        return val;
1062    }
1063
1064    fromUnitsName = std::string(endptr);
1065
1066    if (toUnitsName.empty())  {
1067        // there were no units in the input
1068        // string or no conversion needed
1069        // assume fromUnitsName = toUnitsName
1070        // return the correct value
1071        if (result) {
1072            *result = 0;
1073        }
1074
1075        if (showUnits) {
1076            outVal << numVal << fromUnitsName;
1077        }
1078        else {
1079            outVal << numVal;
1080        }
1081
1082        return std::string(outVal.str());
1083    }
1084
1085    // check if the fromUnitsName is empty or
1086    // if the fromUnitsName == toUnitsName
1087    // these are conditions where no conversion is needed
1088    if ( (fromUnitsName.empty()) || (toUnitsName == fromUnitsName) )  {
1089        // there were no units in the input
1090        // string or no conversion needed
1091        // assume fromUnitsName = toUnitsName
1092        // return the correct value
1093        if (result) {
1094            *result = 0;
1095        }
1096
1097        if (showUnits) {
1098            outVal << numVal << toUnitsName;
1099        }
1100        else {
1101            outVal << numVal;
1102        }
1103
1104        return std::string(outVal.str());
1105    }
1106
1107    RpUnits::units2list(toUnitsName,toUnitsList);
1108    RpUnits::units2list(fromUnitsName,fromUnitsList);
1109
1110    toIter = toUnitsList.begin();
1111
1112    // pass 1: compare basis' of objects to find intra-basis conversions
1113    while ( toIter != toUnitsList.end() ) {
1114        rv = RpUnits::compareListEntryBasis(fromUnitsList, fromIter, toIter);
1115        if (rv == 0) {
1116
1117            // check the names of the units provided by the user
1118            // if the names are the same, no need to do a conversion
1119            if (fromIter->name() != toIter->name()) {
1120
1121                // do an intra-basis conversion
1122                toUnits = toIter->getUnitsObj();
1123                fromUnits = fromIter->getUnitsObj();
1124
1125                // do conversions
1126                factor = 1;
1127                factor = fromUnits->convert(toUnits, factor, &convResult);
1128                numVal *= pow(factor,toIter->getExponent());
1129            }
1130
1131            // remove the elements from the lists
1132            tempIter = toIter;
1133            toIter = toUnitsList.erase(tempIter);
1134//            toUnitsList.erase(tempIter);
1135//            toIter++;
1136
1137            tempIter = fromIter;
1138            fromUnitsList.erase(tempIter);
1139        }
1140        else {
1141            // this is not an intra-basis conversion.
1142            // move onto the next toIter
1143            toIter++;
1144        }
1145    }
1146
1147    toIter = toUnitsList.begin();
1148    fromIter = fromUnitsList.begin();
1149
1150    // pass 2: look for inter-basis conversions
1151    if (fromIter != fromUnitsList.end()) {
1152        // double while loop to compare each toIter with each fromIter.
1153        // the outter while checks the toIter and the inner while
1154        // which is conveniently hidden, adjusts the fromIter and toIter
1155        // (at the bottom in the else statement).
1156        while (toIter != toUnitsList.end()) {
1157
1158            toUnits = toIter->getUnitsObj();
1159            fromUnits = fromIter->getUnitsObj();
1160
1161            // do an inter-basis conversion...the slow way
1162            // there has to be a better way to do this...
1163            convResult = 1;
1164
1165            // in order to convert, exponents must be equal.
1166            fromExp = fromIter->getExponent();
1167            toExp   = toIter->getExponent();
1168
1169            if (fromExp == toExp) {
1170                if (toExp == 1) {
1171                    numVal = fromUnits->convert(toUnits, numVal, &convResult);
1172                }
1173                else {
1174                    factor = 1;
1175                    factor = fromUnits->convert(toUnits, factor, &convResult);
1176                    numVal *= pow(factor,toExp);
1177                }
1178            }
1179
1180            if (convResult == 0) {
1181                // successful conversion reported
1182                // remove the elements from the lists
1183                tempIter = toIter;
1184                toUnitsList.erase(tempIter);
1185                toIter++;
1186
1187                tempIter = fromIter;
1188                fromUnitsList.erase(tempIter);
1189
1190                // conversion complete, jump out of the
1191                // while loop
1192                break;
1193            }
1194            else {
1195                // conversion was unsuccessful
1196                // move onto the next fromIter
1197                fromIter++;
1198                if (fromIter == fromUnitsList.end()) {
1199                    // this is not an inter-basis conversion.
1200                    // move onto the next toIter
1201                    fromIter = fromUnitsList.begin();
1202                    toIter++;
1203                }
1204            } // end unsuccessful conversion
1205        } // end toIter while loop
1206    } // end
1207
1208
1209
1210    if ( (result) && (*result == 0) ) {
1211        *result = convResult;
1212    }
1213
1214    // outVal.flags(std::ios::fixed);
1215    // outVal.precision(10);
1216
1217    if (showUnits) {
1218        outVal << numVal << toUnitsName;
1219    }
1220    else {
1221        outVal << numVal;
1222    }
1223
1224    return std::string(outVal.str());
1225
1226}
1227
1228/**********************************************************************/
1229// METHOD: convert()
1230/// Convert between RpUnits return a string value with or without units
1231/**
1232 * Returns a string value with or without units.
1233 */
1234
1235std::string
1236RpUnits::convert ( const  RpUnits* toUnits,
1237                   double val,
1238                   int showUnits,
1239                   int* result )  const {
1240
1241    double retVal = convert(toUnits,val,result);
1242    std::stringstream unitText;
1243
1244
1245    if (showUnits) {
1246        unitText << retVal << toUnits->getUnitsName();
1247    }
1248    else {
1249        unitText << retVal;
1250    }
1251
1252    return (std::string(unitText.str()));
1253
1254}
1255
1256/**********************************************************************/
1257// METHOD: convert()
1258/// Convert between RpUnits using an RpUnits Object to describe toUnit.
1259/**
1260 * User function to convert a value to the provided RpUnits* toUnits
1261 * if it exists as a conversion from the basis
1262 * example
1263 *      cm.convert(meter,10)
1264 *      cm.convert(angstrum,100)
1265 *
1266 * Returns a double value without units.
1267 */
1268
1269double
1270RpUnits::convert(const RpUnits* toUnit, double val, int* result) const {
1271
1272    // currently we convert this object to its basis and look for the
1273    // connection to the toUnit object from the basis.
1274
1275    double value = val;
1276    const RpUnits* toBasis = toUnit->getBasis();
1277    const RpUnits* fromUnit = this;
1278    const RpUnits* dictToUnit = NULL;
1279    convEntry *p;
1280    int my_result = 0;
1281
1282    // set *result to a default value
1283    if (result) {
1284        *result = 1;
1285    }
1286
1287    // guard against converting to the units you are converting from...
1288    // ie. meters->meters
1289    if (this->getUnitsName() == toUnit->getUnitsName()) {
1290        if (result) {
1291            *result = 0;
1292        }
1293        return val;
1294    }
1295
1296    // convert unit to the basis
1297    // makeBasis(&value);
1298    // trying to avoid the recursive way of converting to the basis.
1299    // need to rethink this.
1300    //
1301    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1302        value = convert(basis,value,&my_result);
1303        if (my_result == 0) {
1304            fromUnit = basis;
1305        }
1306    }
1307
1308    // find the toUnit in our dictionary.
1309    // if the toUnits has a basis, we need to search for the basis
1310    // and convert between basis' and then convert again back to the
1311    // original unit.
1312    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1313        dictToUnit = find(toBasis->getUnitsName());
1314    }
1315    else {
1316        dictToUnit = find(toUnit->getUnitsName());
1317    }
1318
1319    // did we find the unit in the dictionary?
1320    if (dictToUnit == NULL) {
1321        // toUnit was not found in the dictionary
1322        return val;
1323    }
1324
1325    // search through the conversion list to find
1326    // the conversion to the toUnit.
1327
1328    if (basis) {
1329        p = basis->convList;
1330    }
1331    else {
1332        p = this->convList;
1333    }
1334
1335    if (p == NULL) {
1336        // there are no conversions
1337        return val;
1338    }
1339
1340    // loop through our conversion list looking for the correct conversion
1341    do {
1342
1343        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1344            // we found our conversion
1345            // call the function pointer with value
1346
1347            // this should probably be re thought out
1348            // the problem is that convForwFxnPtr has the conversion for a
1349            // one arg conv function pointer and convForwFxnPtrDD has the
1350            // conversion for a two arg conv function pointer
1351            // need to make this simpler, more logical maybe only allow 2 arg
1352            if (       (p->conv->convForwFxnPtr)
1353                    && (! p->conv->convForwFxnPtrDD) ) {
1354
1355                value = p->conv->convForwFxnPtr(value);
1356            }
1357            else if (  (p->conv->convForwFxnPtrDD)
1358                    && (! p->conv->convForwFxnPtr) ) {
1359
1360                value =
1361                    p->conv->convForwFxnPtrDD(value, fromUnit->getExponent());
1362            }
1363
1364            // check to see if we converted to the actual requested unit
1365            // or to the requested unit's basis.
1366            // if we converted to the requested unit's basis. we need to
1367            // do one last conversion from the requested unit's basis back
1368            // to the requested unit.
1369            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1370                my_result = 0;
1371                value = toBasis->convert(toUnit,value,&my_result);
1372                if (my_result != 0) {
1373                    if (result) {
1374                        *result += 1;
1375                    }
1376                }
1377            }
1378
1379            // change the result code to zero, a conversion was performed
1380            // (we think)... its ture that it is possible to get to this
1381            // point and have skipped the conversion because the
1382            // conversion object was not properly created...
1383            // ie. both fxn ptrs were null or neither fxn ptr was null
1384            //
1385            if (result && (*result == 1)) {
1386                *result = 0;
1387            }
1388            break;
1389        }
1390
1391        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1392            // we found our conversion
1393            // call the function pointer with value
1394
1395            // this should probably be re thought out
1396            // the problem is that convForwFxnPtr has the conversion for a
1397            // one arg conv function pointer and convForwFxnPtrDD has the
1398            // conversion for a two arg conv function pointer
1399            // need to make this simpler, more logical maybe only allow 2 arg
1400            if (       (p->conv->convBackFxnPtr)
1401                    && (! p->conv->convBackFxnPtrDD) ) {
1402
1403                value = p->conv->convBackFxnPtr(value);
1404            }
1405            else if (  (p->conv->convBackFxnPtrDD)
1406                    && (! p->conv->convBackFxnPtr) ) {
1407
1408                value =
1409                    p->conv->convBackFxnPtrDD(value, fromUnit->getExponent());
1410            }
1411
1412            // check to see if we converted to the actual requested unit
1413            // or to the requested unit's basis.
1414            // if we converted to the requested unit's basis. we need to
1415            // do one last conversion from the requested unit's basis back
1416            // to the requested unit.
1417            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1418                my_result = 0;
1419                value = toBasis->convert(toUnit,value,&my_result);
1420                if (my_result != 0) {
1421                    if (result) {
1422                        *result += 1;
1423                    }
1424                }
1425            }
1426
1427            // change the result code to zero, a conversion was performed
1428            // (we think)... its ture that it is possible to get to this
1429            // point and have skipped the conversion because the
1430            // conversion object was not properly created...
1431            // ie. both fxn ptrs were null or neither fxn ptr was null
1432            //
1433            if (result && (*result == 1)) {
1434                *result = 0;
1435            }
1436            break;
1437        }
1438
1439        p = p->next;
1440
1441    } while (p != NULL);
1442
1443
1444    if ( p == NULL) {
1445        // we did not find the conversion
1446        if (result) {
1447            *result += 1;
1448        }
1449        return val;
1450    }
1451
1452    // we found the conversion.
1453    // return the converted value.
1454    return value;
1455
1456}
1457
1458
1459/**********************************************************************/
1460// METHOD: convert()
1461/// Convert a value between RpUnits using user defined conversions
1462/**
1463 */
1464
1465void*
1466RpUnits::convert(const RpUnits* toUnit, void* val, int* result) const {
1467
1468    // currently we convert this object to its basis and look for the
1469    // connection ot the toUnit object from the basis.
1470
1471    void* value = val;
1472    const RpUnits* toBasis = toUnit->getBasis();
1473    const RpUnits* fromUnit = this;
1474    const RpUnits* dictToUnit = NULL;
1475    convEntry *p;
1476    int my_result = 0;
1477
1478    // set *result to a default value
1479    if (result) {
1480        *result = 1;
1481    }
1482
1483    // guard against converting to the units you are converting from...
1484    // ie. meters->meters
1485    if (this->getUnitsName() == toUnit->getUnitsName()) {
1486        if (result) {
1487            *result = 0;
1488        }
1489        return val;
1490    }
1491
1492    // convert unit to the basis
1493    // makeBasis(&value);
1494    // trying to avoid the recursive way of converting to the basis.
1495    // need to rethink this.
1496    //
1497    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1498        value = convert(basis,value,&my_result);
1499        if (my_result == 0) {
1500            fromUnit = basis;
1501        }
1502    }
1503
1504    // find the toUnit in our dictionary.
1505    // if the toUnits has a basis, we need to search for the basis
1506    // and convert between basis' and then convert again back to the
1507    // original unit.
1508    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1509        dictToUnit = find(toBasis->getUnitsName());
1510    }
1511    else {
1512        dictToUnit = find(toUnit->getUnitsName());
1513    }
1514
1515    // did we find the unit in the dictionary?
1516    if (dictToUnit == NULL) {
1517        // toUnit was not found in the dictionary
1518        return val;
1519    }
1520
1521    // search through the conversion list to find
1522    // the conversion to the toUnit.
1523
1524    if (basis) {
1525        p = basis->convList;
1526    }
1527    else {
1528        p = this->convList;
1529    }
1530
1531    if (p == NULL) {
1532        // there are no conversions
1533        return val;
1534    }
1535
1536    // loop through our conversion list looking for the correct conversion
1537    do {
1538
1539        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1540            // we found our conversion
1541            // call the function pointer with value
1542
1543            value = p->conv->convForwFxnPtrVoid(p->conv->convForwData,value);
1544
1545            // check to see if we converted to the actual requested unit
1546            // or to the requested unit's basis.
1547            // if we converted to the requested unit's basis. we need to
1548            // do one last conversion from the requested unit's basis back
1549            // to the requested unit.
1550            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1551                my_result = 0;
1552                value = toBasis->convert(toUnit,value,&my_result);
1553                if (my_result != 0) {
1554                    if (result) {
1555                        *result += 1;
1556                    }
1557                }
1558            }
1559
1560            // change the result code to zero, a conversion was performed
1561            // (we think)... its ture that it is possible to get to this
1562            // point and have skipped the conversion because the
1563            // conversion object was not properly created...
1564            // ie. both fxn ptrs were null or neither fxn ptr was null
1565            //
1566            if (result && (*result == 1)) {
1567                *result = 0;
1568            }
1569            break;
1570        }
1571
1572        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1573            // we found our conversion
1574            // call the function pointer with value
1575
1576            value = p->conv->convBackFxnPtrVoid(p->conv->convBackData,value);
1577
1578            // check to see if we converted to the actual requested unit
1579            // or to the requested unit's basis.
1580            // if we converted to the requested unit's basis. we need to
1581            // do one last conversion from the requested unit's basis back
1582            // to the requested unit.
1583            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1584                my_result = 0;
1585                value = toBasis->convert(toUnit,value,&my_result);
1586                if (my_result != 0) {
1587                    if (result) {
1588                        *result += 1;
1589                    }
1590                }
1591            }
1592
1593            // change the result code to zero, a conversion was performed
1594            // (we think)... its ture that it is possible to get to this
1595            // point and have skipped the conversion because the
1596            // conversion object was not properly created...
1597            // ie. both fxn ptrs were null or neither fxn ptr was null
1598            //
1599            if (result && (*result == 1)) {
1600                *result = 0;
1601            }
1602            break;
1603        }
1604
1605        p = p->next;
1606
1607    } while (p != NULL);
1608
1609
1610    if ( p == NULL) {
1611        // we did not find the conversion
1612        if (result) {
1613            *result += 1;
1614        }
1615        return val;
1616    }
1617
1618    // we found the conversion.
1619    // return the converted value.
1620    return value;
1621
1622}
1623
1624/**********************************************************************/
1625// METHOD: insert()
1626/// Place an RpUnits Object into the Rappture Units Dictionary.
1627/**
1628 * Return whether the inserted key was new with a non-zero
1629 * value, or if the key already existed with a value of zero.
1630 */
1631
1632int
1633insert(std::string key,RpUnits* val) {
1634
1635    int newRecord = 0;
1636    // RpUnits* val = this;
1637    // dict pointer
1638    RpUnits::dict->set(key,val,&newRecord);
1639    return newRecord;
1640}
1641
1642/**********************************************************************/
1643// METHOD: connectConversion()
1644/// Attach conversion information to a RpUnits Object.
1645/**
1646 */
1647
1648void
1649RpUnits::connectConversion(conversion* conv) const {
1650
1651    convEntry* p = convList;
1652
1653    if (p == NULL) {
1654        convList = new convEntry (conv,NULL,NULL);
1655    }
1656    else {
1657        while (p->next != NULL) {
1658            p = p->next;
1659        }
1660
1661        p->next = new convEntry (conv,p,NULL);
1662    }
1663
1664}
1665
1666/**********************************************************************/
1667// METHOD: addPresets()
1668/// Add a specific set of predefined units to the dictionary
1669/**
1670 */
1671
1672int
1673RpUnits::addPresets (const std::string group) {
1674    int retVal = -1;
1675    if (group.compare("all") == 0) {
1676        retVal = RpUnitsPreset::addPresetAll();
1677    }
1678    else if (group.compare(RP_TYPE_ENERGY) == 0) {
1679        retVal = RpUnitsPreset::addPresetEnergy();
1680    }
1681    else if (group.compare(RP_TYPE_LENGTH) == 0) {
1682        retVal = RpUnitsPreset::addPresetLength();
1683    }
1684    else if (group.compare(RP_TYPE_TEMP) == 0) {
1685        retVal = RpUnitsPreset::addPresetTemp();
1686    }
1687    else if (group.compare(RP_TYPE_TIME) == 0) {
1688        retVal = RpUnitsPreset::addPresetTime();
1689    }
1690    else if (group.compare(RP_TYPE_VOLUME) == 0) {
1691        retVal = RpUnitsPreset::addPresetVolume();
1692    }
1693    else if (group.compare(RP_TYPE_ANGLE) == 0) {
1694        retVal = RpUnitsPreset::addPresetAngle();
1695    }
1696    else if (group.compare(RP_TYPE_MASS) == 0) {
1697        retVal = RpUnitsPreset::addPresetMass();
1698    }
1699    else if (group.compare(RP_TYPE_PRESSURE) == 0) {
1700        retVal = RpUnitsPreset::addPresetPressure();
1701    }
1702    else if (group.compare(RP_TYPE_MISC) == 0) {
1703        retVal = RpUnitsPreset::addPresetMisc();
1704    }
1705
1706    return retVal;
1707}
1708
1709/**********************************************************************/
1710// METHOD: addPresetAll()
1711/// Call all of the addPreset* functions.
1712/**
1713 *
1714 * Add all predefined units to the units dictionary
1715 * Return codes: 0 success, anything else is error
1716 */
1717
1718int
1719RpUnitsPreset::addPresetAll () {
1720
1721    int result = 0;
1722
1723    result += addPresetTime();
1724    result += addPresetTemp();
1725    result += addPresetLength();
1726    result += addPresetEnergy();
1727    result += addPresetVolume();
1728    result += addPresetAngle();
1729    result += addPresetMass();
1730    result += addPresetPressure();
1731    result += addPresetMisc();
1732
1733    return 0;
1734}
1735
1736/**********************************************************************/
1737// METHOD: addPresetTime()
1738/// Add Time related units to the dictionary
1739/**
1740 * Defines the following units:
1741 *   seconds  (s)
1742 *   minutes  (min)
1743 *   hours    (h)
1744 *   days     (d)
1745 *
1746 *   month and year are not included because simple
1747 *   day->month conversions may be misleading
1748 *   month->year conversions may be included in the future
1749 *
1750 * Return codes: 0 success, anything else is error
1751 */
1752
1753int
1754RpUnitsPreset::addPresetTime () {
1755
1756    RpUnits* second    = RpUnits::define("s", NULL, RP_TYPE_TIME);
1757    RpUnits* minute    = RpUnits::define("min", second, RP_TYPE_TIME);
1758    RpUnits* hour      = RpUnits::define("h", second, RP_TYPE_TIME);
1759    RpUnits* day       = RpUnits::define("d", second, RP_TYPE_TIME);
1760
1761    RpUnits::makeMetric(second);
1762
1763    // add time definitions
1764
1765    RpUnits::define(second, minute, sec2min, min2sec);
1766    RpUnits::define(second, hour, sec2hour, hour2sec);
1767    RpUnits::define(second, day, sec2day, day2sec);
1768
1769    return 0;
1770}
1771
1772/**********************************************************************/
1773// METHOD: addPresetTemp()
1774/// Add Temperature related units to the dictionary
1775/**
1776 * Defines the following units:
1777 *   fahrenheit  (F)
1778 *   celcius     (C)
1779 *   kelvin      (K)
1780 *   rankine     (R)
1781 *
1782 * Return codes: 0 success, anything else is error
1783 */
1784
1785int
1786RpUnitsPreset::addPresetTemp () {
1787
1788    RpUnits* fahrenheit = RpUnits::define("F", NULL, RP_TYPE_TEMP);
1789    RpUnits* celcius    = RpUnits::define("C", NULL, RP_TYPE_TEMP);
1790    RpUnits* kelvin     = RpUnits::define("K", NULL, RP_TYPE_TEMP);
1791    RpUnits* rankine    = RpUnits::define("R", NULL, RP_TYPE_TEMP);
1792
1793    // add temperature definitions
1794    RpUnits::define(fahrenheit, celcius, fahrenheit2centigrade, centigrade2fahrenheit);
1795    RpUnits::define(celcius, kelvin, centigrade2kelvin, kelvin2centigrade);
1796    RpUnits::define(fahrenheit, kelvin, fahrenheit2kelvin, kelvin2fahrenheit);
1797    RpUnits::define(rankine, kelvin, rankine2kelvin, kelvin2rankine);
1798
1799    return 0;
1800}
1801
1802/**********************************************************************/
1803// METHOD: addPresetLength()
1804/// Add Length related units to the dictionary
1805/**
1806 * Defines the following units:
1807 *   meters         (m)
1808 *   angstrom       (A)
1809 *   inch           (in)
1810 *   feet           (ft)
1811 *   yard           (yd)
1812 *
1813 * Return codes: 0 success, anything else is error
1814 */
1815
1816int
1817RpUnitsPreset::addPresetLength () {
1818
1819    RpUnits* meters     = RpUnits::define("m", NULL, RP_TYPE_LENGTH);
1820    RpUnits* angstrom   = RpUnits::define("A", NULL, RP_TYPE_LENGTH);
1821    RpUnits* inch       = RpUnits::define("in", NULL, RP_TYPE_LENGTH);
1822    RpUnits* feet       = RpUnits::define("ft", NULL, RP_TYPE_LENGTH);
1823    RpUnits* yard       = RpUnits::define("yd", NULL, RP_TYPE_LENGTH);
1824
1825    RpUnits::makeMetric(meters);
1826
1827    // add length definitions
1828    RpUnits::define(angstrom, meters, angstrom2meter, meter2angstrom);
1829    RpUnits::define(inch, meters, inch2meter, meter2inch);
1830    RpUnits::define(feet, meters, feet2meter, meter2feet);
1831    RpUnits::define(yard, meters, yard2meter, meter2yard);
1832
1833    return 0;
1834}
1835
1836/**********************************************************************/
1837// METHOD: addPresetEnergy()
1838/// Add Energy related units to the dictionary
1839/**
1840 * Defines the following units:
1841 *   volt          (V)
1842 *   electron Volt (eV)
1843 *   joule         (J)
1844 *
1845 * Return codes: 0 success, anything else is error
1846 */
1847
1848int
1849RpUnitsPreset::addPresetEnergy () {
1850
1851    RpUnits* volt       = RpUnits::define("V", NULL, RP_TYPE_ENERGY);
1852    RpUnits* eVolt      = RpUnits::define("eV", NULL, RP_TYPE_ENERGY);
1853    RpUnits* joule      = RpUnits::define("J", NULL, RP_TYPE_ENERGY);
1854
1855    RpUnits::makeMetric(volt);
1856    RpUnits::makeMetric(eVolt);
1857    RpUnits::makeMetric(joule);
1858
1859    // add energy definitions
1860    RpUnits::define(eVolt,joule,electronVolt2joule,joule2electronVolt);
1861
1862    return 0;
1863}
1864
1865/**********************************************************************/
1866// METHOD: addPresetVolume()
1867/// Add Volume related units to the dictionary
1868/**
1869 * Defines the following units:
1870 *   cubic feet (ft3)
1871 *   us gallons (gal)
1872 *
1873 * Return codes: 0 success, anything else is error
1874 */
1875
1876int
1877RpUnitsPreset::addPresetVolume () {
1878
1879    RpUnits* cubic_meter  = RpUnits::define("m3", NULL, RP_TYPE_VOLUME);
1880    // RpUnits* pcubic_meter  = RpUnits::define("/m3", NULL, RP_TYPE_VOLUME);
1881    RpUnits* cubic_feet   = RpUnits::define("ft3", NULL, RP_TYPE_VOLUME);
1882    RpUnits* us_gallon    = RpUnits::define("gal", NULL, RP_TYPE_VOLUME);
1883
1884    RpUnits::makeMetric(cubic_meter);
1885
1886    // add energy definitions
1887    RpUnits::define(cubic_meter,cubic_feet,meter2feet,feet2meter);
1888    RpUnits::define(cubic_meter,us_gallon,cubicMeter2usGallon,usGallon2cubicMeter);
1889    RpUnits::define(cubic_feet,us_gallon,cubicFeet2usGallon,usGallon2cubicFeet);
1890
1891    return 0;
1892}
1893
1894/**********************************************************************/
1895// METHOD: addPresetAngle()
1896/// Add Angle related units to the dictionary
1897/**
1898 * Defines the following units:
1899 *   degrees  (deg)
1900 *   gradians (grad)
1901 *   radians  (rad) (and metric extensions)
1902 *
1903 * Return codes: 0 success, anything else is error
1904 */
1905
1906int
1907RpUnitsPreset::addPresetAngle () {
1908
1909    RpUnits* degree  = RpUnits::define("deg",  NULL, RP_TYPE_ANGLE);
1910    RpUnits* gradian = RpUnits::define("grad", NULL, RP_TYPE_ANGLE);
1911    RpUnits* radian  = RpUnits::define("rad",  NULL, RP_TYPE_ANGLE);
1912
1913    RpUnits::makeMetric(radian);
1914
1915    // add angle definitions
1916    RpUnits::define(degree,gradian,deg2grad,grad2deg);
1917    RpUnits::define(radian,degree,rad2deg,deg2rad);
1918    RpUnits::define(radian,gradian,rad2grad,grad2rad);
1919
1920    return 0;
1921}
1922
1923/**********************************************************************/
1924// METHOD: addPresetMass()
1925/// Add Mass related units to the dictionary
1926/**
1927 * Defines the following units:
1928 *   gram  (g)
1929 *
1930 * Return codes: 0 success, anything else is error
1931 */
1932
1933int
1934RpUnitsPreset::addPresetMass () {
1935
1936    RpUnits* gram  = RpUnits::define("g",  NULL, RP_TYPE_MASS);
1937
1938    RpUnits::makeMetric(gram);
1939
1940    // add mass definitions
1941    // RpUnits::define(radian,gradian,rad2grad,grad2rad);
1942
1943    return 0;
1944}
1945
1946/**********************************************************************/
1947// METHOD: addPresetPressure()
1948/// Add pressure related units to the dictionary
1949/**
1950 * http://www.ilpi.com/msds/ref/pressureunits.html
1951 *
1952 * Defines the following units:
1953 *   bar                    (bar)
1954 *   pascal                 (Pa)
1955 *   pounds/(in^2)          (psi)
1956 *   torr                   (torr)
1957 *   millimeters Mercury    (mmHg)
1958 *
1959 * mmHg was added because as a convenience to those who have not
1960 * yet switched over to the new representation of torr.
1961 *
1962 * Return codes: 0 success, anything else is error
1963 */
1964
1965int
1966RpUnitsPreset::addPresetPressure () {
1967
1968    RpUnits* atmosphere = RpUnits::define("atm", NULL, RP_TYPE_PRESSURE);
1969    RpUnits* bar = RpUnits::define("bar", NULL, RP_TYPE_PRESSURE);
1970    RpUnits* pascal = RpUnits::define("Pa", NULL, RP_TYPE_PRESSURE);
1971    RpUnits* psi = RpUnits::define("psi", NULL, RP_TYPE_PRESSURE);
1972    RpUnits* torr = RpUnits::define("torr", NULL, RP_TYPE_PRESSURE);
1973    RpUnits* mmHg = RpUnits::define("mmHg", torr, RP_TYPE_PRESSURE);
1974
1975    RpUnits::makeMetric(pascal);
1976    RpUnits::makeMetric(bar);
1977
1978    RpUnits::define(bar,pascal,bar2Pa,Pa2bar);
1979    RpUnits::define(bar,atmosphere,bar2atm,atm2bar);
1980    RpUnits::define(bar,psi,bar2psi,psi2bar);
1981    RpUnits::define(bar,torr,bar2torr,torr2bar);
1982    RpUnits::define(pascal,atmosphere,Pa2atm,atm2Pa);
1983    RpUnits::define(pascal,torr,Pa2torr,torr2Pa);
1984    RpUnits::define(pascal,psi,Pa2psi,psi2Pa);
1985    RpUnits::define(torr,atmosphere,torr2atm,atm2torr);
1986    RpUnits::define(torr,psi,torr2psi,psi2torr);
1987
1988    RpUnits::define(torr,mmHg,torr2mmHg,mmHg2torr);
1989
1990    return 0;
1991}
1992
1993/**********************************************************************/
1994// METHOD: addPresetMisc()
1995/// Add Misc related units to the dictionary
1996/**
1997 * Defines the following units:
1998 *   mole  (mol)
1999 *
2000 * Return codes: 0 success, anything else is error
2001 */
2002
2003int
2004RpUnitsPreset::addPresetMisc () {
2005
2006    RpUnits* mole  = RpUnits::define("mol",  NULL, RP_TYPE_MISC);
2007    RpUnits* hertz = RpUnits::define("Hz",  NULL, RP_TYPE_MISC);
2008    RpUnits* becquerel = RpUnits::define("Bq",  NULL, RP_TYPE_MISC);
2009
2010    RpUnits::makeMetric(mole);
2011    RpUnits::makeMetric(hertz);
2012    RpUnits::makeMetric(becquerel);
2013
2014    // add misc definitions
2015    // RpUnits::define(radian,gradian,rad2grad,grad2rad);
2016
2017    return 0;
2018}
2019
2020// -------------------------------------------------------------------- //
2021
Note: See TracBrowser for help on using the repository browser.