in core/indigo-core/molecule/src/base_molecule.cpp [4553:4750]
void BaseMolecule::getAtomBoundingBox(int atom_idx, float font_size, LABEL_MODE label_mode, Vec2f& bottom_left, Vec2f& top_right)
{
Vec2f vec = _xyz[atom_idx].projectZ();
bottom_left = top_right = vec;
if (font_size <= EPSILON)
return;
float constexpr WIDTH_FACTOR = 0.7f; // width of font symbols
float symbol_size = font_size * WIDTH_FACTOR;
if (isPseudoAtom(atom_idx) || isTemplateAtom(atom_idx))
{
const char* str = isPseudoAtom(atom_idx) ? getPseudoAtom(atom_idx) : getTemplateAtom(atom_idx);
size_t len = strlen(str);
Vec2f shift(len * symbol_size / 2.0f, symbol_size); // TODO: Add pseudoatom parsing
bottom_left.sub(shift);
top_right.add(shift);
}
else
{
int charge = getAtomCharge(atom_idx);
int isotope = getAtomIsotope(atom_idx);
int radical = -1;
int valence = getExplicitValence(atom_idx);
bool query = isQueryMolecule();
int implicit_h = 0;
const Vertex& vertex = getVertex(atom_idx);
int atomNumber = getAtomNumber(atom_idx);
int label = 0;
bool atom_regular = !query || QueryMolecule::queryAtomIsRegular(asQueryMolecule(), atom_idx);
if (!isRSite(atom_idx))
{
if (atom_regular)
label = atomNumber;
radical = getAtomRadical_NoThrow(atom_idx, -1);
if (!query)
implicit_h = asMolecule().getImplicitH_NoThrow(atom_idx, 0);
}
bool plainCarbon = label == ELEM_C && charge == (query ? CHARGE_UNKNOWN : 0) && isotope == (query ? -1 : 0) && radical <= 0 && valence == -1;
bool showLabel = true;
if (label_mode == LABEL_MODE_ALL || vertex.degree() == 0)
;
else if (label_mode == LABEL_MODE_NONE)
showLabel = false;
else if (plainCarbon && (label_mode == LABEL_MODE_HETERO || vertex.degree() > 1))
{
showLabel = false;
if (vertex.degree() == 2)
{
int k1 = vertex.neiBegin();
int k2 = vertex.neiNext(k1);
if (getBondOrder(vertex.neiEdge(k1)) == getBondOrder(vertex.neiEdge(k2)))
{
int a1 = vertex.neiVertex(k1);
int a2 = vertex.neiVertex(k2);
Vec2f vk1(_xyz[a1].x, _xyz[a1].y);
Vec2f vk2(_xyz[a2].x, _xyz[a2].y);
Vec2f dir_k1, dir_k2;
dir_k1.diff(vec, vk1);
dir_k1.normalize();
dir_k2.diff(vec, vk2);
dir_k2.normalize();
float dot = Vec2f::dot(dir_k1, dir_k2);
if (dot < -0.97)
showLabel = true;
}
}
}
if (showLabel)
{
// calc label size
size_t len = 0;
if (query && !atom_regular)
{
Array<int> list;
int atom_type = QueryMolecule::parseQueryAtom(asQueryMolecule(), atom_idx, list);
switch (atom_type)
{
case QueryMolecule::QUERY_ATOM_A:
case QueryMolecule::QUERY_ATOM_X:
case QueryMolecule::QUERY_ATOM_Q:
case QueryMolecule::QUERY_ATOM_M:
len = 1;
break;
case QueryMolecule::QUERY_ATOM_AH:
case QueryMolecule::QUERY_ATOM_XH:
case QueryMolecule::QUERY_ATOM_QH:
case QueryMolecule::QUERY_ATOM_MH:
case QueryMolecule::QUERY_ATOM_SINGLE:
len = 2;
break;
case QueryMolecule::QUERY_ATOM_LIST:
case QueryMolecule::QUERY_ATOM_NOTLIST:
len = 1 + list.size() / 2;
for (int i = 0; i < list.size(); i++)
{
len += strlen(Element::toString(list[i]));
}
break;
}
}
else
{
len = strlen(Element::toString(label));
}
Vec2f shift(len * symbol_size / 2.0f, symbol_size);
bottom_left.sub(shift);
top_right.add(shift);
// Add isotope at left
if (isotope > 0 && !(label = ELEM_H && (isotope == DEUTERIUM || isotope == TRITIUM)))
{
if (isotope > 99)
len = 3;
else if (isotope > 9)
len = 2;
else
len = 1;
bottom_left.x -= len * symbol_size;
}
// Add valence at right
if (valence > 0)
{
static constexpr int count[] = {
1, // 0
1, // I
2, // II
3, // III
2, // IV
1, // V
2, // VI
3, // VII
4, // VIII
2, // IX
1, // X
};
top_right.x += count[valence] * symbol_size;
}
// Add charge at right
if (charge != 0)
{
if (abs(charge) > 9)
len = 3;
else if (abs(charge) > 1)
len = 2;
else
len = 1;
top_right.x += len * symbol_size;
}
if (implicit_h > 0)
{
// add implicit H size
if (implicit_h > 1)
len = 2;
else
len = 1;
bool h_at_right = true;
if (vertex.degree() == 0)
{
if (ElementHygrodenOnLeft(label))
h_at_right = false;
}
else
{
constexpr float min_sin = 0.49f;
float right_weight = 0.3f;
float left_weight = 0.2f;
float left_sin = 0, right_sin = 0;
for (int j = vertex.neiBegin(); j < vertex.neiEnd(); j = vertex.neiNext(j))
{
Vec2f d = _xyz[vertex.neiVertex(j)].projectZ();
d.sub(vec);
d.normalize();
if (d.x > 0)
right_sin = std::max(right_sin, d.x);
else
left_sin = std::max(left_sin, -d.x);
}
if (left_sin > min_sin)
left_weight -= left_sin;
if (right_sin > min_sin)
right_weight -= right_sin;
if (left_weight > right_weight)
h_at_right = false;
}
if (h_at_right)
top_right.x += len * symbol_size;
else
bottom_left.x -= len * symbol_size;
}
}
}
// process AAM
}