00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: DrawMolItem2.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.40 $ $Date: 2021年10月28日 21:12:15 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * A continuation of rendering types from DrawMolItem 00019 * 00020 ***************************************************************************/ 00021 00022 #include <stdlib.h> 00023 #include <stdio.h> 00024 #include "DrawMolItem.h" 00025 #include "DrawMolecule.h" 00026 #include "Scene.h" 00027 00028 // draw the backbone trace (along the C alphas) 00029 // if no proteins are found, connect consequtive C alpha 00030 00032 // it is given the atom index 00033 // if it is invalid (<0) it puts a NULL on the queue 00034 // if it is valid, the new coords and index are pushed on the queue 00035 // If the 2nd and 3rd coords are valid, a line is drawn between them 00036 // with the right colors, etc. 00037 #define PUSH_QUEUE(atomid) { \ 00038 if (atomid < 0) { \ 00039 memmove(CA, CA+1, 3L*sizeof(float *)); CA[3] = NULL; \ 00040 memmove(indicies, indicies+1, 3L*sizeof(int)); indicies[3] = -1; \ 00041 } else { \ 00042 memmove(CA, CA+1, 3L*sizeof(float *)); CA[3] = framepos+3L*atomid; \ 00043 memmove(indicies, indicies+1, 3L*sizeof(int)); indicies[3] = atomid;\ 00044 } \ 00045 /* check if I need to draw a bond */ \ 00046 if (CA[1] && CA[2] && atomSel->on[indicies[1]] && atomSel->on[indicies[2]]) { \ 00047 float midcoord[3]; \ 00048 midcoord[0] = (CA[1][0] + CA[2][0])/2.0f; \ 00049 midcoord[1] = (CA[1][1] + CA[2][1])/2.0f; \ 00050 midcoord[2] = (CA[1][2] + CA[2][2])/2.0f; \ 00051 cmdColorIndex.putdata(atomColor->color[indicies[1]], cmdList); \ 00052 make_connection(CA[0], CA[1], midcoord, NULL, \ 00053 brad, bres, use_cyl); \ 00054 cmdColorIndex.putdata(atomColor->color[indicies[2]], cmdList); \ 00055 make_connection(NULL, midcoord, CA[2], CA[3], \ 00056 brad, bres, use_cyl); \ 00057 } \ 00058 } 00059 00060 00061 // clear out the queue by calling -1 (inserts NULLs) 00062 // This actual calls the queue three more times than need be for 00063 // PUSH_QUEUE to work correctly, but I prefered to keep the semantics 00064 #define EMPTY_QUEUE { \ 00065 int atomidcode = -1; \ 00066 PUSH_QUEUE(atomidcode); \ 00067 PUSH_QUEUE(atomidcode); \ 00068 PUSH_QUEUE(atomidcode); \ 00069 PUSH_QUEUE(atomidcode); \ 00070 } 00071 00072 00073 void DrawMolItem::draw_trace(float *framepos, float brad, int bres, int linethickness) { 00074 sprintf (commentBuffer,"Mol[%d] Rep[%d] Trace", mol->id(), repNumber); 00075 cmdCommentX.putdata(commentBuffer, cmdList); 00076 00077 int use_cyl = FALSE; 00078 if (bres <= 2 || brad < 0.01) { // then going to do lines 00079 append(DMATERIALOFF); 00080 cmdLineType.putdata(SOLIDLINE, cmdList); 00081 cmdLineWidth.putdata(linethickness, cmdList); 00082 } else { 00083 use_cyl = TRUE; 00084 append(DMATERIALON); 00085 } 00086 00087 int pnum = mol->pfragList.num(); 00088 if (pnum > 0) { 00089 // go along each protein fragment 00090 for (int pfrag=0; pfrag<pnum; pfrag++) { 00091 00092 // Reset the queue 00093 // I keep track of four C alphas since I want to use 00094 // the "make_connection" command to draw "extended" 00095 // cylinders at the CA bends, and need 4 coords to do that 00096 // find the CA coords for each residue 00097 float *CA[4] = {NULL, NULL, NULL, NULL}; 00098 int indicies[4] = {-1, -1, -1, -1}; 00099 int res_index; 00100 00101 // go down the residues in each the protein fragment 00102 int rnum = mol->pfragList[pfrag]->num(); 00103 for (int res=0; res<rnum; res++) { 00104 res_index = (*mol->pfragList[pfrag])[res]; 00105 PUSH_QUEUE(mol->find_atom_in_residue("CA", res_index)); 00106 } 00107 // flush out the queue 00108 EMPTY_QUEUE 00109 } 00110 } else { 00111 // if there are no proteins, check for sequential records with a CA 00112 // given the definition of a PDB file, I can go down the list 00113 // and see if record(i).name == CA and record(i-1).name == CA 00114 // and record(i).resid = record(i-1).resid + 1 00115 00116 // As before, to connect records nicely I want to track four at a time 00117 float *CA[4] = {NULL, NULL, NULL, NULL}; 00118 int indicies[4] = {-1, -1, -1, -1}; 00119 int num = mol->nAtoms; 00120 int ca_num = mol->atomNames.typecode("CA"); 00121 int last_resid = -10000; 00122 int resid; 00123 for (int i=0; i<num; i++) { 00124 MolAtom *atm = mol->atom(i); 00125 if (atm->nameindex == ca_num) { 00126 // found a CA, is it sequential? 00127 resid = atm->resid; 00128 if (resid == last_resid + 1) { 00129 // Yippe! push it on the end of the queue 00130 PUSH_QUEUE(i); 00131 } else { 00132 EMPTY_QUEUE 00133 // and add this element 00134 PUSH_QUEUE(i); 00135 } 00136 last_resid = resid; 00137 } else { 00138 // didn't find a CA, so flush the queue 00139 EMPTY_QUEUE 00140 last_resid = -10000; 00141 } 00142 } // end of loop through atoms 00143 // and flush out any remaining data 00144 EMPTY_QUEUE 00145 } // end if check if has proteins 00146 00147 // And do the same for nucleic acids 00148 int nnum = mol -> nfragList.num(); 00149 if (nnum > 0) { 00150 // go along each nucleic fragment 00151 for (int nfrag=0; nfrag<nnum; nfrag++) { 00152 // Reset the queue 00153 // I keep track of four P atoms since I want to use 00154 // the "make_connection" command to draw "extended" 00155 // cylinders at the P bends, and need 4 coords to do that 00156 // find the P coords for each residue 00157 // I keep the name CA since I want to use the same macros 00158 float *CA[4] = {NULL, NULL, NULL, NULL}; 00159 int indicies[4] = {-1, -1, -1, -1}; 00160 int res_index; 00161 00162 // go down the residues in each the nucleic fragment 00163 int rnum = mol->nfragList[nfrag]->num(); 00164 for (int res=0; res<rnum; res++) { 00165 res_index = (*mol->nfragList[nfrag])[res]; 00166 PUSH_QUEUE(mol->find_atom_in_residue("P", res_index)); 00167 } 00168 // flush out the queue 00169 EMPTY_QUEUE 00170 } 00171 } else { 00172 // if there are no proteins, check for sequential records with a P 00173 // given the definition of a PDB file, I can go down the list 00174 // and see if record(i).name == P and record(i-1).name == P 00175 // and record(i).resid = record(i-1).resid + 1 00176 00177 // As before, to connect records nicely I want to track four at a time 00178 float *CA[4] = {NULL, NULL, NULL, NULL}; 00179 int indicies[4] = {-1, -1, -1, -1}; 00180 int num = mol->nAtoms; 00181 int p_num = mol->atomNames.typecode("P"); 00182 int last_resid = -10000; 00183 int resid; 00184 for (int i=0; i<num; i++) { 00185 MolAtom *atm = mol->atom(i); 00186 if (atm -> nameindex == p_num) { 00187 // found a P, is it sequential? 00188 resid = atm->resid; 00189 if (resid == last_resid + 1) { 00190 // Yippe! push it on the end of the queue 00191 PUSH_QUEUE(i); 00192 } else { 00193 EMPTY_QUEUE 00194 // and add this element 00195 PUSH_QUEUE(i); 00196 } 00197 last_resid = resid; 00198 } else { 00199 // didn't find a P, so flush the queue 00200 EMPTY_QUEUE 00201 last_resid = -10000; 00202 } 00203 } // end of loop through atoms 00204 // and flush out any remaining data 00205 EMPTY_QUEUE 00206 00207 } // end if check if has nucleic acid residues 00208 } 00209 00210 00211 // Draw dot surface 00212 // the dot distribution is determined from Jon Leech's 'distribute' 00213 // code. See ftp://ftp.cs.unc.edu/pub/users/leech/points.tar.gz 00214 // and ftp://netlib.att.com/netlib/att/math/sloane/electrons/ 00215 // All the dots are precomputed 00216 #include "DrawMolItemSolventPoints.data" 00217 // Note: DrawMolItem::num_dot_surfaces is actually defined in 00218 // DrawMolItemSolventPoints.data 00219 void DrawMolItem::draw_dot_surface(float *framepos, float srad, int sres, int method) { 00220 // XXX Hack - the value used for num_dot_surfaces should be retrieved 00221 // from AtomRep, I'm just not sure how to do it at the moment. 00222 int num_dot_surfaces = 13; // See the Solvent section of AtomRepInfo 00223 00224 DispCmdLineArray cmdLineArray; 00225 float probe_radius = srad; 00226 // sphereres has range 1 to n 00227 int surface_resolution = sres - 1; 00228 if (surface_resolution >= num_dot_surfaces) // slight paranoia 00229 surface_resolution = num_dot_surfaces - 1; 00230 if (surface_resolution < 0) 00231 surface_resolution = 0; 00232 00233 int num_dots = dot_surface_num_points[surface_resolution]; 00234 float *dots = dot_surface_points[surface_resolution]; 00235 int num_edges = dot_surface_num_lines[surface_resolution]; 00236 int *edges = dot_surface_lines[surface_resolution]; 00237 int *flgs = new int[num_dots]; 00238 const float *aradius = mol->radius(); 00239 00240 // clamp range from 0 to 2 00241 if (method < 0) method = 0; 00242 if (method > 2) method = 2; 00243 00244 sprintf(commentBuffer, "Mol[%d] Rep[%d] Solvent", mol->id(), repNumber); 00245 cmdCommentX.putdata(commentBuffer, cmdList); 00246 00247 append(DMATERIALOFF); // disable shading in all cases 00248 cmdLineType.putdata(SOLIDLINE, cmdList); // set line drawing parameters 00249 cmdLineWidth.putdata(1, cmdList); 00250 00251 // XXX really needs to be done only when selection or color changed 00252 update_lookups(atomColor, atomSel, colorlookups); 00253 00254 // temp info for drawing the little plus sign 00255 // I looked - none of the points are along the x axis 00256 float xaxis[3] = {1.0, 0.0, 0.0}; 00257 float perp1[3], perp2[3]; 00258 float pos1[3], pos2[3]; 00259 00260 ResizeArray<float> verts; 00261 ResizeArray<float> colors; 00262 00263 for (int icolor=0; icolor<MAXCOLORS; icolor++) { 00264 const ColorLookup &cl = colorlookups[icolor]; 00265 if (cl.num == 0) continue; 00266 00267 const float *rgb = scene->color_value(icolor); 00268 if (method != 0) { 00269 cmdColorIndex.putdata(icolor, cmdList); 00270 } 00271 // draw points which are not within range of the bonded atoms 00272 for (int j=0; j<cl.num; j++) { 00273 const int id = cl.idlist[j]; 00274 const MolAtom *atom = mol->atom(id); 00275 const float *pos = framepos + 3L*id; 00276 float radius = aradius[id] + probe_radius; 00277 for (int points=0; points < num_dots; points++) { 00278 const float *d = dots + 3L*points; 00279 flgs[points] = 1; 00280 float xyz[3]; 00281 vec_scale(xyz, radius, d); 00282 vec_add(xyz, xyz, pos); 00283 // check the neighbors 00284 for (int nbr=0; nbr < atom->bonds; nbr++) { 00285 int b = atom->bondTo[nbr]; 00286 const MolAtom *atom2 = mol->atom(b); 00287 float r = aradius[b] + probe_radius; 00288 if (distance2(xyz, framepos + 3L*b) < r*r) { 00289 flgs[points] = 0; 00290 break; 00291 } 00292 // check the neighbor's neighbors 00293 for (int nbr2=0; nbr2 < atom2->bonds; nbr2++) { 00294 int b2 = atom2->bondTo[nbr2]; 00295 if (b2 == id) continue; // don't eliminate myself! 00296 float r2 = aradius[b2] + probe_radius; 00297 if (distance2(xyz, framepos + 3L*b2) < r2*r2) { 00298 flgs[points] = 0; 00299 break; 00300 } 00301 } 00302 if (!flgs[points]) break; 00303 } 00304 if (!flgs[points]) continue; 00305 00306 switch (method) { 00307 case 0: 00308 // draw it as a point 00309 colors.append3(&rgb[0]); 00310 verts.append3(&xyz[0]); 00311 break; 00312 case 1: 00313 // draw a small cross tangent to the surface 00314 cross_prod(perp1, d, xaxis); // d and xaxis are of length 1 00315 cross_prod(perp2, d, perp1); // get the other tangent vector 00316 // scale appropriately 00317 #define CROSS_SCALE_FACTOR 0.05f 00318 perp1[0] *= CROSS_SCALE_FACTOR; 00319 perp1[1] *= CROSS_SCALE_FACTOR; 00320 perp1[2] *= CROSS_SCALE_FACTOR; 00321 perp2[0] *= CROSS_SCALE_FACTOR; 00322 perp2[1] *= CROSS_SCALE_FACTOR; 00323 perp2[2] *= CROSS_SCALE_FACTOR; 00324 vec_add(pos1, xyz, perp1); 00325 vec_sub(pos2, xyz, perp1); 00326 verts.append3(&pos1[0]); 00327 verts.append3(&pos2[0]); 00328 vec_add(pos1, xyz, perp2); 00329 vec_sub(pos2, xyz, perp2); 00330 verts.append3(&pos1[0]); 00331 verts.append3(&pos2[0]); 00332 break; 00333 } 00334 } 00335 00336 if (method == 1) { 00337 cmdLineArray.putdata(&verts[0], verts.num()/6, cmdList); 00338 verts.clear(); 00339 continue; 00340 } 00341 00342 // had to wait to accumulate all the possible vertices 00343 if (method == 2) { 00344 // draw all the connections if both points are used 00345 int a, b; 00346 int offset = 0; 00347 float xyz[2][3]; 00348 // go through the dots 00349 for (a=0; a < num_dots; a++) { 00350 if (flgs[a]) { 00351 // if this point is turned on 00352 xyz[0][0] = pos[0] + radius * dots[3L*a + 0]; 00353 xyz[0][1] = pos[1] + radius * dots[3L*a + 1]; 00354 xyz[0][2] = pos[2] + radius * dots[3L*a + 2]; 00355 00356 // go through the matching connections 00357 while (offset < num_edges && edges[2L*offset] == a) { 00358 // is the neighbor turned on? 00359 b = edges[2L*offset + 1]; 00360 if (flgs[b]) { 00361 xyz[1][0] = pos[0] + radius * dots[3L*b + 0]; 00362 xyz[1][1] = pos[1] + radius * dots[3L*b + 1]; 00363 xyz[1][2] = pos[2] + radius * dots[3L*b + 2]; 00364 verts.append3(&xyz[0][0]); 00365 verts.append3(&xyz[1][0]); 00366 } 00367 offset++; 00368 } 00369 } else { 00370 // just go through the connection until the next number 00371 while (offset < num_edges && edges[2L*offset] == a) { 00372 offset++; 00373 } 00374 } 00375 } 00376 cmdLineArray.putdata(&verts[0], verts.num()/6, cmdList); 00377 verts.clear(); 00378 } // end of drawing as lines 00379 } 00380 } 00381 delete [] flgs; 00382 if (method == 0) { 00383 cmdPointArray.putdata(&verts[0], &colors[0], 1.0f, 00384 verts.num()/3, cmdList); 00385 } 00386 } 00387