Coverage Report

Created: 2025-10-10 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/include/geos/geom/PrecisionModel.h
Line
Count
Source
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
#pragma once
21
22
#include <geos/geom/Coordinate.h>
23
#include <geos/export.h>
24
25
#include <cassert>
26
#include <string>
27
28
// Forward declarations
29
namespace geos {
30
namespace io {
31
}
32
namespace geom {
33
class Coordinate;
34
}
35
}
36
37
namespace geos {
38
namespace geom { // geos::geom
39
40
/**
41
 * \class PrecisionModel geom.h geos.h
42
 *
43
 * \brief Specifies the precision model of the Coordinate in a Geometry.
44
 *
45
 * In other words, specifies the grid of allowable points for a <code>Geometry</code>.
46
 * A precision model may be <b>floating</b> (PrecisionModel::Type::FLOATING or
47
 * PrecisionModel::Type::FLOATING_SINGLE), in which case normal floating-point value semantics apply.
48
 *
49
 * For a PrecisionModel::Type::FIXED precision model the
50
 * makePrecise(geom::Coordinate) method allows rounding a coordinate to
51
 * a "precise" value; that is, one whose precision is known exactly.
52
 *
53
 * Coordinates are assumed to be precise in geometries.
54
 * That is, the coordinates are assumed to be rounded to the
55
 * precision model given for the geometry.
56
 * All internal operations
57
 * assume that coordinates are rounded to the precision model.
58
 * Constructive methods (such as boolean operations) always round computed
59
 * coordinates to the appropriate precision model.
60
 *
61
 * Three types of precision model are supported:
62
 * - FLOATING - represents full double precision floating point.
63
 *   This is the default precision model used in JTS
64
 * - FLOATING_SINGLE - represents single precision floating point.
65
 * - FIXED - represents a model with a fixed number of decimal places.
66
 *   A Fixed Precision Model is specified by a scale factor.
67
 *   The scale factor specifies the grid which numbers are rounded to.
68
 *   Input coordinates are mapped to fixed coordinates according to the
69
 *   following equations:
70
 *   - jtsPt.x = round( inputPt.x * scale ) / scale
71
 *   - jtsPt.y = round( inputPt.y * scale ) / scale
72
 *
73
 * For example, to specify 3 decimal places of precision, use a scale factor
74
 * of 1000. To specify -3 decimal places of precision (i.e. rounding to
75
 * the nearest 1000), use a scale factor of 0.001.
76
 *
77
 * It is also supported to specify a precise grid size
78
 * by providing it as a negative scale factor.
79
 * For example, to specify rounding to the nearest 1000 use a scale factor of -1000.
80
 *
81
 * Coordinates are represented internally as Java double-precision values.
82
 * Java uses the IEEE-394 floating point standard, which
83
 * provides 53 bits of precision. (Thus the maximum precisely representable
84
 * integer is 9,007,199,254,740,992).
85
 *
86
 */
87
class GEOS_DLL PrecisionModel {
88
89
public:
90
91
    /// The types of Precision Model which GEOS supports.
92
    typedef enum {
93
94
        /**
95
         * Fixed Precision indicates that coordinates have a fixed
96
         * number of decimal places.
97
         * The number of decimal places is determined by the log10
98
         * of the scale factor.
99
         */
100
        FIXED,
101
102
        /**
103
         * Floating precision corresponds to the standard Java
104
         * double-precision floating-point representation, which is
105
         * based on the IEEE-754 standard
106
         */
107
        FLOATING,
108
109
        /**
110
         * Floating single precision corresponds to the standard Java
111
         * single-precision floating-point representation, which is
112
         * based on the IEEE-754 standard
113
         */
114
        FLOATING_SINGLE
115
116
    } Type;
117
118
    /// Creates a PrecisionModel with a default precision of FLOATING.
119
    PrecisionModel(void);
120
121
    /// Creates a PrecisionModel specifying an explicit precision model type.
122
    ///
123
    /// If the model type is FIXED the scale factor will default to 1.
124
    ///
125
    /// @param nModelType the type of the precision model
126
    ///
127
    PrecisionModel(Type nModelType);
128
129
    /** \brief
130
     * Creates a <code>PrecisionModel</code> with Fixed precision.
131
     *
132
     * Fixed-precision coordinates are represented as precise internal
133
     * coordinates, which are rounded to the grid defined by the
134
     * scale factor.
135
     *
136
     * @param  newScale  amount by which to multiply a coordinate after
137
     *                   subtracting the offset, to obtain a precise coordinate
138
     * @param  newOffsetX  not used.
139
     * @param  newOffsetY  not used.
140
     *
141
     * @deprecated offsets are no longer supported, since internal
142
     * representation is rounded floating point
143
     */
144
    PrecisionModel(double newScale, double newOffsetX, double newOffsetY);
145
146
    /**
147
     * \brief
148
     * Creates a PrecisionModel with Fixed precision.
149
     *
150
     * Fixed-precision coordinates are represented as precise
151
     * internal coordinates which are rounded to the grid defined
152
     * by the scale factor.
153
     * The provided scale may be negative, to specify an exact grid size.
154
     * The scale is then computed as the reciprocal.
155
     *
156
     * @param newScale amount by which to multiply a coordinate
157
     * after subtracting the offset, to obtain a precise coordinate. Must be non-zero.
158
     */
159
    PrecisionModel(double newScale);
160
161
    /// The maximum precise value representable in a double.
162
    ///
163
    /// Since IEE754 double-precision numbers allow 53 bits of mantissa,
164
    /// the value is equal to 2^53 - 1.
165
    /// This provides <i>almost</i> 16 decimal digits of precision.
166
    ////
167
    static const double maximumPreciseValue;
168
169
    /** \brief
170
     * Rounds a numeric value to the PrecisionModel grid.
171
     *
172
     * Asymmetric Arithmetic Rounding is used, to provide
173
     * uniform rounding behaviour no matter where the number is
174
     * on the number line.
175
     *
176
     * <b>Note:</b> Java's <code>Math#rint</code> uses the "Banker's Rounding" algorithm,
177
     * which is not suitable for precision operations elsewhere in JTS.
178
     */
179
    double makePrecise(double val) const;
180
181
    /// Rounds the given Coordinate to the PrecisionModel grid.
182
    void makePrecise(CoordinateXY& coord) const
183
50.3M
    {
184
        // optimization for full precision
185
50.3M
        if(modelType == FLOATING) {
186
37.2M
            return;
187
37.2M
        }
188
189
13.0M
        coord.x = makePrecise(coord.x);
190
13.0M
        coord.y = makePrecise(coord.y);
191
13.0M
    };
192
193
    void makePrecise(CoordinateXY* coord) const
194
0
    {
195
0
        assert(coord);
196
0
        return makePrecise(*coord);
197
0
    };
198
199
    /// Tests whether the precision model supports floating point
200
    ///
201
    /// @return <code>true</code> if the precision model supports
202
    /// floating point
203
    ///
204
    bool isFloating() const;
205
206
    /// \brief
207
    /// Returns the maximum number of significant digits provided by
208
    /// this precision model.
209
    ///
210
    /// Intended for use by routines which need to print out precise
211
    /// values.
212
    ///
213
    /// @return the maximum number of decimal places provided by this
214
    /// precision model
215
    ///
216
    int getMaximumSignificantDigits() const;
217
218
    /// Gets the type of this PrecisionModel
219
    ///
220
    /// @return the type of this PrecisionModel
221
    ///
222
    Type getType() const
223
0
    {
224
0
        return modelType;
225
0
    };
226
227
    /// Returns the multiplying factor used to obtain a precise coordinate.
228
    double getScale() const
229
18.3k
    {
230
18.3k
        assert(!(scale < 0));
231
18.3k
        return scale;
232
18.3k
    };
233
234
    /**
235
    * Computes the grid size for a fixed precision model.
236
    * This is equal to the reciprocal of the scale factor.
237
    * If the grid size has been set explicitly (via a negative scale factor)
238
    * it will be returned.
239
    *
240
    * @return the grid size at a fixed precision scale.
241
    */
242
    double getGridSize() const
243
0
    {
244
0
        if (isFloating())
245
0
           return DoubleNotANumber;
246
0
247
0
        if (gridSize != 0)
248
0
            return gridSize;
249
0
250
0
        return 1.0 / scale;
251
0
    };
252
253
    /// Returns the x-offset used to obtain a precise coordinate.
254
    ///
255
    /// @return the amount by which to subtract the x-coordinate before
256
    ///         multiplying by the scale
257
    /// @deprecated Offsets are no longer used
258
    ///
259
    double getOffsetX() const;
260
261
    /// Returns the y-offset used to obtain a precise coordinate.
262
    ///
263
    /// @return the amount by which to subtract the y-coordinate before
264
    ///         multiplying by the scale
265
    /// @deprecated Offsets are no longer used
266
    ///
267
    double getOffsetY() const;
268
269
    /*
270
     *  Sets ´internal` to the precise representation of `external`.
271
     *
272
     * @param external the original coordinate
273
     * @param internal the coordinate whose values will be changed to the
274
     *                 precise representation of <code>external</code>
275
     * @deprecated use makePrecise instead
276
     */
277
    //void toInternal(const Coordinate& external, Coordinate* internal) const;
278
279
    /*
280
     *  Returns the precise representation of <code>external</code>.
281
     *
282
     *@param  external  the original coordinate
283
     *@return
284
     *  the coordinate whose values will be changed to the precise
285
     *  representation of <code>external</code>
286
     * @deprecated use makePrecise instead
287
     */
288
    //Coordinate* toInternal(const Coordinate& external) const;
289
290
    /*
291
     *  Returns the external representation of <code>internal</code>.
292
     *
293
     *@param  internal  the original coordinate
294
     *@return           the coordinate whose values will be changed to the
295
     *      external representation of <code>internal</code>
296
     * @deprecated no longer needed, since internal representation is same as external representation
297
     */
298
    //Coordinate* toExternal(const Coordinate& internal) const;
299
300
    /*
301
     *  Sets <code>external</code> to the external representation of
302
     *  <code>internal</code>.
303
     *
304
     * @param  internal  the original coordinate
305
     * @param  external
306
     *  the coordinate whose values will be changed to the
307
     *  external representation of <code>internal</code>
308
     * @deprecated no longer needed, since internal representation is same as external representation
309
     */
310
    //void toExternal(const Coordinate& internal, Coordinate* external) const;
311
312
    std::string toString() const;
313
314
    /// \brief
315
    /// Compares this PrecisionModel object with the specified object
316
    /// for order.
317
    ///
318
    /// A PrecisionModel is greater than another if it provides greater
319
    /// precision.
320
    /// The comparison is based on the value returned by the
321
    /// getMaximumSignificantDigits method.
322
    /// This comparison is not strictly accurate when comparing floating
323
    /// precision models to fixed models;
324
    /// however, it is correct when both models are either floating or
325
    /// fixed.
326
    ///
327
    /// @param other the PrecisionModel with which this PrecisionModel
328
    ///      is being compared
329
    /// @return a negative integer, zero, or a positive integer as this
330
    ///      PrecisionModel is less than, equal to, or greater than the
331
    ///      specified PrecisionModel.
332
    ///
333
    int compareTo(const PrecisionModel* other) const;
334
335
private:
336
337
    /** \brief
338
     * Sets the multiplying factor used to obtain a precise coordinate.
339
     *
340
     * This method is private because PrecisionModel is intended to
341
     * be an immutable (value) type.
342
     *
343
     */
344
    void setScale(double newScale);
345
    // throw IllegalArgumentException
346
347
    /** \brief
348
     * Snaps a value to nearest integer, if within tolerance.
349
     */
350
    static double snapToInt(double val, double tolerance);
351
352
    Type modelType;
353
354
    /**
355
    * The scale factor which determines the number of decimal places in fixed precision.
356
    */
357
    double scale;
358
359
    /**
360
    * If non-zero, the precise grid size specified.
361
    * In this case, the scale is also valid and is computed from the grid size.
362
    * If zero, the scale is used to compute the grid size where needed.
363
    */
364
    double gridSize = 0.0;
365
366
};
367
368
// Equality operator for PrecisionModel, deprecate it ?
369
//inline bool operator==(const PrecisionModel& a, const PrecisionModel& b);
370
371
} // namespace geos::geom
372
} // namespace geos