// Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test // Copyright (c) 2007-2011 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2008-2011 Bruno Lalande, Paris, France. // Copyright (c) 2009-2011 Mateusz Loskot, London, UK. // 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 #include //#define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER //#define BOOST_GEOMETRY_DEBUG_INTERSECTION //#define BOOST_GEOMETRY_DEBUG_TRAVERSE //#define BOOST_GEOMETRY_DEBUG_FOLLOW //#define BOOST_GEOMETRY_DEBUG_ASSEMBLE //#define BOOST_GEOMETRY_DEBUG_IDENTIFIER #include #include #include #include #include #include #include #include #include BOOST_GEOMETRY_REGISTER_LINESTRING_TEMPLATED(std::vector) static std::string pie_2_3_23_0[2] = { "POLYGON((2500 2500,2855 3828,2500 3875,2500 2500))", "POLYGON((2500 2500,2791 3586,2499 3625,2208 3586,2500 2500))" }; template void test_areal() { test_one("pie_2_3_23_0", pie_2_3_23_0[0], pie_2_3_23_0[1], 1, 4, 163292.679042133, 0.1); test_one("simplex_with_empty_1", simplex_normal[0], polygon_empty, 0, 0, 0.0); test_one("simplex_with_empty_2", polygon_empty, simplex_normal[0], 0, 0, 0.0); test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 1, 7, 5.47363293); test_one("star_ring", example_star, example_ring, 1, 18, 2.80983); test_one("star_poly", example_star, example_polygon, 1, 0, // CLN: 23 points, other types: 22 point (one is merged) 2.5020508); test_one("first_within_second1", first_within_second[0], first_within_second[1], 1, 5, 1.0); test_one("first_within_second2", first_within_second[1], first_within_second[0], 1, 5, 1.0); test_one("first_within_hole_of_second", first_within_hole_of_second[0], first_within_hole_of_second[1], 0, 0, 0.0); // Two forming new hole test_one("new_hole", new_hole[0], new_hole[1], 2, 10, 2.0); // Two identical test_one("identical", identical[0], identical[1], 1, 5, 1.0); test_one("intersect_exterior_and_interiors_winded", intersect_exterior_and_interiors_winded[0], intersect_exterior_and_interiors_winded[1], 1, 14, 25.2166667); test_one("intersect_holes_disjoint", intersect_holes_disjoint[0], intersect_holes_disjoint[1], 1, 15, 18.0); test_one("intersect_holes_intersect", intersect_holes_intersect[0], intersect_holes_intersect[1], 1, 14, 18.25); test_one("intersect_holes_intersect_and_disjoint", intersect_holes_intersect_and_disjoint[0], intersect_holes_intersect_and_disjoint[1], 1, 19, 17.25); test_one("intersect_holes_intersect_and_touch", intersect_holes_intersect_and_touch[0], intersect_holes_intersect_and_touch[1], 1, 23, 17.25); test_one("intersect_holes_new_ring", intersect_holes_new_ring[0], intersect_holes_new_ring[1], 2, 23, 122.1039); test_one("winded", winded[0], winded[1], 1, 22, 40.0); test_one("within_holes_disjoint", within_holes_disjoint[0], within_holes_disjoint[1], 1, 15, 23.0); test_one("side_side", side_side[0], side_side[1], 0, 0, 0.0); test_one("two_bends", two_bends[0], two_bends[1], 1, 7, 24.0); test_one("star_comb_15", star_comb_15[0], star_comb_15[1], 28, 150, 189.952883); test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 1, 7, 5.47363293); test_one("distance_zero", distance_zero[0], distance_zero[1], 1, 0 /* f: 4, other: 5 */, 0.29516139, 0.01); test_one("equal_holes_disjoint", equal_holes_disjoint[0], equal_holes_disjoint[1], 1, 20, 81 - 2 * 3 * 3 - 3 * 7); test_one("only_hole_intersections1", only_hole_intersections[0], only_hole_intersections[1], 1, 21, 178.090909); test_one("only_hole_intersection2", only_hole_intersections[0], only_hole_intersections[2], 1, 21, 149.090909); test_one("fitting", fitting[0], fitting[1], 0, 0, 0); test_one("crossed", crossed[0], crossed[1], 3, 0, 1.5); typedef typename bg::coordinate_type::type ct; #ifdef _MSC_VER // Isovist (submitted by Brandon during Formal Review) test_one("isovist", isovist1[0], isovist1[1], 1, if_typed(19, if_typed(20, 20)), 88.19203, if_typed(0.5, if_typed(0.1, 0.01))); #endif //std::cout << typeid(ct).name() << std::endl; test_one("ggl_list_20110306_javier", ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], 1, if_typed_tt(5, 4), 0.6649875, if_typed(1.0, 0.01)); test_one("ggl_list_20110307_javier", ggl_list_20110307_javier[0], ggl_list_20110307_javier[1], 1, 4, 0.4, 0.01); test_one("ggl_list_20110627_phillip", ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1], 1, if_typed_tt(6, 5), 11151.6618); #ifdef _MSC_VER // gcc/linux behaves differently test_one("ggl_list_20110716_enrico", ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1], 3, if_typed(19, if_typed(22, 21)), 35723.8506317139); #endif return; test_one( "polygon_pseudo_line", "Polygon((0 0,0 4,4 4,4 0,0 0))", "Polygon((2 -2,2 -1,2 6,2 -2))", 5, 22, 1.1901714); } template void test_areal_clip() { test_one("boxring", example_box, example_ring, 2, 12, 1.09125); test_one("boxring2", example_ring,example_box, 2, 12, 1.09125); test_one("boxpoly", example_box, example_polygon, 3, 19, 0.840166); test_one("poly1", example_box, "POLYGON((3.4 2,4.1 3,5.3 2.6,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2))", 2, 12, 1.09125); test_one("clip_poly2", example_box, "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 2.5,5.3 2.5,5.4 1.2,4.9 0.8,2.9 0.7,2 1.3))", 2, 12, 1.00375); test_one("clip_poly3", example_box, "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 2.5,4.5 2.5,4.5 1.2,4.9 0.8,2.9 0.7,2 1.3))", 2, 12, 1.00375); test_one("clip_poly4", example_box, "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 2.5,4.5 2.5,4.5 2.3,5.0 2.3,5.0 2.1,4.5 2.1,4.5 1.9,4.0 1.9,4.5 1.2,4.9 0.8,2.9 0.7,2 1.3))", 2, 16, 0.860892); test_one("clip_poly5", example_box, "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 2.5,4.5 1.2,2.9 0.7,2 1.3))", 2, 11, 0.7575961); test_one("clip_poly6", example_box, "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.0 3.0,5.0 2.0,2.9 0.7,2 1.3))", 2, 13, 1.0744456); test_one("clip_poly7", "Box(0 0, 3 3)", "POLYGON((2 2, 1 4, 2 4, 3 3, 2 2))", 1, 4, 0.75); } template void test_boxes(std::string const& wkt1, std::string const& wkt2, double expected_area, bool expected_result) { Box box1, box2; bg::read_wkt(wkt1, box1); bg::read_wkt(wkt2, box2); Box box_out; bool detected = bg::intersection(box1, box2, box_out); typename bg::default_area_result::type area = bg::area(box_out); BOOST_CHECK_EQUAL(detected, expected_result); if (detected && expected_result) { BOOST_CHECK_CLOSE(area, expected_area, 0.01); } } template void test_point_output() { typedef bg::model::linestring

linestring; typedef bg::model::polygon

polygon; typedef bg::model::box

box; typedef bg::model::segment

segment; test_point_output(simplex_normal[0], simplex_normal[1], 6); test_point_output("box(1 1,6 4)", simplex_normal[0], 4); test_point_output("linestring(0 2,6 2)", simplex_normal[0], 2); // NYI because of sectionize: // test_point_output("linestring(0 2,6 2)", simplex_normal[0], 2); // NYI because needs special treatment: // test_point_output("box(0 0,4 4)", "box(2 2,6 6)", 2); } template void test_areal_linear() { std::string const poly_simplex = "POLYGON((1 1,1 3,3 3,3 1,1 1))"; test_one_lp("simplex", poly_simplex, "LINESTRING(0 2,4 2)", 1, 2, 2.0); test_one_lp("case2", poly_simplex, "LINESTRING(0 1,4 3)", 1, 2, sqrt(5.0)); test_one_lp("case3", "POLYGON((2 0,2 5,5 5,5 0,2 0))", "LINESTRING(0 1,1 2,3 2,4 3,6 3,7 4)", 1, 4, 2 + sqrt(2.0)); test_one_lp("case4", "POLYGON((0 0,0 4,2 4,2 0,0 0))", "LINESTRING(1 1,3 2,1 3)", 2, 4, sqrt(5.0)); test_one_lp("case5", poly_simplex, "LINESTRING(0 1,3 4)", 1, 2, sqrt(2.0)); test_one_lp("case6", "POLYGON((2 0,2 4,3 4,3 1,4 1,4 3,5 3,5 1,6 1,6 3,7 3,7 1,8 1,8 3,9 3,9 0,2 0))", "LINESTRING(1 1,10 3)", 4, 8, // Pieces are 1 x 2/9: 4.0 * sqrt(1.0 + 4.0/81.0)); test_one_lp("case7", poly_simplex, "LINESTRING(1.5 1.5,2.5 2.5)", 1, 2, sqrt(2.0)); test_one_lp("case8", poly_simplex, "LINESTRING(1 0,2 0)", 0, 0, 0.0); std::string const poly_9 = "POLYGON((1 1,1 4,4 4,4 1,1 1))"; test_one_lp("case9", poly_9, "LINESTRING(0 1,1 2,2 2)", 1, 2, 1.0); test_one_lp("case10", poly_9, "LINESTRING(0 1,1 2,0 2)", 0, 0, 0.0); test_one_lp("case11", poly_9, "LINESTRING(2 2,4 2,3 3)", 1, 3, 2.0 + sqrt(2.0)); test_one_lp("case12", poly_9, "LINESTRING(2 3,4 4,5 6)", 1, 2, sqrt(5.0)); test_one_lp("case13", poly_9, "LINESTRING(3 2,4 4,2 3)", 1, 3, 2.0 * sqrt(5.0)); test_one_lp("case14", poly_9, "LINESTRING(5 6,4 4,6 5)", 0, 0, 0.0); test_one_lp("case15", poly_9, "LINESTRING(0 2,1 2,1 3,0 3)", 1, 2, 1.0); test_one_lp("case16", poly_9, "LINESTRING(2 2,1 2,1 3,2 3)", 1, 4, 3.0); std::string const angly = "LINESTRING(2 2,2 1,4 1,4 2,5 2,5 3,4 3,4 4,5 4,3 6,3 5,2 5,2 6,0 4)"; test_one_lp("case17", "POLYGON((1 1,1 5,4 5,4 1,1 1))", angly, 3, 8, 6.0); test_one_lp("case18", "POLYGON((1 1,1 5,5 5,5 1,1 1))", angly, 2, 12, 10.0 + sqrt(2.0)); test_one_lp("case19", poly_9, "LINESTRING(1 2,1 3,0 3)", 1, 2, 1.0); test_one_lp("case20", poly_9, "LINESTRING(1 2,1 3,2 3)", 1, 3, 2.0); test_one_lp("case21", poly_9, "LINESTRING(1 2,1 4,4 4,4 1,2 1,2 2)", 1, 6, 11.0); // Compile test - arguments in any order: test_one("simplex", poly_simplex, "LINESTRING(0 2,4 2)", 1, 2, 2.0); test_one("simplex", "LINESTRING(0 2,4 2)", poly_simplex, 1, 2, 2.0); typedef typename bg::point_type::type Point; test_one, LineString>("simplex", poly_simplex, "LINESTRING(0 2,4 2)", 1, 2, 2.0); } template void test_all() { typedef bg::model::linestring

linestring; typedef bg::model::polygon

polygon; typedef bg::model::box

box; typedef bg::model::segment

segment; typedef bg::model::polygon polygon_ccw; typedef bg::model::polygon polygon_open; typedef bg::model::polygon polygon_ccw_open; std::string clip = "box(2 2,8 8)"; test_areal_linear(); test_areal_linear(); test_areal_linear(); test_areal_linear(); // Test polygons clockwise and counter clockwise test_areal(); test_areal(); test_areal(); test_areal(); test_areal_clip(); test_areal_clip(); #if defined(TEST_FAIL_DIFFERENT_ORIENTATIONS) // Should NOT compile // NOTE: this can probably be relaxed later on. test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 1, 7, 5.47363293); // Output ccw, nyi (should be just reversing afterwards) test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 1, 7, 5.47363293); #endif // Basic check: box/linestring, is clipping OK? should compile in any order test_one("llb", "LINESTRING(0 0,10 10)", clip, 1, 2, sqrt(2.0 * 6.0 * 6.0)); test_one("lbl", clip, "LINESTRING(0 0,10 10)", 1, 2, sqrt(2.0 * 6.0 * 6.0)); // Box/segment test_one("lsb", "LINESTRING(0 0,10 10)", clip, 1, 2, sqrt(2.0 * 6.0 * 6.0)); test_one("lbs", clip, "LINESTRING(0 0,10 10)", 1, 2, sqrt(2.0 * 6.0 * 6.0)); // Completely inside test_one("llbi", "LINESTRING(3 3,7 7)", clip, 1, 2, sqrt(2.0 * 4.0 * 4.0)); // Completely outside test_one("llbo", "LINESTRING(9 9,10 10)", clip, 0, 0, 0); // Touching with point (-> output linestring with ONE point) //std::cout << "Note: the output line is degenerate! Might be removed!" << std::endl; test_one("llb_touch", "LINESTRING(8 8,10 10)", clip, 1, 1, 0.0); // Along border test_one("llb_along", "LINESTRING(2 2,2 8)", clip, 1, 2, 6); // Outputting two lines (because of 3-4-5 constructions (0.3,0.4,0.5) // which occur 4 times, the length is expected to be 2.0) test_one("llb_2", "LINESTRING(1.7 1.6,2.3 2.4,2.9 1.6,3.5 2.4,4.1 1.6)", clip, 2, 6, 4 * 0.5); // linear test_one("llp1", "LINESTRING(0 0,1 1)", "LINESTRING(0 1,1 0)", 1, 1, 0); test_one("ssp1", "LINESTRING(0 0,1 1)", "LINESTRING(0 1,1 0)", 1, 1, 0); test_one("llp2", "LINESTRING(0 0,1 1)", "LINESTRING(0 0,2 2)", 2, 2, 0); // polygons outputing points //test_one("ppp1", simplex_normal[0], simplex_normal[1], 1, 7, 5.47363293); test_boxes("box(2 2,8 8)", "box(4 4,10 10)", 16, true); test_boxes("box(2 2,8 7)", "box(4 4,10 10)", 12, true); test_boxes("box(2 2,8 7)", "box(14 4,20 10)", 0, false); test_boxes("box(2 2,4 4)", "box(4 4,8 8)", 0, true); test_point_output

(); /* test_one(99, "box(115041.10 471900.10, 118334.60 474523.40)", "POLYGON ((115483.40 474533.40, 116549.40 474059.20, 117199.90 473762.50, 117204.90 473659.50, 118339.40 472796.90, 118334.50 472757.90, 118315.10 472604.00, 118344.60 472520.90, 118277.90 472419.10, 118071.40 472536.80, 118071.40 472536.80, 117943.10 472287.70, 117744.90 472248.40, 117708.00 472034.50, 117481.90 472056.90, 117481.90 472056.90, 117272.30 471890.10, 117077.90 472161.20, 116146.60 473054.50, 115031.10 473603.30, 115483.40 474533.40))", 1, 26, 3727690.74); */ } void test_pointer_version() { std::vector ln; test::test_point_xy* p; p = new test::test_point_xy; p->x = 0; p->y = 0; ln.push_back(p); p = new test::test_point_xy; p->x = 10; p->y = 10; ln.push_back(p); bg::model::box > box; bg::assign_values(box, 2, 2, 8, 8); typedef bg::model::linestring > output_type; std::vector clip; bg::detail::intersection::intersection_insert(box, ln, std::back_inserter(clip)); double length = 0; int n = 0; for (std::vector::const_iterator it = clip.begin(); it != clip.end(); ++it) { length += bg::length(*it); n += bg::num_points(*it); } BOOST_CHECK_EQUAL(clip.size(), 1u); BOOST_CHECK_EQUAL(n, 2); BOOST_CHECK_CLOSE(length, sqrt(2.0 * 6.0 * 6.0), 0.001); for (unsigned int i = 0; i < ln.size(); i++) { delete ln[i]; } } template void test_exception() { typedef bg::model::polygon

polygon; try { // Define polygon with a spike (= invalid) std::string spike = "POLYGON((0 0,0 4,2 4,2 6,2 4,4 4,4 0,0 0))"; test_one("with_spike", simplex_normal[0], spike, 0, 0, 0); } catch(bg::overlay_invalid_input_exception const& ) { return; } BOOST_CHECK_MESSAGE(false, "No exception thrown"); } template void test_rational() { typedef bg::model::polygon polygon; test_one("simplex_normal", simplex_normal[0], simplex_normal[1], 1, 7, 5.47363293); } int test_main(int, char* []) { test_all >(); #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) test_all >(); #if defined(HAVE_TTMATH) test_all >(); #endif #endif test_exception >(); test_pointer_version(); test_rational > >(); return 0; }