source: trunk/include/core/RpUnits.h @ 382

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

added angle conversions (rad,deg,grad)

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