/* 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 atom_xtal_origin (double xtal_origin[3]) { register int i; double ds[3], new_s[3]; V3mM3 (xtal_origin, HI, ds); V3TRIM (ds, ds); for (i=0; i<np; i++) { V3SUB ( &(s[DIMENSION*i]), ds, new_s ); V3TriM ( new_s ); V3mM3 ( new_s, H, B->BALL[i].x ); } return; } /* end atom_xtal_origin() */
void bond_xtal_origin_update (int iw) { register int i,j; int k; double *new_s, ds[3], tmp[3]; if (temporary_disable_bond) return; MALLOC( bond_xtal_origin_update, new_s, DIMENSION*np, double ); V3mM3 (n[iw].xtal_origin, HI, ds); V3TRIM (ds, ds); for (i=0; i<np; i++) { V3SUB ( &(s[DIMENSION*i]), ds, &(new_s[DIMENSION*i]) ); V3TriM ( &(new_s[DIMENSION*i]) ); } if (n[iw].bond_mode == BOND_MODE_USER) for (k=0; k<C->n_cylinders; k++) { i = CylinderAtoms[2*k]; j = CylinderAtoms[2*k+1]; V3SUB (&(new_s[DIMENSION*j]), &(new_s[DIMENSION*i]), tmp); if ( V3NEED_IMAGE(tmp) ) { /* g<0 means geometric invisibility */ C->CYLINDER[k].g = -fabs(C->CYLINDER[k].g); C->CYLINDER[k].radius = -fabs(C->CYLINDER[k].radius); } else { C->CYLINDER[k].g = fabs(C->CYLINDER[k].g); C->CYLINDER[k].radius = fabs(C->CYLINDER[k].radius); V3EQV (B->BALL[i].x, C->CYLINDER[k].x0); } } else for (i=0; i<np; i++) for (j=N->idx[i]; j<N->idx[i+1]; j++) { V3SUB (&(new_s[DIMENSION*N->list[j]]), &(new_s[DIMENSION*i]), tmp); if ( V3NEED_IMAGE(tmp) ) { /* g<0 means geometric invisibility */ C->CYLINDER[j].g = -fabs(C->CYLINDER[j].g); C->CYLINDER[j].radius = -fabs(C->CYLINDER[j].radius); } else { C->CYLINDER[j].g = BOND_G(i, N->list[j]); V3EQV (B->BALL[i].x, C->CYLINDER[j].x0); if (C->CYLINDER[j].r >= 0) C->CYLINDER[j].radius = n[iw].bond_radius; } } free (new_s); n[iw].bond_xtal_origin_need_update = FALSE; return; } /* end bond_xtal_origin_update() */
bool xtal_origin_goto (int iw) { double old_s[3], s[3]; char danswer[MAX_FILENAME_SIZE],*answer; if (!n[iw].xtal_mode) { printf ("Crystal translation is only available under Xtal mode.\n"); return(FALSE); } V3mM3 (AX_3D[iw].x, HI, old_s); xterm_get_focus(iw); clear_stdin_buffer(); sprintf (danswer, "%g %g %g", old_s[0],old_s[1],old_s[2]); answer = readline_gets("\nCrystal origin s0,s1,s2",danswer); sscanf (answer, "%lf %lf %lf", s, s+1, s+2); xterm_release_focus(iw); V3TRIM (s,s); if (V3EQ(old_s,s)) return(FALSE); V3mM3 (s, H, n[iw].xtal_origin); atom_xtal_origin (n[iw].xtal_origin); if (n[iw].bond_mode) bond_xtal_origin_update (iw); else n[iw].bond_xtal_origin_need_update = TRUE; return (TRUE); } /* end xtal_origin_goto() */
/* Return z>0 if there is intersection, -1 otherwise. */ double Eyesight_Intersect_H_Surface (double H[3][3], int surface_id, double x0[3], double V[3][3], double k0, double k1, double s[3], double x[3]) { int i; double b[3], M[3][3], MI[3][3], tmp; i = surface_id / 2; if (surface_id % 2) V3SUB(x0,H[i],b); else V3EQV(x0,b); M3EQV(H,M); V3NEG(V[2],M[i]); V3SUBmuL(M[i],k0,V[0]); V3SUBmuL(M[i],k1,V[1]); tmp = M3DETERMINANT(M); if (ISTINY(tmp)) return(-1); M3INV(M,MI,tmp); V3mM3(b,MI,s); tmp = s[i]; s[i] = surface_id % 2; V3mM3 (s,H,x); return (tmp); } /* end Eyesight_Intersect_H_Surface() */
/* Allocate balls */ void Config_to_3D_Balls (double atom_r_ratio) { register int i; AX_3D_Balls_Realloc (B, np); for (i=0; i<np; i++) { V3mM3 ( &(s[DIMENSION*i]), H, B->BALL[i].x ); B->BALL[i].radius = ATOM_Radius(ct->Z[(int)tp[i]]) * atom_r_ratio; AX_3D_AssignRGB (B->BALL[i], ATOM_Color_R(ct->Z[(int)tp[i]]), ATOM_Color_G(ct->Z[(int)tp[i]]), ATOM_Color_B(ct->Z[(int)tp[i]]) ); } return; } /* end Config_to_3D_Balls() */
/* Use pointer device to shift the crystal */ bool pointer_xtal_shift (int iw, int to_x, int to_y) { int i; double s[3], xx_last[3], xx_now[3]; if (!n[iw].xtal_mode) { printf ("Crystal translation is only available under Xtal mode.\n"); return(FALSE); } if ((n[iw].lx == to_x) && (n[iw].ly == to_y)) return (FALSE); V3mM3 (AX_3D[iw].x, HI, s); if (V3XIN(s,0,1)) return(pointer_grab_xtal_shift(iw,to_x,to_y)); i = Eyesight_Intersect_H_Box (iw, n[iw].lx, n[iw].ly, xx_last); if (i >= 0) n[iw].last_surface_id = i; else if (Eyesight_Intersect_H_Surface (H, n[iw].last_surface_id, AX_3D[iw].x, AX_3D[iw].V, (n[iw].lx + 0.5 - AX_3D[iw].wx) / AX_3D[iw].k, (n[iw].ly + 0.5 - AX_3D[iw].wy) / AX_3D[iw].k, s, xx_last) <= 0) { n[iw].lx = to_x; n[iw].ly = to_y; return(FALSE); } i = Eyesight_Intersect_H_Box (iw, to_x, to_y, xx_now); if (i >= 0) n[iw].last_surface_id = i; else if (Eyesight_Intersect_H_Surface (H, n[iw].last_surface_id, AX_3D[iw].x, AX_3D[iw].V, (to_x + 0.5 - AX_3D[iw].wx) / AX_3D[iw].k, (to_y + 0.5 - AX_3D[iw].wy) / AX_3D[iw].k, s, xx_now) <= 0) { n[iw].lx = to_x; n[iw].ly = to_y; return(FALSE); } n[iw].lx = to_x; n[iw].ly = to_y; V3AdD(xx_last,n[iw].xtal_origin); V3SuB(n[iw].xtal_origin,xx_now); atom_xtal_origin (n[iw].xtal_origin); if (n[iw].bond_mode) bond_xtal_origin_update (iw); else n[iw].bond_xtal_origin_need_update = TRUE; return (TRUE); } /* end pointer_xtal_shift() */
/* Allocate bonds */ void Config_to_3D_Bonds (double bond_radius) { register int i,j; AX_Float ds[3], DS[3]; AX_3D_Cylinders_Realloc (C, N->idx[np]); for (i=0; i<np; i++) for (j=N->idx[i]; j<N->idx[i+1]; j++) { V3EQV ( B->BALL[i].x, C->CYLINDER[j].x0 ); V3SUB ( &s[DIMENSION*N->list[j]], &s[DIMENSION*i], ds ); V3IMAGE ( ds, DS ); V3mM3 ( DS, H, C->CYLINDER[j].axis ); AX_V3NORMALIZE ( C->CYLINDER[j].axis, C->CYLINDER[j].axis[3] ); BONDCOLOR (i, N->list[j], j); if (V3NEED_IMAGE(ds)) { C->CYLINDER[j].g = -1; C->CYLINDER[j].radius = -1; } else C->CYLINDER[j].radius = bond_radius; } return; } /* end Config_to_3D_Bonds() */
static int tag_atoms_in_monoclinic_filter (V3 origin, M3 HH, double height, double xytolerance, int *selected, char *taglist) { register int i; M3 HHH, HHHI; double dx[4], ds[3]; M3EQV (HH, HHH); V3MuL (height, HHH[2]); M3inv (HHH, HHHI); selected[0] = 0; selected[1] = 0; for (i=np; i--;) { V3SUB (B->BALL[i].x, origin, dx); V3mM3 (dx, HHHI, ds); if ( XIN(ds[0],-xytolerance,1+xytolerance) && XIN(ds[1],-xytolerance,1+xytolerance) && XIN(ds[2],-0.5,0.5) ) { if (ds[2] < 0) { selected[0]++; taglist[i] = 1; } else { selected[1]++; taglist[i] = 2; } } else taglist[i] = 0; } return(selected[0]+selected[1]); } /* end tag_atoms_in_monoclinic_filter() */
bool print_status (int iw) { int i; double x[3], V[3][3]; SimpleStatistics ss; /* xterm_get_focus(iw); */ for (i=0; i<CONFIG_num_auxiliary; i++) { CalculateSimpleStatistics (np, CHARP(CONFIG_auxiliary[i]), sizeof(double), IOVAL_DOUBLE, &ss); printf("\nauxiliary[%d]=%s [%s], threshold=[%g, %g]\n", i, CONFIG_auxiliary_name[i], CONFIG_auxiliary_unit[i], n[iw].auxiliary_threshold[i][0], n[iw].auxiliary_threshold[i][1]); printf("[%g(%d), %g(%d)], avg=%g, std.dev.=%g\n", ss.min, ss.idx_min, ss.max, ss.idx_max, ss.average, ss.standard_deviation); } printf("\n======================= Status of Viewport #%d " "=======================\n",iw); V3EQV (AX_3D[iw].x, x); V3pr ("Viewpoint is at %M A,\n", x); M3inv (H, V); V3mM3 (AX_3D[iw].x, V, x); V3pr("in reduced coordinates it is %M;\n", x); M3EQV(AX_3D[iw].V, V); S3PR("viewport axes = %M;\n", V); printf ("window width = %d, height = %d pixels,\n", AX_size[iw].width, AX_size[iw].height); printf ("and conversion factor is %g pixel/radian,\n", AX_3D[iw].k); printf ("which converts to %g x %g degrees of field of view.\n", RADIAN_TO_DEGREE(2*atan(AX_size[iw].width/2/AX_3D[iw].k)), RADIAN_TO_DEGREE(2*atan(AX_size[iw].height/2/AX_3D[iw].k))); printf ("The viewport is now anchored to %s", (n[iw].anchor>=0)? "atom" : "hook" ); if (n[iw].anchor >= 0) print_atom(iw,n[iw].anchor); else { M3inv (H, V); V3mM3 (n[iw].hook, V, x); printf("\nx = [%g %g %g] A, or s = [%g %g %g].\n", n[iw].hook[0], n[iw].hook[1], n[iw].hook[2], x[0], x[1], x[2]); } printf("parallel projection mode is turned %s.\n", n[iw].parallel_projection?"ON":"OFF"); printf("term printout suppression is turned %s.\n", n[iw].suppress_printout?"ON":"OFF"); V3pr ("background color = %M.\n", n[iw].bgcolor); printf ("atom r_ratio = %f, bond radius = %f A.\n", n[iw].atom_r_ratio, n[iw].bond_radius); printf("bond mode is turned %s.\n", n[iw].bond_mode?"ON":"OFF"); printf("system average IS%s subtracted off from atomistic strains.\n", shear_strain_subtract_mean ? "" : "N'T"); printf("wireframe mode is %s.\n", (n[iw].wireframe_mode==WIREFRAME_MODE_CONTRAST)?"CONTRAST": (n[iw].wireframe_mode==WIREFRAME_MODE_NONE)?"NONE": (n[iw].wireframe_mode==WIREFRAME_MODE_RGBO)?"RGBO": (n[iw].wireframe_mode==WIREFRAME_MODE_RGBK)?"RGBK": (n[iw].wireframe_mode==WIREFRAME_MODE_RGB)?"RGB": "UNKNOWN"); if (n[iw].xtal_mode) { printf ("Xtal mode is turned ON:\n"); V3mM3 (n[iw].xtal_origin, HI, x); V3TRIM (x, x); V3pr ("xtal_origin = %M.\n", x); } else printf ("Xtal mode is turned OFF.\n"); printf ("color mode = %s.\n", (n[iw].color_mode==COLOR_MODE_NORMAL)? "NORMAL" : (n[iw].color_mode==COLOR_MODE_COORD)? "COORDINATION" : (n[iw].color_mode==COLOR_MODE_AUXILIARY)? "Auxiliary Properties" : (n[iw].color_mode==COLOR_MODE_SCRATCH)? "SCRATCH" : "UNKNOWN"); if (n[iw].shell_viewer_mode) printf("Shell viewer auto-invoke is turned ON.\n"); else printf("Shell viewer auto-invoke is turned OFF.\n"); printf("s[%d]=%d surface is now seen or selected.\n", n[iw].last_surface_id/2, n[iw].last_surface_id%2); if (rcut_patching) printf ("Neighbor distance cutoff between %s = %g.\n", rcut_patch_pairname, rcut_patch[rcut_patch_item].rcut); printf ("rate of change = %g.\n", n[iw].delta); if (n[iw].color_mode==COLOR_MODE_AUXILIARY) { i = n[iw].auxiliary_idx; if (i < CONFIG_num_auxiliary) printf("auxiliary[%d] = %s [%s], threshold = [%g, %g],\n", i, CONFIG_auxiliary_name[i], CONFIG_auxiliary_unit[i], n[iw].auxiliary_threshold[i][0], n[iw].auxiliary_threshold[i][1]); else printf("auxiliary = %s, threshold = [%g, %g],\n", geolist[i-CONFIG_MAX_AUXILIARY].token, n[iw].auxiliary_threshold[i][0], n[iw].auxiliary_threshold[i][1]); CalculateSimpleStatistics (np, CHARP(INW(n[iw].auxiliary_idx,CONFIG_num_auxiliary) ? CONFIG_auxiliary[i] : geo[i-CONFIG_MAX_AUXILIARY]), sizeof(double), IOVAL_DOUBLE, &ss); printf("[%g(%d),%g(%d)], avg=%g, std.dev.=%g,\n", ss.min, ss.idx_min, ss.max, ss.idx_max, ss.average, ss.standard_deviation); printf("auxiliaries' colormap = %s \"%s\".\n", AX_cmap_funs[n[iw].auxiliary_cmap].name, AX_cmap_funs[n[iw].auxiliary_cmap].description); printf("invisible outside auxiliary thresholds flag = %s.\n", n[iw].auxiliary_thresholds_saturation?"OFF":"ON"); printf("floating auxiliary thresholds flag = %s.\n", n[iw].auxiliary_thresholds_rigid?"OFF":"ON"); } printf ("clicked atoms = [ "); for (i=0; i<ATOM_STACK_SIZE; i++) printf ("%d ", n[iw].atom_stack[i]); printf ("];\n"); for (i=0; i<AX_3D_MAX_FILTER_PLANE; i++) if (AX_V3NEZERO(AX_3D[iw].fp[i].dx)) printf("%s fp %d: dx = [%g %g %g], s = [%g %g %g]\n", (n[iw].just_activated_fp==i) ? "*" : " ", i, V3E(AX_3D[iw].fp[i].dx), V3E(n[iw].fp[i].s0)); printf("==============================================" "=======================\n"); return(FALSE); } /* end print_status() */
/* Reload the configuration but keeping the rendering state */ void reload_config (int iw, bool term_input_filename) { register int i; int j, k, old_np; char fname[MAX_FILENAME_SIZE], oldfname[MAX_FILENAME_SIZE]; V3 hook_s, tmp, dx; char *old_symbol=NULL; bool incompatible_config; strcpy(oldfname, config_fname); if (n[iw].anchor >= 0) { /* the new configuration may not even have the atom */ V3EQV (B->BALL[n[iw].anchor].x, n[iw].hook); n[iw].anchor = -1; } /* hook_s[] is what is kept invariant */ V3mM3 (n[iw].hook, HI, hook_s); if (term_input_filename) { xterm_get_focus(iw); clear_stdin_buffer(); strcpy(fname,readline_gets("\nLoad configuration",config_fname)); strcpy(config_fname,fname); xterm_release_focus(iw); } if (!Fexists(config_fname)) { printf ("\n** %s: **\n", config_fname); printf ("** There is no such file! **\n"); strcpy(config_fname, oldfname); return; } if (!Freadable(config_fname)) { printf ("\n** %s: **\n", config_fname); printf ("** This file is unreadable! **\n"); strcpy(config_fname, oldfname); return; } cr(); old_np = np; CLONE(symbol, SYMBOL_SIZE*np, char, old_symbol); i = CONFIG_LOAD (config_fname, Config_Aapp_to_Alib); for (k=0; k<CONFIG_num_auxiliary; k++) if (*blank_advance(CONFIG_auxiliary_name[k])==EOS) sprintf(CONFIG_auxiliary_name[k], "auxiliary%d", k); rebind_CT (Config_Aapp_to_Alib, "", ct, &tp); cr(); Neighborlist_Recreate_Form (Config_Aapp_to_Alib, ct, N); if (i == CONFIG_CFG_LOADED) N->s_overflow_err_handler = NEIGHBORLIST_S_OVERFLOW_ERR_HANDLER_FOLD_INTO_PBC; else N->s_overflow_err_handler = NEIGHBORLIST_S_OVERFLOW_ERR_HANDLER_BOUNDING_BOX; N->small_cell_err_handler = NEIGHBORLIST_SMALL_CELL_ERR_HANDLER_MULTIPLY; for (i=0; i<ct->t; i++) for (j=i; j<ct->t; j++) for (k=0; k<rcut_patch_top; k++) if ( ( ( (rcut_patch[k].Zi == ct->Z[i]) && (rcut_patch[k].Zj == ct->Z[j]) ) || ( (rcut_patch[k].Zi == ct->Z[j]) && (rcut_patch[k].Zj == ct->Z[i]) ) ) ) NEIGHBOR_TABLE(N->rcut,ct,i,j) = NEIGHBOR_TABLE(N->rcut,ct,j,i) = rcut_patch[k].rcut; Neighborlist_Recreate (Config_Aapp_to_Alib, stdout, ct, &tp, N); V3mM3 (hook_s, H, tmp); V3SUB (tmp, n[iw].hook, dx); V3EQV (tmp, n[iw].hook); V3AdD (dx, AX_3D[iw].x); M3InV (H, HI, volume); lengthscale = cbrt(volume); V3ASSIGN (0.5,0.5,0.5,tmp); V3mM3 (tmp, H, cm); geo_clear_has_evaluated_flags(); evaluate_geo_measures(); Free(s1); Free(mass); if ( ComputeLeastSquareStrain ) { if (ConfigChecksum(Config_Aapp_to_Alib) != ref->checksum) printf ("This configuration is not isoatomic with the imprinted " "reference\n%s. Least-square strain NOT calculated.\n", ref_fbasename); else LeastSquareStrain_Append(); } incompatible_config = (np != old_np) || memcmp(symbol, old_symbol, SYMBOL_SIZE*MIN(np,old_np)); Free(old_symbol); if (incompatible_config) Config_to_3D_Balls (n[iw].atom_r_ratio); else for (i=0; i<np; i++) V3mM3 ( &(s[DIMENSION*i]), H, B->BALL[i].x ); atom_xtal_origin (n[iw].xtal_origin); if (!n[iw].auxiliary_thresholds_rigid) { for (i=0; i<CONFIG_num_auxiliary; i++) reset_auxiliary_threshold(iw,i); for (i=0; i<MAX_GEO_MEASURES; i++) if (geolist[i].has_evaluated) reset_auxiliary_threshold(iw,CONFIG_MAX_AUXILIARY+i); } if (!temporary_disable_bond) Config_to_3D_Bonds (n[iw].bond_radius); select_fbasename (config_fname); if ((n[iw].xtal_mode) && (n[iw].color_mode == COLOR_MODE_COORD)) assign_coordination_color(iw); else if (n[iw].color_mode == COLOR_MODE_AUXILIARY) color_encode_auxiliary(iw); else if (n[iw].color_mode == COLOR_MODE_SCRATCH) scratch_color (iw); else { strcpy (AX_title[iw],fbasename); AXSetName (iw); XStoreName(AX_display[iw],xterm_win,AX_title[iw]); XSetIconName(AX_display[iw],xterm_win,AX_title[iw]); if (!temporary_disable_bond) { bond_xtal_origin_update (iw); bond_atom_color_update (iw); } } return; } /* end reload_config() */