osra-2.2.4/0000755000175000017500000000000015137157155011157 5ustar igorigorosra-2.2.4/src/0000755000175000017500000000000015137157137011746 5ustar igorigorosra-2.2.4/src/mcdlutil.cpp0000644000175000017500000111006715137157137014275 0ustar igorigor/* -*-C++-*- ********************************************************************** Copyright (C) 2007,2008 by Sergei V. Trepalin sergey_trepalin@chemical-block.com Copyright (C) 2007,2008 by Andrei Gakh andrei.gakh@nnsa.doe.gov This file is part of the Open Babel project. For more information, see This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *********************************************************************** */ #include #include #include #include #include "mcdlutil.h" #include #include //#ifndef WIN32 #include //#endif using namespace std; namespace OpenBabel { #define CONNMAX 15 #define NATOMSMAX 255 #define NBONDSMAX 255 typedef struct adjustedlist { int nb; int adjusted[CONNMAX]; } adjustedlist; typedef adjustedlist neigbourlist[NATOMSMAX]; #define PI 3.141592653589793238462 #define blDenominator 4.0 //Controls bond legth in bondEnlarge #define nRotBondsMax 20 //Determines no. rotating bonds in correctOverlapped //Hydrogen valencies. Zero dummy element is the first const int hVal[NELEMMCDL] = { 0,1,0,0,0,3,4,3,2,1, 0,0,0,3,4,3,2,1,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,4,3,2,1,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 2,3,2,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,2,0,2,1,0,1,2,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0 }; const int maxVal[NELEMMCDL] = { 0,1,0,1,2,4,4,5,3,1, 0,1,2,4,4,6,6,7,0,1, 2,3,4,5,6,7,6,4,4,2, 2,3,4,5,6,7,8,1,2,3, 4,5,6,7,8,6,6,2,2,3, 4,5,6,7,8,1,2,3,4,4, 3,3,3,3,3,4,3,3,3,3, 3,3,4,5,6,7,8,6,6,3, 2,3,4,5,6,7,8,1,2,3, 4,5,6,6,6,6,3,4,3,3, 3,3,1,1,1,0,0,0,0,0, 0,8,1,8,5,0,0,0,0,0,0 }; const int chargeVal[NELEMMCDL] = //0 - dummy { 0,-1,-1,-1,-1,-1,-1, 1, 1, 1,-1, //Ne -1,-1,-1,-1, 1, 1, 1,-1,-1,-1, //Ca -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Zn -1,-1, 1, 1, 1,-1,-1,-1,-1,-1, //Zr -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Sn 1, 1, 1,-1,-1,-1,-1,-1,-1,-1, //Nd -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Yb -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Hg -1,-1, 1, 1, 1,-1,-1,-1,-1,-1, //Th -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, //Fm -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1 }; const string aSymb[NELEMMCDL] = {"0", "H" ,"He","Li","Be","B" ,"C" ,"N" ,"O" ,"F" ,"Ne", "Na","Mg","Al","Si","P" ,"S" ,"Cl","Ar","K" ,"Ca", "Sc","Ti","V" ,"Cr","Mn","Fe","Co","Ni","Cu","Zn", "Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y" ,"Zr", "Nb","Mo","Tc","Ru","Rh","Pd","Ag","Cd","In","Sn", "Sb","Te","I" ,"Xe","Cs","Ba","La","Ce","Pr","Nd", "Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb", "Lu","Hf","Ta","W" ,"Re","Os","Ir","Pt","Au","Hg", "Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th", "Pa","U" ,"Np","Pu","Am","Cm","Bk","Cf","Es","Fm", "Md","No","Lr","D" ,"" ,"G" ,"0" ,"Xx","" ,"" , "M" ,"X" ,"A" ,"Q" ,"" ,"" ,"" ,"" ,"" ,"" }; #define NEXACTATOMS 21 const int exactAtom[NEXACTATOMS]= {6,14,5,50,82,8,16,34,52,7,15,33,51,9,17,35,53,32,13,26,80}; #define NALKALYATOMS 5 const int alkaly[NALKALYATOMS] = {3,11,19,37,55}; #define NALKALYEARTHATOMS 5 const int alkalyEarth[NALKALYEARTHATOMS] = {4,12,20,38,56}; #define NTRIVALENTATOMS 31 const int trivalent[NTRIVALENTATOMS] = {21,31,39,49,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,81,89,90,91,92,93,94,95,96,97,98,99}; #define NTITANATOMS 3 const int titan[NTITANATOMS] = {22,40,72}; #define NVANADIUMATOMS 3 const int vanadium[NVANADIUMATOMS] = {23,41,73}; #define NCHROMIUMATOMS 3 const int cromium[NCHROMIUMATOMS] = {24,42,74}; #define NMANGANESEATOMS 3 const int manganeze[NMANGANESEATOMS] = {25,43,75}; #define NLIKEFEATOMS 2 const int likeFe[NLIKEFEATOMS] = {27,28}; #define NPLATINUMATOMS 6 const int platinum[NPLATINUMATOMS] = {44,45,46,76,77,78}; #define NCOPPERATOMS 3 const int copper[NCOPPERATOMS] = {29,47,79}; #define NZINKATOMS 2 const int zink[NZINKATOMS] = {30,48}; #define NMETALS 78 #define NHALOGENS 5 #define NHETERO 10 #define NAROMMAX 9 #define NLIGHT_METALS 20 #define NHEAVY_METALS 58 #define DEUTERIUM_ATOM 104 #define METALL_ATOM 111 #define HALOGEN_ATOM 112 #define ANY_ATOM 113 #define HETERO_ATOM 114 #define ANY_BOND 8 const int possibleAromatic [NAROMMAX] = {7,8,15,16,33,34,51,52,HETERO_ATOM}; const int metals[NMETALS] = { 3,4,11,12,13,19,20,21,22,23,24,25,26,27,28,29, 30,31,37,38,39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63, 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,87,88,89,90,91, 92,93,94,95,96,97,98,99,100,101,102,103 }; //#define A B ??? - const int lightMetals[NLIGHT_METALS] = { 3,4,11,12,13,19,20,21,22,23,24,25,26,27,28,29,30,31,37,38 }; const int heavyMetals[NHEAVY_METALS] = { 39,40,41,42,43,44,45,46,47,48,49,50,55,56,57,58,59,60,61,62,63, 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,87,88,89,90,91, 92,93,94,95,96,97,98,99,100,101,102,103 }; const int halogens[NHALOGENS] = {9,17,35,53,85}; const int hetero[NHETERO] = {7,8,14,15,16,33,34,51,52,84}; #define RUNDEF -1.2345678E9 #define DEFAULTBONDLENGTH 1.44 #define NDATABASE_MOLECULES 147 const string strData[NDATABASE_MOLECULES]= { "05A53816506A53810000A00008692A99998857A6567442806020101030401050203050504", "06A25008659A74998659A99994330A74990000A25000000A00004330100203030405060106060406020305010305020104", "06A48805837A48800000A00007834A90467987A59523994A999962970802010103040106040502060503050302", "06A33680000A00003697A90943697A90949999A00009999E3368717109020101030203010602050304050606040405", "06A00002886A49980000A99992886A71137887A28867887E49985773070102020303060601010503040405", "07A00002500A00007499A86397499A86392500A43200000A69404999A4235999909070203070304050402030102050606070105", "07A18315489A81685489A18311830A81681830A49990000A00008658A9999865809050403050204010301060602020707010607", "07A51830000A99995257A61733821A00008921A86408921A16055257E45686533100604030601070704050702050301020304050602", "07A43300000A86602500A00002500A86607499A00007499A43309999A213550000801020301050606040402050301070607", "07A69274000A69270000A00000000A00004000A69277999A34649999E3464599909010203040407010707060605050104060203", "07A43309999A00007499A86607499A00002499A86602499A43300000E433049990806050406020101030305020406070702", "08A99994342A99991475A50354342A74810040A50351475A00004363A24800000A00001455100405050301020402030107080806070506030704", "08A14437499A43307499A57735000A43302500A14432500A00005000A57730000A57739999100102020303040405050601060407020808060607", "08A55684926A59770000A13416715A91136862A00003196A24094926A99995337E654534311106030806020101030401070408020708060503050207", "08A00003799A00009999A21890000A83936200A83930000A61999999E21896200E6199379912070206040206010203010805010806080703030507040405", "08A36607320A78867320A99993660A78860000A36600000A15473660A00002113A0000520709010202030304040505060106050701080807", "08A00005000A00008332A57705000A28419999A57708332A57701667A29290000A0000166709010202040405050301030306060707080801", "08A48819390A53570000A00007833A90467986A59523994A11895837A99996297E48815837100603050602080803040807040502070503010401", "08A19105257A80890000A99992628A19100000A00002628A80895257E50001004E500042531101080807070404050105060303020806070204020601", "08A50000000A50006666A00002886A16670000A83320000A99992886E66662886E33332886100108080303040401010707060605050106020302", "08A25008659A74998659A99994330A74990000A25000000A00004330E30622562E6937256209010202030304040505060106060703080708", "09A24994330A74994330A24991444A74991444A49990000A99995773A00005773A85558273A144382731105040305020401030602010607010207090708060908", "09A55375090A55370002A12826830A91696964A64713483A18610000A99995492A00003324E2320509012090305090201010304010704050207050908080308060602", "09A18510000A00003211A90859999A70960000A00008451A52418451A70965241E52413211E18515241130905050602050102080402080608090101040907070403070603", "09A19105257A49994253A49991004A19100000A00002628A80895257A99992628A80890000E386426281101020203030404050105060707080206030805090907", "09A49994252A80895257A49991004A80890000A19090000A00002628A19095257A99992628E218626281101020208080404030103030505060607070103090109", "09A00003622A10641208A32581208A49670000A32583622A99993247A81610000A68065661E593523311101020203030404050501030909070706060808050407", "09A31703170A50000000A00004999A36604999A68293170A63394999A99994999A81698169A18308169100102010303090904040502050106070507080806", "09A82718548A41359999A91956942A00008341A44961502A55014870A11246476A55010000E449664761107040607090401090301030609050608050804020102", "09A70330000A29660000A00002881A00007010A29669891A70339891A99997010A99992881E63994946100102020303040405050606070708010802090509", "09A80419999A43868037A89488452A00009735A15210000A53806452A11118037A53801698E43863169100704060702040102030103060209060805090805", "09A10176779A34868279A63437716A99994155A63430500A34860000A10171406A00004155E26634155100102020303090905050606070708010803040504", "09A16675773A50005773A83325773A50000000A16670000A00002886A83320000A99992886E66662886100102020909040405050601060407070808030302", "09A70296185A40884515A09414515A42940000A00006071A88530000A99994478E46463112E779448571103050803040202050102080409080604070109070706", "10A43309999A86597499A72165000A43305000A28867499A86592500A43300000A28862500A00002500A0000749912020303040405010507080306040810050809091001020607", "10A46515888A50291200A06397575A81687425A55524463A17730000A16865888A88076225A00002513A9999993812070305070201010304010502080509070602090610080410", "10A48804396A48801478A00006392A90466546A59522553A11914396A99994857A59520000A69959494A2962949412060305060201010304010704070505080208040903101009", "10A25474570A16166133A62753127A54374570A54370000A94454931A86996254A38217369A00008932A1791999912010203010504040207040607030506030408020909100810", "10A00006995A25904430A25900855A66250000A99991632A46986995A63859327A85547850A85544430E46981632130201030204030410010607060807090802090509040510060510", "10A53026409A85668294A00008578A65814346A12696409A99996433A51190000A12692065A65810691E53022065130503040510010103040604091008080508070709091001020206", "10A99994745A58033967A85242714A58030000A24865324A65322714A00002818A82426113A18370000E32963967131005061004020205030106040306020808010409090707051007", "10A38760000A23092718A00008169A83160000A23097153A99998464A83164436A67457153E67452718E387644361405080205090402090809100101041007070406070806020103100503", "10A36631099A20423911A00000000A82571099A20428500A99999856A82575689A66328500E66323911E366356891410050508020509040209080910010104100707040607080603020103", "10A73929797A99996506A32668429A26361664A99991664A00009797A63030000A26366506E32663734E68198060130806100802010103030610020804030902050407050709050709", "10A00007120A10935313A99996759A14849577A54623723A48450000A82347300A63309577A89634915E4845531312020105020610100107100506090504010708040803070903", "10A18301830A50000000A81691830A99995000A00005000A18308169A50009999A81698169E50006340E5000366112010202030310100101050506060909080807070608040403", "10A62500000A25002165A76109666A99992165A25006783A40838511A99996491A00009666E74798226E4083374912020110010401070406100502080506080905070903060703", "10A73929796A99996506A32668429A26361663A99991663A00009796A63030000A26366506E32663734E6819805912080610080201010303061002080403090205040705070905", "11A11600000A46320000A57051522A28912486A00761522A28147513A00008476A10849999A45569999A56288476A284451212002010302070608070910100609080405050104030511041101110211110311060811071111091110", "12A86832482A65403688A00002482A21983688A43972482A43970000A21986311A00007446A43977446A65406311A43979999A8683744630030808111112120101060306060504020209090407050510100701021012091107080403010501101202120911101107080908040307030506020604", "11A55476610A55471550A30757567A91868524A65015060A24036610A99997020A32150000A24039664A00004877A00001550130506020101030401070405020705080210061110081109060309", "11A99994719A35190000A50464719A64810000A90277646A00004838A09727765A41667765A60187646A74542927A25462927131003041002111103040206071106030808070905030910010105", "11A54717869A10769779A91039894A00005034A21977869A99998274A65021620A65026365A05821505A19730000E547130661405020805010203010603060801110807110709111007100910040504", "11A63167961A37420000A00005471A63165546A43862037A09653395A68423395A00008150A18139999A47959999E342139991406030506021111030411070405020705030808090910100106070401", "11A50227868A00000000A06467868A63146852A06463611A63142407A88964074A18652407A30859999E18656852E5022361115011111050503060808100410010411060310090309010607070408020205", "11A33586997A99992256A00007945A62567945A51370000A20545575A82195337A20541779A61486761A86960000E33583081130805110501110608030601030906070904010704070205101002", "11A46588688A46585901A23299999A23294644A00008688A00005901A85963661A85960000A23290000E41501367E597136611405060406020401020305030107080207040904101011071108110908", "11A74236368A00008420A80755210A12646263A46091158A53023684A20804895A53020000A61998579A22849999E46094895130704060711040111030103061105060805080901100902100402", "11A31388599A13560000A00009949A58129999A37597499A07368599A63938949A45724300A05043100A17822600E31384849130603050611010103040107040511070510020810110909020508", "11A00004220A00001358A24810000A50001358A74818488A24815626A24818488A74815626A99994220A99991358E50004220130201030204031104061101060706081109081009041005080705", "11A85916567A35746567A99992562A23462655A00009594A49450000A23469594A12637033A79770000E48375123E758051231402040102031111101004030111010406090609030810070205080705", "11A09557693A34559510A65449510A90447693A99994755A90441816A65440000A34550000A09551816A00004755E3675475512010202030304040505060607070808090910011007110311", "11A00009999A42230000A00006825A78729999A52073492A10255079A87345449A87348517E10258517E78726930E422350791406030506021111031011071005020705090608090708041001040301", "11A13393318A13746318A70459999A49670000A86644773A44732909A00005045A90889045A21849999E78206545E49674999130601110210110506110406040702010708100508090210030903", "11A99995000A81698169A81691829A00005000A50009998A50000000A18301829A18308169E50006338E31703169E6830316912070408041004050802050102030106030706110109111009", "11A49991430A25005766A99991430A49997229A00001430A25000000A74990000A74995766E74992892E49994337E2500289212050606010701030904080201110510091110100803070402", "12A49997216A25008659A49994330A00007216A25002886A00004330A74992886A99994330A74998659A99997216A25000000A749900001405030605040202010103040609011009080707030810051107121211", "12A74852867A74850000A44730000A95313961A80111961A56432867A99993093A21052452A00004640A53805093A24853885E5058388515061205060201011204010704050207050809120801101011110903080203", "12A00003057A47044586A99994586A47041529A99991529A73520000A47047643A73529172A99997643A17970584A17975530E735261151406050406021203120305020402070708080909030211100101110410", "12A40419999A55880712A00007357A17531277A55884325A17535184A90205891A90209166A34830000E81107504E41302134E41306289160603050611121203101207100708030108010507050211040406040909020211", "12A83909999A37070000A00005869A00008652A44813000A08764391A75144695A68408652A75147390E08767390E68405999E37074391160603050602121203111207110502070510060910070908110408030401080901", "12A67547130A27484678A78944678A27481245A78941245A31286036A53210000A99995885A00006262A08487356E31282716E570157721412021203020406110305040711070507090210061009080301080601", "13A00008749A21667501A21669999A46659999A68308749A46657501A21662499A46652499A68301250A46650000A21660000A00001250A3501512124010201030304040505060602021313070708080909101011111212071311131013081309131213011303130413061305", "12A98975714A74231429A49490000A24741429A98978571A00005714A00008571A24749999A74239999E49498571E24744285E7423428512120202030304041111060607070808101009090505010112", "13A28577422A57147422A71424948A57142474A28572474A14284948A99994948A71420000A99990000A71429897A99999897A00002474A00007422160102020303040405050601060307040808090907021010111107051201131312", "13A99994826A91595517A83512806A74203552A54942806A94380000A44703607A85380666A16353603A25602863A13885888A00001596A08320912160507030504070204010201030408030608060907111010051310121309111209", "13A39485622A00003358A32469999A69013962A30124453A23988376A61112528A85093962A92982528A68711132A68710000A92980000E84791132160603050602010103040107040502070510130710040808090913101111120912", "13A60776420A66072578A90957683A28148103A52614999A83206052A20806788A00005578A07342947A07340000A20809999A52610000E40781315160506020101030401020507050807090813090213091012100512071104110603", "13A63116880A88436880A88432580A99994701A50224701A63110000A37776880A12442580A12446880A00004701A37770000A37772580A6311258015030413030501010202040513091007090512120808100507111206131106", "13A66660962A66662887A83333849A99992887A99990962A83330000A50000000A33330962A33332887A16660000A00000962A00002887A1666384915010202030304040505060106070808090107101111121213081009130209", "13A22073757A07045817A48844666A00000000A07048909A68573757A25832121A52145817A29129999A52148909A22071212E48847575E25834909160806130802010103030613020810031202051009120905091101071304110704", "13A18232941A00005293A47863921A77493823A00008725A71412941A22020980A51665293A25839999A51668725A18230000E47867254E22024215161308020101030306130208100312020510091209050911010713110704080604", "13A85754958A99992462A99997437A00004924A14072462A85750000A85759898A42717437A42712462A14077437A57289898A57280000E5728495815020103011301060207030813091311081209040510080509120610040711", "13A00008994A36698934A00006804A18349999A55028934A36693254A54560000A18345739A73371064A73373195A36691064E55024260E36696804160103080313080213040106110402091007090612121011071205020513100806", "13A60780000A67532108A39210000A32242108A10892108A89102108A00003963A99993963A39215201A60785201A79516296A20486296E501033451404031304020101031302050406020705080609101110120907120811", "13A60520000A10660521A39180000A20476299A10822113A89172113A00003961A99993961A79526299E60525168E39185168E32162113E675421131412031301010305120613070508061110091004110704080905021302", "14A22012921A22010284A00003814A43083895A26732069A05352921A44973124A67292962A64462313A99992313A84583976A71380000A92750000E74831014190603050602010103040107040502070514120814110909120709081113121413101113100408", "14A18759999A29620000A01974012A48374140A33072038A08392993A53803184A09386433A20735732A53808661A48875732A00008025E40976433E271529932006030506021414030414070405020705080306091304071108130911120809121011131001121001", "14A37508659A62498659A74996495A62494330A37504330A25006495A74992165A62490000A37500000A25002165A00002165A00006495A99996495A999921651701020203030404050506010607080809091004070510120610110313071411121314", "14A52504032A47494920A31242823A25623791A06253791A31240000A00004839A25620887A68756129A74375161A93755161A68758952A99994113A743780641705070305040702040102010304080306080611130911101301100209101409121412", "14A49995955A36928217A99993692A49992263A00008217A86945955A13032263A00004524A63070000A99990000E86942263E63073692E36924524E130359552314050201050208050708130408130213140707041401010411100904100903100603120103120912110606011104", "14A14989134A00007637A67720000A47251181A79534409A99995591A79536772A67722362A55916772A55914409A11815591A35457953A35453228A35455591161314121411141014091405100605070609070810041303040803021101120201", "14A00002151A10824678A74260000A21050075A57591849A38601849A29535658A38604678A57594678A64325658A85664678A99992037E29532829E6432282918130414130305050606040314071308060905101411091011121103120208070201020401", "14A57093413A57090749A79674204A79030000A00002206A99991915A39023454A39020749A16774204A17100083E30962955E30961415E65801415E658027892002040102031414131304030108100708091111121210090708021312060403060510090511071401", "14A00001443A00004330A25005728A60475728A50001443A25000000A75000000A99991443A99994330A85566830E25002887E75005773E60472887E5000433018010202030314140505060106050707080809071301111113141212090910100404030413", "14A14499999A00347478A43809999A58294608A58297478A00344608A00002521A58292521A43800000A14490000A28641391E43804999E14494999E286432171713020201050312051213030107130812090810071110091106020405041406141114", "14A19889999A45149217A66708216A88286043A70752304A13482174A00004521A12467216A70750000A44130000E29313695E56946043E40096303E4009313018131403130403050414050614070608071308071110110910050912110412021201020801", "14A60520641A99990000A38890641A00880000A10822716A88592716A00004565A99114565A20476866A78946866E60525772E38895772E32162716E6695271615130314010103051306140705080612111011091207090810050406020204", "15A15004047A35682933A10222610A35680000A59083989A28862199A54313197A00003461A72723050A67272258A90903461A99991848A75220440A93850440E795414082006070402020501020604030603080108050907101109131012111413141207051509151410111315", "14A99993463A89991732A89995196A60000000A39990000A60006927A10001732A00003463A10005196A39996927E29995196E29991732E70005196E700017321401020214140404050512120707080809091111101006061313030301", "15A14543959A34772874A10002551A34770000A57953929A28402111A53183108A00003402A71132991A65682229A93173842A92260411A99991877A73630411E84542874190607040202050102060403060308010805090710110915101315141014091311121412130705", "15A46187999A69287999A80825999A69284000A46184000A34645999A34642000A11552000A00004000A11555999A80822000A69280000A46180000A00007999A3464999918010202030304040505060106070808090910050706101112121313070411150110141415", "15A33335773A50006735A33333849A66665773A50002886A66663849A16662886A00003849A16666735A00005773A50000962A66660000A83330962A83334811A9999192418050603050102020404060103091001090307070808100511111212130613061413151514", "14A24498659A00004286A50331429A26170000A75508572A99994286A74490000A50337230E75505715E24495715E74492814E26172814E42283637E6140510915081414131303110703070906110608050905030412041202100210010801", "16A73181418A16684435A37326615A33468273A10227107A00004783A68276769A83024030A99994030A95756586A76088273A63930000A33840000A24491418A50242305A5024478330030208070908101111070910040305060602040513121413150101121415141613161516121601161608160916101607161116040316160506161602", "15A25446903A08194678A53505998A29245772A08191396A75436903A00005998A99992565A32750226A57301396A85660000A75431207A99995508E57304678E53502829191406041401030306040214100315020510091509050907010207130608131208151211081011", "16A70462641A70460264A90353433A51463508A66071886A88590264A49702829A29532716A32162075A00002075A13743584A26020000A99991773A06730000E22810906E853726412316030516020101030401070405020705151208151109091207090811131603131412151410111410040806130206", "16A38483333A57733333A67351666A57730000A38480000A28861666A28865000A38486666A57736666A28868333A38489999A57739999A67358333A09625000A00006666A09628333190102020303040405050601060708080901071011111212130810091307141415151616100209", "16A59953466A69901721A69905199A40043466A99993466A09841721A89921721A89925199A59950000A59956920A29865199A29861721A09845199A40046920A40040000A00003442190201030104010508070208030902100311041204141115121606131106120705150913161014", "15A71629322A12851233A50830000A00003000A71620675A50839999A95106091A00006997A95103906A12858764E76162814E34588536E76167185E08895000E3458146215150202040414110505030315130707090911120606010113140808101012", "16A40003464A59993464A69991732A59990000A40000000A30001732A30005196A40006928A59996928A69995196A89995196A99993464A89991732A10001732A00003464A1000519618020303040405050601060708080909100107021010111112121303131415151616070614", "16A61204512A61201863A99992864A46586454A38260538A15304689A25005747A15301863A99990000A00006454A71320000A89854620E71322864E89851869E25002832E457855732308051505020501020715060810060710160601160407010413011203011211021409021412141311110913030309", "16A21912563A23970000A00003476A39953505A26941767A05712563A44522740A81270648A55482740A99992091A63922003A61874654A99993329E89262740E66443329E5091350521060305060201010304010704050207050416070915110911161215120914151313141310141011081008", "16A34524404A83733226A38885581A99991895A22621178A42462150A14683840A83734659A68645581A63880000A83730000A00001843A06740461E67061178E38883226E63882407190605140602161615150502140315080209080309101611100402041113051213071201071501", "16A21141056A39430000A60560000A78861056A78864045A60565101A00001056A99991056A99994045A00004045A21144045A39435101E39432113E60562113E39432988E6056298818010202030304041414131301010704080809071010111112120606051115151616050509", "16A89991732A99993464A69991732A59990000A40000000A30001732A10001732A00003464A10005196A89995196A40006928A59996928E69995196E30005196E59993464E400034641716151503030404050506160606070708080909141411111212131310100202010103", "17A57140000A42850825A71430825A42852474A71432474A85720000A28563299A57143299A99992474A99990825A28564949A14282474A57144949A42855774A14285774A00003299A000049492009100503030606100805040202010103070411071308141304081114121616170712151117150509", "16A49994173A99990759A00001897A87120000A44480000A15444316A14701043A99993083A84913984A00003510E30513367E69853225E69110901E29411897E72051897E485210911705141305041515161614130407140204070310061003080908020611091211010112", "16A00003849A16670962A33330000A16676735A66660000A83320962A33337697A99993849A66667697A83326735E83324810E49996735E83322887E49990962E16674810E16672887161602020303141405050606131308081111101009091212070704041515010116", "17A06651153A56331153A00007272A15759999A00009090A56332970A15754545A06652970A47249999A62989090A62987272A47244545A31490000E31493636E47246363E31499090E1575636318041605040317030507171407121512141115100909161011070812060602080113011302", "18A69995196A89995196A99993464A89991732A69991732A59993464A59996927A69998659A89998659A99996927A40003464A30005196A40006927A59990000A40000000A30001732A10001732A00003464220102020303040405050601060708080909100107021006111112121307130514141515161116171816171812", "18A40005196A59995196A69993464A59991732A40001732A30003464A69996928A89996928A99995196A89993464A10003464A00005196A10006928A30006928A49993464A69990000A49990000A49998609220102020303040405050601060708080909100207031011121213131406110114021504161617171514180718", "17A99992891A49990000A99990952A00000952A83330000A16660000A83335782A00002891A66668673A33338673A16665782E33336733E16663843E66666733E66660952E33330952E833338431716021502051506160717140709141012121111131308080404060305010317011009", "18A50003750A50001587A99990000A38055337A31250504A12503896A20424760A12501587A87493750A00005337A79570577A61940000A68744833A87491441E62590719E20422378E79572959E374046172308051605020501020716060810060710180601180407010409131713011311171409031411031514021512110212", "18A26160872A41280000A58720000A73830872A91270872A99992383A08720872A00002383A08723893A26163893A91273893A41284765A73833893A58724765E58723021E41283021E41281744E587217442001020203030404181817170101070708080909101016161515131314141212101311110606050504", "19A57143298A71432474A57144949A42852474A57141649A71430824A99992474A42855773A42850824A28563298A42854124A85720000A57140000A99990824A28564949A14282474A14285773A00003298A00004949220714020606121214010204090913130610041510030108030401150816181819101617151917110405010207", "19A29138599A32545200A00009919A53629999A72535319A07138599A60138879A75947359A50524360A46493040A52393200A47120000A33172040A64782279A35650680A61060920E39992279E59512080E3595759924060319060201010304010704190207191009181016141411110918161013111716121315171512150708020909050508", "18A83338796A16660979A00003911A33330000A00005865A99995865A66669775A66660000A16668796A83330979A33339775A99993911E50008796E83332932E16666842E50000979E16662932E8333684218081610081410121406121806041602041702031705031505091511091311071301071801", "20A93358165A33223593A66773593A33221633A16774532A66771633A83544532A16770694A50000694A00003593A50004532A99993593A00001633A99991633A75940000A90500000A75947145A66775470A93356205E8322069424101305100204040809040609030611020813070312141420200602051103120715061614151618031907171801191701", "21A51751924A51750189A66372528A37722565A48541396A62861924A36552075A21641999A23691509A95021396A09942641A19000000A04970000A00001509A70751509A74262150A88882603A84492037A99992037A84493924E169606792906030506020101030401070405020705211208211109091207090811131221131411131404081506161516031910171920181810151817201617", "20A83200000A66400000A99990000A33985090A66795090A83205090A17585090A99993327A99991714A50000000A33200000A16400000A00001714A00003427A00005090A00000000A99995090A50005090E50001714E5000332721010302011002051806051706081709080309191011101211161213161415071504071804201813141920", "21A99995173A38633013A26931504A22882200A92786421A22880000A04432955A60151579A55582231A55580149A76552418A72793029A00001158A09390000A80304259A84673649A80305700A99993649E94724259E08932200E4223237430200703200604040702042102030621030821100909021209111208101108201313071314140612151116151717161519161818191705050101191801", "21A93358655A33224083A66774083A33222123A16785022A66772123A83545022A16781184A49050000A00004083A50005022A99994083A00002123A99992123A75940490A90500490A75947635A66775961A93356696E83221184E500011842610130510020404082104062103061102081307031214142020060205110312071506161415161803190717180119170102092009", "22A33333849A33335773A50006735A66665773A66663849A50002886A83336735A99995773A99993849A83332886A16672886A00003849A00005773A16676735A16678659A33339622A50008659A83338659A83330962A66660000A50000962A16670962280102020303040405050601060708080909100407051011121213131401110214151616171703141507181920202121061019112221221718", "22A30772664A46152664A53841332A46150000A30770000A23081332A53843997A69223997A76912664A69221332A76915329A92305329A99993997A92302664A46155329A53846661A69226661A23083997A30775329A07691332A00002664A0769399727010202030304040505060106070808090910020703101112121313140811091407151516161711170118181915190620202121221822", "22A30008660A10008660A00006928A10005196A00003464A10001732A69998660A89998660A99996928A89995196A99993464A89991732A69991732A60000000A40000000A30001732E40006928E30005196E40003464E60003464E69995196E6000692827222121202019191818172217070808090910220721101011111212132013141515161619131406050504041816060302020101170403", "24A16673849A16675773A33336735A50005773A50003849A33332886A66666735A83325773A83323849A66662886A66660962A50000000A33330962A33338659A50009621A66668659A99998659A99996735A00006735A00008659A00000962A00002886A99992886A99990962310102020303040405050601060708080909100407051011121213130610110314141515160716171818080219192021220122232409232113112417161420", "24A31693170A31691056A49990000A68301056A68303170A89433170A99995000A89436830A68306830A68308943A49999999A31698943A31696830A10566830A00005000A10563170A86600000A99991340A99998660A86609999A13399999A00008660A00001340A13390000280102020303040405050606070708080909101011111212131314141515161601041706181817081910202019122114222221162302242423", "25A68361042A10676736A10673126A32261042A89323158A68368895A31618895A89326811A14140000A99751377A86340000A00001302A50240000A00004938A99754987A49499999A86349925A13409925A00008548A99758598A68366811A32263126A31616736A68363158A494949873224252325222521250124022322030422052406210723082109041005110112031304140315081606170618071902200820171505071601130214120918191110", "24A76718683A87797576A96755665A96754023A89382063A77440869A58510000A41080000A59929999A38329999A20659069A06467650A00005731A00003835A08841987A21650706E82286173E63078094E35928094E16716173E16713458E35921537E63071537E8228345824100909181019121111191220141313201421161515211622070808220723050606230524030404240317010202170118", "26A99991663A82650000A66210000A99990000A33330000A16890000A99993039A00001605A00003268A00006537A00008200A16899804A33339804A99996422A49770000A66669804A83099804A99998142A99999804A49779804A99994759A00009804A00004931A00000000E49776651E4977321127040102040302150326150515060524060824090823091023111022111222131220132520162017161917181914182114072101072526", "28A49997302A49992697A73025000A26975000A20233831A38327976A61687976A31576808A79763831A79766167A68086841A38322023A61682023A68423191A31573191A06743831A00005000A06746167A38320674A49990000A61680674A93253831A99995000A93256167A61689324A49999998A38329324A202361673204050106010706080309031010111107021202131314140912151505051616171718121919202021211309222223232424100725252626272706042828182808", "28A26160872A41280000A58720000A73830872A91270872A99995871A08720872A08722616A99994127A91272616A08727383A00005871A00004127A08729127A26169127A91277383A91279127A73839127A58729999A41289999E58728255E41288255E82555871E82554127E17445871E17444127E41281744E587217443201020203030404282827270101070708082626252511111212131308111414151522222121181819192020151817171616232324241010090906061610050504", "30A44366431A33185790A22067722A55474499A55475790A44363849A44367722A33184499A22142574A78864569A33331924A67136525A88962558A44440000A33330649A66663849A22143849A78635797A55630649A99991924A00006423A11115774A11114499A88800015A99990649A66660000A77770649A00087746A89043888A2214647033020103070405050130020604070108020917291010181109120513291415151116041723181219142013280321282221232224252520262727240806300316102619", "36A42856185A57146185A64284948A57143711A42853711A35714948A64282474A57141237A42851237A35712474A78564948A85713711A78562474A64287422A78567422A85716185A35717422A42858659A57148659A21434948A14296185A21437422A21432474A14293711A35710000A14291237A00003711A00006185A14298659A35719896A64289896A85718659A99996185A99993711A85711237A6428000048010202030304040505060106070808090910040705100311111212130713021414151516111601171718181914190620202121221722102323242024262309252821242730182229321519313412163336081335262536353433323130292827", "42A17323500A17326499A08665999A17327499A17322500A08664000A08665000A08662000A00002500A00003500A00006499A00007499A08667999A43302000A34641500A51961500A25982000A43307999A34648499A51968499A25987999A69286499A77935999A69287499A69283500A77934000A69282500A60622000A77935000A60627999A51960500A43300000A34640500A86593500A86592500A77932000A77937999A86597499A86596499A34649499A43309999A5196949948020302040105010603070706050808090910061011121213130403111415141615171705181918201921210422232224252625272728281626292923243030203132323333151631343535363627263424373738383923391940404141422042", "60A21159049A17778821A32689182A51019771A54399999A39459638A05577213A35427935A65078888A71849343A47678759A11047581A85878461A82498233A95786811A90306443A08305967A55447753A98515564A63245965A23246328A67698577A37587292A06883953A19256703A01416446A47485643A17834689A00004435A80685310A77586929A31054538A35284033A08213556A02733187A12641538A20943069A51044356A60942706A16031765A33451110A47510228A43082245A91646046A50851240A67475461A75283670A30831422A79273295A87472418A26680656A44130000A63102064A65830816A59060361A90224032A97103553A77360950A92952786A8075117890010201060112020302070304030804050409050605100611071707260818082109140918101310221122112312251226131413151416151915441619163017211724182019572030203821322231232523272435243725282629273327462833283429342935304931443146323732383343344035363640365137483839394539494041414241434252425443534456454845554647475347564851495050575058515252555354546055585659575958605960", }; #define NBONDTYPES 11 const int bondValence[NBONDTYPES] = {1,2,3,1,1,0,0,0,1,1,1}; const string fsastart="{SA:"; const string fsbstart="{SB:"; string intToStr(int k) { char temp[16]; sprintf(temp,"%d",k); string line=temp; return line; }; //------------------------------------------------------------------- class Rect { public: double left,top,right,bottom; }; class Point { public: double x,y; }; //------------------------------------------------------------------- class TSingleAtom { public: short int na; /*Atom position in the Periodic Table (nucley charge)*/ short int nv; /*Current atom's valence*/ short int nc; /*-9..+9 atom's charge*/ short int iz; /*Isotope difference between round(AtomMass)*/ double rx; /*Internal X-coordinate representation*/ double ry; /*Internal Y-coordinate representation*/ short int rl; /*radical label*/ short int nb; /*Number of neightboring atoms*/ short int currvalence; /*Valence, excluding non-defined hydrogen atoms. Equal sum of valences for each bond type.*/ short int special; /*Special=0 - no special definition =1 - no other atoms, except explicitly defined, can be connected with the atom (query structure)*/ short int ac[CONNMAX]; /*atom's numbers in array ATOM, which are connected with the atom selected*/ short int astereo; /*=0 - no stereo, =1 - R, = 2 -S, = 3 - unknown*/ string anum; int enumerator; int fragIndex; TSingleAtom() { na=6; nv=hVal[na]; nc=0; iz=0; nb=0; rl=0; currvalence=0; special=0; astereo=0; enumerator=0; fragIndex=0; }; TSingleAtom * clone(); int encoder(); int chargeConversion(); int valencyConversion(); int allAtAtom(); void atomCopy(TSingleAtom * source); static bool atomEquivalent(TSingleAtom * structure, TSingleAtom * query, int nHStr, int nHQuery, bool chargeSensitivity, bool isotopeSensitivity); static int chargeDeltaValency(int atomNo); }; class TSingleBond { public: short int tb; /*Bond type: 1 - single 2 - double 3 - triple 4 - aromathic (query) 5 - single/double (query) 6 - coordinational 7 - not used 8 - any (query) 9 - up 10 - down 11 - either*/ short int at[2]; /*Bond definition-atoms number in array ATOM*/ short int db; /*Ring/Chain conditions*/ short int bstereo; /* =0 - no, =1 - E , = 2 - Z, =3 E/Z*/ short int special; int enumerator; /*=1 - Chain (query) =2 - Ring (query) =3 - CIS/TRANS =4 - CIS/TRANS+Chain; =5 - CIS/TRANS+Ring;*/ TSingleBond * clone(); int bondConversion(); void bondCopy(TSingleBond * source); static bool bondEquivalent(TSingleBond * sBond, TSingleBond * qBond); int getValence(); }; //------------------------------------------------------------------- TSingleAtom * TSingleAtom::clone() { TSingleAtom * result; result=new TSingleAtom(); result->astereo=this->astereo; for (int i=0; iac[i]=this->ac[i]; result->currvalence=this->currvalence; result->iz=this->iz; result->na=this->na; result->nb=this->nb; result->nc=this->nc; result->nv=this->nv; result->rl=this->rl; result->rx=this->rx; result->ry=this->ry; result->special=this->special; result->enumerator=this->enumerator; result->fragIndex=this->fragIndex; result->anum=this->anum; return result; }; int TSingleAtom::chargeDeltaValency(int atomNo) { int result=-1; if (atomNo < NELEMMCDL) result=chargeVal[atomNo]; return result; }; int TSingleAtom::encoder() { // For given atom's number ATN in array ATOM returns a number from 1 to 32. // Atoms with related properties have the same number. It is required to reduce // the possible number of fragments in structure} int i; for (i=0; i0 // 0 - charge=0 if (nc < 0) return 2; if (nc > 0) return 1; return 0; }; int TSingleAtom::valencyConversion() { //for atom's number ATN in array ATOM returns some connected with valency value: // =2-Valence of ATN is less, then usual // =1-Valence of ATN is more, then usual // =0-usual valency int k1,k2; int result=0; //Default hydrogen k1=nv; k1=k1-currvalence-abs(nc)-rl; if (k1<0) k1=0; k2=hVal[na]; k2=k2-currvalence-abs(nc)-rl; if (k2<0) k2=0; if (k1 == k2) result=0; else if (k1 < k2) result=1; else result=2; return result; }; int TSingleAtom::allAtAtom() { //Define a digital representation of atom, they include: // a) Position of atom in the Periodic System // b) Its charge // c) Its valency} int b1,b2,b3,w; b1=encoder(); b2=chargeConversion(); b3=valencyConversion(); w=b3; w=w << 2; w=w+b2; w=w << 5; w=w+b1; if (rl != 0) w= ~w; return w; }; void TSingleAtom::atomCopy(TSingleAtom * source) { this->astereo=source->astereo; for (int i=0; iac[i]=source->ac[i]; this->currvalence=source->currvalence; this->iz=source->iz; this->na=source->na; this->nb=source->nb; this->nc=source->nc; this->nv=source->nv; this->rl=source->rl; this->rx=source->rx; this->ry=source->ry; this->special=source->special; }; bool TSingleAtom::atomEquivalent(TSingleAtom * structure, TSingleAtom * query, int nHStr, int nHQuery, bool chargeSensitivity, bool isotopeSensitivity) { bool result=false; int i,j,k; if ((structure == NULL) || (query == NULL)) return result; i=nHQuery; if (i>0) //if explicitly defined H is accociated with query atom { j=structure->nv; k=abs(structure->nc); if (k>9) k=k-9; j=j-structure->currvalence-k; if (j<0) j=0; j=j+nHStr; if (i>j) return result; //on corresponding structure atom must be at least the same number of H} } if (((structure->nc != query->nc) && chargeSensitivity) || ((structure->rl != query->rl) && chargeSensitivity) || ((structure->iz != query->iz) && isotopeSensitivity)) return result; //non-equivalency of Charge and Isotop is case of exact matching of these attributes i=query->special; //'NO OTHER' attribute on query if (i == 1) if ((structure->nb-nHStr) != query->nb) return result; //'NO OTHER' means, that number of neighbour in query must be the same as in structure //Checking for equivalent position in the Periodic Table if (structure->na == query->na) result=true; else { if (query->na == METALL_ATOM) //Metall checking { for (i=0; ina == metals[i]) { result=true; break; } } if (query->na == HALOGEN_ATOM) //Halogen checking { for (i=0; ina == halogens[i]) { result=true; break; } } if (query->na == HETERO_ATOM) //Hetero checking { for (i=0; ina == hetero[i]) { result=true; break; } } if (query->na == ANY_ATOM) result=true; //Any atom } return result; }; //---------------- TSingleBond methods ---------------------- TSingleBond * TSingleBond::clone() { TSingleBond * result; result=new TSingleBond(); result->at[0]=this->at[0]; result->at[1]=this->at[1]; result->bstereo=this->bstereo; result->db=this->db; result->special=this->special; result->tb=this->tb; result->enumerator=this->enumerator; return result; }; int TSingleBond::getValence() { int result=0; if (this->tb <=NBONDTYPES) result=bondValence[this->tb-1]; return result; }; bool TSingleBond::bondEquivalent(TSingleBond * sBond, TSingleBond * qBond) { //for bond's number BONDNUMBER in structure (BOND) and for query bond's number //QBONDNUMBER (QBOND) determines, if they may be accociated one with other. //QBC-array, for each query bond contains explicitly defined cyclic conditions: // 0-no cyclic condition is implemented // 1-query bond and corresponding structure bond must be a Chain // 2-query bond and corresponding structure bond must be a Ring //Function has 'TRUE' value if bonds can be matched, FALSE otherwise bool test1; int bT,qBT,bD,qBD; bool result=false; bT=sBond->tb; qBT=qBond->tb; bD=sBond->db; qBD=qBond->db; if (sBond->special>=3) sBond->special=sBond->special-3; if (qBond->special>=3) qBond->special=qBond->special-3; if (((qBond->special==1) && (bD>1)) || ((qBond->special==2) && (bD<2))) return result; //Explicitly defined cyclic conditions are violated if ((qBD>1) && (bD<2)) return result; //Implicitly defined cyclic conditions are violated} if (qBT==ANY_BOND) //Any bond in query { result=true; return result; }; if ((qBT==4) || (qBD==2) || (qBD==3)) //Aromatic bond { result=(bD==2) || (bD==3) || (bT==4); return result; }; if ((bD==2) || (bD==3)) { //non-Aromatic in query, but Aromatic in structure result=false; return result; }; test1=false; if ((qBT==5) && ((bT==1) || (bT==2) || (bT==5))) test1=true; //SINGLE/DOUBLE query bond if (bT==qBT) test1=true; //Type of bonds in structure and in query are equivalent} result=test1; return result; }; int TSingleBond::bondConversion() { //generate a code for bond's nuber BNB in array BOND. It is took into consi- //deration bond type and cycle size int b1,b2; if (tb > 4) b1=0; else b1=tb; b2=7; //for other Switch value switch (db) { case 0 : b2=5; break; case 1 : b2=0; break; case 2 : b1=4; b2=1; break; case 3 : b1=4; b2=2; break; case 4 : b2=3; break; case 5 : b2=4; break; case 6 : b2=6; break; }; b2=b2 << 2; b2=b2+b1; return b2; }; void TSingleBond::bondCopy(TSingleBond * source) { this->at[0]=source->at[0]; this->at[1]=source->at[1]; this->bstereo=source->bstereo; this->db=source->db; this->special=source->special; this->tb=source->tb; }; //****************************************************************** // TSimpleMolecule //------------------------------------------------------------------ class TSimpleMolecule { protected: std::vector fAtom; std::vector fBond; public: std::ostream * refofs; virtual ~TSimpleMolecule() { clear(); }; TSimpleMolecule() { refofs=NULL; }; int nAtoms(); int nBonds(); TSingleAtom * getAtom(int index); TSingleBond * getBond(int index); void defineAtomConn(); void defineBondConn(neigbourlist & bondConnection); void newB(neigbourlist & bk, int bnum, int anum, int & total, int * e, int * e1); void singleVawe(neigbourlist & bk, std::vector & alreadyDefined, std::vector & prevBond, std::vector & prevAtom, int & nPrev, std::vector & curBond, std::vector & curAtom); void vaweBond(int bondN, neigbourlist & bk, int & ringSize, std::vector & bondList); void allAboutCycles(); void redraw(const std::vectorlistAtomClean, const std::vectorlistBondClean, int & atomClean, int & bondClean, int spn, int sCHA1, int sCHB1, bool iOPT7); void clear(); void readOBMol(OBMol * pmol); void readConnectionMatrix(const std::vectoriA1, const std::vectoriA2, int nAtoms, int nBonds); void readConnectionMatrix(const std::vectoriA1, const std::vectoriA2, const std::vectorrx, const std::vectorry, int nAtoms, int nBonds); void redrawMolecule(); void getMolfile(std::ostream & data); bool checkOverlapped(); double averageBondLength(); void flipSmall(int cHB); int listarSize(); bool makeFragment(int& n, std::vector& list, int aT, int aTEx); void moleculeCopy(TSimpleMolecule & source); int correctOverlapped(); void normalizeCoordinates(double aveBL); void makeEquivalentList(std::vector& equivalenceList, bool isTopologyOnly); void bondEnlarge(int bN); void deleteAtom(int index); void deleteBond(int index); void addAtom(TSingleAtom * sa); void addAtom(int na, int charge, double rx, double ry); void addBond(TSingleBond * sb); void addBond(int tb, int at1, int at2); void setCoordinatesString(string value); void unitVector(int aN, double& xV, double& yV); void bondUnitVector(int bn, double& xv, double& yv); double bondLength(int index); int singleAtomicDescriptor(int aNumber,int bNumber, bool useEnumerator); int hasOverlapped(double delta, bool findFirst); int getNH(int atomNo); private: bool aromatic(int cycleSize, const std::vector bondList, std::vector& arom); void twoAtomUnitVector(int na1, int na2, double & xv, double & yv, const std::vectoratomDefine); void defC(int& currNumDef, int baseCycle, int atomClean, std::vector& cycleDefine, std::vector& atomDefine, std::vector& atomCycle, std::vector& cycleAddress, std::vector& cycleSize, std::vector& dsATN, std::vector& dsTP, std::vector& dsSC, std::vector& dsNA1, std::vector& dsNA2); void defA(int& currNumDef, int atomClean, int sPN, int baseCycle, std::vector& atomDefine, const std::vector listAtomClean, std::vector& cycleDefine, std::vector& cycleSize, std::vector& cycleAddress, std::vector& atomCycle, std::vector& dsATN, std::vector& dsTP, std::vector& dsNA1, std::vector& dsNA2); void canonizeCycle(int ringSize, std::vector & bondList); //Chain rotate members double atomDistanceMetric(int an); bool bondsOverlapped(int bN1, int bN2, double delta); int fragmentSecond(int sphere, int att, int secAt, const std::vector a, const std::vector b, const neigbourlist bk, std::vector& wSphere); bool threeBondResolve(int an, int bondExcluded, double& xv, double& yv, neigbourlist* bkExt); bool unitVectorCoincident(int aN, double xV, double yV); }; int TSimpleMolecule::getNH(int atomNo) { int result=0; TSingleAtom * atom; int i,n; if (atomNo >= nAtoms()) return result; atom=getAtom(atomNo); result=atom->nv; result=result-(atom->currvalence)+(atom->nc*TSingleAtom::chargeDeltaValency(atom->na))-(atom->rl); if (result < 0) result=0; if (atom->nb > 0) for (i=0; inb; i++) { n=atom->ac[i]; if (getAtom(n)->na == 1) result=result+1; }; return result; }; int TSimpleMolecule::singleAtomicDescriptor(int aNumber,int bNumber, bool useEnumerator) { //Bond BNumber has to have type=9 or 10 int result=0; int an [4]; int j,m,k; double x[3]; double y[3]; double r,r1,r2; bool testBad; double tn [2]; bool rsn; bool isInvert; if ((getAtom(aNumber)->nb < 3) || (getAtom(aNumber)->nb > 4)) return result; for (j=0; jnb; j++) an[j]=getAtom(aNumber)->ac[j]; if (useEnumerator) { //fragIndex as main base for (j=0; j<(getAtom(aNumber)->nb-1); j++) for (m=j+1; mnb; m++) if (getAtom(an[j])->fragIndex > getAtom(an[m])->fragIndex) { k=an[j]; an[j]=an[m]; an[m]=k; }; } else { for (j=0; j<(getAtom(aNumber)->nb-1); j++) for (m=j+1; mnb; m++) if (an[j] > an[m]) { k=an[j]; an[j]=an[m]; an[m]=k; }; }; // return 1; for (j=0; j<3; j++) { k=an[j]; x[j]=getAtom(k)->rx-getAtom(aNumber)->rx; y[j]=getAtom(k)->ry-getAtom(aNumber)->ry; }; isInvert=true; if (getAtom(aNumber)->nb == 4) if (getBond(bNumber)->at[1] != an[3]) { isInvert=false; for (j=0; j<3; j++) if (an[j] == getBond(bNumber)->at[1]) { k=an[3]; x[j]=getAtom(k)->rx-getAtom(aNumber)->rx; y[j]=getAtom(k)->ry-getAtom(aNumber)->ry; }; }; testBad=false; for (j=0; j<3; j++) { r=sqrt(x[j]*x[j]+y[j]*y[j]); if (r == 0) testBad=true; else { x[j]=x[j]/r; y[j]=y[j]/r; }; }; // return 1; if (! testBad) { for (j=0; j<2; j++) //determination of the sign of rotation { r1=x[0]*y[j+1]-y[0]*x[j+1]; //Sin r2=x[0]*x[j+1]+y[0]*y[j+1]; //Cos if (r1 < 0) r2=-2-r2; // 0 degress = +1; Pi/2 degrees = 0; Pi degrees = -1; 3*Pi/2 degrees = -2; 2*Pi degrees = -3 tn[j]=r2; }; rsn=( tn[0] > tn[1]); //return 1; //Analizing cases.... if (getBond(bNumber)->tb == 10) rsn=! rsn; if (getAtom(aNumber)->nb == 4) if (isInvert) rsn=! rsn; if (tn[0] != tn[1]) { if (rsn) result=1; else result=2; }; }; return result; }; void TSimpleMolecule::bondUnitVector(int bn, double& xv, double& yv) { //for bon's number BN in the structure, described by ATOM, BOND, CONN calculates //the unit vector (Xv,Yv on output). The vector is best direction to add new fra- //gment to current structure. The procedure is used by TEMPLATE and MAKEPOLI} double si,r1,r2,r3,s1,s2,s3,s4,x1,y1,y2; int na1,na2,i; na1=getBond(bn)->at[0]; na2=getBond(bn)->at[1]; s1=getAtom(na1)->rx; s2=getAtom(na1)->ry; s3=getAtom(na2)->rx; s4=getAtom(na2)->ry; r1=s1-s3; r2=s2-s4; r3=sqrt(r1*r1+r2*r2); r1=r1/r3; //COS r2=r2/r3; //SIN si=0; for (i=0; inb; i++) if (getAtom(na1)->ac[i] != na2) { x1=getAtom(getAtom(na1)->ac[i])->rx-s1; y1=getAtom(getAtom(na1)->ac[i])->ry-s2; y2=x1*r2-y1*r1; if (y2 != 0) si=si+y2/abs(y2); } for (i=0; inb; i++) if (getAtom(na2)->ac[i] != na1) { x1=getAtom(getAtom(na2)->ac[i])->rx-s3; y1=getAtom(getAtom(na2)->ac[i])->ry-s4; y2=x1*r2-y1*r1; if (y2 != 0) si=si+y2/abs(y2); } if (si != 0) si=si/abs(si); else si=1; xv=-r2*si; yv=r1*si; } bool TSimpleMolecule::threeBondResolve(int an, int bondExcluded, double& xv, double& yv, neigbourlist* bkExt) { //Addition from 16 April 2006 int bondNoList [3]; bool result=false; double centerX[3]; double centerY[3]; int nBondNo; neigbourlist* bk; std::vectorbondList(listarSize()); std::vector* blStore=NULL; bool testBad,testOK; int m,j,n1,n2,n,k; int rs; double dist,x,y,minDist; int i; bool test; int at; double r1,r2,s1,s3; if (bkExt != NULL) bk=bkExt; else { bk=(neigbourlist *)malloc((CONNMAX+1)*NBONDSMAX*4); defineBondConn(*bk); }; nBondNo=0; testBad=false; testOK=true; for (i=0; i<(*bk)[an].nb; i++) { n=(*bk)[an].adjusted[i]; if (n != bondExcluded) { vaweBond(n,*bk,rs,bondList); if (rs > 0) { //I have to analize bondList to determine second cycle to exclude adamanthane if (blStore == NULL) { //Save blStore= new std::vector(rs); for (j=0; jsize(); j++) (*blStore)[j]=bondList[j]; } else { m=0; for (j=0; jsize(); j++) { test=false; for (k=0; k 1) && (m < blStore->size())) { testOK=false; }; }; //center determination centerX[nBondNo]=0; centerY[nBondNo]=0; for (j=0; jat[0]; n2=getBond(m)->at[1]; centerX[nBondNo]=centerX[nBondNo]+getAtom(n1)->rx+getAtom(n2)->rx; centerY[nBondNo]=centerY[nBondNo]+getAtom(n1)->ry+getAtom(n2)->ry; }; centerX[nBondNo]=centerX[nBondNo]/(2*rs); centerY[nBondNo]=centerY[nBondNo]/(2*rs); bondNoList[nBondNo]=n; nBondNo++; }; };// else testBad:=true; if ((nBondNo == 3) || (testBad)) break; }; if (nBondNo < 2) testBad=true; if ((! testBad) && testOK) { dist=0; if (nBondNo == 2) { //single bond, attached to ring. Re-definition center.... x=0; y=0; for (i=0; irx; y=y+getAtom(i)->ry; }; x=x/nAtoms(); y=y/nAtoms(); for (i=0; iat[0]; if (at == an) at=getBond(bondNoList[i])->at[1]; r1=getAtom(at)->rx-getAtom(an)->rx; r2=getAtom(at)->ry-getAtom(an)->ry; s1=sqrt(r1*r1+r2*r2); if (s1 == 0) testBad=true; else { r1=r1/s1; r2=r2/s1; x=-r1; y=-r2; minDist=1000000000; for (j=0; jrx-centerX[j]); r2=(y*s1+getAtom(an)->ry-centerY[j]); s3=sqrt(r1*r1+r2*r2); if (s3 < minDist) minDist=s3; }; if (minDist > dist) { dist=minDist; xv=x; yv=y; }; }; }; if (! testBad) result=true; }; //end addition from 16 April 2006 if (bkExt == NULL) free(bk); if (blStore != NULL) delete(blStore); return result; }; bool TSimpleMolecule::unitVectorCoincident(int aN, double xV, double yV) { bool result=false; int i, aT; double r1,r2,s1; for (i=0; inb; i++) { aT=getAtom(aN)->ac[i]; r1=getAtom(aT)->rx-getAtom(aN)->rx; r2=getAtom(aT)->ry-getAtom(aN)->ry; s1=sqrt(r1*r1+r2*r2); if (s1 > 0.00001) { r1=r1/s1; r2=r2/s1; if ((abs(r1-xV) < 0.1) && (abs(r2-yV) < 0.1)) result=true; }; if (result) break; }; return result; }; void TSimpleMolecule::unitVector(int aN, double& xV, double& yV) { //For atom's number AN in the array ATOM (the same structure is described with //bond's array BOND and bond-connection matrix invariants CONN) unit vector //is calculated (XV, YV) on output. Unit vector shows the best direction to //make new bond} double sc[4] = {0,1/2,1.7320508/2,1}; double cc[4] = {1,1.7320508/2,1/2,0}; double sQ3=sqrt(3.0)/2.0; double si,r1,r2,r3,r4,s1,s2,s3,s4,fi; double xm[3]; //Initial dimensions 1..3 double ym[3]; //Initial dimensions 1..3 int i,i1,i2; int nB1,aT,aT1; bool mK[CONNMAX]; bool test; nB1=1; if (getAtom(aN)->nb == 0) { xV=1; yV=0; //if no atoms connected-horizontal unit vector return; } else if (getAtom(aN)->nb == 1) //single atom connected-start calculations} { aT=getAtom(aN)->ac[0]; r1=getAtom(aT)->rx-getAtom(aN)->rx; r2=getAtom(aT)->ry-getAtom(aN)->ry; s1=sqrt(r1*r1+r2*r2); if (s1 == 0) { xV=0.3826834; yV=-0.9238795; return; } r1=r1/s1; r2=r2/s1; nB1=getAtom(aT)->nb; si=1; if (nB1 > 1) { aT1=getAtom(aT)->ac[0]; if (aT1 == aN) aT1=getAtom(aT)->ac[1]; r3=getAtom(aT1)->rx-getAtom(aN)->rx; r4=getAtom(aT1)->ry-getAtom(aN)->ry; s2=sqrt(r3*r3+r4*r4); if (s2 == 0) s2=1; r3=r3/s2; r4=r4/s2; si=r2*r3-r4*r1; if (si != 0) si=si/abs(si); else si=1; } s3=sqrt(3.0)/2.0; s4=-0.5; xV=r1*s4-r2*si*s3; //single atom connected-unit vector at 2Pi/3 angle yV=r2*s4+r1*si*s3; } else //multiply connection case { xV=0; yV=0; for (i=0; inb; i++) mK[i]=true; if (getAtom(aN)->nb == 3) { //three-bond connection-search for projec. of tetrahedron if (threeBondResolve(aN,-1,xV,yV,NULL)) { return; }; for (i=0; i<3; i++) { aT=getAtom(aN)->ac[i]; xm[i]=getAtom(aT)->rx-getAtom(aN)->rx; ym[i]=getAtom(aT)->ry-getAtom(aN)->ry; r1=sqrt(xm[i]*xm[i]+ym[i]*ym[i]); xm[i]=xm[i]/r1; ym[i]=ym[i]/r1; } i=0; do //Search for bond, which make 30 degree angle with another { i1=1; i2=2; switch (i) { case 0: { i1=1; i2=2; break; } case 1: { i1=0; i2=2; break; } case 2: //Else value - only three { i1=0; i2=1; break; } } s1=xm[i1]*xm[i2]+ym[i1]*ym[i2]; s2=xm[i]*xm[i1]+ym[i]*ym[i1]; s3=xm[i]*xm[i2]+ym[i]*ym[i2]; test=false; if (abs(s1+0.5) < 0.05) //two bonds form 120 degrees angle { test=(abs(s2-sQ3)<0.05) || (abs(s3-sQ3)<0.05); if (! test) test=((abs(s2) < 0.05) && (abs(s3+sQ3)<0.05)) || ((abs(s3)<0.05) && (abs(s2+sQ3)<0.05)); } i++; } while (! (test || (i == 3))); if (test) mK[i-1]=false; //In the original Java code without -1 } for (i=0; inb; i++) if (mK[i]) { aT=getAtom(aN)->ac[i]; r1=getAtom(aT)->rx-getAtom(aN)->rx; r2=getAtom(aT)->ry-getAtom(aN)->ry; s1=sqrt(r1*r1+r2*r2); if (s1 < 0.05) s1=1; r1=r1/s1; r2=r2/s1; xV=xV-r1; yV=yV-r2; } r1=sqrt(xV*xV+yV*yV); if (r1 > 0.05) { //unit vector may be calculated from current connection xV=xV/r1; yV=yV/r1; } else { //impossible to calculate unit vector-more definitions if (getAtom(aN)->nb == 2) //linear existing connection-Pi/2 angle { aT=getAtom(aN)->ac[0]; r1=getAtom(aT)->rx-getAtom(aN)->rx; r2=getAtom(aT)->ry-getAtom(aN)->ry; s1=sqrt(r1*r1+r2*r2); if (s1 < 0.05) { xV=0.3826834; yV=-0.9238795; return; } r1=r1/s1; r2=r2/s1; xV=-r2; yV=-r1; } else if (getAtom(aN)->nb == 3) //3-bonds connection - projection of tetrahedrone is calculated { //Which of bonds has the horizontal direction r3=100000; for (i=0; i<3; i++) { aT=getAtom(aN)->ac[i]; r1=getAtom(aT)->rx-getAtom(aN)->rx; r2=getAtom(aT)->ry-getAtom(aN)->ry; s1=sqrt(r1*r1+r2*r2); if (s1 < 0.05) { xV=0.3826834; yV=-0.9238795; return; } r1=abs(r1/s1); r2=abs(r2/s1); if (r1 < r3) { r3=r1; nB1=i; } if (r2 < r3) { r3=r2; nB1=i; } } aT=getAtom(aN)->ac[nB1]; //Horizontal or vertical bond found} r1=getAtom(aT)->rx-getAtom(aN)->rx; r2=getAtom(aT)->ry-getAtom(aN)->ry; s1=sqrt(r1*r1+r2*r2); r1=r1/s1; r2=r2/s1; xV= r1*cos(150*PI/180)+r2*sin(150*PI/180); yV=-r1*sin(150*PI/180)+r2*cos(150*PI/180); } else { xV=sqrt(2.0)/2.0; //other case - Pi/4 to horizont angle yV=-xV; } } //checking if coincided xV and uV with existing bonds if (unitVectorCoincident(aN,xV,yV)) { fi=15*PI/180.0; r3=cos(fi); r4=sin(fi); r1= xV*r3+yV*r4; r2=-xV*r4+yV*r3; if (unitVectorCoincident(aN,r1,r2)) { r1=xV*r3-yV*r4; r2=xV*r4+yV*r3; }; if (unitVectorCoincident(aN,r1,r2)) { fi=7.5*PI/180.0; r3=cos(fi); r4=sin(fi); r1= xV*r3+yV*r4; r2=-xV*r4+yV*r3; if (unitVectorCoincident(aN,r1,r2)) { r1=xV*r3-yV*r4; r2=xV*r4+yV*r3; }; }; xV=r1; yV=r2; }; }; //Correction of angles, closed to 0, 30, 60, 90 degrees to exact values if (getAtom(aN)->nb < 6) for (i=0; i<4; i++) if ((abs(abs(xV)-sc[i])<0.04) && (abs(abs(yV)-cc[i]) < 0.04)) { if (xV < 0) xV=-sc[i]; else xV=sc[i]; if (yV < 0) yV=-cc[i]; else yV=cc[i]; } } void TSimpleMolecule::clear() { for (int i=0; ina=101; else if (s == "2") sa->na=102; else if (s == "3") sa->na=103; else if (s == "A") sa->na=ANY_ATOM; else if (s == "E") { sa->na=ANY_ATOM; sa->special=1; } else sa->na=6; //Atom.positionofAtom(s); n=n+1; s=value.substr(n,4); n=n+4; k=strtol(s.c_str(),NULL,10); sa->rx=(double)k/10000.0; s=value.substr(n,4); n=n+4; k=strtol(s.c_str(),NULL,10); sa->ry=(double)k/10000.0; addAtom(sa); }; s=value.substr(n,2); //2 symbols - number of bonds n=n+2; kk=strtol(s.c_str(),NULL,10); for (i=0; itb=ANY_BOND; //any bond s=value.substr(n,2); n=n+2; k=strtol(s.c_str(),NULL,10); sb->at[0]=k-1; s=value.substr(n,2); n=n+2; k=strtol(s.c_str(),NULL,10); sb->at[1]=k-1; addBond(sb); }; }; void TSimpleMolecule::addAtom(TSingleAtom * sa) { fAtom.push_back(sa); }; void TSimpleMolecule::addAtom(int na, int charge, double rx, double ry) { TSingleAtom * sa; sa=new TSingleAtom(); sa->na=na; sa->nc=charge; sa->rx=rx; sa->ry=ry; fAtom.push_back(sa); }; void TSimpleMolecule::addBond(TSingleBond * sb) { fBond.push_back(sb); }; void TSimpleMolecule::addBond(int tb, int at1, int at2) { TSingleBond * sb; sb=new TSingleBond(); sb->tb=tb; sb->at[0]=at1; sb->at[1]=at2; fBond.push_back(sb); }; void TSimpleMolecule::moleculeCopy(TSimpleMolecule & source) { TSingleAtom * sa; TSingleBond * sb; clear(); for (int i=0; iclone()); }; for (int i=0; iclone()); }; if (refofs == NULL) refofs=source.refofs; }; void TSimpleMolecule::deleteBond(int index) { std::vector tempBond(nBonds()); int i,n; n=0; //bond deletion for (i=0; i tempAtom(nAtoms()-1); std::vector tempBond(nBonds()); int i,n; n=0; //atom deletion for (i=0; iat[0] == index) || (getBond(i)->at[1] == index)) { delete(getBond(i)); fBond[i]=NULL; } else { if (getBond(i)->at[0] > index) getBond(i)->at[0]=getBond(i)->at[0]-1; if (getBond(i)->at[1] > index) getBond(i)->at[1]=getBond(i)->at[1]-1; tempBond[n]=getBond(i); n++; }; }; fBond.resize(n); for (i=0; iat[0]; k2=getBond(index)->at[1]; x=getAtom(k1)->rx-getAtom(k2)->rx; y=getAtom(k1)->ry-getAtom(k2)->ry; result=sqrt(x*x+y*y); return result; }; int TSimpleMolecule::listarSize() { int result=10; //Minimal vector size 10 if (nAtoms() > result) result=nAtoms(); if (nBonds() > result) result=nBonds(); return result; }; bool TSimpleMolecule::makeFragment(int& n, std::vector& list, int aT, int aTEx) { //Starting from atom's number AT in bond-connection matrix invariants array CONN //the all connected atom's (through one or more bonds) numbers are inserted into //the LIST array. Total number of such atoms is stored in N. If ATEX non-equal //zero, than atom with this number and all other, which is connected through //atom ATEX, don't include in LIST array. Boolean variable TEST has TRUE value //on output if between AT and ATEX exist cyclic bond, false otherwise} int i,j,k,l; bool test, test1; test=false; if ((nAtoms() ==0 ) || (aT < 0) || (aT >= nAtoms())) { n=0; list[0]=-1;; return test; } n=1; list[0]=aT; for (i=0; inb; i++) if (getAtom(aT)->ac[i] != aTEx) { list[n]=getAtom(aT)->ac[i]; n++; } if (n == 1) return test; //exit in AT non-connected atom k=0; do //iterational algorithm to define all} { for (i=0; inb; i++) { test1=false; l=getAtom(list[k])->ac[i]; if (l != aTEx) { for (j=0; j= 0) && (l < nAtoms())) { list[n]=l; n++; } } k=k+1; //atoms which are connected with AT} } while (kiA1, const std::vectoriA2, int nAtoms, int nBonds) { TSingleAtom * sa; TSingleBond * sb; int i; clear(); srand(30000); for (i=1; i<=nAtoms; i++) { sa=new TSingleAtom(); sa->na=6; sa->nv=hVal[sa->na]; sa->rx=(double)rand()/1000.0; sa->ry=(double)rand()/1000.0; fAtom.push_back(sa); }; for (i=0; iat[0]=iA1[i]; sb->at[1]=iA2[i]; sb->tb=1; fBond.push_back(sb); }; defineAtomConn(); allAboutCycles(); }; void TSimpleMolecule::readConnectionMatrix(const std::vectoriA1, const std::vectoriA2, const std::vectorrx, const std::vectorry, int nAtoms, int nBonds) { readConnectionMatrix(iA1,iA2,nAtoms,nBonds); for (int i=0; irx=rx[i]; getAtom(i)->ry=ry[i]; }; }; void TSimpleMolecule::normalizeCoordinates(double aveBL) { int i; double d,xMin,yMin; if (nAtoms() == 0) return; d=averageBondLength(); if ((d > 0) && (aveBL>0)) for (i=0; irx=getAtom(i)->rx*aveBL/d; getAtom(i)->ry=getAtom(i)->ry*aveBL/d; }; //Normalizing X and Y coordinates xMin=getAtom(0)->rx; yMin=getAtom(0)->ry; for (i=0; irx < xMin) xMin=getAtom(i)->rx; if (getAtom(i)->ry < yMin) yMin=getAtom(i)->ry; }; for (i=0; i< nAtoms(); i++) { getAtom(i)->rx=getAtom(i)->rx-xMin+aveBL; getAtom(i)->ry=getAtom(i)->ry-yMin+aveBL; }; }; void TSimpleMolecule::readOBMol(OBMol * pmol) { TSingleAtom * sa; TSingleBond * sb; OBAtom * atom; OBBond * bond; int na,nb,i; clear(); na=pmol->NumAtoms(); nb=pmol->NumBonds(); for (i=1; i<=na; i++) { atom=pmol->GetAtom(i); sa=new TSingleAtom(); sa->na=atom->GetAtomicNum(); sa->nc=atom->GetFormalCharge(); sa->rl=atom->GetSpinMultiplicity(); sa->rx=atom->GetX(); sa->ry=atom->GetY(); fAtom.push_back(sa); }; for (i=0; iGetBond(i); sb=new TSingleBond(); sb->at[0]=bond->GetBeginAtomIdx()-1; sb->at[1]=bond->GetEndAtomIdx()-1; sb->tb=bond->GetBondOrder(); // if (bond->IsUp()) sb->tb=9; // if (bond->IsDown()) sb->tb=10; if (bond->IsWedge()) sb->tb=9; if (bond->IsHash()) sb->tb=10; fBond.push_back(sb); }; defineAtomConn(); allAboutCycles(); }; int TSimpleMolecule::nAtoms() { return fAtom.size(); }; int TSimpleMolecule::nBonds() { return fBond.size(); }; TSingleAtom * TSimpleMolecule::getAtom(int index) { return (TSingleAtom *)fAtom.at(index); }; TSingleBond * TSimpleMolecule::getBond(int index) { return (TSingleBond *)fBond.at(index); }; void TSimpleMolecule::defineAtomConn() { //for each atom returns list of adjusted atoms in atomConnection int i,n1, n2; TSingleAtom * sa; for (i=0; inb=0; getAtom(i)->currvalence=0; }; for (i=0; iat[0]; n2=getBond(i)->at[1]; sa=getAtom(n1); sa->ac[sa->nb]=n2; sa->nb++; sa->currvalence=sa->currvalence+getBond(i)->getValence(); sa=getAtom(n2); sa->ac[sa->nb]=n1; sa->nb++; sa->currvalence=sa->currvalence+getBond(i)->getValence(); }; }; void TSimpleMolecule::defineBondConn(neigbourlist & bondConnection) { //for each atom returns list of adjusted bonds in bondConnection int i,n1, n2; for (i=0; i<=nAtoms(); i++) bondConnection[i].nb=0; for (i=0; iat[0]; n2=getBond(i)->at[1]; bondConnection[n1].adjusted[bondConnection[n1].nb]=i; bondConnection[n1].nb++; bondConnection[n2].adjusted[bondConnection[n2].nb]=i; bondConnection[n2].nb++; }; }; void TSimpleMolecule::newB(neigbourlist & bk, int bnum, int anum, int & total, int * e, int * e1) { /*for atom's number ANUM calculates the bond's list, which are connected with the ANUM, excluding bond BNUM. The bond's list is inserted into array L, TOTAL-number of components in the array. Array L1 contains atom's number which is connected with atom ANUM through corresponding bond in the array L.*/ int n,i; total=0; for (i=0; iat[0] == anum) e1[total]=getBond(n)->at[1]; else e1[total]=getBond(n)->at[0]; total++; }; }; void TSimpleMolecule::singleVawe(neigbourlist & bk, std::vector & alreadyDefined, std::vector & prevBond, std::vector & prevAtom, int & nPrev, std::vector & curBond, std::vector & curAtom) { /* a vawe algorithm is used to calculate the neighbour sphere. PREVBOND and PREVATOM contain on input the bond's and atom's list correspondingly, the atom has been took into consideration at previous step. NPREV-number of components in PREVBOND and PREVATOM on input. ALREADYDEFINED is the global array for procedure, which calls the SINGLEVAWE. It contains for each bond's number either zero, if the bond has not been took into consideration yet or bond's number from previous neighbour sphere. The subroutine makes next: 1) calculates the new neighbour sphere for each bond from PREVBOND. 2) if some bonds were not defined, they are labelled in ALREADYDEFINED, they numbers being stored into PREVBOND and PREVATOM. So, on output the arrays contain information for new neighbour sphere. 3) On output NPrev is changed so new number of component in PREVBOND is lighted} */ int e[CONNMAX]; int e1[CONNMAX]; int i,j,ncur; int n; ncur=0; n=0; for (i=0; i & bondList) { /*The procedure for bond's number BONDN determines, whether or not the bond belongs to ring (RINGSIZE=0 if not ring bond and RINGSIZE=number of atoms in the smallest ring, to which the bond is assigned). If the bond belongs to ring, array BONDLIST contains on output the bond's numbers, which are also assigned to the same ring */ int i,j,k,aA,i1,i2; std::vectorpA(NBONDSMAX); std::vectorpB(NBONDSMAX); std::vectoroD(NBONDSMAX); std::vectorcurBond(NBONDSMAX); std::vectorcurAtom(NBONDSMAX); bool test; int nP; for (j=0; jat[0];//pA.setValue(1,fBond.getAT(bondN,1)); aA=getBond(bondN)->at[1];//fBond.getAT(bondN,2); k=0; test=false; while (! ((nP==0) || test)) //recursion { ringSize++; singleVawe(bk,oD,pB,pA,nP,curBond,curAtom); //new neighbour sphere generation} test=false; if (nP>0) for (j=0; j i2) { bondList[i]=i2; bondList[j]=i1; }; }; } else ringSize=0; }; //This method must be called ONLY from AllAboutCycles bool TSimpleMolecule::aromatic(int cycleSize, const std::vector bondList, std::vector& arom) { /*for a cycle with the dimension of CYCLESIZE determines, whether or not the cycle is aromatic. BONDLIST contains the bond's numbers, which are belongs to the cycle. AROM-global array for the structure under study, for each bond in the structure contains label, whether the bond is aromatic or not. On out- put function AROMATIC contains TRUE if the ring is aromatic, FALSE otherwise */ bool test; int i,j,k,n,n1,m; int doubleDetected[11]; int atomDetected[11]; bool result=false; if ((cycleSize<5) || (cycleSize>6)) return result; //procedure define aromatic only for 5 or 6 membered cycles} //Simple Test} n=0; for (i=0; itb == 1) && (arom[k]==0)) doubleDetected[i]=0; else if ((getBond(k)->tb == 2) || (getBond(k)->tb == 4) || (arom[k]>0)) { n=n+1; //number of double or aromatic bonds calculation} doubleDetected[i]=1; } else return result; }; if (cycleSize==6) //6-membered ring} { if (n>=3) { result=true; if (n<=4) for (i=0; iat[0] == getBond(bondList[j])->at[0]) || (getBond(bondList[i])->at[0] == getBond(bondList[j])->at[1]) || (getBond(bondList[i])->at[1] == getBond(bondList[j])->at[0]) || (getBond(bondList[i])->at[1] == getBond(bondList[j])->at[1]); if (test) result=false; if (! result) break; }; if (! result) break; }; }; return result; }; if (n<2) return result; //5-membered ring m=0; for (i=0; iat[0]; m++; atomDetected[m]=getBond(bondList[i])->at[1]; m++; }; n=-1; if (m>0) for (i=0; i<(m-1); i++) for (j=i+1; j=0) { n1=-1; for (i=0; i<(m-1); i++) if (i != n) for (j=i+1; j=0) return result; }; if (n < 0) //No common atoms... { result=m==4; return result; }; test=false; i=0; j=getAtom(atomDetected[n])->na; for (i=0; inc < 0); //cyclopentadienyl checking} result=test; return result; }; void TSimpleMolecule::allAboutCycles() { /* for each bond in the structure cyclic conditions are calculated and stored into the BOND[I].DB variables. Possible values: 0 - chain; 1 - chain, appended to cycle; 2 - aromatic, 5-membered ring; 3 - aromatic, 6-membered ring; 4...more = non-aromatic ring size+1} */ std::vectorbondTested(NBONDSMAX); std::vectorbondList(NBONDSMAX); std::vectorar(NBONDSMAX); std::vectorrSize(NBONDSMAX); std::vectorar1(NBONDSMAX); std::vectorcycleDescription(3*NBONDSMAX); std::vectorcycleAddress(NBONDSMAX); int i,n,j,k; int cycleSize; neigbourlist * bk; bk=(neigbourlist *)malloc((1+CONNMAX)*NBONDSMAX*4); if (nBonds() == 0) { free(bk); return; } defineBondConn(*bk); //initial values for MainList-number of bonds, connected to each atom and their numbers in array BOND for (i=0; idb=0; ar[i]=0;; bondTested[i]=0; }; n=0; cycleAddress[0]=0; for (i=0; i0) //Yes, cyclic { canonizeCycle(cycleSize,bondList); n++; cycleAddress[n]=cycleAddress[n-1]+cycleSize; //store cycle definitions rSize[n-1]=cycleSize; for (j=0; j0) { j=1; while (j != 0) { j=0; for (i=0; idb==0) || (kdb)) getBond(bondList[j])->db=k; }; }; for (i=0; idb=2; if ((cycleSize==6) && (getBond(bondList[j])->db != 2)) getBond(bondList[j])->db=3; }; }; }; free(bk); }; void TSimpleMolecule::redrawMolecule() { int i; int atomClean; int bondClean; std::vectorlistAtomClean(nAtoms()); std::vectorlistBondClean(nBonds()); if (nAtoms()==0) return; for (i=0; iatomDefine) { /*Using atom's numbers NA1 and NA2 in the array ATOMS calculates the direction for bond between NA1 and NA2 (XV,YV on output). At this direction new substitutor may be added with optimal place.*/ double si,r1,r2,r3,s1,s2,s3,s4,x1,y1,y2; int i,k; if ((getAtom(na1)->rx==getAtom(na2)->rx) && (getAtom(na1)->ry==getAtom(na2)->ry)) { xv=1; yv=1; return; }; s1=getAtom(na1)->rx; s2=getAtom(na1)->ry; s3=getAtom(na2)->rx; s4=getAtom(na2)->ry; r1=s1-s3; r2=s2-s4; r3=sqrt(r1*r1+r2*r2); r1=r1/r3; r2=r2/r3; si=0; for (i=0; inb; i++) { k=getAtom(na1)->ac[i]; if (k != na2) if (atomDefine[k] > 0) { x1=getAtom(k)->rx-s1; y1=getAtom(k)->ry-s2; y2=x1*r2-y1*r1; if (y2 != 0) si=si+y2/abs(y2); }; }; for (i=0; inb; i++) { k=getAtom(na2)->ac[i]; if (k != na1) if (atomDefine[k] > 0) { x1=getAtom(k)->rx-s3; y1=getAtom(k)->ry-s4; y2=x1*r2-y1*r1; if (y2 != 0) si=si+y2/abs(y2); }; }; if (si != 0) si=si/abs(si); else si=1; xv=-r2*si; yv=r1*si; }; void TSimpleMolecule::defC(int& currNumDef, int baseCycle, int atomClean, std::vector& cycleDefine, std::vector& atomDefine, std::vector& atomCycle, std::vector& cycleAddress, std::vector& cycleSize, std::vector& dsATN, std::vector& dsTP, std::vector& dsSC, std::vector& dsNA1, std::vector& dsNA2) { //The procedure create priority list formation for cleaning of molecule. Recur- // sive calls to the procedure are required together with DefA. After recursion // have been finished, the DEFINESEQUENCE array will be created. The procedure // analyze cyclic fragments int aA,cN,maxAtDef,i,j,atDef; bool test; test=true; while (test) { cN=-1; if ((baseCycle==0) || (currNumDef==atomClean)) return; maxAtDef=0; for (i=0; i0) atDef=atDef+1; if (atDef > maxAtDef) { // { search for cycles, for which maximal number of atoms were inserted in the priority list} maxAtDef=atDef; cN=i; } else if ((maxAtDef > 0) && (atDef==maxAtDef)) { // {search for minimal cycle size} if (cycleSize[i]=0) if (maxAtDef==cycleSize[cN]) { cycleDefine[cN]=1; cN=-1; }; // {CN-number of selected cycle with max.number of atoms, already defined, or with minimal size} if (cN>=0) { cycleDefine[cN]=1; //{Label, that CN-th cycle is inserted into priority list} test=(atomDefine[atomCycle[cycleAddress[cN]]]>0) && (atomDefine[atomCycle[cycleAddress[cN]+cycleSize[cN]-1]]==0); // {if first atom from cyclic fragment was inserted into list previously and last-no} while (! test) { // {enumeration of atom's sequence in cyclic fragment} aA=atomCycle[cycleAddress[cN]]; for (j=1; j0) && (atomDefine[atomCycle[cycleAddress[cN]+cycleSize[cN]-1]]==0); }; // {now first atom in the cycle definition list must be inserted into the priority list early, and the last atom-no} for (j=0; j& atomDefine, const std::vector listAtomClean, std::vector& cycleDefine, std::vector& cycleSize, std::vector& cycleAddress, std::vector& atomCycle, std::vector& dsATN, std::vector& dsTP, std::vector& dsNA1, std::vector& dsNA2) { //The procedure create priority list formation for cleaning of molecule. Recur- // sive calls to the procedure are required together with DefC. After recursion //have been finished, the DEFINESEQUENCE array will be created. The procedure //analyze chain fragments int i,j,k,rC; if (currNumDef==atomClean) return; for (i=0; inb > 0) for (j=0; jnb; j++) { k=getAtom(listAtomClean[i])->ac[j]; if (atomDefine[k]>0) { //if atom has a neighbour, which has already been inserted into priority // list, then it is inserted into the priority list} dsATN[currNumDef]=listAtomClean[i]; atomDefine[dsATN[currNumDef]]=1; dsTP[currNumDef]=1; //type of clean} dsNA1[currNumDef]=k; dsNA2[currNumDef]=-1; currNumDef++; //only one atom is added into priority list, then it is necessary to // analyze cycles by DEFC procedure!} return; }; }; if ((sPN<3) || (sPN==4)) //{next may not be implemented to CleanGroup command} { //{initializing priority list for clean of a new fragment} rC=0; j=100000; //minimal cycle size searching} if (baseCycle>0) for (i=0; i0) i=atomCycle[cycleAddress[rC]]; else { // {not found-first undefined atom is selected} i=0; while (atomDefine[listAtomClean[i]] != 0) i++; i=listAtomClean[i]; }; } else i=listAtomClean[atomClean-1]; //for group-first atom, from which group started, is selected} dsATN[currNumDef]=i; atomDefine[dsATN[currNumDef]]=1; dsTP[currNumDef]=0; //type of clean} dsNA1[currNumDef]=-1; dsNA2[currNumDef]=-1; currNumDef++; //Addition the atom selected to the list} }; void TSimpleMolecule::canonizeCycle(int ringSize, std::vector & bondList) { //Order of nonds in cycle description in so way, that bond with minimal number //is the first in this description. Then is coming bond, which is appended to //atom with maximal number, then next and so on std::vector bondUsed(ringSize); std::vector newBondList(ringSize); int i,j,n,m,currentAtom; n=bondList[0]; m=0; for (i=0; iat[0]; if (getBond(n)->at[1] > currentAtom) currentAtom=getBond(n)->at[1]; newBondList[0]=n; bondUsed[m]=1; n=1; for (i=1; iat[0] == currentAtom) || (getBond(m)->at[1] == currentAtom)) { bondUsed[j]=1; newBondList[n]=m; n++; if (getBond(m)->at[0] == currentAtom) currentAtom=getBond(m)->at[1]; else currentAtom=getBond(m)->at[0]; break; }; }; }; //copy new set for (i=0; i bondList(nBonds()); std::vector blStore(nBonds()); bool testBad,testOK; int m,j,n1,n2,n,k; int rs; double dist,x,y,minDist; int i; bool test,testStore; int at; double r1,r2,s1,s3; xv=0; yv=1; nBondNo=0; testBad=false; testOK=true; testStore=false; for (i=0; i 0) { //I have to analize bondList to determine second cycle to exclude adamanthane if (! testStore) { //Save blStore.clear(); for (j=0; j 1) && (m < blStore.size())) { testOK=false; }; }; //center determination centerX[nBondNo]=0; centerY[nBondNo]=0; for (j=0; jat[0]; n2=getBond(m)->at[1]; centerX[nBondNo]=centerX[nBondNo]+getAtom(n1)->rx+getAtom(n2)->rx; centerY[nBondNo]=centerY[nBondNo]+getAtom(n1)->ry+getAtom(n2)->ry; }; centerX[nBondNo]=centerX[nBondNo]/(2*rs); centerY[nBondNo]=centerY[nBondNo]/(2*rs); bondNoList[nBondNo]=n; nBondNo++; }; };// else testBad:=true; if ((nBondNo == 3) || (testBad)) break; }; if (nBondNo < 2) testBad=true; if ((! testBad) && testOK) { dist=0; if (nBondNo == 2) { //single bond, attached to ring. Re-definition center.... x=0; y=0; for (i=0; irx; y=y+getAtom(i)->ry; }; x=x/(double)nAtoms(); y=y/(double)nAtoms(); for (i=0; iat[0]; if (at== an) getBond(bondNoList[i])->at[1]; r1=getAtom(at)->rx-getAtom(an)->rx; r2=getAtom(at)->ry-getAtom(an)->ry; s1=sqrt(r1*r1+r2*r2); if (s1 == 0) testBad=true; else { r1=r1/s1; r2=r2/s1; x=-r1; y=-r2; minDist=1000000000; for (j=0; jrx-centerX[j]); r2=(y*s1+getAtom(an)->ry-centerY[j]); s3=sqrt(r1*r1+r2*r2); if (s3 < minDist) minDist=s3; }; if (minDist > dist) { dist=minDist; xv=x; yv=y; }; }; }; if (! testBad) result=true; }; //end addition from 16 April 2006 return result; }; */ void TSimpleMolecule::redraw(const std::vectorlistAtomClean, const std::vectorlistBondClean, int & atomClean, int & bondClean, int spn, int sCHA1, int sCHB1, bool iOPT7) { std::vector dsATN(NBONDSMAX); std::vector dsTP(NBONDSMAX); std::vector dsSC(NBONDSMAX); std::vector dsNA1(NBONDSMAX); std::vector dsNA2(NBONDSMAX); /* the arrays are the priority list for clean. Minimal element of record has the maximal priority. Each element of record contains: ATN-atom's number in the ATOM array, coordinate of which must be calculated at current step. TP -type of calculation of coordinates for the atom ATN: =0 - simple put at any position =1 - calculation from coordinates of previously defined atom NA1. NA2 value hasn't effect in the case. =2 - for cyclic fragment, coordinates of all cyclic atoms must be cal- culated from the ones for atom NA1-base atom in cycle. This type means fragment: chain bond, attached to the cycle. NA2 value hasn't effect in the case. =3 - for cyclic fragment, coordinates of all cyclic atoms must be cal- culated from the ones for pair of atoms NA1 and NA2. The pair is connected with bond. This type means fragment in condenced-cyclic systems. =4 - for cyclic fragment, coordinates of all cyclic atoms must be cal- culated from the ones for pair of atoms NA1 and NA2. The pair is connected through more, then one bond. This type means fragment in polycyclic systems. AN1,AN2-auxiliary atom's numbers (see TP description). SC-cycle size minus number of already defined atoms. The variable is taken into consideration for TP=2-4. */ bool test; int cs; int add,nb,k,k1,k2,l,i,j,baseCycle,lx,ly; int currNumDef; int atomSecond; std::vector atomCycle(2*3*nBonds()); std::vector cycleDescription(2*3*nBonds()); std::vector cycleAddress(nBonds()); std::vector atomDefine(NBONDSMAX); std::vector cycleSize(NBONDSMAX); std::vector cycleDefine(NBONDSMAX); std::vector tempArray(NBONDSMAX); double r,cf,fi,ux,uy,ux1,uy1,ux2,uy2,uvX,uvY,c,s; double xCenterOld,yCenterOld,xCenterNew,yCenterNew,bondLengthOld,bondLengthNew; neigbourlist bk; int n,n1,n2; double r1; bool isCycle,isChainFour; int mm1,mm2,mAny,bnEx; //Lx,Ly,Button:integer; if ((atomClean<1) || (bondClean==0)) return; defineAtomConn(); allAboutCycles(); test=true; defineBondConn(bk); //{Start clean for LISTATOMCLEAN and LISTBONDCLEAN atoms and bonds} cycleAddress[0]=0; baseCycle=0; cs=0; ux=0; uy=0; uvX=0; uvY=0; atomSecond=0; for (i=0; i0) { canonizeCycle(cs,atomDefine); test=false; for (j=0; jat[0]==getBond(j)->at[0]) || (getBond(k)->at[0]==getBond(j)->at[1])) atomCycle[cycleAddress[i]+0]=getBond(k)->at[0]; else atomCycle[cycleAddress[i]+0]=getBond(k)->at[1]; n=atomCycle[cycleAddress[i]+0]; //previoulsly putted atom for (j=1; jat[0]==n) atomCycle[cycleAddress[i]+j]=getBond(k)->at[1]; else atomCycle[cycleAddress[i]+j]=getBond(k)->at[0]; n=atomCycle[cycleAddress[i]+j]; }; }; //calculation of the coordinates of fragment's center and scaling factor} if ((spn<3) || (spn==4)) { xCenterOld=0; yCenterOld=0; bondLengthOld=0; if (spn == 4) { for (i=0; irx; yCenterOld=yCenterOld+getAtom(i)->ry; n++; }; xCenterOld=xCenterOld/(double)n; yCenterOld=yCenterOld/(double)n; for (i=0; ibondLength(i); if (r < bondLengthOld) bondLengthOld=n; r1=r1+r; n++; }; r1=r1/n; if (5*bondLengthOld < r1) bondLengthOld=r1; } else { for (i=0; irx; yCenterOld=yCenterOld+getAtom(k)->ry; }; xCenterOld=xCenterOld/(double)atomClean; yCenterOld=yCenterOld/(double)atomClean; for (i=0; ibondLength(k); }; bondLengthOld=bondLengthOld/(double)bondClean; }; if (bondLengthOld<0.01) bondLengthOld=1; } else { xCenterOld=getAtom(sCHA1)->rx; //{CHA1 - To atom connected, CHB1-splitting bond} yCenterOld=getAtom(sCHA1)->ry; lx=getBond(sCHB1)->at[0]; ly=getBond(sCHB1)->at[1]; if (ly == sCHA1) { lx=getBond(sCHB1)->at[1]; ly=getBond(sCHB1)->at[0]; }; atomSecond=ly; //for group it is necessary to calculate unit vector direction uvX=getAtom(ly)->rx-getAtom(lx)->rx; uvY=getAtom(ly)->ry-getAtom(lx)->ry; bondLengthOld=sqrt(uvX*uvX+uvY*uvY); if (bondLengthOld<0.01) bondLengthOld=1; uvX=uvX/bondLengthOld; uvY=uvY/bondLengthOld; }; for (i=0; irx=(xCenterOld+(getAtom(i)->rx-xCenterOld)/bondLengthOld); getAtom(i)->ry=(yCenterOld+(getAtom(i)->ry-yCenterOld)/bondLengthOld); }; }; i=0; if (atomClean>=1) while (irx=xCenterOld+(getAtom(dsATN[i])->rx-xCenterOld)/bondLengthOld; getAtom(dsATN[i])->ry=yCenterOld+(getAtom(dsATN[i])->ry-yCenterOld)/bondLengthOld; break; } case 1: case 2: if (atomDefine[dsATN[i]] == 0) { k1=dsNA1[i]; k=getAtom(k1)->nb; nb=0; ux=0; uy=0; ux1=0; uy1=0; //bond direction calculation} for (j=0; jac[j]]>0) { k2=getAtom(k1)->ac[j]; nb=nb+1; //number of already cleaned atoms} ux=ux+(getAtom(k1)->rx-getAtom(k2)->rx); uy=uy+(getAtom(k1)->ry-getAtom(k2)->ry); if (dsTP[i]==1) for (l=0; lnb; l++) if (atomDefine[getAtom(k2)->ac[l]]>0) { ux1=ux1+(getAtom(k2)->rx-getAtom(getAtom(k2)->ac[l])->rx); uy1=uy1+(getAtom(k2)->ry-getAtom(getAtom(k2)->ac[l])->rx); }; }; if (dsTP[i]==1) //chain fragment { if ((abs(ux) <= 0.00001) && (abs(uy) <= 0.00001)) { bnEx=-1; for (j=0; jat[0]; if (n1 == k1) n1=getBond(n)->at[1]; if (n1 == dsATN[i]) bnEx=n; if (bnEx >= 0) break; }; test= (bnEx >= 0); if (test) test=threeBondResolve(k1,bnEx,ux,uy,&bk); if (! test) { ux=ux1; uy=uy1; }; }; if ((ux==0) && (uy==0)) ux=1; fi=(k-nb-1)*PI/(double)k; //Addition for fluorine chain fragments... isChainFour=false; n=0; mm1=-1; mm2=-1; mAny=-1; if ((k == 4) && (getAtom(k1)->na == 6)) for (j=0; jnb; j++) { n1=getAtom(k1)->ac[j]; if (atomDefine[n1] == 0) { mAny=n1; if (getAtom(n1)->nb == 1) n++; else { if (mm1 == -1) mm1=n1; else mm2=n1; }; }; }; if ((mm1 == -1) && (n == 3)) { mm1=mAny; n--; }; isChainFour=(n == 2) && (mm1 >= 0); //End addition isCycle=false; if ((nb == 2) && ((k == 4) || (k == 5))) { n=0; for (j=0; jdb > 1) { n1=getBond(k2)->at[0]; if (n1 == k1) n1=getBond(k2)->at[1]; if (atomDefine[n1] != 0) n++; }; }; isCycle=(n == 2); }; if (isChainFour) { n=0; fi=PI/3; ux1= ux*cos(fi)+uy*sin(fi); uy1=-ux*sin(fi)+uy*cos(fi); cf=sqrt(ux1*ux1+uy1*uy1); if (cf != 0) { ux1=ux1/cf; uy1=uy1/cf; }; getAtom(mm1)->rx=getAtom(k1)->rx+ux1; //coordinates getAtom(mm1)->ry=getAtom(k1)->ry+uy1; atomDefine[mm1]=1; if (mm2 >= 0) { fi=-PI/3; ux1= ux*cos(fi)+uy*sin(fi); uy1=-ux*sin(fi)+uy*cos(fi); cf=sqrt(ux1*ux1+uy1*uy1); if (cf != 0) { ux1=ux1/cf; uy1=uy1/cf; }; getAtom(mm2)->rx=getAtom(k1)->rx+ux1; //coordinates getAtom(mm2)->ry=getAtom(k1)->ry+uy1; //coordinates atomDefine[mm2]=1; }; ux=0; uy=0; //New cosines.... for (j=0; jnb; j++) if (atomDefine[getAtom(k1)->ac[j]] > 0) { k2=getAtom(k1)->ac[j]; ux=ux+(getAtom(k1)->rx-getAtom(k2)->rx); uy=uy+(getAtom(k1)->ry-getAtom(k2)->ry); }; fi=PI/6; for (j=0; jnb; j++) { n1=getAtom(k1)->ac[j]; if (atomDefine[n1] == 0) { ux1= ux*cos(fi)+uy*sin(fi); uy1=-ux*sin(fi)+uy*cos(fi); cf=sqrt(ux1*ux1+uy1*uy1); if (cf != 0) { ux1=ux1/cf; uy1=uy1/cf; }; getAtom(n1)->rx=getAtom(k1)->rx+ux1; //coordinates} getAtom(n1)->ry=getAtom(k1)->ry+uy1; //coordinates} fi=-fi; atomDefine[n1]=1; }; }; } else if (isCycle) { if (k == 4) fi=PI/6; else fi=PI/3; ux1= ux*cos(fi)+uy*sin(fi); uy1=-ux*sin(fi)+uy*cos(fi); cf=sqrt(ux1*ux1+uy1*uy1); if (cf != 0) { ux1=ux1/cf; uy1=uy1/cf; }; getAtom(dsATN[i])->rx=getAtom(k1)->rx+ux1; //coordinates getAtom(dsATN[i])->ry=getAtom(k1)->ry+uy1; //coordinates atomDefine[dsATN[i]]=1; for (j=0; jnb; j++) { k2=getAtom(dsNA1[i])->ac[j]; if (atomDefine[k2] == 0) { ux1=ux*cos(fi)-uy*sin(fi); uy1=ux*sin(fi)+uy*cos(fi); if (cf != 0) { ux1=ux1/cf; uy1=uy1/cf; }; getAtom(k2)->rx=getAtom(k1)->rx+ux1; getAtom(k2)->ry=getAtom(k1)->ry+uy1; fi=0; atomDefine[k2]=1; }; }; } else { if (bk[dsNA1[i]].nb == 2) //two-connected fragment { //Search for triple bond or for two double-bonds n1=bk[dsNA1[i]].adjusted[0]; n2=bk[dsNA1[i]].adjusted[1]; if ((getBond(n1)->tb == 3) || (getBond(n2)->tb == 3)) k=3; else if ((getBond(n1)->tb == 2) && (getBond(n2)->tb == 2)) { if (getAtom(dsNA1[i])->na == 6) k=3; }; }; //Two-conncted fragment like pyrophosphate if ((k== 2) && (getAtom(dsNA1[i])->na != 6)) { n1=getAtom(dsNA1[i])->ac[0]; n2=getAtom(dsNA1[i])->ac[1]; if ((getAtom(n1)->nb >= 4) && (getAtom(n2)->nb >= 4) && (getAtom(n1)->na != 6) && (getAtom(n2)->na != 6)) k=3; }; //End pyrophosphate if (k==2) //120 degrees fragment} { if ((ux1==0) && (uy1==0)) ux1=1; fi=PI/3; cf=uy*ux1-ux*uy1; if (cf != 0) fi=fi*cf/abs(cf); }; ux1=ux*cos(fi)+uy*sin(fi); uy1=-ux*sin(fi)+uy*cos(fi); cf=sqrt(ux1*ux1+uy1*uy1); if (cf != 0) { ux1=ux1/cf; uy1=uy1/cf; }; getAtom(dsATN[i])->rx=getAtom(k1)->rx+ux1; //coordinates getAtom(dsATN[i])->ry=getAtom(k1)->ry+uy1; //coordinates atomDefine[dsATN[i]]=1; }; } else //cyclic fragment} { if ((ux==0) && (uy==0)) ux=1; fi=(k-nb-2)*PI/(double)k; ux1=ux*cos(fi)+uy*sin(fi); uy1=-ux*sin(fi)+uy*cos(fi); cf=sqrt(ux1*ux1+uy1*uy1); if (cf != 0) { ux1=ux1/cf; uy1=uy1/cf; }; nb=dsSC[i]; cs=nb+1; cf=1/(2*sin(PI/(double)cs)); ux=getAtom(dsNA1[i])->rx+cf*ux1; uy=getAtom(dsNA1[i])->ry+cf*uy1; fi=2*PI/(double)cs; ux1=getAtom(dsNA1[i])->rx-ux; uy1=getAtom(dsNA1[i])->ry-uy; //coordinates of all atoms for the cycle under study are calculated} for (j=0; jrx=ux+ux1*cos((j+1)*fi)+uy1*sin((j+1)*fi); getAtom(dsATN[i+j-0])->ry=uy-ux1*sin((j+1)*fi)+uy1*cos((j+1)*fi); atomDefine[dsATN[i+j-0]]=1; }; i=i+nb-1; }; break; } else break; case 3: case 4: { twoAtomUnitVector(dsNA1[i],dsNA2[i],ux,uy,atomDefine); //calculation of an optimal side to add new fragment ux1=getAtom(dsNA1[i])->rx-getAtom(dsNA2[i])->rx; uy1=getAtom(dsNA1[i])->ry-getAtom(dsNA2[i])->ry; if (dsTP[i]==3) //angle calc. for condenced cycle} { nb=dsSC[i]; cs=nb+2; fi=sqrt(ux1*ux1+uy1*uy1); cf=fi/(2*sin(PI/(double)cs)/cos(PI/(double)cs)); add=0; } else //angle calc. for polycycle { r=sqrt(ux1*ux1+uy1*uy1); add=(int)ceil(r); nb=dsSC[i]; cs=nb+2+add; cf=r/(2*sin(PI*(nb+1)/(double)cs)); r=r/2.0; cf=sqrt(cf*cf-r*r); }; ux=(getAtom(dsNA1[i])->rx+getAtom(dsNA2[i])->rx)/2.0+ux*cf; uy=(getAtom(dsNA1[i])->ry+getAtom(dsNA2[i])->ry)/2.0+uy*cf; ux1=getAtom(dsNA1[i])->rx-ux; uy1=getAtom(dsNA1[i])->ry-uy; fi=2*PI/(double)cs; ux2=ux+ux1*cos((1.0+add)*fi)+uy1*sin((1.0+add)*fi); uy2=uy-ux1*sin((1.0+add)*fi)+uy1*cos((1.0+add)*fi); if ((abs(getAtom(dsNA2[i])->rx-ux2)<0.01) && (abs(getAtom(dsNA2[i])->ry-uy2)<0.01)) fi=-fi; //FAtom's coordinates calculation for (j=0; jrx=ux+ux1*cos((j+1)*fi)+uy1*sin((j+1)*fi); getAtom(dsATN[i+j-0])->ry=uy-ux1*sin((j+1)*fi)+uy1*cos((j+1)*fi); atomDefine[dsATN[i+j-0]]=1; } i=i+nb-1; break; } } i++; } bondLengthNew=0; //Rescaling and shift of structure for (i=0; irx; yCenterNew=yCenterNew+getAtom(listAtomClean[i])->ry; }; xCenterNew=xCenterNew/(double)atomClean; yCenterNew=yCenterNew/(double)atomClean; bondLengthNew=0.15*bondLengthOld; //IOPT[7]-controlles, whether or not the atom's shifts should be created, if coordinates of pair of atoms are identical if (spn==3) //Rescaling and shift coordinates for group (CODE=3) { xCenterNew=getAtom(sCHA1)->rx; yCenterNew=getAtom(sCHA1)->ry; ux=getAtom(atomSecond)->rx-getAtom(sCHA1)->rx; uy=getAtom(atomSecond)->ry-getAtom(sCHA1)->ry; r=sqrt(ux*ux+uy*uy); ux=ux/r; uy=uy/r; c=ux*uvX+uy*uvY; s=ux*uvY-uy*uvX; for (i=0; irx-xCenterNew; uy1=getAtom(listAtomClean[i])->ry-yCenterNew; getAtom(listAtomClean[i])->rx=c*ux1-s*uy1; getAtom(listAtomClean[i])->ry=s*ux1+c*uy1; }; xCenterNew=0; yCenterNew=0; }; if (spn != 4) for (i=0; irx=getAtom(listAtomClean[i])->rx-xCenterNew+xCenterOld; getAtom(listAtomClean[i])->ry=getAtom(listAtomClean[i])->ry-yCenterNew+yCenterOld; }; }; void TSimpleMolecule::getMolfile(std::ostream & data) { char buff[BUFF_SIZE]; TSingleAtom * sa; TSingleBond * sb; int charge,bondType,stereoType; data<nc) { case 1: charge = 3; break; case 2: charge = 2; break; case 3: charge = 1; break; case -1: charge = 5; break; case -2: charge = 6; break; case -3: charge = 7; break; default: charge=0; break; } snprintf(buff, BUFF_SIZE, "%10.4f%10.4f%10.4f %-3s%2d%3d%3d%3d%3d", sa->rx, sa->ry, 0.0, (aSymb[sa->na]).c_str(), 0,charge,0,0,0); data << buff << endl; }; for (int i=0; itb; stereoType=0; if (bondType == 9) { bondType=1; stereoType=1; } else if (bondType == 10) { bondType=1; stereoType=6; } else if (bondType == 11) { bondType=1; stereoType=4; }; snprintf(buff, BUFF_SIZE, "%3d%3d%3d%3d%3d%3d",(sb->at[0]+1), (sb->at[1]+1), bondType, stereoType, 0, 0); data << buff << endl; }; }; //******************************************************************************* //Below routines from ChainRotate-flipping acyclic bonds and enlarging bonds to get fine picture //******************************************************************************* double TSimpleMolecule::atomDistanceMetric(int an) { int i, n; double r, rr; double x1, y1, x2, y2, d, result; if (getAtom(an)->nb == 0) return 0; result=0.01; n=getAtom(an)->ac[0]; x1=getAtom(an)->rx-getAtom(n)->rx; y1=getAtom(an)->ry-getAtom(n)->ry; rr=sqrt(x1*x1+y1*y1); for (i=0; irx-getAtom(n)->rx; y2=getAtom(i)->ry-getAtom(n)->ry; d=rr*sqrt(x2*x2+y2*y2); if (d == 0) r=0; else r=(x1*x2+y1*y2)/d; if (r > 0) result=result+r; }; return result; }; double xDistPoint(double x1, double y1, double x2, double y2, double x0, double y0) { //The function finds distance between FAtom AN and bond BN (including sign). // The bond is treated as segment, not as straight line!} double d, r, r1, yMin, yMax, xMin, xMax, xx, yy, result; if (y1 < y2) { yMin=y1; yMax=y2; } else { yMin=y2; yMax=y1; }; xx=x1-x2; yy=y1-y2; r1=sqrt(xx*xx+yy*yy); yMin=yMin-0.1*r1; yMax=yMax+0.1*r1; d=y2-y1; if (abs(d) < 1E-8) { result=1E9; return result; }; if ((y0 > yMin) && (y0 < yMax)) { r=x1+(y0-y1)*(x2-x1)/d; if (x1 > x2) { xMin=x2; xMax=x1; } else { xMin=x1; xMax=x2; }; xMin=xMin-0.1*r1; xMax=xMax+0.1*r1; if (r < xMin) r=xMin; if (r > xMax) r=xMax; result=r-x0; } else result=1E9; return result; }; bool overlapped(double x1A, double y1A, double x2A, double y2A, double x1B, double y1B, double x2B, double y2B, double delta) { double a1, b1, c1, a2, b2, c2, r, cX, cY, x, y, r1, r2; double xMin, xMax, yMin, yMax; bool result=false; r=y2A-y1A; if (abs(r) > 1E-9) { a1=1/r; cY=-y1A/r; } else { a1=1E9; cY=-y1A*1E9; if (r < 0) { a1=-a1; cY=-cY; }; }; r=x2A-x1A; if (abs(r) > 1E-9) { b1=1/r; cX=x1A/r; } else { b1=1E9; cX=x1A*1E9; if (r < 0) { b1=-b1; cX=-cX; }; }; b1=-b1; c1=cX+cY; r=y2B-y1B; if (abs(r) > 1E-9) { a2=1/r; cY=-y1B/r; } else { a2=1E9; cY=-y1B*1E9; if (r < 0) { a2=-a2; cY=-cY; }; }; r=x2B-x1B; if (abs(r) > 1E-9) { b2=1/r; cX=x1B/r; } else { b2=1E9; cX=x1B*1E9; if (r < 0) { b2=-b2; cX=-cX; }; }; b2=-b2; c2=cX+cY; r1=b1*c2-b2*c1; r2=a1*b2-a2*b1; if (abs(r2) > 1E-9) y=r1/r2; else { y=1E9; if (r1 < 0) y=-y; }; r1=c1*a2-c2*a1; r2=a1*b2-a2*b1; if (abs(r2) > 1E-9) x=r1/r2; else { x=1E9; if (r1 < 0) x=-x; }; if (x1A < x2A) { xMin=x1A; xMax=x2A; } else { xMin=x2A; xMax=x1A; }; if (y1A < y2A) { yMin=y1A; yMax=y2A; } else { yMin=y2A; yMax=y1A; }; xMin=xMin-delta; xMax=xMax+delta; yMin=yMin-delta; yMax=yMax+delta; result=((x >= xMin) && (x <= xMax) && (y >= yMin) && (y <= yMax)); if (result) { if (x1B < x2B) { xMin=x1B; xMax=x2B; } else { xMin=x2B; xMax=x1B; }; if (y1B < y2B) { yMin=y1B; yMax=y2B; } else { yMin=y2B; yMax=y1B; }; xMin=xMin-delta; xMax=xMax+delta; yMin=yMin-delta; yMax=yMax+delta; result=((x >= xMin) && (x <= xMax) && (y >= yMin) && (y <= yMax)); }; if (! result) result=(abs(xDistPoint(x1A,y1A,x2A,y2A,x1B,y1B)) < delta); if (! result) result=(abs(xDistPoint(x1A,y1A,x2A,y2A,x2B,y2B)) < delta); if (! result) result=(abs(xDistPoint(x1B,y1B,x2B,y2B,x1A,y1A)) < delta); if (! result) result=(abs(xDistPoint(x1B,y1B,x2B,y2B,x2A,y2A)) < delta); return result; }; bool TSimpleMolecule::bondsOverlapped(int bN1, int bN2, double delta) { double x1A,y1A,x2A,y2A,x1B,y1B,x2B,y2B; bool result; x1A=getAtom(getBond(bN1)->at[0])->rx; y1A=getAtom(getBond(bN1)->at[0])->ry; x2A=getAtom(getBond(bN1)->at[1])->rx; y2A=getAtom(getBond(bN1)->at[1])->ry; x1B=getAtom(getBond(bN2)->at[0])->rx; y1B=getAtom(getBond(bN2)->at[0])->ry; x2B=getAtom(getBond(bN2)->at[1])->rx; y2B=getAtom(getBond(bN2)->at[1])->ry; result=false; if (((x1A>(x1B+delta)) && (x2A>(x1B+delta)) && (x1A>(x2B+delta)) && (x2A>(x2B+delta))) || ((x1A<(x1B-delta)) && (x2A<(x1B-delta)) && (x1A<(x2B-delta)) && (x2A<(x2B-delta))) || ((y1A>(y1B+delta)) && (y2A>(y1B+delta)) && (y1A>(y2B+delta)) && (y2A>(y2B+delta))) || ((y1A<(y1B-delta)) && (y2A<(y1B-delta)) && (y1A<(y2B-delta)) && (y2A<(y2B-delta)))) return result; result=overlapped(x1A,y1A,x2A,y2A,x1B,y1B,x2B,y2B,delta); return result; }; int TSimpleMolecule::hasOverlapped(double delta, bool findFirst) { int i, j; bool test; double r,xx,yy; int result=0; for (i=1; i<(nBonds()-1); i++) for (j=i+1; jat[0] == getBond(j)->at[0]) || (getBond(i)->at[0] == getBond(j)->at[1]) || (getBond(i)->at[1] == getBond(j)->at[0]) || (getBond(i)->at[1] == getBond(j)->at[1]); if (! test) if (bondsOverlapped(i,j,delta)) { result++; if (findFirst) return result; }; }; for (i=0; i<(nAtoms()-1); i++) for (j=i+1; jrx-getAtom(j)->rx; yy=getAtom(i)->ry-getAtom(j)->ry; r=sqrt(xx*xx+yy*yy); if (r < (2*delta)) { result++; if (findFirst) return result; }; }; return result; }; bool TSimpleMolecule::checkOverlapped() { bool result; result=hasOverlapped(averageBondLength()/32,true)>0; return result; }; double TSimpleMolecule::averageBondLength() { double result=0; if (nBonds() == 0) return result; for (int i=0; ilist1(listarSize()); double r, xc, yc, xo, yo, xn, yn; int i; int nB1; if (cHB < 0) return; test=makeFragment(nB1,list1,getBond(cHB)->at[1],getBond(cHB)->at[0]); if (nB1 > 1) { //One of the atoms haven't neighbours-flip unavalable cHA1=getBond(cHB)->at[0]; cHA2=getBond(cHB)->at[1]; xc=getAtom(cHA2)->rx-getAtom(cHA1)->rx; //Axes direction calculation yc=getAtom(cHA2)->ry-getAtom(cHA1)->ry; r=sqrt(xc*xc+yc*yc); xc=xc/r; yc=yc/r; xo=xc*xc-yc*yc; yo=2*xc*yc; for (i=0; irx-getAtom(cHA1)->rx; yc=getAtom(n)->ry-getAtom(cHA1)->ry; xn=xc*xo+yc*yo; yn=xc*yo-yc*xo; getAtom(n)->rx=getAtom(cHA1)->rx+xn; getAtom(n)->ry=getAtom(cHA1)->ry+yn; }; }; }; void TSimpleMolecule::bondEnlarge(int bN) { int nB; double r; std::vector list(listarSize()); int cHA1, cH1, cH2, n; bool test; double xc, yc, xc1, yc1; int i; for (i=0; iat[0]; test=makeFragment(nB,list,cHA1,getBond(bN)->at[1]); if (list[0] == getBond(bN)->at[0]) //center definition { cH1=getBond(bN)->at[0]; cH2=getBond(bN)->at[1]; } else { cH1=getBond(bN)->at[1]; cH2=getBond(bN)->at[2]; }; xc=getAtom(cH1)->rx-getAtom(cH2)->rx; yc=getAtom(cH1)->ry-getAtom(cH2)->ry; r=sqrt(xc*xc+yc*yc); xc=xc/r; yc=yc/r; xc1=getAtom(cH2)->rx-getAtom(cH1)->rx; yc1=getAtom(cH2)->ry-getAtom(cH1)->ry; r=r*2; for (i=0; irx=getAtom(n)->rx+xc1+r*xc; getAtom(n)->ry=getAtom(n)->ry+yc1+r*yc; }; }; bool compareAtoms(int a1, int a2, const std::vector *> aeqList) { std::vector * l1; std::vector * l2; int i; bool result=false; if ((a1 < 0) || (a2 < 0) || (a1 >= aeqList.size()) || (a2 >= aeqList.size())) return result; l1 = (std::vector *)(aeqList.at(a1)); l2 = (std::vector *)(aeqList.at(a2)); if ((l1 == NULL) || (l2 == NULL)) return result; if (l1->size() != l2->size()) return result; result=true; for (i=0; isize(); i++) if ((*l1)[i] != (*l2)[i]) { result=false; break; }; return result; }; int TSimpleMolecule::fragmentSecond(int sphere, int att, int secAt, const std::vector a, const std::vector b, const neigbourlist bk, std::vector& wSphere) { /*Generate a longinteger number, which is characterize fragment with atom CHA in center. Up to second neigbour's sphere are took into account. Array A contains the atom's codes, generated by ALLATATOM, array B-bond's codes, generated by BONDCONVERSION*/ int i,j,k,n,i1,i2,i3,jj; std::vector aDist(listarSize()); std::vector aList(listarSize()); std::vector atomoBond(listarSize()); std::vector * aPrev [3]; bool test,testOK; int w2; int l2,l3,tl1,tl2; std::vector ab(listarSize()); int result=0; // String s; if (nAtoms()==0) return result; for (j=0; j<3; j++) aPrev[j]=new std::vector(listarSize()); for (i=0; i 0) for (j=0; jat[0]; if (i2 == i1) i2=getBond(i3)->at[1]; if ((aDist[i2] >= k) && (aDist[i2] <= 65700)) { //if the neighbour has not been added yet to list} aDist[i2]=k; //Mark neighbour's sphere number jj=0; test=true; for (jj=1; jj<=3; jj++) { if (((*aPrev[jj-1])[i2] == -1) || (jj == 3)) { (*aPrev[jj-1])[i2]=i1; break; }; }; w2=a[i2]; w2=w2 << 6; w2=w2+b[i3]; w2=w2 ^ atomoBond[i2]; //atomoBond[I2]:=AtomoBond[I2] xor W2; !!!!!!! atomoBond[i2]=w2; }; }; }; if (secAt < 0) testOK=(k==sphere); else testOK=((k>=sphere) && (aDist[secAt] < 65700)); if (testOK) test=false; }; //end WHILE // At this point I have sphere numbers in Adist, corresponding AtomoBond word, number of atom(s), from //which the desirable atom were generated for (i=0; i=1; i1--) { n=0; for (i=0; i 0) { i2=0; for (i=0; i= 0) { tl1=ab[aList[i]]; tl2=atomoBond[(*aPrev[j-1])[aList[i]]]; // [Aprev[J][AList[I]]]; tl2=tl2 << 9; tl1=tl1 ^ tl2; ab[aList[i]]=tl1; }; }; //Sorting if (n > 1) for (i=0; i<(n-1); i++) for (j=i+1; j 1) i2=15/(n-1); l2=ab[aList[0]]; if (n > 1) for (i=1; inc; if (l3 != 0) l2=-l2; for (i=0; i& equivalenceList, bool isTopologyOnly) { //AllAboutCycles must be called early std::vector a(listarSize()); std::vector b(listarSize()); TSimpleMolecule * em; int i,j,n; neigbourlist bk; std::vector *> aeqList(0); std::vector * lL; em= new TSimpleMolecule(); em->moleculeCopy(*this); //Only topology-nothing more!!!! if (isTopologyOnly) { for (i=0; inAtoms(); i++) { em->getAtom(i)->na=6; em->getAtom(i)->nv=4; em->getAtom(i)->rl=6; em->getAtom(i)->nc=0; }; for (i=0; inBonds(); i++) em->getBond(i)->tb=1; em->defineAtomConn(); } else { for (i=0; inBonds(); i++) if ((em->getBond(i)->tb >= 9) && (em->getBond(i)->tb <= 11)) em->getBond(i)->tb=1; }; em->defineBondConn(bk); // for (i=0; inAtoms(); i++) a[i]=em->getAtom(i)->allAtAtom(); for (i=0; inBonds(); i++) b[i]=em->getBond(i)->bondConversion(); for (i=0; inAtoms(); i++) { lL=new vector(em->listarSize()); for (j=0; jsize(); j++) (*lL)[i]=0; em->fragmentSecond(em->nAtoms(),i,-1,a,b,bk,*lL); aeqList.push_back(lL); }; equivalenceList.resize(em->nAtoms()); n=0; for (i=0; inAtoms(); i++) if (equivalenceList[i] == 0) { n++; equivalenceList[i]=n; if (i < (em->nAtoms()-1)) for (j=i+1; jnAtoms(); j++) if (equivalenceList[j] == 0) { if (compareAtoms(j,i,aeqList)) equivalenceList[j]=n; } }; //freeing resorces for (int i=0; i& currentValues, const std::vector maxValues) { int i,l; bool result=false; for (i=0; i currentValues(nBonds()); std::vector maxValues(nBonds()); std::vector rotBondList(nBonds()); int at1,at2; int nn; r=averageBondLength()/blDenominator; k=hasOverlapped(r,false); result=k; smCopy->moleculeCopy(*this); test=true; while (test) { test=false; for (i=0; idb == 0) { flipSmall(i); kk=hasOverlapped(r,false); if (kkmoleculeCopy(*this); } else moleculeCopy(*smCopy); }; if (k == 0) test=false; }; result=k; if (result > 0) //multiply bonds rotation... { smCopy->moleculeCopy(*this); for (i=0; idb == 0) { at1=getBond(i)->at[0]; at2=getBond(i)->at[1]; if ((getAtom(at1)->nb >= 2) && (getAtom(at2)->nb >=2)) { //checking if greter 1 test=false; if (getAtom(at1)->nb == 3) { test=true; for (j=0; jnb; j++) { k=getAtom(at1)->ac[j]; if ((k != at2) && (getAtom(k)->nb > 1)) test=false; }; }; if ((! test) && (getAtom(at2)->nb == 3)) { test=true; for (j=0; jnb; j++) { k=getAtom(at2)->ac[j]; if ((k != at1) && (getAtom(k)->nb > 1)) test=false; }; }; if (! test) rotBondList[i]=1; }; }; nn=0; for (i=0; i0)) //All possible combinations of rotations... { currentValues.resize(nn); maxValues.resize(nn); for (i=0; imoleculeCopy(*smCopy); test=true; while (test && (k>0)) { moleculeCopy(*smCopy); n=0; for (i=0; imoleculeCopy(*this); }; test=incrementValues(currentValues,maxValues); };// (k=0) or (not test); moleculeCopy(*bestStore); result=k; }; }; if (result>0) //Bond enlarge....] { k=hasOverlapped(r,false); n=1; while (n != 0) { n=0; for (i=0; idb == 0) { smCopy->moleculeCopy(*this); smCopy->bondEnlarge(i); kk=smCopy->hasOverlapped(r,false); if (kk < k) { k=kk; n=i; }; smCopy->flipSmall(i); kk=smCopy->hasOverlapped(r,false); if (kk < k) { k=kk; n=-i; }; }; if (abs(n) != 0) { bondEnlarge(abs(n)); if (n < 0) flipSmall(abs(n)); }; }; result=k; }; //freeing resources if (smCopy != NULL) delete(smCopy); if (bestStore != NULL) delete(bestStore); return result; }; //******************************************************************************** // Determine Bond orders from attached hydrogens //******************************************************************************* void deleteIntElement(std::vector * source, int index) { int i,n; std::vector temp(source->size()-1); n=0; for (i=0; isize(); i++) if (i != index) { temp[n]=(*source)[i]; n++; }; source->resize(source->size()-1); for (i=0; isize(); i++) (*source)[i]=temp[i]; }; int hydrogenValency(int na) //Hydrogen valency { int result=0; if (na < NELEMMCDL) result=hVal[na]; return result; }; int maxValency(int na) //Maximal valency of a specified element { int result=8; if (na < NELEMMCDL) result=maxVal[na]; return result; }; static int findAlternateSinglets(const std::vectoriA1, const std::vectoriA2, const std::vector nH, const std::vector hydrogenValency, std::vector& bondOrder, int nAtoms, int nBonds) { //return values: 0 - no singlet found, 1 - found and assigned singlet, 2 - assigned singlet only with special std::vectornUnassigned(nAtoms); std::vectornAssigned(nAtoms); std::vectorbNumber(nAtoms); int i,n,k; int result; result=0; for (i=0; i 0) && (nUnassigned[i] == 1)) { n=bNumber[i]; k=hydrogenValency[i]-(nH[i]+nAssigned[i]); if (k < 1) { if (k == 0) //increment H valence by 2 { k=2; } else { k=1; }; result=2; }; if (k > 3) { k=3; result=3; }; bondOrder[n]=k; if (result == 0) { result=1; }; }; return result; }; static void makeAssignment(const std::vector iA1, const std::vector iA2, const std::vector nH, const std::vector hydrogenValency, const std::vector bondAssignment, const std::vector specialFlag, std::vector& bondOrder, int nAtoms, int nBonds, int & nAss) { int i,k; nAss=0; for (i=0; i iA1,const std::vector iA2, const std::vector nH, const std::vector hydrogenValency, const std::vector maxValency, const std::vector bondOrder, const std::vector atomCheckFlag, int nAtoms, int nBonds, int & nGtMax, int & nNEH, int & nOddEven, bool testExceedHydrogen, bool oddEvenCheck) { std::vectornBondsValency(nAtoms); //dynamically allocation int i,k; bool result; nGtMax=0; nNEH=0; nOddEven=0; for (i=0; i maxValency[i]) nGtMax++; if (testExceedHydrogen) { if ((nH[i]+nBondsValency[i]) != hydrogenValency[i]) nNEH++; } else { if ((hydrogenValency[i] > 0) && (nH[i] > 0)) if ((nH[i]+nBondsValency[i]) != hydrogenValency[i]) nNEH++; if ((hydrogenValency[i] > 0) && (nH[i] ==0)) if (nBondsValency[i] < hydrogenValency[i]) nNEH++; if (oddEvenCheck) { k=nH[i]+nBondsValency[i]; if ((k % 2) != (maxValency[i] % 2)) nOddEven++; }; }; }; result=((nGtMax == 0) && (nNEH == 0) && (nOddEven == 0)); return result; }; static bool incrementAssignment(std::vector& bondAssignment, int nAss) { int i,j; bool result; result=false; for (i=nAss-1; i>=0; i--) if (bondAssignment[i] == 1) { bondAssignment[i]++; if (i < (nAss-1)) for (j=i+1; j iA1, const std::vector iA2, const std::vector nH, const std::vector maxValency,std::vector& bondOrder, std::vector& hydrogenValency, int nAtoms, int nBonds, bool oddEvenViolate) { //On input BortOrder has to be initialized. Real bond orders have to be putted. 0 means this order should be determined //MaxValency and HydrogenValency and NH are required only for those atoms, which are included in BondOrder=0 std::vectornNeighbour(nAtoms); std::vectorbondAssignment(nBonds); //Should be Max(Atoms, Bonds); std::vectorbondOrderStore(nBonds); std::vectorspecialFlag(nBonds); int i,j,k,n,nAss; bool test; int nGtMax; //number of atoms, for which maximal valency is exausted int nNEH; //bumber of atoms, for which number of calc and desirable hydrogens are disagree int nOddEven;//Parity violation - atom with odd maximal valency has even valency and back int result; k=nAtoms; if (nBonds > k) k=nBonds; k++; result=0; for (i=0; i 0) { n=nH[i]+nNeighbour[i]; if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2; if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2; }; //Label all bonds which have order 1 exactly for (i=0; i 0) && (nH[i] > 0)) { n=nH[i]+nNeighbour[i]; if (n == hydrogenValency[i]) for (j=0; j 0) { n=nH[i]+nNeighbour[i]; if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2; if (n > hydrogenValency[i]) hydrogenValency[i]=hydrogenValency[i]+2; }; //below array NNeighbour is used for picking atoms, for which valency have to be checked.. for (i=0; i aPosition,const std::vector aCharge, const std::vector aRad,const std::vector nHydr, const std::vector iA1, const std::vector iA2, std::vector & bondOrders, int nAtoms, int nBonds) { std::vector hVal(nAtoms); std::vector maxVal(nAtoms); int i,result; for (i=0; i 0) { if (aRad[i] != 0) hVal[i]=hVal[i]-1; //returns 0 for non-radical and 2 for radical if (aPosition[i] == 5) hVal[i]=hVal[i]-aCharge[i]; //B else if (aPosition[i] == 6) hVal[i]=hVal[i]-abs(aCharge[i]); //C else hVal[i]=hVal[i]+aCharge[i]; //Heteroatoms if (hVal[i] < 0) hVal[i]=0; }; maxVal[i]=maxValency(aPosition[i]); if (aCharge[i] != 0) maxVal[i]=maxVal[i]+1; }; result=determineBondsOrder(iA1,iA2,nHydr,maxVal,bondOrders,hVal,nAtoms,nBonds,true); return result; }; int alternate(OBMol * pmol, const std::vector nH, std::vector& bondOrders) { //This overloaded method does not work. By unknown reason I cannot extract //connection matrix from pmol //number of hydogens must be filled on input. std::vector hVal(pmol->NumAtoms()); std::vector maxVal(pmol->NumAtoms()); std::vectoriA1(pmol->NumBonds()); std::vectoriA2(pmol->NumBonds()); int nAtoms,nBonds; int i,k,na; OBAtom * sa; OBBond * sb; int result=0; pmol->AssignSpinMultiplicity(); nAtoms=pmol->NumAtoms(); nBonds=pmol->NumBonds(); for (i=0; iGetBond(i); iA1[i]=sb->GetBeginAtomIdx()-1; iA2[i]=sb->GetEndAtomIdx()-1; }; for (i=1; i<=nAtoms; i++) { sa=pmol->GetAtom(i); na=sa->GetAtomicNum(); hVal[i-1]=hydrogenValency(na); if (hVal[i-1] > 0) { if (sa->GetSpinMultiplicity() != 0) hVal[i-1]=hVal[i-1]-1; //returns 0 for non-radical and 2 for radical k=sa->GetFormalCharge(); if (sa->IsHeteroatom()) hVal[i-1]=hVal[i-1]+k; else if (na == 6) hVal[i-1]=hVal[i-1]-abs(k); else hVal[i-1]=hVal[i-1]-k; if (hVal[i-1] < 0) hVal[i-1]=0; }; maxVal[i-1]=maxValency(na); if (sa->GetFormalCharge() != 0) maxVal[i-1]=maxVal[i-1]+1; }; result=determineBondsOrder(iA1,iA2,nH,maxVal,bondOrders,hVal,nAtoms,nBonds,true); for (i=0; iGetBond(i); sb->SetBondOrder(bondOrders[i]); }; return result; }; //***************************************************************************** //******************* EditedMolecule class *********************************** //***************************************************************************** class TEditedMolecule: public TSimpleMolecule { protected: neigbourlist queryBK; neigbourlist structureBK; std::vector queryQHydr; std::vector queryAGer; std::vector queryBQCounter; std::vector queryCurrentAssignment; std::vector queryEnum; std::vector queryInverse; bool queryStereoQ,fIsQueryPrepare; std::vector aSTested; std::vector bSTested; std::vector bSTestedStore; bool aEQ[NATOMSMAX][NATOMSMAX]; bool bEQ[NBONDSMAX][NBONDSMAX]; void removeHydrogen(std::vector * qHydr, std::vector * qEnumerator); void atomBondChange(); bool stereoBondChange(); void directBondAss(int& bnq, bool& test, bool& test1, const bool beq[NBONDSMAX][NBONDSMAX], const bool aeq[NATOMSMAX][NATOMSMAX], std::vector& bqcounter, std::vector& aqtested, std::vector& bstested, std::vector& bqtested, std::vector& astested, const std::vector ager, const neigbourlist bqconn, const neigbourlist bsconn, TSimpleMolecule * smol); bool allQueryPresent(const std::vector qA, const std::vector qB, int nA, int nB); public: static int const NOOTHER_MASK=1; static int const AROMATIC_MASK=NOOTHER_MASK << 1; static int const EXACTNUMBER_MASK=AROMATIC_MASK << 1; bool fIOPT10; //charge sensitivite bool fIOPT11; //isotopes difference int fIOPT12; //stereo bond change bool fIOPT13; //semipolar bond as double std::vector queryAQTested; std::vector queryBQTested; std::vector* fIncludedList; TEditedMolecule() { TSimpleMolecule(); fIncludedList=NULL; }; int prepareQuery(TSimpleMolecule & sMol); bool fragmentSearch(TEditedMolecule * molecule1, std::vector* bondLabel); TEditedMolecule * extractFragment(int atomN, std::vector * enumerator); void addAsTemplate(TEditedMolecule& fragmentMol, int thisAN, int smAN, int thisBN, int smBN, bool isAddition); int addFragment(TEditedMolecule & eMolecule, int naDEF, int cha, int chb, int chb1, std::vector& list, double xOldCenter, double yOldCenter, double xNewCenter, double yNewCenter, double scale, double cFi, double sFi, int buttonStatus, bool clearEnumerator); }; int TEditedMolecule::addFragment(TEditedMolecule & eMolecule, int naDEF, int cha, int chb, int chb1, std::vector& list, double xOldCenter, double yOldCenter, double xNewCenter, double yNewCenter, double scale, double cFi, double sFi, int buttonStatus, bool clearEnumerator) { // The procedure is used by TEMPLATE and MAKEPOLI procedure to add large frag- // ments to structure. The connection between structure and fragment may be // achived both through atoms (CHA>0) and through bonds (CHB>0). // Variables description: // NAtoms-number of atoms in structure // NBonds-number of bonds in structure // ATOM-atom's attributes in structure // BOND-bond's attributes in structure // CONN-some invariants of bond-connection matrix // NAtoms1, NBonds1, ATOM1, BOND1, CONN1-the same for fragments (these varia- // bles can contain data for more, than one fragments) // LIST-atom's number in arrays ATOM1,CONN1, which should be added to structure // NaDef-number of principal components in LIST array // CHA-atom's number in array ATOM (structure), which was selected for addition // CHB-bond's number in array BOND (structure), which was selected for addition // CHB1-bond's number in array BOND1 (fragment), which was selected for addition // XOldCenter,YOldCenter-old coordinates of the fragment on screen (center rotation) // XNewCenter,YNewCenter-new coordinates of the fragment on screen // Scale-scale variables to resize fragment // CFi,SFi-cosine and sine of the angle of rotation of the fragment relative // old coordinate of ths type of a fragment addition (active only for addition // through atoms). If e fragment on screen // ButtonStatus-regulateButtonStatus=1 then fragment will be added to structure // (new bond arise). If ButtonStatus=2 then fragment will be freezed in // structure (selected new atom for structure will be deleted, no new bond // will be arised)} // Returns 0 if addition is OK, otherwise: // =1 - Maxima number of atoms is reached // =2 - Maximal number of bonds is reached int i,j1,j2,na,k1,k2,j,nb,n1,n2; int l1=0; int l2=0; bool test; double r1,r2,r3,r4,emBLength; std::vector bTested(NBONDSMAX); std::vector bList(NBONDSMAX); std::vector aList(NBONDSMAX); TSingleAtom * sa=NULL; TSingleBond * sb=NULL; int result=0; //return result; //Analizing on boundaries} k2=1; k1=1; if ((nAtoms()+naDEF) >= NATOMSMAX) { result=1; return result; } //Analizing of bond's nb=0; emBLength=0; for (i=0; iat[0]; n2=eMolecule.getBond(i)->at[1]; if ((bList[n1] != 0) || (bList[n2] != 0)) { nb++; emBLength=emBLength+eMolecule.bondLength(i); } } if (nb > 0) emBLength=emBLength/nb; if ((nb+nBonds()) >= NBONDSMAX) { result=2; return result; } na=nAtoms(); nb=nBonds(); if (chb >= 0) //Bond was selected for addition { l1=getBond(chb)->at[0]; //L1,L2,K1,K2-atoms numbers for corresponding bonds l2=getBond(chb)->at[1]; //in structure and in fragment k1=eMolecule.getBond(chb1)->at[0]; k2=eMolecule.getBond(chb1)->at[1]; j=0; for (i=0; i 0)) { if (nBonds() == 0) r1=DEFAULTBONDLENGTH; else r1=averageBondLength(); scale=r1/emBLength; } //End addition for (i=0; irx-xOldCenter; r2=eMolecule.getAtom(list[i])->ry-yOldCenter; r3=scale*(r1*cFi-r2*sFi); r4=scale*(r1*sFi+r2*cFi); sa=eMolecule.getAtom(list[i])->clone(); sa->rx=xNewCenter+r3; sa->ry=yNewCenter+r4; if (clearEnumerator) sa->enumerator=0; sa->fragIndex=0; addAtom(sa); } if (chb >= 0) { //specific for bond-to-bond addition block-determination of correspondence //of pair of atoms, which make bond, in fragment to the same pair of atoms in //structure. Determination is perfomed through internuclear distances} r1=getAtom(l2)->rx-getAtom(nAtoms()-1)->rx; r2=getAtom(l2)->ry-getAtom(nAtoms()-1)->ry; r3=r1*r1+r2*r2; r1=getAtom(l1)->rx-getAtom(nAtoms()-1)->rx; r2=getAtom(l1)->ry-getAtom(nAtoms()-1)->ry; r4=r1*r1+r2*r2; if (r3 < r4) { k2=nAtoms()-1; k1=nAtoms()-2; } else { k2=nAtoms()-2; k1=nAtoms()-1; } } for (i=0; i= 0) && (i != chb1))) { //addition of bonds from fragment to structure test=false; j1=-1; do //Search, if bond I from BOND1 is presented in the fragment { j1++; if (eMolecule.getBond(i)->at[0] == list[j1]) test=true; } while (! (test || (j1 == (naDEF-1)))); if (test) //Bond is presented-addition { j2=-1; do //Search for second atom, which makes I-th bond in fragment j2++; while (eMolecule.getBond(i)->at[1] != list[j2]); sb=new TSingleBond(); j1=na+j1; //atoms, which make the bond, renumeration j2=na+j2; sb->tb=eMolecule.getBond(i)->tb; //attributes copy sb->at[0]=j1; sb->at[1]=j2; if (clearEnumerator) sb->enumerator=0; addBond(sb); } } if (chb >= 0) //bond-to-bond addition { for (i=0; iat[0] == k1) getBond(i)->at[0]=l1; if (getBond(i)->at[0] == k2) getBond(i)->at[0]=l2; if (getBond(i)->at[1] == k1) getBond(i)->at[1]=l1; if (getBond(i)->at[1] == k2) getBond(i)->at[1]=l2; } //Two atoms deleted... delete(fAtom[nAtoms()-1]); delete(fAtom[nAtoms()-2]); fAtom.resize(nAtoms()-2); //two atoms, which make the bond to be added in fragment, //are deleted. They occupy last positions in arrays ATOM and CONN due to //initial sorting /* Contains mistake-commented to the better time i=0; do { //Two or three bond connection is calculated j=na; if (j < nAtoms()) do { //Search for concided atoms rr1=getAtom(i)->rx-getAtom(j)->rx; rr2=getAtom(i)->ry-getAtom(j)->ry; lR=sqrt(rr1*rr1+rr2*rr2); test=((i != j) & ((lR) <= 3)); if (test) { //Concided pair of atoms found for (k=0; kat[0] == j) getBond(k)->at[0]=i; if (getBond(k)->at[1] == j) getBond(k)->at[1]=i; } deleteAtom(j); //Deletion of atom k=0; do { //Search for bonds, which have identical pair of atom or which l=k; do { test=(getBond(k)->at[0] == getBond(l)->at[0]) && (getBond(k)->at[1] == getBond(l)->at[1]); test=test || (getBond(k)->at[0] == getBond(l)->at[1]) && (getBond(k)->at[1] == getBond(l)->at[0]); test=test || (getBond(l)->at[0] == getBond(l)->at[1]); if (test) { //Bad bonds was found-deletion deleteBond(l); l--; } l++; } while (l < nBonds()); k++; } while (k < (nBonds()-1)); j--; } j++; } while (j < nAtoms()); i++; } while (i < na); */ } if ((buttonStatus>1) && (chb < 0)) { //if fragment 'is freezed' through atom, the atom needs to be deleted for (i=0; iat[0] == cha) getBond(i)->at[0]=na; if (getBond(i)->at[1] == cha) getBond(i)->at[1]=na; } defineAtomConn(); deleteAtom(cha); //atom deleting }; //new values for attribute array defineAtomConn(); //Search for badly-connected aromatic bonds /* commented to better time. Use alternation bond instead if (chb>=0) { for (i=0; icurrvalence > maxVal[getAtom(i)->na]); i++; } while (! (test || (i == nAtoms()))); if (test) { //Creation aromtic bond list n=0; aList[0]=i-1; doubleSearch=true; do { j=nb; test=false; if (j < nBonds()) do { test=((getBond(j)->at[0] == aList[n]) || (getBond(j)->at[1] == aList[n])); if (doubleSearch) test=(test && (getBond(j)->tb == 2)); else test=(test && (getBond(j)->tb == 1)); test=(test && (bTested[j] == 0)); j++; } while (! (test || (j == nBonds()))); if (test) { //Addition to the aromatic list bList[n]=j-1; bTested[j]=1; l=getBond(j-1)->at[0]; if (l == aList[n]) l=getBond(j-1)->at[1]; n++; aList[n]=l; doubleSearch= ! doubleSearch; } } while (test); if (n > 1) { //Alternation of aromatic chain for (j=1; j list(NBONDSMAX); std::vector listA(NBONDSMAX); std::vector listB(NBONDSMAX); double r,scale,xOld,yOld,xNew,yNew,xCenter,yCenter; double r1; double r2; double xu1; double yu1; double xu2; double yu2; double cAngle; double rxTemp1,ryTemp1; int mouseButton=0; int n; double amin; if (fragmentMol.nAtoms() == 0) return; naDef1=smAN; test1=true; test2=false; xCenter=0; yCenter=0; if (thisBN >= 0) { naDef1=fragmentMol.getBond(smBN)->at[0]; test1=false; test2=true; } scale=1; xOld=0; yOld=0; test=fragmentMol.makeFragment(naNum,list,naDef1,-1); //creation of template's fragment //Scale definitions if (thisAN >= 0) //connection through atoms { xCenter=this->getAtom(thisAN)->rx; yCenter=this->getAtom(thisAN)->ry; naDef=thisAN; scale=1; r1=0; r2=0; if (fragmentMol.getAtom(naDef1)->nb > 0) { amin=100000000; n=1; for (i=0; inb; i++) { rxTemp1=fragmentMol.getAtom(naDef1)->rx-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[i])->rx; ryTemp1=fragmentMol.getAtom(naDef1)->ry-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[i])->ry; r1=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1); if(r1 < amin) { amin=r1; n=i; }; }; rxTemp1=fragmentMol.getAtom(naDef1)->rx-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[n])->rx; ryTemp1=fragmentMol.getAtom(naDef1)->ry-fragmentMol.getAtom(fragmentMol.getAtom(naDef1)->ac[n])->ry; r1=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1); } else r1=DEFAULTBONDLENGTH; if (this->getAtom(naDef)->nb > 0) { amin=100000000; n=1; for (i=0; igetAtom(naDef)->nb; i++) { rxTemp1=this->getAtom(naDef)->rx-this->getAtom(this->getAtom(naDef)->ac[i])->rx; ryTemp1=this->getAtom(naDef)->ry-this->getAtom(this->getAtom(naDef)->ac[i])->ry; r2=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1); if(r2 < amin) { amin=r2; n=i; }; }; rxTemp1=this->getAtom(naDef)->rx-this->getAtom(this->getAtom(naDef)->ac[n])->rx; ryTemp1=this->getAtom(naDef)->ry-this->getAtom(this->getAtom(naDef)->ac[n])->ry; r2=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1); } else { if (this->nBonds() > 0) r2=this->averageBondLength(); else r2=DEFAULTBONDLENGTH; } if (r1 > 0) scale=r2/r1; else scale=1; } else if (thisBN >= 0) //connection through bonds { rxTemp1=fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->rx-fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->rx; ryTemp1=fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->ry-fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->ry; r1=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1); rxTemp1=this->getAtom(this->getBond(thisBN)->at[0])->rx-this->getAtom(this->getBond(thisBN)->at[1])->rx; ryTemp1=this->getAtom(this->getBond(thisBN)->at[0])->ry-this->getAtom(this->getBond(thisBN)->at[1])->ry; r2=sqrt(rxTemp1*rxTemp1+ryTemp1*ryTemp1); if (r1 > 0) scale=r2/r1; else scale=1; } //Old coordinates definition if (smAN >= 0) { xOld=fragmentMol.getAtom(smAN)->rx; yOld=fragmentMol.getAtom(smAN)->ry; } if (thisBN >= 0) { xOld=(fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->rx+fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->rx)/2; yOld=(fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[0])->ry+fragmentMol.getAtom(fragmentMol.getBond(smBN)->at[1])->ry)/2; } //New coordinate definition if (thisBN >= 0) //connection through bonds { xNew=(this->getAtom(this->getBond(thisBN)->at[0])->rx+this->getAtom(this->getBond(thisBN)->at[1])->rx)/2; yNew=(this->getAtom(this->getBond(thisBN)->at[0])->ry+this->getAtom(this->getBond(thisBN)->at[1])->ry)/2; } else //connection through atoms} { if (isAddition) //addition of fragment { this->unitVector(thisAN,xu1,yu1); if (xu1 > -0.999) r=yu1/(1+xu1); else if (yu1 > 0) r=1E9; else r=-1E9; cAngle=2*180*atan(r)/PI; if (true) { cAngle=(int)(cAngle/30); cAngle=30*cAngle; r=cAngle*PI/180; xu1=cos(r); yu1=sin(r); } xNew=r1*scale*xu1+this->getAtom(thisAN)->rx; yNew=r1*scale*yu1+this->getAtom(thisAN)->ry; } else //freezing of fragment { if (this->getAtom(thisAN)->nb == 0) { xu1=1; yu1=0; } else if (this->getAtom(thisAN)->nb == 1) { xu1=this->getAtom(thisAN)->rx-this->getAtom(this->getAtom(thisAN)->ac[0])->rx; yu1=this->getAtom(thisAN)->ry-this->getAtom(this->getAtom(thisAN)->ac[0])->ry; //yu1=this.fAtom.getRY(thisAN)-this.fAtom.getRY(this.fAtom.getAC(thisAN,1)); r2=sqrt(xu1*xu1+yu1*yu1); if (r2 > 1.0E-4) { xu1=xu1/r2; yu1=yu1/r2; } else { xu1=1; yu1=0; } } else this->unitVector(thisAN,xu1,yu1); if (xu1 > -0.999) r=yu1/(1+xu1); else if (yu1 > 0) r=1E9; else r=-1E9; cAngle=2*180*atan(r)/PI; if (true) { cAngle=(int)(cAngle/30); cAngle=30*cAngle; r=cAngle*PI/180; xu1=cos(r); yu1=sin(r); } xNew=this->getAtom(thisAN)->rx; yNew=this->getAtom(thisAN)->ry; } } //Angle definition if (thisAN >= 0) //connection through atoms { fragmentMol.unitVector(smAN,xu2,yu2); xu2=-xu2; yu2=-yu2; r1=xu1*xu2+yu1*yu2; r2=yu1*xu2-xu1*yu2; nBondsOld=this->nBonds(); nAtomsOld=this->nAtoms(); if (isAddition) mouseButton=1; else mouseButton=2; this->addFragment(fragmentMol,naNum,thisAN,thisBN,smBN,list, xOld,yOld,xNew,yNew,scale,r1,r2,mouseButton,false); if (isAddition) { this->addBond(1,nAtomsOld,thisAN); } else nAtomsOld=nAtomsOld-1; } else if ((smBN >= 0) && (thisBN >= 0)) //connection through bonds { this->bondUnitVector(thisBN,xu1,yu1); fragmentMol.bondUnitVector(smBN,xu2,yu2); xu2=-xu2; yu2=-yu2; r1=xu1*xu2+yu1*yu2; r2=yu1*xu2-xu1*yu2; nBondsOld=this->nBonds(); nAtomsOld=this->nAtoms(); addFragment(fragmentMol,naNum,thisAN,thisBN,smBN,list, xOld,yOld,xNew,yNew,scale,r1,r2,1,false); } } TEditedMolecule * TEditedMolecule::extractFragment(int atomN, std::vector * enumerator) { std::vector list(listarSize()); std::vector inverseList(listarSize()); int i,j,k; int na; bool test; TSingleAtom * sa; TSingleBond * sb; TEditedMolecule * result=NULL; if ((atomN < 0) || (atomN >= nAtoms())) return result; if (enumerator != NULL) for (i=0; i1) for (i=0; i<(na-1); i++) for (j=i+1; jlist[j]) { k=list[i]; list[i]=list[j]; list[j]=k; }; if (na > 0) for (i=0; i 0) for (i=0; igetAtom(list[i])->clone(); result->addAtom(sa); if (enumerator != NULL) (*enumerator)[list[i]]=i; } if (nBonds() > 0) for (i=0; iat[0]] >= 0) { sb=getBond(i)->clone(); sb->at[0]=inverseList[getBond(i)->at[0]]; sb->at[1]=inverseList[getBond(i)->at[1]]; result->addBond(sb); } return result; } int TEditedMolecule::prepareQuery(TSimpleMolecule & sMol) { /*Returns error code: 0 - no error -1 - input molecule is not assigned or number of atoms equal zero -2 - unconnected fragments were detected -3 - an exception take place*/ TEditedMolecule * molecule1; int i,j,k,l; bool test,test1,test2,test3; int aQ1,aQ2,bNQ; int result; bool whileCondition,whileCondition1; result=-1; if (sMol.nAtoms()==0) return result; sMol.defineAtomConn(); sMol.allAboutCycles(); //Three above line instead of this line: CalculateAllIndeces(SMOl); moleculeCopy(sMol); result=0; fIsQueryPrepare=true; for (i=0; ina==104) && (! fIOPT11)) getAtom(i)->na=1; if (! fIOPT11) getAtom(i)->iz=0; }; //Initializinf arrays queryQHydr.resize(listarSize()); queryAGer.resize(listarSize()); queryAQTested.resize(listarSize()); queryBQTested.resize(listarSize()); queryBQCounter.resize(listarSize()); queryCurrentAssignment.resize(listarSize()); aSTested.resize(listarSize()); bSTested.resize(listarSize()); bSTestedStore.resize(listarSize()); //initializing for (i=0; ispecial; l=1; if (nAtoms()>2) { j=queryBK[0].nb; for (i=1; ij; test2=(getAtom(l)->na<104) && (getAtom(l)->na!=6); test3=(getAtom(i)->na<104) && (getAtom(i)->na!=6); if ((test1 && (! test2)) || (test3 && (! test2)) || (test1 && test2 && test3)) { j=k; l=i; }; }; }; queryAQTested[0]=0; //Sequence for query assignment begin from the atom aQ1=0; bNQ=-1; test=true; if (nBonds()>0) while (test) //Define sequence to match query and structure { i=0; whileCondition=true; while (whileCondition) { test=(queryAQTested[i] != -1); if (test) { j=0; whileCondition1=true; if (queryBK[i].nb>0) while (whileCondition1) { k=queryBK[i].adjusted[j]; j++; test=(bSTested[k]==-1); whileCondition1=test || (j>=queryBK[i].nb); whileCondition1=! whileCondition1; }; if (queryBK[i].nb==0) test=false; }; i++; whileCondition=test || (i==nAtoms()); whileCondition=! whileCondition; }; if (test) //connected atom found { i--; //zero-index aQ2=i; whileCondition=true; while (whileCondition) { j=0; //search for query bond appended to AQ2, which has not been assigned yet whileCondition1=true; k=0; test1=true; if (queryBK[aQ2].nb>0) while (whileCondition1) { k=queryBK[aQ2].adjusted[j]; test1=(bSTested[k]==-1); j++; whileCondition1=test1 || (j>=queryBK[aQ2].nb); whileCondition1=! whileCondition1; } else { k=0; test1=false; }; if (test1) //found { bNQ++; bSTested[k]=bNQ; //store, that BNQ has been assigned l=getBond(k)->at[1]; //atoms enumeration if (l==aQ2) { l=getBond(k)->at[0]; getBond(k)->at[1]=l; getBond(k)->at[0]=aQ2; }; test1=(queryAQTested[l]==-1); //Make AGER array for end-of cycle BNQ bond} if (test1) { queryAGer[bNQ]=l; aQ1=aQ1+1; queryAQTested[l]=aQ1; aQ2=l; } else aQ2=-1; }; whileCondition=(! test1) || (aQ2==-1); whileCondition=! whileCondition; }; }; }; //Detection of unconnected fragment} for (i=0; i=0) { //Creation of inverse enumeration queryInverse.resize(queryAQTested.size()); for (j=0; jmoleculeCopy(*this); for (i=0; igetAtom(queryAQTested[i])->atomCopy(this->getAtom(i)); for (i=0; i0) for (i=0; i0) for (i=0; igetBond(bSTested[i])->bondCopy(this->getBond(i)); bSTestedStore.resize(bSTested.size()); for (i=0; i0) for (i=0; igetBond(i)->at[0]=queryAQTested[molecule1->getBond(i)->at[0]]; molecule1->getBond(i)->at[1]=queryAQTested[molecule1->getBond(i)->at[1]]; }; //Enumeration of this->moleculeCopy(*molecule1); defineAtomConn(); //Store NO OTHER atom attribute for (i=0; ispecial=aSTested[i]; defineBondConn(queryBK); j=0; //Search for last non-special atom in query} queryStereoQ=stereoBondChange(); //Stereo bond conversion }; delete(molecule1); return result; }; void TEditedMolecule::removeHydrogen(std::vector * qHydr, std::vector * qEnumerator) { //Explicitly-defined hydrogens are removed from the structure, which is characte- //rized of total number of atoms NA, total number of bonds NB, atom's attribute //array ATOM, bond's attribute array BOND, bond-connection matrix invariants //ONN. Number of explicitly-defined hydrogens for each atom are stored in //QHYDR. If QUERYLABEL points on some atom, the value is recalculated so that //the same atom is pointed after hydrogens have been removed from the structure //NB! QueryLabel should be array!} int i,j,i1; bool test,test1,test2; if (qEnumerator != NULL) { if (qEnumerator->size() != nAtoms()) qEnumerator->resize(nAtoms()); for (i=0; isize(); i++) (*qEnumerator)[i]=i; }; for (i=0; ina==104)) getAtom(i)->na=1; //D->H if no isotop sensitivity} }; i=0; test1=false; if (nAtoms()>0) while (ina==1) //hydrogen found { test1=true; j=0; i1=0; test2=true; if (nBonds()>0) while (test2) //search for corresponding bond and hydrogen's neighbour detection { test=(getBond(j)->at[0]==i) || (getBond(j)->at[1]==i); if (test) { i1=getBond(j)->at[0]; if (i1==i) i1=getBond(j)->at[1]; }; test2=test || (j==nBonds()); test2=! test1; j++; }; deleteAtom(i); if ((qHydr != NULL) && (i<(nAtoms()-1))) deleteIntElement(qHydr,i); if (i1>i) i1=i1-1; //shift of attribute's arrays if (qEnumerator != NULL) { for (j=0; jsize(); j++) { if ((*qEnumerator)[j] == i) (*qEnumerator)[j]=-i1; else if ((*qEnumerator)[j] > i) (*qEnumerator)[j]=(*qEnumerator)[j]-1; else if (((*qEnumerator)[j] < 0) && (abs((*qEnumerator)[j]) > i)) (*qEnumerator)[j]=(*qEnumerator)[j]+1; }; }; if ((i1 > 0) && (qHydr != NULL)) (*qHydr)[i1]=(*qHydr)[i1]+1; //counter of explicitly defined hydrogens i--; }; i++; }; if (test1) { defineAtomConn(); //Inverse enumerator creation... New QA->OldQA array} if (qEnumerator != NULL) { //??? Is it required ?} }; }; }; void TEditedMolecule::atomBondChange() { //substitutes the semipolar bond with double. NBONDS-total number of bonds, //BOND-bond's attributes, ATOM-atom's attributes} int i; int ca,cb; if (nBonds()==0) return; for (i=0; iat[0])->nc; cb=getAtom(getBond(i)->at[1])->nc; if ((((ca<0) && (cb>0)) || ((ca>0) && (cb<0))) && ((getBond(i)->tb<3) || (getBond(i)->tb>8))) { if (ca<0) { getAtom(getBond(i)->at[0])->nc=ca+1; getAtom(getBond(i)->at[1])->nc=cb-1; }; if (ca>0) { getAtom(getBond(i)->at[0])->nc=ca-1; getAtom(getBond(i)->at[1])->nc=cb+1; }; if (getBond(i)->tb<3) getBond(i)->tb=getBond(i)->tb+1; else getBond(i)->tb=2; }; }; }; bool TEditedMolecule::stereoBondChange() { //Subtitute stereo bonds with single. On output TEST has TRUE value, if at //least one stereo bond was detected in structure with bond attributes BOND //nd total number of bonds NBONDS int i; bool result; result=false; if ((nBonds()==0) || (fIOPT12==2)) return result; //If Exact Stereo Search-no substitution for (i=0; itb==11) getBond(i)->tb=1; if (getBond(i)->tb>=9) result=true; }; if (fIOPT12==1) if (getBond(i)->tb>=9) getBond(i)->tb=1; //If No Stereo search-all bonds substitution }; return result; }; void TEditedMolecule::directBondAss(int& bnq, bool& test, bool& test1, const bool beq[NBONDSMAX][NBONDSMAX], const bool aeq[NATOMSMAX][NATOMSMAX], std::vector& bqcounter, std::vector& aqtested, std::vector& bstested, std::vector& bqtested, std::vector& astested, const std::vector ager, const neigbourlist bqconn, const neigbourlist bsconn, TSimpleMolecule * smol) { //Assign a structure atom to query atom. Variables: //BNQ-query bond's number, which needs to be assigned //BEQ,AEQ-boolean matrix, contains list of equivalent bonds //BQCONN,BSCONN-for each atom containes list of connected bonds in query and // structure respectively. //QBOND,SBOND-bond's attributes for query and structure respectively //ASTESTED- I-th element of the array contains the query atom's number, which // has been assigned to I-th atom of structure (=0-no assignment) //AQTESTED- I-th element of the array contains the structure atom's number, // which has been assigned to I-th atom of query (=0-no assignment) //BSTESTED- I-th element of the array contains the query bond's number, which // has been assigned to I-th bond of structure (=0-no assignment) //BQTESTED- I-th element of the array contains the structure bond's number, // which has been assigned to I-th bond of query (=0-no assignment) //BQCOUNTER-for each query bond contains bond's number in array BSCONN(!)-con- // nected to corresponding structure atom bonds. The structure bonds // in array BSCONN with less than or equal number have been tested on // assignment, with above number-no. //AGER-for each query bond contains query atom's number, which must be generated // at assignment of this bond to structure or zero, if no atom may be gene- // rated. This array is used for cyclic conditions definition (last bond in // the cycle must be created between already-defined query atoms-no genera- // tion). //TEST-on output contains TRUE, if assignment was successfull, FALSE otherwise //TEST1-on output contains TRUE if all bonds, connected to last assigned atom // in structure will be tested, FALSE otherwise. If TEST1=TRUE and TEST= // FALSE it means, that last atom in structure had been unproperly assigned // -backstep is required to reassign the atom.*/ int bns,bs,as1,as2,aq2,aq1; bool whiletest; test=false; aq1=getBond(bnq)->at[0]; //first query atom, already assigned as1=aqtested[aq1]; //corresponding first structure atom if (as1<0) return; aq2=getBond(bnq)->at[1]; //second query atom} bs=bqcounter[bnq]; bns=0; as2=0; whiletest=true; if (bsgetBond(bns)->at[0]; //second structure atom} if (as2==as1) as2=smol->getBond(bns)->at[1]; test=false; //if no new structure atom assignment must be generated-checking, if AS2 // equal already defined atom for query atom AQ2} if ((ager[bnq]<0) && (astested[as2]>=0)) test=(aqtested[aq2]==as2); //if new atom in structure must be assigned-testing equivalence with //corresponding query if ((ager[bnq]>=0) && (astested[as2]<0)) test=aeq[as2][aq2]; }; bs=bs+1; whiletest=(bs==bsconn[as1].nb) || test; whiletest=! whiletest; }; //until(BS=BSCONN[AS1].NB) or TEST; //until all list of structure bonds will be exausted or success in assignment if (test) //Success { if (ager[bnq]>=0) //if new atom has been assigned-store assignment} { aqtested[aq2]=as2; astested[as2]=aq2; }; bstested[bns]=bnq; //store assignment of bonds} bqtested[bnq]=bns; }; bqcounter[bnq]=bs; //last used structure bond's number in SCONN array} test1=(bs==bsconn[as1].nb); //test, if SCONN for atom given is exausted} }; bool TEditedMolecule::allQueryPresent(const std::vector qA, const std::vector qB, int nA, int nB) { //the function returns TRUE if for all query atoms and bonds the equivalent //structure atom (bond) can be found, FALSE otherwise. QA-for each query atom //contains '1' if a structure atom may be associated with the query, '0' other- //wise. The same is true for bond's list QB. NA-total number of query atoms, //NB-total number of query bonds int i; bool test,whiletest; i=0; if (nA<0) return false; whiletest=true; test=false; while (whiletest) { test=qA[i]==1; i++; whiletest=(! test) || (i==nA); whiletest=! whiletest; }; if (test && (nB>=0)) { i=0; whiletest=false; while (whiletest) { test=qB[i]==1; i++; whiletest=(! test) || (i==nB); whiletest=! whiletest; }; }; return test; }; bool TEditedMolecule::fragmentSearch(TEditedMolecule * molecule1, std::vector* bondLabel) { int cycleNumber; int j,k,l,m,mm; bool test; bool test1; bool test2,test3,stereoS; int aq1,aq2,as1,as2,j1,i1; int ii; bool result=false; bool whiletest1,whiletest2; if ((molecule1==NULL) || (! fIsQueryPrepare)) return result; if (molecule1->nAtoms()==0) return result; if (molecule1->listarSize()>aSTested.size()) aSTested.resize(molecule1->listarSize()); if (molecule1->listarSize()>bSTested.size()) bSTested.resize(molecule1->listarSize()); if (molecule1->listarSize()>queryQHydr.size()) queryQHydr.resize(molecule1->listarSize()); if (molecule1->listarSize()>queryAQTested.size()) queryAQTested.resize(molecule1->listarSize()); if (molecule1->listarSize()>queryBQTested.size()) queryBQTested.resize(molecule1->listarSize()); if (molecule1->listarSize()>queryCurrentAssignment.size()) queryCurrentAssignment.resize(molecule1->listarSize()); if (this->listarSize()>queryAQTested.size()) queryAQTested.resize(this->listarSize()); for (int i=0; inAtoms(); i++) for (j=0; jnBonds(); i++) for (j=0; j0) { j=0; if (molecule1.fBruttoFormula.nD>0) { whiletest1=true; while (whiletest1) { j++; k=0; test1.value=(fBruttoFormula.eList[j]==104) && (! fIOPT11); whiletest2=true; if ((fBruttoFormula.eList[j] != 1) && (! test1.value)) while (whiletest2) { k++; test2=((fBruttoFormula.eList[j]==molecule1.fBruttoFormula.eList[k]) && (fBruttoFormula.eNumber[j]<=molecule1.fBruttoFormula.eNumber[k])); whiletest2=test2 || (k==molecule1.fBruttoFormula.nD); whiletest2=! whiletest2; } else test2=true; whiletest1=(! test2) || (j==fBruttoFormula.nD); whiletest1=! whiletest1; }; } else test2=false; } else test2=true; */ test2=true; //turn of molecular formula filter molecule1->fIOPT11=fIOPT11; molecule1->fIOPT12=fIOPT13; molecule1->fIOPT13=fIOPT13; if (test2) { //{R/S/Z/E description are removed: they are not used in substructure search} if (fIOPT13) molecule1->atomBondChange(); //Semipolar bond conversion molecule1->defineAtomConn(); molecule1->defineBondConn(structureBK); stereoS=molecule1->stereoBondChange(); //Stereo bond conversion} for (j=0; jnAtoms(); j++) { //Isotops conversion} if ((molecule1->getAtom(j)->na==104) && (! fIOPT11)) molecule1->getAtom(j)->na=1; if (! fIOPT11) molecule1->getAtom(j)->iz=0; bSTested[j]=0; //bsTested contains nu. explicit hydrogens - so 0 is fine! }; for (j=0; jnAtoms(); j++) if (molecule1->getAtom(j)->na==1) if (molecule1->getAtom(j)->nb>0) for (k=0; kgetAtom(j)->nb; k++) { //Formation of list explicitly-defined hydrogens} l=molecule1->getAtom(j)->ac[k]; bSTested[l]=bSTested[l]+1; }; for (k=0; knAtoms()>0) while (whiletest1) { test2=TSingleAtom::atomEquivalent(molecule1->getAtom(j),getAtom(0),bSTested[j],queryQHydr[0],fIOPT10,fIOPT11); //Addition for aromatic search} if (test2 && ((getAtom(0)->special & AROMATIC_MASK)!=0) ) { test2=false; for (m=0; m<=structureBK[j].nb; m++) { mm=structureBK[j].adjusted[m]; if ((molecule1->getBond(mm)->db==2) || (molecule1->getBond(mm)->db==3)) { test2=true; break; }; }; }; //End addition} if (test2) { if (queryEnum.size()<1) queryEnum.resize(1); queryEnum[0]=0; if (queryAQTested.size()<1) queryAQTested.resize(1); queryAQTested[0]=j; }; j++; whiletest1=test2 || (j==molecule1->nAtoms()); whiletest1=! whiletest1; }; } else if (nBonds()==0) test2=false; else { //General case - substructure search if (fIncludedList != NULL) { for (j=0; jnAtoms(); j++) for (k=0; knAtoms(); j++) for (k=0; kgetAtom(j),getAtom(k),bSTested[j], queryQHydr[k],fIOPT10,fIOPT11) && (getAtom(k)->nb<=molecule1->getAtom(j)->nb)); //Addition for aromatic search if (test3 && ((getAtom(k)->special & AROMATIC_MASK) !=0)) { test3=false; for (m=0; mgetBond(mm)->db==2) || (molecule1->getBond(mm)->db==3)) { test3=true; break; }; }; }; aEQ[j][k]=test3; if (test3) aSTested[k]=1; }; }; for (j=0; jnBonds(); j++) for (k=0; kat[0]; aq2=getBond(k)->at[1]; as1=molecule1->getBond(j)->at[0]; as2=molecule1->getBond(j)->at[1]; test2=(aEQ[as1][aq1] && aEQ[as2][aq2]) || (aEQ[as1][aq2] && aEQ[as2][aq1]); if (test2) { test3=TSingleBond::bondEquivalent(molecule1->getBond(j),getBond(k)); bEQ[j][k]=test3; if (test3) queryAQTested[k]=1; } else bEQ[j][k]=false; }; //Check, if all query atoms has a partner in structure test2=allQueryPresent(aSTested,queryAQTested,nAtoms(),nBonds()); if (test2) { j1=0; for (k=1; knAtoms(); k++) if (aEQ[k][0]) { //Collection of structure atoms, which may be associated with first query atom j=0; whiletest1=true; while (whiletest1) { test=bEQ[structureBK[k].adjusted[j]][0]; if (test) { queryCurrentAssignment[j1]=k; j1++; }; j++; whiletest1=test || (j==structureBK[k].nb); whiletest1=! whiletest1; }; }; i1=0; whiletest1=true; if (j1>0) while (whiletest1) //for each structure, which may be assigned to 1-st query { for (j=0; jnBonds(); j++) bSTested[j]=-1; for (j=0; jnAtoms(); j++) aSTested[j]=-1; queryAQTested[0]=queryCurrentAssignment[i1]; aSTested[queryCurrentAssignment[i1]]=0; ii=0; whiletest2=true; while (whiletest2) //start recursion { directBondAss(ii,test,test1,bEQ,aEQ,queryBQCounter,queryAQTested,bSTested, queryBQTested,aSTested,queryAGer,queryBK,structureBK,molecule1); if ((! test) && (ii>=1)) { //previous atom were badly assigned-backstep queryBQCounter[ii]=0; k=queryAGer[ii-1]; if (k>=0) { l=queryAQTested[k]; queryAQTested[k]=-1; aSTested[l]=-1; }; bSTested[queryBQTested[ii-1]]=-1; queryBQTested[ii-1]=-1; ii=ii-2; test=true; }; ii=ii+1; //query bond counter whiletest2=(ii==nBonds()) || ((! test) && (ii==1)); whiletest2=! whiletest2; }; i1++; test2=(ii==nBonds()); //Checking, if success has been reached whiletest1=((j1==i1) || test2); whiletest1=! whiletest1; } else test2=false; }; }; }; if ((bondLabel != NULL) && (nBonds()>0)) { bondLabel->resize(molecule1->nBonds()); if (test2) for (j=0; jnBonds(); j++) if (bSTested[j]>=0) (*bondLabel)[j]=1; else (*bondLabel)[j]=0; }; result=test2; return result; }; //*************************************************************************** // Diagram generation routines //*************************************************************************** class PartFragmentDefinition { public: int fragID1,fragID2,fragID3,fragFirstAtomNo; int fragmentCount; double fragWidth,fragHeight,fragTop,fragLeft; PartFragmentDefinition() { }; void assign(const PartFragmentDefinition source) { fragID1=source.fragID1; fragID2=source.fragID2; fragID3=source.fragID3; fragFirstAtomNo=source.fragFirstAtomNo; fragmentCount=source.fragmentCount; fragWidth=source.fragWidth; fragHeight=source.fragHeight; fragTop=source.fragTop; fragLeft=source.fragLeft; }; }; class TemplateRedraw { public: TemplateRedraw(); // virtual ~TemplateRedraw() { // clear(); // }; bool isOverlapped(const std::vector list, int fragNo, double xSuggested, double ySuggested); void arrangeFragments(std::vector& list, int fragNo, double aspOptimal); void redrawFine(TSimpleMolecule& smIn); int coordinatesPrepare(TEditedMolecule& sm, int kk, int anTemplateNo); private: static std::vector queryData; void clear(); bool internalBondsPresent(TEditedMolecule * mQuery, TSimpleMolecule * mStructure); void rotateBondVertically(TSimpleMolecule * sm, const std::vectorbondList, int bondNo, double xuValue, double yuValue, double& c1, double& s1, double& xSize, double& ySize, double& xCenter, double& yCenter, int& nVert); void selectFragmentConfiguration(TSimpleMolecule * sm, std::vector* atomList); void rescaleSingleFragment(TSimpleMolecule * sm, std::vector* atomList, int alCount, PartFragmentDefinition& pf, double offset); void arrangeMolecules(std::vector& extendedList, double aspOptimal); bool loadTemplates(); }; //Initialization of static member variable std::vector TemplateRedraw::queryData; bool TemplateRedraw::loadTemplates() { std::ifstream ifs; string filename("templates.sdf");//("e:\\templates.sdf"); TEditedMolecule sm; TEditedMolecule * em; int i,na1,na2; bool test; bool result=false; try { OpenDatafile(ifs, filename); } catch (exception ex) { return result; }; //Read into a vector of OBMol if (ifs) { OBConversion conv(&ifs); conv.SetInFormat("sdf"); OBMol mol; // mol.SetIsPatternStructure(); // modified by Igor - not in OB 2.2.0 while (conv.Read(&mol)) { sm.readOBMol(&mol); mol.Clear(); for (i=0; ina != 1) sm.getAtom(i)->na=ANY_ATOM; sm.getAtom(i)->nc=0; } for (i=0; iat[0]; na2=sm.getBond(i)->at[1]; test=((sm.getAtom(na1)->na != 1) && (sm.getAtom(na2)->na != 1)); if (test) sm.getBond(i)->tb=ANY_BOND; //ANY bons } sm.defineAtomConn(); sm.allAboutCycles(); em=new TEditedMolecule(); em->prepareQuery(sm); queryData.push_back(em); } result=true; obErrorLog.ThrowError(__FUNCTION__, "Read OK " + filename, obInfo); } // else {obErrorLog.ThrowError(__FUNCTION__, "Cannot find " + filename, obWarning);} return result; }; TemplateRedraw::TemplateRedraw() { if(queryData.empty()) //Load internal and external templates only once { int i,j; TEditedMolecule * em; TEditedMolecule * em1; TEditedMolecule * em2; TEditedMolecule sm; bool test; //Load external.. loadTemplates(); //...and internal templates for (i=0; iprepareQuery(sm); queryData.push_back(em); } if (queryData.size()>1) for (i=0; i<(queryData.size()-1); i++) for (j=i+1; jnAtoms() < em2->nAtoms()) test=true; else if (em1->nAtoms() > em2->nAtoms()) test=false; else if (em1->nBonds() < em2->nBonds()) test=true; if (test) { queryData[i]=em2; queryData[j]=em1; } } } } void TemplateRedraw::clear() { for (int i=0; i aList(mStructure->nAtoms()); std::vector bList(mStructure->nBonds()); int i,n1,n2; bool result=false; for (i=0; inAtoms(); i++) aList[mQuery->queryAQTested[i]]=1; for (i=0; inBonds(); i++) bList[mQuery->queryBQTested[i]]=1; for (i=0; igetBond(i)->at[0]; n2=mStructure->getBond(i)->at[1]; if ((aList[n1] == 1) && (aList[n2] == 1)) result=true; if (result) break; }; //seek for 3-attached atom return result; }; void TemplateRedraw::rotateBondVertically(TSimpleMolecule * sm, const std::vectorbondList, int bondNo, double xuValue, double yuValue, double& c1, double& s1, double& xSize, double& ySize, double& xCenter, double& yCenter, int& nVert) { //Dummy rotation of molecule //Two solution - when c2,s2 are used - are determined for cases of rotaition when Up and Down are counterchnged. Single solution would be enough std::vector atomList(NATOMSMAX); int i,n,n1,n2; bool test; double rX,rY,r; std::vector coorX(NATOMSMAX); std::vector coorY(NATOMSMAX); double xMin,xMax,yMin,yMax; xSize=0; ySize=0; c1=1; s1=0; xCenter=0; yCenter=0; nVert=0; for (i=0; inAtoms(); i++) atomList[i]=false; test=false; for (i=0; igetBond(n)->at[0]; n2=sm->getBond(n)->at[1]; atomList[n1]=true; atomList[n2]=true; }; if (! test) return; //bond is absent in the list.... n1=sm->getBond(bondNo)->at[0]; n2=sm->getBond(bondNo)->at[1]; xCenter=sm->getAtom(n2)->rx; yCenter=sm->getAtom(n2)->ry; rX=sm->getAtom(n1)->rx-xCenter; rY=sm->getAtom(n1)->ry-yCenter; r=sqrt(rX*rX+rY*rY); if (r != 0) { rX=rX/r; rY=rY/r; if (abs(rX) < 0.00001) { s1=xuValue/rY; c1=-yuValue/rY; } else if (abs(rY) < 0.00001) { s1=yuValue/rX; c1=xuValue/rX; } else { s1=(xuValue/rX+yuValue/rY)/(rY/rX+rX/rY); c1=(xuValue/rY-yuValue/rX)/(rY/rX+rX/rY); }; }; //c1, s1 analizing for (i=0; inAtoms(); i++) { coorX[i]=c1*(sm->getAtom(i)->rx-xCenter)+s1*(sm->getAtom(i)->ry-yCenter); coorY[i]=s1*(sm->getAtom(i)->rx-xCenter)-c1*(sm->getAtom(i)->ry-yCenter); }; xMin=RUNDEF; xMax=RUNDEF; yMin=RUNDEF; yMax=RUNDEF; for (i=0; inAtoms(); i++) if (atomList[i]) { if ((coorX[i] < xMin) || (xMin == RUNDEF)) xMin=coorX[i]; if ((coorX[i] > xMax) || (xMax == RUNDEF)) xMax=coorX[i]; if ((coorY[i] < yMin) || (yMin == RUNDEF)) yMin=coorY[i]; if ((coorY[i] > yMax) || (yMax == RUNDEF)) yMax=coorY[i]; }; xSize=xMax-xMin; ySize=yMax-yMin; //calculation no. vertical bonds... for (i=0; igetBond(n)->at[0]; n2=sm->getBond(n)->at[1]; //no. vert. bonds r=coorY[n1]-coorY[n2]; if (abs(r) > 0) { r=abs((coorX[n1]-coorX[n2])/r); if (r < 0.02) nVert++; }; }; }; void TemplateRedraw::selectFragmentConfiguration(TSimpleMolecule * sm, std::vector* atomList) { //for each fragment in AtomList select optimal angle of rotation double xMax; double xSize; double ySize; double xCenter; double yCenter; double c; double s; int nVert; double cMax,sMax,x,y; std::vector bondList(0); std::vector bondListAll(0); std::vector atomCleaned(NATOMSMAX); int i,j,n,n1,n2,w; bool test; if (atomList == NULL) { for (i=0; inAtoms(); i++) atomCleaned[i]=true; } else { for (i=0; inAtoms(); i++) atomCleaned[i]=false; for (i=0; isize(); i++) { n=(*atomList)[i]; atomCleaned[n]=true; }; }; //bondList generation... for (i=0; inBonds(); i++) { n1=sm->getBond(i)->at[0]; n2=sm->getBond(i)->at[1]; if (atomCleaned[n1] && atomCleaned[n2]) { w=i; bondListAll.push_back(w); if (sm->getBond(i)->db > 1) bondList.push_back(w); //only ring bonds... }; }; if (bondList.size() == 0) { bondList.resize(bondListAll.size()); for (i=0; i 0) { //search for 4-coordinater non-carbon test=false; n=-1; for (i=0; inAtoms(); i++) if (atomCleaned[i] && (sm->getAtom(i)->na != 6) && (sm->getAtom(i)->nb == 4)) { test=true; for (j=0; jnBonds(); j++) if ((sm->getBond(j)->at[0] == i) || (sm->getBond(j)->at[1] == i)) { n=j; if (sm->getBond(j)->db > 1) { n=-1; test=false; break; }; }; if (test) break; }; if (! test) for (i=0; inBonds(); i++) if (atomCleaned[sm->getBond(i)->at[0]] && (sm->getBond(i)->db == 5)) { n=i; test=true; break; }; if (test) { rotateBondVertically(sm,bondListAll,n,1.0,0.0,c,s,xSize,ySize,xCenter,yCenter,nVert); if (ySize > xSize) rotateBondVertically(sm,bondListAll,n,0.0,1.0,c,s,xSize,ySize,xCenter,yCenter,nVert); cMax=c; sMax=s; } else { xMax=0; cMax=1; sMax=0; for (i=0; i xMax) { xMax=xSize; cMax=c; sMax=s; }; }; for (i=0; i xMax) { xMax=xSize; cMax=c; sMax=s; }; }; }; //Rotation for (i=0; inAtoms(); i++) if (atomCleaned[i]) { x=cMax*(sm->getAtom(i)->rx-xCenter)+sMax*(sm->getAtom(i)->ry-yCenter); y=sMax*(sm->getAtom(i)->rx-xCenter)-cMax*(sm->getAtom(i)->ry-yCenter); sm->getAtom(i)->rx=x; sm->getAtom(i)->ry=y; }; }; }; void TemplateRedraw::rescaleSingleFragment(TSimpleMolecule * sm, std::vector* atomList, int alCount, PartFragmentDefinition& pf, double offset) { int i,n; double xMin,xMax,yMin,yMax; double scale,r1,r2; double x,y; xMin=RUNDEF; xMax=RUNDEF; yMin=RUNDEF; yMax=RUNDEF; for (i=0; igetAtom(n)->rx < xMin) || (xMin == RUNDEF)) xMin=sm->getAtom(n)->rx; if ((sm->getAtom(n)->rx > xMax) || (xMax == RUNDEF)) xMax=sm->getAtom(n)->rx; if ((sm->getAtom(n)->ry < yMin) || (yMin == RUNDEF)) yMin=sm->getAtom(n)->ry; if ((sm->getAtom(n)->ry > yMax) || (yMax == RUNDEF)) yMax=sm->getAtom(n)->ry; }; if ((xMax == xMin) && (yMax == yMin)) { for (i=0; igetAtom(n)->rx=(pf.fragLeft+pf.fragWidth/2); sm->getAtom(n)->ry=(pf.fragTop+pf.fragHeight/2); }; return; }; if (xMin == xMax) //y should be scaled { scale=(pf.fragHeight-2*offset)/(yMax-yMin); } else if (yMin == yMax) //x should be scaled { scale=(pf.fragWidth-2*offset)/(xMax-xMin); } else { r1=(pf.fragHeight-2*offset)/(yMax-yMin); r2=(pf.fragWidth-2*offset)/(xMax-xMin); if (r1 > r2) scale=r2; else scale=r1; }; for (i=0; igetAtom(n)->rx-xMin)*scale; y=pf.fragTop+offset+(sm->getAtom(n)->ry-yMin)*scale; sm->getAtom(n)->rx=x; sm->getAtom(n)->ry=y; }; }; bool ptInRect(const Rect r, const Point p) { bool result=((p.x >= r.left) & (p.x <= r.right) & (p.y >= r.top) & (p.y <= r.bottom)); return result; } bool TemplateRedraw::isOverlapped(const std::vector list, int fragNo, double xSuggested, double ySuggested) { // !!! Zero-based fragno !!! //checking if recteangles are overlapped from different fagments. Rect rect; Point p; int i,j,n1,n2; PartFragmentDefinition * ef; PartFragmentDefinition * efTemp; bool test, result; result=false; ef=(PartFragmentDefinition *)list[fragNo]; rect.left=xSuggested; rect.top=ySuggested; rect.right=rect.left+ef->fragWidth; rect.bottom=rect.top+ef->fragHeight; for (i=0; ifragLeft+efTemp->fragWidth) < rect.left); if (! test) test=((efTemp->fragTop+efTemp->fragHeight) < rect.top); if (! test) test=(efTemp->fragLeft > rect.right); if (! test) test=(efTemp->fragTop > rect.bottom); if (! test) { n1=(int)(efTemp->fragLeft); n2=(int)(efTemp->fragLeft+efTemp->fragWidth); for (j=n1; j<=n2; j++) { p.x=j; p.y=efTemp->fragTop; if (ptInRect(rect,p)) { result=true; return result; }; p.x=j; p.y=efTemp->fragTop+efTemp->fragHeight; if (ptInRect(rect,p)) { result=true; return result; }; }; n1=(int)(efTemp->fragTop); n2=(int)(efTemp->fragTop+efTemp->fragHeight); for (j=n1; j<=n2; j++) { p.y=j; p.x=efTemp->fragLeft; if (ptInRect(rect,p)) { result=true; return result; }; p.y=j; p.x=efTemp->fragLeft+efTemp->fragWidth; if (ptInRect(rect,p)) { result=true; return result; }; }; }; }; return result; }; void TemplateRedraw::arrangeFragments(std::vector& list, int fragNo, double aspOptimal) { //!! Frag no zero-based! double aspDelta,xNice,yNice,xMax,yMax,xMin,yMin,r,x,y,xNew,yNew; PartFragmentDefinition * ef; PartFragmentDefinition * efInterest; int i; ef=(PartFragmentDefinition *)list[0]; xMax=ef->fragLeft+ef->fragWidth; yMax=ef->fragTop+ef->fragHeight; xMin=ef->fragLeft; yMin=ef->fragTop; //Calculate sizes.... for (i=1; ifragLeft+ef->fragWidth; if (r > xMax) xMax=r; r=ef->fragTop+ef->fragHeight; if (r > yMax) yMax=r; if (ef->fragTop < yMin) yMin=ef->fragTop; if (ef->fragLeft < xMin) xMin=ef->fragLeft; }; aspDelta=1000000; xNice=0; yNice=0; efInterest=(PartFragmentDefinition *)list[fragNo]; for (i=0; ifragLeft+ef->fragWidth+1; y=ef->fragTop; if (! isOverlapped(list,fragNo,x,y)) { if (((x+efInterest->fragWidth) <= xMax) && ((y+efInterest->fragHeight) <= yMax)) { efInterest->fragLeft=x; efInterest->fragTop=y; list[fragNo]=efInterest; return; }; xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax; yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax; r=(yNew-yMin)/(xNew-xMin); if (abs(r-aspOptimal) < aspDelta) { xNice=x; yNice=y; aspDelta=abs(r-aspOptimal); }; }; x=ef->fragLeft; y=ef->fragTop+ef->fragHeight+1; if (! isOverlapped(list,fragNo,x,y)) { if (((x+efInterest->fragWidth) <= xMax) && ((y+efInterest->fragHeight) <= yMax)) { efInterest->fragLeft=x; efInterest->fragTop=y; list[fragNo]=efInterest; return; }; xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax; yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax; r=(yNew-yMin)/(xNew-xMin); if (abs(r-aspOptimal) < aspDelta) { xNice=x; yNice=y; aspDelta=abs(r-aspOptimal); }; }; }; //if here - maxX,0 and 0,MaxY have to be tested... x=xMax; y=0; xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax; yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax; r=(yNew-yMin)/(xNew-xMin); if (abs(r-aspOptimal) < aspDelta) { xNice=x; yNice=y; aspDelta=abs(r-aspOptimal); }; x=0; y=yMax; xNew=x+efInterest->fragWidth; if (xMax > xNew) xNew=xMax; yNew=y+efInterest->fragHeight; if (yMax > yNew) yNew=yMax; r=(yNew-yMin)/(xNew-xMin); if (abs(r-aspOptimal) < aspDelta) { xNice=x; yNice=y; aspDelta=abs(r-aspOptimal); }; efInterest->fragLeft=xNice; efInterest->fragTop=yNice; list[fragNo]=efInterest; }; void TemplateRedraw::arrangeMolecules(std::vector& extendedList, double aspOptimal) { int i,j; PartFragmentDefinition * ef; PartFragmentDefinition * efTemp; double maxX,minY,minX,maxY,r,r1; if (extendedList.size() > 1) { //Search for Max Width and MaxHeight fragments for (i=0; i<(extendedList.size()-1); i++) for (j=i+1; jfragWidth > ef->fragWidth) { extendedList[j]=ef; extendedList[i]=efTemp; }; }; if (extendedList.size() > 2) { ef=(PartFragmentDefinition *)extendedList[1]; for (i=2; ifragHeight > ef->fragHeight) { extendedList[i]=ef; extendedList[1]=efTemp; ef=efTemp; }; }; }; //Try to arrange 1-st and 2-nd fragments.... ef=(PartFragmentDefinition *)extendedList[0]; efTemp=(PartFragmentDefinition *)extendedList[1]; maxX=ef->fragWidth+efTemp->fragWidth; minY=efTemp->fragHeight; if (ef->fragHeight > minY) minY=ef->fragHeight; r=minY/maxX; minX=ef->fragWidth; maxY=ef->fragHeight+efTemp->fragHeight; r1=maxY/minX; if (abs(r-aspOptimal) < abs(r1-aspOptimal)) { if (ef->fragHeight > efTemp->fragHeight) { efTemp->fragLeft=ef->fragWidth; extendedList[1]=efTemp; } else { ef->fragLeft=efTemp->fragWidth; extendedList[0]=ef; }; } else { efTemp->fragTop=ef->fragHeight; extendedList[1]=efTemp; }; //Arranging of 3-rd and more frgments... if (extendedList.size()>2) for (i=2; i listAtomClean(NBONDSMAX); std::vector listBondClean(NBONDSMAX); std::vector templateAtomNumber(0); std::vector fragmentAtomNumber(0); bool test,test1; std::vector groupsFind(0); TEditedMolecule tm; TEditedMolecule * emTemplate; std::vector enumerator(0); TSingleBond * sb; int nFound; TEditedMolecule * smFragment; TEditedMolecule * smRest; int naStore; int result; sm.defineAtomConn(); sm.allAboutCycles(); result=-1; for (i=kk; ifragmentSearch(&sm,NULL)) { em=(TEditedMolecule *)queryData[i]; if (! internalBondsPresent(em,&sm)) { result=i+1; break; }; em=NULL; }; if (em == NULL) { if (anTemplateNo >= 0) { sm.addAtom(6,0,0.0,0.0); sm.addBond(1,anTemplateNo,sm.nAtoms()-1); sm.defineAtomConn(); }; sm.redrawMolecule(); if (anTemplateNo >= 0) { sm.deleteBond(sm.nBonds()); sm.deleteAtom(sm.nAtoms()-1); sm.defineAtomConn(); }; } else { //Hurrah! Found! Redraw from template listAtomClean.resize(NBONDSMAX); listBondClean.resize(NBONDSMAX); templateAtomNumber.resize(0); fragmentAtomNumber.resize(0); //Atom list formation atomClean=0; for (i=0; inAtoms(); j++) { k=em->queryAQTested[j]; if (i==k) { //Coordinates assigning sm.getAtom(i)->rx=em->getAtom(j)->rx; sm.getAtom(i)->ry=em->getAtom(j)->ry; test=true; break; }; }; if (test) //Only those atoms, defined at template, are cleaned..... { listAtomClean[atomClean]=i; atomClean++; }; }; enumerator.resize(sm.nAtoms()); //index-old number value-new number for (i=0; iclone()); }; //Bond enumeration for (i=0; iclone(); sb->at[0]=enumerator[sb->at[0]]; sb->at[1]=enumerator[sb->at[1]]; tm.addBond(sb); }; nFound=atomClean; //now tm is the same as sm (simplemolecule) on input, but coordinates will be taken from template for first nFound atoms tm.defineAtomConn(); tm.allAboutCycles(); //search for connected bonds test=true; while (test) { test=false; for (i=tm.nBonds()-1; i>=0; i--) { test1=((tm.getBond(i)->at[0]<=nFound) && (tm.getBond(i)->at[1]>nFound)) || ((tm.getBond(i)->at[1]<=nFound) && (tm.getBond(i)->at[0]>nFound)); if (test1) if ((tm.getBond(i)->db<=1) && (tm.getAtom(tm.getBond(i)->at[0])->nb > 1) && (tm.getAtom(tm.getBond(i)->at[1])->nb > 1)) //acyclic bond { test=true; emTemplate=new TEditedMolecule(); if (tm.getBond(i)->at[1] >nFound) fragmentAN=tm.getBond(i)->at[1]; else fragmentAN=tm.getBond(i)->at[0]; //Error is absent! Really 2-nd atom is compared in both operators! if (tm.getBond(i)->at[1] >nFound) templateAN=tm.getBond(i)->at[0]; else templateAN=tm.getBond(i)->at[1]; templateAtomNumber.push_back(tm.getAtom(templateAN)->enumerator); //in template.... fragmentAtomNumber.push_back(tm.getAtom(fragmentAN)->enumerator); tm.deleteBond(i); //must be called prior extract fragment tm.defineAtomConn(); smFragment=tm.extractFragment(fragmentAN,NULL); smRest=tm.extractFragment(templateAN,NULL); tm.moleculeCopy(*smRest); //I have to delete unnecessary atoms and bond here... emTemplate->moleculeCopy(*smFragment); groupsFind.push_back(emTemplate); delete(smFragment); delete(smRest); }; if (test) break; }; }; //Atom clean list formation atomClean=tm.nAtoms()-nFound; for (i=0; iat[0]) test=true; if (listAtomClean[j]==tm.getBond(i)->at[1]) test=true; if (test) break; }; if (test) { listBondClean[bondClean]=i; bondClean++; }; }; //and cleaning.... tm.defineAtomConn(); tm.redraw(listAtomClean,listBondClean,atomClean,bondClean,4,0,0,false); for (i=0; inAtoms(); j++) if (emTemplate->getAtom(j)->enumerator==fragmentAtomNumber[i]) { fragmentAN=j; break; }; emTemplate->refofs=sm.refofs; coordinatesPrepare(*emTemplate,0,fragmentAN); //recursive call templateAN=-1; fragmentAN=-1; for (j=0; jenumerator==templateAtomNumber[i]) { templateAN=j; break; }; for (j=0; jnAtoms(); j++) if (emTemplate->getAtom(j)->enumerator==fragmentAtomNumber[i]) { fragmentAN=j; break; }; naStore=tm.nAtoms(); tm.refofs=sm.refofs; tm.addAsTemplate(*emTemplate,templateAN,fragmentAN,-1,-1,true); if ((naStore+emTemplate->nAtoms()) == tm.nAtoms()) for (j=0; jnAtoms(); j++) { tm.getAtom(naStore+j)->enumerator=emTemplate->getAtom(j)->enumerator; }; }; sm.moleculeCopy(tm); sm.defineAtomConn(); sm.allAboutCycles(); }; for (i=0; i atomTested(smIn.nAtoms()); std::vector atomList(NATOMSMAX); std::vector stereoBondList(0); int w; PartFragmentDefinition * pf; std::vector frList(0); double xMin,xMax,yMin,yMax; double oldBondLength,newBondLength; std::vector molList(0); //contains list of molecules... TEditedMolecule * sm; TEditedMolecule smCopy; TEditedMolecule smCopy2; int frCount,nA; TSingleAtom * sA; TSingleBond * sB; StereoBondStore * sbs; int nOverlapped, nOverlappedMin; //smIn will be clear-nothing oldBondLength=smIn.averageBondLength(); if (oldBondLength < 0.1) oldBondLength=1.0; smCopy.moleculeCopy(smIn); for (i=0; itb == 9) || (smIn.getBond(i)->tb == 10)) { w=0; //!!!! add for STEREO later !!!! w.value=ProcessStereo.analizeRS(smIn,smIn.fBond.getAT(i,1)); if (w>0) { sbs=new StereoBondStore(); sbs->bn=i; sbs->w=w; stereoBondList.push_back(sbs); }; }; for (i=0; ianum=intToStr(i); for (i=0; idefineAtomConn(); molList.push_back(sm); }; int qq=0; for (frCount=0; frCountnAtoms(); i++) sm->getAtom(i)->enumerator=i; n=0; nOverlappedMin=10000000; smCopy2.moleculeCopy(*sm); while (n >=0) { qq++; sm->refofs=smIn.refofs; n=coordinatesPrepare(*sm,n,-1); //Contrary to Delphi project - block of storing double-bonds is absent here. //I need to create AnalizeZE rpocedure to handle double-bond nOverlapped=sm->correctOverlapped(); if (nOverlapped < nOverlappedMin) { smCopy2.moleculeCopy(*sm); nOverlappedMin=nOverlapped; } else sm->moleculeCopy(smCopy2); if (nOverlappedMin == 0) n=-1; }; sm->defineAtomConn(); atomList.resize(sm->nAtoms()); for (i=0; iaverageBondLength(); if (newBondLength > 0) for (i=0; inAtoms(); i++) { sm->getAtom(i)->rx=sm->getAtom(i)->rx*oldBondLength/newBondLength; sm->getAtom(i)->ry=sm->getAtom(i)->ry*oldBondLength/newBondLength; }; //stereo input try }; frList.resize(0); smCopy.clear(); nA=0; for (frCount=0; frCountnAtoms(); i++) { sA=sm->getAtom(i)->clone(); smCopy.addAtom(sA); }; for (i=0; inBonds(); i++) { sB=sm->getBond(i)->clone(); sB->at[0]=sm->getBond(i)->at[0]+nA; sB->at[1]=sm->getBond(i)->at[1]+nA; smCopy.addBond(sB); }; //dimensions store.... xMin=RUNDEF; xMax=RUNDEF; yMin=RUNDEF; yMax=RUNDEF; for (j=0; jnAtoms(); j++) { if ((sm->getAtom(j)->rx < xMin) || (xMin == RUNDEF)) xMin=sm->getAtom(j)->rx; if ((sm->getAtom(j)->rx > xMax) || (xMax == RUNDEF)) xMax=sm->getAtom(j)->rx; if ((sm->getAtom(j)->ry < yMin) || (yMin == RUNDEF)) yMin=sm->getAtom(j)->ry; if ((sm->getAtom(j)->ry > yMax) || (yMax == RUNDEF)) yMax=sm->getAtom(j)->ry; }; pf=new PartFragmentDefinition(); pf->fragID1=0; pf->fragID2=0; pf->fragID3=0; pf->fragFirstAtomNo=nA+1; pf->fragmentCount=1; pf->fragWidth=xMax-xMin; pf->fragHeight=yMax-yMin; pf->fragTop=0; pf->fragLeft=0; frList.push_back(pf); //Prepare for new get nA=nA+sm->nAtoms(); }; smCopy.defineAtomConn(); //arrange fragments atomList.resize(NATOMSMAX); if (frList.size()>1) { newBondLength=smCopy.averageBondLength(); for (i=0; ifragWidth=pf->fragWidth+newBondLength; pf->fragHeight=pf->fragHeight+newBondLength; }; arrangeMolecules(frList,1/1.5); //rescaling in fragments.... for (i=0; ifragFirstAtomNo,-1); rescaleSingleFragment(&smCopy,&atomList,w,*pf,newBondLength/2); }; }; //rescaling to satisfy bond length newBondLength=smCopy.averageBondLength(); if (newBondLength>0) for (i=0; irx=smCopy.getAtom(i)->rx*oldBondLength/newBondLength; smCopy.getAtom(i)->ry=smCopy.getAtom(i)->ry*oldBondLength/newBondLength; }; for (i=0; ianum.c_str()); if (n >= 0) { smIn.getAtom(n)->rx=smCopy.getAtom(i)->rx; smIn.getAtom(n)->ry=smCopy.getAtom(i)->ry; }; }; for (i=0; ibn,1)); !!!! add for STEREO later !!!! if ((w > 0) && (w != sbs->w)) { if (smIn.getBond(sbs->bn)->tb == 9) smIn.getBond(sbs->bn)->tb=10; else smIn.getBond(sbs->bn)->tb=9; }; }; for (i=0; i