in packages/ketcher-core/src/application/editor/MacromoleculesConverter.ts [421:686]
public static convertStructToDrawingEntities(
struct: Struct,
drawingEntitiesManager: DrawingEntitiesManager,
) {
const editor = CoreEditor.provideEditorInstance();
const sgroupToMonomer = new Map<SGroup, BaseMonomer>();
const fragmentIdToMonomer = new Map<number, BaseMonomer>();
const command = new Command();
struct.sgroups.forEach((sgroup) => {
if (sgroup instanceof MonomerMicromolecule) {
command.merge(
this.convertMonomerMicromoleculeToMonomer(
sgroup,
drawingEntitiesManager,
sgroupToMonomer,
),
);
}
});
const fragments = this.getFragmentsGroupedBySgroup(struct);
let fragmentNumber = 1;
const fragmentIdToAtomIdMap = new Map<number, Map<number, number>>();
const globalAtomIdToMonomerMap = new Map<number, BaseMonomer>();
fragments.forEach((_fragment) => {
const atomIdMap = new Map<number, number>();
const fragmentStruct = struct.getFragment(_fragment, false, atomIdMap);
const monomerAddCommand = this.convertFragmentToChem(
fragmentNumber,
fragmentStruct,
drawingEntitiesManager,
);
const monomer = monomerAddCommand.operations[0].monomer as BaseMonomer;
const atomIdMapObject = Object.fromEntries(atomIdMap.entries());
const localAtomIdToGlobalAtomId = invert(atomIdMapObject);
const atomsMap = new Map<number, Atom>();
_fragment.forEach((fragmentId) => {
fragmentIdToMonomer.set(fragmentId as number, monomer);
fragmentIdToAtomIdMap.set(fragmentId, atomIdMap);
});
command.merge(monomerAddCommand);
if (
monomer.monomerItem.props.isMicromoleculeFragment &&
!isMonomerSgroupWithAttachmentPoints(monomer)
) {
monomer.monomerItem.struct.atoms.forEach((atom, atomId) => {
const atomAddCommand = drawingEntitiesManager.addAtom(
atom.pp,
monomer,
atomId,
atom.label as AtomLabel,
{
charge: atom.charge,
explicitValence: atom.explicitValence,
isotope: atom.isotope,
radical: atom.radical,
alias: atom.alias,
},
);
command.merge(atomAddCommand);
atomsMap.set(atomId, atomAddCommand.operations[0].atom as Atom);
globalAtomIdToMonomerMap.set(
Number(localAtomIdToGlobalAtomId[atomId]),
monomer,
);
});
monomer.monomerItem.struct.bonds.forEach((bond, bondId) => {
const firstAtom = atomsMap.get(bond.begin);
const secondAtom = atomsMap.get(bond.end);
if (!firstAtom || !secondAtom) {
return;
}
command.merge(
drawingEntitiesManager.addBond(
firstAtom,
secondAtom,
bond.type,
bond.stereo,
bondId,
),
);
});
}
fragmentNumber++;
});
const superatomAttachmentPointToBond = new Map<
SGroupAttachmentPoint,
Bond
>();
struct.bonds.forEach((bond) => {
const beginAtom = struct.atoms.get(bond.begin);
const endAtom = struct.atoms.get(bond.end);
const beginAtomSgroup = struct.getGroupFromAtomId(bond.begin);
beginAtomSgroup?.getAttachmentPoints();
const endAtomSgroup = struct.getGroupFromAtomId(bond.end);
const isConnectionBetweenMonomerAndMolecule =
(beginAtomSgroup instanceof MonomerMicromolecule &&
!(endAtomSgroup instanceof MonomerMicromolecule) &&
!endAtomSgroup?.isSuperatomWithoutLabel) ||
(endAtomSgroup instanceof MonomerMicromolecule &&
!(beginAtomSgroup instanceof MonomerMicromolecule) &&
!beginAtomSgroup?.isSuperatomWithoutLabel);
if (!isConnectionBetweenMonomerAndMolecule) {
return;
}
const moleculeAtomId =
beginAtomSgroup instanceof MonomerMicromolecule ? bond.end : bond.begin;
const moleculeAtom =
beginAtomSgroup instanceof MonomerMicromolecule ? endAtom : beginAtom;
const monomerSgroup =
beginAtomSgroup instanceof MonomerMicromolecule
? beginAtomSgroup
: endAtomSgroup;
if (!moleculeAtom || !monomerSgroup) {
return;
}
const atomsMap = fragmentIdToAtomIdMap.get(moleculeAtom.fragment);
const atomIdInMicromolecules = atomsMap?.get(moleculeAtomId);
const monomer = sgroupToMonomer.get(monomerSgroup);
if (!isNumber(atomIdInMicromolecules) || !monomer) {
return;
}
const atomToConnect =
MacromoleculesConverter.findAtomByMicromoleculeAtomId(
drawingEntitiesManager,
atomIdInMicromolecules,
globalAtomIdToMonomerMap.get(moleculeAtomId),
);
if (
!atomToConnect ||
!isNumber(bond.beginSuperatomAttachmentPointNumber)
) {
return;
}
command.merge(
drawingEntitiesManager.addMonomerToAtomBond(
monomer,
atomToConnect,
getAttachmentPointLabel(bond.beginSuperatomAttachmentPointNumber),
),
);
});
struct.bonds.forEach((bond) => {
const beginAtom = struct.atoms.get(bond.begin);
const endAtom = struct.atoms.get(bond.end);
if (!beginAtom || !endAtom) {
return;
}
const beginAtomSgroup = struct.getGroupFromAtomId(bond.begin);
const beginAtomSgroupAttachmentPoints =
beginAtomSgroup?.getAttachmentPoints();
const endAtomSgroup = struct.getGroupFromAtomId(bond.end);
const endAtomSgroupAttachmentPoints =
endAtomSgroup?.getAttachmentPoints();
const beginAtomAttachmentPointNumber = isNumber(
bond.beginSuperatomAttachmentPointNumber,
)
? bond.beginSuperatomAttachmentPointNumber
: beginAtomSgroupAttachmentPoints?.findIndex(
(sgroupAttachmentPoint) =>
sgroupAttachmentPoint.atomId === bond.begin &&
!superatomAttachmentPointToBond.has(sgroupAttachmentPoint),
);
const beginAtomAttachmentPoint =
isNumber(beginAtomAttachmentPointNumber) &&
beginAtomSgroupAttachmentPoints?.find(
(attachmentPoint) =>
attachmentPoint.attachmentPointNumber ===
beginAtomAttachmentPointNumber,
);
const endAtomAttachmentPointNumber = isNumber(
bond.endSuperatomAttachmentPointNumber,
)
? bond.endSuperatomAttachmentPointNumber
: endAtomSgroupAttachmentPoints?.findIndex(
(sgroupAttachmentPoint) =>
sgroupAttachmentPoint.atomId === bond.end &&
!superatomAttachmentPointToBond.has(sgroupAttachmentPoint),
);
const endAtomAttachmentPoint =
isNumber(endAtomAttachmentPointNumber) &&
endAtomSgroupAttachmentPoints?.find(
(attachmentPoint) =>
attachmentPoint.attachmentPointNumber ===
endAtomAttachmentPointNumber,
);
if (beginAtomAttachmentPoint) {
superatomAttachmentPointToBond.set(beginAtomAttachmentPoint, bond);
}
if (endAtomAttachmentPoint) {
superatomAttachmentPointToBond.set(endAtomAttachmentPoint, bond);
}
if (
endAtomSgroup !== beginAtomSgroup &&
isNumber(beginAtomAttachmentPointNumber) &&
isNumber(endAtomAttachmentPointNumber) &&
beginAtomSgroup &&
endAtomSgroup &&
(beginAtomSgroup instanceof MonomerMicromolecule ||
beginAtomSgroup.isSuperatomWithoutLabel) &&
(endAtomSgroup instanceof MonomerMicromolecule ||
endAtomSgroup.isSuperatomWithoutLabel)
) {
// Here we take monomers from sgroupToMonomer in case of macromolecules structure and
// from fragmentIdToMonomer in case of micromolecules structure.
const firstMonomer =
beginAtomSgroup instanceof MonomerMicromolecule
? sgroupToMonomer.get(beginAtomSgroup)
: fragmentIdToMonomer.get(beginAtom.fragment);
const secondMonomer =
endAtomSgroup instanceof MonomerMicromolecule
? sgroupToMonomer.get(endAtomSgroup)
: fragmentIdToMonomer.get(endAtom.fragment);
assert(firstMonomer);
assert(secondMonomer);
command.merge(
drawingEntitiesManager.createPolymerBond(
firstMonomer,
secondMonomer,
getAttachmentPointLabel(beginAtomAttachmentPointNumber),
getAttachmentPointLabel(endAtomAttachmentPointNumber),
bond.type === Bond.PATTERN.TYPE.HYDROGEN
? MACROMOLECULES_BOND_TYPES.HYDROGEN
: MACROMOLECULES_BOND_TYPES.SINGLE,
),
);
}
});
drawingEntitiesManager.setMicromoleculesHiddenEntities(struct);
if (editor) {
editor.viewModel.initialize([...drawingEntitiesManager.bonds.values()]);
}
return {
drawingEntitiesManager,
modelChanges: command,
fragmentIdToMonomer,
fragmentIdToAtomIdMap,
};
}