377 строки
9.7 KiB
C++
377 строки
9.7 KiB
C++
//
|
|
// Test Suite for geos::simplify::DouglasPeuckerSimplifierTest
|
|
|
|
#include <tut/tut.hpp>
|
|
// geos
|
|
#include <geos/io/WKTReader.h>
|
|
#include <geos/io/WKTWriter.h>
|
|
#include <geos/geom/PrecisionModel.h>
|
|
#include <geos/geom/GeometryFactory.h>
|
|
#include <geos/geom/Geometry.h>
|
|
#include <geos/geom/Coordinate.h>
|
|
#include <geos/geom/CoordinateSequenceFilter.h>
|
|
#include <geos/simplify/DouglasPeuckerSimplifier.h>
|
|
#include <geos/util.h>
|
|
// std
|
|
#include <string>
|
|
#include <memory>
|
|
|
|
namespace tut {
|
|
using namespace geos::simplify;
|
|
|
|
//
|
|
// Test Group
|
|
//
|
|
|
|
// Common data used by tests
|
|
struct test_dpsimp_data {
|
|
geos::io::WKTReader wktreader;
|
|
geos::io::WKTWriter wktwriter;
|
|
|
|
typedef geos::geom::Geometry::Ptr GeomPtr;
|
|
|
|
test_dpsimp_data()
|
|
:
|
|
wktreader()
|
|
{}
|
|
};
|
|
|
|
typedef test_group<test_dpsimp_data> group;
|
|
typedef group::object object;
|
|
|
|
group test_dpsimp_group("geos::simplify::DouglasPeuckerSimplifier");
|
|
|
|
//
|
|
// Test Cases
|
|
//
|
|
|
|
// 1 - PolygonNoReduction
|
|
template<>
|
|
template<>
|
|
void object::test<1>
|
|
()
|
|
{
|
|
std::string wkt("POLYGON((20 220, 40 220, 60 220, 80 220, 100 220, \
|
|
120 220, 140 220, 140 180, 100 180, 60 180, 20 180, 20 220))");
|
|
|
|
GeomPtr g(wktreader.read(wkt));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
// topology is unchanged
|
|
ensure(simplified->equals(g.get()));
|
|
}
|
|
|
|
// 2 - PolygonReductionWithSplit
|
|
template<>
|
|
template<>
|
|
void object::test<2>
|
|
()
|
|
{
|
|
std::string wkt_in("POLYGON ((40 240, 160 241, 280 240, 280 160, \
|
|
160 240, 40 140, 40 240))");
|
|
|
|
std::string wkt_ex("MULTIPOLYGON (((40.0 240.0, 160.0 240.0, 40.0 140.0, 40.0 240.0)), \
|
|
((160.0 240.0, 280.0 240.0, 280.0 160.0, 160.0 240.0)))");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
// TODO: This test blows because if instability of geos.index.strtree::yComparator() predicate
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
|
|
}
|
|
|
|
// 3 - PolygonReduction
|
|
template<>
|
|
template<>
|
|
void object::test<3>
|
|
()
|
|
{
|
|
std::string wkt_in("POLYGON ((120 120, 121 121, 122 122, 220 120, \
|
|
180 199, 160 200, 140 199, 120 120))");
|
|
|
|
std::string wkt_ex("POLYGON ((120 120, 140 199, 160 200, 180 199, 220 120, 120 120))");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
|
|
}
|
|
|
|
// 4 - PolygonWithTouchingHole
|
|
template<>
|
|
template<>
|
|
void object::test<4>
|
|
()
|
|
{
|
|
std::string wkt_in("POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200), \
|
|
(120 120, 220 120, 180 199, 160 200, 140 199, 120 120))");
|
|
|
|
std::string wkt_ex("POLYGON ((80 200, 160 200, 240 200, 240 60, 80 60, 80 200), \
|
|
(160 200, 140 199, 120 120, 220 120, 180 199, 160 200)))");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
|
|
}
|
|
|
|
// 5 - FlattishPolygon
|
|
template<>
|
|
template<>
|
|
void object::test<5>
|
|
()
|
|
{
|
|
std::string wkt_in("POLYGON ((0 0, 50 0, 53 0, 55 0, 100 0, 70 1, 60 1, 50 1, 40 1, 0 0))");
|
|
std::string wkt_ex("POLYGON EMPTY");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
//ensure_equals( *simplified, *expected );
|
|
|
|
}
|
|
|
|
// 6 - TinySquare
|
|
template<>
|
|
template<>
|
|
void object::test<6>
|
|
()
|
|
{
|
|
std::string wkt_in("POLYGON ((0 5, 5 5, 5 0, 0 0, 0 1, 0 5))");
|
|
std::string wkt_ex("POLYGON EMPTY");
|
|
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
|
|
}
|
|
|
|
// 7 - TinyLineString
|
|
template<>
|
|
template<>
|
|
void object::test<7>
|
|
()
|
|
{
|
|
std::string wkt_in("LINESTRING (0 5, 1 5, 2 5, 5 5)");
|
|
std::string wkt_ex("LINESTRING (0 5, 5 5)");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
|
|
}
|
|
|
|
// 8 - MultiPoint
|
|
template<>
|
|
template<>
|
|
void object::test<8>
|
|
()
|
|
{
|
|
std::string wkt_in("MULTIPOINT(80 200, 240 200, 240 60, 80 60, 80 200, 140 199, 120 120)");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
// MultiPoint is *not* simplified
|
|
ensure(simplified->equalsExact(g.get()));
|
|
}
|
|
|
|
// 9 - MultiLineString
|
|
template<>
|
|
template<>
|
|
void object::test<9>
|
|
()
|
|
{
|
|
std::string wkt_in("MULTILINESTRING( (0 0, 50 0, 70 0, 80 0, 100 0), \
|
|
(0 0, 50 1, 60 1, 100 0) )");
|
|
|
|
std::string wkt_ex("MULTILINESTRING( (0 0, 100 0), (0 0, 100 0) )");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
}
|
|
|
|
// 10 - GeometryCollection
|
|
template<>
|
|
template<>
|
|
void object::test<10>
|
|
()
|
|
{
|
|
std::string wkt_in("GEOMETRYCOLLECTION ( \
|
|
MULTIPOINT (80 200, 240 200, 240 60, 80 60, 80 200, 140 199, 120 120), \
|
|
POLYGON ((80 200, 240 200, 240 60, 80 60, 80 200)), \
|
|
LINESTRING (80 200, 240 200, 240 60, 80 60, 80 200, 140 199, 120 120) )");
|
|
|
|
std::string wkt_ex("MULTILINESTRING( (0 0, 100 0), (0 0, 100 0) )");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 10.0);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
// Non simplification occurs
|
|
ensure(simplified->equalsExact(g.get()));
|
|
}
|
|
|
|
// 11 - A kind of reversed simplification
|
|
template<>
|
|
template<>
|
|
void object::test<11>
|
|
()
|
|
{
|
|
using namespace geos::geom;
|
|
|
|
std::string
|
|
wkt("MULTIPOLYGON(((0.561648 1,1 1,1 0,0.468083 0,0.52758 0.00800554,0.599683 0.0280924, 0.601611 0.265374, \
|
|
0.622693 0.316765,0.69507 0.357497,0.695623 0.429711,0.655111 0.502298, 0.696467 0.543147,0.840712 0.593546, \
|
|
0.882583 0.66546,0.852357 0.748213,0.84264 0.789567,0 .832667 0.841202,0.832667 0.841202,0.740538 0.873004, \
|
|
0.617349 0.905045,0.566576 0.977697,0.561648 1)),((0 0.801979,0.0308575 0.786234,0.0705513 0.631135, \
|
|
0.141616 0.527248,0.233985 0.505872,0.264777 0.526263,0.336631 0.505009,0.356603 0.422321,0.355803 0.350038, \
|
|
0.375252 0.205364,0.415206 0.0709182,0.45479 0,0 0,0 0,0 0.801979)))");
|
|
|
|
GeomPtr g(wktreader.read(wkt));
|
|
std::size_t const gN = g->getNumPoints();
|
|
ensure_equals(gN, std::size_t(37));
|
|
|
|
// 1) Simplify with 1/2048
|
|
double const d1 = 1 / 2048.0;
|
|
GeomPtr simplified1 = DouglasPeuckerSimplifier::simplify(g.get(), d1);
|
|
ensure(simplified1->isValid());
|
|
ensure(simplified1->equals(g.get()));
|
|
std::size_t const simplifiedN1 = simplified1->getNumPoints();
|
|
ensure_equals(simplifiedN1, std::size_t(36));
|
|
//std::string const simplifiedWkd = wktwriter.write(simplified1.get());
|
|
|
|
// 2) Multiply points by 2047
|
|
struct Multiplier : public CoordinateSequenceFilter {
|
|
double f;
|
|
Multiplier(double p_f) : f(p_f) {}
|
|
void
|
|
filter_rw(CoordinateSequence& seq, std::size_t i) override
|
|
{
|
|
seq.setOrdinate(i, CoordinateSequence::X, seq[i].x * f);
|
|
seq.setOrdinate(i, CoordinateSequence::Y, seq[i].y * f);
|
|
}
|
|
void
|
|
filter_ro(const CoordinateSequence& seq, std::size_t i) override
|
|
{
|
|
::geos::ignore_unused_variable_warning(seq);
|
|
::geos::ignore_unused_variable_warning(i);
|
|
}
|
|
bool
|
|
isDone() const override
|
|
{
|
|
return false;
|
|
}
|
|
bool
|
|
isGeometryChanged() const override
|
|
{
|
|
return true;
|
|
}
|
|
};
|
|
|
|
Multiplier m(2047);
|
|
g->apply_rw(m);
|
|
std::size_t const multipliedN = g->getNumPoints();
|
|
ensure_equals(multipliedN, std::size_t(37));
|
|
//std::string const multipliedWkt = wktwriter.write(g.get());
|
|
|
|
// 3) Simplify with 1.0
|
|
double const d2 = 1.0;
|
|
GeomPtr simplified2 = DouglasPeuckerSimplifier::simplify(g.get(), d2);
|
|
ensure(simplified2->isValid());
|
|
ensure(simplified2->equals(g.get()));
|
|
std::size_t const simplifiedN2 = simplified2->getNumPoints();
|
|
ensure_equals(simplifiedN2, std::size_t(36));
|
|
//std::string const simplifiedWkt2 = wktwriter.write(simplified2.get());
|
|
}
|
|
|
|
// 13 - Polygon with inner ring whose extent is less than the simplify distance (#741)
|
|
template<>
|
|
template<>
|
|
void object::test<13>
|
|
()
|
|
{
|
|
std::string wkt_in("POLYGON ((0 0,0 1,1 1,0 0),(0.1 0.1,0.2 0.1,0.2 0.2,0.1 0.1))");
|
|
|
|
std::string wkt_ex("POLYGON ((0 0,0 1,1 1,0 0))");
|
|
|
|
GeomPtr g(wktreader.read(wkt_in));
|
|
|
|
GeomPtr expected(wktreader.read(wkt_ex));
|
|
|
|
GeomPtr simplified = DouglasPeuckerSimplifier::simplify(
|
|
g.get(), 0.5);
|
|
|
|
ensure(simplified->isValid());
|
|
|
|
ensure(simplified->equalsExact(expected.get()));
|
|
}
|
|
|
|
} // namespace tut
|
|
|