diff --git a/src/spatialjoin/BoxIds.h b/src/spatialjoin/BoxIds.h index f7b1095..4b9aaf5 100644 --- a/src/spatialjoin/BoxIds.h +++ b/src/spatialjoin/BoxIds.h @@ -21,6 +21,8 @@ const static double WORLD_H = 20037508.3427892 * PREC * 2; const static double GRID_W = WORLD_W / NUM_GRID_CELLS; const static double GRID_H = WORLD_H / NUM_GRID_CELLS; +const static double GRID_AREA = GRID_W * GRID_H; + typedef std::pair BoxId; typedef std::vector BoxIdList; @@ -43,62 +45,68 @@ inline int32_t getBoxId(const util::geo::I32Point& p) { } // ____________________________________________________________________________ -inline BoxIdList getBoxIds(const util::geo::I32XSortedLine& line, - const util::geo::I32Box& envelope, - std::map* cutouts) { - int32_t startX = std::floor( - (1.0 * envelope.getLowerLeft().getX() + WORLD_W / 2.0) / GRID_W); - int32_t startY = std::floor( - (1.0 * envelope.getLowerLeft().getY() + WORLD_H / 2.0) / GRID_H); +inline void getBoxIds(const util::geo::I32XSortedLine& line, + const util::geo::I32Box& envelope, int xFrom, int xTo, + int yFrom, int yTo, int xWidth, int yHeight, + BoxIdList* ret, std::map* cutouts, + size_t startA, size_t startB) { - int32_t endX = - std::floor((1.0 * envelope.getUpperRight().getX() + WORLD_W / 2.0) / - GRID_W) + - 1; - int32_t endY = - std::floor((1.0 * envelope.getUpperRight().getY() + WORLD_H / 2.0) / - GRID_H) + - 1; + for (int32_t y = yFrom; y < yTo; y += yHeight) { + size_t firstInA = startA; + size_t firstInB = startB; - BoxIdList boxIds; + for (int32_t x = xFrom; x < xTo; x += xWidth) { + int localXWidth = std::min(xTo - x, xWidth); + int localYHeight = std::min(yTo - y, yHeight); - for (int32_t y = startY; y < endY; y++) { - for (int32_t x = startX; x < endX; x++) { util::geo::I32Box box( {(x * GRID_W - WORLD_W / 2), (y * GRID_H - WORLD_H / 2)}, - {(x + 1) * GRID_W - WORLD_W / 2, (y + 1) * GRID_H - WORLD_H / 2}); + {(x + localXWidth + 1) * GRID_W - WORLD_W / 2, + (y + localYHeight + 1) * GRID_H - WORLD_H / 2}); + + if (!util::geo::intersects(box, envelope)) continue; const util::geo::I32XSortedPolygon boxPoly{util::geo::I32Polygon(box)}; - size_t firstInA = 0; - size_t firstInB = 0; + auto check = util::geo::intersectsContainsCovers( + line, envelope, boxPoly, box, &firstInA, &firstInB); - if (std::get<0>(util::geo::intersectsContainsCovers( - line, envelope, boxPoly, box, &firstInA, &firstInB))) { - int32_t newId = y * NUM_GRID_CELLS + x + 1; - if (!boxIds.empty() && boxIds.back().second < 254 && - boxIds.back().first + boxIds.back().second == newId - 1) { - boxIds.back().second++; + if (std::get<0>(check)) { + if (localXWidth == 1 && localYHeight == 1) { + int32_t newId = y * NUM_GRID_CELLS + x + 1; if (cutouts) (*cutouts)[newId] = firstInB; + + if (!ret->empty() && ret->back().second < 254 && + ret->back().first - ret->back().second == newId + 1) { + ret->back().second++; + } else { + ret->push_back({newId, 0}); + } } else { - boxIds.push_back({newId, 0}); - if (cutouts) (*cutouts)[newId] = firstInB; + // we need to check in detail on a smaller level! + // recurse down... + int newXWidth = (localXWidth + 1) / 2; + int newYHeight = (localYHeight + 1) / 2; + + getBoxIds(line, envelope, x, x + localXWidth, y, y + localYHeight, + newXWidth, newYHeight, ret, cutouts, firstInA, firstInB); } } } } - - return boxIds; } // ____________________________________________________________________________ inline void getBoxIds(const util::geo::I32XSortedPolygon& poly, - const util::geo::I32Polygon& polyr, const util::geo::I32Box& envelope, double area, int xFrom, int xTo, int yFrom, int yTo, int xWidth, int yHeight, - BoxIdList* ret, std::map* cutouts) { + BoxIdList* ret, std::map* cutouts, + size_t startA, size_t startB) { for (int32_t y = yFrom; y < yTo; y += yHeight) { + size_t firstInA = startA; + size_t firstInB = startB; + for (int32_t x = xFrom; x < xTo; x += xWidth) { int localXWidth = std::min(xTo - x, xWidth); int localYHeight = std::min(yTo - y, yHeight); @@ -108,18 +116,14 @@ inline void getBoxIds(const util::geo::I32XSortedPolygon& poly, {(x + localXWidth + 1) * GRID_W - WORLD_W / 2, (y + localYHeight + 1) * GRID_H - WORLD_H / 2}); - if (!util::geo::intersects(box, envelope)) { - continue; - } + if (!util::geo::intersects(box, envelope)) continue; const util::geo::I32XSortedPolygon boxPoly{util::geo::I32Polygon(box)}; - size_t firstInA = 0; - size_t firstInB = 0; + double boxArea = GRID_AREA * (localXWidth + 1) * (localYHeight + 1); auto check = util::geo::intersectsContainsCovers( - boxPoly, box, util::geo::area(box), poly, envelope, area, &firstInA, - &firstInB); + boxPoly, box, boxArea, poly, envelope, area, &firstInA, &firstInB); if (std::get<1>(check)) { // we can insert all at once @@ -152,19 +156,54 @@ inline void getBoxIds(const util::geo::I32XSortedPolygon& poly, int newXWidth = (localXWidth + 1) / 2; int newYHeight = (localYHeight + 1) / 2; - getBoxIds(poly, polyr, envelope, area, x, x + localXWidth, y, - y + localYHeight, newXWidth, newYHeight, ret, cutouts); + getBoxIds(poly, envelope, area, x, x + localXWidth, y, + y + localYHeight, newXWidth, newYHeight, ret, cutouts, + firstInA, firstInB); } } } } } +// ____________________________________________________________________________ +inline BoxIdList getBoxIds(const util::geo::I32XSortedLine& line, + const util::geo::I32Box& envelope, + std::map* cutouts) { + int32_t a = getBoxId(envelope.getLowerLeft()); + int32_t b = getBoxId(envelope.getUpperRight()); + if (a == b) return {{a, 0}}; // shortcut + + int32_t startX = std::floor( + (1.0 * envelope.getLowerLeft().getX() + WORLD_W / 2.0) / GRID_W); + int32_t startY = std::floor( + (1.0 * envelope.getLowerLeft().getY() + WORLD_H / 2.0) / GRID_H); + + int32_t endX = + std::floor((1.0 * envelope.getUpperRight().getX() + WORLD_W / 2.0) / + GRID_W) + + 1; + int32_t endY = + std::floor((1.0 * envelope.getUpperRight().getY() + WORLD_H / 2.0) / + GRID_H) + + 1; + + BoxIdList boxIds; + + getBoxIds(line, envelope, startX, endX, startY, endY, (endX - startX + 3) / 4, + (endY - startY + 3) / 4, &boxIds, cutouts, 0, 0); + std::sort(boxIds.begin(), boxIds.end(), BoxIdCmp()); + + return boxIds; +} + // ____________________________________________________________________________ inline BoxIdList getBoxIds(const util::geo::I32XSortedPolygon& poly, - const util::geo::I32Polygon& polyr, const util::geo::I32Box& envelope, double area, std::map* cutouts) { + int32_t a = getBoxId(envelope.getLowerLeft()); + int32_t b = getBoxId(envelope.getUpperRight()); + if (a == b) return {{-a, 0}}; // shortcut + int32_t startX = std::floor( (1.0 * envelope.getLowerLeft().getX() + WORLD_W / 2.0) / GRID_W); int32_t startY = std::floor( @@ -181,8 +220,9 @@ inline BoxIdList getBoxIds(const util::geo::I32XSortedPolygon& poly, BoxIdList boxIds; - getBoxIds(poly, polyr, envelope, area, startX, endX, startY, endY, - (endX - startX + 3) / 4, (endY - startY + 3) / 4, &boxIds, cutouts); + getBoxIds(poly, envelope, area, startX, endX, startY, endY, + (endX - startX + 3) / 4, (endY - startY + 3) / 4, &boxIds, cutouts, + 0, 0); std::sort(boxIds.begin(), boxIds.end(), BoxIdCmp()); return boxIds; @@ -193,6 +233,11 @@ inline BoxIdList packBoxIds(const BoxIdList& ids) { if (ids.empty()) { return {{0, 0}}; } + + if (ids.size() == 1) { + return {{1, 0}, ids[0]}; + } + // assume the list is sorted! BoxIdList ret; diff --git a/src/spatialjoin/GeometryCache.cpp b/src/spatialjoin/GeometryCache.cpp index 8f971ee..23d59b5 100644 --- a/src/spatialjoin/GeometryCache.cpp +++ b/src/spatialjoin/GeometryCache.cpp @@ -162,9 +162,7 @@ sj::Area sj::GeometryCache::getFromDisk(size_t off, // geom readPoly(_geomsFReads[tid], ret.geom); - // TODO: careful, resize initializes entire vector! - - // envelopes + // envelope _geomsFReads[tid].read(reinterpret_cast(&ret.box), sizeof(util::geo::I32Box)); @@ -212,9 +210,21 @@ sj::Area sj::GeometryCache::getFromDisk(size_t off, // simplified inner readPoly(_geomsFReads[tid], ret.inner); + _geomsFReads[tid].read(reinterpret_cast(&ret.innerBox), + sizeof(util::geo::I32Box)); + + _geomsFReads[tid].read(reinterpret_cast(&ret.innerOuterArea), + sizeof(double)); + // simplified outer readPoly(_geomsFReads[tid], ret.outer); + _geomsFReads[tid].read(reinterpret_cast(&ret.outerBox), + sizeof(util::geo::I32Box)); + + _geomsFReads[tid].read(reinterpret_cast(&ret.outerOuterArea), + sizeof(double)); + return ret; } @@ -327,7 +337,7 @@ size_t sj::GeometryCache::add(const sj::Area& val) { // geoms writePoly(val.geom); - // envelopes + // envelope _geomsF.write(reinterpret_cast(&val.box), sizeof(util::geo::I32Box)); _geomsOffset += sizeof(util::geo::I32Box); @@ -381,9 +391,25 @@ size_t sj::GeometryCache::add(const sj::Area& val) { // innerGeom writePoly(val.inner); + _geomsF.write(reinterpret_cast(&val.innerBox), + sizeof(util::geo::I32Box)); + _geomsOffset += sizeof(util::geo::I32Box); + + // inner area + _geomsF.write(reinterpret_cast(&val.innerOuterArea), sizeof(double)); + _geomsOffset += sizeof(double); + // outerGeom writePoly(val.outer); + _geomsF.write(reinterpret_cast(&val.outerBox), + sizeof(util::geo::I32Box)); + _geomsOffset += sizeof(util::geo::I32Box); + + // outer area + _geomsF.write(reinterpret_cast(&val.outerOuterArea), sizeof(double)); + _geomsOffset += sizeof(double); + return ret; } @@ -394,10 +420,6 @@ void sj::GeometryCache::flush() { _geomsF.flush(); _geomsF.close(); } - - for (size_t i = 0; i < _geomsFReads.size(); i++) { - _geomsFReads[i].open(getFName(), std::ios::in | std::ios::binary); - } } // ____________________________________________________________________________ @@ -548,25 +570,25 @@ void sj::GeometryCache::writeLine(const util::geo::I32XSortedLine& geom) { // ____________________________________________________________________________ template <> std::string sj::GeometryCache::getFName() const { - return _dir + "/areas"; + return util::getTmpFName(_dir, ".spatialjoin", "areas"); } // ____________________________________________________________________________ template <> std::string sj::GeometryCache::getFName() const { - return _dir + "/lines"; + return util::getTmpFName(_dir, ".spatialjoin", "lines"); } // ____________________________________________________________________________ template <> std::string sj::GeometryCache::getFName() const { - return _dir + "/points"; + return util::getTmpFName(_dir, ".spatialjoin", "points"); } // ____________________________________________________________________________ template <> std::string sj::GeometryCache::getFName() const { - return _dir + "/simplelines"; + return util::getTmpFName(_dir, ".spatialjoin", "simplelines"); } // ____________________________________________________________________________ diff --git a/src/spatialjoin/GeometryCache.h b/src/spatialjoin/GeometryCache.h index 793974c..b016f5c 100644 --- a/src/spatialjoin/GeometryCache.h +++ b/src/spatialjoin/GeometryCache.h @@ -55,8 +55,20 @@ struct Area { // inner geom util::geo::I32XSortedPolygon inner; + // inner polygon envelope + util::geo::I32Box innerBox; + + // outer area for inner polygon + double innerOuterArea; + // outer geom util::geo::I32XSortedPolygon outer; + + // outer polygon envelope + util::geo::I32Box outerBox; + + // outer area for outer polygon + double outerOuterArea; }; struct SimpleLine { @@ -105,8 +117,7 @@ struct Point { template class GeometryCache { public: - GeometryCache(size_t maxSize, size_t numthreads, - const std::string& dir, bool reuse) + GeometryCache(size_t maxSize, size_t numthreads, const std::string& dir) : _maxSize(maxSize), _dir(dir) { _geomsFReads.resize(numthreads); _accessCount.resize(numthreads); @@ -115,17 +126,17 @@ class GeometryCache { _vals.resize(numthreads); _idMap.resize(numthreads); - if (reuse) { - flush(); - } else { - _geomsF.open(getFName(), std::ios::out | std::ios::in | std::ios::binary | - std::ios::trunc); + _fName = getFName(); + + _geomsF.open(_fName, std::ios::out | std::ios::in | std::ios::binary | + std::ios::trunc); + + for (size_t i = 0; i < _geomsFReads.size(); i++) { + _geomsFReads[i].open(_fName, std::ios::in | std::ios::binary); } + unlink(_fName.c_str()); } - GeometryCache(size_t maxSize, size_t numthreads, const std::string& dir) - : GeometryCache(maxSize, numthreads, dir, false) {} - ~GeometryCache() { size_t access = 0; size_t diskAccess = 0; @@ -135,6 +146,11 @@ class GeometryCache { } std::cerr << "Geometry cache <" << getFName() << ">: " << access << " accesses, " << diskAccess << " disk lookups" << std::endl; + + if (_geomsF.is_open()) _geomsF.close(); + for (size_t i = 0; i < _geomsFReads.size(); i++) { + _geomsFReads[i].close(); + } } size_t add(const W& val); @@ -174,6 +190,7 @@ class GeometryCache { size_t _maxSize; std::string _dir; + std::string _fName; }; } // namespace sj diff --git a/src/spatialjoin/SpatialJoinMain.cpp b/src/spatialjoin/SpatialJoinMain.cpp index ac4c6ad..9cc0c76 100755 --- a/src/spatialjoin/SpatialJoinMain.cpp +++ b/src/spatialjoin/SpatialJoinMain.cpp @@ -86,8 +86,6 @@ int main(int argc, char** argv) { // initialize randomness srand(time(NULL) + rand()); // NOLINT - bool useCache = false; - int state = 0; std::string prefix = ""; @@ -118,9 +116,6 @@ int main(int argc, char** argv) { printHelp(argc, argv); exit(0); } - // if (cur == "-C") { - // useCache = true; - // } if (cur == "--prefix") { state = 1; } else if (cur == "--contains") { @@ -220,23 +215,21 @@ int main(int argc, char** argv) { {NUM_THREADS, prefix, intersects, contains, covers, touches, equals, overlaps, crosses, suffix, useBoxIds, useArea, useOBB, useCutouts, useDiagBox, useFastSweepSkip, useInnerOuter}, - useCache, cache, output); + cache, output); - if (!useCache) { - LOGTO(INFO, std::cerr) << "Parsing input geometries..."; - auto ts = TIME(); + LOGTO(INFO, std::cerr) << "Parsing input geometries..."; + auto ts = TIME(); - while ((len = read(0, buf, 1024 * 1024 * 100)) > 0) { - parse(buf, len, dangling, &gid, sweeper); - } + while ((len = read(0, buf, 1024 * 1024 * 100)) > 0) { + parse(buf, len, dangling, &gid, sweeper); + } - sweeper.flush(); + sweeper.flush(); - LOGTO(INFO, std::cerr) << "done (" << TOOK(ts) / 1000000000.0 << "s)."; - } + LOGTO(INFO, std::cerr) << "done (" << TOOK(ts) / 1000000000.0 << "s)."; LOGTO(INFO, std::cerr) << "Sweeping..."; - auto ts = TIME(); + ts = TIME(); sweeper.sweep(); LOGTO(INFO, std::cerr) << "done (" << TOOK(ts) / 1000000000.0 << "s)."; } diff --git a/src/spatialjoin/Sweeper.cpp b/src/spatialjoin/Sweeper.cpp index cfaf48e..5a444ef 100644 --- a/src/spatialjoin/Sweeper.cpp +++ b/src/spatialjoin/Sweeper.cpp @@ -29,6 +29,7 @@ using sj::innerouter::Mode; using util::writeAll; using util::geo::area; using util::geo::getBoundingBox; +using util::geo::I32Box; using util::geo::I32Line; using util::geo::I32MultiLine; using util::geo::I32MultiPoint; @@ -46,6 +47,9 @@ using util::geo::webMercToLatLng; const static size_t CUTOUTS_MIN_SIZE = 100; const static size_t OBB_MIN_SIZE = 100; +const static double sin45 = 1.0 / sqrt(2); +const static double cos45 = 1.0 / sqrt(2); + // _____________________________________________________________________________ void Sweeper::add(const I32MultiPolygon& a, const std::string& gid) { uint16_t subid = 0; // a subid of 0 means "single polygon" @@ -142,9 +146,9 @@ void Sweeper::add(const I32Polygon& poly, const std::string& gid, if (_cfg.useBoxIds) { if (_cfg.useCutouts && poly.getOuter().size() > CUTOUTS_MIN_SIZE) { - boxIds = packBoxIds(getBoxIds(spoly, poly, box, areaSize, &cutouts)); + boxIds = packBoxIds(getBoxIds(spoly, box, areaSize, &cutouts)); } else { - boxIds = packBoxIds(getBoxIds(spoly, poly, box, areaSize, 0)); + boxIds = packBoxIds(getBoxIds(spoly, box, areaSize, 0)); } } @@ -157,28 +161,49 @@ void Sweeper::add(const I32Polygon& poly, const std::string& gid, } I32XSortedPolygon inner, outer; + I32Box innerBox, outerBox; + double outerOuterAreaSize = 0; + double innerOuterAreaSize = 0; if (_cfg.useInnerOuter) { - inner = sj::innerouter::simplifiedPoly(poly, 1 / (3.14 * 20)); - outer = sj::innerouter::simplifiedPoly(poly, 1 / (3.14 * 20)); + const auto& innerPoly = + sj::innerouter::simplifiedPoly(poly, 1 / (3.14 * 20)); + const auto& outerPoly = + sj::innerouter::simplifiedPoly(poly, 1 / (3.14 * 20)); + + innerBox = getBoundingBox(innerPoly); + outerBox = getBoundingBox(outerPoly); + + innerOuterAreaSize = outerArea(innerPoly); + outerOuterAreaSize = outerArea(outerPoly); + + inner = innerPoly; + outer = outerPoly; } util::geo::I32Polygon obb; - obb = util::geo::convexHull(util::geo::getOrientedEnvelope(poly)); - auto polyR = util::geo::rotate(poly, 45, I32Point(0, 0)); - const auto& box45 = getBoundingBox(polyR); + I32Box box45; + if (_cfg.useDiagBox) { + auto polyR = util::geo::rotateSinCos(poly, sin45, cos45, I32Point(0, 0)); + box45 = getBoundingBox(polyR); + } - if (!_cfg.useOBB || poly.getOuter().size() < OBB_MIN_SIZE || - obb.getOuter().size() >= poly.getOuter().size()) - obb = {}; + if (_cfg.useOBB && poly.getOuter().size() >= OBB_MIN_SIZE) { + obb = util::geo::convexHull( + util::geo::pad(util::geo::getOrientedEnvelope(poly), 10)); + + // drop redundant oriented bbox + if (obb.getOuter().size() >= poly.getOuter().size()) obb = {}; + } if (subid > 0) multiAdd(gid, box.getLowerLeft().getX(), box.getUpperRight().getX()); size_t id = _areaCache.add({spoly, box, gid, subid, areaSize, _cfg.useArea ? outerAreaSize : 0, boxIds, cutouts, - obb, inner, outer}); + obb, inner, innerBox, innerOuterAreaSize, outer, + outerBox, outerOuterAreaSize}); diskAdd({id, box.getLowerLeft().getY(), box.getUpperRight().getY(), box.getLowerLeft().getX(), false, POLYGON, areaSize, box45}); @@ -208,18 +233,13 @@ void Sweeper::add(const I32Line& line, const std::string& gid, size_t subid) { } } - double len = util::geo::len(line); - - util::geo::I32Polygon obb; - obb = util::geo::convexHull(util::geo::getOrientedEnvelope(line)); + const double len = util::geo::len(line); - auto lineR = util::geo::rotate(line, 45, I32Point(0, 0)); - const auto& box45 = getBoundingBox(lineR); - - // drop redundant oriented bbox - if (!_cfg.useOBB || line.size() < OBB_MIN_SIZE || - obb.getOuter().size() >= line.size()) - obb = {}; + I32Box box45; + if (_cfg.useDiagBox) { + auto polyR = util::geo::rotateSinCos(line, sin45, cos45, I32Point(0, 0)); + box45 = getBoundingBox(polyR); + } if (subid > 0) multiAdd(gid, box.getLowerLeft().getX(), box.getUpperRight().getX()); @@ -234,13 +254,22 @@ void Sweeper::add(const I32Line& line, const std::string& gid, size_t subid) { diskAdd({id, box.getLowerLeft().getY(), box.getUpperRight().getY(), box.getUpperRight().getX(), true, SIMPLE_LINE, len, box45}); } else { + // normal line I32XSortedLine sline(line); + util::geo::I32Polygon obb; + if (_cfg.useOBB && line.size() >= OBB_MIN_SIZE) { + obb = util::geo::convexHull( + util::geo::pad(util::geo::getOrientedEnvelope(line), 10)); + + // drop redundant oriented bbox + if (obb.getOuter().size() >= line.size()) obb = {}; + } if (!_cfg.useFastSweepSkip) { sline.setMaxSegLen(std::numeric_limits::max()); } - size_t id = + const size_t id = _lineCache.add({sline, box, gid, subid, len, boxIds, cutouts, obb}); diskAdd({id, box.getLowerLeft().getY(), box.getUpperRight().getY(), @@ -262,7 +291,7 @@ void Sweeper::add(const I32Point& point, const std::string& gid) { void Sweeper::add(const I32Point& point, const std::string& gid, size_t subid) { size_t id = _pointCache.add({gid, subid}); if (subid > 0) multiAdd(gid, point.getX(), point.getX()); - auto pointR = util::geo::rotate(point, 45, I32Point(0, 0)); + auto pointR = util::geo::rotateSinCos(point, sin45, cos45, I32Point(0, 0)); diskAdd({id, point.getY(), point.getY(), point.getX(), false, POINT, 0, util::geo::getBoundingBox(pointR)}); diskAdd({id, point.getY(), point.getY(), point.getX(), true, POINT, 0, @@ -462,8 +491,9 @@ void Sweeper::flush() { LOGTO(INFO, std::cerr) << "Sorting events..."; - std::string newFName = _cache + "/.sortTmp"; + std::string newFName = util::getTmpFName(_cache, ".spatialjoin", "sorttmp"); int newFile = open(newFName.c_str(), O_RDWR | O_CREAT, 0666); + unlink(newFName.c_str()); if (newFile < 0) { throw std::runtime_error("Could not open temporary file " + newFName); @@ -477,11 +507,7 @@ void Sweeper::flush() { fsync(newFile); - // remove old file - std::remove((_cache + "/events").c_str()); - std::rename((_cache + "/.sortTmp").c_str(), (_cache + "/events").c_str()); - - _file = open((_cache + "/events").c_str(), O_RDONLY); + _file = newFile; #ifdef __unix__ posix_fadvise(newFile, 0, 0, POSIX_FADV_SEQUENTIAL); @@ -655,11 +681,9 @@ std::tuple Sweeper::check(const Area* a, } if (_cfg.useOBB) { - if (a->obb.getOuter().rawRing().size() && - b->obb.getOuter().rawRing().size()) { + if (!a->obb.empty() && !b->obb.empty()) { auto ts = TIME(); - auto r = util::geo::intersectsContainsCovers( - a->obb, a->box, a->outerArea, b->obb, b->box, b->outerArea); + auto r = util::geo::intersectsContainsCovers(a->obb, b->obb); _stats[t].timeOBBIsectAreaArea += TOOK(ts); if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; } @@ -668,7 +692,8 @@ std::tuple Sweeper::check(const Area* a, if (_cfg.useInnerOuter && !a->outer.empty() && !b->outer.empty()) { auto ts = TIME(); auto r = util::geo::intersectsContainsCovers( - a->outer, a->box, a->outerArea, b->outer, b->box, b->outerArea); + a->outer, a->outerBox, a->outerOuterArea, b->outer, b->outerBox, + b->outerOuterArea); _stats[t].timeInnerOuterCheckAreaArea += TOOK(ts); _stats[t].innerOuterChecksAreaArea++; if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; @@ -677,7 +702,8 @@ std::tuple Sweeper::check(const Area* a, if (_cfg.useInnerOuter && !a->outer.empty() && !b->inner.empty()) { auto ts = TIME(); auto r = util::geo::intersectsContainsCovers( - a->outer, a->box, a->outerArea, b->inner, b->box, b->outerArea); + a->outer, a->outerBox, a->outerOuterArea, b->inner, b->innerBox, + b->innerOuterArea); _stats[t].timeInnerOuterCheckAreaArea += TOOK(ts); _stats[t].innerOuterChecksAreaArea++; if (std::get<1>(r)) return {1, 1, 1, 0, 0}; @@ -685,8 +711,9 @@ std::tuple Sweeper::check(const Area* a, if (_cfg.useInnerOuter && a->outer.empty() && !b->outer.empty()) { auto ts = TIME(); - auto r = util::geo::intersectsContainsCovers( - a->geom, a->box, a->outerArea, b->outer, b->box, b->outerArea); + auto r = util::geo::intersectsContainsCovers(a->geom, a->box, a->outerArea, + b->outer, b->outerBox, + b->outerOuterArea); _stats[t].timeInnerOuterCheckAreaArea += TOOK(ts); _stats[t].innerOuterChecksAreaArea++; if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; @@ -694,8 +721,9 @@ std::tuple Sweeper::check(const Area* a, if (_cfg.useInnerOuter && a->outer.empty() && !b->inner.empty()) { auto ts = TIME(); - auto r = util::geo::intersectsContainsCovers( - a->geom, a->box, a->outerArea, b->inner, b->box, b->outerArea); + auto r = util::geo::intersectsContainsCovers(a->geom, a->box, a->outerArea, + b->inner, b->innerBox, + b->innerOuterArea); _stats[t].timeInnerOuterCheckAreaArea += TOOK(ts); _stats[t].innerOuterChecksAreaArea++; if (std::get<1>(r)) return {1, 1, 1, 0, 0}; @@ -750,10 +778,9 @@ std::tuple Sweeper::check(const Line* a, } if (_cfg.useOBB) { - if (a->obb.getOuter().rawRing().size() && - b->obb.getOuter().rawRing().size()) { + if (!a->obb.empty() && !b->obb.empty()) { auto ts = TIME(); - auto r = intersectsContainsCovers(a->obb, a->box, 0, b->obb, b->box, 0); + auto r = intersectsContainsCovers(a->obb, b->obb); _stats[t].timeOBBIsectAreaLine += TOOK(ts); if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; } @@ -761,8 +788,8 @@ std::tuple Sweeper::check(const Line* a, if (_cfg.useInnerOuter && !b->outer.empty()) { auto ts = TIME(); - auto r = - util::geo::intersectsContainsCovers(a->geom, a->box, b->outer, b->box); + auto r = util::geo::intersectsContainsCovers(a->geom, a->box, b->outer, + b->outerBox); _stats[t].timeInnerOuterCheckAreaLine += TOOK(ts); _stats[t].innerOuterChecksAreaLine++; if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; @@ -770,8 +797,8 @@ std::tuple Sweeper::check(const Line* a, if (_cfg.useInnerOuter && !b->inner.empty()) { auto ts = TIME(); - auto r = - util::geo::intersectsContainsCovers(a->geom, a->box, b->inner, b->box); + auto r = util::geo::intersectsContainsCovers(a->geom, a->box, b->inner, + b->innerBox); _stats[t].timeInnerOuterCheckAreaLine += TOOK(ts); _stats[t].innerOuterChecksAreaLine++; if (std::get<1>(r)) return {1, 1, 1, 0, 0}; @@ -829,11 +856,9 @@ std::tuple Sweeper::check(const Line* a, } if (_cfg.useOBB) { - if (a->obb.getOuter().rawRing().size() && - b->obb.getOuter().rawRing().size()) { + if (!a->obb.empty() && !b->obb.empty()) { auto ts = TIME(); - auto r = util::geo::intersectsContainsCovers(a->obb, a->box, 0, b->obb, - b->box, 0); + auto r = util::geo::intersectsContainsCovers(a->obb, b->obb); _stats[t].timeOBBIsectLineLine += TOOK(ts); if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; } @@ -881,11 +906,10 @@ std::tuple Sweeper::check(const SimpleLine* a, } } - if (_cfg.useOBB && b->obb.getOuter().rawRing().size()) { + if (_cfg.useOBB && !b->obb.empty()) { auto ts = TIME(); auto r = intersectsContainsCovers( - I32XSortedLine(LineSegment(a->a, a->b)), - getBoundingBox(LineSegment(a->a, a->b)), b->obb, b->box); + I32XSortedLine(LineSegment(a->a, a->b)), b->obb); _stats[t].timeOBBIsectAreaLine += TOOK(ts); if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; } @@ -894,7 +918,8 @@ std::tuple Sweeper::check(const SimpleLine* a, auto ts = TIME(); auto r = util::geo::intersectsContainsCovers( I32XSortedLine(LineSegment(a->a, a->b)), - getBoundingBox(LineSegment(a->a, a->b)), b->outer, b->box); + getBoundingBox(LineSegment(a->a, a->b)), b->outer, + b->outerBox); _stats[t].timeInnerOuterCheckAreaLine += TOOK(ts); _stats[t].innerOuterChecksAreaLine++; if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; @@ -953,16 +978,6 @@ std::tuple Sweeper::check(const SimpleLine* a, std::tuple Sweeper::check(const SimpleLine* a, const Line* b, size_t t) const { - // if (_cfg.useOBB) { - // auto ts = TIME(); - // auto r = intersectsContainsCovers( - // I32XSortedLine(LineSegment(a->a, a->b)), b->obb); - // _stats[t].timeOBBIsectLineLine += TOOK(ts); - // if (!std::get<0>(r)) { - // return {0, 0, 0, 0, 0}; - // } - // } - if (_cfg.useBoxIds) { auto ts = TIME(); auto r = boxIdIsect({{1, 0}, {getBoxId(a->a), 0}}, b->boxIds); @@ -989,6 +1004,14 @@ std::tuple Sweeper::check(const SimpleLine* a, } } + if (_cfg.useOBB && !b->obb.empty()) { + auto ts = TIME(); + auto r = intersectsContainsCovers( + I32XSortedLine(LineSegment(a->a, a->b)), b->obb); + _stats[t].timeOBBIsectLineLine += TOOK(ts); + if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; + } + auto ts = TIME(); auto res = intersectsCovers( I32XSortedLine(LineSegment(a->a, a->b)), b->geom, @@ -1002,16 +1025,6 @@ std::tuple Sweeper::check(const SimpleLine* a, std::tuple Sweeper::check(const Line* a, const SimpleLine* b, size_t t) const { - // if (_cfg.useOBB) { - // auto ts = TIME(); - // auto r = intersectsContainsCovers( - // I32XSortedLine(LineSegment(b->a, b->b)), a->obb); - // _stats[t].timeOBBIsectLineLine += TOOK(ts); - // if (!std::get<0>(r)) { - // return {0, 0, 0, 0, 0}; - // } - // } - if (_cfg.useBoxIds) { auto ts = TIME(); auto r = boxIdIsect(a->boxIds, {{1, 0}, {getBoxId(b->a), 0}}); @@ -1038,6 +1051,14 @@ std::tuple Sweeper::check(const Line* a, } } + if (_cfg.useOBB && !a->obb.empty()) { + auto ts = TIME(); + auto r = intersectsContainsCovers( + I32XSortedLine(LineSegment(b->a, b->b)), a->obb); + _stats[t].timeOBBIsectLineLine += TOOK(ts); + if (!std::get<0>(r)) return {0, 0, 0, 0, 0}; + } + auto ts = TIME(); auto res = intersectsCovers( a->geom, I32XSortedLine(LineSegment(b->a, b->b)), a->box, @@ -1161,14 +1182,35 @@ void Sweeper::writeContains(size_t t, const std::string& a, writeRel(t, a, b, _cfg.sepContains); } +// ____________________________________________________________________________ +void Sweeper::writeRelToBuf(size_t t, const std::string& a, + const std::string& b, const std::string& pred) { + memcpy(_outBuffers[t] + _outBufPos[t], _cfg.pairStart.c_str(), + _cfg.pairStart.size()); + _outBufPos[t] += _cfg.pairStart.size(); + memcpy(_outBuffers[t] + _outBufPos[t], a.c_str(), a.size()); + _outBufPos[t] += a.size(); + memcpy(_outBuffers[t] + _outBufPos[t], pred.c_str(), pred.size()); + _outBufPos[t] += pred.size(); + memcpy(_outBuffers[t] + _outBufPos[t], b.c_str(), b.size()); + _outBufPos[t] += b.size(); + memcpy(_outBuffers[t] + _outBufPos[t], _cfg.pairEnd.c_str(), + _cfg.pairEnd.size()); + _outBufPos[t] += _cfg.pairEnd.size(); +} + // ____________________________________________________________________________ void Sweeper::writeRel(size_t t, const std::string& a, const std::string& b, const std::string& pred) { auto ts = TIME(); - std::string out = _cfg.pairStart + a + pred + b + _cfg.pairEnd; + + if (_outMode == NONE) return; + + size_t totSize = _cfg.pairStart.size() + a.size() + pred.size() + b.size() + + _cfg.pairEnd.size(); if (_outMode == BZ2) { - if (_outBufPos[t] + out.size() >= BUFFER_S_PAIRS) { + if (_outBufPos[t] + totSize >= BUFFER_S_PAIRS) { int err = 0; BZ2_bzWrite(&err, _files[t], _outBuffers[t], _outBufPos[t]); if (err == BZ_IO_ERROR) { @@ -1178,10 +1220,9 @@ void Sweeper::writeRel(size_t t, const std::string& a, const std::string& b, _outBufPos[t] = 0; } - memcpy(_outBuffers[t] + _outBufPos[t], out.c_str(), out.size()); - _outBufPos[t] += out.size(); + writeRelToBuf(t, a, b, pred); } else if (_outMode == GZ) { - if (_outBufPos[t] + out.size() >= BUFFER_S_PAIRS) { + if (_outBufPos[t] + totSize >= BUFFER_S_PAIRS) { int r = gzwrite(_gzFiles[t], _outBuffers[t], _outBufPos[t]); if (r != (int)_outBufPos[t]) { gzclose(_gzFiles[t]); @@ -1190,10 +1231,9 @@ void Sweeper::writeRel(size_t t, const std::string& a, const std::string& b, _outBufPos[t] = 0; } - memcpy(_outBuffers[t] + _outBufPos[t], out.c_str(), out.size()); - _outBufPos[t] += out.size(); + writeRelToBuf(t, a, b, pred); } else if (_outMode == PLAIN) { - if (_outBufPos[t] + out.size() >= BUFFER_S_PAIRS) { + if (_outBufPos[t] + totSize >= BUFFER_S_PAIRS) { size_t r = fwrite(_outBuffers[t], sizeof(char), _outBufPos[t], _rawFiles[t]); if (r != _outBufPos[t]) { @@ -1202,10 +1242,14 @@ void Sweeper::writeRel(size_t t, const std::string& a, const std::string& b, _outBufPos[t] = 0; } - memcpy(_outBuffers[t] + _outBufPos[t], out.c_str(), out.size()); - _outBufPos[t] += out.size(); + writeRelToBuf(t, a, b, pred); } else if (_outMode == COUT) { - fputs(out.c_str(), stdout); + if (_outBufPos[t] + totSize + 1 >= BUFFER_S_PAIRS) { + _outBuffers[t][_outBufPos[t]] = 0; + fputs(reinterpret_cast(_outBuffers[t]), stdout); + _outBufPos[t] = 0; + } + writeRelToBuf(t, a, b, pred); } _stats[t].timeWrite += TOOK(ts); @@ -1880,6 +1924,12 @@ void Sweeper::doCheck(const BoxVal cur, const SweepVal sv, size_t t) { // _____________________________________________________________________________ void Sweeper::flushOutputFiles() { + if (_outMode == COUT) { + for (size_t i = 0; i < _cfg.numThreads + 1; i++) { + _outBuffers[i][_outBufPos[i]] = 0; + fputs(reinterpret_cast(_outBuffers[i]), stdout); + } + } if (_outMode == BZ2 || _outMode == GZ || _outMode == PLAIN) { if (_outMode == BZ2) { for (size_t i = 0; i < _cfg.numThreads + 1; i++) { @@ -1913,18 +1963,20 @@ void Sweeper::flushOutputFiles() { } // merge files into first file - std::ofstream out(_cache + "/.rels0", std::ios_base::binary | - std::ios_base::app | - std::ios_base::ate); + std::ofstream out( + _cache + "/.rels" + std::to_string(getpid()) + "-0", + std::ios_base::binary | std::ios_base::app | std::ios_base::ate); for (size_t i = 1; i < _cfg.numThreads + 1; i++) { - std::string fName = _cache + "/.rels" + std::to_string(i); + std::string fName = _cache + "/.rels" + std::to_string(getpid()) + "-" + + std::to_string(i); std::ifstream ifCur(fName, std::ios_base::binary); out << ifCur.rdbuf(); std::remove(fName.c_str()); } // move first file to output file - std::rename((_cache + "/.rels0").c_str(), _out.c_str()); + std::rename((_cache + "/.rels" + std::to_string(getpid()) + "-0").c_str(), + _out.c_str()); } } @@ -1932,8 +1984,10 @@ void Sweeper::flushOutputFiles() { void Sweeper::prepareOutputFiles() { if (_outMode == BZ2) { for (size_t i = 0; i < _cfg.numThreads + 1; i++) { - _rawFiles[i] = - fopen((_cache + "/.rels" + std::to_string(i)).c_str(), "w"); + _rawFiles[i] = fopen((_cache + "/.rels" + std::to_string(getpid()) + "-" + + std::to_string(i)) + .c_str(), + "w"); int err = 0; _files[i] = BZ2_bzWriteOpen(&err, _rawFiles[i], 6, 0, 30); if (err != BZ_OK) { @@ -1943,8 +1997,10 @@ void Sweeper::prepareOutputFiles() { } } else if (_outMode == GZ) { for (size_t i = 0; i < _cfg.numThreads + 1; i++) { - _gzFiles[i] = - gzopen((_cache + "/.rels" + std::to_string(i)).c_str(), "w"); + _gzFiles[i] = gzopen((_cache + "/.rels" + std::to_string(getpid()) + "-" + + std::to_string(i)) + .c_str(), + "w"); if (_gzFiles[i] == Z_NULL) { throw std::runtime_error("Could not open bzip file for writing."); } @@ -1952,8 +2008,14 @@ void Sweeper::prepareOutputFiles() { } } else if (_outMode == PLAIN) { for (size_t i = 0; i < _cfg.numThreads + 1; i++) { - _rawFiles[i] = - fopen((_cache + "/.rels" + std::to_string(i)).c_str(), "w"); + _rawFiles[i] = fopen((_cache + "/.rels" + std::to_string(getpid()) + "-" + + std::to_string(i)) + .c_str(), + "w"); + _outBuffers[i] = new unsigned char[BUFFER_S_PAIRS]; + } + } else if (_outMode == COUT) { + for (size_t i = 0; i < _cfg.numThreads + 1; i++) { _outBuffers[i] = new unsigned char[BUFFER_S_PAIRS]; } } diff --git a/src/spatialjoin/Sweeper.h b/src/spatialjoin/Sweeper.h index 4d782f2..93c744b 100644 --- a/src/spatialjoin/Sweeper.h +++ b/src/spatialjoin/Sweeper.h @@ -93,16 +93,18 @@ static const ssize_t BUFFER_S = sizeof(BoxVal) * 64 * 1024 * 1024; static const size_t BUFFER_S_PAIRS = 1024 * 1024 * 10; +static const size_t MAX_OUT_LINE_LENGTH = 1000; + class Sweeper { public: - explicit Sweeper(SweeperCfg cfg, bool reUse, const std::string cache, + explicit Sweeper(SweeperCfg cfg, const std::string cache, const std::string out) : _cfg(cfg), _obufpos(0), - _pointCache(100000, cfg.numThreads, cache, reUse), - _areaCache(100000, cfg.numThreads, cache, reUse), - _lineCache(100000, cfg.numThreads, cache, reUse), - _simpleLineCache(100000, cfg.numThreads, cache, reUse), + _pointCache(100000, cfg.numThreads, cache), + _areaCache(100000, cfg.numThreads, cache), + _lineCache(100000, cfg.numThreads, cache), + _simpleLineCache(100000, cfg.numThreads, cache), _cache(cache), _out(out), _jobs(100) { @@ -126,20 +128,16 @@ class Sweeper { } } - std::string fname = _cache + "/events"; - - if (reUse) { - _file = open(fname.c_str(), O_RDONLY); - _curSweepId = (lseek(_file, 0, SEEK_END) + 1) / (2 * sizeof(BoxVal)); - lseek(_file, 0, SEEK_SET); - } else { - _file = open(fname.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666); - } + _fname = util::getTmpFName(_cache, ".spatialjoin", "events"); + _file = open(_fname.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666); if (_file < 0) { - throw std::runtime_error("Could not open temporary file " + fname); + throw std::runtime_error("Could not open temporary file " + _fname); } + // immediately unlink + unlink(_fname.c_str()); + #ifdef __unix__ posix_fadvise(_file, 0, 0, POSIX_FADV_SEQUENTIAL); #endif @@ -168,6 +166,7 @@ class Sweeper { private: const SweeperCfg _cfg; size_t _curSweepId = 0; + std::string _fname; int _file; unsigned char* _outBuffer; ssize_t _obufpos; @@ -257,6 +256,8 @@ class Sweeper { void writeCrosses(size_t t, const std::string& a, const std::string& b); void writeRel(size_t t, const std::string& a, const std::string& b, const std::string& pred); + void writeRelToBuf(size_t t, const std::string& a, const std::string& b, + const std::string& pred); void writeContainsMulti(size_t t, const std::string& a, const std::string& b, size_t bSub); void writeCoversMulti(size_t t, const std::string& a, const std::string& b, diff --git a/src/spatialjoin/tests/TestMain.cpp b/src/spatialjoin/tests/TestMain.cpp index 53010a8..3068a15 100644 --- a/src/spatialjoin/tests/TestMain.cpp +++ b/src/spatialjoin/tests/TestMain.cpp @@ -14,11 +14,8 @@ using sj::Sweeper; // _____________________________________________________________________________ -std::string fullRun(const std::string& file) { - Sweeper sweeper({1, "$", " intersects ", " contains ", " covers ", - " touches ", " equals ", " overlaps ", " crosses ", "$\n", - true, true, true, true, true, true, true}, - false, ".", ".resTmp"); +std::string fullRun(const std::string& file, const sj::SweeperCfg& cfg) { + Sweeper sweeper(cfg, ".", ".resTmp"); size_t gid = 0; @@ -51,313 +48,409 @@ std::string fullRun(const std::string& file) { // _____________________________________________________________________________ int main(int, char**) { - { - auto res = fullRun("../src/spatialjoin/tests/datasets/freiburg"); - - TEST(res.find("$freiburg1 covers freiburg2$") != std::string::npos); - TEST(res.find("$freiburg2 covers freiburg1$") != std::string::npos); - TEST(res.find("$freiburg1 equals freiburg2$") != std::string::npos); - TEST(res.find("$freiburg2 equals freiburg1$") != std::string::npos); - TEST(res.find("$freiburg1 contains freiburg2$") == std::string::npos); - TEST(res.find("$freiburg2 contains freiburg1$") == std::string::npos); - TEST(res.find("$freiburg1 intersects freiburg2$") != std::string::npos); - TEST(res.find("$freiburg2 intersects freiburg1$") != std::string::npos); - TEST(res.find("$freiburg2 overlaps freiburg1$") == std::string::npos); - TEST(res.find("$freiburg2 touches freiburg1$") == std::string::npos); - - TEST(res.find("$freiburg1 covers grenzpart$") != std::string::npos); - TEST(res.find("$freiburg1 contains grenzpart$") == std::string::npos); - TEST(res.find("$grenzpart covers freiburg1$") == std::string::npos); - - TEST(res.find("$freiburg1 intersects grenz$") != std::string::npos); - TEST(res.find("$freiburg2 intersects grenz$") != std::string::npos); - TEST(res.find("$freiburg1 covers grenz$") == std::string::npos); - TEST(res.find("$freiburg2 covers grenz$") == std::string::npos); - TEST(res.find("$freiburg1 contains grenz$") == std::string::npos); - TEST(res.find("$freiburg2 contains grenz$") == std::string::npos); - - TEST(res.find("$freiburg1 intersects a$") != std::string::npos); - TEST(res.find("$freiburg2 intersects a$") != std::string::npos); - TEST(res.find("$freiburg1 covers a$") == std::string::npos); - TEST(res.find("$freiburg2 covers a$") == std::string::npos); - TEST(res.find("$freiburg1 contains a$") == std::string::npos); - TEST(res.find("$freiburg2 contains a$") == std::string::npos); - - TEST(res.find("$freiburg1 intersects b$") != std::string::npos); - TEST(res.find("$freiburg2 intersects b$") != std::string::npos); - TEST(res.find("$freiburg1 covers b$") == std::string::npos); - TEST(res.find("$freiburg2 covers b$") == std::string::npos); - TEST(res.find("$freiburg1 contains b$") == std::string::npos); - TEST(res.find("$freiburg2 contains b$") == std::string::npos); - - TEST(res.find("$freiburg1 intersects c$") != std::string::npos); - TEST(res.find("$freiburg2 intersects c$") != std::string::npos); - TEST(res.find("$freiburg1 covers c$") == std::string::npos); - TEST(res.find("$freiburg2 covers c$") == std::string::npos); - TEST(res.find("$freiburg1 contains c$") == std::string::npos); - TEST(res.find("$freiburg2 contains c$") == std::string::npos); - - TEST(res.find("$freiburg1 intersects d$") != std::string::npos); - TEST(res.find("$freiburg2 intersects d$") != std::string::npos); - TEST(res.find("$freiburg1 covers d$") == std::string::npos); - TEST(res.find("$freiburg2 covers d$") == std::string::npos); - TEST(res.find("$freiburg1 contains d$") == std::string::npos); - TEST(res.find("$freiburg2 contains d$") == std::string::npos); - - TEST(res.find("$freiburg1 intersects grenzpunkt$") != std::string::npos); - TEST(res.find("$freiburg2 intersects grenzpunkt$") != std::string::npos); - TEST(res.find("$freiburg1 covers grenzpunkt$") != std::string::npos); - TEST(res.find("$freiburg2 covers grenzpunkt$") != std::string::npos); - TEST(res.find("$freiburg1 contains grenzpunkt$") == std::string::npos); - TEST(res.find("$freiburg2 contains grenzpunkt$") == std::string::npos); - - TEST(res.find("$freiburg1 intersects grenzpunkt2$") != std::string::npos); - TEST(res.find("$freiburg2 intersects grenzpunkt2$") != std::string::npos); - TEST(res.find("$freiburg1 covers grenzpunkt2$") != std::string::npos); - TEST(res.find("$freiburg2 covers grenzpunkt2$") != std::string::npos); - TEST(res.find("$freiburg1 contains grenzpunkt2$") == std::string::npos); - TEST(res.find("$freiburg2 contains grenzpunkt2$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Umkirch$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Sankt Georgen$") != std::string::npos); - TEST(res.find("$freiburg1 intersects Sankt Georgen$") != std::string::npos); - TEST(res.find("$freiburg1 contains Sankt Georgen$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Haslach$") != std::string::npos); - - TEST(res.find("$freiburg1 covers Günterstal$") != std::string::npos); - TEST(res.find("$freiburg1 intersects Günterstal$") != std::string::npos); - TEST(res.find("$freiburg1 contains Günterstal$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Kappel$") != std::string::npos); - TEST(res.find("$freiburg1 intersects Kappel$") != std::string::npos); - TEST(res.find("$freiburg1 contains Kappel$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Littenweiler$") != std::string::npos); - TEST(res.find("$freiburg1 intersects Littenweiler$") != std::string::npos); - TEST(res.find("$freiburg1 contains Littenweiler$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Waldsee$") != std::string::npos); - TEST(res.find("$freiburg1 intersects Waldsee$") != std::string::npos); - TEST(res.find("$freiburg1 contains Waldsee$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Wiehre$") != std::string::npos); - TEST(res.find("$freiburg1 covers Waltershofen$") != std::string::npos); - TEST(res.find("$freiburg1 covers Hochdorf$") != std::string::npos); - TEST(res.find("$freiburg1 covers Opfingen$") != std::string::npos); - TEST(res.find("$freiburg1 covers Betzenhausen$") != std::string::npos); - TEST(res.find("$freiburg1 covers Brühl$") != std::string::npos); - TEST(res.find("$freiburg1 covers Landwasser$") != std::string::npos); - TEST(res.find("$freiburg1 covers Lehen$") != std::string::npos); - TEST(res.find("$freiburg1 covers Mooswald$") != std::string::npos); - - TEST(res.find("$freiburg1 covers Munzingen$") != std::string::npos); - TEST(res.find("$freiburg1 intersects Munzingen$") != std::string::npos); - TEST(res.find("$freiburg1 contains Munzingen$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Tiengen$") != std::string::npos); - TEST(res.find("$freiburg1 intersects Tiengen$") != std::string::npos); - TEST(res.find("$freiburg1 contains Tiengen$") == std::string::npos); - - TEST(res.find("$freiburg1 covers Mundenhof$") != std::string::npos); - TEST(res.find("$freiburg1 covers Rieselfeld$") != std::string::npos); - TEST(res.find("$freiburg1 covers Weingarten$") != std::string::npos); - TEST(res.find("$freiburg1 covers Altstadt$") != std::string::npos); - TEST(res.find("$freiburg1 covers Stühlinger$") != std::string::npos); - TEST(res.find("$freiburg1 covers Neuburg$") != std::string::npos); - TEST(res.find("$freiburg1 covers Herdern$") != std::string::npos); - TEST(res.find("$freiburg1 covers Zähringen$") != std::string::npos); - TEST(res.find("$freiburg1 covers Ebnet$") != std::string::npos); - TEST(res.find("$freiburg1 covers Oberau$") != std::string::npos); - TEST(res.find("$freiburg1 covers Sankt Georgen Süd$") != std::string::npos); - TEST(res.find("$freiburg1 covers Sankt Georgen Nord$") != - std::string::npos); - TEST(res.find("$Sankt Georgen covers Sankt Georgen Süd$") != - std::string::npos); - TEST(res.find("$Sankt Georgen covers Sankt Georgen Nord$") != - std::string::npos); - TEST(res.find("$Sankt Georgen Süd touches Sankt Georgen Nord$") != - std::string::npos); - TEST(res.find("$Sankt Georgen Nord touches Sankt Georgen Süd$") != - std::string::npos); - TEST(res.find("$freiburg1 covers Haslach-Haid$") != std::string::npos); - TEST(res.find("$freiburg1 covers Haslach-Gartenstadt$") != - std::string::npos); - TEST(res.find("$Haslach covers Haslach-Haid$") != std::string::npos); - TEST(res.find("$Haslach covers Haslach-Gartenstadt$") != std::string::npos); - TEST(res.find("$Haslach covers Haslach-Schildacker$") != std::string::npos); - TEST(res.find("$Haslach covers Haslach-Egerten$") != std::string::npos); - TEST(res.find("$freiburg1 covers Haslach-Schildacker$") != - std::string::npos); - TEST(res.find("$freiburg1 covers Haslach-Egerten$") != std::string::npos); - TEST(res.find("$freiburg1 covers Unterwiehre-Nord$") != std::string::npos); - TEST(res.find("$freiburg1 covers Unterwiehre-Süd$") != std::string::npos); - TEST(res.find("$Wiehre covers Unterwiehre-Nord$") != std::string::npos); - TEST(res.find("$Wiehre covers Unterwiehre-Süd$") != std::string::npos); - TEST(res.find("$freiburg1 covers Altstadt-Ring$") != std::string::npos); - TEST(res.find("$freiburg1 covers Alt-Stühlinger$") != std::string::npos); - TEST(res.find("$freiburg1 covers Betzenhausen-Bischofslinde$") != - std::string::npos); - TEST(res.find("$freiburg1 covers Stühlinger-Eschholz$") != - std::string::npos); - TEST(res.find("$freiburg1 covers Mooswald-Ost$") != std::string::npos); - TEST(res.find("$freiburg1 covers Brühl-Beurbarung$") != std::string::npos); - TEST(res.find("$freiburg1 covers Brühl-Industriegebiet$") != - std::string::npos); - TEST(res.find("$freiburg1 covers Altstadt-Mitte$") != std::string::npos); - TEST(res.find("$freiburg1 covers Mittelwiehre$") != std::string::npos); - TEST(res.find("$freiburg1 covers Oberwiehre$") != std::string::npos); - TEST(res.find("$Wiehre covers Mittelwiehre$") != std::string::npos); - TEST(res.find("$Wiehre contains Mittelwiehre$") == std::string::npos); - TEST(res.find("$Wiehre covers Oberwiehre$") != std::string::npos); - TEST(res.find("$Wiehre contains Oberwiehre$") == std::string::npos); - TEST(res.find("$freiburg1 covers Alt-Betzenhausen$") != std::string::npos); - TEST(res.find("$freiburg1 covers Mooswald-West$") != std::string::npos); - TEST(res.find("$freiburg1 covers Brühl-Güterbahnhof$") != - std::string::npos); - TEST(res.find("$freiburg1 covers Herdern-Süd$") != std::string::npos); - TEST(res.find("$freiburg1 covers Herdern-Nord$") != std::string::npos); - TEST(res.find("$Herdern covers Herdern-Süd$") != std::string::npos); - TEST(res.find("$Herdern covers Herdern-Nord$") != std::string::npos); - TEST(res.find("$freiburg1 covers Vauban$") != std::string::npos); - - TEST(res.find("$someway intersects someotherway$") != std::string::npos); - TEST(res.find("$someway covers someotherway$") == std::string::npos); - TEST(res.find("$someway contains someotherway$") == std::string::npos); - - TEST(res.find("$someway covers someway2$") != std::string::npos); - TEST(res.find("$someway intersects someway2$") != std::string::npos); - - TEST(res.find("$someway2 covers someway$") != std::string::npos); - TEST(res.find("$someway2 intersects someway$") != std::string::npos); - - TEST(res.find("$someotherway intersects someway$") != std::string::npos); - TEST(res.find("$someotherway covers someway$") == std::string::npos); - TEST(res.find("$someotherway contains someway$") == std::string::npos); - } - - { - auto res = fullRun("../src/spatialjoin/tests/datasets/brandenburg"); - TEST(res.find("$Brandenburg covers Brandenburg2$") != std::string::npos); - TEST(res.find("$Brandenburg equals Brandenburg2$") != std::string::npos); - TEST(res.find("$Brandenburg2 equals Brandenburg$") != std::string::npos); - TEST(res.find("$Brandenburg intersects Grenzpart$") != std::string::npos); - TEST(res.find("$Brandenburg covers Grenzpart$") != std::string::npos); - TEST(res.find("$Brandenburg contains Grenzpart$") == std::string::npos); - - TEST(res.find("$Brandenburg intersects Berlin$") != std::string::npos); - TEST(res.find("$Brandenburg touches Berlin$") != std::string::npos); - TEST(res.find("$Brandenburg overlaps Berlin$") == std::string::npos); - TEST(res.find("$Berlin touches Brandenburg$") != std::string::npos); - TEST(res.find("$Berlin overlaps Brandenburg$") == std::string::npos); - TEST(res.find("$Brandenburg contains Berlin$") == std::string::npos); - TEST(res.find("$Brandenburg covers Berlin$") == std::string::npos); - - TEST(res.find("$Berlin intersects Grenzpart$") != std::string::npos); - TEST(res.find("$Berlin covers Grenzpart$") != std::string::npos); - TEST(res.find("$Berlin contains Grenzpart$") == std::string::npos); - - TEST(res.find("$Haus overlaps Brandenburg$") != std::string::npos); - TEST(res.find("$Haus-Way intersects Brandenburg$") != std::string::npos); - TEST(res.find("$Haus intersects Brandenburg-Way$") != std::string::npos); - TEST(res.find("$Haus-Way intersects Brandenburg-Way$") != - std::string::npos); - - TEST(res.find("$Brandenburg-Point intersects Brandenburg-Way$") != - std::string::npos); - TEST(res.find("$Brandenburg-Point intersects Brandenburg$") != - std::string::npos); - } - - { - auto res = fullRun("../src/spatialjoin/tests/datasets/multitests"); - - TEST(res.find("$28 covers 27$") != std::string::npos); - - TEST(res.find("$27 overlaps 28$") == std::string::npos); - TEST(res.find("$28 overlaps 27$") == std::string::npos); - - TEST(res.find("$17 touches 18$") != std::string::npos); - TEST(res.find("$19 touches 18$") != std::string::npos); - TEST(res.find("$17 touches 16$") != std::string::npos); - - TEST(res.find("$1 equals 2$") != std::string::npos); - TEST(res.find("$1 overlaps 2$") == std::string::npos); - TEST(res.find("$2 equals 1$") != std::string::npos); - TEST(res.find("$3 equals 1$") == std::string::npos); - TEST(res.find("$3 equals 2$") == std::string::npos); - TEST(res.find("$3 equals 4$") != std::string::npos); - TEST(res.find("$3 equals 5$") != std::string::npos); - TEST(res.find("$4 equals 3$") != std::string::npos); - TEST(res.find("$5 equals 3$") != std::string::npos); - TEST(res.find("$5 equals 4$") != std::string::npos); - TEST(res.find("$4 equals 5$") != std::string::npos); - TEST(res.find("$4 overlaps 5$") == std::string::npos); - TEST(res.find("$1 touches 6$") != std::string::npos); - TEST(res.find("$6 touches 1$") != std::string::npos); - TEST(res.find("$2 touches 6$") != std::string::npos); - TEST(res.find("$6 touches 2$") != std::string::npos); - TEST(res.find("$3 touches 6$") != std::string::npos); - TEST(res.find("$6 touches 3$") != std::string::npos); - TEST(res.find("$4 touches 6$") != std::string::npos); - TEST(res.find("$6 touches 4$") != std::string::npos); - TEST(res.find("$6 touches 7$") == std::string::npos); - TEST(res.find("$7 touches 6$") == std::string::npos); - - TEST(res.find("$8 touches 9$") != std::string::npos); - TEST(res.find("$9 touches 8$") != std::string::npos); - - TEST(res.find("$8 touches 11$") == std::string::npos); - - TEST(res.find("$9 touches 10$") == std::string::npos); - TEST(res.find("$8 touches 10$") == std::string::npos); - TEST(res.find("$12 touches 10$") != std::string::npos); - TEST(res.find("$13 equals 10$") != std::string::npos); - - TEST(res.find("$6 equals 14$") != std::string::npos); - TEST(res.find("$15 touches 16$") != std::string::npos); - TEST(res.find("$17 touches 6$") == std::string::npos); - TEST(res.find("$17 intersects 16$") != std::string::npos); - TEST(res.find("$17 intersects 18$") != std::string::npos); - - TEST(res.find("$8 overlaps 20$") != std::string::npos); - TEST(res.find("$20 overlaps 8$") != std::string::npos); - - TEST(res.find("$17 crosses 21$") != std::string::npos); - TEST(res.find("$21 crosses 17$") != std::string::npos); - - TEST(res.find("$17 crosses 22$") == std::string::npos); - TEST(res.find("$22 crosses 17$") == std::string::npos); - - TEST(res.find("$17 overlaps 22$") == std::string::npos); - TEST(res.find("$22 overlaps 17$") == std::string::npos); - - TEST(res.find("$24 covers 25$") != std::string::npos); - - TEST(res.find("$25 overlaps 24$") == std::string::npos); - TEST(res.find("$24 overlaps 25$") == std::string::npos); - - TEST(res.find("$23 overlaps 24$") == std::string::npos); - TEST(res.find("$24 overlaps 23$") == std::string::npos); - - TEST(res.find("$26 overlaps 24$") != std::string::npos); - TEST(res.find("$24 overlaps 26$") != std::string::npos); - - TEST(res.find("$26 overlaps 27$") != std::string::npos); - TEST(res.find("$27 overlaps 26$") != std::string::npos); - - TEST(res.find("$26 overlaps 28$") != std::string::npos); - TEST(res.find("$28 overlaps 26$") != std::string::npos); - - TEST(res.find("8 overlaps 29$") == std::string::npos); - TEST(res.find("8 overlaps 29$") == std::string::npos); - TEST(res.find("30 covers 8$") != std::string::npos); - TEST(res.find("8 overlaps 30$") == std::string::npos); - TEST(res.find("29 overlaps 30$") == std::string::npos); - TEST(res.find("30 overlaps 29") == std::string::npos); - - TEST(res.find("31 overlaps 30$") != std::string::npos); - TEST(res.find("30 overlaps 31") != std::string::npos); + sj::SweeperCfg baseline{ + 1, "$", " intersects ", " contains ", " covers ", + " touches ", " equals ", " overlaps ", " crosses ", "$\n", + false, false, false, false, false, + false, false}; + + sj::SweeperCfg all{1, "$", " intersects ", " contains ", + " covers ", " touches ", " equals ", " overlaps ", + " crosses ", "$\n", true, true, + true, true, true, true, + true}; + + sj::SweeperCfg noSurfaceArea{ + 1, "$", " intersects ", " contains ", " covers ", + " touches ", " equals ", " overlaps ", " crosses ", "$\n", + true, false, true, true, true, + true, true}; + + sj::SweeperCfg noBoxIds{ + 1, "$", " intersects ", " contains ", " covers ", + " touches ", " equals ", " overlaps ", " crosses ", "$\n", + false, true, true, true, true, + true, true}; + + sj::SweeperCfg noObb{1, "$", " intersects ", " contains ", + " covers ", " touches ", " equals ", " overlaps ", + " crosses ", "$\n", true, true, + false, true, true, true, + true}; + + sj::SweeperCfg noCutouts{ + 1, "$", " intersects ", " contains ", " covers ", + " touches ", " equals ", " overlaps ", " crosses ", "$\n", + true, true, true, false, true, + true, true}; + + sj::SweeperCfg noDiagBox{ + 1, "$", " intersects ", " contains ", " covers ", + " touches ", " equals ", " overlaps ", " crosses ", "$\n", + true, true, true, true, false, + true, true}; + + sj::SweeperCfg noFastSweep{ + 1, "$", " intersects ", " contains ", " covers ", + " touches ", " equals ", " overlaps ", " crosses ", "$\n", + true, true, true, true, true, + false, true}; + + sj::SweeperCfg noInnerOuter{ + 1, "$", " intersects ", " contains ", " covers ", + " touches ", " equals ", " overlaps ", " crosses ", "$\n", + true, true, true, true, true, + true, false}; + + std::vector cfgs{baseline, all, noSurfaceArea, + noBoxIds, noObb, noCutouts, + noDiagBox, noFastSweep, noInnerOuter}; + + for (auto cfg : cfgs) { + { + auto res = fullRun("../src/spatialjoin/tests/datasets/freiburg", cfg); + + TEST(res.find("$freiburg1 covers freiburg2$") != std::string::npos); + TEST(res.find("$freiburg2 covers freiburg1$") != std::string::npos); + TEST(res.find("$freiburg1 equals freiburg2$") != std::string::npos); + TEST(res.find("$freiburg2 equals freiburg1$") != std::string::npos); + TEST(res.find("$freiburg1 contains freiburg2$") == std::string::npos); + TEST(res.find("$freiburg2 contains freiburg1$") == std::string::npos); + TEST(res.find("$freiburg1 intersects freiburg2$") != std::string::npos); + TEST(res.find("$freiburg2 intersects freiburg1$") != std::string::npos); + TEST(res.find("$freiburg2 overlaps freiburg1$") == std::string::npos); + TEST(res.find("$freiburg2 touches freiburg1$") == std::string::npos); + + TEST(res.find("$freiburg1 covers grenzpart$") != std::string::npos); + TEST(res.find("$freiburg1 contains grenzpart$") == std::string::npos); + TEST(res.find("$grenzpart covers freiburg1$") == std::string::npos); + + TEST(res.find("$freiburg1 intersects grenz$") != std::string::npos); + TEST(res.find("$freiburg2 intersects grenz$") != std::string::npos); + TEST(res.find("$freiburg1 covers grenz$") == std::string::npos); + TEST(res.find("$freiburg2 covers grenz$") == std::string::npos); + TEST(res.find("$freiburg1 contains grenz$") == std::string::npos); + TEST(res.find("$freiburg2 contains grenz$") == std::string::npos); + + TEST(res.find("$freiburg1 intersects a$") != std::string::npos); + TEST(res.find("$freiburg2 intersects a$") != std::string::npos); + TEST(res.find("$freiburg1 covers a$") == std::string::npos); + TEST(res.find("$freiburg2 covers a$") == std::string::npos); + TEST(res.find("$freiburg1 contains a$") == std::string::npos); + TEST(res.find("$freiburg2 contains a$") == std::string::npos); + + TEST(res.find("$freiburg1 intersects b$") != std::string::npos); + TEST(res.find("$freiburg2 intersects b$") != std::string::npos); + TEST(res.find("$freiburg1 covers b$") == std::string::npos); + TEST(res.find("$freiburg2 covers b$") == std::string::npos); + TEST(res.find("$freiburg1 contains b$") == std::string::npos); + TEST(res.find("$freiburg2 contains b$") == std::string::npos); + + TEST(res.find("$freiburg1 intersects c$") != std::string::npos); + TEST(res.find("$freiburg2 intersects c$") != std::string::npos); + TEST(res.find("$freiburg1 covers c$") == std::string::npos); + TEST(res.find("$freiburg2 covers c$") == std::string::npos); + TEST(res.find("$freiburg1 contains c$") == std::string::npos); + TEST(res.find("$freiburg2 contains c$") == std::string::npos); + + TEST(res.find("$freiburg1 intersects d$") != std::string::npos); + TEST(res.find("$freiburg2 intersects d$") != std::string::npos); + TEST(res.find("$freiburg1 covers d$") == std::string::npos); + TEST(res.find("$freiburg2 covers d$") == std::string::npos); + TEST(res.find("$freiburg1 contains d$") == std::string::npos); + TEST(res.find("$freiburg2 contains d$") == std::string::npos); + + TEST(res.find("$freiburg1 intersects grenzpunkt$") != std::string::npos); + TEST(res.find("$freiburg2 intersects grenzpunkt$") != std::string::npos); + TEST(res.find("$freiburg1 covers grenzpunkt$") != std::string::npos); + TEST(res.find("$freiburg2 covers grenzpunkt$") != std::string::npos); + TEST(res.find("$freiburg1 contains grenzpunkt$") == std::string::npos); + TEST(res.find("$freiburg2 contains grenzpunkt$") == std::string::npos); + + TEST(res.find("$freiburg1 intersects grenzpunkt2$") != std::string::npos); + TEST(res.find("$freiburg2 intersects grenzpunkt2$") != std::string::npos); + TEST(res.find("$freiburg1 covers grenzpunkt2$") != std::string::npos); + TEST(res.find("$freiburg2 covers grenzpunkt2$") != std::string::npos); + TEST(res.find("$freiburg1 contains grenzpunkt2$") == std::string::npos); + TEST(res.find("$freiburg2 contains grenzpunkt2$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Umkirch$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Sankt Georgen$") != std::string::npos); + TEST(res.find("$freiburg1 intersects Sankt Georgen$") != + std::string::npos); + TEST(res.find("$freiburg1 contains Sankt Georgen$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Haslach$") != std::string::npos); + + TEST(res.find("$freiburg1 covers Günterstal$") != std::string::npos); + TEST(res.find("$freiburg1 intersects Günterstal$") != std::string::npos); + TEST(res.find("$freiburg1 contains Günterstal$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Kappel$") != std::string::npos); + TEST(res.find("$freiburg1 intersects Kappel$") != std::string::npos); + TEST(res.find("$freiburg1 contains Kappel$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Littenweiler$") != std::string::npos); + TEST(res.find("$freiburg1 intersects Littenweiler$") != + std::string::npos); + TEST(res.find("$freiburg1 contains Littenweiler$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Waldsee$") != std::string::npos); + TEST(res.find("$freiburg1 intersects Waldsee$") != std::string::npos); + TEST(res.find("$freiburg1 contains Waldsee$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Wiehre$") != std::string::npos); + TEST(res.find("$freiburg1 covers Waltershofen$") != std::string::npos); + TEST(res.find("$freiburg1 covers Hochdorf$") != std::string::npos); + TEST(res.find("$freiburg1 covers Opfingen$") != std::string::npos); + TEST(res.find("$freiburg1 covers Betzenhausen$") != std::string::npos); + TEST(res.find("$freiburg1 covers Brühl$") != std::string::npos); + TEST(res.find("$freiburg1 covers Landwasser$") != std::string::npos); + TEST(res.find("$freiburg1 covers Lehen$") != std::string::npos); + TEST(res.find("$freiburg1 covers Mooswald$") != std::string::npos); + + TEST(res.find("$freiburg1 covers Munzingen$") != std::string::npos); + TEST(res.find("$freiburg1 intersects Munzingen$") != std::string::npos); + TEST(res.find("$freiburg1 contains Munzingen$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Tiengen$") != std::string::npos); + TEST(res.find("$freiburg1 intersects Tiengen$") != std::string::npos); + TEST(res.find("$freiburg1 contains Tiengen$") == std::string::npos); + + TEST(res.find("$freiburg1 covers Mundenhof$") != std::string::npos); + TEST(res.find("$freiburg1 covers Rieselfeld$") != std::string::npos); + TEST(res.find("$freiburg1 covers Weingarten$") != std::string::npos); + TEST(res.find("$freiburg1 covers Altstadt$") != std::string::npos); + TEST(res.find("$freiburg1 covers Stühlinger$") != std::string::npos); + TEST(res.find("$freiburg1 covers Neuburg$") != std::string::npos); + TEST(res.find("$freiburg1 covers Herdern$") != std::string::npos); + TEST(res.find("$freiburg1 covers Zähringen$") != std::string::npos); + TEST(res.find("$freiburg1 covers Ebnet$") != std::string::npos); + TEST(res.find("$freiburg1 covers Oberau$") != std::string::npos); + TEST(res.find("$freiburg1 covers Sankt Georgen Süd$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Sankt Georgen Nord$") != + std::string::npos); + TEST(res.find("$Sankt Georgen covers Sankt Georgen Süd$") != + std::string::npos); + TEST(res.find("$Sankt Georgen covers Sankt Georgen Nord$") != + std::string::npos); + TEST(res.find("$Sankt Georgen Süd touches Sankt Georgen Nord$") != + std::string::npos); + TEST(res.find("$Sankt Georgen Nord touches Sankt Georgen Süd$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Haslach-Haid$") != std::string::npos); + TEST(res.find("$freiburg1 covers Haslach-Gartenstadt$") != + std::string::npos); + TEST(res.find("$Haslach covers Haslach-Haid$") != std::string::npos); + TEST(res.find("$Haslach covers Haslach-Gartenstadt$") != + std::string::npos); + TEST(res.find("$Haslach covers Haslach-Schildacker$") != + std::string::npos); + TEST(res.find("$Haslach covers Haslach-Egerten$") != std::string::npos); + TEST(res.find("$freiburg1 covers Haslach-Schildacker$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Haslach-Egerten$") != std::string::npos); + TEST(res.find("$freiburg1 covers Unterwiehre-Nord$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Unterwiehre-Süd$") != std::string::npos); + TEST(res.find("$Wiehre covers Unterwiehre-Nord$") != std::string::npos); + TEST(res.find("$Wiehre covers Unterwiehre-Süd$") != std::string::npos); + TEST(res.find("$freiburg1 covers Altstadt-Ring$") != std::string::npos); + TEST(res.find("$freiburg1 covers Alt-Stühlinger$") != std::string::npos); + TEST(res.find("$freiburg1 covers Betzenhausen-Bischofslinde$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Stühlinger-Eschholz$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Mooswald-Ost$") != std::string::npos); + TEST(res.find("$freiburg1 covers Brühl-Beurbarung$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Brühl-Industriegebiet$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Altstadt-Mitte$") != std::string::npos); + TEST(res.find("$freiburg1 covers Mittelwiehre$") != std::string::npos); + TEST(res.find("$freiburg1 covers Oberwiehre$") != std::string::npos); + TEST(res.find("$Wiehre covers Mittelwiehre$") != std::string::npos); + TEST(res.find("$Wiehre contains Mittelwiehre$") == std::string::npos); + TEST(res.find("$Wiehre covers Oberwiehre$") != std::string::npos); + TEST(res.find("$Wiehre contains Oberwiehre$") == std::string::npos); + TEST(res.find("$freiburg1 covers Alt-Betzenhausen$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Mooswald-West$") != std::string::npos); + TEST(res.find("$freiburg1 covers Brühl-Güterbahnhof$") != + std::string::npos); + TEST(res.find("$freiburg1 covers Herdern-Süd$") != std::string::npos); + TEST(res.find("$freiburg1 covers Herdern-Nord$") != std::string::npos); + TEST(res.find("$Herdern covers Herdern-Süd$") != std::string::npos); + TEST(res.find("$Herdern covers Herdern-Nord$") != std::string::npos); + TEST(res.find("$freiburg1 covers Vauban$") != std::string::npos); + + TEST(res.find("$someway intersects someotherway$") != std::string::npos); + TEST(res.find("$someway covers someotherway$") == std::string::npos); + TEST(res.find("$someway contains someotherway$") == std::string::npos); + + TEST(res.find("$someway covers someway2$") != std::string::npos); + TEST(res.find("$someway intersects someway2$") != std::string::npos); + + TEST(res.find("$someway2 covers someway$") != std::string::npos); + TEST(res.find("$someway2 intersects someway$") != std::string::npos); + + TEST(res.find("$someotherway intersects someway$") != std::string::npos); + TEST(res.find("$someotherway covers someway$") == std::string::npos); + TEST(res.find("$someotherway contains someway$") == std::string::npos); + } + + { + auto res = fullRun("../src/spatialjoin/tests/datasets/brandenburg", cfg); + TEST(res.find("$Brandenburg covers Brandenburg2$") != std::string::npos); + TEST(res.find("$Brandenburg equals Brandenburg2$") != std::string::npos); + TEST(res.find("$Brandenburg2 equals Brandenburg$") != std::string::npos); + TEST(res.find("$Brandenburg intersects Grenzpart$") != std::string::npos); + TEST(res.find("$Brandenburg covers Grenzpart$") != std::string::npos); + TEST(res.find("$Brandenburg contains Grenzpart$") == std::string::npos); + + TEST(res.find("$Brandenburg intersects Berlin$") != std::string::npos); + TEST(res.find("$Brandenburg touches Berlin$") != std::string::npos); + TEST(res.find("$Brandenburg overlaps Berlin$") == std::string::npos); + TEST(res.find("$Berlin touches Brandenburg$") != std::string::npos); + TEST(res.find("$Berlin overlaps Brandenburg$") == std::string::npos); + TEST(res.find("$Brandenburg contains Berlin$") == std::string::npos); + TEST(res.find("$Brandenburg covers Berlin$") == std::string::npos); + + TEST(res.find("$Berlin intersects Grenzpart$") != std::string::npos); + TEST(res.find("$Berlin covers Grenzpart$") != std::string::npos); + TEST(res.find("$Berlin contains Grenzpart$") == std::string::npos); + + TEST(res.find("$Haus overlaps Brandenburg$") != std::string::npos); + TEST(res.find("$Haus-Way intersects Brandenburg$") != std::string::npos); + TEST(res.find("$Haus intersects Brandenburg-Way$") != std::string::npos); + TEST(res.find("$Haus-Way intersects Brandenburg-Way$") != + std::string::npos); + + TEST(res.find("$Brandenburg-Point intersects Brandenburg-Way$") != + std::string::npos); + TEST(res.find("$Brandenburg-Point intersects Brandenburg$") != + std::string::npos); + } + + { + auto res = fullRun("../src/spatialjoin/tests/datasets/multitests", cfg); + + TEST(res.find("$28 covers 27$") != std::string::npos); + + TEST(res.find("$27 overlaps 28$") == std::string::npos); + TEST(res.find("$28 overlaps 27$") == std::string::npos); + + TEST(res.find("$17 touches 18$") != std::string::npos); + TEST(res.find("$19 touches 18$") != std::string::npos); + TEST(res.find("$17 touches 16$") != std::string::npos); + + TEST(res.find("$1 equals 2$") != std::string::npos); + TEST(res.find("$1 overlaps 2$") == std::string::npos); + TEST(res.find("$2 equals 1$") != std::string::npos); + TEST(res.find("$3 equals 1$") == std::string::npos); + TEST(res.find("$3 equals 2$") == std::string::npos); + TEST(res.find("$3 equals 4$") != std::string::npos); + TEST(res.find("$3 equals 5$") != std::string::npos); + TEST(res.find("$4 equals 3$") != std::string::npos); + TEST(res.find("$5 equals 3$") != std::string::npos); + TEST(res.find("$5 equals 4$") != std::string::npos); + TEST(res.find("$4 equals 5$") != std::string::npos); + TEST(res.find("$4 overlaps 5$") == std::string::npos); + TEST(res.find("$1 touches 6$") != std::string::npos); + TEST(res.find("$6 touches 1$") != std::string::npos); + TEST(res.find("$2 touches 6$") != std::string::npos); + TEST(res.find("$6 touches 2$") != std::string::npos); + TEST(res.find("$3 touches 6$") != std::string::npos); + TEST(res.find("$6 touches 3$") != std::string::npos); + TEST(res.find("$4 touches 6$") != std::string::npos); + TEST(res.find("$6 touches 4$") != std::string::npos); + TEST(res.find("$6 touches 7$") == std::string::npos); + TEST(res.find("$7 touches 6$") == std::string::npos); + + TEST(res.find("$8 touches 9$") != std::string::npos); + TEST(res.find("$9 touches 8$") != std::string::npos); + + TEST(res.find("$8 touches 11$") == std::string::npos); + + TEST(res.find("$9 touches 10$") == std::string::npos); + TEST(res.find("$8 touches 10$") == std::string::npos); + TEST(res.find("$12 touches 10$") != std::string::npos); + TEST(res.find("$13 equals 10$") != std::string::npos); + + TEST(res.find("$6 equals 14$") != std::string::npos); + TEST(res.find("$15 touches 16$") != std::string::npos); + TEST(res.find("$17 touches 6$") == std::string::npos); + TEST(res.find("$17 intersects 16$") != std::string::npos); + TEST(res.find("$17 intersects 18$") != std::string::npos); + + TEST(res.find("$8 overlaps 20$") != std::string::npos); + TEST(res.find("$20 overlaps 8$") != std::string::npos); + + TEST(res.find("$17 crosses 21$") != std::string::npos); + TEST(res.find("$21 crosses 17$") != std::string::npos); + + TEST(res.find("$17 crosses 22$") == std::string::npos); + TEST(res.find("$22 crosses 17$") == std::string::npos); + + TEST(res.find("$17 overlaps 22$") == std::string::npos); + TEST(res.find("$22 overlaps 17$") == std::string::npos); + + TEST(res.find("$24 covers 25$") != std::string::npos); + + TEST(res.find("$25 overlaps 24$") == std::string::npos); + TEST(res.find("$24 overlaps 25$") == std::string::npos); + + TEST(res.find("$23 overlaps 24$") == std::string::npos); + TEST(res.find("$24 overlaps 23$") == std::string::npos); + + TEST(res.find("$26 overlaps 24$") != std::string::npos); + TEST(res.find("$24 overlaps 26$") != std::string::npos); + + TEST(res.find("$26 overlaps 27$") != std::string::npos); + TEST(res.find("$27 overlaps 26$") != std::string::npos); + + TEST(res.find("$26 overlaps 28$") != std::string::npos); + TEST(res.find("$28 overlaps 26$") != std::string::npos); + + TEST(res.find("8 overlaps 29$") == std::string::npos); + TEST(res.find("8 overlaps 29$") == std::string::npos); + TEST(res.find("30 covers 8$") != std::string::npos); + TEST(res.find("8 overlaps 30$") == std::string::npos); + TEST(res.find("29 overlaps 30$") == std::string::npos); + TEST(res.find("30 overlaps 29") == std::string::npos); + + TEST(res.find("31 overlaps 30$") != std::string::npos); + TEST(res.find("30 overlaps 31") != std::string::npos); + } + + { + auto res = fullRun("../src/spatialjoin/tests/datasets/coverfail", cfg); + TEST(res.find("$1 intersects 2$") != std::string::npos); + TEST(res.find("$2 intersects 1$") != std::string::npos); + TEST(res.find("$1 contains 2$") == std::string::npos); + TEST(res.find("$2 contains 1$") == std::string::npos); + TEST(res.find("$1 covers 2$") == std::string::npos); + TEST(res.find("$2 covers 1$") == std::string::npos); + TEST(res.find("$1 touches 2$") != std::string::npos); + TEST(res.find("$2 touches 1$") != std::string::npos); + } + + { + auto res = fullRun("../src/spatialjoin/tests/datasets/touchfail", cfg); + TEST(res.find("$1 intersects 2$") != std::string::npos); + TEST(res.find("$2 intersects 1$") != std::string::npos); + TEST(res.find("$1 overlaps 2$") != std::string::npos); + TEST(res.find("$2 overlaps 1$") != std::string::npos); + TEST(res.find("$1 touches 2$") == std::string::npos); + TEST(res.find("$2 touches 1$") == std::string::npos); + } + + { + auto res = fullRun("../src/spatialjoin/tests/datasets/touchwayfail", cfg); + TEST(res.find("$1 touches 2$") != std::string::npos); + TEST(res.find("$2 touches 1$") != std::string::npos); + } } } diff --git a/src/util b/src/util index 900378b..159a5c5 160000 --- a/src/util +++ b/src/util @@ -1 +1 @@ -Subproject commit 900378b085108ff8224fdff23374c92d19d1cc18 +Subproject commit 159a5c52458974c3079179da86914c60338d0916