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