1 /**********************************************************************
2  *
3  * GEOS - Geometry Engine Open Source
4  * http://geos.osgeo.org
5  *
6  * Copyright (C) 2011 Sandro Santilli <strk@kbt.io>
7  * Copyright (C) 2006 Refractions Research Inc.
8  *
9  * This is free software; you can redistribute and/or modify it under
10  * the terms of the GNU Lesser General Public Licence as published
11  * by the Free Software Foundation.
12  * See the COPYING file for more information.
13  *
14  **********************************************************************
15  *
16  * Last port: geom/PrecisionModel.java r378 (JTS-1.12)
17  *
18  **********************************************************************/
19 
20 #ifndef GEOS_GEOM_PRECISIONMODEL_H
21 #define GEOS_GEOM_PRECISIONMODEL_H
22 
23 #include <geos/export.h>
24 #include <geos/inline.h>
25 
26 
27 #include <string>
28 
29 // Forward declarations
30 namespace geos {
31 namespace io {
32 class Unload;
33 }
34 namespace geom {
35 class Coordinate;
36 }
37 }
38 
39 namespace geos {
40 namespace geom { // geos::geom
41 
42 /**
43  * \class PrecisionModel geom.h geos.h
44  *
45  * \brief Specifies the precision model of the Coordinate in a Geometry.
46  *
47  * In other words, specifies the grid of allowable
48  * points for all <code>Geometry</code>s.
49  *
50  * The makePrecise method allows rounding a coordinate to
51  * a "precise" value; that is, one whose
52  * precision is known exactly.
53  *
54  * Coordinates are assumed to be precise in geometries.
55  * That is, the coordinates are assumed to be rounded to the
56  * precision model given for the geometry.
57  * JTS input routines automatically round coordinates to the precision model
58  * before creating Geometries.
59  * All internal operations
60  * assume that coordinates are rounded to the precision model.
61  * Constructive methods (such as boolean operations) always round computed
62  * coordinates to the appropriate precision model.
63  *
64  * Currently three types of precision model are supported:
65  * - FLOATING - represents full double precision floating point.
66  *   This is the default precision model used in JTS
67  * - FLOATING_SINGLE - represents single precision floating point.
68  * - FIXED - represents a model with a fixed number of decimal places.
69  *   A Fixed Precision Model is specified by a scale factor.
70  *   The scale factor specifies the grid which numbers are rounded to.
71  *   Input coordinates are mapped to fixed coordinates according to the
72  *   following equations:
73  *   - jtsPt.x = round( inputPt.x * scale ) / scale
74  *   - jtsPt.y = round( inputPt.y * scale ) / scale
75  *
76  * For example, to specify 3 decimal places of precision, use a scale factor
77  * of 1000. To specify -3 decimal places of precision (i.e. rounding to
78  * the nearest 1000), use a scale factor of 0.001.
79  *
80  * Coordinates are represented internally as Java double-precision values.
81  * Since Java uses the IEEE-394 floating point standard, this
82  * provides 53 bits of precision. (Thus the maximum precisely representable
83  * integer is 9,007,199,254,740,992).
84  *
85  * JTS methods currently do not handle inputs with different precision models.
86  */
87 class GEOS_DLL PrecisionModel {
88     friend class io::Unload;
89 
90 public:
91 
92     /// The types of Precision Model which GEOS supports.
93     typedef enum {
94 
95         /**
96          * Fixed Precision indicates that coordinates have a fixed
97          * number of decimal places.
98          * The number of decimal places is determined by the log10
99          * of the scale factor.
100          */
101         FIXED,
102 
103         /**
104          * Floating precision corresponds to the standard Java
105          * double-precision floating-point representation, which is
106          * based on the IEEE-754 standard
107          */
108         FLOATING,
109 
110         /**
111          * Floating single precision corresponds to the standard Java
112          * single-precision floating-point representation, which is
113          * based on the IEEE-754 standard
114          */
115         FLOATING_SINGLE
116 
117     } Type;
118 
119     /// Creates a PrecisionModel with a default precision of FLOATING.
120     PrecisionModel(void);
121 
122     /// Creates a PrecisionModel specifying an explicit precision model type.
123     ///
124     /// If the model type is FIXED the scale factor will default to 1.
125     ///
126     /// @param nModelType the type of the precision model
127     ///
128     PrecisionModel(Type nModelType);
129 
130     /** \brief
131      * Creates a <code>PrecisionModel</code> with Fixed precision.
132      *
133      * Fixed-precision coordinates are represented as precise internal
134      * coordinates, which are rounded to the grid defined by the
135      * scale factor.
136      *
137      * @param  newScale  amount by which to multiply a coordinate after
138      *                   subtracting the offset, to obtain a precise coordinate
139      * @param  newOffsetX  not used.
140      * @param  newOffsetY  not used.
141      *
142      * @deprecated offsets are no longer supported, since internal
143      * representation is rounded floating point
144      */
145     PrecisionModel(double newScale, double newOffsetX, double newOffsetY);
146 
147     /**
148      * \brief
149      * Creates a PrecisionModel with Fixed precision.
150      *
151      * Fixed-precision coordinates are represented as precise
152      * internal coordinates which are rounded to the grid defined
153      * by the scale factor.
154      *
155      * @param newScale amount by which to multiply a coordinate
156      * after subtracting the offset, to obtain a precise coordinate
157      */
158     PrecisionModel(double newScale);
159 
160     /// The maximum precise value representable in a double.
161     ///
162     /// Since IEE754 double-precision numbers allow 53 bits of mantissa,
163     /// the value is equal to 2^53 - 1.
164     /// This provides <i>almost</i> 16 decimal digits of precision.
165     ////
166     static const double maximumPreciseValue;
167 
168     /** \brief
169      * Rounds a numeric value to the PrecisionModel grid.
170      *
171      * Asymmetric Arithmetic Rounding is used, to provide
172      * uniform rounding behaviour no matter where the number is
173      * on the number line.
174      *
175      * <b>Note:</b> Java's <code>Math#rint</code> uses the "Banker's Rounding" algorithm,
176      * which is not suitable for precision operations elsewhere in JTS.
177      */
178     double makePrecise(double val) const;
179 
180     /// Rounds the given Coordinate to the PrecisionModel grid.
181     void makePrecise(Coordinate& coord) const;
182 
183     void makePrecise(Coordinate* coord) const;
184 
185     /// Tests whether the precision model supports floating point
186     ///
187     /// @return <code>true</code> if the precision model supports
188     /// floating point
189     ///
190     bool isFloating() const;
191 
192     /// \brief
193     /// Returns the maximum number of significant digits provided by
194     /// this precision model.
195     ///
196     /// Intended for use by routines which need to print out precise
197     /// values.
198     ///
199     /// @return the maximum number of decimal places provided by this
200     /// precision model
201     ///
202     int getMaximumSignificantDigits() const;
203 
204     /// Gets the type of this PrecisionModel
205     ///
206     /// @return the type of this PrecisionModel
207     ///
208     Type getType() const;
209 
210     /// Returns the multiplying factor used to obtain a precise coordinate.
211     double getScale() const;
212 
213     /// Returns the x-offset used to obtain a precise coordinate.
214     ///
215     /// @return the amount by which to subtract the x-coordinate before
216     ///         multiplying by the scale
217     /// @deprecated Offsets are no longer used
218     ///
219     double getOffsetX() const;
220 
221     /// Returns the y-offset used to obtain a precise coordinate.
222     ///
223     /// @return the amount by which to subtract the y-coordinate before
224     ///         multiplying by the scale
225     /// @deprecated Offsets are no longer used
226     ///
227     double getOffsetY() const;
228 
229     /*
230      *  Sets ´internal` to the precise representation of `external`.
231      *
232      * @param external the original coordinate
233      * @param internal the coordinate whose values will be changed to the
234      *                 precise representation of <code>external</code>
235      * @deprecated use makePrecise instead
236      */
237     //void toInternal(const Coordinate& external, Coordinate* internal) const;
238 
239     /*
240      *  Returns the precise representation of <code>external</code>.
241      *
242      *@param  external  the original coordinate
243      *@return
244      *	the coordinate whose values will be changed to the precise
245      *	representation of <code>external</code>
246      * @deprecated use makePrecise instead
247      */
248     //Coordinate* toInternal(const Coordinate& external) const;
249 
250     /*
251      *  Returns the external representation of <code>internal</code>.
252      *
253      *@param  internal  the original coordinate
254      *@return           the coordinate whose values will be changed to the
255      *      external representation of <code>internal</code>
256      * @deprecated no longer needed, since internal representation is same as external representation
257      */
258     //Coordinate* toExternal(const Coordinate& internal) const;
259 
260     /*
261      *  Sets <code>external</code> to the external representation of
262      *  <code>internal</code>.
263      *
264      * @param  internal  the original coordinate
265      * @param  external
266      *	the coordinate whose values will be changed to the
267      *	external representation of <code>internal</code>
268      * @deprecated no longer needed, since internal representation is same as external representation
269      */
270     //void toExternal(const Coordinate& internal, Coordinate* external) const;
271 
272     std::string toString() const;
273 
274     /// \brief
275     /// Compares this PrecisionModel object with the specified object
276     /// for order.
277     ///
278     /// A PrecisionModel is greater than another if it provides greater
279     /// precision.
280     /// The comparison is based on the value returned by the
281     /// getMaximumSignificantDigits method.
282     /// This comparison is not strictly accurate when comparing floating
283     /// precision models to fixed models;
284     /// however, it is correct when both models are either floating or
285     /// fixed.
286     ///
287     /// @param other the PrecisionModel with which this PrecisionModel
288     ///      is being compared
289     /// @return a negative integer, zero, or a positive integer as this
290     ///      PrecisionModel is less than, equal to, or greater than the
291     ///      specified PrecisionModel.
292     ///
293     int compareTo(const PrecisionModel* other) const;
294 
295 private:
296 
297     /** \brief
298      * Sets the multiplying factor used to obtain a precise coordinate.
299      *
300      * This method is private because PrecisionModel is intended to
301      * be an immutable (value) type.
302      *
303      */
304     void setScale(double newScale);
305     // throw IllegalArgumentException
306 
307     Type modelType;
308 
309     double scale;
310 
311 };
312 
313 // Equality operator for PrecisionModel, deprecate it ?
314 //inline bool operator==(const PrecisionModel& a, const PrecisionModel& b);
315 
316 } // namespace geos::geom
317 } // namespace geos
318 
319 #ifdef GEOS_INLINE
320 # include "geos/geom/PrecisionModel.inl"
321 #endif
322 
323 #endif // ndef GEOS_GEOM_PRECISIONMODEL_H
324