Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backmerge: #5935 - Unable to establish hydrogen bond connection if monomer has no free attachment points #5958

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions packages/ketcher-core/src/application/editor/modes/BaseMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { PolymerBond } from 'domain/entities/PolymerBond';
import { ketcherProvider } from 'application/utils';
import { DrawingEntitiesManager } from 'domain/entities/DrawingEntitiesManager';
import { HydrogenBond } from 'domain/entities/HydrogenBond';
import { AttachmentPointName } from 'domain/types';
import { MACROMOLECULES_BOND_TYPES } from 'application/editor/tools/Bond';

export abstract class BaseMode {
private _pasteIsInProgress = false;
Expand Down Expand Up @@ -115,10 +117,7 @@ export abstract class BaseMode {
entity.position,
entity,
);
} else if (
(entity instanceof PolymerBond || entity instanceof HydrogenBond) &&
entity.secondMonomer
) {
} else if (entity instanceof PolymerBond && entity.secondMonomer) {
const firstAttachmentPoint =
entity.firstMonomer.getAttachmentPointByBond(entity);
const secondAttachmentPoint =
Expand All @@ -138,6 +137,15 @@ export abstract class BaseMode {
entity,
);
}
} else if (entity instanceof HydrogenBond && entity.secondMonomer) {
drawingEntitiesManager.finishPolymerBondCreationModelChange(
entity.firstMonomer,
entity.secondMonomer,
AttachmentPointName.HYDROGEN,
AttachmentPointName.HYDROGEN,
MACROMOLECULES_BOND_TYPES.HYDROGEN,
entity,
);
}
});
const ketSerializer = new KetSerializer();
Expand Down
22 changes: 20 additions & 2 deletions packages/ketcher-core/src/application/editor/tools/Bond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class PolymerBond implements BaseTool {
const startAttachmentPoint =
selectedRenderer.monomer.startBondAttachmentPoint;

if (!startAttachmentPoint) {
if (!startAttachmentPoint && !this.isHydrogenBond) {
this.editor.events.error.dispatch(
"Selected monomer doesn't have any free attachment points",
);
Expand Down Expand Up @@ -339,14 +339,32 @@ class PolymerBond implements BaseTool {

private finishBondCreation(secondMonomer: BaseMonomer) {
assert(this.bondRenderer);
if (!secondMonomer.hasFreeAttachmentPoint) {

if (!this.isHydrogenBond && !secondMonomer.hasFreeAttachmentPoint) {
this.editor.events.error.dispatch(
"Monomers don't have any connection point available",
);

return this.editor.drawingEntitiesManager.cancelPolymerBondCreation(
this.bondRenderer.polymerBond,
);
}

if (
this.isHydrogenBond &&
secondMonomer.hasHydrogenBondWithMonomer(
this.bondRenderer?.polymerBond.firstMonomer,
)
) {
this.editor.events.error.dispatch(
'Unable to establish multiple hydrogen bonds between two monomers',
);

return this.editor.drawingEntitiesManager.cancelPolymerBondCreation(
this.bondRenderer.polymerBond,
);
}

const firstMonomerAttachmentPoint = this.isHydrogenBond
? AttachmentPointName.HYDROGEN
: this.bondRenderer.polymerBond.firstMonomer.getPotentialAttachmentPointByBond(
Expand Down
63 changes: 52 additions & 11 deletions packages/ketcher-core/src/domain/entities/BaseMonomer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export abstract class BaseMonomer extends DrawingEntity {
public attachmentPointsVisible = false;
public monomerItem: MonomerItemType;
public isMonomerInRnaChainRow = false;
public hydrogenBonds: HydrogenBond[] = [];

constructor(
monomerItem: MonomerItemType,
Expand Down Expand Up @@ -108,16 +109,28 @@ export abstract class BaseMonomer extends DrawingEntity {

public setPotentialBond(
attachmentPoint: string | undefined,
potentialBond?: PolymerBond | null,
potentialBond?: PolymerBond | HydrogenBond | null,
) {
if (potentialBond instanceof HydrogenBond) {
this.hydrogenBonds.push(potentialBond);

return;
}

if (attachmentPoint !== undefined) {
this.potentialAttachmentPointsToBonds[attachmentPoint] = potentialBond;
}
}

public getAttachmentPointByBond(
bond: PolymerBond | MonomerToAtomBond,
bond: PolymerBond | MonomerToAtomBond | HydrogenBond,
): AttachmentPointName | undefined {
if (bond instanceof HydrogenBond) {
return this.hydrogenBonds.find((hydrogenBond) => hydrogenBond === bond)
? AttachmentPointName.HYDROGEN
: undefined;
}

for (const attachmentPointName in this.attachmentPointsToBonds) {
if (this.attachmentPointsToBonds[attachmentPointName] === bond) {
return attachmentPointName as AttachmentPointName;
Expand Down Expand Up @@ -206,7 +219,7 @@ export abstract class BaseMonomer extends DrawingEntity {

public forEachBond(
callback: (
polymerBond: PolymerBond | MonomerToAtomBond,
polymerBond: PolymerBond | MonomerToAtomBond | HydrogenBond,
attachmentPointName: AttachmentPointName,
) => void,
) {
Expand All @@ -218,21 +231,42 @@ export abstract class BaseMonomer extends DrawingEntity {
);
}
}

this.hydrogenBonds.forEach((hydrogenBond) => {
callback(hydrogenBond, AttachmentPointName.HYDROGEN);
});
}

public setBond(
attachmentPointName: AttachmentPointName,
bond: PolymerBond | MonomerToAtomBond | HydrogenBond,
) {
this.attachmentPointsToBonds[
bond instanceof HydrogenBond
? AttachmentPointName.HYDROGEN
: attachmentPointName
] = bond;
if (!(bond instanceof HydrogenBond)) {
this.attachmentPointsToBonds[attachmentPointName] = bond;

return;
}

if (!this.hydrogenBonds.includes(bond)) {
this.hydrogenBonds.push(bond);
}
}

public unsetBond(attachmentPointName: AttachmentPointName) {
this.attachmentPointsToBonds[attachmentPointName] = null;
public unsetBond(
attachmentPointName?: AttachmentPointName,
bondToDelete?: HydrogenBond | PolymerBond,
) {
if (bondToDelete instanceof HydrogenBond) {
this.hydrogenBonds = this.hydrogenBonds.filter(
(bond) => bond !== bondToDelete,
);

return;
}

if (attachmentPointName) {
this.attachmentPointsToBonds[attachmentPointName] = null;
}
}

public get hasBonds() {
Expand All @@ -242,7 +276,14 @@ export abstract class BaseMonomer extends DrawingEntity {
hasBonds = true;
}
}
return hasBonds;

return hasBonds || this.hydrogenBonds.length > 0;
}

public hasHydrogenBondWithMonomer(monomer: BaseMonomer) {
return this.hydrogenBonds.find(
(bond) => bond.firstMonomer === monomer || bond.secondMonomer === monomer,
);
}

public hasPotentialBonds() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -698,11 +698,17 @@ export class DrawingEntitiesManager {
polymerBond.secondMonomer?.removePotentialBonds();
polymerBond.firstMonomer.turnOffSelection();
polymerBond.secondMonomer?.turnOffSelection();
if (firstMonomerAttachmentPoint) {
polymerBond.firstMonomer.unsetBond(firstMonomerAttachmentPoint);
if (firstMonomerAttachmentPoint || polymerBond instanceof HydrogenBond) {
polymerBond.firstMonomer.unsetBond(
firstMonomerAttachmentPoint,
polymerBond,
);
}
if (secondMonomerAttachmentPoint) {
polymerBond.secondMonomer?.unsetBond(secondMonomerAttachmentPoint);
if (secondMonomerAttachmentPoint || polymerBond instanceof HydrogenBond) {
polymerBond.secondMonomer?.unsetBond(
secondMonomerAttachmentPoint,
polymerBond,
);
}
}

Expand Down
8 changes: 5 additions & 3 deletions packages/ketcher-core/src/domain/entities/HydrogenBond.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { BaseRenderer } from 'application/render/renderers/BaseRenderer';
import { SnakeModePolymerBondRenderer } from 'application/render/renderers/PolymerBondRenderer/SnakeModePolymerBondRenderer';
import { BaseMonomer } from './BaseMonomer';
import { BaseBond } from './BaseBond';
import { FlexOrSequenceOrSnakeModePolymerBondRenderer } from 'domain/entities/PolymerBond';

export class HydrogenBond extends BaseBond {
public secondMonomer?: BaseMonomer;
public renderer?: SnakeModePolymerBondRenderer = undefined;
public renderer?: FlexOrSequenceOrSnakeModePolymerBondRenderer = undefined;

constructor(public firstMonomer: BaseMonomer, secondMonomer?: BaseMonomer) {
super();
Expand All @@ -21,7 +21,9 @@ export class HydrogenBond extends BaseBond {
this.secondMonomer = monomer;
}

public setRenderer(renderer: SnakeModePolymerBondRenderer): void {
public setRenderer(
renderer: FlexOrSequenceOrSnakeModePolymerBondRenderer,
): void {
super.setBaseRenderer(renderer as BaseRenderer);
this.renderer = renderer;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ketcher-core/src/domain/entities/PolymerBond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { AttachmentPointName } from 'domain/types';
import { BaseMonomer } from './BaseMonomer';
import { BaseBond } from 'domain/entities/BaseBond';

type FlexOrSequenceOrSnakeModePolymerBondRenderer =
export type FlexOrSequenceOrSnakeModePolymerBondRenderer =
| BackBoneBondSequenceRenderer
| FlexModePolymerBondRenderer
| PolymerBondSequenceRenderer
Expand Down
Loading