diff options
Diffstat (limited to 'src/3rdparty/2geom/tests/convex-hull-test.cpp')
-rw-r--r-- | src/3rdparty/2geom/tests/convex-hull-test.cpp | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/src/3rdparty/2geom/tests/convex-hull-test.cpp b/src/3rdparty/2geom/tests/convex-hull-test.cpp new file mode 100644 index 0000000..2f20f43 --- /dev/null +++ b/src/3rdparty/2geom/tests/convex-hull-test.cpp @@ -0,0 +1,335 @@ +/** @file + * @brief Unit tests for ConvexHull and related functions. + * Uses the Google Testing Framework + *//* + * Authors: + * Nathan Hurst <njh@njhurst.com> + * Krzysztof KosiĆski <tweenk.pl@gmail.com> + * + * Copyright 2011-2015 Authors + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + */ + +#include "testing.h" +#include <iostream> + +#include <2geom/convex-hull.h> +#include <vector> +#include <iterator> + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +using namespace std; +using namespace Geom; + +void points_from_shape(std::vector<Point> &pts, std::string const &shape) { + pts.clear(); + int x = 0, y = 0; + for (char c : shape) { + if (c == '\n') { + x = 0; ++y; + continue; + } + if (c == ' ') { + ++x; + continue; + } + pts.emplace_back(x, y); + ++x; + } +} + +class ConvexHullTest : public ::testing::Test { +protected: + ConvexHullTest() + : null(hulls[0]) + , point(hulls[1]) + , line(hulls[2]) + , triangle(hulls[3]) + , square(hulls[4]) + , hexagon(hulls[5]) + , antihexagon(hulls[6]) + , gem(hulls[7]) + , diamond(hulls[8]) + { + null = ConvexHull(); + + std::vector<Point> pts; + + pts.emplace_back(0,0); + point = ConvexHull(pts); + pts.emplace_back(1,0); + line = ConvexHull(pts); + pts.emplace_back(0,1); + triangle = ConvexHull(pts); + pts.emplace_back(1,1); + square = ConvexHull(pts); + pts.clear(); + + for(int i = 0; i < 6; i++) { + pts.emplace_back(cos(i*M_PI*2/6), sin(i*M_PI*2/6)); + } + hexagon = ConvexHull(pts); + pts.clear(); + + for(int i = 0; i < 6; i++) { + pts.emplace_back(cos((1-i*2)*M_PI/6), sin((1-i*2)*M_PI/6)); + } + antihexagon = ConvexHull(pts); + pts.clear(); + + gem_shape = + " ++++ \n" + "++++++ \n" + "++++++ \n" + "++++++ \n" + " ++++ \n"; + points_from_shape(pts, gem_shape); + gem.swap(pts); + + diamond_shape = + " + \n" + " +++++ \n" + " +++++ \n" + "+++++++ \n" + " +++++ \n" + " +++++ \n" + " + \n"; + points_from_shape(pts, diamond_shape); + diamond.swap(pts); + } + + ConvexHull hulls[9]; + ConvexHull &null, &point, &line, &triangle, &square, &hexagon, &antihexagon, &gem, ⋄ + std::string gem_shape, diamond_shape; +}; + +void check_convex(ConvexHull &/*ch*/) { + // TODO +} + +TEST_F(ConvexHullTest, SizeAndDegeneracy) { + EXPECT_EQ(0u, null.size()); + EXPECT_TRUE(null.empty()); + EXPECT_TRUE(null.isDegenerate()); + EXPECT_FALSE(null.isSingular()); + EXPECT_FALSE(null.isLinear()); + + EXPECT_EQ(1u, point.size()); + EXPECT_FALSE(point.empty()); + EXPECT_TRUE(point.isDegenerate()); + EXPECT_TRUE(point.isSingular()); + EXPECT_FALSE(point.isLinear()); + + EXPECT_EQ(2u, line.size()); + EXPECT_FALSE(line.empty()); + EXPECT_TRUE(line.isDegenerate()); + EXPECT_FALSE(line.isSingular()); + EXPECT_TRUE(line.isLinear()); + + EXPECT_EQ(3u, triangle.size()); + EXPECT_FALSE(triangle.empty()); + EXPECT_FALSE(triangle.isDegenerate()); + EXPECT_FALSE(triangle.isSingular()); + EXPECT_FALSE(triangle.isLinear()); + + EXPECT_EQ(4u, square.size()); + EXPECT_FALSE(square.empty()); + EXPECT_FALSE(square.isDegenerate()); + EXPECT_FALSE(square.isSingular()); + EXPECT_FALSE(square.isLinear()); + + EXPECT_EQ(6u, hexagon.size()); + EXPECT_FALSE(hexagon.empty()); + EXPECT_FALSE(hexagon.isDegenerate()); + EXPECT_FALSE(hexagon.isSingular()); + EXPECT_FALSE(hexagon.isLinear()); + + EXPECT_EQ(6u, antihexagon.size()); + EXPECT_FALSE(antihexagon.empty()); + EXPECT_FALSE(antihexagon.isDegenerate()); + EXPECT_FALSE(antihexagon.isSingular()); + EXPECT_FALSE(antihexagon.isLinear()); + + EXPECT_EQ(8u, gem.size()); + EXPECT_FALSE(gem.empty()); + EXPECT_FALSE(gem.isDegenerate()); + EXPECT_FALSE(gem.isSingular()); + EXPECT_FALSE(gem.isLinear()); + + EXPECT_EQ(8u, diamond.size()); + EXPECT_FALSE(diamond.empty()); + EXPECT_FALSE(diamond.isDegenerate()); + EXPECT_FALSE(diamond.isSingular()); + EXPECT_FALSE(diamond.isLinear()); +} + + +TEST_F(ConvexHullTest, Area) { + EXPECT_EQ(0, null.area()); + EXPECT_EQ(0, point.area()); + EXPECT_EQ(0, line.area()); + EXPECT_EQ(0.5, triangle.area()); + EXPECT_EQ(1, square.area()); + EXPECT_EQ(18, gem.area()); + EXPECT_EQ(24, diamond.area()); + EXPECT_FLOAT_EQ(6*(0.5*1*sin(M_PI/3)), hexagon.area()); + EXPECT_FLOAT_EQ(6*(0.5*1*sin(M_PI/3)), antihexagon.area()); +} + +TEST_F(ConvexHullTest, Bounds) { + //Rect hexbounds(-1,sin(M_PI/3),1,-sin(M_PI/3)); + + EXPECT_EQ(OptRect(), null.bounds()); + EXPECT_EQ(OptRect(0,0,0,0), point.bounds()); + EXPECT_EQ(OptRect(0,0,1,0), line.bounds()); + EXPECT_EQ(OptRect(0,0,1,1), triangle.bounds()); + EXPECT_EQ(OptRect(0,0,1,1), square.bounds()); + EXPECT_EQ(OptRect(0,0,5,4), gem.bounds()); + EXPECT_EQ(OptRect(0,0,6,6), diamond.bounds()); + //EXPECT_TRUE(hexbounds == hexagon.bounds()); + //EXPECT_TRUE(hexbounds == antihexagon.bounds()); +} + +::testing::AssertionResult HullContainsPoint(ConvexHull const &h, Point const &p) { + if (h.contains(p)) { + return ::testing::AssertionSuccess(); + } else { + return ::testing::AssertionFailure() + << "Convex hull:\n" + << h << "\ndoes not contain " << p; + } +} + +TEST_F(ConvexHullTest, PointContainment) { + Point zero(0,0), half(0.5, 0.5), x(0.25, 0.25); + EXPECT_FALSE(HullContainsPoint(null, zero)); + EXPECT_TRUE(HullContainsPoint(point, zero)); + EXPECT_TRUE(HullContainsPoint(line, zero)); + EXPECT_TRUE(HullContainsPoint(triangle, zero)); + EXPECT_TRUE(HullContainsPoint(square, zero)); + EXPECT_FALSE(HullContainsPoint(line, half)); + EXPECT_TRUE(HullContainsPoint(triangle, x)); + EXPECT_TRUE(HullContainsPoint(triangle, half)); + EXPECT_TRUE(HullContainsPoint(square, half)); + EXPECT_TRUE(HullContainsPoint(hexagon, zero)); + EXPECT_TRUE(HullContainsPoint(antihexagon, zero)); + + std::vector<Point> pts; + + points_from_shape(pts, gem_shape); + for (auto & pt : pts) { + EXPECT_TRUE(HullContainsPoint(gem, pt)); + } + + points_from_shape(pts, diamond_shape); + for (auto & pt : pts) { + EXPECT_TRUE(HullContainsPoint(diamond, pt)); + } + + /*EXPECT_FALSE(null.interiorContains(zero)); + EXPECT_FALSE(point.interiorContains(zero)); + EXPECT_FALSE(line.interiorContains(zero)); + EXPECT_FALSE(triangle.interiorContains(zero)); + EXPECT_FALSE(square.interiorContains(zero)); + EXPECT_FALSE(line.interiorContains(half)); + EXPECT_FALSE(triangle.interiorContains(Point(0,0.5))); + EXPECT_FALSE(triangle.interiorContains(half)); + EXPECT_TRUE(square.interiorContains(half));*/ +} + +TEST_F(ConvexHullTest, ExtremePoints) { + Point zero(0,0); + EXPECT_EQ(0., point.top()); + EXPECT_EQ(0., point.right()); + EXPECT_EQ(0., point.bottom()); + EXPECT_EQ(0., point.left()); + EXPECT_EQ(zero, point.topPoint()); + EXPECT_EQ(zero, point.rightPoint()); + EXPECT_EQ(zero, point.bottomPoint()); + EXPECT_EQ(zero, point.leftPoint()); + + // line from 0,0 to 1,0 + EXPECT_EQ(0., line.top()); + EXPECT_EQ(1., line.right()); + EXPECT_EQ(0., line.bottom()); + EXPECT_EQ(0., line.left()); + EXPECT_EQ(Point(1,0), line.topPoint()); + EXPECT_EQ(Point(1,0), line.rightPoint()); + EXPECT_EQ(Point(0,0), line.bottomPoint()); + EXPECT_EQ(Point(0,0), line.leftPoint()); + + // triangle 0,0 1,0 0,1 + EXPECT_EQ(0., triangle.top()); + EXPECT_EQ(1., triangle.right()); + EXPECT_EQ(1., triangle.bottom()); + EXPECT_EQ(0., triangle.left()); + EXPECT_EQ(Point(1,0), triangle.topPoint()); + EXPECT_EQ(Point(1,0), triangle.rightPoint()); + EXPECT_EQ(Point(0,1), triangle.bottomPoint()); + EXPECT_EQ(Point(0,0), triangle.leftPoint()); + + // square 0,0 to 1,1 + EXPECT_EQ(0., square.top()); + EXPECT_EQ(1., square.right()); + EXPECT_EQ(1., square.bottom()); + EXPECT_EQ(0., square.left()); + EXPECT_EQ(Point(1,0), square.topPoint()); + EXPECT_EQ(Point(1,1), square.rightPoint()); + EXPECT_EQ(Point(0,1), square.bottomPoint()); + EXPECT_EQ(Point(0,0), square.leftPoint()); + + EXPECT_EQ(0., gem.top()); + EXPECT_EQ(5., gem.right()); + EXPECT_EQ(4., gem.bottom()); + EXPECT_EQ(0., gem.left()); + EXPECT_EQ(Point(4,0), gem.topPoint()); + EXPECT_EQ(Point(5,3), gem.rightPoint()); + EXPECT_EQ(Point(1,4), gem.bottomPoint()); + EXPECT_EQ(Point(0,1), gem.leftPoint()); + + EXPECT_EQ(0., diamond.top()); + EXPECT_EQ(6., diamond.right()); + EXPECT_EQ(6., diamond.bottom()); + EXPECT_EQ(0., diamond.left()); + EXPECT_EQ(Point(3,0), diamond.topPoint()); + EXPECT_EQ(Point(6,3), diamond.rightPoint()); + EXPECT_EQ(Point(3,6), diamond.bottomPoint()); + EXPECT_EQ(Point(0,3), diamond.leftPoint()); +} + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : |