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 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
//
// 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).
//
// This is an abstract base class for drawing text into a MolDraw2D
// object.
#ifndef RDKIT_DRAWTEXT_H
#define RDKIT_DRAWTEXT_H
#include <string>
#include <vector>
#include <RDGeneral/export.h>
#include <Geometry/point.h>
#include <GraphMol/MolDraw2D/MolDraw2DHelpers.h>
#include <GraphMol/MolDraw2D/StringRect.h>
using RDGeom::Point2D;
namespace RDKit {
class MolDraw2D;
namespace MolDraw2D_detail {
// for aligning the drawing of text to the passed in coords.
enum class TextDrawType : unsigned char {
TextDrawNormal = 0,
TextDrawSuperscript,
TextDrawSubscript
};
std::ostream &operator<<(std::ostream &oss, const OrientType &o);
std::ostream &operator<<(std::ostream &oss, const TextAlignType &tat);
std::ostream &operator<<(std::ostream &oss, const TextDrawType &tdt);
// ****************************************************************************
// This is an implementation class, not intended to be used by the great
// unwashed. If you want to draw a string used MolDraw2D::drawString().
class RDKIT_MOLDRAW2D_EXPORT DrawText {
public:
virtual ~DrawText() = 0;
static constexpr double DEFAULT_FONT_SCALE =
0.6; // seems to be a good number
DrawText(double max_fnt_sz, double min_fnt_sz);
DrawText(const DrawText &) = delete;
DrawText(DrawText &&) = delete;
DrawText &operator=(const DrawText &) = delete;
DrawText &operator=(DrawText &&) = delete;
DrawColour const &colour() const;
void setColour(const DrawColour &col);
// size in "pixels" i.e scale() * base_font_size_.
double fontSize() const;
void setFontSize(double new_size);
double baseFontSize() const;
void setBaseFontSize(double new_size);
double maxFontSize() const;
void setMaxFontSize(double new_max);
double minFontSize() const;
void setMinFontSize(double new_max);
double fontScale() const;
// returns false if min or max font size is hit, true otherwise.
// ignoreLimits ignores minFontSize and maxFontSize.
bool setFontScale(double new_scale, bool ignoreLimits = false);
// these are only relevant for the FreeType DrawText classes.
virtual std::string getFontFile() const { return ""; }
virtual void setFontFile(const std::string &font_file) {
RDUNUSED_PARAM(font_file);
}
//! using the current scale, work out the size of the label
/*!
Bear in mind when implementing this, that, for example, NH2 will appear as
NH<sub>2</sub> to convey that the 2 is a subscript, and this needs to
be accounted for in the width and height.
*/
virtual void getStringSize(const std::string &label, double &label_width,
double &label_height) const;
// returns the extremes of the label, in draw (pixel) coords. dontSplit
// true suppresses the call to atomLabelToPieces.
void getStringExtremes(const std::string &label, OrientType orient,
double &x_min, double &y_min, double &x_max,
double &y_max, bool dontSplit = false) const;
// get the rectangles that go round each character of the string. If
// dontSplit is false, it assumes it's an atom label and splits it
// in a sensible way for that. If the OrientType is C, it applies
// textAlign, otherwise the text is aligned set appropriately for the
// OrientType.
void getStringRects(const std::string &text, OrientType orient,
std::vector<std::shared_ptr<StringRect>> &rects,
std::vector<TextDrawType> &draw_modes,
std::vector<char> &draw_chars, bool dontSplit = false,
TextAlignType textAlign = TextAlignType::MIDDLE) const;
//! drawString centres the string on cds.
virtual void drawString(const std::string &str, const Point2D &cds,
TextAlignType align);
// Aligns them according to OrientType. This version assumes it's an
// atomic symbol and calls atomLabelToPieces. This will behave
// badly with general text. Surround the string with <lit></lit>
// if that's an issue, or use the version above.
void drawString(const std::string &label, const Point2D &cds,
OrientType orient);
// put the label on end2, and then move end2 so that it is at
// the intersection of a string rectangle and the line from end1 to
// end2, if there is an intersection. Mostly for trimming bonds
// back from atom labels. end1 and end2 in draw coords.
void adjustLineForString(const std::string &label, OrientType orient,
const Point2D &end1, Point2D &end2) const;
// draw the char, with the bottom left hand corner at cds
virtual void drawChar(char c, const Point2D &cds) = 0;
// puts a colourful rectangle around each character in the string.
// For debugging, mostly.
void drawStringRects(const std::string &label, OrientType orient,
TextAlignType talign, const Point2D &cds,
MolDraw2D &mol_draw) const;
// cds in draw coords
// does the label at cds intersect the given StringRect.
bool doesRectIntersect(const std::string &label, OrientType orient,
const Point2D &cds, const StringRect &rect) const;
// does the vector of StringRects, each translated by cds, intersect the
// given StringRect.
bool doesRectIntersect(const std::vector<std::shared_ptr<StringRect>> &rects,
const Point2D &cds, const StringRect &rect) const;
bool doesLineIntersect(const std::string &label, OrientType orient,
const Point2D &cds, const Point2D &end1,
const Point2D &end2, double padding) const;
bool doesLineIntersect(const std::vector<std::shared_ptr<StringRect>> &rects,
const Point2D &cds, const Point2D &end1,
const Point2D &end2, double padding) const;
bool doesStringIntersect(
const std::vector<std::shared_ptr<StringRect>> &rects,
const Point2D &cds1, const std::string &label2, OrientType orient2,
const Point2D &cds2) const;
bool doesStringIntersect(const std::string &label1, OrientType orient1,
const Point2D &cds1, const std::string &label2,
OrientType orient2, const Point2D &cds2) const;
virtual void alignString(
TextAlignType align, const std::vector<TextDrawType> &draw_modes,
std::vector<std::shared_ptr<StringRect>> &rects) const;
// adjust the string rectangles up and down for super- and subscripts
void adjustStringRectsForSuperSubScript(
const std::vector<TextDrawType> &draw_modes,
std::vector<std::shared_ptr<StringRect>> &rects) const;
// return a scale factor appropriate for the character and draw type
// (normal or super- or subscript)
double selectScaleFactor(char c, TextDrawType draw_type) const;
// amount to scale subscripts and superscripts by
constexpr static double SUBS_SCALE = 0.66;
constexpr static double SUPER_SCALE = 0.66;
DrawColour colour_;
double font_scale_;
double max_font_size_;
double min_font_size_;
double base_font_size_ = DEFAULT_FONT_SCALE;
// return a vector of StringRects, one for each char in text, with
// super- and subscripts taken into account. Sizes in pixel coords,
// i.e. scaled by fontScale().
virtual void getStringRects(const std::string &text,
std::vector<std::shared_ptr<StringRect>> &rects,
std::vector<TextDrawType> &draw_modes,
std::vector<char> &draw_chars) const = 0;
void drawChars(const Point2D &a_cds,
const std::vector<std::shared_ptr<StringRect>> &rects,
const std::vector<TextDrawType> &draw_modes,
const std::vector<char> &draw_chars);
};
//! establishes whether to put string draw mode into super- or sub-script
//! mode based on contents of instring from i onwards. Increments i
//! appropriately
//! \returns true or false depending on whether it did something or not
RDKIT_MOLDRAW2D_EXPORT bool setStringDrawMode(const std::string &instring,
TextDrawType &draw_mode,
size_t &i);
// take the label for the given atom and return the individual pieces
// that need to be drawn for it. So NH<sub>2</sub> will return
// "N", "H<sub>2</sub>".
std::vector<std::string> atomLabelToPieces(const std::string &label,
OrientType orient);
} // namespace MolDraw2D_detail
} // namespace RDKit
#endif // RDKIT_DRAWTEXT_H
|