in packages/ketcher-core/src/application/editor/actions/template.ts [92:208]
export function fromTemplateOnAtom(
restruct,
template,
aid,
angle,
extraBond,
isPreview = false,
): [Action, { atoms: number[]; bonds: number[] }] {
let action = new Action();
const tmpl = template.molecule;
const struct = restruct.molecule;
const isTmplSingleGroup = template.molecule.isSingleGroup();
let atom = struct.atoms.get(aid); // aid - the atom that was clicked on
let aid1 = aid; // aid1 - the atom on the other end of the extra bond || aid
let delta: any = null;
if (extraBond) {
// create extra bond after click on atom
const extraRes = extraBondAction(restruct, aid, angle);
action = extraRes.action;
aid1 = extraRes.aid1;
atom = struct.atoms.get(aid1);
delta =
utils.calcAngle(struct.atoms.get(aid).pp, atom.pp) - template.angle0;
} else {
if (angle === null) {
angle = utils.calcAngle(atom.pp, atomForNewBond(restruct, aid).pos);
}
delta = angle - template.angle0;
}
const map = new Map();
const xy0 = tmpl.atoms.get(template.aid).pp;
const frid = atomGetAttr(restruct, aid, 'fragment');
/* For merge */
const pasteItems = {
// only atoms and bonds now
atoms: [] as number[],
bonds: [] as number[],
};
/* ----- */
tmpl.atoms.forEach((a, id) => {
const attrs: any = Atom.getAttrHash(a);
attrs.fragment = frid;
if (id === template.aid) {
action.mergeWith(fromAtomsAttrs(restruct, aid1, attrs, true));
map.set(id, aid1);
pasteItems.atoms.push(aid1);
} else {
const v = Vec2.diff(a.pp, xy0).rotate(delta).add(atom.pp);
const operation = new AtomAdd(attrs, v.get_xy0()).perform(
restruct,
) as AtomAdd;
action.addOp(operation);
map.set(id, operation.data.aid);
pasteItems.atoms.push(operation.data.aid);
}
});
if (!isTmplSingleGroup) mergeSgroups(action, restruct, pasteItems.atoms, aid);
tmpl.bonds.forEach((bond) => {
const operation = new BondAdd(
map.get(bond.begin),
map.get(bond.end),
bond,
).perform(restruct) as BondAdd;
action.addOp(operation);
new BondAttr(operation.data.bid, 'isPreview', isPreview).perform(restruct);
pasteItems.bonds.push(operation.data.bid);
});
tmpl.sgroups.forEach((sg: SGroup) => {
const newsgid = restruct.molecule.sgroups.newId();
const sgAtoms = sg.atoms.map((aid) => map.get(aid));
const attachmentPoints = sg.cloneAttachmentPoints(map);
const sgAction = fromSgroupAddition(
restruct,
sg.type,
sgAtoms,
{
...sg.data,
expanded: isPreview ? true : sg.data.expanded,
},
newsgid,
attachmentPoints,
atom.pp,
sg.type === 'SUP' ? sg.isExpanded() : null,
sg.data.name,
);
sgAction.operations.reverse().forEach((oper) => {
action.addOp(oper);
});
});
action.operations.reverse();
action.addOp(new CalcImplicitH([...pasteItems.atoms, aid]).perform(restruct));
action.mergeWith(
fromBondStereoUpdate(
restruct,
restruct.molecule.bonds.get(pasteItems.bonds[0]),
),
);
return [action, pasteItems];
}