home *** CD-ROM | disk | FTP | other *** search
/ Hackers Magazine 57 / CdHackersMagazineNr57.iso / Software / Multimedia / k3d-setup-0.7.11.0.exe / include / k3d / k3dsdk / measurement.h < prev    next >
C/C++ Source or Header  |  2008-11-07  |  12KB  |  394 lines

  1. #ifndef K3DSDK_MEASUREMENT_H
  2. #define K3DSDK_MEASUREMENT_H
  3.  
  4. // K-3D
  5. // Copyright (c) 1995-2004, Timothy M. Shead
  6. //
  7. // Contact: tshead@k-3d.com
  8. //
  9. // This program is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17. // General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public
  20. // License along with this program; if not, write to the Free Software
  21. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22.  
  23. /** \file
  24.         \brief Provides a type-safe framework for doing real-world unit-of-measure conversion and I/O
  25.         \author Tim Shead (tshead@k-3d.com)
  26. */
  27.  
  28. #include <cassert>
  29. #include <iosfwd>
  30. #include <map>
  31. #include <string>
  32.  
  33. namespace k3d
  34. {
  35.  
  36. namespace measurement
  37. {
  38.  
  39. namespace conversion
  40. {
  41.  
  42. /// Conversion policy for real world units that can be converted solely through multiplication
  43. class multiplicative
  44. {
  45. public:
  46.     const double to_si(const double RHS) const
  47.     {
  48.         return RHS * m_constant;
  49.     }
  50.  
  51.     const double from_si(const double RHS) const
  52.     {
  53.         return RHS / m_constant;
  54.     }
  55.  
  56. protected:
  57.     explicit multiplicative(const double Constant) :
  58.         m_constant(Constant)
  59.     {
  60.         assert(m_constant);
  61.     }
  62.  
  63. private:
  64.     double m_constant;
  65. };
  66.  
  67. } // namespace conversion
  68.  
  69. /// Defines a real-world unit of measure, including singular written name, plural written name, and functions to_si() and from_si() for converting quantities to-and-from their corresponding SI standard units
  70. template<typename conversion_policy>
  71. class unit :
  72.     public conversion_policy
  73. {
  74. public:
  75.     typedef unit<conversion_policy> this_t;
  76.  
  77.     const std::string name() const
  78.     {
  79.         return m_name;
  80.     }
  81.  
  82.     const std::string plural_name() const
  83.     {
  84.         return m_plural_name;
  85.     }
  86.  
  87.     friend bool operator==(const this_t& LHS, const this_t& RHS)
  88.     {
  89.         return LHS.m_name == RHS.m_name;
  90.     }
  91.  
  92.     friend bool operator<(const this_t& LHS, const this_t& RHS)
  93.     {
  94.         return LHS.m_name < RHS.m_name;
  95.     }
  96.  
  97. protected:
  98. /*
  99.     explicit unit(const std::string Name, const std::string PluralName) :
  100.         conversion_policy(),
  101.         m_name(Name),
  102.         m_plural_name(Name)
  103.     {
  104.         assert(m_name.size());
  105.         assert(m_plural_name.size());
  106.     }
  107. */
  108.  
  109.     explicit unit(const std::string Name, const std::string PluralName, const double MultiplicativeConstant) :
  110.         conversion_policy(MultiplicativeConstant),
  111.         m_name(Name),
  112.         m_plural_name(PluralName)
  113.     {
  114.         assert(m_name.size());
  115.         assert(m_plural_name.size());
  116.     }
  117.  
  118. private:
  119.     std::string m_name;
  120.     std::string m_plural_name;
  121. };
  122.  
  123. /// Defines a proxy object so we can do conversion-by-assignment
  124. template<typename quantity_t>
  125. class conversion_proxy
  126. {
  127. public:
  128.     explicit conversion_proxy(const quantity_t Quantity) :
  129.         m_quantity(Quantity)
  130.     {
  131.     }
  132.  
  133.     const double to_si() const
  134.     {
  135.         return m_quantity.to_si();
  136.     }
  137.  
  138. private:
  139.     const quantity_t m_quantity;
  140. };
  141.  
  142. /// Convenience function for creating conversion_proxy objects
  143. template<typename quantity_t>
  144. conversion_proxy<quantity_t> convert(const quantity_t Quantity)
  145. {
  146.     return conversion_proxy<quantity_t>(Quantity);
  147. }
  148.  
  149. /// Convenience function for converting a quantity to another unit-of-measure
  150. template<typename quantity_t>
  151. const quantity_t convert(const quantity_t Quantity, const typename quantity_t::unit_type Units)
  152. {
  153.     return quantity_t(Units.from_si(Quantity.to_si()), Units);
  154. }
  155.  
  156. /// Defines a real-world quantity (a combination of value and unit)
  157. template<typename unit_t>
  158. class quantity
  159. {
  160. public:
  161.     typedef unit_t unit_type;
  162.     typedef quantity<unit_t> this_t;
  163.  
  164.     explicit quantity(const unit_t Units) :
  165.         m_units(Units)
  166.     {
  167.     }
  168.  
  169.     explicit quantity(const double Value, const unit_t Units) :
  170.         m_value(Value),
  171.         m_units(Units)
  172.     {
  173.     }
  174.  
  175.     operator double() const
  176.     {
  177.         return m_value;
  178.     }
  179.  
  180.     const double value() const
  181.     {
  182.         return m_value;
  183.     }
  184.  
  185.     const unit_t& units() const
  186.     {
  187.         return m_units;
  188.     }
  189.  
  190.     const double to_si() const
  191.     {
  192.         return m_units.to_si(m_value);
  193.     }
  194.  
  195.     this_t& operator=(const conversion_proxy<this_t>& RHS)
  196.     {
  197.         m_value = m_units.from_si(RHS.to_si());
  198.         return *this;
  199.     }
  200.  
  201.     friend std::ostream& operator<<(std::ostream& Stream, const this_t& RHS)
  202.     {
  203.         Stream << RHS.m_value << " ";
  204.         Stream << (1 == RHS.m_value ? RHS.m_units.name() : RHS.m_units.plural_name());
  205.         return Stream;
  206.     }
  207.  
  208. private:
  209.     double m_value;
  210.     unit_t m_units;
  211. };
  212.  
  213. /// Defines a "scalar" quantity (no unit-of-measure)
  214. typedef void scalar;
  215.  
  216. /// Defines an angular unit-of-measure
  217. class angle :
  218.     public unit<conversion::multiplicative>
  219. {
  220. public:
  221.     explicit angle(const std::string Name, const std::string PluralName, const double Constant) :
  222.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  223.     {
  224.     }
  225. };
  226.  
  227. /// Defines a unit-of-measure for area
  228. class area :
  229.     public unit<conversion::multiplicative>
  230. {
  231. public:
  232.     explicit area(const std::string Name, const std::string PluralName, const double Constant) :
  233.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  234.     {
  235.     }
  236. };
  237.  
  238. /// Defines a unit-of-measure for distance
  239. class distance :
  240.     public unit<conversion::multiplicative>
  241. {
  242. public:
  243.     explicit distance(const std::string Name, const std::string PluralName, const double Constant) :
  244.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  245.     {
  246.     }
  247. };
  248.  
  249. /// Defines a unit-of-measure for force
  250. class force :
  251.     public unit<conversion::multiplicative>
  252. {
  253. public:
  254.     explicit force(const std::string Name, const std::string PluralName, const double Constant) :
  255.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  256.     {
  257.     }
  258. };
  259.  
  260. /// Defines a unit-of-measure for mass
  261. class mass :
  262.     public unit<conversion::multiplicative>
  263. {
  264. public:
  265.     explicit mass(const std::string Name, const std::string PluralName, const double Constant) :
  266.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  267.     {
  268.     }
  269. };
  270.  
  271. /// Defines a unit-of-measure for pressure
  272. class pressure :
  273.     public unit<conversion::multiplicative>
  274. {
  275. public:
  276.     explicit pressure(const std::string Name, const std::string PluralName, const double Constant) :
  277.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  278.     {
  279.     }
  280. };
  281.  
  282. /// Defines a unit-of-measure for time
  283. class time :
  284.     public unit<conversion::multiplicative>
  285. {
  286. public:
  287.     explicit time(const std::string Name, const std::string PluralName, const double Constant) :
  288.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  289.     {
  290.     }
  291. };
  292.  
  293. /// Defines a unit-of-measure for volume
  294. class volume :
  295.     public unit<conversion::multiplicative>
  296. {
  297. public:
  298.     explicit volume(const std::string Name, const std::string PluralName, const double Constant) :
  299.         unit<conversion::multiplicative>(Name, PluralName, Constant)
  300.     {
  301.     }
  302. };
  303.  
  304. /**
  305.  
  306. \brief Parses a mathematical expression with optional real-world units-of-measure
  307. \param Stream Input stream containing the expression to be parsed
  308. \param Value Iff the input expression is completely parsed, contains the expression value; otherwise unchanged
  309. \param Units Iff the input expression is completely parsed, contains the (optional) unit-of-measure symbol; otherwise unchanged
  310. \return true, iff the input expression is completely parsed, false otherwise
  311.  
  312. */
  313. bool parse(std::istream& Stream, double&Value, std::string& Units);
  314.  
  315. /**
  316.  
  317. \brief Parses a mathematical expression with optional real-world units-of-measure
  318. \param Buffer Input buffer containing the expression to be parsed
  319. \param Value Iff the input expression is completely parsed, contains the expression value; otherwise unchanged
  320. \param Units Iff the input expression is completely parsed, contains the (optional) unit-of-measure symbol; otherwise unchanged
  321. \return true, iff the input expression is completely parsed, false otherwise
  322.  
  323. */
  324. bool parse(const std::string Buffer, double&Value, std::string& Units);
  325.  
  326. /**
  327.  
  328. \brief Parses a mathematical expression with optional real-world units-of-measure, automatically converting it to the appropriate SI units
  329. \param Buffer Input buffer containing the expression to be parsed
  330. \param Value Iff the input expression is completely parsed, contains the expression value in SI units
  331. \param Units Defines the type of measurement (e.g. angle, distance, time, volume, etc) to be formatted
  332. \return true, iff the input expression is completely parsed, false otherwise
  333.  
  334. */
  335. bool parse(const std::string Buffer, double&Value, const std::type_info* const Units);
  336.  
  337. /// Defines a collection of units of angular measure, keyed by string (typically name or symbol)
  338. typedef std::map<std::string, angle> angle_units_t;
  339. /// Defines a collection of units of area, keyed by string (typically name or symbol)
  340. typedef std::map<std::string, area> area_units_t;
  341. /// Defines a collection of units of distance, keyed by string (typically name or symbol)
  342. typedef std::map<std::string, distance> distance_units_t;
  343. /// Defines a collection of units of force, keyed by string (typically name or symbol)
  344. typedef std::map<std::string, force> force_units_t;
  345. /// Defines a collection of units of mass, keyed by string (typically name or symbol)
  346. typedef std::map<std::string, mass> mass_units_t;
  347. /// Defines a collection of units of pressure, keyed by string (typically name or symbol)
  348. typedef std::map<std::string, pressure> pressure_units_t;
  349. /// Defines a collection of units of time, keyed by string (typically name or symbol)
  350. typedef std::map<std::string, time> time_units_t;
  351. /// Defines a collection of units of volume, keyed by string (typically name or symbol)
  352. typedef std::map<std::string, volume> volume_units_t;
  353.  
  354. /// Returns a singleton collection of common units of angular measure, keyed by symbol
  355. const angle_units_t& angle_units();
  356. /// Returns a singleton collection of common units of area, keyed by symbol
  357. const area_units_t& area_units();
  358. /// Returns a singleton collection of common units of distance, keyed by symbol
  359. const distance_units_t& distance_units();
  360. /// Returns a singleton collection of common units of force, keyed by symbol
  361. const force_units_t& force_units();
  362. /// Returns a singleton collection of common units of mass, keyed by symbol
  363. const mass_units_t& mass_units();
  364. /// Returns a singleton collection of common units of pressure, keyed by symbol
  365. const pressure_units_t& pressure_units();
  366. /// Returns a singleton collection of common units of time, keyed by symbol
  367. const time_units_t& time_units();
  368. /// Returns a singleton collection of common units of volume, keyed by symbol
  369. const volume_units_t& volume_units();
  370.  
  371. /// Returns a reference to a common unit of angular measure keyed by symbol.  Throws std::exception if the symbol is unknown.
  372. const angle& angle_units(const std::string Symbol);
  373. /// Returns a reference to a common unit of area keyed by symbol.  Throws std::exception if the symbol is unknown.
  374. const area& area_units(const std::string Symbol);
  375. /// Returns a reference to a common unit of distance keyed by symbol.  Throws std::exception if the symbol is unknown.
  376. const distance& distance_units(const std::string Symbol);
  377. /// Returns a reference to a common unit of force keyed by symbol.  Throws std::exception if the symbol is unknown.
  378. const force& force_units(const std::string Symbol);
  379. /// Returns a reference to a common unit of mass keyed by symbol.  Throws std::exception if the symbol is unknown.
  380. const mass& mass_units(const std::string Symbol);
  381. /// Returns a reference to a common unit of pressure keyed by symbol.  Throws std::exception if the symbol is unknown.
  382. const pressure& pressure_units(const std::string Symbol);
  383. /// Returns a reference to a common unit of time keyed by symbol.  Throws std::exception if the symbol is unknown.
  384. const time& time_units(const std::string Symbol);
  385. /// Returns a reference to a common unit of volume keyed by symbol.  Throws std::exception if the symbol is unknown.
  386. const volume& volume_units(const std::string Symbol);
  387.  
  388. } // namespace measurement
  389.  
  390. } // namespace k3d
  391.  
  392. #endif // !K3DSDK_MEASUREMENT_H
  393.  
  394.