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

Last change on this file since 119 was 119, checked in by dkearney, 19 years ago
  1. added doxygen headers to some fortran RpLibrary? bindings
  2. cleaned up app-fermi/fortran example
  3. removed rp_add_presets(...) function from api
  4. minor logic changes to RpUnits.cc.
File size: 40.0 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*>();
20static RpUnitsPreset loader;
21
22/************************************************************************
23 *
24 * add RpUnits Object
25 *
26 ************************************************************************/
27
28RpUnits *
29RpUnits::define( const std::string units, const RpUnits* basis) {
30
31    RpUnits* newRpUnit = NULL;
32
33    std::string searchStr = units;
34    std::string sendStr = "";
35    int len = searchStr.length();
36    int idx = len-1;
37    double exponent = 1;
38
39    if (units == "") {
40        // raise error, user sent null units!
41        return NULL;
42    }
43
44    // check to see if the user is trying to trick me!
45    if ( (basis) && (units == basis->getUnits()) ) {
46        // dont trick me!
47        return NULL;
48    }
49
50    // check to see if the said unit can already be found in the dictionary
51    if (RpUnits::find(units)) {
52        return NULL;
53    }
54
55    //default exponent
56    exponent = 1;
57
58    // check to see if there is an exponent at the end
59    // of the search string
60    idx = RpUnits::grabExponent(searchStr, &exponent);
61    searchStr.erase(idx);
62
63    // move idx pointer back to where last character was found
64    idx--;
65
66    if ( searchStr[0] == '/') {
67        // need to negate all of the previous exponents
68        exponent = -1*exponent;
69        sendStr = searchStr.c_str()+1;
70    }
71    else {
72        // sendStr = searchStr.substr(idx+1,);
73        // we have a unit string to parse
74        sendStr = searchStr;
75    }
76
77    newRpUnit = new RpUnits(sendStr, exponent, basis);
78    if (newRpUnit) {
79        insert(newRpUnit->getUnitsName(),newRpUnit);
80    }
81
82    // return a copy of the new object to user
83    return newRpUnit;
84}
85
86int
87RpUnits::grabExponent(const std::string& inStr, double* exp) {
88
89    int len = inStr.length();
90    int idx = len - 1;
91
92    *exp = 1;
93
94    while (isdigit(inStr[idx])) {
95        idx--;
96    }
97
98    if ( (inStr[idx] == '+') || (inStr[idx] == '-') ) {
99        idx--;
100    }
101
102    idx++;
103
104    if (idx != len) {
105        // process the exponent.
106        *exp = strtod(inStr.c_str()+idx,NULL);
107    }
108
109    return idx;
110}
111
112int
113RpUnits::grabUnitString ( const std::string& inStr ) {
114
115    int idx = inStr.length() - 1;
116
117    while (isalpha(inStr[idx])) {
118        idx--;
119    }
120
121    // move the index forward one position to
122    // represent the start of the unit string
123    idx++;
124
125    return idx;
126}
127
128const RpUnits*
129RpUnits::grabUnits ( std::string inStr, int* offset) {
130
131    const RpUnits* unit = NULL;
132    int len = inStr.length();
133
134    while ( ! inStr.empty() ) {
135        unit = RpUnits::find(inStr);
136        if (unit) {
137            *offset = len - inStr.length();
138            break;
139        }
140        inStr.erase(0,1);
141    }
142
143    return unit;
144}
145
146
147
148/************************************************************************
149 *
150 * add relation rule
151 *
152 ************************************************************************/
153RpUnits *
154RpUnits::define(  const RpUnits* from,
155                  const RpUnits* to,
156                  double (*convForwFxnPtr)(double),
157                  double (*convBackFxnPtr)(double)  ) {
158
159    // this is kinda the wrong way to get the job done...
160    // how do we only create 1 conversion object and share it between atleast two RpUnits
161    // objs so that when the RpUnits objs are deleted, we are not trying to delete already
162    // deleted memory.
163    // so for the sake of safety we get the following few lines of code.
164
165    conversion* conv1 = NULL;
166    conversion* conv2 = NULL;
167
168    if (from && to) {
169
170        conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
171        conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
172
173        from->connectConversion(conv1);
174        to->connectConversion(conv2);
175    }
176
177    return NULL;
178}
179
180RpUnits *
181RpUnits::define(  const RpUnits* from,
182                  const RpUnits* to,
183                  double (*convForwFxnPtr)(double,double),
184                  double (*convBackFxnPtr)(double,double)) {
185
186    // this is kinda the wrong way to get the job done...
187    // how do we only create 1 conversion object and share it between
188    // atleast two RpUnits objs so that when the RpUnits objs are
189    // deleted, we are not trying to delete already deleted memory.
190    // so for the sake of safety we get the following few lines of code.
191
192    conversion* conv1 = NULL;
193    conversion* conv2 = NULL;
194
195    if (from && to) {
196        conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
197        conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
198
199        from->connectConversion(conv1);
200        to->connectConversion(conv2);
201    }
202
203    return NULL;
204}
205
206RpUnits *
207RpUnits::define(  const RpUnits* from,
208                  const RpUnits* to,
209                  void* (*convForwFxnPtr)(void*, void*),
210                  void* convForwData,
211                  void* (*convBackFxnPtr)(void*, void*),
212                  void* convBackData) {
213
214    // this is kinda the wrong way to get the job done...
215    // how do we only create 1 conversion object and share it between at
216    // least two RpUnits objs so that when the RpUnits objs are deleted,
217    // we are not trying to delete already deleted memory.
218    // so for the sake of safety we get the following few lines of code.
219
220    conversion* conv1 = NULL;
221    conversion* conv2 = NULL;
222
223    if (from && to) {
224        conv1 = new conversion ( from, to, convForwFxnPtr,convForwData,
225                                 convBackFxnPtr,convBackData);
226        conv2 = new conversion ( from,to,convForwFxnPtr,convForwData,
227                                 convBackFxnPtr,convBackData);
228
229        from->connectConversion(conv1);
230        to->connectConversion(conv2);
231    }
232
233    return NULL;
234}
235
236/************************************************************************
237 *
238 * report the units this object represents back to the user
239 *
240 ************************************************************************/
241
242/**********************************************************************/
243// METHOD: getUnits()
244/// Report the text portion of the units of this object back to caller.
245/**
246 * See Also getUnitsName().
247 */
248
249std::string
250RpUnits::getUnits() const {
251
252    return units;
253}
254
255/************************************************************************
256 *
257 * report the units this object represents back to the user
258 *
259 ************************************************************************/
260
261/**********************************************************************/
262// METHOD: getUnitsName()
263/// Report the full name of the units of this object back to caller.
264/**
265 * Reports the full text and exponent of the units represented by this
266 * object, back to the caller. Note that if the exponent == 1, no
267 * exponent will be printed.
268 */
269
270std::string
271RpUnits::getUnitsName() const {
272
273    std::stringstream unitText;
274    double exponent;
275
276    exponent = getExponent();
277
278    if (exponent == 1) {
279        unitText << units;
280    }
281    else {
282        unitText << units << exponent;
283    }
284
285    return (std::string(unitText.str()));
286}
287
288/************************************************************************
289 *
290 * report the exponent of the units of this object back to the user
291 *
292 * **********************************************************************/
293/**********************************************************************/
294// METHOD: getExponent()
295/// Report the exponent of the units of this object back to caller.
296/**
297 * Reports the exponent of the units represented by this
298 * object, back to the caller. Note that if the exponent == 1, no
299 * exponent will be printed.
300 */
301
302double
303RpUnits::getExponent() const {
304
305    return exponent;
306}
307
308/************************************************************************
309 *
310 *  report the basis of this object to the user
311 *
312 * **********************************************************************/
313/**********************************************************************/
314// METHOD: getBasis()
315/// Retrieve the RpUnits object representing the basis of this object.
316/**
317 * Returns a pointer to a RpUnits object which, on success, points to the
318 * RpUnits object that is the basis of the calling object.
319 */
320
321const RpUnits *
322RpUnits::getBasis() const {
323
324    return basis;
325}
326
327/************************************************************************
328 *
329 *  convert the current unit to its basis units
330 *
331 *  Return Codes
332 *      0) no error (could also mean or no prefix was found)
333 *          in some cases, this means the value is in its basis format
334 *      1) the prefix found does not have a built in factor associated.
335 *
336 ************************************************************************/
337double
338RpUnits::makeBasis(double value, int* result) const {
339
340    double retVal = value;
341
342    if (result) {
343        *result = 0;
344    }
345
346    if (basis == NULL) {
347        // this unit is a basis
348        // do nothing
349    }
350    else {
351        retVal = convert(basis,value,result);
352    }
353
354    return retVal;
355}
356
357const RpUnits&
358RpUnits::makeBasis(double* value, int* result) const {
359    double retVal = *value;
360    int convResult = 1;
361
362    if (basis == NULL) {
363        // this unit is a basis
364        // do nothing
365    }
366    else {
367        retVal = convert(basis,retVal,&convResult);
368    }
369
370    if ( (convResult == 0) ) {
371        *value = retVal;
372    }
373
374    if (result) {
375        *result = convResult;
376    }
377
378    return *this;
379}
380
381/************************************************************************
382 *
383 *  static int makeMetric(RpUnits * basis);
384 *  create the metric attachments for the given basis.
385 *  should only be used if this unit is of metric type
386 *
387 * **********************************************************************/
388
389int
390RpUnits::makeMetric(const RpUnits* basis) {
391
392    if (!basis) {
393        return 0;
394    }
395
396    std::string basisName = basis->getUnitsName();
397    std::string name;
398
399    name = "c" + basisName;
400    RpUnits * centi = RpUnits::define(name, basis);
401    RpUnits::define(centi, basis, centi2base, base2centi);
402
403    name = "m" + basisName;
404    RpUnits * milli = RpUnits::define(name, basis);
405    RpUnits::define(milli, basis, milli2base, base2milli);
406
407    name = "u" + basisName;
408    RpUnits * micro = RpUnits::define(name, basis);
409    RpUnits::define(micro, basis, micro2base, base2micro);
410
411    name = "n" + basisName;
412    RpUnits * nano  = RpUnits::define(name, basis);
413    RpUnits::define(nano, basis, nano2base, base2nano);
414
415    name = "p" + basisName;
416    RpUnits * pico  = RpUnits::define(name, basis);
417    RpUnits::define(pico, basis, pico2base, base2pico);
418
419    name = "f" + basisName;
420    RpUnits * femto = RpUnits::define(name, basis);
421    RpUnits::define(femto, basis, femto2base, base2femto);
422
423    name = "a" + basisName;
424    RpUnits * atto  = RpUnits::define(name, basis);
425    RpUnits::define(atto, basis, atto2base, base2atto);
426
427    name = "k" + basisName;
428    RpUnits * kilo  = RpUnits::define(name, basis);
429    RpUnits::define(kilo, basis, kilo2base, base2kilo);
430
431    name = "M" + basisName;
432    RpUnits * mega  = RpUnits::define(name, basis);
433    RpUnits::define(mega, basis, mega2base, base2mega);
434
435    name = "G" + basisName;
436    RpUnits * giga  = RpUnits::define(name, basis);
437    RpUnits::define(giga, basis, giga2base, base2giga);
438
439    name = "T" + basisName;
440    RpUnits * tera  = RpUnits::define(name, basis);
441    RpUnits::define(tera, basis, tera2base, base2tera);
442
443    name = "P" + basisName;
444    RpUnits * peta  = RpUnits::define(name, basis);
445    RpUnits::define(peta, basis, peta2base, base2peta);
446
447    return (1);
448}
449
450
451const RpUnits*
452RpUnits::find(std::string key) {
453
454    // dict pointer
455    const RpUnits* unitEntry = NULL;
456    double exponent = 1;
457    int idx = 0;
458    std::stringstream tmpKey;
459
460    if (key[0] == '/') {
461        // check to see if there is an exponent at the end
462        // of the search string
463        idx = RpUnits::grabExponent(key, &exponent);
464        tmpKey << key.substr(1,idx-1) << (-1*exponent);
465        key = tmpKey.str();
466    }
467
468    unitEntry = *(dict->find(key).getValue());
469
470    // dict pointer
471    if (unitEntry == *(dict->getNullEntry().getValue()) ) {
472        unitEntry = NULL;
473    }
474
475    return unitEntry;
476}
477
478int
479RpUnits::negateListExponents(RpUnitsList& unitsList) {
480    RpUnitsListIter iter = unitsList.begin();
481    int nodeCnt = unitsList.size();
482
483    if (nodeCnt > 0) {
484        for (; iter != unitsList.end(); iter++) {
485            iter->negateExponent();
486            nodeCnt--;
487        }
488    }
489
490    return nodeCnt;
491}
492
493// negate the exponent
494void
495RpUnitsListEntry::negateExponent() const {
496    exponent = exponent * -1;
497    return;
498}
499
500// provide the caller with the name of this object
501std::string
502RpUnitsListEntry::name() const {
503    std::stringstream name;
504    name << unit->getUnits() << exponent;
505    return std::string(name.str());
506}
507
508// provide the caller with the basis of the RpUnits object being stored
509const RpUnits*
510RpUnitsListEntry::getBasis() const {
511    return unit->getBasis();
512}
513
514// get the RpUnits*
515const RpUnits*
516RpUnitsListEntry::getUnitsObj() const {
517    return unit;
518}
519
520// get the RpUnits*
521double
522RpUnitsListEntry::getExponent() const {
523    return exponent;
524}
525
526int
527RpUnits::printList(RpUnitsList& unitsList) {
528    RpUnitsListIter iter = unitsList.begin();
529    int nodeCnt = unitsList.size();
530
531    if (nodeCnt > 0) {
532        for (; iter != unitsList.end(); iter++) {
533            std::cout << iter->name() << " ";
534            nodeCnt--;
535        }
536        std::cout << std::endl;
537    }
538
539    return nodeCnt;
540}
541
542int
543RpUnits::units2list ( const std::string& inUnits,
544                      RpUnitsList& outList ) {
545
546    std::string myInUnits   = inUnits;
547    std::string sendUnitStr = "";
548    double exponent         = 1;
549    int offset              = 0;
550    int idx                 = 0;
551    int last                = 0;
552    const RpUnits* unit     = NULL;
553
554
555    while ( !myInUnits.empty() ) {
556
557        // check to see if we came across a '/' character
558        last = myInUnits.length()-1;
559        if (myInUnits[last] == '/') {
560            myInUnits.erase(last);
561            // multiply previous exponents by -1
562            if ( ! outList.empty() ) {
563                RpUnits::negateListExponents(outList);
564            }
565            continue;
566        }
567
568        // get the exponent
569        offset = RpUnits::grabExponent(myInUnits,&exponent);
570        myInUnits.erase(offset);
571        idx = offset - 1;
572
573        // grab the largest string we can find
574        offset = RpUnits::grabUnitString(myInUnits);
575        idx = offset;
576
577        // figure out if we have some defined units in that string
578        sendUnitStr = myInUnits.substr(offset,std::string::npos);
579        unit = grabUnits(sendUnitStr,&offset);
580        if (unit) {
581            // a unit was found
582            // add this unit to the list
583            // erase the found unit's name from our search string
584            outList.push_front(RpUnitsListEntry(unit,exponent));
585            myInUnits.erase(idx+offset);
586        }
587        else {
588            // we came across a unit we did not recognize
589            // raise error and delete character for now
590            myInUnits.erase(last);
591        }
592
593        // reset our vars
594        idx = 0;
595        offset = 0;
596        exponent = 1;
597    }
598
599    return 0;
600}
601
602int RpUnits::compareListEntryBasis ( RpUnitsList& fromList,
603                                     RpUnitsListIter& fromIter,
604                                     RpUnitsListIter& toIter ) {
605
606    const RpUnits* toBasis = NULL;
607    const RpUnits* fromBasis = NULL;
608    int retVal = 1;
609    double fromExp = 0;
610    double toExp = 0;
611
612    fromIter = fromList.begin();
613
614    // get the basis of the object being stored
615    // if the basis is NULL, then we'll compare the object
616    // itself because the object is the basis.
617    toBasis = toIter->getBasis();
618    if (toBasis == NULL) {
619        toBasis = toIter->getUnitsObj();
620    }
621
622    toExp   = toIter->getExponent();
623
624    while ( fromIter != fromList.end() ) {
625
626        fromExp = fromIter->getExponent();
627
628        // in order to convert, exponents must be equal.
629        if (fromExp == toExp) {
630
631            // get the basis of the object being stored
632            // if the basis is NULL, then we'll compare the object
633            // itself because the object is the basis.
634            fromBasis = fromIter->getBasis();
635            if (fromBasis == NULL) {
636                fromBasis = fromIter->getUnitsObj();
637            }
638
639            if (toBasis == fromBasis) {
640                // conversion needed between 2 units of the same basis.
641                // these two units could actually be the same unit (m->m)
642                retVal = 0;
643                break;
644            }
645        }
646
647        fromIter++;
648    }
649
650    return retVal;
651}
652
653int RpUnits::compareListEntrySearch ( RpUnitsList& fromList,
654                                     RpUnitsListIter& fromIter,
655                                     RpUnitsListIter& toIter ) {
656
657    const RpUnits* toBasis = NULL;
658    const RpUnits* fromBasis = NULL;
659    int retVal = 1;
660
661    fromIter = fromList.begin();
662
663    // get the basis of the object being stored
664    // if the basis is NULL, then we'll compare the object
665    // itself because the object is the basis.
666    toBasis = toIter->getBasis();
667    if (toBasis == NULL) {
668        toBasis = toIter->getUnitsObj();
669    }
670
671    while ( fromIter != fromList.end() ) {
672
673        // get the basis of the object being stored
674        // if the basis is NULL, then we'll compare the object
675        // itself because the object is the basis.
676        fromBasis = fromIter->getBasis();
677        if (fromBasis == NULL) {
678            fromBasis = fromIter->getUnitsObj();
679        }
680
681        if (toBasis == fromBasis) {
682            // conversion needed between 2 units of the same basis.
683            // these two units could actually be the same unit (m->m)
684            retVal = 0;
685            break;
686        }
687
688        fromIter++;
689    }
690
691    return retVal;
692}
693
694// convert function so people can just send in two strings and
695// we'll see if the units exists and do a conversion
696// strVal = RpUnits::convert("300K","C",1);
697std::string
698RpUnits::convert (  std::string val,
699                    std::string toUnitsName,
700                    int showUnits,
701                    int* result ) {
702
703    RpUnitsList toUnitsList;
704    RpUnitsList fromUnitsList;
705
706    RpUnitsListIter toIter;
707    RpUnitsListIter fromIter;
708    RpUnitsListIter tempIter;
709
710    const RpUnits* toUnits = NULL;
711    const RpUnits* fromUnits = NULL;
712
713    std::string tmpNumVal = "";
714    std::string fromUnitsName = "";
715    std::string convVal = "";
716    double origNumVal = 0;
717    double numVal = 0;
718    double toExp = 0;
719    double fromExp = 0;
720    int convResult = 0;
721    char* endptr = NULL;
722    std::stringstream outVal;
723
724    int rv = 0;
725    double factor = 1;
726
727
728    // set  default result flag/error code
729    if (result) {
730        *result = 0;
731    }
732
733    // search our string to see where the numeric part stops
734    // and the units part starts
735    //
736    //  convert("5J", "neV") => 3.12075e+28neV
737    //  convert("3.12075e+28neV", "J") => 4.99999J
738    // now we can actually get the scientific notation portion of the string.
739    //
740
741    numVal = strtod(val.c_str(),&endptr);
742    origNumVal = numVal;
743
744    if ( (numVal == 0) && (endptr == val.c_str()) ) {
745        // no conversion was done.
746        // number in incorrect format probably.
747        if (result) {
748            *result = 1;
749        }
750        return val;
751    }
752
753    fromUnitsName = std::string(endptr);
754
755    // check if the fromUnitsName is empty or
756    // if the fromUnitsName == toUnitsName
757    // these are conditions where no conversion is needed
758    if ( (fromUnitsName.empty()) || (toUnitsName == fromUnitsName) )  {
759        // there were no units in the input
760        // string or no conversion needed
761        // assume fromUnitsName = toUnitsName
762        // return the correct value
763        if (result) {
764            *result = 0;
765        }
766
767        if (showUnits) {
768            outVal << numVal << toUnitsName;
769        }
770        else {
771            outVal << numVal;
772        }
773
774        return std::string(outVal.str());
775    }
776
777    RpUnits::units2list(toUnitsName,toUnitsList);
778    RpUnits::units2list(fromUnitsName,fromUnitsList);
779
780    toIter = toUnitsList.begin();
781
782    // pass 1: compare basis' of objects to find intra-basis conversions
783    while ( toIter != toUnitsList.end() ) {
784        rv = RpUnits::compareListEntryBasis(fromUnitsList, fromIter, toIter);
785        if (rv == 0) {
786
787            // check the names of the units provided by the user
788            // if the names are the same, no need to do a conversion
789            if (fromIter->name() != toIter->name()) {
790
791                // do an intra-basis conversion
792                toUnits = toIter->getUnitsObj();
793                fromUnits = fromIter->getUnitsObj();
794
795                // do conversions
796                factor = 1;
797                factor = fromUnits->convert(toUnits, factor, &convResult);
798                numVal *= pow(factor,toIter->getExponent());
799            }
800
801            // remove the elements from the lists
802            tempIter = toIter;
803            toUnitsList.erase(tempIter);
804            toIter++;
805
806            tempIter = fromIter;
807            fromUnitsList.erase(tempIter);
808        }
809        else {
810            // this is not an intra-basis conversion.
811            // move onto the next toIter
812            toIter++;
813        }
814    }
815
816    toIter = toUnitsList.begin();
817    fromIter = fromUnitsList.begin();
818
819    // pass 2: look for inter-basis conversions
820    if (fromIter != fromUnitsList.end()) {
821        // double while loop to compare each toIter with each fromIter.
822        // the outter while checks the toIter and the inner while
823        // which is conveniently hidden, adjusts the fromIter and toIter
824        // (at the bottom in the else statement).
825        while (toIter != toUnitsList.end()) {
826
827            toUnits = toIter->getUnitsObj();
828            fromUnits = fromIter->getUnitsObj();
829
830            // do an inter-basis conversion...the slow way
831            // there has to be a better way to do this...
832            convResult = 1;
833
834            // in order to convert, exponents must be equal.
835            fromExp = fromIter->getExponent();
836            toExp   = toIter->getExponent();
837
838            if (fromExp == toExp) {
839                if (toExp == 1) {
840                    numVal = fromUnits->convert(toUnits, numVal, &convResult);
841                }
842                else {
843                    factor = 1;
844                    factor = fromUnits->convert(toUnits, factor, &convResult);
845                    numVal *= pow(factor,toExp);
846                }
847            }
848
849            if (convResult == 0) {
850                // successful conversion reported
851                // remove the elements from the lists
852                tempIter = toIter;
853                toUnitsList.erase(tempIter);
854                toIter++;
855
856                tempIter = fromIter;
857                fromUnitsList.erase(tempIter);
858
859                // conversion complete, jump out of the
860                // while loop
861                break;
862            }
863            else {
864                // conversion was unsuccessful
865                // move onto the next fromIter
866                fromIter++;
867                if (fromIter == fromUnitsList.end()) {
868                    // this is not an inter-basis conversion.
869                    // move onto the next toIter
870                    fromIter = fromUnitsList.begin();
871                    toIter++;
872                }
873            } // end unsuccessful conversion
874        } // end toIter while loop
875    } // end
876
877
878
879    if ( (result) && (*result == 0) ) {
880        *result = convResult;
881    }
882
883    if (showUnits) {
884        outVal << numVal << toUnitsName;
885    }
886    else {
887        outVal << numVal;
888    }
889
890    return std::string(outVal.str());
891
892}
893
894std::string
895RpUnits::convert ( const  RpUnits* toUnits,
896                   double val,
897                   int showUnits,
898                   int* result )  const {
899
900    double retVal = convert(toUnits,val,result);
901    std::stringstream unitText;
902
903
904    if (showUnits) {
905        unitText << retVal << toUnits->getUnitsName();
906    }
907    else {
908        unitText << retVal;
909    }
910
911    return (std::string(unitText.str()));
912
913}
914
915// user function to convert a value to the provided RpUnits* toUnits
916// if it exists as a conversion from the basis
917// example
918//      cm.convert(meter,10)
919//      cm.convert(angstrum,100)
920double
921RpUnits::convert(const RpUnits* toUnit, double val, int* result) const {
922
923    // currently we convert this object to its basis and look for the
924    // connection to the toUnit object from the basis.
925
926    double value = val;
927    const RpUnits* toBasis = toUnit->getBasis();
928    const RpUnits* fromUnit = this;
929    const RpUnits* dictToUnit = NULL;
930    convEntry *p;
931    int my_result = 0;
932
933    // set *result to a default value
934    if (result) {
935        *result = 1;
936    }
937
938    // guard against converting to the units you are converting from...
939    // ie. meters->meters
940    if (this->getUnitsName() == toUnit->getUnitsName()) {
941        if (result) {
942            *result = 0;
943        }
944        return val;
945    }
946
947    // convert unit to the basis
948    // makeBasis(&value);
949    // trying to avoid the recursive way of converting to the basis.
950    // need to rethink this.
951    //
952    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
953        value = convert(basis,value,&my_result);
954        if (my_result == 0) {
955            fromUnit = basis;
956        }
957    }
958
959    // find the toUnit in our dictionary.
960    // if the toUnits has a basis, we need to search for the basis
961    // and convert between basis' and then convert again back to the
962    // original unit.
963    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
964        dictToUnit = find(toBasis->getUnitsName());
965    }
966    else {
967        dictToUnit = find(toUnit->getUnitsName());
968    }
969
970    // did we find the unit in the dictionary?
971    if (dictToUnit == NULL) {
972        // toUnit was not found in the dictionary
973        return val;
974    }
975
976    // search through the conversion list to find
977    // the conversion to the toUnit.
978
979    if (basis) {
980        p = basis->convList;
981    }
982    else {
983        p = this->convList;
984    }
985
986    if (p == NULL) {
987        // there are no conversions
988        return val;
989    }
990
991    // loop through our conversion list looking for the correct conversion
992    do {
993
994        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
995            // we found our conversion
996            // call the function pointer with value
997
998            // this should probably be re thought out
999            // the problem is that convForwFxnPtr has the conversion for a
1000            // one arg conv function pointer and convForwFxnPtrDD has the
1001            // conversion for a two arg conv function pointer
1002            // need to make this simpler, more logical maybe only allow 2 arg
1003            if (       (p->conv->convForwFxnPtr)
1004                    && (! p->conv->convForwFxnPtrDD) ) {
1005
1006                value = p->conv->convForwFxnPtr(value);
1007            }
1008            else if (  (p->conv->convForwFxnPtrDD)
1009                    && (! p->conv->convForwFxnPtr) ) {
1010
1011                value =
1012                    p->conv->convForwFxnPtrDD(value, fromUnit->getExponent());
1013            }
1014
1015            // check to see if we converted to the actual requested unit
1016            // or to the requested unit's basis.
1017            // if we converted to the requested unit's basis. we need to
1018            // do one last conversion from the requested unit's basis back
1019            // to the requested unit.
1020            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1021                my_result = 0;
1022                value = toBasis->convert(toUnit,value,&my_result);
1023                if (my_result != 0) {
1024                    if (result) {
1025                        *result += 1;
1026                    }
1027                }
1028            }
1029
1030            // change the result code to zero, a conversion was performed
1031            // (we think)... its ture that it is possible to get to this
1032            // point and have skipped the conversion because the
1033            // conversion object was not properly created...
1034            // ie. both fxn ptrs were null or neither fxn ptr was null
1035            //
1036            if (result && (*result == 1)) {
1037                *result = 0;
1038            }
1039            break;
1040        }
1041
1042        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1043            // we found our conversion
1044            // call the function pointer with value
1045
1046            // this should probably be re thought out
1047            // the problem is that convForwFxnPtr has the conversion for a
1048            // one arg conv function pointer and convForwFxnPtrDD has the
1049            // conversion for a two arg conv function pointer
1050            // need to make this simpler, more logical maybe only allow 2 arg
1051            if (       (p->conv->convBackFxnPtr)
1052                    && (! p->conv->convBackFxnPtrDD) ) {
1053
1054                value = p->conv->convBackFxnPtr(value);
1055            }
1056            else if (  (p->conv->convBackFxnPtrDD)
1057                    && (! p->conv->convBackFxnPtr) ) {
1058
1059                value =
1060                    p->conv->convBackFxnPtrDD(value, fromUnit->getExponent());
1061            }
1062
1063            // check to see if we converted to the actual requested unit
1064            // or to the requested unit's basis.
1065            // if we converted to the requested unit's basis. we need to
1066            // do one last conversion from the requested unit's basis back
1067            // to the requested unit.
1068            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1069                my_result = 0;
1070                value = toBasis->convert(toUnit,value,&my_result);
1071                if (my_result != 0) {
1072                    if (result) {
1073                        *result += 1;
1074                    }
1075                }
1076            }
1077
1078            // change the result code to zero, a conversion was performed
1079            // (we think)... its ture that it is possible to get to this
1080            // point and have skipped the conversion because the
1081            // conversion object was not properly created...
1082            // ie. both fxn ptrs were null or neither fxn ptr was null
1083            //
1084            if (result && (*result == 1)) {
1085                *result = 0;
1086            }
1087            break;
1088        }
1089
1090        p = p->next;
1091
1092    } while (p != NULL);
1093
1094
1095    if ( p == NULL) {
1096        // we did not find the conversion
1097        if (result) {
1098            *result += 1;
1099        }
1100        return val;
1101    }
1102
1103    // we found the conversion.
1104    // return the converted value.
1105    return value;
1106
1107}
1108
1109
1110void*
1111RpUnits::convert(const RpUnits* toUnit, void* val, int* result) const {
1112
1113    // currently we convert this object to its basis and look for the
1114    // connection ot the toUnit object from the basis.
1115
1116    void* value = val;
1117    const RpUnits* toBasis = toUnit->getBasis();
1118    const RpUnits* fromUnit = this;
1119    const RpUnits* dictToUnit = NULL;
1120    convEntry *p;
1121    int my_result = 0;
1122
1123    // set *result to a default value
1124    if (result) {
1125        *result = 1;
1126    }
1127
1128    // guard against converting to the units you are converting from...
1129    // ie. meters->meters
1130    if (this->getUnitsName() == toUnit->getUnitsName()) {
1131        if (result) {
1132            *result = 0;
1133        }
1134        return val;
1135    }
1136
1137    // convert unit to the basis
1138    // makeBasis(&value);
1139    // trying to avoid the recursive way of converting to the basis.
1140    // need to rethink this.
1141    //
1142    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1143        value = convert(basis,value,&my_result);
1144        if (my_result == 0) {
1145            fromUnit = basis;
1146        }
1147    }
1148
1149    // find the toUnit in our dictionary.
1150    // if the toUnits has a basis, we need to search for the basis
1151    // and convert between basis' and then convert again back to the
1152    // original unit.
1153    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1154        dictToUnit = find(toBasis->getUnitsName());
1155    }
1156    else {
1157        dictToUnit = find(toUnit->getUnitsName());
1158    }
1159
1160    // did we find the unit in the dictionary?
1161    if (dictToUnit == NULL) {
1162        // toUnit was not found in the dictionary
1163        return val;
1164    }
1165
1166    // search through the conversion list to find
1167    // the conversion to the toUnit.
1168
1169    if (basis) {
1170        p = basis->convList;
1171    }
1172    else {
1173        p = this->convList;
1174    }
1175
1176    if (p == NULL) {
1177        // there are no conversions
1178        return val;
1179    }
1180
1181    // loop through our conversion list looking for the correct conversion
1182    do {
1183
1184        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1185            // we found our conversion
1186            // call the function pointer with value
1187
1188            value = p->conv->convForwFxnPtrVoid(p->conv->convForwData,value);
1189
1190            // check to see if we converted to the actual requested unit
1191            // or to the requested unit's basis.
1192            // if we converted to the requested unit's basis. we need to
1193            // do one last conversion from the requested unit's basis back
1194            // to the requested unit.
1195            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1196                my_result = 0;
1197                value = toBasis->convert(toUnit,value,&my_result);
1198                if (my_result != 0) {
1199                    if (result) {
1200                        *result += 1;
1201                    }
1202                }
1203            }
1204
1205            // change the result code to zero, a conversion was performed
1206            // (we think)... its ture that it is possible to get to this
1207            // point and have skipped the conversion because the
1208            // conversion object was not properly created...
1209            // ie. both fxn ptrs were null or neither fxn ptr was null
1210            //
1211            if (result && (*result == 1)) {
1212                *result = 0;
1213            }
1214            break;
1215        }
1216
1217        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1218            // we found our conversion
1219            // call the function pointer with value
1220
1221            value = p->conv->convBackFxnPtrVoid(p->conv->convBackData,value);
1222
1223            // check to see if we converted to the actual requested unit
1224            // or to the requested unit's basis.
1225            // if we converted to the requested unit's basis. we need to
1226            // do one last conversion from the requested unit's basis back
1227            // to the requested unit.
1228            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1229                my_result = 0;
1230                value = toBasis->convert(toUnit,value,&my_result);
1231                if (my_result != 0) {
1232                    if (result) {
1233                        *result += 1;
1234                    }
1235                }
1236            }
1237
1238            // change the result code to zero, a conversion was performed
1239            // (we think)... its ture that it is possible to get to this
1240            // point and have skipped the conversion because the
1241            // conversion object was not properly created...
1242            // ie. both fxn ptrs were null or neither fxn ptr was null
1243            //
1244            if (result && (*result == 1)) {
1245                *result = 0;
1246            }
1247            break;
1248        }
1249
1250        p = p->next;
1251
1252    } while (p != NULL);
1253
1254
1255    if ( p == NULL) {
1256        // we did not find the conversion
1257        if (result) {
1258            *result += 1;
1259        }
1260        return val;
1261    }
1262
1263    // we found the conversion.
1264    // return the converted value.
1265    return value;
1266
1267}
1268
1269int
1270// RpUnits::insert(std::string key,RpUnits* val) {
1271insert(std::string key,RpUnits* val) {
1272
1273    int newRecord = 0;
1274    // RpUnits* val = this;
1275    // dict pointer
1276    RpUnits::dict->set(key,val,&newRecord);
1277    return newRecord;
1278}
1279
1280void
1281RpUnits::connectConversion(conversion* conv) const {
1282
1283    convEntry* p = convList;
1284
1285    if (p == NULL) {
1286        convList = new convEntry (conv,NULL,NULL);
1287    }
1288    else {
1289        while (p->next != NULL) {
1290            p = p->next;
1291        }
1292
1293        p->next = new convEntry (conv,p,NULL);
1294    }
1295
1296}
1297
1298// return codes: 0 success, anything else is error
1299int
1300RpUnits::addPresets (const std::string group) {
1301    int retVal = -1;
1302    if (group.compare("all") == 0) {
1303        retVal = RpUnitsPreset::addPresetAll();
1304    }
1305    else if (group.compare("energy") == 0) {
1306        retVal = RpUnitsPreset::addPresetEnergy();
1307    }
1308    else if (group.compare("length") == 0) {
1309        retVal = RpUnitsPreset::addPresetLength();
1310    }
1311    else if (group.compare("temp") == 0) {
1312        retVal = RpUnitsPreset::addPresetTemp();
1313    }
1314    else if (group.compare("time") == 0) {
1315        retVal = RpUnitsPreset::addPresetTime();
1316    }
1317    else if (group.compare("volume") == 0) {
1318        retVal = RpUnitsPreset::addPresetTime();
1319    }
1320
1321    return retVal;
1322}
1323
1324// return codes: 0 success, anything else is error
1325int
1326RpUnitsPreset::addPresetAll () {
1327
1328    int result = 0;
1329
1330    result += addPresetTime();
1331    result += addPresetTemp();
1332    result += addPresetLength();
1333    result += addPresetEnergy();
1334    result += addPresetVolume();
1335
1336    return 0;
1337}
1338
1339// return codes: 0 success, anything else is error
1340int
1341RpUnitsPreset::addPresetTime () {
1342
1343    RpUnits* seconds    = RpUnits::define("s", NULL);
1344
1345    RpUnits::makeMetric(seconds);
1346
1347    // add time definitions
1348
1349    return 0;
1350}
1351
1352// return codes: 0 success, anything else is error
1353int
1354RpUnitsPreset::addPresetTemp () {
1355
1356    RpUnits* fahrenheit = RpUnits::define("F", NULL);
1357    RpUnits* celcius    = RpUnits::define("C", NULL);
1358    RpUnits* kelvin     = RpUnits::define("K", NULL);
1359    RpUnits* rankine    = RpUnits::define("R", NULL);
1360
1361    // add temperature definitions
1362    RpUnits::define(fahrenheit, celcius, fahrenheit2centigrade, centigrade2fahrenheit);
1363    RpUnits::define(celcius, kelvin, centigrade2kelvin, kelvin2centigrade);
1364    RpUnits::define(fahrenheit, kelvin, fahrenheit2kelvin, kelvin2fahrenheit);
1365    RpUnits::define(rankine, kelvin, rankine2kelvin, kelvin2rankine);
1366
1367    return 0;
1368}
1369
1370// return codes: 0 success, anything else is error
1371int
1372RpUnitsPreset::addPresetLength () {
1373
1374    RpUnits* meters     = RpUnits::define("m", NULL);
1375    RpUnits* angstrom   = RpUnits::define("A", NULL);
1376    RpUnits* inch       = RpUnits::define("in", NULL);
1377    RpUnits* feet       = RpUnits::define("ft", NULL);
1378    RpUnits* yard       = RpUnits::define("yd", NULL);
1379
1380    RpUnits::makeMetric(meters);
1381
1382    // add length definitions
1383    RpUnits::define(angstrom, meters, angstrom2meter, meter2angstrom);
1384    RpUnits::define(inch, meters, inch2meter, meter2inch);
1385    RpUnits::define(feet, meters, feet2meter, meter2feet);
1386    RpUnits::define(yard, meters, yard2meter, meter2yard);
1387
1388    return 0;
1389}
1390
1391// return codes: 0 success, anything else is error
1392int
1393RpUnitsPreset::addPresetEnergy () {
1394
1395    RpUnits* volt       = RpUnits::define("V", NULL);
1396    RpUnits* eVolt      = RpUnits::define("eV", NULL);
1397    RpUnits* joule      = RpUnits::define("J", NULL);
1398
1399    RpUnits::makeMetric(volt);
1400    RpUnits::makeMetric(eVolt);
1401    RpUnits::makeMetric(joule);
1402
1403    // add energy definitions
1404    RpUnits::define(eVolt,joule,electronVolt2joule,joule2electronVolt);
1405
1406    return 0;
1407}
1408
1409// return codes: 0 success, anything else is error
1410int
1411RpUnitsPreset::addPresetVolume () {
1412
1413    RpUnits* cubic_meter  = RpUnits::define("m3", NULL);
1414    // RpUnits* pcubic_meter  = RpUnits::define("/m3", NULL);
1415    RpUnits* cubic_feet   = RpUnits::define("ft3", NULL);
1416    RpUnits* us_gallon    = RpUnits::define("gal", NULL);
1417
1418    RpUnits::makeMetric(cubic_meter);
1419
1420    // add energy definitions
1421    RpUnits::define(cubic_meter,cubic_feet,meter2feet,feet2meter);
1422    RpUnits::define(cubic_meter,us_gallon,cubicMeter2usGallon,usGallon2cubicMeter);
1423    RpUnits::define(cubic_feet,us_gallon,cubicFeet2usGallon,usGallon2cubicFeet);
1424
1425    return 0;
1426}
1427
1428// -------------------------------------------------------------------- //
1429
Note: See TracBrowser for help on using the repository browser.