public static convertStructToDrawingEntities()

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,
    };
  }