diff options
Diffstat (limited to 'plugins/AdvaImg/src/Metadata/FIRational.cpp')
-rw-r--r-- | plugins/AdvaImg/src/Metadata/FIRational.cpp | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/plugins/AdvaImg/src/Metadata/FIRational.cpp b/plugins/AdvaImg/src/Metadata/FIRational.cpp new file mode 100644 index 0000000000..d383c8d38f --- /dev/null +++ b/plugins/AdvaImg/src/Metadata/FIRational.cpp @@ -0,0 +1,176 @@ +// ========================================================== +// Helper class for rational numbers +// +// Design and implementation by +// - Hervé Drolon <drolon@infonie.fr> +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#include "FreeImage.h" +#include "Utilities.h" +#include "FIRational.h" + +/// Initialize and normalize a rational number +void FIRational::initialize(LONG n, LONG d) { + if(d) { + _numerator = n; + _denominator = d; + // normalize rational + normalize(); + } else { + _numerator = 0; + _denominator = 0; + } +} + +/// Default constructor +FIRational::FIRational() { + _numerator = 0; + _denominator = 0; +} + +/// Constructor with longs +FIRational::FIRational(LONG n, LONG d) { + initialize(n, d); +} + +/// Constructor with FITAG +FIRational::FIRational(const FITAG *tag) { + switch(FreeImage_GetTagType((FITAG*)tag)) { + case FIDT_RATIONAL: // 64-bit unsigned fraction + { + DWORD *pvalue = (DWORD*)FreeImage_GetTagValue((FITAG*)tag); + initialize((LONG)pvalue[0], (LONG)pvalue[1]); + break; + } + + case FIDT_SRATIONAL: // 64-bit signed fraction + { + LONG *pvalue = (LONG*)FreeImage_GetTagValue((FITAG*)tag); + initialize((LONG)pvalue[0], (LONG)pvalue[1]); + break; + } + } +} + +FIRational::FIRational(float value) { + if (value == (float)((LONG)value)) { + _numerator = (LONG)value; + _denominator = 1L; + } else { + int k, count; + LONG n[4]; + + float x = fabs(value); + int sign = (value > 0) ? 1 : -1; + + // make a continued-fraction expansion of x + count = -1; + for(k = 0; k < 4; k++) { + n[k] = (LONG)floor(x); + count++; + x -= (float)n[k]; + if(x == 0) break; + x = 1 / x; + } + // compute the rational + _numerator = 1; + _denominator = n[count]; + + for(int i = count - 1; i >= 0; i--) { + if(n[i] == 0) break; + LONG _num = (n[i] * _numerator + _denominator); + LONG _den = _numerator; + _numerator = _num; + _denominator = _den; + } + _numerator *= sign; + } +} + +/// Copy constructor +FIRational::FIRational (const FIRational& r) { + initialize(r._numerator, r._denominator); +} + +/// Destructor +FIRational::~FIRational() { +} + +/// Assignement operator +FIRational& FIRational::operator=(FIRational& r) { + if(this != &r) { + initialize(r._numerator, r._denominator); + } + return *this; +} + +/// Get the numerator +LONG FIRational::getNumerator() { + return _numerator; +} + +/// Get the denominator +LONG FIRational::getDenominator() { + return _denominator; +} + +/// Calculate GCD +LONG FIRational::gcd(LONG a, LONG b) { + LONG temp; + while (b) { // While non-zero value + temp = b; // Save current value + b = a % b; // Assign remainder of division + a = temp; // Copy old value + } + return a; // Return GCD of numbers +} + +/// Normalize numerator / denominator +void FIRational::normalize() { + if (_numerator != 1 && _denominator != 1) { // Is there something to do? + // Calculate GCD + LONG common = gcd(_numerator, _denominator); + if (common != 1) { // If GCD is not one + _numerator /= common; // Calculate new numerator + _denominator /= common; // Calculate new denominator + } + } + if(_denominator < 0) { // If sign is in denominator + _numerator *= -1; // Multiply num and den by -1 + _denominator *= -1; // To keep sign in numerator + } +} + +/// Checks if this rational number is an Integer, either positive or negative +BOOL FIRational::isInteger() { + if(_denominator == 1 || (_denominator != 0 && (_numerator % _denominator == 0)) || (_denominator == 0 && _numerator == 0)) + return TRUE; + return FALSE; +} + +/// Convert as "numerator/denominator" +std::string FIRational::toString() { + std::ostringstream s; + if(isInteger()) { + s << intValue(); + } else { + s << _numerator << "/" << _denominator; + } + return s.str(); +} + + |