rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,3014 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.00
6
+ * April 13, 2005
7
+ * Developed at NIST
8
+ */
9
+
10
+ /* this file is used only in case of #define CREATE_0D_PARITIES */
11
+
12
+ #include <stdio.h>
13
+ #include <stdlib.h>
14
+ #include <math.h>
15
+ #include <string.h>
16
+ #include <ctype.h>
17
+
18
+ #include "e_mode.h"
19
+ #include "inchi_api.h"
20
+ #include "e_inchi_atom.h"
21
+ #include "e_ichisize.h"
22
+ #include "e_comdef.h"
23
+ #include "e_ichicomp.h"
24
+ #include "e_util.h"
25
+ #include "e_0dstereo.h"
26
+
27
+ #define ALWAYS_SET_STEREO_PARITY 0
28
+
29
+ #define SB_PARITY_FLAG 0x38 /* disconnected structure has undef. parity */
30
+ #define SB_PARITY_SHFT 3
31
+ #define SB_PARITY_MASK 0x07
32
+ #define SB_PARITY_1(X) (X & SB_PARITY_MASK) /* refers to connected structure */
33
+ #define SB_PARITY_2(X) (((X) >> SB_PARITY_SHFT) & SB_PARITY_MASK) /* refers to connected structure */
34
+
35
+ #define inchi_NUMH(AT,CUR_AT) (AT[CUR_AT].num_iso_H[0]+AT[CUR_AT].num_iso_H[1]+AT[CUR_AT].num_iso_H[2]+AT[CUR_AT].num_iso_H[3])
36
+ #define inchi_NUMH2(AT,CUR_AT) ((AT[CUR_AT].num_iso_H[0]>0?AT[CUR_AT].num_iso_H[0]:0) +AT[CUR_AT].num_iso_H[1]+AT[CUR_AT].num_iso_H[2]+AT[CUR_AT].num_iso_H[3])
37
+ #define IS_METAL(a) (a == AtType_Metal || a == AtType_Sn4 || a == AtType_Sn3 || a == AtType_Sn2)
38
+
39
+ typedef struct tagStereo0D {
40
+ inchi_Stereo0D *stereo0D; /* array of num_stereo0D 0D stereo elements or NULL */
41
+ int num_stereo0D; /* number of 0D stereo elements */
42
+ int max_num_Stereo0D; /* allocated length of stereo0D */
43
+ int delta_num_stereo0D;/* allocation increments */
44
+ S_CHAR *cAtType;
45
+ } Stereo0D;
46
+
47
+ typedef enum tagAtType {
48
+ /* possible stereocenter */
49
+ AtType_C4 = 1, /* >C< */
50
+ AtType_Si4 = 2, /* >Si< */
51
+ AtType_Ge4 = 3, /* >Ge< */
52
+ AtType_Sn4 = 4, /* >Sn< */
53
+ AtType_B4m = 5, /* B(-) */
54
+ AtType_S4 = 6, /* =S< */
55
+ AtType_S6 = 7, /* >S<, 2 double bonds */
56
+ AtType_S3p = 8, /* -S(+)< */
57
+ AtType_S5p = 9, /* >S(+)<, 1 double bond */
58
+ AtType_Se4 =10, /* =Se< */
59
+ AtType_Se6 =11, /* >Se<, 2 double bonds */
60
+ AtType_Se3p =12, /* -Se(+)< */
61
+ AtType_Se5p =13, /* >Se(+)<, 1 double bond */
62
+ AtType_N5 =14, /* >N<, 1 double bond */
63
+ AtType_N4p =15, /* >N(+)< */
64
+ AtType_N3r =16, /* -N<| (N in a 3-member ring) */
65
+ AtType_P4p =17, /* >N(+)< */
66
+ AtType_P5 =18, /* >P<, 1 double bond */
67
+ AtType_As4p =19, /* >As(+)< */
68
+ AtType_As5 =20, /* >As<, 1 double bond */
69
+ /* possible stereobond */
70
+ AtType_C3 =21, /* =C<, =C/ */
71
+ AtType_Si3 =22,
72
+ AtType_Ge3 =23,
73
+ AtType_Sn3 =24,
74
+ AtType_N3p =25, /* =N(+)< */
75
+ AtType_N3 =26, /* =N/ */
76
+ /* middle allene/cumulene */
77
+ AtType_C2 =27, /* =C= */
78
+ AtType_Si2 =28, /* =Si= */
79
+ AtType_Ge2 =29, /* =Ge= */
80
+ AtType_Sn2 =30, /* =Ge= */
81
+ /* may become stereobond after charge or radical shift */
82
+ AtType_Nns =31,
83
+ /* metal */
84
+ AtType_Metal =32,
85
+ /* terminal H */
86
+ AtType_TermH =33,
87
+ AtType_TermD =34,
88
+ AtType_TermT =35
89
+ } AT_TYPE;
90
+
91
+ typedef enum tagElType {
92
+ ElType_C = 1,
93
+ ElType_Si = 2,
94
+ ElType_Ge = 3,
95
+ ElType_Sn = 4,
96
+ ElType_B = 5,
97
+ ElType_S = 6,
98
+ ElType_Se = 7,
99
+ ElType_N = 8,
100
+ ElType_P = 9,
101
+ ElType_As =10,
102
+ ElType_H =11,
103
+ ElType_D =12,
104
+ ElType_T =13
105
+
106
+ } EL_TYPE;
107
+
108
+ inchi_Stereo0D *e_GetNewStereo( Stereo0D *pStereo );
109
+
110
+
111
+ static int ee_extract_ChargeRadical( char *elname, int *pnRadical, int *pnCharge );
112
+ static int ee_extract_H_atoms( char *elname, S_CHAR num_iso_H[] );
113
+ static int e_GetElType( inchi_Atom *at, int cur_atom );
114
+ static int e_bCanInpAtomBeAStereoCenter( int cur_at, S_CHAR *cAtType );
115
+ static int e_nNumNonMetalNeigh( inchi_Atom *atom, int cur_at, Stereo0D *pStereo, int *i_ord_LastMetal );
116
+
117
+ void e_swap ( char *a, char *b, size_t width );
118
+ int e_insertions_sort( void *base, size_t num, size_t width, int ( *compare )(const void *e1, const void *e2 ) );
119
+ int e_bCanAtomHaveAStereoBond( inchi_Atom *at, int cur_at, S_CHAR *cAtType );
120
+ int e_bCanAtomBeMiddleAllene( int cur_at, S_CHAR *cAtType );
121
+ int e_bCanAtomBeTerminalAllene( int cur_at, S_CHAR *cAtType );
122
+
123
+ /**********************************************************************************/
124
+ #define AMBIGUOUS_STEREO 1
125
+ #define AMBIGUOUS_STEREO_ERROR 32
126
+
127
+
128
+ #define AB_MAX_WELL_DEFINED_PARITY inchi_max(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* 1, 2 => well defined parities, uncluding 'unknown' */
129
+ #define AB_MIN_WELL_DEFINED_PARITY inchi_min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) /* min(INCHI_PARITY_ODD, INCHI_PARITY_EVEN) */
130
+
131
+ #define AMBIGUOUS_STEREO 1
132
+
133
+ #define MIN_DOT_PROD 50 /* min value of at->stereo_bond_z_prod[i] to define parity */
134
+
135
+ #define ATOM_PARITY_WELL_DEF(X) (AB_MIN_WELL_DEFINED_PARITY <= (X) && (X) <= AB_MAX_WELL_DEFINED_PARITY)
136
+ /**********************************************************************************/
137
+
138
+ #define CT_ERR_FIRST (-30000)
139
+ #define CT_OUT_OF_RAM (CT_ERR_FIRST- 2) /*(-30002) */
140
+ #define CT_ISO_H_ERR (CT_ERR_FIRST- 9) /*(-30009) */
141
+ #define CT_CALC_STEREO_ERR (CT_ERR_FIRST-15) /*(-30015) */
142
+ #define CT_UNKNOWN_ERR (CT_ERR_FIRST-18) /*(-30018) */
143
+
144
+ #define CT_ERR_MIN CT_UNKNOWN_ERR
145
+ #define CT_ERR_MAX CT_ERR_FIRST
146
+
147
+ #define RETURNED_ERROR(nVal) (CT_ERR_MIN<=(nVal) && (nVal)<=CT_ERR_MAX)
148
+ /**********************************************************************************/
149
+ #define MAX_CUMULENE_LEN 2 /* max number of bonds in a cumulene chain - 1 */
150
+ /**********************************************************************************/
151
+ int ee_extract_ChargeRadical( char *elname, int *pnRadical, int *pnCharge )
152
+ {
153
+ char *q, *r, *p;
154
+ int nCharge=0, nRad = 0, charge_len = 0, k, nVal, nSign, nLastSign=1, len;
155
+
156
+ p = elname;
157
+
158
+ /* extract radicals & charges */
159
+ while ( q = strpbrk( p, "+-^" ) ) {
160
+ switch ( *q ) {
161
+ case '+':
162
+ case '-':
163
+ for ( k = 0, nVal=0; (nSign = ('+' == q[k])) || (nSign = -('-' == q[k])); k++ ) {
164
+ nVal += (nLastSign = nSign);
165
+ charge_len ++;
166
+ }
167
+ if ( nSign = (int)strtol( q+k, &r, 10 ) ) { /* fixed 12-5-2001 */
168
+ nVal += nLastSign * (nSign-1);
169
+ }
170
+ charge_len = r - q;
171
+ nCharge += nVal;
172
+ break;
173
+ /* case '.': */ /* singlet '.' may be confused with '.' in formulas like CaO.H2O */
174
+ case '^':
175
+ nRad = 1; /* doublet here is 1. See below */
176
+ charge_len = 1;
177
+ for ( k = 1; q[0] == q[k]; k++ ) {
178
+ nRad ++;
179
+ charge_len ++;
180
+ }
181
+ break;
182
+ }
183
+ memmove( q, q+charge_len, strlen(q+charge_len)+1 );
184
+ }
185
+ len = strlen(p);
186
+ /* radical */
187
+ if ( (q = strrchr( p, ':' )) && !q[1]) {
188
+ nRad = RADICAL_SINGLET;
189
+ q[0] = '\0';
190
+ len --;
191
+ } else {
192
+ while( (q = strrchr( p, '.' )) && !q[1] ) {
193
+ nRad ++;
194
+ q[0] = '\0';
195
+ len --;
196
+ }
197
+
198
+ nRad = nRad == 1? RADICAL_DOUBLET :
199
+ nRad == 2? RADICAL_TRIPLET : 0;
200
+ }
201
+ *pnRadical = nRad;
202
+ *pnCharge = nCharge;
203
+ return ( nRad || nCharge );
204
+
205
+ }
206
+ /***********************************************************************/
207
+ int ee_extract_H_atoms( char *elname, S_CHAR num_iso_H[] )
208
+ {
209
+ int i, len, c, k, val, bExtracted = 0;
210
+ char *q;
211
+ i = 0;
212
+ len = (int)strlen(elname);
213
+ c = UCINT elname[0];
214
+ while ( i < len ) {
215
+ switch ( c ) {
216
+ case 'H':
217
+ k = 0;
218
+ break;
219
+ case 'D':
220
+ k = 2;
221
+ break;
222
+ case 'T':
223
+ k = 3;
224
+ break;
225
+ default:
226
+ k = -1;
227
+ break;
228
+ }
229
+ q = elname+i+1; /* pointer to the next to elname[i] character */
230
+ c = UCINT q[0];
231
+ if ( k >= 0 && !islower( c ) ) {
232
+ /* found a hydrogen */
233
+ bExtracted ++;
234
+ if ( isdigit( c ) ) {
235
+ val = (int)strtol( q, &q, 10 );
236
+ /* q = pointer to the next to number of hydrogen atom(s) character */
237
+ } else {
238
+ val = 1;
239
+ }
240
+ num_iso_H[k] += val;
241
+ /* remove the hydrogen atom from the string */
242
+ len -= (q-elname)-i;
243
+ memmove( elname+i, q, len + 1 );
244
+ /* c = UCINT elname[i]; */
245
+ } else {
246
+ i ++;
247
+ }
248
+ c = UCINT elname[i]; /* moved here 11-04-2002 */
249
+ }
250
+ return bExtracted;
251
+ }
252
+ /************************************************/
253
+ #define MAX_BOND_TYPE 4
254
+ int e_GetElType( inchi_Atom *at, int cur_atom )
255
+ {
256
+ char szEl[ATOM_EL_LEN];
257
+ int nRadical, nCharge, bChargeOrRad, bH, bAddH = 0, nElType=0, bond_valence, valence, num_H=0;
258
+ S_CHAR num_iso_H[NUM_H_ISOTOPES+1];
259
+ S_CHAR num_bonds[MAX_BOND_TYPE];
260
+ int i;
261
+ int nRadicalValence = 0;
262
+
263
+ if ( sizeof(at->num_iso_H) != sizeof(num_iso_H) ||
264
+ sizeof(at->num_iso_H[0]) != sizeof(num_iso_H[0]) ) {
265
+ /* program error */
266
+ return -1;
267
+ }
268
+ strcpy( szEl, at[cur_atom].elname);
269
+ memset( num_iso_H, 0, sizeof(num_iso_H) );
270
+ bChargeOrRad = ee_extract_ChargeRadical( szEl, &nRadical, &nCharge );
271
+ bH = ee_extract_H_atoms( szEl, num_iso_H );
272
+ if ( !bChargeOrRad ) {
273
+ nRadical = at[cur_atom].radical;
274
+ nCharge = at[cur_atom].charge;
275
+ }
276
+ if ( !bH ) {
277
+ memcpy( num_iso_H, at[cur_atom].num_iso_H, sizeof(num_iso_H) );
278
+ if ( bAddH = (num_iso_H[0] < 0 ) ) {
279
+ num_iso_H[0] = 0;
280
+ }
281
+ }
282
+ num_H = num_iso_H[0]+num_iso_H[1]+num_iso_H[2]+num_iso_H[3];
283
+
284
+ if (nRadical==INCHI_RADICAL_DOUBLET) {
285
+ nRadicalValence = 1;
286
+ } else
287
+ if ( nRadical==INCHI_RADICAL_TRIPLET || nRadical==INCHI_RADICAL_SINGLET ){
288
+ nRadicalValence = 2;
289
+ }
290
+
291
+ /* element type */
292
+ if ( !strcmp( szEl, "C" ) ) {
293
+ nElType = ElType_C;
294
+ } else
295
+ if ( !strcmp( szEl, "Si" ) ) {
296
+ nElType = ElType_Si;
297
+ } else
298
+ if ( !strcmp( szEl, "Ge" ) ) {
299
+ nElType = ElType_Ge;
300
+ } else
301
+ if ( !strcmp( szEl, "Sn" ) ) {
302
+ nElType = ElType_Sn;
303
+ } else
304
+ if ( !strcmp( szEl, "B" ) ) {
305
+ nElType = ElType_B;
306
+ } else
307
+ if ( !strcmp( szEl, "S" ) ) {
308
+ nElType = ElType_S;
309
+ } else
310
+ if ( !strcmp( szEl, "Se" ) ) {
311
+ nElType = ElType_Se;
312
+ } else
313
+ if ( !strcmp( szEl, "N" ) ) {
314
+ nElType = ElType_N;
315
+ } else
316
+ if ( !strcmp( szEl, "P" ) ) {
317
+ nElType = ElType_P;
318
+ } else
319
+ if ( !strcmp( szEl, "As" ) ) {
320
+ nElType = ElType_As;
321
+ } else
322
+ if ( !szEl[0] ) {
323
+ if ( 1 == num_H && (num_iso_H[0] == 1 || num_iso_H[1] == 1) ) {
324
+ nElType = ElType_H;
325
+ } else
326
+ if ( 1 == num_H && num_iso_H[2] == 1 ) {
327
+ nElType = ElType_D;
328
+ } else
329
+ if ( 1 == num_H && num_iso_H[3] == 1 ) {
330
+ nElType = ElType_T;
331
+ } else {
332
+ return -1;
333
+ }
334
+ } else {
335
+ if ( e_is_element_a_metal( szEl ) ) {
336
+ return AtType_Metal;
337
+ }
338
+ return -1; /* no stereo */
339
+ }
340
+
341
+ /* atom type */
342
+ memset( num_bonds, 0, sizeof(num_bonds) );
343
+ bond_valence = 0;
344
+ valence = at[cur_atom].num_bonds;
345
+ for ( i = 0; i < valence; i ++ ) {
346
+ if ( 0 < at[cur_atom].bond_type[i] && at[cur_atom].bond_type[i] <= MAX_BOND_TYPE ) {
347
+ num_bonds[at[cur_atom].bond_type[i]-1] ++;
348
+ }
349
+ }
350
+ bond_valence = num_bonds[0] + 2*num_bonds[1] + 3*num_bonds[2];
351
+ if ( num_bonds[3] ) {
352
+ if ( num_bonds[3] == 2 ) {
353
+ bond_valence += 3; /* -C= */
354
+ } else
355
+ if ( num_bonds[3] == 3 ) {
356
+ bond_valence += 4; /* >C= */
357
+ } else {
358
+ return -1;
359
+ }
360
+ }
361
+
362
+ switch( nElType ) {
363
+
364
+ case ElType_C:
365
+ case ElType_Si:
366
+ case ElType_Ge:
367
+ case ElType_Sn:
368
+
369
+ if ( bAddH && bond_valence + num_H + (abs(nCharge)==1) + nRadicalValence == 4 ) {
370
+ bAddH = 0; /* no H will be added */
371
+ }
372
+
373
+ if ( bond_valence == valence && (valence==4 || valence == 3 && (bAddH || num_H==1)) && !nRadical ) {
374
+ switch( nElType ) {
375
+ case ElType_C:
376
+ return AtType_C4;
377
+ case ElType_Si:
378
+ return AtType_Si4;
379
+ case ElType_Ge:
380
+ return AtType_Ge4;
381
+ case ElType_Sn:
382
+ return AtType_Sn4;
383
+ }
384
+ } else
385
+ if ( bond_valence == valence && (valence==3 || valence == 2 && (bAddH || num_H==1)) && nRadical == INCHI_RADICAL_DOUBLET ) {
386
+ switch( nElType ) {
387
+ case ElType_C:
388
+ return AtType_C3;
389
+ case ElType_Si:
390
+ return -1;
391
+ case ElType_Ge:
392
+ return -1;
393
+ case ElType_Sn:
394
+ return AtType_Metal;
395
+ }
396
+ } else
397
+ if ( bond_valence == 4 && valence == 2 && !num_H && !nRadical ) {
398
+ /* two double bonds or single & triple */
399
+ switch( nElType ) {
400
+ case ElType_C:
401
+ return AtType_C2;
402
+ case ElType_Si:
403
+ return AtType_Si2;
404
+ case ElType_Ge:
405
+ return AtType_Ge2;
406
+ case ElType_Sn:
407
+ return AtType_Sn2;
408
+ }
409
+ } else
410
+ if ( bond_valence == 3 && valence == 2 && !num_H && nRadical == INCHI_RADICAL_DOUBLET ) {
411
+ /* two double bonds or single & triple */
412
+ switch( nElType ) {
413
+ case ElType_C:
414
+ return AtType_C2;
415
+ case ElType_Si:
416
+ return -1;
417
+ case ElType_Ge:
418
+ return -1;
419
+ case ElType_Sn:
420
+ return AtType_Metal;
421
+ }
422
+ } else
423
+ if ( bond_valence > valence && (valence==3 || valence == 2 && (bAddH || num_H==1)) && !nRadical ) {
424
+ /* "bond_valence > valence" instead of "bond_valence == valence+1" to accommodate
425
+ * erroneouse acceptance by 1.12Beta of stereo bond case when C has valence > 5 */
426
+ switch( nElType ) {
427
+ case ElType_C:
428
+ return AtType_C3;
429
+ case ElType_Si:
430
+ return AtType_Si3;
431
+ case ElType_Ge:
432
+ return AtType_Ge3;
433
+ case ElType_Sn:
434
+ return AtType_Sn3;
435
+ }
436
+ } else
437
+ if ( bond_valence == valence+1 && bond_valence > 3 ) {
438
+ /* trying to accommodate hypervalence in coord compounds before disconnection */
439
+ switch( nElType ) {
440
+ case ElType_C:
441
+ return AtType_C3;
442
+ case ElType_Si:
443
+ return -1;
444
+ case ElType_Ge:
445
+ return -1;
446
+ case ElType_Sn:
447
+ return AtType_Metal;
448
+ }
449
+ } else
450
+ if ( bond_valence == valence && bond_valence >= 2 && abs(nCharge) == 1 && 3 == (valence + (bAddH || num_H==1)) ) {
451
+ /* trying to accommodate C(-)-N(+) bond that may become double after ion pair removal. added 2004-01-31 */
452
+ switch( nElType ) {
453
+ case ElType_C:
454
+ return AtType_C3;
455
+ case ElType_Si:
456
+ return AtType_Si3;
457
+ case ElType_Ge:
458
+ return -1;
459
+ case ElType_Sn:
460
+ return AtType_Metal;
461
+ }
462
+ }
463
+ return (nElType == ElType_Sn)? AtType_Metal : -1;
464
+
465
+ case ElType_B:
466
+ if ( bond_valence == valence && (valence==4 || valence==3 && (bAddH || num_H==1)) && nCharge == -1 && !nRadical ) {
467
+ return AtType_B4m;
468
+ }
469
+ return -1;
470
+
471
+ case ElType_S:
472
+ case ElType_Se:
473
+ if ( (valence == 3 && bond_valence == 3) && (nCharge == 1 || nRadical == INCHI_RADICAL_DOUBLET) ) {
474
+ switch( nElType ) {
475
+ case ElType_S:
476
+ return AtType_S3p;
477
+ case ElType_Se:
478
+ return AtType_Se3p;
479
+ }
480
+ } else
481
+ if ( (valence == 3 && bond_valence == 4) && nCharge == 0 && !nRadical ) {
482
+ switch( nElType ) {
483
+ case ElType_S:
484
+ return AtType_S4;
485
+ case ElType_Se:
486
+ return AtType_Se4;
487
+ }
488
+ } else
489
+ if ( (valence == 4 && bond_valence == 5) && (nCharge == 1 || nRadical == INCHI_RADICAL_DOUBLET) ) {
490
+ switch( nElType ) {
491
+ case ElType_S:
492
+ return AtType_S5p;
493
+ case ElType_Se:
494
+ return AtType_Se5p;
495
+ }
496
+ } else
497
+ if ( (valence == 4 && bond_valence == 6) && nCharge == 0 && !nRadical ) {
498
+ switch( nElType ) {
499
+ case ElType_S:
500
+ return AtType_S6;
501
+ case ElType_Se:
502
+ return AtType_S6;
503
+ }
504
+ } else {
505
+ return -1;
506
+ }
507
+ case ElType_N:
508
+ case ElType_P:
509
+ case ElType_As:
510
+ if ( bAddH && bond_valence + num_H - (abs(nCharge)==1? nCharge:0) + nRadicalValence == 3 ) {
511
+ bAddH = 0; /* no H will be added */
512
+ } else
513
+ if ( bAddH && bond_valence + num_H == 5 ) {
514
+ bAddH = 0; /* no H will be added */
515
+ }
516
+ if ( bond_valence == valence && (valence==4 || valence==3 && (bAddH || num_H==1)) && nCharge == 1 && !nRadical ) {
517
+ switch( nElType ) {
518
+ case ElType_N:
519
+ return AtType_N4p;
520
+ case ElType_P:
521
+ return AtType_P4p;
522
+ case ElType_As:
523
+ return AtType_As4p;
524
+ }
525
+ } else
526
+ if ( bond_valence == valence+1 && (valence==4 /*|| valence == 3*/) && nCharge == 0 ) {
527
+ switch( nElType ) {
528
+ case ElType_N:
529
+ return AtType_N5;
530
+ case ElType_P:
531
+ return AtType_P5;
532
+ case ElType_As:
533
+ return AtType_As5;
534
+ }
535
+ } else
536
+ if ( bond_valence == valence && valence==3 && nCharge == 0 && !nRadical ) {
537
+ switch( nElType ) {
538
+ case ElType_N:
539
+ {
540
+ AT_NUM neigh1, neigh2;
541
+ int j1, j2, bIn3MembRing = 0;
542
+ for ( j1 = 0; j1 < valence && !bIn3MembRing; j1 ++ ) {
543
+ neigh1 = at[cur_atom].neighbor[j1];
544
+ for ( j2 = j1+1; j2 < valence && !bIn3MembRing; j2 ++ ) {
545
+ neigh2 = at[cur_atom].neighbor[j2];
546
+ if ( e_is_in_the_slist( at[neigh1].neighbor, neigh2, at[neigh1].num_bonds ) ) {
547
+ bIn3MembRing ++;
548
+ }
549
+ }
550
+ }
551
+ return bIn3MembRing? AtType_N3r : AtType_Nns /* -1*/;
552
+ }
553
+ case ElType_P:
554
+ case ElType_As:
555
+ return -1;
556
+ }
557
+ } else
558
+ if ( bond_valence == valence+1 && valence==2 && nCharge == 0 && !nRadical ) {
559
+ switch( nElType ) {
560
+ case ElType_N:
561
+ return AtType_N3;
562
+ case ElType_P:
563
+ case ElType_As:
564
+ return -1;
565
+ }
566
+ } else
567
+ if ( bond_valence == valence+1 && valence==3 && nCharge == 0 && !nRadical ) {
568
+ /* reproduce 1.12Beta bug: =N< is accepted in stereogenic bonds */
569
+ switch( nElType ) {
570
+ case ElType_N:
571
+ return AtType_N3;
572
+ case ElType_P:
573
+ case ElType_As:
574
+ return -1;
575
+ }
576
+ } else
577
+ if ( bond_valence == valence && valence==2 && nCharge == 0 && nRadical == INCHI_RADICAL_DOUBLET ) {
578
+ switch( nElType ) {
579
+ case ElType_N:
580
+ return AtType_N3;
581
+ case ElType_P:
582
+ case ElType_As:
583
+ return -1;
584
+ }
585
+ } else
586
+ if ( bond_valence == valence+1 && (valence==3 || valence == 2 && (bAddH || num_H==1)) && nCharge == 1 ) {
587
+ switch( nElType ) {
588
+ case ElType_N:
589
+ return AtType_N3p;
590
+ case ElType_P:
591
+ case ElType_As:
592
+ return -1;
593
+ }
594
+ } else
595
+ if ( bond_valence == valence && (valence==3 || valence == 2 && (bAddH || num_H==1)) && nCharge == 1 && nRadical == INCHI_RADICAL_DOUBLET ) {
596
+ switch( nElType ) {
597
+ case ElType_N:
598
+ return AtType_N3p;
599
+ case ElType_P:
600
+ case ElType_As:
601
+ return -1;
602
+ }
603
+ } else
604
+ if ( bond_valence == valence && valence == 2 && (bAddH || num_H==1) && nCharge == 0 ||
605
+ bond_valence == valence && valence == 2 && nCharge == -1 ) {
606
+ switch( nElType ) {
607
+ case ElType_N:
608
+ return AtType_Nns;
609
+ case ElType_P:
610
+ case ElType_As:
611
+ return -1;
612
+ }
613
+ } else
614
+ if ( (bond_valence == valence+2 || bond_valence + nRadicalValence == valence+2) && valence==3 ) {
615
+ switch( nElType ) {
616
+ case ElType_N:
617
+ return AtType_Nns; /* -N<< may be in a stereogenic bond in case of double bond metal disconnection */
618
+ case ElType_P:
619
+ case ElType_As:
620
+ return -1;
621
+ }
622
+ }
623
+ return -1;
624
+
625
+ case ElType_H:
626
+ if ( valence == 1 )
627
+ return AtType_TermH;
628
+ break;
629
+ case ElType_D:
630
+ if ( valence == 1 )
631
+ return AtType_TermD;
632
+ break;
633
+ case ElType_T:
634
+ if ( valence == 1 )
635
+ return AtType_TermT;
636
+ break;
637
+
638
+ }
639
+
640
+ return -1;
641
+ }
642
+
643
+
644
+ /**********************************************************************************/
645
+ void e_swap ( char *a, char *b, size_t width )
646
+ {
647
+ char tmp;
648
+ if ( a != b )
649
+ while ( width-- ) {
650
+ tmp = *a;
651
+ *a++ = *b;
652
+ *b++ = tmp;
653
+ }
654
+ }
655
+ /**********************************************************************************/
656
+ /* Sort by insertions */
657
+ int e_insertions_sort( void *base, size_t num, size_t width, int ( *compare )(const void *e1, const void *e2 ) )
658
+ {
659
+ char *i, *j, *pk;
660
+ int num_trans = 0;
661
+ size_t k;
662
+ for( k=1, pk = (char*)base; k < num; k++, pk += width ) {
663
+ for( i = pk, j = pk + width; j > (char*)base && (*compare)(i,j) > 0; j=i, i -= width ) {
664
+ e_swap( i, j, width );
665
+ num_trans ++;
666
+ }
667
+ }
668
+ return num_trans;
669
+ }
670
+
671
+
672
+ #define ZTYPE_DOWN (-1) /* should be equal to -ZTYPE_UP */
673
+ #define ZTYPE_NONE 0
674
+ #define ZTYPE_UP 1 /* should be equal to -ZTYPE_DOWN */
675
+ #define ZTYPE_3D 3
676
+ #define ZTYPE_EITHER 9999
677
+
678
+ /* criteria for ill-defined */
679
+ #define MIN_ANGLE 0.10 /* 5.73 degrees */
680
+ #define MIN_SINE 0.03 /* min edge/plane angle in case the tetrahedra has significantly different edge length */
681
+ #define MIN_ANGLE_DBOND 0.087156 /* 5 degrees = max angle considered as too small for unambiguous double bond stereo */
682
+ #define MIN_SINE_OUTSIDE 0.06 /* min edge/plane angle to determine whether the central atom is outside of the tetrahedra */
683
+ #define MIN_SINE_SQUARE 0.125 /* min edge/plane angle in case the tetrahedra is somewhat close to a parallelogram */
684
+ #define MIN_SINE_EDGE 0.167 /* min sine/(min.edge) ratio to avoid undefined in case of long edges */
685
+ #define MIN_LEN_STRAIGHT 1.900 /* min length of two normalized to 1 bonds in a straight line */
686
+ #define MAX_SINE 0.70710678118654752440084436210485 /* 1/sqrt(2)=sin(pi/4) */
687
+ #define MIN_BOND_LEN 0.000001
688
+ #define ZERO_LENGTH MIN_BOND_LEN
689
+ #define ZERO_FLOAT 1.0e-12
690
+ #define BOND_PARITY_UNDEFINED 64
691
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
692
+ #define MPY_SINE 1.00 /* was 3.0 */
693
+ #define MAX_EDGE_RATIO 2.50 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
694
+ #else
695
+ #define MPY_SINE 3.00
696
+ #define MAX_EDGE_RATIO 6.00 /* max max/min edge ratio for a tetrahedra close to a parallelogram */
697
+ #endif
698
+ /* local prototypes */
699
+ static double e_get_z_coord( inchi_Atom* at, int cur_atom, int neigh_no, int *nType,int bPointedEdgeStereo );
700
+ static double e_len3( const double c[] );
701
+ static double e_len2( const double c[] );
702
+ static double* e_diff3( const double a[], const double b[], double result[] );
703
+ static double* e_add3( const double a[], const double b[], double result[] );
704
+ static double* e_mult3( const double a[], double b, double result[] );
705
+ static double* e_copy3( const double a[], double result[] );
706
+ static double* e_change_sign3( const double a[], double result[] );
707
+ static double e_dot_prod3( const double a[], const double b[] );
708
+ static int e_dot_prodchar3( const S_CHAR a[], const S_CHAR b[] );
709
+ static double* e_cross_prod3( const double a[], const double b[], double result[] );
710
+ static double e_triple_prod( double a[], double b[], double c[], double *sine_value );
711
+ static double e_triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine);
712
+ static int are_3_vect_in_one_plane( double at_coord[][3], double min_sine);
713
+ static int e_triple_prod_char( inchi_Atom *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
714
+ int at_2, int i_next_at_2, S_CHAR *z_dir2 );
715
+
716
+ static int e_CompDble( const void *a1, const void *a2 );
717
+ static int e_Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor );
718
+ static double e_triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous);
719
+ static int e_are_4at_in_one_plane( double at_coord[][3], double min_sine);
720
+ static int e_half_stereo_bond_parity( inchi_Atom *at, int cur_at, S_CHAR *z_dir, int *bOnlyNonMetal, int bPointedEdgeStereo, Stereo0D *pStereo );
721
+ static int e_set_stereo_bonds_parity( Stereo0D *pStereo, inchi_Atom *at, int at_1, int bPointedEdgeStereo );
722
+ static int e_set_stereo_atom_parity( Stereo0D *pStereo, inchi_Atom *at, int cur_at, int bPointedEdgeStereo );
723
+ static int e_FixSb0DParities( inchi_Atom *at, Stereo0D *pStereo, int chain_length, AT_NUM at_middle,
724
+ int at_1, int i_next_at_1, S_CHAR z_dir1[], S_CHAR z_dir1NM[], int bOnlyNM1, int bAnomaly1NM, int parity1, int parity1NM,
725
+ int at_2, int i_next_at_2, S_CHAR z_dir2[], S_CHAR z_dir2NM[], int bOnlyNM2, int bAnomaly2NM, int parity2, int parity2NM );
726
+
727
+
728
+ /******************************************************************/
729
+
730
+
731
+ static double *pDoubleForSort;
732
+
733
+ /**********************************************************************************/
734
+ double e_get_z_coord( inchi_Atom* at, int cur_atom, int neigh_no, int *nType, int bPointedEdgeStereo )
735
+ {
736
+ int stereo_value = at[cur_atom].bond_stereo[neigh_no];
737
+ int stereo_type = abs( stereo_value );
738
+ int neigh = (int)at[cur_atom].neighbor[neigh_no];
739
+ double z = at[neigh].z - at[cur_atom].z;
740
+ int bFlat;
741
+
742
+ if ( bFlat = (fabs(z) < ZERO_LENGTH) ) {
743
+ int i;
744
+ for ( i = 0; i < at[cur_atom].num_bonds; i ++ ) {
745
+ if ( fabs(at[cur_atom].z - at[(int)at[cur_atom].neighbor[i]].z) > ZERO_LENGTH ) {
746
+ bFlat = 0;
747
+ break;
748
+ }
749
+ }
750
+ }
751
+
752
+ if ( bFlat ) {
753
+ if ( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) {
754
+ /* bPointedEdgeStereo > 0: define stereo from pointed end of the stereo bond only */
755
+ /* bPointedEdgeStereo < 0: define stereo from wide end of the stereo bond only (case of removed H) */
756
+ switch( stereo_type ) {
757
+ /* 1=Up (solid triangle), 6=Down (Dashed triangle), 4=Either (zigzag triangle) */
758
+ case 0: /* No stereo */
759
+ *nType = ZTYPE_NONE;
760
+ break;
761
+ case INCHI_BOND_STEREO_SINGLE_1UP: /* 1= Up */
762
+ *nType = ZTYPE_UP;
763
+ break;
764
+ case INCHI_BOND_STEREO_SINGLE_1EITHER: /* 4 = Either */
765
+ *nType = ZTYPE_EITHER;
766
+ break;
767
+ case INCHI_BOND_STEREO_SINGLE_1DOWN: /* 6 = Down */
768
+ *nType = ZTYPE_DOWN;
769
+ break;
770
+ default:
771
+ *nType = ZTYPE_NONE; /* ignore unexpected values */
772
+ }
773
+ if ( stereo_value < 0 && (*nType == ZTYPE_DOWN || *nType == ZTYPE_UP) )
774
+ *nType = -*nType;
775
+ } else {
776
+ *nType = ZTYPE_NONE; /* no stereo */
777
+ }
778
+ } else
779
+ if ( stereo_type == INCHI_BOND_STEREO_SINGLE_1EITHER &&
780
+ ( !bPointedEdgeStereo || bPointedEdgeStereo * stereo_value >= 0 ) ) {
781
+ *nType = ZTYPE_EITHER;
782
+ } else {
783
+ *nType = ZTYPE_3D;
784
+ }
785
+ return z;
786
+ }
787
+ /******************************************************************/
788
+ double e_len3( const double c[] )
789
+ {
790
+ return sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] );
791
+ }
792
+ /******************************************************************/
793
+ double e_len2( const double c[] )
794
+ {
795
+ return sqrt( c[0]*c[0] + c[1]*c[1] );
796
+ }
797
+ /******************************************************************/
798
+ double* e_diff3( const double a[], const double b[], double result[] )
799
+ {
800
+
801
+ result[0] = a[0] - b[0];
802
+ result[1] = a[1] - b[1];
803
+ result[2] = a[2] - b[2];
804
+
805
+ return result;
806
+ }
807
+ /******************************************************************/
808
+ double* e_add3( const double a[], const double b[], double result[] )
809
+ {
810
+ result[0] = a[0] + b[0];
811
+ result[1] = a[1] + b[1];
812
+ result[2] = a[2] + b[2];
813
+
814
+ return result;
815
+ }
816
+ /******************************************************************/
817
+ double* e_mult3( const double a[], double b, double result[] )
818
+ {
819
+ result[0] = a[0] * b;
820
+ result[1] = a[1] * b;
821
+ result[2] = a[2] * b;
822
+
823
+ return result;
824
+ }
825
+ /*************************************************************/
826
+ double* e_copy3( const double a[], double result[] )
827
+ {
828
+ result[0] = a[0];
829
+ result[1] = a[1];
830
+ result[2] = a[2];
831
+
832
+ return result;
833
+ }
834
+ /*************************************************************/
835
+ double* e_change_sign3( const double a[], double result[] )
836
+ {
837
+ result[0] = -a[0];
838
+ result[1] = -a[1];
839
+ result[2] = -a[2];
840
+
841
+ return result;
842
+ }
843
+ /*************************************************************/
844
+ double e_dot_prod3( const double a[], const double b[] )
845
+ {
846
+ return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
847
+ }
848
+ /*************************************************************/
849
+ int e_dot_prodchar3( const S_CHAR a[], const S_CHAR b[] )
850
+ {
851
+ int prod = ((int)a[0]*(int)b[0] + (int)a[1]*(int)b[1] + (int)a[2]*(int)b[2])/100;
852
+ if ( prod > 100 )
853
+ prod = 100;
854
+ else
855
+ if ( prod < -100 )
856
+ prod = -100;
857
+ return prod;
858
+ }
859
+ /*************************************************************/
860
+ double* e_cross_prod3( const double a[], const double b[], double result[] )
861
+ {
862
+ double tmp[3];
863
+
864
+ tmp[0] = (a[1]*b[2]-a[2]*b[1]);
865
+ tmp[1] = -(a[0]*b[2]-a[2]*b[0]);
866
+ tmp[2] = (a[0]*b[1]-a[1]*b[0]);
867
+
868
+ result[0] = tmp[0];
869
+ result[1] = tmp[1];
870
+ result[2] = tmp[2];
871
+
872
+ return result;
873
+ }
874
+ /*************************************************************/
875
+ double e_triple_prod( double a[], double b[], double c[], double *sine_value )
876
+ {
877
+ double ab[3], dot_prod_ab_c, abs_c, abs_ab;
878
+ e_cross_prod3( a, b, ab );
879
+ /* ab[0] = (a[1]*b[2]-a[2]*b[1]); */
880
+ /* ab[1] = -(a[0]*b[2]-a[2]*b[0]); */
881
+ /* ab[2] = (a[0]*b[1]-a[1]*b[0]); */
882
+ dot_prod_ab_c = e_dot_prod3( ab, c );
883
+ /* dot_prod_ab_c = ab[0]*c[0] + ab[1]*c[1] + ab[2]*c[2]; */
884
+ if ( sine_value ) {
885
+ abs_c = e_len3( c );
886
+ /* abs_c = sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] ); */
887
+ abs_ab = e_len3( ab );
888
+ /* abs_ab = sqrt( ab[0]*ab[0] + ab[1]*ab[1] + ab[2]*ab[2] ); */
889
+
890
+ if ( abs_c > 1.e-7 /* otherwise c has zero length */ && abs_ab > 1.e-7 /* otherwise a is parallel to b*/ ) {
891
+ *sine_value = MPY_SINE * dot_prod_ab_c / ( abs_c * abs_ab);
892
+ /* *sine_value = dot_prod_ab_c / ( abs_c * abs_ab); */
893
+ } else {
894
+ *sine_value = 0.0;
895
+ }
896
+ }
897
+ return dot_prod_ab_c;
898
+ }
899
+ /*************************************************************/
900
+ int e_CompDble( const void *a1, const void *a2 )
901
+ {
902
+ double diff = pDoubleForSort[*(const int*)a1] - pDoubleForSort[*(const int*)a2];
903
+ if ( diff > 0.0 )
904
+ return 1;
905
+ if ( diff < 0.0 )
906
+ return -1;
907
+ return 0;
908
+ }
909
+ /*************************************************************/
910
+ #define T2D_OKAY 1
911
+ #define T2D_WARN 2
912
+ #define T2D_UNDF 4
913
+ int e_Get2DTetrahedralAmbiguity( double at_coord[][3], int bAddExplicitNeighbor )
914
+ {
915
+ const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
916
+ const double two_pi = 2.0*one_pi;
917
+ const double dAngleAndPiMaxDiff = 2.0*atan2(1.0, sqrt(7.0)); /* min sine between 2 InPlane bonds */
918
+ int nBondType[MAX_NUM_STEREO_ATOM_NEIGH], nBondOrder[MAX_NUM_STEREO_ATOM_NEIGH];
919
+ double dBondDirection[MAX_NUM_STEREO_ATOM_NEIGH], dAngle, dAlpha, dLimit, dBisector;
920
+ int nNumNeigh = MAX_NUM_STEREO_ATOM_NEIGH - (bAddExplicitNeighbor != 0);
921
+ int i, num_Up, num_Dn, bPrev_Up, cur_len_Up, cur_first_Up, len_Up, first_Up;
922
+ int ret;
923
+
924
+ ret = 0;
925
+ for ( i = 0, num_Up = num_Dn = 0; i < nNumNeigh; i ++ ) {
926
+ dAngle = atan2( at_coord[i][1], at_coord[i][0] ); /* range from -pi to +pi */
927
+ if ( dAngle < 0.0 ) {
928
+ dAngle += two_pi;
929
+ }
930
+ dBondDirection[i] = dAngle;
931
+ nBondType[i] = (at_coord[i][2] > 0.0)? 1 : (at_coord[i][2] < 0.0)? -1 : 0; /* z-coord sign */
932
+ if ( nBondType[i] > 0 ) {
933
+ num_Up ++;
934
+ } else
935
+ if ( nBondType[i] < 0 ) {
936
+ num_Dn ++;
937
+ }
938
+ nBondOrder[i] = i;
939
+ }
940
+ if ( num_Up < num_Dn ) {
941
+ for ( i = 0; i < nNumNeigh; i ++ ) {
942
+ nBondType[i] = -nBondType[i];
943
+ }
944
+ e_swap( (char*)&num_Dn, (char*)&num_Up, sizeof(num_Dn) );
945
+ }
946
+ if ( !num_Up ) {
947
+ return T2D_UNDF;
948
+ }
949
+ /* sort according to the bond orientations */
950
+ pDoubleForSort = dBondDirection;
951
+ e_insertions_sort( nBondOrder, nNumNeigh, sizeof(nBondOrder[0]), e_CompDble );
952
+
953
+ /* find the longest contiguous sequence of Up bonds */
954
+ if ( num_Up == nNumNeigh ) {
955
+ /* all bonds are Up */
956
+ len_Up = cur_len_Up = nNumNeigh; /* added cur_len_Up initialization 1/8/2002 */
957
+ first_Up = 0;
958
+ } else {
959
+ /* at least one bond is not Up */
960
+ cur_len_Up = len_Up = bPrev_Up = 0;
961
+ /* prev. cycle header version ---
962
+ for ( i = 0; 1; i ++ ) {
963
+ if ( i >= nNumNeigh && !bPrev_Up ) {
964
+ break;
965
+ }
966
+ ----------} */
967
+ /* look at all bonds and continue (circle therough the beginning) as long as the current bond is Up */
968
+ for ( i = 0; i < nNumNeigh || bPrev_Up; i ++ ) {
969
+ if ( nBondType[nBondOrder[i % nNumNeigh]] > 0 ) {
970
+ if ( bPrev_Up ) {
971
+ cur_len_Up ++; /* uncrement number of Up bonds in current contiguous sequence of them */
972
+ } else {
973
+ bPrev_Up = 1; /* start new contiguous sequence of Up bonds */
974
+ cur_len_Up = 1;
975
+ cur_first_Up = i % nNumNeigh;
976
+ }
977
+ } else
978
+ if ( bPrev_Up ) { /* end of contiguous sequence of Up bonds */
979
+ if ( cur_len_Up > len_Up ) {
980
+ first_Up = cur_first_Up; /* store the sequence because it is longer than the ptrvious one */
981
+ len_Up = cur_len_Up;
982
+ }
983
+ bPrev_Up = 0;
984
+ }
985
+ }
986
+ }
987
+ /* Turn all the bonds around the center so that */
988
+ /* the 1st Up bond has zero radian direction */
989
+ dAlpha = dBondDirection[nBondOrder[first_Up]];
990
+ for ( i = 0; i < nNumNeigh; i ++ ) {
991
+ if ( i == nBondOrder[first_Up] ) {
992
+ dBondDirection[i] = 0.0;
993
+ } else {
994
+ dAngle = dBondDirection[i] - dAlpha;
995
+ if ( dAngle < 0.0 ) {
996
+ dAngle += two_pi;
997
+ }
998
+ dBondDirection[i] = dAngle;
999
+ }
1000
+ }
1001
+
1002
+ /********************************************************
1003
+ * Process particular cases
1004
+ ********************************************************/
1005
+
1006
+ switch( nNumNeigh ) {
1007
+
1008
+ /************************ 3 bonds ***********************
1009
+ */
1010
+ case 3:
1011
+ switch( num_Up ) {
1012
+ /* -------------------------- 0 Up ------------ */
1013
+ case 0:
1014
+ return T2D_UNDF;
1015
+ /* -------------------------- 1 Up ------------ */
1016
+ case 1:
1017
+ if ( num_Dn ) {
1018
+ #ifdef _DEBUG
1019
+ if ( num_Dn != 1 ) /* debug only */
1020
+ return -1;
1021
+ #endif
1022
+ ret = (T2D_UNDF | T2D_WARN);
1023
+ } else {
1024
+ dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
1025
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
1026
+ if ( dAngle < 0.0 ) {
1027
+ dAngle += two_pi;
1028
+ }
1029
+ if ( dAngle - one_pi < -MIN_ANGLE || dAngle - one_pi > MIN_ANGLE ) {
1030
+ ret = T2D_OKAY;
1031
+ } else {
1032
+ ret = (T2D_UNDF | T2D_WARN);
1033
+ }
1034
+ }
1035
+ break;
1036
+ /* -------------------------- 2 Up ------------ */
1037
+ case 2:
1038
+ if ( num_Dn ) {
1039
+ dAlpha = dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]] -
1040
+ dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]];
1041
+ if ( dAlpha < 0.0 ) {
1042
+ dAlpha += two_pi;
1043
+ }
1044
+ if ( dAlpha > one_pi - MIN_ANGLE ) {
1045
+ ret = T2D_OKAY;
1046
+ } else
1047
+ if ( dAlpha < two_pi / 3.0 - MIN_ANGLE ) {
1048
+ ret = (T2D_UNDF | T2D_WARN);
1049
+ } else {
1050
+ /* angle between 2 Up bonds is between 120 and 180 degrees */
1051
+ /* direction of the (Alpha angle bisector) + 180 degrees */
1052
+ dBisector = (dBondDirection[nBondOrder[(first_Up ) % nNumNeigh]] +
1053
+ dBondDirection[nBondOrder[(first_Up + 1 ) % nNumNeigh]] ) / 2.0 - one_pi;
1054
+ if ( dBisector < 0.0 ) {
1055
+ dBisector += two_pi;
1056
+ }
1057
+ if ( dAlpha < two_pi / 3.0 + MIN_ANGLE ) {
1058
+ /* dAlpha is inside ( 2pi/3 - eps, 2pi/3 + eps ) interval */
1059
+ dLimit = MIN_ANGLE * 3.0 / 2.0;
1060
+ } else {
1061
+ dLimit = dAlpha * 3.0 / 2.0 - one_pi;
1062
+ }
1063
+ dAngle = dBondDirection[nBondOrder[(first_Up + 2 ) % nNumNeigh]];
1064
+ if ( dBisector - dAngle < -dLimit ||
1065
+ dBisector - dAngle > dLimit ) {
1066
+ ret = (T2D_UNDF | T2D_WARN);
1067
+ } else {
1068
+ ret = T2D_OKAY;
1069
+ }
1070
+ }
1071
+ } else {
1072
+ ret = T2D_OKAY;
1073
+ }
1074
+
1075
+ break;
1076
+ /* -------------------------- 3 Up ------------ */
1077
+ case 3:
1078
+ ret = T2D_OKAY;
1079
+ break;
1080
+ /* -------------------------- other Up -------- */
1081
+ default:
1082
+ return -1;
1083
+
1084
+ }
1085
+
1086
+ break;
1087
+
1088
+ /************************************** 4 bonds **************************
1089
+ */
1090
+ case 4:
1091
+ switch( num_Up ) {
1092
+ /* -------------------------- 0 Up ------------ */
1093
+ case 0:
1094
+ return T2D_UNDF;
1095
+ /* -------------------------- 1 Up ------------ */
1096
+ case 1:
1097
+ if ( num_Dn ) {
1098
+ if ( nBondType[nBondOrder[(first_Up + 2) % nNumNeigh]] < 0 ) {
1099
+ /*
1100
+ * Up, In Plane, Dn, In Plane. Undefined if angle between
1101
+ * two In Plane bonds is wuthin pi +/- 2*arcsine(1/sqrt(8)) interval
1102
+ * That is, 138.5 to 221.4 degrees; for certainty the interval is
1103
+ * increased by 5.7 degrees at each end to
1104
+ * 134.8 to 227.1 degrees
1105
+ */
1106
+ dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
1107
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
1108
+ if ( dAngle < 0.0 ) {
1109
+ dAngle += two_pi;
1110
+ }
1111
+ if ( fabs( dAngle - one_pi ) < dAngleAndPiMaxDiff + MIN_ANGLE ) {
1112
+ ret = (T2D_UNDF | T2D_WARN);
1113
+ } else {
1114
+ ret = T2D_OKAY;
1115
+ }
1116
+ } else {
1117
+ ret = T2D_OKAY;
1118
+ }
1119
+ #ifdef _DEBUG
1120
+ if ( num_Dn != 1 ) /* debug only */
1121
+ return -1;
1122
+ #endif
1123
+ } else {
1124
+ ret = T2D_OKAY;
1125
+ dAngle = dBondDirection[nBondOrder[(first_Up + 3) % nNumNeigh]] -
1126
+ dBondDirection[nBondOrder[(first_Up + 1) % nNumNeigh]];
1127
+ if ( dAngle < 0.0 ) {
1128
+ dAngle += two_pi;
1129
+ }
1130
+ if ( dAngle < one_pi - MIN_ANGLE ) {
1131
+ ret |= T2D_WARN;
1132
+ }
1133
+ }
1134
+ break;
1135
+ /* -------------------------- 2 Up ------------ */
1136
+ case 2:
1137
+ if ( cur_len_Up == 1 ) {
1138
+ ret = T2D_OKAY;
1139
+ } else {
1140
+ ret = (T2D_UNDF | T2D_WARN);
1141
+ }
1142
+ break;
1143
+ /* -------------------------- 3 Up ------------ */
1144
+ case 3:
1145
+ ret = T2D_OKAY;
1146
+ dAngle = dBondDirection[nBondOrder[(first_Up + 2) % nNumNeigh]] -
1147
+ dBondDirection[nBondOrder[(first_Up + 0) % nNumNeigh]];
1148
+ if ( dAngle < 0.0 ) {
1149
+ dAngle += two_pi;
1150
+ }
1151
+ if ( dAngle < one_pi - MIN_ANGLE ) {
1152
+ ret |= T2D_WARN;
1153
+ }
1154
+ break;
1155
+ /* -------------------------- 4 Up ------------ */
1156
+ case 4:
1157
+ ret = (T2D_UNDF | T2D_WARN);
1158
+ break;
1159
+ /* -------------------------- other Up -------- */
1160
+ default:
1161
+ return -1; /* program error */
1162
+ }
1163
+
1164
+ if ( ret == T2D_OKAY ) {
1165
+ /* check whether all bonds are inside a less than 180 degrees sector */
1166
+ for ( i = 0; i < nNumNeigh; i ++ ) {
1167
+ dAngle = dBondDirection[nBondOrder[(i + nNumNeigh - 1) % nNumNeigh]] -
1168
+ dBondDirection[nBondOrder[ i % nNumNeigh]];
1169
+ if ( dAngle < 0.0 ) {
1170
+ dAngle += two_pi;
1171
+ }
1172
+ if ( dAngle < one_pi - MIN_ANGLE ) {
1173
+ ret |= T2D_WARN;
1174
+ break;
1175
+ }
1176
+ }
1177
+ }
1178
+
1179
+ break;
1180
+ /*************************** other nuber of bonds ******************/
1181
+ default:
1182
+ return -1; /* error */
1183
+ }
1184
+
1185
+ return ret;
1186
+
1187
+ }
1188
+ /*************************************************************/
1189
+ double e_triple_prod_and_min_abs_sine2(double at_coord[][3], double central_at_coord[], int bAddedExplicitNeighbor, double *min_sine, int *bAmbiguous)
1190
+ {
1191
+ double min_sine_value=9999.0, sine_value, min_edge_len, max_edge_len, min_edge_len_NoExplNeigh, max_edge_len_NoExplNeigh;
1192
+ double s0, s1, s2, s3, e01, e02, e03, e12, e13, e23, tmp[3], e[3][3];
1193
+ double prod, ret, central_prod[4];
1194
+ int bLongEdges;
1195
+
1196
+ if ( !min_sine ) {
1197
+ return e_triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
1198
+ }
1199
+
1200
+ ret = e_triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
1201
+ sine_value = MPY_SINE * fabs( sine_value );
1202
+
1203
+ e_diff3( at_coord[1], at_coord[0], e[2] );
1204
+ e_diff3( at_coord[0], at_coord[2], e[1] );
1205
+ e_diff3( at_coord[2], at_coord[1], e[0] );
1206
+
1207
+ /* lengths of the 6 edges of the tetrahedra */
1208
+ e03 = e_len3( at_coord[0] ); /* 1 */
1209
+ e13 = e_len3( at_coord[1] );
1210
+ e23 = e_len3( at_coord[2] ); /* includes added neighbor if bAddedExplicitNeighbor*/
1211
+ e02 = e_len3( e[1] ); /* includes added neighbor if bAddedExplicitNeighbor*/
1212
+ e12 = e_len3( e[0] ); /* includes added neighbor if bAddedExplicitNeighbor*/
1213
+ e01 = e_len3( e[2] );
1214
+
1215
+ /* min & max edge length */
1216
+ max_edge_len =
1217
+ min_edge_len = e03;
1218
+
1219
+ if ( min_edge_len > e13 )
1220
+ min_edge_len = e13;
1221
+ if ( min_edge_len > e01 )
1222
+ min_edge_len = e01;
1223
+ min_edge_len_NoExplNeigh = min_edge_len;
1224
+
1225
+ if ( min_edge_len > e23 )
1226
+ min_edge_len = e23;
1227
+ if ( min_edge_len > e02 )
1228
+ min_edge_len = e02;
1229
+ if ( min_edge_len > e12 )
1230
+ min_edge_len = e12;
1231
+
1232
+ if ( max_edge_len < e13 )
1233
+ max_edge_len = e13;
1234
+ if ( max_edge_len < e01 )
1235
+ max_edge_len = e01;
1236
+ max_edge_len_NoExplNeigh = max_edge_len;
1237
+
1238
+ if ( max_edge_len < e23 )
1239
+ max_edge_len = e23;
1240
+ if ( max_edge_len < e02 )
1241
+ max_edge_len = e02;
1242
+ if ( max_edge_len < e12 )
1243
+ max_edge_len = e12;
1244
+
1245
+ if ( !bAddedExplicitNeighbor ) {
1246
+ min_edge_len_NoExplNeigh = min_edge_len;
1247
+ max_edge_len_NoExplNeigh = max_edge_len;
1248
+ }
1249
+
1250
+ bLongEdges = bAddedExplicitNeighbor?
1251
+ ( max_edge_len_NoExplNeigh < MAX_EDGE_RATIO * min_edge_len_NoExplNeigh ) :
1252
+ ( max_edge_len < MAX_EDGE_RATIO * min_edge_len );
1253
+
1254
+ if ( sine_value > MIN_SINE && ( min_sine || bAmbiguous ) ) {
1255
+ if ( min_sine ) {
1256
+ prod = fabs( ret );
1257
+ /* tetrahedra height = volume(prod) / area of a plane(cross_prod) */
1258
+ /* (instead of a tetrahedra calculate parallelogram/parallelepiped area/volume) */
1259
+
1260
+ /* 4 heights from each of the 4 vertices to the opposite plane */
1261
+ s0 = prod / e_len3( e_cross_prod3( at_coord[1], at_coord[2], tmp ) );
1262
+ s1 = prod / e_len3( e_cross_prod3( at_coord[0], at_coord[2], tmp ) );
1263
+ s2 = prod / e_len3( e_cross_prod3( at_coord[0], at_coord[1], tmp ) );
1264
+ s3 = prod / e_len3( e_cross_prod3( e[0], e[1], tmp ) );
1265
+ /* abs. value of a sine of an angle between each tetrahedra edge and plane */
1266
+ /* sine = height / edge length */
1267
+ if ( (sine_value = s0/e01) < min_sine_value )
1268
+ min_sine_value = sine_value;
1269
+ if ( (sine_value = s0/e02) < min_sine_value )
1270
+ min_sine_value = sine_value;
1271
+ if ( (sine_value = s0/e03) < min_sine_value )
1272
+ min_sine_value = sine_value;
1273
+
1274
+ if ( (sine_value = s1/e01) < min_sine_value )
1275
+ min_sine_value = sine_value;
1276
+ if ( (sine_value = s1/e12) < min_sine_value )
1277
+ min_sine_value = sine_value;
1278
+ if ( (sine_value = s1/e13) < min_sine_value )
1279
+ min_sine_value = sine_value;
1280
+
1281
+ if ( (sine_value = s2/e02) < min_sine_value )
1282
+ min_sine_value = sine_value;
1283
+ if ( (sine_value = s2/e12) < min_sine_value )
1284
+ min_sine_value = sine_value;
1285
+ if ( (sine_value = s2/e23) < min_sine_value )
1286
+ min_sine_value = sine_value;
1287
+
1288
+ if ( (sine_value = s3/e03) < min_sine_value )
1289
+ min_sine_value = sine_value;
1290
+ if ( (sine_value = s3/e13) < min_sine_value )
1291
+ min_sine_value = sine_value;
1292
+ if ( (sine_value = s3/e23) < min_sine_value )
1293
+ min_sine_value = sine_value;
1294
+ /* actually use triple sine */
1295
+ *min_sine = sine_value = MPY_SINE * min_sine_value;
1296
+ }
1297
+
1298
+ if ( bAmbiguous && sine_value >= MIN_SINE ) {
1299
+ /* check whether the central atom is outside the tetrahedra (0,0,0), at_coord[0,1,2] */
1300
+ /* compare the tetrahedra volume and the volume of a tetrahedra having central_at_coord[] vertex */
1301
+ int i;
1302
+ e_diff3( central_at_coord, at_coord[0], tmp );
1303
+ central_prod[0] = e_triple_prod( at_coord[0], at_coord[1], central_at_coord, NULL );
1304
+ central_prod[1] = e_triple_prod( at_coord[1], at_coord[2], central_at_coord, NULL );
1305
+ central_prod[2] = e_triple_prod( at_coord[2], at_coord[0], central_at_coord, NULL );
1306
+ central_prod[3] = e_triple_prod( e[2], e[1], tmp, NULL );
1307
+ for ( i = 0; i <= 3; i ++ ) {
1308
+ if ( central_prod[i] / ret < -MIN_SINE_OUTSIDE ) {
1309
+ *bAmbiguous |= AMBIGUOUS_STEREO;
1310
+ break;
1311
+ }
1312
+ }
1313
+ }
1314
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
1315
+
1316
+ if ( bLongEdges && !bAddedExplicitNeighbor && max_edge_len >= MIN_LEN_STRAIGHT ) {
1317
+ /* possible planar tetragon */
1318
+ if ( sine_value < MIN_SINE_SQUARE ) {
1319
+ *min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
1320
+ if ( bAmbiguous && !*bAmbiguous ) {
1321
+ *bAmbiguous |= AMBIGUOUS_STEREO;
1322
+ }
1323
+ }
1324
+ }
1325
+
1326
+ if ( bLongEdges && sine_value < MIN_SINE_SQUARE && sine_value < MIN_SINE_EDGE * min_edge_len_NoExplNeigh ) {
1327
+ *min_sine = MIN_SINE / 2.0; /* force parity to be undefined */
1328
+ if ( bAmbiguous && !*bAmbiguous ) {
1329
+ *bAmbiguous |= AMBIGUOUS_STEREO;
1330
+ }
1331
+ }
1332
+ #endif
1333
+
1334
+ } else
1335
+ if ( min_sine ) {
1336
+ *min_sine = sine_value;
1337
+ }
1338
+
1339
+ return ret;
1340
+ }
1341
+ /*************************************************************/
1342
+ double e_triple_prod_and_min_abs_sine(double at_coord[][3], double *min_sine)
1343
+ {
1344
+ double min_sine_value=9999.0, sine_value;
1345
+ double prod=0.0;
1346
+
1347
+ if ( !min_sine ) {
1348
+ return e_triple_prod( at_coord[0], at_coord[1], at_coord[2], NULL );
1349
+ }
1350
+
1351
+ prod = e_triple_prod( at_coord[0], at_coord[1], at_coord[2], &sine_value );
1352
+ sine_value = fabs( sine_value );
1353
+ min_sine_value = inchi_min( min_sine_value, sine_value );
1354
+
1355
+ prod = e_triple_prod( at_coord[1], at_coord[2], at_coord[0], &sine_value );
1356
+ sine_value = fabs( sine_value );
1357
+ min_sine_value = inchi_min( min_sine_value, sine_value );
1358
+
1359
+ prod = e_triple_prod( at_coord[2], at_coord[0], at_coord[1], &sine_value );
1360
+ sine_value = fabs( sine_value );
1361
+ min_sine_value = inchi_min( min_sine_value, sine_value );
1362
+
1363
+ *min_sine = min_sine_value;
1364
+
1365
+ return prod;
1366
+ }
1367
+ /*************************************************************/
1368
+ /* Find if point (0,0,0)a and 3 atoms are in one plane */
1369
+ int are_3_vect_in_one_plane( double at_coord[][3], double min_sine)
1370
+ {
1371
+ double actual_min_sine;
1372
+ double prod;
1373
+ prod = e_triple_prod_and_min_abs_sine( at_coord, &actual_min_sine);
1374
+ return actual_min_sine <= min_sine;
1375
+ }
1376
+ /*************************************************************/
1377
+ /* Find if 4 atoms are in one plane */
1378
+ int e_are_4at_in_one_plane( double at_coord[][3], double min_sine)
1379
+ {
1380
+ double actual_min_sine, min_actual_min_sine;
1381
+ double coord[3][3], prod;
1382
+ int i, k, j;
1383
+ for ( k = 0; k < 4; k ++ ) { /* cycle added 4004-08-15 */
1384
+ for ( i = j = 0; i < 4; i ++ ) {
1385
+ if ( i != k ) {
1386
+ e_diff3( at_coord[i], at_coord[k], coord[j] );
1387
+ j ++;
1388
+ }
1389
+ }
1390
+ prod = e_triple_prod_and_min_abs_sine( coord, &actual_min_sine);
1391
+ if ( !k || actual_min_sine < min_actual_min_sine ) {
1392
+ min_actual_min_sine = actual_min_sine;
1393
+ }
1394
+ }
1395
+ return min_actual_min_sine <= min_sine;
1396
+ }
1397
+ /*************************************************************/
1398
+ int e_triple_prod_char( inchi_Atom *at, int at_1, int i_next_at_1, S_CHAR *z_dir1,
1399
+ int at_2, int i_next_at_2, S_CHAR *z_dir2 )
1400
+ {
1401
+ inchi_Atom *at1, *at2;
1402
+ double pnt[3][3], len;
1403
+ int i;
1404
+ int ret = 0;
1405
+
1406
+ at1 = at + at_1;
1407
+ at2 = at + at[at_1].neighbor[i_next_at_1];
1408
+
1409
+ pnt[0][0] = at2->x - at1->x;
1410
+ pnt[0][1] = at2->y - at1->y;
1411
+ pnt[0][2] = at2->z - at1->z;
1412
+
1413
+ at2 = at + at_2;
1414
+ at1 = at + at[at_2].neighbor[i_next_at_2];
1415
+
1416
+ pnt[1][0] = at2->x - at1->x;
1417
+ pnt[1][1] = at2->y - at1->y;
1418
+ pnt[1][2] = at2->z - at1->z;
1419
+ /*
1420
+ * resultant pnt vector directions:
1421
+ *
1422
+ * pnt[0] pnt[1]
1423
+ *
1424
+ * [at_1]---->[...] [...]---->[at_2]
1425
+ *
1426
+ *
1427
+ * e_add3 below: (pnt[0] + pnt[1]) -> pnt[1]
1428
+ */
1429
+ e_add3( pnt[0], pnt[1], pnt[1] );
1430
+
1431
+
1432
+
1433
+ for ( i = 0; i < 3; i ++ ) {
1434
+ pnt[0][i] = (double)z_dir1[i];
1435
+ pnt[2][i] = (double)z_dir2[i];
1436
+ }
1437
+ for ( i = 0; i < 3; i ++ ) {
1438
+ len = e_len3( pnt[i] );
1439
+ if ( len < MIN_BOND_LEN ) {
1440
+ goto exit_function; /* too short bond */
1441
+ }
1442
+ e_mult3( pnt[i], 1.0/len, pnt[i] );
1443
+ }
1444
+ len = 100.0*e_triple_prod(pnt[0], pnt[1], pnt[2], NULL );
1445
+ /*
1446
+ * ^ pnt[0]
1447
+ * | The orientation on this diagram
1448
+ * | produces len = -100
1449
+ * [at_1]------>[at_2]
1450
+ * pnt[1] /
1451
+ * /
1452
+ * / pnt[2] (up from the plane)
1453
+ * v
1454
+ *
1455
+ * Note: len is invariant upon at_1 <--> at_2 transposition because
1456
+ * triple product changes sign upon pnt[0]<-->pnt[2] transposition and
1457
+ * triple product changes sign upon pnt[1]--> -pnt[1] change of direction:
1458
+ *
1459
+ * e_triple_prod(pnt[0], pnt[1], pnt[2], NULL ) =
1460
+ * e_triple_prod(pnt[2], -pnt[1], pnt[0], NULL )
1461
+ *
1462
+ */
1463
+
1464
+ ret = len >= 0.0? (int)floor(len+0.5) : -(int)floor(0.5-len);
1465
+
1466
+ exit_function:
1467
+
1468
+ return ret;
1469
+ }
1470
+
1471
+ #ifdef NEVER
1472
+ /********************************************************************************************/
1473
+ int bCanInpAtomBeAStereoCenter( inchi_Atom *at, int cur_at )
1474
+ {
1475
+
1476
+ /*************************************************************************************
1477
+ * current version
1478
+ *************************************************************************************
1479
+ * Use #define to split the stereocenter description table into parts
1480
+ * to make it easier to read
1481
+ *
1482
+ * --------- 4 single bonds stereocenters -------
1483
+ *
1484
+ * | | | | | |
1485
+ * -C- -Si- -Ge- -Sn- >As[+] >B[-]
1486
+ * | | | | | |
1487
+ */
1488
+ #define SZELEM1 "C\000","Si", "Ge", "Sn", "As", "B\000",
1489
+ #define CCHARGE1 0, 0, 0, 0, 1, -1,
1490
+ #define CNUMBONDSANDH1 4, 4, 4, 4, 4, 4,
1491
+ #define CCHEMVALENCEH1 4, 4, 4, 4, 4, 4,
1492
+ #define CHAS3MEMBRING1 0, 0, 0, 0, 0, 0,
1493
+ #define CREQUIRDNEIGH1 0, 0, 0, 0, 3, 0,
1494
+ /*
1495
+ * --------------- S, Se stereocenters ----------
1496
+ *
1497
+ * | | || | | ||
1498
+ * -S= =S= -S[+] >S[+] -Se= =Se= -Se[+] >Se[+]
1499
+ * | | | | | | | |
1500
+ */
1501
+ #define SZELEM2 "S\000","S\000","S\000","S\000","Se", "Se", "Se", "Se",
1502
+ #define CCHARGE2 0, 0, 1, 1, 0, 0, 1, 1,
1503
+ #define CNUMBONDSANDH2 3, 4, 3, 4, 3, 4, 3, 4,
1504
+ #define CCHEMVALENCEH2 4, 6, 3, 5, 4, 6, 3, 5,
1505
+ #define CHAS3MEMBRING2 0, 0, 0, 0, 0, 0, 0, 0,
1506
+ #define CREQUIRDNEIGH2 3, 3, 3, 3, 3, 3, 3, 3,
1507
+ /*
1508
+ * ------------------ N, P stereocenters --------
1509
+ *
1510
+ * X---Y
1511
+ * | | \ / | |
1512
+ * =N- >N[+] N >P[+] =P-
1513
+ * | | | | |
1514
+ */
1515
+ #define SZELEM3 "N\000","N\000","N\000","P\000","P\000",
1516
+ #define CCHARGE3 0, 1, 0, 1, 0,
1517
+ #define CNUMBONDSANDH3 4, 4, 3, 4, 4,
1518
+ #define CCHEMVALENCEH3 5, 4, 3, 4, 5,
1519
+ #define CHAS3MEMBRING3 0, 0, 1, 0, 0,
1520
+ #define CREQUIRDNEIGH3 3, 3, 1, 3, 3,
1521
+
1522
+
1523
+
1524
+ static char szElem[][3]={ SZELEM1 SZELEM2 SZELEM3 };
1525
+ static S_CHAR cCharge[]={ CCHARGE1 CCHARGE2 CCHARGE3 };
1526
+ static S_CHAR cNumBondsAndH[]={ CNUMBONDSANDH1 CNUMBONDSANDH2 CNUMBONDSANDH3 };
1527
+ static S_CHAR cChemValenceH[]={ CCHEMVALENCEH1 CCHEMVALENCEH2 CCHEMVALENCEH3 };
1528
+ static S_CHAR cHas3MembRing[]={ CHAS3MEMBRING1 CHAS3MEMBRING2 CHAS3MEMBRING3 };
1529
+ static S_CHAR cRequirdNeigh[]={ CREQUIRDNEIGH1 CREQUIRDNEIGH2 CREQUIRDNEIGH3 };
1530
+
1531
+ static int n = sizeof(szElem)/sizeof(szElem[0]);
1532
+ /* reqired neighbor types (bitmap):
1533
+ 0 => check bonds only
1534
+ 1 => no terminal hydrogen atom neighbors
1535
+ 2 => no terminal -X and -XH together (don't care the bond type, charge, radical)
1536
+ (X = tautomeric endpoint atom)
1537
+ Note: whenever cChemValenceH[] > cNumBondsAndH[]
1538
+ the tautomeric and/or alternating bonds
1539
+ are permitted
1540
+
1541
+ */
1542
+ int i, ret = 0;
1543
+ for ( i = 0; i < n; i++ ) {
1544
+ if ( !strcmp( at[cur_at].elname, szElem[i]) &&
1545
+ at[cur_at].charge == cCharge[i] &&
1546
+ (!at[cur_at].radical || at[cur_at].radical == 1) &&
1547
+ at[cur_at].num_bonds + inchi_NUMH(at,cur_at) == cNumBondsAndH[i] &&
1548
+ at[cur_at].chem_bonds_valence+inchi_NUMH(at,cur_at) == cChemValenceH[i] &&
1549
+ (cHas3MembRing[i]? is_atom_in_3memb_ring( at, cur_at ) : 1) &&
1550
+ e_bInpAtomHasRequirdNeigh ( at, cur_at, cRequirdNeigh[i], cChemValenceH[i]-cNumBondsAndH[i]) ) {
1551
+ ret = cNumBondsAndH[i];
1552
+ break;
1553
+ }
1554
+ }
1555
+ return ret;
1556
+ }
1557
+
1558
+ #endif /* NEVER */
1559
+ /********************************************************************************************/
1560
+ int e_bCanInpAtomBeAStereoCenter( int cur_at, S_CHAR *cAtType )
1561
+ {
1562
+ switch ( cAtType[cur_at] ) {
1563
+ case AtType_C4 :
1564
+ case AtType_Si4 :
1565
+ case AtType_Ge4 :
1566
+ case AtType_Sn4 :
1567
+ case AtType_B4m :
1568
+ case AtType_S6 :
1569
+ case AtType_S5p :
1570
+ case AtType_Se6 :
1571
+ case AtType_Se5p:
1572
+ case AtType_N5 :
1573
+ case AtType_N4p :
1574
+ case AtType_P4p :
1575
+ case AtType_P5 :
1576
+ case AtType_As4p:
1577
+ case AtType_As5 :
1578
+ return 4;
1579
+
1580
+ case AtType_S3p :
1581
+ case AtType_Se3p:
1582
+ case AtType_S4 :
1583
+ case AtType_Se4 :
1584
+ case AtType_N3r :
1585
+ return 3;
1586
+ }
1587
+ return 0;
1588
+ }
1589
+ /****************************************************************/
1590
+ /* used for atoms adjacent to stereogenic bonds only */
1591
+ int e_bCanAtomHaveAStereoBond( inchi_Atom *at, int cur_at, S_CHAR *cAtType )
1592
+ {
1593
+ int i, neigh, nNumFound;
1594
+ char *p;
1595
+ static char sNeigh[] = "O;S;Se;Te;";
1596
+ switch ( cAtType[cur_at] ) {
1597
+ case AtType_C3 :
1598
+ case AtType_Si3:
1599
+ case AtType_Ge3:
1600
+ case AtType_Sn3:
1601
+ case AtType_N3p:
1602
+ case AtType_N3 :
1603
+ return 3;
1604
+ case AtType_Nns:
1605
+ /*
1606
+ |
1607
+ found =N=
1608
+
1609
+ if it has one neighbor =O or =S or =Se or =Te then return 3, otherwise return 1
1610
+
1611
+ */
1612
+ nNumFound = 0;
1613
+ for ( i = 0; i < at[cur_at].num_bonds; i ++ ) {
1614
+ if ( at[cur_at].bond_type[i] == INCHI_BOND_TYPE_DOUBLE ) {
1615
+ neigh = (int)at[cur_at].neighbor[i];
1616
+ if ( (p = strstr(sNeigh, at[neigh].elname)) &&
1617
+ ';' == p[strlen(at[neigh].elname)] ) {
1618
+ nNumFound ++;
1619
+ }
1620
+ }
1621
+ }
1622
+ return nNumFound==1? 3 : 1;
1623
+ }
1624
+ return 0;
1625
+ }
1626
+ /****************************************************************/
1627
+ int e_bCanAtomBeMiddleAllene( int cur_at, S_CHAR *cAtType )
1628
+ {
1629
+ switch ( cAtType[cur_at] ) {
1630
+ case AtType_C2 :
1631
+ case AtType_Si2:
1632
+ case AtType_Ge2:
1633
+ case AtType_Sn2:
1634
+ return 2;
1635
+ }
1636
+ return 0;
1637
+ }
1638
+ /****************************************************************/
1639
+ int e_bCanAtomBeTerminalAllene( int cur_at, S_CHAR *cAtType )
1640
+ {
1641
+ switch ( cAtType[cur_at] ) {
1642
+ case AtType_C3 :
1643
+ case AtType_Si3:
1644
+ case AtType_Ge3:
1645
+ case AtType_Sn3:
1646
+ return 3;
1647
+ }
1648
+ return 0;
1649
+ }
1650
+ /*******************************************************************************************/
1651
+ int e_FixSb0DParities( inchi_Atom *at, Stereo0D *pStereo, int chain_length, AT_NUM at_middle,
1652
+ int at_1, int i_next_at_1, S_CHAR z_dir1[], S_CHAR z_dir1NM[], int bOnlyNM1, int bAnomaly1NM, int parity1, int parity1NM,
1653
+ int at_2, int i_next_at_2, S_CHAR z_dir2[], S_CHAR z_dir2NM[], int bOnlyNM2, int bAnomaly2NM, int parity2, int parity2NM )
1654
+ {
1655
+ int i_neigh_at_1, i_neigh_at_2, i, j1, j2;
1656
+ int j_neigh_at_1, j_neigh_at_2, j_next_at_1, j_next_at_2; /* positions after metal removal */
1657
+ inchi_Stereo0D *stereo0D = NULL;
1658
+ int dot_prod_z = 0, dot_prod_zNM = 0, parity, parityNM;
1659
+
1660
+ if ( (!parity1 || !parity2) && (!parity1NM || !parity2NM) )
1661
+ return 0;
1662
+
1663
+ if ( ATOM_PARITY_WELL_DEF( parity1 ) && ATOM_PARITY_WELL_DEF( parity2 ) ) {
1664
+ /* find how the whole bond parity depend on geometry */
1665
+ /* if dot_prod_z < 0 then bond_parity := 3-bond_parity */
1666
+ /* can be done only for a well-defined geometry */
1667
+ /********************************************************************
1668
+ * Case of bOnlyNonMetal: stereobond end atoms have valence > 3
1669
+ * therefore they will not be recognized until metals have
1670
+ * been disconnected. Until then the assigned parities will
1671
+ * not change: ReconcileCmlIncidentBondParities() in the dll
1672
+ * ignores hypervanlence atoms marked as belonging to a stereobond.
1673
+ * Explicit H are removed only after metal diconnection.
1674
+ *
1675
+ * However, there is a possibility that the normalization
1676
+ * removes an explicit H thus reducing the valence to acceptable
1677
+ * value for the bond to be treated as stereogenic.
1678
+ * In this case a wrong INChI stereolayer for the reconnected
1679
+ * structure will be produced.
1680
+ *
1681
+ * After the metal disconnection ReconcileAllCmlBondParities()
1682
+ * will be called to reconcile newly appearing stereobonds
1683
+ ********************************************************************/
1684
+
1685
+ dot_prod_z = (chain_length%2)?
1686
+ e_triple_prod_char( at, at_1, i_next_at_1, z_dir1, at_2, i_next_at_2, z_dir2 ) :
1687
+ e_dot_prodchar3(z_dir1, z_dir2);
1688
+
1689
+ if ( abs(dot_prod_z) < MIN_DOT_PROD ) {
1690
+ /* The geometry is not well-defined */
1691
+ parity1 = parity2 = INCHI_PARITY_UNDEFINED;
1692
+ dot_prod_z = 0;
1693
+ }
1694
+
1695
+ }
1696
+ if ( ATOM_PARITY_WELL_DEF( parity1NM ) && ATOM_PARITY_WELL_DEF( parity2NM ) ) {
1697
+ /* find how the whole bond parity depend on geometry */
1698
+ /* if dot_prod_z < 0 then bond_parity := 3-bond_parity */
1699
+ /* can be done only for a well-defined geometry */
1700
+ /********************************************************************
1701
+ * Case of bOnlyNonMetal: stereobond end atoms have valence > 3
1702
+ * therefore they will not be recognized until metals have
1703
+ * been disconnected. Until then the assigned parities will
1704
+ * not change: ReconcileCmlIncidentBondParities() in the dll
1705
+ * ignores hypervanlence atoms marked as belonging to a stereobond.
1706
+ * Explicit H are removed only after metal diconnection.
1707
+ *
1708
+ * However, there is a possibility that the normalization
1709
+ * removes an explicit H thus reducing the valence to acceptable
1710
+ * value for the bond to be treated as stereogenic.
1711
+ * In this case a wrong INChI stereolayer for the reconnected
1712
+ * structure will be produced.
1713
+ *
1714
+ * After the metal disconnection ReconcileAllCmlBondParities()
1715
+ * will be called to reconcile newly appearing stereobonds
1716
+ ********************************************************************/
1717
+
1718
+ dot_prod_zNM = (chain_length%2)?
1719
+ e_triple_prod_char( at, at_1, i_next_at_1, z_dir1NM, at_2, i_next_at_2, z_dir2NM ) :
1720
+ e_dot_prodchar3(z_dir1NM, z_dir2NM);
1721
+
1722
+ if ( abs(dot_prod_zNM) < MIN_DOT_PROD ) {
1723
+ /* The geometry is not well-defined */
1724
+ parity1NM = parity2NM = INCHI_PARITY_UNDEFINED;
1725
+ dot_prod_zNM = 0;
1726
+ }
1727
+
1728
+ }
1729
+
1730
+ i_neigh_at_1 = i_neigh_at_2 = -1;
1731
+ j_neigh_at_1 = j_neigh_at_2 = j_next_at_1 = j_next_at_2 = -1;
1732
+
1733
+ /************************************************************************
1734
+ *
1735
+ * The possibly stereogenic bond is defined by atoms at_1, at_2 and
1736
+ * positions in their adjacency lists i_next_at_1, i_next_at_2.
1737
+ *
1738
+ * We need one more neighbor of at_1 and at_2 to establist cis or trans.
1739
+ * The current API allows only same neighbors for both connected and
1740
+ * metal-disconnected (or non-metal, NM) structures. Therefore if an
1741
+ * atom has both metal and non-metal neighbors, select the non-metal one.
1742
+ *
1743
+ * In case of bOnlyNM we have to use ordering numbers of the bonds
1744
+ * counted as if all metals have been disconnected.
1745
+ *
1746
+ * In all other cases we use real ordering numbers of the bonds
1747
+ * to calculate the parities.
1748
+ *
1749
+ * The input parities meaning:
1750
+ * ===========================
1751
+ * EVEN=2: the atoms in the adjacency list are arranged clockwise as
1752
+ * seen from the arrowhead of the z_dir vector
1753
+ *
1754
+ * The output parities meaning:
1755
+ * ============================
1756
+ * EVEN=2: trans geometry. For more details see the API description.
1757
+ *
1758
+ **************************************************************************/
1759
+
1760
+ if ( bOnlyNM1 || ATOM_PARITY_WELL_DEF( parity1NM ) ) {
1761
+ /* disconnected metal case */
1762
+ for ( i = j1 = 0; i < at[at_1].num_bonds; i ++ ) {
1763
+ if ( IS_METAL(pStereo->cAtType[at[at_1].neighbor[i]]) ) {
1764
+ continue;
1765
+ }
1766
+ if ( i == i_next_at_1 ) {
1767
+ j_next_at_1 = j1; /* position of the stereo bond in adjacency list
1768
+ when metals are disconnected */
1769
+ } else
1770
+ if ( i_neigh_at_1 < 0 ) {
1771
+ i_neigh_at_1 = i; /* position of the first non-metal neighbor (metal is connected) */
1772
+ j_neigh_at_1 = j1; /* position of the first non-metal neighbor (metal is disconnected) */
1773
+ }
1774
+ j1 ++;
1775
+ }
1776
+ } else {
1777
+ /* no metal case */
1778
+ j_neigh_at_1 = i_neigh_at_1 = (i_next_at_1==0);
1779
+ j_next_at_1 = i_next_at_1;
1780
+ j1 = at[at_1].num_bonds;
1781
+ }
1782
+
1783
+ if ( bOnlyNM2 || ATOM_PARITY_WELL_DEF( parity2NM ) ) {
1784
+ for ( i = j2 = 0; i < at[at_2].num_bonds; i ++ ) {
1785
+ if ( IS_METAL(pStereo->cAtType[at[at_2].neighbor[i]]) ) {
1786
+ continue;
1787
+ }
1788
+ if ( i == i_next_at_2 ) {
1789
+ j_next_at_2 = j2;
1790
+ } else
1791
+ if ( i_neigh_at_2 < 0 ) {
1792
+ i_neigh_at_2 = i;
1793
+ j_neigh_at_2 = j2;
1794
+ }
1795
+ j2 ++;
1796
+ }
1797
+ } else {
1798
+ j_neigh_at_2 = i_neigh_at_2 = (i_next_at_2==0);
1799
+ j_next_at_2 = i_next_at_2;
1800
+ j2 = at[at_2].num_bonds;
1801
+ }
1802
+
1803
+ if ( i_neigh_at_1 < 0 || i_neigh_at_2 < 0 ||
1804
+ j_neigh_at_1 < 0 || j_neigh_at_2 < 0 ||
1805
+ j_next_at_1 < 0 || j_next_at_2 < 0 ) {
1806
+ return 0; /* debugging */
1807
+ }
1808
+ if ( parity1 || parity1NM ) {
1809
+ /* create a new stereo descriptor */
1810
+ stereo0D = e_GetNewStereo( pStereo );
1811
+ if ( !stereo0D ) {
1812
+ return -1; /* error */
1813
+ }
1814
+ /* choose the smallest (earliest in the adjacency list) neighbor of at_1 */
1815
+ stereo0D->neighbor[0] = at[at_1].neighbor[i_neigh_at_1];
1816
+ /* stereibond atoms */
1817
+ stereo0D->neighbor[1] = at_1;
1818
+ stereo0D->neighbor[2] = at_2;
1819
+ /* choose the smallest neighbor of at_2 */
1820
+ stereo0D->neighbor[3] = at[at_2].neighbor[i_neigh_at_2];
1821
+ stereo0D->central_atom = at_middle;
1822
+ stereo0D->type = (chain_length % 2)? INCHI_StereoType_Allene : INCHI_StereoType_DoubleBond;
1823
+
1824
+ if ( dot_prod_z || dot_prod_zNM ) {
1825
+
1826
+ int i_parity1 = i_neigh_at_1 + i_next_at_1 + (i_neigh_at_1 > i_next_at_1);
1827
+ int j_parity1 = j_neigh_at_1 + j_next_at_1 + (j_neigh_at_1 > j_next_at_1);
1828
+ int i_parity2 = i_neigh_at_2 + i_next_at_2 + (i_neigh_at_2 > i_next_at_2);
1829
+ int j_parity2 = j_neigh_at_2 + j_next_at_2 + (j_neigh_at_2 > j_next_at_2);
1830
+
1831
+ /* regular (connected) parity; parity1 and parity2 are well-defined only together */
1832
+ if ( ATOM_PARITY_WELL_DEF( parity1 ) ) {
1833
+ parity = 2 - ( parity1 + parity2 + (dot_prod_z < 0) +
1834
+ ((bOnlyNM1)? j_parity1 : i_parity1) +
1835
+ ((bOnlyNM2)? j_parity2 : i_parity2) ) % 2;
1836
+ } else {
1837
+ parity = parity1;
1838
+ }
1839
+
1840
+
1841
+ /* disconnected parity; parity1NM and parity2NM are well-defined only together */
1842
+ if ( ATOM_PARITY_WELL_DEF( parity1NM ) ) {
1843
+ parityNM = 2 - ( parity1NM + parity2NM + (dot_prod_zNM < 0) +
1844
+ ((bOnlyNM1||bAnomaly1NM)? j_parity1 : i_parity1) +
1845
+ ((bOnlyNM2||bAnomaly2NM)? j_parity2 : i_parity2) ) % 2;
1846
+ } else {
1847
+ parityNM = parity1NM;
1848
+ }
1849
+ } else {
1850
+ parity = parity1;
1851
+ parityNM = parity1NM;
1852
+ }
1853
+ stereo0D->parity = parity;
1854
+ if ( parityNM != parity || bAnomaly1NM || bAnomaly2NM ) {
1855
+ stereo0D->parity |= (parityNM << SB_PARITY_SHFT);
1856
+ }
1857
+
1858
+ return stereo0D->parity;
1859
+ }
1860
+ return 0;
1861
+ }
1862
+ /**************************************************************************/
1863
+ int e_nNumNonMetalNeigh( inchi_Atom *atom, int cur_at, Stereo0D *pStereo, int *i_ord_LastMetal )
1864
+ {
1865
+ int j, nNumNonMetal;
1866
+ inchi_Atom *at = atom + cur_at;
1867
+ int val = at->num_bonds;
1868
+ int atype;
1869
+
1870
+ *i_ord_LastMetal = -1;
1871
+ nNumNonMetal = 0;
1872
+
1873
+ atype = pStereo->cAtType[cur_at];
1874
+
1875
+ if ( IS_METAL(atype) )
1876
+ return 0;
1877
+ for ( j = 0; j < val; j ++ ) {
1878
+ atype = pStereo->cAtType[(int)at->neighbor[j]];
1879
+ if ( IS_METAL(atype) )
1880
+ *i_ord_LastMetal = j;
1881
+ else
1882
+ nNumNonMetal ++;
1883
+ }
1884
+ return nNumNonMetal;
1885
+ }
1886
+ /*======================================================================================================
1887
+
1888
+ e_half_stereo_bond_parity() General Description:
1889
+
1890
+ A) find projections of 3 bonds on a reasonable plane defined
1891
+ by a vector z_dir perpendicular to the plane
1892
+ B) calculate parity (parity=2[EVEN]: neighbors are clockwise as seen from the arrowhead of z_dir[] vector)
1893
+
1894
+ e_half_stereo_bond_parity() Detailed Description:
1895
+
1896
+ 1) Find at_coord[] = vectors from the central atoms to its neighbors
1897
+ 2) If only 2 neighbors are present, then create a reasonable 3rd neighbor
1898
+ (an implicit H or a fictitious atom in case of =NX) coordinates
1899
+ 3) Normalize at_coord[] to unit length
1900
+ 4) Find unit vector pnt[2] perpendicular to the plane containing
1901
+ at_coord[] arrow ends.
1902
+ Even though it is not necessary, make z-coordinate of pnt[2] positive.
1903
+ ** pnt[2] has the new z-axis direction **
1904
+ 5) Let pnt[0] = perpendicular to pnt[2] component of at_coord[0];
1905
+ Normalize pnt[0] to unit length.
1906
+ ** pnt[0] has the new x-axis direction **
1907
+ 6) Let pnt[1] = pnt[2] x pnt[0] (cross-product);
1908
+ ** pnt[1] has the new y-axis direction **
1909
+ 7) Find at_coord[] in the new xyz-basis and normalize their xy-projections
1910
+ to a unit length
1911
+ 8) In the new xy-plane find (counterclockwise) angles:
1912
+ tmp1 = (from at_coord[0] to at_coord[1])
1913
+ tmp2 = (from at_coord[0] to at_coord[2])
1914
+ 9) Calculate the parity: if tmp1 < tmp2 then 1 (odd) else 2 (even)
1915
+ (even: looking from the arrow end of the new z-axis, 0, 1, and 2 neighbors
1916
+ are in clockwise order)
1917
+ 10) Calculate z_dir = 100*pnt[2].
1918
+
1919
+ Note1. If z_dir vectors of atoms located at the opposite ends of a double bond have approximately
1920
+ opposite directions (that is, their dot-product is negative) then the parity of the
1921
+ stereogenic bond calculated from half-bond-parities should be inverted
1922
+
1923
+ Note2. In case of a tetrahedral cumulene a triple product (z_dir1, (1->2), z_dir2) is used instead
1924
+ of the dot-product. (1->2) is a vector from the atom#1 to the atom #2. This triple product
1925
+ is invariant with respect to the atom numbering because it does not change upon (1,2)
1926
+ permutation.
1927
+
1928
+ Stereo ambiguity in case of 2 neighbors:
1929
+ ----------------------------------------
1930
+ Undefined: single-double bond angle > pi - arcsin(0.03) = 178.28164199834454285275613218975 degrees
1931
+ Ambiguous: single-double bond angle > 175 degrees = pi - 0.087156 Rad
1932
+
1933
+ Return values
1934
+ (cases: I=only in case of isotopic H atoms the neighbors are different,
1935
+ N=in case of non-isotopic H atoms the neighbors are different)
1936
+
1937
+ -4 = INCHI_PARITY_UNDEFINED => atom is adjacent to a stereogenic bond, but the geometry is undefined, I
1938
+ -3 = INCHI_PARITY_UNKNOWN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, I
1939
+ -2 =-INCHI_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, I
1940
+ -1 =-INCHI_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, I
1941
+ 0 = INCHI_PARITY_NONE => the atom is not adjacent to a stereogenic bond
1942
+ 1 = INCHI_PARITY_ODD => parity of an atom adjacent to a stereogenic bond, N&I
1943
+ 2 = INCHI_PARITY_EVEN => parity of an atom adjacent to a stereogenic bond, N&I
1944
+ 3 = INCHI_PARITY_UNKNOWN => atom is adjacent to a stereogenic bond, but the geometry is not known to the iuser, N&I
1945
+ 4 = INCHI_PARITY_UNDEFINED => atom is adjacent to a stereogenic bond, but the geometry is undefined, N&I
1946
+
1947
+
1948
+ =====================================================================================================*/
1949
+
1950
+ int e_half_stereo_bond_parity( inchi_Atom *at, int cur_at, S_CHAR *z_dir, int *bOnlyNonMetal,
1951
+ int bPointedEdgeStereo, Stereo0D *pStereo )
1952
+ {
1953
+ double at_coord[MAX_NUM_STEREO_BOND_NEIGH][3], c, s, tmp[3], tmp1, tmp2, min_tmp, max_tmp, z;
1954
+ double temp[3], pnt[3][3];
1955
+ int j, k, p0, p1, p2, next, num_z, nType, num_either_single, num_either_double;
1956
+ int nNumExplictAttachments;
1957
+ int bond_parity = INCHI_PARITY_UNDEFINED;
1958
+ int num_H=0, num_eH=0, num_nH=0 /* = num_iso_H[0] */;
1959
+ const double one_pi = 2.0*atan2(1.0 /* y */, 0.0 /* x */);
1960
+ const double two_pi = 2.0*one_pi;
1961
+ AT_NUM nSbNeighOrigAtNumb[MAX_NUM_STEREO_BOND_NEIGH];
1962
+ int bAmbiguousStereo = 0;
1963
+ S_CHAR num_iso_eH[NUM_H_ISOTOPES+1]; /* count explicit H */
1964
+
1965
+ if ( z_dir && !z_dir[0] && !z_dir[1] && !z_dir[2] ) {
1966
+ z_dir[2]=100;
1967
+ }
1968
+ /* *bOnlyNonMetal = 0; */
1969
+ if ( at[cur_at].num_bonds > MAX_NUM_STEREO_BOND_NEIGH || *bOnlyNonMetal ) {
1970
+ int i_ord_LastMetal;
1971
+ int nNumNonMetal = e_nNumNonMetalNeigh( at, cur_at, pStereo, &i_ord_LastMetal );
1972
+ if ( nNumNonMetal <= MAX_NUM_STEREO_BOND_NEIGH ) {
1973
+ *bOnlyNonMetal = 1;
1974
+ if ( 1 == nNumNonMetal ) {
1975
+ return bond_parity; /* INCHI_PARITY_UNDEFINED */
1976
+ }
1977
+ if ( 0 == nNumNonMetal ) {
1978
+ return INCHI_PARITY_NONE;
1979
+ }
1980
+ } else {
1981
+ return INCHI_PARITY_NONE;
1982
+ }
1983
+ }
1984
+ memset(num_iso_eH, 0, sizeof(num_iso_eH));
1985
+ for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
1986
+ next = at[cur_at].neighbor[j];
1987
+ switch( pStereo->cAtType[next] ) {
1988
+ case AtType_TermH:
1989
+ if ( 0 <= at[next].isotopic_mass && at[next].isotopic_mass <= NUM_H_ISOTOPES ) {
1990
+ num_iso_eH[at[next].isotopic_mass] ++;
1991
+ } else {
1992
+ num_iso_eH[0] ++;
1993
+ }
1994
+ num_eH ++;
1995
+ break;
1996
+ case AtType_TermD:
1997
+ num_iso_eH[2] ++;
1998
+ num_eH ++;
1999
+ break;
2000
+ case AtType_TermT:
2001
+ num_iso_eH[3] ++;
2002
+ num_eH ++;
2003
+ break;
2004
+ }
2005
+ }
2006
+
2007
+
2008
+ num_H = inchi_NUMH2(at,cur_at) + num_eH;
2009
+ if ( num_H > NUM_H_ISOTOPES )
2010
+ return 0; /* at least 2 H atoms are isotopically identical */
2011
+
2012
+ for ( j = 0, num_nH = num_H; j < NUM_H_ISOTOPES; j ++ ) {
2013
+ if ( (k = (int)at[cur_at].num_iso_H[j+1]+(int)num_iso_eH[j+1]) > 1 ) {
2014
+ return INCHI_PARITY_NONE; /* two or more identical isotopic H atoms */
2015
+ }
2016
+ num_nH -= k;
2017
+ }
2018
+ /* at this point num_nH = number of non-isotopic H atoms */
2019
+ if ( num_nH > 1 )
2020
+ return INCHI_PARITY_NONE; /* two or more identical non-isotopic H atoms */
2021
+ if ( num_nH < 0 )
2022
+ return CT_ISO_H_ERR; /* program error */ /* <BRKPT> */
2023
+
2024
+ /********************************************************************
2025
+ * Note. At this point all (implicit and explicit) isotopic
2026
+ * terminal H neighbors are either different or not present.
2027
+ ********************************************************************/
2028
+
2029
+ /* store neighbors coordinates */
2030
+ num_z = num_either_single = num_either_double = 0;
2031
+ nNumExplictAttachments = 0;
2032
+ for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
2033
+ next = at[cur_at].neighbor[j];
2034
+ if ( *bOnlyNonMetal && IS_METAL(pStereo->cAtType[next]) )
2035
+ continue;
2036
+ at_coord[nNumExplictAttachments][0] = at[next].x - at[cur_at].x;
2037
+ at_coord[nNumExplictAttachments][1] = at[next].y - at[cur_at].y;
2038
+ nSbNeighOrigAtNumb[nNumExplictAttachments] = next;
2039
+
2040
+ z = e_get_z_coord( at, cur_at, j /*neighbor #*/, &nType, bPointedEdgeStereo );
2041
+ switch ( nType ) {
2042
+ case ZTYPE_EITHER:
2043
+ num_either_single ++; /* bond in "Either" direction. */
2044
+ break;
2045
+ case ZTYPE_UP:
2046
+ case ZTYPE_DOWN:
2047
+ z = e_len2( at_coord[nNumExplictAttachments] );
2048
+ /*
2049
+ z = sqrt( at_coord[nNumExplictAttachments][0]*at_coord[nNumExplictAttachments][0]
2050
+ + at_coord[nNumExplictAttachments][1]*at_coord[nNumExplictAttachments][1] );
2051
+ */
2052
+ if ( nType == ZTYPE_DOWN )
2053
+ z = -z;
2054
+ /* no break; here */
2055
+ case ZTYPE_3D:
2056
+ num_z ++;
2057
+ }
2058
+ at_coord[nNumExplictAttachments][2] = z;
2059
+ nNumExplictAttachments ++;
2060
+ }
2061
+
2062
+ if ( num_either_single ) {
2063
+ bond_parity = INCHI_PARITY_UNKNOWN; /* single bond is 'unknown' */
2064
+ goto exit_function;
2065
+ }
2066
+
2067
+ /* nNumExplictAttachments is a total number of attachments */
2068
+ if ( nNumExplictAttachments == 2 ) {
2069
+ /* create coordinates of the implicit hydrogen (or a fictitious atom in case of ==N-X ), */
2070
+ /* coord[2][], attached to the cur_at. */
2071
+ for ( j = 0; j < 3; j ++ ) {
2072
+ at_coord[2][j] = - ( at_coord[0][j] + at_coord[1][j] );
2073
+ }
2074
+ nSbNeighOrigAtNumb[nNumExplictAttachments] = -1; /* implicit H or lone pair */
2075
+ }
2076
+ for ( j = 0; j < 3; j ++ ) {
2077
+ tmp[j] = e_len3( at_coord[j] );
2078
+ }
2079
+ min_tmp = inchi_min( tmp[0], inchi_min(tmp[1], tmp[2]) );
2080
+ max_tmp = inchi_max( tmp[0], inchi_max(tmp[1], tmp[2]) );
2081
+ if ( min_tmp < MIN_BOND_LEN || min_tmp < MIN_SINE*max_tmp ) {
2082
+ /* all bonds or some of bonds are too short */
2083
+ goto exit_function;
2084
+ }
2085
+ /* normalize lengths to 1 */
2086
+ for ( j = 0; j < 3; j ++ ) {
2087
+ e_mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
2088
+ }
2089
+
2090
+ /* find projections of at_coord vector differences on the plane containing their arrowhead ends */
2091
+ for ( j = 0; j < 3; j ++ ) {
2092
+ /* pnt[0..2] = {0-1, 1-2, 2-0} */
2093
+ tmp[j] = e_len3(e_diff3( at_coord[j], at_coord[(j+1)%3], pnt[j] ));
2094
+ if ( tmp[j] < MIN_SINE ) {
2095
+ goto exit_function; /* angle #i-cur_at-#j is too small */
2096
+ }
2097
+ e_mult3( pnt[j], 1.0/tmp[j], pnt[j] ); /* 2003-10-06 */
2098
+ }
2099
+ /* find pnt[p2], a vector perpendicular to the plane, and its length tmp[p2] */
2100
+ /* replace previous pnt[p2], tmp[p2] with new values; the old values do not have any additional */
2101
+ /* information because pnt[p0]+pnt[p1]+pnt[p2]=0 */
2102
+ /* 10-6-2003: a cross-product of one pair pnt[j], pnt[(j+1)%3] can be very small. Find the larges one */
2103
+ tmp1 = e_len3( e_cross_prod3( pnt[0], pnt[1], temp ) );
2104
+ for (j = 1, k = 0; j < 3; j ++ ) {
2105
+ tmp2 = e_len3( e_cross_prod3( pnt[j], pnt[(j+1)%3], temp ) );
2106
+ if ( tmp2 > tmp1 ) {
2107
+ tmp1 = tmp2;
2108
+ k = j;
2109
+ }
2110
+ }
2111
+ /* previously p0=0, p1=1, p2=2 */
2112
+ p0 = k;
2113
+ p1 = (k+1)%3;
2114
+ p2 = (k+2)%3;
2115
+ tmp[p2] = e_len3( e_cross_prod3( pnt[p0], pnt[p1], pnt[p2] ) );
2116
+ if ( tmp[p2] < MIN_SINE*tmp[p0]*tmp[p1] ) {
2117
+ goto exit_function; /* pnt[p0] is almost colinear to pnt[p1] */
2118
+ }
2119
+ /* new basis: pnt[p0], pnt[p1], pnt[p2]; set z-coord sign and make abs(pnt[p2]) = 1 */
2120
+ e_mult3( pnt[p2], (pnt[p2][2]>0.0? 1.0:-1.0)/tmp[p2], pnt[p2] ); /* unit vector in the new z-axis direction */
2121
+
2122
+ min_tmp = e_dot_prod3( at_coord[0], pnt[p2] ); /* non-planarity measure (sine): hight of at_coord[] pyramid */
2123
+ e_mult3( pnt[p2], min_tmp, pnt[p0] ); /* vector height of the pyramid, ideally 0 */
2124
+ /* find new pnt[p0] = projection of at_coord[p0] on plane orthogonal to pnt[p2] */
2125
+ tmp[p0] = e_len3(e_diff3( at_coord[0], pnt[p0], pnt[p0] ));
2126
+ e_mult3( pnt[p0], 1.0/tmp[p0], pnt[p0] ); /* new x axis basis vector */
2127
+ e_cross_prod3( pnt[p2], pnt[p0], pnt[p1] ); /* new y axis basis vector */
2128
+ /* find at_coord in the new basis of {pnt[p0], pnt[p1], pnt[p2]} */
2129
+ for ( j = 0; j < 3; j ++ ) {
2130
+ e_copy3( at_coord[j], temp );
2131
+ for ( k = 0; k < 3; k ++ ) {
2132
+ at_coord[j][k] = e_dot_prod3( temp, pnt[(k+p0)%3] );
2133
+ }
2134
+ /* new xy plane projection length */
2135
+ tmp[j] = sqrt(at_coord[j][0]*at_coord[j][0] + at_coord[j][1]*at_coord[j][1]);
2136
+ /* make new xy plane projection length = 1 */
2137
+ e_mult3( at_coord[j], 1.0/tmp[j], at_coord[j] );
2138
+ }
2139
+
2140
+ s = fabs( at_coord[1][0]*at_coord[2][1] - at_coord[1][1]*at_coord[2][0] ); /* 1-2 sine */
2141
+ c = at_coord[1][0]*at_coord[2][0] + at_coord[1][1]*at_coord[2][1]; /* 1-2 cosine */
2142
+ if ( s < MIN_SINE && c > 0.5 ) {
2143
+ goto exit_function; /* bonds to neigh. 1 and 2 have almost same direction; relative angles are undefined */
2144
+ }
2145
+ c = at_coord[0][0]; /* cosine of the angle between new Ox axis and a bond to the neighbor 0. Should be 1 */
2146
+ s = at_coord[0][1]; /* sine. Should be 0 */
2147
+ /* turn vectors so that vector #1 (at_coord[0]) becomes {1, 0} */
2148
+ for ( j = 0; j < MAX_NUM_STEREO_BOND_NEIGH; j ++ ) {
2149
+ tmp1 = c*at_coord[j][0] + s*at_coord[j][1];
2150
+ tmp2 = -s*at_coord[j][0] + c*at_coord[j][1];
2151
+ at_coord[j][0] = tmp1;
2152
+ at_coord[j][1] = tmp2;
2153
+ }
2154
+ /* counterclockwise angles from the direction to neigh 0 to to directions to neighbors 1 and 2: */
2155
+ tmp1 = atan2( at_coord[1][1], at_coord[1][0] ); /* range -pi and +pi */
2156
+ tmp2 = atan2( at_coord[2][1], at_coord[2][0] );
2157
+ if ( tmp1 < 0.0 )
2158
+ tmp1 += two_pi; /* range 0 to 2*pi */
2159
+ if ( tmp2 < 0.0 )
2160
+ tmp2 += two_pi;
2161
+ /*-----------------------------------
2162
+ Example
2163
+ 1 \ case tmp1 < tmp2
2164
+ \ parity is odd
2165
+ \ (counterclockwise)
2166
+ A------- 0
2167
+ /
2168
+ /
2169
+ 2 /
2170
+
2171
+ ------------------------------------*/
2172
+ bond_parity = 2 - ( tmp1 < tmp2 );
2173
+ for ( j = 0; j < 3; j ++ ) {
2174
+ z_dir[j] = (S_CHAR)(pnt[p2][j]>= 0.0? floor(0.5 + 100.0 * pnt[p2][j]) :
2175
+ -floor(0.5 - 100.0 * pnt[p2][j])); /* abs(z_dir) = 100 */
2176
+ }
2177
+ /* check for ambiguity */
2178
+ if ( nNumExplictAttachments > 2 ) {
2179
+ min_tmp = inchi_min( tmp1, tmp2 );
2180
+ max_tmp = inchi_max( tmp1, tmp2 );
2181
+ if ( min_tmp > one_pi-MIN_SINE || max_tmp < one_pi+MIN_SINE || max_tmp-min_tmp > one_pi - MIN_SINE ) {
2182
+ bAmbiguousStereo |= AMBIGUOUS_STEREO;
2183
+ } else /* 3D ambiguity 8-28-2002 */
2184
+ if ( fabs(at_coord[0][2]) > MAX_SINE ) { /* all fabs(at_coord[j][2] (j=0..2) must be equal */
2185
+ bAmbiguousStereo |= AMBIGUOUS_STEREO;
2186
+ }
2187
+ } else
2188
+ if ( nNumExplictAttachments == 2 ) { /* 10-6-2003: added */
2189
+ min_tmp = fabs(tmp1 - one_pi);
2190
+ if ( min_tmp < MIN_SINE ) {
2191
+ bond_parity = INCHI_PARITY_UNDEFINED; /* consider as undefined 10-6-2003 */
2192
+ } else
2193
+ if ( min_tmp < MIN_ANGLE_DBOND ) {
2194
+ bAmbiguousStereo |= AMBIGUOUS_STEREO;
2195
+ }
2196
+ }
2197
+
2198
+ /* for 3 neighbors moving implicit H to the index=0 from index=2 position */
2199
+ /* can be done in 2 transpositions and does not change atom's parity */
2200
+
2201
+ exit_function:
2202
+ return bond_parity;
2203
+ }
2204
+
2205
+ #define MAX_ALLENE_LEN 20
2206
+ /*************************************************************/
2207
+ int e_set_stereo_bonds_parity( Stereo0D *pStereo, inchi_Atom *at, int at_1, int bPointedEdgeStereo )
2208
+ {
2209
+ int j, k, next_at_1, i_next_at_1, i_next_at_2, at_2, next_at_2, num_stereo_bonds, bFound, bAllene;
2210
+ int bond_type, num_2s_1, num_alt_1, bNxtStereobond, bCurStereobond, bNxtCumulene;
2211
+ int num_stored_stereo_bonds, num_stored_isotopic_stereo_bonds;
2212
+ int chain_length, num_chains, cur_chain_length;
2213
+ int all_at_2[MAX_NUM_STEREO_BONDS];
2214
+ int all_pos_1[MAX_NUM_STEREO_BONDS], all_pos_2[MAX_NUM_STEREO_BONDS];
2215
+ S_CHAR all_unkn[MAX_NUM_STEREO_BONDS], all_chain_len[MAX_NUM_STEREO_BONDS];
2216
+ int all_middle_at[MAX_NUM_STEREO_BONDS];
2217
+ AT_NUM chain_atoms[MAX_ALLENE_LEN], at_middle;
2218
+ int nUnknown;
2219
+ int bOnlyNM1, bOnlyNM2;
2220
+
2221
+ bCurStereobond = e_bCanAtomHaveAStereoBond( at, at_1, pStereo->cAtType );
2222
+ if ( !bCurStereobond )
2223
+ return 0;
2224
+
2225
+ /* count bonds and find the second atom on the stereo bond */
2226
+ num_2s_1 = num_alt_1 = 0;
2227
+ chain_length = 0;
2228
+ num_chains = 0;
2229
+ for ( i_next_at_1 = 0, num_stereo_bonds = 0; i_next_at_1 < at[at_1].num_bonds; i_next_at_1 ++ ) {
2230
+
2231
+ at_2 = next_at_1 = at[at_1].neighbor[i_next_at_1];
2232
+ bond_type = at[at_1].bond_type[i_next_at_1];
2233
+ nUnknown = (at[at_1].bond_stereo[i_next_at_1] == INCHI_PARITY_UNKNOWN);
2234
+ next_at_2 = at_1;
2235
+
2236
+ bNxtStereobond = e_bCanAtomHaveAStereoBond( at, at_2, pStereo->cAtType );
2237
+ bNxtCumulene = 0;
2238
+ cur_chain_length = 0;
2239
+
2240
+ if ( bNxtStereobond + bCurStereobond > 3 ) {
2241
+ /* this includes single (ring) bonds in -NH-CH=N(+)< that may be deprotonated to -N=C-N< */
2242
+ if ( bond_type == INCHI_BOND_TYPE_TRIPLE ) {
2243
+ continue;
2244
+ }
2245
+ /* possibly stereogenic bond */
2246
+ } else {
2247
+ bNxtCumulene =
2248
+ e_bCanAtomBeMiddleAllene(at_2, pStereo->cAtType ) &&
2249
+ e_bCanAtomBeTerminalAllene( at_1, pStereo->cAtType );
2250
+ if ( !bNxtCumulene ) {
2251
+ continue;
2252
+ }
2253
+ if ( bond_type != INCHI_BOND_TYPE_DOUBLE ) {
2254
+ continue;
2255
+ }
2256
+ /* possibly allene or cumulenr */
2257
+ chain_atoms[cur_chain_length] = at_1;
2258
+ chain_atoms[cur_chain_length+1] = at_2;
2259
+
2260
+ /*
2261
+ * Example of cumulene
2262
+ * chain length = 2: >X=C=C=Y<
2263
+ * | | | |
2264
+ * 1st cumulene atom= at_1 | | at_2 =last cumlene chain atom
2265
+ * next to at_1= next_at_1 next_at_2 =previous to at_2
2266
+ *
2267
+ * chain length odd: stereocenter on the middle atom ( 1=> allene )
2268
+ * chain length even: "long stereogenic bond"
2269
+ */
2270
+ while ( cur_chain_length < MAX_ALLENE_LEN-3 &&
2271
+ (bAllene =
2272
+ e_bCanAtomBeMiddleAllene( at_2, pStereo->cAtType ))) {
2273
+ k = ((int)at[at_2].neighbor[0]==next_at_2); /* opposite neighbor position */
2274
+ next_at_2 = at_2;
2275
+ nUnknown += (at[at_2].bond_stereo[k] == INCHI_BOND_STEREO_DOUBLE_EITHER);
2276
+ at_2 = (int)at[at_2].neighbor[k];
2277
+ cur_chain_length ++; /* count =C= atoms */
2278
+ chain_atoms[cur_chain_length+1] = at_2;
2279
+ }
2280
+ if ( cur_chain_length ) {
2281
+ if ( bAllene /* at the end of the chain atom Y is =Y=, not =Y< or =Y- */ ||
2282
+ !e_bCanAtomBeTerminalAllene( at_2, pStereo->cAtType)) {
2283
+ cur_chain_length = 0;
2284
+ continue; /* ignore: does not fit cumulene description; go to check next at_1 neighbor */
2285
+ }
2286
+ }
2287
+ if ( !cur_chain_length &&
2288
+ !e_bCanAtomHaveAStereoBond( at, at_2, pStereo->cAtType ) ) {
2289
+ continue; /* reject non-stereogenic bond to neighbor #i_next_at_1 */
2290
+ }
2291
+ }
2292
+
2293
+ /* check atom at the opposite end of possibly stereogenic bond */
2294
+
2295
+ bFound = ( at_1 > at_2 ); /* i_next_at_1 = at_1 stereogenic bond neighbor attachment number */
2296
+
2297
+ if ( bFound ) {
2298
+ i_next_at_2 = -1; /* unassigned mark */
2299
+ for ( j = 0; j < at[at_2].num_bonds; j ++ ) {
2300
+ if ( (int)at[at_2].neighbor[j] == next_at_2 ) {
2301
+ i_next_at_2 = j; /* assigned */
2302
+ break;
2303
+ }
2304
+ }
2305
+ if ( i_next_at_2 < 0 ) {
2306
+ continue;
2307
+ }
2308
+ /* store the results */
2309
+ all_pos_1[num_stereo_bonds] = i_next_at_1; /* neighbor to at_1 position */
2310
+ all_pos_2[num_stereo_bonds] = i_next_at_2; /* neighbor to at_2 position */
2311
+ all_at_2[num_stereo_bonds] = at_2; /* at_2 */
2312
+ all_unkn[num_stereo_bonds] = nUnknown; /* stereogenic bond has Unknown configuration */
2313
+ /* allene/cumulene stuff */
2314
+ all_chain_len[num_stereo_bonds] = cur_chain_length;
2315
+ all_middle_at[num_stereo_bonds] = (cur_chain_length%2)? chain_atoms[(cur_chain_length+1)/2] : -1;
2316
+ num_stereo_bonds ++;
2317
+ }
2318
+ }
2319
+ if ( !num_stereo_bonds || num_stereo_bonds > 3 /*|| num_chains > 1*/ ) {
2320
+ return 0; /* At the end, we cannot be more than 1 cumulene chain. */
2321
+ }
2322
+
2323
+ /* ================== calculate parities ====================== */
2324
+ /* find possibly stereo bonds and save them */
2325
+ num_stored_isotopic_stereo_bonds = 0;
2326
+ num_stored_stereo_bonds = 0;
2327
+ for ( k = 0; k < num_stereo_bonds; k ++ ) {
2328
+ /* NM stands for non-metal */
2329
+ int parity_at_1, parity_at_2, parity_at_1NM=0, parity_at_2NM=0, bOnlyNM;
2330
+ S_CHAR z_dir1[3], z_dir2[3], z_dir1NM[3], z_dir2NM[3]; /* 3D vectors for half stereo bond parity direction */
2331
+ int i_ord_LastMetal1, i_ord_LastMetal2, bAnomaly1NM, bAnomaly2NM;
2332
+
2333
+ at_2 = all_at_2[k];
2334
+ i_next_at_1 = all_pos_1[k];
2335
+ i_next_at_2 = all_pos_2[k];
2336
+ nUnknown = all_unkn[k];
2337
+ at_middle = all_middle_at[k];
2338
+ cur_chain_length = all_chain_len[k];
2339
+ memset(z_dir1, 0, sizeof(z_dir1));
2340
+ memset(z_dir2, 0, sizeof(z_dir2));
2341
+ memset(z_dir1NM, 0, sizeof(z_dir1NM));
2342
+ memset(z_dir2NM, 0, sizeof(z_dir2NM));
2343
+ bOnlyNM1 = bOnlyNM2 = 0;
2344
+ bAnomaly1NM = bAnomaly2NM = 0;
2345
+ i_ord_LastMetal1 = i_ord_LastMetal2 = -1;
2346
+
2347
+ if ( nUnknown ) {
2348
+ parity_at_1 = parity_at_2 = parity_at_1NM = parity_at_2NM = INCHI_PARITY_UNKNOWN;
2349
+ } else {
2350
+ /***********************************************************************
2351
+ *
2352
+ * Obtain each atom parity from the geometry
2353
+ *
2354
+ * Warning: case when dot-product
2355
+ * (z_dir1,z_dir1NM) < 0 or (z_dir2,z_dir2NM) < 0
2356
+ * is not treated proprly.
2357
+ * This case may happen especially when z_dir?[3] << 100
2358
+ *
2359
+ ***********************************************************************/
2360
+
2361
+ parity_at_1 = e_half_stereo_bond_parity( at, at_1, z_dir1, &bOnlyNM1, bPointedEdgeStereo, pStereo );
2362
+ parity_at_2 = e_half_stereo_bond_parity( at, at_2, z_dir2, &bOnlyNM2, bPointedEdgeStereo, pStereo );
2363
+
2364
+ if ( RETURNED_ERROR(parity_at_1) || RETURNED_ERROR(parity_at_2) ) {
2365
+ return CT_CALC_STEREO_ERR;
2366
+ }
2367
+ parity_at_1 = abs(parity_at_1);
2368
+ parity_at_2 = abs(parity_at_2);
2369
+ /* bond parities for the disconnected structure */
2370
+ if ( bOnlyNM1 ) {
2371
+ parity_at_1NM = parity_at_1;
2372
+ memcpy( z_dir1NM, z_dir1, sizeof(z_dir1NM) );
2373
+ parity_at_1 = INCHI_PARITY_NONE;
2374
+ } else
2375
+ if ( at[at_1].num_bonds == e_nNumNonMetalNeigh( at, at_1, pStereo, &i_ord_LastMetal1 ) ) {
2376
+ parity_at_1NM = parity_at_1; /* no metal bond present */
2377
+ memcpy( z_dir1NM, z_dir1, sizeof(z_dir1NM) );
2378
+ } else {
2379
+ bOnlyNM = 1; /* at_1 has a metal neighbor; in adjacency list
2380
+ it is located in (zero-based) position i_ord_LastMetal1 */
2381
+ parity_at_1NM = e_half_stereo_bond_parity( at, at_1, z_dir1NM, &bOnlyNM,
2382
+ bPointedEdgeStereo, pStereo );
2383
+ if ( RETURNED_ERROR(parity_at_1NM) ) {
2384
+ return CT_CALC_STEREO_ERR;
2385
+ }
2386
+ parity_at_1NM = abs(parity_at_1NM);
2387
+ /*
2388
+ if ( ATOM_PARITY_WELL_DEF(parity_at_1NM) && !ATOM_PARITY_WELL_DEF(parity_at_1) ) {
2389
+ memcpy( z_dir1, z_dir1NM, sizeof(z_dir1) );
2390
+ }
2391
+ */
2392
+ if ( ATOM_PARITY_WELL_DEF(parity_at_1NM) && ATOM_PARITY_WELL_DEF(parity_at_1) &&
2393
+ 0 <= i_ord_LastMetal1 ) {
2394
+ if ( 1 == i_ord_LastMetal1 % 2 && parity_at_1NM == parity_at_1 ||
2395
+ 0 == i_ord_LastMetal1 % 2 && parity_at_1NM != parity_at_1 ) {
2396
+ /* abnormal geometry: all bonds in a sector < 180 degrees */
2397
+ /*parity_at_1NM = 3 - parity_at_1;*/
2398
+ bAnomaly1NM = 1;
2399
+ } else {
2400
+ parity_at_1 = parity_at_1NM;
2401
+ bOnlyNM1 = 1;
2402
+ }
2403
+ } else
2404
+ if ( ATOM_PARITY_WELL_DEF(parity_at_1NM) && !ATOM_PARITY_WELL_DEF(parity_at_1) &&
2405
+ 0 <= i_ord_LastMetal1 ) {
2406
+ bAnomaly1NM = 1; /* 2005-02-01 force atom parity from non-metal neighbors */
2407
+ }
2408
+
2409
+ }
2410
+
2411
+ if ( bOnlyNM2 ) {
2412
+ parity_at_2NM = parity_at_2;
2413
+ memcpy( z_dir2NM, z_dir2, sizeof(z_dir2NM) );
2414
+ parity_at_2 = INCHI_PARITY_NONE;
2415
+ } else
2416
+ if ( at[at_2].num_bonds == e_nNumNonMetalNeigh( at, at_2, pStereo, &i_ord_LastMetal2 ) ) {
2417
+ memcpy( z_dir2NM, z_dir2, sizeof(z_dir2NM) );
2418
+ parity_at_2NM = parity_at_2; /* no metal bond present */
2419
+ } else {
2420
+ bOnlyNM = 1;
2421
+ parity_at_2NM = e_half_stereo_bond_parity( at, at_2, z_dir2NM, &bOnlyNM,
2422
+ bPointedEdgeStereo, pStereo );
2423
+ if ( RETURNED_ERROR(parity_at_2NM) ) {
2424
+ return CT_CALC_STEREO_ERR;
2425
+ }
2426
+ parity_at_2NM = abs(parity_at_2NM);
2427
+ if ( ATOM_PARITY_WELL_DEF(parity_at_2NM) && ATOM_PARITY_WELL_DEF(parity_at_2) &&
2428
+ 0 <= i_ord_LastMetal2 ) {
2429
+ if ( 1 == i_ord_LastMetal2 % 2 && parity_at_2NM == parity_at_2 ||
2430
+ 0 == i_ord_LastMetal2 % 2 && parity_at_2NM != parity_at_2 ) {
2431
+ /* abnormal geometry: all bonds in a sector < 180 degrees */
2432
+ /*parity_at_2NM = 3 - parity_at_2;*/
2433
+ bAnomaly2NM = 1;
2434
+ } else {
2435
+ parity_at_2 = parity_at_2NM;
2436
+ bOnlyNM2 = 1;
2437
+ }
2438
+ } else
2439
+ if ( ATOM_PARITY_WELL_DEF(parity_at_2NM) && !ATOM_PARITY_WELL_DEF(parity_at_2) &&
2440
+ 0 <= i_ord_LastMetal2 ) {
2441
+ bAnomaly2NM = 1; /* 2005-02-01 force atom parity from non-metal neighbors */
2442
+ }
2443
+ }
2444
+ /* make both atoms have non-metal neighbors only */
2445
+ if ( (bOnlyNM1 || bAnomaly1NM) && ATOM_PARITY_WELL_DEF(parity_at_1NM) &&
2446
+ !(bOnlyNM2 || bAnomaly2NM) && ATOM_PARITY_WELL_DEF(parity_at_2NM) &&
2447
+ 0 <= i_ord_LastMetal2 ) {
2448
+
2449
+ bAnomaly2NM = 1;
2450
+ parity_at_2NM = 2 - (parity_at_2NM + i_ord_LastMetal2) % 2;
2451
+ } else
2452
+ if ( !(bOnlyNM1 || bAnomaly1NM) && ATOM_PARITY_WELL_DEF(parity_at_1NM) &&
2453
+ (bOnlyNM2 || bAnomaly2NM) && ATOM_PARITY_WELL_DEF(parity_at_2NM) &&
2454
+ 0 <= i_ord_LastMetal1 ) {
2455
+
2456
+ bAnomaly1NM = 1;
2457
+ parity_at_1NM = 2 - (parity_at_1NM + i_ord_LastMetal1) % 2;
2458
+ }
2459
+
2460
+ /* consistency */
2461
+ if ( parity_at_1 == INCHI_PARITY_NONE || parity_at_2 == INCHI_PARITY_NONE ) {
2462
+ parity_at_1 = parity_at_2 = INCHI_PARITY_NONE; /* =zero */
2463
+ } else {
2464
+ switch( !ATOM_PARITY_WELL_DEF( parity_at_1 ) + 2*!ATOM_PARITY_WELL_DEF( parity_at_2 ) ) {
2465
+ case 1:
2466
+ parity_at_2 = parity_at_1; /* set both to not-well-def */
2467
+ break;
2468
+ case 2:
2469
+ parity_at_1 = parity_at_2; /* set both to not-well-def */
2470
+ break;
2471
+ case 3:
2472
+ parity_at_1 = parity_at_2 = inchi_min(parity_at_1, parity_at_2);
2473
+ break;
2474
+ }
2475
+ }
2476
+
2477
+ if ( parity_at_1NM == INCHI_PARITY_NONE || parity_at_2NM == INCHI_PARITY_NONE ) {
2478
+ parity_at_1NM = parity_at_2NM = INCHI_PARITY_NONE; /* =zero */
2479
+ } else {
2480
+ switch( !ATOM_PARITY_WELL_DEF( parity_at_1NM ) + 2*!ATOM_PARITY_WELL_DEF( parity_at_2NM ) ) {
2481
+ case 1:
2482
+ parity_at_2NM = parity_at_1NM; /* set both to not-well-def */
2483
+ break;
2484
+ case 2:
2485
+ parity_at_1NM = parity_at_2NM; /* set both to not-well-def */
2486
+ break;
2487
+ case 3:
2488
+ parity_at_1NM = parity_at_2NM = inchi_min(parity_at_1NM, parity_at_2NM);
2489
+ break;
2490
+ }
2491
+ }
2492
+ if ( parity_at_1 != INCHI_PARITY_NONE && parity_at_1NM == INCHI_PARITY_NONE ) {
2493
+ parity_at_1NM = parity_at_2NM = INCHI_PARITY_UNDEFINED;
2494
+ } else
2495
+ if ( parity_at_1 == INCHI_PARITY_NONE && parity_at_1NM != INCHI_PARITY_NONE ) {
2496
+ parity_at_1 = parity_at_2 = INCHI_PARITY_UNDEFINED;
2497
+ }
2498
+
2499
+
2500
+
2501
+ if ( (parity_at_1 == INCHI_PARITY_UNDEFINED || parity_at_1 == INCHI_PARITY_NONE) &&
2502
+ (parity_at_1NM == INCHI_PARITY_UNDEFINED || parity_at_1NM == INCHI_PARITY_NONE) ) {
2503
+ continue;
2504
+ }
2505
+ }
2506
+ parity_at_1 = e_FixSb0DParities( at, pStereo, cur_chain_length, at_middle,
2507
+ at_1, i_next_at_1, z_dir1, z_dir1NM, bOnlyNM1, bAnomaly1NM, parity_at_1, parity_at_1NM,
2508
+ at_2, i_next_at_2, z_dir2, z_dir2NM, bOnlyNM2, bAnomaly2NM, parity_at_2, parity_at_2NM);
2509
+ num_stored_stereo_bonds += (parity_at_1 != 0);
2510
+
2511
+ }
2512
+ return num_stored_stereo_bonds;
2513
+ }
2514
+
2515
+
2516
+ /***************************************************************
2517
+ * Get stereo atom parity for the current order of attachments
2518
+ * The result in at[cur_at].parity is valid for previously removed
2519
+ * explicit hydrogen atoms, including isotopic ones, that are located in at_removed_H[]
2520
+ * The return value is a calculated parity.
2521
+ */
2522
+ #define ADD_EXPLICIT_HYDROGEN_NEIGH 1
2523
+ #define ADD_EXPLICIT_LONE_PAIR_NEIGH 2
2524
+ int e_set_stereo_atom_parity( Stereo0D *pStereo, inchi_Atom *at, int cur_at, int bPointedEdgeStereo )
2525
+ {
2526
+ int j, k, next_at, num_z, j1, nType, num_eH, num_iH, tot_num_iso_H, nMustHaveNumNeigh, bAmbiguousStereo;
2527
+ double z, sum_xyz[3], min_sine, triple_product;
2528
+ double at_coord[MAX_NUM_STEREO_ATOM_NEIGH][3];
2529
+ double bond_len_xy[4], rmax, rmin;
2530
+ double at_coord_center[3];
2531
+ int parity, out_parity, out_stereo_atom_parity, bAmbiguous = 0, bAddExplicitNeighbor = 0;
2532
+ int b2D = 0, n2DTetrahedralAmbiguity = 0;
2533
+ AT_NUM nSbNeighOrigAtNumb[MAX_NUM_STEREO_ATOM_NEIGH];
2534
+ S_CHAR num_iso_eH[NUM_H_ISOTOPES+1]; /* count explicit H */
2535
+
2536
+ out_parity = out_stereo_atom_parity = INCHI_PARITY_NONE;
2537
+ parity = INCHI_PARITY_NONE;
2538
+ bAmbiguousStereo = 0;
2539
+ memset(num_iso_eH, 0, sizeof(num_iso_eH));
2540
+ num_eH = 0; /* number of explicit H -- will be found later */
2541
+ num_iH = inchi_NUMH2(at,cur_at); /* implicit H */
2542
+
2543
+ if ( !(nMustHaveNumNeigh = e_bCanInpAtomBeAStereoCenter( cur_at, pStereo->cAtType ) ) ||
2544
+ num_iH > NUM_H_ISOTOPES
2545
+ ) {
2546
+ goto exit_function;
2547
+ }
2548
+ /* find explicit terminal H */
2549
+ memset(num_iso_eH, 0, sizeof(num_iso_eH));
2550
+ for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
2551
+ next_at = at[cur_at].neighbor[j];
2552
+ switch(pStereo->cAtType[next_at] ) {
2553
+ case AtType_TermH:
2554
+ if ( 0 <= at[next_at].isotopic_mass && at[next_at].isotopic_mass <= NUM_H_ISOTOPES ) {
2555
+ num_iso_eH[at[next_at].isotopic_mass] ++;
2556
+ } else {
2557
+ num_iso_eH[0] ++;
2558
+ }
2559
+ num_eH ++;
2560
+ break;
2561
+ case AtType_TermD:
2562
+ num_iso_eH[2] ++;
2563
+ num_eH ++;
2564
+ break;
2565
+ case AtType_TermT:
2566
+ num_iso_eH[3] ++;
2567
+ num_eH ++;
2568
+ break;
2569
+ }
2570
+ }
2571
+
2572
+ /* numbers of isotopic H atoms */
2573
+ for ( j = 0, tot_num_iso_H = 0; j < NUM_H_ISOTOPES; j ++ ) {
2574
+ if ( at[cur_at].num_iso_H[j+1] + num_iso_eH[j+1] > 1 ) {
2575
+ goto exit_function; /* two or more identical hydrogen isotopic neighbors */
2576
+ }
2577
+ tot_num_iso_H += at[cur_at].num_iso_H[j+1] + num_iso_eH[j+1];
2578
+ }
2579
+
2580
+ /* number of non-isotopic H atoms */
2581
+ if ( inchi_NUMH2(at,cur_at) + num_eH - tot_num_iso_H > 1 ) {
2582
+ goto exit_function; /* two or more identical hydrogen non-isotopic neighbors */
2583
+ }
2584
+
2585
+ /* coordinates initialization */
2586
+ num_z = 0;
2587
+ sum_xyz[0] = sum_xyz[1] = sum_xyz[2] = 0.0;
2588
+
2589
+ at_coord_center[0] =
2590
+ at_coord_center[1] =
2591
+ at_coord_center[2] = 0.0;
2592
+
2593
+ /* fill out stereo center neighbors coordinates */
2594
+ /* and obtain the parity from the geometry */
2595
+
2596
+ /* add all coordinates of other neighboring atoms */
2597
+ for ( j = j1 = 0; j < at[cur_at].num_bonds; j ++, j1 ++ ) {
2598
+ next_at = at[cur_at].neighbor[j];
2599
+ z = e_get_z_coord( at, cur_at, j, &nType, bPointedEdgeStereo );
2600
+ switch ( nType ) {
2601
+ case ZTYPE_EITHER:
2602
+ parity = INCHI_PARITY_UNKNOWN; /* unknown parity: bond in "Either" direction. */
2603
+ goto exit_function;
2604
+ case ZTYPE_UP:
2605
+ case ZTYPE_DOWN:
2606
+ b2D ++;
2607
+ case ZTYPE_3D:
2608
+ num_z ++;
2609
+ }
2610
+
2611
+ nSbNeighOrigAtNumb[j1] = next_at+1;
2612
+ at_coord[j1][0] = at[next_at].x-at[cur_at].x;
2613
+ at_coord[j1][1] = at[next_at].y-at[cur_at].y;
2614
+ bond_len_xy[j1] = e_len2(at_coord[j1]);
2615
+ at_coord[j1][2] = (nType==ZTYPE_3D? z :
2616
+ nType==ZTYPE_UP? bond_len_xy[j1] :
2617
+ nType==ZTYPE_DOWN? -bond_len_xy[j1] : 0.0 );
2618
+ }
2619
+ /* j1 is the number of explicit neighbors (that is, all neighbors except implicit H) */
2620
+
2621
+ b2D = (b2D == num_z && num_z); /* 1 => two-dimensional */
2622
+
2623
+ if ( MAX_NUM_STEREO_ATOM_NEIGH != at[cur_at].num_bonds+num_iH &&
2624
+ MAX_NUM_STEREO_ATOM_NEIGH-1 != at[cur_at].num_bonds+num_iH ) {
2625
+ /* not enough geometry data to find the central atom parity */
2626
+ goto exit_function;
2627
+ }
2628
+ /* make all vector lengths equal to 1; exit if too short. 9-10-2002 */
2629
+ for ( j = 0; j < j1; j ++ ) {
2630
+ z = e_len3( at_coord[j] );
2631
+ if ( z < MIN_BOND_LEN ) {
2632
+ parity = INCHI_PARITY_UNDEFINED;
2633
+ goto exit_function;
2634
+ }
2635
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
2636
+ else {
2637
+ e_mult3( at_coord[j], 1.0/z, at_coord[j] );
2638
+ }
2639
+ #endif
2640
+ rmax = j? inchi_max( rmax, z) : z;
2641
+ rmin = j? inchi_min( rmin, z) : z;
2642
+ }
2643
+ if ( rmin / rmax < MIN_SINE ) {
2644
+ /* bond ratio is too small */
2645
+ parity = INCHI_PARITY_UNDEFINED;
2646
+ goto exit_function;
2647
+ }
2648
+ for ( j = 0; j < j1; j ++ ) {
2649
+ e_add3( sum_xyz, at_coord[j], sum_xyz );
2650
+ }
2651
+
2652
+
2653
+
2654
+ /* here j1 is a number of neighbors including explicit terminal isotopic H */
2655
+ /* num_iso_eH[0] = number of explicit non-isotopic hydrogen atom neighbors */
2656
+ j = j1;
2657
+ /* Add Explicit Neighbor */
2658
+ if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
2659
+ /* add an explicit neighbor if possible */
2660
+ if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
2661
+ bAddExplicitNeighbor = ADD_EXPLICIT_LONE_PAIR_NEIGH;
2662
+ } else
2663
+ if ( nMustHaveNumNeigh == MAX_NUM_STEREO_ATOM_NEIGH ) {
2664
+ /* check whether an explicit non-isotopic hydrogen can be added */
2665
+ /* to an atom that is a stereogenic atom */
2666
+ bAddExplicitNeighbor = ADD_EXPLICIT_HYDROGEN_NEIGH;
2667
+ }
2668
+ }
2669
+
2670
+ if ( bAddExplicitNeighbor ) {
2671
+ /***********************************************************
2672
+ * May happen only if (j1 == MAX_NUM_STEREO_ATOM_NEIGH-1)
2673
+ * 3 neighbors only, no H-neighbors. Create and add coordinates of an implicit H
2674
+ * or a fake 4th neighbor, that is, a lone pair
2675
+ */
2676
+ if ( parity == INCHI_PARITY_UNKNOWN ) {
2677
+ goto exit_function; /* the user insists the parity is unknown and the isotopic */
2678
+ /* composition of the neighbors does not contradict */
2679
+ } else
2680
+ if ( num_z == 0 || are_3_vect_in_one_plane(at_coord, MIN_SINE) ) {
2681
+ /* "hydrogen down" rule is needed to resolve an ambiguity */
2682
+ if ( num_z > 0 ) {
2683
+ bAmbiguous |= AMBIGUOUS_STEREO;
2684
+ }
2685
+ #if( APPLY_IMPLICIT_H_DOWN_RULE == 1 ) /* { */
2686
+ /* Although H should be at the top of the list, add it to the bottom. */
2687
+ /* This will be taken care of later by inverting parity 1<->2 */
2688
+ at_coord[j][0] = 0.0;
2689
+ at_coord[j][1] = 0.0;
2690
+ #if( STEREO_CENTER_BONDS_NORM == 1 )
2691
+ at_coord[j][2] = -1.0;
2692
+ #else
2693
+ at_coord[j][2] = -(bond_len_xy[0]+bond_len_xy[1]+bond_len_xy[2])/3.0;
2694
+ #endif
2695
+ #else /* } APPLY_IMPLICIT_H_DOWN_RULE { */
2696
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
2697
+ parity = INCHI_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
2698
+ #else
2699
+ parity = INCHI_PARITY_UNDEFINED;
2700
+ #endif
2701
+ goto exit_function;
2702
+ #endif /* } APPLY_IMPLICIT_H_DOWN_RULE */
2703
+ } else {
2704
+ /* we have enough information to find implicit hydrogen coordinates */
2705
+ e_copy3( sum_xyz, at_coord[j] );
2706
+ e_change_sign3( at_coord[j], at_coord[j] );
2707
+ z = e_len3( at_coord[j] );
2708
+ rmax = inchi_max( rmax, z );
2709
+ rmin = inchi_min( rmin, z );
2710
+ if ( z < MIN_BOND_LEN || rmin/rmax < MIN_SINE ) {
2711
+ /* the new 4th bond is too short */
2712
+ parity = INCHI_PARITY_UNDEFINED;
2713
+ goto exit_function;
2714
+ }
2715
+ #if( STEREO_CENTER_BOND4_NORM == 1 )
2716
+ else {
2717
+ e_mult3( at_coord[j], 1.0/z, at_coord[j] );
2718
+ }
2719
+ #endif
2720
+ }
2721
+ } else
2722
+ if ( j1 != MAX_NUM_STEREO_ATOM_NEIGH ) {
2723
+ if ( parity == INCHI_PARITY_UNKNOWN ) {
2724
+ parity = -INCHI_PARITY_UNDEFINED; /* isotopic composition of H-neighbors contradicts 'unknown' */
2725
+ }
2726
+ goto exit_function;
2727
+ } else /* j1 == MAX_NUM_STEREO_ATOM_NEIGH */
2728
+ if ( num_z == 0 || e_are_4at_in_one_plane(at_coord, MIN_SINE) ) {
2729
+ /* all four neighours in xy plane: undefined geometry. */
2730
+ if ( num_z > 0 ) {
2731
+ bAmbiguous |= AMBIGUOUS_STEREO;
2732
+ }
2733
+ if ( parity != INCHI_PARITY_UNKNOWN ) {
2734
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
2735
+ parity = INCHI_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
2736
+ #else
2737
+ /* all 4 bonds are in one plain */
2738
+ parity = INCHI_PARITY_UNDEFINED;
2739
+ #endif
2740
+ }
2741
+ goto exit_function;
2742
+ }
2743
+ /***********************************************************
2744
+ * At this point we have 4 neighboring atoms.
2745
+ * check for tetrahedral ambiguity in 2D case
2746
+ */
2747
+ if ( b2D ) {
2748
+ if ( 0 < (n2DTetrahedralAmbiguity = e_Get2DTetrahedralAmbiguity( at_coord, bAddExplicitNeighbor )) ) {
2749
+ if ( T2D_WARN & n2DTetrahedralAmbiguity ) {
2750
+ bAmbiguous |= AMBIGUOUS_STEREO;
2751
+ }
2752
+ if ( T2D_UNDF & n2DTetrahedralAmbiguity ) {
2753
+ if ( parity != INCHI_PARITY_UNKNOWN ) {
2754
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
2755
+ parity = INCHI_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
2756
+ #else
2757
+ parity = INCHI_PARITY_UNDEFINED; /* no parity */
2758
+ #endif
2759
+ }
2760
+ goto exit_function;
2761
+ }
2762
+ } else
2763
+ if ( n2DTetrahedralAmbiguity < 0 ) {
2764
+ bAmbiguous |= AMBIGUOUS_STEREO_ERROR; /* error */
2765
+ parity = INCHI_PARITY_UNDEFINED;
2766
+ goto exit_function;
2767
+ }
2768
+ }
2769
+
2770
+ /************************************************************/
2771
+ /* Move coordinates origin to the neighbor #0 */
2772
+ for ( j = 1; j < MAX_NUM_STEREO_ATOM_NEIGH; j ++ ) {
2773
+ e_diff3(at_coord[j], at_coord[0], at_coord[j]);
2774
+ }
2775
+ e_diff3(at_coord_center, at_coord[0], at_coord_center);
2776
+
2777
+ /********************************************************
2778
+ * find the central (cur_at) atom's parity
2779
+ * (orientation of atoms #1-3 when looking from #0)
2780
+ ********************************************************/
2781
+ triple_product = e_triple_prod_and_min_abs_sine2(&at_coord[1], at_coord_center, bAddExplicitNeighbor, &min_sine, &bAmbiguous);
2782
+ if ( fabs(triple_product) > ZERO_FLOAT && (min_sine > MIN_SINE || fabs(min_sine) > ZERO_FLOAT && (n2DTetrahedralAmbiguity & T2D_OKAY ) ) ) {
2783
+ /* Even => sorted in correct order, Odd=>transposed */
2784
+ parity = triple_product > 0.0? INCHI_PARITY_EVEN : INCHI_PARITY_ODD;
2785
+
2786
+ /* for 4 attached atoms, moving the implicit H from index=3 to index=0 */
2787
+ /* can be done in odd number (3) transpositions: (23)(12)(01), which inverts the parity */
2788
+ if ( j1 == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
2789
+ parity = 3 - parity;
2790
+ }
2791
+ } else {
2792
+ #if (ALWAYS_SET_STEREO_PARITY == 1)
2793
+ parity = AT_PARITY_EVEN; /* suppose atoms are pre-sorted (testing) */
2794
+ #else
2795
+ if ( num_z > 0 ) {
2796
+ bAmbiguous |= AMBIGUOUS_STEREO;
2797
+ }
2798
+ parity = INCHI_PARITY_UNDEFINED; /* no parity: 4 bonds are in one plane. */
2799
+ #endif
2800
+ }
2801
+ exit_function:
2802
+
2803
+ if ( parity ) {
2804
+ bAmbiguousStereo |= bAmbiguous;
2805
+ }
2806
+ /* isotopic parity => parity */
2807
+ if ( parity < 0 )
2808
+ parity = -parity;
2809
+
2810
+ if ( 0 < parity && parity < INCHI_PARITY_UNDEFINED ) {
2811
+ inchi_Stereo0D *stereo0D;
2812
+ if ( stereo0D = e_GetNewStereo( pStereo ) ) {
2813
+ stereo0D->central_atom = cur_at;
2814
+ stereo0D->parity = parity;
2815
+ stereo0D->type = INCHI_StereoType_Tetrahedral;
2816
+ k = 0;
2817
+ if ( at[cur_at].num_bonds == 3 ) {
2818
+ stereo0D->neighbor[k++] = cur_at;
2819
+ }
2820
+ for ( j = 0; j < at[cur_at].num_bonds; j ++ ) {
2821
+ stereo0D->neighbor[k++] = at[cur_at].neighbor[j];
2822
+ }
2823
+ }
2824
+ }
2825
+ return parity;
2826
+
2827
+ }
2828
+ #undef ADD_EXPLICIT_HYDROGEN_NEIGH
2829
+ #undef ADD_EXPLICIT_LONE_PAIR_NEIGH
2830
+
2831
+ /*************************************************************/
2832
+ inchi_Stereo0D *e_GetNewStereo( Stereo0D *pStereo )
2833
+ {
2834
+ #define DEFAULT_0D_STEREO_DELTA 64
2835
+ int delta = pStereo->delta_num_stereo0D > 0? pStereo->delta_num_stereo0D : DEFAULT_0D_STEREO_DELTA;
2836
+ if ( pStereo->num_stereo0D >= pStereo->max_num_Stereo0D ) {
2837
+ /*inchi_Stereo0D *pNew = (inchi_Stereo0D *)e_inchi_calloc( pStereo->max_num_Stereo0D + delta, sizeof(pNew[0]) );*/
2838
+ inchi_Stereo0D *pNew = e_CreateInchi_Stereo0D( pStereo->max_num_Stereo0D + delta );
2839
+ if ( pNew ) {
2840
+ if ( pStereo->num_stereo0D > 0 ) {
2841
+ memcpy( pNew, pStereo->stereo0D, pStereo->num_stereo0D * sizeof(pNew[0]) );
2842
+ }
2843
+ /*e_inchi_free(pStereo->stereo0D);*/
2844
+ e_FreeInchi_Stereo0D( &pStereo->stereo0D );
2845
+ pStereo->stereo0D = pNew;
2846
+ pStereo->max_num_Stereo0D += delta;
2847
+ }
2848
+ }
2849
+ return pStereo->stereo0D + pStereo->num_stereo0D ++;
2850
+ #undef DEFAULT_0D_STEREO_DELTA
2851
+ }
2852
+
2853
+ /*************************************************************/
2854
+ int set_0D_stereo_parities( inchi_Input *pInp, int bPointedEdgeStereo )
2855
+ {
2856
+ int num_3D_stereo_atoms=0, num_stereo_bonds=0;
2857
+
2858
+ int i, is_stereo, num_stereo;
2859
+ inchi_Atom* at = pInp->atom;
2860
+ int num_at = pInp->num_atoms;
2861
+ Stereo0D stereo;
2862
+ Stereo0D *pStereo = &stereo;
2863
+
2864
+ /**********************************************************
2865
+ *
2866
+ * Note: this parity reflects only relative positions of
2867
+ * the atoms-neighbors and their ordering in the
2868
+ * lists of neighbors.
2869
+ *
2870
+ * To obtain the actual parity, the parity of a number
2871
+ * of neighbors transpositions (to obtain a sorted
2872
+ * list of numbers assigned to the atoms) should be
2873
+ * added.
2874
+ *
2875
+ **********************************************************/
2876
+
2877
+ /*********************************************************************************
2878
+
2879
+ An example of parity=1 for stereogenic center, tetrahedral asymmetric atom
2880
+
2881
+
2882
+
2883
+ (1)
2884
+ |
2885
+ |
2886
+ [C] |
2887
+ |
2888
+ (2)------(0)
2889
+ /
2890
+ /
2891
+ /
2892
+ /
2893
+ (3)
2894
+
2895
+
2896
+ Notation: (n) is a tetrahedral atom neighbor; n is an index of a neighbor in
2897
+ the central_at->neighbor[] array : neighbor atom number is central_at->neighbor[n].
2898
+
2899
+ (0)-(1), (0)-(2), (0)-(3) are lines connecting atom [C] neighbors to neighbor (0)
2900
+ (0), (1) and (2) are in the plane
2901
+ (0)-(3) is directed from the plain to the viewer
2902
+ [C] is somewhere between (0), (1), (2), (3)
2903
+ Since (1)-(2)-(3) are in a clockwise order when looking from (0), parity is 2, or even;
2904
+ otherwise parity would be 1, or odd.
2905
+
2906
+ **********************************************************************************
2907
+
2908
+ Examples of a stereogenic bond.
2909
+
2910
+ Notation: [atom number], (index of a neighbor):
2911
+ [1] and [2] are atoms connected by the stereogenic bond
2912
+ numbers in () are indexes of neighbors of [1] or [2].
2913
+ (12 x 16)z = z-component of [1]-[2] and [1]-[6] cross-product
2914
+
2915
+ atom [1] atom [2]
2916
+ [8] [4] prod01 = (12 x 16)z < 0 prod01 = (21 x 24)z < 0
2917
+ \ / prod02 = (12 x 18)z > 0 prod02 = (21 x 25)z > 0
2918
+ (2) (1) 0 transpositions because 0 transpositions because
2919
+ \ / double bond is in 0 posit. double bond is in 0 position
2920
+ [1]==(0)(0)==[2] 0 = (prod01 > prod02) 0 = (prod01 > prod02)
2921
+ / \
2922
+ (1) (2) result: parity = 2, even result: parity=2, even
2923
+ / \
2924
+ [6] [5]
2925
+
2926
+
2927
+
2928
+ atom [1] atom [2]
2929
+ [8] [5] prod01 = (12 x 18)z > 0 prod01 = (21 x 24)z > 0
2930
+ \ / prod02 = (12 x 16)z < 0 prod02 = (21 x 25)z < 0
2931
+ (0) (2) 2 transpositions to move 1 transposition to move
2932
+ \ / at [2] from 2 to 0 pos. at [1] from 1 to 0 position
2933
+ [1]==(2)(1)==[2] 1 = (prod01 > prod02) 1 = (prod01 > prod02)
2934
+ / \
2935
+ (1) (0) result: parity = (1+2) result: parity=(1+1)
2936
+ / \ 2-(1+2)%2 = 1, odd 2-(1+1)%2 = 2, even
2937
+ [6] [4]
2938
+
2939
+
2940
+ ***********************************************************************************
2941
+ Note: atoms' numbers [1], [2], [4],... are not used to calculate parity at this
2942
+ point. They will be used for each numbering in the canonicalization.
2943
+ Note: parity=3 for a stereo atom means entered undefined bond direction
2944
+ parity=4 for an atom means parity cannot be determined from the given geometry
2945
+ ***********************************************************************************/
2946
+
2947
+ if ( !at ) {
2948
+ return -1;
2949
+ }
2950
+
2951
+ /* clear stereo descriptors */
2952
+ memset( pStereo, 0, sizeof(*pStereo) );
2953
+ pStereo->delta_num_stereo0D = num_at;
2954
+ pStereo->cAtType = (S_CHAR *)e_inchi_calloc( num_at, sizeof(pStereo->cAtType[0]) );
2955
+ if (!pStereo->cAtType ) {
2956
+ return -1;
2957
+ }
2958
+ /* atom stereo types */
2959
+ for ( i = 0; i < num_at; i ++ ) {
2960
+ pStereo->cAtType[i] = e_GetElType( at, i );
2961
+ }
2962
+
2963
+
2964
+
2965
+ /* calculate stereo descriptors */
2966
+ /* main cycle: set stereo parities */
2967
+ for( i = 0, num_stereo = 0; i < num_at; i ++ ) {
2968
+
2969
+ if ( is_stereo = e_set_stereo_atom_parity( pStereo, at, i, bPointedEdgeStereo ) ) {
2970
+ num_3D_stereo_atoms += ATOM_PARITY_WELL_DEF( is_stereo );
2971
+ num_stereo += ATOM_PARITY_WELL_DEF( is_stereo );
2972
+ } else {
2973
+ is_stereo = e_set_stereo_bonds_parity( pStereo, at, i, bPointedEdgeStereo );
2974
+ if ( RETURNED_ERROR( is_stereo ) ) {
2975
+ num_3D_stereo_atoms = is_stereo;
2976
+ is_stereo = 0;
2977
+ break;
2978
+ } else {
2979
+ num_stereo_bonds += is_stereo;
2980
+ num_stereo += is_stereo;
2981
+ }
2982
+ }
2983
+ }
2984
+ /*
2985
+ if ( (nMode & REQ_MODE_SC_IGN_ALL_UU )
2986
+ REQ_MODE_SC_IGN_ALL_UU
2987
+ REQ_MODE_SB_IGN_ALL_UU
2988
+ */
2989
+ if ( pStereo->cAtType ) {
2990
+ e_inchi_free( pStereo->cAtType );
2991
+ }
2992
+ if ( pInp->stereo0D ) {
2993
+ }
2994
+
2995
+ pInp->stereo0D = pStereo->stereo0D;
2996
+ pInp->num_stereo0D = pStereo->num_stereo0D;
2997
+
2998
+ return RETURNED_ERROR( num_3D_stereo_atoms )? num_3D_stereo_atoms : num_stereo;
2999
+ }
3000
+ /*****************************************************************/
3001
+ int Clear3D2Dstereo(inchi_Input *pInp)
3002
+ {
3003
+ int i;
3004
+ if ( !pInp->atom || !pInp->num_atoms )
3005
+ return 0;
3006
+ for ( i = 0; i < pInp->num_atoms; i ++ ) {
3007
+ pInp->atom[i].x =
3008
+ pInp->atom[i].y =
3009
+ pInp->atom[i].z = 0.0;
3010
+ memset( pInp->atom[i].bond_stereo, 0, sizeof(pInp->atom[i].bond_stereo) );
3011
+ }
3012
+ return 1;
3013
+ }
3014
+