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

#2078 center molecules after layout #2931

Merged
merged 3 commits into from
Jul 19, 2023
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
35 changes: 35 additions & 0 deletions ketcher-autotests/tests/Indigo-Tools/Layout/layout.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Page, test } from '@playwright/test';
import {
selectTopPanelButton,
TopPanelButton,
takeEditorScreenshot,
openFile,
pressButton,
waitForLoad,
getCoordinatesOfTheMiddleOfTheScreen,
} from '@utils';

async function openFileWithShift(filename: string, page: Page) {
await selectTopPanelButton(TopPanelButton.Open, page);
await openFile(filename, page);
await waitForLoad(page, async () => {
await pressButton(page, 'Add to Canvas');
});
const { x, y } = await getCoordinatesOfTheMiddleOfTheScreen(page);
const shift = 150;
await page.mouse.click(x + shift, y + shift);
}

test.describe('Indigo Tools - Layout', () => {
test.beforeEach(async ({ page }) => {
await page.goto('');
});

test('Center molecule after layout', async ({ page }) => {
// Related Github issue: https://github.com/epam/ketcher/issues/2078
const anyStructure = 'benzene-rings.mol';
await openFileWithShift(anyStructure, page);
await selectTopPanelButton(TopPanelButton.Layout, page);
await takeEditorScreenshot(page);
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions ketcher-autotests/tests/test-data/benzene-rings.mol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
null
Ketcher 7172314 12D 1 1.00000 0.00000 0

18 20 0 0 0 0 0 0 0 0999 V2000
20.5750 -8.6000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
19.7090 -10.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
19.7090 -9.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
20.5750 -10.6000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
21.4410 -9.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
21.4410 -10.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
19.8679 -7.8929 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
18.1961 -7.4466 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
18.9014 -8.1523 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
18.4545 -6.4796 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
20.1273 -6.9220 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
19.4156 -6.2194 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
20.1227 -5.5123 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
18.8981 -4.2900 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
19.1560 -5.2537 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
19.6054 -3.5817 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
20.8329 -4.8013 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
20.5678 -3.8369 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
3 1 2 0 0 0
4 2 2 0 0 0
1 5 1 0 0 0
2 3 1 0 0 0
5 6 2 0 0 0
6 4 1 0 0 0
1 7 1 0 0 0
9 7 2 0 0 0
10 8 2 0 0 0
7 11 1 0 0 0
8 9 1 0 0 0
11 12 2 0 0 0
12 10 1 0 0 0
12 13 1 0 0 0
15 13 2 0 0 0
16 14 2 0 0 0
13 17 1 0 0 0
14 15 1 0 0 0
17 18 2 0 0 0
18 16 1 0 0 0
M END
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { Action } from './action';
import { fromAtomsFragmentAttr } from './atom';
import { getRelSGroupsBySelection } from './utils';

export function fromMultipleMove(restruct, lists, d) {
export function fromMultipleMove(restruct, lists, d: Vec2) {
d = new Vec2(d);

const action = new Action();
Expand Down
30 changes: 30 additions & 0 deletions packages/ketcher-core/src/application/editor/editor.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Action } from '../editor/actions';
import { Render } from 'application/render';
import { Struct } from 'domain/entities';
import { selectionKeys } from './shared/constants';
import { PipelineSubscription, Subscription } from 'subscription';

export interface EditorHistory {
readonly current?: number;
Expand All @@ -35,6 +36,11 @@ export type EditorSelection = {
[key in typeof selectionKeys[number]]?: number[];
};

export type FloatingToolsParams = {
visible?: boolean;
rotateHandlePosition?: { x: number; y: number };
};

export interface Editor {
isDitrty: () => boolean;
setOrigin: () => void;
Expand All @@ -51,6 +57,30 @@ export interface Editor {
zoom: (value?: any) => any;
structSelected: () => Struct;
explicitSelected: () => EditorSelection;
centerStruct: () => void;
zoomAccordingContent: () => void;
errorHandler: ((message: string) => void) | null;
event: {
message: Subscription;
elementEdit: PipelineSubscription;
bondEdit: PipelineSubscription;
rgroupEdit: PipelineSubscription;
sgroupEdit: PipelineSubscription;
sdataEdit: PipelineSubscription;
quickEdit: PipelineSubscription;
attachEdit: PipelineSubscription;
removeFG: PipelineSubscription;
change: Subscription;
selectionChange: PipelineSubscription;
aromatizeStruct: PipelineSubscription;
dearomatizeStruct: PipelineSubscription;
enhancedStereoEdit: PipelineSubscription;
confirm: PipelineSubscription;
showInfo: PipelineSubscription;
apiSettings: PipelineSubscription;
cursor: Subscription;
updateFloatingTools: Subscription<FloatingToolsParams>;
};
update: (
action: Action | true,
ignoreHistory?: boolean,
Expand Down
49 changes: 27 additions & 22 deletions packages/ketcher-react/src/script/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@

import {
Action,
FloatingToolsParams,
Editor as KetcherEditor,
Pile,
Render,
Struct,
Vec2,
fromDescriptorsAlign,
fromMultipleMove,
fromNewCanvas,
} from 'ketcher-core';
import {
Expand All @@ -44,6 +46,11 @@ import {
ToolConstructorInterface,
ToolEventHandlerName,
} from './tool/Tool';
import {
getSelectionMap,
getStructCenter,
recoordinate,
} from './utils/structLayout';

const SCALE = 40;
const HISTORY_SIZE = 32; // put me to options
Expand Down Expand Up @@ -101,11 +108,6 @@ function selectStereoFlagsIfNecessary(
return stereoFlags;
}

export type FloatingToolsParams = {
visible?: boolean;
rotateHandlePosition?: { x: number; y: number };
};

export interface Selection {
atoms?: Array<number>;
bonds?: Array<number>;
Expand Down Expand Up @@ -330,6 +332,26 @@ class Editor implements KetcherEditor {
return this.render.options.zoom;
}

centerStruct() {
const structure = this.render.ctab;
const { scale, offset } = this.render.options;
const structCenter = getStructCenter(structure);
const { width, height } = this.render.clientArea.getBoundingClientRect();
const canvasCenterVector = new Vec2(width, height);
const canvasCenter = this.render.view2obj(canvasCenterVector).scaled(0.5);
const shiftFactor = 0.4;
const shiftVector = canvasCenter
.sub(structCenter)
.sub(offset.scaled(shiftFactor / scale));

const structureToMove = getSelectionMap(structure);

const action = fromMultipleMove(structure, structureToMove, shiftVector);
this.update(action, true);

recoordinate(this, canvasCenter);
}

zoomAccordingContent() {
this.zoom(1);
const clientAreaBoundingBox =
Expand Down Expand Up @@ -782,23 +804,6 @@ function domEventSetup(editor: Editor, clientArea: HTMLElement) {
});
}

function recoordinate(editor: Editor, rp?: Vec2 /* , vp */) {
// rp is a point in scaled coordinates, which will be positioned
// vp is the point where the reference point should now be (in view coordinates)
// or the center if not set
console.assert(rp, 'Reference point not specified');
if (rp) {
editor.render.setScrollOffset(rp.x, rp.y);
} else {
editor.render.setScrollOffset(0, 0);
}
}

function getStructCenter(ReStruct, selection?) {
const bb = ReStruct.getVBoxObj(selection || {});
return Vec2.lc2(bb.p0, 0.5, bb.p1, 0.5);
}

export { Editor };
export default Editor;

Expand Down
1 change: 1 addition & 0 deletions packages/ketcher-react/src/script/editor/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@

export * from './customOnChangeHandler';
export * from './elementOffset';
export * from './structLayout';
23 changes: 23 additions & 0 deletions packages/ketcher-react/src/script/editor/utils/structLayout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Editor, ReStruct, Vec2 } from 'ketcher-core';

export function getSelectionMap(structure: ReStruct) {
return Object.keys(ReStruct.maps).reduce((result, map) => {
result[map] = Array.from(structure[map].keys());
return result;
}, {});
}

export function getStructCenter(ReStruct, selection?) {
const bb = ReStruct.getVBoxObj(selection || {});
return Vec2.lc2(bb.p0, 0.5, bb.p1, 0.5);
}

export function recoordinate(editor: Editor, rp?: Vec2) {
// rp is a point in scaled coordinates, which will be positioned
console.assert(rp, 'Reference point not specified');
if (rp) {
editor.render.setScrollOffset(rp.x, rp.y);
} else {
editor.render.setScrollOffset(0, 0);
}
}
12 changes: 9 additions & 3 deletions packages/ketcher-react/src/script/ui/state/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
Struct,
SupportedFormat,
emitEventRequestIsFinished,
Editor,
} from 'ketcher-core';

import { supportedSGroupTypes } from './constants';
Expand Down Expand Up @@ -96,7 +97,7 @@ export function removeStructAction(): {
export function load(struct: Struct, options?) {
return async (dispatch, getState) => {
const state = getState();
const editor = state.editor;
const editor = state.editor as Editor;
const server = state.server;
const errorHandler = editor.errorHandler;

Expand Down Expand Up @@ -129,7 +130,11 @@ export function load(struct: Struct, options?) {
// NB: reset id
const oldStruct = editor.struct().clone();
parsedStruct.sgroups.forEach((sg, sgId) => {
const offset = SGroup.getOffset(oldStruct.sgroups.get(sgId));
const sgroup = oldStruct.sgroups.get(sgId);
if (!sgroup) {
throw Error('Incorrect sgroupId provided');
}
const offset = SGroup.getOffset(sgroup);
const atomSet = new Pile(sg.atoms);
const crossBonds = SGroup.getCrossBonds(parsedStruct, atomSet);
SGroup.bracketPos(sg, parsedStruct, crossBonds);
Expand Down Expand Up @@ -171,12 +176,13 @@ export function load(struct: Struct, options?) {
}

editor.zoomAccordingContent();
editor.centerStruct();

dispatch(setAnalyzingFile(false));
dispatch({ type: 'MODAL_CLOSE' });
} catch (err: any) {
dispatch(setAnalyzingFile(false));
err && errorHandler(err.message);
err && errorHandler && errorHandler(err.message);
} finally {
emitEventRequestIsFinished();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ketcher-react/src/typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ declare module 'subscription' {
export class PipelineSubscription<
TDispatchValue = any,
> extends Subscription<TDispatchValue> {
dispatch: (value: TDispatchValue) => any;
dispatch: (value?: TDispatchValue) => any;
}

export class StoppableSubscription<
Expand Down