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

Last change on this file since 104 was 104, checked in by dkearney, 19 years ago

This update brings us one step closer to being const correct in the RpUnits
class. Added a few more comments. All other files touched were made to
comply with the new const correct RpUnits.[h,cc]

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