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

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

adding new core units function getType() and getCompatible()
adding new tcl bindings related to getType() and getCompatible()
adjusted test files for testing.

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