diff --git a/benchmarks/geom/TopologyPredicatePerfTest.cpp b/benchmarks/geom/TopologyPredicatePerfTest.cpp index e21ffce77..c3ea05bae 100644 --- a/benchmarks/geom/TopologyPredicatePerfTest.cpp +++ b/benchmarks/geom/TopologyPredicatePerfTest.cpp @@ -4,7 +4,12 @@ * Tests a target geometry against grids of points, lines and polygons covering the target. * Target is either a geometry from a WKT file or a set of generated sine stars increasing in size. * - * Usage: perf_topo_predicate [WKT file] [ intersects | contains | covers | touches ] [num target geoms] + * Usage: perf_topo_predicate [-v] [WKT file] [ pred ] [num target geoms] + * where pred ::= intersects | contains | covers | touches | relate:PPPPPPPPP + * with PPPPPPPPP being a DE-9IM pattern + * (e.g. T******** (INTERIOR_INTERSECTS) or T**FF*FF* (CONTAINS_PROPERLY) + * - -v enables verbose mode. The test geometries are printed + * ******************************************************/ #include @@ -31,14 +36,17 @@ std::size_t MAX_ITER = 1; std::size_t NUM_GEOM = 1000; std::size_t NUM_PTS = 100; -#define INTERSECTS 0 -#define CONTAINS 1 -#define COVERS 2 -#define TOUCHES 3 +#define PRED_INTERSECTS 0 +#define PRED_CONTAINS 1 +#define PRED_COVERS 2 +#define PRED_TOUCHES 3 +#define PRED_RELATE 4 +bool isVerbose = false; std::string inputFilename{""}; std::string predicateName{"intersects"}; -int predicateOp = INTERSECTS; +std::string relatePattern{"********"}; +int predicateOp = PRED_INTERSECTS; std::size_t numTestGeometries = NUM_GEOM; int testRelateOpIntersects(const Geometry& g, const std::vector>& geoms) { @@ -77,6 +85,15 @@ int testRelateOpTouches(const Geometry& g, const std::vector>& geoms) { + int count = 0; + for (const auto& geom : geoms) { + auto im = RelateOp::relate(&g, geom.get()); + count += im->matches(relatePattern.c_str()); + } + return count; +} + int testGeometryIntersects(const Geometry& g, const std::vector>& geoms) { int count = 0; for (const auto& geom : geoms) { @@ -109,6 +126,14 @@ int testGeometryTouches(const Geometry& g, const std::vector>& geoms) { + int count = 0; + for (const auto& geom : geoms) { + count += g.relate(geom.get(), relatePattern.c_str()); + } + return count; +} + int testPrepGeomIntersects(const Geometry& g, const std::vector>& geoms) { int count = 0; auto prep = prep::PreparedGeometryFactory::prepare(&g); @@ -172,6 +197,15 @@ int testRelateNGPreparedTouches(const Geometry& g, const std::vector>& geoms) { + int count = 0; + auto prep = geos::operation::relateng::RelateNG::prepare(&g); + for (const auto& line : geoms) { + count += prep->evaluate(line.get(), *geos::operation::relateng::RelatePredicate::matches(relatePattern.c_str())); + } + return count; +} + template double test(const Geometry& g, const std::vector>& geoms, const std::string& method, F&& fun, double baseTime) { @@ -187,12 +221,12 @@ double test(const Geometry& g, const std::vector>& geo double tot = sw.getTot(); double timesFaster = baseTime == 0 ? 1 : baseTime / tot; std::cout << std::fixed << std::setprecision(0); - std::cout << g.getNumPoints() << "," - << MAX_ITER * geoms.size() << "," - << count << "," << geoms[0]->getGeometryType() << "," - << geoms[0]->getNumPoints() << "," - << method << " - " << predicateName << "," - << tot << ","; + std::cout << g.getNumPoints() << ", " + << MAX_ITER * geoms.size() << ", " + << count << ", " << geoms[0]->getGeometryType() << ", " + << geoms[0]->getNumPoints() << ", " + << method << " - " << predicateName << ", " + << tot << ", "; std::cout << std::fixed << std::setprecision(1); std::cout << timesFaster << std::endl; @@ -215,7 +249,27 @@ loadWKT(std::string& fname) { return geom; } +void dump(std::vector>& geoms) +{ + for (const auto& geom : geoms) { + std::cout << geom->toString() << std::endl; + } +} + +double computeSize(Geometry& target, size_t numGeoms) +{ + const Envelope* env = target.getEnvelopeInternal(); + double w = env->getWidth(); + double h = env->getHeight(); + double d = std::min(w, h); + double size = d / std::sqrt(numGeoms); + return size; +} + void testTarget(int dim, Geometry& target) { + + double size = computeSize(target, numTestGeometries); + std::vector> geoms; switch (dim) { case 0: @@ -224,43 +278,52 @@ void testTarget(int dim, Geometry& target) { break; case 1: geoms = geos::benchmark::createLines(*target.getEnvelopeInternal(), - numTestGeometries, 1.0, NUM_PTS); + numTestGeometries, size, NUM_PTS); break; case 2: geoms = geos::benchmark::createPolygons(*target.getEnvelopeInternal(), - numTestGeometries, 1.0, NUM_PTS); + numTestGeometries, size, NUM_PTS); break; } + if (isVerbose) dump(geoms); double baseTime; switch (predicateOp) { - case INTERSECTS: + case PRED_INTERSECTS: baseTime = test(target, geoms, "RelateOp", testRelateOpIntersects, 0); test(target, geoms, "Geometry", testGeometryIntersects, baseTime); test(target, geoms, "PreparedGeom", testPrepGeomIntersects, baseTime); test(target, geoms, "RelateNGPrepared", testRelateNGPreparedIntersects, baseTime); break; - case CONTAINS: + case PRED_CONTAINS: baseTime = test(target, geoms, "RelateOp", testRelateOpIntersects, 0); test(target, geoms, "Geometry", testGeometryIntersects, baseTime); test(target, geoms, "PreparedGeom", testPrepGeomContains, baseTime); test(target, geoms, "RelateNGPrepared", testRelateNGPreparedContains, baseTime); break; - case COVERS: + case PRED_COVERS: baseTime = test(target, geoms, "RelateOp", testRelateOpCovers, 0); test(target, geoms, "Geometry", testGeometryCovers, baseTime); test(target, geoms, "PreparedGeom", testPrepGeomCovers, baseTime); test(target, geoms, "RelateNGPrepared", testRelateNGPreparedCovers, baseTime); break; - case TOUCHES: + case PRED_TOUCHES: baseTime = test(target, geoms, "RelateOp", testRelateOpTouches, 0); test(target, geoms, "Geometry", testGeometryTouches, baseTime); test(target, geoms, "RelateNGPrepared", testRelateNGPreparedTouches, baseTime); break; + case PRED_RELATE: + baseTime = test(target, geoms, "RelateOp", testRelateOpRelate, 0); + test(target, geoms, "Geometry", testGeometryRelate, baseTime); + test(target, geoms, "RelateNGPrepared", testRelateNGPreparedRelate, baseTime); + break; } } void testStar(int dim, std::size_t npts) { std::unique_ptr star = geos::benchmark::createSineStar({0, 0}, 100, npts); + if (isVerbose) { + std::cout << star->toString() << std::endl << std::endl; + } testTarget(dim, *star); } @@ -276,45 +339,67 @@ void testStarAll(int dim) testStar(dim, 16000); } -void parseArgs(int argc, char** argv) { - int iPred = -1; - int iFile = -1; - //-- parse filename, predicate, num geoms, if present - for (int i = 1; i < argc; i++) { - std::string arg = argv[i]; - if (arg.find(".") != std::string::npos) - iFile = i; - else { - bool isInt = (arg.find_first_not_of( "0123456789" ) == std::string::npos); - if (isInt) { - numTestGeometries = (size_t) std::stoi(arg); - } - else { - iPred = i; - } +void parsePredicate(std::string& predArg) +{ + predicateName = predArg; + if (predicateName.substr(0, 6) == "relate") { + if (predicateName.length() != 16) { + std::cerr << "Invalid relate pattern: " << predicateName << std::endl; + exit(1); } - } - - if (iPred > 0) { - predicateName = argv[iPred]; - } - if (iFile > 0) { - inputFilename = argv[iFile]; + relatePattern = predicateName.substr(7, 9); } //------------------ //-- interpret args - predicateOp = INTERSECTS; + predicateOp = PRED_INTERSECTS; if (predicateName == "contains") { - predicateOp = CONTAINS; + predicateOp = PRED_CONTAINS; } else if (predicateName == "covers") { - predicateOp = COVERS; + predicateOp = PRED_COVERS; } else if (predicateName == "touches") { - predicateOp = TOUCHES; + predicateOp = PRED_TOUCHES; + } + else if (predicateName.substr(0, 6) == "relate") { + predicateOp = PRED_RELATE; + } +} + +void parseArgs(int argc, char** argv) { + int iArg = 1; + + //-- parse verbose flag, if present + if (iArg >= argc) return; + std::string arg = argv[iArg]; + if (arg == "-v") { + isVerbose = true; + iArg++; + } + + //-- parse filename, if present + if (iArg >= argc) return; + arg = argv[iArg]; + if (arg.find(".") != std::string::npos) { + inputFilename = arg; + iArg++; } + + //-- parse predicate, if present + if (iArg >= argc) return; + arg = argv[iArg]; + bool isInt = (arg.find_first_not_of( "0123456789" ) == std::string::npos); + if (! isInt) { + parsePredicate(arg); + iArg++; + } + + //-- parse predicate, if present + if (iArg >= argc) return; + arg = argv[iArg]; + numTestGeometries = (size_t) std::stoi(arg); } int main(int argc, char** argv) {