Coverage Report

Created: 2026-06-13 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/geos/src/geom/Envelope.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * GEOS - Geometry Engine Open Source
4
 * http://geos.osgeo.org
5
 *
6
 * Copyright (C) 2005-2006 Refractions Research Inc.
7
 * Copyright (C) 2001-2002 Vivid Solutions Inc.
8
 *
9
 * This is free software; you can redistribute and/or modify it under
10
 * the terms of the GNU Lesser General Public Licence as published
11
 * by the Free Software Foundation.
12
 * See the COPYING file for more information.
13
 *
14
 **********************************************************************
15
 *
16
 * Last port: geom/Envelope.java rev 1.46 (JTS-1.10)
17
 *
18
 **********************************************************************/
19
20
#include <geos/geom/Envelope.h>
21
#include <geos/geom/Coordinate.h>
22
23
#include <algorithm>
24
#include <sstream>
25
#include <cmath>
26
27
28
#ifndef GEOS_DEBUG
29
#define GEOS_DEBUG 0
30
#endif
31
32
#if GEOS_DEBUG
33
#include <iostream>
34
#endif
35
36
namespace geos {
37
namespace geom { // geos::geom
38
39
/*public*/
40
bool
41
Envelope::intersects(const CoordinateXY& p1, const CoordinateXY& p2,
42
                     const CoordinateXY& q)
43
220M
{
44
    //OptimizeIt shows that Math#min and Math#max here are a bottleneck.
45
    //Replace with direct comparisons. [Jon Aquino]
46
220M
    if(((q.x >= (p1.x < p2.x ? p1.x : p2.x)) && (q.x <= (p1.x > p2.x ? p1.x : p2.x))) &&
47
188M
            ((q.y >= (p1.y < p2.y ? p1.y : p2.y)) && (q.y <= (p1.y > p2.y ? p1.y : p2.y)))) {
48
153M
        return true;
49
153M
    }
50
66.5M
    return false;
51
220M
}
52
53
/*public*/
54
bool
55
Envelope::intersects(const CoordinateXY& a, const CoordinateXY& b) const
56
4.33M
{
57
    // These comparisons look redundant, but an alternative using
58
    // std::minmax performs no better and compiles down to more
59
    // instructions.
60
4.33M
    double envminx = (a.x < b.x) ? a.x : b.x;
61
4.33M
    if(!std::isgreaterequal(maxx, envminx)) { // awkward comparison catches cases where this->isNull()
62
1.98M
        return false;
63
1.98M
    }
64
65
2.34M
    double envmaxx = (a.x > b.x) ? a.x : b.x;
66
2.34M
    if(std::isless(envmaxx, minx)) {
67
27.8k
        return false;
68
27.8k
    }
69
70
2.31M
    double envminy = (a.y < b.y) ? a.y : b.y;
71
2.31M
    if(std::isgreater(envminy, maxy)) {
72
72.4k
        return false;
73
72.4k
    }
74
75
2.24M
    double envmaxy = (a.y > b.y) ? a.y : b.y;
76
2.24M
    if(std::isless(envmaxy, miny)) {
77
21.0k
        return false;
78
21.0k
    }
79
80
2.22M
    return true;
81
2.24M
}
82
83
/*public*/
84
Envelope::Envelope(const std::string& str)
85
0
{
86
    // The string should be in the format:
87
    // Env[7.2:2.3,7.1:8.2]
88
89
    // extract out the values between the [ and ] characters
90
0
    std::string::size_type index = str.find('[');
91
0
    std::string coordString = str.substr(index + 1, str.size() - 1 - 1);
92
93
    // now split apart the string on : and , characters
94
0
    std::vector<std::string> values = split(coordString, ":,");
95
96
    // create a new envelope
97
0
    init(strtod(values[0].c_str(), nullptr),
98
0
         strtod(values[1].c_str(), nullptr),
99
0
         strtod(values[2].c_str(), nullptr),
100
0
         strtod(values[3].c_str(), nullptr));
101
0
}
102
103
/*public*/
104
bool
105
Envelope::covers(const Envelope& other) const
106
49.3k
{
107
49.3k
    return
108
49.3k
        std::isgreaterequal(other.minx,  minx) &&
109
45.3k
        std::islessequal(other.maxx,  maxx) &&
110
40.4k
        std::isgreaterequal(other.miny, miny) &&
111
38.4k
        std::islessequal(other.maxy,  maxy);
112
49.3k
}
113
114
/*public*/
115
bool
116
Envelope::equals(const Envelope* other) const
117
8.14k
{
118
8.14k
    if(isNull()) {
119
0
        return other->isNull();
120
0
    }
121
8.14k
    return  other->minx == minx &&
122
2.47k
            other->maxx == maxx &&
123
532
            other->miny == miny &&
124
214
            other->maxy == maxy;
125
8.14k
}
126
127
bool
128
Envelope::isfinite() const
129
0
{
130
0
    return std::isfinite(minx) && std::isfinite(maxx) &&
131
0
           std::isfinite(miny) && std::isfinite(maxy);
132
0
}
133
134
/* public */
135
std::ostream&
136
operator<< (std::ostream& os, const Envelope& o)
137
0
{
138
0
    os << "Env[" << o.minx << ":" << o.maxx << ","
139
0
       << o.miny << ":" << o.maxy << "]";
140
0
    return os;
141
0
}
142
143
144
/*public*/
145
std::string
146
Envelope::toString() const
147
0
{
148
0
    std::ostringstream s;
149
0
    s << *this;
150
0
    return s.str();
151
0
}
152
153
/*public static*/
154
std::vector<std::string>
155
Envelope::split(const std::string& str, const std::string& delimiters)
156
0
{
157
0
    std::vector<std::string> tokens;
158
159
    // Find first "non-delimiter".
160
0
    std::string::size_type lastPos = 0;
161
0
    std::string::size_type pos = str.find_first_of(delimiters, lastPos);
162
163
0
    while(std::string::npos != pos || std::string::npos != lastPos) {
164
        // Found a token, add it to the vector.
165
0
        tokens.push_back(str.substr(lastPos, pos - lastPos));
166
167
        // Skip delimiters.  Note the "not_of"
168
0
        lastPos = str.find_first_not_of(delimiters, pos);
169
170
        // Find next "non-delimiter"
171
0
        pos = str.find_first_of(delimiters, lastPos);
172
0
    }
173
174
0
    return tokens;
175
0
}
176
177
/*public*/
178
bool
179
Envelope::centre(CoordinateXY& p_centre) const
180
0
{
181
0
    if(isNull()) {
182
0
        return false;
183
0
    }
184
0
    p_centre.x = (getMinX() + getMaxX()) / 2.0;
185
0
    p_centre.y = (getMinY() + getMaxY()) / 2.0;
186
0
    return true;
187
0
}
188
189
/*public*/
190
bool
191
Envelope::intersection(const Envelope& env, Envelope& result) const
192
11.4k
{
193
11.4k
    if(isNull() || env.isNull() || ! intersects(env)) {
194
1
        return false;
195
1
    }
196
197
11.4k
    double intMinX = minx > env.minx ? minx : env.minx;
198
11.4k
    double intMinY = miny > env.miny ? miny : env.miny;
199
11.4k
    double intMaxX = maxx < env.maxx ? maxx : env.maxx;
200
11.4k
    double intMaxY = maxy < env.maxy ? maxy : env.maxy;
201
11.4k
    result.init(intMinX, intMaxX, intMinY, intMaxY);
202
11.4k
    return true;
203
11.4k
}
204
205
/*public*/
206
Envelope
207
Envelope::intersection(const Envelope& env) const
208
0
{
209
0
    Envelope ret;
210
211
0
    if(isNull() || env.isNull() || ! intersects(env)) {
212
0
        return ret;
213
0
    }
214
215
0
    double intMinX = minx > env.minx ? minx : env.minx;
216
0
    double intMinY = miny > env.miny ? miny : env.miny;
217
0
    double intMaxX = maxx < env.maxx ? maxx : env.maxx;
218
0
    double intMaxY = maxy < env.maxy ? maxy : env.maxy;
219
0
    ret.init(intMinX, intMaxX, intMinY, intMaxY);
220
0
    return ret;
221
0
}
222
223
/*public*/
224
void
225
Envelope::translate(double transX, double transY)
226
0
{
227
0
    if(isNull()) {
228
0
        return;
229
0
    }
230
0
    init(getMinX() + transX, getMaxX() + transX,
231
0
         getMinY() + transY, getMaxY() + transY);
232
0
}
233
234
235
/*public*/
236
void
237
Envelope::expandBy(double deltaX, double deltaY)
238
52.0M
{
239
52.0M
    minx -= deltaX;
240
52.0M
    maxx += deltaX;
241
52.0M
    miny -= deltaY;
242
52.0M
    maxy += deltaY;
243
244
    // check for envelope disappearing
245
52.0M
    if(std::isgreater(minx, maxx) || std::isgreater(miny, maxy)) {
246
0
        setToNull();
247
0
    }
248
52.0M
}
249
250
251
bool
252
operator< (const Envelope& a, const Envelope& b)
253
0
{
254
    /*
255
    * Compares two envelopes using lexicographic ordering.
256
    * The ordering comparison is based on the usual numerical
257
    * comparison between the sequence of ordinates.
258
    * Null envelopes are less than all non-null envelopes.
259
    */
260
0
    if (a.isNull()) {
261
        // null == null
262
0
        if (b.isNull())
263
0
            return false;
264
        // null < notnull
265
0
        else
266
0
            return true;
267
0
    }
268
    // notnull > null
269
0
    if (b.isNull())
270
0
        return false;
271
272
    // compare based on numerical ordering of ordinates
273
0
    if (a.getMinX() < b.getMinX()) return true;
274
0
    if (a.getMinX() > b.getMinX()) return false;
275
0
    if (a.getMinY() < b.getMinY()) return true;
276
0
    if (a.getMinY() > b.getMinY()) return false;
277
0
    if (a.getMaxX() < b.getMaxX()) return true;
278
0
    if (a.getMaxX() > b.getMaxX()) return false;
279
0
    if (a.getMaxY() < b.getMaxY()) return true;
280
0
    if (a.getMaxY() > b.getMaxY()) return false;
281
0
    return false; // == is not strictly <
282
0
}
283
284
285
286
} // namespace geos::geom
287
} // namespace geos