1 /**********************************************************************
2 Copyright (C) 2007 by Mike N. Burnett, burnettmn@ornl.gov
3 Copyright (C) 2007 by Sergei V. Trepalin sergey_trepalin@chemical-block.com
4 Copyright (C) 2007 by Andrei Gakh andrei.gakh@nnsa.doe.gov
5
6 Code translation from Java
7
8 This file is part of the Open Babel project.
9 For more information, see <http://openbabel.org/>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19 ***********************************************************************/
20 #include <openbabel/babelconfig.h>
21 #include <openbabel/obmolecformat.h>
22 #include <openbabel/mol.h>
23 #include <openbabel/atom.h>
24 #include <openbabel/elements.h>
25 #include <openbabel/bond.h>
26
27 #include <openbabel/mcdlutil.h>
28 #include <cstdlib>
29
30 using namespace std;
31 namespace OpenBabel
32 {
33
34 class MCDLFormat : public OBMoleculeFormat
35 {
36 public:
MCDLFormat()37 MCDLFormat()
38 {
39 OBConversion::RegisterFormat("mcdl",this);
40 init();
41 }
42
Description()43 virtual const char* Description() //required
44 {
45 return
46 "MCDL format\n"
47 "Modular Chemical Descriptor Language\n\n"
48 "As described in [gb2001]_.\n\n"
49
50 ".. [gb2001] A.A. Gakh and M.N. Burnett. **Modular Chemical Descriptor\n"
51 " Language (MCDL): Composition, Connectivity and\n"
52 " Supplementary Modules.**\n"
53 " *J. Chem. Inf. Comput. Sci.*, **2004**, *41*, 1491-1499.\n"
54 " [`Link <https://doi.org/10.1021/ci000108y>`_]\n\n"
55
56 "Here's an example conversion from SMILES to MCDL::\n\n"
57 " obabel -:\"CC(=O)Cl\" -omcdl\n"
58 " CHHH;COCl[2]\n";
59 }
60
SpecificationURL()61 virtual const char* SpecificationURL(){return
62 "http://pubs.acs.org/cgi-bin/abstract.cgi/jcisd8/2001/41/i06/abs/ci000108y.html";}
63
GetMIMEType()64 virtual const char* GetMIMEType()
65 { return "chemical/x-MCDL"; }
66
67 /* Flags() can return be any of the following combined by |
68 or be omitted if none apply
69 NOTREADABLE READONEONLY NOTWRITABLE WRITEONEONLY DEFAULTFORMAT
70 READBINARY WRITEBINARY READXML ZEROATOMSOK*/
Flags()71 virtual unsigned int Flags()
72 {
73 return 0;
74 }
75
SkipObjects(int n,OBConversion * pConv)76 virtual int SkipObjects(int n, OBConversion* pConv)
77 {
78 if(n==0) n++;
79 string temp;
80 istream& ifs = *pConv->GetInStream();
81 do {
82 if(ifs.good())
83 getline(ifs, temp);
84 }while(ifs.good() && --n);
85 return ifs.good() ? 1 : -1;
86 }
87
88 ////////////////////////////////////////////////////
89 /// Declarations for the "API" interface functions. Definitions are below
90 virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
91 virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
92
93 private:
94
95 string fsastart;
96 string fsbstart;
97 string fchstart;
98 string fradstart;
99 //coordinates string
100 string fnastart;
101 string fnbstart;
102 string fzcoorstart;
103 string fablockstart;
104 string fbblockstart;
105 string fchargeblockstart;
106 string fstereobondstart;
107 string ftitlestart;
108
109 // int fragNo;
110 int maxdepth;
111 int kflag;
112
113 int ntatoms;
114 int nbonds;
115 string finalstr;
116
117 int qx [MAXFRAGS];
118 int qa [MAXBONDS][4];
119 // int HVal[NELEMMAX];
120
121 private:
122 void init();
123 void initGlobals();
124 void solve(int ntypes, int z[MAXBONDS][4], int depth);
125 string constring(int conntab [MAXBONDS][4], char * tstr);
126 string intToStr(int k);
127 string getMCDL(OBMol* pmol, bool includeCoordinates);
128 void restoreFullMCDL(string value, OBMol* pmol);
129 void setMCDL(const string lineToParse, OBMol* pmol, string & sout);
130 void assignCharges(const std::vector <int> aPosition, const std::vector <int> iA1,
131 const std::vector <int> iA2, std::vector <int>& aCharges, std::vector <int>& charges,
132 std::vector <int>& bondOrder, int aPos, int nPrev, int nt, int acount, int bcount);
133 int indexOf(const string instring, const string substring, int fromPos=0);
134 int lastIndexOf(const string instring, const string substring);
135 bool parseFormula(const string formulaString, std::vector <int>& enumber);
136 string getMolTitle(string & line);
137
138 };
139
140
141
init()142 void MCDLFormat::init(){
143 fsastart="{SA:";
144 fsbstart="{SB:";
145 fchstart="{CZ:";
146 fradstart="{RA:";
147 //coordinates string
148 fnastart="{NA:";
149 fnbstart="{NB:";
150 fzcoorstart="{ZV:";
151 fablockstart="{CC:";
152 fbblockstart="{BB:";
153 fchargeblockstart="{MM:CHG,";
154 fstereobondstart="{BS:";
155 ftitlestart="{CN:}";
156
157 };
158
initGlobals()159 void MCDLFormat::initGlobals(){
160 int i,j;
161
162 maxdepth=0;
163 kflag=0;
164
165 ntatoms=0;
166 nbonds=0;
167 finalstr="";
168
169 for (i=0; i<MAXFRAGS; i++) {
170 qx[i]=0;
171 for (j=0; j<4; j++) qa[i][j]=0;
172 };
173
174 };
175
176
177
178 /* Create descriptor connectivity string from connectivity table of fragments */
constring(int conntab[MAXBONDS][4],char * tstr)179 string MCDLFormat::constring(int conntab [MAXBONDS][4], char * tstr)
180 {
181 int i,j,k,n,nn,icons[6],comma;
182 char line[82],semis[100];
183 string result="";
184
185 result="[";
186 semis[0] = '\0';
187
188 for (i=0; i<ntatoms; i++)
189 {
190 if (i > 0)
191 strcat(semis,";");
192
193 n = 0;
194 for (j=0; j<nbonds; j++)
195 if (conntab[j][2] == (i+1))
196 icons[n++] = conntab[j][3];
197 if (n > 1)
198 {
199 for (j=0; j<n-1; j++)
200 for (k=j+1; k<n; k++)
201 if (icons[k] < icons[j])
202 {
203 nn = icons[j];
204 icons[j] = icons[k];
205 icons[k] = nn;
206 }
207
208 }
209 comma = 0;
210 for (j=0; j<n; j++)
211 {
212 if (icons[j] > (i+1) && comma == 0)
213 {
214 sprintf(line,"%s%d",semis,icons[j]);
215 result=result+line;//strcat(sp,line);
216 comma = 1;
217 semis[0] = '\0';
218 }
219 else if (icons[j] > (i+1) && comma == 1)
220 {
221 sprintf(line,",%d",icons[j]);
222 result=result+line;//strcat(sp,line);
223 }
224
225 }
226 }
227
228 result=result+"]";
229 return result;
230 }
231
232
solve(int ntypes,int z[MAXBONDS][4],int depth)233 void MCDLFormat::solve(int ntypes, int z[MAXBONDS][4], int depth)
234 {
235 int i,dupnum,j,k,ktype,nn,nt;
236 bool iflag,newone;
237 int * nsum[MAXBONDS];
238 bool lflag[MAXFRAGS];
239 char strg[MAXFRAGS+1];
240 char * strngs[MAXFRAGS+1];
241 char tstr[MAXFRAGS+1];
242 int numdups, dupfrag, jump;
243 bool jflag;
244 int ix[MAXFRAGS],conntab[MAXBONDS][4],cx[MAXFRAGS];
245 int mx[MAXFRAGS];
246
247 //stack overflow message-move data from stack to heap
248 for (i=0; i<=MAXFRAGS; i++) strngs[i]=(char *)malloc(MAXFRAGS);
249 for (i=0; i<MAXBONDS; i++) nsum[i]=(int *) malloc(MAXFRAGS);
250
251 // depth = recursion level
252 if (depth > 10)
253 {
254 printf("Ten recursion levels exceeded.\n");
255 return;
256 //exitprog(freeflag);
257 }
258 if (depth > maxdepth)
259 maxdepth = depth;
260
261 for (i=0; i<nbonds; i++)
262 {
263 for (j=0; j<4; j++)
264 conntab[i][j] = z[i][j];
265 mx[conntab[i][0]-1] = conntab[i][2];
266 }
267
268 jflag = true;
269 if (depth == 1)
270 {
271 jflag = false;
272 for (i=0; i<ntatoms; i++)
273 {
274 ix[i] = mx[i];
275 if (ix[i] != mx[0])
276 jflag = true;
277 }
278 }
279
280 iflag = true;
281 while (iflag)
282 {
283 if (jflag)
284 for (i=0; i<ntatoms; i++)
285 ix[i] = 0;
286
287 nt = 1;
288 ktype = 1;
289 iflag = false;
290
291 while (nt <= ntypes && jflag)
292 {
293 for (j=0; j<ntatoms; j++)
294 {
295 lflag[j] = false;
296 for (i=0; i<nbonds; i++)
297 nsum[i][j] = 0;
298 }
299
300 for (i=0; i<nbonds; i++)
301 if (conntab[i][2] == nt)
302 {
303 j = conntab[i][0]-1;
304 k = conntab[i][3]-1;
305 nsum[j][k]++;
306 lflag[j] = true;
307 }
308
309 nn = 0;
310
311 for (i=0; i<ntatoms; i++)
312 if (lflag[i])
313 {
314 for (j=0; j<ntypes; j++)
315 strg[j] = nsum[i][j]+48;
316 strg[ntypes] = '\0';
317 newone = true;
318 for (j=0; j<nn; j++)
319 if (strcmp(strngs[j],strg) == 0)
320 { newone = false;
321 break;
322 }
323 if (newone)
324 strcpy(strngs[nn++],strg);
325 }
326
327 if (nn > 1)
328 {
329 iflag = true;
330
331 // sort strings
332 for (i=0; i<nn-1; i++)
333 for (j=i+1; j<nn; j++)
334 if (strcmp(strngs[j],strngs[i]) > 0)
335 {
336 strcpy(tstr,strngs[i]);
337 strcpy(strngs[i],strngs[j]);
338 strcpy(strngs[j],tstr);
339 }
340 }
341
342 for (i=0; i<ntatoms; i++)
343 if (lflag[i])
344 {
345 for (j=0; j<ntypes; j++)
346 strg[j] = nsum[i][j]+48;
347 strg[ntypes] = '\0';
348 for (j=0; j<nn; j++)
349 if (strcmp(strg,strngs[j]) == 0)
350 ix[i] = ktype+j;
351 }
352
353 nt++;
354 ktype += nn;
355 }
356
357 ntypes = 0;
358 for (i=0; i<nbonds; i++)
359 {
360 conntab[i][2] = ix[conntab[i][0]-1];
361 conntab[i][3] = ix[conntab[i][1]-1];
362 if (conntab[i][2] > ntypes)
363 ntypes = conntab[i][2];
364 }
365
366 if (iflag)
367 continue;
368
369 if (ntypes < ntatoms)
370 {
371 for (j=0; j<ntypes; j++)
372 {
373 numdups = 0;
374 for (i=0; i<ntatoms; i++)
375 if (ix[i] == j+1)
376 {
377 numdups++;
378 jump = ix[i] - mx[i];
379 }
380 if (numdups > 1)
381 {
382 dupfrag = j+1;
383 break;
384 }
385 }
386
387 for (i=0; i<ntatoms; i++)
388 cx[i] = ix[i];
389
390 for (j=0; j<numdups; j++)
391 {
392 for (i=0; i<ntatoms; i++)
393 ix[i] = cx[i];
394
395 dupnum = 0;
396 for (i=0; i<ntatoms; i++)
397 {
398 if (ix[i] > dupfrag)
399 ix[i] = mx[i] + jump + 1;
400 else if (ix[i] == dupfrag && j != dupnum)
401 {
402 dupnum++;
403 ix[i] = mx[i] + jump + 1;
404 }
405 else if (ix[i] == dupfrag && j == dupnum)
406 dupnum++;
407 }
408
409 ntypes = 0;
410 for (i=0; i<nbonds; i++)
411 {
412 conntab[i][2] = ix[conntab[i][0]-1];
413 conntab[i][3] = ix[conntab[i][1]-1];
414 if (conntab[i][2] > ntypes)
415 ntypes = conntab[i][2];
416 }
417 solve(ntypes,conntab,depth+1);
418 }
419 }
420 }
421
422 if (ntypes == ntatoms)
423 {
424 //if (true) fprintf(o_verbose,"%s\n",constring(conntab,tstr));
425
426 if (!kflag)
427 {
428 kflag++;
429 finalstr=constring(conntab,tstr);
430 for (i=0; i<ntatoms; i++)
431 qx[i] = ix[i];
432 for (i=0; i<nbonds; i++)
433 for (j=0; j<4; j++)
434 qa[i][j] = conntab[i][j];
435 }
436 else if (finalstr != constring(conntab,tstr))
437 {
438 for (i=0; i<ntatoms; i++)
439 {
440 tstr[0] = '\0';
441 strg[0] = '\0';
442 for (j=0; j<ntatoms; j++)
443 {
444 strcat(tstr,"0");
445 strcat(strg,"0");
446 }
447 for (j=0; j<nbonds; j++)
448 {
449 if (conntab[j][2] == (i+1))
450 tstr[conntab[j][3]-1] = '1';
451 if (qa[j][2] == (i+1))
452 strg[qa[j][3]-1] = '1';
453 }
454 if (strcmp(tstr,strg) < 0)
455 break;
456 if (strcmp(tstr,strg) > 0)
457 {
458 finalstr=constring(conntab,tstr);
459 for (j=0; j<ntatoms; j++)
460 qx[j] = ix[j];
461 for (j=0; j<nbonds; j++)
462 for (k=0; k<4; k++)
463 qa[j][k] = conntab[j][k];
464 break;
465 }
466 }
467 }
468 }
469 //freeing resources
470 for (i=0; i<=MAXFRAGS; i++) free(strngs[i]);
471 for (i=0; i< MAXBONDS; i++) free(nsum[i]);
472 }
473
474
intToStr(int k)475 string MCDLFormat::intToStr(int k) {
476 char temp[16];
477 sprintf(temp,"%d",k);
478 string line=temp;
479 return line;
480 };
481
482
483
getMCDL(OBMol * pmol,bool includeCoordinates)484 string MCDLFormat::getMCDL(OBMol* pmol, bool includeCoordinates) {
485 int i=0;
486 int j=0;
487 int k=0;
488 int n=0;
489 int nt=0;
490 int nn=0;
491 int ntypes=0;
492 int charge=0;
493 int netcharge=0;
494 int netradical=0;
495 int chgarray[60][2];
496 std::vector<int> ifragnum(MAXFRAGS);
497 int ltypes=0;
498 int ia0=0;
499 int ia1=0;
500 int chgflag=0;
501 int radicalflag=0;
502 int icons[96];
503 int newone=0;
504 std::vector<int> nchg(MAXFRAGS);
505 std::vector<int> nrad(MAXFRAGS);
506 int naStore,nbStore;
507 string constr="";
508 string frag="";
509 string fragment [MAXFRAGS];
510 string line="";
511 string semis="";
512 int comma;
513 std::vector<int> ix(MAXFRAGS);
514 int ia[MAXBONDS][4];
515 string data="";
516 int z[MAXBONDS][4];
517 //FRAGCON
518 int nHydr[MAXFRAGS];
519 string aSymb [MAXFRAGS];
520 int aCharge[MAXFRAGS];
521 int aRadical[MAXFRAGS];
522 std::vector<int> aNumber(MAXFRAGS);
523 int bonds[MAXBONDS][4];
524 int nConn[MAXFRAGS];
525 //string s;
526 int l;//,m;
527 string astereo="";
528 string bstereo="";
529 string s1,s2;
530 std::vector <int> eqList;
531 std::vector <int> bondStereoList;
532 std::vector <int> atomStereoList;
533 std::vector <int> anumStereo;
534 string as1,as2,as3,as4;
535 string linestereo;
536 OBAtom *atom;
537 OBBond *bond;
538
539 /* read in fragments and find different types */
540 /* ntypes: number of fragment types */
541 /* ntatoms: total number of fragments */
542 /* fragment[i]: atomic symbol string of fragment type i */
543 /* ifragnum[i]: number of fragments of type i */
544
545 initGlobals();
546 ntypes = 0;
547 ntatoms = 0;
548 for (i=0; i<MAXFRAGS; i++)
549 ifragnum[i] = 0;
550
551 chgflag = 0;
552 netcharge = 0;
553 radicalflag=0;
554 netradical=0;
555
556 netcharge=pmol->GetTotalCharge();
557 netradical=pmol->GetTotalSpinMultiplicity()-1;
558
559 //Here FRAGCON conversion...
560 pmol->DeleteHydrogens();
561 createStereoLists(pmol,bondStereoList,atomStereoList,eqList);
562 // return "started"; //passed
563 naStore=pmol->NumAtoms();
564 nbStore=pmol->NumBonds();
565 for (i=1; i<=naStore; i++) {
566 atom=pmol->GetAtom(i);
567 nHydr[i-1]=atom->GetImplicitHCount()+atom->ExplicitHydrogenCount();
568 aCharge[i-1]=atom->GetFormalCharge();
569 aRadical[i-1]=atom->GetSpinMultiplicity();
570 aSymb[i-1]=OBElements::GetSymbol(atom->GetAtomicNum());
571 nConn[i-1]=atom->GetHvyDegree();
572 aNumber[i-1]=i-1;
573 };
574 for (i=1; i<=nbStore; i++) {
575 bond=pmol->GetBond(i-1);
576 bonds[i-1][0]=bond->GetBeginAtomIdx();
577 bonds[i-1][1]=bond->GetEndAtomIdx();
578 bonds[i-1][2]=bond->GetBondOrder(); //type of bond store
579 bonds[i-1][3]=i; //bond number in sm store
580 };
581 //FRAGCON
582 i=0;
583 while (i < naStore) {
584 if ((nConn[i] == 1) && (nHydr[i] == 0)) {
585 k=-1;
586 for (j=0; j<nbStore; j++) if ((bonds[j][0] == (i+1)) || (bonds[j][1] == (i+1))) {
587 k=j;
588 break;
589 }
590 if (k>=0) {
591 if (bonds[k][0] == (i+1)) nn=bonds[k][1]-1; else nn=bonds[k][0]-1;
592 aCharge[nn]=aCharge[nn]+aCharge[i];
593 aRadical[nn]=aRadical[nn]+aRadical[i];
594 aSymb[nn]=aSymb[nn]+aSymb[i];
595 for (j=i; j<(naStore-1); j++) {
596 nHydr[j]=nHydr[j+1];
597 aCharge[j]=aCharge[j+1];
598 aRadical[j]=aRadical[j+1];
599 aSymb[j]=aSymb[j+1];
600 nConn[j]=nConn[j+1];
601 aNumber[j]=aNumber[j+1];
602 };
603 for (j=0; j<nbStore; j++) {
604 if (bonds[j][0] > (i+1)) bonds[j][0]--;
605 if (bonds[j][1] > (i+1)) bonds[j][1]--;
606 };
607 for (j=k; j<(nbStore-1); j++) {
608 bonds[j][0]=bonds[j+1][0];
609 bonds[j][1]=bonds[j+1][1];
610 bonds[j][2]=bonds[j+1][2];
611 bonds[j][3]=bonds[j+1][3];
612 };
613 i--;
614 naStore--;
615 nbStore--;
616 };
617 };
618 i++;
619 }
620 //Ald without fragcon
621 for (i=1; i<=naStore; i++) {
622 charge=aCharge[i-1];
623 if (charge != 0) chgflag = 1;
624 if (aRadical[i-1] != 0) radicalflag=1;
625 ntatoms++;
626 newone = 1;
627 frag=aSymb[i-1];
628 j=nHydr[i-1];
629 if (j>0) for (l=0; l<j; l++) {
630 frag=frag+"H";
631 };
632 for (j=0; j<ntypes; j++) if (fragment[j] == frag) {
633 ifragnum[j]++;
634 newone = 0;
635 break;
636 }
637 if (newone != 0) {
638 fragment[ntypes]=frag;
639 ifragnum[ntypes]++;
640 ntypes++;
641 }
642 }
643
644 ltypes=ntypes;
645 // order fragment types in ASCII order
646 for (i=0; i<ntypes-1; i++) for (j=i+1; j<ntypes; j++) if (fragment[j] < fragment[i]) {
647 frag=fragment[i];
648 fragment[i]=fragment[j];
649 fragment[j]=frag;
650 k = ifragnum[i];
651 ifragnum[i] = ifragnum[j];
652 ifragnum[j] = k;
653 }
654 // reread the fragments
655 // ix[i]: fragment type of fragment i
656 for (i=1; i<=ntatoms; i++) {
657 frag=aSymb[i-1];
658 j=nHydr[i-1];
659 if (j>0) for (l=0; l<j; l++) {
660 frag=frag+"H";
661 };
662 for (j=0; j<ntypes; j++) if (frag == fragment[j]) ix[i-1] = j+1;
663 }
664
665 //FRAGCON format atoms conversion
666 // read in the connections
667 // ia[i][0]: from fragment; ia[i][1]: to fragment of connection i
668 nbonds = 0;
669 for (i=1; i<=nbStore; i++) {
670 // Possible, DRAGON format can contains multiply bonds between 2 atoms. Bond order?
671 ia0=bonds[i-1][0];
672 ia1=bonds[i-1][1];
673
674 newone = 1;
675 for (j=0; j<nbonds; j++)
676 if ((ia[j][0] == ia0 && ia[j][1] == ia1) ||
677 (ia[j][0] == ia1 && ia[j][1] == ia0))
678 {
679 newone = 0;
680 break;
681 }
682 if (newone == 1) {
683 ia[nbonds][0] = ia0;
684 ia[nbonds][1] = ia1;
685 nbonds=nbonds+1;
686 ia[nbonds][0] = ia1;
687 ia[nbonds][1] = ia0;
688 nbonds=nbonds+1;
689 }
690 };
691 for (i=0; i<nbonds; i++) {
692 ia[i][2] = ix[ia[i][0]-1];
693 ia[i][3] = ix[ia[i][1]-1];
694 };
695 for (i=0; i<nbonds; i++) for (j=0; j<4; j++) {
696 z[i][j] = ia[i][j];
697 };
698 maxdepth = 1;
699
700 // data ready for solution
701 solve(ntypes,z,1);
702
703 for (i=0; i<ntatoms; i++) ix[i] = qx[i];
704 for (i=0; i<nbonds; i++) for (j=0; j<4; j++) ia[i][j] = qa[i][j];
705
706 //atoms stereo getting
707 astereo=getAtomMCDL(pmol,ntatoms,ix,aNumber,atomStereoList,eqList);
708 //bond stereo getting
709 bstereo=getBondMCDL(pmol,nbStore,ntatoms,ix,aNumber,bonds,bondStereoList,eqList);
710
711 // original and final fragment numbers
712 if (chgflag != 0) for (i=0; i<ntatoms; i++) nchg[ix[i]] = aCharge[i];
713 if (radicalflag != 0) for (i=0; i<ntatoms; i++) nrad[ix[i]] = aRadical[i];
714
715 // net charge
716 data="";
717 if (netcharge != 0)
718 {
719 if (netcharge > 0)
720 data=data+intToStr(netcharge)+"+;";
721 else data=data+intToStr(abs(netcharge))+"-;";
722 }
723 if (netradical != 0) data=data+intToStr(netradical)+"*;";
724 // fragment portion of linear descriptor
725 for (i=0; i<ltypes; i++) {
726 if (i > 0) {
727 data=data+';';
728 }
729 if (ifragnum[i] > 1) {
730 data=data+intToStr(ifragnum[i]);
731 }
732 data=data+fragment[i];
733 }
734 constr="[";
735 // connectivity portion of linear descriptor
736 semis="";
737 nt = 1;
738 for (i=0; i<ntatoms; i++) {
739 if (i > 0) {
740 semis=semis+";";
741 }
742 n = 0;
743 for (j=0; j<nbonds; j++) if (ia[j][2] == (i+1)) icons[n++] = ia[j][3];
744 if (n > 1) {
745 for (j=0; j<n-1; j++) for (k=j+1; k<n; k++) if (icons[k] < icons[j]) {
746 nn = icons[j];
747 icons[j] = icons[k];
748 icons[k] = nn;
749 }
750 }
751 comma = 0;
752 for (j=0; j<n; j++) {
753 if ((icons[j] > (i+1)) && (comma == 0)) {
754 constr=constr+semis;
755 constr=constr+intToStr(icons[j]);
756 comma = 1;
757 semis="";
758 } else if ((icons[j] > (i+1)) && (comma == 1)) {
759 constr=constr+","+intToStr(icons[j]);
760 }
761 }
762 nt++;
763 };
764 line=line+"]";
765
766 constr=constr+line;
767 data=data+constr;
768 // fragment charges
769 if (chgflag != 0) {
770 nt = 0;
771 for (n=-3; n<4; n++) for (i=0; i<ntatoms; i++) if ((nchg[ix[i]] == n) && (n != 0)) {
772 chgarray[nt][0] = n;
773 chgarray[nt++][1] = ix[i];
774 }
775 for (i=0; i<nt-1; i++) for (j=i; j<nt; j++) if (chgarray[i][0] > chgarray[j][0]) {
776 k = chgarray[i][0];
777 n = chgarray[i][1];
778 chgarray[i][0] = chgarray[j][0];
779 chgarray[i][1] = chgarray[j][1];
780 chgarray[j][0] = k;
781 chgarray[j][1] = n;
782 }
783 for (i=0; i<nt-1; i++) for (j=i; j<nt; j++) if ((chgarray[i][0] == chgarray[j][0]) && (chgarray[i][1] > chgarray[j][1])) {
784 n = chgarray[i][1];
785 chgarray[i][1] = chgarray[j][1];
786 chgarray[j][1] = n;
787 }
788 line="";
789 for (i=-1; i>-4; i--) {
790 n = 0;
791 for (j=0; j<nt; j++) if (chgarray[j][0] == i) n++;
792 if (n > 0) {
793 for (j=0; j<nt; j++) if (chgarray[j][0] == i) {
794 if (chgarray[j][1] == 0)
795 frag=""+intToStr(chgarray[j][1])+","+intToStr(abs(i))+"-";//Math.abs(i)+"-1";
796 else
797 frag=""+intToStr(chgarray[j][1])+","+intToStr(abs(i))+"-";//Math.abs(i)+"-"+chgarray[j][1];
798 if (line.length() > 0) line=line+";";
799 line=line+frag;
800 }
801 }
802 }
803 for (i=1; i<4; i++){
804 n = 0;
805 for (j=0; j<nt; j++) if (chgarray[j][0] == i) n++;
806 if (n > 0) {
807 for (j=0; j<nt; j++) if (chgarray[j][0] == i) {
808 if (chgarray[j][1] == 0)
809 frag=""+intToStr(chgarray[j][1])+","+intToStr(i)+"+";//i+"+1";
810 else
811 frag=""+intToStr(chgarray[j][1])+","+intToStr(i)+"+";
812 if (line.length() > 0) line=line+";";
813 line=line+frag;
814 }
815 }
816 }
817 if (ntypes>1) {
818 constr=fchstart;//"{CZ:";
819 constr=constr+line;
820 constr=constr+"}";
821 data=data+constr;
822 };
823
824 };
825 //radical processing
826 if (radicalflag != 0) {
827 for (i=0; i<ntatoms; i++) {
828 chgarray[i][0]=0;
829 chgarray[i][1]=0;
830 };
831 nt = 0;
832 for (n=1; n<3; n++) for (i=0; i<ntatoms; i++) if (nrad[ix[i]] == n) {
833 chgarray[nt][0] = n;
834 chgarray[nt++][1] = ix[i];
835 }
836 for (i=0; i<nt-1; i++) for (j=i; j<nt; j++) if (chgarray[i][0] > chgarray[j][0]) {
837 k = chgarray[i][0];
838 n = chgarray[i][1];
839 chgarray[i][0] = chgarray[j][0];
840 chgarray[i][1] = chgarray[j][1];
841 chgarray[j][0] = k;
842 chgarray[j][1] = n;
843 }
844 for (i=0; i<nt-1; i++) for (j=i; j<nt; j++) if ((chgarray[i][0] == chgarray[j][0]) && (chgarray[i][1] > chgarray[j][1])) {
845 n = chgarray[i][1];
846 chgarray[i][1] = chgarray[j][1];
847 chgarray[j][1] = n;
848 }
849 line="";
850 for (i=1; i<3; i++){
851 n = 0;
852 for (j=0; j<nt; j++) if (chgarray[j][0] == i) n++;
853 if (n > 0) {
854 for (j=0; j<nt; j++) if (chgarray[j][0] == i) {
855 if (chgarray[j][1] == 0)
856 frag=""+intToStr(chgarray[j][1])+","+intToStr(i)+"*";
857 else
858 frag=""+intToStr(chgarray[j][1])+","+intToStr(i)+"*";
859 if (line.length() > 0) line=line+";";
860 line=line+frag;
861 }
862 }
863 }
864 if (ntypes>1) {
865 constr=fradstart;//"{CZ:";
866 constr=constr+line;
867 constr=constr+"}";
868 data=data+constr;
869 };
870
871 };
872
873 //*****************************************************************************
874 data=data+astereo;
875 data=data+bstereo;
876 //*****************************************************************************
877 /* Block should be saved for future using
878
879 if (includeCoordinates && (sm.fAtom.maxIndex() > 0)) {
880 //Atom and bond blocks include
881 data=data+fnastart+sm.fAtom.maxIndex()+"}";//};
882 data=data+fnbstart+sm.fBond.maxIndex()+"}";//};
883 data=data+fzcoorstart+"N}";
884 //analizing minimal and maximal values of atomic coordinates
885 xMin=sm.fAtom.getRX(1); xMax=sm.fAtom.getRX(1); yMin=sm.fAtom.getRY(1); yMax=sm.fAtom.getRY(1);
886 for (i=1; i<=sm.fAtom.maxIndex(); i++) {
887 if (sm.fAtom.getRX(i) < xMin) xMin=sm.fAtom.getRX(i);
888 if (sm.fAtom.getRX(i) > xMax) xMax=sm.fAtom.getRX(i);
889 if (sm.fAtom.getRY(i) < yMin) yMin=sm.fAtom.getRY(i);
890 if (sm.fAtom.getRY(i) > yMax) yMax=sm.fAtom.getRY(i);
891 };
892 scale=0;
893 if (xMax != xMin) scale=1/(xMax-xMin);
894 if (yMax != yMin) if ((1/(yMax-yMin)) < scale) scale=1/(yMax-yMin);
895 if (scale == 0) scale=1;
896 line=fablockstart;
897 nCharge=0;
898 for (i=1; i<=sm.fAtom.maxIndex(); i++) {
899 r=sm.fAtom.getRX(i);
900 r=9.99*(r-xMin)*scale;
901 s=CommonRout.str(r,0,2);
902 line=line+s+",";
903 r=sm.fAtom.getRY(i);
904 r=9.99*(r-yMin)*scale;
905 s=CommonRout.str(r,0,2);
906 line=line+s+Atom.symbolofAtom(sm.fAtom.getNA(i));
907 if (i < sm.fAtom.maxIndex()) line=line+";"; else line=line+"}";//};
908 if (sm.fAtom.getNC(i) != 0) nCharge++;
909 };
910 data=data+line;
911 line=fbblockstart;
912 //two lines - adition for stereo handling
913 test=false;
914 linestereo=fstereobondstart;
915 for (i=1; i<=sm.fBond.maxIndex(); i++) {
916 n=sm.fBond.getTB(i);
917 s="s";
918 if (n > 3) n=1;
919 if (n == 2) s="d"; else if (n == 3) s="t";
920 s=""+sm.fBond.getAT(i,1)+s+sm.fBond.getAT(i,2);
921 line=line+s;
922 if (i < sm.fBond.maxIndex()) line=line+";"; else line=line+"}"; //};
923 //stereoanalizing
924 n=sm.fBond.getTB(i);
925 if ((n >= 9) && (n <= 11)) {
926 if (test) linestereo=linestereo+";";
927 test=true;
928 s="p";
929 if (n == 10) s="o"; else if (n == 11) s="e";
930 s=""+sm.fBond.getAT(i,1)+s+sm.fBond.getAT(i,2);
931 linestereo=linestereo+s;
932 };
933 };
934 data=data+line;
935 if (test) {
936 linestereo=linestereo+"}"; //};
937 data=data+linestereo;
938 };
939 if (nCharge != 0) {
940 line=fchargeblockstart+nCharge;
941 for (i=1; i<= sm.fAtom.maxIndex(); i++) if (sm.fAtom.getNC(i) != 0) line=line+","+i+","+sm.fAtom.getNC(i);
942 line=line+"}";
943 data=data+line;
944 };
945 };
946 */
947 return data;
948 };
949
restoreFullMCDL(string value,OBMol * pmol)950 void MCDLFormat::restoreFullMCDL(string value, OBMol* pmol) {
951
952 };
953
setMCDL(const string lineToParse,OBMol * pmol,string & sout)954 void MCDLFormat::setMCDL(const string lineToParse, OBMol* pmol, string & sout) {
955
956 std::vector <int> nH(MAXFRAGS);
957 std::vector <int> nF(MAXFRAGS);
958 // int nb;//,na;
959 unsigned int i, j, nt, n1, n2;//,n3, nfrag;
960 bool test;
961 OBAtom sa;
962 string mf="";
963 string s="";
964 string temp="";
965 string ss="";
966 string sstore="";
967 int m,n,k;
968 std::vector <int> nHydr(MAXFRAGS);
969 string astereo="";
970 string bstereo="";
971 string chargestring="";
972 string radicalstring="";
973 int nPrev;
974 string sa1="";
975 string sa2="";
976 string sF="";
977 std::vector <int> charges(MAXFRAGS);
978 std::vector <int> radicals(MAXFRAGS);
979 std::vector <int> fragIndex(MAXFRAGS);
980 std::vector <int> sbSpecial(MAXBONDS);
981 std::vector <int> enumber(NELEMMAX); //number of elements...
982 std::vector <int> bondOrders(MAXBONDS);
983 std::vector <double> rx(MAXFRAGS);
984 std::vector <double> ry(MAXFRAGS);
985 std::vector <string> names(MAXFRAGS);
986 int netcharge=0;
987 int netradical=0;
988 unsigned int nelements=0;
989 int kk;
990 string value="";
991 unsigned int acount, bcount, flags;
992
993 std::vector <int> iA1(MAXBONDS);
994 std::vector <int> iA2(MAXBONDS);
995 std::vector <int> aPosition(MAXFRAGS);
996 std::vector <int> aCharge(MAXFRAGS);
997 std::vector <int> aRad(MAXFRAGS);
998 std::vector <int> stereoBonds(MAXBONDS);
999
1000 value=lineToParse;
1001 sout="";
1002
1003 if ((indexOf(value,fablockstart) >= 0) && (indexOf(value,fbblockstart) > 0)) {
1004 restoreFullMCDL(value,pmol);
1005 return;
1006 };
1007 for (i=0; i<MAXBONDS; i++) {
1008 stereoBonds[i]=0;
1009 sbSpecial[i]=0;
1010 iA1[i]=0;
1011 iA2[i]=0;
1012 };
1013
1014 for (i=0; i<MAXFRAGS; i++) {
1015 charges[i]=0;
1016 radicals[i]=0;
1017 fragIndex[i]=0;
1018 //special[i]=0;
1019 nHydr[i]=0;
1020 names[i]="";
1021 aPosition[i]=6;
1022 aCharge[i]=0;
1023 aRad[i]=0;
1024 };
1025 //removing net charges and radiacal
1026 test=false;
1027 n=1;
1028 while ((value.length() > 0) && (value.at(0) >= '0') && (value.at(0) <= '9') && (! test) && (n>0)) {
1029 n=indexOf(value,";");
1030 if (n>0) {
1031 s=value.substr(0,n);
1032 n1=indexOf(s,"+");
1033 if (n1 < 0) n1=indexOf(s,"-");
1034 if (n1 < 0) n1=indexOf(s,"*");
1035 if (n1 < 0) {
1036 n=0;
1037 test=true;
1038 };
1039 };
1040 if (n > 0) {
1041 s=value.substr(0,n);
1042 if ((s.at(s.length()-1) == '+') || (s.at(s.length()-1) == '-')) {
1043 //total charge processing
1044 if (s.at(s.length()-1) == '+') netcharge=1; else netcharge=-1;
1045 s=s.substr(0,s.length()-1);
1046 n1=atoi(s.c_str());
1047 netcharge=netcharge*n1;
1048 } else if (s.at(s.length()-1) == '*') {
1049 //radical processing
1050 s=s.substr(0,s.length()-1);
1051 n1=atoi(s.c_str());
1052 netradical=n1;
1053 };
1054 value=value.substr(n+1,value.length());
1055 if (value.length() > 0) if (value.at(0) == ';'){
1056 value=value.substr(1);
1057 };
1058 };
1059 };
1060
1061 //stereo string extraction
1062
1063 n1=indexOf(value,fsastart);
1064 if (n1>=0) {
1065 n2=indexOf(value,"}",n1);
1066 if (n2>0) {
1067 astereo=""+value.substr(n1+fsastart.length(),n2);
1068 value=value.substr(0,n1)+value.substr(n2+1);
1069 }
1070 };
1071 n1=indexOf(value,fsbstart);
1072 if (n1>=0) {
1073 n2=indexOf(value,"}",n1);
1074 if (n2>0) {
1075 bstereo=""+value.substr(n1+fsbstart.length(),n2);
1076 value=value.substr(0,n1)+value.substr(n2+1);
1077 }
1078 };
1079 //charges processing
1080 n1=indexOf(value,fchstart);
1081 if (n1>=0) {
1082 n2=indexOf(value,"}",n1);
1083 if (n2>0) {
1084 chargestring=""+value.substr(n1+fchstart.length(),n2);
1085 value=value.substr(0,n1)+value.substr(n2+1);
1086 };
1087 };
1088 if ((netcharge != 0) && (chargestring == "")) {
1089 chargestring = "1," +intToStr(abs(netcharge));
1090 if (netcharge < 0) chargestring=chargestring+"-"; else chargestring=chargestring+"+";
1091 };
1092 //radical processing
1093 n1=indexOf(value,fradstart);
1094 if (n1>=0) {
1095 n2=indexOf(value,"}",n1);
1096 if (n2>0) {
1097 radicalstring=""+value.substr(n1+fradstart.length(),n2);
1098 value=value.substr(0,n1)+value.substr(n2+1);
1099 };
1100 };
1101 if ((netradical != 0) && (radicalstring == "")) {
1102 radicalstring= "1," + intToStr(abs(netcharge)) + "*";
1103 };
1104
1105 n1=indexOf(value,"]");
1106 if (n1 > 0) {
1107 value=value.substr(0,n1); //by unknown reason it was n1-1
1108 };
1109
1110 //Atom array analizing
1111 test=true;
1112 nt=0;
1113 nelements=0;
1114
1115
1116 while (test) {
1117 n1=indexOf(value,";");
1118 n2=indexOf(value,"[");
1119
1120 if (n1<0) {
1121 n1=n2;
1122 } else {
1123 if ((n2<n1) && (n2>=0)) n1=n2;
1124 };
1125 mf=value.substr(0,n1);
1126 value=value.substr(n1,value.length());
1127 if (value.at(0)==';') value=value.substr(1,value.length());
1128 n1=1;
1129 if ((mf.at(0)>='0') && (mf.at(0)<='9')) {
1130 test=true;
1131 temp="";
1132 while (test) {
1133 temp=temp+mf.at(0);
1134 mf=mf.substr(1,mf.length());
1135 test=(mf.at(0)>='0') && (mf.at(0)<='9');
1136 };
1137 n1=atoi(temp.c_str());
1138 };
1139 //do not change n1==nFrag!!!
1140 nt=nt+n1;
1141 //Conversion of XxHHHH to XxHn
1142 n2=lastIndexOf(mf,"HH");
1143 while (n2>0) {
1144 if (n2<(mf.length()-2)) {
1145 ss=mf.substr(mf.length()-1,mf.length());
1146 k=atoi(ss.c_str())+1;//Integer.parseInt(ss)+1;
1147 } else k=2;
1148 mf=mf.substr(0,n2+1)+intToStr(k);
1149 n2=lastIndexOf(mf,"HH");
1150 };
1151 //passed to this point...
1152 //End convsrsion
1153 n2=indexOf(mf,"H");
1154 temp="0";
1155 if (n2>0) {
1156 if (n2<(mf.length()-1)) {
1157 temp=mf.substr(n2+1,mf.length());
1158 } else temp="1";
1159 mf=mf.substr(0,n2);
1160 };
1161 n2=atoi(temp.c_str());//Integer.parseInt(temp);
1162 //do not change n2 - number of hydrogens...
1163
1164 nH[nelements]=n2;
1165 nF[nelements]=n1;
1166 names[nelements]=mf;
1167 nelements++;
1168
1169 test=value.at(0) != '[';
1170 };
1171
1172 sa.Clear();
1173
1174 acount=nt;
1175
1176 //parsing and analizing...
1177 for (i=0; i<MAXFRAGS; i++) charges[i]=0;
1178 if (chargestring != "") while (chargestring.length() > 0) {
1179 n1=indexOf(chargestring,";");
1180 if (n1>0) {
1181 s=chargestring.substr(0,n1);
1182 chargestring=chargestring.substr(n1+1);
1183 } else {
1184 s=chargestring;
1185 chargestring="";
1186 };
1187 n1=indexOf(s,",");
1188 if (n1 > 0) {
1189 sa1=s.substr(0,n1);
1190 s=s.substr(n1+1);
1191 n2=1;
1192 if (indexOf(s,"-") > 0) n2=-1;
1193 s=s.substr(0,s.length()-1);
1194 n1=atoi(s.c_str());
1195 n1=n1*n2;
1196 n2=atoi(sa1.c_str());
1197 charges[n2-1]=n1;
1198 };
1199 };
1200 for (i=0; i<MAXFRAGS; i++) radicals[i]=0;
1201 if (radicalstring != "") while (radicalstring.length() > 0) {
1202 n1=indexOf(radicalstring,";");
1203 if (n1>0) {
1204 s=radicalstring.substr(0,n1);
1205 radicalstring=radicalstring.substr(n1+1);
1206 } else {
1207 s=radicalstring;
1208 radicalstring="";
1209 };
1210 n1=indexOf(s,",");
1211 if (n1 > 0) {
1212 sa1=s.substr(0,n1);
1213 s=s.substr(n1+1);
1214 n2=1;
1215 if (indexOf(s,"-") > 0) n2=-1;
1216 s=s.substr(0,s.length()-1);
1217 n2=atoi(sa1.c_str());
1218 radicals[n2-1]=1;
1219 };
1220 };
1221 //passed
1222
1223
1224
1225 nt=0;
1226 ss="";
1227 bcount=0;
1228
1229 for (i=0; i<nelements; i++) {
1230 s=names[i];
1231 n1=1;
1232 if (s.length()>1) if ((s.at(1)>='a') && (s.at(1)<='z')) n1=2;
1233 temp=s.substr(0,n1);
1234 if (n1<s.length()) sstore=s.substr(n1,s.length()); else sstore="";
1235 n1=nF[i];
1236 n2=OBElements::GetAtomicNum(temp.c_str());//Atom.positionofAtom(temp);
1237 nPrev=acount;
1238
1239 for (j=1; j<=n1; j++) {
1240 fragIndex[nt]=nt+1;//sa.fragIndex=fragNo;
1241 nHydr[nt]=nH[i]; //sa.special=(byte)nH.getValue(i+1);
1242 nt++;
1243
1244 aPosition[nt-1]=n2;
1245
1246 if (sstore.length()>0) if (parseFormula(sstore,enumber)) { //bf=Formula.parseString(sstore);
1247 for (k=1; k<NELEMMAX; k++) if (enumber[k] > 0) for (m=1; m<=enumber[k]; m++) {
1248 fragIndex[acount]=nt+1;//sa.fragIndex=fragNo; //Do not increment!
1249 nHydr[acount]=0;//special[acount]=0;
1250 aPosition[acount]=k;
1251 acount++;
1252
1253 kk=hydrogenValency(k);//HVal[k];
1254 if (kk == 0) kk=1;
1255 bcount++;
1256 sbSpecial[bcount-1]=1;
1257 bondOrders[bcount-1]=kk;
1258 iA1[bcount-1]=nt-1;
1259 iA2[bcount-1]=acount-1;
1260 };
1261 //checking for nitrogen...
1262 //length analizing-extracting and addition of other atoms...
1263 };
1264 //charges analizing and restore
1265
1266 if (charges[nt-1] != 0) { //search for appropriate atom to put charge..
1267 if (nPrev == acount) {
1268 aCharge[nt-1]=charges[nt-1];
1269 } else {
1270 if (charges[nt-1] < 0) {
1271 assignCharges(aPosition,iA1,iA2,aCharge,charges,bondOrders,8,nPrev,nt,acount,bcount);
1272 assignCharges(aPosition,iA1,iA2,aCharge,charges,bondOrders,7,nPrev,nt,acount,bcount);
1273 assignCharges(aPosition,iA1,iA2,aCharge,charges,bondOrders,16,nPrev,nt,acount,bcount);
1274 if (charges[nt-1] != 0) {
1275 aCharge[nt-1]=charges[nt-1];
1276 };
1277 } else { //positive charge-at central atom
1278 aCharge[nt-1]=charges[nt-1];
1279 };
1280 };
1281 };
1282 if (radicals[nt-1] != 0) { //search for appropriate atom to put charge..
1283 aRad[nt-1]=radicals[nt-1];
1284 };
1285 nPrev=acount;
1286 };
1287
1288 };
1289
1290 //Bond analizing....
1291 value=value.substr(1,value.length());
1292
1293 nt=0;
1294 ss="";
1295 test=true;
1296 while ((value.length()>0) && test) {
1297 n1=indexOf(value,";");
1298 n2=indexOf(value,"]");
1299 if (n1<0) n1=n2; else if ((n2<n1) && (n2>=0)) n1=n2;
1300 mf="";
1301 if ((n1>=0) && (value.length() > n1)) {
1302 mf=value.substr(0,n1);
1303 value=value.substr(n1+1,value.length());
1304 } else {
1305 test=false;
1306 mf=value;
1307 value="";
1308 };
1309 nt++;
1310 //parsing each fragment
1311 while (mf.length()>0) {
1312 n1=indexOf(mf,",");
1313 if (n1>=0) {
1314 s=mf.substr(0,n1);
1315 mf=mf.substr(n1+1,mf.length());
1316 } else {
1317 s=mf;
1318 mf="";
1319 };
1320 n1=atoi(s.c_str());
1321 bcount++;
1322 bondOrders[bcount-1]=0;
1323 iA1[bcount-1]=nt-1;
1324 iA2[bcount-1]=n1-1;
1325 };
1326
1327 if (value.length()>0) if (value.at(0)==']') value=""; //end parsing
1328 };
1329
1330 //Alternation
1331 alternate(aPosition,aCharge,aRad,nHydr,iA1,iA2,bondOrders,acount,bcount);
1332 generateDiagram(iA1,iA2,rx,ry,acount,bcount);
1333 for (i=0; i<bcount; i++) if (bondOrders[i] == 1) stereoBonds[i]=-1; //flags for bonds, which might be stereo
1334 implementAtomStereo(iA1,iA2,stereoBonds,rx,ry,acount,bcount,astereo);
1335 implementBondStereo(iA1,iA2,rx,ry,acount,bcount,bstereo);
1336
1337
1338 if (pmol != nullptr) {
1339 for (i=0; i<acount; i++) {
1340 sa.Clear();
1341 sa.SetAtomicNum(aPosition[i]);
1342 if (aCharge[i] != 0) sa.SetFormalCharge(aCharge[i]);
1343 if (aRad[i] != 0) sa.SetSpinMultiplicity(1);
1344 sa.SetVector(rx[i],ry[i],0.0);
1345 pmol->AddAtom(sa);
1346 };
1347 for (i=0; i<bcount; i++) {
1348 flags=0;
1349 if (stereoBonds[i] == 1) flags=OB_WEDGE_BOND; else
1350 if (stereoBonds[i] == 2) flags=OB_HASH_BOND;
1351 pmol->AddBond(iA1[i]+1,iA2[i]+1,bondOrders[i],flags);
1352 };
1353 };
1354 };
1355
assignCharges(const std::vector<int> aPosition,const std::vector<int> iA1,const std::vector<int> iA2,std::vector<int> & aCharges,std::vector<int> & charges,std::vector<int> & bondOrder,int aPos,int nPrev,int nt,int acount,int bcount)1356 void MCDLFormat::assignCharges(const std::vector <int> aPosition, const std::vector <int> iA1,
1357 const std::vector <int> iA2, std::vector <int>& aCharges, std::vector <int>& charges,
1358 std::vector <int>& bondOrder, int aPos, int nPrev, int nt, int acount, int bcount){
1359 //set negative charges
1360 int k,j,n;
1361
1362 //return;
1363
1364 for (k=nPrev; k<acount; k++) {
1365 if (aPosition[k] == aPos) {
1366 aCharges[k]=-1;
1367 charges[nt-1]=charges[nt-1]+1;
1368 for (j=0; j<bcount; j++) {
1369 if ((((iA1[j]+1) == nt) && (iA2[j] == k)) || ((iA1[j] == k) && ((iA2[j]+1) == nt))) {
1370 n=bondOrder[j];
1371 if (n > 1) {
1372 n=n-1;
1373 bondOrder[j]=n;
1374 };
1375 };
1376 };
1377 };
1378 if (charges[nt-1] == 0) break;
1379 };
1380 };
1381
1382
indexOf(const string instring,const string substring,int fromPos)1383 int MCDLFormat::indexOf(const string instring, const string substring, int fromPos) {
1384 int result=instring.find(substring,fromPos);
1385 if (result == string::npos) result=-1;
1386 if (result >= instring.length()) result=-1;
1387 return result;
1388 };
1389
lastIndexOf(const string instring,const string substring)1390 int MCDLFormat::lastIndexOf(const string instring, const string substring) {
1391 int result,n;
1392 bool test;
1393
1394 result=-1;
1395 test=true;
1396 n=-1;
1397 while (test) {
1398 n=instring.find(substring,n+1);
1399 if (n == string::npos)
1400 test=false;
1401 else {
1402 result=n;
1403 };
1404 };
1405 //int result=instring.find_last_of(substring);
1406 //if (result == string::npos) result=-1;
1407 //if (result > (instring.length()-substring.length())) result=-1;
1408 return result;
1409 };
1410
parseFormula(const string formulaString,std::vector<int> & enumber)1411 bool MCDLFormat::parseFormula(const string formulaString, std::vector <int>& enumber) {
1412 //vector<string> items;
1413 unsigned int i, n, k, n1, n2;//,j,nStart;
1414 string s;
1415 bool test;
1416 string asym;
1417 string value=formulaString;
1418
1419 for (i = 0; i<NELEMMCDL; i++) enumber[i] = 0;
1420
1421 for (i = 1; i<NELEMMCDL; i++) if (strlen(OBElements::GetSymbol(i)) == 2) {
1422 test=true;
1423 asym=OBElements::GetSymbol(i);
1424 while (test) {
1425 test=false;
1426 n=indexOf(value,asym);
1427 if (n>=0) {
1428 test=true;
1429 value=value.substr(0,n)+value.substr(n+asym.length(),value.length());
1430 k=1;
1431 if (n<value.length()) if ((value.at(n)>='0') && (value.at(n)<='9')) {
1432 n1=n;
1433 n2=n;
1434 while ((n2<(value.length()-1)) && (value.at(n2)>='0') && (value.at(n2)<='9')) n2++;
1435 if (! ((value.at(n2)>='0') && (value.at(n2)<='9'))) n2--;
1436 s=value.substr(n1,n2+1);
1437 k=atoi(s.c_str());
1438 value=value.substr(0,n1)+value.substr(n2+1,value.length());
1439 };
1440 enumber[i]=enumber[i]+k;
1441 };
1442 };
1443 };
1444 for (i = 1; i<NELEMMCDL; i++) if (strlen(OBElements::GetSymbol(i)) == 1) {
1445 test=true;
1446 asym=OBElements::GetSymbol(i);
1447 while (test) {
1448 test=false;
1449 n=indexOf(value,asym);
1450 if (n>=0) {
1451 test=true;
1452 value=value.substr(0,n)+value.substr(n+asym.length(),value.length());
1453 k=1;
1454 if (n<value.length()) if ((value.at(n)>='0') && (value.at(n)<='9')) {
1455 n1=n;
1456 n2=n;
1457 while ((n2<(value.length()-1)) && (value.at(n2)>='0') && (value.at(n2)<='9')) n2++;
1458 if (! ((value.at(n2)>='0') && (value.at(n2)<='9'))) n2--;
1459 s=value.substr(n1,n2+1);
1460 k=atoi(s.c_str());
1461 value=value.substr(0,n1)+value.substr(n2+1,value.length());
1462 };
1463 enumber[i]=enumber[i]+k;
1464 };
1465 };
1466 };
1467 return (value.length() == 0);
1468 };
1469
getMolTitle(string & line)1470 string MCDLFormat::getMolTitle(string & line) {
1471 string::size_type n,k;
1472 string result;
1473 n=line.find(ftitlestart);
1474 if (n != string::npos) {
1475 k=line.find("}",n+ftitlestart.size());
1476 if (k != string::npos) {
1477 result=line.substr(n+ftitlestart.length(),k-n-ftitlestart.length());
1478 line=line.substr(0,n+1)+line.substr(k+1);
1479 }
1480 }
1481 return result;
1482 }
1483
1484
1485 ////////////////////////////////////////////////////
1486
1487 //Make an instance of the format class
1488 MCDLFormat theMCDLFormat;
1489
1490 /////////////////////////////////////////////////////////////////
1491
ReadMolecule(OBBase * pOb,OBConversion * pConv)1492 bool MCDLFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
1493 {
1494 OBMol* pmol = pOb->CastAndClear<OBMol>();
1495 if (pmol == nullptr)
1496 return false;
1497
1498 istream& ifs = *pConv->GetInStream();
1499
1500 pmol->BeginModify();
1501
1502 int dim=0;
1503 pmol->SetDimension(dim);
1504
1505 string line="";
1506 if(ifs.good()) getline(ifs, line);
1507
1508 string molTitle=getMolTitle(line);
1509
1510 if (molTitle.length() > 0) pmol->SetTitle(molTitle.c_str());
1511 if (line.length() > 0) setMCDL(line,pmol,molTitle);
1512
1513 pmol->EndModify();
1514
1515 return true;
1516 }
1517
1518 ////////////////////////////////////////////////////////////////
1519
WriteMolecule(OBBase * pOb,OBConversion * pConv)1520 bool MCDLFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
1521 {
1522 OBMol* pmol = dynamic_cast<OBMol*>(pOb);
1523 if (pmol == nullptr) return false;
1524
1525 std::ostream & ofs = *pConv->GetOutStream();
1526
1527 //To use an output option
1528 string title=pmol->GetTitle();
1529 if (title.length() > 0) title=ftitlestart+title+"}";
1530 ofs << getMCDL(pmol,false) << title << endl;
1531 // prepareTest(pmol,ofs);
1532 //generateDiagram(pmol,ofs);
1533
1534 return true; //or false to stop converting
1535 }
1536
1537 } //namespace OpenBabel
1538
1539