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

Last change on this file since 73 was 73, checked in by dkearney, 15 years ago
  1. changes to RpUnits, modified RpUnits::define() function not to look for base units.
  2. changed python RpUnits to return string when units!="off" and a number when units=="off"
  3. modified make files, hopefully making them easier to read, removing vpaths,

cleaning up the make process, combining smaller libraries into one library,
librappture, and putting the core objects into one library - libRpObjects,
for testing.

  1. copied rpResult function into rappture_interface.c to stop compiler from

complaining about undefined references ot the function. trying to use the
function probably won't work. but that can be fixed after the repository is
reorganized.

  1. in example/app-fermi/python/fermi.py, changed exit() to sys.exit() to

stop python from complaining about no function called exit().

  1. examples/app-fermi/fortran still does not run, but new rappture parser

should take care of these problems. (same with examples/fermi_fortran)

File size: 35.2 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
10 *  Purdue Research Foundation, West Lafayette, IN
11 * ======================================================================
12 */
13
14#include "RpUnits.h"
15
16// dict pointer
17RpDict<std::string,RpUnits*>* RpUnits::dict = new RpDict<std::string,RpUnits*>();
18
19/************************************************************************
20 *                                                                     
21 * add RpUnits Object                                                   
22 *                                                                     
23 ************************************************************************/
24
25RpUnits * RpUnits::define(const std::string units, RpUnits * basis)
26{
27    RpUnits * newRpUnit = NULL;
28
29    if (units == "") {
30        // raise error, user sent null units!
31        return NULL;
32    }
33
34    // check to see if the user is trying to trick me!
35    if ( (basis) && (units == basis->getUnits()) ) {
36        // dont trick me!
37        return NULL;
38    }
39
40    double exp = 0.0;
41    double oldExponent = 0;
42    double newExponent = 0;
43    int digiSearch = 0; // flag to show we are searching digits
44    int alphaSearch = 0; // flag to show we are searching chars
45
46    std::string cmpStr = "";
47
48    std::string::size_type length = units.length();
49    int srchIndex = length;
50    std::string srchStr = units;
51
52    while ((srchStr.length() > 0)) {
53
54        srchIndex--;
55 
56        if (srchIndex < 0) {
57            break;
58        }
59 
60        if     ( isdigit(srchStr[srchIndex]) && !digiSearch && !alphaSearch) {
61            digiSearch = 1;
62        }
63        else if(!isdigit(srchStr[srchIndex]) &&  digiSearch && !alphaSearch) {
64 
65            // convert our exponent to integer
66 
67            // check to see if there is a + or - sign
68            if (  ( srchStr[srchIndex] == '+' )
69               || ( srchStr[srchIndex] == '-' ) ) {
70 
71                // evaluate a '+' or '-' sign with the value
72                srchIndex--;
73            }
74 
75            srchIndex++;
76 
77            exp = atoi(&srchStr[srchIndex]);
78 
79            // we are no longer in a digit search
80            digiSearch = 0;
81 
82            // place null character where the number starts
83            // so we know what we've already parsed
84 
85            srchStr.erase(srchIndex);
86            length = srchStr.length();
87 
88        }
89        else if( isalpha(srchStr[srchIndex]) && !digiSearch && !alphaSearch) {
90            alphaSearch = 1;
91        }
92        else if(!isalpha(srchStr[srchIndex]) && !digiSearch && alphaSearch) {
93           
94            // adjust the exponent if none was provided
95            if (exp == 0) {
96                exp = 1;
97            }
98 
99            // compare unit string to see if it is a recognized system
100 
101 
102            std::string cmpStr = srchStr.substr(srchIndex+1,length-srchIndex-1);
103            if (newRpUnit) {
104                 newRpUnit->addUnit( cmpStr, exp, basis);
105            }
106            else {
107                 newRpUnit= new RpUnits(cmpStr, exp, basis);
108            }
109
110            // place a null character at the end of the string
111            // so we know what we've parsed so far.
112         
113            srchStr.erase(srchIndex);
114            length = srchStr.length();
115 
116            // fix our searching flag
117            alphaSearch = 0;
118
119        }
120        else if( srchStr[srchIndex] == '/' ) {
121            // have to go back to all of the objects created and
122            // multiply their exponents by -1.
123 
124            if (newRpUnit) {
125                unit* p = newRpUnit->head;
126                while (p) {
127                    oldExponent = p->getExponent();
128                    newExponent = oldExponent*-1;
129                    p->newExponent(newExponent);
130                    p = p->next;
131                }
132            }
133
134            // place a null character at the end of the string
135            // so we know what we've parsed so far.
136       
137            srchStr.erase(srchIndex);
138            length = srchStr.length();
139
140        }
141        else {
142            continue;
143        }
144
145
146    } // end while loop
147       
148
149    // complete the last iteration
150    if (srchIndex < 0) {
151
152
153        if (digiSearch) {
154            // convert whatever is left
155            exp = atoi(&srchStr[srchIndex+1]);
156           
157            // if we get here, that means units name starts with a digit
158            // normally we wont get here, but if we do, should we place
159            // the unit into the dictionary? i think not since digits are
160            // always considered exponents.
161        }
162        else if (alphaSearch) {
163            // adjust the exponent if none was provided
164            if (exp == 0) {
165                exp = 1;
166            }
167
168            // compare unit string to see if it is a recognized system
169
170            std::string cmpStr = srchStr.substr(srchIndex+1,length-srchIndex-1);
171            newRpUnit= new RpUnits(cmpStr, exp, basis);
172            newRpUnit->insert(newRpUnit->getUnitsName());
173        }
174    }
175
176    // place the new object into the dictionary
177   
178    // return a copy of the new object to user
179    return newRpUnit;
180}
181
182
183/************************************************************************
184 *                                                                     
185 * add a complex RpUnits Object                                                   
186 *                                                                     
187 ************************************************************************/
188
189RpUnits * RpUnits::defineCmplx ( const std::string units,
190                            RpUnits * basis )
191{
192    RpUnits * newRpUnit = NULL;
193
194    if (units == "") {
195        // raise error, user sent null units!
196        return NULL;
197    }
198
199    // check to see if the user is trying to trick me!
200    if ( (basis) && (units == basis->getUnits()) ) {
201        // dont trick me!
202        return NULL;
203    }
204
205    double exp = 0.0;
206    double oldExponent = 0;
207    double newExponent = 0;
208    int digiSearch = 0; // flag to show we are searching digits
209    int alphaSearch = 0; // flag to show we are searching chars
210    std::string dbText = "";
211
212    std::string cmpStr = "";
213    int cmpIndex = 0;
214
215    std::string::size_type length = units.length();
216    int srchIndex = length;
217    std::string srchStr = units;
218
219
220    while ((srchStr.length() > 0)) {
221
222        srchIndex--;
223 
224        if (srchIndex < 0) {
225            break;
226        }
227 
228        if     ( isdigit(srchStr[srchIndex]) && !digiSearch && !alphaSearch) {
229            digiSearch = 1;
230        }
231        else if(!isdigit(srchStr[srchIndex]) &&  digiSearch && !alphaSearch) {
232 
233            // convert our exponent to integer
234 
235            // check to see if there is a + or - sign
236            if (  ( srchStr[srchIndex] == '+' )
237               || ( srchStr[srchIndex] == '-' ) ) {
238 
239                // evaluate a '+' or '-' sign with the value
240                srchIndex--;
241            }
242 
243            srchIndex++;
244 
245            exp = atoi(&srchStr[srchIndex]);
246 
247            // we are no longer in a digit search
248            digiSearch = 0;
249 
250            // place null character where the number starts
251            // so we know what we've already parsed
252 
253            srchStr.erase(srchIndex);
254            length = srchStr.length();
255 
256        }
257        else if( isalpha(srchStr[srchIndex]) && !digiSearch && !alphaSearch) {
258            alphaSearch = 1;
259        }
260        else if(!isalpha(srchStr[srchIndex]) && !digiSearch && alphaSearch) {
261           
262            // adjust the exponent if none was provided
263            if (exp == 0) {
264                exp = 1;
265            }
266 
267            // compare unit string to see if it is a recognized system
268 
269 
270            std::string cmpStr = srchStr.substr(srchIndex+1,length-srchIndex-1);
271            cmpIndex = 0;
272 
273            if ( (unsigned)(cmpIndex = pre_compare(cmpStr,basis)) ==
274                    std::string::npos ) {
275                alphaSearch = 0;
276 
277                // there are units we did not recognize,
278                // right now we ignore them,
279                // we may want to deal with them differntly in the future
280 
281                // erase only the last character and reprocess the string
282                // because our precompare doesnt take care of this yet.
283                srchStr.erase(srchStr.length()-1);
284                length = srchStr.length();
285                srchIndex = length;
286               
287 
288                // continue parsing characters
289                continue;
290            }
291 
292            // the compare function was successful
293            // move the search pointer to one value infront of
294            // where the units were found.
295            //
296            // cmpIndex tells us how far ahead of the srchIndex the matching
297            // unit was found. so we add srchIndex to get the real index.
298            cmpIndex += srchIndex+1;
299            srchIndex = cmpIndex;
300            std::string newUnitText = srchStr.substr(cmpIndex,length-cmpIndex);
301 
302            // call the function to create the unit object
303 
304            // we need pre-compare to return the basis of what it found.
305            if (newRpUnit) {
306                 newRpUnit->addUnit( newUnitText, exp, basis);
307            }
308            else {
309                 newRpUnit= new RpUnits(newUnitText, exp, basis);
310            }
311 
312 
313            // place a null character at the end of the string
314            // so we know what we've parsed so far.
315         
316            srchStr.erase(srchIndex);
317            length = srchStr.length();
318 
319            // fix our searching flag
320            alphaSearch = 0;
321
322        }
323        else if( srchStr[srchIndex] == '/' ) {
324            // have to go back to all of the objects created and
325            // multiply their exponents by -1.
326 
327            if (newRpUnit) {
328                unit* p = newRpUnit->head;
329                while (p) {
330                    oldExponent = p->getExponent();
331                    newExponent = oldExponent*-1;
332                    p->newExponent(newExponent);
333                    p = p->next;
334                }
335            }
336
337            // place a null character at the end of the string
338            // so we know what we've parsed so far.
339       
340            srchStr.erase(srchIndex);
341            length = srchStr.length();
342
343        }
344        else {
345            continue;
346        }
347
348
349    } // end while loop
350       
351
352    // complete the last iteration
353    if (srchIndex < 0) {
354
355
356        if (digiSearch) {
357            // convert whatever is left
358            exp = atoi(&srchStr[srchIndex+1]);
359           
360            // if we get here, that means units name starts with a digit
361            // normally we wont get here, but if we do, should we place
362            // the unit into the dictionary? i think not since digits are
363            // always considered exponents.
364        }
365        else if (alphaSearch) {
366            // adjust the exponent if none was provided
367            if (exp == 0) {
368                exp = 1;
369            }
370
371            // compare unit string to see if it is a recognized system
372
373            std::string cmpStr = srchStr.substr(srchIndex+1,length-srchIndex-1);
374            cmpIndex = 0;
375
376            if ( (cmpIndex = pre_compare(cmpStr,basis)) < 0 ) {
377                // no matches in the compare function
378
379                // there are units we did not recognize,
380
381                // create a new unit with basis of null to show its a
382                // fundamental type
383                newRpUnit = new RpUnits(cmpStr, exp, basis);
384               
385                // put the unit into the dictionary
386                //
387                newRpUnit->insert(newRpUnit->getUnitsName());
388               
389
390            }
391            else {
392
393                // the compare function was successful
394                // move the search pointer to one value infront of
395                // where the units were found.
396                // adjusting the search pointer to point to the units
397                std::string newUnitText = srchStr.substr(cmpIndex,length-cmpIndex);
398
399                // call the function to create the unit object
400
401                // we need pre-compare to return the basis of what it found.
402                if (newRpUnit) {
403                     newRpUnit->addUnit( newUnitText, exp, basis );
404                }
405                else {
406                     newRpUnit = new RpUnits(newUnitText, exp, basis);
407                }
408
409                // creating unit
410                //
411                // putting unit into dictionary
412                newRpUnit->insert(newRpUnit->getUnitsName());
413            }
414
415        }
416    }
417
418    // place the new object into the dictionary
419   
420    // return a copy of the new object to user
421    return newRpUnit;
422}
423
424
425/************************************************************************
426 *                                                                     
427 * add relation rule                                                   
428 *                                                                     
429 ************************************************************************/
430RpUnits * RpUnits::define(  RpUnits* from,
431                            RpUnits* to,
432                            double (*convForwFxnPtr)(double),
433                            double (*convBackFxnPtr)(double))
434{
435    RpUnits* conv = new RpUnits(from,to,convForwFxnPtr,convBackFxnPtr,NULL,NULL);
436   
437    return conv;
438}
439
440RpUnits * RpUnits::define(  RpUnits* from,
441                            RpUnits* to,
442                            void* (*convForwFxnPtr)(void*, void*),
443                            void* convForwData,
444                            void* (*convBackFxnPtr)(void*, void*),
445                            void* convBackData)
446{
447    RpUnits* conv = new RpUnits(    from,
448                                    to,
449                                    convForwFxnPtr,
450                                    convForwData,
451                                    convBackFxnPtr,
452                                    convBackData,
453                                    NULL,
454                                    NULL);
455   
456    return conv;
457}
458
459/************************************************************************
460 *                                                                     
461 * report the units this object represents back to the user             
462 *                                                                     
463 * **********************************************************************/
464std::string RpUnits::getUnits()
465{
466    std::stringstream unitText;
467    unit* p = head;
468   
469    while (p) {
470        unitText << p->getUnits() ;
471        p = p->next;
472    }
473   
474    return (unitText.str());
475}
476
477/************************************************************************
478 *                                                                     
479 * report the units this object represents back to the user             
480 *                                                                     
481 * **********************************************************************/
482std::string RpUnits::getUnitsName()
483{
484    std::stringstream unitText;
485    unit* p = head;
486    double exponent;
487   
488    while (p) {
489
490        exponent = p->getExponent();
491
492        if (exponent == 1) {
493            unitText << p->getUnits();
494        }
495        else {
496            unitText << p->getUnits() << p->getExponent();
497        }
498
499        p = p->next;
500    }
501   
502    return (unitText.str());
503}
504
505/************************************************************************
506 *                                                                     
507 * report the exponent of the units of this object back to the user
508 *                                                                     
509 * **********************************************************************/
510double RpUnits::getExponent()
511{
512    return head->getExponent();
513    return 0;
514}
515
516/************************************************************************
517 *                                                                     
518 *  report the basis of this object to the user                         
519 *                                                                     
520 * **********************************************************************/
521RpUnits * RpUnits::getBasis()
522{
523    // check if head exists?
524    return head->getBasis();
525}
526
527/************************************************************************
528 *                                                                     
529 *  convert the current unit to its basis units
530 * 
531 *  Return Codes
532 *      0) no error (could also mean or no prefix was found)
533 *          in some cases, this means the value is in its basis format
534 *      1) the prefix found does not have a built in factor associated.
535 *                                                                     
536 ************************************************************************/
537double RpUnits::makeBasis(double value, int* result)
538{
539
540    RpUnits* basis = getBasis();
541    double retVal = value;
542
543    if (result) {
544        *result = 0;
545    }
546
547    if (basis == NULL) {
548        // this unit is a basis
549        // do nothing
550       
551        if (result) {
552            *result = 1;
553        }
554    }
555    else {
556        retVal = convert(basis,value,result);
557    }
558
559    return retVal;
560}
561
562RpUnits& RpUnits::makeBasis(double* value, int* result)
563{
564    RpUnits* basis = getBasis();
565    double retVal = *value;
566    int convResult = 0;
567
568    if (basis == NULL) {
569        // this unit is a basis
570        // do nothing
571       
572        if (result) {
573            *result = 1;
574        }
575    }
576    else {
577        retVal = convert(basis,retVal,&convResult);
578    }
579
580    if ( (convResult == 1) ) {
581        *value = retVal;
582    }
583
584    if (result) {
585        *result = convResult;
586    }
587
588   
589
590    return *this;
591}
592
593/************************************************************************
594 *                                                                     
595 *  static int makeMetric(RpUnits * basis);                     
596 *  create the metric attachments for the given basis.
597 *  should only be used if this unit is of metric type                 
598 *                                                                     
599 * **********************************************************************/
600int RpUnits::makeMetric(RpUnits * basis) {
601
602    if (!basis) {
603        return 0;
604    }
605
606    std::string basisName = basis->getUnits();
607    std::string name;
608    std::string forw, back;
609   
610    name = "c" + basisName;
611    RpUnits * centi = RpUnits::define(name, basis);
612    RpUnits::define(centi, basis, centi2base, base2centi);
613
614    name = "m" + basisName;
615    RpUnits * milli = RpUnits::define(name, basis);
616    RpUnits::define(milli, basis, milli2base, base2milli);
617
618    name = "u" + basisName;
619    RpUnits * micro = RpUnits::define(name, basis);
620    RpUnits::define(micro, basis, micro2base, base2micro);
621
622    name = "n" + basisName;
623    RpUnits * nano  = RpUnits::define(name, basis);
624    RpUnits::define(nano, basis, nano2base, base2nano);
625   
626    name = "p" + basisName;
627    RpUnits * pico  = RpUnits::define(name, basis);
628    RpUnits::define(pico, basis, pico2base, base2pico);
629
630    name = "f" + basisName;
631    RpUnits * femto = RpUnits::define(name, basis);
632    RpUnits::define(femto, basis, femto2base, base2femto);
633
634    name = "a" + basisName;
635    RpUnits * atto  = RpUnits::define(name, basis);
636    RpUnits::define(atto, basis, atto2base, base2atto);
637
638    name = "k" + basisName;
639    RpUnits * kilo  = RpUnits::define(name, basis);
640    RpUnits::define(kilo, basis, kilo2base, base2kilo);
641
642    name = "M" + basisName;
643    RpUnits * mega  = RpUnits::define(name, basis);
644    RpUnits::define(mega, basis, mega2base, base2mega);
645
646    name = "G" + basisName;
647    RpUnits * giga  = RpUnits::define(name, basis);
648    RpUnits::define(giga, basis, giga2base, base2giga);
649
650    name = "T" + basisName;
651    RpUnits * tera  = RpUnits::define(name, basis);
652    RpUnits::define(tera, basis, tera2base, base2tera);
653
654    name = "P" + basisName;
655    RpUnits * peta  = RpUnits::define(name, basis);
656    RpUnits::define(peta, basis, peta2base, base2peta);
657   
658    return (1);
659}
660
661// convert function so people can just send in two strings and
662// we'll see if the units exists and do a conversion
663// strVal = RpUnits::convert("300K","C",1);
664std::string
665RpUnits::convert (  std::string val,
666                    std::string toUnitsName,
667                    int showUnits,
668                    int* result ) {
669
670    int valLen = 0;
671    RpUnits* toUnits = NULL;
672    RpUnits* fromUnits = NULL;
673    std::string tmpNumVal = "";
674    std::string fromUnitsName = "";
675    std::string convVal = "";
676    double numVal = 0;
677    int idx = 0;
678    int convResult = 0;
679
680
681    // set  default result flag/error code
682    if (result) {
683        *result = 0;
684    }
685   
686    toUnits = find(toUnitsName);   
687
688    // did we find the unit in the dictionary?
689    if (toUnits == NULL) {
690        // toUnitsName was not found in the dictionary
691        return val;
692    }
693   
694    valLen = val.length();
695
696    // search our string to see where the numeric part stops
697    // and the units part starts
698    // make sure not to stop searching if we encounter '.', '-', '+'
699    for (idx=0; idx < valLen; idx++) {
700        if ( !((val[idx] >= '0') && (val[idx] <= '9')) ) {
701            if ( (val[idx] != '.')&&(val[idx] != '-')&&(val[idx] != '+') ) {
702                break;
703            }
704        }
705    }
706
707    if ( (idx < valLen) && (idx > 0) ) {
708        tmpNumVal = val.substr(0,idx);
709        if (!tmpNumVal.empty()) {
710            numVal = atof(tmpNumVal.c_str());
711        }
712        else {
713            // tmpNumVal was empty string?
714            // set error code here and return error
715
716            if (result) {
717                *result = 1;
718            }
719        }
720        fromUnitsName = val.substr(idx, valLen-idx);
721    }
722    else {
723        // return error, no units or no number in the val string?
724        if (result) {
725            *result = 1;
726        }
727    }
728   
729    fromUnits = find(fromUnitsName);   
730
731    // did we find the unit in the dictionary?
732    if (fromUnits == NULL) {
733        // fromUnitsName was not found in the dictionary
734        return val;
735    }
736
737    convVal = fromUnits->convert(toUnits, numVal, showUnits, &convResult);
738   
739    if ( (result) && (*result == 0) ) {
740        *result = convResult;
741    }
742
743    return convVal;
744
745}
746
747std::string RpUnits::convert (   RpUnits* toUnits,
748                        double val,
749                        int showUnits,
750                        int* result )
751{
752    double retVal = convert(toUnits,val,result);
753    std::stringstream unitText;
754   
755
756    if (showUnits) {
757        unitText << retVal << toUnits->getUnits();
758    }
759    else {
760        unitText << retVal;
761    }
762
763    return (unitText.str());
764
765}
766
767// user function to convert a value to the provided RpUnits* toUnits
768// if it exists as a conversion from the basis
769// example
770//      cm.convert(meter,10)
771//      cm.convert(angstrum,100)
772double RpUnits::convert(RpUnits* toUnit, double val, int* result)
773{
774
775    // currently we convert this object to its basis and look for the
776    // connection to the toUnit object from the basis.
777
778    double value = val;
779    RpUnits* basis = this->getBasis();
780    RpUnits* fromUnit = this;
781    RpUnits* dictToUnit = NULL;
782    convEntry *p;
783    int my_result = 0;
784
785    // set *result to a default value
786    if (result) {
787        *result = 0;
788    }
789
790    // guard against converting to the units you are converting from...
791    // ie. meters->meters
792    if (this->getUnits() == toUnit->getUnits()) {
793        if (result) {
794            *result = 1;
795        }
796        return val;
797    }
798   
799    // convert unit to the basis
800    // makeBasis(&value);
801    // trying to avoid the recursive way of converting to the basis.
802    // need to rethink this.
803    //
804    if ( (basis) && (basis->getUnits() != toUnit->getUnits()) ) {
805        value = convert(basis,value,&my_result);
806        if (my_result) {
807            fromUnit = basis;
808        }   
809    }
810
811    // find the toUnit in our dictionary.
812
813    dictToUnit = find(toUnit->getUnits());
814
815    // did we find the unit in the dictionary?
816    if (dictToUnit == NULL) {
817        // toUnit was not found in the dictionary
818        return val;
819    }
820
821    // search through the conversion list to find
822    // the conversion to the toUnit.
823
824    if (basis) {
825        p = basis->convList;
826    }
827    else {
828        p = this->convList;
829    }
830
831    if (p == NULL) {
832        // there are no conversions
833        return val;
834    }
835
836    // loop through our conversion list looking for the correct conversion
837    do {
838       
839        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
840            // we found our conversion
841            // call the function pointer with value
842
843            value = p->conv->convForwFxnPtr(value);
844            if (result) {
845                *result = 1;
846            }
847            break;
848        }
849       
850        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
851            // we found our conversion
852            // call the function pointer with value
853
854            value = p->conv->convBackFxnPtr(value);
855            if (result) {
856                *result = 1;
857            }
858            break;
859        }
860
861        p = p->next;
862
863    } while (p != NULL);
864
865
866    if ( p == NULL) {
867        // we did not find the conversion
868        return val;
869    }
870
871    // we found the conversion.
872    // return the converted value.
873    return value;
874
875}
876
877
878void* RpUnits::convert(RpUnits* toUnit, void* val, int* result)
879{
880
881    // currently we convert this object to its basis and look for the
882    // connection ot the toUnit object from the basis.
883
884    void* value = val;
885    RpUnits* basis = this->getBasis();
886    RpUnits* fromUnit = this;
887    RpUnits* dictToUnit = NULL;
888    convEntry *p;
889    int my_result = 0;
890
891    // set *result to a default value
892    if (result) {
893        *result = 0;
894    }
895
896    // guard against converting to the units you are converting from...
897    // ie. meters->meters
898    if (this->getUnits() == toUnit->getUnits()) {
899        if (result) {
900            *result = 1;
901        }
902        return val;
903    }
904   
905    // convert unit to the basis
906    // makeBasis(&value);
907    // trying to avoid the recursive way of converting to the basis.
908    // need to rethink this.
909    //
910    if ( (basis) && (basis->getUnits() != toUnit->getUnits()) ) {
911        value = convert(basis,value,&my_result);
912        if (my_result) {
913            fromUnit = basis;
914        }   
915    }
916
917    // find the toUnit in our dictionary.
918
919    dictToUnit = find(toUnit->getUnits());
920
921    // did we find the unit in the dictionary?
922    if (dictToUnit == NULL) {
923        // toUnit was not found in the dictionary
924        return val;
925    }
926
927    // search through the conversion list to find
928    // the conversion to the toUnit.
929
930    if (basis) {
931        p = basis->convList;
932    }
933    else {
934        p = this->convList;
935    }
936
937    if (p == NULL) {
938        // there are no conversions
939        return val;
940    }
941
942    // loop through our conversion list looking for the correct conversion
943    do {
944       
945        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
946            // we found our conversion
947            // call the function pointer with value
948
949            value = p->conv->convForwFxnPtrVoid(p->conv->convForwData,value);
950
951            if (result) {
952                *result = 1;
953            }
954            break;
955        }
956       
957        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
958            // we found our conversion
959            // call the function pointer with value
960
961            value = p->conv->convBackFxnPtrVoid(p->conv->convBackData,value);
962            if (result) {
963                *result = 1;
964            }
965            break;
966        }
967
968        p = p->next;
969
970    } while (p != NULL);
971
972
973    if ( p == NULL) {
974        // we did not find the conversion
975        return val;
976    }
977
978    // we found the conversion.
979    // return the converted value.
980    return value;
981
982}
983
984void RpUnits::addUnit( const std::string& units,
985                       double&  exponent,
986                       RpUnits* basis
987                      )
988{
989    unit* p = NULL;
990
991    // check if the list was created previously. if not, start the list
992    if (head == 0) {
993        head = new unit(units,exponent,basis,NULL);
994        return;
995    }
996
997    // now add a new node at the beginning of the list:
998    p = new unit(units,exponent,basis,head);
999    head->prev = p;
1000    head = p;
1001
1002}
1003
1004int RpUnits::insert(std::string key)
1005{
1006    int newRecord = 0;
1007    RpUnits* val = this;
1008    // dict pointer
1009    RpUnits::dict->set(key,val,&newRecord);
1010    return newRecord;
1011}
1012
1013
1014int RpUnits::pre_compare( std::string& units, RpUnits* basis )
1015{
1016
1017    // compare the incomming units with the previously defined units.
1018    // compareStr will hold a copy of the incomming string.
1019    // first look for the units as they are listed in the incomming variable
1020    // next look move searchStr toward the end of the string,
1021    // each time the pointer is moved, searchStr should be compared to all of
1022    // the previously defined units.
1023    // if searchStr is at the end of the string, then searchStr will be moved
1024    // back to the beginning of the string.
1025    // next it will traverse the string again, changing the case of the char
1026    // it points to and the resultant string will be compared again to all
1027    // of the previously defined units.
1028
1029    int compareSuccess = 0;
1030    // std::string::size_type units_len = units.length();
1031    // char * retVal = NULL;
1032    int retIndex = std::string::npos;
1033    // std::string compareStr = units;
1034    std::string searchStr = units;
1035    std::string dbText = "";
1036   
1037    // pass 1: look for exact match of units as they came into the function
1038    //          move searchStr pointer through string to find match.
1039    while ( ! compareSuccess &&
1040            (searchStr.length() > 0) ) {
1041
1042        // dict pointer
1043        if (dict->find(searchStr) == dict->getNullEntry()) {
1044            // the string was not found,
1045            // keep incrementing the pointer
1046            // searchStr (pass1)  does not match";
1047        }
1048        else {
1049            // compare was successful,
1050            // searchStr (pass1)  found a match
1051            compareSuccess++;
1052            break;
1053            // is it possible to create the unit here and
1054            // keep looking for units fro mthe provided string?
1055        }
1056
1057        searchStr.erase(0,1);
1058
1059        if (basis) {
1060            if ( (searchStr == basis->getUnits()) &&
1061                 (searchStr.length() == basis->getUnits().length()) )
1062            {
1063                break;
1064            }
1065        }
1066    }
1067
1068
1069    if (compareSuccess == 0) {
1070        // refresh our searchStr var.
1071        searchStr = units;
1072    }
1073
1074    // pass 2: capitolize the first letter of the search string and compare
1075    //          for each letter in the string
1076    while ( ! compareSuccess &&
1077            (searchStr.length() > 0) ) {
1078
1079        if (islower((int)(searchStr[0]))) {
1080            searchStr[0] = (char) toupper((int)(searchStr[0]));
1081        }
1082
1083        // dict pointer
1084        if (dict->find(searchStr) == dict->getNullEntry()) {
1085            // the string was not found,
1086            // keep incrementing the pointer
1087            // searchStr (pass2)  does not match
1088        }
1089        else {
1090            // compare was successful,
1091            // searchStr (pass2)  found a match
1092            compareSuccess++;
1093            break;
1094        }
1095        searchStr.erase(0,1);
1096
1097        // check to see if we are at the basis.
1098        if (basis) {
1099            if ( (searchStr == basis->getUnits()) &&
1100                 (searchStr.length() == basis->getUnits().length()) )
1101            {
1102                break;
1103            }
1104           
1105        }
1106
1107    }
1108
1109
1110
1111    // if we found a match, find the first occurance of the string which
1112    // was used to get the match, in our original units string.
1113    // this gets dicey for capitolizations.
1114    if ( compareSuccess ) {
1115        // need to think about if we want to search from the start
1116        // or the end of the string (find or rfind)
1117        // i think its the start because in this fxn (above)
1118        // we start at the beginning of the string and work
1119        // our way to the end. so if there is a second match at the
1120        // end, we would have only seen the first match.
1121        retIndex = units.find(searchStr);
1122    }
1123
1124    return retIndex;
1125
1126}
1127
1128
1129void RpUnits::connectConversion(RpUnits* myRpUnit)
1130{
1131    convEntry* p = myRpUnit->convList;
1132
1133    if (p == NULL) {
1134        myRpUnit->convList = new convEntry (this->conv,NULL,NULL);
1135    }
1136    else {
1137        while (p->next != NULL) {
1138            p = p->next;
1139        }
1140
1141        p->next = new convEntry (this->conv,p,NULL);
1142    }
1143
1144}
1145
1146// return codes: 0 success, anything else is error
1147int
1148RpUnits::addPresets (std::string group) {
1149    int retVal = 1;
1150    if (group.compare("all") == 0) {
1151        retVal = addPresetAll();
1152    }
1153    else if (group.compare("energy") == 0) {
1154        retVal = addPresetEnergy();
1155    }
1156    else if (group.compare("length") == 0) {
1157        retVal = addPresetLength();
1158    }
1159    else if (group.compare("temp") == 0) {
1160        retVal = addPresetTemp();
1161    }
1162    else if (group.compare("time") == 0) {
1163        retVal = addPresetTime();
1164    }
1165   
1166    return retVal;
1167}
1168   
1169// return codes: 0 success, anything else is error
1170int
1171RpUnits::addPresetAll () {
1172
1173
1174    addPresetTime();
1175    addPresetTemp();
1176    addPresetLength();
1177    addPresetEnergy();
1178
1179    return 0;
1180}
1181
1182// return codes: 0 success, anything else is error
1183int
1184RpUnits::addPresetTime () {
1185
1186    RpUnits* seconds    = RpUnits::define("s", NULL);
1187   
1188    RpUnits::makeMetric(seconds);
1189   
1190    // add time definitions
1191
1192    return 0;
1193}
1194
1195// return codes: 0 success, anything else is error
1196int
1197RpUnits::addPresetTemp () {
1198
1199    RpUnits* fahrenheit = RpUnits::define("F", NULL);
1200    RpUnits* celcius    = RpUnits::define("C", NULL);
1201    RpUnits* kelvin     = RpUnits::define("K", NULL);
1202    RpUnits* rankine    = RpUnits::define("R", NULL);
1203   
1204    // add temperature definitions
1205    RpUnits::define(fahrenheit, celcius, fahrenheit2centigrade, centigrade2fahrenheit);
1206    RpUnits::define(celcius, kelvin, centigrade2kelvin, kelvin2centigrade);
1207    RpUnits::define(fahrenheit, kelvin, fahrenheit2kelvin, kelvin2fahrenheit);
1208    RpUnits::define(rankine, kelvin, rankine2kelvin, kelvin2rankine);
1209
1210    return 0;
1211}
1212
1213// return codes: 0 success, anything else is error
1214int
1215RpUnits::addPresetLength () {
1216
1217    RpUnits* meters     = RpUnits::define("m", NULL);
1218    RpUnits* angstrom   = RpUnits::define("A", NULL);
1219    RpUnits* inch       = RpUnits::define("in", NULL);
1220    RpUnits* feet       = RpUnits::define("ft", NULL);
1221    RpUnits* yard       = RpUnits::define("yd", NULL);
1222   
1223    RpUnits::makeMetric(meters);
1224
1225    // add length definitions
1226    RpUnits::define(angstrom, meters, angstrom2meter, meter2angstrom);
1227    RpUnits::define(inch, meters, inch2meter, meter2inch);
1228    RpUnits::define(feet, meters, feet2meter, meter2feet);
1229    RpUnits::define(yard, meters, yard2meter, meter2yard);
1230
1231    return 0;
1232}
1233
1234// return codes: 0 success, anything else is error
1235int
1236RpUnits::addPresetEnergy () {
1237
1238    RpUnits* volt       = RpUnits::define("V", NULL);
1239    RpUnits* electrVolt = RpUnits::define("eV", NULL);
1240    RpUnits* joule      = RpUnits::define("J", NULL);
1241   
1242    RpUnits::makeMetric(volt);
1243
1244    // add energy definitions
1245    RpUnits::define(electrVolt,joule,electronVolt2joule,joule2electronVolt);
1246
1247    return 0;
1248}
1249
1250// -------------------------------------------------------------------- //
1251
Note: See TracBrowser for help on using the repository browser.