RDCode: DepictUtils.h Source File

- Main Page
- Namespaces
- Classes
- Files
- Directories

# DepictUtils.h

Go to the documentation of this file.

    00001 //
    00002 //  Copyright (C) 2003-2008 Greg Landrum and Rational Discovery LLC
    00003 //
    00004 //   @@ All Rights Reserved  @@
    00005 //
    00006 #ifndef _RD_DEPICT_UTILS_H_
    00007 #define _RD_DEPICT_UTILS_H_
    00008
    00009 // REVIEW: remove extra headers here
    00010 #include <RDGeneral/types.h>
    00011 #include <GraphMol/RDKitBase.h>
    00012 #include <GraphMol/RWMol.h>
    00013 #include <GraphMol/ROMol.h>
    00014 #include <Geometry/Transform2D.h>
    00015 #include <Geometry/point.h>
    00016 #include <queue>
    00017
    00018 namespace RDDepict {
    00019   const double BOND_LEN=1.5;
    00020   const double COLLISION_THRES=0.35;
    00021   const double BOND_THRES = 0.50;
    00022   const double ANGLE_OPEN=0.1222; // that is about 7 deg
    00023   const unsigned int MAX_COLL_ITERS=15;
    00024   const double HETEROATOM_COLL_SCALE=1.3;
    00025   const unsigned int NUM_BONDS_FLIPS=3;
    00026
    00027   typedef std::vector<const RDGeom::Point2D *> VECT_C_POINT;
    00028
    00029   typedef std::pair<int, int> PAIR_I_I;
    00030   typedef std::vector<PAIR_I_I> VECT_PII;
    00031   struct gtIIPair {
    00032     bool operator() ( const PAIR_I_I &pd1, const PAIR_I_I &pd2) const {
    00033       return pd1.first > pd2.first;
    00034     }
    00035   };
    00036
    00037   typedef std::priority_queue<PAIR_I_I, VECT_PII, gtIIPair> PR_QUEUE;
    00038
    00039   typedef std::pair<double, PAIR_I_I> PAIR_D_I_I;
    00040   typedef std::list<PAIR_D_I_I> LIST_PAIR_DII;
    00041
    00042
    00043   //! Some utility functions used in generating 2D coordinates
    00044
    00045   //! Embed a ring as a convex polygon in 2D
    00046   /*!
    00047     The process here is very straightforward:
    00048
    00049     We take the center of the ring to lie at the origin, so put the first
    00050     point at the origin and then sweep
    00051     anti-clockwise by an angle A = 360/n for the next point.
    00052
    00053     The length of the arm (l) we want to sweep is easy to compute given the
    00054     bond length (b) we want to use for each bond in the ring (for now
    00055     we will assume that this bond legnth is the same for all bonds in the ring:
    00056
    00057     l = b/sqrt(2*(1 - cos(A))
    00058
    00059     the above formula derives from the triangle formula, where side 'c' is given
    00060     in terms of sides 'a' and 'b' as:
    00061
    00062     c = a^2 + b^2 - 2.a.b.cos(A)
    00063
    00064     where A is the angle between a and b
    00065    */
    00066   RDGeom::INT_POINT2D_MAP embedRing(const RDKit::INT_VECT &ring);
    00067
    00068   void transformPoints(RDGeom::INT_POINT2D_MAP &nringCor, const RDGeom::Transform2D &trans);
    00069
    00070   //! Find a point that bisects the angle at rcr
    00071   /*!
    00072     The new point lies between nb1 and nb2. The line (rcr, newPt) bisects the angle
    00073     'ang' at rcr
    00074   */
    00075   RDGeom::Point2D computeBisectPoint(const RDGeom::Point2D &rcr,
    00076                                      double ang, const RDGeom::Point2D &nb1,
    00077                                      const RDGeom::Point2D &nb2);
    00078
    00079   //! Reflect a set of point through a the line joining two point
    00080   /*!
    00081     ARGUMENTS:
    00082     \param coordMap       a map of <int, point2D> going from atom id to current
    00083                           coordinates of the points that need to be reflected:
    00084                           The coordinates are overwritten
    00085     \param loc1           the first point of the line that is to be used as a mirror
    00086     \param loc2           the second point of the line to be used as a mirror
    00087    */
    00088   void reflectPoints(RDGeom::INT_POINT2D_MAP &coordMap, const RDGeom::Point2D &loc1,
    00089                    const RDGeom::Point2D &loc2);
    00090
    00091   RDGeom::Point2D reflectPoint(const RDGeom::Point2D &point, const RDGeom::Point2D &loc1,
    00092                                const RDGeom::Point2D &loc2);
    00093
    00094   //! Set the neighbors yet to added to aid such that the atoms with the most subs fall on opposite sides
    00095   /*!
    00096     Ok this needs some explanation
    00097     - Let A, B, C, D be the substituent on the central atom X (given
    00098       by atom index aid)
    00099     - also let A be the atom that is already embedded
    00100     - Now we want the order in which the remaining neighbors B,C,D are
    00101       added to X such that the atoms with atom with largest number of
    00102       substituent fall on opposite sides of X so as to minimize atom
    00103       clashes later in the depiction
    00104
    00105     E.g. let say we have the following situation
    00106 <pre>
    00107             B
    00108          |  |
    00109          A--X--C
    00110          |  |
    00111           --D--
    00112             |
    00113 </pre>
    00114     In this case the the number substituent of A, B, C, D are 3, 1, 1,
    00115     4 respectively so want to A and D to go opposite sides and so that
    00116     we draw
    00117 <pre>
    00118             B
    00119          |  |  |
    00120          A--X--D--
    00121          |  |  |
    00122             C
    00123 </pre>
    00124     And the correct ordering of the neighbors is B,D,C
    00125   */
    00126   RDKit::INT_VECT setNbrOrder(unsigned int aid, const RDKit::INT_VECT &nbrs, const RDKit::ROMol &mol);
    00127
    00128   //! \brief From a given set of rings find the ring the largest common elements with other rings
    00129   /*
    00130     Bit of a weird function - this is typically called once we have embedded some of the
    00131     rings in a fused system and we are looking for the ring that must be embedded (or merged)
    00132     next. The heuristic used here is to pick the rings with the maximum number of atoms
    00133     in common with the rings that are already embedded.
    00134
    00135     \param doneRings    a vertor of ring IDs that have been embedded already
    00136     \param fusedRings   list of all the rings in the the fused system
    00137     \param nextId       this is where the ID for the next ring is written
    00138
    00139     \return list of atom ids that are common
    00140   */
    00141   RDKit::INT_VECT findNextRingToEmbed(const RDKit::INT_VECT &doneRings,
    00142                                       const RDKit::VECT_INT_VECT &fusedRings,
    00143                                       int &nextId);
    00144
    00145   typedef std::pair<int,int> INT_PAIR;
    00146   typedef std::vector<INT_PAIR> INT_PAIR_VECT;
    00147   typedef INT_PAIR_VECT::const_iterator INT_PAIR_VECT_CI;
    00148
    00149   typedef std::pair<double, INT_PAIR> DOUBLE_INT_PAIR;
    00150
    00151   //! Sort a list of atoms by their  CIP rank
    00152   /*!
    00153     \param mol        molecule of interest
    00154     \param commAtms   atoms that need to be ranked
    00155     \param ascending  sort to an ascending order or a descending order
    00156   */
    00157   template<class T> T rankAtomsByRank(const RDKit::ROMol &mol, const T &commAtms,
    00158                                       bool ascending=true);
    00159
    00160
    00161   //! computes a subangle for an atom of given hybridization and degree
    00162   /*!
    00163     \param degree the degree of the atom (number of neighbors)
    00164     \param htype  the atom's hybridization
    00165
    00166     \return the subangle (in radians)
    00167   */
    00168   inline double computeSubAngle(unsigned int degree, RDKit::Atom::HybridizationType htype) {
    00169     double angle = M_PI;
    00170     switch (htype) {
    00171     case RDKit::Atom::SP3 :
    00172       if (degree == 4) {
    00173         angle = M_PI/2;
    00174       } else {
    00175         angle = 2*M_PI/3;
    00176       }
    00177       break;
    00178     case RDKit::Atom::SP2 :
    00179       angle = 2*M_PI/3;
    00180       break;
    00181     default:
    00182       angle = 2.*RDKit::PI/degree;
    00183     }
    00184     return angle;
    00185   }
    00186
    00187   //! computes the rotation direction between two vectors
    00188   /*!
    00189
    00190     Let:
    00191
    00192        v1 = loc1 - center
    00193
    00194        v2 = loc2 - center
    00195
    00196     If remaining angle(v1, v2) is < 180 and corss(v1, v2) > 0.0 then the rotation dir is +1.0
    00197
    00198     else if remAngle(v1, v2) is > 180 and cross(v1, v2) < 0.0 then rotation dir is -1.0
    00199
    00200     else if remAngle(v1, v2) is < 180 and cross(v1, v2) < 0.0 then rotation dir is -1.0
    00201
    00202     finally if remAngle(v1, v2) is > 180 and cross(v1, v2) < 0.0 then rotation dir is +1.0
    00203
    00204     \param center     the common point
    00205     \param loc1       endpoint 1
    00206     \param loc2       endpoint 2
    00207     \param remAngle   the remaining angle about center in radians
    00208
    00209     \return the rotation direction (1 or -1)
    00210   */
    00211   inline int rotationDir(const RDGeom::Point2D &center, const RDGeom::Point2D &loc1,
    00212                           const RDGeom::Point2D &loc2, double remAngle) {
    00213      RDGeom::Point2D pt1 = loc1 - center;
    00214      RDGeom::Point2D pt2 = loc2 - center;
    00215      double cross = pt1.x*pt2.y - pt1.y*pt2.x;
    00216      double diffAngle = RDKit::PI - remAngle;
    00217      cross  *= diffAngle;
    00218      if (cross >= 0.0) {
    00219        return -1;
    00220      } else {
    00221        return 1;
    00222      }
    00223    }
    00224
    00225   //! computes and return the normal of a vector between two points
    00226   /*!
    00227     \param center     the common point
    00228     \param other      the endpoint
    00229
    00230     \return the normal
    00231   */
    00232   inline RDGeom::Point2D computeNormal(const RDGeom::Point2D &center,
    00233                                        const RDGeom::Point2D &other) {
    00234     RDGeom::Point2D res = other - center;
    00235     res.normalize();
    00236     double tmp = res.x;
    00237     res.x = -res.y;
    00238     res.y = tmp;
    00239     return res;
    00240   }
    00241
    00242   //! computes the rotation angle between two vectors
    00243   /*!
    00244     \param center     the common point
    00245     \param loc1       endpoint 1
    00246     \param loc2       endpoint 2
    00247
    00248     \return the angle (in radians)
    00249   */
    00250   inline double computeAngle(const RDGeom::Point2D &center,
    00251                              const RDGeom::Point2D &loc1,
    00252                              const RDGeom::Point2D &loc2) {
    00253     RDGeom::Point2D v1 = loc1 - center;
    00254     RDGeom::Point2D v2 = loc2 - center;
    00255     return v1.angleTo(v2);
    00256   }
    00257
    00258   //! \brief pick the ring to embed first in a fused system
    00259   /*!
    00260     \param mol        the molecule of interest
    00261     \param fusedRings the collection of the molecule's fused rings
    00262
    00263     \return the index of the ring with the least number of substitutions
    00264   */
    00265   int pickFirstRingToEmbed(const RDKit::ROMol &mol, const RDKit::VECT_INT_VECT &fusedRings);
    00266
    00267   //! \brief find the rotatable bonds on the shortest path between two atoms
    00268   //!   we will ignore ring atoms, and double bonds which are marked cis/trans
    00269   /*!
    00270     <b>Note</b> that rotatable in this context doesn't connect to the
    00271       standard chemical definition of a rotatable bond; we're just talking
    00272       about bonds than can be flipped in order to clean up the depiction.
    00273
    00274     \param mol   the molecule of interest
    00275     \param aid1  index of the first atom
    00276     \param aid2  index of the second atom
    00277
    00278     \return a set of the indices of the rotatable bonds
    00279   */
    00280   RDKit::INT_VECT getRotatableBonds(const RDKit::ROMol &mol, unsigned int aid1,
    00281                                     unsigned int aid2);
    00282
    00283   //! \brief find all the rotatable bonds in a molecule
    00284   //!   we will ignore ring atoms, and double bonds which are marked cis/trans
    00285   /*!
    00286     <b>Note</b> that rotatable in this context doesn't connect to the
    00287       standard chemical definition of a rotatable bond; we're just talking
    00288       about bonds than can be flipped in order to clean up the depiction.
    00289
    00290     \param mol   the molecule of interest
    00291
    00292     \return a set of the indices of the rotatable bonds
    00293   */
    00294   RDKit::INT_VECT getAllRotatbleBonds(const RDKit::ROMol &mol);
    00295
    00296   //! Get the ids of the atoms and bonds that are connected to aid
    00297   void getNbrAtomAndBondIds(unsigned int aid, const RDKit::ROMol *mol,
    00298                             RDKit::INT_VECT &aids, RDKit::INT_VECT &bids);
    00299
    00300   //! Find pairs of bonds that can be permuted at a non-ring degree 4 atom
    00301   /*!
    00302     This function will return only those pairs that cannot be
    00303     permuted by flipping a rotatble bond
    00304
    00305            D
    00306            |
    00307            b3
    00308            |
    00309       A-b1-B-b2-C
    00310            |
    00311            b4
    00312            |
    00313            E
    00314      For example in teh above situation on the pairs (b1, b3) and (b1, b4) will be returned
    00315      All other permutations can be achieved via a rotatable bond flip.
    00316
    00317      ARGUMENTS:
    00318      \param center - location of the central atom
    00319      \param nbrBids - a vector (of length 4) containing the ids of the bonds to the neighbors
    00320      \param nbrLocs - locations of the neighbors
    00321   */
    00322   INT_PAIR_VECT findBondsPairsToPermuteDeg4(const RDGeom::Point2D &center, const RDKit::INT_VECT &nbrBids,
    00323                                             const VECT_C_POINT &nbrLocs);
    00324 }
    00325
    00326 #endif