Coverage Report

Created: 2025-11-16 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/operation/distance/FacetSequence.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2016 Daniel Baston
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
 * Last port: operation/distance/FacetSequence.java (f6187ee2 JTS-1.14)
16
 *
17
 **********************************************************************/
18
19
#include <geos/algorithm/Distance.h>
20
#include <geos/operation/distance/FacetSequence.h>
21
22
#include <memory>
23
24
using namespace geos::geom;
25
using namespace geos::operation::distance;
26
using namespace geos::algorithm;
27
28
FacetSequence::FacetSequence(const Geometry *p_geom, const CoordinateSequence* p_pts, std::size_t p_start, std::size_t p_end) :
29
0
    pts(p_pts),
30
0
    start(p_start),
31
0
    end(p_end),
32
0
    geom(p_geom)
33
0
{
34
0
    computeEnvelope();
35
0
}
36
37
FacetSequence::FacetSequence(const CoordinateSequence* p_pts, std::size_t p_start, std::size_t p_end) :
38
0
    pts(p_pts),
39
0
    start(p_start),
40
0
    end(p_end),
41
0
    geom(nullptr)
42
0
{
43
0
    computeEnvelope();
44
0
}
45
46
size_t
47
FacetSequence::size() const
48
0
{
49
0
    return end - start;
50
0
}
51
52
bool
53
FacetSequence::isPoint() const
54
0
{
55
0
    return end - start == 1;
56
0
}
57
58
double
59
FacetSequence::distance(const FacetSequence& facetSeq) const
60
0
{
61
0
    bool isPointThis = isPoint();
62
0
    bool isPointOther = facetSeq.isPoint();
63
64
0
    if(isPointThis && isPointOther) {
65
0
        const Coordinate& pt = pts->getAt(start);
66
0
        const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start);
67
0
        return pt.distance(seqPt);
68
0
    }
69
0
    else if(isPointThis) {
70
0
        const Coordinate& pt = pts->getAt(start);
71
0
        return computeDistancePointLine(pt, facetSeq, nullptr);
72
0
    }
73
0
    else if(isPointOther) {
74
0
        const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start);
75
0
        return computeDistancePointLine(seqPt, *this, nullptr);
76
0
    }
77
0
    else {
78
0
        return computeDistanceLineLine(facetSeq, nullptr);
79
0
    }
80
0
}
81
82
/*
83
* Rather than get bent out of shape about returning a pointer
84
* just return the whole mess, since it only ends up holding two
85
* locations.
86
*/
87
std::vector<GeometryLocation>
88
FacetSequence::nearestLocations(const FacetSequence& facetSeq)  const
89
0
{
90
0
    bool isPointThis = isPoint();
91
0
    bool isPointOther = facetSeq.isPoint();
92
0
    std::vector<GeometryLocation> locs;
93
0
    if (isPointThis && isPointOther) {
94
0
        const Coordinate& pt = pts->getAt(start);
95
0
        const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start);
96
0
        GeometryLocation gl1(geom, start, pt);
97
0
        GeometryLocation gl2(facetSeq.geom, facetSeq.start, seqPt);
98
0
        locs.clear();
99
0
        locs.push_back(gl1);
100
0
        locs.push_back(gl2);
101
0
    }
102
0
    else if (isPointThis) {
103
0
        const Coordinate& pt = pts->getAt(start);
104
0
        computeDistancePointLine(pt, facetSeq, &locs);
105
0
    }
106
0
    else if (isPointOther) {
107
0
        const Coordinate& seqPt = facetSeq.pts->getAt(facetSeq.start);
108
0
        computeDistancePointLine(seqPt, *this, &locs);
109
        // unflip the locations
110
0
        GeometryLocation tmp = locs[0];
111
0
        locs[0] = locs[1];
112
0
        locs[1] = tmp;
113
0
    }
114
0
    else {
115
0
        computeDistanceLineLine(facetSeq, &locs);
116
0
    }
117
0
    return locs;
118
0
}
119
120
double
121
FacetSequence::computeDistancePointLine(const Coordinate& pt,
122
                                        const FacetSequence& facetSeq,
123
                                        std::vector<GeometryLocation> *locs) const
124
0
{
125
0
    double minDistance = DoubleInfinity;
126
127
0
    for(std::size_t i = facetSeq.start; i < facetSeq.end - 1; i++) {
128
0
        const Coordinate& q0 = facetSeq.pts->getAt(i);
129
0
        const Coordinate& q1 = facetSeq.pts->getAt(i + 1);
130
0
        double dist = Distance::pointToSegment(pt, q0, q1);
131
0
        if(dist < minDistance || (locs != nullptr && locs->empty())) {
132
0
            minDistance = dist;
133
0
            if (locs != nullptr) {
134
0
                updateNearestLocationsPointLine(pt, facetSeq, i, q0, q1, locs);
135
0
            }
136
0
            if(minDistance <= 0.0) {
137
0
                return minDistance;
138
0
            }
139
0
        }
140
0
    }
141
142
0
    return minDistance;
143
0
}
144
145
void
146
FacetSequence::updateNearestLocationsPointLine(const Coordinate& pt,
147
        const FacetSequence& facetSeq, std::size_t i,
148
        const Coordinate& q0, const Coordinate &q1,
149
        std::vector<GeometryLocation> *locs) const
150
0
{
151
0
    geom::LineSegment seg(q0, q1);
152
0
    Coordinate segClosestPoint;
153
0
    seg.closestPoint(pt, segClosestPoint);
154
0
    locs->clear();
155
0
    locs->emplace_back(geom, start, pt);
156
0
    locs->emplace_back(facetSeq.geom, i, segClosestPoint);
157
0
    return;
158
0
}
159
160
double
161
FacetSequence::computeDistanceLineLine(const FacetSequence& facetSeq, std::vector<GeometryLocation> *locs) const
162
0
{
163
0
    double minDistance = DoubleInfinity;
164
165
0
    for(std::size_t i = start; i < end - 1; i++) {
166
0
        const Coordinate& p0 = pts->getAt(i);
167
0
        const Coordinate& p1 = pts->getAt(i + 1);
168
169
        // Avoid calculating distance from zero-length segment
170
0
        if (p0 == p1)
171
0
            continue;
172
173
0
        Envelope pEnv(p0, p1);
174
0
        if (pEnv.distanceSquared(*facetSeq.getEnvelope()) > minDistance*minDistance) {
175
0
            continue;
176
0
        }
177
178
0
        for(std::size_t j = facetSeq.start; j < facetSeq.end - 1; j++) {
179
0
            const Coordinate& q0 = facetSeq.pts->getAt(j);
180
0
            const Coordinate& q1 = facetSeq.pts->getAt(j + 1);
181
182
            // Avoid calculating distance to zero-length segment
183
0
            if (q0 == q1)
184
0
                continue;
185
186
0
            Envelope qEnv(q0, q1);
187
0
            if (pEnv.distanceSquared(qEnv) > minDistance*minDistance) {
188
0
                continue;
189
0
            }
190
191
0
            double dist = Distance::segmentToSegment(p0, p1, q0, q1);
192
0
            if(dist <= minDistance) {
193
0
                minDistance = dist;
194
0
                if(locs != nullptr) {
195
0
                    updateNearestLocationsLineLine(i, p0, p1, facetSeq, j, q0, q1, locs);
196
0
                }
197
0
                if(minDistance <= 0.0) return minDistance;
198
0
            }
199
0
        }
200
0
    }
201
202
0
    return minDistance;
203
0
}
204
205
void
206
FacetSequence::updateNearestLocationsLineLine(std::size_t i, const Coordinate& p0, const Coordinate& p1,
207
        const FacetSequence& facetSeq,
208
        std::size_t j, const Coordinate& q0, const Coordinate &q1,
209
        std::vector<GeometryLocation> *locs) const
210
0
{
211
0
    LineSegment seg0(p0, p1);
212
0
    LineSegment seg1(q0, q1);
213
214
0
    auto closestPts = seg0.closestPoints(seg1);
215
216
0
    locs->clear();
217
0
    locs->emplace_back(geom, i, closestPts[0]);
218
0
    locs->emplace_back(facetSeq.geom, j, closestPts[1]);
219
0
}
220
221
void
222
FacetSequence::computeEnvelope()
223
0
{
224
0
    env = Envelope();
225
0
    for(std::size_t i = start; i < end; i++) {
226
0
        env.expandToInclude(pts->getAt(i));
227
0
    }
228
0
}
229
230
const Envelope*
231
FacetSequence::getEnvelope() const
232
0
{
233
0
    return &env;
234
0
}
235
236
const Coordinate*
237
FacetSequence::getCoordinate(std::size_t index) const
238
0
{
239
0
    return &(pts->getAt(start + index));
240
0
}
241