1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
//
// Copyright (C) 2021-2022 David Cosgrove and other RDKit contributors
//
// @@ 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.
//
// Original author: David Cosgrove (CozChemIx Limited)
//
#include <RDGeneral/BoostStartInclude.h>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <RDGeneral/BoostEndInclude.h>
#include <GraphMol/MolDraw2D/AtomSymbol.h>
#include <GraphMol/MolDraw2D/DrawText.h>
#include <GraphMol/MolDraw2D/MolDraw2D.h>
namespace RDKit {
namespace MolDraw2D_detail {
// ****************************************************************************
AtomSymbol::AtomSymbol(const std::string &symbol, int atIdx, OrientType orient,
const Point2D &cds, const DrawColour &colour,
DrawText &textDrawer)
: symbol_(symbol),
atIdx_(atIdx),
orient_(orient),
cds_(cds),
colour_(colour),
textDrawer_(textDrawer) {
if (symbol_.empty()) {
return;
}
textDrawer_.getStringRects(symbol_, orient_, rects_, drawModes_, drawChars_,
false, TextAlignType::MIDDLE);
adjustColons();
}
// ****************************************************************************
void AtomSymbol::findExtremes(double &xmin, double &xmax, double &ymin,
double &ymax) const {
Point2D bl, br, tl, tr, origTrans;
for (auto rect : rects_) {
origTrans = rect->trans_;
rect->trans_ += cds_;
rect->calcCorners(tl, tr, br, bl, 0.0);
// sometimes the rect is in a coordinate frame where +ve y is down,
// sometimes it's up. For these purposes, we don't care so long as
// the ymax is larger than the ymin. We probably don't need to do
// all the tests for xmin and xmax.
xmin = std::min({tr.x, bl.x, xmin});
ymin = std::min({tr.y, bl.y, ymin});
xmax = std::max({tr.x, bl.x, xmax});
ymax = std::max({tr.y, bl.y, ymax});
rect->trans_ = origTrans;
}
}
// ****************************************************************************
void AtomSymbol::scale(const Point2D &scaleFactor) {
cds_.x *= scaleFactor.x;
cds_.y *= scaleFactor.y;
recalculateRects();
}
// ****************************************************************************
void AtomSymbol::move(const Point2D &trans) { cds_ += trans; }
// ****************************************************************************
void AtomSymbol::recalculateRects() {
// rebuild the rectangles, because the fontScale may be different,
// and the widths etc might not scale by the same amount.
rects_.clear();
drawModes_.clear();
drawChars_.clear();
textDrawer_.getStringRects(symbol_, orient_, rects_, drawModes_, drawChars_,
false, TextAlignType::MIDDLE);
}
// ****************************************************************************
void AtomSymbol::draw(MolDraw2D &molDrawer) const {
std::string o_class = molDrawer.getActiveClass();
std::string actClass = o_class;
if (!actClass.empty()) {
actClass += " ";
}
actClass += (boost::format("atom-%d") % atIdx_).str();
molDrawer.setActiveClass(actClass);
textDrawer_.setColour(colour_);
textDrawer_.drawString(symbol_, cds_, orient_);
molDrawer.setActiveClass(o_class);
// drawRects(molDrawer);
}
// ****************************************************************************
bool AtomSymbol::doesRectClash(const StringRect &rect, double padding) const {
for (auto &alrect : rects_) {
auto oldTrans = alrect->trans_;
alrect->trans_ += cds_;
bool dii = alrect->doesItIntersect(rect, padding);
alrect->trans_ = oldTrans;
if (dii) {
return true;
}
}
return false;
}
// ****************************************************************************
void AtomSymbol::adjustColons() {
if (symbol_.empty()) {
return; // but probably it's always got something in it.
}
size_t colonPos = symbol_.find(':');
if (colonPos == std::string::npos) {
return;
}
// we need to allow for markup in the symbol, such as <lit>[CH2;X2:4]</lit>
// and the easiest way to do that is to use the fact that atomLabelToPieces
// strips it out.
std::string tmpSym = symbol_;
while (true) {
size_t ltPos = tmpSym.find('<');
if (ltPos == std::string::npos) {
break;
}
size_t gtPos = tmpSym.find('>');
tmpSym = tmpSym.substr(0, ltPos) + tmpSym.substr(gtPos + 1);
}
colonPos = tmpSym.find(':');
if (colonPos == std::string::npos) {
return;
}
CHECK_INVARIANT(colonPos <= rects_.size(), "bad rects_ size");
double leftHeight = colonPos ? rects_[colonPos - 1]->height_ : 0;
double rightHeight =
colonPos < symbol_.size() - 1 ? rects_[colonPos + 1]->height_ : 0;
rects_[colonPos]->height_ = std::min(leftHeight, rightHeight);
}
// ****************************************************************************
void AtomSymbol::drawRects(MolDraw2D &molDrawer) const {
Point2D tl, tr, br, bl, origTrans;
for (auto &rect : rects_) {
origTrans = rect->trans_;
rect->trans_ += cds_;
rect->calcCorners(tl, tr, br, bl, 0.0);
molDrawer.setColour(DrawColour(1.0, 0.0, 0.0));
molDrawer.drawLine(tl, tr, true);
molDrawer.setColour(DrawColour(0.0, 1.0, 0.0));
molDrawer.drawLine(tr, br, true);
molDrawer.setColour(DrawColour(0.0, 0.0, 1.0));
molDrawer.drawLine(br, bl, true);
molDrawer.setColour(DrawColour(0.0, 0.95, 0.95));
molDrawer.drawLine(bl, tl, true);
rect->trans_ = origTrans;
}
}
} // namespace MolDraw2D_detail
} // namespace RDKit
|