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