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

#2229: Bond between Functional Group and structure disappears after adding Functional Group again #2230

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
17 changes: 17 additions & 0 deletions packages/ketcher-core/src/domain/entities/sgroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,23 @@ export class SGroup {
this.pp = topLeftPoint
}

getAttAtomId(struct: Struct): number {
for (const atomId of this.atoms) {
const atom = struct.atoms.get(atomId)
if (!atom) continue
if (Number.isInteger(atom.attpnt)) return atomId
}
// in normal circumstances this should never be invoked
return this.atoms[0]
}

isGroupAttached(struct: Struct): boolean {
const attachPointId = this.getAttAtomId(struct)
const neighbours = struct.atomGetNeighbors(attachPointId)

return !neighbours?.every(({ aid }) => this.atoms.includes(aid))
}

static getOffset(sgroup: SGroup): null | Vec2 {
if (!sgroup?.pp) return null
return Vec2.diff(sgroup.pp, sgroup.bracketBox.p1)
Expand Down
62 changes: 45 additions & 17 deletions packages/ketcher-react/src/script/editor/tool/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,14 @@ class TemplateTool {

const dragCtx = this.dragCtx
const ci = dragCtx.item
let pos0: Vec2 | null | undefined = null
const pos1 = this.editor.render.page2obj(event)
let targetPos: Vec2 | null | undefined = null
const eventPos = this.editor.render.page2obj(event)
const struct = restruct.molecule

/* moving when attached to bond */
if (ci && ci.map === 'bonds' && this.mode !== 'fg') {
const bond = struct.bonds.get(ci.id)
let sign = getSign(struct, bond, pos1)
let sign = getSign(struct, bond, eventPos)

if (dragCtx.sign1 * this.template.sign > 0) {
sign = -sign
Expand Down Expand Up @@ -296,21 +296,22 @@ class TemplateTool {
// calc initial pos and is extra bond needed
if (!ci) {
// ci.type == 'Canvas'
pos0 = dragCtx.xy0
targetPos = dragCtx.xy0
} else if (ci.map === 'atoms') {
pos0 = struct.atoms.get(ci.id)?.pp
targetPos = struct.atoms.get(ci.id)?.pp

if (pos0) {
extraBond = this.mode === 'fg' ? true : Vec2.dist(pos0, pos1) > 1
if (targetPos) {
extraBond =
this.mode === 'fg' ? true : Vec2.dist(targetPos, eventPos) > 1
}
}

if (!pos0) {
if (!targetPos) {
return true
}

// calc angle
let angle = utils.calcAngle(pos0, pos1)
let angle = utils.calcAngle(targetPos, eventPos)

if (!event.ctrlKey) {
angle = utils.fracAngle(angle, null)
Expand Down Expand Up @@ -373,9 +374,8 @@ class TemplateTool {
delete this.dragCtx

const restruct = this.editor.render.ctab
const sgroups = restruct.sgroups
const struct = restruct.molecule
const ci = dragCtx.item
let ci = dragCtx.item
const functionalGroups = struct.functionalGroups

/* after moving around bond */
Expand All @@ -402,7 +402,6 @@ class TemplateTool {

let action
let pasteItems = null
let isFunctionalGroupReplace = false

if (SGroup.isSaltOrSolvent(this.template.molecule.name)) {
addSaltsAndSolventsOnCanvasWithoutMerge(
Expand All @@ -417,18 +416,47 @@ class TemplateTool {
FunctionalGroup.isContractedFunctionalGroup(ci.id, functionalGroups) &&
this.mode === 'fg'
) {
const sGroup = sgroups.get(ci.id)
const closestGroup = this.editor.struct().sgroups.get(ci.id)
const isClosestGroupAttached =
closestGroup && closestGroup.isGroupAttached(this.editor.struct())

if (isClosestGroupAttached) {
const groupAttachmentAtomId = this.editor
.struct()
.atoms.find((atomId) => {
return !!this.editor
.struct()
.atomGetNeighbors(atomId)
?.find(
(neighbor) =>
neighbor.aid ===
closestGroup.getAttAtomId(this.editor.struct())
)
})

if (groupAttachmentAtomId !== null) {
const targetPos =
this.editor.struct().atoms.get(groupAttachmentAtomId)?.pp ||
dragCtx.xy0
const eventPos = this.editor.render.page2obj(event)

const dist = Vec2.dist(targetPos, eventPos)
ci = { map: 'atoms', dist, id: groupAttachmentAtomId }
}
}

this.editor.update(
fromFragmentDeletion(this.editor.render.ctab, {
atoms: [...SGroup.getAtoms(struct, sGroup?.item)],
bonds: [...SGroup.getBonds(struct, sGroup?.item)]
atoms: [...SGroup.getAtoms(struct, closestGroup)],
bonds: [...SGroup.getBonds(struct, closestGroup)]
})
)
isFunctionalGroupReplace = true

if (!isClosestGroupAttached) ci = null
}

if (!dragCtx.action) {
if (!ci || isFunctionalGroupReplace) {
if (!ci) {
// ci.type == 'Canvas'
;[action, pasteItems] = fromTemplateOnCanvas(
restruct,
Expand Down