Files
rdkit/Code/GraphMol/Depictor/DepictUtils.h
Nic Zonta b854399558 Spiro flipping (#9204)
* add flipping of spiro rings as a way to solve clashes

* remove extra function

* add test file

* update coordgen parameters to allow for bond flipping

* fix failing tests

* Update Code/GraphMol/Depictor/EmbeddedFrag.h

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* Update Code/GraphMol/Depictor/EmbeddedFrag.cpp

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* Update Code/GraphMol/Depictor/EmbeddedFrag.cpp

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* Update Code/GraphMol/Depictor/EmbeddedFrag.cpp

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* [bot] Update molecular templates header (#9234)

Co-authored-by: github-actions[bot] <github-actions[bot]@noreply.github.com>

* Add some std::ranges support (#9218)

* initial ranges support for Atom/Bond iterators.
needs more testing

* support random access
test sort

more testing please

* compiles on windows

* fix size()
more testing
add some benchmarking

* disable benchmarking code by default

* do not allow modifying the graph through the iterators

---------

Co-authored-by: = <=>

* mention AI tools in the contrib guidelines (#9224)

* mention AI tools in the contrib guidelines

* response to review

---------

Co-authored-by: = <=>

* Add getSGroupDataLabels() to MolDraw2D_detail namespace (#9189)

Adds a new function MolDraw2D_detail::getSGroupDataLabels() that returns
the text and molecule-coordinate positions of DAT SGroup labels, using
the same placement logic as the drawing code. This allows external
renderers to display SGroup labels consistently with RDKit's placement.

Refactors DrawMol::extractSGroupData() to call getSGroupDataLabels()
internally, eliminating the duplicate FIELDDISP parsing and position
computation logic.

Closes #7829

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* MolDraw2D: configurable legend position and vertical side legends (Issue #9023) (#9183)

* Configurable legend position (Top/Left/Right/Bottom) and vertical text (GitHub #9023)

- Add LegendPosition enum and legendPosition, legendVerticalText to MolDrawOptions
- Support legend at Top, Left, Right, Bottom; vertical text for Left/Right
- Python: MolDrawOptions.legendPosition, .legendVerticalText; LegendPosition enum
- Python: MolToSVG() wrapper with legend/drawOptions; doc updates for MolToImage
- JSON: legendPosition (string), legendVerticalText (bool) in draw options
- C++ and Python tests; release note and Cartridge.md docs

* MolDraw2D: legend gutter for horizontal side legends; vertical side height fit

- Reserve horizontal gap between molecule and left/right horizontal legends
  (scale mol to molWidth-gutter, align toward legend strip).
- Position horizontal side legend by measured text width from partition edge.
- Vertical side legends: iterative scale so n*max_h+(n-1)*gap fits panel.
- Catch: long vertical side legend section.

* Update legend-position tests and review-driven cleanup

Use enum/default wording for legendPosition docs, move the lightweight Python test to Wrap, add regex-based placement checks (including horizontal side and vertical stacking), and refactor extractLegend helpers per style guidance.

* Fix MolDraw2D legend edge cases

* MolDraw2D: review follow-up (legend tests, bounds, DRY Top/Bottom)

* Update no-FT legend test coords

* Address PR review: document constants, remove release-note text, and simplify extra-padding logic

* make sorting more consistent (#9239)

* Cleanup/get atoms and bonds (#9243)

* Fix bug in inversion term for UFF, add finite difference checker. (#9228)

* Fix copyright

* Address review comments

Removed finite diff from RDKit headers

Used explicit coordinates

* If templates match, skip ring number check (#9217)

* remove ring mathcing for templates

* remove extra code

* remove empty lines

* fix build error

* Tautomer insensitive hash v2, E/Z and stereocenter-preservation (#9128)

* Tautomer insensitive hash v2, E/Z and stereocenter-preservation

* Preserve E/Z stereochemistry and stereocenters in TautomerHashv2

Simplify extension logic to better protect stereocenters connected via
single bonds to aromatic systems. Preserve E/Z stereo on exocyclic
double bonds to distinguish geometric isomers (e.g., E/Z hydrazones).

* add helper function to remove duplicated code

* Fix ring info and bond aromaticity handling in MolHash

- Add fastFindRings check in TautomerHashv2 before ring queries
- Set isAromatic consistent with bond type (true for AROMATIC bonds)
- Fix inverted condition in RegioisomerHash

* more consistent hashes regardless of stereo annotation

* Ensure that StereoGroups don't have duplicate atoms or bonds (#9258)

* check for duplicate atoms/bonds in StereoGroups

* explicit handling of duplicate stereogroup atoms in CTAB and CXSMILES parsers

---------

Co-authored-by: = <=>

* Add Getter functions to MMFF property python interface (#9254)

* Support using iterators with MolSuppliers (#9230)

* iterators for random-access MolSuppliers
add optional caching to SDMolSupplier

* add support to SmilesMolSupplier too
There is a lot of duplicate code between the random-access suppliers that would be worth trying to remove
but at the moment it looks like it would require multiple inheritance, and I think we want to avoid that

* add input iterators for ForwardSDMolSupplier()

* throw when calling begin() on a used supplier

* switch to use the spaceship operator

* init() should reset the mol cache

* Make SDMolSupplier and SmilesMolSupplier safe for multi-threaded reads

* add benchmarking

* add TDTMolSupplier support
improved testing
add benchmarks for parallel iteration
optional TBB support

* better const handling, add reverse iterators

doesn't look like const_iterator is possible since getting data from the underlyng supplier object is non-const

* improve docs
more usings
add reverse iterator to TDTMolSupplier

* tests only try execution::par when it is there

* fix typo

* more testing/demo

* remove accidentally added files

* review changes

* add default ctors

* disable a false-positive compiler warning
it is stupid to have to do this

---------

Co-authored-by: = <=>

* Pandastools improvements (#9251)

* Added automatic parsing functionality

* Added documentation

* Slightly changed check for gzip extension

* Apply suggestions from code review

Added small changes for readability

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

---------

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* Add optional default_val parameter to GetProp()  (#9242)

* SHARED-12256: Add test and change function.

* SHARED-12256: Update to only wrapping changes.

* SHARED-12256: Parameterize tests.

* SHARED-12256: GetPropIfPresent changes.

* Revert "SHARED-12256: GetPropIfPresent changes."

This reverts commit f598f8c161.

* SHARED-12256: Make default the keyword in the boost wrappings.

* SHARED-12256: Overload function instead of using a sentinel.

* SHARED-12256: Extend GetProp changes.

* SHARED-12256: Add entry point for tests and fix tests.

* Extended fix for #9101 (#9255)

* fix extended boundary issue (3 mols)

* clang pass

* no change. retrigger CI for failed java test

there's a failing java test that seems to be failing by chance rather than by changes, as it depends on rng. this is just to retrigger the CI pipeline to confirm this

* no change. retrigger the CI (yet again)

* raw strings and removed garbage collector

* CIP labeller performance: Don't calculate auxiliary descriptors unnecessarily (#9171)

* CIP labeller: Don't calculate auxiliary descriptors unnecessarily

The first 3 rules (the constitutional rules) are pretty easy
to understand. After rule 3, we need to calculate auxiliary
stereo descriptors to break ties.

However, we _were actually_ calculating auxiliary stereodescriptors
for all centers! We should only need to calculate auxiliary
stereocenters for sites that are needed to break ties.

This cost time - it also caused errors if the auxiliary descriptors
needed a graph expansion, because bonds in the digraph might be
pointed in the wrong direction.

Example case PDB ID 4AXM
Before this commit, errored with "Could not calculate parity! Carrier mismatch"
after 14s. After this commit, completes successfully in 0.036s.
Labelled centers all match (for the centers that had labels in
the failure case).

Includes a test that I can imagine breaking with this optimization.
The reference labels are from before this change

* Ensure all "arms" of stereo bonds and atropisomer bonds are expanded

For tetrahedral centers, ranking using the constitutional rules
always expands as far as is needed (but no further). For SP2bond
and atropisomers, if the first side is not resolvable, the
second side is never visited.

If the constitutional rules don't resolve a side, we need to
label the auxiliary centers. It's important to label all
auxiliary centers that _will_ be visited, so we need to know
what centers will be visited.

This commit updates the label() call in SP2 and Atropisomer
bonds to always attempt to label both sides if using the
constitutional rule set.

The constitutional rules are cheap, and if they fail, we
always go on to the full rule set. It is not a savings to skip
the search on the second side if we're going to keep going
anyway!

Includes a test that reproduces Ricardo's example.

This has no measurable effect on performance relative to the
original solution

* If any parts of the center have been seen, label it.

I couldn't make an example hit this, but Ric is totally
theoretically right

* Greg's ranges suggestion #2

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* any_of for container search

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

---------

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* CIPLabeler performance: Store vector of bonds (#9250)

* CIPLabeler performance: Store vector of bonds

CIPLabelling refers to bonds by index over and over again. This
causes a measurable hit in performance in findConfigs() because
we iterate over a bitset of "allowed" bonds. For very large
molecules with many bonds, this can be a rate-limiting step!

This affects many PDB-sized structures.

2J3N goes from 0.7s to 0.25s with this change.

I had another example for which the findBondWithIdx() call was
taking 500ms of a 700ms call (after the performance update
in #9171 was implemented)

* yikes, XXL reserve

thanks, greg

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

---------

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>

* Address PR #9204 review feedback

Implemented performance improvements suggested by @greglandrum:

1. Move cheap degree check to start of isSpiroCenter()
   - Early bailout eliminates ~95% of candidates immediately

2. Replace std::set with boost::dynamic_bitset<>
   - Faster set operations for ring membership tests
   - More efficient intersection using bitwise AND

3. Remove expensive PRECONDITION in flipAboutSpiroCenter()
   - Caller already validates spiro center, no need to check again

All tests pass (testDepictor: 7.85s).

* Use boost::dynamic_bitset in removeCollisionsBondAndSpiroFlip

Replaced std::set<unsigned int> with boost::dynamic_bitset<> for
spiro center caching in collision resolution:

- Changed spiroCenters from std::set to boost::dynamic_bitset
- Updated tryResolvingCollisionWithSpiroFlip() signature
- Replaced set.find() with bitset.test() for membership checks
- Replaced set.insert() with bitset.set() for marking spiro centers

Benefits:
- Faster membership tests (O(1) bit test vs O(log n) tree lookup)
- Better cache locality (contiguous bit array vs scattered nodes)
- Simpler code (no iterator comparisons)

All tests pass (testDepictor: 2.64s).

* remove unnecessary reformatting

* more unneeded formatting

* even more unecessary formatting

---------

Co-authored-by: Greg Landrum <greg.landrum@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@noreply.github.com>
Co-authored-by: Chris Von Bargen <christopher.vonbargen@schrodinger.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Brandon Novy <142041993+Brandon-Cole@users.noreply.github.com>
Co-authored-by: Ricardo Rodriguez <ricrogz@users.noreply.github.com>
Co-authored-by: Kevin Boyd <kboyd@nvidia.com>
Co-authored-by: Eloy Félix <eloyfelix@gmail.com>
Co-authored-by: Marco Ballarotto <marco.ballarotto@icr.ac.uk>
Co-authored-by: Emily Rhodes <70823163+emilyrrhodes@users.noreply.github.com>
Co-authored-by: Raul Sofia <67133355+RaulSofia@users.noreply.github.com>
Co-authored-by: Dan Nealschneider <dan.nealschneider@schrodinger.com>
2026-06-03 05:56:04 +02:00

414 lines
14 KiB
C++

//
// Copyright (C) 2003-2022 Greg Landrum 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.
//
#include <RDGeneral/export.h>
#ifndef RD_DEPICT_UTILS_H
#define RD_DEPICT_UTILS_H
// REVIEW: remove extra headers here
#include <RDGeneral/types.h>
#include <GraphMol/RDKitBase.h>
#include <GraphMol/RWMol.h>
#include <GraphMol/ROMol.h>
#include <GraphMol/Substruct/SubstructUtils.h>
#include <Geometry/Transform2D.h>
#include <Geometry/Transform3D.h>
#include <Geometry/point.h>
#include <queue>
namespace RDDepict {
RDKIT_DEPICTOR_EXPORT extern double BOND_LEN;
RDKIT_DEPICTOR_EXPORT extern double COLLISION_THRES;
RDKIT_DEPICTOR_EXPORT extern double BOND_THRES;
RDKIT_DEPICTOR_EXPORT extern double ANGLE_OPEN;
RDKIT_DEPICTOR_EXPORT extern unsigned int MAX_COLL_ITERS;
RDKIT_DEPICTOR_EXPORT extern double HETEROATOM_COLL_SCALE;
RDKIT_DEPICTOR_EXPORT extern unsigned int NUM_BONDS_FLIPS;
typedef std::vector<const RDGeom::Point2D *> VECT_C_POINT;
typedef std::pair<int, int> PAIR_I_I;
typedef std::vector<PAIR_I_I> VECT_PII;
struct RDKIT_DEPICTOR_EXPORT gtIIPair {
bool operator()(const PAIR_I_I &pd1, const PAIR_I_I &pd2) const {
return pd1.first > pd2.first;
}
};
typedef std::priority_queue<PAIR_I_I, VECT_PII, gtIIPair> PR_QUEUE;
typedef std::pair<double, PAIR_I_I> PAIR_D_I_I;
typedef std::list<PAIR_D_I_I> LIST_PAIR_DII;
//! Some utility functions used in generating 2D coordinates
//! Embed a ring as a convex polygon in 2D
/*!
The process here is very straightforward:
We take the center of the ring to lie at the origin, so put the first
point at the origin and then sweep
anti-clockwise by an angle A = 360/n for the next point.
The length of the arm (l) we want to sweep is easy to compute given the
bond length (b) we want to use for each bond in the ring (for now
we will assume that this bond legnth is the same for all bonds in the ring:
l = b/sqrt(2*(1 - cos(A))
the above formula derives from the triangle formula, where side 'c' is given
in terms of sides 'a' and 'b' as:
c = a^2 + b^2 - 2.a.b.cos(A)
where A is the angle between a and b
*/
RDKIT_DEPICTOR_EXPORT RDGeom::INT_POINT2D_MAP embedRing(
const RDKit::INT_VECT &ring);
RDKIT_DEPICTOR_EXPORT void transformPoints(RDGeom::INT_POINT2D_MAP &nringCor,
const RDGeom::Transform2D &trans);
//! Find a point that bisects the angle at rcr
/*!
The new point lies between nb1 and nb2. The line (rcr, newPt) bisects the
angle 'ang' at rcr
*/
RDKIT_DEPICTOR_EXPORT RDGeom::Point2D computeBisectPoint(
const RDGeom::Point2D &rcr, double ang, const RDGeom::Point2D &nb1,
const RDGeom::Point2D &nb2);
//! Reflect a set of point through the line joining two point
/*!
ARGUMENTS:
\param coordMap a map of <int, point2D> going from atom id to current
coordinates of the points that need to be reflected:
The coordinates are overwritten
\param loc1 the first point of the line that is to be used as a
mirror
\param loc2 the second point of the line to be used as a mirror
*/
RDKIT_DEPICTOR_EXPORT void reflectPoints(RDGeom::INT_POINT2D_MAP &coordMap,
const RDGeom::Point2D &loc1,
const RDGeom::Point2D &loc2);
RDKIT_DEPICTOR_EXPORT RDGeom::Point2D reflectPoint(const RDGeom::Point2D &point,
const RDGeom::Point2D &loc1,
const RDGeom::Point2D &loc2);
//! Set the neighbors yet to added to aid such that the atoms with the most subs
/// fall on opposite sides
/*!
Ok this needs some explanation
- Let A, B, C, D be the substituent on the central atom X (given
by atom index aid)
- also let A be the atom that is already embedded
- Now we want the order in which the remaining neighbors B,C,D are
added to X such that the atoms with atom with largest number of
substituent fall on opposite sides of X so as to minimize atom
clashes later in the depiction
E.g. let say we have the following situation
<pre>
B
| |
A--X--C
| |
--D--
|
</pre>
In this case the number substituent of A, B, C, D are 3, 1, 1,
4 respectively so want to A and D to go opposite sides and so that
we draw
<pre>
B
| | |
A--X--D--
| | |
C
</pre>
And the correct ordering of the neighbors is B,D,C
*/
RDKIT_DEPICTOR_EXPORT RDKit::INT_VECT setNbrOrder(unsigned int aid,
const RDKit::INT_VECT &nbrs,
const RDKit::ROMol &mol);
//! \brief From a given set of fused rings find the "core" rings, i.e. the rings
//! that are left after iteratively removing rings that are fused with only one
//! other ring by one or two atoms
/*
\param fusedRings list of all the rings in the fused system
\param coreRingsIds this is where the IDs of the core rings are written
\param mol the molecule of interest
\return list of rings that represent the core
*/
RDKIT_DEPICTOR_EXPORT RDKit::VECT_INT_VECT findCoreRings(
const RDKit::VECT_INT_VECT &fusedRings, RDKit::INT_VECT &coreRingsIds,
const RDKit::ROMol &mol);
//! \brief From a given set of rings find the ring the largest common elements
/// with other rings
/*
Bit of a weird function - this is typically called once we have embedded some
of the rings in a fused system and we are looking for the ring that must be
embedded (or merged) next. The heuristic used here is to pick the rings with
the maximum number of atoms in common with the rings that are already
embedded.
\param doneRings a vector of ring IDs that have been embedded already
\param fusedRings list of all the rings in the fused system \param nextId
this is where the ID for the next ring is written
\return list of atom ids that are common
*/
RDKIT_DEPICTOR_EXPORT RDKit::INT_VECT findNextRingToEmbed(
const RDKit::INT_VECT &doneRings, const RDKit::VECT_INT_VECT &fusedRings,
int &nextId);
typedef std::pair<int, int> INT_PAIR;
typedef std::vector<INT_PAIR> INT_PAIR_VECT;
typedef INT_PAIR_VECT::const_iterator INT_PAIR_VECT_CI;
typedef std::pair<double, INT_PAIR> DOUBLE_INT_PAIR;
//! Sort a list of atoms by their CIP rank
/*!
\param mol molecule of interest
\param commAtms atoms that need to be ranked
\param ascending sort to an ascending order or a descending order
*/
template <class T>
RDKIT_DEPICTOR_EXPORT T rankAtomsByRank(const RDKit::ROMol &mol,
const T &commAtms,
bool ascending = true);
//! computes a subangle for an atom of given hybridization and degree
/*!
\param degree the degree of the atom (number of neighbors)
\param htype the atom's hybridization
\return the subangle (in radians)
*/
inline double computeSubAngle(unsigned int degree,
RDKit::Atom::HybridizationType htype) {
double angle = M_PI;
switch (htype) {
case RDKit::Atom::UNSPECIFIED:
case RDKit::Atom::SP3:
if (degree == 4) {
angle = M_PI / 2;
} else {
angle = 2 * M_PI / 3;
}
break;
case RDKit::Atom::SP2:
angle = 2 * M_PI / 3;
break;
default:
angle = 2. * M_PI / degree;
}
return angle;
}
//! computes the rotation direction between two vectors
/*!
Let:
v1 = loc1 - center
v2 = loc2 - center
If remaining angle(v1, v2) is < 180 and corss(v1, v2) > 0.0 then the rotation
dir is +1.0
else if remAngle(v1, v2) is > 180 and cross(v1, v2) < 0.0 then rotation dir is
-1.0
else if remAngle(v1, v2) is < 180 and cross(v1, v2) < 0.0 then rotation dir is
-1.0
finally if remAngle(v1, v2) is > 180 and cross(v1, v2) < 0.0 then rotation dir
is +1.0
\param center the common point
\param loc1 endpoint 1
\param loc2 endpoint 2
\param remAngle the remaining angle about center in radians
\return the rotation direction (1 or -1)
*/
inline int rotationDir(const RDGeom::Point2D &center,
const RDGeom::Point2D &loc1, const RDGeom::Point2D &loc2,
double remAngle) {
auto pt1 = loc1 - center;
auto pt2 = loc2 - center;
auto cross = pt1.x * pt2.y - pt1.y * pt2.x;
auto diffAngle = M_PI - remAngle;
cross *= diffAngle;
if (cross >= 0.0) {
return -1;
} else {
return 1;
}
}
//! computes and return the normal of a vector between two points
/*!
\param center the common point
\param other the endpoint
\return the normal
*/
inline RDGeom::Point2D computeNormal(const RDGeom::Point2D &center,
const RDGeom::Point2D &other) {
auto res = other - center;
res.normalize();
std::swap(res.x, res.y);
res.x *= -1;
return res;
}
//! computes the rotation angle between two vectors
/*!
\param center the common point
\param loc1 endpoint 1
\param loc2 endpoint 2
\return the angle (in radians)
*/
inline double computeAngle(const RDGeom::Point2D &center,
const RDGeom::Point2D &loc1,
const RDGeom::Point2D &loc2) {
auto v1 = loc1 - center;
auto v2 = loc2 - center;
return v1.angleTo(v2);
}
//! \brief pick the ring to embed first in a fused system
/*!
\param mol the molecule of interest
\param fusedRings the collection of the molecule's fused rings
\return the index of the ring with the least number of substitutions
*/
RDKIT_DEPICTOR_EXPORT int pickFirstRingToEmbed(
const RDKit::ROMol &mol, const RDKit::VECT_INT_VECT &fusedRings);
//! \brief find the rotatable bonds on the shortest path between two atoms
//! we will ignore ring atoms, and double bonds which are marked cis/trans
/*!
<b>Note</b> that rotatable in this context doesn't connect to the
standard chemical definition of a rotatable bond; we're just talking
about bonds than can be flipped in order to clean up the depiction.
\param mol the molecule of interest
\param aid1 index of the first atom
\param aid2 index of the second atom
\return a set of the indices of the rotatable bonds
*/
RDKIT_DEPICTOR_EXPORT RDKit::INT_VECT getRotatableBonds(const RDKit::ROMol &mol,
unsigned int aid1,
unsigned int aid2);
//! \brief find all the rotatable bonds in a molecule
//! we will ignore ring atoms, and double bonds which are marked cis/trans
/*!
<b>Note</b> that rotatable in this context doesn't connect to the
standard chemical definition of a rotatable bond; we're just talking
about bonds than can be flipped in order to clean up the depiction.
\param mol the molecule of interest
\return a set of the indices of the rotatable bonds
*/
RDKIT_DEPICTOR_EXPORT RDKit::INT_VECT getAllRotatableBonds(
const RDKit::ROMol &mol);
//! \brief check if an atom is a spiro center (belongs to exactly 2 rings)
/*!
\param aid index of the atom
\param mol the molecule of interest
\return true if the atom is a spiro center
*/
RDKIT_DEPICTOR_EXPORT bool isSpiroCenter(unsigned int aid,
const RDKit::ROMol *mol);
//! \brief find spiro centers on the shortest path between two atoms
/*!
\param mol the molecule of interest
\param aid1 index of the first atom
\param aid2 index of the second atom
\return a set of the indices of spiro centers
*/
RDKIT_DEPICTOR_EXPORT RDKit::INT_VECT getSpiroCenters(
const RDKit::ROMol &mol, unsigned int aid1, unsigned int aid2);
//! Get the ids of the atoms and bonds that are connected to aid
RDKIT_DEPICTOR_EXPORT void getNbrAtomAndBondIds(unsigned int aid,
const RDKit::ROMol *mol,
RDKit::INT_VECT &aids,
RDKit::INT_VECT &bids);
//! Find pairs of bonds that can be permuted at a non-ring degree 4 atom
/*!
This function will return only those pairs that cannot be
permuted by flipping a rotatble bond
D
|
b3
|
A-b1-B-b2-C
|
b4
|
E
For example in the above situation on the pairs (b1, b3) and (b1, b4) will be
returned
// All other permutations can be achieved via a rotatable bond flip.
ARGUMENTS:
\param center - location of the central atom
\param nbrBids - a vector (of length 4) containing the ids of the bonds to
the neighbors
\param nbrLocs - locations of the neighbors
*/
RDKIT_DEPICTOR_EXPORT INT_PAIR_VECT findBondsPairsToPermuteDeg4(
const RDGeom::Point2D &center, const RDKit::INT_VECT &nbrBids,
const VECT_C_POINT &nbrLocs);
//! returns the rank of the atom for determining draw order
inline int getAtomDepictRank(const RDKit::Atom *at) {
const int maxAtNum = 1000;
const int maxDeg = 100;
int anum = at->getAtomicNum();
anum = anum == 1 ? maxAtNum : anum; // favor non-hydrogen atoms
int deg = at->getDegree();
return maxDeg * anum + deg;
}
RDKIT_DEPICTOR_EXPORT bool hasTerminalRGroupOrQueryHydrogen(
const RDKit::ROMol &query);
RDKIT_DEPICTOR_EXPORT std::unique_ptr<RDKit::RWMol> prepareTemplateForRGroups(
RDKit::RWMol &templateMol);
RDKIT_DEPICTOR_EXPORT void reducedToFullMatches(
const RDKit::RWMol &reducedQuery, const RDKit::RWMol &molHs,
std::vector<RDKit::MatchVectType> &matches);
RDKIT_DEPICTOR_EXPORT bool invertWedgingIfMolHasFlipped(
RDKit::ROMol &mol, const RDGeom::Transform3D &trans);
} // namespace RDDepict
#endif