Files
rdkit/Code/GraphMol/MolDraw2D/DrawText.h
David Cosgrove f93016a77f Refactor mol draw2 d (#4948)
* MolDraw2D refactoring
- rename setupMoleculeDraw->initMoleculeDraw
- track whether or not initDrawing() has been called
- centralize calls to initDrawing() and clearDrawing() into initMoleculeDraw()
- update svg hashes in tests

* update some expected test results

* support changing font scale and default scale
add reaction test

* does not work... this is hard

* all tests pass

* do something about legends

* docs

* more tests

* more docs

* cleanup

* going around in circles...
hopefully converging

* cleanup

* Single bond skeleton works.

* Simple bond drawing seems to be working.

* Initial addition of atom symbols.

* Stash of not-quite-working atom symbols prior to major surgery.

* Atom symbols seem to be working.  Major surgery not required, just inverted Y coords at the outset.

* Add classes to atom labels.

* Renamed AtomLabel AtomSymbol.

* Add highlights.

* Fix bug from PR4839.

* Molecule note.

* Added atom notes.

* Added bond notes.

* Extract radicals.

* Annotation via new DrawAnnotation class.

* Add brackets.

* Add linknodes.

* Add close contacts.

* Add attachment points.  Fix wavy lines.

* Draw molecules in grid.

* Tidy.

* Fix radicals when font has hit maxFontSize.
Make getDrawCoords work.

* Draw primitives take atom or draw coords.

* Fix legends.

* More fixing for tests.  DrawMol::setScale now takes font scale as well.

* tidy debug writes

* Variable fraction of panel for legend.

* Better legend positioning.

* Fix sub- and super-script spacing.
Added spaces to Freetype strings.

* Basic reaction drawing.

* Reaction highlighting.

* Minor tweak to reacctions.

* Tweaked reaction DrawMol widths.

* Fix atomTags.

* Fix catch tests except contours.

* Contouring working in catch_tests.cpp.

* Fix catch tests.

* AtomSymbol and DrawAnnotation into MolDraw2D_detail.

* DrawMol and DrawShape into MolDraw2D_detail.

* DrawText inot MolDraw2D_detail.

* Machete out.

* DrawText goes private.

* Move some stuff about, such as StringRect to its own header.

* Python wrapper compiles (but crashes when Draw imported).

* More tidying.  Python DrawArrow failing.

* Linux changes.

* Fixed error in DrawShapeArrow spotted by valgrind.
Fixed some warnings from gcc.

* Maybe fixed DrawArrow.

* Added basic argparse interface.

* Added newlines.

* Changes in response to review.
Non-const args in move constructors and operator=.
Added missing classes to MolDraw2D_detail.
Deleted move operator= where it had been forgotten.
Fixed copyright dates.

* Deleted all default c'tors in derived classes.

* Changes in response to review:
Wedge widths now a proportion of mean bond length in draw coords..
Add padding below legend when positioning it.

* Fix tests.

* Fix the private/protected mess of the new classes.

* Moved doesLineIntersect etc.

* Reinstate original alignString for non-FT drawings.

* More faffing about with reaction layouts.

* Fix font sizes in testGitHub3391.

* Fix atom notes fitting inside fat wedges.

* Fix molecule annotation font size.

* More fixes of rectangle/triangle collision detection.

* Test for highlight linewidth multiplier.

* Use push_back not emplace_back.

* Attempt at better Freetype char spacing.

* Option to turn off TEST_ASSERT. Currently off.

* Fixed embarrassing maths to do with wedge fatness.

* More tidying post-review.

* Document highlight_linewidth_multipliers.

* Expose baseFontSize to Python.

* Changes in response to review.

* Allow DrawMolecules molecules to be drawn to different scales.

* Fix bond sneaking between C:8 in, for example, reactions.

* Fix bad re-factoring.

* Fix globbing.

* Changes in response to review.

* Add invariant check.

* Add draw option to fix font size.

* suggested changes

* Update catch test results.

* Fix expected freetype results.

* Fix non-freetype drawers.

* Fin non-freetype test results.

* get the Qt drawer working too

* Fix disappearing reaction highlights.

* Changes as result of review.

* Fixed non-FreeType hash codes for reaction SVGs.  Extra comment in catch_tests.

* reactant highlighting was clearning properties

* Fix for failing contour python test.

* fix a non-freetype problem

* swig wrappers working

* Bump timeouts in test.

Co-authored-by: greg landrum <greg.landrum@gmail.com>
Co-authored-by: David Cosgrove <david@cozchemix.co.uk>
2022-02-18 16:30:21 +01:00

207 lines
8.8 KiB
C++

//
// 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