in packages/ketcher-core/src/domain/entities/DrawingEntitiesManager.ts [2703:2833]
public recalculateAntisenseChains() {
const command = new Command();
const chainsCollection = ChainsCollection.fromMonomers([
...this.monomers.values(),
]);
const senseToAntisenseChains = new Map<Chain, Chain[]>();
const handledChains = new Set<Chain>();
this.monomers.forEach((monomer) => {
command.merge(
this.modifyMonomerItem(monomer, {
...monomer.monomerItem,
isAntisense: false,
isSense: false,
}),
);
});
chainsCollection.chains.forEach((chain) => {
if (handledChains.has(chain)) {
return;
}
let senseChain: Chain;
const complimentaryChainsWithData =
chainsCollection.getComplimentaryChainsWithData(chain);
const chainsToCheck = new Set<Chain>();
complimentaryChainsWithData.forEach((complimentaryChainWithData) => {
const hasHydrogenBondWithRnaBase =
complimentaryChainWithData.complimentaryChain.monomers.some(
(monomer) => {
return (
(isRnaBaseOrAmbiguousRnaBase(monomer) &&
Boolean(getSugarFromRnaBase(monomer)) &&
monomer.hydrogenBonds.length > 0) ||
monomer.hydrogenBonds.some((hydrogenBond) => {
const anotherMonomer =
hydrogenBond.getAnotherMonomer(monomer);
return (
isRnaBaseOrAmbiguousRnaBase(anotherMonomer) &&
Boolean(getSugarFromRnaBase(anotherMonomer))
);
})
);
},
);
if (hasHydrogenBondWithRnaBase) {
chainsToCheck.add(complimentaryChainWithData.complimentaryChain);
}
});
chainsToCheck.add(chain);
const chainToMonomers = new Map<Chain, BaseMonomer[]>();
chainsToCheck.forEach((chainToCheck) => {
chainToMonomers.set(chainToCheck, chainToCheck.monomers);
});
const largestChainsMonomersAmount = Math.max(
...[...chainToMonomers.values()].map((monomers) => monomers.length),
);
const largestChains = [...chainToMonomers.entries()].filter(
([, monomers]) => monomers.length === largestChainsMonomersAmount,
);
if (largestChains.length === 1) {
senseChain = largestChains[0][0];
} else {
const chainsToCenters = new Map<Chain, Vec2>();
largestChains.forEach(([chainToCheck, monomers]) => {
const chainBbox = DrawingEntitiesManager.geStructureBbox(monomers);
chainsToCenters.set(
chainToCheck,
new Vec2(
chainBbox.left + chainBbox.width / 2,
chainBbox.top + chainBbox.height / 2,
),
);
});
const chainsToCenterArray = [...chainsToCenters.entries()];
const chainWithLowestCenter = chainsToCenterArray.reduce(
([previousChain, previousChainCenter], [chainToCheck, center]) => {
return center.y < previousChainCenter.y
? [chainToCheck, center]
: [previousChain, previousChainCenter];
},
chainsToCenterArray[0],
);
senseChain = chainWithLowestCenter[0];
}
chainsToCheck.forEach((chainToCheck) => {
if (chainToCheck === senseChain) {
handledChains.add(chainToCheck);
return;
}
if (!senseToAntisenseChains.has(senseChain)) {
senseToAntisenseChains.set(senseChain, []);
}
senseToAntisenseChains.get(senseChain)?.push(chainToCheck);
handledChains.add(chainToCheck);
});
});
senseToAntisenseChains.forEach((antisenseChains, senseChain) => {
senseChain.monomers.forEach((monomer) => {
command.merge(this.markMonomerAsSense(monomer));
});
antisenseChains.forEach((antisenseChain) => {
antisenseChain.monomers.forEach((monomer) => {
command.merge(this.markMonomerAsAntisense(monomer));
});
});
});
return command;
}