Skip to content

Commit

Permalink
#4241 - Pasting large cyclodextrins structure cause Ketcher to freeze
Browse files Browse the repository at this point in the history
- added debounce for structures merge calculations
- added functionalGroup link to sgroup to more efficiently search it during different operations (for example for checking is atom in contracted group)
  • Loading branch information
rrodionov91 committed Mar 18, 2024
1 parent 0176cab commit 75dff63
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class BondAttr extends BaseOperation {
}

execute(restruct: ReStruct) {
console.error('here');
if (this.data) {
const { attribute, bid, value } = this.data;
const bond = restruct.molecule.bonds.get(bid)!;
Expand All @@ -49,7 +50,7 @@ export class BondAttr extends BaseOperation {

bond[attribute] = value;

BaseOperation.invalidateBond(restruct, bid);
// BaseOperation.invalidateBond(restruct, bid);
if (attribute === 'type') {
BaseOperation.invalidateLoop(restruct, bid);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ class BondAdd extends BaseOperation {
throw new Error('Distinct atoms expected');
}

BaseOperation.invalidateAtom(restruct, begin, 1);
BaseOperation.invalidateAtom(restruct, end, 1);
// BaseOperation.invalidateAtom(restruct, begin, 1);
// BaseOperation.invalidateAtom(restruct, end, 1);

const pp: {
type: number;
Expand Down
37 changes: 20 additions & 17 deletions packages/ketcher-core/src/domain/entities/functionalGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class FunctionalGroup {
assert(sgroup != null);

this.#sgroup = sgroup;
sgroup.setFunctionalGroup(this);
}

get name(): string {
Expand Down Expand Up @@ -175,19 +176,14 @@ export class FunctionalGroup {
if (sgroupsFromReStruct) {
sgroups.forEach((sg) => {
if (
FunctionalGroup.isContractedFunctionalGroup(
sg.item.id,
functionalGroups,
)
FunctionalGroup.isContractedFunctionalGroup(sg.item, functionalGroups)
) {
contractedFunctionalGroups.push(sg.item.id);
}
});
} else {
sgroups.forEach((sg) => {
if (
FunctionalGroup.isContractedFunctionalGroup(sg.id, functionalGroups)
) {
if (FunctionalGroup.isContractedFunctionalGroup(sg, functionalGroups)) {
contractedFunctionalGroups.push(sg.id);
}
});
Expand All @@ -200,12 +196,11 @@ export class FunctionalGroup {
sGroups: Map<number, ReSGroup> | Pool<SGroup>,
functionalGroups: Pool<FunctionalGroup>,
) {
return [...sGroups.values()].some((sGroup) => {
const sGroupId = 'item' in sGroup ? sGroup?.item?.id : sGroup.id;
const atomsInSGroup =
'item' in sGroup ? sGroup?.item?.atoms : sGroup.atoms;
return [...sGroups.values()].some((_sGroup) => {
const sGroup = 'item' in _sGroup ? _sGroup?.item : _sGroup;
const atomsInSGroup = sGroup?.atoms;
const isContracted = FunctionalGroup.isContractedFunctionalGroup(
sGroupId,
sGroup,
functionalGroups,
);
return (
Expand All @@ -229,15 +224,23 @@ export class FunctionalGroup {
);
}

static isContractedFunctionalGroup(sgroupId, functionalGroups): boolean {
static isContractedFunctionalGroup(sgroup, functionalGroups): boolean {
let isFunctionalGroup = false;
let expanded = false;
functionalGroups.forEach((fg) => {
if (fg.relatedSGroupId === sgroupId) {

if (sgroup instanceof SGroup) {
if (sgroup.functionalGroup) {
isFunctionalGroup = true;
expanded = fg.isExpanded;
expanded = sgroup.functionalGroup.isExpanded;
}
});
} else {
functionalGroups.forEach((fg) => {
if (fg.relatedSGroupId === sgroup) {
isFunctionalGroup = true;
expanded = fg.isExpanded;
}
});
}
return !expanded && isFunctionalGroup;
}
}
7 changes: 6 additions & 1 deletion packages/ketcher-core/src/domain/entities/sgroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { Struct } from './struct';
import { SaltsAndSolventsProvider } from '../helpers';
import { Vec2 } from './vec2';
import { ReStruct } from '../../application/render';
import { Pool, SGroupAttachmentPoint } from 'domain/entities';
import { FunctionalGroup, Pool, SGroupAttachmentPoint } from 'domain/entities';
import { ReSGroup } from 'application/render';
import { SgContexts } from 'application/editor/shared/constants';
import assert from 'assert';
Expand Down Expand Up @@ -84,6 +84,7 @@ export class SGroup {
pp: Vec2 | null;
data: any;
dataArea: any;
functionalGroup: FunctionalGroup | undefined;
private readonly attachmentPoints: SGroupAttachmentPoint[];

constructor(type: string) {
Expand Down Expand Up @@ -136,6 +137,10 @@ export class SGroup {
return this.data[attr];
}

setFunctionalGroup(functionalGroup: FunctionalGroup) {
this.functionalGroup = functionalGroup;
}

// TODO: should be group-specific
getAttrs(): any {
const attrs = {};
Expand Down
44 changes: 39 additions & 5 deletions packages/ketcher-react/src/script/editor/tool/paste.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@ import { dropAndMerge } from './helper/dropAndMerge';
import { getGroupIdsFromItemArrays } from './helper/getGroupIdsFromItems';
import { filterNotInContractedSGroup } from './helper/filterNotInCollapsedSGroup';
import { Tool } from './Tool';
import { debounce } from 'lodash';

let isMovePreviewCalculationInProgress = false;

const debouncedSetAndHoverMergeItems = debounce(function (
editor,
pasteItems,
pasteToolInstance,
needResetTool = false,
) {
const mergeItems = getItemsToFuse(editor, pasteItems);
editor.hover(
getHoverToFuse(mergeItems),
needResetTool ? pasteToolInstance : undefined,
);
pasteToolInstance.setMergeItems(mergeItems);
},
50);

class PasteTool implements Tool {
private readonly editor: Editor;
Expand Down Expand Up @@ -65,8 +83,11 @@ class PasteTool implements Tool {

this.editor.update(this.action, true);

this.mergeItems = getItemsToFuse(this.editor, pasteItems);
this.editor.hover(getHoverToFuse(this.mergeItems), this);
debouncedSetAndHoverMergeItems(this.editor, pasteItems, this, true);
}

public setMergeItems(mergeItems) {
this.mergeItems = mergeItems;
}

private get restruct() {
Expand Down Expand Up @@ -111,6 +132,12 @@ class PasteTool implements Tool {
}

mousemove(event) {
this.mergeItems = null;
this.editor.hover(null);
if (isMovePreviewCalculationInProgress) {
return;
}
isMovePreviewCalculationInProgress = true;
if (this.action) {
this.action?.perform(this.restruct);
}
Expand Down Expand Up @@ -147,8 +174,12 @@ class PasteTool implements Tool {
// eslint-disable-next-line no-prototype-builtins
this.dragCtx.hasOwnProperty('angle') &&
this.dragCtx.angle === degrees
)
) {
requestAnimationFrame(() => {
isMovePreviewCalculationInProgress = false;
});
return;
}

if (this.dragCtx.action) {
this.dragCtx.action.perform(this.restruct);
Expand Down Expand Up @@ -187,9 +218,12 @@ class PasteTool implements Tool {
this.editor.struct(),
);

this.mergeItems = getItemsToFuse(this.editor, visiblePasteItems);
this.editor.hover(getHoverToFuse(this.mergeItems));
debouncedSetAndHoverMergeItems(this.editor, visiblePasteItems, this);
}

requestAnimationFrame(() => {
isMovePreviewCalculationInProgress = false;
});
}

mouseup() {
Expand Down

0 comments on commit 75dff63

Please sign in to comment.