123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Unit Test
- // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
- // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
- // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
- // This file was modified by Oracle on 2014.
- // Modifications copyright (c) 2014 Oracle and/or its affiliates.
- // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
- // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
- // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
- // Use, modification and distribution is subject to the Boost Software License,
- // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- #include <sstream>
- #include <string>
- #include <boost/algorithm/string.hpp>
- #include <geometry_test_common.hpp>
- #include <boost/geometry/geometries/geometries.hpp>
- #include <boost/geometry/algorithms/area.hpp>
- #include <boost/geometry/algorithms/length.hpp>
- #include <boost/geometry/algorithms/num_points.hpp>
- #include <boost/geometry/algorithms/perimeter.hpp>
- #include <boost/geometry/strategies/strategies.hpp>
- #include <boost/geometry/core/point_type.hpp>
- #include <boost/geometry/core/topological_dimension.hpp>
- #include <boost/geometry/io/wkt/read.hpp>
- #include <boost/geometry/io/wkt/write.hpp>
- #include <boost/variant/variant.hpp>
- template <typename G>
- void check_wkt(G const& geometry, std::string const& expected)
- {
- std::ostringstream out;
- out << bg::wkt(geometry);
- BOOST_CHECK_EQUAL(boost::to_upper_copy(out.str()),
- boost::to_upper_copy(expected));
- }
- template <typename G>
- void test_wkt(std::string const& wkt, std::string const& expected,
- std::size_t n, double len = 0, double ar = 0, double peri = 0)
- {
- G geometry;
- bg::read_wkt(wkt, geometry);
- /*
- std::cout << "n=" << bg::num_points(geometry)
- << " dim=" << bg::topological_dimension<G>::value
- << " length=" << bg::length(geometry)
- << " area=" << bg::area(geometry)
- << " perimeter=" << bg::perimeter(geometry)
- << std::endl << "\t\tgeometry=" << dsv(geometry)
- << std::endl;
- */
- BOOST_CHECK_EQUAL(bg::num_points(geometry), n);
- if (n > 0)
- {
- BOOST_CHECK_CLOSE(double(bg::length(geometry)), len, 0.0001);
- BOOST_CHECK_CLOSE(double(bg::area(geometry)), ar, 0.0001);
- BOOST_CHECK_CLOSE(double(bg::perimeter(geometry)), peri, 0.0001);
- }
- check_wkt(geometry, expected);
- check_wkt(boost::variant<G>(geometry), expected);
- }
- template <typename G>
- void test_wkt(std::string const& wkt,
- std::size_t n, double len = 0, double ar = 0, double peri = 0)
- {
- test_wkt<G>(wkt, wkt, n, len, ar, peri);
- }
- template <typename G>
- void test_relaxed_wkt(std::string const& wkt, std::string const& expected)
- {
- std::string e;
- G geometry;
- bg::read_wkt(wkt, geometry);
- std::ostringstream out;
- out << bg::wkt(geometry);
- BOOST_CHECK_EQUAL(boost::to_upper_copy(out.str()), boost::to_upper_copy(expected));
- }
- template <typename G>
- void test_wrong_wkt(std::string const& wkt, std::string const& start)
- {
- std::string e("no exception");
- G geometry;
- try
- {
- bg::read_wkt(wkt, geometry);
- }
- catch(bg::read_wkt_exception const& ex)
- {
- e = ex.what();
- boost::to_lower(e);
- }
- catch(...)
- {
- e = "other exception";
- }
- bool check = true;
- #if defined(HAVE_TTMATH)
- // For ttmath we skip bad lexical casts
- typedef typename bg::coordinate_type<G>::type ct;
- if (boost::is_same<ct, ttmath_big>::type::value
- && boost::starts_with(start, "bad lexical cast"))
- {
- check = false;
- }
- #endif
- if (check)
- {
- BOOST_CHECK_MESSAGE(boost::starts_with(e, start), " Expected:"
- << start << " Got:" << e << " with WKT: " << wkt);
- }
- }
- template <typename G>
- void test_wkt_output_iterator(std::string const& wkt)
- {
- G geometry;
- bg::read_wkt<G>(wkt, std::back_inserter(geometry));
- }
- #ifndef GEOMETRY_TEST_MULTI
- template <typename T>
- void test_order_closure()
- {
- using namespace boost::geometry;
- typedef bg::model::point<T, 2, bg::cs::cartesian> Pt;
- typedef bg::model::polygon<Pt, true, true> PCWC;
- typedef bg::model::polygon<Pt, true, false> PCWO;
- typedef bg::model::polygon<Pt, false, true> PCCWC;
- typedef bg::model::polygon<Pt, false, false> PCCWO;
- {
- std::string wkt_cwc = "POLYGON((0 0,0 2,2 2,2 0,0 0))";
- std::string wkt_cwo = "POLYGON((0 0,0 2,2 2,2 0))";
- std::string wkt_ccwc = "POLYGON((0 0,2 0,2 2,0 2,0 0))";
- std::string wkt_ccwo = "POLYGON((0 0,2 0,2 2,0 2))";
- test_wkt<PCWC>(wkt_cwc, 5, 0, 4, 8);
- test_wkt<PCWO>(wkt_cwc, 4, 0, 4, 8);
- test_wkt<PCWO>(wkt_cwo, wkt_cwc, 4, 0, 4, 8);
- test_wkt<PCCWC>(wkt_ccwc, 5, 0, 4, 8);
- test_wkt<PCCWO>(wkt_ccwc, 4, 0, 4, 8);
- test_wkt<PCCWO>(wkt_ccwo, wkt_ccwc, 4, 0, 4, 8);
- }
- {
- 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))";
- std::string wkt_cwo = "POLYGON((0 0,0 3,3 3,3 0),(1 1,2 1,2 2,1 2))";
- 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))";
- std::string wkt_ccwo = "POLYGON((0 0,3 0,3 3,0 3),(1 1,1 2,2 2,2 1,1 1))";
- test_wkt<PCWC>(wkt_cwc, 10, 0, 8, 16);
- test_wkt<PCWO>(wkt_cwc, 8, 0, 8, 16);
- test_wkt<PCWO>(wkt_cwo, wkt_cwc, 8, 0, 8, 16);
- test_wkt<PCCWC>(wkt_ccwc, 10, 0, 8, 16);
- test_wkt<PCCWO>(wkt_ccwc, 8, 0, 8, 16);
- test_wkt<PCCWO>(wkt_ccwo, wkt_ccwc, 8, 0, 8, 16);
- }
- }
- template <typename T>
- void test_all()
- {
- using namespace boost::geometry;
- typedef bg::model::point<T, 2, bg::cs::cartesian> P;
- test_wkt<P>("POINT(1 2)", 1);
- test_wkt<bg::model::linestring<P> >("LINESTRING(1 1,2 2,3 3)", 3, 2 * sqrt(2.0));
- test_wkt<bg::model::polygon<P> >("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))", 15, 0, 18, 24);
- // Non OGC: a box defined by a polygon
- //test_wkt<box<P> >("POLYGON((0 0,0 1,1 1,1 0,0 0))", 4, 0, 1, 4);
- test_wkt<bg::model::ring<P> >("POLYGON((0 0,0 1,1 1,1 0,0 0))", 5, 0, 1, 4);
- // We accept empty sequences as well (much better than EMPTY)...
- // ...or even POINT() (see below)
- test_wkt<bg::model::linestring<P> >("LINESTRING()", 0, 0);
- test_wkt<bg::model::polygon<P> >("POLYGON(())", 0);
- // ... or even with empty holes
- test_wkt<bg::model::polygon<P> >("POLYGON((),(),())", 0);
- // which all make no valid geometries, but they can exist.
- // These WKT's are incomplete or abnormal but they are considered OK
- test_relaxed_wkt<P>("POINT(1)", "POINT(1 0)");
- test_relaxed_wkt<P>("POINT()", "POINT(0 0)");
- test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING(1,2,3)",
- "LINESTRING(1 0,2 0,3 0)");
- test_relaxed_wkt<P>("POINT ( 1 2) ", "POINT(1 2)");
- test_relaxed_wkt<P>("POINT M ( 1 2)", "POINT(1 2)");
- test_relaxed_wkt<bg::model::box<P> >("BOX(1 1,2 2)", "POLYGON((1 1,1 2,2 2,2 1,1 1))");
- test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING EMPTY", "LINESTRING()");
- test_relaxed_wkt<bg::model::polygon<P> >("POLYGON( ( ) , ( ) , ( ) )",
- "POLYGON((),(),())");
- // Wrong WKT's
- test_wrong_wkt<P>("POINT(1 2", "expected ')'");
- test_wrong_wkt<P>("POINT 1 2)", "expected '('");
- test_wrong_wkt<P>("POINT(1 2,)", "expected ')'");
- test_wrong_wkt<P>("POINT(1 2)foo", "too many tokens at 'foo'");
- test_wrong_wkt<P>("POINT(1 2 3)", "expected ')'");
- test_wrong_wkt<P>("POINT(a 2 3)", "bad lexical cast");
- test_wrong_wkt<P>("POINT 2 3", "expected '('");
- test_wrong_wkt<P>("POINT Z (1 2 3)", "z only allowed");
- test_wrong_wkt<P>("PIONT (1 2)", "should start with 'point'");
- test_wrong_wkt<bg::model::linestring<P> >("LINESTRING())", "too many tokens");
- test_wrong_wkt<bg::model::polygon<P> >("POLYGON((1 1,1 4,4 4,4 1,1 1)"
- ",((2 2,2 3,3 3,3 2,2 2))", "bad lexical cast");
- test_wrong_wkt<bg::model::box<P> >("BOX(1 1,2 2,3 3)", "box should have 2");
- test_wrong_wkt<bg::model::box<P> >("BOX(1 1,2 2) )", "too many tokens");
- if ( BOOST_GEOMETRY_CONDITION(boost::is_floating_point<T>::type::value
- || ! boost::is_fundamental<T>::type::value ) )
- {
- test_wkt<P>("POINT(1.1 2.1)", 1);
- }
- // Deprecated:
- // test_wkt_output_iterator<bg::model::linestring<P> >("LINESTRING(1 1,2 2,3 3)");
- // test_wkt_output_iterator<bg::model::ring<P> >("POLYGON((1 1,2 2,3 3))");
- test_order_closure<T>();
- }
- #endif
- int test_main(int, char* [])
- {
- test_all<double>();
- test_all<int>();
- #if defined(HAVE_TTMATH)
- test_all<ttmath_big>();
- #endif
- return 0;
- }
- /*
- Results can be checked in PostGIS by query below,
- or by MySQL (but replace length by glength and remove the perimeter)
- Note:
- - PostGIS gives "3" for a numpoints of a multi-linestring of 6 points in total (!)
- --> "npoints" should be taken for all geometries
- - SQL Server 2008 gives "6"
- select geometry::STGeomFromText('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5,6 6))',0).STNumPoints()
- - MySQL gives "NULL"
- select 1 as code,'np p' as header,npoints(geomfromtext('POINT(1 2)')) as contents
- union select 2,'length point', length(geomfromtext('POINT(1 2)'))
- union select 3,'peri point', perimeter(geomfromtext('POINT(1 2)'))
- union select 4,'area point',area(geomfromtext('POINT(1 2)'))
- union select 5,'# ls',npoints(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
- union select 6,'length ls',length(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
- union select 7,'peri ls',perimeter(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
- union select 8,'aera ls',area(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
- 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))'))
- 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))'))
- 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))'))
- 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))'))
- */
|