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

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

fixed the python rpunits setup script so now it really finds PyRpUnits?.cc

added more conversions to RpUnitsStd?.[h,cc]

added static convert function to RpUnits.[h,cc] so now users can ask for a
conversion as without having to make an RpUnits Object. instead, the
user specifies the value to be converted (value with attached units) as well
as the units we should convert to and if they want units in the returned
string. if the units exist, the conversion is done, if not, the original
string should be returned.

also added the ability to load preset units into the dictionary.
use the static function RpUnits::addPresets(...) in c++ this is done
automatically in python (although, maybe it shouldn't be).

  • Property svn:executable set to *
File size: 14.8 KB
Line 
1#include <iostream>
2#include <string>
3#include <sstream>
4#include <stdlib.h>
5#include <errno.h>
6
7#ifndef _RpDICT_H
8    #include "RpDict.h"
9#endif
10
11#include "RpUnitsStd.h"
12
13#ifndef _RpUNITS_H
14#define _RpUNITS_H
15
16class RpUnits;
17
18class unit
19{
20
21    public:
22
23        const std::string getUnits(){ return units; };
24        double getExponent() {return exponent;};
25        RpUnits * getBasis() {return basis;};
26
27        friend class RpUnits;
28
29    private:
30        const std::string units;
31        double exponent;
32        // RpUnits* basis[4];
33        RpUnits* basis;
34
35        unit* prev;
36        unit* next;
37
38        unit (
39                const std::string& units,
40                double&            exponent,
41                // RpUnits**           basis,
42                RpUnits*           basis,
43                unit*              next
44             )
45            :   units    (units),
46                exponent (exponent),
47                basis    (basis),
48                prev     (NULL),
49                next     (next)
50            { };
51
52
53        void newExponent(double newExponent) {exponent = newExponent;};
54
55
56};
57
58// simple class to hold info about a conversion.
59// holds where we are converting from
60// holds where we are converting to
61// hold the pointer to a function to do the forward conversion (from->to)
62// hold the pointer to a function to do the backward conversion (to->from)
63//
64class conversion
65{
66    public:
67
68        const RpUnits* getFrom()    { return (const RpUnits*) fromPtr; };
69        const RpUnits* getTo()      { return (const RpUnits*) toPtr; };
70       
71        friend class RpUnits;
72
73    private:
74
75        RpUnits* fromPtr;
76        RpUnits* toPtr;
77        double (*convForwFxnPtr)(double);
78        double (*convBackFxnPtr)(double);
79        void* (*convForwFxnPtrVoid)(void*, void*);
80        void* convForwData;
81        void* (*convBackFxnPtrVoid)(void*, void*);
82        void* convBackData;
83
84        conversion* prev;
85        conversion* next;
86
87        // constructor
88        // private because i only want RpUnits to be able to
89        // create a conversion
90        conversion (
91                RpUnits* fromPtr,
92                RpUnits* toPtr,
93                double (*convForwFxnPtr)(double),
94                double (*convBackFxnPtr)(double),
95                conversion* prev,
96                conversion* next
97             )
98            :   fromPtr             (fromPtr),
99                toPtr               (toPtr),
100                convForwFxnPtr      (convForwFxnPtr),
101                convBackFxnPtr      (convBackFxnPtr),
102                convForwFxnPtrVoid  (NULL),
103                convForwData        (NULL),
104                convBackFxnPtrVoid  (NULL),
105                convBackData        (NULL),
106                prev                (prev),
107                next                (next)
108            {
109            };
110
111        conversion (
112                RpUnits* fromPtr,
113                RpUnits* toPtr,
114                void* (*convForwFxnPtrVoid)(void*, void*),
115                void* convForwData,
116                void* (*convBackFxnPtrVoid)(void*, void*),
117                void* convBackData,
118                conversion* prev,
119                conversion* next
120             )
121            :   fromPtr             (fromPtr),
122                toPtr               (toPtr),
123                convForwFxnPtr      (NULL),
124                convBackFxnPtr      (NULL),
125                convForwFxnPtrVoid  (convForwFxnPtrVoid),
126                convForwData        (convForwData),
127                convBackFxnPtrVoid  (convBackFxnPtrVoid),
128                convBackData        (convBackData),
129                prev                (prev),
130                next                (next)
131            {
132            };
133
134        // copy constructor
135
136        // destructor
137};
138
139// used by the RpUnits class to create a linked list of the conversions
140// associated with the specific unit.
141//
142// we could templitize this and make a generic linked list
143// or could use generic linked list class from book programming with objects
144//
145class convEntry
146{
147
148    public:
149
150        friend class RpUnits;
151
152    private:
153
154        conversion* conv;
155        convEntry*  prev;
156        convEntry*  next;
157
158        convEntry (
159                conversion* conv,
160                convEntry*  prev,
161                convEntry*  next
162             )
163            :   conv    (conv),
164                prev    (prev),
165                next    (next)
166            { };
167
168        /*
169        ~convEntry()
170        {
171
172        }
173        */
174};
175
176class RpUnits
177{
178    /*
179     * helpful units site
180     * http://aurora.regenstrief.org/~gunther/units.html
181     */
182
183    public:
184       
185        // users member fxns
186        std::string getUnits();
187        std::string getUnitsName();
188        double getExponent();
189        RpUnits* getBasis();
190
191        // convert from one RpUnits to another if the conversion is defined
192        double convert(RpUnits* toUnits, double val, int* result = NULL);
193        // convert from one RpUnits to another if the conversion is defined
194        void* convert(RpUnits* toUnits, void* val, int* result = NULL);
195        // convert from one RpUnits to another if the conversion is defined
196        double convert(std::string, double val);
197        // convert from one RpUnits to another if the conversion is defined
198        std::string convert (   RpUnits* toUnits,
199                                double val,
200                                int showUnits = 0,
201                                int* result = NULL  );
202
203        static std::string convert ( std::string val,
204                                     std::string toUnits,
205                                     int showUnits,
206                                     int* result = NULL );
207
208        // dictionary to store the units.
209        // static RpDict<std::string,RpUnits> dict;
210
211        // turn the current unit to the metric system
212        // this should only be used for units that are part of the
213        // metric system. doesnt deal with exponents, just prefixes
214        double makeBasis(double value, int* result = NULL);
215        RpUnits & makeBasis(double* value, int* result = NULL);
216       
217        static int makeMetric(RpUnits * basis);
218
219        // find an RpUnits object that should exist in RpUnitsTable
220        // returns 0 on success (object was found)
221        // returns !0 on failure (object not found)
222        static RpUnits* find(std::string key)
223        {
224            // dict.find seems to return a (RpUnits* const) so i had to
225            // cast it as a (RpUnits*)
226
227            // dict pointer
228             // RpUnits* unitEntry = (RpUnits*) *(dict.find(key).getValue());
229             RpUnits* unitEntry = (RpUnits*) *(dict->find(key).getValue());
230
231            // RpUnits* unitEntry = (RpUnits*) dEntr.getValue();
232
233            // dict pointer
234            // if (unitEntry == (RpUnits*)dict.getNullEntry().getValue()) {
235            if (unitEntry == (RpUnits*)dict->getNullEntry().getValue()) {
236                unitEntry = NULL;
237            }
238
239            return unitEntry;
240        };
241
242        // user calls define to add a RpUnits object or to add a relation rule
243        //
244        // add RpUnits Object
245        static RpUnits * define(const std::string units, RpUnits * basis);
246        //
247        // add relation rule
248
249        static RpUnits * define(RpUnits* from,
250                                RpUnits* to,
251                                double (*convForwFxnPtr)(double),
252                                double (*convBackFxnPtr)(double));
253
254        static RpUnits * define(RpUnits* from,
255                                RpUnits* to,
256                                void* (*convForwFxnPtr)(void*, void*),
257                                void* convForwData,
258                                void* (*convBackFxnPtr)(void*, void*),
259                                void* convBackData);
260
261        // populate the dictionary with a set of units specified by group
262        // if group equals......................then load................
263        //      "all"                       load all available units
264        //      "energy"                    load units related to length
265        //      "length"                    load units related to length
266        //      "temp"                      load units related to temperature
267        //      "time"                      load units related to time
268        //  (no other groups have been created)
269
270        static int addPresets (std::string group);
271
272        // undefining a relation rule is probably not needed
273        // int undefine(); // delete a relation
274
275        // convert fxn will be taken care of in the RpUnitsConversion class
276        // i think
277        // int convert(const char* from, const char* to);
278
279        // why are these functions friends...
280        // probably need to find a better way to let RpUnits
281        // use the RpDict and RpDictEntry fxns
282        friend class RpDict<std::string,RpUnits*>;
283        friend class RpDictEntry<std::string,RpUnits*>;
284
285        // copy constructor
286        RpUnits ( const RpUnits& myRpUnit )
287        {
288
289            /*
290            from = myRpUnit.from;
291            to = myRpUnit.to;
292            convertForw = myRpUnit.convertForw;
293            convertBack = myRpUnit.convertBack;
294            */
295
296            // copy constructor for unit
297            unit* tmp = NULL;
298            unit* newUnit = NULL;
299            unit* p = myRpUnit.head;
300
301            while (p != NULL) {
302                newUnit = new unit(p->units, p->exponent,p->basis,NULL);
303
304                newUnit->prev = tmp;
305                if (tmp) {
306                    tmp->next = newUnit;
307                }
308
309                tmp = newUnit;
310                p = p->next;
311            }
312
313            if (tmp) {
314                while (tmp->prev != NULL) {
315                   tmp = tmp->prev;
316                }
317            }
318
319            head = tmp;
320               
321        };
322
323    private:
324
325        // i hope to replace these vars with a small class representing a
326        // of a linked list of units. that way we can handle complex units.
327        // this will also require that we move the getUnits, getExponent,
328        // and getBasis, makeBasis functionality into the smaller class,
329        // that represents each part of the units. we should keep getUnits,
330        // getBasis, and makeBasis in this class, but modify them to go
331        // through the linked list of units and combine the units back into
332        // what the caller expects to see.
333        // ie. cm2/Vms (mobility), will be split into the objects cm2, V, ms
334        // when getUnits is called, the user should see cm2/Vms again.
335        // for basis, possibly let the user choose a basis, and for makeBasis
336        // move through the linked list, only converting the metric elements.
337        //
338       
339        // used by the RpUnits when defining units elements
340        unit* head;
341
342        // linked list of units this RpUnit can convert to
343        convEntry* convList;
344
345        // used by the RpUnits when defining conversion elements
346        conversion* conv;
347
348        // dictionary to store the units.
349        // dict pointer
350        // static RpDict<std::string,RpUnits*> dict;
351        static RpDict<std::string,RpUnits*>* dict;
352
353        // create a units element
354        // class takes in three pieces of info
355        // 1) string describing the units
356        // 2) double describing the exponent
357        // 3) pointer to RpUnits object describing the basis
358        //      of the units (the fundamental unit)
359        //
360        RpUnits (
361                    const std::string& units,
362                    double& exponent,
363                    // RpUnits* basis[]
364                    RpUnits* basis
365                )
366            :   head        ( new unit( units, exponent, basis, NULL) ),
367                convList    (NULL),
368                conv        (NULL)
369        {};
370
371        // create a conversion element
372
373        RpUnits (
374                    RpUnits* from,
375                    RpUnits* to,
376                    double (*convForwFxnPtr)(double),
377                    double (*convBackFxnPtr)(double),
378                    conversion* prev,
379                    conversion* next
380                )
381            :   head (NULL),
382                convList (NULL),
383                conv (new conversion
384                        (from,to,convForwFxnPtr,convBackFxnPtr,prev,next))
385        {
386            connectConversion(from);
387            connectConversion(to);
388        };
389
390        RpUnits (
391                    RpUnits* from,
392                    RpUnits* to,
393                    void* (*convForwFxnPtr)(void*, void*),
394                    void* convForwData,
395                    void* (*convBackFxnPtr)(void*, void*),
396                    void* convBackData,
397                    conversion* prev,
398                    conversion* next
399                )
400            :   head (NULL),
401                convList (NULL),
402                conv (new conversion (  from, to,
403                                        convForwFxnPtr, convForwData,
404                                        convBackFxnPtr, convBackData,
405                                        prev, next
406                                     )
407                     )
408        {
409            connectConversion(from);
410            connectConversion(to);
411        };
412
413        // default destructor
414        //
415        //~RpUnits ();
416        ~RpUnits ()
417        {
418            // clean up dynamic memory
419
420            unit* p = head;
421            while (p != NULL) {
422                unit* tmp = p;
423                p = p->next;
424                delete tmp;
425            }
426        }
427
428        void RpUnits::connectConversion(RpUnits* myRpUnit);
429
430        void RpUnits::fillMetricMap();
431
432        // create the container keeping track of defined units
433        // returns 0 on success (table created or already exists)
434        // returns !0 on failure (table not created or cannot exist)
435        int RpUnits::createUnitsTable();
436
437        // insert new RpUnits object into RpUnitsTable
438        // returns 0 on success (object inserted or already exists)
439        // returns !0 on failure (object cannot be inserted or dne)
440        int RpUnits::insert(std::string key);   
441
442        // link two RpUnits objects that already exist in RpUnitsTable
443        // returns 0 on success (linking within table was successful)
444        // returns !0 on failure (linking was not successful)
445        int RpUnits::link(RpUnits * unitA);
446
447
448        static int pre_compare( std::string& units, RpUnits* basis = NULL);
449        void addUnit( const std::string& units,
450                      double &  exponent,
451                      RpUnits * basis
452                     );
453
454        static int addPresetAll();
455        static int addPresetEnergy();
456        static int addPresetLength();
457        static int addPresetTemp();
458        static int addPresetTime();
459
460
461};
462
463/*--------------------------------------------------------------------------*/
464/*--------------------------------------------------------------------------*/
465
466// #include "../src/RpUnits.cc"
467
468#endif
Note: See TracBrowser for help on using the repository browser.