Coverage Report

Created: 2025-03-15 06:58

/src/geos/src/geom/util/Densifier.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2010 Sandro Santilli <strk@kbt.io>
7
 * Copyright (C) 2005-2006 Refractions Research Inc.
8
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
9
 *
10
 * This is free software; you can redistribute and/or modify it under
11
 * the terms of the GNU Lesser General Public Licence as published
12
 * by the Free Software Foundation.
13
 * See the COPYING file for more information.
14
 *
15
 **********************************************************************
16
 *
17
 * Last port: operation/polygonize/Polygonizer.java rev. 1.6 (JTS-1.10)
18
 *
19
 **********************************************************************/
20
21
#include <cmath>
22
23
#include <geos/geom/util/Densifier.h>
24
#include <geos/geom/CoordinateList.h>
25
#include <geos/geom/Geometry.h>
26
#include <geos/geom/GeometryFactory.h>
27
#include <geos/geom/MultiPoint.h>
28
#include <geos/geom/MultiPolygon.h>
29
#include <geos/geom/MultiLineString.h>
30
#include <geos/geom/CoordinateSequence.h>
31
#include <geos/geom/PrecisionModel.h>
32
#include <geos/geom/Polygon.h>
33
#include <geos/geom/Point.h>
34
#include <geos/geom/LineString.h>
35
#include <geos/geom/LinearRing.h>
36
#include <geos/geom/LineSegment.h>
37
#include <geos/geom/GeometryCollection.h>
38
#include <geos/util/Interrupt.h>
39
#include <geos/util/IllegalArgumentException.h>
40
#include <geos/util.h>
41
42
#include <limits>
43
#include <vector>
44
45
using namespace geos::geom;
46
using namespace geos::geom::util;
47
48
namespace geos {
49
namespace geom { // geos.geom
50
namespace util { // geos.geom.util
51
52
/* geom::util::Densifier::DensifyTransformer */
53
Densifier::DensifyTransformer::DensifyTransformer(double distTol):
54
0
    distanceTolerance(distTol)
55
0
{}
56
57
CoordinateSequence::Ptr
58
Densifier::DensifyTransformer::transformCoordinates(const CoordinateSequence* coords, const Geometry* parent)
59
0
{
60
0
    Coordinate::Vect emptyPts;
61
0
    Coordinate::Vect inputPts;
62
0
    auto newPts = Densifier::densifyPoints(*coords, distanceTolerance, parent->getPrecisionModel());
63
64
0
    if(const LineString* ls = dynamic_cast<const LineString*>(parent)) {
65
0
        if(ls->getNumPoints() <= 1) {
66
0
            newPts->clear();
67
0
        }
68
0
    }
69
70
0
    return newPts;
71
0
}
72
73
Geometry::Ptr
74
Densifier::DensifyTransformer::transformPolygon(const Polygon* geom, const Geometry* parent)
75
0
{
76
0
    Geometry::Ptr roughGeom = GeometryTransformer::transformPolygon(geom, parent);
77
    // don't try and correct if the parent is going to do this
78
0
    if(parent && parent->getGeometryTypeId() == GEOS_MULTIPOLYGON) {
79
0
        return roughGeom;
80
0
    }
81
0
    Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
82
0
    return validGeom;
83
0
}
84
85
Geometry::Ptr
86
Densifier::DensifyTransformer::transformMultiPolygon(const MultiPolygon* geom, const Geometry* parent)
87
0
{
88
0
    Geometry::Ptr roughGeom = GeometryTransformer::transformMultiPolygon(geom, parent);
89
0
    Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
90
0
    return validGeom;
91
0
}
92
93
std::unique_ptr<Geometry>
94
Densifier::DensifyTransformer::createValidArea(const Geometry* roughAreaGeom)
95
0
{
96
0
    if (roughAreaGeom->isValid())
97
0
        return Geometry::Ptr(roughAreaGeom->clone());
98
0
    return roughAreaGeom->buffer(0.0);
99
0
}
100
101
/* util::Densifier */
102
103
Densifier::Densifier(const Geometry* geom):
104
0
    inputGeom(geom)
105
0
{}
106
107
std::unique_ptr<CoordinateSequence>
108
Densifier::densifyPoints(const CoordinateSequence& pts, double distanceTolerance, const PrecisionModel* precModel)
109
0
{
110
0
    geom::LineSegment seg;
111
0
    auto coordList = detail::make_unique<CoordinateSequence>();
112
113
0
    auto items = pts.items<Coordinate>();
114
0
    for(auto it = items.cbegin(), itEnd = items.cend() - 1; it < itEnd; ++it) {
115
0
        seg.p0 = *it;
116
0
        seg.p1 = *(it + 1);
117
0
        coordList->add(seg.p0, false);
118
0
        const double len = seg.getLength();
119
0
        const double densifiedSegCountDbl = ceil(len / distanceTolerance);
120
0
        if(densifiedSegCountDbl > std::numeric_limits<int>::max()) {
121
0
            throw geos::util::GEOSException(
122
0
                "Tolerance is too small compared to geometry length");
123
0
        }
124
125
0
        const int densifiedSegCount = static_cast<int>(densifiedSegCountDbl);
126
0
        if(densifiedSegCount > 1) {
127
0
            double densifiedSegLen = len / densifiedSegCount;
128
0
            for(int j = 1; j < densifiedSegCount; j++) {
129
0
                double segFract = (j * densifiedSegLen) / len;
130
0
                Coordinate p;
131
0
                seg.pointAlong(segFract, p);
132
0
                precModel->makePrecise(p);
133
0
                coordList->add(p, false);
134
0
            }
135
0
        }
136
0
        else {
137
            // no densification required; insert the last coordinate and continue
138
0
            coordList->add(seg.p1, false);
139
0
        }
140
0
    }
141
0
    coordList->add(pts[pts.size() - 1], false);
142
143
0
    return coordList;
144
0
}
145
146
/**
147
 * Densifies a geometry using a given distance tolerance,
148
 * and respecting the input geometry's {@link PrecisionModel}.
149
 *
150
 * @param geom the geometry to densify
151
 * @param distanceTolerance the distance tolerance to densify
152
 * @return the densified geometry
153
 */
154
Geometry::Ptr
155
Densifier::densify(const Geometry* geom, double distTol)
156
0
{
157
0
    util::Densifier densifier(geom);
158
0
    densifier.setDistanceTolerance(distTol);
159
0
    return densifier.getResultGeometry();
160
0
}
161
162
void
163
Densifier::setDistanceTolerance(double tol)
164
0
{
165
    // Test written to catch NaN as well
166
0
    if(!(tol > 0.0)) {
167
0
        throw geos::util::IllegalArgumentException("Tolerance must be positive");
168
0
    }
169
0
    distanceTolerance = tol;
170
0
}
171
172
Geometry::Ptr
173
Densifier::getResultGeometry() const
174
0
{
175
0
    if (inputGeom->isEmpty()) {
176
0
        return inputGeom->clone();
177
0
    }
178
179
0
    DensifyTransformer dt(distanceTolerance);
180
0
    return dt.transform(inputGeom);
181
0
}
182
183
184
} // namespace geos.geom.util
185
} // namespace geos.geom
186
} // namespace geos