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
|
//
// Copyright (C) 2020-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).
//
// A concrete class derived from DrawText that uses SVG
// to draw text onto a picture.
#include <sstream>
#include <RDGeneral/BoostStartInclude.h>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
#include <RDGeneral/BoostEndInclude.h>
#include <GraphMol/MolDraw2D/MolDraw2DDetails.h>
#include <GraphMol/MolDraw2D/DrawTextSVG.h>
#include <GraphMol/MolDraw2D/MolDraw2DSVG.h>
#include <GraphMol/MolDraw2D/MolDraw2DDetails.h>
namespace RDKit {
std::string DrawColourToSVG(const DrawColour &col);
namespace MolDraw2D_detail {
// ****************************************************************************
DrawTextSVG::DrawTextSVG(double max_fnt_sz, double min_fnt_sz,
std::ostream &oss, std::string &d_act_class)
: DrawTextNotFT(max_fnt_sz, min_fnt_sz),
oss_(oss),
d_active_class_(d_act_class) {}
namespace {
void escape_xhtml(std::string &data) {
boost::algorithm::replace_all(data, "&", "&");
boost::algorithm::replace_all(data, "\"", """);
boost::algorithm::replace_all(data, "\'", "'");
boost::algorithm::replace_all(data, "<", "<");
boost::algorithm::replace_all(data, ">", ">");
}
} // namespace
// ****************************************************************************
// draw the char, with the bottom left hand corner at cds
void DrawTextSVG::drawChar(char c, const Point2D &cds) {
unsigned int fontSz = fontSize();
std::string col = DrawColourToSVG(colour());
oss_ << "<text";
oss_ << " x='" << MolDraw2D_detail::formatDouble(cds.x);
oss_ << "' y='" << MolDraw2D_detail::formatDouble(cds.y) << "'";
if (!d_active_class_.empty()) {
oss_ << " class='" << d_active_class_ << "'";
}
std::string cs;
cs += c;
escape_xhtml(cs);
oss_ << " style='font-size:" << fontSz
<< "px;font-style:normal;font-weight:normal;fill-opacity:1;stroke:none;"
"font-family:sans-serif;text-anchor:start;"
<< "fill:" << col << "'";
oss_ << " >";
oss_ << cs;
oss_ << "</text>"
<< "\n";
}
// ****************************************************************************
void DrawTextSVG::getStringRects(
const std::string &text, std::vector<std::shared_ptr<StringRect>> &rects,
std::vector<TextDrawType> &draw_modes,
std::vector<char> &draw_chars) const {
double running_x = 0.0;
double act_font_size = fontSize();
double char_height;
double max_width = 0.0;
TextDrawType draw_mode = TextDrawType::TextDrawNormal;
for (size_t i = 0; i < text.length(); ++i) {
// setStringDrawMode moves i along to the end of any <sub> or <sup>
// markup
if ('<' == text[i] && setStringDrawMode(text, draw_mode, i)) {
continue;
}
draw_modes.push_back(draw_mode);
draw_chars.push_back(text[i]);
max_width = std::max(
max_width,
static_cast<double>(MolDraw2D_detail::char_widths[(int)text[i]]));
}
for (size_t i = 0; i < draw_chars.size(); ++i) {
double char_width =
0.6 * act_font_size *
static_cast<double>(MolDraw2D_detail::char_widths[(int)draw_chars[i]]) /
max_width;
// Absent a proper set of font metrics (we don't know what font we'll be
// using, for starters) this is something of an empirical bodge.
if (draw_chars[i] == '+') {
char_height = 0.6 * act_font_size;
} else if (draw_chars[i] == '-') {
char_height = 0.4 * act_font_size;
} else {
char_height = 0.8 * act_font_size;
}
double cscale = selectScaleFactor(draw_chars[i], draw_modes[i]);
char_height *= cscale;
char_width *= cscale;
Point2D offset(char_width / 2, char_height / 2);
if (draw_chars[i] == '+' || draw_chars[i] == '-') {
offset.y /= 2.0;
}
Point2D g_centre(char_width / 2, char_height / 2);
rects.push_back(std::shared_ptr<StringRect>(
new StringRect(offset, g_centre, char_width, char_height)));
rects.back()->trans_.x += running_x;
// empirical spacing.
if (draw_modes[i] != TextDrawType::TextDrawNormal) {
running_x += char_width * 1.05;
} else {
running_x += char_width * 1.15;
}
}
for (auto r : rects) {
r->g_centre_.y = act_font_size - r->g_centre_.y;
r->offset_.y = act_font_size / 2.0;
}
adjustStringRectsForSuperSubScript(draw_modes, rects);
}
} // namespace MolDraw2D_detail
} // namespace RDKit
|