Files
rdkit/Code/GraphMol/MolDraw2D/DrawShape.h
David Cosgrove f00735a310 Fix arrowhead8500 (#8504)
* Fix the arrow heads.

* Tidy.

* Looser tolerance on test.

---------

Co-authored-by: David Cosgrove <david@cozchemix.co.uk>
2025-05-08 06:48:54 +02:00

259 lines
10 KiB
C++

//
// 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)
//
// A set of shapes used in 2D drawing.d Not part of the public API.
#ifndef RDKIT_DRAWSHAPE_H
#define RDKIT_DRAWSHAPE_H
#include <vector>
#include <Geometry/point.h>
#include <GraphMol/MolDraw2D/MolDraw2DHelpers.h>
namespace RDKit {
class MolDraw2D;
const DashPattern noDash;
const DashPattern dots{2.0, 6.0};
const DashPattern dashes{6.0, 4.0};
const DashPattern shortDashes{2.0, 2.0};
namespace MolDraw2D_detail {
struct StringRect;
class DrawShape {
public:
DrawShape(const std::vector<Point2D> &points, double lineWidth = 2.0,
bool scaleLineWidth = false,
DrawColour lineColour = DrawColour(0, 0, 0), bool fill = false,
int atom1 = -1, int atom2 = -1, int bond = -1);
DrawShape(const DrawShape &) = delete;
DrawShape(DrawShape &&) = delete;
virtual ~DrawShape() = default;
DrawShape &operator=(const DrawShape &) = delete;
DrawShape &operator=(DrawShape &&) = delete;
void draw(MolDraw2D &drawer);
virtual void myDraw(MolDraw2D &drawer) const = 0;
virtual void findExtremes(double &xmin, double &xmax, double &ymin,
double &ymax) const;
virtual void scale(const Point2D &scale_factor);
virtual void move(const Point2D &trans);
virtual bool doesRectClash(const StringRect &rect, double padding) const;
std::vector<Point2D> points_;
double lineWidth_;
bool scaleLineWidth_;
DrawColour lineColour_;
bool fill_;
int atom1_, atom2_, bond_;
};
class DrawShapeArrow : public DrawShape {
public:
DrawShapeArrow(const std::vector<Point2D> &points, double lineWidth = 2.0,
bool scaleLineWidth = false,
DrawColour lineColour = DrawColour(0, 0, 0), bool fill = false,
int atom1 = -1, int atom2 = -1, int bond = -1,
double frac = 0.2, double angle = M_PI / 6);
DrawShapeArrow(const DrawShapeArrow &) = delete;
DrawShapeArrow(DrawShapeArrow &&) = delete;
~DrawShapeArrow() override = default;
DrawShapeArrow &operator=(const DrawShapeArrow &) = delete;
DrawShapeArrow &operator=(DrawShapeArrow &&) = delete;
void myDraw(MolDraw2D &drawer) const override;
void findExtremes(double &xmin, double &xmax, double &ymin,
double &ymax) const override;
void scale(const Point2D &scale_factor) override;
void move(const Point2D &trans) override;
bool doesRectClash(const StringRect &rect, double padding) const override;
double frac_;
double angle_;
Point2D origPts_[4]{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}};
};
class DrawShapeEllipse : public DrawShape {
public:
// Points should be size 2 - the first entry is the centre, the second
// gives the x and y radii of the ellipse.
DrawShapeEllipse(const std::vector<Point2D> &points, double lineWidth = 2,
bool scaleLineWidth = false,
DrawColour lineColour = DrawColour(0, 0, 0),
bool fill = false, int atom1 = -1);
DrawShapeEllipse(const DrawShapeEllipse &) = delete;
DrawShapeEllipse(DrawShapeEllipse &&) = delete;
~DrawShapeEllipse() override = default;
DrawShapeEllipse &operator=(const DrawShapeEllipse &) = delete;
DrawShapeEllipse &operator=(DrawShapeEllipse &&) = delete;
void myDraw(MolDraw2D &drawer) const override;
void findExtremes(double &xmin, double &xmax, double &ymin,
double &ymax) const override;
void move(const Point2D &trans) override;
bool doesRectClash(const StringRect &rect, double padding) const override;
};
class DrawShapeSimpleLine : public DrawShape {
public:
DrawShapeSimpleLine(const std::vector<Point2D> &points,
double lineWidth = 2.0, bool scaleLineWidth = false,
DrawColour lineColour = DrawColour(0, 0, 0),
int atom1 = -1, int atom2 = -1, int bond = -1,
DashPattern dashPattern = noDash);
DrawShapeSimpleLine(const DrawShapeSimpleLine &) = delete;
DrawShapeSimpleLine(DrawShapeSimpleLine &&) = delete;
~DrawShapeSimpleLine() override = default;
DrawShapeSimpleLine &operator=(const DrawShapeSimpleLine &) = delete;
DrawShapeSimpleLine &operator=(DrawShapeSimpleLine &&) = delete;
void myDraw(MolDraw2D &drawer) const override;
bool doesRectClash(const StringRect &rect, double padding) const override;
DashPattern dashPattern_;
};
class DrawShapePolyLine : public DrawShape {
public:
DrawShapePolyLine(const std::vector<Point2D> &points, double lineWidth = 2.0,
bool scaleLineWidth = false,
DrawColour lineColour = DrawColour(0, 0, 0),
bool fill = false, int atom1 = -1, int atom2 = -1,
int bond = -1, DashPattern dashPattern = noDash);
DrawShapePolyLine(const DrawShapePolyLine &) = delete;
DrawShapePolyLine(DrawShapePolyLine &&) = delete;
~DrawShapePolyLine() override = default;
DrawShapePolyLine &operator=(const DrawShapePolyLine &) = delete;
DrawShapePolyLine &operator=(DrawShapePolyLine &&) = delete;
void myDraw(MolDraw2D &drawer) const override;
bool doesRectClash(const StringRect &rect, double padding) const override;
DashPattern dashPattern_;
};
class DrawShapeSolidWedge : public DrawShape {
public:
DrawShapeSolidWedge(const std::vector<Point2D> points, const DrawColour &col1,
const DrawColour &col2, bool splitBonds,
std::vector<Point2D> &otherBondVecs,
double lineWidth = 1.0, int atom1 = -1, int atom2 = -1,
int bond = -1);
DrawShapeSolidWedge(const DrawShapeSolidWedge &) = delete;
DrawShapeSolidWedge(DrawShapeSolidWedge &&) = delete;
~DrawShapeSolidWedge() override = default;
DrawShapeSolidWedge &operator=(const DrawShapeSolidWedge &) = delete;
DrawShapeSolidWedge &operator=(DrawShapeSolidWedge &&) = delete;
void buildTriangles();
void buildSingleColorTriangles();
void buildTwoColorTriangles();
void myDraw(MolDraw2D &drawer) const override;
bool doesRectClash(const StringRect &rect, double padding) const override;
// if otherBondVecs_.size() > 2, then we only want the two vecs with the
// widest angle between them.
void trimOtherBondVecs();
// if there are 2 otherBondVecs_ (assuming we've already trimmed down to 2 if
// necessary) make sure the first is on the points_[1] side, the second on
// the points_[2] side, so that the merging of the triangles to the bond
// lines is correct.
void orderOtherBondVecs();
DrawColour col2_;
bool splitBonds_;
std::vector<Point2D> otherBondVecs_;
};
class DrawShapeDashedWedge : public DrawShape {
public:
// oneLessDash means that the last dash at the fat end of the wedge
// isn't drawn. The wedge will be as fat as it would have been with
// the extra dash. This is so that bonds coming out of the fat end
// of the wedge aren't directly incident on a dash.
DrawShapeDashedWedge(const std::vector<Point2D> points,
const DrawColour &col1, const DrawColour &col2,
bool oneLessDash = true, double lineWidth = 1.0,
int atom1 = -1, int atom2 = -1, int bond = -1);
DrawShapeDashedWedge(const DrawShapeDashedWedge &) = delete;
DrawShapeDashedWedge(DrawShapeDashedWedge &&) = delete;
~DrawShapeDashedWedge() override = default;
DrawShapeDashedWedge &operator=(const DrawShapeDashedWedge &) = delete;
DrawShapeDashedWedge &operator=(DrawShapeDashedWedge &&) = delete;
void buildLines();
void myDraw(MolDraw2D &drawer) const override;
void scale(const Point2D &scale_factor) override;
void move(const Point2D &trans) override;
void findExtremes(double &xmin, double &xmax, double &ymin,
double &ymax) const override;
bool doesRectClash(const StringRect &rect, double padding) const override;
DrawColour col2_;
bool oneLessDash_;
std::vector<DrawColour> lineColours_;
// for when we re-create the lines, such as after scaling, this is
// the initial points[0-2] from the c'tor.
Point2D at1Cds_, end1Cds_, end2Cds_;
};
class DrawShapeWavyLine : public DrawShape {
public:
DrawShapeWavyLine(const std::vector<Point2D> points, double lineWidth = 2.0,
bool scaleLineWidth = false,
const DrawColour &col1 = DrawColour(0, 0, 0),
const DrawColour &col2 = DrawColour(0, 0, 0),
double offset = 0.05, int atom1 = -1, int atom2 = -1,
int bond = -1);
DrawShapeWavyLine(const DrawShapeWavyLine &) = delete;
DrawShapeWavyLine(DrawShapeWavyLine &&) = delete;
~DrawShapeWavyLine() override = default;
DrawShapeWavyLine &operator=(const DrawShapeWavyLine &) = delete;
DrawShapeWavyLine &operator=(DrawShapeWavyLine &&) = delete;
void myDraw(MolDraw2D &drawer) const override;
void scale(const Point2D &scaleFactor) override;
bool doesRectClash(const StringRect &rect, double padding) const override;
DrawColour col2_;
double offset_;
};
class DrawShapeArc : public DrawShape {
public:
// draw the arc of an ellipse between ang1 and ang2. Note that 0 is
// at 3 o-clock and 90 at 12 o'clock as you'd expect from your maths.
// BUT because y increases down the screen, the angles go anticlockwise, such
// that 90 is actually at 6 o'clock on the screen.
// ang2 must be > ang1 - it won't draw backwards. Angles in degrees,
// between 0 and 360.0.
// Points should be size 2 - the first entry is the centre, the second
// gives the x and y radii of the ellipse.
DrawShapeArc(const std::vector<Point2D> points, double ang1, double ang2,
double lineWidth = 2.0, bool scaleLineWidth = false,
const DrawColour &col1 = DrawColour(0, 0, 0), bool fill = false,
int atom1 = -1);
DrawShapeArc(const DrawShapeArc &) = delete;
DrawShapeArc(DrawShapeArc &&) = delete;
~DrawShapeArc() override = default;
DrawShapeArc &operator=(const DrawShapeArc &) = delete;
DrawShapeArc &operator=(DrawShapeArc &&) = delete;
void myDraw(MolDraw2D &drawer) const override;
void findExtremes(double &xmin, double &xmax, double &ymin,
double &ymax) const override;
void move(const Point2D &trans) override;
bool doesRectClash(const StringRect &rect, double padding) const override;
double ang1_, ang2_;
};
} // namespace MolDraw2D_detail
} // namespace RDKit
#endif // RDKIT_DRAWSHAPE_H