New upstream version 3.10.0~beta3
Bas Couwenberg
2 years ago
0 | ## Building GEOS From Source | |
1 | ||
2 | ### Prerequisites | |
3 | ||
4 | GEOS has no external library dependencies and can be built with any C++11 | |
5 | compiler. | |
6 | ||
7 | ### Unix | |
8 | ||
9 | GEOS can be built on Unix systems using the CMake build system. | |
10 | ||
11 | #### Using CMake: | |
12 | ||
13 | To build `GEOS` using CMake, create a build directory and run the `cmake` command | |
14 | from that location: | |
15 | ||
16 | mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. | |
17 | ||
18 | Setting `CMAKE_BUILD_TYPE` to `Release` is necessary to enable compiler | |
19 | optimizations. | |
20 | ||
21 | Once the `cmake` tool has run, GEOS can be built by running `make` and | |
22 | installed by running `make install`. | |
23 | ||
24 | The entire test suite can be run using `make check`. | |
25 | Alternatively, the `ctest` command can be used, which provides more control over test execution. | |
26 | For example, `ctest -R unit-capi -j2` uses a regular expression to run all tests | |
27 | associated with the C API, using two processes in parallel. | |
28 | A list of available tests can be obtained using `ctest -N`. | |
29 | ||
30 | ### Microsoft Windows | |
31 | ||
32 | GEOS can be built with Microsoft Visual C++ by opening the `CMakeLists.txt` in | |
33 | the project root using `File > Open > CMake`. | |
34 | ||
35 | If you prefer the command-line | |
36 | ||
37 | #### Build with CMake generator for Ninja (fast) | |
38 | ||
39 | In the Visual Studio 2019 command prompt, `x64 Native Tools Command Prompt for VS 2019` or `x64_x86 Cross Tools Command Prompt for VS 2019`: | |
40 | ||
41 | ``` | |
42 | cmake -S . -B _build_vs2019_ninja -G Ninja -DCMAKE_BUILD_TYPE=Release | |
43 | cmake --build _build_vs2019_ninja -j 16 --verbose | |
44 | ``` | |
45 | ||
46 | #### Build with CMake generator for MSBuild (default) | |
47 | ||
48 | In the non-specific Command Prompt: | |
49 | ||
50 | ##### 64-bit | |
51 | ||
52 | ``` | |
53 | cmake -S . -B _build_vs2019x64 -G "Visual Studio 16 2019" -A x64 -DCMAKE_GENERATOR_TOOLSET=host=x64 | |
54 | cmake --build _build_vs2019x64 --config Release -j 16 --verbose | |
55 | ``` | |
56 | ||
57 | ##### 32-bit | |
58 | ||
59 | ``` | |
60 | cmake -S . -B _build_vs2019x32 -G "Visual Studio 16 2019" -A x32 -DCMAKE_GENERATOR_TOOLSET=host=x64 | |
61 | cmake --build _build_vs2019x32 --config Release -j 16 --verbose | |
62 | ``` | |
63 | ||
64 | #### Test using CMake | |
65 | ||
66 | ``` | |
67 | cd <build directory> | |
68 | ctest --show-only | |
69 | ctest | |
70 | ctest --output-on-failure | |
71 | ctest -V | |
72 | ctest -VV | |
73 | ``` | |
74 |
0 | ## Building GEOS From Source | |
1 | ||
2 | ### Prerequisites | |
3 | ||
4 | GEOS has no external library dependencies and can be built with any C++11 | |
5 | compiler. | |
6 | ||
7 | ### Unix | |
8 | ||
9 | GEOS can be built on Unix systems using the CMake build system. | |
10 | ||
11 | #### Using CMake: | |
12 | ||
13 | To build `GEOS` using CMake, create a build directory and run the `cmake` command | |
14 | from that location: | |
15 | ||
16 | mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. | |
17 | ||
18 | Setting `CMAKE_BUILD_TYPE` to `Release` is necessary to enable compiler | |
19 | optimizations. | |
20 | ||
21 | Once the `cmake` tool has run, GEOS can be built by | |
22 | ||
23 | * running `make` and installed by running `make install`, or | |
24 | * running `cmake --build .` and `cmake --build . --target install` | |
25 | ||
26 | The entire test suite can be run by | |
27 | ||
28 | * using `make check`, or | |
29 | * using `ctest --output-on-failure .` | |
30 | ||
31 | The `ctest` command can be used to control which tests are run. | |
32 | For example, `ctest -R unit-capi -j2` uses a regular expression to run all tests | |
33 | associated with the C API, using two processes in parallel. | |
34 | A list of available tests can be obtained using `ctest -N`. | |
35 | ||
36 | ### Microsoft Windows | |
37 | ||
38 | GEOS can be built with Microsoft Visual C++ by opening the `CMakeLists.txt` in | |
39 | the project root using `File > Open > CMake`. | |
40 | ||
41 | If you prefer the command-line | |
42 | ||
43 | #### Build with CMake generator for Ninja (fast) | |
44 | ||
45 | In the Visual Studio 2019 command prompt, `x64 Native Tools Command Prompt for VS 2019` or `x64_x86 Cross Tools Command Prompt for VS 2019`: | |
46 | ||
47 | ``` | |
48 | cmake -S . -B _build_vs2019_ninja -G Ninja -DCMAKE_BUILD_TYPE=Release | |
49 | cmake --build _build_vs2019_ninja -j 16 --verbose | |
50 | ``` | |
51 | ||
52 | #### Build with CMake generator for MSBuild (default) | |
53 | ||
54 | In the non-specific Command Prompt: | |
55 | ||
56 | ##### 64-bit | |
57 | ||
58 | ``` | |
59 | cmake -S . -B _build_vs2019x64 -G "Visual Studio 16 2019" -A x64 -DCMAKE_GENERATOR_TOOLSET=host=x64 | |
60 | cmake --build _build_vs2019x64 --config Release -j 16 --verbose | |
61 | ``` | |
62 | ||
63 | ##### 32-bit | |
64 | ||
65 | ``` | |
66 | cmake -S . -B _build_vs2019x32 -G "Visual Studio 16 2019" -A x32 -DCMAKE_GENERATOR_TOOLSET=host=x64 | |
67 | cmake --build _build_vs2019x32 --config Release -j 16 --verbose | |
68 | ``` | |
69 |
113 | 113 | in the default build. To build the documentation, run: |
114 | 114 | |
115 | 115 | cmake -DBUILD_DOCUMENTATION=YES |
116 | make docs | |
116 | cmake --build . --target docs | |
117 | 117 | |
118 | 118 | ## Style |
119 | 119 |
4 | 4 | GEOS_VERSION_PATCH=0 |
5 | 5 | |
6 | 6 | # OPTIONS: "", "dev", "rc1" etc. |
7 | GEOS_PATCH_WORD=beta2 | |
7 | GEOS_PATCH_WORD=beta3 | |
8 | 8 | |
9 | 9 | # GEOS CAPI Versions |
10 | 10 | # |
38 | 38 | class GEOS_DLL Angle { |
39 | 39 | public: |
40 | 40 | |
41 | static const double PI_TIMES_2; // 2.0 * PI; | |
42 | static const double PI_OVER_2; // PI / 2.0; | |
43 | static const double PI_OVER_4; // PI / 4.0; | |
41 | static constexpr double PI_TIMES_2 = 2.0 * MATH_PI; | |
42 | static constexpr double PI_OVER_2 = MATH_PI / 2.0; | |
43 | static constexpr double PI_OVER_4 = MATH_PI / 4.0; | |
44 | 44 | |
45 | 45 | /// Constant representing counterclockwise orientation |
46 | 46 | static const int COUNTERCLOCKWISE = Orientation::COUNTERCLOCKWISE; |
139 | 139 | findNearestPoint(const geom::Coordinate& p, |
140 | 140 | const std::vector<geom::Coordinate>& pts) const |
141 | 141 | { |
142 | double minDistSq = std::numeric_limits<double>::max(); | |
142 | double minDistSq = DoubleInfinity; | |
143 | 143 | geom::Coordinate result = geom::Coordinate::getNull(); |
144 | 144 | for(std::size_t i = 0, n = pts.size(); i < n; ++i) { |
145 | 145 | double distSq = p.distanceSquared(pts[i]); |
16 | 16 | * |
17 | 17 | *********************************************************************/ |
18 | 18 | |
19 | #ifndef INCLUDE_GEOS_CONSTANTS_H_ | |
20 | #define INCLUDE_GEOS_CONSTANTS_H_ | |
19 | #pragma once | |
21 | 20 | |
22 | 21 | #ifdef _MSC_VER |
23 | 22 | #ifndef NOMINMAX |
34 | 33 | |
35 | 34 | constexpr double MATH_PI = 3.14159265358979323846; |
36 | 35 | |
37 | ||
38 | ||
39 | 36 | // Some handy constants |
40 | 37 | constexpr double DoubleNotANumber = std::numeric_limits<double>::quiet_NaN(); |
41 | 38 | constexpr double DoubleMax = (std::numeric_limits<double>::max)(); |
42 | 39 | constexpr double DoubleInfinity = (std::numeric_limits<double>::infinity)(); |
43 | 40 | constexpr double DoubleNegInfinity = (-(std::numeric_limits<double>::infinity)()); |
41 | constexpr double DoubleEpsilon = std::numeric_limits<double>::epsilon(); | |
44 | 42 | |
45 | } // namespace geos | |
43 | } // namespace geos | |
46 | 44 | |
47 | ||
48 | #endif // INCLUDE_GEOS_CONSTANTS_H_ |
34 | 34 | /*public*/ |
35 | 35 | INLINE |
36 | 36 | Envelope::Envelope() : |
37 | minx(std::numeric_limits<double>::quiet_NaN()), | |
38 | maxx(std::numeric_limits<double>::quiet_NaN()), | |
39 | miny(std::numeric_limits<double>::quiet_NaN()), | |
40 | maxy(std::numeric_limits<double>::quiet_NaN()) | |
37 | minx(DoubleNotANumber), | |
38 | maxx(DoubleNotANumber), | |
39 | miny(DoubleNotANumber), | |
40 | maxy(DoubleNotANumber) | |
41 | 41 | {} |
42 | 42 | |
43 | 43 | /*public*/ |
297 | 297 | INLINE void |
298 | 298 | Envelope::setToNull() |
299 | 299 | { |
300 | minx = maxx = miny = maxy = std::numeric_limits<double>::quiet_NaN(); | |
300 | minx = maxx = miny = maxy = DoubleNotANumber; | |
301 | 301 | } |
302 | 302 | |
303 | 303 | INLINE double |
46 | 46 | } |
47 | 47 | |
48 | 48 | ItemPair nearestNeighbour(NodePair& initPair) { |
49 | return nearestNeighbour(initPair, std::numeric_limits<double>::infinity()); | |
49 | return nearestNeighbour(initPair, DoubleInfinity); | |
50 | 50 | } |
51 | 51 | |
52 | 52 | private: |
144 | 144 | NodePair sp = isFlipped ? NodePair(nodeOther, *child, m_id) : NodePair(*child, nodeOther, m_id); |
145 | 145 | |
146 | 146 | // only add to queue if this pair might contain the closest points |
147 | if (minDistance == std::numeric_limits<double>::infinity() || sp.getDistance() < minDistance) { | |
147 | if (minDistance == DoubleInfinity || sp.getDistance() < minDistance) { | |
148 | 148 | priQ.push(sp); |
149 | 149 | } |
150 | 150 | } |
23 | 23 | namespace geos { |
24 | 24 | namespace algorithm { // geos.algorithm |
25 | 25 | |
26 | namespace { | |
27 | const double PI = 3.14159265358979323846; | |
28 | } | |
29 | ||
30 | const double Angle::PI_TIMES_2 = 2.0 * PI; | |
31 | const double Angle::PI_OVER_2 = PI / 2.0; | |
32 | const double Angle::PI_OVER_4 = PI / 4.0; | |
33 | 26 | |
34 | 27 | /* public static */ |
35 | 28 | double |
36 | 29 | Angle::toDegrees(double radians) |
37 | 30 | { |
38 | return (radians * 180) / (PI); | |
31 | return (radians * 180) / (MATH_PI); | |
39 | 32 | } |
40 | 33 | |
41 | 34 | /* public static */ |
42 | 35 | double |
43 | 36 | Angle::toRadians(double angleDegrees) |
44 | 37 | { |
45 | return (angleDegrees * PI) / 180.0; | |
38 | return (angleDegrees * MATH_PI) / 180.0; | |
46 | 39 | } |
47 | 40 | |
48 | 41 | /* public static */ |
115 | 108 | double angDel = a2 - a1; |
116 | 109 | |
117 | 110 | // normalize, maintaining orientation |
118 | if(angDel <= -PI) { | |
111 | if(angDel <= -MATH_PI) { | |
119 | 112 | return angDel + PI_TIMES_2; |
120 | 113 | } |
121 | if(angDel > PI) { | |
114 | if(angDel > MATH_PI) { | |
122 | 115 | return angDel - PI_TIMES_2; |
123 | 116 | } |
124 | 117 | return angDel; |
153 | 146 | double |
154 | 147 | Angle::normalize(double angle) |
155 | 148 | { |
156 | while(angle > PI) { | |
149 | while(angle > MATH_PI) { | |
157 | 150 | angle -= PI_TIMES_2; |
158 | 151 | } |
159 | while(angle <= -PI) { | |
152 | while(angle <= -MATH_PI) { | |
160 | 153 | angle += PI_TIMES_2; |
161 | 154 | } |
162 | 155 | return angle; |
200 | 193 | delAngle = ang1 - ang2; |
201 | 194 | } |
202 | 195 | |
203 | if(delAngle > PI) { | |
204 | delAngle = (2 * PI) - delAngle; | |
196 | if(delAngle > MATH_PI) { | |
197 | delAngle = (2 * MATH_PI) - delAngle; | |
205 | 198 | } |
206 | 199 | |
207 | 200 | return delAngle; |
39 | 39 | |
40 | 40 | InteriorPointLine::InteriorPointLine(const Geometry* g) |
41 | 41 | { |
42 | minDistance = DoubleMax; | |
42 | minDistance = DoubleInfinity; | |
43 | 43 | hasInterior = false; |
44 | 44 | if (g->getCentroid(centroid)) { |
45 | 45 | #if GEOS_DEBUG |
32 | 32 | /*public*/ |
33 | 33 | InteriorPointPoint::InteriorPointPoint(const Geometry* g) |
34 | 34 | { |
35 | minDistance = DoubleMax; | |
35 | minDistance = DoubleInfinity; | |
36 | 36 | if (! g->getCentroid(centroid)) { |
37 | 37 | hasInterior = false; |
38 | 38 | } |
346 | 346 | * intersect. |
347 | 347 | */ |
348 | 348 | Coordinate p; |
349 | double z = std::numeric_limits<double>::quiet_NaN(); | |
349 | double z = DoubleNotANumber; | |
350 | 350 | |
351 | 351 | if(Pq1 == 0 || Pq2 == 0 || Qp1 == 0 || Qp2 == 0) { |
352 | 352 |
298 | 298 | Coordinate |
299 | 299 | MinimumBoundingCircle::pointWitMinAngleWithX(std::vector<Coordinate>& pts, Coordinate& P) |
300 | 300 | { |
301 | double minSin = std::numeric_limits<double>::max(); | |
301 | double minSin = DoubleInfinity; | |
302 | 302 | Coordinate minAngPt; |
303 | 303 | minAngPt.setNull(); |
304 | 304 | for(const auto& p : pts) { |
332 | 332 | MinimumBoundingCircle::pointWithMinAngleWithSegment(std::vector<Coordinate>& pts, Coordinate& P, Coordinate& Q) |
333 | 333 | { |
334 | 334 | assert(!pts.empty()); |
335 | double minAng = std::numeric_limits<double>::max(); | |
335 | double minAng = DoubleInfinity; | |
336 | 336 | const Coordinate* minAngPt = &pts[0]; |
337 | 337 | |
338 | 338 | for(const auto& p : pts) { |
214 | 214 | void |
215 | 215 | MinimumDiameter::computeConvexRingMinDiameter(const CoordinateSequence* pts) |
216 | 216 | { |
217 | minWidth = DoubleMax; | |
217 | minWidth = DoubleInfinity; | |
218 | 218 | unsigned int currMaxIndex = 1; |
219 | 219 | LineSegment seg; |
220 | 220 | |
284 | 284 | double dx = minBaseSeg.p1.x - minBaseSeg.p0.x; |
285 | 285 | double dy = minBaseSeg.p1.y - minBaseSeg.p0.y; |
286 | 286 | |
287 | double minPara = DoubleMax; | |
288 | double maxPara = -DoubleMax; | |
289 | double minPerp = DoubleMax; | |
290 | double maxPerp = -DoubleMax; | |
287 | double minPara = DoubleInfinity; | |
288 | double maxPara = DoubleNegInfinity; | |
289 | double minPerp = DoubleInfinity; | |
290 | double maxPerp = DoubleNegInfinity; | |
291 | 291 | |
292 | 292 | // compute maxima and minima of lines parallel and perpendicular to base segment |
293 | 293 | std::size_t const n = convexHullPts->getSize(); |
166 | 166 | BasicPreparedGeometry::distance(const geom::Geometry* g) const |
167 | 167 | { |
168 | 168 | std::unique_ptr<geom::CoordinateSequence> coords = nearestPoints(g); |
169 | if ( ! coords ) return std::numeric_limits<double>::infinity(); | |
169 | if ( ! coords ) return DoubleInfinity; | |
170 | 170 | return coords->getAt(0).distance( coords->getAt(1) ); |
171 | 171 | } |
172 | 172 |
28 | 28 | { |
29 | 29 | if ( prepLine.getGeometry().isEmpty() || g->isEmpty() ) |
30 | 30 | { |
31 | return std::numeric_limits<double>::infinity(); | |
31 | return DoubleInfinity; | |
32 | 32 | } |
33 | 33 | |
34 | 34 | // TODO: test if this shortcut be any useful |
32 | 32 | { |
33 | 33 | if ( prepPoly.getGeometry().isEmpty() || g->isEmpty() ) |
34 | 34 | { |
35 | return std::numeric_limits<double>::infinity(); | |
35 | return DoubleInfinity; | |
36 | 36 | } |
37 | 37 | |
38 | 38 | if ( prepPoly.intersects(g) ) return 0.0; |
135 | 135 | bp.reset(new BoundablePair(child, bndOther, itemDistance)); |
136 | 136 | } |
137 | 137 | |
138 | if (minDistance == std::numeric_limits<double>::infinity() || bp->getDistance() < minDistance) { | |
138 | if (minDistance == DoubleInfinity || bp->getDistance() < minDistance) { | |
139 | 139 | priQ.push(bp.release()); |
140 | 140 | } |
141 | 141 |
155 | 155 | std::pair<const void*, const void*> |
156 | 156 | STRtree::nearestNeighbour(BoundablePair* initBndPair) |
157 | 157 | { |
158 | return nearestNeighbour(initBndPair, std::numeric_limits<double>::infinity()); | |
158 | return nearestNeighbour(initBndPair, DoubleInfinity); | |
159 | 159 | } |
160 | 160 | |
161 | 161 | /*public*/ |
243 | 243 | /*private*/ |
244 | 244 | bool STRtree::isWithinDistance(BoundablePair* initBndPair, double maxDistance) |
245 | 245 | { |
246 | double distanceUpperBound = std::numeric_limits<double>::infinity(); | |
246 | double distanceUpperBound = DoubleInfinity; | |
247 | 247 | |
248 | 248 | // initialize search queue |
249 | 249 | BoundablePair::BoundablePairQueue priQ; |
58 | 58 | std::pair<const void*, const void*> |
59 | 59 | SimpleSTRdistance::nearestNeighbour(SimpleSTRpair* p_initPair) |
60 | 60 | { |
61 | return nearestNeighbour(p_initPair, std::numeric_limits<double>::infinity()); | |
61 | return nearestNeighbour(p_initPair, DoubleInfinity); | |
62 | 62 | } |
63 | 63 | |
64 | 64 | |
198 | 198 | bool |
199 | 199 | SimpleSTRdistance::isWithinDistance(SimpleSTRpair* p_initPair, double maxDistance) |
200 | 200 | { |
201 | double distanceUpperBound = std::numeric_limits<double>::infinity(); | |
201 | double distanceUpperBound = DoubleInfinity; | |
202 | 202 | |
203 | 203 | // initialize search queue |
204 | 204 | STRpairQueue priQ; |
17 | 17 | **********************************************************************/ |
18 | 18 | |
19 | 19 | #include <geos/io/StringTokenizer.h> |
20 | #include <geos/constants.h> | |
20 | 21 | |
21 | 22 | #include <string> |
22 | 23 | #include <cstdlib> |
57 | 58 | |
58 | 59 | if(stricmp(pos, "inf") == 0) { |
59 | 60 | if(!sign || sign == '+') { |
60 | dbl = std::numeric_limits<double>::infinity(); | |
61 | dbl = DoubleInfinity; | |
61 | 62 | } |
62 | 63 | else { |
63 | dbl = -(std::numeric_limits<double>::infinity)(); | |
64 | dbl = DoubleNegInfinity; | |
64 | 65 | } |
65 | 66 | *str_end[0] = '\0'; |
66 | 67 | } |
67 | 68 | else if(stricmp(pos, "nan") == 0) { |
68 | dbl = std::numeric_limits<double>::quiet_NaN(); | |
69 | dbl = DoubleNotANumber; | |
69 | 70 | *str_end[0] = '\0'; |
70 | 71 | } |
71 | 72 | } |
83 | 83 | double |
84 | 84 | LengthIndexOfPoint::indexOfFromStart(const Coordinate& inputPt, double minIndex) const |
85 | 85 | { |
86 | double minDistance = std::numeric_limits<double>::max(); | |
86 | double minDistance = DoubleInfinity; | |
87 | 87 | |
88 | 88 | double ptMeasure = minIndex; |
89 | 89 | double segmentStartMeasure = 0.0; |
38 | 38 | LocationIndexOfPoint::indexOfFromStart(const Coordinate& inputPt, |
39 | 39 | const LinearLocation* minIndex) const |
40 | 40 | { |
41 | double minDistance = std::numeric_limits<double>::max(); | |
41 | double minDistance = DoubleInfinity; | |
42 | 42 | std::size_t minComponentIndex = 0; |
43 | 43 | std::size_t minSegmentIndex = 0; |
44 | 44 | double minFrac = -1.0; |
48 | 48 | |
49 | 49 | /*private data*/ |
50 | 50 | const double OffsetSegmentGenerator::CURVE_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-6; |
51 | const double OffsetSegmentGenerator::PI = 3.14159265358979; | |
52 | 51 | const double OffsetSegmentGenerator::OFFSET_SEGMENT_SEPARATION_FACTOR = 1.0E-3; |
53 | 52 | const double OffsetSegmentGenerator::INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR = 1.0E-3; |
54 | 53 | const double OffsetSegmentGenerator::SIMPLIFY_FACTOR = 100.0; |
79 | 78 | { |
80 | 79 | // compute intersections in full precision, to provide accuracy |
81 | 80 | // the points are rounded as they are inserted into the curve line |
82 | filletAngleQuantum = PI / 2.0 / bufParams.getQuadrantSegments(); | |
81 | filletAngleQuantum = MATH_PI / 2.0 / bufParams.getQuadrantSegments(); | |
83 | 82 | |
84 | 83 | /* |
85 | 84 | * Non-round joins cause issues with short closing segments, |
204 | 203 | case BufferParameters::CAP_ROUND: |
205 | 204 | // add offset seg points with a fillet between them |
206 | 205 | segList.addPt(offsetL.p1); |
207 | addDirectedFillet(p1, angle + PI / 2.0, angle - PI / 2.0, | |
206 | addDirectedFillet(p1, angle + MATH_PI / 2.0, angle - MATH_PI / 2.0, | |
208 | 207 | Orientation::CLOCKWISE, distance); |
209 | 208 | segList.addPt(offsetR.p1); |
210 | 209 | break; |
246 | 245 | |
247 | 246 | if(direction == Orientation::CLOCKWISE) { |
248 | 247 | if(startAngle <= endAngle) { |
249 | startAngle += 2.0 * PI; | |
248 | startAngle += 2.0 * MATH_PI; | |
250 | 249 | } |
251 | 250 | } |
252 | 251 | else { // direction==COUNTERCLOCKWISE |
253 | 252 | if(startAngle >= endAngle) { |
254 | startAngle -= 2.0 * PI; | |
253 | startAngle -= 2.0 * MATH_PI; | |
255 | 254 | } |
256 | 255 | } |
257 | 256 | |
291 | 290 | // add start point |
292 | 291 | Coordinate pt(p.x + p_distance, p.y); |
293 | 292 | segList.addPt(pt); |
294 | addDirectedFillet(p, 0.0, 2.0 * PI, -1, p_distance); | |
293 | addDirectedFillet(p, 0.0, 2.0 * MATH_PI, -1, p_distance); | |
295 | 294 | segList.closeRing(); |
296 | 295 | } |
297 | 296 | |
510 | 509 | // angle for bisector of the interior angle between the segments |
511 | 510 | double midAng = Angle::normalize(ang0 + angDiffHalf); |
512 | 511 | // rotating this by PI gives the bisector of the reflex angle |
513 | double mitreMidAng = Angle::normalize(midAng + PI); | |
512 | double mitreMidAng = Angle::normalize(midAng + MATH_PI); | |
514 | 513 | |
515 | 514 | // the miterLimit determines the distance to the mitre bevel |
516 | 515 | double mitreDist = p_mitreLimit * p_distance; |
81 | 81 | DistanceOp::DistanceOp(const Geometry* g0, const Geometry* g1): |
82 | 82 | geom{{g0, g1}}, |
83 | 83 | terminateDistance(0.0), |
84 | minDistance(DoubleMax) | |
84 | minDistance(DoubleInfinity) | |
85 | 85 | {} |
86 | 86 | |
87 | 87 | DistanceOp::DistanceOp(const Geometry& g0, const Geometry& g1): |
88 | 88 | geom{{&g0, &g1}}, |
89 | 89 | terminateDistance(0.0), |
90 | minDistance(DoubleMax) | |
90 | minDistance(DoubleInfinity) | |
91 | 91 | {} |
92 | 92 | |
93 | 93 | DistanceOp::DistanceOp(const Geometry& g0, const Geometry& g1, double tdist) |
94 | 94 | : |
95 | 95 | geom{{&g0, &g1}}, |
96 | 96 | terminateDistance(tdist), |
97 | minDistance(DoubleMax) | |
97 | minDistance(DoubleInfinity) | |
98 | 98 | {} |
99 | 99 | |
100 | 100 | /** |
527 | 527 | double distance) |
528 | 528 | { |
529 | 529 | // check envelope distance for a short-circuit negative result |
530 | if ( g0.isEmpty() || g1.isEmpty() ) return false; | |
530 | 531 | const Envelope* env0 = g0.getEnvelopeInternal(); |
531 | 532 | const Envelope* env1 = g1.getEnvelopeInternal(); |
532 | 533 | double envDist = env0->distance(*env1); |
121 | 121 | const FacetSequence& facetSeq, |
122 | 122 | std::vector<GeometryLocation> *locs) const |
123 | 123 | { |
124 | double minDistance = std::numeric_limits<double>::infinity(); | |
124 | double minDistance = DoubleInfinity; | |
125 | 125 | |
126 | 126 | for(std::size_t i = facetSeq.start; i < facetSeq.end - 1; i++) { |
127 | 127 | const Coordinate& q0 = facetSeq.pts->getAt(i); |
159 | 159 | double |
160 | 160 | FacetSequence::computeDistanceLineLine(const FacetSequence& facetSeq, std::vector<GeometryLocation> *locs) const |
161 | 161 | { |
162 | double minDistance = std::numeric_limits<double>::infinity(); | |
162 | double minDistance = DoubleInfinity; | |
163 | 163 | |
164 | 164 | for(std::size_t i = start; i < end - 1; i++) { |
165 | 165 | const Coordinate& p0 = pts->getAt(i); |
141 | 141 | bool |
142 | 142 | EdgeNodingBuilder::hasEdgesFor(uint8_t geomIndex) const |
143 | 143 | { |
144 | assert(geomIndex >= 0 && geomIndex < 2); | |
144 | assert(geomIndex < 2); | |
145 | 145 | return hasEdges[geomIndex]; |
146 | 146 | } |
147 | 147 |
27 | 27 | #include <geos/operation/valid/IndexedNestedHoleTester.h> |
28 | 28 | #include <geos/operation/valid/IndexedNestedPolygonTester.h> |
29 | 29 | #include <geos/util/UnsupportedOperationException.h> |
30 | #include <geos/util/IllegalArgumentException.h> | |
30 | 31 | |
31 | 32 | #include <cmath> |
32 | 33 | |
80 | 81 | IsValidOp::isValidGeometry(const Geometry* g) |
81 | 82 | { |
82 | 83 | validErr.reset(nullptr); |
84 | ||
85 | if (!g) | |
86 | throw util::IllegalArgumentException("Null geometry argument to IsValidOp"); | |
83 | 87 | |
84 | 88 | // empty geometries are always valid |
85 | 89 | if (g->isEmpty()) return true; |
45 | 45 | compute(); |
46 | 46 | |
47 | 47 | // return empty line string if no min pts were found |
48 | if(minClearance == std::numeric_limits<double>::infinity()) { | |
48 | if (minClearance == DoubleInfinity) { | |
49 | 49 | return inputGeom->getFactory()->createLineString(); |
50 | 50 | } |
51 | 51 | |
71 | 71 | |
72 | 72 | public: |
73 | 73 | MinClearanceDistance() : |
74 | minDist(std::numeric_limits<double>::infinity()), | |
74 | minDist(DoubleInfinity), | |
75 | 75 | minPts(std::vector<Coordinate>(2)) |
76 | 76 | {} |
77 | 77 | |
83 | 83 | |
84 | 84 | double operator()(const FacetSequence* fs1, const FacetSequence* fs2) |
85 | 85 | { |
86 | minDist = std::numeric_limits<double>::infinity(); | |
86 | minDist = DoubleInfinity; | |
87 | 87 | return distance(fs1, fs2); |
88 | 88 | } |
89 | 89 | |
166 | 166 | // initialize to "No Distance Exists" state |
167 | 167 | minClearancePts = std::unique_ptr<CoordinateSequence>(inputGeom->getFactory()->getCoordinateSequenceFactory()->create(2, |
168 | 168 | 2)); |
169 | minClearance = std::numeric_limits<double>::infinity(); | |
169 | minClearance = DoubleInfinity; | |
170 | 170 | |
171 | 171 | // handle empty geometries |
172 | 172 | if(inputGeom->isEmpty()) { |
132 | 132 | std::size_t shortestHoleVertexIndex = 0; |
133 | 133 | //--- pick the shell-hole vertex pair that gives the shortest distance |
134 | 134 | if (std::abs(shellCoord.x - holeCoord.x) < EPS) { |
135 | double shortest = std::numeric_limits<double>::max(); | |
135 | double shortest = DoubleInfinity; | |
136 | 136 | for (std::size_t i = 0; i < holeLeftVerticesIndex.size(); i++) { |
137 | 137 | for (std::size_t j = 0; j < shellCoordsList.size(); j++) { |
138 | 138 | double shellCoordY = shellCoordsList[j].y; |
18 | 18 | |
19 | 19 | typedef geos::algorithm::LineIntersector RobustLineIntersector; |
20 | 20 | |
21 | #define DoubleNaN std::numeric_limits<double>::quiet_NaN() | |
22 | ||
23 | 21 | namespace tut { |
24 | 22 | // |
25 | 23 | // Test Group |
184 | 182 | { |
185 | 183 | checkIntersection( |
186 | 184 | line(1, 1, 1, 3, 3, 3), |
187 | line(1, 3, 10, 3, 1, DoubleNaN), | |
185 | line(1, 3, 10, 3, 1, geos::DoubleNotANumber), | |
188 | 186 | pt(2, 2, 6)); |
189 | 187 | } |
190 | 188 | |
205 | 203 | () |
206 | 204 | { |
207 | 205 | checkIntersection( line(1, 1, 3, 3), line(3, 3, 3, 1), |
208 | pt(3, 3, DoubleNaN)); | |
206 | pt(3, 3, geos::DoubleNotANumber)); | |
209 | 207 | } |
210 | 208 | |
211 | 209 | // testEndpoint2D3D |
14 | 14 | #include <geos/geom/PrecisionModel.h> |
15 | 15 | #include <geos/io/WKTReader.h> |
16 | 16 | #include <geos/io/WKTWriter.h> |
17 | #include <geos/constants.h> | |
17 | 18 | // std |
18 | 19 | #include <sstream> |
19 | 20 | #include <string> |
8 | 8 | #include <cstdarg> |
9 | 9 | #include <cstdio> |
10 | 10 | #include <cstdlib> |
11 | #include <fenv.h> | |
11 | 12 | #include <memory> |
12 | 13 | #include <math.h> |
13 | 14 | |
116 | 117 | GEOSGeom_destroy(g2); |
117 | 118 | } |
118 | 119 | |
120 | // point distance does not raise floating point exception | |
121 | template<> | |
122 | template<> | |
123 | void object::test<4> | |
124 | () | |
125 | { | |
126 | GEOSGeometry* g1 = GEOSGeomFromWKT("POINT (0 0)"); | |
127 | GEOSGeometry* g2 = GEOSGeomFromWKT("POINT (1 1)"); | |
128 | ||
129 | // clear all floating point exceptions | |
130 | feclearexcept (FE_ALL_EXCEPT); | |
131 | ||
132 | double d; | |
133 | int status = GEOSDistance(g1, g2, &d); | |
134 | ||
135 | ensure_equals(status, 1); | |
136 | ensure_equals(d, sqrt(2)); | |
137 | ||
138 | // check for floating point overflow exceptions | |
139 | int raised = fetestexcept(FE_OVERFLOW); | |
140 | ensure_equals(raised & FE_OVERFLOW, 0); | |
141 | ||
142 | GEOSGeom_destroy(g1); | |
143 | GEOSGeom_destroy(g2); | |
144 | } | |
145 | ||
146 | // same distance between boundables should not raise floating point exception | |
147 | template<> | |
148 | template<> | |
149 | void object::test<5> | |
150 | () | |
151 | { | |
152 | GEOSGeometry* g1 = GEOSGeomFromWKT("LINESTRING (0 0, 1 1)"); | |
153 | GEOSGeometry* g2 = GEOSGeomFromWKT("LINESTRING (2 1, 1 2)"); | |
154 | ||
155 | // clear all floating point exceptions | |
156 | feclearexcept (FE_ALL_EXCEPT); | |
157 | ||
158 | double d; | |
159 | int status = GEOSDistance(g1, g2, &d); | |
160 | ||
161 | ensure_equals(status, 1); | |
162 | // ensure_equals(d, sqrt(2)); | |
163 | ||
164 | // check for floating point overflow exceptions | |
165 | int raised = fetestexcept(FE_OVERFLOW); | |
166 | ensure_equals(raised & FE_OVERFLOW, 0); | |
167 | ||
168 | GEOSGeom_destroy(g1); | |
169 | GEOSGeom_destroy(g2); | |
170 | } | |
171 | ||
119 | 172 | } // namespace tut |
120 | 173 |
0 | 0 | // |
1 | // Test Suite for C-API GEOSDistance | |
1 | // Test Suite for C-API GEOSDistanceWithin | |
2 | 2 | |
3 | 3 | #include <tut/tut.hpp> |
4 | 4 | // geos |
5 | #include <geos/constants.h> | |
5 | 6 | #include <geos_c.h> |
6 | #include <geos/constants.h> | |
7 | 7 | // std |
8 | #include <limits> | |
8 | 9 | #include <cstdarg> |
9 | 10 | #include <cstdio> |
10 | 11 | #include <cstdlib> |
12 | #include <math.h> | |
11 | 13 | #include <memory> |
12 | #include <math.h> | |
13 | 14 | |
14 | 15 | #include "capi_test_utils.h" |
15 | 16 | |
18 | 19 | // Test Group |
19 | 20 | // |
20 | 21 | |
21 | // Common data used in test cases. | |
22 | 22 | struct test_capigeosdistancewithin_data : public capitest::utility { |
23 | test_capigeosdistancewithin_data() { | |
24 | GEOSWKTWriter_setTrim(wktw_, 1); | |
25 | } | |
23 | void testGEOSDistanceWithin(const char* wkt1, const char* wkt2, | |
24 | double distance, char expectedResult) { | |
25 | ||
26 | GEOSGeometry *input1 = GEOSGeomFromWKT(wkt1); | |
27 | ensure(input1 != nullptr); | |
28 | GEOSGeometry *input2 = GEOSGeomFromWKT(wkt2); | |
29 | ensure(input2 != nullptr); | |
30 | ||
31 | char ret = GEOSDistanceWithin(input1, input2, distance); | |
32 | ||
33 | GEOSGeom_destroy(input1); | |
34 | GEOSGeom_destroy(input2); | |
35 | ||
36 | ensure_equals("return code", (int)ret, (int)expectedResult); | |
37 | ||
38 | }; | |
26 | 39 | }; |
27 | 40 | |
28 | 41 | typedef test_group<test_capigeosdistancewithin_data> group; |
30 | 43 | |
31 | 44 | group test_capigeosdistancewithin_group("capi::GEOSDistanceWithin"); |
32 | 45 | |
33 | // | |
34 | // Test Cases | |
35 | // | |
36 | ||
37 | template<> | |
38 | template<> | |
39 | void object::test<1> | |
40 | () | |
41 | { | |
42 | geom1_ = GEOSGeomFromWKT("POINT(10 10)"); | |
43 | geom2_ = GEOSGeomFromWKT("POINT(3 6)"); | |
44 | ||
45 | double dist = 8.1; | |
46 | char ret = GEOSDistanceWithin(geom1_, geom2_, dist); | |
47 | ensure_equals(ret, 1); | |
48 | ||
49 | ret = GEOSDistanceWithin(geom1_, geom2_, dist-0.1); | |
50 | ensure_equals(ret, 0); | |
51 | } | |
46 | // point within distance should return true | |
47 | template <> | |
48 | template <> | |
49 | void object::test<1>() { | |
50 | testGEOSDistanceWithin( | |
51 | "POINT(0 0)", | |
52 | "POINT(0 1)", | |
53 | 1.0, | |
54 | 1 | |
55 | ); | |
56 | } | |
57 | ||
58 | // point not within distance should return false | |
59 | template <> | |
60 | template <> | |
61 | void object::test<2>() { | |
62 | testGEOSDistanceWithin( | |
63 | "POINT(0 0)", | |
64 | "POINT(0 1)", | |
65 | 0.999999, | |
66 | 0 | |
67 | ); | |
68 | } | |
69 | ||
70 | // point at same location should return true even if distance is 0 | |
71 | template <> | |
72 | template <> | |
73 | void object::test<3>() { | |
74 | testGEOSDistanceWithin( | |
75 | "POINT(0 0)", | |
76 | "POINT(0 0)", | |
77 | 0.0, | |
78 | 1 | |
79 | ); | |
80 | } | |
81 | ||
82 | // line within distance of another line should return true | |
83 | template <> | |
84 | template <> | |
85 | void object::test<4>() { | |
86 | testGEOSDistanceWithin( | |
87 | "LINESTRING(0 0, 1 1)", | |
88 | "LINESTRING(0 1, 1 2)", | |
89 | 1.0, | |
90 | 1 | |
91 | ); | |
92 | } | |
93 | ||
94 | // line not within distance of another line should return false | |
95 | template <> | |
96 | template <> | |
97 | void object::test<5>() { | |
98 | testGEOSDistanceWithin( | |
99 | "LINESTRING(0 0, 1 0)", | |
100 | "LINESTRING(0 1, 1 1)", | |
101 | 0.999999, | |
102 | 0 | |
103 | ); | |
104 | } | |
105 | ||
106 | // line that equals another line should return true even if distance is 0 | |
107 | template <> | |
108 | template <> | |
109 | void object::test<6>() { | |
110 | testGEOSDistanceWithin( | |
111 | "LINESTRING(0 0, 1 1)", | |
112 | "LINESTRING(0 0, 1 1)", | |
113 | 0.0, | |
114 | 1 | |
115 | ); | |
116 | } | |
117 | ||
118 | // line that intersects another line should return true even if distance is 0 | |
119 | template <> | |
120 | template <> | |
121 | void object::test<7>() { | |
122 | testGEOSDistanceWithin( | |
123 | "LINESTRING(0 0, 1 1)", | |
124 | "LINESTRING(1 1, 0 0)", | |
125 | 0.0, | |
126 | 1 | |
127 | ); | |
128 | } | |
129 | ||
130 | // line that shares segment with other line should return true even if distance is 0 | |
131 | template <> | |
132 | template <> | |
133 | void object::test<8>() { | |
134 | testGEOSDistanceWithin( | |
135 | "LINESTRING(0 0, 2 2)", | |
136 | "LINESTRING(0 0, 1 1)", | |
137 | 0.0, | |
138 | 1 | |
139 | ); | |
140 | } | |
141 | ||
142 | ||
143 | // point within distance of line should return true | |
144 | template <> | |
145 | template <> | |
146 | void object::test<9>() { | |
147 | testGEOSDistanceWithin( | |
148 | "LINESTRING(0 0, 1 1)", | |
149 | "POINT( 0 1)", | |
150 | 1.0, | |
151 | 1 | |
152 | ); | |
153 | } | |
154 | ||
155 | // point not within distance of line should return false | |
156 | template <> | |
157 | template <> | |
158 | void object::test<10>() { | |
159 | testGEOSDistanceWithin( | |
160 | "LINESTRING(0 0, 1 0)", | |
161 | "POINT(0 1)", | |
162 | 0.999999, | |
163 | 0 | |
164 | ); | |
165 | } | |
166 | ||
167 | // line within distance of point should return true | |
168 | template <> | |
169 | template <> | |
170 | void object::test<11>() { | |
171 | testGEOSDistanceWithin( | |
172 | "POINT( 0 1)", | |
173 | "LINESTRING(0 0, 1 1)", | |
174 | 1.0, | |
175 | 1 | |
176 | ); | |
177 | } | |
178 | ||
179 | // line not within distance of point should return false | |
180 | template <> | |
181 | template <> | |
182 | void object::test<12>() { | |
183 | testGEOSDistanceWithin( | |
184 | "POINT(0 1)", | |
185 | "LINESTRING(0 0, 1 0)", | |
186 | 0.999999, | |
187 | 0 | |
188 | ); | |
189 | } | |
190 | ||
191 | ||
192 | ||
193 | // point that intersects line should return true even if distance is 0 | |
194 | template <> | |
195 | template <> | |
196 | void object::test<13>() { | |
197 | testGEOSDistanceWithin( | |
198 | "LINESTRING(0 0, 1 1)", | |
199 | "POINT(0.5 0.5)", | |
200 | 0.0, | |
201 | 1 | |
202 | ); | |
203 | } | |
204 | ||
205 | // polygon within distance of other polygon should return true | |
206 | template <> | |
207 | template <> | |
208 | void object::test<14>() { | |
209 | testGEOSDistanceWithin( | |
210 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
211 | "POLYGON((0 3, 2 3, 1 2, 0 3))", | |
212 | 1.0, | |
213 | 1 | |
214 | ); | |
215 | } | |
216 | ||
217 | // polygon not within distance of other polygon should return true | |
218 | template <> | |
219 | template <> | |
220 | void object::test<15>() { | |
221 | testGEOSDistanceWithin( | |
222 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
223 | "POLYGON((0 3, 2 3, 1 2, 0 3))", | |
224 | 0.999999, | |
225 | 0 | |
226 | ); | |
227 | } | |
228 | ||
229 | // polygon that intersects polygon should return true even if distance is 0 | |
230 | template <> | |
231 | template <> | |
232 | void object::test<16>() { | |
233 | testGEOSDistanceWithin( | |
234 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
235 | "POLYGON((0 3, 2 3, 1 0, 0 3))", | |
236 | 0.0, | |
237 | 1 | |
238 | ); | |
239 | } | |
240 | ||
241 | // polygon that is equal to polygon should return true even if distance is 0 | |
242 | template <> | |
243 | template <> | |
244 | void object::test<17>() { | |
245 | testGEOSDistanceWithin( | |
246 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
247 | "POLYGON((1 1, 2 0, 0 0, 1 1))", | |
248 | 0.0, | |
249 | 1 | |
250 | ); | |
251 | } | |
252 | ||
253 | // point within distance of polygon should return true | |
254 | template <> | |
255 | template <> | |
256 | void object::test<18>() { | |
257 | testGEOSDistanceWithin( | |
258 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
259 | "POINT(1 2)", | |
260 | 1.0, | |
261 | 1 | |
262 | ); | |
263 | } | |
264 | ||
265 | // point not within distance of polygon should return false | |
266 | template <> | |
267 | template <> | |
268 | void object::test<19>() { | |
269 | testGEOSDistanceWithin( | |
270 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
271 | "POINT(1 2)", | |
272 | 0.999999, | |
273 | 0 | |
274 | ); | |
275 | } | |
276 | ||
277 | ||
278 | // polygon within distance of point should return true | |
279 | template <> | |
280 | template <> | |
281 | void object::test<20>() { | |
282 | testGEOSDistanceWithin( | |
283 | "POINT(1 2)", | |
284 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
285 | 1.0, | |
286 | 1 | |
287 | ); | |
288 | } | |
289 | ||
290 | // point not within distance of polygon should return false | |
291 | template <> | |
292 | template <> | |
293 | void object::test<21>() { | |
294 | testGEOSDistanceWithin( | |
295 | "POINT(1 2)", | |
296 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
297 | 0.999999, | |
298 | 0 | |
299 | ); | |
300 | } | |
301 | ||
302 | // polygon that intersects point should return true even if distance is 0 | |
303 | template <> | |
304 | template <> | |
305 | void object::test<22>() { | |
306 | testGEOSDistanceWithin( | |
307 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
308 | "POINT(1 0)", | |
309 | 0.0, | |
310 | 1 | |
311 | ); | |
312 | } | |
313 | ||
314 | // polygon within distance of line should return true | |
315 | template <> | |
316 | template <> | |
317 | void object::test<23>() { | |
318 | testGEOSDistanceWithin( | |
319 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
320 | "LINESTRING(0 -1, 2 -1)", | |
321 | 1.0, | |
322 | 1 | |
323 | ); | |
324 | } | |
325 | ||
326 | // polygon not within distance of line should return false | |
327 | template <> | |
328 | template <> | |
329 | void object::test<24>() { | |
330 | testGEOSDistanceWithin( | |
331 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
332 | "LINESTRING(0 -1, 2 -1)", | |
333 | 0.999999, | |
334 | 0 | |
335 | ); | |
336 | } | |
337 | ||
338 | // polygon that intersects line should return true even if distance is 0 | |
339 | template <> | |
340 | template <> | |
341 | void object::test<25>() { | |
342 | testGEOSDistanceWithin( | |
343 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
344 | "LINESTRING(0 -1, 0.5 0.5, 2 -1)", | |
345 | 0.0, | |
346 | 1 | |
347 | ); | |
348 | } | |
349 | ||
350 | // polygon that shares edge with line should return true even if distance is 0 | |
351 | template <> | |
352 | template <> | |
353 | void object::test<26>() { | |
354 | testGEOSDistanceWithin( | |
355 | "POLYGON((0 0, 1 1, 2 0, 0 0))", | |
356 | "LINESTRING(0 0, 1 1, 2 0)", | |
357 | 0.0, | |
358 | 1 | |
359 | ); | |
360 | } | |
361 | ||
362 | ||
363 | // empty geometries should return false (distance 1) | |
364 | template <> | |
365 | template <> | |
366 | void object::test<27>() { | |
367 | testGEOSDistanceWithin( | |
368 | "POINT EMPTY", | |
369 | "LINESTRING EMPTY", | |
370 | 1.0, | |
371 | 0 | |
372 | ); | |
373 | } | |
374 | ||
375 | // empty geometries should return false (distance 0) | |
376 | template <> | |
377 | template <> | |
378 | void object::test<28>() { | |
379 | testGEOSDistanceWithin( | |
380 | "POINT EMPTY", | |
381 | "LINESTRING EMPTY", | |
382 | 0.0, | |
383 | 0 | |
384 | ); | |
385 | } | |
386 | ||
387 | // empty geometries should return false (distance Infinity) | |
388 | template <> | |
389 | template <> | |
390 | void object::test<29>() { | |
391 | testGEOSDistanceWithin( | |
392 | "POINT EMPTY", | |
393 | "LINESTRING EMPTY", | |
394 | geos::DoubleInfinity, | |
395 | 0 | |
396 | ); | |
397 | } | |
398 | ||
399 | // empty geometry is never within any distance | |
400 | template <> | |
401 | template <> | |
402 | void object::test<30>() { | |
403 | testGEOSDistanceWithin( | |
404 | "POINT EMPTY", | |
405 | "LINESTRING(0 0, 20 0)", | |
406 | geos::DoubleInfinity, | |
407 | 0 | |
408 | ); | |
409 | } | |
410 | ||
411 | // empty geometry is never within any distance | |
412 | template <> | |
413 | template <> | |
414 | void object::test<31>() { | |
415 | testGEOSDistanceWithin( | |
416 | "LINESTRING(0 0, 20 0)", | |
417 | "POINT EMPTY", | |
418 | geos::DoubleInfinity, | |
419 | 0 | |
420 | ); | |
421 | } | |
422 | ||
423 | ||
424 | ||
52 | 425 | |
53 | 426 | } // namespace tut |
54 |
2 | 2 | |
3 | 3 | #include <tut/tut.hpp> |
4 | 4 | // geos |
5 | #include <geos/constants.h> | |
5 | 6 | #include <geos_c.h> |
6 | 7 | // std |
7 | 8 | #include <cstdarg> |
96 | 97 | { |
97 | 98 | GEOSCoordSequence* cs = GEOSCoordSeq_create(5, 2); |
98 | 99 | |
99 | constexpr double nan = std::numeric_limits<double>::quiet_NaN(); | |
100 | 100 | GEOSCoordSeq_setX(cs, 0, 1); |
101 | 101 | GEOSCoordSeq_setY(cs, 0, 1); |
102 | 102 | for(unsigned int i = 1; i < 4; ++i) { |
103 | GEOSCoordSeq_setX(cs, i, nan); | |
104 | GEOSCoordSeq_setY(cs, i, nan); | |
103 | GEOSCoordSeq_setX(cs, i, geos::DoubleNotANumber); | |
104 | GEOSCoordSeq_setY(cs, i, geos::DoubleNotANumber); | |
105 | 105 | } |
106 | 106 | GEOSCoordSeq_setX(cs, 4, 1); |
107 | 107 | GEOSCoordSeq_setY(cs, 4, 1); |
3 | 3 | #include <tut/tut.hpp> |
4 | 4 | // geos |
5 | 5 | #include <geos_c.h> |
6 | #include <geos/constants.h> | |
6 | 7 | // std |
7 | 8 | #include <cstdarg> |
8 | 9 | #include <cstdio> |
96 | 97 | { |
97 | 98 | GEOSCoordSequence* cs = GEOSCoordSeq_create(5, 2); |
98 | 99 | |
99 | constexpr double nan = std::numeric_limits<double>::quiet_NaN(); | |
100 | constexpr double nan = geos::DoubleNotANumber; | |
100 | 101 | GEOSCoordSeq_setX(cs, 0, 1); |
101 | 102 | GEOSCoordSeq_setY(cs, 0, 1); |
102 | 103 | for(unsigned int i = 1; i < 4; ++i) { |
2 | 2 | #include <tut/tut.hpp> |
3 | 3 | // geos |
4 | 4 | #include <geos_c.h> |
5 | #include <geos/constants.h> | |
5 | 6 | // std |
6 | 7 | #include <cstdarg> |
7 | 8 | #include <cstdio> |
42 | 43 | int error = GEOSMinimumClearance(input, &d); |
43 | 44 | |
44 | 45 | ensure(!error); |
45 | if(clearance == std::numeric_limits<double>::infinity()) { | |
46 | if(clearance == geos::DoubleInfinity) { | |
46 | 47 | ensure(d == clearance); |
47 | 48 | } |
48 | 49 | else { |
75 | 76 | { |
76 | 77 | testClearance("MULTIPOINT ((100 100), (100 100))", |
77 | 78 | "LINESTRING EMPTY", |
78 | std::numeric_limits<double>::infinity()); | |
79 | geos::DoubleInfinity); | |
79 | 80 | } |
80 | 81 | |
81 | 82 | template<> |
115 | 116 | { |
116 | 117 | testClearance("POLYGON EMPTY", |
117 | 118 | "LINESTRING EMPTY", |
118 | std::numeric_limits<double>::infinity()); | |
119 | geos::DoubleInfinity); | |
119 | 120 | } |
120 | 121 | |
121 | 122 | } // namespace tut |
3 | 3 | #include <tut/tut.hpp> |
4 | 4 | // geos |
5 | 5 | #include <geos_c.h> |
6 | #include <geos/constants.h> | |
6 | 7 | // std |
7 | 8 | #include <cstdarg> |
8 | 9 | #include <cstdio> |
66 | 67 | checkDistance( |
67 | 68 | "POLYGON EMPTY", |
68 | 69 | "POLYGON EMPTY", |
69 | std::numeric_limits<double>::infinity() | |
70 | geos::DoubleInfinity | |
70 | 71 | ); |
71 | 72 | } |
72 | 73 | |
139 | 140 | checkDistance( |
140 | 141 | "LINESTRING EMPTY", |
141 | 142 | "POINT EMPTY", |
142 | std::numeric_limits<double>::infinity() | |
143 | geos::DoubleInfinity | |
143 | 144 | ); |
144 | 145 | } |
145 | 146 | |
151 | 152 | checkDistance( |
152 | 153 | "POINT EMPTY", |
153 | 154 | "LINESTRING EMPTY", |
154 | std::numeric_limits<double>::infinity() | |
155 | geos::DoubleInfinity | |
155 | 156 | ); |
156 | 157 | } |
157 | 158 |
3 | 3 | #include <tut/tut.hpp> |
4 | 4 | // geos |
5 | 5 | #include <geos_c.h> |
6 | #include <geos/constants.h> | |
6 | 7 | // std |
7 | 8 | #include <cstdarg> |
8 | 9 | #include <cstdio> |
64 | 65 | checkDistanceWithin( |
65 | 66 | "POLYGON EMPTY", |
66 | 67 | "POLYGON EMPTY", |
67 | std::numeric_limits<double>::infinity(), | |
68 | 1 | |
68 | geos::DoubleInfinity, | |
69 | 0 | |
69 | 70 | ); |
70 | 71 | } |
71 | 72 | |
143 | 144 | checkDistanceWithin( |
144 | 145 | "LINESTRING EMPTY", |
145 | 146 | "POINT EMPTY", |
146 | std::numeric_limits<double>::infinity(), | |
147 | 1 | |
147 | geos::DoubleInfinity, | |
148 | 0 | |
148 | 149 | ); |
149 | 150 | } |
150 | 151 | |
156 | 157 | checkDistanceWithin( |
157 | 158 | "POINT EMPTY", |
158 | 159 | "LINESTRING EMPTY", |
159 | std::numeric_limits<double>::infinity(), | |
160 | 1 | |
160 | geos::DoubleInfinity, | |
161 | 0 | |
162 | ); | |
163 | } | |
164 | ||
165 | template<> | |
166 | template<> | |
167 | void object::test<9> | |
168 | () | |
169 | { | |
170 | checkDistanceWithin( | |
171 | "POINT EMPTY", | |
172 | "POINT(0 0)", | |
173 | geos::DoubleInfinity, | |
174 | 0 | |
175 | ); | |
176 | } | |
177 | ||
178 | template<> | |
179 | template<> | |
180 | void object::test<10> | |
181 | () | |
182 | { | |
183 | checkDistanceWithin( | |
184 | "LINESTRING(0 0, 10 0)", | |
185 | "POLYGON EMPTY", | |
186 | geos::DoubleInfinity, | |
187 | 0 | |
161 | 188 | ); |
162 | 189 | } |
163 | 190 |
3 | 3 | #include <tut/tut.hpp> |
4 | 4 | // geos |
5 | 5 | #include <geos_c.h> |
6 | #include <geos/constants.h> | |
6 | 7 | // std |
7 | 8 | #include <cstdarg> |
8 | 9 | #include <cstdio> |
114 | 115 | for(std::size_t i = 0; i < ngeoms; i++) { |
115 | 116 | const GEOSGeometry* nearest = GEOSSTRtree_nearest(tree, queryPoints[i]); |
116 | 117 | const GEOSGeometry* nearestBruteForce = nullptr; |
117 | double nearestBruteForceDistance = std::numeric_limits<double>::max(); | |
118 | double nearestBruteForceDistance = geos::DoubleInfinity; | |
118 | 119 | for(std::size_t j = 0; j < ngeoms; j++) { |
119 | 120 | double distance; |
120 | 121 | GEOSDistance(queryPoints[i], geoms[j], &distance); |
8 | 8 | // Test Group |
9 | 9 | // |
10 | 10 | |
11 | struct test_geosisvalid_data : public capitest::utility {}; | |
11 | struct test_geosisvalidreason_data : public capitest::utility {}; | |
12 | 12 | |
13 | typedef test_group<test_geosisvalid_data> group; | |
13 | typedef test_group<test_geosisvalidreason_data> group; | |
14 | 14 | typedef group::object object; |
15 | 15 | |
16 | group test_geosisvalid("capi::GEOSisValid"); | |
16 | group test_geosisvalidreason("capi::GEOSisValidReason"); | |
17 | 17 | |
18 | 18 | template<> |
19 | 19 | template<> |
21 | 21 | { |
22 | 22 | GEOSGeometry* input = GEOSGeomFromWKT("LINESTRING (1 2, 4 5, 9 -2)"); |
23 | 23 | |
24 | ensure_equals(1, GEOSisValid(input)); | |
24 | char* reason = GEOSisValidReason(input); | |
25 | ||
26 | ensure_equals(std::string(reason), "Valid Geometry"); | |
25 | 27 | |
26 | 28 | GEOSGeom_destroy(input); |
29 | GEOSFree(reason); | |
27 | 30 | } |
28 | 31 | |
29 | 32 | template<> |
32 | 35 | { |
33 | 36 | GEOSGeometry* input = GEOSGeomFromWKT("POLYGON ((0 0, 1 0, 0 1, 1 1, 0 0))"); |
34 | 37 | |
35 | ensure_equals(0, GEOSisValid(input)); | |
38 | char* reason = GEOSisValidReason(input); | |
39 | ||
40 | ensure_equals(std::string(reason), "Self-intersection[0.5 0.5]"); | |
36 | 41 | |
37 | 42 | GEOSGeom_destroy(input); |
43 | GEOSFree(reason); | |
38 | 44 | } |
39 | 45 | |
40 | 46 |
8 | 8 | // Test Group |
9 | 9 | // |
10 | 10 | |
11 | struct test_geosisvalidreason_data : public capitest::utility {}; | |
11 | struct test_geosisvalid_data : public capitest::utility {}; | |
12 | 12 | |
13 | typedef test_group<test_geosisvalidreason_data> group; | |
13 | typedef test_group<test_geosisvalid_data> group; | |
14 | 14 | typedef group::object object; |
15 | 15 | |
16 | group test_geosisvalidreason("capi::GEOSisValidReason"); | |
16 | group test_geosisvalid("capi::GEOSisValid"); | |
17 | 17 | |
18 | 18 | template<> |
19 | 19 | template<> |
21 | 21 | { |
22 | 22 | GEOSGeometry* input = GEOSGeomFromWKT("LINESTRING (1 2, 4 5, 9 -2)"); |
23 | 23 | |
24 | char* reason = GEOSisValidReason(input); | |
25 | ||
26 | ensure_equals(std::string(reason), "Valid Geometry"); | |
24 | ensure_equals(1, GEOSisValid(input)); | |
27 | 25 | |
28 | 26 | GEOSGeom_destroy(input); |
29 | GEOSFree(reason); | |
30 | 27 | } |
31 | 28 | |
32 | 29 | template<> |
35 | 32 | { |
36 | 33 | GEOSGeometry* input = GEOSGeomFromWKT("POLYGON ((0 0, 1 0, 0 1, 1 1, 0 0))"); |
37 | 34 | |
38 | char* reason = GEOSisValidReason(input); | |
39 | ||
40 | ensure_equals(std::string(reason), "Self-intersection[0.5 0.5]"); | |
35 | ensure_equals(0, GEOSisValid(input)); | |
41 | 36 | |
42 | 37 | GEOSGeom_destroy(input); |
43 | GEOSFree(reason); | |
44 | 38 | } |
45 | 39 | |
46 | 40 | |
41 | // Unclosed polygon | |
42 | template<> | |
43 | template<> | |
44 | void object::test<3>() | |
45 | { | |
46 | GEOSCoordSequence* shell_seq = GEOSCoordSeq_create(4, 2); | |
47 | double shell_coords[] = {0,0, 0,10, 10,10, 10,0}; | |
48 | for (unsigned int i = 0; i < 4; i++) { | |
49 | GEOSCoordSeq_setXY(shell_seq, i, shell_coords[2*i], shell_coords[2*i+1]); | |
50 | } | |
51 | ||
52 | // Unclosed ring fails in construction | |
53 | // Linear ring takes ownership of coordinate sequence and | |
54 | // frees it when construction fails | |
55 | GEOSGeometry* shell = GEOSGeom_createLinearRing(shell_seq); | |
56 | ensure(shell == nullptr); | |
57 | // So we end up handing nullptr into create polygon | |
58 | GEOSGeometry* polygon = GEOSGeom_createPolygon(shell, nullptr, 0); | |
59 | ensure(polygon == nullptr); | |
60 | // Which also returns nullptr and that goes into isvalid | |
61 | char isvalid = GEOSisValid(polygon); | |
62 | // Which causes an exception that we catch | |
63 | ensure_equals(2, isvalid); | |
64 | } | |
65 | ||
47 | 66 | } // namespace tut |
48 |
9 | 9 | #include <geos/geom/Geometry.h> |
10 | 10 | #include <geos/geom/GeometryFactory.h> |
11 | 11 | #include <geos/geom/Point.h> |
12 | #include <geos/constants.h> | |
12 | 13 | |
13 | 14 | #include <utility.h> |
14 | 15 | |
153 | 154 | template<> |
154 | 155 | void object::test<4>() |
155 | 156 | { |
156 | std::unique_ptr<Point> pt = createPoint(0, std::numeric_limits<double>::infinity()); | |
157 | std::unique_ptr<Point> pt = createPoint(0, geos::DoubleInfinity); | |
157 | 158 | checkFix(pt.get() , "POINT EMPTY"); |
158 | 159 | } |
159 | 160 | |
162 | 163 | template<> |
163 | 164 | void object::test<5>() |
164 | 165 | { |
165 | std::unique_ptr<Point> pt = createPoint(0, std::numeric_limits<double>::infinity()); | |
166 | std::unique_ptr<Point> pt = createPoint(0, geos::DoubleInfinity); | |
166 | 167 | checkFix(pt.get() , "POINT EMPTY"); |
167 | 168 | } |
168 | 169 |