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
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
39
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
49class RpUnits;
50
51class RpUnitsPreset {
52    public:
53        RpUnitsPreset () {
54            addPresetAll();
55        };
56
57        static int addPresetAll();
58        static int addPresetEnergy();
59        static int addPresetLength();
60        static int addPresetTemp();
61        static int addPresetTime();
62        static int addPresetVolume();
63        static int addPresetAngle();
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)
71//
72class conversion
73{
74    public:
75
76        const RpUnits* getFrom()    { return (const RpUnits*) fromPtr; };
77        const RpUnits* getTo()      { return (const RpUnits*) toPtr; };
78
79        friend class RpUnits;
80
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
115    private:
116
117        const RpUnits* fromPtr;
118        const RpUnits* toPtr;
119        double (*convForwFxnPtr)(double);
120        double (*convBackFxnPtr)(double);
121        double (*convForwFxnPtrDD)(double,double);
122        double (*convBackFxnPtrDD)(double,double);
123        void* (*convForwFxnPtrVoid)(void*, void*);
124        void* convForwData;
125        void* (*convBackFxnPtrVoid)(void*, void*);
126        void* convBackData;
127
128        // constructor
129        // private because i only want RpUnits to be able to
130        // create a conversion
131        conversion (
132                const RpUnits* fromPtr,
133                const RpUnits* toPtr,
134                double (*convForwFxnPtr)(double),
135                double (*convBackFxnPtr)(double)
136             )
137            :   fromPtr             (fromPtr),
138                toPtr               (toPtr),
139                convForwFxnPtr      (convForwFxnPtr),
140                convBackFxnPtr      (convBackFxnPtr),
141                convForwFxnPtrDD    (NULL),
142                convBackFxnPtrDD    (NULL),
143                convForwFxnPtrVoid  (NULL),
144                convForwData        (NULL),
145                convBackFxnPtrVoid  (NULL),
146                convBackData        (NULL)
147            {};
148
149        // constructor for 2 argument conversion functions
150        conversion (
151                const RpUnits* fromPtr,
152                const RpUnits* toPtr,
153                double (*convForwFxnPtr)(double,double),
154                double (*convBackFxnPtr)(double,double)
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),
165                convBackData        (NULL)
166            {};
167
168        // constructor for user defined void* returning 1 arg conversion fxns.
169        // the 1 arg is a user defined void* object
170        conversion (
171                const RpUnits* fromPtr,
172                const RpUnits* toPtr,
173                void* (*convForwFxnPtrVoid)(void*, void*),
174                void* convForwData,
175                void* (*convBackFxnPtrVoid)(void*, void*),
176                void* convBackData
177             )
178            :   fromPtr             (fromPtr),
179                toPtr               (toPtr),
180                convForwFxnPtr      (NULL),
181                convBackFxnPtr      (NULL),
182                convForwFxnPtrDD    (NULL),
183                convBackFxnPtrDD    (NULL),
184                convForwFxnPtrVoid  (convForwFxnPtrVoid),
185                convForwData        (convForwData),
186                convBackFxnPtrVoid  (convBackFxnPtrVoid),
187                convBackData        (convBackData)
188            {};
189
190};
191
192// used by the RpUnits class to create a linked list of the conversions
193// associated with the specific unit.
194//
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
205        virtual ~convEntry()
206        {}
207
208    private:
209
210        conversion* conv;
211        convEntry*  prev;
212        convEntry*  next;
213
214        convEntry (
215                conversion* conv,
216                convEntry*  prev,
217                convEntry*  next
218             )
219            :   conv    (conv),
220                prev    (prev),
221                next    (next)
222            {};
223
224};
225
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
275class RpUnits
276{
277    /*
278     * helpful units site
279     * http://aurora.regenstrief.org/~gunther/units.html
280     * http://www.nodc.noaa.gov/dsdt/ucg/
281     * http://www.cellml.org/meeting_minutes/archive/
282     *        20010110_meeting_minutes.html
283     */
284
285    public:
286
287        // users member fxns
288        std::string getUnits() const;
289        std::string getUnitsName() const;
290        double getExponent() const;
291        const RpUnits* getBasis() const;
292
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
300        // convert from one RpUnits to another if the conversion is defined
301        double convert(         const RpUnits* toUnits,
302                                double val,
303                                int* result=NULL    ) const;
304        // convert from one RpUnits to another if the conversion is defined
305        void* convert(          const RpUnits* toUnits,
306                                void* val,
307                                int* result=NULL) const;
308        // convert from one RpUnits to another if the conversion is defined
309        // double convert(std::string, double val);
310        // convert from one RpUnits to another if the conversion is defined
311        std::string convert (   const RpUnits* toUnits,
312                                double val,
313                                int showUnits = 0,
314                                int* result = NULL  ) const;
315
316        static std::string convert ( std::string val,
317                                     std::string toUnits,
318                                     int showUnits,
319                                     int* result = NULL );
320
321        /*
322        static std::string convert ( std::string val,
323                                     std::string toUnits,
324                                     int showUnits,
325                                     int* result = NULL );
326        */
327
328        // turn the current unit to the metric system
329        // this should only be used for units that are part of the
330        // metric system. doesnt deal with exponents, just prefixes
331        double makeBasis(double value, int* result = NULL) const;
332        const RpUnits & makeBasis(double* value, int* result = NULL) const;
333
334        static int makeMetric(const RpUnits * basis);
335
336        // find a RpUnits object that should exist in RpUnitsTable
337        // returns 0 on success (object was found)
338        // returns !0 on failure (object not found)
339        static const RpUnits* find(std::string key);
340
341        // user calls define to add a RpUnits object or to add a relation rule
342        //
343        // add RpUnits Object
344        static RpUnits * define(const std::string units,
345                                const RpUnits* basis=NULL,
346                                const std::string type=""   );
347
348        // add relation rule
349
350        static RpUnits * define(const RpUnits* from,
351                                const RpUnits* to,
352                                double (*convForwFxnPtr)(double),
353                                double (*convBackFxnPtr)(double));
354
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,
362                                void* (*convForwFxnPtr)(void*, void*),
363                                void* convForwData,
364                                void* (*convBackFxnPtr)(void*, void*),
365                                void* convBackData);
366
367
368        // populate the dictionary with a set of units specified by group
369        // if group equals......................then load................
370        //      "all"                       load all available units
371        //      "energy"                    load units related to energy
372        //      "length"                    load units related to length
373        //      "temp"                      load units related to temperature
374        //      "time"                      load units related to time
375        //      "volume"                    load units related to volume
376        //      "angle"                     load units related to angles
377        //  (no other groups have been created)
378
379        static int addPresets (const std::string group);
380
381        // undefining a relation rule is probably not needed
382        // int undefine(); // delete a relation
383
384        // why are these functions friends...
385        // probably need to find a better way to let RpUnits
386        // use the RpDict and RpDictEntry fxns
387        friend class RpDict<std::string,RpUnits*>;
388        friend class RpDictEntry<std::string,RpUnits*>;
389
390        friend int insert(std::string key,RpUnits* val);
391
392
393        // copy constructor
394        RpUnits (RpUnits &other)
395            : units    (other.units),
396              exponent (other.exponent),
397              basis    (other.basis),
398              type     (other.type),
399              convList (NULL)
400        {
401            convEntry* q = NULL;
402            convEntry* curr = NULL;
403
404            dict = other.dict;
405
406            if (other.convList) {
407                q = other.convList;
408                convList = new convEntry (q->conv,NULL,NULL);
409                curr = convList;
410                while (q->next) {
411                    q = q->next;
412                    curr->next = new convEntry (q->conv,curr,NULL);
413                    curr = curr->next;
414                }
415            }
416        }
417
418        // copy assignment operator
419        RpUnits& operator= (const RpUnits& other) {
420
421            convEntry* q = NULL;
422            convEntry* curr = NULL;
423
424            if ( this != &other ) {
425                delete convList;
426            }
427
428            dict = other.dict;
429            units = other.units;
430            exponent = other.exponent;
431            basis = other.basis;
432            type = other.type;
433
434            if (other.convList) {
435                q = other.convList;
436                convList = new convEntry (q->conv,NULL,NULL);
437                curr = convList;
438                while (q->next) {
439                    q = q->next;
440                    curr->next = new convEntry (q->conv,curr,NULL);
441                    curr = curr->next;
442                }
443            }
444
445            return *this;
446        }
447
448        // default destructor
449        //
450        ~RpUnits ()
451        {
452            // go to the type list and remove a variable by this name
453
454
455            // clean up dynamic memory
456
457            convEntry* p = convList;
458            convEntry* tmp = p;
459
460            while (p != NULL) {
461                tmp = p;
462                p = p->next;
463                delete tmp;
464            }
465        }
466
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        //
482
483        std::string units;
484        double exponent;
485        const RpUnits* basis;
486        std::string type;
487
488        // linked list of units this RpUnit can convert to
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;
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        //
505
506        RpUnits (
507                    const std::string& units,
508                    double& exponent,
509                    const RpUnits* basis,
510                    const std::string type
511                )
512            :   units       (units),
513                exponent    (exponent),
514                basis       (basis),
515                type        (type),
516                convList    (NULL)
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)
522        // int RpUnits::insert(std::string key) const;
523
524        typedef std::list<LIST_TEMPLATE> RpUnitsList;
525        typedef RpUnitsList::iterator RpUnitsListIter;
526
527        void newExponent(double newExponent) {exponent = newExponent;};
528
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);
536
537        static int RpUnits::compareListEntryBasis( RpUnitsList& fromList,
538                                                   RpUnitsListIter& fromIter,
539                                                   RpUnitsListIter& toIter);
540
541        static int RpUnits::compareListEntrySearch( RpUnitsList& fromList,
542                                                    RpUnitsListIter& fromIter,
543                                                    RpUnitsListIter& toIter);
544
545        void RpUnits::connectConversion(conversion* conv) const;
546
547};
548
549/*--------------------------------------------------------------------------*/
550/*--------------------------------------------------------------------------*/
551
552#endif
Note: See TracBrowser for help on using the repository browser.