Skip to content

Commit

Permalink
#5949 - Delete of micromolecules bonds works wrong (or doesn't work) (#…
Browse files Browse the repository at this point in the history
…6110)

- added invertAfterAllOperations method to atom and bonds operations to allow renderers rely on final state of model before rendering
- added deleting of atoms and bonds from molecules struct to synchronize molecules and macromolecules modes
  • Loading branch information
rrodionov91 committed Dec 10, 2024
1 parent 59563ef commit 15a1021
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ export class MacromoleculesConverter {
);
});

monomer.monomerItem.struct.bonds.forEach((bond) => {
monomer.monomerItem.struct.bonds.forEach((bond, bondId) => {
const firstAtom = atomsMap.get(bond.begin);
const secondAtom = atomsMap.get(bond.end);

Expand All @@ -491,6 +491,7 @@ export class MacromoleculesConverter {
secondAtom,
bond.type,
bond.stereo,
bondId,
),
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,105 @@
import { RenderersManager } from 'application/render/renderers/RenderersManager';
import { Operation } from 'domain/entities/Operation';
import { Atom } from 'domain/entities/CoreAtom';
import {
Bond as MicromoleculesBond,
Atom as MicromoleculesAtom,
} from 'domain/entities';
import { KetcherLogger } from 'utilities';

interface BondWithIdInMicromolecules {
bondId: number;
bond: MicromoleculesBond;
}

interface DeletedMoleculeStructItems {
atomInMoleculeStruct: MicromoleculesAtom;
bondsInMoleculeStruct: BondWithIdInMicromolecules[];
}

function addAtomToMoleculeStruct(
atom: Atom,
atomInMoleculeStruct: MicromoleculesAtom,
bondsInMoleculeStruct: BondWithIdInMicromolecules[] = [],
) {
const moleculeStruct = atom.monomer.monomerItem.struct;

moleculeStruct.atoms.set(atom.atomIdInMicroMode, atomInMoleculeStruct);

bondsInMoleculeStruct.forEach(({ bondId, bond }) => {
moleculeStruct.bonds.set(bondId, bond);
});
}

function deleteAtomFromMoleculeStruct(atom: Atom) {
const moleculeStruct = atom.monomer.monomerItem.struct;
const atomInMoleculeStruct = moleculeStruct.atoms.get(atom.atomIdInMicroMode);

if (!atomInMoleculeStruct) {
KetcherLogger.warn('Atom is not found in molecule struct during deletion');

return;
}

const bondsInMoleculeStruct = moleculeStruct.bonds.filter((_, bond) => {
return (
bond.begin === atom.atomIdInMicroMode ||
bond.end === atom.atomIdInMicroMode
);
});

moleculeStruct.atoms.delete(atom.atomIdInMicroMode);

bondsInMoleculeStruct.forEach((_, bondId) => {
moleculeStruct.bonds.delete(bondId);
});

return {
atomInMoleculeStruct,
bondsInMoleculeStruct: [...bondsInMoleculeStruct.entries()].map(
([bondId, bond]) => {
return { bondId, bond };
},
),
};
}
export class AtomAddOperation implements Operation {
public atom: Atom;
private deletedMoleculeStructItems?: DeletedMoleculeStructItems;

constructor(
public addAtomChangeModel: (atom?: Atom) => Atom,
public deleteAtomChangeModel: () => void,
public deleteAtomChangeModel: (atom: Atom) => void,
) {
this.atom = this.addAtomChangeModel();
}

public execute(renderersManager: RenderersManager) {
this.atom = this.addAtomChangeModel(this.atom);
renderersManager.addAtom(this.atom);

if (this.deletedMoleculeStructItems) {
addAtomToMoleculeStruct(
this.atom,
this.deletedMoleculeStructItems.atomInMoleculeStruct,
this.deletedMoleculeStructItems.bondsInMoleculeStruct,
);
}
}

public invert(renderersManager: RenderersManager) {
if (this.atom) {
this.deleteAtomChangeModel();
this.deleteAtomChangeModel(this.atom);
renderersManager.deleteAtom(this.atom);
}

this.deletedMoleculeStructItems = deleteAtomFromMoleculeStruct(this.atom);
}
}

export class AtomDeleteOperation implements Operation {
private deletedMoleculeStructItems?: DeletedMoleculeStructItems;

constructor(
public atom: Atom,
public deleteAtomChangeModel: () => void,
Expand All @@ -52,10 +127,23 @@ export class AtomDeleteOperation implements Operation {
public execute(renderersManager: RenderersManager) {
this.deleteAtomChangeModel();
renderersManager.deleteAtom(this.atom);

this.deletedMoleculeStructItems = deleteAtomFromMoleculeStruct(this.atom);
}

public invert(renderersManager: RenderersManager) {
public invert() {
this.addAtomChangeModel(this.atom);

if (this.deletedMoleculeStructItems) {
addAtomToMoleculeStruct(
this.atom,
this.deletedMoleculeStructItems.atomInMoleculeStruct,
this.deletedMoleculeStructItems.bondsInMoleculeStruct,
);
}
}

public invertAfterAllOperations(renderersManager: RenderersManager) {
renderersManager.addAtom(this.atom);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,80 @@
import { RenderersManager } from 'application/render/renderers/RenderersManager';
import { Operation } from 'domain/entities/Operation';
import { Bond } from 'domain/entities/CoreBond';
import { Bond as MicromoleculesBond } from 'domain/entities/bond';

function addBondToMoleculeStruct(
bond: Bond,
bondInMoleculeStruct: MicromoleculesBond,
) {
const moleculeStruct = bond.firstAtom.monomer.monomerItem.struct;

moleculeStruct.bonds.set(bond.bondIdInMicroMode, bondInMoleculeStruct);
}

function deleteBondFromMoleculeStruct(bond: Bond) {
const moleculeStruct = bond.firstAtom.monomer.monomerItem.struct;
const bondInMoleculeStruct = moleculeStruct.bonds.get(bond.bondIdInMicroMode);

moleculeStruct.bonds.delete(bond.bondIdInMicroMode);

return bondInMoleculeStruct;
}

export class BondAddOperation implements Operation {
public bond: Bond;
private bondInMoleculeStruct?: MicromoleculesBond;
constructor(
public addBondChangeModel: (bond?: Bond) => Bond,
public deleteBondChangeModel: (bond?: Bond) => void,
public deleteBondChangeModel: (bond: Bond) => void,
) {
this.bond = this.addBondChangeModel();
}

public execute(renderersManager: RenderersManager) {
this.bond = this.addBondChangeModel(this.bond);
renderersManager.addBond(this.bond);

if (this.bondInMoleculeStruct) {
addBondToMoleculeStruct(this.bond, this.bondInMoleculeStruct);
}
}

public invert(renderersManager: RenderersManager) {
if (this.bond) {
this.deleteBondChangeModel(this.bond);
renderersManager.deleteBond(this.bond);
}

this.bondInMoleculeStruct = deleteBondFromMoleculeStruct(this.bond);
}
}

export class BondDeleteOperation implements Operation {
private bondInMoleculeStruct?: MicromoleculesBond;

constructor(
public bond: Bond,
public deleteBondChangeModel: (bond?: Bond) => void,
public addBondChangeModel: (bond?: Bond) => Bond,
public deleteBondChangeModel: (bond: Bond) => void,
public addBondChangeModel: (bond: Bond) => Bond,
) {}

public execute(renderersManager: RenderersManager) {
this.deleteBondChangeModel(this.bond);
renderersManager.deleteBond(this.bond);

this.bondInMoleculeStruct = deleteBondFromMoleculeStruct(this.bond);
}

public invert(renderersManager: RenderersManager) {
public invert() {
this.addBondChangeModel(this.bond);

if (this.bondInMoleculeStruct) {
addBondToMoleculeStruct(this.bond, this.bondInMoleculeStruct);
}
}

public invertAfterAllOperations(renderersManager: RenderersManager) {
renderersManager.addBond(this.bond);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,16 @@ export class RenderersManager {
monomer.renderer?.updateAttachmentPoints();
}

public update(modelChanges?: Command) {
public reinitializeViewModel() {
const editor = CoreEditor.provideEditorInstance();
const viewModel = editor.viewModel;

modelChanges?.execute(this);
viewModel.initialize([...editor.drawingEntitiesManager.bonds.values()]);
}

public update(modelChanges?: Command) {
this.reinitializeViewModel();
modelChanges?.execute(this);
modelChanges?.executeAfterAllOperations(this);

this.runPostRenderMethods();
Expand Down
20 changes: 18 additions & 2 deletions packages/ketcher-core/src/domain/entities/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export class Command {
}

operations.forEach((operation) => operation.invert(renderersManagers));
renderersManagers.reinitializeViewModel();
this.invertAfterAllOperations(renderersManagers, operations);
renderersManagers.runPostRenderMethods();
}

Expand All @@ -43,14 +45,28 @@ export class Command {
renderersManagers.runPostRenderMethods();
}

public executeAfterAllOperations(renderersManagers: RenderersManager) {
this.operations.forEach((operation) => {
public executeAfterAllOperations(
renderersManagers: RenderersManager,
operations = this.operations,
) {
operations.forEach((operation) => {
if (operation.executeAfterAllOperations) {
operation.executeAfterAllOperations(renderersManagers);
}
});
}

public invertAfterAllOperations(
renderersManagers: RenderersManager,
operations = this.operations,
) {
operations.forEach((operation) => {
if (operation.invertAfterAllOperations) {
operation.invertAfterAllOperations(renderersManagers);
}
});
}

public clear() {
this.operations = [];
}
Expand Down
1 change: 1 addition & 0 deletions packages/ketcher-core/src/domain/entities/CoreBond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class Bond extends DrawingEntity {
constructor(
public firstAtom: Atom,
public secondAtom: Atom,
public bondIdInMicroMode,
public type = 1,
public stereo = 0,
) {
Expand Down
Loading

0 comments on commit 15a1021

Please sign in to comment.