source: trunk/src/core/RpUnits.h @ 525

Last change on this file since 525 was 525, checked in by dkearney, 18 years ago

added new pressure units pascal, bar, torr, mmHg, psi, atm. rewrote some of the test cases for units.

  • Property svn:executable set to *
File size: 19.7 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpUnits.h - Header file for Rappture Units
4 *
5 *   RpUnits Class Declaration / Definition
6 *
7 * ======================================================================
8 *  AUTHOR:  Derrick Kearney, Purdue University
9 *  Copyright (c) 2004-2005  Purdue Research Foundation
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15#include <iostream>
16#include <string>
17#include <list>
18#include <sstream>
19#include <stdlib.h>
20#include <errno.h>
21#include <math.h>
22
23#include "RpDict.h"
24#include "RpUnitsStd.h"
25
26#ifndef _RpUNITS_H
27#define _RpUNITS_H
28
29#define LIST_TEMPLATE RpUnitsListEntry
30
31//define our different types of units
32#define RP_TYPE_ENERGY      "energy"
33#define RP_TYPE_LENGTH      "length"
34#define RP_TYPE_TEMP        "temperature"
35#define RP_TYPE_TIME        "time"
36#define RP_TYPE_VOLUME      "volume"
37#define RP_TYPE_ANGLE       "angle"
38#define RP_TYPE_MASS        "mass"
39#define RP_TYPE_PRESSURE    "pressure"
40#define RP_TYPE_MISC        "misc"
41
42// should the define function:
43// 1. compare portions of inStr to unit names that have previously
44//    been defined (you must parse in order for this option to work)
45#define COMPARE_MASK    1
46// 2. create a unit if no unit by the name exists.
47#define CREATE_MASK     2
48// 3. parse the unit name to try to find previously defined units.
49#define PARSE_MASK      4
50
51class RpUnits;
52
53class RpUnitsPreset {
54    public:
55        RpUnitsPreset () {
56            addPresetAll();
57        };
58
59        static int addPresetAll();
60        static int addPresetEnergy();
61        static int addPresetLength();
62        static int addPresetTemp();
63        static int addPresetTime();
64        static int addPresetVolume();
65        static int addPresetAngle();
66        static int addPresetMass();
67        static int addPresetPressure();
68        static int addPresetMisc();
69};
70
71// simple class to hold info about a conversion.
72// holds where we are converting from
73// holds where we are converting to
74// hold the pointer to a function to do the forward conversion (from->to)
75// hold the pointer to a function to do the backward conversion (to->from)
76//
77class conversion
78{
79    public:
80
81        const RpUnits* getFrom()    { return (const RpUnits*) fromPtr; };
82        const RpUnits* getTo()      { return (const RpUnits*) toPtr; };
83
84        friend class RpUnits;
85
86        // copy constructor
87        conversion ( conversion& other)
88            :   fromPtr             (other.fromPtr),
89                toPtr               (other.toPtr),
90                convForwFxnPtr      (other.convForwFxnPtr),
91                convBackFxnPtr      (other.convBackFxnPtr),
92                convForwFxnPtrDD    (other.convForwFxnPtrDD),
93                convBackFxnPtrDD    (other.convBackFxnPtrDD),
94                convForwFxnPtrVoid  (other.convForwFxnPtrVoid),
95                convForwData        (other.convForwData),
96                convBackFxnPtrVoid  (other.convBackFxnPtrVoid),
97                convBackData        (other.convBackData)
98            {};
99
100        // copy assignment operator
101        conversion& operator= ( conversion& other )
102            {
103                fromPtr             = other.fromPtr;
104                toPtr               = other.toPtr;
105                convForwFxnPtr      = other.convForwFxnPtr;
106                convBackFxnPtr      = other.convBackFxnPtr;
107                convForwFxnPtrDD    = other.convForwFxnPtrDD;
108                convBackFxnPtrDD    = other.convBackFxnPtrDD;
109                convForwFxnPtrVoid  = other.convForwFxnPtrVoid;
110                convForwData        = other.convForwData;
111                convBackFxnPtrVoid  = other.convBackFxnPtrVoid;
112                convBackData        = other.convBackData;
113                return *this;
114            }
115
116        // default destructor
117        virtual ~conversion ()
118        {}
119
120    private:
121
122        const RpUnits* fromPtr;
123        const RpUnits* toPtr;
124        double (*convForwFxnPtr)(double);
125        double (*convBackFxnPtr)(double);
126        double (*convForwFxnPtrDD)(double,double);
127        double (*convBackFxnPtrDD)(double,double);
128        void* (*convForwFxnPtrVoid)(void*, void*);
129        void* convForwData;
130        void* (*convBackFxnPtrVoid)(void*, void*);
131        void* convBackData;
132
133        // constructor
134        // private because i only want RpUnits to be able to
135        // create a conversion
136        conversion (
137                const RpUnits* fromPtr,
138                const RpUnits* toPtr,
139                double (*convForwFxnPtr)(double),
140                double (*convBackFxnPtr)(double)
141             )
142            :   fromPtr             (fromPtr),
143                toPtr               (toPtr),
144                convForwFxnPtr      (convForwFxnPtr),
145                convBackFxnPtr      (convBackFxnPtr),
146                convForwFxnPtrDD    (NULL),
147                convBackFxnPtrDD    (NULL),
148                convForwFxnPtrVoid  (NULL),
149                convForwData        (NULL),
150                convBackFxnPtrVoid  (NULL),
151                convBackData        (NULL)
152            {};
153
154        // constructor for 2 argument conversion functions
155        conversion (
156                const RpUnits* fromPtr,
157                const RpUnits* toPtr,
158                double (*convForwFxnPtr)(double,double),
159                double (*convBackFxnPtr)(double,double)
160             )
161            :   fromPtr             (fromPtr),
162                toPtr               (toPtr),
163                convForwFxnPtr      (NULL),
164                convBackFxnPtr      (NULL),
165                convForwFxnPtrDD    (convForwFxnPtr),
166                convBackFxnPtrDD    (convBackFxnPtr),
167                convForwFxnPtrVoid  (NULL),
168                convForwData        (NULL),
169                convBackFxnPtrVoid  (NULL),
170                convBackData        (NULL)
171            {};
172
173        // constructor for user defined void* returning 1 arg conversion fxns.
174        // the 1 arg is a user defined void* object
175        conversion (
176                const RpUnits* fromPtr,
177                const RpUnits* toPtr,
178                void* (*convForwFxnPtrVoid)(void*, void*),
179                void* convForwData,
180                void* (*convBackFxnPtrVoid)(void*, void*),
181                void* convBackData
182             )
183            :   fromPtr             (fromPtr),
184                toPtr               (toPtr),
185                convForwFxnPtr      (NULL),
186                convBackFxnPtr      (NULL),
187                convForwFxnPtrDD    (NULL),
188                convBackFxnPtrDD    (NULL),
189                convForwFxnPtrVoid  (convForwFxnPtrVoid),
190                convForwData        (convForwData),
191                convBackFxnPtrVoid  (convBackFxnPtrVoid),
192                convBackData        (convBackData)
193            {};
194
195};
196
197// used by the RpUnits class to create a linked list of the conversions
198// associated with the specific unit.
199//
200// we could templitize this and make a generic linked list
201// or could use generic linked list class from book programming with objects
202//
203class convEntry
204{
205
206    public:
207
208        friend class RpUnits;
209
210        virtual ~convEntry()
211        {}
212
213    private:
214
215        conversion* conv;
216        convEntry*  prev;
217        convEntry*  next;
218
219        convEntry (
220                conversion* conv,
221                convEntry*  prev,
222                convEntry*  next
223             )
224            :   conv    (conv),
225                prev    (prev),
226                next    (next)
227            {};
228
229};
230
231class RpUnitsListEntry
232{
233
234    public:
235
236        // constructor
237        RpUnitsListEntry (const RpUnits* unit, double exponent)
238            : unit     (unit),
239              exponent (exponent)
240        {};
241
242        // copy constructor
243        RpUnitsListEntry (const RpUnitsListEntry& other)
244            : unit     (other.unit),
245              exponent (other.exponent)
246        {};
247
248        // copy assignment operator
249        RpUnitsListEntry& operator= (const RpUnitsListEntry& other) {
250            unit = other.unit;
251            exponent = other.exponent;
252            return *this;
253        }
254
255        // negate the exponent
256        void negateExponent() const;
257
258        // print the name of the object
259        std::string name() const;
260
261        // report the basis of the RpUnits object being stored.
262        const RpUnits* getBasis() const;
263
264        // return the RpUnits*
265        const RpUnits* getUnitsObj() const;
266
267        // return the exponent
268        double getExponent() const;
269
270        // destructor
271        virtual ~RpUnitsListEntry ()
272        {}
273
274    private:
275
276        const RpUnits* unit;
277        mutable double exponent;
278};
279
280class RpUnits
281{
282    /*
283     * helpful units site
284     * http://aurora.regenstrief.org/~gunther/units.html
285     * http://www.nodc.noaa.gov/dsdt/ucg/
286     * http://www.cellml.org/meeting_minutes/archive/
287     *        20010110_meeting_minutes.html
288     */
289
290    public:
291
292        // constant static class variables
293        // flags to tell how convert should return the value
294        static const int UNITS_OFF;
295        static const int UNITS_ON;
296
297        // users member fxns
298        std::string getUnits() const;
299        std::string getUnitsName() const;
300        double getExponent() const;
301        const RpUnits* getBasis() const;
302
303        // retrieve a units type.
304        std::string getType() const;
305
306        // retrieve a list of compatible units.
307        std::list<std::string> getCompatible(double expMultiplier=1.0) const;
308
309
310        // convert from one RpUnits to another if the conversion is defined
311        double convert(         const RpUnits* toUnits,
312                                double val,
313                                int* result=NULL    ) const;
314        // convert from one RpUnits to another if the conversion is defined
315        void* convert(          const RpUnits* toUnits,
316                                void* val,
317                                int* result=NULL) const;
318        // convert from one RpUnits to another if the conversion is defined
319        // double convert(std::string, double val);
320        // convert from one RpUnits to another if the conversion is defined
321        std::string convert (   const RpUnits* toUnits,
322                                double val,
323                                int showUnits = 0,
324                                int* result = NULL  ) const;
325
326        static std::string convert ( std::string val,
327                                     std::string toUnits,
328                                     int showUnits,
329                                     int* result = NULL );
330
331        /*
332        static std::string convert ( std::string val,
333                                     std::string toUnits,
334                                     int showUnits,
335                                     int* result = NULL );
336        */
337
338        // turn the current unit to the metric system
339        // this should only be used for units that are part of the
340        // metric system. doesnt deal with exponents, just prefixes
341        double makeBasis(double value, int* result = NULL) const;
342        const RpUnits & makeBasis(double* value, int* result = NULL) const;
343
344        static int makeMetric(const RpUnits * basis);
345
346        // find a RpUnits object that should exist in RpUnitsTable
347        // returns 0 on success (object was found)
348        // returns !0 on failure (object not found)
349        static const RpUnits* find(std::string key);
350
351        // validate is very similar to find, but it works better
352        // for seeing complex units can be interpreted.
353        // it validates that if the a certain units string is
354        // provided as a unit type, then all of the base components
355        // of that unit are available for conversions.
356        // returns 0 on success (units are valid)
357        // returns !0 on failure (units not valid)
358        static int validate(const std::string& inUnits,
359                            std::string& type,
360                            std::list<std::string>* compatList=NULL);
361
362        // user calls define to add a RpUnits object or to add a relation rule
363        //
364        // add RpUnits Object
365        static RpUnits * define(const std::string units,
366                                const RpUnits* basis=NULL,
367                                const std::string type=""   );
368
369        // add relation rule
370
371        static RpUnits * define(const RpUnits* from,
372                                const RpUnits* to,
373                                double (*convForwFxnPtr)(double),
374                                double (*convBackFxnPtr)(double));
375
376        static RpUnits * define(const RpUnits* from,
377                                const RpUnits* to,
378                                double (*convForwFxnPtr)(double,double),
379                                double (*convBackFxnPtr)(double,double));
380
381        static RpUnits * define(const RpUnits* from,
382                                const RpUnits* to,
383                                void* (*convForwFxnPtr)(void*, void*),
384                                void* convForwData,
385                                void* (*convBackFxnPtr)(void*, void*),
386                                void* convBackData);
387
388
389        // populate the dictionary with a set of units specified by group
390        // if group equals......................then load................
391        //      "all"                       load all available units
392        //      "energy"                    load units related to energy
393        //      "length"                    load units related to length
394        //      "temp"                      load units related to temperature
395        //      "time"                      load units related to time
396        //      "volume"                    load units related to volume
397        //      "angle"                     load units related to angles
398        //  (no other groups have been created)
399
400        static int addPresets (const std::string group);
401
402        // undefining a relation rule is probably not needed
403        // int undefine(); // delete a relation
404
405        // why are these functions friends...
406        // probably need to find a better way to let RpUnits
407        // use the RpDict and RpDictEntry fxns
408        friend class RpDict<std::string,RpUnits*>;
409        friend class RpDictEntry<std::string,RpUnits*>;
410
411        friend int insert(std::string key,RpUnits* val);
412
413
414        // copy constructor
415        RpUnits (RpUnits &other)
416            : units    (other.units),
417              exponent (other.exponent),
418              basis    (other.basis),
419              type     (other.type),
420              convList (NULL)
421        {
422            convEntry* q = NULL;
423            convEntry* curr = NULL;
424
425            dict = other.dict;
426
427            if (other.convList) {
428                q = other.convList;
429                convList = new convEntry (q->conv,NULL,NULL);
430                curr = convList;
431                while (q->next) {
432                    q = q->next;
433                    curr->next = new convEntry (q->conv,curr,NULL);
434                    curr = curr->next;
435                }
436            }
437        }
438
439        // copy assignment operator
440        RpUnits& operator= (const RpUnits& other) {
441
442            convEntry* q = NULL;
443            convEntry* curr = NULL;
444
445            if ( this != &other ) {
446                delete convList;
447            }
448
449            dict = other.dict;
450            units = other.units;
451            exponent = other.exponent;
452            basis = other.basis;
453            type = other.type;
454
455            if (other.convList) {
456                q = other.convList;
457                convList = new convEntry (q->conv,NULL,NULL);
458                curr = convList;
459                while (q->next) {
460                    q = q->next;
461                    curr->next = new convEntry (q->conv,curr,NULL);
462                    curr = curr->next;
463                }
464            }
465
466            return *this;
467        }
468
469        // default destructor
470        //
471        ~RpUnits ()
472        {
473            // go to the type list and remove a variable by this name
474
475
476            // clean up dynamic memory
477
478            convEntry* p = convList;
479            convEntry* tmp = p;
480
481            while (p != NULL) {
482                tmp = p;
483                p = p->next;
484                delete tmp;
485            }
486        }
487
488    private:
489
490        // i hope to replace these vars with a small class representing a
491        // of a linked list of units. that way we can handle complex units.
492        // this will also require that we move the getUnits, getExponent,
493        // and getBasis, makeBasis functionality into the smaller class,
494        // that represents each part of the units. we should keep getUnits,
495        // getBasis, and makeBasis in this class, but modify them to go
496        // through the linked list of units and combine the units back into
497        // what the caller expects to see.
498        // ie. cm2/Vms (mobility), will be split into the objects cm2, V, ms
499        // when getUnits is called, the user should see cm2/Vms again.
500        // for basis, possibly let the user choose a basis, and for makeBasis
501        // move through the linked list, only converting the metric elements.
502        //
503
504        std::string units;
505        double exponent;
506        const RpUnits* basis;
507        std::string type;
508
509        // linked list of units this RpUnit can convert to
510        // its mutable because the connectConversion function takes in a
511        // const RpUnits* and attempts to change the convList variable
512        // within the RpUnits Object
513        mutable convEntry* convList;
514
515
516        // dictionary to store the units.
517        static RpDict<std::string,RpUnits*>* dict;
518
519        // create a units element
520        // class takes in three pieces of info
521        // 1) string describing the units
522        // 2) double describing the exponent
523        // 3) pointer to RpUnits object describing the basis
524        //      of the units (the fundamental unit)
525        //
526
527        RpUnits (
528                    const std::string& units,
529                    double& exponent,
530                    const RpUnits* basis,
531                    const std::string type
532                )
533            :   units       (units),
534                exponent    (exponent),
535                basis       (basis),
536                type        (type),
537                convList    (NULL)
538        {};
539
540        // insert new RpUnits object into RpUnitsTable
541        // returns 0 on success (object inserted or already exists)
542        // returns !0 on failure (object cannot be inserted or dne)
543        // int RpUnits::insert(std::string key) const;
544
545        typedef std::list<LIST_TEMPLATE> RpUnitsList;
546        typedef RpUnitsList::iterator RpUnitsListIter;
547
548        void newExponent(double newExponent) {exponent = newExponent;};
549
550        static int units2list( const std::string& inUnits,
551                               RpUnitsList& outList         );
552        static int grabExponent(const std::string& inStr, double* exp);
553        static int grabUnitString( const std::string& inStr);
554        static const RpUnits* grabUnits (std::string inStr, int* offset);
555        static int negateListExponents(RpUnitsList& unitsList);
556        static int RpUnits::printList(RpUnitsList& unitsList);
557
558        static int RpUnits::compareListEntryBasis( RpUnitsList& fromList,
559                                                   RpUnitsListIter& fromIter,
560                                                   RpUnitsListIter& toIter);
561
562        static int RpUnits::compareListEntrySearch( RpUnitsList& fromList,
563                                                    RpUnitsListIter& fromIter,
564                                                    RpUnitsListIter& toIter);
565
566        void RpUnits::connectConversion(conversion* conv) const;
567
568};
569
570/*--------------------------------------------------------------------------*/
571/*--------------------------------------------------------------------------*/
572
573#endif
Note: See TracBrowser for help on using the repository browser.