Coverage Report

Created: 2025-10-12 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/include/geos/simplify/PolygonHullSimplifier.h
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2021 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/geom/Geometry.h>
18
#include <geos/util/IllegalArgumentException.h>
19
#include <geos/simplify/RingHull.h>
20
21
22
namespace geos {
23
namespace geom {
24
class GeometryFactory;
25
class LinearRing;
26
class MultiPolygon;
27
class Polygon;
28
}
29
namespace algorithm {
30
namespace hull {
31
class RingHullIndex;
32
}
33
}
34
}
35
36
namespace geos {
37
namespace simplify { // geos::simplify
38
39
/**
40
 * Computes topology-preserving simplified hulls of polygonal geometry.
41
 * Both outer and inner hulls can be computed.
42
 * Outer hulls contain the input geometry and are larger in area.
43
 * Inner hulls are contained by the input geometry and are smaller in area.
44
 * In both the hull vertices are a subset of the input vertices.
45
 * The hull construction attempts to minimize the area difference
46
 * with the input geometry.
47
 * Hulls are generally concave if the input is.
48
 * Computed hulls are topology-preserving:
49
 * they do not contain any self-intersections or overlaps,
50
 * so the result polygonal geometry is valid.
51
 *
52
 * Polygons with holes and MultiPolygons are supported.
53
 * The result has the same geometric type and structure as the input.
54
 *
55
 * The number of vertices in the computed hull is determined by a target parameter.
56
 * Two parameters are supported:
57
 *
58
 *  * Vertex Number fraction: the fraction of the input vertices retained in the result.
59
 *    Value 1 produces the original geometry.
60
 *    Smaller values produce less concave results.
61
 *    For outer hulls, value 0 produces the convex hull (with triangles for any holes).
62
 *    For inner hulls, value 0 produces a triangle (if no holes are present).
63
 *
64
 *  * Area Delta ratio: the ratio of the change in area to the input area.
65
 *    Value 0 produces the original geometry.
66
 *    Larger values produce less concave results.
67
 *
68
 * The algorithm ensures that the result does not cause the target parameter
69
 * to be exceeded.  This allows computing outer or inner hulls
70
 * with a small area delta ratio as an effective way of removing
71
 * narrow gores and spikes.
72
 *
73
 * @author Martin Davis
74
 *
75
 */
76
class GEOS_DLL PolygonHullSimplifier
77
{
78
    using Envelope = geos::geom::Envelope;
79
    using Geometry = geos::geom::Geometry;
80
    using GeometryFactory = geos::geom::GeometryFactory;
81
    using LinearRing = geos::geom::LinearRing;
82
    using MultiPolygon = geos::geom::MultiPolygon;
83
    using Polygon = geos::geom::Polygon;
84
85
public:
86
87
    /**
88
    * Creates a new instance
89
    * to compute a simplified hull of a polygonal geometry.
90
    * An outer or inner hull is computed
91
    * depending on the value of "isOuter".
92
    *
93
    * @param geom the polygonal geometry to process
94
    * @param bOuter indicates whether to compute an outer or inner hull
95
    */
96
    PolygonHullSimplifier(const Geometry* geom, bool bOuter)
97
0
        : inputGeom(geom)
98
0
        , geomFactory(geom->getFactory())
99
0
        , isOuter(bOuter)
100
0
        , vertexNumFraction(-1.0)
101
0
        , areaDeltaRatio(-1.0)
102
0
    {
103
0
        if (!geom->isPolygonal()) {
104
0
            throw util::IllegalArgumentException("Input geometry must be polygonal");
105
0
        }
106
0
    };
107
108
    /**
109
    * Computes a topology-preserving simplified hull of a polygonal geometry,
110
    * with hull shape determined by a target parameter
111
    * specifying the fraction of the input vertices retained in the result.
112
    * Larger values compute less concave results.
113
    * A value of 1 produces the convex hull; a value of 0 produces the original geometry.
114
    * Either outer or inner hulls can be computed.
115
    *
116
    * @param geom the polygonal geometry to process
117
    * @param isOuter indicates whether to compute an outer or inner hull
118
    * @param vertexNumFraction the target fraction of number of input vertices in result
119
    * @return the hull geometry
120
    */
121
    static std::unique_ptr<Geometry> hull(
122
        const Geometry* geom,
123
        bool isOuter,
124
        double vertexNumFraction);
125
126
    /**
127
    * Computes a topology-preserving simplified hull of a polygonal geometry,
128
    * with hull shape determined by a target parameter
129
    * specifying the ratio of maximum difference in area to original area.
130
    * Larger values compute less concave results.
131
    * A value of 0 produces the original geometry.
132
    * Either outer or inner hulls can be computed..
133
    *
134
    * @param geom the polygonal geometry to process
135
    * @param isOuter indicates whether to compute an outer or inner hull
136
    * @param areaDeltaRatio the target ratio of area difference to original area
137
    * @return the hull geometry
138
    */
139
    static std::unique_ptr<Geometry> hullByAreaDelta(
140
        const Geometry* geom,
141
        bool isOuter,
142
        double areaDeltaRatio);
143
144
145
    /**
146
    * Sets the target fraction of input vertices
147
    * which are retained in the result.
148
    * The value should be in the range [0,1].
149
    *
150
    * @param p_vertexNumFraction a fraction of the number of input vertices
151
    */
152
    void setVertexNumFraction(double p_vertexNumFraction);
153
    /**
154
    * Sets the target maximum ratio of the change in area of the result to the input area.
155
    * The value must be 0 or greater.
156
    *
157
    * @param p_areaDeltaRatio a ratio of the change in area of the result
158
    */
159
    void setAreaDeltaRatio(double p_areaDeltaRatio);
160
161
    /**
162
    * Gets the result polygonal hull geometry.
163
    *
164
    * @return the polygonal geometry for the hull
165
    */
166
    std::unique_ptr<Geometry> getResult();
167
168
169
170
private:
171
172
    // Members
173
    const Geometry* inputGeom;
174
    const GeometryFactory* geomFactory;
175
    bool isOuter;
176
    double vertexNumFraction;
177
    double areaDeltaRatio;
178
    // Allocate the RingHull* in here so they are cleaned
179
    // up with PolygonHullSimplifier
180
    std::vector<std::unique_ptr<RingHull>> ringStore;
181
182
    /**
183
    * Computes hulls for MultiPolygon elements for
184
    * the cases where hulls might overlap.
185
    *
186
    * @param multiPoly the MultiPolygon to process
187
    * @return the hull geometry
188
    */
189
    std::unique_ptr<Geometry> computeMultiPolygonAll(const MultiPolygon* multiPoly);
190
    std::unique_ptr<Geometry> computeMultiPolygonEach(const MultiPolygon* multiPoly);
191
    std::unique_ptr<Polygon> computePolygon(const Polygon* poly);
192
193
    /**
194
    * Create all ring hulls for the rings of a polygon,
195
    * so that all are in the hull index if required.
196
    *
197
    * @param poly the polygon being processed
198
    * @param hullIndex the hull index if present, or null
199
    * @return the list of ring hulls
200
    */
201
    std::vector<RingHull*> initPolygon(const Polygon* poly,
202
        RingHullIndex& hullIndex);
203
204
    double ringArea(const Polygon* poly) const;
205
206
    RingHull* createRingHull(
207
        const LinearRing* ring,
208
        bool isOuter,
209
        double areaTotal,
210
        RingHullIndex& hullIndex);
211
212
    std::unique_ptr<Polygon> polygonHull(
213
        const Polygon* poly,
214
        std::vector<RingHull*>& ringHulls,
215
        RingHullIndex& hullIndex) const;
216
217
    /**
218
     * Disable copy construction and assignment. Needed to make this
219
     * class compile under MSVC. (See https://stackoverflow.com/q/29565299)
220
     */
221
    PolygonHullSimplifier(const PolygonHullSimplifier&) = delete;
222
    PolygonHullSimplifier& operator=(const PolygonHullSimplifier&) = delete;
223
224
}; // PolygonHullSimplifier
225
226
227
} // geos::simplify
228
} // geos
229