/*
Contributors: Nicola Zonta
Copyright Schrodinger, LLC. All rights reserved
*/
#ifndef COORDGEN_FRAGMENT_BUILDER_H
#define COORDGEN_FRAGMENT_BUILDER_H
#include <queue>
#include <set>
#include <stack>
#include <vector>
#include "CoordgenConfig.hpp"
#include "CoordgenMacrocycleBuilder.h"
class sketcherMinimizerAtom;
class sketcherMinimizerBond;
class sketcherMinimizerRing;
class sketcherMinimizerFragment;
class sketcherMinimizerPointF;
/*
class that handles the creation of 2d coordinates for a molecular fragment
*/
class EXPORT_COORDGEN CoordgenFragmentBuilder
{
public:
/*
create coordinates for a molecular fragment
*/
void initializeCoordinates(sketcherMinimizerFragment* fragment) const;
/*
return a vector of ring atoms so that bound atoms are placed next to each
other
*/
static std::vector<sketcherMinimizerAtom*>
orderRingAtoms(const sketcherMinimizerRing* r);
/*
return a vector of atoms so that bound atoms are placed next to each other
*/
static std::vector<sketcherMinimizerAtom*>
orderChainOfAtoms(const std::vector<sketcherMinimizerAtom*>& atoms,
sketcherMinimizerAtom* startAtom);
/*
return a list of coordinates representing a regular polygon for the given
atoms in a ring
*/
static std::vector<sketcherMinimizerPointF>
listOfCoordinatesFromListofRingAtoms(
const std::vector<sketcherMinimizerAtom*>& atoms);
/*
set a flag that forces the macrocycle builder to skip expensive polyomino
matching routines and go straight to the breaking a bond approach
*/
void setForceOpenMacrocycles(bool b)
{
m_macrocycleBuilder.m_forceOpenMacrocycles = b;
}
/* set precision of the calculations. Higher precisions settings result
better
quality but slower
calculations */
void setPrecision(float f) { m_macrocycleBuilder.setPrecision(f); }
/*
all bonds are placed at even intervals around the atom, as opposed for
instance to the 90°-90°-120°-60° around tetracoordinated centers
*/
bool m_evenAngles;
private:
/*
find if the present ring is fused with another than has already gotten
coordinates for
*/
sketcherMinimizerRing* getSharedAtomsWithAlreadyDrawnRing(
const sketcherMinimizerRing* ring,
std::vector<sketcherMinimizerAtom*>& fusionAtoms,
sketcherMinimizerBond*& fusionBond) const;
/*
assign coordinates to a ring
*/
void buildRing(sketcherMinimizerRing* ring) const;
/*
generate coordinates for a group of fused rings that share more than two
atoms with each other
*/
void generateCoordinatesCentralRings(
std::vector<sketcherMinimizerRing*> centralRings) const;
sketcherMinimizerRing* findCentralRingOfSystem(
const std::vector<sketcherMinimizerRing*>& rings) const;
/*
find a template to generate coordinates for a ring system
*/
bool findTemplate(const std::vector<sketcherMinimizerRing*>& rings) const;
/*
generate coordinates for rings that have been stripped away from the core
(see buildRings)
*/
void generateCoordinatesSideRings(
std::stack<sketcherMinimizerRing*> sideRings) const;
/*
after coordinates are generated, find an orientation for the main fragment
*/
void rotateMainFragment(sketcherMinimizerFragment* fragment) const;
/*
assign coordinates to a fragment
*/
void buildFragment(sketcherMinimizerFragment* fragment) const;
/*
assign coordinates to all ring atoms. Start by stripping out side rings
that only share two atoms with other rings to find a core of central rings
*/
void buildRings(sketcherMinimizerFragment* fragment) const;
/*
assign coordinates to atoms that are not in rings
*/
void buildNonRingAtoms(sketcherMinimizerFragment* fragment) const;
/*
initialize information about connectivity of rings
*/
void
initializeFusedRingInformation(sketcherMinimizerFragment* fragment) const;
/*
split ring system into side rings and central rings by stripping away
recursively rings that only
share two atoms with other rings
*/
void
simplifyRingSystem(const std::vector<sketcherMinimizerRing*>& allRings,
std::stack<sketcherMinimizerRing*>& sideRings,
std::vector<sketcherMinimizerRing*>& centralRings) const;
/* if the fragment contains any NaN coordinates and 3d coords are available,
* use thouse instead */
void fallbackIfNanCoordinates(sketcherMinimizerFragment* fragment) const;
/* generate the coordinates of atoms bound to the first atom in the queue */
void generateCoordinatesNeighborsOfFirstAtomInQueue(
std::queue<sketcherMinimizerAtom*>& atomQueue,
std::set<sketcherMinimizerAtom*>& isAtomVisited,
const sketcherMinimizerFragment* fragment) const;
/* return a list of angles that bonds from the given atoms should form */
std::vector<float>
neighborsAnglesAtCenter(const sketcherMinimizerAtom* atom) const;
/* initialize data to generate coordinates of atoms bound to a non-ring atom
*/
void initializeVariablesForNeighboursCoordinates(
sketcherMinimizerAtom* atom,
std::set<sketcherMinimizerAtom*>& isAtomVisited,
sketcherMinimizerPointF& startCoordinates,
std::vector<sketcherMinimizerAtom*>& orderedNeighbours,
std::vector<float>& angles) const;
/* initialize data to generate coordinates of atoms bound to a ring atom */
void initializeVariablesForNeighboursCoordinatesRingAtom(
const sketcherMinimizerAtom* atom,
std::set<sketcherMinimizerAtom*>& isAtomVisited,
sketcherMinimizerPointF& startCoordinates,
std::vector<sketcherMinimizerAtom*>& orderedNeighbours,
std::vector<float>& angles) const;
/* check if the atom is part of a macrocycle and has some degrees of freedom
that can be added to be used in the minimizer */
void maybeAddMacrocycleDOF(sketcherMinimizerAtom* atom) const;
/* make sure ZE chirality is maintained */
void
avoidZEInversions(const sketcherMinimizerAtom* at,
std::set<sketcherMinimizerAtom*>& isAtomVisited) const;
/* assign a score to the possibility of rings to be drawn on a plane */
float
newScorePlanarity(const std::vector<sketcherMinimizerRing*>& rings) const;
/* the macrocycle builder */
CoordgenMacrocycleBuilder m_macrocycleBuilder;
};
#endif /* defined(COORDGEN_FRAGMENT_BUILDER_H) */