Skip to content

Commit 177257d

Browse files
authored
Support nucleotide S-groups in macro rendering
1 parent 9b820d8 commit 177257d

7 files changed

Lines changed: 102 additions & 4 deletions

File tree

packages/ketcher-core/__tests__/application/render/restruct/resgroup.test.ts

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@ import {
66
Render,
77
} from 'application/render';
88
import {
9-
type Struct,
9+
Atom,
1010
Bond,
1111
Pool,
1212
RGroupAttachmentPoint,
1313
SGroup,
14+
SUPERATOM_CLASS,
15+
Struct,
1416
Vec2,
1517
} from 'domain/entities';
1618
import { restruct } from '../../../mock-data';
1719
import { mockFn } from 'jest-mock-extended';
1820
import type { RenderOptions } from 'application/render/render.types';
21+
import { RenderStruct } from 'application/render/renderStruct';
1922

2023
describe('resgroup should draw brackets with attachment points correctly', () => {
2124
const mockBonds = [
@@ -99,6 +102,7 @@ describe('resgroup should draw brackets with attachment points correctly', () =>
99102
y: 6.574988999717658,
100103
z: 0,
101104
});
105+
102106
restruct.rgroupAttachmentPoints.set(0, reRGroupAttachmentPoint);
103107
const option = {
104108
microModeScale: 20,
@@ -125,7 +129,7 @@ describe('resgroup should draw brackets with attachment points correctly', () =>
125129
const bonds = new Pool();
126130
mockBonds.forEach((bond, i) => bonds.set(i, new Bond(bond)));
127131
restruct.molecule.bonds = bonds;
128-
reSgroup.draw(restruct, sGroup);
132+
reSgroup.draw(restruct as unknown as ReStruct, sGroup);
129133
expect(attachmentsSpy).toHaveBeenCalled();
130134
});
131135

@@ -144,7 +148,7 @@ describe('resgroup should draw brackets with attachment points correctly', () =>
144148
restruct.rgroupAttachmentPoints.set(1, reRGroupAttachmentPoint);
145149
restruct.molecule.getRGroupAttachmentPointsByAtomId =
146150
mockFn().mockReturnValue([0, 1]);
147-
reSgroup.draw(restruct, sGroup);
151+
reSgroup.draw(restruct as unknown as ReStruct, sGroup);
148152
expect(attachmentsSpy).toHaveBeenCalled();
149153
});
150154

@@ -169,3 +173,48 @@ describe('resgroup should draw brackets with attachment points correctly', () =>
169173
expect(attachmentsSpy).toHaveBeenCalled();
170174
});
171175
});
176+
177+
describe('resgroup should draw nucleotide component S-groups', () => {
178+
it('should draw nucleotide component brackets and class label', () => {
179+
const option = {
180+
microModeScale: 20,
181+
width: 100,
182+
height: 100,
183+
} as RenderOptions;
184+
const render = new Render(document as unknown as HTMLElement, option);
185+
render.ctab = restruct as unknown as ReStruct;
186+
restruct.render = render as any;
187+
188+
const sGroup = new SGroup('nucleotideComponent');
189+
const reSgroup = new ReSGroup(sGroup);
190+
sGroup.data.class = SUPERATOM_CLASS.BASE;
191+
SGroup.addAtom(sGroup, 2, restruct.molecule as unknown as Struct);
192+
193+
reSgroup.draw(restruct as unknown as ReStruct, sGroup);
194+
195+
expect(
196+
render.paper.canvas.querySelector('[data-label-text="Base"]'),
197+
).toBeTruthy();
198+
});
199+
});
200+
201+
describe('RenderStruct.prepareStruct in macromolecules mode', () => {
202+
const isPolymerEditorTurnedOn = window.isPolymerEditorTurnedOn;
203+
204+
afterEach(() => {
205+
window.isPolymerEditorTurnedOn = isPolymerEditorTurnedOn;
206+
});
207+
208+
it('should preserve S-groups for macromolecules rendering', () => {
209+
const struct = new Struct();
210+
const atomId = struct.atoms.add(new Atom({ label: 'C' }));
211+
const sGroup = new SGroup('GEN');
212+
SGroup.addAtom(sGroup, atomId, struct);
213+
sGroup.id = struct.sgroups.add(sGroup);
214+
window.isPolymerEditorTurnedOn = true;
215+
216+
const preparedStruct = RenderStruct.prepareStruct(struct);
217+
218+
expect(preparedStruct.sgroups.size).toBe(1);
219+
});
220+
});

packages/ketcher-core/__tests__/domain/serializers/ket/KetSerializer.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
RxnArrow,
1616
RxnPlus,
1717
SimpleObject,
18+
SGroup,
19+
Struct,
1820
Text,
1921
Vec2,
2022
} from 'domain/entities';
@@ -267,6 +269,24 @@ describe('serialize (ToKet)', () => {
267269
expect(spy.mock.results[2].value.sgroups[5].subscript).toEqual('n');
268270
expect(spy.mock.results[2].value.sgroups[5].connectivity).toEqual('HT');
269271
});
272+
it('serializes and deserializes nucleotide component S-groups', () => {
273+
const struct = new Struct();
274+
const sgroup = new SGroup('nucleotideComponent');
275+
sgroup.atoms = [0];
276+
sgroup.data.class = 'BASE';
277+
struct.sgroups.add(sgroup);
278+
279+
const serialized = moleculeToKet.moleculeToKet(struct);
280+
expect(serialized.sgroups[0]).toEqual({
281+
type: 'nucleotideComponent',
282+
atoms: [0],
283+
class: 'BASE',
284+
});
285+
286+
const deserialized = moleculeToStruct.sgroupToStruct(serialized.sgroups[0]);
287+
expect(deserialized.type).toEqual('nucleotideComponent');
288+
expect(deserialized.data.class).toEqual('BASE');
289+
});
270290
it('rgroupToKet', () => {
271291
const spy = jest.spyOn(rgroupToKet, 'rgroupToKet');
272292
const result = JSON.parse(ket.serialize(contentRgroupStruct)).rg14;

packages/ketcher-core/src/application/render/renderStruct.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export class RenderStruct {
2323
if (struct.sgroups.size > 0) {
2424
const newStruct = struct.clone();
2525
convertAllSGroupAttachmentPointsToRGroupAttachmentPoints(newStruct);
26+
if (window.isPolymerEditorTurnedOn) {
27+
return newStruct;
28+
}
2629
if (!newStruct.sgroups.get(0)?.isSuperatomWithoutLabel) {
2730
newStruct.sgroups.delete(0);
2831
}

packages/ketcher-core/src/application/render/restruct/resgroup.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,14 @@ class ReSGroup extends ReObject {
148148
SGroupdrawBracketsOptions.superatomClass = sgroup.data.class;
149149
break;
150150
}
151+
case 'nucleotideComponent': {
152+
SGroupdrawBracketsOptions.lowerIndexText =
153+
SUPERATOM_CLASS_TEXT[sgroup.data.class];
154+
SGroupdrawBracketsOptions.upperIndexText = null;
155+
SGroupdrawBracketsOptions.indexAttribute = { 'font-style': 'italic' };
156+
SGroupdrawBracketsOptions.superatomClass = sgroup.data.class;
157+
break;
158+
}
151159
case 'DAT': {
152160
set = drawGroupDat(remol, sgroup);
153161
break;
@@ -166,6 +174,7 @@ class ReSGroup extends ReObject {
166174
'GEN',
167175
'COP',
168176
'queryComponent',
177+
'nucleotideComponent',
169178
];
170179
if (
171180
sgroupTypesWithBrackets.includes(sgroup.type) &&

packages/ketcher-core/src/domain/serializers/ket/fromKet/moleculeToStruct.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ export function sgroupToStruct(source) {
164164
);
165165
break;
166166
}
167+
case 'nucleotideComponent': {
168+
ifDef(sgroup.data, 'class', source.class);
169+
break;
170+
}
167171
case 'DAT': {
168172
ifDef(sgroup.data, 'absolute', source.placement);
169173
ifDef(sgroup.data, 'attached', source.display);

packages/ketcher-core/src/domain/serializers/ket/schema.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,16 @@
508508
},
509509
"type": {
510510
"type": "string",
511-
"enum": ["GEN", "MUL", "SRU", "SUP", "DAT", "queryComponent", "COP"]
511+
"enum": [
512+
"GEN",
513+
"MUL",
514+
"SRU",
515+
"SUP",
516+
"DAT",
517+
"queryComponent",
518+
"nucleotideComponent",
519+
"COP"
520+
]
512521
}
513522
},
514523
"if": {

packages/ketcher-core/src/domain/serializers/ket/toKet/moleculeToKet.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ function sgroupToKet(struct: Struct, source: SGroup) {
216216
);
217217
break;
218218
}
219+
case 'nucleotideComponent': {
220+
ifDef(result, 'class', source.data.class);
221+
break;
222+
}
219223
case 'DAT': {
220224
const data = source.data;
221225
ifDef(result, 'placement', data.absolute, true);

0 commit comments

Comments
 (0)