File indexing completed on 2024-05-12 04:35:06

0001 /* This file is part of the TikZKit project.
0002  *
0003  * Copyright (C) 2013-2014 Dominik Haumann <dhaumann@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU Library General Public License as published
0007  * by the Free Software Foundation, either version 2 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, see
0017  * <http://www.gnu.org/licenses/>.
0018  */
0019 #ifndef TIKZ_VALUE_H
0020 #define TIKZ_VALUE_H
0021 
0022 #include "tikz_export.h"
0023 #include "tikz.h"
0024 
0025 #include <cmath>
0026 #include <QDebug>
0027 
0028 namespace tikz
0029 {
0030 
0031 namespace internal {
0032     // see: http://tex.stackexchange.com/questions/8260
0033     static constexpr qreal units[4][4] = {
0034         // pt          , mm      , cm     , in
0035 
0036         // conversion from pt
0037         {1.0           , 2540.0/7227.0, 254.0/7227.0, 100.0/7227.0},
0038         // conversion from mm
0039         {7227.0/2540.0 , 1.0          , 0.1         , 5.0/127.0},
0040         // conversion from cm
0041         {7227.0/254.0  , 10.0         , 1.0         , 50.0/127.0},
0042         // conversion from in
0043         {7227.0/100.0  , 127.0/5.0    , 127.0/50.0  , 1.0}
0044     };
0045 }
0046 
0047 /**
0048  * The Value class provides a unit-aware value.
0049  *
0050  * The Value is defined by a real number and its unit.
0051  * By using the Value class whenever metric values are required,
0052  * it is recommended to use Value as it avoids unit conversion errors.
0053  */
0054 class TIKZKITCORE_EXPORT Value
0055 {
0056     //
0057     // static functions
0058     //
0059     public:
0060         /**
0061          * 'ultra thin' line width according to the PGF/TikZ standard.
0062          */
0063         static inline constexpr Value ultraThin() noexcept {
0064             return Value(0.1, Unit::Point);
0065         }
0066 
0067         /**
0068          * 'very thin' line width according to the PGF/TikZ standard.
0069          */
0070         static inline constexpr Value veryThin() noexcept {
0071             return Value(0.2, Unit::Point);
0072         }
0073 
0074         /**
0075          * 'thin' line width according to the PGF/TikZ standard.
0076          */
0077         static inline constexpr Value thin() noexcept {
0078             return Value(0.4, Unit::Point);
0079         }
0080 
0081         /**
0082          * 'semithick' line width according to the PGF/TikZ standard.
0083          */
0084         static inline constexpr Value semiThick() noexcept {
0085             return Value(0.6, Unit::Point);
0086         }
0087 
0088         /**
0089          * 'thick' line width according to the PGF/TikZ standard.
0090          */
0091         static inline constexpr Value thick() noexcept {
0092             return Value(0.8, Unit::Point);
0093         }
0094 
0095         /**
0096          * 'very thick' line width according to the PGF/TikZ standard.
0097          */
0098         static inline constexpr Value veryThick() noexcept {
0099             return Value(1.2, Unit::Point);
0100         }
0101 
0102         /**
0103          * 'ultra thick' line width according to the PGF/TikZ standard.
0104          */
0105         static inline constexpr Value ultraThick() noexcept {
0106             return Value(1.6, Unit::Point);
0107         }
0108 
0109         /**
0110          * Invalid size, set to NaN.
0111          * @see isValid()
0112          */
0113         static inline constexpr Value invalid() noexcept {
0114             return Value(std::sqrt(-1));
0115         }
0116 
0117     public:
0118         /**
0119          * Constructor with value and type.
0120          */
0121         constexpr Value(qreal value = 0.0, Unit unit = Unit::Point)
0122             : m_value(value)
0123             , m_unit(unit)
0124         {
0125         }
0126 
0127         /**
0128          * Check whether this value is a finite value, i.e. other than NaN or infinity.
0129          */
0130         inline bool isValid() const noexcept
0131         {
0132             return std::isfinite(m_value);
0133         }
0134 
0135         /**
0136          * Get the Unit.
0137          */
0138         inline constexpr Unit unit() const noexcept
0139         {
0140             return m_unit;
0141         }
0142 
0143         /**
0144          * Explicit conversion to value.
0145          */
0146         inline constexpr qreal value() const noexcept
0147         {
0148             return m_value;
0149         }
0150 
0151         /**
0152          * Explicit conversion to Point.
0153          */
0154         inline constexpr qreal toPoint() const noexcept
0155         {
0156             return convertTo(tikz::Unit::Point).m_value;
0157         }
0158 
0159         /**
0160          *
0161          */
0162         inline constexpr Value convertTo(Unit unit) const noexcept
0163         {
0164             return Value(m_value * internal::units[static_cast<int>(m_unit)][static_cast<int>(unit)], unit);
0165         }
0166 
0167         /**
0168          * Convert this number to a string.
0169          */
0170         QString toString() const;
0171 
0172         /**
0173          * Convert @p str to a Value.
0174          */
0175         static Value fromString(const QString & str);
0176 
0177     //
0178     // operators for qreal values
0179     //
0180     public:
0181 //         /**
0182 //          * Implicit cast to value.
0183 //          * @warning the returned value \e always is of type Unit::Point!
0184 //          */
0185 //         inline constexpr operator qreal () const noexcept
0186 //         {
0187 //             return convertTo(Unit::Point).value();
0188 //         }
0189 
0190         /**
0191          * Adds @p value to this Value and returns a reference to this Value.
0192          * @warning This operation is independent of the unit.
0193          */
0194         inline Value & operator+=(qreal value) noexcept
0195         {
0196             Q_ASSERT(isValid());
0197             m_value += value;
0198             return *this;
0199         }
0200 
0201         /**
0202          * Subtracts @p value from this Value and returns a reference to this Value.
0203          * @warning This operation is independent of the unit.
0204          */
0205         inline Value & operator-=(qreal value) noexcept
0206         {
0207             Q_ASSERT(isValid());
0208             m_value -= value;
0209             return *this;
0210         }
0211 
0212         /**
0213          * Multiplies this Value with @p factor and returns a reference to this Value.
0214          * @warning This operation is independent of the unit.
0215          */
0216         inline Value & operator*=(qreal factor) noexcept
0217         {
0218             Q_ASSERT(isValid());
0219             m_value *= factor;
0220             return *this;
0221         }
0222 
0223         /**
0224          * Divides this Value by @p divisor and returns a reference to this Value.
0225          * @warning This operation is independent of the unit.
0226          */
0227         inline Value & operator/=(qreal divisor) noexcept
0228         {
0229             Q_ASSERT(isValid());
0230             m_value /= divisor;
0231             return *this;
0232         }
0233 
0234     //
0235     // operators for two Value
0236     //
0237     public:
0238         /**
0239          * Plus operator for two Value%s.
0240          * Returns a new Value object with the same unit increased by @p value.
0241          * If @p value's unit is different, @p value is first converted to a
0242          * compatible Unit before adding the value.
0243          */
0244         inline Value operator+(const Value & value) const noexcept
0245         {
0246             Q_ASSERT(isValid());
0247             Q_ASSERT(value.isValid());
0248             return Value(m_value + value.convertTo(m_unit).value(), m_unit);
0249         }
0250 
0251         /**
0252          * Minus operator for two Value%s.
0253          * Returns a new Value object with the same unit decreased by @p value.
0254          * If @p value's unit is different, @p value is first converted to a
0255          * compatible Unit before adding the value.
0256          */
0257         inline Value operator-(const Value & value) const noexcept
0258         {
0259             Q_ASSERT(isValid());
0260             Q_ASSERT(value.isValid());
0261             return Value(m_value - value.convertTo(m_unit).value(), m_unit);
0262         }
0263 
0264         /**
0265          * += operator for two Value%s.
0266          * Returns a reference to this object increased by @p value.
0267          * If @p value's unit is different, @p value is first converted to a
0268          * compatible Unit before adding the value.
0269          */
0270         inline Value & operator+=(const Value & value)
0271         {
0272             Q_ASSERT(isValid());
0273             Q_ASSERT(value.isValid());
0274             return operator+=(value.convertTo(m_unit).value());
0275         }
0276 
0277         /**
0278          * -= operator for two Value%s.
0279          * Returns a reference to this object decreased by @p value.
0280          * If @p value's unit is different, @p value is first converted to a
0281          * compatible Unit before adding the value.
0282          */
0283         inline Value & operator-=(const Value & value)
0284         {
0285             Q_ASSERT(isValid());
0286             Q_ASSERT(value.isValid());
0287             return operator-=(value.convertTo(m_unit).value());
0288         }
0289 
0290         /**
0291          * QDebug support.
0292          */
0293         inline friend QDebug operator<<(QDebug s, const tikz::Value & value)
0294         {
0295             s.nospace() << value.toString();
0296             return s.space();
0297         }
0298 
0299         operator QVariant() const
0300         {
0301             return QVariant::fromValue(*this);
0302         }
0303 
0304     private:
0305         /**
0306          * The value.
0307          */
0308         qreal m_value = 0;
0309 
0310         /**
0311          * The unit of this value.
0312          */
0313         Unit m_unit = Unit::Point;
0314 };
0315 
0316 /**
0317  * Equality operator.
0318  * Return @e true, if the Value @p lhs equals the Value @p rhs.
0319  * @note The comparison is unit-aware.
0320  */
0321 inline bool operator==(const Value & lhs, const Value & rhs) noexcept
0322 {
0323     return (!lhs.isValid() && !rhs.isValid())
0324         || qFuzzyIsNull(lhs.value() - rhs.convertTo(lhs.unit()).value());
0325 }
0326 
0327 /**
0328  * Inequality operator.
0329  * Return @e true, if the Value @p lhs does not equal the Value @p rhs.
0330  * @note The comparison is unit-aware.
0331  */
0332 inline bool operator!=(const Value & lhs, const Value & rhs) noexcept
0333 {
0334     return ! (lhs == rhs);
0335 }
0336 
0337 /**
0338  * Returns a Value that is formed by multiplying @p value with @p factor.
0339  * @warning This operation is independent of the unit.
0340  */
0341 inline Value operator*(const Value & value, qreal factor) noexcept
0342 {
0343     return Value(value.value() * factor, value.unit());
0344 }
0345 
0346 /**
0347  * Returns a Value that is formed by multiplying @p value with @p factor.
0348  * @warning This operation is independent of the unit.
0349  */
0350 inline Value operator*(qreal factor, const Value & value) noexcept
0351 {
0352     return value * factor;
0353 }
0354 
0355 /**
0356  * Returns a Value that is formed by dividing @p value by @p divisor.
0357  * @warning This operation is independent of the unit.
0358  */
0359 inline Value operator/(const Value & value, qreal divisor)
0360 {
0361     Q_ASSERT(divisor != 0);
0362     return Value(value.value() / divisor, value.unit());
0363 }
0364 
0365 /**
0366  * Returns @e true if @p value is greater than @p valInPoints.
0367  * @warning @valInPoints is interpreted in Points.
0368  */
0369 inline constexpr bool operator>(const Value & value, qreal valInPoints) noexcept
0370 {
0371     return value.toPoint() > valInPoints;
0372 }
0373 
0374 /**
0375  * Returns @e true if @p value is greater than @p valInPoints.
0376  * @warning @valInPoints is interpreted in Points.
0377  */
0378 inline constexpr bool operator>(qreal valInPoints, const Value & value) noexcept
0379 {
0380     return valInPoints > value.toPoint();
0381 }
0382 
0383 /**
0384  * Returns true if @p value in Point is greater than or equal to @p valInPoints.
0385  * @warning @valInPoints is interpreted in Points.
0386  */
0387 inline constexpr bool operator>=(const Value & value, qreal valInPoints) noexcept
0388 {
0389     return value.toPoint() >= valInPoints;
0390 }
0391 
0392 /**
0393  * Returns true if @p value in Point is less than @p valInPoints.
0394  * @warning @valInPoints is interpreted in Points.
0395  */
0396 inline constexpr bool operator<(const Value & value, qreal valInPoints) noexcept
0397 {
0398     return value.toPoint() < valInPoints;
0399 }
0400 
0401 /**
0402  * Returns true if @p value in Point is less than or equal to @p valInPoints.
0403  * @warning @valInPoints is interpreted in Points.
0404  */
0405 inline constexpr bool operator<=(const Value & value, qreal valInPoints) noexcept
0406 {
0407     return value.toPoint() <= valInPoints;
0408 }
0409 
0410 /**
0411  * Returns true if Value @p lhs is greater than Valule @p rhs.
0412  * @note This comparison is unit-aware.
0413  */
0414 inline bool operator>(const Value & lhs, const Value & rhs) noexcept
0415 {
0416     Q_ASSERT(lhs.isValid());
0417     Q_ASSERT(rhs.isValid());
0418     return lhs.value() > rhs.convertTo(lhs.unit()).value();
0419 }
0420 
0421 /**
0422  * Returns true if Value @p lhs is greater than or equal to Valule @p rhs.
0423  * @note This comparison is unit-aware.
0424  */
0425 inline bool operator>=(const Value & lhs, const Value & rhs) noexcept
0426 {
0427     Q_ASSERT(lhs.isValid());
0428     Q_ASSERT(rhs.isValid());
0429     return lhs.value() >= rhs.convertTo(lhs.unit()).value();
0430 }
0431 
0432 /**
0433  * Returns true if Value @p lhs is less than Valule @p rhs.
0434  * @note This comparison is unit-aware.
0435  */
0436 inline bool operator<(const Value & lhs, const Value & rhs) noexcept
0437 {
0438     Q_ASSERT(lhs.isValid());
0439     Q_ASSERT(rhs.isValid());
0440     return lhs.value() < rhs.convertTo(lhs.unit()).value();
0441 }
0442 
0443 /**
0444  * Returns true if Value @p lhs is less than or equal to Valule @p rhs.
0445  * @note This comparison is unit-aware.
0446  */
0447 inline bool operator<=(const Value & lhs, const Value & rhs) noexcept
0448 {
0449     Q_ASSERT(lhs.isValid());
0450     Q_ASSERT(rhs.isValid());
0451     return lhs.value() <= rhs.convertTo(lhs.unit()).value();
0452 }
0453 
0454 /**
0455  * Convert @p value from unit @p from to unit @p to.
0456  */
0457 inline constexpr qreal convertTo(qreal value, Unit from, Unit to)
0458 {
0459     return value * internal::units[static_cast<int>(from)][static_cast<int>(to)];
0460 }
0461 
0462 //
0463 // pt to *
0464 //
0465 inline constexpr qreal pt2mm(qreal value)
0466 {
0467     return convertTo(value, Unit::Point, Unit::Millimeter);
0468 }
0469 
0470 inline constexpr qreal pt2cm(qreal value)
0471 {
0472     return convertTo(value, Unit::Point, Unit::Centimeter);
0473 }
0474 
0475 inline constexpr qreal pt2in(qreal value)
0476 {
0477     return convertTo(value, Unit::Point, Unit::Inch);
0478 }
0479 
0480 //
0481 // cm to *
0482 //
0483 inline constexpr qreal cm2pt(qreal value)
0484 {
0485     return convertTo(value, Unit::Centimeter, Unit::Point);
0486 }
0487 
0488 inline constexpr qreal cm2mm(qreal value)
0489 {
0490     return convertTo(value, Unit::Centimeter, Unit::Millimeter);
0491 }
0492 
0493 inline constexpr qreal cm2in(qreal value)
0494 {
0495     return convertTo(value, Unit::Centimeter, Unit::Inch);
0496 }
0497 
0498 //
0499 // mm to *
0500 //
0501 inline constexpr qreal mm2pt(qreal value)
0502 {
0503     return convertTo(value, Unit::Millimeter, Unit::Point);
0504 }
0505 
0506 inline constexpr qreal mm2cm(qreal value)
0507 {
0508     return convertTo(value, Unit::Millimeter, Unit::Centimeter);
0509 }
0510 
0511 inline constexpr qreal mm2in(qreal value)
0512 {
0513     return convertTo(value, Unit::Millimeter, Unit::Inch);
0514 }
0515 
0516 //
0517 // in to *
0518 //
0519 inline constexpr qreal in2pt(qreal value)
0520 {
0521     return convertTo(value, Unit::Inch, Unit::Point);
0522 }
0523 
0524 inline constexpr qreal in2cm(qreal value)
0525 {
0526     return convertTo(value, Unit::Inch, Unit::Centimeter);
0527 }
0528 
0529 inline constexpr qreal in2mm(qreal value)
0530 {
0531     return convertTo(value, Unit::Inch, Unit::Millimeter);
0532 }
0533 
0534 }
0535 
0536 inline constexpr tikz::Value operator""_pt(long double value)
0537 {
0538     return tikz::Value(value, tikz::Unit::Point);
0539 }
0540 
0541 inline constexpr tikz::Value operator""_mm(long double value)
0542 {
0543     return tikz::Value(value, tikz::Unit::Millimeter);
0544 }
0545 
0546 inline constexpr tikz::Value operator""_cm(long double value)
0547 {
0548     return tikz::Value(value, tikz::Unit::Centimeter);
0549 }
0550 
0551 inline constexpr tikz::Value operator""_in(long double value)
0552 {
0553     return tikz::Value(value, tikz::Unit::Inch);
0554 }
0555 
0556 namespace QTest
0557 {
0558     // forward declaration of template in qtestcase.h
0559     template<typename T> char* toString(const T&);
0560     
0561     template<>
0562     TIKZKITCORE_EXPORT char *toString(const tikz::Value & value);
0563 }
0564 
0565 /**
0566  * Declare as movable, since the members of Value are primitive types.
0567  */
0568 Q_DECLARE_TYPEINFO(tikz::Value, Q_MOVABLE_TYPE);
0569 Q_DECLARE_METATYPE(tikz::Value)
0570 
0571 #endif // TIKZ_VALUE_H
0572 
0573 // kate: indent-width 4; replace-tabs on;