]>
Commit | Line | Data |
---|---|---|
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) | |
2 | // Unit Test | |
3 | ||
4 | // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. | |
5 | // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. | |
6 | // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. | |
7 | ||
8 | // This file was modified by Oracle on 2014. | |
9 | // Modifications copyright (c) 2014 Oracle and/or its affiliates. | |
10 | ||
11 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
12 | ||
13 | // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library | |
14 | // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. | |
15 | ||
16 | // Use, modification and distribution is subject to the Boost Software License, | |
17 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
18 | // http://www.boost.org/LICENSE_1_0.txt) | |
19 | ||
20 | #include <sstream> | |
21 | #include <string> | |
22 | ||
23 | #include <boost/algorithm/string.hpp> | |
24 | ||
25 | #include <geometry_test_common.hpp> | |
26 | ||
27 | #include <boost/geometry/geometries/geometries.hpp> | |
28 | ||
29 | #include <boost/geometry/algorithms/area.hpp> | |
30 | #include <boost/geometry/algorithms/length.hpp> | |
31 | #include <boost/geometry/algorithms/num_points.hpp> | |
32 | #include <boost/geometry/algorithms/perimeter.hpp> | |
33 | #include <boost/geometry/strategies/strategies.hpp> | |
34 | #include <boost/geometry/core/point_type.hpp> | |
35 | #include <boost/geometry/core/topological_dimension.hpp> | |
36 | #include <boost/geometry/io/wkt/read.hpp> | |
37 | #include <boost/geometry/io/wkt/write.hpp> | |
38 | #include <boost/variant/variant.hpp> | |
39 | ||
40 | template <typename G> | |
41 | void check_wkt(G const& geometry, std::string const& expected) | |
42 | { | |
43 | std::ostringstream out; | |
44 | out << bg::wkt(geometry); | |
45 | BOOST_CHECK_EQUAL(boost::to_upper_copy(out.str()), | |
46 | boost::to_upper_copy(expected)); | |
47 | } | |
48 | ||
49 | template <typename G> | |
50 | void test_wkt(std::string const& wkt, std::string const& expected, | |
51 | std::size_t n, double len = 0, double ar = 0, double peri = 0) | |
52 | { | |
53 | G geometry; | |
54 | ||
55 | bg::read_wkt(wkt, geometry); | |
56 | ||
57 | /* | |
58 | std::cout << "n=" << bg::num_points(geometry) | |
59 | << " dim=" << bg::topological_dimension<G>::value | |
60 | << " length=" << bg::length(geometry) | |
61 | << " area=" << bg::area(geometry) | |
62 | << " perimeter=" << bg::perimeter(geometry) | |
63 | << std::endl << "\t\tgeometry=" << dsv(geometry) | |
64 | << std::endl; | |
65 | */ | |
66 | ||
67 | BOOST_CHECK_EQUAL(bg::num_points(geometry), n); | |
68 | if (n > 0) | |
69 | { | |
70 | BOOST_CHECK_CLOSE(double(bg::length(geometry)), len, 0.0001); | |
71 | BOOST_CHECK_CLOSE(double(bg::area(geometry)), ar, 0.0001); | |
72 | BOOST_CHECK_CLOSE(double(bg::perimeter(geometry)), peri, 0.0001); | |
73 | } | |
74 | ||
75 | check_wkt(geometry, expected); | |
76 | check_wkt(boost::variant<G>(geometry), expected); | |
77 | } | |
78 | ||
79 | template <typename G> | |
80 | void test_wkt(std::string const& wkt, | |
81 | std::size_t n, double len = 0, double ar = 0, double peri = 0) | |
82 | { | |
83 | test_wkt<G>(wkt, wkt, n, len, ar, peri); | |
84 | } | |
85 | ||
86 | template <typename G> | |
87 | void test_relaxed_wkt(std::string const& wkt, std::string const& expected) | |
88 | { | |
89 | std::string e; | |
90 | G geometry; | |
91 | bg::read_wkt(wkt, geometry); | |
92 | std::ostringstream out; | |
93 | out << bg::wkt(geometry); | |
94 | ||
95 | BOOST_CHECK_EQUAL(boost::to_upper_copy(out.str()), boost::to_upper_copy(expected)); | |
96 | } | |
97 | ||
98 | ||
99 | ||
100 | ||
101 | template <typename G> | |
102 | void test_wrong_wkt(std::string const& wkt, std::string const& start) | |
103 | { | |
104 | std::string e("no exception"); | |
105 | G geometry; | |
106 | try | |
107 | { | |
108 | bg::read_wkt(wkt, geometry); | |
109 | } | |
110 | catch(bg::read_wkt_exception const& ex) | |
111 | { | |
112 | e = ex.what(); | |
113 | boost::to_lower(e); | |
114 | } | |
115 | catch(...) | |
116 | { | |
117 | e = "other exception"; | |
118 | } | |
119 | ||
120 | bool check = true; | |
121 | ||
122 | #if defined(HAVE_TTMATH) | |
123 | // For ttmath we skip bad lexical casts | |
124 | typedef typename bg::coordinate_type<G>::type ct; | |
125 | ||
126 | if (boost::is_same<ct, ttmath_big>::type::value | |
127 | && boost::starts_with(start, "bad lexical cast")) | |
128 | { | |
129 | check = false; | |
130 | } | |
131 | #endif | |
132 | ||
133 | if (check) | |
134 | { | |
135 | BOOST_CHECK_MESSAGE(boost::starts_with(e, start), " Expected:" | |
136 | << start << " Got:" << e << " with WKT: " << wkt); | |
137 | } | |
138 | } | |
139 | ||
140 | template <typename G> | |
141 | void test_wkt_output_iterator(std::string const& wkt) | |
142 | { | |
143 | G geometry; | |
144 | bg::read_wkt<G>(wkt, std::back_inserter(geometry)); | |
145 | } | |
146 | ||
147 | ||
148 | ||
149 | #ifndef GEOMETRY_TEST_MULTI | |
150 | template <typename T> | |
151 | void test_order_closure() | |
152 | { | |
153 | using namespace boost::geometry; | |
154 | typedef bg::model::point<T, 2, bg::cs::cartesian> Pt; | |
155 | typedef bg::model::polygon<Pt, true, true> PCWC; | |
156 | typedef bg::model::polygon<Pt, true, false> PCWO; | |
157 | typedef bg::model::polygon<Pt, false, true> PCCWC; | |
158 | typedef bg::model::polygon<Pt, false, false> PCCWO; | |
159 | ||
160 | { | |
161 | std::string wkt_cwc = "POLYGON((0 0,0 2,2 2,2 0,0 0))"; | |
162 | std::string wkt_cwo = "POLYGON((0 0,0 2,2 2,2 0))"; | |
163 | std::string wkt_ccwc = "POLYGON((0 0,2 0,2 2,0 2,0 0))"; | |
164 | std::string wkt_ccwo = "POLYGON((0 0,2 0,2 2,0 2))"; | |
165 | ||
166 | test_wkt<PCWC>(wkt_cwc, 5, 0, 4, 8); | |
167 | test_wkt<PCWO>(wkt_cwc, 4, 0, 4, 8); | |
168 | test_wkt<PCWO>(wkt_cwo, wkt_cwc, 4, 0, 4, 8); | |
169 | test_wkt<PCCWC>(wkt_ccwc, 5, 0, 4, 8); | |
170 | test_wkt<PCCWO>(wkt_ccwc, 4, 0, 4, 8); | |
171 | test_wkt<PCCWO>(wkt_ccwo, wkt_ccwc, 4, 0, 4, 8); | |
172 | } | |
173 | { | |
174 | std::string wkt_cwc = "POLYGON((0 0,0 3,3 3,3 0,0 0),(1 1,2 1,2 2,1 2,1 1))"; | |
175 | std::string wkt_cwo = "POLYGON((0 0,0 3,3 3,3 0),(1 1,2 1,2 2,1 2))"; | |
176 | std::string wkt_ccwc = "POLYGON((0 0,3 0,3 3,0 3,0 0),(1 1,1 2,2 2,2 1,1 1))"; | |
177 | std::string wkt_ccwo = "POLYGON((0 0,3 0,3 3,0 3),(1 1,1 2,2 2,2 1,1 1))"; | |
178 | ||
179 | test_wkt<PCWC>(wkt_cwc, 10, 0, 8, 16); | |
180 | test_wkt<PCWO>(wkt_cwc, 8, 0, 8, 16); | |
181 | test_wkt<PCWO>(wkt_cwo, wkt_cwc, 8, 0, 8, 16); | |
182 | test_wkt<PCCWC>(wkt_ccwc, 10, 0, 8, 16); | |
183 | test_wkt<PCCWO>(wkt_ccwc, 8, 0, 8, 16); | |
184 | test_wkt<PCCWO>(wkt_ccwo, wkt_ccwc, 8, 0, 8, 16); | |
185 | } | |
186 | } | |
187 | ||
188 | template <typename T> | |
189 | void test_all() | |
190 | { | |
191 | using namespace boost::geometry; | |
192 | typedef bg::model::point<T, 2, bg::cs::cartesian> P; | |
193 | ||
194 | test_wkt<P>("POINT(1 2)", 1); | |
195 | test_wkt<bg::model::linestring<P> >("LINESTRING(1 1,2 2,3 3)", 3, 2 * sqrt(2.0)); | |
196 | test_wkt<bg::model::polygon<P> >("POLYGON((0 0,0 4,4 4,4 0,0 0)" | |
197 | ",(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))", 15, 0, 18, 24); | |
198 | ||
199 | // Non OGC: a box defined by a polygon | |
200 | //test_wkt<box<P> >("POLYGON((0 0,0 1,1 1,1 0,0 0))", 4, 0, 1, 4); | |
201 | test_wkt<bg::model::ring<P> >("POLYGON((0 0,0 1,1 1,1 0,0 0))", 5, 0, 1, 4); | |
202 | ||
203 | // We accept empty sequences as well (much better than EMPTY)... | |
204 | // ...or even POINT() (see below) | |
205 | test_wkt<bg::model::linestring<P> >("LINESTRING()", 0, 0); | |
206 | test_wkt<bg::model::polygon<P> >("POLYGON(())", 0); | |
207 | // ... or even with empty holes | |
208 | test_wkt<bg::model::polygon<P> >("POLYGON((),(),())", 0); | |
209 | // which all make no valid geometries, but they can exist. | |
210 | ||
211 | // These WKT's are incomplete or abnormal but they are considered OK | |
212 | test_relaxed_wkt<P>("POINT(1)", "POINT(1 0)"); | |
213 | test_relaxed_wkt<P>("POINT()", "POINT(0 0)"); | |
214 | test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING(1,2,3)", | |
215 | "LINESTRING(1 0,2 0,3 0)"); | |
216 | test_relaxed_wkt<P>("POINT ( 1 2) ", "POINT(1 2)"); | |
217 | test_relaxed_wkt<P>("POINT M ( 1 2)", "POINT(1 2)"); | |
218 | test_relaxed_wkt<bg::model::box<P> >("BOX(1 1,2 2)", "POLYGON((1 1,1 2,2 2,2 1,1 1))"); | |
219 | ||
220 | test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING EMPTY", "LINESTRING()"); | |
221 | ||
222 | test_relaxed_wkt<bg::model::polygon<P> >("POLYGON( ( ) , ( ) , ( ) )", | |
223 | "POLYGON((),(),())"); | |
224 | ||
225 | // Wrong WKT's | |
226 | test_wrong_wkt<P>("POINT(1 2", "expected ')'"); | |
227 | test_wrong_wkt<P>("POINT 1 2)", "expected '('"); | |
228 | test_wrong_wkt<P>("POINT(1 2,)", "expected ')'"); | |
229 | test_wrong_wkt<P>("POINT(1 2)foo", "too many tokens at 'foo'"); | |
230 | test_wrong_wkt<P>("POINT(1 2 3)", "expected ')'"); | |
231 | test_wrong_wkt<P>("POINT(a 2 3)", "bad lexical cast"); | |
232 | test_wrong_wkt<P>("POINT 2 3", "expected '('"); | |
233 | test_wrong_wkt<P>("POINT Z (1 2 3)", "z only allowed"); | |
234 | ||
235 | test_wrong_wkt<P>("PIONT (1 2)", "should start with 'point'"); | |
236 | ||
237 | test_wrong_wkt<bg::model::linestring<P> >("LINESTRING())", "too many tokens"); | |
238 | ||
239 | test_wrong_wkt<bg::model::polygon<P> >("POLYGON((1 1,1 4,4 4,4 1,1 1)" | |
240 | ",((2 2,2 3,3 3,3 2,2 2))", "bad lexical cast"); | |
241 | ||
242 | test_wrong_wkt<bg::model::box<P> >("BOX(1 1,2 2,3 3)", "box should have 2"); | |
243 | test_wrong_wkt<bg::model::box<P> >("BOX(1 1,2 2) )", "too many tokens"); | |
244 | ||
245 | if ( BOOST_GEOMETRY_CONDITION(boost::is_floating_point<T>::type::value | |
246 | || ! boost::is_fundamental<T>::type::value ) ) | |
247 | { | |
248 | test_wkt<P>("POINT(1.1 2.1)", 1); | |
249 | } | |
250 | ||
251 | // Deprecated: | |
252 | // test_wkt_output_iterator<bg::model::linestring<P> >("LINESTRING(1 1,2 2,3 3)"); | |
253 | // test_wkt_output_iterator<bg::model::ring<P> >("POLYGON((1 1,2 2,3 3))"); | |
254 | ||
255 | test_order_closure<T>(); | |
256 | } | |
257 | #endif | |
258 | ||
259 | int test_main(int, char* []) | |
260 | { | |
261 | test_all<double>(); | |
262 | test_all<int>(); | |
263 | ||
264 | #if defined(HAVE_TTMATH) | |
265 | test_all<ttmath_big>(); | |
266 | #endif | |
267 | ||
268 | return 0; | |
269 | } | |
270 | ||
271 | /* | |
272 | ||
273 | Results can be checked in PostGIS by query below, | |
274 | or by MySQL (but replace length by glength and remove the perimeter) | |
275 | ||
276 | Note: | |
277 | - PostGIS gives "3" for a numpoints of a multi-linestring of 6 points in total (!) | |
278 | --> "npoints" should be taken for all geometries | |
279 | - SQL Server 2008 gives "6" | |
280 | select geometry::STGeomFromText('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5,6 6))',0).STNumPoints() | |
281 | - MySQL gives "NULL" | |
282 | ||
283 | select 1 as code,'np p' as header,npoints(geomfromtext('POINT(1 2)')) as contents | |
284 | union select 2,'length point', length(geomfromtext('POINT(1 2)')) | |
285 | union select 3,'peri point', perimeter(geomfromtext('POINT(1 2)')) | |
286 | union select 4,'area point',area(geomfromtext('POINT(1 2)')) | |
287 | ||
288 | ||
289 | union select 5,'# ls',npoints(geomfromtext('LINESTRING(1 1,2 2,3 3)')) | |
290 | union select 6,'length ls',length(geomfromtext('LINESTRING(1 1,2 2,3 3)')) | |
291 | union select 7,'peri ls',perimeter(geomfromtext('LINESTRING(1 1,2 2,3 3)')) | |
292 | union select 8,'aera ls',area(geomfromtext('LINESTRING(1 1,2 2,3 3)')) | |
293 | ||
294 | union select 9,'# poly',npoints(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))')) | |
295 | union select 10,'length poly',length(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))')) | |
296 | union select 11,'peri poly',perimeter(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))')) | |
297 | union select 12,'area poly',area(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))')) | |
298 | ||
299 | */ |