Coverage Report

Created: 2025-08-25 06:57

/src/geos/src/operation/overlayng/OverlayPoints.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) 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
#include <geos/operation/overlayng/OverlayPoints.h>
16
17
#include <geos/geom/Coordinate.h>
18
#include <geos/geom/CoordinateSequence.h>
19
#include <geos/geom/GeometryFactory.h>
20
#include <geos/geom/PrecisionModel.h>
21
#include <geos/operation/overlayng/OverlayNG.h>
22
#include <geos/operation/overlayng/OverlayUtil.h>
23
24
using namespace geos::geom;
25
26
namespace geos {      // geos
27
namespace operation { // geos.operation
28
namespace overlayng { // geos.operation.overlayng
29
30
struct PointExtractingFilter final: public GeometryComponentFilter {
31
32
    PointExtractingFilter(std::map<CoordinateXY, std::unique_ptr<Point>>& p_ptMap, const PrecisionModel* p_pm)
33
1.01k
        : ptMap(p_ptMap), pm(p_pm)
34
1.01k
    {}
35
36
    void
37
    filter_ro(const Geometry* geom) override
38
197k
    {
39
197k
        if (geom->getGeometryTypeId() != GEOS_POINT) return;
40
41
195k
        const Point* pt = static_cast<const Point*>(geom);
42
        // don't add empty points
43
195k
        if (pt->isEmpty()) return;
44
45
195k
        pt->getCoordinatesRO()->forEach([this, &pt](const auto& coord) -> void {
46
195k
            auto rounded = roundCoord(coord, pm);
47
48
            /**
49
            * Only add first occurrence of a point.
50
            * This provides the merging semantics of overlay
51
            */
52
195k
            if (ptMap.find(rounded) == ptMap.end()) {
53
13.5k
                std::unique_ptr<Point> newPt(pt->getFactory()->createPoint(rounded));
54
13.5k
                ptMap[rounded] = std::move(newPt);
55
13.5k
            }
56
195k
        });
Unexecuted instantiation: void geos::operation::overlayng::PointExtractingFilter::filter_ro(geos::geom::Geometry const*)::{lambda(auto:1 const&)#1}::operator()<geos::geom::CoordinateXY>(geos::geom::CoordinateXY const&) const
void geos::operation::overlayng::PointExtractingFilter::filter_ro(geos::geom::Geometry const*)::{lambda(auto:1 const&)#1}::operator()<geos::geom::Coordinate>(geos::geom::Coordinate const&) const
Line
Count
Source
45
192k
        pt->getCoordinatesRO()->forEach([this, &pt](const auto& coord) -> void {
46
192k
            auto rounded = roundCoord(coord, pm);
47
48
            /**
49
            * Only add first occurrence of a point.
50
            * This provides the merging semantics of overlay
51
            */
52
192k
            if (ptMap.find(rounded) == ptMap.end()) {
53
12.6k
                std::unique_ptr<Point> newPt(pt->getFactory()->createPoint(rounded));
54
12.6k
                ptMap[rounded] = std::move(newPt);
55
12.6k
            }
56
192k
        });
Unexecuted instantiation: void geos::operation::overlayng::PointExtractingFilter::filter_ro(geos::geom::Geometry const*)::{lambda(auto:1 const&)#1}::operator()<geos::geom::CoordinateXYM>(geos::geom::CoordinateXYM const&) const
void geos::operation::overlayng::PointExtractingFilter::filter_ro(geos::geom::Geometry const*)::{lambda(auto:1 const&)#1}::operator()<geos::geom::CoordinateXYZM>(geos::geom::CoordinateXYZM const&) const
Line
Count
Source
45
2.93k
        pt->getCoordinatesRO()->forEach([this, &pt](const auto& coord) -> void {
46
2.93k
            auto rounded = roundCoord(coord, pm);
47
48
            /**
49
            * Only add first occurrence of a point.
50
            * This provides the merging semantics of overlay
51
            */
52
2.93k
            if (ptMap.find(rounded) == ptMap.end()) {
53
911
                std::unique_ptr<Point> newPt(pt->getFactory()->createPoint(rounded));
54
911
                ptMap[rounded] = std::move(newPt);
55
911
            }
56
2.93k
        });
57
195k
    }
58
59
    template<typename CoordType>
60
    static CoordType
61
    roundCoord(const CoordType& p, const PrecisionModel* p_pm)
62
195k
    {
63
195k
        if (OverlayUtil::isFloating(p_pm))
64
195k
            return p;
65
0
        CoordType p2(p);
66
0
        p_pm->makePrecise(p2);
67
0
        return p2;
68
195k
    }
Unexecuted instantiation: geos::geom::CoordinateXY geos::operation::overlayng::PointExtractingFilter::roundCoord<geos::geom::CoordinateXY>(geos::geom::CoordinateXY const&, geos::geom::PrecisionModel const*)
geos::geom::Coordinate geos::operation::overlayng::PointExtractingFilter::roundCoord<geos::geom::Coordinate>(geos::geom::Coordinate const&, geos::geom::PrecisionModel const*)
Line
Count
Source
62
192k
    {
63
192k
        if (OverlayUtil::isFloating(p_pm))
64
192k
            return p;
65
0
        CoordType p2(p);
66
0
        p_pm->makePrecise(p2);
67
0
        return p2;
68
192k
    }
Unexecuted instantiation: geos::geom::CoordinateXYM geos::operation::overlayng::PointExtractingFilter::roundCoord<geos::geom::CoordinateXYM>(geos::geom::CoordinateXYM const&, geos::geom::PrecisionModel const*)
geos::geom::CoordinateXYZM geos::operation::overlayng::PointExtractingFilter::roundCoord<geos::geom::CoordinateXYZM>(geos::geom::CoordinateXYZM const&, geos::geom::PrecisionModel const*)
Line
Count
Source
62
2.93k
    {
63
2.93k
        if (OverlayUtil::isFloating(p_pm))
64
2.93k
            return p;
65
0
        CoordType p2(p);
66
0
        p_pm->makePrecise(p2);
67
0
        return p2;
68
2.93k
    }
69
70
private:
71
    std::map<CoordinateXY, std::unique_ptr<Point>>& ptMap;
72
    const PrecisionModel* pm;
73
};
74
75
/*public static*/
76
std::unique_ptr<Geometry>
77
OverlayPoints::overlay(int opCode, const Geometry* geom0, const Geometry* geom1, const PrecisionModel* pm)
78
509
{
79
509
    OverlayPoints overlay(opCode, geom0, geom1, pm);
80
509
    return overlay.getResult();
81
509
}
82
83
84
/*public*/
85
std::unique_ptr<Geometry>
86
OverlayPoints::getResult()
87
509
{
88
509
    PointMap map0 = buildPointMap(geom0);
89
509
    PointMap map1 = buildPointMap(geom1);
90
91
509
    std::vector<std::unique_ptr<Point>> rsltList;
92
509
    switch (opCode) {
93
112
        case OverlayNG::INTERSECTION: {
94
112
            computeIntersection(map0, map1, rsltList);
95
112
            break;
96
0
        }
97
196
        case OverlayNG::UNION: {
98
196
            computeUnion(map0, map1, rsltList);
99
196
            break;
100
0
        }
101
201
        case OverlayNG::DIFFERENCE: {
102
201
            computeDifference(map0, map1, rsltList);
103
201
            break;
104
0
        }
105
0
        case OverlayNG::SYMDIFFERENCE: {
106
0
            computeDifference(map0, map1, rsltList);
107
0
            computeDifference(map1, map0, rsltList);
108
0
            break;
109
0
        }
110
509
    }
111
509
    if (rsltList.empty()) {
112
99
        uint8_t coordDim = OverlayUtil::resultCoordinateDimension(
113
99
                                            geom0->getCoordinateDimension(), 
114
99
                                            geom1->getCoordinateDimension());
115
99
        return OverlayUtil::createEmptyResult(0, coordDim, geometryFactory);
116
99
    }
117
118
410
    return geometryFactory->buildGeometry(std::move(rsltList));
119
509
}
120
121
/*private*/
122
void
123
OverlayPoints::computeIntersection(PointMap& map0,
124
                    PointMap& map1,
125
                    std::vector<std::unique_ptr<Point>>& rsltList)
126
112
{
127
    // for each entry in map0
128
3.56k
    for (auto& ent : map0) {
129
        // is there an entry in map1?
130
3.56k
        const auto& it = map1.find(ent.first);
131
3.56k
        if (it != map1.end()) {
132
            // add it to the result, taking ownership
133
74
            rsltList.emplace_back(ent.second.release());
134
74
        }
135
3.56k
    }
136
112
}
137
138
/*private*/
139
void
140
OverlayPoints::computeDifference(PointMap& map0,
141
                  PointMap& map1,
142
                  std::vector<std::unique_ptr<Point>>& rsltList)
143
201
{
144
    // for each entry in map0
145
3.63k
    for (auto& ent : map0) {
146
        // is there no entry in map1?
147
3.63k
        const auto& it = map1.find(ent.first);
148
3.63k
        if (it == map1.end()) {
149
            // add it to the result, taking ownership
150
3.55k
            rsltList.emplace_back(ent.second.release());
151
3.55k
        }
152
3.63k
    }
153
201
}
154
155
/*private*/
156
void
157
OverlayPoints::computeUnion(PointMap& map0,
158
             PointMap& map1,
159
             std::vector<std::unique_ptr<Point>>& rsltList)
160
196
{
161
    // take all map0 points
162
1.18k
    for (auto& ent : map0) {
163
1.18k
        rsltList.emplace_back(ent.second.release());
164
1.18k
    }
165
166
    // find any map1 points that aren't already in the result
167
3.48k
    for (auto& ent : map1) {
168
        // is there no entry in map0?
169
3.48k
        const auto& it = map0.find(ent.first);
170
3.48k
        if (it == map0.end()) {
171
            // add it to the result, taking ownership
172
3.41k
            rsltList.emplace_back(ent.second.release());
173
3.41k
        }
174
3.48k
    }
175
196
}
176
177
/*private*/
178
std::map<CoordinateXY, std::unique_ptr<Point>>
179
OverlayPoints::buildPointMap(const Geometry* geom)
180
1.01k
{
181
1.01k
    std::map<CoordinateXY, std::unique_ptr<Point>> map;
182
1.01k
    PointExtractingFilter filter(map, pm);
183
1.01k
    geom->apply_ro(&filter);
184
1.01k
    return map;
185
1.01k
}
186
187
} // namespace geos.operation.overlayng
188
} // namespace geos.operation
189
} // namespace geos