// // Copyright (C) 2019-2023 Greg Landrum // // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // #include #include #include #include #include "Conrec.h" #include #include #include #include #include TEST_CASE("Conrec basics", "[conrec]") { SECTION("basics") { std::vector pts = {{0., 0.}, {1., 0.}, {1., 1.}, {0., 1.}}; const size_t gridSz = 100; auto grid = std::make_unique(gridSz * gridSz); double xps[gridSz]; double yps[gridSz]; double x1 = -4, y1 = -4, x2 = 6, y2 = 6; double dx = (x2 - x1) / gridSz, dy = (y2 - y1) / gridSz; double maxV = 0.0; for (size_t ix = 0; ix < gridSz; ++ix) { auto px = x1 + ix * dx; xps[ix] = px; for (size_t iy = 0; iy < gridSz; ++iy) { auto py = y1 + iy * dy; if (ix == 0) { yps[iy] = py; } RDGeom::Point2D loc(px, py); double val = 0.0; for (const auto &pt : pts) { auto dv = loc - pt; auto r = dv.length(); if (r > 0) { val += 1 / r; } } // to make the contours more visible, we cap the max val we set at 1000 maxV = std::max(std::min(val, 1000.), maxV); grid[ix * gridSz + iy] = val; } } std::vector segs; const size_t nContours = 10; double isoLevels[nContours]; for (size_t i = 0; i < nContours; ++i) { isoLevels[i] = (i + 1) * (maxV / (nContours + 1)); } conrec::Contour(grid.get(), 0, gridSz - 1, 0, gridSz - 1, xps, yps, nContours, isoLevels, segs); std::ofstream outs("./blah.svg"); outs << R"SVG( )SVG"; for (const auto &seg : segs) { outs << "" << std::endl; ; } outs << "" << std::endl; } } TEST_CASE("connectLineSegments", "[conrec]") { SECTION("basics") { std::vector pts = {{0., 0.}, {1., 0.}, {1., 1.}, {0., 1.}}; const size_t gridSz = 100; auto grid = std::make_unique(gridSz * gridSz); double xps[gridSz]; double yps[gridSz]; double x1 = -4, y1 = -4, x2 = 6, y2 = 6; double dx = (x2 - x1) / gridSz, dy = (y2 - y1) / gridSz; double maxV = 0.0; for (size_t ix = 0; ix < gridSz; ++ix) { auto px = x1 + ix * dx; xps[ix] = px; for (size_t iy = 0; iy < gridSz; ++iy) { auto py = y1 + iy * dy; if (ix == 0) { yps[iy] = py; } RDGeom::Point2D loc(px, py); double val = 0.0; for (const auto &pt : pts) { auto dv = loc - pt; auto r = dv.length(); if (r > 1e-4) { val += 1 / r; } } maxV = std::max(std::min(val, 1000.), maxV); grid[ix * gridSz + iy] = val; } } std::vector segs; const size_t nContours = 10; double isoLevels[nContours]; for (size_t i = 0; i < nContours; ++i) { isoLevels[i] = (i + 1) * (maxV / (nContours + 1)); } conrec::Contour(grid.get(), 0, gridSz - 1, 0, gridSz - 1, xps, yps, nContours, isoLevels, segs); auto contours = conrec::connectLineSegments(segs); CHECK(contours.size() == 74); std::ofstream outs("./blah.contour.svg"); outs << R"SVG( )SVG"; for (const auto &pr : contours) { auto [contour, val] = pr; REQUIRE(contour.size()); outs << "" << std::endl; } outs << "" << std::endl; } } TEST_CASE("super chunky", "[conrec]") { // an example where you can really see any holes in the contours SECTION("basics") { std::vector pts = {{0., 0.}, {1., 0.}, {1., 1.}, {0., 1.}}; const size_t gridSz = 5; auto grid = std::make_unique(gridSz * gridSz); double xps[gridSz]; double yps[gridSz]; double x1 = -4, y1 = -4, x2 = 6, y2 = 6; double dx = (x2 - x1) / gridSz, dy = (y2 - y1) / gridSz; double maxV = 0.0; for (size_t ix = 0; ix < gridSz; ++ix) { auto px = x1 + ix * dx; xps[ix] = px; for (size_t iy = 0; iy < gridSz; ++iy) { auto py = y1 + iy * dy; if (ix == 0) { yps[iy] = py; } RDGeom::Point2D loc(px, py); double val = 0.0; for (const auto &pt : pts) { auto dv = loc - pt; auto r = dv.length(); if (r > 0) { val += 1 / r; } } maxV = std::max(val, maxV); grid[ix * gridSz + iy] = val; } } std::vector segs; const size_t nContours = 1; double isoLevels[nContours]; for (size_t i = 0; i < nContours; ++i) { isoLevels[i] = (i + 1) * (maxV / (nContours + 1)); } conrec::Contour(grid.get(), 0, gridSz - 1, 0, gridSz - 1, xps, yps, nContours, isoLevels, segs); std::ofstream outs("./chunky.svg"); outs << R"SVG( )SVG"; for (const auto &seg : segs) { outs << "" << std::endl; ; } outs << "" << std::endl; auto contours = conrec::connectLineSegments(segs); std::ofstream outs2("./chunky.contour.svg"); outs2 << R"SVG( )SVG"; for (const auto &pr : contours) { auto [contour, val] = pr; REQUIRE(contour.size()); outs2 << "" << std::endl; } outs2 << "" << std::endl; } }