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

Generated on Fri Apr 3 06:03:01 2009 for RDCode by  doxygen 1.5.6