/* Rotate viewport as V' = R*V but letting the anchor stay at the same place */ void rotate (int iw, double R[3][3]) { double V0[3][3], s[3], tmp[3]; if (n[iw].anchor >= 0) { V3SUB (B->BALL[n[iw].anchor].x, AX_3D[iw].x, tmp); M3mV3 (AX_3D[iw].V, tmp, s); } else { V3SUB (n[iw].hook, AX_3D[iw].x, tmp); M3mV3 (AX_3D[iw].V, tmp, s); } M3EQV (AX_3D[iw].V, V0); V3mM3 (R[0], V0, AX_3D[iw].V[0]); V3mM3 (R[1], V0, AX_3D[iw].V[1]); V3NORMALIZE (AX_3D[iw].V[1], tmp[0]); /* ensure the orthogonality numerically */ V3CROSS (AX_3D[iw].V[0], AX_3D[iw].V[1], AX_3D[iw].V[2]); V3NORMALIZE (AX_3D[iw].V[2], tmp[0]); V3CROSS (AX_3D[iw].V[1], AX_3D[iw].V[2], AX_3D[iw].V[0]); if (n[iw].anchor >= 0) { V3mM3 (s, AX_3D[iw].V, tmp); V3SUB (B->BALL[n[iw].anchor].x, tmp, AX_3D[iw].x); } else { V3mM3 (s, AX_3D[iw].V, tmp); V3SUB (n[iw].hook, tmp, AX_3D[iw].x); } return; } /* end rotate() */
void p3dp_print_atom_quartet_info (int iw, int l, int k, int j, int i, int lrank, int krank, int jrank, int irank) { double dxkj[4], dxij[4], angle, normal[4], dxlk[4], dxjk[4], dihedral; double sl[3], sk[3], sj[3], si[3]; p3dp_s(sl, l, lrank); p3dp_s(sk, k, krank); p3dp_s(sj, j, jrank); p3dp_s(si, i, irank); angle = p3dp_atom_triplet_s(sk, sj, si, dxkj, dxij); print_atom_pair_info_s(iw, i, j, irank, jrank, si, sj); if (IS_MANAGER) printf ("bond angle = %g degrees.\n", RADIAN_TO_DEGREE(angle)); print_atom_pair_info_s(iw, k, j, krank, jrank, sk, sj); V3CROSS (dxkj, dxij, normal); normal[3] = V3LENGTH2 (normal); angle = p3dp_atom_triplet_s(sl, sk, sj, dxlk, dxjk); if (IS_MANAGER) printf ("bond angle = %g degrees.\n", RADIAN_TO_DEGREE(angle)); print_atom_pair_info_s(iw, l, k, lrank, krank, sl, sk); /* right-handed helix gives positive dihedral angle */ if ( (normal[3]>0) && (dxlk[3]>0) ) dihedral = acos( V3DOT(normal,dxlk)/sqrt(normal[3])/sqrt(dxlk[3]) ) - PI / 2; else dihedral = 0; if (IS_MANAGER) printf ("dihedral angle = %g degrees.\n", RADIAN_TO_DEGREE(dihedral)); return; }
/* use pointer device to rotate (via magic sphere) */ bool pointer_rotate (int iw, int to_x, int to_y) { double a[3], b[3], c[3], R[3][3]; mgs ( n[iw].lx - AX_size[iw].width/2., n[iw].ly - AX_size[iw].height/2., n[iw].mgs_radius, a ); mgs ( to_x - AX_size[iw].width/2., to_y - AX_size[iw].height/2., n[iw].mgs_radius, b ); V3CROSS (a, b, c); if (V3LENGTH2(c) < MIN_RADIAN*MIN_RADIAN) return (FALSE); M3geodesic (b, a, R); rotate (iw, R); n[iw].lx = to_x; n[iw].ly = to_y; return (TRUE); } /* end pointer_rotate() */
void print_atom_quartet_info (int iw, int l, int k, int j, int i) { double dxkj[4], dxij[4], angle, normal[4], dxlk[4], dxjk[4], dihedral; angle = atom_triplet (k, j, i, dxkj, dxij); print_atom_pair_info (iw, i, j); printf ("bond angle = %g degrees.\n", RADIAN_TO_DEGREE(angle)); print_atom_pair_info (iw, k, j); V3CROSS (dxkj, dxij, normal); normal[3] = V3LENGTH2 (normal); angle = atom_triplet (l, k, j, dxlk, dxjk); printf ("bond angle = %g degrees.\n", RADIAN_TO_DEGREE(angle)); print_atom_pair_info (iw, l, k); /* right-handed helix gives positive dihedral angle */ if ( (normal[3]>0) && (dxlk[3]>0) ) dihedral = acos( V3DOT(normal,dxlk)/sqrt(normal[3])/sqrt(dxlk[3]) ) - PI / 2; else dihedral = 0; printf ("dihedral angle = %g degrees.\n", RADIAN_TO_DEGREE(dihedral)); return; } /* end print_atom_quartet_info() */
/* Save atoms selected in a monoclinic filter to a file */ void save_atoms_in_monoclinic_filter (int iw) { M3 HH; double d0, zmargin, xytolerance, origin[3]; char danswer[MAX_FILENAME_SIZE], *answer, fname[MAX_FILENAME_SIZE]; char *taglist = NULL; int selected[2]; V3SUB( B->BALL[n[iw].atom_stack[0]].x, B->BALL[n[iw].atom_stack[1]].x, HH[0] ); V3SUB( B->BALL[n[iw].atom_stack[2]].x, B->BALL[n[iw].atom_stack[1]].x, HH[1] ); V3CROSS (HH[0], HH[1], HH[2]); if (V3ISSMALL(HH[2])) { printf("The selected parallelogram is ill-conditioned\n" "for constructing a monoclinic filter.\n"); return; } V3NORMALIZE (HH[2], d0); printf ("\"up\" is [%g %g %g]\n" "check it agrees with your mirror normal...\n", V3E(HH[2])); d0 = 2.5; zmargin = 0.01; xytolerance = 0.01; xterm_get_focus(iw); clear_stdin_buffer(); REALLOC (save_atoms_in_monoclinic_filter, taglist, np, char); while (1) { sprintf (danswer, "%g %g %g", d0, zmargin, xytolerance); answer = readline_gets ("Interplanar spacing [A] z-margin [A] xy-tolerance", danswer); sscanf(answer, "%lf %lf %lf", &d0, &zmargin, &xytolerance); V3ADDMUL (B->BALL[n[iw].atom_stack[1]].x, d0/2,HH[2], origin); if (tag_atoms_in_monoclinic_filter (origin,HH, d0+2*zmargin,xytolerance, selected,taglist)>0) break; strcpy (danswer, answer); } printf("down=%d and up=%d atoms selected in filter.\n", selected[0], selected[1]); while (1) { sprintf (danswer, "%s.idx", fbasename); answer = readline_gets("Save the selected atoms to", danswer); sscanf(answer, "%s", fname); if ( tested_to_be_writable(fname) ) { save_dipole_indices (selected, taglist, fname); printf ("selected atom indices [0-%d] saved to %s.\n", np-1,fname); Free (taglist); break; } else { printf ("\n** %s: **\n", fname); printf ("** This file is unwritable! **\n"); } strcpy(danswer, answer); } xterm_release_focus(iw); return; } /* end save_atoms_in_monoclinic_filter() */
/* Allocate arrows */ void Config_to_3D_Arrows(int arrow_idx, double scale_factor, double head_height, double head_width, double up[3], int overlay, double color[3]) { register int i, j, offset; double dx[3], head[3], head1[3], perp[3], perp2[3], sum; AX_3D_Lines tmp_arrows[1] = {{0}}; tmp_arrows[0].LINE = NULL; if (overlay) { offset = arrows->n_lines; if (offset != 0) { AX_3D_Lines_Realloc(tmp_arrows, arrows->n_lines); for (i=0; i<arrows->n_lines; i++) { V3EQV(arrows->LINE[i].x0, tmp_arrows->LINE[i].x0); V3EQV(arrows->LINE[i].x1, tmp_arrows->LINE[i].x1); AX_3D_AssignRGB (tmp_arrows->LINE[i], arrows->LINE[i].r, arrows->LINE[i].g, arrows->LINE[i].b); } } AX_3D_Lines_Realloc(arrows, arrows->n_lines + 3*np); if (offset != 0) { for (i=0; i<tmp_arrows->n_lines; i++) { V3EQV(tmp_arrows->LINE[i].x0, arrows->LINE[i].x0); V3EQV(tmp_arrows->LINE[i].x1, arrows->LINE[i].x1); AX_3D_AssignRGB (arrows->LINE[i], tmp_arrows->LINE[i].r, tmp_arrows->LINE[i].g, tmp_arrows->LINE[i].b); } AX_3D_Lines_Free(tmp_arrows); } } else { AX_3D_Lines_Realloc(arrows, 3*np); offset = 0; } /* auto scale */ if (scale_factor == 0.0) { sum = 0.0; for (i=0; i<np; i++) { dx[0] = *(CONFIG_auxiliary[arrow_idx+0]+i); dx[1] = *(CONFIG_auxiliary[arrow_idx+1]+i); dx[2] = *(CONFIG_auxiliary[arrow_idx+2]+i); sum += V3LENGTH(dx); } scale_factor = 1.0/(sum/np); printf("Config_to_3D_Arrows: average magnitude = %f, scale_factor set to %f\n", 1.0/scale_factor, scale_factor); } printf("Config_to_3D_Arrows: color = <%.3f,%.3f,%.3f>\n", color[0], color[1], color[2]); for (i=0; i<np; i++) { AX_3D_AssignRGB (arrows->LINE[offset+3*i], color[0], color[1], color[2]); AX_3D_AssignRGB (arrows->LINE[offset+3*i+1], color[0], color[1], color[2]); AX_3D_AssignRGB (arrows->LINE[offset+3*i+2], color[0], color[1], color[2]); dx[0] = *(CONFIG_auxiliary[arrow_idx+0]+i)*scale_factor; dx[1] = *(CONFIG_auxiliary[arrow_idx+1]+i)*scale_factor; dx[2] = *(CONFIG_auxiliary[arrow_idx+2]+i)*scale_factor; if (V3EQZERO(dx)) { for (j=0; j<3; j++) { V3EQV(B->BALL[i].x, arrows->LINE[offset+3*i+j].x0); V3EQV(B->BALL[i].x, arrows->LINE[offset+3*i+j].x1); } } else { V3ADD(B->BALL[i].x, dx, head); V3EQV(B->BALL[i].x, arrows->LINE[offset+3*i+0].x0); V3EQV(head, arrows->LINE[offset+3*i+0].x1); V3EQV(head, arrows->LINE[offset+3*i+1].x0); V3EQV(head, arrows->LINE[offset+3*i+2].x0); V3CROSS(dx, up, perp2); if (V3EQZERO(perp2)) { V3ASSIGN(1.0, 0.0, 0.0,perp); } else { V3CROSS(dx, perp2, perp); V3normalize(perp); } V3mul(head_width*V3LENGTH(dx),perp,perp); V3EQV(dx, head1); V3mul(head_height,head1,head1); V3SUB(head,head1,head1); V3ADD(head1,perp,arrows->LINE[offset+3*i+1].x1); V3SUB(head1,perp,arrows->LINE[offset+3*i+2].x1); } } }