Coverage Report

Created: 2026-03-20 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/simplify/ComponentJumpChecker.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2006 Refractions Research Inc.
7
 * Copyright (C) 2023 Martin Davis <mtnclimb@gmail.com>
8
 * Copyright (C) 2023 Paul Ramsey <pramsey@cleverelephant.ca>
9
 *
10
 * This is free software; you can redistribute and/or modify it under
11
 * the terms of the GNU Lesser General Licence as published
12
 * by the Free Software Foundation.
13
 * See the COPYING file for more information.
14
 *
15
 **********************************************************************/
16
17
#include <geos/simplify/ComponentJumpChecker.h>
18
#include <geos/simplify/TaggedLineString.h>
19
20
#include <geos/algorithm/RayCrossingCounter.h>
21
#include <geos/geom/Coordinate.h>
22
#include <geos/geom/CoordinateSequence.h>
23
#include <geos/geom/Envelope.h>
24
#include <geos/geom/LineSegment.h>
25
#include <geos/util.h>
26
27
using geos::algorithm::RayCrossingCounter;
28
using geos::geom::Coordinate;
29
using geos::geom::CoordinateSequence;
30
using geos::geom::Envelope;
31
using geos::geom::LineSegment;
32
33
34
namespace geos {
35
namespace simplify { // geos::simplify
36
37
/**
38
* Checks if a line section jumps a component if flattened.
39
*
40
* Assumes start <= end.
41
*
42
* @param line the line containing the section being flattened
43
* @param start start index of the section
44
* @param end end index of the section
45
* @param seg the flattening segment
46
* @return true if the flattened section jumps a component
47
*/
48
/*public*/
49
bool
50
ComponentJumpChecker::hasJump(
51
    const TaggedLineString* line,
52
    std::size_t start, std::size_t end,
53
    const LineSegment& seg) const
54
0
{
55
0
    Envelope sectionEnv = computeEnvelope(line, start, end);
56
0
    for (TaggedLineString* comp : components) {
57
      //-- don't test component against itself
58
0
        if (comp == line)
59
0
            continue;
60
61
0
        const Coordinate& compPt = comp->getComponentPoint();
62
0
        if (sectionEnv.intersects(compPt)) {
63
0
            if (hasJumpAtComponent(compPt, line, start, end, seg)) {
64
0
                return true;
65
0
            }
66
0
        }
67
0
    }
68
0
    return false;
69
0
}
70
71
72
/**
73
* Checks if two consecutive segments jumps a component if flattened.
74
* The segments are assumed to be consecutive.
75
* (so the seg1.p1 = seg2.p0).
76
* The flattening segment must be the segment between seg1.p0 and seg2.p1.
77
*
78
* @param line the line containing the section being flattened
79
* @param seg1 the first replaced segment
80
* @param seg2 the next replaced segment
81
* @param seg the flattening segment
82
* @return true if the flattened segment jumps a component
83
*/
84
/* public */
85
bool
86
ComponentJumpChecker::hasJump(
87
    const TaggedLineString* line,
88
    const LineSegment* seg1,
89
    const LineSegment* seg2,
90
    const LineSegment& seg) const
91
0
{
92
0
    Envelope sectionEnv = computeEnvelope(seg1, seg2);
93
0
    for (TaggedLineString* comp : components) {
94
        //-- don't test component against itself
95
0
        if (comp == line)
96
0
            continue;
97
98
0
        const Coordinate& compPt = comp->getComponentPoint();
99
0
        if (sectionEnv.intersects(compPt)) {
100
0
            if (hasJumpAtComponent(compPt, seg1, seg2, seg)) {
101
0
                return true;
102
0
            }
103
0
        }
104
0
    }
105
0
    return false;
106
0
}
107
108
109
/*private static*/
110
bool
111
ComponentJumpChecker::hasJumpAtComponent(
112
    const Coordinate& compPt,
113
    const TaggedLineString* line,
114
    std::size_t start, std::size_t end,
115
    const LineSegment& seg)
116
0
{
117
0
    std::size_t sectionCount = crossingCount(compPt, line, start, end);
118
0
    std::size_t segCount = crossingCount(compPt, seg);
119
0
    bool hasJump = sectionCount % 2 != segCount % 2;
120
0
    return hasJump;
121
0
}
122
123
/*private static*/
124
bool
125
ComponentJumpChecker::hasJumpAtComponent(
126
    const Coordinate& compPt,
127
    const LineSegment* seg1, const LineSegment* seg2,
128
    const LineSegment& seg)
129
0
{
130
0
    std::size_t sectionCount = crossingCount(compPt, seg1, seg2);
131
0
    std::size_t segCount = crossingCount(compPt, seg);
132
0
    bool hasJump = sectionCount % 2 != segCount % 2;
133
0
    return hasJump;
134
0
}
135
136
/*private static*/
137
std::size_t
138
ComponentJumpChecker::crossingCount(
139
    const Coordinate& compPt,
140
    const LineSegment& seg)
141
0
{
142
0
    RayCrossingCounter rcc(compPt);
143
0
    rcc.countSegment(seg.p0,  seg.p1);
144
0
    return rcc.getCount();
145
0
}
146
147
/*private static*/
148
std::size_t
149
ComponentJumpChecker::crossingCount(
150
    const Coordinate& compPt,
151
    const LineSegment* seg1, const LineSegment* seg2)
152
0
{
153
0
    RayCrossingCounter rcc(compPt);
154
0
    rcc.countSegment(seg1->p0,  seg1->p1);
155
0
    rcc.countSegment(seg2->p0,  seg2->p1);
156
0
    return rcc.getCount();
157
0
}
158
159
/*private static*/
160
std::size_t
161
ComponentJumpChecker::crossingCount(
162
    const Coordinate& compPt,
163
    const TaggedLineString* line,
164
    std::size_t start, std::size_t end)
165
0
{
166
0
    RayCrossingCounter rcc(compPt);
167
0
    for (std::size_t i = start; i < end; i++) {
168
0
        rcc.countSegment(line->getCoordinate(i), line->getCoordinate(i + 1));
169
0
    }
170
0
    return rcc.getCount();
171
0
}
172
173
/*private static*/
174
Envelope
175
ComponentJumpChecker::computeEnvelope(
176
    const LineSegment* seg1, const LineSegment* seg2)
177
0
{
178
0
    Envelope env;
179
0
    env.expandToInclude(seg1->p0);
180
0
    env.expandToInclude(seg1->p1);
181
0
    env.expandToInclude(seg2->p0);
182
0
    env.expandToInclude(seg2->p1);
183
0
    return env;
184
0
}
185
186
/*private static*/
187
Envelope
188
ComponentJumpChecker::computeEnvelope(
189
    const TaggedLineString* line,
190
    std::size_t start, std::size_t end)
191
0
{
192
0
    Envelope env;
193
0
    for (std::size_t i = start; i <= end; i++) {
194
0
        env.expandToInclude(line->getCoordinate(i));
195
0
    }
196
0
    return env;
197
0
}
198
199
200
201
} // namespace geos::simplify
202
} // namespace geos