Skip to content

Commit

Permalink
Add options to TopologyPredicatePerfTest
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-jts committed Nov 23, 2024
1 parent 1ab10dd commit 930487a
Showing 1 changed file with 130 additions and 45 deletions.
175 changes: 130 additions & 45 deletions benchmarks/geom/TopologyPredicatePerfTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <geos/geom/util/SineStarFactory.h>
Expand All @@ -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<std::unique_ptr<Geometry>>& geoms) {
Expand Down Expand Up @@ -77,6 +85,15 @@ int testRelateOpTouches(const Geometry& g, const std::vector<std::unique_ptr<Geo
return count;
}

int testRelateOpRelate(const Geometry& g, const std::vector<std::unique_ptr<Geometry>>& 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<std::unique_ptr<Geometry>>& geoms) {
int count = 0;
for (const auto& geom : geoms) {
Expand Down Expand Up @@ -109,6 +126,14 @@ int testGeometryTouches(const Geometry& g, const std::vector<std::unique_ptr<Geo
return count;
}

int testGeometryRelate(const Geometry& g, const std::vector<std::unique_ptr<Geometry>>& 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<std::unique_ptr<Geometry>>& geoms) {
int count = 0;
auto prep = prep::PreparedGeometryFactory::prepare(&g);
Expand Down Expand Up @@ -172,6 +197,15 @@ int testRelateNGPreparedTouches(const Geometry& g, const std::vector<std::unique
return count;
}

int testRelateNGPreparedRelate(const Geometry& g, const std::vector<std::unique_ptr<Geometry>>& 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<typename F>
double test(const Geometry& g, const std::vector<std::unique_ptr<Geometry>>& geoms, const std::string& method, F&& fun, double baseTime)
{
Expand All @@ -187,12 +221,12 @@ double test(const Geometry& g, const std::vector<std::unique_ptr<Geometry>>& 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;
Expand All @@ -215,7 +249,27 @@ loadWKT(std::string& fname) {
return geom;
}

void dump(std::vector<std::unique_ptr<Geometry>>& 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<std::unique_ptr<Geometry>> geoms;
switch (dim) {
case 0:
Expand All @@ -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<Geometry> star = geos::benchmark::createSineStar({0, 0}, 100, npts);
if (isVerbose) {
std::cout << star->toString() << std::endl << std::endl;
}
testTarget(dim, *star);
}

Expand All @@ -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) {
Expand Down

0 comments on commit 930487a

Please # to comment.