Coverage Report

Created: 2026-05-30 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/include/geos/operation/overlayng/PrecisionUtil.h
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2020 Paul Ramsey <pramsey@cleverelephant.ca>
7
 *
8
 * This is free software; you can redistribute and/or modify it under
9
 * the terms of the GNU Lesser General Public Licence as published
10
 * by the Free Software Foundation.
11
 * See the COPYING file for more information.
12
 *
13
 **********************************************************************/
14
15
#pragma once
16
17
#include <geos/export.h>
18
19
#include <geos/geom/CoordinateFilter.h>
20
#include <geos/geom/Coordinate.h>
21
22
#include <vector>
23
#include <map>
24
25
26
// Forward declarations
27
namespace geos {
28
namespace geom {
29
class Geometry;
30
class Envelope;
31
class PrecisionModel;
32
}
33
namespace operation {
34
}
35
}
36
37
namespace geos {      // geos.
38
namespace operation { // geos.operation
39
namespace overlayng { // geos.operation.overlayng
40
41
/**
42
 * Unions a collection of geometries in an
43
 * efficient way, using {@link OverlayNG}
44
 * to ensure robust computation.
45
 * @author Martin Davis
46
 */
47
class GEOS_DLL PrecisionUtil {
48
    using Geometry = geos::geom::Geometry;
49
    using Envelope = geos::geom::Envelope;
50
    using PrecisionModel = geos::geom::PrecisionModel;
51
    using CoordinateFilter = geos::geom::CoordinateFilter;
52
53
private:
54
55
    static double robustScale(double inherentScale, double safeScale);
56
57
    /**
58
    * Determines the maximum magnitude (absolute value) of the bounds of an
59
    * of an envelope.
60
    * This is equal to the largest ordinate value
61
    * which must be accommodated by a scale factor.
62
    *
63
    */
64
    static double maxBoundMagnitude(const Envelope* env);
65
66
    /**
67
    * Computes the scale factor which will
68
    * produce a given number of digits of precision (significant digits)
69
    * when used to round the given number.
70
    *
71
    * For example: to provide 5 decimal digits of precision
72
    * for the number 123.456 the precision scale factor is 100;
73
    * for 3 digits of precision the scale factor is 1;
74
    * for 2 digits of precision the scale factor is 0.1.
75
    *
76
    * Rounding to the scale factor can be performed with {@link PrecisionModel#round}
77
    *
78
    * @see PrecisionModel.round
79
    */
80
    static double precisionScale(double value, int precisionDigits);
81
82
83
84
public:
85
86
    static constexpr int MAX_ROBUST_DP_DIGITS = 14;
87
88
0
    PrecisionUtil() {};
89
90
    /**
91
    * Determines a precision model to
92
    * use for robust overlay operations.
93
    * The precision scale factor is chosen to maximize
94
    * output precision while avoiding round-off issues.
95
    *
96
    * NOTE: this is a heuristic determination, so is not guaranteed to
97
    * eliminate precision issues.
98
    *
99
    * WARNING: this is quite slow.
100
    */
101
    static PrecisionModel robustPM(const Geometry* a, const Geometry* b);
102
103
    /**
104
    * Determines a precision model to
105
    * use for robust overlay operations for one geometry.
106
    * The precision scale factor is chosen to maximize
107
    * output precision while avoiding round-off issues.
108
    *
109
    * NOTE: this is a heuristic determination, so is not guaranteed to
110
    * eliminate precision issues.
111
    *
112
    * WARNING: this is quite slow.
113
    */
114
    static PrecisionModel robustPM(const Geometry* a);
115
116
    /**
117
    * Determines a scale factor which maximizes
118
    * the digits of precision and is
119
    * safe to use for overlay operations.
120
    * The robust scale is the minimum of the
121
    * inherent scale and the safe scale factors.
122
    */
123
    static double robustScale(const Geometry* a, const Geometry* b);
124
125
    /**
126
    * Determines a scale factor which maximizes
127
    * the digits of precision and is
128
    * safe to use for overlay operations.
129
    * The robust scale is the minimum of the
130
    * inherent scale and the safe scale factors.
131
    */
132
    static double robustScale(const Geometry* a);
133
134
    /**
135
    * Computes a safe scale factor for a numeric value.
136
    * A safe scale factor ensures that rounded
137
    * number has no more than MAX_PRECISION_DIGITS
138
    * digits of precision.
139
    */
140
    static double safeScale(double value);
141
142
    /**
143
    * Computes a safe scale factor for a geometry.
144
    * A safe scale factor ensures that the rounded
145
    * ordinates have no more than MAX_PRECISION_DIGITS
146
    * digits of precision.
147
    */
148
    static double safeScale(const Geometry* geom);
149
150
    /**
151
    * Computes a safe scale factor for two geometries.
152
    * A safe scale factor ensures that the rounded
153
    * ordinates have no more than MAX_PRECISION_DIGITS
154
    * digits of precision.
155
    */
156
    static double safeScale(const Geometry* a, const Geometry* b);
157
158
    /**
159
    * Computes the inherent scale of a number.
160
    * The inherent scale is the scale factor for rounding
161
    * which preserves all digits of precision
162
    * (significant digits)
163
    * present in the numeric value.
164
    * In other words, it is the scale factor which does not
165
    * change the numeric value when rounded:
166
    *
167
    *   num = round( num, inherentScale(num) )
168
    */
169
    static double inherentScale(double value);
170
171
    /**
172
    * Computes the inherent scale of a geometry.
173
    * The inherent scale is the scale factor for rounding
174
    * which preserves <b>all</b> digits of precision
175
    * (significant digits)
176
    * present in the geometry ordinates.
177
    *
178
    * This is the maximum inherent scale
179
    * of all ordinate values in the geometry.
180
    */
181
    static double inherentScale(const Geometry* geom);
182
183
    /**
184
    * Computes the inherent scale of two geometries.
185
    * The inherent scale is the scale factor for rounding
186
    * which preserves <b>all</b> digits of precision
187
    * (significant digits)
188
    * present in the geometry ordinates.
189
    *
190
    * This is the maximum inherent scale
191
    * of all ordinate values in the geometries.
192
    */
193
    static double inherentScale(const Geometry* a, const Geometry* b);
194
195
    /**
196
    * Determines the
197
    * number of decimal places represented in a double-precision
198
    * number (as determined by Java).
199
    * This uses the Java double-precision print routine
200
    * to determine the number of decimal places,
201
    * This is likely not optimal for performance,
202
    * but should be accurate and portable.
203
    */
204
    static int numberOfDecimals(double value);
205
206
    /**
207
    * Applies the inherent scale calculation
208
    * to every ordinate in a geometry.
209
    */
210
    class GEOS_DLL InherentScaleFilter: public CoordinateFilter {
211
212
        private:
213
214
            double scale;
215
216
0
            void updateScaleMax(double value) {
217
0
                double scaleVal = PrecisionUtil::inherentScale(value);
218
0
                if (scaleVal > scale) {
219
0
                    scale = scaleVal;
220
0
                }
221
0
            }
222
223
        public:
224
225
            InherentScaleFilter()
226
0
                : scale(0.0)
227
0
                {}
228
229
            void filter_ro(const geom::Coordinate* coord) override
230
0
            {
231
0
                updateScaleMax(coord->x);
232
0
                updateScaleMax(coord->y);
233
0
            }
234
235
0
            double getScale() const {
236
0
                return scale;
237
0
            }
238
    };
239
240
241
};
242
243
244
} // namespace geos.operation.overlayng
245
} // namespace geos.operation
246
} // namespace geos
247