diff --git a/Code/GraphMol/MolDraw2D/DrawMol.cpp b/Code/GraphMol/MolDraw2D/DrawMol.cpp index dffb52625..147e82a10 100755 --- a/Code/GraphMol/MolDraw2D/DrawMol.cpp +++ b/Code/GraphMol/MolDraw2D/DrawMol.cpp @@ -1116,11 +1116,13 @@ void DrawMol::calculateScale() { partitionForLegend(); if (xRange_ > 1e-4 || yRange_ > 1e-4) { - double widthForScale = molWidth_ > 0 ? double(molWidth_) : double(drawWidth_); + double widthForScale = + molWidth_ > 0 ? double(molWidth_) : double(drawWidth_); const bool sideLegendHoriz = !legend_.empty() && (drawOptions_.legendPosition == MolDrawOptions::LegendPosition::Left || - drawOptions_.legendPosition == MolDrawOptions::LegendPosition::Right) && + drawOptions_.legendPosition == + MolDrawOptions::LegendPosition::Right) && !drawOptions_.legendVerticalText; if (sideLegendHoriz && molWidth_ > 0) { // Keep a minimum absolute side gap of 8 px so labels do not crowd the @@ -1132,8 +1134,7 @@ void DrawMol::calculateScale() { widthForScale = double(molWidth_) - g; } } - newScale = - std::min(widthForScale / xRange_, double(molHeight_) / yRange_); + newScale = std::min(widthForScale / xRange_, double(molHeight_) / yRange_); double fix_scale = newScale; // after all that, use the fixed scale unless it's too big, in which case // scale the drawing down to fit. @@ -1402,6 +1403,7 @@ void DrawMol::shrinkToFit(bool withPadding) { } else { legendHeight_ = 0; molHeight_ = height_; + molWidth_ = drawWidth_; drawHeight_ = height_ * (1 - 2 * padding); } } @@ -1801,24 +1803,23 @@ std::vector split_legend_bits(const std::string &legend, return legend_bits; } boost::split(legend_bits, legend, boost::is_any_of("\n")); - legend_bits.erase(std::remove_if(legend_bits.begin(), legend_bits.end(), - [](const std::string &s) { - return s.empty(); - }), - legend_bits.end()); + legend_bits.erase( + std::remove_if(legend_bits.begin(), legend_bits.end(), + [](const std::string &s) { return s.empty(); }), + legend_bits.end()); return legend_bits; } -void place_bottom_legend(const std::vector &legend_bits, - double relFontScale, const DrawColour &legendColour, - DrawText &textDrawer, double baseX, double baseY, - double drawWidth, double drawHeight, - std::vector> &legends) { +void place_bottom_legend( + const std::vector &legend_bits, double relFontScale, + const DrawColour &legendColour, DrawText &textDrawer, double baseX, + double baseY, double drawWidth, double drawHeight, + std::vector> &legends) { Point2D loc(baseX + drawWidth / 2.0, baseY + drawHeight); for (const auto &bit : legend_bits) { - legends.emplace_back(new DrawAnnotation(bit, TextAlignType::MIDDLE, "legend", - relFontScale, loc, legendColour, - textDrawer)); + legends.emplace_back(new DrawAnnotation(bit, TextAlignType::MIDDLE, + "legend", relFontScale, loc, + legendColour, textDrawer)); } double xmin, xmax, ymin, ymax; double lastAbove = 0.0; @@ -1847,7 +1848,8 @@ void place_top_legend(const std::vector &legend_bits, for (size_t i = 0; i < legend_bits.size(); ++i) { double height, width; DrawAnnotation da(legend_bits[i], TextAlignType::MIDDLE, "legend", - relFontScale, Point2D(0.0, 0.0), legendColour, textDrawer); + relFontScale, Point2D(0.0, 0.0), legendColour, + textDrawer); da.getDimensions(width, height); total_h += height; if (i + 1 < legend_bits.size()) { @@ -1859,13 +1861,14 @@ void place_top_legend(const std::vector &legend_bits, for (size_t i = 0; i < legend_bits.size(); ++i) { double height, width; DrawAnnotation da(legend_bits[i], TextAlignType::MIDDLE, "legend", - relFontScale, Point2D(0.0, 0.0), legendColour, textDrawer); + relFontScale, Point2D(0.0, 0.0), legendColour, + textDrawer); da.getDimensions(width, height); y += height / 2.0; Point2D loc(baseX + drawWidth / 2.0, y); - legends.emplace_back(new DrawAnnotation(legend_bits[i], TextAlignType::MIDDLE, - "legend", relFontScale, loc, - legendColour, textDrawer)); + legends.emplace_back( + new DrawAnnotation(legend_bits[i], TextAlignType::MIDDLE, "legend", + relFontScale, loc, legendColour, textDrawer)); y += height / 2.0; if (i + 1 < legend_bits.size()) { y += gap; @@ -1876,8 +1879,9 @@ void place_top_legend(const std::vector &legend_bits, void place_side_legend(const std::vector &legend_bits, double relFontScale, const DrawColour &legendColour, DrawText &textDrawer, bool vertText, bool is_left, - double baseX, double baseY, int legendWidth, int molWidth, - double drawWidth, double drawHeight, double marginPadding, + double baseX, double baseY, int legendWidth, + int molWidth, double drawWidth, double drawHeight, + double marginPadding, std::vector> &legends) { if (legend_bits.empty()) { return; @@ -1925,9 +1929,9 @@ void place_side_legend(const std::vector &legend_bits, for (size_t i = 0; i < legend_bits.size(); ++i) { y += max_h / 2.0; Point2D loc(stripCentreX, y); - legends.emplace_back(new DrawAnnotation(legend_bits[i], TextAlignType::MIDDLE, - "legend", relFontScale, loc, - legendColour, textDrawer)); + legends.emplace_back( + new DrawAnnotation(legend_bits[i], TextAlignType::MIDDLE, "legend", + relFontScale, loc, legendColour, textDrawer)); y += max_h / 2.0; if (i + 1 < legend_bits.size()) { y += gap; @@ -1955,9 +1959,9 @@ void place_side_legend(const std::vector &legend_bits, da.getDimensions(width, height); y += height / 2.0; Point2D loc(stripCentreX, y); - legends.emplace_back(new DrawAnnotation(legend_bits[i], TextAlignType::MIDDLE, - "legend", relFontScale, loc, - legendColour, textDrawer)); + legends.emplace_back( + new DrawAnnotation(legend_bits[i], TextAlignType::MIDDLE, "legend", + relFontScale, loc, legendColour, textDrawer)); y += height / 2.0; if (i + 1 < legend_bits.size()) { y += gap; @@ -2007,7 +2011,8 @@ void DrawMol::extractLegend() { (drawOptions_.legendPosition == MolDrawOptions::LegendPosition::Left || drawOptions_.legendPosition == MolDrawOptions::LegendPosition::Right) && !vertText; - if (total_width > maxWidth && maxWidth > 0 && !flexiCanvasX_ && !sideHorizontal) { + if (total_width > maxWidth && maxWidth > 0 && !flexiCanvasX_ && + !sideHorizontal) { relFontScale *= maxWidth / total_width; calc_legend_dims(legend_bits, relFontScale, drawOptions_.legendColour, textDrawer_, total_width, total_height); @@ -2064,9 +2069,8 @@ void DrawMol::extractLegend() { } const double gap = calc_line_gap(textDrawer_, vertText, relFontScale); const size_t n = legend_bits.size(); - const double span = - static_cast(n) * max_h + - (n > 1 ? static_cast(n - 1) * gap : 0.0); + const double span = static_cast(n) * max_h + + (n > 1 ? static_cast(n - 1) * gap : 0.0); if (span <= avail || span <= 0.0) { break; } @@ -2098,9 +2102,9 @@ void DrawMol::extractLegend() { break; case MolDrawOptions::LegendPosition::Right: place_side_legend(legend_bits, relFontScale, drawOptions_.legendColour, - textDrawer_, vertText, false, baseX, baseY, legendWidth_, - molWidth_, drawWidth_, drawHeight_, marginPadding_, - legends_); + textDrawer_, vertText, false, baseX, baseY, + legendWidth_, molWidth_, drawWidth_, drawHeight_, + marginPadding_, legends_); break; } } diff --git a/Code/GraphMol/MolDraw2D/catch_tests.cpp b/Code/GraphMol/MolDraw2D/catch_tests.cpp index de7069ac1..a0fcdf85b 100644 --- a/Code/GraphMol/MolDraw2D/catch_tests.cpp +++ b/Code/GraphMol/MolDraw2D/catch_tests.cpp @@ -375,6 +375,7 @@ const std::map SVG_HASHES = { {"testDrawingExtentsInclude_allButHighlights.svg", 1604243819U}, {"testDrawingExtentsIncludeWithHighlights_allButHighlights.svg", 436783789U}, + {"test_Github9301_1.svg", 3573122884U}, {"test_Github9280_1.0.svg", 1658116840U}, {"test_Github9280_2.0.svg", 1805554327U}, {"test_Github9280_0.3.svg", 893100468U}, @@ -11361,6 +11362,37 @@ M END } } +TEST_CASE("Github9301 - reaction layout regression") { + std::unique_ptr rxn(RxnSmartsToChemicalReaction( + "[CH3:1][C:2](=[O:3])[OH:4].[CH3:5][NH2:6]>CC(O)C.[Pt]>[CH3:1][C:2](=[O:3])[NH:6][CH3:5].[OH2:4]")); + MolDraw2DSVG drawer(450, 200, 450, 200, NO_FREETYPE); + drawer.drawReaction(*rxn); + drawer.finishDrawing(); + std::ofstream outs("test_Github9301_1.svg"); + auto txt = drawer.getDrawingText(); + outs << txt; + outs.close(); + const static std::regex atom0( + "C"); + std::ptrdiff_t const match_count( + std::distance(std::sregex_iterator(txt.begin(), txt.end(), atom0), + std::sregex_iterator())); + CHECK(match_count == 3); + auto match_begin = std::sregex_iterator(txt.begin(), txt.end(), atom0); + std::smatch match = *match_begin; + CHECK_THAT(stod(match[1]), Catch::Matchers::WithinAbs(40.2, 0.1)); + CHECK_THAT(stod(match[2]), Catch::Matchers::WithinAbs(125.8, 0.1)); + ++match_begin; + match = *match_begin; + CHECK_THAT(stod(match[1]), Catch::Matchers::WithinAbs(138.3, 0.1)); + CHECK_THAT(stod(match[2]), Catch::Matchers::WithinAbs(104.5, 0.1)); + ++match_begin; + match = *match_begin; + CHECK_THAT(stod(match[1]), Catch::Matchers::WithinAbs(355.9, 0.1)); + CHECK_THAT(stod(match[2]), Catch::Matchers::WithinAbs(80.0, 0.1)); + check_file_hash("test_Github9301_1.svg"); +} + TEST_CASE("Github 9280 - font scaling bug") { auto mol = "CC(C)Oc1ccc(N2CCc3nccc(C(=O)Nc4ccccn4)c3C2)nc1"_smiles; {