1 //
2 // Test Suite for C-API GEOSDistance
3
4 #include <tut/tut.hpp>
5 // geos
6 #include <geos_c.h>
7 #include <geos/constants.h>
8 // std
9 #include <cstdarg>
10 #include <cstdio>
11 #include <cstdlib>
12 #include <memory>
13 #include <math.h>
14
15 namespace tut {
16 //
17 // Test Group
18 //
19
20 // Common data used in test cases.
21 struct test_capigeosdistance_data {
22 GEOSGeometry* geom1_;
23 GEOSGeometry* geom2_;
24 GEOSGeometry* geom3_;
25 GEOSWKTWriter* w_;
26
27 static void
noticetut::test_capigeosdistance_data28 notice(const char* fmt, ...)
29 {
30 std::fprintf(stdout, "NOTICE: ");
31
32 va_list ap;
33 va_start(ap, fmt);
34 std::vfprintf(stdout, fmt, ap);
35 va_end(ap);
36
37 std::fprintf(stdout, "\n");
38 }
39
test_capigeosdistance_datatut::test_capigeosdistance_data40 test_capigeosdistance_data()
41 : geom1_(nullptr), geom2_(nullptr), geom3_(nullptr), w_(nullptr)
42 {
43 initGEOS(notice, notice);
44 w_ = GEOSWKTWriter_create();
45 GEOSWKTWriter_setTrim(w_, 1);
46 }
47
~test_capigeosdistance_datatut::test_capigeosdistance_data48 ~test_capigeosdistance_data()
49 {
50 GEOSGeom_destroy(geom1_);
51 GEOSGeom_destroy(geom2_);
52 GEOSGeom_destroy(geom3_);
53 GEOSWKTWriter_destroy(w_);
54 geom1_ = nullptr;
55 geom2_ = nullptr;
56 geom3_ = nullptr;
57 finishGEOS();
58 }
59
60 };
61
62 typedef test_group<test_capigeosdistance_data> group;
63 typedef group::object object;
64
65 group test_capigeosdistance_group("capi::GEOSDistance");
66
67 //
68 // Test Cases
69 //
70
71 /// See http://trac.osgeo.org/geos/ticket/377
72 template<>
73 template<>
test()74 void object::test<1>
75 ()
76 {
77 geom1_ = GEOSGeomFromWKT("POINT(10 10)");
78 geom2_ = GEOSGeomFromWKT("POINT(3 6)");
79
80 double dist;
81 int ret = GEOSDistance(geom1_, geom2_, &dist);
82
83 ensure_equals(ret, 1);
84 ensure_distance(dist, 8.06225774829855, 1e-12);
85 }
86
87 GEOSGeometry*
random_polygon(double x,double y,double r,size_t num_points)88 random_polygon(double x, double y, double r, size_t num_points)
89 {
90 std::vector<double> angle(num_points);
91 std::vector<double> radius(num_points);
92
93
94 for(size_t i = 0; i < num_points; i++) {
95 angle[i] = 2 * geos::MATH_PI * std::rand() / RAND_MAX;
96 radius[i] = r * std::rand() / RAND_MAX;
97 }
98
99 std::sort(angle.begin(), angle.end());
100
101 GEOSCoordSequence* seq_1 = GEOSCoordSeq_create(static_cast<unsigned int>(num_points), 2);
102 for(unsigned int i = 0; i < num_points; i++) {
103 auto idx = i == (num_points - 1) ? 0 : i;
104
105 GEOSCoordSeq_setX(seq_1, i, x + radius[idx] * cos(angle[idx]));
106 GEOSCoordSeq_setY(seq_1, i, y + radius[idx] * sin(angle[idx]));
107 }
108
109 return GEOSGeom_createPolygon(GEOSGeom_createLinearRing(seq_1), nullptr, 0);
110 }
111
112 /* Generate two complex polygons and verify that GEOSDistance and GEOSDistanceIndexed
113 * return identical results.
114 */
115 template<>
116 template<>
test()117 void object::test<2>
118 ()
119 {
120 std::srand(12345);
121
122 GEOSGeometry* g1 = random_polygon(-3, -8, 7, 1000);
123 GEOSGeometry* g2 = random_polygon(14, 22, 6, 500);
124
125 double d_raw, d_indexed;
126 ensure(GEOSDistance(g1, g2, &d_raw) != 0);
127 ensure(GEOSDistanceIndexed(g1, g2, &d_indexed) != 0);
128
129 ensure_equals(d_indexed, d_raw);
130
131 GEOSGeom_destroy(g1);
132 GEOSGeom_destroy(g2);
133 }
134
135 // https://github.com/libgeos/geos/issues/295
136 template<>
137 template<>
test()138 void object::test<3>
139 ()
140 {
141 GEOSGeometry* g1 = GEOSGeomFromWKT("MultiPolygon Z (EMPTY,((-0.14000000000000001 44.89999999999999858 0, -0.14699999999999999 44.90400000000000347 0, -0.14729999999999999 44.90500000000000114 0, -0.14000000000000001 44.89999999999999858 0)))");
142 GEOSGeometry* g2 = GEOSGeomFromWKT("POLYGON ((0 0, 1 0, 1 1, 0 0))");
143
144 double d;
145 int status = GEOSDistance(g1, g2, &d);
146
147 ensure_equals(status, 1);
148
149 GEOSGeom_destroy(g1);
150 GEOSGeom_destroy(g2);
151 }
152
153 } // namespace tut
154
155