Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-02 09:13:36

0001 // Created on: 1993-02-17
0002 // Created by: Remi LEQUETTE
0003 // Copyright (c) 1993-1999 Matra Datavision
0004 // Copyright (c) 1999-2014 OPEN CASCADE SAS
0005 //
0006 // This file is part of Open CASCADE Technology software library.
0007 //
0008 // This library is free software; you can redistribute it and/or modify it under
0009 // the terms of the GNU Lesser General Public License version 2.1 as published
0010 // by the Free Software Foundation, with special exception defined in the file
0011 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0012 // distribution for complete text of the license and disclaimer of any warranty.
0013 //
0014 // Alternatively, this file may be used under the terms of Open CASCADE
0015 // commercial license or contractual agreement.
0016 
0017 #ifndef _Precision_HeaderFile
0018 #define _Precision_HeaderFile
0019 
0020 #include <Standard.hxx>
0021 #include <Standard_DefineAlloc.hxx>
0022 #include <Standard_Real.hxx>
0023 
0024 //! The Precision package offers a set of functions defining precision criteria
0025 //! for use in conventional situations when comparing two numbers.
0026 //! Generalities
0027 //! It is not advisable to use floating number equality. Instead, the difference
0028 //! between numbers must be compared with a given precision, i.e. :
0029 //! double x1, x2 ;
0030 //! x1 = ...
0031 //! x2 = ...
0032 //! If ( x1 == x2 ) ...
0033 //! should not be used and must be written as indicated below:
0034 //! double x1, x2 ;
0035 //! double Precision = ...
0036 //! x1 = ...
0037 //! x2 = ...
0038 //! If ( Abs ( x1 - x2 ) < Precision ) ...
0039 //! Likewise, when ordering floating numbers, you must take the following into account :
0040 //! double x1, x2 ;
0041 //! double Precision = ...
0042 //! x1 = ...       ! a large number
0043 //! x2 = ...       ! another large number
0044 //! If ( x1 < x2 - Precision ) ...
0045 //! is incorrect when x1 and x2 are large numbers ; it is better to write :
0046 //! double x1, x2 ;
0047 //! double Precision = ...
0048 //! x1 = ...       ! a large number
0049 //! x2 = ...       ! another large number
0050 //! If ( x2 - x1 > Precision ) ...
0051 //! Precision in Cas.Cade
0052 //! Generally speaking, the precision criterion is not implicit in Cas.Cade. Low-level geometric
0053 //! algorithms accept precision criteria as arguments. As a rule, they should not refer directly to
0054 //! the precision criteria provided by the Precision package. On the other hand, high-level modeling
0055 //! algorithms have to provide the low-level geometric algorithms that they call, with a precision
0056 //! criteria. One way of doing this is to use the above precision criteria. Alternatively, the
0057 //! high-level algorithms can have their own system for precision management. For example, the
0058 //! Topology Data Structure stores precision criteria for each elementary shape (as a vertex, an
0059 //! edge or a face). When a new topological object is constructed, the precision criteria are taken
0060 //! from those provided by the Precision package, and stored in the related data structure. Later, a
0061 //! topological algorithm which analyses these objects will work with the values stored in the data
0062 //! structure. Also, if this algorithm is to build a new topological object, from these precision
0063 //! criteria, it will compute a new precision criterion for the new topological object, and write it
0064 //! into the data structure of the new topological object. The different precision criteria offered
0065 //! by the Precision package, cover the most common requirements of geometric algorithms, such as
0066 //! intersections, approximations, and so on. The choice of precision depends on the algorithm and
0067 //! on the geometric space. The geometric space may be :
0068 //! -   a "real" 2D or 3D space, where the lengths are measured in meters, millimeters, microns,
0069 //! inches, etc ..., or
0070 //! -   a "parametric" space, 1D on a curve or 2D on a surface, where lengths have no dimension.
0071 //! The choice of precision criteria for real space depends on the choice of the product, as it is
0072 //! based on the accuracy of the machine and the unit of measurement. The choice of precision
0073 //! criteria for parametric space depends on both the accuracy of the machine and the dimensions of
0074 //! the curve or the surface, since the parametric precision criterion and the real precision
0075 //! criterion are linked : if the curve is defined by the equation P(t), the inequation : Abs ( t2 -
0076 //! t1 ) < ParametricPrecision means that the parameters t1 and t2 are considered to be equal, and
0077 //! the inequation : Distance ( P(t2) , P(t1) ) < RealPrecision means that the points P(t1) and
0078 //! P(t2) are considered to be coincident. It seems to be the same idea, and it would be wonderful
0079 //! if these two inequations were equivalent. Note that this is rarely the case ! What is provided
0080 //! in this package? The Precision package provides :
0081 //! -   a set of real space precision criteria for the algorithms, in view of checking distances and
0082 //! angles,
0083 //! -   a set of parametric space precision criteria for the algorithms, in view of checking both :
0084 //! -   the equality of parameters in a parametric space,
0085 //! -   or the coincidence of points in the real space, by using parameter values,
0086 //! -   the notion of infinite value, composed of a value assumed to be infinite, and checking tests
0087 //! designed to verify if any value could be considered as infinite. All the provided functions are
0088 //! very simple. The returned values result from the adaptation of the applications developed by the
0089 //! Open CASCADE company to Open CASCADE algorithms. The main interest of these functions lies in
0090 //! that it incites engineers developing applications to ask questions on precision factors. Which
0091 //! one is to be used in such or such case ? Tolerance criteria are context dependent. They must
0092 //! first choose :
0093 //! -   either to work in real space,
0094 //! -   or to work in parametric space,
0095 //! -   or to work in a combined real and parametric space.
0096 //! They must next decide which precision factor will give the best answer to the current problem.
0097 //! Within an application environment, it is crucial to master precision even though this process
0098 //! may take a great deal of time.
0099 class Precision
0100 {
0101 public:
0102   DEFINE_STANDARD_ALLOC
0103 
0104   //! Returns the recommended precision value
0105   //! when checking the equality of two angles (given in radians).
0106   //! double Angle1 = ... , Angle2 = ... ;
0107   //! If ( std::abs( Angle2 - Angle1 ) < Precision::Angular() ) ...
0108   //! The tolerance of angular equality may be used to check the parallelism of two vectors :
0109   //! gp_Vec V1, V2 ;
0110   //! V1 = ...
0111   //! V2 = ...
0112   //! If ( V1.IsParallel (V2, Precision::Angular() ) ) ...
0113   //! The tolerance of angular equality is equal to 1.e-12.
0114   //! Note : The tolerance of angular equality can be used when working with scalar products or
0115   //! cross products since sines and angles are equivalent for small angles. Therefore, in order to
0116   //! check whether two unit vectors are perpendicular :
0117   //! gp_Dir D1, D2 ;
0118   //! D1 = ...
0119   //! D2 = ...
0120   //! you can use :
0121   //! If ( std::abs( D1.D2 ) < Precision::Angular() ) ...
0122   //! (although the function IsNormal does exist).
0123   static constexpr double Angular() { return 1.e-12; }
0124 
0125   //! Returns the recommended precision value when
0126   //! checking coincidence of two points in real space.
0127   //! The tolerance of confusion is used for testing a 3D
0128   //! distance :
0129   //! -   Two points are considered to be coincident if their
0130   //! distance is smaller than the tolerance of confusion.
0131   //! gp_Pnt P1, P2 ;
0132   //! P1 = ...
0133   //! P2 = ...
0134   //! if ( P1.IsEqual ( P2 , Precision::Confusion() ) )
0135   //! then ...
0136   //! -   A vector is considered to be null if it has a null length :
0137   //! gp_Vec V ;
0138   //! V = ...
0139   //! if ( V.Magnitude() < Precision::Confusion() ) then ...
0140   //! The tolerance of confusion is equal to 1.e-7.
0141   //! The value of the tolerance of confusion is also used to
0142   //! define :
0143   //! -   the tolerance of intersection, and
0144   //! -   the tolerance of approximation.
0145   //! Note : As a rule, coordinate values in Cas.Cade are not
0146   //! dimensioned, so 1. represents one user unit, whatever
0147   //! value the unit may have : the millimeter, the meter, the
0148   //! inch, or any other unit. Let's say that Cas.Cade
0149   //! algorithms are written to be tuned essentially with
0150   //! mechanical design applications, on the basis of the
0151   //! millimeter. However, these algorithms may be used with
0152   //! any other unit but the tolerance criterion does no longer
0153   //! have the same signification.
0154   //! So pay particular attention to the type of your application,
0155   //! in relation with the impact of your unit on the precision criterion.
0156   //! -   For example in mechanical design, if the unit is the
0157   //! millimeter, the tolerance of confusion corresponds to a
0158   //! distance of 1 / 10000 micron, which is rather difficult to measure.
0159   //! -   However in other types of applications, such as
0160   //! cartography, where the kilometer is frequently used,
0161   //! the tolerance of confusion corresponds to a greater
0162   //! distance (1 / 10 millimeter). This distance
0163   //! becomes easily measurable, but only within a restricted
0164   //! space which contains some small objects of the complete scene.
0165   static constexpr double Confusion() { return 1.e-7; }
0166 
0167   //! Returns square of Confusion.
0168   //! Created for speed and convenience.
0169   static constexpr double SquareConfusion() { return Confusion() * Confusion(); }
0170 
0171   //! Returns a precision value at machine epsilon level, used for
0172   //! low-level numerical computations and floating-point comparisons.
0173   //! Unlike the geometric tolerances (Confusion, Intersection, Approximation)
0174   //! which are application-level values for modeling operations, this value
0175   //! represents the fundamental limit of floating-point arithmetic precision.
0176   //!
0177   //! Typical use cases include:
0178   //! -   Checking if squared magnitudes are effectively zero (e.g., vector.SquareMagnitude() <
0179   //! SquareComputational())
0180   //! -   Division-by-zero protection in numerical algorithms
0181   //! -   Convergence criteria in iterative solvers at machine precision level
0182   //! -   Detecting numerical degeneracies in low-level computations
0183   //!
0184   //! The computational tolerance is equal to DBL_EPSILON (approximately 2.22e-16),
0185   //! which is the smallest positive value such that 1.0 + eps != 1.0 in double
0186   //! precision floating-point arithmetic. This is the fundamental machine epsilon
0187   //! for double (double) type.
0188   //!
0189   //! Note: This value should NOT be used for geometric comparisons.
0190   //! Use Precision::Confusion() for comparing geometric distances,
0191   //! Precision::Angular() for angles, etc.
0192   static constexpr double Computational() { return RealEpsilon(); }
0193 
0194   //! Returns square of Computational.
0195   //! Created for speed and convenience when comparing squared values.
0196   static constexpr double SquareComputational() { return Computational() * Computational(); }
0197 
0198   //! Returns the precision value in real space, frequently
0199   //! used by intersection algorithms to decide that a solution is reached.
0200   //! This function provides an acceptable level of precision
0201   //! for an intersection process to define the adjustment limits.
0202   //! The tolerance of intersection is designed to ensure
0203   //! that a point computed by an iterative algorithm as the
0204   //! intersection between two curves is indeed on the
0205   //! intersection. It is obvious that two tangent curves are
0206   //! close to each other, on a large distance. An iterative
0207   //! algorithm of intersection may find points on these
0208   //! curves within the scope of the confusion tolerance, but
0209   //! still far from the true intersection point. In order to force
0210   //! the intersection algorithm to continue the iteration
0211   //! process until a correct point is found on the tangent
0212   //! objects, the tolerance of intersection must be smaller
0213   //! than the tolerance of confusion.
0214   //! On the other hand, the tolerance of intersection must
0215   //! be large enough to minimize the time required by the
0216   //! process to converge to a solution.
0217   //! The tolerance of intersection is equal to :
0218   //! Precision::Confusion() / 100.
0219   //! (that is, 1.e-9).
0220   static constexpr double Intersection() { return Confusion() * 0.01; }
0221 
0222   //! Returns the precision value in real space, frequently used
0223   //! by approximation algorithms.
0224   //! This function provides an acceptable level of precision for
0225   //! an approximation process to define adjustment limits.
0226   //! The tolerance of approximation is designed to ensure
0227   //! an acceptable computation time when performing an
0228   //! approximation process. That is why the tolerance of
0229   //! approximation is greater than the tolerance of confusion.
0230   //! The tolerance of approximation is equal to :
0231   //! Precision::Confusion() * 10.
0232   //! (that is, 1.e-6).
0233   //! You may use a smaller tolerance in an approximation
0234   //! algorithm, but this option might be costly.
0235   static constexpr double Approximation() { return Confusion() * 10.0; }
0236 
0237   //! Convert a real space precision to a parametric
0238   //! space precision. <T> is the mean value of the
0239   //! length of the tangent of the curve or the surface.
0240   //!
0241   //! Value is P / T
0242   static constexpr double Parametric(const double P, const double T) { return P / T; }
0243 
0244   //! Returns a precision value in parametric space, which may be used :
0245   //! -   to test the coincidence of two points in the real space,
0246   //! by using parameter values, or
0247   //! -   to test the equality of two parameter values in a parametric space.
0248   //! The parametric tolerance of confusion is designed to
0249   //! give a mean value in relation with the dimension of
0250   //! the curve or the surface. It considers that a variation of
0251   //! parameter equal to 1. along a curve (or an
0252   //! isoparametric curve of a surface) generates a segment
0253   //! whose length is equal to 100. (default value), or T.
0254   //! The parametric tolerance of confusion is equal to :
0255   //! -   Precision::Confusion() / 100., or Precision::Confusion() / T.
0256   //! The value of the parametric tolerance of confusion is also used to define :
0257   //! -   the parametric tolerance of intersection, and
0258   //! -   the parametric tolerance of approximation.
0259   //! Warning
0260   //! It is rather difficult to define a unique precision value in parametric space.
0261   //! -   First consider a curve (c) ; if M is the point of
0262   //! parameter u and M' the point of parameter u+du on
0263   //! the curve, call 'parametric tangent' at point M, for the
0264   //! variation du of the parameter, the quantity :
0265   //! T(u,du)=MM'/du (where MM' represents the
0266   //! distance between the two points M and M', in the real space).
0267   //! -   Consider the other curve resulting from a scaling
0268   //! transformation of (c) with a scale factor equal to
0269   //! 10. The 'parametric tangent' at the point of
0270   //! parameter u of this curve is ten times greater than the
0271   //! previous one. This shows that for two different curves,
0272   //! the distance between two points on the curve, resulting
0273   //! from the same variation of parameter du, may vary considerably.
0274   //! -   Moreover, the variation of the parameter along the
0275   //! curve is generally not proportional to the curvilinear
0276   //! abscissa along the curve. So the distance between two
0277   //! points resulting from the same variation of parameter
0278   //! du, at two different points of a curve, may completely differ.
0279   //! -   Moreover, the parameterization of a surface may
0280   //! generate two quite different 'parametric tangent' values
0281   //! in the u or in the v parametric direction.
0282   //! -   Last, close to the poles of a sphere (the points which
0283   //! correspond to the values -Pi/2. and Pi/2. of the
0284   //! v parameter) the u parameter may change from 0 to
0285   //! 2.Pi without impacting on the resulting point.
0286   //! Therefore, take great care when adjusting a parametric
0287   //! tolerance to your own algorithm.
0288   static constexpr double PConfusion(const double T) { return Parametric(Confusion(), T); }
0289 
0290   //! Returns square of PConfusion.
0291   //! Created for speed and convenience.
0292   static constexpr double SquarePConfusion() { return PConfusion() * PConfusion(); }
0293 
0294   //! Returns a precision value in parametric space, which
0295   //! may be used by intersection algorithms, to decide that
0296   //! a solution is reached. The purpose of this function is to
0297   //! provide an acceptable level of precision in parametric
0298   //! space, for an intersection process to define the adjustment limits.
0299   //! The parametric tolerance of intersection is
0300   //! designed to give a mean value in relation with the
0301   //! dimension of the curve or the surface. It considers
0302   //! that a variation of parameter equal to 1. along a curve
0303   //! (or an isoparametric curve of a surface) generates a
0304   //! segment whose length is equal to 100. (default value), or T.
0305   //! The parametric tolerance of intersection is equal to :
0306   //! -   Precision::Intersection() / 100., or Precision::Intersection() / T.
0307   static constexpr double PIntersection(const double T) { return Parametric(Intersection(), T); }
0308 
0309   //! Returns a precision value in parametric space, which may
0310   //! be used by approximation algorithms. The purpose of this
0311   //! function is to provide an acceptable level of precision in
0312   //! parametric space, for an approximation process to define
0313   //! the adjustment limits.
0314   //! The parametric tolerance of approximation is
0315   //! designed to give a mean value in relation with the
0316   //! dimension of the curve or the surface. It considers
0317   //! that a variation of parameter equal to 1. along a curve
0318   //! (or an isoparametric curve of a surface) generates a
0319   //! segment whose length is equal to 100. (default value), or T.
0320   //! The parametric tolerance of intersection is equal to :
0321   //! -   Precision::Approximation() / 100., or Precision::Approximation() / T.
0322   static constexpr double PApproximation(const double T) { return Parametric(Approximation(), T); }
0323 
0324   //! Convert a real space precision to a parametric
0325   //! space precision on a default curve.
0326   //!
0327   //! Value is Parametric(P,1.e+2)
0328   static constexpr double Parametric(const double P) { return P * 0.01; }
0329 
0330   //! Used to test distances in parametric space on a
0331   //! default curve.
0332   //!
0333   //! This is Precision::Parametric(Precision::Confusion())
0334   static constexpr double PConfusion() { return Confusion() * 0.01; }
0335 
0336   //! Used for Intersections in parametric space on a
0337   //! default curve.
0338   //!
0339   //! This is Precision::Parametric(Precision::Intersection())
0340   static constexpr double PIntersection() { return Intersection() * 0.01; }
0341 
0342   //! Used for Approximations in parametric space on a
0343   //! default curve.
0344   //!
0345   //! This is Precision::Parametric(Precision::Approximation())
0346   static constexpr double PApproximation() { return Approximation() * 0.01; }
0347 
0348   //! Returns True if R may be considered as an infinite
0349   //! number. Currently std::abs(R) > 1e100
0350   static inline bool IsInfinite(const double R)
0351   {
0352     return std::abs(R) >= (0.5 * Precision::Infinite());
0353   }
0354 
0355   //! Returns True if R may be considered as a positive
0356   //! infinite number. Currently R > 1e100
0357   static constexpr bool IsPositiveInfinite(const double R)
0358   {
0359     return R >= (0.5 * Precision::Infinite());
0360   }
0361 
0362   //! Returns True if R may be considered as a negative
0363   //! infinite number. Currently R < -1e100
0364   static constexpr bool IsNegativeInfinite(const double R)
0365   {
0366     return R <= -(0.5 * Precision::Infinite());
0367   }
0368 
0369   //! Returns a big number that can be considered as
0370   //! infinite. Use -Infinite() for a negative big number.
0371   static constexpr double Infinite() { return 2.e+100; }
0372 };
0373 
0374 #endif // _Precision_HeaderFile