FloatT.h
Go to the documentation of this file.
00001 //-----------------------------------------------------------------------------
00002 //  (c) 2006 by Basler Vision Technologies
00003 //  Section: Vision Components
00004 //  Project: GenApi
00005 //  Author:  Alexander Happe
00006 //  $Header$
00007 //
00008 //  License: This file is published under the license of the EMVA GenICam  Standard Group.
00009 //  A text file describing the legal terms is included in  your installation as 'GenICam_license.pdf'.
00010 //  If for some reason you are missing  this file please contact the EMVA or visit the website
00011 //  (http://www.genicam.org) for a full copy.
00012 //
00013 //  THIS SOFTWARE IS PROVIDED BY THE EMVA GENICAM STANDARD GROUP "AS IS"
00014 //  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
00015 //  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00016 //  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE EMVA GENICAM STANDARD  GROUP
00017 //  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  SPECIAL,
00018 //  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT  LIMITED TO,
00019 //  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,  DATA, OR PROFITS;
00020 //  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY  THEORY OF LIABILITY,
00021 //  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)
00022 //  ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00023 //  POSSIBILITY OF SUCH DAMAGE.
00024 //-----------------------------------------------------------------------------
00031 #ifndef GENAPI_FLOATT_H
00032 #define GENAPI_FLOATT_H
00033 
00034 
00035 #include "../NodeCallback.h"
00036 #include "INodePrivate.h"
00037 #include "../Synch.h"
00038 #include "../Counter.h"
00039 #include "Value2String.h"
00040 #include "GenApi/impl/Log.h"
00041 #include <limits>
00042 #include <cmath>
00043 #include <cstdlib>
00044 #include <algorithm>
00045 #include "Exception.h"
00046 #include "AutovectorImpl.h"
00047 
00048 #ifdef _MSC_VER
00049 #   pragma warning( disable : 4706 ) // assignment within conditional expression
00050 #endif
00051 
00052 namespace GENAPI_NAMESPACE
00053 {
00057     template<class Base>
00058     class FloatT : public Base
00059     {
00060     public:
00061 
00063         FloatT< Base >() :
00064             Base(),
00065             m_ImposedMax( (std::numeric_limits<double>::max)() ),
00066             m_ImposedMin( -(std::numeric_limits<double>::max)() )
00067         {
00068         }
00069 
00071         virtual void SetValue(double Value, bool Verify = true)
00072         {
00073 
00074             // a list of callbacks to fire held outside(!) the autolock on the stack(!)
00075             std::list<CNodeCallback*> CallbacksToFire;
00076             {
00077                 AutoLock l(Base::GetLock());
00078                 typename Base::EntryMethodFinalizer E( this, meSetValue );
00079 
00080                 GCLOGINFOPUSH( Base::m_pValueLog, "SetValue( %f )...", Value );
00081 
00082                 if( Verify )
00083                 {
00084                     if( !IsWritable( this ) )
00085                         throw ACCESS_EXCEPTION_NODE("Node is not writable.");
00086 
00087                     CHECK_RANGE_FLT_NODE(Value, Base::InternalGetMin(), Base::InternalGetMax());
00088                 }
00089 
00090                 {
00091                     typename Base::PostSetValueFinalizer PostSetValueCaller(this, CallbacksToFire);  // dtor calls Base::PostSetValue
00092 
00093                     // invalidates all nodes if this is the first call in a chain of SetValue calls
00094                     Base::PreSetValue();
00095 
00096                     // sets the value
00097                     Base::InternalSetValue(Value, Verify);
00098 
00099                     if( Verify )
00100                         Base::InternalCheckError();
00101 
00102                     #if ! defined( DISABLE_VALUE_CACHING ) || (DISABLE_VALUE_CACHING == 0)
00103                         // Fill cache
00104                         if( WriteThrough == static_cast<INode *>(this)->GetCachingMode() )
00105                         {
00106                             m_ValueCache = Value;
00107                             Base::m_ValueCacheValid = true;
00108                             Base::m_DontDeleteThisCache = true;
00109                         }
00110                     #endif
00111 
00112                 }
00113 
00114                 GCLOGINFOPOP( Base::m_pValueLog, "...SetValue" );
00115 
00116                 // fire callbacks inside the lock
00117                 std::list<CNodeCallback*>::iterator ptrCallback;
00118                 for( ptrCallback = CallbacksToFire.begin(); ptrCallback != CallbacksToFire.end(); ptrCallback++ )
00119                 {
00120                     (*ptrCallback)->operator ()(cbPostInsideLock);
00121                 }
00122             }
00123 
00124             // fire callbacks outside the lock
00125             std::list<CNodeCallback*>::iterator ptrCallback;
00126             for( ptrCallback = CallbacksToFire.begin(); ptrCallback != CallbacksToFire.end(); ptrCallback++ )
00127             {
00128                 (*ptrCallback)->operator ()(cbPostOutsideLock);
00129             }
00130         }
00131 
00133         virtual IFloat& operator=(double Value)
00134         {
00135             SetValue(Value);
00136 
00137             return *this;
00138         }
00139 
00140         /* This is a helper function used in the method ToString (see below)
00141            It parses a floating point number given in a buffer s and creates a correction value used for correct rounding
00142            
00143            If the number in s is given in fixed point notation like
00144                123.4567
00145            the correction is
00146                  0.00005
00147            that is it has zeros for all trailing digits of the number followed by a '5'
00148 
00149            In case of scientific notation like
00150                1.1234e-12
00151            the correction number is
00152                0.00005e-12
00153            that is it has zeros for all trailing digits of the number followed by a '5' plus it has 
00154            the same exponent as the original number.
00155 
00156            The use of the correction number is explained below in the method ToString
00157 
00158            The code is inspired from from http://www.hackchina.com/en/r/185703/ATOF.C__html
00159         */
00160         double Correction( const char *s )
00161         {
00162             // note that while parsing the parsed value is composed even if that is not necessary
00163             // nevertheless the code is left as is for clarification and verification purposes
00164             bool sign;
00165             char c;
00166 
00167             // eat white space 
00168             while( isspace(c = *s) )
00169                 s++;
00170 
00171             // handle sign
00172             if ((sign = (c == '-')))
00173                 s++;
00174             else if (c == '+')
00175                 s++;
00176 
00177             // read digits before decimal point
00178             double v = 0.0;
00179             while( isdigit(*s) )
00180                 v = 10.0 * v + (*s++ - '0');
00181 
00182             double Cor = 0.5;
00183             if( *s == '.' )
00184             {
00185                 s++;
00186 
00187                 // eat digits after decimal point
00188                 double fr = 10.0;
00189                 while( isdigit(*s) )
00190                 {
00191                     v += (*s++ - '0') / fr;
00192                     Cor *= 0.1;
00193                     fr *= 10.0;
00194                 }
00195             }
00196 
00197             // handle exponent
00198             double exp = 1.0;
00199             if (tolower(*s) == 'e')
00200             {
00201                 int i = atoi(s);
00202                 exp = pow(10.0, i);
00203             }
00204 
00205             //v *= exp;
00206             //v = sign ? -v : v;
00207 
00208             Cor *= exp;
00209 
00210             return Cor;
00211         }
00212 
00214         virtual GENICAM_NAMESPACE::gcstring InternalToString(bool Verify = false, bool IgnoreCache = false)
00215         {
00216             AutoLock l(Base::GetLock());
00217             
00218             std::stringstream Buffer;
00219             std::ostringstream CorrectedBuffer;
00220 
00221             // set DisplayNotation
00222             switch( Base::InternalGetDisplayNotation() )
00223             {
00224             case fnAutomatic:
00225                 // default
00226                 break;
00227             case fnFixed:
00228                 Buffer.setf(std::ios::fixed, std::ios::floatfield);
00229                 CorrectedBuffer.setf(std::ios::fixed, std::ios::floatfield);
00230                 break;
00231             case fnScientific:
00232                 Buffer.setf(std::ios::scientific, std::ios::floatfield);
00233                 CorrectedBuffer.setf(std::ios::scientific, std::ios::floatfield);
00234                 break;
00235             #pragma BullseyeCoverage off
00236             default:
00237                 assert(false);
00238             #pragma BullseyeCoverage on
00239             }
00240 
00241             // set DisplayPrecision
00242             int Precision = (int)GetDisplayPrecision();
00243             Buffer.precision( Precision ); 
00244             CorrectedBuffer.precision( Precision ); 
00245 
00246             // output
00247             double Value = GetValue( Verify, IgnoreCache );
00248             Buffer << Value;
00249 
00250             // Make sure FromString will work with the result
00251             // for details see the test code in FloatTestSuite::TestTicket785
00252 
00253             // read back the created string
00254             double VerifyValue;
00255             Buffer >> VerifyValue;
00256 
00257             double CorrectedValue = Value;
00258             bool LimitsExceeded = false;
00259             
00260             // the string may be too large due to rounding issues
00261             if( VerifyValue > Base::InternalGetMax() )
00262             {
00263                 CorrectedValue = Value - Correction( Buffer.str().c_str() );
00264                 LimitsExceeded = true;
00265             }
00266             else if( VerifyValue < Base::InternalGetMin() )
00267             {
00268                 CorrectedValue = Value + Correction( Buffer.str().c_str() );
00269                 LimitsExceeded = true;
00270             }
00271             
00272             GENICAM_NAMESPACE::gcstring valueString;
00273             if( LimitsExceeded )
00274             {
00275                 CorrectedBuffer << CorrectedValue;
00276                 valueString = CorrectedBuffer.str().c_str();
00277             }
00278             else
00279             {
00280                 valueString = Buffer.str().c_str();
00281             }
00282             return valueString;
00283         }
00284 
00286         virtual double GetValue(bool Verify = false, bool IgnoreCache = false)
00287         {
00288             AutoLock l(Base::GetLock());
00289             typename Base::EntryMethodFinalizer E( this, meGetValue, IgnoreCache );
00290 
00291             // Note that readability is tested regardless of Verify
00292             if( !IsReadable( this ) )
00293                 throw ACCESS_EXCEPTION_NODE("Node is not readable.");
00294 
00295             #if ! defined( DISABLE_VALUE_CACHING ) || (DISABLE_VALUE_CACHING == 0)
00296                 // Use cache
00297                 if (!IgnoreCache && Base::m_ValueCacheValid && !Verify)
00298                 {
00299                     GCLOGINFO( Base::m_pValueLog, "GetValue = %f  (from cache)", m_ValueCache );
00300 
00301                     return m_ValueCache;
00302                 }
00303             #endif
00304 
00305             GCLOGINFOPUSH( Base::m_pValueLog, "GetValue...");
00306 
00307             const double Value( Base::InternalGetValue(Verify, IgnoreCache) );
00308 
00309             GCLOGINFOPOP( Base::m_pValueLog, "...GetValue = %f", Value );
00310 
00311             if( Verify )
00312             {
00313                 CHECK_RANGE_FLT_NODE(Value, Base::InternalGetMin(), Base::InternalGetMax());
00314                 Base::InternalCheckError();
00315             }
00316 
00317             #if ! defined( DISABLE_VALUE_CACHING ) || (DISABLE_VALUE_CACHING == 0)
00318                 // Fill cache
00319                 const ECachingMode CachingMode(static_cast<INode *>(this)->GetCachingMode());
00320                 if(    WriteThrough == CachingMode
00321                     || WriteAround  == CachingMode  )
00322                 {
00323                     m_ValueCache = Value;
00324                     Base::m_ValueCacheValid = true;                            
00325                 }
00326             #endif
00327 
00328             return Value;
00329 
00330         }
00331 
00333         virtual double operator()()
00334         {
00335             return GetValue();
00336         }
00337 
00339         virtual double operator*()
00340         {
00341             return GetValue();
00342         }
00343 
00345         virtual void InternalFromString(const GENICAM_NAMESPACE::gcstring& ValueStr, bool Verify = true)
00346         {
00347             double value;
00348             if (!String2Value(ValueStr,&value))
00349                 throw INVALID_ARGUMENT_EXCEPTION_NODE("Node '%s' : cannot convert string '%s' to double.", Base::m_Name.c_str(),  ValueStr.c_str() );
00350 
00351             SetValue(value, Verify);
00352         }
00353 
00354 
00356         virtual double GetMin()
00357         {
00358             AutoLock l(Base::GetLock());
00359             typename Base::EntryMethodFinalizer E( this, meGetMin );
00360 
00361             // only allowed for available nodes
00362             if (!IsAvailable(this))
00363                 throw ACCESS_EXCEPTION_NODE("Node is not available.");
00364 
00365             GCLOGINFOPUSH( Base::m_pRangeLog, "GetMin..." );
00366 
00367             double Minimum = Base::InternalGetMin();
00368             Minimum = (std::max)(Minimum, m_ImposedMin);
00369 
00370             GCLOGINFOPOP( Base::m_pRangeLog, "...GetMin = %f", Minimum );
00371 
00372             return Minimum;
00373 
00374         }
00375 
00377         virtual double GetMax()
00378         {
00379             AutoLock l(Base::GetLock());
00380             typename Base::EntryMethodFinalizer E( this, meGetMax );
00381 
00382             // only allowed for available nodes
00383             if (!IsAvailable(this))
00384                 throw ACCESS_EXCEPTION_NODE("Node is not available.");
00385 
00386             GCLOGINFOPUSH( Base::m_pRangeLog, "GetMax...");
00387 
00388             double Maximum(Base::InternalGetMax());
00389             Maximum = (std::min)( Maximum, m_ImposedMax );
00390 
00391             GCLOGINFOPOP( Base::m_pRangeLog, "...GetMax = %f", Maximum );
00392 
00393             return Maximum;
00394 
00395         }
00396 
00398         virtual bool HasInc()
00399         {
00400             AutoLock l(Base::GetLock());
00401 
00402             GCLOGINFOPUSH( Base::m_pRangeLog, "HasInc...");
00403 
00404             bool HasInc( Base::InternalHasInc() );
00405 #pragma BullseyeCoverage off
00406             GCLOGINFOPOP( Base::m_pRangeLog, "...HasInc = " + (HasInc ? GENICAM_NAMESPACE::gcstring("true") : GENICAM_NAMESPACE::gcstring("false")));
00407 #pragma BullseyeCoverage on
00408 
00409             return HasInc;
00410 
00411         }
00412 
00413         virtual EIncMode GetIncMode()
00414         {
00415             AutoLock l(Base::GetLock());
00416             typename Base::EntryMethodFinalizer E( this, meGetIncMode );
00417 
00418             GCLOGINFOPUSH( Base::m_pRangeLog, "GetIncMode...");
00419 
00420             if( ! Base::m_ListOfValidValuesCacheValid )
00421             {
00422                m_CurentValidValueSet = Base::InternalGetListOfValidValues();
00423                Base::m_ListOfValidValuesCacheValid = true;
00424             }
00425 
00426             EIncMode incMode( (m_CurentValidValueSet.size())? listIncrement: Base::InternalHasInc()? fixedIncrement : noIncrement  );
00427 
00428             GCLOGINFOPOP( Base::m_pRangeLog, "...GetIncMode" );
00429 
00430             return incMode;
00431         }
00432 
00434         virtual double GetInc()
00435         {
00436             AutoLock l(Base::GetLock());
00437             typename Base::EntryMethodFinalizer E( this, meGetInc );
00438 
00439             if( !Base::InternalHasInc() )
00440                 throw RUNTIME_EXCEPTION_NODE("node does not have an increment." );
00441 
00442             // only allowed for available nodes
00443             if (!IsAvailable(this))
00444                 throw ACCESS_EXCEPTION_NODE("Node is not available.");
00445 
00446             GCLOGINFOPUSH( Base::m_pRangeLog, "GetInc...");
00447 
00448             double Inc( Base::InternalGetInc() );
00449 
00450             GCLOGINFOPOP( Base::m_pRangeLog, "...GetInc = %f", Inc );
00451 
00452             return Inc;
00453         }
00454 
00456         virtual double_autovector_t GetListOfValidValues(bool bounded = true)
00457         {
00458             AutoLock l(Base::GetLock());
00459             typename Base::EntryMethodFinalizer E( this, meGetListOfValidValues );
00460 
00461             GCLOGINFOPUSH( Base::m_pRangeLog, "GetListOfValidValues...");
00462             if( ! Base::m_ListOfValidValuesCacheValid )
00463             {
00464                m_CurentValidValueSet = Base::InternalGetListOfValidValues();
00465                Base::m_ListOfValidValuesCacheValid = true;
00466             }
00467 
00468             double_autovector_t list( ( bounded)? m_CurentValidValueSet.duplicate( Base::InternalGetMin(), Base::InternalGetMax()) : m_CurentValidValueSet);
00469 
00470 
00471             GCLOGINFOPOP( Base::m_pRangeLog, "...GetListOfValidValues" );
00472             return list;
00473 
00474 
00475         }
00476 
00477 
00479         virtual  ERepresentation GetRepresentation()
00480         {
00481             AutoLock l(Base::GetLock());
00482             return Base::InternalGetRepresentation();
00483         }
00484 
00486         virtual GENICAM_NAMESPACE::gcstring GetUnit() const
00487         {
00488             AutoLock l(Base::GetLock());
00489             return Base::InternalGetUnit();
00490         }
00491 
00493         virtual EDisplayNotation GetDisplayNotation() const
00494         {
00495             AutoLock l(Base::GetLock());
00496             return Base::InternalGetDisplayNotation();
00497         }
00498 
00500         virtual int64_t GetDisplayPrecision() const
00501         {
00502             AutoLock l(Base::GetLock());
00503 
00504             int64_t Precision = Base::InternalGetDisplayPrecision();
00505 
00506             if( Precision == -1 )
00507             {
00508                 // determine built in precision
00509                 std::stringstream Buffer;
00510                 switch( Base::InternalGetDisplayNotation() )
00511                 {
00512                 case fnFixed:
00513                     Buffer.setf(std::ios::fixed, std::ios::floatfield);
00514                     break;
00515                 case fnScientific:
00516                     Buffer.setf(std::ios::scientific, std::ios::floatfield);
00517                     break;
00518                 case fnAutomatic:
00519                     // default
00520                     break;
00521             #pragma BullseyeCoverage off
00522                 default:
00523                     assert(false);
00524             #pragma BullseyeCoverage on
00525                  }
00526 
00527                 Precision = Buffer.precision();
00528             }
00529 
00530             return Precision;
00531         }
00532 
00534         virtual void ImposeMin(double Value)
00535         {
00536             m_ImposedMin = Value;
00537             Base::SetInvalid(INodePrivate::simAll);
00538         }
00539 
00541         virtual void ImposeMax(double Value)
00542         {
00543             m_ImposedMax = Value;
00544             Base::SetInvalid(INodePrivate::simAll);
00545         }
00546 
00547     protected:
00549         double m_ValueCache;
00550 
00552         double m_ImposedMax;
00553 
00555         double m_ImposedMin;
00556 
00558         double_autovector_impl m_CurentValidValueSet;
00559     };
00560 }
00561 
00562 #endif // GENAPI_FLOATT_H


rc_genicam_api
Author(s): Heiko Hirschmueller
autogenerated on Thu Jun 6 2019 18:42:46