rino 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+