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

Last change on this file since 478 was 478, checked in by nkissebe, 18 years ago

prevent buffer underrun in RpUnits::grabUnitString()

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