|
@@ -17,6 +17,8 @@ export class SdfEncoder implements Encoder<string> {
|
|
|
private encoded = false;
|
|
|
private error = false;
|
|
|
private componentData: ComponentBond;
|
|
|
+ readonly isBinary = false;
|
|
|
+ binaryEncodingProvider = void 0;
|
|
|
|
|
|
setComponentBondData(componentData: ComponentBond) {
|
|
|
this.componentData = componentData;
|
|
@@ -74,7 +76,6 @@ export class SdfEncoder implements Encoder<string> {
|
|
|
const fields = this.getSortedFields(instance);
|
|
|
const label_atom_id = this.getField(instance, 'label_atom_id');
|
|
|
const label_comp_id = this.getField(instance, 'label_comp_id');
|
|
|
- const fieldCount = fields.length;
|
|
|
|
|
|
// write header
|
|
|
const name = label_comp_id.value(source[0].keys().move(), source[0].data, 0) as string;
|
|
@@ -83,7 +84,43 @@ export class SdfEncoder implements Encoder<string> {
|
|
|
const bondMap = this.componentData.entries.get(name)!;
|
|
|
let bondCount = 0;
|
|
|
|
|
|
+ // traverse once to determine all actually present atoms
|
|
|
+ const atoms = this.getAtoms(source, fields, label_atom_id, ctab);
|
|
|
+
|
|
|
+ atoms.forEach((av, ak) => {
|
|
|
+ const { id } = this.split(ak);
|
|
|
+ bondMap.map.get(ak)!.forEach((bv, bk) => {
|
|
|
+ const { id: partnerId, label: partnerLabel } = this.split(bk);
|
|
|
+ if (id <= partnerId && atoms.has(bk) && !this.skipHydrogen(partnerLabel)) {
|
|
|
+ const { order } = bv;
|
|
|
+ StringBuilder.writeIntegerPadLeft(bonds, id, 3);
|
|
|
+ StringBuilder.writeIntegerPadLeft(bonds, partnerId, 3);
|
|
|
+ StringBuilder.writeIntegerPadLeft(bonds, order, 3);
|
|
|
+ StringBuilder.writeSafe(bonds, ' 0 0 0 0\n');
|
|
|
+ // TODO 2nd value: Single bonds: 0 = not stereo, 1 = Up, 4 = Either, 6 = Down,
|
|
|
+ // Double bonds: 0 = Use x-, y-, z-coords from atom block to determine cis or trans, 3 = Cis or trans (either) double bond
|
|
|
+ bondCount++;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // write counts line
|
|
|
+ // 'Important specifications here relate to the number of atoms, bonds, and atom lists, the chiral flag setting, and the Ctab version.'
|
|
|
+ StringBuilder.writeIntegerPadLeft(this.builder, rowCount, 3);
|
|
|
+ StringBuilder.writeIntegerPadLeft(this.builder, bondCount, 3);
|
|
|
+ StringBuilder.write(this.builder, ' 0 0 0 0 0 0 0999 V2000\n'); // TODO 2nd value: chiral flag: 0=not chiral, 1=chiral
|
|
|
+
|
|
|
+ StringBuilder.writeSafe(this.builder, StringBuilder.getString(ctab));
|
|
|
+ StringBuilder.writeSafe(this.builder, StringBuilder.getString(bonds));
|
|
|
+ StringBuilder.writeSafe(this.builder, StringBuilder.getString(charges)); // TODO charges
|
|
|
+
|
|
|
+ StringBuilder.writeSafe(this.builder, 'M END\n');
|
|
|
+ }
|
|
|
+
|
|
|
+ private getAtoms(source: any, fields: Field<any, any>[], label_atom_id: Field<any, any>, ctab: StringBuilder): Map<string, { id: number, label: string }> {
|
|
|
+ const atoms = new Map<string, any>();
|
|
|
let index = 0;
|
|
|
+
|
|
|
for (let _c = 0; _c < source.length; _c++) {
|
|
|
const src = source[_c];
|
|
|
const data = src.data;
|
|
@@ -93,50 +130,27 @@ export class SdfEncoder implements Encoder<string> {
|
|
|
const it = src.keys();
|
|
|
while (it.hasNext) {
|
|
|
const key = it.move();
|
|
|
- for (let _f = 0; _f < fieldCount; _f++) {
|
|
|
+ for (let _f = 0, _fl = fields.length; _f < _fl; _f++) {
|
|
|
const f: Field<any, any> = fields[_f]!;
|
|
|
const val = f.value(key, data, index);
|
|
|
if (f.name === 'type_symbol') {
|
|
|
- const lai = label_atom_id.value(key, data, index) as string;
|
|
|
- const { id, label } = this.split(lai);
|
|
|
+ const val = label_atom_id.value(key, data, index) as string;
|
|
|
+ const lai = this.split(val);
|
|
|
+ const { label } = lai;
|
|
|
if (this.skipHydrogen(label)) {
|
|
|
continue;
|
|
|
}
|
|
|
-
|
|
|
- bondMap.map.get(lai)!.forEach((v, k) => {
|
|
|
- const { id: partnerId, label: partnerLabel } = this.split(k);
|
|
|
- if (id <= partnerId && !this.skipHydrogen(partnerLabel)) {
|
|
|
- const { order } = v;
|
|
|
- StringBuilder.writeIntegerPadLeft(bonds, id, 3);
|
|
|
- StringBuilder.writeIntegerPadLeft(bonds, partnerId, 3);
|
|
|
- StringBuilder.writeIntegerPadLeft(bonds, order, 3);
|
|
|
- StringBuilder.writeSafe(bonds, ' 0 0 0 0\n');
|
|
|
- // TODO 2nd value: Single bonds: 0 = not stereo, 1 = Up, 4 = Either, 6 = Down,
|
|
|
- // Double bonds: 0 = Use x-, y-, z-coords from atom block to determine cis or trans, 3 = Cis or trans (either) double bond
|
|
|
- bondCount++;
|
|
|
- }
|
|
|
- });
|
|
|
+ atoms.set(val, lai);
|
|
|
}
|
|
|
this.writeValue(ctab, val, f.type);
|
|
|
}
|
|
|
|
|
|
StringBuilder.writeSafe(ctab, ' 0 0 0 0 0 0 0 0 0 0 0 0\n');
|
|
|
-
|
|
|
index++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // write counts line
|
|
|
- // 'Important specifications here relate to the number of atoms, bonds, and atom lists, the chiral flag setting, and the Ctab version.'
|
|
|
- StringBuilder.writeIntegerPadLeft(this.builder, rowCount, 3);
|
|
|
- StringBuilder.writeIntegerPadLeft(this.builder, bondCount, 3);
|
|
|
- StringBuilder.write(this.builder, ' 0 0 0 0 0 0 0999 V2000\n'); // TODO 2nd value: chiral flag: 0=not chiral, 1=chiral
|
|
|
-
|
|
|
- StringBuilder.writeSafe(this.builder, StringBuilder.getString(ctab));
|
|
|
- StringBuilder.writeSafe(this.builder, StringBuilder.getString(bonds));
|
|
|
- StringBuilder.writeSafe(this.builder, StringBuilder.getString(charges)); // TODO charges
|
|
|
-
|
|
|
- StringBuilder.writeSafe(this.builder, 'M END\n');
|
|
|
+ return atoms;
|
|
|
}
|
|
|
|
|
|
private skipHydrogen(label: string) {
|
|
@@ -193,9 +207,6 @@ export class SdfEncoder implements Encoder<string> {
|
|
|
return instance.fields.find(f => f.name === name)!;
|
|
|
}
|
|
|
|
|
|
- readonly isBinary = false;
|
|
|
- binaryEncodingProvider = void 0;
|
|
|
-
|
|
|
encode() {
|
|
|
// write meta-information, do so after ctab
|
|
|
if (this.error || this.metaInformation) {
|