Skip to content

Commit

Permalink
#3660 - Macro: After removing the abbreviation in micro mode and swit…
Browse files Browse the repository at this point in the history
…ching to macro mode, the monomer disappears (#3735)

* #3660 - Macro: After removing the abbreviation in micro mode and switching to macro mode, the monomer disappears

- restricted several operations with macro entities in micro mode (expand/remove abbreviation, replace, etc)

---------

Co-authored-by: Roman Rodionov <[email protected]>
  • Loading branch information
rrodionov91 and rrodionov91 authored Dec 21, 2023
1 parent dd5ddf3 commit 9e5ad98
Show file tree
Hide file tree
Showing 15 changed files with 109 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ import {
waitForPageInit,
waitForRender,
} from '@utils';
import { rotateToCoordinates } from '@tests/Structure-Creating-&-Editing/Actions-With-Structures/Rotation/utils';

export const COORDINATES_TO_PERFORM_ROTATION = {
x: 20,
y: 100,
};

async function zoomWithMouseWheel(
page: Page,
Expand Down Expand Up @@ -174,25 +168,7 @@ test.describe('Macro-Micro-Switcher', () => {
await takeEditorScreenshot(page);
});

test('Create a sequence of monomers in macro mode then switch to micro mode select the entire structure and rotate it', async ({
page,
}) => {
/*
Test case: Macro-Micro-Switcher
Description: Sequence of monomers rotate in Micro mode
Now test working not properly because we have bug https://github.com/epam/ketcher/issues/3655
*/
await openFileAndAddToCanvas(
'KET/three-monomers-connected-with-bonds.ket',
page,
);
await turnOnMicromoleculesEditor(page);
await page.keyboard.press('Control+a');
await rotateToCoordinates(page, COORDINATES_TO_PERFORM_ROTATION);
await takeEditorScreenshot(page);
});

test('Add monomers in macro mode then switch to micro mode and expand them', async ({
test('Add monomers in macro mode then switch to micro mode and check that it can not be expanded and abreviation can not be removed', async ({
page,
}) => {
/*
Expand All @@ -206,30 +182,10 @@ test.describe('Macro-Micro-Switcher', () => {
);
await turnOnMicromoleculesEditor(page);
await page.getByText('A6OH').click({ button: 'right' });
await page.getByText('Expand Abbreviation').click();
await takeEditorScreenshot(page);
});

test('Add monomers in macro mode then switch to micro mode remove abbreviation and switch to macro mode', async ({
page,
}) => {
/*
Test case: Macro-Micro-Switcher
Description: After switch to Macro mode monomer exist on canvas.
Now test working not properly because we have bug https://github.com/epam/ketcher/issues/3660
*/
await openFileAndAddToCanvas(
'KET/three-monomers-connected-with-bonds.ket',
page,
);
await turnOnMicromoleculesEditor(page);
await page.getByText('A6OH').click({ button: 'right' });
await page.getByText('Remove Abbreviation').click();
await turnOnMacromoleculesEditor(page);
await takeEditorScreenshot(page);
});

test('Add monomers in macro mode then switch to micro mode and move them to a new position several times', async ({
test('Add monomers in macro mode then switch to micro mode and check that it can not be moved', async ({
page,
}) => {
/*
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions packages/ketcher-core/src/domain/entities/struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1216,4 +1216,31 @@ export class Struct {
const sgroup = this.getGroupFromAtomId(atomId);
return sgroup instanceof MonomerMicromolecule;
}

isBondFromMacromolecule(bondId: number) {
const bond = this.bonds.get(bondId);

assert(bond);

return (
this.isAtomFromMacromolecule(bond.begin) ||
this.isAtomFromMacromolecule(bond.end)
);
}

isFunctionalGroupFromMacromolecule(functionalGroupId: number) {
const functionalGroup = this.functionalGroups.get(functionalGroupId);

return functionalGroup?.relatedSGroup instanceof MonomerMicromolecule;
}

isTargetFromMacromolecule(target?: { id: number; map: string }) {
return (
target &&
((target.map === 'functionalGroups' &&
this.isFunctionalGroupFromMacromolecule(target.id)) ||
(target.map === 'atoms' && this.isAtomFromMacromolecule(target.id)) ||
(target.map === 'bonds' && this.isBondFromMacromolecule(target.id)))
);
}
}
8 changes: 7 additions & 1 deletion packages/ketcher-react/src/script/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,14 +408,20 @@ class Editor implements KetcherEditor {
return this._selection; // eslint-disable-line
}

const struct = this.struct();
let ReStruct = this.render.ctab;
let selectAll = false;
this._selection = null; // eslint-disable-line
if (ci === 'all') {
selectAll = true;
// TODO: better way will be this.struct()
ci = structObjects.reduce((res, key) => {
res[key] = Array.from(ReStruct[key].keys());
let restructItemsIds: number[] = Array.from(ReStruct[key].keys());
restructItemsIds = restructItemsIds.filter(
(restructItemId) =>
!struct.isTargetFromMacromolecule({ map: key, id: restructItemId }),
);
res[key] = restructItemsIds;
return res;
}, {});
}
Expand Down
15 changes: 15 additions & 0 deletions packages/ketcher-react/src/script/editor/tool/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ class AtomTool implements Tool {

const eventMaps = ['atoms', 'functionalGroups'];
const ci = editor.findItem(event, eventMaps);
const struct = editor.struct();

if (struct.isTargetFromMacromolecule(ci)) {
return;
}

if (ci?.map === 'atoms') {
const atomId = ci.id;
Expand Down Expand Up @@ -143,6 +148,11 @@ class AtomTool implements Tool {

const eventMaps = ['atoms', 'functionalGroups'];
const ci = editor.findItem(event, eventMaps);
const struct = editor.struct();

if (struct.isTargetFromMacromolecule(ci)) {
return;
}

if (
!dragCtx?.item ||
Expand Down Expand Up @@ -222,8 +232,13 @@ class AtomTool implements Tool {
} = this;

const ci = editor.findItem(event, ['atoms', 'bonds', 'functionalGroups']);
const struct = editor.struct();
const action = new Action();

if (struct.isTargetFromMacromolecule(ci) || !dragCtx) {
return;
}

if ((!dragCtx.item || dragCtx?.isSaltOrSolvent) && !ci) {
action.mergeWith(
fromAtomAddition(reStruct, rnd.page2obj(event), atomProps),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { MonomerMicromolecule } from 'ketcher-core';
import { Editor } from '../../Editor';

const isMacroMolecule = (editor: Editor, id: number): boolean => {
const functionalGroups = editor.render.ctab.molecule.functionalGroups;
const matchingGroup = functionalGroups?.get(id);
return matchingGroup?.relatedSGroup instanceof MonomerMicromolecule;
const struct = editor.struct();
return struct.isFunctionalGroupFromMacromolecule(id);
};

// dragCtx is actually "any" in the code
Expand All @@ -18,22 +16,11 @@ const isMergingToMacroMolecule = (editor: Editor, dragCtx: any): boolean => {
return isMacroMolecule(editor, targetObjectId);
};

const isBondingWithMacroMolecule = (
editor: Editor,
event: MouseEvent,
): boolean => {
const isBondingWithMacroMolecule = (editor: Editor, event: MouseEvent) => {
const ci = editor.findItem(event, ['bonds', 'functionalGroups']);
if (ci?.map === 'functionalGroups') {
return isMacroMolecule(editor, ci?.id);
} else if (ci?.map === 'bonds') {
const struct = editor.struct();
const bond = struct.bonds.get(ci.id);
const sGroup = struct.getGroupFromAtomId(bond?.begin);
const struct = editor.struct();

return sGroup instanceof MonomerMicromolecule;
}

return false;
return struct.isTargetFromMacromolecule(ci);
};

export {
Expand Down
30 changes: 25 additions & 5 deletions packages/ketcher-react/src/script/editor/tool/helper/locate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,30 @@
* limitations under the License.
***************************************************************************/

import { FunctionalGroup, Vec2 } from 'ketcher-core';
import {
FunctionalGroup,
MonomerMicromolecule,
Struct,
Vec2,
} from 'ketcher-core';

function getElementsInRectangle(restruct, p0, p1) {
const bondList: Array<number> = [];
const atomList: Array<number> = [];
const sGroups = restruct.sgroups;
const functionalGroups = restruct.molecule.functionalGroups;
const struct: Struct = restruct.molecule;

const x0 = Math.min(p0.x, p1.x);
const x1 = Math.max(p0.x, p1.x);
const y0 = Math.min(p0.y, p1.y);
const y1 = Math.max(p0.y, p1.y);

restruct.bonds.forEach((bond, bid) => {
if (struct.isBondFromMacromolecule(bid)) {
return;
}

const centre = Vec2.lc2(
restruct.atoms.get(bond.b.begin).a.pp,
0.5,
Expand All @@ -54,8 +64,9 @@ function getElementsInRectangle(restruct, p0, p1) {
functionalGroups,
aid,
);
const sGroup = restruct.sgroups.get(relatedFGId);
const reSGroup = restruct.sgroups.get(relatedFGId);
if (
!(reSGroup?.item instanceof MonomerMicromolecule) &&
atom.a.pp.x > x0 &&
atom.a.pp.x < x1 &&
atom.a.pp.y > y0 &&
Expand All @@ -66,7 +77,7 @@ function getElementsInRectangle(restruct, p0, p1) {
functionalGroups,
true,
) ||
aid === sGroup.item.atoms[0])
aid === reSGroup.item.atoms[0])
) {
atomList.push(aid);
}
Expand Down Expand Up @@ -172,12 +183,20 @@ function getElementsInPolygon(restruct, rr) {
const r: any = [];
const sGroups = restruct.sgroups;
const functionalGroups = restruct.molecule.functionalGroups;
const struct: Struct = restruct.molecule;

for (let i = 0; i < rr.length; ++i) {
r[i] = new Vec2(rr[i].x, rr[i].y);
}

restruct.bonds.forEach((bond, bid) => {
if (
struct.isAtomFromMacromolecule(bond.b.begin) ||
struct.isAtomFromMacromolecule(bond.b.end)
) {
return;
}

const centre = Vec2.lc2(
restruct.atoms.get(bond.b.begin).a.pp,
0.5,
Expand All @@ -201,16 +220,17 @@ function getElementsInPolygon(restruct, rr) {
functionalGroups,
aid,
);
const sGroup = restruct.sgroups.get(relatedFGId);
const reSGroup = restruct.sgroups.get(relatedFGId);
if (
!(reSGroup?.item instanceof MonomerMicromolecule) &&
isPointInPolygon(r, atom.a.pp) &&
(!FunctionalGroup.isAtomInContractedFunctionalGroup(
atom.a,
sGroups,
functionalGroups,
true,
) ||
aid === sGroup.item.atoms[0])
aid === reSGroup.item.atoms[0])
) {
atomList.push(aid);
}
Expand Down
10 changes: 9 additions & 1 deletion packages/ketcher-react/src/script/editor/tool/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ import {
} from 'ketcher-core';

import LassoHelper from './helper/lasso';
import { isMergingToMacroMolecule } from './helper/isMacroMolecule';
import {
isBondingWithMacroMolecule,
isMergingToMacroMolecule,
} from './helper/isMacroMolecule';
import { atomLongtapEvent } from './atom';
import SGroupTool from './sgroup';
import { xor } from 'lodash/fp';
Expand Down Expand Up @@ -92,6 +95,10 @@ class SelectTool implements Tool {
);
const ci = this.editor.findItem(event, map, null);

if (isBondingWithMacroMolecule(this.editor, event)) {
return;
}

const selected = {
...(ci?.map === 'atoms' && { atoms: [ci.id] }),
...(ci?.map === 'bonds' && { bonds: [ci.id] }),
Expand Down Expand Up @@ -239,6 +246,7 @@ class SelectTool implements Tool {

if (this.#lassoHelper.running()) {
const sel = this.#lassoHelper.addPoint(event);

editor.selection(
!event.shiftKey ? sel : selMerge(sel, editor.selection(), false),
);
Expand Down
17 changes: 15 additions & 2 deletions packages/ketcher-react/src/script/editor/tool/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
Bond,
BondAttr,
AtomAttr,
MonomerMicromolecule,
} from 'ketcher-core';
import Editor from '../Editor';
import { getGroupIdsFromItemArrays } from './helper/getGroupIdsFromItems';
Expand Down Expand Up @@ -189,7 +190,13 @@ class TemplateTool implements Tool {

private get isNeedToShowRemoveAbbreviationPopup(): boolean {
const targetId = this.findKeyOfRelatedGroupId(this.closestItem?.id);
const isTargetExpanded = this.functionalGroups.get(targetId!)?.isExpanded;
const functionalGroup = this.functionalGroups.get(targetId!);

if (functionalGroup?.relatedSGroup instanceof MonomerMicromolecule) {
return false;
}

const isTargetExpanded = functionalGroup?.isExpanded;
const isTargetAtomOrBond =
this.targetGroupsIds.length && !this.isModeFunctionalGroup;

Expand Down Expand Up @@ -224,6 +231,9 @@ class TemplateTool implements Tool {
}

async mousedown(event: MouseEvent) {
const target = this.editor.findItem(event, this.findItems);
const struct = this.editor.struct();

this.event = event;

this.templatePreview?.hidePreview();
Expand All @@ -250,6 +260,10 @@ class TemplateTool implements Tool {
}
}

if (struct.isTargetFromMacromolecule(target)) {
return;
}

if (this.isNeedToShowRemoveAbbreviationPopup) {
await this.showRemoveAbbreviationPopup();

Expand Down Expand Up @@ -304,7 +318,6 @@ class TemplateTool implements Tool {
const dragCtx = this.dragCtx;
const ci = dragCtx.item;
let targetPos: Vec2 | null | undefined = null;

/* moving when attached to bond */
if (ci && ci.map === 'bonds' && !this.isModeFunctionalGroup) {
const bond = this.struct.bonds.get(ci.id);
Expand Down
Loading

0 comments on commit 9e5ad98

Please sign in to comment.