in layer2/RepCartoon.cpp [401:1423]
static void do_ring(PyMOLGlobals * G, nuc_acid_data *ndata, int n_atom,
int *atix, ObjectMolecule * obj,
CoordSet * cs, float ring_width, CGO * cgo, int ring_color,
float ladder_radius, int ladder_color, int ladder_mode,
int sc_helper,
float ring_alpha, float alpha, int *marked, float *moved,
float ring_radius)
{
float *v_i[MAX_RING_ATOM];
const float *col[MAX_RING_ATOM];
float n_up[MAX_RING_ATOM][3];
float n_dn[MAX_RING_ATOM][3];
AtomInfoType *ai_i[MAX_RING_ATOM];
int have_all = true;
int all_marked = true;
AtomInfoType *ai;
int have_C4 = -1;
int have_C4_prime = -1;
int have_C_number = -1;
int nf = false;
int ring_mode = ndata->ring_mode;
int finder = ndata->ring_finder;
const auto& nuc_flag = ndata->nuc_flag;
/* first, make sure all atoms have known coordinates */
{
int a, i;
for(i = 0; i <= n_atom; i++) {
int a1 = atix[i];
int have_atom = false;
if(nuc_flag[a1])
nf = true;
a = cs->atmToIdx(a1);
if(a >= 0) {
ai = obj->AtomInfo + a1;
if(ai->visRep & cRepCartoonBit) {
ai_i[i] = ai;
// take atom level settings from any ring atom (effectifly from the
// last one with settings)
AtomSettingGetIfDefined(G, ai, cSetting_cartoon_ring_mode, &ring_mode);
AtomSettingGetIfDefined(G, ai, cSetting_cartoon_ring_color, &ring_color);
AtomSettingGetIfDefined(G, ai, cSetting_cartoon_ring_radius, &ring_radius);
AtomSettingGetIfDefined(G, ai, cSetting_cartoon_ring_width, &ring_width);
AtomSettingGetIfDefined(G, ai, cSetting_cartoon_ladder_mode, &ladder_mode);
AtomSettingGetIfDefined(G, ai, cSetting_cartoon_ladder_color, &ladder_color);
AtomSettingGetIfDefined(G, ai, cSetting_cartoon_ladder_radius, &ladder_radius);
col[i] = ColorGet(G, ai->color);
v_i[i] = cs->Coord + 3 * a;
have_atom = true;
const char * ai_name = LexStr(G, ai->name);
if(WordMatchExact(G, "C4", ai_name, 1))
have_C4 = a1;
else if(
WordMatchExact(G, "C4'", ai_name, 1) ||
WordMatchExact(G, "C4*", ai_name, 1))
have_C4_prime = a1;
if(((ai_name[0] == 'C') || (ai_name[0] == 'c')) &&
isdigit(ai_name[1]))
have_C_number = a1;
}
if(!marked[a1])
all_marked = false;
}
if(!have_atom) {
have_all = false;
break;
}
}
}
if(!ring_mode)
finder = 0;
ring_width *= 0.5F;
if(n_atom && have_all && (!all_marked)) {
if(ladder_mode) {
int i;
int a1;
AtomInfoType *ai2;
AtomInfoType *atomInfo = obj->AtomInfo;
int mem0, mem1, mem2, mem3, mem4, mem5, mem6, mem7;
int *neighbor = obj->Neighbor;
int nbr[7];
int sugar_at = -1, base_at = -1;
int phos3_at = -1, phos5_at = -1;
int o3_at = -1, o5_at = -1, c1_at = -1;
int purine_flag = false;
int c1 = -1, c1_linked = -1;
int c2 = -1, c2_linked = -1;
int c3 = -1, c3_linked = -1;
int c4 = -1, c4_linked = -1;
int c5 = -1, c5_linked = -1;
if(n_atom == 5) { /* going from the sugar to the base */
for(i = 0; i < n_atom; i++) {
a1 = atix[i];
if(!nf)
nf = nuc_flag[a1];
ai = atomInfo + a1;
if((ai->protons == cAN_C) && (!marked[a1]) &&
(WordMatchExact(G, "C3*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "C3'", LexStr(G, ai->name), 1))) {
sugar_at = a1;
mem0 = a1;
nbr[0] = neighbor[mem0] + 1;
while((mem1 = neighbor[nbr[0]]) >= 0) {
if((atomInfo[mem1].protons == cAN_O) && (!marked[mem1])) {
ai = atomInfo + mem1;
if(WordMatchExact(G, "O3*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "O3'", LexStr(G, ai->name), 1))
o3_at = mem1;
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (!marked[mem2]) &&
(atomInfo[mem2].protons == cAN_P)) {
phos3_at = mem2;
}
nbr[1] += 2;
}
}
if((atomInfo[mem1].protons == cAN_C) && (!marked[mem1])) {
ai2 = atomInfo + mem1;
if(WordMatchExact(G, NUCLEIC_NORMAL1, LexStr(G, ai2->name), 1) ||
WordMatchExact(G, NUCLEIC_NORMAL2, LexStr(G, ai2->name), 1))
sugar_at = mem1;
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (!marked[mem2]) &&
(atomInfo[mem2].protons == cAN_C)) {
ai = atomInfo + mem2;
if(WordMatchExact(G, "C1*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "C1'", LexStr(G, ai->name), 1))
c1_at = mem2;
nbr[2] = neighbor[mem2] + 1;
while((mem3 = neighbor[nbr[2]]) >= 0) {
if((mem3 != mem1) && (mem3 != mem0)) {
if((atomInfo[mem3].protons == cAN_O) && (!marked[mem3])) {
ai = atomInfo + mem3;
if(WordMatchExact(G, "O5*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "O5'", LexStr(G, ai->name), 1))
o5_at = mem3;
nbr[3] = neighbor[mem3] + 1;
while((mem4 = neighbor[nbr[3]]) >= 0) {
if((mem4 != mem2) && (!marked[mem4]) &&
(atomInfo[mem4].protons == cAN_P)) {
phos5_at = mem4;
}
nbr[3] += 2;
}
}
if(atomInfo[mem3].protons == cAN_N) {
if(ring_mode) {
ai2 = atomInfo + mem3;
if((!marked[mem3])
&& (WordMatchExact(G, "N1", LexStr(G, ai2->name), 1)
|| WordMatchExact(G, "N9", LexStr(G, ai2->name), 1))) {
base_at = mem3;
if(ring_mode != 3) {
ladder_radius = ring_width * 1.5;
} else {
ladder_radius = ring_width * 3;
}
}
} else {
nbr[3] = neighbor[mem3] + 1;
while((mem4 = neighbor[nbr[3]]) >= 0) {
if((mem4 != mem2) && (mem4 != mem1) && (mem4 != mem0) &&
(atomInfo[mem4].protons == cAN_C)) {
nbr[4] = neighbor[mem4] + 1;
while((mem5 = neighbor[nbr[4]]) >= 0) {
if((mem5 != mem3) && (mem5 != mem2) && (mem5 != mem1)
&& (mem5 != mem0)
&& (atomInfo[mem5].protons == cAN_N)
&& (marked[mem5])) {
/* must be in a mapped ring */
/* clear flag here */
purine_flag = false;
nbr[5] = neighbor[mem5] + 1;
while((mem6 = neighbor[nbr[5]]) >= 0) {
if((mem6 != mem4) && (mem6 != mem3)
&& (mem6 != mem2) && (mem6 != mem1)
&& (mem6 != mem0)
&& (atomInfo[mem6].protons == cAN_C)
&& (marked[mem6])) {
nbr[6] = neighbor[mem6] + 1;
while((mem7 = neighbor[nbr[6]]) >= 0) {
ai2 = atomInfo + mem7;
if((mem7 != mem5) && (mem7 != mem4)
&& (mem7 != mem3) && (mem7 != mem2)
&& (mem7 != mem2) && (mem7 != mem1)
&& (mem7 != mem0) && (ai2->protons == cAN_N)
&& (marked[mem7])) {
if(WordMatchExact(G, "N1", LexStr(G, ai2->name), 1)) {
/* and set flag */
base_at = mem7;
purine_flag = true;
}
}
nbr[6] += 2;
}
}
nbr[5] += 2;
}
if(!purine_flag) {
ai2 = atomInfo + mem5;
if(marked[mem5]
&& WordMatchExact(G, "N3", LexStr(G, ai2->name), 1)) {
base_at = mem5;
}
}
}
nbr[4] += 2;
}
}
nbr[3] += 2;
}
}
}
}
nbr[2] += 2;
}
}
nbr[1] += 2;
}
}
nbr[0] += 2;
}
}
}
} else if((!ring_mode) && (n_atom == 6)) { /* going from the base to the sugar */
for(i = 0; i < n_atom; i++) {
a1 = atix[i];
if(!nf)
nf = nuc_flag[a1];
ai = atomInfo + a1;
/* base-hunting */
if((ai->protons == cAN_N) && (!marked[a1]) &&
(WordMatchExact(G, "N1", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "N3", LexStr(G, ai->name), 1))) {
mem0 = a1;
nbr[0] = neighbor[mem0] + 1;
while((mem1 = neighbor[nbr[0]]) >= 0) {
if((atomInfo[mem1].protons == cAN_C) && (!marked[mem1])) {
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (!marked[mem2]) &&
(atomInfo[mem2].protons == cAN_N)) {
nbr[2] = neighbor[mem2] + 1;
while((mem3 = neighbor[nbr[2]]) >= 0) {
if((mem3 != mem1) && (mem3 != mem0) &&
(atomInfo[mem3].protons == cAN_C)) {
nbr[3] = neighbor[mem3] + 1;
while((mem4 = neighbor[nbr[3]]) >= 0) {
if((mem4 != mem2) && (mem4 != mem1) && (mem4 != mem0)) {
if((atomInfo[mem4].protons == cAN_N) ||
WordMatchExact(G, "C5", LexStr(G, atomInfo[mem4].name), 1)) { /* purine case */
nbr[4] = neighbor[mem4] + 1;
while((mem5 = neighbor[nbr[4]]) >= 0) {
if((mem5 != mem3) && (mem5 != mem2) && (mem5 != mem1)
&& (mem5 != mem0) && (marked[mem5])
&& (atomInfo[mem5].protons == cAN_C)) {
nbr[5] = neighbor[mem5] + 1;
while((mem6 = neighbor[nbr[5]]) >= 0) {
if((mem6 != mem4) && (mem6 != mem3) && (mem6 != mem2)
&& (mem6 != mem1) && (mem6 != mem0)
&& ((atomInfo[mem6].protons == cAN_C)
|| (atomInfo[mem6].protons == cAN_O))
&& (marked[mem6])) {
nbr[6] = neighbor[mem6] + 1;
while((mem7 = neighbor[nbr[6]]) >= 0) {
ai2 = atomInfo + mem7;
if((mem7 != mem5) && (mem7 != mem4)
&& (mem7 != mem3) && (mem7 != mem2)
&& (mem7 != mem2) && (mem7 != mem1)
&& (mem7 != mem0) && (ai2->protons == cAN_C)
&& (marked[mem7])) {
if(WordMatchExact
(G, NUCLEIC_NORMAL1, LexStr(G, ai2->name), 1)
|| WordMatchExact(G, NUCLEIC_NORMAL2,
LexStr(G, ai2->name), 1)) {
base_at = a1;
sugar_at = mem7;
}
}
nbr[6] += 2;
}
}
nbr[5] += 2;
}
}
nbr[4] += 2;
}
} else if(((atomInfo[mem4].protons == cAN_C)
|| (atomInfo[mem4].protons == cAN_O))
&& (marked[mem4])) {
/* pyrimidine case */
nbr[4] = neighbor[mem4] + 1;
while((mem5 = neighbor[nbr[4]]) >= 0) {
ai2 = atomInfo + mem5;
if((mem5 != mem3) && (mem5 != mem2) && (mem5 != mem1)
&& (mem5 != mem0) && (ai2->protons == cAN_C)
&& (marked[mem5])) {
if(WordMatchExact(G, NUCLEIC_NORMAL1, LexStr(G, ai2->name), 1)
|| WordMatchExact(G, NUCLEIC_NORMAL2, LexStr(G, ai2->name), 1)) {
base_at = a1;
sugar_at = mem5;
}
}
nbr[4] += 2;
}
}
}
nbr[3] += 2;
}
}
nbr[2] += 2;
}
}
nbr[1] += 2;
}
}
nbr[0] += 2;
}
}
}
}
if(n_atom == 6) {
for(i = 0; i < n_atom; i++) {
a1 = atix[i];
ai = atomInfo + a1;
/* glycosylation hunting */
if((ai->protons == cAN_C) && (!marked[a1])) { /* unmarked C in ring */
mem0 = a1;
nbr[0] = neighbor[mem0] + 1;
while((mem1 = neighbor[nbr[0]]) >= 0) {
if((atomInfo[mem1].protons == cAN_C) && /* exocyclic C */
(!marked[mem1])) {
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (!marked[mem2])
&& (atomInfo[mem2].protons == cAN_O)) {
/* exocyclic O */
nbr[2] = neighbor[mem2] + 1;
while((mem3 = neighbor[nbr[2]]) >= 0) {
if((mem3 != mem1) && (mem3 != mem0) && (marked[mem3])
&& (atomInfo[mem3].protons == cAN_C)) {
/* cyclic C */
if(WordMatchExact(G, "C5", LexStr(G, ai->name), 1) &&
WordMatchExact(G, "C6", LexStr(G, atomInfo[mem1].name), 1)) {
c5_linked = mem3;
c5 = mem0;
}
}
nbr[2] += 2;
}
}
nbr[1] += 2;
}
} else if((atomInfo[mem1].protons == cAN_O) && /* exocyclic O */
(!marked[mem1])) {
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (marked[mem2])
&& (atomInfo[mem2].protons == cAN_C)) {
/* cyclic C */
const char * ai_name = LexStr(G, ai->name);
if(WordMatchExact(G, "C1", ai_name, 1)) {
c1_linked = mem2;
c1 = mem0;
} else if(WordMatchExact(G, "C2", ai_name, 1)) {
c2_linked = mem2;
c2 = mem0;
} else if(WordMatchExact(G, "C3", ai_name, 1)) {
c3_linked = mem2;
c3 = mem0;
} else if(WordMatchExact(G, "C4", ai_name, 1)) {
c4_linked = mem2;
c4 = mem0;
}
} else if((mem2 != mem0) && (!marked[mem2])
&& (atomInfo[mem2].protons == cAN_C)) {
/* exocyclic C */
nbr[2] = neighbor[mem2] + 1;
while((mem3 = neighbor[nbr[2]]) >= 0) {
if((mem3 != mem1) && (mem3 != mem0) && (marked[mem3])
&& (atomInfo[mem3].protons == cAN_C)) {
/* cyclic C */
if(WordMatchExact(G, "C5", LexStr(G, atomInfo[mem3].name), 1) &&
WordMatchExact(G, "C6", LexStr(G, atomInfo[mem2].name), 1)) {
c5 = mem0;
c5_linked = mem3;
}
} else if((mem3 != mem1) && (mem3 != mem0) && (!marked[mem3])
&& (atomInfo[mem3].protons == cAN_C)) {
/* exocyclic */
if(WordMatchExact(G, "C1", LexStr(G, ai->name), 1) &&
WordMatchExact(G, "CA", LexStr(G, atomInfo[mem3].name), 1)) {
c1 = mem0;
c1_linked = mem3;
}
}
nbr[2] += 2;
}
}
nbr[1] += 2;
}
} else if((atomInfo[mem1].protons == cAN_N) && /* exocyclic N */
(!marked[mem1])) {
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (!marked[mem2])
&& (atomInfo[mem2].protons == cAN_C)) {
/* exocyclic C */
nbr[2] = neighbor[mem2] + 1;
while((mem3 = neighbor[nbr[2]]) >= 0) {
if((mem3 != mem1) && (mem3 != mem0) && (!marked[mem3])
&& (atomInfo[mem3].protons == cAN_C)) {
/* exocyclic */
nbr[3] = neighbor[mem3] + 1;
while((mem4 = neighbor[nbr[3]]) >= 0) {
if((mem4 != mem2) && (mem3 != mem1) && (!marked[mem4])
&& (atomInfo[mem4].protons == cAN_C)) {
/* exocyclic */
if(WordMatchExact(G, "C1", LexStr(G, ai->name), 1) &&
WordMatchExact(G, "CA", LexStr(G, atomInfo[mem4].name), 1)) {
c1 = mem0;
c1_linked = mem4;
}
}
nbr[3] += 2;
}
}
nbr[2] += 2;
}
}
nbr[1] += 2;
}
}
nbr[0] += 2;
}
}
}
}
if(sugar_at >= 0) { /* still need to find the phosphates... */
int c3_index = -1;
ai = atomInfo + sugar_at;
if(WordMatchExact(G, "C3*", LexStr(G, ai->name), 1) || WordMatchExact(G, "C3'", LexStr(G, ai->name), 1)) {
c3_index = sugar_at;
} else {
mem0 = sugar_at;
nbr[0] = neighbor[mem0] + 1;
while((mem1 = neighbor[nbr[0]]) >= 0) {
if((atomInfo[mem1].protons == cAN_C) && (!marked[mem1])) {
ai = atomInfo + mem1;
if(!(WordMatchExact(G, "C3*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "C3'", LexStr(G, ai->name), 1))) {
c3_index = mem1;
}
}
nbr[0] += 2;
}
}
if(c3_index >= 0) { /* now we know where we are... */
mem0 = c3_index;
nbr[0] = neighbor[mem0] + 1;
while((mem1 = neighbor[nbr[0]]) >= 0) {
if((atomInfo[mem1].protons == cAN_O) && (!marked[mem1])) {
ai = atomInfo + mem1;
if(WordMatchExact(G, "O3*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "O3'", LexStr(G, ai->name), 1))
o3_at = mem1;
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (!marked[mem2]) && (atomInfo[mem2].protons == cAN_P)) {
phos3_at = mem2;
}
nbr[1] += 2;
}
}
if((atomInfo[mem1].protons == cAN_C) && (marked[mem1])) {
nbr[1] = neighbor[mem1] + 1;
while((mem2 = neighbor[nbr[1]]) >= 0) {
if((mem2 != mem0) && (!marked[mem2]) && (atomInfo[mem2].protons == cAN_C)) {
ai = atomInfo + mem2;
if(WordMatchExact(G, "C1*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "C1'", LexStr(G, ai->name), 1))
c1_at = mem2;
nbr[2] = neighbor[mem2] + 1;
while((mem3 = neighbor[nbr[2]]) >= 0) {
if((mem3 != mem1) && (mem3 != mem0) &&
(atomInfo[mem3].protons == cAN_O) && (!marked[mem3])) {
ai = atomInfo + mem3;
if(WordMatchExact(G, "O5*", LexStr(G, ai->name), 1) ||
WordMatchExact(G, "O5'", LexStr(G, ai->name), 1))
o5_at = mem3;
nbr[3] = neighbor[mem3] + 1;
while((mem4 = neighbor[nbr[3]]) >= 0) {
if((mem4 != mem2) && (!marked[mem4]) &&
(atomInfo[mem4].protons == cAN_P)) {
phos5_at = mem4;
}
nbr[3] += 2;
}
}
nbr[2] += 2;
}
}
nbr[1] += 2;
}
}
nbr[0] += 2;
}
}
}
/* glycosylation connectors */
if(1) {
if((ring_mode) && (finder >= 3)) {
if(finder >= 3) {
int b;
float glyco_radius;
switch (ring_mode) {
case 3:
case 4:
glyco_radius = ring_width * 3;
break;
case 5:
glyco_radius = ladder_radius;
break;
default:
glyco_radius = ring_width * 1.5;
break;
}
if((alpha != 1.0F) || (ring_alpha != alpha))
CGOAlpha(cgo, alpha);
for(b = 0; b < 5; b++) {
int g1 = -1, g2 = -1;
switch (b) {
case 0:
g1 = c1;
g2 = c1_linked;
break;
case 1:
g1 = c2;
g2 = c2_linked;
break;
case 2:
g1 = c3;
g2 = c3_linked;
break;
case 3:
g1 = c4;
g2 = c4_linked;
break;
case 4:
g1 = c5;
g2 = c5_linked;
break;
}
if((g1 >= 0) && (g2 >= 0)) {
AtomInfoType *g1_ai = atomInfo + g1;
AtomInfoType *g2_ai = atomInfo + g2;
if (ring_connector_visible(G, g1_ai, g2_ai, sc_helper)) {
float *g1p, *g2p;
float avg[3];
{
int g1_x, g2_x;
if(obj->DiscreteFlag) {
if(cs == obj->DiscreteCSet[g1] && cs == obj->DiscreteCSet[g2]) {
g1_x = obj->DiscreteAtmToIdx[g1];
g2_x = obj->DiscreteAtmToIdx[g2];
} else {
g1_x = -1;
g2_x = -1;
}
} else {
g1_x = cs->AtmToIdx[g1];
g2_x = cs->AtmToIdx[g2];
}
g1p = cs->Coord + 3 * g1_x;
g2p = cs->Coord + 3 * g2_x;
}
if(!((!((ring_mode == 0) || (ring_mode == 4) || (ring_mode == 5))) ||
(!marked[g2]))) {
g2p = moved + 3 * g2;
}
if((ring_mode == 0) || (ring_mode == 4) || (ring_mode == 5)) {
/* ring center */
int i;
/* compute average coordinate and mark atoms so that ring is only drawn once */
zero3f(avg);
for(i = 0; i < n_atom; i++) {
add3f(avg, v_i[i], avg);
}
scale3f(avg, 1.0F / n_atom, avg);
g1p = avg;
}
{
const float *color1, *color2;
if (ladder_color >= 0) {
color1 = color2 = ColorGet(G, ladder_color);
} else {
color1 = ColorGet(G, g1_ai->color);
color2 = ColorGet(G, g2_ai->color);
}
CGOPickColor(cgo, g1, g1_ai->masked ? cPickableNoPick : cPickableAtom);
Pickable pickcolor2 = { g2, g2_ai->masked ? cPickableNoPick : cPickableAtom };
float axis[3];
subtract3f(g2p, g1p, axis);
CGOColorv(cgo, color1);
cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, g1p, axis, glyco_radius, 0x1f, color2, &pickcolor2);
}
}
}
}
}
}
}
/* see if any of the neighbors are confirmed nucleic acids... */
if(sugar_at >= 0) {
if(!nf) {
auto seen = std::set<int>();
nf = has_nuc_neighbor(nuc_flag, obj->Neighbor, sugar_at, 5, seen);
}
if(nf) {
if((ring_mode) && ((finder == 1) || (finder >= 3))) {
if((c1_at >= 0) && (base_at >= 0)) {
int save_at = sugar_at;
sugar_at = c1_at;
{
AtomInfoType *sug_ai = atomInfo + sugar_at;
AtomInfoType *bas_ai = atomInfo + base_at;
if (ring_connector_visible(G, bas_ai, sug_ai, sc_helper)) {
int sug, bas;
if(obj->DiscreteFlag) {
if(cs == obj->DiscreteCSet[sugar_at] &&
cs == obj->DiscreteCSet[base_at]) {
sug = obj->DiscreteAtmToIdx[sugar_at];
bas = obj->DiscreteAtmToIdx[base_at];
} else {
sug = -1;
bas = -1;
}
} else {
sug = cs->AtmToIdx[sugar_at];
bas = cs->AtmToIdx[base_at];
}
if((sug >= 0) && (bas >= 0)) {
{
const float *color1, *color2;
if (ladder_color >= 0) {
color1 = color2 = ColorGet(G, ladder_color);
} else {
color1 = ColorGet(G, sug_ai->color);
color2 = ColorGet(G, bas_ai->color);
}
CGOPickColor(cgo, sugar_at, sug_ai->masked ? cPickableNoPick : cPickableAtom);
Pickable pickcolor2 = { base_at, bas_ai->masked ? cPickableNoPick : cPickableAtom };
float axis[3];
subtract3f(cs->Coord + 3 * bas, cs->Coord + 3 * sug, axis);
CGOColorv(cgo, color1);
cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, cs->Coord + 3 * sug, axis, ladder_radius, 0x1f, color2, &pickcolor2);
}
}
}
}
base_at = save_at;
sugar_at = save_at;
}
}
if((base_at >= 0) && (sugar_at >= 0)) {
AtomInfoType *sug_ai = atomInfo + sugar_at;
AtomInfoType *bas_ai = atomInfo + base_at;
if (ring_connector_visible(G, bas_ai, sug_ai, sc_helper)) {
int sug, bas;
float *v_outer, tmp[3], outer[3];
if(obj->DiscreteFlag) {
if(cs == obj->DiscreteCSet[sugar_at] && cs == obj->DiscreteCSet[base_at]) {
sug = obj->DiscreteAtmToIdx[sugar_at];
bas = obj->DiscreteAtmToIdx[base_at];
} else {
sug = -1;
bas = -1;
}
} else {
sug = cs->AtmToIdx[sugar_at];
bas = cs->AtmToIdx[base_at];
}
if((sug >= 0) && (bas >= 0)) {
int p3, p5;
v_outer = cs->Coord + 3 * sug;
if((o3_at >= 0) && (phos3_at < 0))
phos3_at = o3_at;
if((o5_at >= 0) && (phos5_at < 0))
phos5_at = o5_at;
if((ndata->na_mode != 1) && (phos3_at >= 0) && (phos5_at >= 0)) {
if(obj->DiscreteFlag) {
if(cs == obj->DiscreteCSet[phos3_at] &&
cs == obj->DiscreteCSet[phos5_at]) {
p3 = obj->DiscreteAtmToIdx[phos3_at];
p5 = obj->DiscreteAtmToIdx[phos5_at];
} else {
p3 = -1;
p5 = -1;
}
} else {
p3 = cs->AtmToIdx[phos3_at];
p5 = cs->AtmToIdx[phos5_at];
}
if((p3 >= 0) && (p5 >= 0)) {
if(ring_mode) {
scale3f(cs->Coord + 3 * p5, 0.333333F, outer);
scale3f(cs->Coord + 3 * p3, 0.666667F, tmp);
} else {
scale3f(cs->Coord + 3 * p3, 0.5F, outer);
scale3f(cs->Coord + 3 * p5, 0.5F, tmp);
}
add3f(tmp, outer, outer);
v_outer = outer;
}
}
{
const float *color1, *color2;
if (ladder_color >= 0) {
color1 = color2 = ColorGet(G, ladder_color);
} else {
color1 = ColorGet(G, sug_ai->color);
color2 = ColorGet(G, bas_ai->color);
}
CGOPickColor(cgo, sugar_at, sug_ai->masked ? cPickableNoPick : cPickableAtom);
Pickable pickcolor2 = { base_at, bas_ai->masked ? cPickableNoPick : cPickableAtom };
float axis[3];
subtract3f(cs->Coord + 3 * bas, v_outer, axis);
CGOColorv(cgo, color1);
cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, v_outer, axis, ladder_radius, 0x1f, color2, &pickcolor2);
}
}
}
}
}
}
}
if((!ring_mode) || (finder == 2)) {
if(ladder_mode) { /* mark sure all rings traversed are mark */
int i;
for(i = 0; i <= n_atom; i++) {
marked[atix[i]] = true;
}
}
}
if((!nf) && ((have_C4_prime >= 0) || (have_C4 >= 0))) {
int mem0;
/* see if any of the neighbors are confirmed nucleic acids... */
if(have_C4_prime >= 0)
mem0 = have_C4_prime;
else if(have_C4 >= 0)
mem0 = have_C4;
else
mem0 = -1;
if(mem0 >= 1) {
auto seen = std::set<int>();
nf = has_nuc_neighbor(nuc_flag, obj->Neighbor, mem0, 9, seen);
}
}
if(n_atom) { /* store center of ring */
float avg[3];
float avg_col[3];
int i;
float up[3], upi[3];
float vc0[3], vc1[3];
const float *color = NULL;
/* compute average coordinate and mark atoms so that ring is only drawn once */
zero3f(avg);
zero3f(avg_col);
for(i = 0; i < n_atom; i++) {
add3f(avg, v_i[i], avg);
add3f(avg_col, col[i], avg_col);
marked[atix[i]] = true;
}
scale3f(avg, 1.0F / n_atom, avg);
scale3f(avg_col, 1.0F / n_atom, avg_col);
for(i = 0; i < n_atom; i++) {
float *v_moved = moved + atix[i] * 3;
copy3f(avg, v_moved); /* store ring center for later use */
}
if((nf || (!ladder_mode) || (finder >= 3)) &&
ring_mode &&
(((finder == 1) && ((have_C4 >= 0) || (have_C4_prime >= 0))) ||
((finder == 2) && ((have_C4 >= 0))) ||
((finder == 3) && ((have_C_number >= 0))) || ((finder == 4)))) {
if((alpha != 1.0F) || (ring_alpha != alpha))
CGOAlpha(cgo, ring_alpha);
if(ring_color >= 0) {
color = ColorGet(G, ring_color);
} else {
color = avg_col;
}
CGOColorv(cgo, color);
if((ring_mode == 4) || (ring_mode == 5)) { /* spherical ring */
float radius = ring_radius;
if(radius < 0.0F) {
radius = 0.0F;
if(ring_mode == 4) {
for(i = 0; i < n_atom; i++) {
float dist = diff3f(avg, v_i[i]);
if(radius < dist)
radius = dist;
}
} else {
radius = ladder_radius;
}
}
if(n_atom) {
CGOColorv(cgo, avg_col);
CGOPickColor(cgo, atix[0], ai_i[0]->masked ? cPickableNoPick : cPickableAtom);
CGOSphere(cgo, avg, radius);
}
} else {
/* clear the normals */
for(i = 0; i <= n_atom; i++) {
zero3f(n_up[i]);
zero3f(n_dn[i]);
}
/* compute average normals */
{
float acc[3];
int ii;
zero3f(acc);
for(i = 0; i < n_atom; i++) {
ii = i + 1;
subtract3f(v_i[i], avg, vc0);
subtract3f(v_i[ii], avg, vc1);
cross_product3f(vc0, vc1, up);
add3f(up, n_up[i], n_up[i]);
add3f(up, n_up[ii], n_dn[ii]);
if(!i) {
add3f(up, n_up[n_atom], n_up[n_atom]);
} else if(ii == n_atom) {
add3f(up, n_up[0], n_up[0]);
}
add3f(up, acc, acc);
}
normalize3f(up);
scale3f(up, -1.0F, upi);
}
for(i = 0; i <= n_atom; i++) {
normalize3f(n_up[i]);
scale3f(n_up[i], -1.0F, n_dn[i]);
}
{
int ii;
float mid[3];
float up_add[3];
float ct[3], cb[3];
float v0t[3], v0b[3];
float v1t[3], v1b[3];
float out[3];
CGOBegin(cgo, GL_TRIANGLES);
for(i = 0; i < n_atom; i++) {
ii = i + 1;
average3f(v_i[ii], v_i[i], mid);
subtract3f(mid, avg, out); /* compute outward-facing normal */
normalize3f(out);
scale3f(up, ring_width, up_add);
add3f(avg, up_add, ct);
subtract3f(avg, up_add, cb);
add3f(v_i[i], up_add, v0t);
subtract3f(v_i[i], up_add, v0b);
add3f(v_i[ii], up_add, v1t);
subtract3f(v_i[ii], up_add, v1b);
CGONormalv(cgo, up);
if(ring_color < 0)
CGOColorv(cgo, color);
CGOPickColor(cgo, atix[i], ai_i[i]->masked ? cPickableNoPick : cPickableAtom);
CGOVertexv(cgo, ct);
CGONormalv(cgo, n_up[i]);
if(ring_color < 0)
CGOColorv(cgo, col[i]);
// CGOPickColor(cgo, atix[i], cPickableAtom);
CGOVertexv(cgo, v0t);
CGONormalv(cgo, n_up[ii]);
if(ring_color < 0)
CGOColorv(cgo, col[ii]);
CGOPickColor(cgo, atix[ii], ai_i[ii]->masked ? cPickableNoPick : cPickableAtom);
// CGOPickColor(cgo, atix[ii], cPickableAtom);
CGOVertexv(cgo, v1t);
if(ring_mode > 1) {
CGONormalv(cgo, out);
if(ring_color < 0)
CGOColorv(cgo, col[i]);
// CGOPickColor(cgo, atix[i], cPickableAtom);
CGOVertexv(cgo, v0t);
CGOVertexv(cgo, v0b);
if(ring_color < 0)
CGOColorv(cgo, col[ii]);
CGOVertexv(cgo, v1t);
CGOVertexv(cgo, v1t);
if(ring_color < 0)
CGOColorv(cgo, col[i]);
CGOVertexv(cgo, v0b);
if(ring_color < 0)
CGOColorv(cgo, col[ii]);
CGOVertexv(cgo, v1b);
}
CGONormalv(cgo, upi);
if(ring_color < 0)
CGOColorv(cgo, color);
CGOVertexv(cgo, cb);
CGONormalv(cgo, n_dn[ii]);
if(ring_color < 0)
CGOColorv(cgo, col[ii]);
CGOVertexv(cgo, v1b);
CGONormalv(cgo, n_dn[i]);
if(ring_color < 0)
CGOColorv(cgo, col[i]);
CGOVertexv(cgo, v0b);
}
CGOEnd(cgo);
if((alpha != 1.0F) || (ring_alpha != alpha))
CGOAlpha(cgo, alpha);
{
float ring_width_for_mode = ring_width;
if (ring_mode == 3){
ring_width_for_mode = 3.f * ring_width;
}
for(i = 0; i < n_atom; i++) {
ii = i + 1;
{
const float *color1, *color2;
if (ring_color < 0) {
color1 = col[i];
color2 = col[ii];
} else {
color1 = color2 = color;
}
CGOPickColor(cgo, atix[i], ai_i[i]->masked ? cPickableNoPick : cPickableAtom);
Pickable pickcolor2 = { atix[ii], ai_i[ii]->masked ? cPickableNoPick : cPickableAtom };
float axis[3];
subtract3f(v_i[ii], v_i[i], axis);
CGOColorv(cgo, color1);
cgo->add<cgo::draw::shadercylinder2ndcolor>(cgo, v_i[i], axis, ring_width_for_mode, 0x1f, color2, &pickcolor2);
}
}
}
}
}
}
}
}
}