diff --git a/api/tests/integration/ref/formats/cdxml_to_mol.py.out b/api/tests/integration/ref/formats/cdxml_to_mol.py.out index 72ef61c5e1..cdee36b9da 100644 --- a/api/tests/integration/ref/formats/cdxml_to_mol.py.out +++ b/api/tests/integration/ref/formats/cdxml_to_mol.py.out @@ -4,46 +4,46 @@ sgroups.cdxml -INDIGO-01000000002D 40 36 0 0 0 0 0 0 0 0999 V2000 - 384.2900 7.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 396.7600 0.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 409.2300 7.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 421.7100 0.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 359.3500 7.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 371.8200 0.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 434.1800 7.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 446.6500 0.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 362.9500 153.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 375.4200 146.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 387.8900 153.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 400.3600 146.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 412.8300 153.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 425.3100 146.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 437.7800 153.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 450.2500 146.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 365.4700 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 377.9400 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 390.4100 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 402.8800 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 415.3500 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 427.8300 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 440.3000 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 452.7700 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 362.5900 52.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 375.0600 45.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 387.5300 52.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 400.0000 45.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 412.4700 52.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 424.9500 45.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 437.4200 52.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 449.8900 45.3100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 390.4100 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 402.8800 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 415.3500 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 427.8300 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 390.4100 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 402.8800 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 415.3500 105.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 427.8300 97.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.8363 -5.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.2520 -5.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.6677 -5.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0837 -5.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.0050 -5.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4207 -5.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.4993 -5.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9150 -5.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.1250 -0.2500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5407 -0.4900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.9563 -0.2500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.3720 -0.4900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7877 -0.2500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2037 -0.4900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6193 -0.2500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0350 -0.4900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.2090 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.6247 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.0403 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.4560 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8717 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2877 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.7033 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.1190 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.1130 -3.6100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.5287 -3.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.9443 -3.6100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.3600 -3.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7757 -3.6100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.1917 -3.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6073 -3.6100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.0230 -3.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.0403 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.4560 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8717 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2877 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.0403 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.4560 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8717 -1.8580 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.2877 -2.0980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 2 3 1 0 0 0 0 3 4 1 0 0 0 0 @@ -103,202 +103,202 @@ test-multi.cdxml -INDIGO-01000000002D 196212 0 0 0 0 0 0 0 0999 V2000 - 290.9700 1245.0699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 264.9900 1230.0699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 239.0100 1245.0699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 290.9700 1275.0699 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 213.0300 1230.0699 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 333.8700 1062.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 333.7900 1092.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 359.7300 1107.5699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 307.7700 1107.4199 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 359.6500 1137.5699 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 307.9400 1047.4199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 280.7000 1059.4299 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 260.7300 1037.1899 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 275.6700 1011.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 304.8600 1017.5800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 266.4200 982.9200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 286.3500 960.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 315.5300 966.7999 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 324.7900 995.1500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 329.6700 1062.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 329.5900 1092.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 355.5300 1107.5699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 303.5700 1107.4199 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 355.4500 1137.5699 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 303.7400 1047.4199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 276.5000 1059.4299 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 256.5300 1037.1899 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 271.4700 1011.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 300.6600 1017.5800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 262.2200 982.9200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 282.1500 960.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 311.3300 966.7999 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 320.5900 995.1500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 214.7100 1139.7400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 216.7500 1191.6699 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 230.7200 1165.1200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 260.7000 1163.9399 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 274.6700 1137.3900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 276.7100 1189.3099 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 184.7400 1140.9199 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 232.7600 1217.0399 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 262.7400 1215.8600 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 218.7900 1243.5900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 234.8000 1268.9600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 264.7800 1267.7800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 280.7800 1293.1500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 266.8200 1319.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 236.8400 1320.8800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 220.8300 1295.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 149.7000 790.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 123.7200 775.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 97.7400 790.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 149.7000 820.5100 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 71.7600 775.5099 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 205.6800 790.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 231.6600 775.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 179.7000 775.5099 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 231.6600 745.5099 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 214.9200 887.8300 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 224.2500 916.1600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 253.4400 922.2400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 273.3200 899.9200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 234.7900 865.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 264.0000 871.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 278.8700 845.6400 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 258.8500 823.4500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 231.6400 835.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 205.6700 820.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 287.6400 775.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 313.6200 790.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 261.6600 790.5099 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 313.6200 820.5100 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 296.8700 678.1800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 306.2100 649.8600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 335.4000 643.7800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 355.2800 666.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 316.7500 700.6600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 345.9600 694.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 360.8400 720.3799 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 340.8100 742.5699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 313.6000 730.4900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 287.6300 745.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 417.5500 790.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 391.5700 745.5099 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 391.5700 775.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 365.5900 790.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 365.5900 820.5100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 339.6100 775.5099 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 417.5500 820.5100 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 417.5500 730.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 417.5500 700.5099 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 443.5300 745.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 469.5100 730.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 469.5100 700.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 495.4900 685.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 521.4700 700.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 521.4700 730.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 495.4900 745.5099 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 227.5800 168.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 253.5600 183.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 253.5600 213.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 201.6000 183.0200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 227.5800 228.0200 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 253.5600 123.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 279.5400 138.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 227.5800 138.0200 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 305.5200 123.0200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 190.9000 118.7500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 161.5600 124.9900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 141.4800 102.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 150.7500 74.1699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 200.1700 90.2200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 180.1000 67.9299 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 195.1000 41.9500 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 224.4400 48.1799 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 227.5800 78.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 253.5600 93.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 305.5200 183.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 305.5200 213.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 279.5400 168.0200 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 331.5000 228.0200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 394.1600 142.2899 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 423.5000 136.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 443.5800 158.3400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 434.3100 186.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 384.8900 170.8199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 404.9600 193.1100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 389.9600 219.0900 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 360.6200 212.8600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 357.4800 183.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 331.5000 168.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 227.5800 258.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 253.5600 303.0200 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 253.5600 273.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 279.5400 258.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 305.5200 273.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 279.5400 228.0200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 201.6000 273.0200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 227.5800 318.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 227.5800 348.0200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 201.6000 303.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 175.6200 318.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 175.6200 348.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 149.6400 363.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 123.6500 348.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 123.6500 318.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 149.6400 303.0200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 930.8300 826.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 901.4800 832.9399 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 881.4100 810.6400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 852.0600 816.8800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 831.9900 794.5800 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 842.7900 845.4100 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 813.4500 851.6500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 804.1800 880.1799 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 774.8300 886.4200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 824.2500 902.4700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 814.9800 931.0100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 835.0500 953.2999 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 825.7800 981.8300 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 864.4000 947.0599 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 873.6700 918.5300 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 903.0100 912.2900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 912.2800 883.7600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 941.6300 877.5200 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 892.2100 861.4700 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 785.6400 937.2400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 776.3700 965.7700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 794.0000 990.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 776.3700 1014.3199 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 747.8300 1005.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 747.8300 975.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 721.8500 960.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 695.8700 975.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 695.8700 1005.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 721.8500 1020.0499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 793.3700 829.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 764.0300 835.5900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 751.8300 863.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 721.9900 859.8600 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 715.7500 830.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 741.7400 815.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 741.7400 785.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 715.7500 770.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 689.7700 785.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 689.7700 815.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 890.6800 782.1100 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 - 920.0200 775.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 929.2900 747.3400 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 - 941.2400 797.0900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 970.2100 789.3199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 991.4300 810.5300 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1020.4000 802.7700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1028.1700 773.7900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 1006.9600 752.5800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 - 977.9800 760.3400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6673 -2.0793 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8013 -2.5793 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.9353 -2.0793 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.6673 -1.0793 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.0693 -2.5793 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0973 -8.1650 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0947 -7.1650 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9593 -6.6627 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2273 -6.6677 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9567 -5.6627 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.2330 -8.6677 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3250 -8.2673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6593 -9.0087 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1573 -9.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1303 -9.6623 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8490 -10.8177 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5133 -11.5600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4860 -11.3550 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.7947 -10.4100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9573 -8.1650 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.9547 -7.1650 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8193 -6.6627 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0873 -6.6677 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8167 -5.6627 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 8.0930 -8.6677 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1850 -8.2673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5193 -9.0087 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0173 -9.8700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.9903 -9.6623 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7090 -10.8177 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3733 -11.5600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.3460 -11.3550 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.6547 -10.4100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1253 -5.5903 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1933 -3.8593 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6590 -4.7443 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6583 -4.7837 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1240 -5.6687 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.1920 -3.9380 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.1263 -5.5510 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7270 -3.0137 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7263 -3.0530 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.2613 -2.1287 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7950 -1.2830 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7943 -1.3223 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.3277 -0.4767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.8623 0.4083 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.8630 0.4477 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.3293 -0.3980 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9583 -17.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0923 -17.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.2263 -17.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9583 -16.2313 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 0.3603 -17.7313 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8243 -17.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6903 -17.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9583 -17.7313 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6903 -18.7313 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.1323 -13.9873 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4433 -13.0430 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4163 -12.8403 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.0790 -13.5843 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.7947 -14.7367 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.7683 -14.5313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2640 -15.3937 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.5967 -16.1333 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.6897 -15.7310 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.8240 -16.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5563 -17.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4223 -17.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.6903 -17.2313 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4223 -16.2313 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 7.8640 -20.9757 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1753 -21.9197 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.1483 -22.1223 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8110 -21.3783 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.5267 -20.2263 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.5003 -20.4317 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9963 -19.5690 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.3287 -18.8293 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.4217 -19.2320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.5560 -18.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8867 -17.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0207 -18.7313 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 11.0207 -17.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1547 -17.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.1547 -16.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.2887 -17.7313 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8867 -16.2313 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8867 -19.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.8867 -20.2313 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7527 -18.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6187 -19.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 13.6187 -20.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4847 -20.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.3507 -20.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 15.3507 -19.2313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 14.4847 -18.7313 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5543 -37.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4203 -37.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4203 -36.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6883 -37.4810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5543 -35.9810 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4203 -39.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2863 -38.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5543 -38.9810 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1523 -39.4810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.3317 -39.6233 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.3537 -39.4153 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.6843 -40.1583 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9933 -41.1093 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6407 -40.5743 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.9717 -41.3173 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 4.4717 -42.1833 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 5.4497 -41.9757 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5543 -40.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4203 -40.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1523 -37.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1523 -36.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2863 -37.9810 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0183 -35.9810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 11.1070 -38.8387 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.0850 -39.0467 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.7543 -38.3037 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 12.4453 -37.3527 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.7980 -37.8877 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 11.4670 -37.1447 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 10.9670 -36.2787 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 9.9890 -36.4863 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.8843 -37.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 9.0183 -37.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5543 -34.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4203 -33.4810 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 6.4203 -34.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2863 -34.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 8.1523 -34.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 7.2863 -35.9810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6883 -34.4810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5543 -32.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 5.5543 -31.9810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 4.6883 -33.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8223 -32.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 3.8223 -31.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9563 -31.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0900 -31.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0900 -32.9810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.9563 -33.4810 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.9960 -16.0250 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.0177 -15.8170 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.3487 -16.5603 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 26.3703 -16.3523 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.7013 -17.0957 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 26.0613 -15.4013 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 25.0833 -15.1933 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.7743 -14.2423 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.7960 -14.0343 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 25.4433 -13.4993 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 25.1343 -12.5480 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.8033 -11.8050 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 25.4943 -10.8540 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 26.7817 -12.0130 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 27.0907 -12.9640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.0687 -13.1720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.3777 -14.1230 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 29.3560 -14.3310 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 27.7087 -14.8660 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 24.1563 -12.3403 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.8473 -11.3893 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.4350 -10.5800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.8473 -9.7710 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 22.8960 -10.0800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.8960 -11.0800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.0300 -11.5800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.1640 -11.0800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.1640 -10.0800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.0300 -9.5800 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 24.4140 -15.9367 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.4360 -15.7287 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 23.0293 -14.8150 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.0347 -14.9197 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8267 -15.8977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.6930 -16.3977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 22.6930 -17.3977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 21.8267 -17.8977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.9607 -17.3977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 20.9607 -16.3977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 27.6577 -17.5113 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + 28.6357 -17.7193 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 28.9447 -18.6703 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0 + 29.3430 -17.0120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.3087 -17.2710 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 31.0160 -16.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 31.9817 -16.8227 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 32.2407 -17.7887 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 31.5337 -18.4957 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 30.5677 -18.2370 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 0 2 3 1 0 0 0 0 1 4 2 0 0 0 0 diff --git a/api/tests/integration/ref/formats/linux/rxn_to_cdxml.py.out b/api/tests/integration/ref/formats/linux/rxn_to_cdxml.py.out deleted file mode 100644 index ddc38675f8..0000000000 --- a/api/tests/integration/ref/formats/linux/rxn_to_cdxml.py.out +++ /dev/null @@ -1,2697 +0,0 @@ -*** Rxn to CDXML *** -1-3-Quinazoline-2-4-dione.rxn -*** Try as Reaction *** -molfile loader: atom lists are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - N - - - - - - O - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - Cl,Br,I - - - - - H - - - - - - - - - - - - - - - - N - - - - - - N - - - - - O - - - - - O - - - - - - - - - - - - - - - - - - - - - - + - - - + - - - - - - - 1,3-Quinazoline 2,4-dione formation - - - - -AcetylateSecondaryAmine.rxn -*** Try as Reaction *** -molfile loader: 'any' atoms are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - A - - - - - N - - - - - A - - - - - H - - - - - - - - - - A - - - - - N - - - - - A - - - - - - O - - - - - - - - - - - - - - - - -AmideFormation.ket -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - - -AmideFormation.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - Amide Formation - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - Amide Formation - - - - -CN_Bond-S-GRP.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - NH - - - - - - H - - - - - - - - - - NH - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - NH - - - - - - H - - - - - - - - - - NH - - - - - - - - + - - - - - - - - -CN_Bond.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -CN_Bond_map.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -Claisen.ket -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -Claisen.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -Markush6.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - O - - - - - H - - - - - H - - - - - - R1 - - - - - - - - - - - - - - - - - - - N - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - - - - - - - - - - - - - - - - - - N - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - R1 - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - O - - - - - H - - - - - H - - - - - - R1 - - - - - - - - - - - - - - - - - - - N - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - - - - - - - - - - - - - - - - - - N - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - R1 - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -SN2_XtoOR_Stereo.rxn -*** Try as Reaction *** -molfile loader: atom lists are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - A - - - - - - H - - - - - A - - - - - Cl,Br,I - - - - - - - - - - - OH - - - - - H - - - - - - - - A - - - - - - H - - - - - A - - - - - OH - - - - - - - - - + - - - - - - - - -amiderxn3.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - R1 - - - - - - O - - - - - OH - - - - - - - - - - NH - 2 - - - - - R2 - - - - - - - - R3 - - - - - SH - - - - - - - - - - - - R1 - - - - - - O - - - - - NH - - - - - R2 - - - - - - - - - - - R3 - - - - - SH - - - - - - - - - - + - - - + - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - R1 - - - - - - O - - - - - OH - - - - - - - - - - NH - 2 - - - - - R2 - - - - - - - - R3 - - - - - SH - - - - - - - - - - - - R1 - - - - - - O - - - - - NH - - - - - R2 - - - - - - - - - - - R3 - - - - - SH - - - - - - - - - - + - - - + - - - + - - - - - - - - -only_products.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -only_reactants.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -v3000.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - - - - - NH - - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - - - - - NH - - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - - - - - - diff --git a/api/tests/integration/ref/formats/mac/rxn_to_cdxml.py.out b/api/tests/integration/ref/formats/mac/rxn_to_cdxml.py.out deleted file mode 100644 index 46761d92dd..0000000000 --- a/api/tests/integration/ref/formats/mac/rxn_to_cdxml.py.out +++ /dev/null @@ -1,2697 +0,0 @@ -*** Rxn to CDXML *** -1-3-Quinazoline-2-4-dione.rxn -*** Try as Reaction *** -molfile loader: atom lists are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - N - - - - - - O - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - Cl,Br,I - - - - - H - - - - - - - - - - - - - - - - N - - - - - - N - - - - - O - - - - - O - - - - - - - - - - - - - - - - - - - - - - + - - - + - - - - - - - 1,3-Quinazoline 2,4-dione formation - - - - -AcetylateSecondaryAmine.rxn -*** Try as Reaction *** -molfile loader: 'any' atoms are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - A - - - - - N - - - - - A - - - - - H - - - - - - - - - - A - - - - - N - - - - - A - - - - - - O - - - - - - - - - - - - - - - - -AmideFormation.ket -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - - -AmideFormation.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - Amide Formation - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - Amide Formation - - - - -CN_Bond-S-GRP.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - NH - - - - - - H - - - - - - - - - - NH - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - NH - - - - - - H - - - - - - - - - - NH - - - - - - - - + - - - - - - - - -CN_Bond.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -CN_Bond_map.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -Claisen.ket -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -Claisen.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -Markush6.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - O - - - - - H - - - - - H - - - - - - R1 - - - - - - - - - - - - - - - - - - - N - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - - - - - - - - - - - - - - - - - - N - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - R1 - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - O - - - - - H - - - - - H - - - - - - R1 - - - - - - - - - - - - - - - - - - - N - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - - - - - - - - - - - - - - - - - - N - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - R1 - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -SN2_XtoOR_Stereo.rxn -*** Try as Reaction *** -molfile loader: atom lists are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - A - - - - - - H - - - - - A - - - - - Cl,Br,I - - - - - - - - - - - OH - - - - - H - - - - - - - - A - - - - - - H - - - - - A - - - - - OH - - - - - - - - - + - - - - - - - - -amiderxn3.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - R1 - - - - - - O - - - - - OH - - - - - - - - - - NH - 2 - - - - - R2 - - - - - - - - R3 - - - - - SH - - - - - - - - - - - - R1 - - - - - - O - - - - - NH - - - - - R2 - - - - - - - - - - - R3 - - - - - SH - - - - - - - - - - + - - - + - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - R1 - - - - - - O - - - - - OH - - - - - - - - - - NH - 2 - - - - - R2 - - - - - - - - R3 - - - - - SH - - - - - - - - - - - - R1 - - - - - - O - - - - - NH - - - - - R2 - - - - - - - - - - - R3 - - - - - SH - - - - - - - - - - + - - - + - - - + - - - - - - - - -only_products.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -only_reactants.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -v3000.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - - - - - NH - - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - - - - - NH - - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - - - - - - diff --git a/api/tests/integration/ref/formats/mingw/rxn_to_cdxml.py.out b/api/tests/integration/ref/formats/mingw/rxn_to_cdxml.py.out deleted file mode 100644 index ddc38675f8..0000000000 --- a/api/tests/integration/ref/formats/mingw/rxn_to_cdxml.py.out +++ /dev/null @@ -1,2697 +0,0 @@ -*** Rxn to CDXML *** -1-3-Quinazoline-2-4-dione.rxn -*** Try as Reaction *** -molfile loader: atom lists are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - N - - - - - - O - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - Cl,Br,I - - - - - H - - - - - - - - - - - - - - - - N - - - - - - N - - - - - O - - - - - O - - - - - - - - - - - - - - - - - - - - - - + - - - + - - - - - - - 1,3-Quinazoline 2,4-dione formation - - - - -AcetylateSecondaryAmine.rxn -*** Try as Reaction *** -molfile loader: 'any' atoms are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - A - - - - - N - - - - - A - - - - - H - - - - - - - - - - A - - - - - N - - - - - A - - - - - - O - - - - - - - - - - - - - - - - -AmideFormation.ket -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - - -AmideFormation.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - Amide Formation - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - O - - - - - H - - - - - - - - - - - N - - - - - - H - - - - - H - - - - - H - - - - - - - - - - - - - O - - - - - NH - - - - - - - - - - + - - - - - - - Amide Formation - - - - -CN_Bond-S-GRP.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - NH - - - - - - H - - - - - - - - - - NH - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - NH - - - - - - H - - - - - - - - - - NH - - - - - - - - + - - - - - - - - -CN_Bond.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -CN_Bond_map.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - + - - - - - - - - -Claisen.ket -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -Claisen.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - O - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - - - - - - - - - - - - - - - - -Markush6.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - O - - - - - H - - - - - H - - - - - - R1 - - - - - - - - - - - - - - - - - - - N - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - - - - - - - - - - - - - - - - - - N - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - R1 - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OH - - - - - O - - - - - H - - - - - H - - - - - - R1 - - - - - - - - - - - - - - - - - - - N - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - - - - - - - - - - - - - - - - - - N - - - - - O - - - - - H - - - - - H - - - - - H - - - - - - - - - NH - - - - - - R2 - - - - - - R1 - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -SN2_XtoOR_Stereo.rxn -*** Try as Reaction *** -molfile loader: atom lists are allowed only for queries -*** Try as QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - A - - - - - - H - - - - - A - - - - - Cl,Br,I - - - - - - - - - - - OH - - - - - H - - - - - - - - A - - - - - - H - - - - - A - - - - - OH - - - - - - - - - + - - - - - - - - -amiderxn3.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - R1 - - - - - - O - - - - - OH - - - - - - - - - - NH - 2 - - - - - R2 - - - - - - - - R3 - - - - - SH - - - - - - - - - - - - R1 - - - - - - O - - - - - NH - - - - - R2 - - - - - - - - - - - R3 - - - - - SH - - - - - - - - - - + - - - + - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - R1 - - - - - - O - - - - - OH - - - - - - - - - - NH - 2 - - - - - R2 - - - - - - - - R3 - - - - - SH - - - - - - - - - - - - R1 - - - - - - O - - - - - NH - - - - - R2 - - - - - - - - - - - R3 - - - - - SH - - - - - - - - - - + - - - + - - - + - - - - - - - - -only_products.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -only_reactants.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - -v3000.rxn -*** Try as Reaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - - - - - NH - - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - - - - - - -*** Compare with QueryReaction *** - - - - - - - - - - - - - - - - - - - - - - - - - Br - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - NH - - - - - - H - - - - - - - - - - - NH - - - - - - - - - - - - - NH - - - - - - - - - + - - - + - - - + - - - + - - - + - - - + - - - - - - - - diff --git a/api/tests/integration/ref/formats/mol_to_cdxml.py.out b/api/tests/integration/ref/formats/mol_to_cdxml.py.out index c85fec3fc0..774328b082 100644 --- a/api/tests/integration/ref/formats/mol_to_cdxml.py.out +++ b/api/tests/integration/ref/formats/mol_to_cdxml.py.out @@ -4,8 +4,8 @@ stereo_either-0020.mol - - + + diff --git a/api/tests/integration/ref/formats/rxn_to_cdxml.py.out b/api/tests/integration/ref/formats/rxn_to_cdxml.py.out index 4b1c9bf6a2..16ab45eb92 100644 --- a/api/tests/integration/ref/formats/rxn_to_cdxml.py.out +++ b/api/tests/integration/ref/formats/rxn_to_cdxml.py.out @@ -7,8 +7,8 @@ molfile loader: atom lists are allowed only for queries - - + + @@ -23,40 +23,40 @@ molfile loader: atom lists are allowed only for queries - - - - - - - - + + + + + + + + N - - - + + + O - - + + O - - + + H - - + + H - - + + H @@ -75,24 +75,24 @@ molfile loader: atom lists are allowed only for queries - - + + N - - - + + + H - - + + H - - + + H @@ -102,14 +102,14 @@ molfile loader: atom lists are allowed only for queries - - - + + + Cl,Br,I - - + + H @@ -117,36 +117,36 @@ molfile loader: atom lists are allowed only for queries - - - - - - - - - + + + + + + + + + N - - - + + + N - - + + O - - + + O - - + + @@ -163,17 +163,17 @@ molfile loader: atom lists are allowed only for queries - + + - + + - + - + 1,3-Quinazoline 2,4-dione formation @@ -187,8 +187,8 @@ molfile loader: 'any' atoms are allowed only for queries - - + + @@ -203,23 +203,23 @@ molfile loader: 'any' atoms are allowed only for queries - - + + A - - + + N - - + + A - - + + H @@ -228,35 +228,35 @@ molfile loader: 'any' atoms are allowed only for queries - - + + A - - + + N - - + + A - - - + + + O - + - + @@ -269,8 +269,8 @@ AmideFormation.ket - - + + @@ -356,9 +356,9 @@ AmideFormation.ket + - + - + @@ -368,8 +368,8 @@ AmideFormation.ket - - + + @@ -455,9 +455,9 @@ AmideFormation.ket + - + - + @@ -468,8 +468,8 @@ AmideFormation.rxn - - + + @@ -484,20 +484,20 @@ AmideFormation.rxn - - - - + + + + O - - + + O - - + + H @@ -507,24 +507,24 @@ AmideFormation.rxn - - + + N - - - + + + H - - + + H - - + + H @@ -534,32 +534,32 @@ AmideFormation.rxn - - - - + + + + O - - + + NH - + - + + - + - + Amide Formation @@ -570,8 +570,8 @@ AmideFormation.rxn - - + + @@ -586,20 +586,20 @@ AmideFormation.rxn - - - - + + + + O - - + + O - - + + H @@ -609,24 +609,24 @@ AmideFormation.rxn - - + + N - - - + + + H - - + + H - - + + H @@ -636,32 +636,32 @@ AmideFormation.rxn - - - - + + + + O - - + + NH - + - + + - + - + Amide Formation @@ -673,8 +673,8 @@ CN_Bond-S-GRP.rxn - - + + @@ -689,23 +689,23 @@ CN_Bond-S-GRP.rxn - - - + + + Br - - + + NH - - - + + + H @@ -713,20 +713,20 @@ CN_Bond-S-GRP.rxn - - - + + + NH - + - + + - + @@ -738,8 +738,8 @@ CN_Bond-S-GRP.rxn - - + + @@ -754,23 +754,23 @@ CN_Bond-S-GRP.rxn - - - + + + Br - - + + NH - - - + + + H @@ -778,20 +778,20 @@ CN_Bond-S-GRP.rxn - - - + + + NH - + - + + - + @@ -804,8 +804,8 @@ CN_Bond.rxn - - + + @@ -820,10 +820,10 @@ CN_Bond.rxn - - - - + + + + Br @@ -831,14 +831,14 @@ CN_Bond.rxn - - + + NH - - - + + + H @@ -846,22 +846,22 @@ CN_Bond.rxn - - - - + + + + NH - + - + + - + @@ -873,8 +873,8 @@ CN_Bond.rxn - - + + @@ -889,10 +889,10 @@ CN_Bond.rxn - - - - + + + + Br @@ -900,14 +900,14 @@ CN_Bond.rxn - - + + NH - - - + + + H @@ -915,22 +915,22 @@ CN_Bond.rxn - - - - + + + + NH - + - + + - + @@ -943,8 +943,8 @@ CN_Bond_map.rxn - - + + @@ -959,10 +959,10 @@ CN_Bond_map.rxn - - - - + + + + Br @@ -970,14 +970,14 @@ CN_Bond_map.rxn - - + + NH - - - + + + H @@ -985,22 +985,22 @@ CN_Bond_map.rxn - - - - + + + + NH - + - + + - + @@ -1012,8 +1012,8 @@ CN_Bond_map.rxn - - + + @@ -1028,10 +1028,10 @@ CN_Bond_map.rxn - - - - + + + + Br @@ -1039,14 +1039,14 @@ CN_Bond_map.rxn - - + + NH - - - + + + H @@ -1054,22 +1054,22 @@ CN_Bond_map.rxn - - - - + + + + NH - + - + + - + @@ -1082,8 +1082,8 @@ Claisen.ket - - + + @@ -1124,14 +1124,14 @@ Claisen.ket - - + + - - + + - + @@ -1149,9 +1149,9 @@ Claisen.ket - + - + @@ -1161,8 +1161,8 @@ Claisen.ket - - + + @@ -1203,14 +1203,14 @@ Claisen.ket - - + + - - + + - + @@ -1228,9 +1228,9 @@ Claisen.ket - + - + @@ -1241,8 +1241,8 @@ Claisen.rxn - - + + @@ -1257,20 +1257,20 @@ Claisen.rxn - - - - - - - - + + + + + + + + O - - - + + + @@ -1283,17 +1283,17 @@ Claisen.rxn - - - - - - - - - - - + + + + + + + + + + + OH @@ -1308,7 +1308,7 @@ Claisen.rxn - + @@ -1320,8 +1320,8 @@ Claisen.rxn - - + + @@ -1336,20 +1336,20 @@ Claisen.rxn - - - - - - - - + + + + + + + + O - - - + + + @@ -1362,17 +1362,17 @@ Claisen.rxn - - - - - - - - - - - + + + + + + + + + + + OH @@ -1387,7 +1387,7 @@ Claisen.rxn - + @@ -1400,8 +1400,8 @@ Markush6.rxn - - + + @@ -1416,36 +1416,36 @@ Markush6.rxn - - - - - - - - - + + + + + + + + + OH - - + + O - - + + H - - + + H - - - + + + R1 @@ -1463,33 +1463,33 @@ Markush6.rxn - - + + N - - + + H - - + + H - - - - - - + + + + + + NH - - - + + + R2 @@ -1504,56 +1504,56 @@ Markush6.rxn - - - - - - - - - + + + + + + + + + N - - + + O - - + + H - - + + H - - + + H - - - - - - + + + + + + NH - - - + + + R2 - - - + + + R1 @@ -1578,10 +1578,10 @@ Markush6.rxn - + + - + @@ -1593,8 +1593,8 @@ Markush6.rxn - - + + @@ -1609,36 +1609,36 @@ Markush6.rxn - - - - - - - - - + + + + + + + + + OH - - + + O - - + + H - - + + H - - - + + + R1 @@ -1656,33 +1656,33 @@ Markush6.rxn - - + + N - - + + H - - + + H - - - - - - + + + + + + NH - - - + + + R2 @@ -1697,56 +1697,56 @@ Markush6.rxn - - - - - - - - - + + + + + + + + + N - - + + O - - + + H - - + + H - - + + H - - - - - - + + + + + + NH - - - + + + R2 - - - + + + R1 @@ -1771,10 +1771,10 @@ Markush6.rxn - + + - + @@ -1789,8 +1789,8 @@ molfile loader: atom lists are allowed only for queries - - + + @@ -1805,76 +1805,76 @@ molfile loader: atom lists are allowed only for queries - - + + A - - - + + + H - - + + A - - + + Cl,Br,I - - + + - - + + OH - - + + H - - + + A - - - + + + H - - + + A - - + + OH - - + + - + + - + @@ -1887,8 +1887,8 @@ amiderxn3.rxn - - + + @@ -1903,19 +1903,19 @@ amiderxn3.rxn - - + + R1 - - - + + + O - - + + OH @@ -1924,55 +1924,55 @@ amiderxn3.rxn - - + + NH 2 - - + + R2 - - + + R3 - - + + SH - - + + - - + + R1 - - - + + + O - - + + NH - - + + R2 @@ -1982,32 +1982,32 @@ amiderxn3.rxn - - + + R3 - - + + SH - - + + - + + - + + - + + - + @@ -2019,8 +2019,8 @@ amiderxn3.rxn - - + + @@ -2035,19 +2035,19 @@ amiderxn3.rxn - - + + R1 - - - + + + O - - + + OH @@ -2056,55 +2056,55 @@ amiderxn3.rxn - - + + NH 2 - - + + R2 - - + + R3 - - + + SH - - + + - - + + R1 - - - + + + O - - + + NH - - + + R2 @@ -2114,32 +2114,32 @@ amiderxn3.rxn - - + + R3 - - + + SH - - + + - + + - + + - + + - + @@ -2152,8 +2152,8 @@ only_products.rxn - - + + @@ -2168,12 +2168,12 @@ only_products.rxn - - - - - - + + + + + + @@ -2182,12 +2182,12 @@ only_products.rxn - - - - - - + + + + + + @@ -2195,10 +2195,10 @@ only_products.rxn - + + - + @@ -2210,8 +2210,8 @@ only_products.rxn - - + + @@ -2226,12 +2226,12 @@ only_products.rxn - - - - - - + + + + + + @@ -2240,12 +2240,12 @@ only_products.rxn - - - - - - + + + + + + @@ -2253,10 +2253,10 @@ only_products.rxn - + + - + @@ -2269,8 +2269,8 @@ only_reactants.rxn - - + + @@ -2285,12 +2285,12 @@ only_reactants.rxn - - - - - - + + + + + + @@ -2299,12 +2299,12 @@ only_reactants.rxn - - - - - - + + + + + + @@ -2312,10 +2312,10 @@ only_reactants.rxn - + + - + @@ -2327,8 +2327,8 @@ only_reactants.rxn - - + + @@ -2343,12 +2343,12 @@ only_reactants.rxn - - - - - - + + + + + + @@ -2357,12 +2357,12 @@ only_reactants.rxn - - - - - - + + + + + + @@ -2370,10 +2370,10 @@ only_reactants.rxn - + + - + @@ -2386,8 +2386,8 @@ v3000.rxn - - + + @@ -2402,10 +2402,10 @@ v3000.rxn - - - - + + + + Br @@ -2413,14 +2413,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2428,14 +2428,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2443,14 +2443,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2458,14 +2458,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2473,14 +2473,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2488,50 +2488,50 @@ v3000.rxn - - - - + + + + NH - + - - - - + + + + NH - + - + + - + + - + + - + + - + + - + + - + @@ -2543,8 +2543,8 @@ v3000.rxn - - + + @@ -2559,10 +2559,10 @@ v3000.rxn - - - - + + + + Br @@ -2570,14 +2570,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2585,14 +2585,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2600,14 +2600,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2615,14 +2615,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2630,14 +2630,14 @@ v3000.rxn - - + + NH - - - + + + H @@ -2645,50 +2645,50 @@ v3000.rxn - - - - + + + + NH - + - - - - + + + + NH - + - + + - + + - + + - + + - + + - + + - + diff --git a/api/tests/integration/tests/formats/rxn_to_cdxml.py b/api/tests/integration/tests/formats/rxn_to_cdxml.py index 7259f38261..4f58a19871 100644 --- a/api/tests/integration/tests/formats/rxn_to_cdxml.py +++ b/api/tests/integration/tests/formats/rxn_to_cdxml.py @@ -21,16 +21,13 @@ print("*** Try as Reaction ***") rxn = indigo.loadReactionFromFile(os.path.join(root, filename)) indigo.setOption("layout-horintervalfactor", "1.4") - rxn.layout() print(rxn.cdxml()) print("*** Compare with QueryReaction ***") rxn2 = indigo.loadQueryReactionFromFile(os.path.join(root, filename)) - rxn2.layout() print(rxn2.cdxml()) except IndigoException as e: print(getIndigoExceptionText(e)) print("*** Try as QueryReaction ***") rxn = indigo.loadQueryReactionFromFile(os.path.join(root, filename)) indigo.setOption("layout-horintervalfactor", "1.4") - rxn.layout() print(rxn.cdxml()) diff --git a/api/wasm/indigo-ketcher/indigo-ketcher.cpp b/api/wasm/indigo-ketcher/indigo-ketcher.cpp index fb3e134e6a..c22fcd2e90 100644 --- a/api/wasm/indigo-ketcher/indigo-ketcher.cpp +++ b/api/wasm/indigo-ketcher/indigo-ketcher.cpp @@ -139,6 +139,10 @@ namespace indigo { return _checkResultString(indigoCml(id())); } + else if (outputFormat == "cdxml" || outputFormat == "chemical/x-cdxml") + { + return _checkResultString(indigoCdxml(id())); + } else if (outputFormat == "inchi" || outputFormat == "chemical/x-inchi") { return _checkResultString(indigoInchiGetInchi(id())); diff --git a/core/indigo-core/common/base_cpp/properties_map.cpp b/core/indigo-core/common/base_cpp/properties_map.cpp index 65a6283b77..f8312436c3 100644 --- a/core/indigo-core/common/base_cpp/properties_map.cpp +++ b/core/indigo-core/common/base_cpp/properties_map.cpp @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ +#include #include "base_cpp/properties_map.h" @@ -38,6 +39,12 @@ void PropertiesMap::copy(PropertiesMap& other) insert(other.key(p), other.value(p)); } } + +void PropertiesMap::insert(const char* key, const std::string& value) +{ + insert(key, value.c_str()); +} + void PropertiesMap::insert(const char* key, const char* value) { if (_properties.find(key)) diff --git a/core/indigo-core/common/base_cpp/properties_map.h b/core/indigo-core/common/base_cpp/properties_map.h index a2df3a2eba..fc35aaa735 100644 --- a/core/indigo-core/common/base_cpp/properties_map.h +++ b/core/indigo-core/common/base_cpp/properties_map.h @@ -45,6 +45,8 @@ namespace indigo void copy(RedBlackStringObjMap>& properties); void copy(PropertiesMap&); void insert(const char* key, const char* value); + void insert(const char* key, const std::string& value); + Array& insert(const char* key); const char* key(int); diff --git a/core/indigo-core/common/math/algebra.h b/core/indigo-core/common/math/algebra.h index 498b1119b5..310e5d05e5 100644 --- a/core/indigo-core/common/math/algebra.h +++ b/core/indigo-core/common/math/algebra.h @@ -417,6 +417,16 @@ namespace indigo return Vec2f(middleX(), middleY()); } + inline float width() const + { + return _rightTop.x - _leftBottom.x; + } + + inline float height() const + { + return _rightTop.y - _leftBottom.y; + } + protected: Vec2f _leftBottom; Vec2f _rightTop; diff --git a/core/indigo-core/molecule/base_molecule.h b/core/indigo-core/molecule/base_molecule.h index ca879b4aaf..20988fa6de 100644 --- a/core/indigo-core/molecule/base_molecule.h +++ b/core/indigo-core/molecule/base_molecule.h @@ -94,7 +94,6 @@ namespace indigo SKIP_ATTACHMENT_POINTS = 0x10, SKIP_TGROUPS = 0x20, SKIP_TEMPLATE_ATTACHMENT_POINTS = 0x40, - COPY_BOND_DIRECTIONS = 0x80 }; class Molecule; diff --git a/core/indigo-core/molecule/ket_commons.h b/core/indigo-core/molecule/ket_commons.h index e5161db7e4..89afef6428 100644 --- a/core/indigo-core/molecule/ket_commons.h +++ b/core/indigo-core/molecule/ket_commons.h @@ -32,6 +32,11 @@ namespace indigo { const double KETDefaultFontSize = 13; const double KETFontScaleFactor = 47; + const auto KETFontBoldStr = "BOLD"; + const auto KETFontItalicStr = "ITALIC"; + const auto KETFontSuperscriptStr = "SUPERSCRIPT"; + const auto KETFontSubscriptStr = "SUBSCRIPT"; + const auto KETFontCustomSizeStr = "CUSTOM_FONT_SIZE"; struct compareFunction { @@ -53,8 +58,6 @@ namespace indigo return string_hash(s, count); } - const std::unordered_map KTextStylesMap{{"BOLD", 0}, {"ITALIC", 1}, {"SUPERSCRIPT", 2}, {"SUBSCRIPT", 3}}; - class KETSimpleObject : public MetaObject { public: @@ -85,13 +88,17 @@ namespace indigo public: enum { - EBold = 0, - EItalic = 1, - ESuperScript = 2, - ESubScript = 3, - EFontSize = 4 + EPlain = 0, + EBold = 1, + EItalic = 2, + ESuperScript = 3, + ESubScript = 4, + EFontSize = 5 }; + const std::unordered_map KTextStylesMap{ + {KETFontBoldStr, EBold}, {KETFontItalicStr, EItalic}, {KETFontSuperscriptStr, ESuperScript}, {KETFontSubscriptStr, ESubScript}}; + struct KETTextLine { std::string text; diff --git a/core/indigo-core/molecule/metadata_storage.h b/core/indigo-core/molecule/metadata_storage.h index a4efef968c..1e8392daca 100644 --- a/core/indigo-core/molecule/metadata_storage.h +++ b/core/indigo-core/molecule/metadata_storage.h @@ -38,12 +38,13 @@ namespace indigo public: DECL_ERROR; void clone(const MetaDataStorage& other); + void append(const MetaDataStorage& other); virtual ~MetaDataStorage() { } - void addMetaObject(MetaObject* pobj); + int addMetaObject(MetaObject* pobj); void resetMetaData() { diff --git a/core/indigo-core/molecule/molecule_cdxml_loader.h b/core/indigo-core/molecule/molecule_cdxml_loader.h index aa52fb9cda..a7c2e5957d 100644 --- a/core/indigo-core/molecule/molecule_cdxml_loader.h +++ b/core/indigo-core/molecule/molecule_cdxml_loader.h @@ -38,6 +38,8 @@ typedef int INT32; typedef unsigned int UINT32; #include "molecule/CDXConstants.h" +const int KCDXMLChemicalFontStyle = 96; + namespace tinyxml2 { class XMLHandle; @@ -77,6 +79,23 @@ namespace indigo int val; }; + union CDXMLFontStyle { + CDXMLFontStyle(unsigned int val) : face(val) + { + } + struct + { + unsigned int is_bold : 1; + unsigned int is_italic : 1; + unsigned int is_underline : 1; + unsigned int is_outline : 1; + unsigned int is_shadow : 1; + unsigned int is_subscript : 1; + unsigned int is_superscript : 1; + }; + unsigned int face; + }; + struct _ExtConnection { int bond_id; @@ -156,20 +175,30 @@ namespace indigo MoleculeCdxmlLoader(Scanner& scanner); void loadMolecule(BaseMolecule& mol); + void loadMoleculeFromFragment(BaseMolecule& mol, tinyxml2::XMLElement* pElem); + + static void applyDispatcher(const tinyxml2::XMLAttribute* pAttr, + const std::unordered_map>& dispatcher); + void parseCDXMLAttributes(const tinyxml2::XMLAttribute* pAttr); + void parseBBox(const std::string& data, Rect2f& bbox); + void parsePos(const std::string& data, Vec3f& bbox); StereocentersOptions stereochemistry_options; bool ignore_bad_valence; bool _has_bounding_box; - Rect2f _cdxml_bbox; - AutoInt _cdxml_bond_length; - std::vector _nodes; - std::vector _bonds; - std::vector _brackets; + Rect2f cdxml_bbox; + AutoInt cdxml_bond_length; + std::vector nodes; + std::vector bonds; + std::vector brackets; + static const int SCALE = 30; protected: Scanner* _scanner; const tinyxml2::XMLNode* _fragment; - void _parseCDXMLAttributes(const tinyxml2::XMLAttribute* pAttr); + void _initMolecule(BaseMolecule& mol); + void _parseCollections(BaseMolecule& mol); + void _parseNode(CdxmlNode& node, tinyxml2::XMLElement* pElem); void _addNode(CdxmlNode& node); @@ -177,14 +206,16 @@ namespace indigo void _addBond(CdxmlBond& node); void _parseBracket(CdxmlBracket& bracket, const tinyxml2::XMLAttribute* pAttr); + void _parseText(const tinyxml2::XMLElement* pElem); + void _parseGraphic(const tinyxml2::XMLElement* pElem); + void _parseArrow(const tinyxml2::XMLElement* pElem); - void _applyDispatcher(const tinyxml2::XMLAttribute* pAttr, const std::unordered_map>& dispatcher); void _addAtomsAndBonds(BaseMolecule& mol, const std::vector& atoms, const std::vector& bonds); void _addBracket(BaseMolecule& mol, const CdxmlBracket& bracket); void _handleSGroup(SGroup& sgroup, const std::unordered_set& atoms, BaseMolecule& bmol); void _parseCDXMLPage(tinyxml2::XMLElement* pElem); - void _parseCDXMLFragment(tinyxml2::XMLElement* pElem); + void _parseCDXMLElements(tinyxml2::XMLElement* pElem, bool no_siblings = false); void _parseFragmentAttributes(const tinyxml2::XMLAttribute* pAttr); void _appendQueryAtom(const char* atom_label, std::unique_ptr& atom); @@ -196,6 +227,13 @@ namespace indigo std::unordered_map _id_to_node_index; std::unordered_map _id_to_bond_index; std::vector _fragment_nodes; + std::vector> _text_objects; + std::vector _pluses; + std::vector, int>> _arrows; + + std::unordered_set _superced_ids; + + float _bond_length; private: MoleculeCdxmlLoader(const MoleculeCdxmlLoader&); // no implicit copy diff --git a/core/indigo-core/molecule/molecule_cdxml_saver.h b/core/indigo-core/molecule/molecule_cdxml_saver.h index 2bf0814287..b4969e3e86 100644 --- a/core/indigo-core/molecule/molecule_cdxml_saver.h +++ b/core/indigo-core/molecule/molecule_cdxml_saver.h @@ -22,6 +22,7 @@ #include #include "base_cpp/properties_map.h" +#include "ket_commons.h" #include "math/algebra.h" namespace tinyxml2 @@ -44,11 +45,8 @@ namespace indigo ~MoleculeCdxmlSaver(); void saveMolecule(BaseMolecule& mol); - enum - { - BOND_LENGTH = 30 - }; - + static const int SCALE = 30; + static const int MAX_PAGE_HEIGHT = 64; struct Bounds { Vec2f min, max; @@ -61,11 +59,12 @@ namespace indigo void addColorTable(const char* color); void addColorToTable(int id, int r, int g, int b); void saveMoleculeFragment(BaseMolecule& mol, const Vec2f& offset, float scale, int id, Array& nodes_ids); + void addMetaData(const MetaDataStorage& meta, int id); void addText(const Vec2f& pos, const char* text); void addText(const Vec2f& pos, const char* text, const char* alignment); void addCustomText(const Vec2f& pos, const char* alignment, float line_height, const char* text); void addTitle(const Vec2f& pos, const char* text); - void addGraphic(int id, const Vec2f& p1, const Vec2f& p2, PropertiesMap& attrs); + void addElement(const char* element, int id, const Vec2f& p1, const Vec2f& p2, PropertiesMap& attrs); void addCustomElement(int id, Array& name, PropertiesMap& attrs); void startCurrentElement(int id, Array& name, PropertiesMap& attrs); void endCurrentElement(); diff --git a/core/indigo-core/molecule/src/base_molecule.cpp b/core/indigo-core/molecule/src/base_molecule.cpp index 705976f0ac..a9ce50c04a 100644 --- a/core/indigo-core/molecule/src/base_molecule.cpp +++ b/core/indigo-core/molecule/src/base_molecule.cpp @@ -92,8 +92,8 @@ void BaseMolecule::clear() use_scsr_name = false; expand_mod_templates = false; ignore_chem_templates = false; - updateEditRevision(); + _meta.resetMetaData(); } bool BaseMolecule::hasCoord(BaseMolecule& mol) @@ -267,6 +267,7 @@ void BaseMolecule::_mergeWithSubmolecule_Sub(BaseMolecule& mol, const Array reaction_atom_inversion.expandFill(vertexEnd(), 0); reaction_atom_exact_change.expandFill(vertexEnd(), 0); reaction_bond_reacting_center.expandFill(edgeEnd(), 0); + _bond_directions.expandFill(edgeEnd(), -1); for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) { @@ -278,37 +279,13 @@ void BaseMolecule::_mergeWithSubmolecule_Sub(BaseMolecule& mol, const Array reaction_atom_exact_change[mapping[i]] = mol.reaction_atom_exact_change[i]; } - if (skip_flags & COPY_BOND_DIRECTIONS) - { - _bond_directions.expandFill(edgeEnd() + mol.edgeEnd(), 0); - } - else - _bond_directions.expandFill(mol.edgeEnd(), 0); - for (int j = mol.edgeBegin(); j != mol.edgeEnd(); j = mol.edgeNext(j)) { - const Edge& edge = mol.getEdge(j); - - if ((mapping[edge.beg] > -1) && (mapping[edge.end] > -1)) - { - int bond_idx = findEdgeIndex(mapping[edge.beg], mapping[edge.end]); - if (bond_idx > -1) - { - reaction_bond_reacting_center[bond_idx] = mol.reaction_bond_reacting_center[j]; - } - } - } - - // trick for molecules with incorrect stereochemistry, of which we do permutations - if ((skip_flags & COPY_BOND_DIRECTIONS) || (vertexCount() == mol.vertexCount() && edgeCount() == mol.edgeCount())) - { - for (int j = mol.edgeBegin(); j != mol.edgeEnd(); j = mol.edgeNext(j)) - { - const Edge& edge = mol.getEdge(j); - - if (mol.getBondDirection(j) != 0) - _bond_directions[findEdgeIndex(mapping[edge.beg], mapping[edge.end])] = mol.getBondDirection(j); - } + int edge_idx = edge_mapping[j]; + if (edge_idx < 0) + continue; + reaction_bond_reacting_center[edge_idx] = mol.reaction_bond_reacting_center[j]; + _bond_directions[edge_idx] = mol.getBondDirection(j); } // RGroups diff --git a/core/indigo-core/molecule/src/metadata_storage.cpp b/core/indigo-core/molecule/src/metadata_storage.cpp index 9f7d430935..5ee8c7912d 100644 --- a/core/indigo-core/molecule/src/metadata_storage.cpp +++ b/core/indigo-core/molecule/src/metadata_storage.cpp @@ -6,7 +6,7 @@ using namespace indigo; IMPL_ERROR(MetaDataStorage, "metadata storage"); -void MetaDataStorage::addMetaObject(MetaObject* pobj) +int MetaDataStorage::addMetaObject(MetaObject* pobj) { int index = _meta_data.size(); _meta_data.expand(index + 1); @@ -29,16 +29,22 @@ void MetaDataStorage::addMetaObject(MetaObject* pobj) default: break; } + return index; } -void MetaDataStorage::clone(const MetaDataStorage& other) +void MetaDataStorage::append(const MetaDataStorage& other) { - resetMetaData(); const auto& meta = other.metaData(); for (int i = 0; i < meta.size(); i++) addMetaObject(meta[i]->clone()); } +void MetaDataStorage::clone(const MetaDataStorage& other) +{ + resetMetaData(); + append(other); +} + const MetaObject& MetaDataStorage::getMetaObject(uint32_t meta_type, int index) const { switch (meta_type) diff --git a/core/indigo-core/molecule/src/molecule_auto_loader.cpp b/core/indigo-core/molecule/src/molecule_auto_loader.cpp index 95fde3fe69..e2fa095046 100644 --- a/core/indigo-core/molecule/src/molecule_auto_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_auto_loader.cpp @@ -325,6 +325,8 @@ void MoleculeAutoLoader::_loadMolecule(BaseMolecule& mol, bool query) _scanner->skipSpace(); if (_scanner->lookNext() == '<' && _scanner->findWord("CDXML")) { + if (_scanner->findWord("seek(pos, SEEK_SET); MoleculeCdxmlLoader loader(*_scanner); loader.stereochemistry_options = stereochemistry_options; diff --git a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp index 05a687d101..b4e2892b2e 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_loader.cpp @@ -16,17 +16,21 @@ * limitations under the License. ***************************************************************************/ -#include "molecule/molecule_cdxml_loader.h" - +#include +#include +#include #include #include "base_cpp/scanner.h" #include "molecule/elements.h" +#include "molecule/ket_commons.h" #include "molecule/molecule.h" +#include "molecule/molecule_cdxml_loader.h" #include "molecule/molecule_scaffold_detection.h" using namespace indigo; using namespace tinyxml2; +using namespace rapidjson; static float readFloat(const char* point_str) { @@ -46,9 +50,18 @@ MoleculeCdxmlLoader::MoleculeCdxmlLoader(Scanner& scanner) _scanner = &scanner; } -void MoleculeCdxmlLoader::loadMolecule(BaseMolecule& mol) +void MoleculeCdxmlLoader::_initMolecule(BaseMolecule& mol) { mol.clear(); + nodes.clear(); + bonds.clear(); + _id_to_atom_idx.clear(); + _id_to_node_index.clear(); + _id_to_bond_index.clear(); + _fragment_nodes.clear(); + _text_objects.clear(); + _pluses.clear(); + brackets.clear(); _pmol = NULL; _pqmol = NULL; if (mol.isQueryMolecule()) @@ -60,7 +73,11 @@ void MoleculeCdxmlLoader::loadMolecule(BaseMolecule& mol) _pmol = &mol.asMolecule(); _pmol->setIgnoreBadValenceFlag(ignore_bad_valence); } +} +void MoleculeCdxmlLoader::loadMolecule(BaseMolecule& mol) +{ + _initMolecule(mol); if (_scanner != 0) { QS_DEF(Array, buf); @@ -72,79 +89,104 @@ void MoleculeCdxmlLoader::loadMolecule(BaseMolecule& mol) if (xml.Error()) throw Error("XML parsing error: %s", xml.ErrorStr()); - _parseCDXMLAttributes(xml.RootElement()->FirstAttribute()); + parseCDXMLAttributes(xml.RootElement()->FirstAttribute()); _parseCDXMLPage(xml.RootElement()); - if (!_nodes.size()) + if (!nodes.size()) throw Error("CDXML has no data"); - std::vector atoms; - for (auto& node : _nodes) + _parseCollections(mol); + } +} + +void MoleculeCdxmlLoader::_parseCollections(BaseMolecule& mol) +{ + std::vector atoms; + for (auto& node : nodes) + { + int node_idx = _id_to_node_index.at(node.id); + switch (node.type) { - int node_idx = _id_to_node_index.at(node.id); - switch (node.type) - { - case kCDXNodeType_Element: - case kCDXNodeType_ElementList: - atoms.push_back(node_idx); - break; - case kCDXNodeType_ExternalConnectionPoint: - break; - case kCDXNodeType_Fragment: - _fragment_nodes.push_back(node_idx); - break; - default: - break; - } + case kCDXNodeType_Element: + case kCDXNodeType_ElementList: + atoms.push_back(node_idx); + break; + case kCDXNodeType_ExternalConnectionPoint: + break; + case kCDXNodeType_Fragment: + _fragment_nodes.push_back(node_idx); + break; + default: + break; } + } - _addAtomsAndBonds(mol, atoms, _bonds); + _addAtomsAndBonds(mol, atoms, bonds); - for (auto& brk : _brackets) - _addBracket(mol, brk); + for (auto& brk : brackets) + _addBracket(mol, brk); + + for (const auto& to : _text_objects) + mol.meta().addMetaObject(new KETTextObject(to.first, to.second)); + + for (const auto& plus : _pluses) + mol.meta().addMetaObject(new KETReactionPlus(plus)); + + for (const auto& arrow : _arrows) + { + const auto& arr_info = arrow.first; + Vec2f v1(arr_info.first.x, arr_info.first.y); + Vec2f v2(arr_info.second.x, arr_info.second.y); + mol.meta().addMetaObject(new KETReactionArrow(arrow.second, v1, v2)); } } -void MoleculeCdxmlLoader::_parseCDXMLAttributes(const XMLAttribute* pAttr) +void MoleculeCdxmlLoader::loadMoleculeFromFragment(BaseMolecule& mol, tinyxml2::XMLElement* pElem) +{ + _initMolecule(mol); + _parseCDXMLElements(pElem, true); + _parseCollections(mol); +} + +void MoleculeCdxmlLoader::parseCDXMLAttributes(const XMLAttribute* pAttr) { - auto cdxml_bbox_lambda = [this](std::string& data) { + auto cdxml_bbox_lambda = [this](const std::string& data) { std::vector coords = split(data, ' '); if (coords.size() == 4) { this->_has_bounding_box = true; - this->_cdxml_bbox = Rect2f(Vec2f(std::stof(coords[0]), std::stof(coords[1])), Vec2f(std::stof(coords[2]), std::stof(coords[3]))); + this->cdxml_bbox = Rect2f(Vec2f(std::stof(coords[0]), std::stof(coords[1])), Vec2f(std::stof(coords[2]), std::stof(coords[3]))); } else throw Error("Not enought coordinates for atom position"); }; - auto& bond_length = _cdxml_bond_length; - auto cdxml_bond_length_lambda = [&bond_length](std::string& data) { bond_length = data; }; - std::unordered_map> cdxml_dispatcher = {{"BoundingBox", cdxml_bbox_lambda}, - {"BondLength", cdxml_bond_length_lambda}}; - _applyDispatcher(pAttr, cdxml_dispatcher); + auto& bond_length = cdxml_bond_length; + auto cdxml_bond_length_lambda = [&bond_length](const std::string& data) { bond_length = data; }; + std::unordered_map> cdxml_dispatcher = {{"BoundingBox", cdxml_bbox_lambda}, + {"BondLength", cdxml_bond_length_lambda}}; + applyDispatcher(pAttr, cdxml_dispatcher); } void MoleculeCdxmlLoader::_parseCDXMLPage(XMLElement* pElem) { - auto pPageElem = pElem->FirstChildElement(); - for (pPageElem; pPageElem; pPageElem = pPageElem->NextSiblingElement()) + for (auto pPageElem = pElem->FirstChildElement(); pPageElem; pPageElem = pPageElem->NextSiblingElement()) { if (std::string(pPageElem->Value()).compare("page") == 0) { - _parseCDXMLFragment(pPageElem->FirstChildElement()); + _parseCDXMLElements(pPageElem->FirstChildElement()); } } } -void MoleculeCdxmlLoader::_parseCDXMLFragment(XMLElement* pElem) +void MoleculeCdxmlLoader::_parseCDXMLElements(XMLElement* pElem, bool no_siblings) { auto node_lambda = [this](XMLElement* pElem) { CdxmlNode node; this->_parseNode(node, pElem); _addNode(node); if (node.type == kCDXNodeType_Fragment) - this->_parseCDXMLFragment(pElem->FirstChildElement()); + this->_parseCDXMLElements(pElem->FirstChildElement()); }; auto bond_lambda = [this](XMLElement* pElem) { @@ -155,19 +197,26 @@ void MoleculeCdxmlLoader::_parseCDXMLFragment(XMLElement* pElem) auto fragment_lambda = [this](XMLElement* pElem) { this->_parseFragmentAttributes(pElem->FirstAttribute()); - this->_parseCDXMLFragment(pElem->FirstChildElement()); + this->_parseCDXMLElements(pElem->FirstChildElement()); }; - auto group_lambda = [this](XMLElement* pElem) { this->_parseCDXMLFragment(pElem->FirstChildElement()); }; + auto group_lambda = [this](XMLElement* pElem) { this->_parseCDXMLElements(pElem->FirstChildElement()); }; auto bracketed_lambda = [this](XMLElement* pElem) { CdxmlBracket bracket; this->_parseBracket(bracket, pElem->FirstAttribute()); - this->_brackets.push_back(bracket); + this->brackets.push_back(bracket); }; + auto text_lambda = [this](XMLElement* pElem) { this->_parseText(pElem); }; + + auto graphic_lambda = [this](XMLElement* pElem) { this->_parseGraphic(pElem); }; + + auto arrow_lambda = [this](XMLElement* pElem) { this->_parseArrow(pElem); }; + std::unordered_map> cdxml_dispatcher = { - {"n", node_lambda}, {"b", bond_lambda}, {"fragment", fragment_lambda}, {"group", group_lambda}, {"bracketedgroup", bracketed_lambda}}; + {"n", node_lambda}, {"b", bond_lambda}, {"fragment", fragment_lambda}, {"group", group_lambda}, {"bracketedgroup", bracketed_lambda}, + {"t", text_lambda}, {"graphic", graphic_lambda}, {"arrow", arrow_lambda}}; for (pElem; pElem; pElem = pElem->NextSiblingElement()) { @@ -178,8 +227,9 @@ void MoleculeCdxmlLoader::_parseCDXMLFragment(XMLElement* pElem) } else { - // printf("Unhandled cdxml tag: %s\n", pElem->Value()); } + if (no_siblings) + break; } } @@ -187,7 +237,7 @@ void MoleculeCdxmlLoader::_updateConnection(const CdxmlNode& node, int atom_idx) { for (auto fidx : _fragment_nodes) { - auto& frag_node = _nodes[fidx]; + auto& frag_node = nodes[fidx]; auto fit = frag_node.node_id_to_connection_idx.find(node.id); if (fit != frag_node.node_id_to_connection_idx.end()) { @@ -210,7 +260,7 @@ void MoleculeCdxmlLoader::_addAtomsAndBonds(BaseMolecule& mol, const std::vector int atom_idx; for (auto atom_idx : atoms) { - auto& atom = _nodes[atom_idx]; + auto& atom = nodes[atom_idx]; if (_pmol) { atom_idx = _pmol->addAtom(atom.element); @@ -236,8 +286,8 @@ void MoleculeCdxmlLoader::_addAtomsAndBonds(BaseMolecule& mol, const std::vector { auto bond_first_it = _id_to_atom_idx.find(bond.be.first); auto bond_second_it = _id_to_atom_idx.find(bond.be.second); - auto& fn = _nodes[_id_to_node_index.at(bond.be.first)]; - auto& sn = _nodes[_id_to_node_index.at(bond.be.second)]; + auto& fn = nodes[_id_to_node_index.at(bond.be.first)]; + auto& sn = nodes[_id_to_node_index.at(bond.be.second)]; if (bond_first_it != _id_to_atom_idx.end() && bond_second_it != _id_to_atom_idx.end()) { @@ -343,7 +393,6 @@ void MoleculeCdxmlLoader::_addBracket(BaseMolecule& mol, const CdxmlBracket& bra default: break; } - _handleSGroup(sgroup, sgroup_atoms, mol); } } @@ -436,9 +485,9 @@ void MoleculeCdxmlLoader::_parseFragmentAttributes(const XMLAttribute* pAttr) { // it means that we are inside of NodeType=Fragment // let's check it - if (_nodes.size() && _nodes.back().type == kCDXNodeType_Fragment) + if (nodes.size() && nodes.back().type == kCDXNodeType_Fragment) { - auto& fn = _nodes.back(); + auto& fn = nodes.back(); auto vec_str = split(pAttr->Value(), ' '); if (fn.connections.size() == vec_str.size()) { @@ -458,7 +507,7 @@ void MoleculeCdxmlLoader::_parseFragmentAttributes(const XMLAttribute* pAttr) } } -void MoleculeCdxmlLoader::_applyDispatcher(const XMLAttribute* pAttr, const std::unordered_map>& dispatcher) +void MoleculeCdxmlLoader::applyDispatcher(const XMLAttribute* pAttr, const std::unordered_map>& dispatcher) { for (pAttr; pAttr; pAttr = pAttr->Next()) { @@ -474,15 +523,15 @@ void MoleculeCdxmlLoader::_applyDispatcher(const XMLAttribute* pAttr, const std: void MoleculeCdxmlLoader::_parseNode(CdxmlNode& node, XMLElement* pElem) { // Atom parsing lambdas definition - auto id_lambda = [&node](std::string& data) { node.id = data; }; - auto hydrogens_lambda = [&node](std::string& data) { node.hydrogens = data; }; - auto charge_lambda = [&node](std::string& data) { node.charge = data; }; - auto element_lambda = [&node](std::string& data) { node.element = data; }; - auto isotope_lambda = [&node](std::string& data) { node.isotope = data; }; - auto radical_lambda = [&node](std::string& data) { node.radical = data; }; - auto label_lambda = [&node](std::string& data) { node.label = data; }; - - auto bond_ordering_lambda = [&node](std::string& data) { + auto id_lambda = [&node](const std::string& data) { node.id = data; }; + auto hydrogens_lambda = [&node](const std::string& data) { node.hydrogens = data; }; + auto charge_lambda = [&node](const std::string& data) { node.charge = data; }; + auto element_lambda = [&node](const std::string& data) { node.element = data; }; + auto isotope_lambda = [&node](const std::string& data) { node.isotope = data; }; + auto radical_lambda = [&node](const std::string& data) { node.radical = data; }; + auto label_lambda = [&node](const std::string& data) { node.label = data; }; + + auto bond_ordering_lambda = [&node](const std::string& data) { auto vec_str = split(data, ' '); for (auto& str : vec_str) { @@ -492,29 +541,14 @@ void MoleculeCdxmlLoader::_parseNode(CdxmlNode& node, XMLElement* pElem) } }; - auto pos_lambda = [&node, this](std::string& data) { - std::vector coords = split(data, ' '); - if (coords.size() >= 2) - { - node.pos.x = std::stof(coords[0]); - node.pos.y = std::stof(coords[1]); - if (this->_has_bounding_box) - node.pos.y = this->_cdxml_bbox.top() - node.pos.y; - if (coords.size() == 3) - node.pos.z = std::stof(coords[2]); - else - node.pos.z = 0; - } - else - throw Error("Not enought coordinates for atom position"); - }; + auto pos_lambda = [&node, this](const std::string& data) { this->parsePos(data, node.pos); }; - auto stereo_lambda = [&node](std::string& data) { + auto stereo_lambda = [&node](const std::string& data) { static const std::unordered_map cip_map = {{"U", 0}, {"N", 1}, {"R", 2}, {"S", 3}, {"r", 4}, {"s", 5}, {"u", 6}}; node.stereo = cip_map.at(data); }; - auto node_type_lambda = [&node](std::string& data) { + auto node_type_lambda = [&node](const std::string& data) { static const std::unordered_map node_type_map = {{"Unspecified", kCDXNodeType_Unspecified}, {"Element", kCDXNodeType_Element}, {"ElementList", kCDXNodeType_ElementList}, @@ -532,7 +566,7 @@ void MoleculeCdxmlLoader::_parseNode(CdxmlNode& node, XMLElement* pElem) node.type = node_type_map.at(data); }; - auto element_list_lambda = [&node](std::string& data) { + auto element_list_lambda = [&node](const std::string& data) { std::vector elements = split(data, ' '); if (elements.size() && elements.front().compare("NOT") == 0) { @@ -542,47 +576,47 @@ void MoleculeCdxmlLoader::_parseNode(CdxmlNode& node, XMLElement* pElem) node.element_list.assign(elements.begin(), elements.end()); }; - std::unordered_map> node_dispatcher = {{"id", id_lambda}, - {"p", pos_lambda}, - {"xyz", pos_lambda}, - {"NumHydrogens", hydrogens_lambda}, - {"Charge", charge_lambda}, - {"Isotope", isotope_lambda}, - {"Radical", radical_lambda}, - {"AS", stereo_lambda}, - {"NodeType", node_type_lambda}, - {"Element", element_lambda}, - {"GenericNickname", label_lambda}, - {"ElementList", element_list_lambda}, - {"BondOrdering", bond_ordering_lambda}}; - - _applyDispatcher(pElem->FirstAttribute(), node_dispatcher); + std::unordered_map> node_dispatcher = {{"id", id_lambda}, + {"p", pos_lambda}, + {"xyz", pos_lambda}, + {"NumHydrogens", hydrogens_lambda}, + {"Charge", charge_lambda}, + {"Isotope", isotope_lambda}, + {"Radical", radical_lambda}, + {"AS", stereo_lambda}, + {"NodeType", node_type_lambda}, + {"Element", element_lambda}, + {"GenericNickname", label_lambda}, + {"ElementList", element_list_lambda}, + {"BondOrdering", bond_ordering_lambda}}; + + applyDispatcher(pElem->FirstAttribute(), node_dispatcher); } void MoleculeCdxmlLoader::_addNode(CdxmlNode& node) { - _nodes.push_back(node); - _id_to_node_index.emplace(node.id, _nodes.size() - 1); + nodes.push_back(node); + _id_to_node_index.emplace(node.id, nodes.size() - 1); } void MoleculeCdxmlLoader::_addBond(CdxmlBond& bond) { - _bonds.push_back(bond); - _id_to_bond_index.emplace(bond.id, _bonds.size() - 1); + bonds.push_back(bond); + _id_to_bond_index.emplace(bond.id, bonds.size() - 1); } void MoleculeCdxmlLoader::_parseBond(CdxmlBond& bond, const XMLAttribute* pAttr) { - auto id_lambda = [&bond](std::string& data) { bond.id = data; }; - auto bond_begin_lambda = [&bond](std::string& data) { bond.be.first = data; }; - auto bond_end_lambda = [&bond](std::string& data) { bond.be.second = data; }; - auto bond_order_lambda = [&bond](std::string& data) { + auto id_lambda = [&bond](const std::string& data) { bond.id = data; }; + auto bond_begin_lambda = [&bond](const std::string& data) { bond.be.first = data; }; + auto bond_end_lambda = [&bond](const std::string& data) { bond.be.second = data; }; + auto bond_order_lambda = [&bond](const std::string& data) { static const std::unordered_map order_map = { {"1", BOND_SINGLE}, {"2", BOND_DOUBLE}, {"3", BOND_TRIPLE}, {"1.5", BOND_AROMATIC}, {"dative", _BOND_COORDINATION}, {"hydrogen", _BOND_HYDROGEN}}; bond.order = order_map.at(data); }; - auto bond_dir_lambda = [&bond](std::string& data) { + auto bond_dir_lambda = [&bond](const std::string& data) { static const std::unordered_map> dir_map = {{"WedgedHashBegin", {BOND_DOWN, false}}, {"WedgedHashEnd", {BOND_DOWN, true}}, {"WedgeBegin", {BOND_UP, false}}, @@ -599,20 +633,235 @@ void MoleculeCdxmlLoader::_parseBond(CdxmlBond& bond, const XMLAttribute* pAttr) } }; - std::unordered_map> bond_dispatcher = { + std::unordered_map> bond_dispatcher = { {"id", id_lambda}, {"B", bond_begin_lambda}, {"E", bond_end_lambda}, {"Order", bond_order_lambda}, {"Display", bond_dir_lambda}}; - _applyDispatcher(pAttr, bond_dispatcher); + applyDispatcher(pAttr, bond_dispatcher); +} + +void MoleculeCdxmlLoader::parsePos(const std::string& data, Vec3f& pos) +{ + std::vector coords = split(data, ' '); + if (coords.size() >= 2) + { + pos.x = std::stof(coords[0]); + pos.y = std::stof(coords[1]); + pos.z = 0; + if (this->_has_bounding_box) + { + pos.x -= this->cdxml_bbox.left(); + pos.y -= this->cdxml_bbox.bottom(); + } + pos.x /= SCALE; + pos.y /= -SCALE; + } + else + throw Error("Not enought coordinates"); +} + +void MoleculeCdxmlLoader::parseBBox(const std::string& data, Rect2f& bbox) +{ + std::vector coords = split(data, ' '); + if (coords.size() == 4) + { + Vec2f v1(std::stof(coords[0]), std::stof(coords[1])); + Vec2f v2(std::stof(coords[2]), std::stof(coords[3])); + if (this->_has_bounding_box) + { + v1.sub(this->cdxml_bbox.leftBottom()); + v2.sub(this->cdxml_bbox.leftBottom()); + } + v1.x /= SCALE; + v2.x /= SCALE; + v1.y /= -SCALE; + v2.y /= -SCALE; + bbox = Rect2f(v1, v2); + } + else + throw Error("Not enought coordinates for text bounding box"); +} + +void MoleculeCdxmlLoader::_parseGraphic(const XMLElement* pElem) +{ + AutoInt superseded_id = 0; + auto superseded_lambda = [&superseded_id](const std::string& data) { superseded_id = data; }; + + Rect2f graph_bbox; + auto graphic_bbox_lambda = [&graph_bbox, this](const std::string& data) { this->parseBBox(data, graph_bbox); }; + + std::string graphic_type; + auto graphic_type_lambda = [&graphic_type](const std::string& data) { graphic_type = data; }; + + std::string symbol_type; + auto symbol_type_lambda = [&symbol_type](const std::string& data) { symbol_type = data; }; + + std::string arrow_type; + auto arrow_type_lambda = [&arrow_type](const std::string& data) { arrow_type = data; }; + + AutoInt head_size; + auto head_size_lambda = [&head_size](const std::string& data) { head_size = data; }; + + std::unordered_map> graphic_dispatcher = { + {"SupersededBy", superseded_lambda}, {"BoundingBox", graphic_bbox_lambda}, {"GraphicType", graphic_type_lambda}, + {"SymbolType", symbol_type_lambda}, {"ArrowType", arrow_type_lambda}, {"HeadSize", head_size_lambda}}; + + auto pAttr = pElem->FirstAttribute(); + applyDispatcher(pAttr, graphic_dispatcher); + + if (graphic_type == "Line" && arrow_type == "FullHead") + { + } + else if (graphic_type == "Symbol" && symbol_type == "Plus") + { + _pluses.emplace_back(graph_bbox.center()); + } +} + +void MoleculeCdxmlLoader::_parseArrow(const tinyxml2::XMLElement* pElem) +{ + Rect2f text_bbox; + auto arrow_bbox_lambda = [&text_bbox, this](const std::string& data) { this->parseBBox(data, text_bbox); }; + Vec3f begin_pos; + auto arrow_begin_lambda = [&begin_pos, this](const std::string& data) { this->parsePos(data, begin_pos); }; + Vec3f end_pos; + auto arrow_end_lambda = [&end_pos, this](const std::string& data) { this->parsePos(data, end_pos); }; + std::string fill_type; + auto fill_type_lambda = [&fill_type](const std::string& data) { fill_type = data; }; + std::string arrow_head; + auto arrow_head_lambda = [&arrow_head](const std::string& data) { arrow_head = data; }; + std::string head_type; + auto head_type_lambda = [&head_type](const std::string& data) { head_type = data; }; + std::unordered_map> arrow_dispatcher = { + {"BoundingBox", arrow_bbox_lambda}, {"FillType", fill_type_lambda}, {"ArrowheadHead", arrow_head_lambda}, + {"ArrowheadType", head_type_lambda}, {"Head3D", arrow_end_lambda}, {"Tail3D", arrow_begin_lambda}}; + + auto pAttr = pElem->FirstAttribute(); + applyDispatcher(pAttr, arrow_dispatcher); + _arrows.push_back(std::make_pair(std::make_pair(begin_pos, end_pos), 2)); +} + +void MoleculeCdxmlLoader::_parseText(const XMLElement* pElem) +{ + Vec3f text_pos; + auto text_coordinates_lambda = [&text_pos, this](const std::string& data) { this->parsePos(data, text_pos); }; + + Rect2f text_bbox; + auto text_bbox_lambda = [&text_bbox, this](const std::string& data) { this->parseBBox(data, text_bbox); }; + + std::string label_justification, label_alignment; + auto label_justification_lambda = [&label_justification, this](const std::string& data) { label_justification = data; }; + auto label_justification_alignment_lambda = [&label_alignment, this](const std::string& data) { label_alignment = data; }; + + std::unordered_map> text_dispatcher = {{"p", text_coordinates_lambda}, + {"BoundingBox", text_bbox_lambda}, + {"LabelJustification", label_justification_lambda}, + {"LabelAlignment", label_justification_alignment_lambda}}; + + AutoInt font_id, font_color_id, font_face; + float font_size; + + auto style_font_lambda = [&font_id](const std::string& data) { font_id = data; }; + auto style_size_lambda = [&font_size](const std::string& data) { font_size = std::stof(data) * 1.5; }; + auto style_color_lambda = [&font_color_id](const std::string& data) { font_color_id = data; }; + auto style_face_lambda = [&font_face](const std::string& data) { font_face = data; }; + + std::unordered_map> style_dispatcher = { + {"font", style_font_lambda}, {"size", style_size_lambda}, {"color", style_color_lambda}, {"face", style_face_lambda}}; + + auto pAttr = pElem->FirstAttribute(); + applyDispatcher(pAttr, text_dispatcher); + + StringBuffer s; + Writer writer(s); + writer.StartObject(); + writer.Key("blocks"); + writer.StartArray(); + for (auto pTextStyle = pElem->FirstChildElement(); pTextStyle; pTextStyle = pTextStyle->NextSiblingElement()) + { + std::string text_element = pTextStyle->Value(); + if (text_element == "s") + { + font_face = 0; + font_size = 0.0; + auto pStyleAttribute = pTextStyle->FirstAttribute(); + applyDispatcher(pStyleAttribute, style_dispatcher); + std::vector text_vec_styles; + CDXMLFontStyle fs(font_face); + if (font_face == KCDXMLChemicalFontStyle) + { + // special case + } + else + { + if (fs.is_bold) + text_vec_styles.push_back(KETFontBoldStr); + if (fs.is_italic) + text_vec_styles.push_back(KETFontItalicStr); + if (fs.is_superscript) + text_vec_styles.push_back(KETFontSuperscriptStr); + if (fs.is_superscript) + text_vec_styles.push_back(KETFontSubscriptStr); + } + if (font_size > 0) + text_vec_styles.push_back(std::string(KETFontCustomSizeStr) + "_" + std::to_string((int)ceil(font_size)) + "px"); + + std::string label_plain = pTextStyle->GetText(); + std::remove_if(label_plain.begin(), label_plain.end(), [](char c) { return (c == '\r'); }); + + auto labels = split(label_plain, '\n'); + for (const auto& label : labels) + { + writer.StartObject(); + writer.Key("text"); + writer.String(label.c_str()); + writer.Key("inlineStyleRanges"); + writer.StartArray(); + for (auto style_str : text_vec_styles) + { + writer.StartObject(); + writer.Key("offset"); + writer.Int(0); + writer.Key("length"); + writer.Int(label.size()); + writer.Key("style"); + writer.String(style_str.c_str()); + } + writer.EndObject(); + writer.EndArray(); + + writer.Key("entityRanges"); + writer.StartArray(); + writer.EndArray(); + + writer.Key("data"); + writer.StartObject(); + writer.EndObject(); + + writer.EndObject(); + } + } + else + { + throw Error("unrecognized text element: %s", text_element.c_str()); + } + } + writer.EndArray(); + writer.Key("entityMap"); + writer.StartObject(); + writer.EndObject(); + + writer.EndObject(); + text_pos.y -= text_bbox.height() / 2; + _text_objects.emplace_back(text_pos, s.GetString()); } void MoleculeCdxmlLoader::_parseBracket(CdxmlBracket& bracket, const XMLAttribute* pAttr) { - auto bracketed_ids_lambda = [&bracket](std::string& data) { + auto bracketed_ids_lambda = [&bracket](const std::string& data) { std::vector vec_str = split(data, ' '); bracket.bracketed_list.assign(vec_str.begin(), vec_str.end()); }; - - auto bracket_usage_lambda = [&bracket](std::string& data) { + auto bracket_usage_lambda = [&bracket](const std::string& data) { static const std::unordered_map usage_map = {{"Unspecified", kCDXBracketUsage_Unspecified}, {"Unused1", kCDXBracketUsage_Unused1}, {"Unused2", kCDXBracketUsage_Unused2}, @@ -637,22 +886,22 @@ void MoleculeCdxmlLoader::_parseBracket(CdxmlBracket& bracket, const XMLAttribut bracket.usage = usage_map.at(data); }; - auto repeat_count_lambda = [&bracket](std::string& data) { bracket.repeat_count = data; }; - auto repeat_pattern_lambda = [&bracket](std::string& data) { + auto repeat_count_lambda = [&bracket](const std::string& data) { bracket.repeat_count = data; }; + auto repeat_pattern_lambda = [&bracket](const std::string& data) { static const std::unordered_map rep_map = { {"HeadToTail", RepeatingUnit::HEAD_TO_TAIL}, {"HeadToHead", RepeatingUnit::HEAD_TO_HEAD}, {"EitherUnknown", RepeatingUnit::EITHER}}; bracket.repeat_pattern = rep_map.at(data); }; - auto sru_label_lambda = [&bracket](std::string& data) { bracket.sru_label = data; }; + auto sru_label_lambda = [&bracket](const std::string& data) { bracket.sru_label = data; }; - std::unordered_map> bracket_dispatcher = {{"BracketedObjectIDs", bracketed_ids_lambda}, - {"BracketUsage", bracket_usage_lambda}, - {"RepeatCount", repeat_count_lambda}, - {"PolymerRepeatPattern", repeat_pattern_lambda}, - {"SRULabel", sru_label_lambda}}; + std::unordered_map> bracket_dispatcher = {{"BracketedObjectIDs", bracketed_ids_lambda}, + {"BracketUsage", bracket_usage_lambda}, + {"RepeatCount", repeat_count_lambda}, + {"PolymerRepeatPattern", repeat_pattern_lambda}, + {"SRULabel", sru_label_lambda}}; - _applyDispatcher(pAttr, bracket_dispatcher); + applyDispatcher(pAttr, bracket_dispatcher); } void MoleculeCdxmlLoader::_appendQueryAtom(const char* atom_label, std::unique_ptr& atom) diff --git a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp index 5e5202a82c..9e0b71a676 100644 --- a/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_cdxml_saver.cpp @@ -16,14 +16,15 @@ * limitations under the License. ***************************************************************************/ -#include "molecule/molecule_cdxml_saver.h" - +#include #include #include "base_cpp/locale_guard.h" #include "base_cpp/output.h" #include "molecule/elements.h" #include "molecule/molecule.h" +#include "molecule/molecule_cdxml_loader.h" +#include "molecule/molecule_cdxml_saver.h" #include "molecule/query_molecule.h" using namespace indigo; @@ -33,8 +34,8 @@ IMPL_ERROR(MoleculeCdxmlSaver, "molecule CDXML saver"); MoleculeCdxmlSaver::MoleculeCdxmlSaver(Output& output) : _output(output) { - _bond_length = BOND_LENGTH; - _max_page_height = 64; + _bond_length = SCALE; + _max_page_height = MAX_PAGE_HEIGHT; _pages_height = 1; } @@ -201,7 +202,6 @@ void MoleculeCdxmlSaver::addColorToTable(int id, int r, int g, int b) void MoleculeCdxmlSaver::addDefaultFontTable() { - int id = -1; Array name; PropertiesMap attrs; @@ -209,17 +209,17 @@ void MoleculeCdxmlSaver::addDefaultFontTable() attrs.clear(); name.readString("fonttable", true); - startCurrentElement(id, name, attrs); + startCurrentElement(-1, name, attrs); name.readString("font", true); - id = 3; - attrs.insert("charset", "iso-8859-1"); + int id = 1; + attrs.insert("charset", "utf-8"); attrs.insert("name", "Arial"); addCustomElement(id, name, attrs); attrs.clear(); - id = 4; - attrs.insert("charset", "iso-8859-1"); + id++; + attrs.insert("charset", "utf-8"); attrs.insert("name", "Times New Roman"); addCustomElement(id, name, attrs); @@ -667,7 +667,6 @@ void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& of } if (parity == MoleculeCisTrans::TRANS) { - std::swap(s3, s4); } QS_DEF(Array, buf); @@ -703,6 +702,235 @@ void MoleculeCdxmlSaver::saveMoleculeFragment(BaseMolecule& mol, const Vec2f& of _current = parent; } +void MoleculeCdxmlSaver::addMetaData(const MetaDataStorage& meta, int id) +{ + const auto& meta_objects = meta.metaData(); + for (int meta_index = 0; meta_index < meta_objects.size(); ++meta_index) + { + id++; + PropertiesMap attrs; + attrs.clear(); + auto pobj = meta_objects[meta_index]; + switch (pobj->_class_id) + { + case KETReactionArrow::CID: { + KETReactionArrow& ar = (KETReactionArrow&)(*pobj); + attrs.insert("FillType", "None"); + attrs.insert("ArrowheadType", "Solid"); + attrs.insert("HeadSize", "2250"); + attrs.insert("ArrowheadWidth", "563"); + switch (ar._arrow_type) + { + case KETReactionArrow::EOpenAngle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "25"); + break; + case KETReactionArrow::EFilledTriangle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "2250"); + break; + + case KETReactionArrow::EFilledBow: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "1125"); + break; + + case KETReactionArrow::EDashedOpenAngle: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "25"); + attrs.insert("LineType", "Dashed"); + break; + + case KETReactionArrow::EFailed: + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadCenterSize", "1125"); + attrs.insert("NoGo", "Cross"); + break; + + case KETReactionArrow::EBothEndsFilledTriangle: + attrs.insert("ArrowheadCenterSize", "2250"); + attrs.insert("ArrowheadHead", "Full"); + attrs.insert("ArrowheadTail", "Full"); + break; + + case KETReactionArrow::EEquilibriumFilledHalfBow: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "1125"); + attrs.insert("ArrowShaftSpacing", "300"); + break; + + case KETReactionArrow::EEquilibriumFilledTriangle: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "2250"); + attrs.insert("ArrowShaftSpacing", "300"); + break; + + case KETReactionArrow::EEquilibriumOpenAngle: + attrs.insert("ArrowheadHead", "HalfLeft"); + attrs.insert("ArrowheadTail", "HalfLeft"); + attrs.insert("ArrowheadCenterSize", "25"); + attrs.insert("ArrowShaftSpacing", "300"); + break; + + case KETReactionArrow::EUnbalancedEquilibriumFilledHalfBow: + break; + + case KETReactionArrow::EUnbalancedEquilibriumLargeFilledHalfBow: + break; + + case KETReactionArrow::EUnbalancedEquilibriumOpenHalfAngle: + break; + + case KETReactionArrow::EUnbalancedEquilibriumFilledHalfTriangle: + break; + + case KETReactionArrow::EEllipticalArcFilledBow: + break; + + case KETReactionArrow::EEllipticalArcFilledTriangle: + break; + + case KETReactionArrow::EEllipticalArcOpenAngle: + break; + + case KETReactionArrow::EEllipticalArcOpenHalfAngle: + break; + + default: + break; + } + + Vec3f ar_beg(ar._begin.x, -ar._begin.y, 0); + Vec3f ar_end(ar._end.x, -ar._end.y, 0); + ar_beg.scale(_bond_length); + ar_end.scale(_bond_length); + + attrs.insert("Head3D", std::to_string(ar_end.x) + " " + std::to_string(ar_end.y) + " " + std::to_string(ar_end.z)); + attrs.insert("Tail3D", std::to_string(ar_beg.x) + " " + std::to_string(ar_beg.y) + " " + std::to_string(ar_beg.z)); + addElement("arrow", id, ar._end, ar._begin, attrs); + } + break; + case KETReactionPlus::CID: { + KETReactionPlus& rp = (KETReactionPlus&)(*pobj); + } + break; + case KETSimpleObject::CID: { + auto simple_obj = (KETSimpleObject*)pobj; + Rect2f bbox(simple_obj->_coordinates.first, simple_obj->_coordinates.second); + switch (simple_obj->_mode) + { + case KETSimpleObject::EKETEllipse: { + auto ecenter = bbox.center(); + Vec2f maj_axis, min_axis; + if (bbox.width() > bbox.height()) + { + maj_axis.copy(bbox.rightMiddle()); + min_axis.copy(bbox.topMiddle()); + } + else + { + maj_axis.copy(bbox.topMiddle()); + min_axis.copy(bbox.rightMiddle()); + } + ecenter.scale(_bond_length); + min_axis.scale(_bond_length); + maj_axis.scale(_bond_length); + ecenter.y = -ecenter.y; + min_axis.y = -min_axis.y; + maj_axis.y = -maj_axis.y; + Rect2f bbox_new(ecenter, bbox.rightTop()); + bbox.copy(bbox_new); + attrs.insert("Center3D", std::to_string(ecenter.x) + " " + std::to_string(ecenter.y)); + attrs.insert("MajorAxisEnd3D", std::to_string(maj_axis.x) + " " + std::to_string(maj_axis.y)); + attrs.insert("MinorAxisEnd3D", std::to_string(min_axis.x) + " " + std::to_string(min_axis.y)); + attrs.insert("GraphicType", "Oval"); + } + break; + case KETSimpleObject::EKETRectangle: + attrs.insert("GraphicType", "Rectangle"); + break; + case KETSimpleObject::EKETLine: + attrs.insert("GraphicType", "Line"); + break; + } + addElement("graphic", id, bbox.leftBottom(), bbox.rightTop(), attrs); + } + break; + case KETTextObject::CID: { + const KETTextObject& ko = static_cast(*pobj); + double text_offset_y = 0; + int font_size = 13; + CDXMLFontStyle font_face(0); + for (auto& text_item : ko._block) + { + int first_index = -1; + int second_index = -1; + double text_offset_x = 0; + FONT_STYLE_SET current_styles; + Vec2f text_origin(ko._pos.x, ko._pos.y); + std::string pos_str = std::to_string(_bond_length * text_origin.x) + " " + std::to_string(-_bond_length * text_origin.y); + XMLElement* t = _doc->NewElement("t"); + _current->LinkEndChild(t); + t->SetAttribute("p", pos_str.c_str()); + t->SetAttribute("Justification", "Left"); + t->SetAttribute("InterpretChemically", "no"); + for (auto& kvp : text_item.styles) + { + if (first_index == -1) + { + first_index = kvp.first; + current_styles = kvp.second; + continue; + } + second_index = kvp.first; + + std::wstring_convert> utf82w; + std::wstring_convert> w2utf8; + + auto sub_text = w2utf8.to_bytes(utf82w.from_bytes(text_item.text).substr(first_index, second_index - first_index)); + for (const auto& text_style : current_styles) + { + switch (text_style.first) + { + case KETTextObject::EPlain: + break; + case KETTextObject::EBold: + font_face.is_bold = text_style.second; + break; + case KETTextObject::EItalic: + font_face.is_italic = text_style.second; + break; + case KETTextObject::ESuperScript: + font_face.is_superscript = text_style.second; + break; + case KETTextObject::ESubScript: + font_face.is_subscript = text_style.second; + break; + default: + font_size = text_style.second ? text_style.first : 13; + break; + } + } + + XMLElement* s = _doc->NewElement("s"); + t->LinkEndChild(s); + s->SetAttribute("font", 4); + s->SetAttribute("size", font_size); + s->SetAttribute("face", font_face.face); + XMLText* txt = _doc->NewText(sub_text.c_str()); + s->LinkEndChild(txt); + current_styles = kvp.second; + first_index = second_index; + } + } + } + break; + } + } +} + void MoleculeCdxmlSaver::addText(const Vec2f& pos, const char* text) { addText(pos, text, "Center"); @@ -762,9 +990,9 @@ void MoleculeCdxmlSaver::addTitle(const Vec2f& pos, const char* text) s->LinkEndChild(txt); } -void MoleculeCdxmlSaver::addGraphic(int id, const Vec2f& p1, const Vec2f& p2, PropertiesMap& attrs) +void MoleculeCdxmlSaver::addElement(const char* element, int id, const Vec2f& p1, const Vec2f& p2, PropertiesMap& attrs) { - XMLElement* g = _doc->NewElement("graphic"); + XMLElement* g = _doc->NewElement(element); _current->LinkEndChild(g); if (id > 0) diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index b3cedbb480..b00b935a93 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -931,7 +931,7 @@ void MoleculeJsonLoader::loadMolecule(BaseMolecule& mol, bool load_arrows) } Array mapping; - mol.mergeWithMolecule(*pmol, &mapping, COPY_BOND_DIRECTIONS); + mol.mergeWithMolecule(*pmol, &mapping, 0); for (auto& sc : stereo_centers) { @@ -994,6 +994,7 @@ void MoleculeJsonLoader::loadMolecule(BaseMolecule& mol, bool load_arrows) } mol.buildCisTrans(ignore_cistrans.data()); + mol.have_xyz = true; if (mol.stereocenters.size() == 0) { mol.buildFrom3dCoordinatesStereocenters(stereochemistry_options); diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 81790b0a70..ebb9492e24 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -855,6 +855,7 @@ void MoleculeJsonSaver::saveMolecule(BaseMolecule& bmol, Writer& w { std::unique_ptr mol(bmol.neu()); mol->clone_KeepIndices(bmol); + MoleculeCIPCalculator mcc; mcc.updateCIPStereoDescriptors(*mol, _add_stereo_desc); @@ -865,6 +866,7 @@ void MoleculeJsonSaver::saveMolecule(BaseMolecule& bmol, Writer& w ml.make(); } BaseMolecule::collapse(*mol); + QS_DEF(Array, buf); ArrayOutput out(buf); std::set rgrp_full_list; diff --git a/core/indigo-core/reaction/base_reaction.h b/core/indigo-core/reaction/base_reaction.h index f208bb6675..cdc001c955 100644 --- a/core/indigo-core/reaction/base_reaction.h +++ b/core/indigo-core/reaction/base_reaction.h @@ -37,6 +37,16 @@ namespace indigo class QueryReaction; class BaseReaction; + struct SpecialCondition + { + public: + SpecialCondition(int idx, const Rect2f& box) : meta_idx(idx), bbox(box) + { + } + int meta_idx; + Rect2f bbox; + }; + class SideIter : public AutoIterator { public: @@ -197,6 +207,16 @@ namespace indigo return _types[index]; } + int undefinedCount() const + { + return _undefinedCount; + } + + int intermediateCount() const + { + return _intermediateCount; + } + int reactantsCount() const { return _reactantCount; @@ -210,6 +230,11 @@ namespace indigo return _catalystCount; } + int specialConditionsCount() const + { + return _specialConditions.size(); + } + int reactionBlocksCount() const { return _reactionBlocks.size(); @@ -270,6 +295,9 @@ namespace indigo int addCatalyst(); int addIntermediate(); int addUndefined(); + int addSpecialCondition(int meta_idx, const Rect2f& bbox); + void clearSpecialConditions(); + const SpecialCondition& specialCondition(int meta_idx) const; int addReactantCopy(BaseMolecule& mol, Array* mapping, Array* inv_mapping); int addProductCopy(BaseMolecule& mol, Array* mapping, Array* inv_mapping); @@ -304,12 +332,14 @@ namespace indigo ObjArray _reactionBlocks; // for multistep reactions only Array _types; + Array _specialConditions; int _reactantCount; int _productCount; int _catalystCount; int _intermediateCount; int _undefinedCount; + int _specialCount; int _nextElement(int type, int index); diff --git a/core/indigo-core/reaction/reaction_cdxml_loader.h b/core/indigo-core/reaction/reaction_cdxml_loader.h new file mode 100644 index 0000000000..91bbb0f61d --- /dev/null +++ b/core/indigo-core/reaction/reaction_cdxml_loader.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#ifndef __reaction_cdxml_loader__ +#define __reaction_cdxml_loader__ + +#include "base_cpp/exception.h" +#include "molecule/molecule.h" +#include "molecule/molecule_cdxml_loader.h" +#include "molecule/molecule_stereocenter_options.h" +#include "molecule/query_molecule.h" +#include "reaction/base_reaction.h" + +namespace indigo +{ + + class Scanner; + class Reaction; + + class ReactionCdxmlLoader + { + public: + DECL_ERROR; + + ReactionCdxmlLoader(Scanner& scanner); + ~ReactionCdxmlLoader(); + + void loadReaction(BaseReaction& rxn); + + StereocentersOptions stereochemistry_options; + bool ignore_bad_valence; + std::set reactants_ids; + std::set products_ids; + std::set intermediates_ids; + std::set arrows_ids; + std::set agents_ids; + + protected: + Scanner& _scanner; + + private: + ReactionCdxmlLoader(const ReactionCdxmlLoader&); // no implicit copy + void _initReaction(BaseReaction& rxn); + void _parseStep(const tinyxml2::XMLAttribute* pAttr); + Reaction* _prxn; + QueryReaction* _pqrxn; + Molecule _mol; + QueryMolecule _qmol; + BaseMolecule* _pmol; + std::map _cdxml_elements; + }; + +}; // namespace indigo + +#endif diff --git a/core/indigo-core/reaction/reaction_cdxml_saver.h b/core/indigo-core/reaction/reaction_cdxml_saver.h index 42094a820d..bfdcd1a294 100644 --- a/core/indigo-core/reaction/reaction_cdxml_saver.h +++ b/core/indigo-core/reaction/reaction_cdxml_saver.h @@ -19,6 +19,8 @@ #ifndef __reaction_cdxml_saver__ #define __reaction_cdxml_saver__ +#include + #include "base_cpp/array.h" #include "base_cpp/exception.h" #include "base_cpp/obj_array.h" @@ -51,9 +53,9 @@ namespace indigo void _addArrow(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, int arrow_id); void _addScheme(MoleculeCdxmlSaver& molsaver); void _closeScheme(MoleculeCdxmlSaver& molsaver); - void _addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, Array& reactants_ids, Array& products_ids, ObjArray>& nodes_ids, - int arrow_id); - void _generateCdxmlObjIds(BaseReaction& rxn, Array& reactants_ids, Array& products_ids, ObjArray>& nodes_ids, int& arrow_id); + void _addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::unordered_map& mol_ids, ObjArray>& nodes_ids, int arrow_id); + void _generateCdxmlObjIds(BaseReaction& rxn, std::unordered_map& mol_ids, std::unordered_map& meta_ids, + ObjArray>& nodes_ids, int& arrow_id); void _addTitle(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver); }; diff --git a/core/indigo-core/reaction/reaction_json_loader.h b/core/indigo-core/reaction/reaction_json_loader.h index 451a81a9b2..87df4f06d2 100644 --- a/core/indigo-core/reaction/reaction_json_loader.h +++ b/core/indigo-core/reaction/reaction_json_loader.h @@ -37,7 +37,7 @@ namespace indigo lb.x = std::min(bb1.left(), bb2.left()); rt.x = std::max(bb1.right(), bb2.right()); lb.y = std::min(bb1.bottom(), bb2.bottom()); - lb.y = std::max(bb1.top(), bb2.top()); + rt.y = std::max(bb1.top(), bb2.top()); bb1 = Rect2f(lb, rt); } diff --git a/core/indigo-core/reaction/src/base_reaction.cpp b/core/indigo-core/reaction/src/base_reaction.cpp index daace30bd3..e133105549 100644 --- a/core/indigo-core/reaction/src/base_reaction.cpp +++ b/core/indigo-core/reaction/src/base_reaction.cpp @@ -268,6 +268,22 @@ void BaseReaction::clearAAM() } } +int BaseReaction::addSpecialCondition(int meta_idx, const Rect2f& bbox) +{ + _specialConditions.push(SpecialCondition(meta_idx, bbox)); + return _specialConditions.size() - 1; +} + +void BaseReaction::clearSpecialConditions() +{ + _specialConditions.clear(); +} + +const SpecialCondition& BaseReaction::specialCondition(int meta_idx) const +{ + return _specialConditions[meta_idx]; +} + int BaseReaction::addReactantCopy(BaseMolecule& mol, Array* mapping, Array* inv_mapping) { int idx = _allMolecules.add(mol.neu()); diff --git a/core/indigo-core/reaction/src/reaction_auto_loader.cpp b/core/indigo-core/reaction/src/reaction_auto_loader.cpp index d37dccf865..1cc39c42f7 100644 --- a/core/indigo-core/reaction/src/reaction_auto_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_auto_loader.cpp @@ -23,6 +23,7 @@ #include "reaction/icr_saver.h" #include "reaction/query_reaction.h" #include "reaction/reaction.h" +#include "reaction/reaction_cdxml_loader.h" #include "reaction/reaction_cml_loader.h" #include "reaction/reaction_json_loader.h" #include "reaction/rsmiles_loader.h" @@ -174,6 +175,28 @@ void ReactionAutoLoader::_loadReaction(BaseReaction& reaction, bool query) _scanner->seek(pos, SEEK_SET); } + // check for CDXML format + { + long long pos = _scanner->tell(); + _scanner->skipSpace(); + if (_scanner->lookNext() == '<' && _scanner->findWord("findWord("seek(pos, SEEK_SET); + ReactionCdxmlLoader loader(*_scanner); + loader.stereochemistry_options = stereochemistry_options; + loader.loadReaction(reaction); + return; + } + else + { + throw Error("CDXML: not a reacton. No arrows found."); + } + } + _scanner->seek(pos, SEEK_SET); + } + // check for JSON-KET format { diff --git a/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp new file mode 100644 index 0000000000..b6a2091742 --- /dev/null +++ b/core/indigo-core/reaction/src/reaction_cdxml_loader.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** + * Copyright (C) from 2009 to Present EPAM Systems. + * + * This file is part of Indigo toolkit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ***************************************************************************/ + +#include + +#include "base_cpp/scanner.h" +#include "base_cpp/tlscont.h" +#include "molecule/ket_commons.h" +#include "molecule/molecule_cdxml_loader.h" +#include "reaction/reaction.h" +#include "reaction/reaction_cdxml_loader.h" + +using namespace indigo; +using namespace tinyxml2; + +IMPL_ERROR(ReactionCdxmlLoader, "reaction CDXML loader"); + +ReactionCdxmlLoader::ReactionCdxmlLoader(Scanner& scanner) : _scanner(scanner) +{ + ignore_bad_valence = false; +} + +ReactionCdxmlLoader::~ReactionCdxmlLoader() +{ +} + +void ReactionCdxmlLoader::_initReaction(BaseReaction& rxn) +{ + rxn.clear(); + reactants_ids.clear(); + products_ids.clear(); + intermediates_ids.clear(); + arrows_ids.clear(); + agents_ids.clear(); + + if (rxn.isQueryReaction()) + _pqrxn = &rxn.asQueryReaction(); + else + _prxn = &rxn.asReaction(); + + if (_prxn) + { + _pmol = &_mol; + } + else if (_pqrxn) + { + _pmol = &_qmol; + } + else + throw Error("unknown reaction type: %s", typeid(rxn).name()); +} + +void ReactionCdxmlLoader::_parseStep(const XMLAttribute* pAttr) +{ + auto reactants_lambda = [this](const std::string& data) { + std::vector frag_ids = split(data, ' '); + for (const auto& ids : frag_ids) + { + auto id = std::stoi(ids); + if (this->products_ids.find(id) != this->products_ids.end()) + { + this->products_ids.erase(id); + this->intermediates_ids.insert(id); + } + else + { + this->reactants_ids.insert(id); + } + } + }; + auto products_lambda = [this](const std::string& data) { + std::vector frag_ids = split(data, ' '); + for (const auto& ids : frag_ids) + { + auto id = std::stoi(ids); + if (this->reactants_ids.find(id) != this->reactants_ids.end()) + { + this->reactants_ids.erase(id); + this->intermediates_ids.insert(id); + } + else + { + this->products_ids.insert(id); + } + } + }; + auto arrows_lambda = [this](const std::string& data) { + std::vector frag_ids = split(data, ' '); + for (const auto& ids : frag_ids) + this->arrows_ids.insert(std::stoi(ids)); + }; + auto agents_lambda = [this](const std::string& data) { + std::vector frag_ids = split(data, ' '); + for (const auto& ids : frag_ids) + this->agents_ids.insert(std::stoi(ids)); + }; + + std::unordered_map> cdxml_dispatcher = {{"ReactionStepReactants", reactants_lambda}, + {"ReactionStepProducts", products_lambda}, + {"ReactionStepArrows", arrows_lambda}, + {"ReactionStepObjectsAboveArrow", agents_lambda}, + {"ReactionStepObjectsBelowArrow", agents_lambda}}; + MoleculeCdxmlLoader::applyDispatcher(pAttr, cdxml_dispatcher); +} + +void ReactionCdxmlLoader::loadReaction(BaseReaction& rxn) +{ + _initReaction(rxn); + QS_DEF(Array, buf); + _scanner.readAll(buf); + buf.push(0); + XMLDocument xml; + xml.Parse(buf.ptr()); + + if (xml.Error()) + throw Error("XML parsing error: %s", xml.ErrorStr()); + + MoleculeCdxmlLoader loader(_scanner); + loader.parseCDXMLAttributes(xml.RootElement()->FirstAttribute()); + + for (auto pPageElem = xml.RootElement()->FirstChildElement(); pPageElem; pPageElem = pPageElem->NextSiblingElement()) + { + if (std::string(pPageElem->Value()).compare("page") == 0) + { + for (auto pCdxmlElem = pPageElem->FirstChildElement(); pCdxmlElem; pCdxmlElem = pCdxmlElem->NextSiblingElement()) + { + if (std::string(pCdxmlElem->Value()).compare("scheme") == 0) + { + for (auto pSchemeElement = pCdxmlElem->FirstChildElement(); pSchemeElement; pSchemeElement = pSchemeElement->NextSiblingElement()) + if (std::string(pSchemeElement->Value()).compare("step") == 0) + _parseStep(pSchemeElement->FirstAttribute()); + } + else + { + auto pid = pCdxmlElem->FindAttribute("id"); + if (pid) + _cdxml_elements.emplace(atoi(pid->Value()), pCdxmlElem); + } + } + } + } + + for (auto id : reactants_ids) + { + auto elem_it = _cdxml_elements.find(id); + if (elem_it != _cdxml_elements.end()) + { + loader.loadMoleculeFromFragment(*_pmol, elem_it->second); + if (_pmol->vertexCount()) + rxn.addReactantCopy(*_pmol, 0, 0); + else + throw Error("Empty reactant: %d", id); + _cdxml_elements.erase(elem_it); + } + } + + for (auto id : products_ids) + { + auto elem_it = _cdxml_elements.find(id); + if (elem_it != _cdxml_elements.end()) + { + loader.loadMoleculeFromFragment(*_pmol, elem_it->second); + if (_pmol->vertexCount()) + rxn.addProductCopy(*_pmol, 0, 0); + else + throw Error("Empty product: %d", id); + _cdxml_elements.erase(elem_it); + } + } + + for (auto id : agents_ids) + { + auto elem_it = _cdxml_elements.find(id); + if (elem_it != _cdxml_elements.end()) + { + loader.loadMoleculeFromFragment(*_pmol, elem_it->second); + if (_pmol->vertexCount()) + rxn.addCatalystCopy(*_pmol, 0, 0); + else + { + for (int i = 0; i < _pmol->meta().getMetaCount(KETTextObject::CID); ++i) + { + auto& text = (KETTextObject&)_pmol->meta().getMetaObject(KETTextObject::CID, i); + int idx = rxn.meta().addMetaObject(text.clone()); + rxn.addSpecialCondition(idx, Rect2f(Vec2f(text._pos.x, text._pos.y), Vec2f(text._pos.x, text._pos.y))); + } + _pmol->meta().resetMetaData(); + } + _cdxml_elements.erase(elem_it); + } + } + + for (auto id : arrows_ids) + { + auto elem_it = _cdxml_elements.find(id); + if (elem_it != _cdxml_elements.end()) + { + loader.loadMoleculeFromFragment(*_pmol, elem_it->second); + rxn.meta().append(_pmol->meta()); + _cdxml_elements.erase(elem_it); + } + } + + for (const auto& kvp : _cdxml_elements) + { + loader.loadMoleculeFromFragment(*_pmol, kvp.second); + rxn.meta().append(_pmol->meta()); + } +} diff --git a/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp b/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp index bf5902a39a..8f9adf7b1a 100644 --- a/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp +++ b/core/indigo-core/reaction/src/reaction_cdxml_saver.cpp @@ -16,10 +16,13 @@ * limitations under the License. ***************************************************************************/ -#include "reaction/reaction_cdxml_saver.h" +#include + #include "base_cpp/output.h" +#include "molecule/ket_commons.h" #include "molecule/molecule_cdxml_saver.h" #include "reaction/reaction.h" +#include "reaction/reaction_cdxml_saver.h" using namespace indigo; @@ -74,8 +77,9 @@ ReactionCdxmlSaver::~ReactionCdxmlSaver() void ReactionCdxmlSaver::saveReaction(BaseReaction& rxn) { int i; - Array reactants_ids; - Array products_ids; + std::unordered_map mol_ids; + std::unordered_map meta_ids; + ObjArray> nodes_ids; int arrow_id; @@ -83,10 +87,7 @@ void ReactionCdxmlSaver::saveReaction(BaseReaction& rxn) MoleculeCdxmlSaver molsaver(_output); MoleculeCdxmlSaver::Bounds b; - reactants_ids.clear(); - products_ids.clear(); - - _generateCdxmlObjIds(rxn, reactants_ids, products_ids, nodes_ids, arrow_id); + _generateCdxmlObjIds(rxn, mol_ids, meta_ids, nodes_ids, arrow_id); molsaver.beginDocument(NULL); molsaver.addDefaultFontTable(); @@ -95,34 +96,21 @@ void ReactionCdxmlSaver::saveReaction(BaseReaction& rxn) Vec2f offset(0, 0); - if (rxn.reactantsCount() > 0) + for (i = rxn.begin(); i != rxn.end(); i = rxn.next(i)) + molsaver.saveMoleculeFragment(rxn.getBaseMolecule(i), offset, 1, mol_ids[i], nodes_ids[i]); + + _addPlusses(rxn, molsaver); + if (rxn.meta().metaData().size()) // we have metadata { - for (i = rxn.reactantBegin(); i != rxn.reactantEnd(); i = rxn.reactantNext(i)) - { - molsaver.saveMoleculeFragment(rxn.getBaseMolecule(i), offset, 1, reactants_ids[i], nodes_ids[i]); - } + molsaver.addMetaData(rxn.meta(), arrow_id); } - if (rxn.productsCount() > 0) + else { - for (i = rxn.productBegin(); i != rxn.productEnd(); i = rxn.productNext(i)) - { - molsaver.saveMoleculeFragment(rxn.getBaseMolecule(i), offset, 1, products_ids[i], nodes_ids[i]); - } + _addArrow(rxn, molsaver, arrow_id); } - /* - if (rxn.catalystCount() > 0) - { - for (i = rxn.catalystBegin(); i != rxn.catalystEnd(); i = rxn.catalystNext(i)) - { - molsaver.saveMoleculeFragment(rxn.getBaseMolecule(i), offset, 1); - } - } - */ - _addPlusses(rxn, molsaver); - _addArrow(rxn, molsaver, arrow_id); _addScheme(molsaver); - _addStep(rxn, molsaver, reactants_ids, products_ids, nodes_ids, arrow_id); + _addStep(rxn, molsaver, mol_ids, nodes_ids, arrow_id); _closeScheme(molsaver); if (rxn.name.size() > 0) @@ -282,7 +270,7 @@ void ReactionCdxmlSaver::_addArrow(BaseReaction& rxn, MoleculeCdxmlSaver& molsav attrs.insert("ArrowType", "FullHead"); attrs.insert("HeadSize", "1000"); - molsaver.addGraphic(id, p1, p2, attrs); + molsaver.addElement("graphic", id, p1, p2, attrs); } void ReactionCdxmlSaver::_addScheme(MoleculeCdxmlSaver& molsaver) @@ -303,8 +291,8 @@ void ReactionCdxmlSaver::_closeScheme(MoleculeCdxmlSaver& molsaver) molsaver.endCurrentElement(); } -void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, Array& reactants_ids, Array& products_ids, - ObjArray>& nodes_ids, int arrow_id) +void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsaver, std::unordered_map& mol_ids, ObjArray>& nodes_ids, + int arrow_id) { int id = -1; Array name; @@ -317,10 +305,10 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave Array buf; ArrayOutput buf_out(buf); - for (auto i = 0; i < reactants_ids.size(); i++) + for (auto i = rxn.reactantBegin(); i < rxn.reactantEnd(); i = rxn.reactantNext(i)) { - if (reactants_ids[i] > 0) - buf_out.printf("%d ", reactants_ids[i]); + if (mol_ids[i] > 0) + buf_out.printf("%d ", mol_ids[i]); } if (buf.size() > 1) { @@ -330,10 +318,10 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave } buf.clear(); - for (auto i = 0; i < products_ids.size(); i++) + for (auto i = rxn.productBegin(); i < rxn.productEnd(); i = rxn.productNext(i)) { - if (products_ids[i] > 0) - buf_out.printf("%d ", products_ids[i]); + if (mol_ids[i] > 0) + buf_out.printf("%d ", mol_ids[i]); } if (buf.size() > 1) { @@ -342,6 +330,22 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave attrs.insert("ReactionStepProducts", buf.ptr()); } + std::string below_arrow, above_arrow; + for (auto i = rxn.catalystBegin(); i < rxn.catalystEnd(); i = rxn.catalystNext(i)) + { + if (mol_ids[i] > 0) + { + if (above_arrow.size()) + above_arrow += " "; + above_arrow += std::to_string(mol_ids[i]); + } + } + if (above_arrow.size()) + attrs.insert("ReactionStepObjectsAboveArrow", above_arrow.c_str()); + + if (below_arrow.size()) + attrs.insert("ReactionStepObjectsAboveArrow", above_arrow.c_str()); + buf.clear(); buf_out.printf("%d", arrow_id); buf.push(0); @@ -380,21 +384,15 @@ void ReactionCdxmlSaver::_addStep(BaseReaction& rxn, MoleculeCdxmlSaver& molsave molsaver.addCustomElement(id, name, attrs); } -void ReactionCdxmlSaver::_generateCdxmlObjIds(BaseReaction& rxn, Array& reactants_ids, Array& products_ids, ObjArray>& nodes_ids, - int& arrow_id) +void ReactionCdxmlSaver::_generateCdxmlObjIds(BaseReaction& rxn, std::unordered_map& mol_ids, std::unordered_map& meta_ids, + ObjArray>& nodes_ids, int& arrow_id) { - reactants_ids.clear_resize(rxn.reactantEnd()); - reactants_ids.zerofill(); - - products_ids.clear_resize(rxn.productEnd()); - products_ids.zerofill(); int id = 0; - - for (auto i = rxn.reactantBegin(); i != rxn.reactantEnd(); i = rxn.reactantNext(i)) + for (auto i = rxn.begin(); i != rxn.end(); i = rxn.next(i)) { id++; - reactants_ids[i] = id; + mol_ids.insert(std::make_pair(i, id)); BaseMolecule& mol = rxn.getBaseMolecule(i); @@ -409,26 +407,20 @@ void ReactionCdxmlSaver::_generateCdxmlObjIds(BaseReaction& rxn, Array& rea } } - for (auto i = rxn.productBegin(); i != rxn.productEnd(); i = rxn.productNext(i)) + // generate ids for meta objects. 1 node and 1 extra object. text or graphics + for (auto i = 0; i < rxn.meta().metaData().size(); ++i) { + int r_id = i + rxn.end(); id++; - products_ids[i] = id; - - BaseMolecule& mol = rxn.getBaseMolecule(i); - - nodes_ids.expand(i + 1); - nodes_ids[i].clear_resize(mol.vertexEnd()); - nodes_ids[i].zerofill(); - - for (auto j = mol.vertexBegin(); j != mol.vertexEnd(); j = mol.vertexNext(j)) - { - id++; - nodes_ids[i][j] = id; - } + meta_ids.insert(std::make_pair(r_id, id)); + nodes_ids.expand(r_id + 1); + nodes_ids[r_id].clear_resize(1); + nodes_ids[r_id].zerofill(); + id += 2; + nodes_ids[r_id][0] = id; } arrow_id = id + 1; - return; } diff --git a/core/indigo-core/reaction/src/reaction_json_loader.cpp b/core/indigo-core/reaction/src/reaction_json_loader.cpp index 830f78a772..e585d4058a 100644 --- a/core/indigo-core/reaction/src/reaction_json_loader.cpp +++ b/core/indigo-core/reaction/src/reaction_json_loader.cpp @@ -449,7 +449,7 @@ void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) { enum RecordIndexes { - LEFT_BOUND_IDX = 0, + BBOX_IDX = 0, FRAGMENT_TYPE_IDX, MOLECULE_IDX }; @@ -458,74 +458,92 @@ void ReactionJsonLoader::parseOneArrowReaction(BaseReaction& rxn) { MOLECULE, PLUS, - ARROW + ARROW, + TEXT }; - using ReactionComponent = std::tuple>; - - std::unique_ptr merged_molecule; - - if (rxn.isQueryReaction()) - merged_molecule = std::make_unique(); - else - merged_molecule = std::make_unique(); - - int count = _pmol->countComponents(); + using ReactionComponent = std::tuple>; std::vector components; - for (int index = 0; index < count; ++index) + for (int index = 0; index < _pmol->countComponents(); ++index) { + std::unique_ptr mol; if (_pmol->isQueryMolecule()) - components.emplace_back(0, ReactionFragmentType::MOLECULE, std::make_unique()); + mol = std::make_unique(); else - components.emplace_back(0, ReactionFragmentType::MOLECULE, std::make_unique()); + mol = std::make_unique(); + Filter filter(_pmol->getDecomposition().ptr(), Filter::EQ, index); - ReactionComponent& rc = components.back(); - BaseMolecule& mol = *(std::get(rc)); - mol.makeSubmolecule(*_pmol, filter, 0, 0); + mol->makeSubmolecule(*_pmol, filter, 0, 0); Rect2f bbox; - mol.getBoundingBox(bbox); - - std::get(rc) = bbox.left(); + mol->getBoundingBox(bbox); + components.emplace_back(bbox, ReactionFragmentType::MOLECULE, std::move(mol)); } auto& arrow = (const KETReactionArrow&)rxn.meta().getMetaObject(KETReactionArrow::CID, 0); + Vec2f arrow_vec(arrow._begin); + arrow_vec.sub(arrow._end); - float arrow_x = arrow._begin.x; - components.emplace_back(arrow_x, ReactionFragmentType::ARROW, nullptr); - for (int i = 0; i < rxn.meta().getMetaCount(KETReactionPlus::CID); ++i) + for (int i = 0; i < rxn.meta().getMetaCount(KETTextObject::CID); ++i) { - auto& plus = (const KETReactionPlus&)rxn.meta().getMetaObject(KETReactionPlus::CID, i); - components.emplace_back(plus._pos.x, ReactionFragmentType::PLUS, nullptr); + auto& text = (const KETReactionPlus&)rxn.meta().getMetaObject(KETTextObject::CID, i); + Rect2f bbox(text._pos, text._pos); // change to real text box later + components.emplace_back(bbox, ReactionFragmentType::TEXT, nullptr); } - std::sort(components.begin(), components.end(), - [](const ReactionComponent& a, const ReactionComponent& b) -> bool { return std::get(a) < std::get(b); }); - - bool is_arrow_passed = false; - + int text_meta_idx = 0; for (const auto& comp : components) { switch (std::get(comp)) { - case ReactionFragmentType::MOLECULE: - merged_molecule->mergeWithMolecule(*std::get(comp), 0, 0); - break; - case ReactionFragmentType::ARROW: - rxn.addReactantCopy(*merged_molecule, 0, 0); - is_arrow_passed = true; - merged_molecule->clear(); - break; - case ReactionFragmentType::PLUS: - if (is_arrow_passed) - rxn.addProductCopy(*merged_molecule, 0, 0); - else - rxn.addReactantCopy(*merged_molecule, 0, 0); - merged_molecule->clear(); + case ReactionFragmentType::MOLECULE: { + auto& cmol = *std::get(comp); + for (int idx = cmol.vertexBegin(); idx < cmol.vertexEnd(); idx = cmol.vertexNext(idx)) + { + Vec3f& v3 = cmol.getAtomXyz(idx); + Vec2f slope1(v3.x, v3.y); + Vec2f slope2(slope1); + slope1.sub(arrow._begin); + slope2.sub(arrow._end); + auto dt1 = Vec2f::dot(slope1, arrow_vec); + auto dt2 = Vec2f::dot(slope2, arrow_vec); + if (std::signbit(dt1) != std::signbit(dt2)) + { + rxn.addCatalystCopy(cmol, 0, 0); + break; + } + else if (std::signbit(dt1) && std::signbit(dt2)) + { + rxn.addProductCopy(cmol, 0, 0); + break; + } + else + { + rxn.addReactantCopy(cmol, 0, 0); + break; + } + } + } + case ReactionFragmentType::TEXT: { + const auto& bbox = std::get(comp); + Vec2f slope1(bbox.leftTop().x, bbox.leftTop().y); + Vec2f slope2(slope1); + slope1.sub(arrow._begin); + slope2.sub(arrow._end); + auto dt1 = Vec2f::dot(slope1, arrow_vec); + auto dt2 = Vec2f::dot(slope2, arrow_vec); + if (std::signbit(dt1) != std::signbit(dt2)) + { + rxn.addSpecialCondition(text_meta_idx, bbox); + break; + } + text_meta_idx++; + } + break; + default: break; } } - rxn.addProductCopy(*merged_molecule, 0, 0); } diff --git a/core/indigo-core/reaction/src/reaction_json_saver.cpp b/core/indigo-core/reaction/src/reaction_json_saver.cpp index d51dd79ee2..72b6746823 100644 --- a/core/indigo-core/reaction/src/reaction_json_saver.cpp +++ b/core/indigo-core/reaction/src/reaction_json_saver.cpp @@ -78,7 +78,7 @@ void ReactionJsonSaver::saveReaction(BaseReaction& rxn, BaseMolecule& merged, Mo { std::vector pluses; - Vec2f rmin(0, 0), rmax(0, 0), pmin(0, 0), pmax(0, 0); + Vec2f rmin(0, 0), rmax(0, 0), pmin(0, 0), pmax(0, 0), cmin(0, 0), cmax(0, 0); if (rxn.reactantsCount() > 0) { @@ -142,6 +142,26 @@ void ReactionJsonSaver::saveReaction(BaseReaction& rxn, BaseMolecule& merged, Mo } } + if (rxn.catalystCount() > 0) + { + for (int i = rxn.catalystBegin(); i != rxn.catalystEnd(); i = rxn.catalystNext(i)) + { + Vec2f min1, max1; + _getBounds(rxn.getBaseMolecule(i), min1, max1, 1.0); + merged.mergeWithMolecule(rxn.getBaseMolecule(i), 0, 0); + if (i == rxn.catalystBegin()) + { + cmin = min1; + cmax = max1; + } + else + { + cmin.min(min1); + cmax.max(max1); + } + } + } + // dump molecules StringBuffer s; Writer writer(s); @@ -208,6 +228,14 @@ void ReactionJsonSaver::saveReaction(BaseReaction& rxn, BaseMolecule& merged, Mo p1.x = (rmax.x + pmin.x) / 2 + 1.0f; p1.y = (pmin.y + pmax.y) / 2; } + if (rxn.catalystCount() && cmin.x != cmax.x) + { + if (cmin.x < p2.x) + p2.x = cmin.x; + + if (cmax.x > p1.x) + p1.x = cmax.x; + } } Value arrow(kObjectType); diff --git a/core/render2d/src/render_cdxml.cpp b/core/render2d/src/render_cdxml.cpp index c9b8824df0..8306805cea 100644 --- a/core/render2d/src/render_cdxml.cpp +++ b/core/render2d/src/render_cdxml.cpp @@ -223,7 +223,7 @@ void RenderParamCdxmlInterface::_renderMols(RenderParams& params) // On average letters has width 6 float letter_width = params.rOpt.titleFontFactor / 1.5f; - float title_width = longest_line * letter_width / MoleculeCdxmlSaver::BOND_LENGTH; + float title_width = longest_line * letter_width / MoleculeCdxmlSaver::SCALE; title_widths[mol_idx] = title_width; width = std::max(width, title_width); } @@ -237,10 +237,10 @@ void RenderParamCdxmlInterface::_renderMols(RenderParams& params) float letter_width = context.propertyFontSize / 1.5f; int longest_line = _getLongestLineXml(data.propertyName); - key_widths[mol_idx] = longest_line * letter_width / MoleculeCdxmlSaver::BOND_LENGTH; + key_widths[mol_idx] = longest_line * letter_width / MoleculeCdxmlSaver::SCALE; longest_line += _getLongestLineXml(data.propertyValue); - float prop_width = longest_line * letter_width / MoleculeCdxmlSaver::BOND_LENGTH; + float prop_width = longest_line * letter_width / MoleculeCdxmlSaver::SCALE; prop_widths[mol_idx] = prop_width; width = std::max(width, prop_width); @@ -287,7 +287,7 @@ void RenderParamCdxmlInterface::_renderMols(RenderParams& params) if (title.size() > 0) { int lines = title.count('\n') + 1; - float letter_height = params.rOpt.titleFontFactor / MoleculeCdxmlSaver::BOND_LENGTH; + float letter_height = params.rOpt.titleFontFactor / MoleculeCdxmlSaver::SCALE; // float title_height = lines * saver.textLineHeight(); // p.all_size.y += title_height + saver.textLineHeight(); // Add blank line float title_height = lines * letter_height; @@ -303,7 +303,7 @@ void RenderParamCdxmlInterface::_renderMols(RenderParams& params) RenderCdxmlContext::PropertyData& data = context.property_data.at(mol_idx); int lines = data.propertyName.count('\n') + 1; - float letter_height = params.rOpt.titleFontFactor / MoleculeCdxmlSaver::BOND_LENGTH; + float letter_height = params.rOpt.titleFontFactor / MoleculeCdxmlSaver::SCALE; float prop_height = lines * letter_height; p.all_size.y += prop_height + letter_height; // Add blank line } diff --git a/utils/indigo-depict/main.c b/utils/indigo-depict/main.c index d1a0e26ac6..a09fda90a8 100644 --- a/utils/indigo-depict/main.c +++ b/utils/indigo-depict/main.c @@ -247,6 +247,7 @@ enum OEXT_KER, OEXT_CDX, OEXT_CDXML, + OEXT_CDXMLR, OEXT_SMI, OEXT_OTHER }; @@ -283,7 +284,7 @@ void renderToFile(int obj, const char* outfile) typedef struct tagParams { const char* outfile; - char outfile_ext[4], infile_ext[7]; + char outfile_ext[7], infile_ext[7]; int width; int height; int bond; @@ -337,7 +338,7 @@ int parseParams(Params* p, int argc, char* argv[]) if (strcasecmp(p->infile_ext, "cdx") == 0 || strcasecmp(p->infile_ext, "mol") == 0 || strcasecmp(p->infile_ext, "ket") == 0 || strcasecmp(p->infile_ext, "xml") == 0) p->mode = MODE_SINGLE_MOLECULE; - else if (strcasecmp(p->infile_ext, "rxn") == 0 || strcasecmp(p->infile_ext, "ker") == 0) + else if (strcasecmp(p->infile_ext, "rxn") == 0 || strcasecmp(p->infile_ext, "ker") == 0 || strcasecmp(p->infile_ext, "xmr") == 0) p->mode = MODE_SINGLE_REACTION; else if (strcasecmp(p->infile_ext, "smi") == 0) { @@ -379,11 +380,11 @@ int parseParams(Params* p, int argc, char* argv[]) p->outfile = argv[i++]; - if (strlen(p->outfile) < 5 || p->outfile[strlen(p->outfile) - 4] != '.') + const char* ptr_dot = strstr(p->outfile, "."); + if (!ptr_dot) USAGE(); - p->outfile_ext[3] = 0; - strncpy(p->outfile_ext, p->outfile + strlen(p->outfile) - 3, 3); + strcpy(p->outfile_ext, ptr_dot + 1); indigoSetOptionBool("treat-x-as-pseudoatom", 1); indigoSetOptionBool("render-coloring", 1); @@ -865,6 +866,10 @@ int main(int argc, char* argv[]) p.out_ext = OEXT_KER; else if (strcmp(p.outfile_ext, "smi") == 0) p.out_ext = OEXT_SMI; + else if (strcmp(p.outfile_ext, "cdxml") == 0) + p.out_ext = OEXT_CDXML; + else if (strcmp(p.outfile_ext, "cdxmr") == 0) + p.out_ext = OEXT_CDXMLR; // guess whether to layout or render by extension p.action = ACTION_LAYOUT; @@ -920,6 +925,10 @@ int main(int argc, char* argv[]) return -1; } } + else if (p.out_ext == OEXT_CDXML) + { + indigoSaveCdxmlToFile(obj, p.outfile); + } else indigoSaveCmlToFile(obj, p.outfile); } @@ -951,8 +960,13 @@ int main(int argc, char* argv[]) indigoSaveCmlToFile(obj, p.outfile); else if (p.out_ext == OEXT_RXN) indigoSaveRxnfileToFile(obj, p.outfile); + else if (p.out_ext == OEXT_CDXML) + indigoSaveCdxmlToFile(obj, p.outfile); else + { indigoSaveJsonToFile(obj, p.outfile); + printf("smiles: %s\n", indigoSmiles(obj)); + } } else { diff --git a/utils/indigo-service/backend/service/v2/indigo_api.py b/utils/indigo-service/backend/service/v2/indigo_api.py index 86797ccd69..30bc435085 100644 --- a/utils/indigo-service/backend/service/v2/indigo_api.py +++ b/utils/indigo-service/backend/service/v2/indigo_api.py @@ -370,6 +370,8 @@ def save_moldata(md, output_format=None, options={}, indigo=None): return md.struct.smarts() elif output_format == "chemical/x-cml": return md.struct.cml() + elif output_format == "chemical/x-cdxml": + return md.struct.cdxml() elif output_format == "chemical/x-inchi": return indigo.inchi.getInchi(md.struct) elif output_format == "chemical/x-inchi-key":