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

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

updates to RpUnits to reduce memory leaks
created copy constructors, destructors, and copy assignment operators
for Units classes. removed conv as a data member and removed several
constructors. removed prev & next pointers from conversion class.
this removes linked list feature from conversion class which was not
being used. this update does not fix python's problem with performing
conversion between RpUnits objects or the allow for the recognition of
/cm3 as an object related to cm3.

also removed some outdated files rappture_interface.h, rappture_interface.c.
RpDict?.cc has been moved into RpDict?.h in previous checkins to reduce
dependencies on include files.

File size: 42.6 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpUnits.cc
4 *
5 *   Data Members and member functions for the RpUnits class
6 *
7 * ======================================================================
8 *  AUTHOR:  Derrick Kearney, Purdue University
9 *  Copyright (c) 2004-2005
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    // this is kinda the wrong way to get the job done...
438    // how do we only create 1 conversion object and share it between atleast two RpUnits
439    // objs so that when the RpUnits objs are deleted, we are not trying to delete already
440    // deleted memory.
441    // so for the sake of safety we get the following few lines of code.
442
443    conversion* conv1 = NULL;
444    conversion* conv2 = NULL;
445
446    conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
447    conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
448
449    from->connectConversion(conv1);
450    to->connectConversion(conv2);
451
452    return NULL;
453}
454
455RpUnits *
456RpUnits::define(  const RpUnits* from,
457                  const RpUnits* to,
458                  double (*convForwFxnPtr)(double,double),
459                  double (*convBackFxnPtr)(double,double)) {
460
461    // this is kinda the wrong way to get the job done...
462    // how do we only create 1 conversion object and share it between atleast two RpUnits
463    // objs so that when the RpUnits objs are deleted, we are not trying to delete already
464    // deleted memory.
465    // so for the sake of safety we get the following few lines of code.
466
467    conversion* conv1 = NULL;
468    conversion* conv2 = NULL;
469
470    conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
471    conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
472
473    from->connectConversion(conv1);
474    to->connectConversion(conv2);
475
476    return NULL;
477}
478
479RpUnits *
480RpUnits::define(  const RpUnits* from,
481                  const RpUnits* to,
482                  void* (*convForwFxnPtr)(void*, void*),
483                  void* convForwData,
484                  void* (*convBackFxnPtr)(void*, void*),
485                  void* convBackData) {
486
487    // this is kinda the wrong way to get the job done...
488    // how do we only create 1 conversion object and share it between atleast two RpUnits
489    // objs so that when the RpUnits objs are deleted, we are not trying to delete already
490    // deleted memory.
491    // so for the sake of safety we get the following few lines of code.
492
493    conversion* conv1 = NULL;
494    conversion* conv2 = NULL;
495
496    conv1 = new conversion (from,to,convForwFxnPtr,convForwData,convBackFxnPtr,convBackData);
497    conv2 = new conversion (from,to,convForwFxnPtr,convForwData,convBackFxnPtr,convBackData);
498
499    from->connectConversion(conv1);
500    to->connectConversion(conv2);
501
502    return NULL;
503}
504
505/************************************************************************
506 *
507 * report the units this object represents back to the user
508 *
509 ************************************************************************/
510
511/**********************************************************************/
512// METHOD: getUnits()
513// /// Report the text portion of the units of this object back to caller.
514// /**
515//  * See Also getUnitsName().
516//  */
517//
518std::string
519RpUnits::getUnits() const {
520
521    std::stringstream unitText;
522    unit* p = head;
523
524    while (p) {
525        unitText << p->getUnits() ;
526        p = p->next;
527    }
528
529    return (unitText.str());
530}
531
532/************************************************************************
533 *
534 * report the units this object represents back to the user
535 *
536 ************************************************************************/
537
538/**********************************************************************/
539// METHOD: getUnitsName()
540// /// Report the full name of the units of this object back to caller.
541// /**
542//  * Reports the full text and exponent of the units represented by this
543//  * object, back to the caller. Note that if the exponent == 1, no
544//  * exponent will be printed.
545//  */
546//
547std::string
548RpUnits::getUnitsName() const {
549
550    std::stringstream unitText;
551    unit* p = head;
552    double exponent;
553
554    while (p) {
555
556        exponent = p->getExponent();
557
558        if (exponent == 1) {
559            unitText << p->getUnits();
560        }
561        else {
562            unitText << p->getUnits() << p->getExponent();
563        }
564
565        p = p->next;
566    }
567
568    return (unitText.str());
569}
570
571/************************************************************************
572 *
573 * report the exponent of the units of this object back to the user
574 *
575 * **********************************************************************/
576/**********************************************************************/
577// METHOD: getExponent()
578// /// Report the exponent of the units of this object back to caller.
579// /**
580//  * Reports the exponent of the units represented by this
581//  * object, back to the caller. Note that if the exponent == 1, no
582//  * exponent will be printed.
583//  */
584//
585double
586RpUnits::getExponent() const {
587
588    return head->getExponent();
589}
590
591/************************************************************************
592 *
593 *  report the basis of this object to the user
594 *
595 * **********************************************************************/
596/**********************************************************************/
597// METHOD: getBasis()
598// /// Retrieve the RpUnits object representing the basis of this object.
599// /**
600//  * Returns a pointer to a RpUnits object which, on success, points to the
601//  * RpUnits object that is the basis of the calling object.
602//  */
603//
604const RpUnits *
605RpUnits::getBasis() const {
606
607    // check if head exists?
608    if (!head) {
609        // raise error for badly formed Rappture Units object
610    }
611
612    return head->getBasis();
613}
614
615/************************************************************************
616 *
617 *  convert the current unit to its basis units
618 *
619 *  Return Codes
620 *      0) no error (could also mean or no prefix was found)
621 *          in some cases, this means the value is in its basis format
622 *      1) the prefix found does not have a built in factor associated.
623 *
624 ************************************************************************/
625double
626RpUnits::makeBasis(double value, int* result) const {
627
628    const RpUnits* basis = getBasis();
629    double retVal = value;
630
631    if (result) {
632        *result = 0;
633    }
634
635    if (basis == NULL) {
636        // this unit is a basis
637        // do nothing
638
639        // if (result) {
640        //     *result = 1;
641        // }
642    }
643    else {
644        retVal = convert(basis,value,result);
645    }
646
647    return retVal;
648}
649
650const RpUnits&
651RpUnits::makeBasis(double* value, int* result) const {
652    const RpUnits* basis = getBasis();
653    double retVal = *value;
654    int convResult = 1;
655
656    if (basis == NULL) {
657        // this unit is a basis
658        // do nothing
659
660        // if (result) {
661        //     *result = 1;
662        // }
663    }
664    else {
665        retVal = convert(basis,retVal,&convResult);
666    }
667
668    if ( (convResult == 0) ) {
669        *value = retVal;
670    }
671
672    if (result) {
673        *result = convResult;
674    }
675
676    return *this;
677}
678
679/************************************************************************
680 *
681 *  static int makeMetric(RpUnits * basis);
682 *  create the metric attachments for the given basis.
683 *  should only be used if this unit is of metric type
684 *
685 * **********************************************************************/
686
687int
688RpUnits::makeMetric(const RpUnits * basis) {
689
690    if (!basis) {
691        return 0;
692    }
693
694    std::string basisName = basis->getUnitsName();
695    std::string name;
696    std::string forw, back;
697
698    name = "c" + basisName;
699    RpUnits * centi = RpUnits::define(name, basis);
700    RpUnits::define(centi, basis, centi2base, base2centi);
701
702    name = "m" + basisName;
703    RpUnits * milli = RpUnits::define(name, basis);
704    RpUnits::define(milli, basis, milli2base, base2milli);
705
706    name = "u" + basisName;
707    RpUnits * micro = RpUnits::define(name, basis);
708    RpUnits::define(micro, basis, micro2base, base2micro);
709
710    name = "n" + basisName;
711    RpUnits * nano  = RpUnits::define(name, basis);
712    RpUnits::define(nano, basis, nano2base, base2nano);
713
714    name = "p" + basisName;
715    RpUnits * pico  = RpUnits::define(name, basis);
716    RpUnits::define(pico, basis, pico2base, base2pico);
717
718    name = "f" + basisName;
719    RpUnits * femto = RpUnits::define(name, basis);
720    RpUnits::define(femto, basis, femto2base, base2femto);
721
722    name = "a" + basisName;
723    RpUnits * atto  = RpUnits::define(name, basis);
724    RpUnits::define(atto, basis, atto2base, base2atto);
725
726    name = "k" + basisName;
727    RpUnits * kilo  = RpUnits::define(name, basis);
728    RpUnits::define(kilo, basis, kilo2base, base2kilo);
729
730    name = "M" + basisName;
731    RpUnits * mega  = RpUnits::define(name, basis);
732    RpUnits::define(mega, basis, mega2base, base2mega);
733
734    name = "G" + basisName;
735    RpUnits * giga  = RpUnits::define(name, basis);
736    RpUnits::define(giga, basis, giga2base, base2giga);
737
738    name = "T" + basisName;
739    RpUnits * tera  = RpUnits::define(name, basis);
740    RpUnits::define(tera, basis, tera2base, base2tera);
741
742    name = "P" + basisName;
743    RpUnits * peta  = RpUnits::define(name, basis);
744    RpUnits::define(peta, basis, peta2base, base2peta);
745
746    return (1);
747}
748
749
750const RpUnits*
751RpUnits::find(std::string key) {
752
753    // dict.find seems to return a (RpUnits* const) so i had to
754    // cast it as a (RpUnits*)
755
756    // dict pointer
757    const RpUnits* unitEntry = *(dict->find(key).getValue());
758
759    // dict pointer
760    if (unitEntry == *(dict->getNullEntry().getValue()) ) {
761        unitEntry = NULL;
762    }
763
764    return unitEntry;
765}
766
767
768// convert function so people can just send in two strings and
769// we'll see if the units exists and do a conversion
770// strVal = RpUnits::convert("300K","C",1);
771std::string
772RpUnits::convert (  std::string val,
773                    std::string toUnitsName,
774                    int showUnits,
775                    int* result ) {
776
777    const RpUnits* toUnits = NULL;
778    const RpUnits* fromUnits = NULL;
779    std::string tmpNumVal = "";
780    std::string fromUnitsName = "";
781    std::string convVal = "";
782    double numVal = 0;
783    // int idx = 0;
784    int convResult = 0;
785    char* endptr = NULL;
786    std::stringstream outVal;
787
788
789    // set  default result flag/error code
790    if (result) {
791        *result = 0;
792    }
793
794    toUnits = find(toUnitsName);
795
796    // did we find the unit in the dictionary?
797    if (toUnits == NULL) {
798        // toUnitsName was not found in the dictionary
799        if (result) {
800            *result = 1;
801        }
802        return val;
803    }
804
805    // search our string to see where the numeric part stops
806    // and the units part starts
807    //
808    //  convert("5J", "neV") => 3.12075e+28neV
809    //  convert("3.12075e+28neV", "J") => 4.99999J
810    // now we can actually get the scientific notation portion of the string.
811    //
812
813    numVal = strtod(val.c_str(),&endptr);
814
815    if ( (numVal == 0) && (endptr == val.c_str()) ) {
816        // no conversion was done.
817        // number in incorrect format probably.
818        if (result) {
819            *result = 1;
820        }
821        return val;
822    }
823
824    fromUnitsName = std::string(endptr);
825    if ( fromUnitsName.empty() )  {
826        // there were no units in the input string
827        // assume fromUnitsName = toUnitsName
828        // return the correct value
829        if (result) {
830            *result = 0;
831        }
832
833        if (showUnits) {
834            outVal << val << toUnitsName;
835        }
836        else {
837            outVal << val;
838        }
839
840        return outVal.str();
841    }
842
843    fromUnits = find(fromUnitsName);
844
845    // did we find the unit in the dictionary?
846    if (fromUnits == NULL) {
847        // fromUnitsName was not found in the dictionary
848        if (result) {
849            *result = 1;
850        }
851        return val;
852    }
853
854    convVal = fromUnits->convert(toUnits, numVal, showUnits, &convResult);
855
856    if ( (result) && (*result == 0) ) {
857        *result = convResult;
858    }
859
860    return convVal;
861
862}
863
864std::string
865RpUnits::convert ( const  RpUnits* toUnits,
866                   double val,
867                   int showUnits,
868                   int* result )  const {
869
870    double retVal = convert(toUnits,val,result);
871    std::stringstream unitText;
872
873
874    if (showUnits) {
875        unitText << retVal << toUnits->getUnitsName();
876    }
877    else {
878        unitText << retVal;
879    }
880
881    return (unitText.str());
882
883}
884
885// user function to convert a value to the provided RpUnits* toUnits
886// if it exists as a conversion from the basis
887// example
888//      cm.convert(meter,10)
889//      cm.convert(angstrum,100)
890double
891RpUnits::convert(const RpUnits* toUnit, double val, int* result) const {
892
893    // currently we convert this object to its basis and look for the
894    // connection to the toUnit object from the basis.
895
896    double value = val;
897    const RpUnits* basis = this->getBasis();
898    const RpUnits* toBasis = toUnit->getBasis();
899    const RpUnits* fromUnit = this;
900    const RpUnits* dictToUnit = NULL;
901    convEntry *p;
902    int my_result = 0;
903
904    // set *result to a default value
905    if (result) {
906        *result = 0;
907    }
908
909    // guard against converting to the units you are converting from...
910    // ie. meters->meters
911    if (this->getUnitsName() == toUnit->getUnitsName()) {
912        if (result) {
913            *result = 0;
914        }
915        return val;
916    }
917
918    // convert unit to the basis
919    // makeBasis(&value);
920    // trying to avoid the recursive way of converting to the basis.
921    // need to rethink this.
922    //
923    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
924        value = convert(basis,value,&my_result);
925        if (my_result == 0) {
926            fromUnit = basis;
927        }
928    }
929
930    // find the toUnit in our dictionary.
931    // if the toUnits has a basis, we need to search for the basis
932    // and convert between basis' and then convert again back to the
933    // original unit.
934    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
935        dictToUnit = find(toBasis->getUnitsName());
936    }
937    else {
938        dictToUnit = find(toUnit->getUnitsName());
939    }
940
941    // did we find the unit in the dictionary?
942    if (dictToUnit == NULL) {
943        // toUnit was not found in the dictionary
944        return val;
945    }
946
947    // search through the conversion list to find
948    // the conversion to the toUnit.
949
950    if (basis) {
951        p = basis->convList;
952    }
953    else {
954        p = this->convList;
955    }
956
957    if (p == NULL) {
958        // there are no conversions
959        return val;
960    }
961
962    // loop through our conversion list looking for the correct conversion
963    do {
964
965        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
966            // we found our conversion
967            // call the function pointer with value
968
969            // this should probably be re thought out
970            // the problem is that convForwFxnPtr has the conversion for a
971            // one arg conv function pointer and convForwFxnPtrDD has the
972            // conversion for a two arg conv function pointer
973            // need to make this simpler, more logical maybe only allow 2 arg
974            if (       (p->conv->convForwFxnPtr)
975                    && (! p->conv->convForwFxnPtrDD) ) {
976
977                value = p->conv->convForwFxnPtr(value);
978            }
979            else if (  (p->conv->convForwFxnPtrDD)
980                    && (! p->conv->convForwFxnPtr) ) {
981
982                value =
983                    p->conv->convForwFxnPtrDD(value, fromUnit->getExponent());
984            }
985
986            // check to see if we converted to the actual requested unit
987            // or to the requested unit's basis.
988            // if we converted to the requested unit's basis. we need to
989            // do one last conversion from the requested unit's basis back
990            // to the requested unit.
991            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
992                my_result = 0;
993                value = toBasis->convert(toUnit,value,&my_result);
994                if (my_result != 0) {
995                    if (result) {
996                        *result += 1;
997                    }
998                }
999            }
1000
1001            // we can probably remove this
1002            if (result) {
1003                *result += 0;
1004            }
1005            break;
1006        }
1007
1008        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1009            // we found our conversion
1010            // call the function pointer with value
1011
1012            // this should probably be re thought out
1013            // the problem is that convForwFxnPtr has the conversion for a
1014            // one arg conv function pointer and convForwFxnPtrDD has the
1015            // conversion for a two arg conv function pointer
1016            // need to make this simpler, more logical maybe only allow 2 arg
1017            if (       (p->conv->convBackFxnPtr)
1018                    && (! p->conv->convBackFxnPtrDD) ) {
1019
1020                value = p->conv->convBackFxnPtr(value);
1021            }
1022            else if (  (p->conv->convBackFxnPtrDD)
1023                    && (! p->conv->convBackFxnPtr) ) {
1024
1025                value =
1026                    p->conv->convBackFxnPtrDD(value, fromUnit->getExponent());
1027            }
1028
1029            // check to see if we converted to the actual requested unit
1030            // or to the requested unit's basis.
1031            // if we converted to the requested unit's basis. we need to
1032            // do one last conversion from the requested unit's basis back
1033            // to the requested unit.
1034            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1035                my_result = 0;
1036                value = toBasis->convert(toUnit,value,&my_result);
1037                if (my_result != 0) {
1038                    if (result) {
1039                        *result += 1;
1040                    }
1041                }
1042            }
1043
1044            // we can probably remove this
1045            if (result) {
1046                *result += 0;
1047            }
1048            break;
1049        }
1050
1051        p = p->next;
1052
1053    } while (p != NULL);
1054
1055
1056    if ( p == NULL) {
1057        // we did not find the conversion
1058        if (result) {
1059            *result += 1;
1060        }
1061        return val;
1062    }
1063
1064    // we found the conversion.
1065    // return the converted value.
1066    return value;
1067
1068}
1069
1070
1071void*
1072RpUnits::convert(const RpUnits* toUnit, void* val, int* result) const {
1073
1074    // currently we convert this object to its basis and look for the
1075    // connection ot the toUnit object from the basis.
1076
1077    void* value = val;
1078    const RpUnits* basis = this->getBasis();
1079    const RpUnits* toBasis = toUnit->getBasis();
1080    const RpUnits* fromUnit = this;
1081    const RpUnits* dictToUnit = NULL;
1082    convEntry *p;
1083    int my_result = 0;
1084
1085    // set *result to a default value
1086    if (result) {
1087        *result = 0;
1088    }
1089
1090    // guard against converting to the units you are converting from...
1091    // ie. meters->meters
1092    if (this->getUnitsName() == toUnit->getUnitsName()) {
1093        if (result) {
1094            *result = 0;
1095        }
1096        return val;
1097    }
1098
1099    // convert unit to the basis
1100    // makeBasis(&value);
1101    // trying to avoid the recursive way of converting to the basis.
1102    // need to rethink this.
1103    //
1104    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1105        value = convert(basis,value,&my_result);
1106        if (my_result == 0) {
1107            fromUnit = basis;
1108        }
1109    }
1110
1111    // find the toUnit in our dictionary.
1112    // if the toUnits has a basis, we need to search for the basis
1113    // and convert between basis' and then convert again back to the
1114    // original unit.
1115    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1116        dictToUnit = find(toBasis->getUnitsName());
1117    }
1118    else {
1119        dictToUnit = find(toUnit->getUnitsName());
1120    }
1121
1122    // did we find the unit in the dictionary?
1123    if (dictToUnit == NULL) {
1124        // toUnit was not found in the dictionary
1125        return val;
1126    }
1127
1128    // search through the conversion list to find
1129    // the conversion to the toUnit.
1130
1131    if (basis) {
1132        p = basis->convList;
1133    }
1134    else {
1135        p = this->convList;
1136    }
1137
1138    if (p == NULL) {
1139        // there are no conversions
1140        return val;
1141    }
1142
1143    // loop through our conversion list looking for the correct conversion
1144    do {
1145
1146        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1147            // we found our conversion
1148            // call the function pointer with value
1149
1150            value = p->conv->convForwFxnPtrVoid(p->conv->convForwData,value);
1151
1152            // check to see if we converted to the actual requested unit
1153            // or to the requested unit's basis.
1154            // if we converted to the requested unit's basis. we need to
1155            // do one last conversion from the requested unit's basis back
1156            // to the requested unit.
1157            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1158                my_result = 0;
1159                value = toBasis->convert(toUnit,value,&my_result);
1160                if (my_result != 0) {
1161                    if (result) {
1162                        *result += 1;
1163                    }
1164                }
1165            }
1166
1167            // we can probably remove this
1168            if (result) {
1169                *result = 0;
1170            }
1171            break;
1172        }
1173
1174        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1175            // we found our conversion
1176            // call the function pointer with value
1177
1178            value = p->conv->convBackFxnPtrVoid(p->conv->convBackData,value);
1179
1180            // check to see if we converted to the actual requested unit
1181            // or to the requested unit's basis.
1182            // if we converted to the requested unit's basis. we need to
1183            // do one last conversion from the requested unit's basis back
1184            // to the requested unit.
1185            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1186                my_result = 0;
1187                value = toBasis->convert(toUnit,value,&my_result);
1188                if (my_result != 0) {
1189                    if (result) {
1190                        *result += 1;
1191                    }
1192                }
1193            }
1194
1195            // we can probably remove this
1196            if (result) {
1197                *result = 0;
1198            }
1199            break;
1200        }
1201
1202        p = p->next;
1203
1204    } while (p != NULL);
1205
1206
1207    if ( p == NULL) {
1208        // we did not find the conversion
1209        if (result) {
1210            *result += 1;
1211        }
1212        return val;
1213    }
1214
1215    // we found the conversion.
1216    // return the converted value.
1217    return value;
1218
1219}
1220
1221void
1222RpUnits::addUnit( const std::string& units,
1223                  double&  exponent,
1224                  const RpUnits* basis) {
1225
1226    unit* p = NULL;
1227
1228    // check if the list was created previously. if not, start the list
1229    if (head == 0) {
1230        head = new unit(units,exponent,basis,NULL,NULL);
1231        return;
1232    }
1233
1234    // now add a new node at the beginning of the list:
1235    p = new unit(units,exponent,basis,NULL,head);
1236    head->prev = p;
1237    head = p;
1238
1239}
1240
1241int
1242RpUnits::insert(std::string key) {
1243
1244    int newRecord = 0;
1245    RpUnits* val = this;
1246    // dict pointer
1247    RpUnits::dict->set(key,val,&newRecord);
1248    return newRecord;
1249}
1250
1251
1252int
1253RpUnits::pre_compare( std::string& units, const RpUnits* basis ) {
1254
1255    // compare the incomming units with the previously defined units.
1256    // compareStr will hold a copy of the incomming string.
1257    // first look for the units as they are listed in the incomming variable
1258    // next look move searchStr toward the end of the string,
1259    // each time the pointer is moved, searchStr should be compared to all of
1260    // the previously defined units.
1261    // if searchStr is at the end of the string, then searchStr will be moved
1262    // back to the beginning of the string.
1263    // next it will traverse the string again, changing the case of the char
1264    // it points to and the resultant string will be compared again to all
1265    // of the previously defined units.
1266
1267    int compareSuccess = 0;
1268    // std::string::size_type units_len = units.length();
1269    // char * retVal = NULL;
1270    int retIndex = std::string::npos;
1271    // std::string compareStr = units;
1272    std::string searchStr = units;
1273    std::string dbText = "";
1274
1275    // pass 1: look for exact match of units as they came into the function
1276    //          move searchStr pointer through string to find match.
1277    while ( ! compareSuccess &&
1278            (searchStr.length() > 0) ) {
1279
1280        // dict pointer
1281        if (dict->find(searchStr) == dict->getNullEntry()) {
1282            // the string was not found,
1283            // keep incrementing the pointer
1284            // searchStr (pass1)  does not match";
1285        }
1286        else {
1287            // compare was successful,
1288            // searchStr (pass1)  found a match
1289            compareSuccess++;
1290            break;
1291            // is it possible to create the unit here and
1292            // keep looking for units fro mthe provided string?
1293        }
1294
1295        searchStr.erase(0,1);
1296
1297        if (basis) {
1298            if ( (searchStr == basis->getUnits()) &&
1299                 (searchStr.length() == basis->getUnits().length()) )
1300            {
1301                break;
1302            }
1303        }
1304    }
1305
1306
1307    if (compareSuccess == 0) {
1308        // refresh our searchStr var.
1309        searchStr = units;
1310    }
1311
1312    // pass 2: capitolize the first letter of the search string and compare
1313    //          for each letter in the string
1314    while ( ! compareSuccess &&
1315            (searchStr.length() > 0) ) {
1316
1317        if (islower((int)(searchStr[0]))) {
1318            searchStr[0] = (char) toupper((int)(searchStr[0]));
1319        }
1320
1321        // dict pointer
1322        if (dict->find(searchStr) == dict->getNullEntry()) {
1323            // the string was not found,
1324            // keep incrementing the pointer
1325            // searchStr (pass2)  does not match
1326        }
1327        else {
1328            // compare was successful,
1329            // searchStr (pass2)  found a match
1330            compareSuccess++;
1331            break;
1332        }
1333        searchStr.erase(0,1);
1334
1335        // check to see if we are at the basis.
1336        if (basis) {
1337            if ( (searchStr == basis->getUnits()) &&
1338                 (searchStr.length() == basis->getUnits().length()) )
1339            {
1340                break;
1341            }
1342
1343        }
1344
1345    }
1346
1347
1348
1349    // if we found a match, find the first occurance of the string which
1350    // was used to get the match, in our original units string.
1351    // this gets dicey for capitolizations.
1352    if ( compareSuccess ) {
1353        // need to think about if we want to search from the start
1354        // or the end of the string (find or rfind)
1355        // i think its the start because in this fxn (above)
1356        // we start at the beginning of the string and work
1357        // our way to the end. so if there is a second match at the
1358        // end, we would have only seen the first match.
1359        retIndex = units.find(searchStr);
1360    }
1361
1362    return retIndex;
1363
1364}
1365
1366
1367void
1368RpUnits::connectConversion(conversion* conv) const {
1369
1370    convEntry* p = convList;
1371
1372    if (p == NULL) {
1373        convList = new convEntry (conv,NULL,NULL);
1374    }
1375    else {
1376        while (p->next != NULL) {
1377            p = p->next;
1378        }
1379
1380        p->next = new convEntry (conv,p,NULL);
1381    }
1382
1383}
1384
1385// return codes: 0 success, anything else is error
1386int
1387RpUnits::addPresets (const std::string group) {
1388    int retVal = -1;
1389    if (group.compare("all") == 0) {
1390        retVal = addPresetAll();
1391    }
1392    else if (group.compare("energy") == 0) {
1393        retVal = addPresetEnergy();
1394    }
1395    else if (group.compare("length") == 0) {
1396        retVal = addPresetLength();
1397    }
1398    else if (group.compare("temp") == 0) {
1399        retVal = addPresetTemp();
1400    }
1401    else if (group.compare("time") == 0) {
1402        retVal = addPresetTime();
1403    }
1404    else if (group.compare("volume") == 0) {
1405        retVal = addPresetTime();
1406    }
1407
1408    return retVal;
1409}
1410
1411// return codes: 0 success, anything else is error
1412int
1413RpUnits::addPresetAll () {
1414
1415    int result = 0;
1416
1417    result += addPresetTime();
1418    result += addPresetTemp();
1419    result += addPresetLength();
1420    result += addPresetEnergy();
1421    result += addPresetVolume();
1422
1423    return 0;
1424}
1425
1426// return codes: 0 success, anything else is error
1427int
1428RpUnits::addPresetTime () {
1429
1430    RpUnits* seconds    = RpUnits::define("s", NULL);
1431
1432    RpUnits::makeMetric(seconds);
1433
1434    // add time definitions
1435
1436    return 0;
1437}
1438
1439// return codes: 0 success, anything else is error
1440int
1441RpUnits::addPresetTemp () {
1442
1443    RpUnits* fahrenheit = RpUnits::define("F", NULL);
1444    RpUnits* celcius    = RpUnits::define("C", NULL);
1445    RpUnits* kelvin     = RpUnits::define("K", NULL);
1446    RpUnits* rankine    = RpUnits::define("R", NULL);
1447
1448    // add temperature definitions
1449    RpUnits::define(fahrenheit, celcius, fahrenheit2centigrade, centigrade2fahrenheit);
1450    RpUnits::define(celcius, kelvin, centigrade2kelvin, kelvin2centigrade);
1451    RpUnits::define(fahrenheit, kelvin, fahrenheit2kelvin, kelvin2fahrenheit);
1452    RpUnits::define(rankine, kelvin, rankine2kelvin, kelvin2rankine);
1453
1454    return 0;
1455}
1456
1457// return codes: 0 success, anything else is error
1458int
1459RpUnits::addPresetLength () {
1460
1461    RpUnits* meters     = RpUnits::define("m", NULL);
1462    RpUnits* angstrom   = RpUnits::define("A", NULL);
1463    RpUnits* inch       = RpUnits::define("in", NULL);
1464    RpUnits* feet       = RpUnits::define("ft", NULL);
1465    RpUnits* yard       = RpUnits::define("yd", NULL);
1466
1467    RpUnits::makeMetric(meters);
1468
1469    // add length definitions
1470    RpUnits::define(angstrom, meters, angstrom2meter, meter2angstrom);
1471    RpUnits::define(inch, meters, inch2meter, meter2inch);
1472    RpUnits::define(feet, meters, feet2meter, meter2feet);
1473    RpUnits::define(yard, meters, yard2meter, meter2yard);
1474
1475    return 0;
1476}
1477
1478// return codes: 0 success, anything else is error
1479int
1480RpUnits::addPresetEnergy () {
1481
1482    RpUnits* volt       = RpUnits::define("V", NULL);
1483    RpUnits* eVolt      = RpUnits::define("eV", NULL);
1484    RpUnits* joule      = RpUnits::define("J", NULL);
1485
1486    RpUnits::makeMetric(volt);
1487    RpUnits::makeMetric(eVolt);
1488    RpUnits::makeMetric(joule);
1489
1490    // add energy definitions
1491    RpUnits::define(eVolt,joule,electronVolt2joule,joule2electronVolt);
1492
1493    return 0;
1494}
1495
1496// return codes: 0 success, anything else is error
1497int
1498RpUnits::addPresetVolume () {
1499
1500    RpUnits* cubic_meter  = RpUnits::define("m3", NULL);
1501    RpUnits* cubic_feet   = RpUnits::define("ft3", NULL);
1502    RpUnits* us_gallon    = RpUnits::define("gal", NULL);
1503
1504    RpUnits::makeMetric(cubic_meter);
1505
1506    // add energy definitions
1507    RpUnits::define(cubic_meter,cubic_feet,meter2feet,feet2meter);
1508    RpUnits::define(cubic_meter,us_gallon,cubicMeter2usGallon,usGallon2cubicMeter);
1509    RpUnits::define(cubic_feet,us_gallon,cubicFeet2usGallon,usGallon2cubicFeet);
1510
1511    return 0;
1512}
1513
1514// -------------------------------------------------------------------- //
1515
Note: See TracBrowser for help on using the repository browser.