diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 9e228b5..727a9cb 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -14,8 +14,9 @@ * Remove case sensitivity of xyz file inputs (#9) * Add CLI option to disable centering of molecules (#14) * Disable default rotation wrt inertia axis for z-matrix input and add a CLI option to force it (#14) -* Read molecules from the standard input -* Show infrared intensities and mode masses +* Read molecules from the standard input (#28) +* Show infrared intensities and mode masses (#35) +* Improve the text-in-corner look (de242c7, #36) * Improve data structures and code readability ### Fixes @@ -24,6 +25,7 @@ * Fix NaNs when compute dihedrals (#14) * Fix the "readagain" (`r`) and "readmore" (`tab`) bugs (#31) * Fix z-matrix input with unit=bohr (8554864) +* Fix text blinking when playing animation (80cae88, #36) ### Coming in the next version: * extended xyz (#16, #17) diff --git a/obj/v/ac3_print.d b/obj/v/ac3_print.d index 197fbc5..0ca5016 100644 --- a/obj/v/ac3_print.d +++ b/obj/v/ac3_print.d @@ -1,2 +1,2 @@ obj/v/ac3_print.o obj-pic/v/ac3_print.o: src/v/ac3_print.c src/v/v.h \ - src/mol/mol.h src/mol/common.h src/v/pars.h + src/mol/mol.h src/mol/common.h src/v/pars.h src/math/vec3.h diff --git a/obj/v/evr.d b/obj/v/evr.d index 540e7cf..349aa02 100644 --- a/obj/v/evr.d +++ b/obj/v/evr.d @@ -1,3 +1,3 @@ obj/v/evr.o obj-pic/v/evr.o: src/v/evr.c src/v/v.h src/mol/mol.h \ - src/mol/common.h src/v/pars.h src/v/x.h src/v/evr.h src/math/3d.h \ + src/mol/common.h src/v/pars.h src/v/evr.h src/math/3d.h \ src/math/matrix.h src/math/vecn.h src/math/vec3.h diff --git a/obj/v/redraw.d b/obj/v/redraw.d new file mode 100644 index 0000000..f33fa35 --- /dev/null +++ b/obj/v/redraw.d @@ -0,0 +1,3 @@ +obj/v/redraw.o obj-pic/v/redraw.o: src/v/redraw.c src/v/v.h src/mol/mol.h \ + src/mol/common.h src/v/pars.h src/v/evr.h src/math/3d.h \ + src/math/matrix.h src/math/vecn.h diff --git a/obj/v/x.d b/obj/v/x.d index a00fd1b..4491afd 100644 --- a/obj/v/x.d +++ b/obj/v/x.d @@ -1,3 +1,3 @@ obj/v/x.o obj-pic/v/x.o: src/v/x.c src/v/v.h src/mol/mol.h \ - src/mol/common.h src/v/pars.h src/v/x.h src/math/vec2.h \ - src/mol/palette_v.h src/mol/palette_cpk.h + src/mol/common.h src/v/pars.h src/v/x.h src/mol/palette_v.h \ + src/mol/palette_cpk.h diff --git a/python/vmol/main.py b/python/vmol/main.py index 3f1ea56..974a800 100644 --- a/python/vmol/main.py +++ b/python/vmol/main.py @@ -47,7 +47,6 @@ class vibr_t(ctypes.Structure): # noqa: N801 double * ints; double * disp; double * mass; - double * r0; int n; } vibr_t; ``` @@ -58,7 +57,6 @@ class vibr_t(ctypes.Structure): # noqa: N801 ("ints", c_double_p), ("disp", c_double_p), ("mass", c_double_p), - ("r0", c_double_p), ("n", c_int), ) @@ -399,13 +397,13 @@ def vib2struct(nat, vib=None): Returns: vibr_t: An instance of `vibr_t` with the fields set. If missing, the optional fields are set to 0, - and the `r0` is set to NULL. If the input dictionary is None, everything is set to 0/NULL. + If the input dictionary is None, everything is set to 0/NULL. Raises: TypeError: If mol is neither a dictionary nor None. """ if vib is None: - return vibr_t(n=c_int(0), disp=None, freq=None, ints=None, mass=None, r0=None) + return vibr_t(n=c_int(0), disp=None, freq=None, ints=None, mass=None) if not isinstance(vib, dict): msg = f"vib must be None or a dictionary, but got {type(vib)}" @@ -452,7 +450,7 @@ def check_array(key, required=True, shape=None, ndim=None, dtype=c_double): for key, val in vdict.items(): vdict[key] = val.ctypes.data_as(c_double_p) - v = vibr_t(n=nvib, disp=vdict['disp'], freq=vdict['freq'], ints=vdict['ints'], mass=vdict['mass'], r0=None) + v = vibr_t(n=nvib, disp=vdict['disp'], freq=vdict['freq'], ints=vdict['ints'], mass=vdict['mass']) v._keepalive = (nvib, vdict['disp'], vdict['freq'], vdict['ints'], vdict['mass']) # keep strong references return v diff --git a/src/math/3d.h b/src/math/3d.h index 04f9de9..d0fbe6b 100644 --- a/src/math/3d.h +++ b/src/math/3d.h @@ -2,10 +2,12 @@ #define DEG2RAD (M_PI/180.0) -void rotmx0_update(double mx[9], double mx1[9], double phi, int axis); -void rot3d (int n, double * r, double m[9]); +void rotmx0_update(double mx[9], double phi, int axis); +void rot3d(int n, double * v, const double * r, const double m[9]); +void rot3d_inplace(int n, double * r, const double m[9]); void rotmx (double * rot, double * u, double phi); void rot_around_perp(double rot[9], double dx, double dy, double factor); +void mx3_lmultmx(const double A[9], double B[9]); int zmat2cart(int n, double r[3], double a[3], double b[3], double c[3], diff --git a/src/math/matrix.c b/src/math/matrix.c index 76adf84..d2c49a1 100644 --- a/src/math/matrix.c +++ b/src/math/matrix.c @@ -11,7 +11,7 @@ void mx_id(unsigned int n, double * a){ } void mx_multmx(unsigned int m, unsigned int n, unsigned int q, - double * p, double * a, double * b){ + double * p, const double * a, const double * b){ /* a: m*n * b: n*q * p = ab: m*q diff --git a/src/math/matrix.h b/src/math/matrix.h index 3f71c0e..924ec96 100644 --- a/src/math/matrix.h +++ b/src/math/matrix.h @@ -15,7 +15,7 @@ static inline unsigned int mpos(unsigned int i, unsigned int j){ #endif void mx_id (unsigned int n, double * a); -void mx_multmx (unsigned int m, unsigned int n, unsigned int q, double * p, double * a, double * b); +void mx_multmx (unsigned int m, unsigned int n, unsigned int q, double * p, const double * a, const double * b); int mx_inv (unsigned int n, unsigned int r, double * b, double * a, double eps); void jacobi (double * a, double * b, double * d, unsigned int n, double eps, unsigned int rot, FILE * f); diff --git a/src/math/rot3d.c b/src/math/rot3d.c index 0310504..39ed53b 100644 --- a/src/math/rot3d.c +++ b/src/math/rot3d.c @@ -1,8 +1,7 @@ #include "3d.h" #include "vec3.h" -void rotmx0_update(double mx[9], double mx1[9], double phi, int axis){ - +void rotmx0_update(double mx[9], double phi, int axis){ double c = cos(phi); double s = sin(phi); double ms[3][9]={ @@ -10,15 +9,18 @@ void rotmx0_update(double mx[9], double mx1[9], double phi, int axis){ { c, 0.0, -s, 0.0, 1.0, 0.0, s, 0.0, c }, { c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0 } }; - veccp(9, mx1, ms[axis]); + mx3_lmultmx(ms[axis], mx); + return; +} - double mx0[9]; - veccp(9, mx0, mx); - mx_multmx(3,3,3, mx, mx1, mx0); +void rot3d(int n, double * v, const double * r, const double m[9]){ + for(int i=0; iread.fname, ap.ip.colors); init_keys(kp); init_font(ap.ip.fontname); -#if 0 - myDrawString = &XDrawString; -#else - myDrawString = &XDrawImageString; -#endif -#if 0 - canv = win; -#else - canv = px; -#endif /*= Main loop ==============================================================*/ main_loop(ent, dp, kp); diff --git a/src/v/ac3_draw.c b/src/v/ac3_draw.c index 657dcbe..d06b405 100644 --- a/src/v/ac3_draw.c +++ b/src/v/ac3_draw.c @@ -2,17 +2,11 @@ #include "x.h" #define EPS 1e-15 -#define BOND_OFFSET 0.666 // bond line starts this fraction of the atom radius away from the atom center -#define RESOL_SCALE (128.0/768.0) // reference resolution for atom sizes +#define BOND_OFFSET 0.666 // bond line starts this fraction of the atom radius away from the atom center +#define RESOL_SCALE (128.0/768.0) // reference resolution for atom sizes +#define XDRAWSTRING XDrawImageString // change to XDrawString to remove white boxes behind atom/bond labels -extern int W,H; -extern int screen; -extern Display * dis; -extern GC gc_white, gc_black, gc_dot[2], gcc[NCOLORS]; -extern Window win; -extern Pixmap px; -extern Drawable canv; -extern int (*myDrawString)(); +extern draw_world_t world; static inline int getgci(int q){ return abs(q)n; kzstr * kz = malloc(sizeof(kzstr)*n); int * ks = (rend.bonds>0) ? malloc(sizeof(int)*n) : NULL; - double d = MIN(H,W) * rend.scale; - double resol = MIN(H,W) * RESOL_SCALE; + double resol = world.size * RESOL_SCALE; double r1 = rend.r * resol * rend.scale; for(int k=0; kq[k]); int r = MAX(1, rt); - XFillArc (dis, canv, gcc[getgci(q)], x-r, y-r, 2*r, 2*r, 0, 360*64); + XFillArc (world.dis, world.canv, world.gcc[getgci(q)], x-r, y-r, 2*r, 2*r, 0, 360*64); if(r>1){ - XDrawArc(dis, canv, q>0?gc_black:gc_dot[1], x-r, y-r, 2*r, 2*r, 0, 360*64); + XDrawArc(world.dis, world.canv, q>0?world.gc_black:world.gc_dot[1], x-r, y-r, 2*r, 2*r, 0, 360*64); } if(rend.num == 1){ char text[16]; snprintf(text, sizeof(text), "%d", k+1); - myDrawString(dis, canv, gc_black, x, y, text, strlen(text)); + XDRAWSTRING(world.dis, world.canv, world.gc_black, x, y, text, strlen(text)); } else if(rend.num == -1){ char text[16]; const char * s = getname(q); s ? snprintf(text, sizeof(text), "%s", s) : snprintf(text, sizeof(text), "%d", q ); - myDrawString(dis, canv, gc_black, x, y, text, strlen(text)); + XDRAWSTRING(world.dis, world.canv, world.gc_black, x, y, text, strlen(text)); } if(rend.bonds>0){ @@ -104,19 +91,17 @@ void ac3_draw(atcoord * ac, rendpars rend){ continue; } double dd = BOND_OFFSET * r / sqrt(r2d); - XDrawLine(dis, canv, gc_black, x+dd*dx, y+dd*dy, x1, y1); + XDrawLine(world.dis, world.canv, world.gc_black, x+dd*dx, y+dd*dy, x1, y1); if(rend.bonds==2){ char text[16]; snprintf(text, sizeof(text), "%.3lf", ac->bonds.r[j]); - myDrawString(dis, canv, gc_black, x+dx/2, y+dy/2, text, strlen(text)); + XDRAWSTRING(world.dis, world.canv, world.gc_black, x+dx/2, y+dy/2, text, strlen(text)); } } } - } free(kz); free(ks); - FILLCANV; return; } diff --git a/src/v/ac3_print.c b/src/v/ac3_print.c index 470783e..64a9d1d 100644 --- a/src/v/ac3_print.c +++ b/src/v/ac3_print.c @@ -1,4 +1,5 @@ #include "v.h" +#include "vec3.h" void ac3_print(atcoord * ac, rendpars rend){ PRINTOUT(stdout, "$molecule\ncart\n"); @@ -42,8 +43,7 @@ void ac3_print_xyz(atcoord * ac, rendpars rend){ return; } -void ac3_print2fig(atcoord * ac, rendpars rend, double * v){ - +void ac3_print2fig(atcoord * ac, rendpars rend, double vert[9]){ int n = ac->n; for(int i=0; iq[i], @@ -52,12 +52,12 @@ void ac3_print2fig(atcoord * ac, rendpars rend, double * v){ ac->r[i*3+2]); } - if(v){ + if(vert){ for(int i=0; i<8; i++){ + double v[3]; + r3mx(v, vert+3*i, rend.ac3rmx); PRINTOUT(stdout, "atom %3d% 13.7lf% 13.7lf% 13.7lf\n", 0, - rend.xy0[0] + v[i*3 ], - rend.xy0[1] + v[i*3+1], - v[i*3+2]); + rend.xy0[0] + v[0], rend.xy0[1] + v[1], v[2]); } } @@ -75,7 +75,7 @@ void ac3_print2fig(atcoord * ac, rendpars rend, double * v){ } } - if(v){ + if(vert){ #define LINE(I,J) PRINTOUT(stdout, "bond %3d %3d % 3d\n", (J)+n+1, (I)+n+1, -1) for(int i=0; i<8; i+=2){ LINE(i,i+1); // || z-axis diff --git a/src/v/ac3_read.c b/src/v/ac3_read.c index daf57e9..18e081b 100644 --- a/src/v/ac3_read.c +++ b/src/v/ac3_read.c @@ -7,21 +7,24 @@ atcoord * atcoord_fill(mol * m0, int b, const geompars geom){ size_t q_size = sizeof(int ) * n; size_t r_size = sizeof(double) * n*3; + size_t r0_size = sizeof(double) * n*3; struct {size_t r_size; size_t a_size;} bonds = {0, 0}; if(b!=-1){ bonds.a_size = sizeof(int ) * n*BONDS_MAX; bonds.r_size = sizeof(double) * n*BONDS_MAX; } - size_t size = sizeof(atcoord) + q_size + r_size + bonds.a_size + bonds.r_size; + size_t size = sizeof(atcoord) + q_size + r_size + r0_size + bonds.a_size + bonds.r_size; atcoord * m = calloc(size, 1); if(b==-1){ m->r = (double *) (m + 1); - m->q = (int *) MEM_END(m,r); + m->r0 = (double *) MEM_END(m,r); + m->q = (int *) MEM_END(m,r0); } else{ m->r = (double *) (m + 1); - m->bonds.r = (double *) MEM_END(m,r); + m->r0 = (double *) MEM_END(m,r); + m->bonds.r = (double *) MEM_END(m,r0); m->q = (int *) MEM_END(m,bonds.r); m->bonds.a = (int *) MEM_END(m,q); } @@ -30,20 +33,20 @@ atcoord * atcoord_fill(mol * m0, int b, const geompars geom){ m->fname = m0->name; for(int i=0; iq[i] = m0->q[i]; - r3cp(m->r+i*3, m0->r+i*3); } + veccp(n*3, m->r, m0->r); if(geom.bohr){ vecscal(n*3, m->r, BA); } if(geom.inertia){ - // should not change m0 + // we should not change m0 position(&((mol){.n=n, .q=m->q, .r=m->r}), NULL, 1); } if(geom.center){ center_mol(n, m->r, geom.center==2 ? m->q : NULL); } - + veccp(n*3, m->r0, m->r); return m; } diff --git a/src/v/evr.c b/src/v/evr.c index 04d15ce..f502917 100644 --- a/src/v/evr.c +++ b/src/v/evr.c @@ -1,76 +1,18 @@ #include "v.h" -#include "x.h" #include "evr.h" #include "vec3.h" - -#define EPS_INV 1e-15 - -static const double step_rot = M_PI/90.0; -static const double step_move = 0.2; -static const double step_zoom = 1.1; -static const double step_r = 1.1; -static const double step_mod = 0.03125; -static const double rl_move_pbc_scale = 0.9; -static const double vibration_amplitude = 0.1; - -static void redraw_ac3(object * ent, drawpars * dp){ - atcoord * ac = ent->m[dp->n]; - - if(dp->rend.bonds>0){ - bonds_fill(dp->bond, ac); - } - - ac3_draw(ac, dp->rend); - ac3_text(ac, dp); - - if(dp->cell.vert == 1){ - double v[24]; - for(int i=0; i<8; i++){ - r3mx (v+3*i, dp->cell.vertices+3*i, dp->rend.ac3rmx); - } - drawvertices(v, dp->rend.scale, dp->rend.xy0); - } - else if(dp->cell.vert == 2){ - drawshell(dp->cell.vertices[0], dp->cell.vertices[1], dp->rend.scale, dp->rend.xy0); - } - - return; -} - -static void redraw_vibro(object * ent, drawpars * dp){ - - atcoord * m = ent->m[0]; - double * r0 = ent->vib->r0; - double * dr = ent->vib->disp + dp->n * m->n*3; - - if(dp->rend.bonds>0){ - bonds_fill(dp->bond, m); - } - - vecsums(m->n*3, m->r, r0, dr, sin( dp->anim.t * 2.0*M_PI/TMAX ) * vibration_amplitude*sqrt(m->n) ); - for(int j=0; jn; j++){ - double v[3]; - r3mx(v, m->r+3*j, dp->rend.ac3rmx); - r3cp(m->r+3*j, v); - } - - ac3_draw(m, dp->rend); - vibro_text(ent->vib, dp); - - return; -} +#include "3d.h" void kp_readmore(object * ent, drawpars * dp){ if(dp->task == AT3COORDS){ - object * acs = ent; if(!dp->read.f){ PRINT_ERR("cannot read from the file '%s'\n", dp->read.fname); return; } fseek(dp->read.f, 0, SEEK_CUR); - acs_readmore(dp->read, dp->rend.bonds, dp->geom, acs); - newmol_prep(acs, dp); - redraw_ac3 (acs, dp); + acs_readmore(dp->read, dp->rend.bonds, dp->geom, ent); + dp->N = ent->n; + redraw_ac3 (ent, dp); } return; } @@ -83,31 +25,27 @@ void kp_readagain(object * ent, drawpars * dp){ return; } - object * acs = ent; - for(int i=0; in; i++){ - free(acs->m[i]); + for(int i=0; in; i++){ + free(ent->m[i]); } - acs->n = dp->N = dp->n = 0; - - acs_readmore(dp->read, dp->rend.bonds, dp->geom, acs); - newmol_prep(acs, dp); - redraw_ac3 (acs, dp); + ent->n = dp->N = dp->n = 0; + acs_readmore(dp->read, dp->rend.bonds, dp->geom, ent); + dp->N = ent->n; + redraw_ac3 (ent, dp); } return; } void kp_print(object * ent, drawpars * dp){ if (dp->task == AT3COORDS){ - atcoord * ac = ent->m[dp->n]; - ac3_print(ac, dp->rend); + ac3_print(ent->m[dp->n], dp->rend); } return; } void kp_print_xyz(object * ent, drawpars * dp){ if (dp->task == AT3COORDS){ - atcoord * ac = ent->m[dp->n]; - ac3_print_xyz(ac, dp->rend); + ac3_print_xyz(ent->m[dp->n], dp->rend); } return; } @@ -124,14 +62,7 @@ void kp_printrot(object * ent __attribute__ ((unused)), drawpars * dp){ void kp_print2fig(object * ent, drawpars * dp){ if (dp->task == AT3COORDS){ - double v[3*8]; - if(dp->cell.vert == 1){ - for(int i=0; i<8; i++){ - r3mx (v+3*i, dp->cell.vertices+3*i, dp->rend.ac3rmx); - } - } - atcoord * ac = ent->m[dp->n]; - ac3_print2fig(ac, dp->rend, dp->cell.vert==1?v:NULL); + ac3_print2fig(ent->m[dp->n], dp->rend, dp->cell.vert==1?dp->cell.vertices:NULL); } return; } @@ -146,7 +77,7 @@ static void rl_changed(object * ent, drawpars * dp){ void kp_rl_dec(object * ent, drawpars * dp){ if(dp->rend.bonds>0){ - dp->bond.rl /= step_r; + dp->bond.rl /= STEP_R; rl_changed(ent, dp); } return; @@ -154,32 +85,32 @@ void kp_rl_dec(object * ent, drawpars * dp){ void kp_rl_inc(object * ent, drawpars * dp){ if(dp->rend.bonds>0){ - dp->bond.rl *= step_r; + dp->bond.rl *= STEP_R; rl_changed(ent, dp); } return; } void kp_r_dec(object * ent, drawpars * dp){ - dp->rend.r /= step_r; + dp->rend.r /= STEP_R; exp_redraw(ent, dp); return; } void kp_r_inc(object * ent, drawpars * dp){ - dp->rend.r *= step_r; + dp->rend.r *= STEP_R; exp_redraw(ent, dp); return; } void kp_zoom_out(object * ent, drawpars * dp){ - dp->rend.scale /= step_zoom; + dp->rend.scale /= STEP_ZOOM; exp_redraw(ent, dp); return; } void kp_zoom_in(object * ent, drawpars * dp){ - dp->rend.scale *= step_zoom; + dp->rend.scale *= STEP_ZOOM; exp_redraw(ent, dp); return; } @@ -206,83 +137,66 @@ void kp_frame_dec(object * ent, drawpars * dp){ return; } -void rot_ent_pointer(object * ent, drawpars * dp, int dx, int dy, double speed){ - - double rotation_matrix[9]; - rot_around_perp(rotation_matrix, (double)dx, (double)dy, speed); - - double mx0[9]; - veccp(9, mx0, dp->rend.ac3rmx); - mx_multmx(3,3,3, dp->rend.ac3rmx, rotation_matrix, mx0); - if(dp->task == AT3COORDS){ - object * acs = ent; - for(int i=0; iN; i++){ - rot3d(acs->m[i]->n, acs->m[i]->r, rotation_matrix); - } +void rot_ent_pointer(object * ent __attribute__ ((unused)), drawpars * dp, int dx, int dy, double speed){ + double mx[9]; + rot_around_perp(mx, (double)dx, (double)dy, speed); + mx3_lmultmx(mx, dp->rend.ac3rmx); + for(int i=0; in; i++){ + ent->m[i]->rotated = 0; } return; } -static void rot_ent(object * ent, drawpars * dp, int axis, double angle){ +static void rot_ent(object * ent __attribute__ ((unused)), drawpars * dp, int axis, double angle){ if(dp->ui.modkey){ - angle *= step_mod; + angle *= STEP_MOD; } - - double m[9]; - rotmx0_update(dp->rend.ac3rmx, m, angle, axis); - - if(dp->task == AT3COORDS){ - object * acs = ent; - for(int i=0; iN; i++){ - rot3d(acs->m[i]->n, acs->m[i]->r, m); - } + rotmx0_update(dp->rend.ac3rmx, angle, axis); + for(int i=0; in; i++){ + ent->m[i]->rotated = 0; } return; } void kp_rotx_l(object * ent, drawpars * dp){ - rot_ent(ent, dp, 0, +step_rot); + rot_ent(ent, dp, 0, +STEP_ROT); exp_redraw(ent, dp); return; } void kp_rotx_r(object * ent, drawpars * dp){ - rot_ent(ent, dp, 0, -step_rot); + rot_ent(ent, dp, 0, -STEP_ROT); exp_redraw(ent, dp); return; } void kp_roty_l(object * ent, drawpars * dp){ - rot_ent(ent, dp, 1, +step_rot); + rot_ent(ent, dp, 1, +STEP_ROT); exp_redraw(ent, dp); return; } void kp_roty_r(object * ent, drawpars * dp){ - rot_ent(ent, dp, 1, -step_rot); + rot_ent(ent, dp, 1, -STEP_ROT); exp_redraw(ent, dp); return; } void kp_rotz_l(object * ent, drawpars * dp){ - rot_ent(ent, dp, 2, +step_rot); + rot_ent(ent, dp, 2, +STEP_ROT); exp_redraw(ent, dp); return; } void kp_rotz_r(object * ent, drawpars * dp){ - rot_ent(ent, dp, 2, -step_rot); + rot_ent(ent, dp, 2, -STEP_ROT); exp_redraw(ent, dp); return; } -static void mol2cell(double r0[3], drawpars * dp){ - double mat[9], r[3]; - veccp(9, mat, dp->rend.ac3rmx); - r3cp(r, r0); - mx_inv (3, 1, r, mat, EPS_INV); +static void mol2cell(double r[3], cellpars * cell){ double rcell[3]; - r3mx(rcell, r, dp->cell.rot_to_cell_basis); + r3mx(rcell, r, cell->rot_to_cell_basis); for(int i=0; i<3; i++){ if(rcell[i]<-0.5){ rcell[i] += 1.0; @@ -291,21 +205,28 @@ static void mol2cell(double r0[3], drawpars * dp){ rcell[i] -= 1.0; } } - r3mx(r, rcell, dp->cell.rot_to_lab_basis); - r3mx(r0, r, dp->rend.ac3rmx); + r3mx(r, rcell, cell->rot_to_lab_basis); return; } static void move_pbc(object * acs, drawpars * dp, int dir, double d){ - for(int i=0; iN; i++){ - for(int j=0; jm[i]->n; j++){ - double * r = acs->m[i]->r+j*3; - r[dir] += d; - mol2cell(r, dp); + + double dr[3], v[3] = {}; + v[dir] = d; // translation in the view basis + r3mxt(dr, v, dp->rend.ac3rmx); // translation in the mol basis. + // not true if the initial "rotation" from CLI is not unitary, but ignore this + for(int i=0; in; i++){ + atcoord * m = acs->m[i]; + for(int j=0; jn; j++){ + double * r = m->r0+j*3; + r3add(r, dr); + mol2cell(r, &dp->cell); + r3cp(m->r+j*3, r); + m->rotated = 0; } if(dp->rend.bonds>0){ - acs->m[i]->bonds.flag = 0; - acs->m[i]->bonds.rl *= rl_move_pbc_scale; + m->bonds.flag = 0; + m->bonds.rl *= RL_MOVE_PBC_SCALE; } } return; @@ -313,7 +234,7 @@ static void move_pbc(object * acs, drawpars * dp, int dir, double d){ static void move_ent(object * ent, drawpars * dp, int dir, double step){ if(dp->ui.modkey){ - step *= step_mod; + step *= STEP_MOD; } if(dp->cell.vert == 1){ move_pbc(ent, dp, dir, step); @@ -325,25 +246,25 @@ static void move_ent(object * ent, drawpars * dp, int dir, double step){ } void kp_move_l(object * ent, drawpars * dp){ - move_ent(ent, dp, 0, -step_move); + move_ent(ent, dp, 0, -STEP_MOVE); exp_redraw(ent, dp); return; } void kp_move_r(object * ent, drawpars * dp){ - move_ent(ent, dp, 0, +step_move); + move_ent(ent, dp, 0, +STEP_MOVE); exp_redraw(ent, dp); return; } void kp_move_u(object * ent, drawpars * dp){ - move_ent(ent, dp, 1, +step_move); + move_ent(ent, dp, 1, +STEP_MOVE); exp_redraw(ent, dp); return; } void kp_move_d(object * ent, drawpars * dp){ - move_ent(ent, dp, 1, -step_move); + move_ent(ent, dp, 1, -STEP_MOVE); exp_redraw(ent, dp); return; } @@ -440,11 +361,11 @@ static void savevib(drawpars * dp, int c){ char s[STRLEN]; int l = (int)(log10( dp->N + 0.5 )) + 1; snprintf(s, sizeof(s), "%s_%0*d_%02d.xpm", dp->read.fname, l, dp->n+1, c); - if (savepic(s) != XpmSuccess){ - PRINT_ERR("cannot save '%s'\n", s); + if(savepic(s)){ + fprintf(stderr, "%s\n", s); } else{ - fprintf(stderr, "%s\n", s); + PRINT_ERR("cannot save '%s'\n", s); } return; } @@ -454,11 +375,11 @@ void kp_savepic(object * ent __attribute__ ((unused)), drawpars * dp){ int l = (int)(log10(dp->N+0.5))+1; atcoord * ac = ent->m[dp->n]; snprintf(s, sizeof(s), "%s_%0*d.xpm", ac->fname, l, dp->n+1); - if (savepic(s) != XpmSuccess){ - PRINT_ERR("cannot save '%s'\n", s); + if(savepic(s)){ + fprintf(stderr, "%s\n", s); } else{ - fprintf(stderr, "%s\n", s); + PRINT_ERR("cannot save '%s'\n", s); } return; } diff --git a/src/v/evr.h b/src/v/evr.h index 949e32d..c311015 100644 --- a/src/v/evr.h +++ b/src/v/evr.h @@ -1,5 +1,28 @@ #include "3d.h" + #define TMAX 20 +#define VIBR_AMP 0.1 +#define STEP_ROT (M_PI/90.0) +#define STEP_MOVE 0.2 +#define STEP_ZOOM 1.1 +#define STEP_R 1.1 +#define STEP_MOD 0.03125 +#define RL_MOVE_PBC_SCALE 0.9 + +static inline void fill_bonds(atcoord * m, drawpars * dp){ + if(dp->rend.bonds>0){ + bonds_fill(dp->bond, m); + } + return; +} + +static inline void rotate_mol(atcoord * m, drawpars * dp){ + if(!m->rotated){ + rot3d(m->n, m->r, m->r0, dp->rend.ac3rmx); + m->rotated = 1; + } + return; +} void kp_readmore (object * ent, drawpars * dp); void kp_readagain(object * ent, drawpars * dp); diff --git a/src/v/headless.c b/src/v/headless.c index 485ad84..b4a07ee 100644 --- a/src/v/headless.c +++ b/src/v/headless.c @@ -48,10 +48,8 @@ void run_commands(FILE * f, char * command, drawpars * dp, object * ent){ } int headless(drawpars * dp, object * ent){ - atcoord * ac = ent->m[dp->n]; - if(dp->rend.bonds>0){ - bonds_fill(dp->bond, ac); - } + fill_bonds(ent->m[dp->n], dp); + rotate_mol(ent->m[dp->n], dp); run_commands(stdin, dp->ui.com, dp, ent); obj_free(ent); CLOSE0(dp->read.f); diff --git a/src/v/load.c b/src/v/load.c index 2246d2c..d211db9 100644 --- a/src/v/load.c +++ b/src/v/load.c @@ -49,30 +49,32 @@ void acs_readmore(readpars read, int b, geompars geom, object * acs){ return; } -static object * mode_read_try(FILE * f, atcoord * ac){ +static object * mode_read_try(FILE * f, object * ent, drawpars * dp){ long pos = ftell(f); rewind(f); + atcoord * m = ent->m[ent->n-1]; + vibr_t * vib = mode_read(f, m->n); - int n = ac->n; - vibr_t * modes = mode_read(f, n); - - if(modes){ - object * ent = malloc(sizeof(object)); - ent->Nmem = ent->n = 1; - ent->m = malloc(ent->Nmem*sizeof(atcoord *)); - ent->m[0] = ac; - ent->vib = modes; - veccp(n*3, ent->vib->r0, ac->r); - return ent; - } - else{ + if(!vib){ fseek(f, pos, SEEK_SET); return NULL; } + else{ + for(int i=0; in-1; i++){ + free(ent->m[i]); + } + ent->Nmem = ent->n = 1; + ent->m = realloc(ent->m, sizeof(atcoord *)); + ent->m[0] = m; + ent->vib = vib; + dp->rend.scale = ac3_scale(m); + dp->N = vib->n; + return ent; + } } -static FILE * acs_read_newfile(object * acs, char * fname, drawpars * dp){ +static FILE * acs_read_newfile(char * fname, object * acs, drawpars * dp){ FILE * f; if(!strcmp(fname, "-")){ f = stdin; @@ -95,7 +97,7 @@ static object * ent_read(char * fname, drawpars * dp){ acs->m = NULL; acs->vib = NULL; - FILE * f = acs_read_newfile(acs, fname, dp); + FILE * f = acs_read_newfile(fname, acs, dp); if(!f || !acs->n){ free(acs); return NULL; @@ -103,13 +105,9 @@ static object * ent_read(char * fname, drawpars * dp){ dp->read.fname = fname; if(dp->task==UNKNOWN || dp->task==VIBRO){ - object * vib = mode_read_try(f, acs->m[acs->n-1]); + object * vib = mode_read_try(f, acs, dp); if(vib){ - acs->n--; - obj_free(acs); fclose(f); - dp->rend.scale = ac3_scale(vib->m[0]); - dp->N = vib->vib->n; dp->task = VIBRO; return vib; } @@ -145,7 +143,7 @@ object * read_files(allpars * ap){ object * acs = ent; int n0 = acs->n; for(i++; irend.scale = acs_scale(acs); - newmol_prep(acs, dp); + dp->N = acs->n; intcoord_check(INT_MAX, dp->anal.intcoord); } else{ @@ -198,7 +196,7 @@ object * acs_from_var(int n, mol * m, vibr_t vib, allpars * ap){ fill_nf(ent, 0); dp->rend.scale = acs_scale(ent); - newmol_prep(ent, dp); + dp->N = ent->n; int natmax = 0; for(int i=0; im[0] = atcoord_fill(m+n-1, dp->rend.bonds, dp->geom); int nat = ent->m[0]->n; ent->vib = make_vibr_t(vib.n, nat); - veccp(nat*3, ent->vib->r0, ent->m[0]->r); veccp(vib.n*nat*3, ent->vib->disp, vib.disp); veccp(vib.n, ent->vib->freq, vib.freq); veccp(vib.n, ent->vib->ints, vib.ints); diff --git a/src/v/loop.c b/src/v/loop.c index 1dd4971..667f251 100644 --- a/src/v/loop.c +++ b/src/v/loop.c @@ -4,9 +4,7 @@ #define VIBRO_SUBSTEPS 4 -extern int W,H; -extern Display * dis; -extern Window win; +extern draw_world_t world; typedef struct { int click; @@ -18,7 +16,7 @@ static void process_mouse(XMotionEvent * event, object * ent, drawpars * dp, mou if(mouse->click){ int x = event->x; int y = event->y; - rot_ent_pointer(ent, dp, x-mouse->x0, y-mouse->y0, POINTER_SPEED/MIN(W,H)); + rot_ent_pointer(ent, dp, x-mouse->x0, y-mouse->y0, POINTER_SPEED/world.size); exp_redraw(ent, dp); mouse->x0 = x; mouse->y0 = y; @@ -71,8 +69,8 @@ static void run_animation(object * ent, drawpars * dp, int * tr){ void main_loop(object * ent, drawpars * dp, ptf kp[NKP]){ // To handle window closing. Thanks to https://stackoverflow.com/a/1186544 - Atom wm_delete_window = XInternAtom(dis, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dis, win, &wm_delete_window, 1); + Atom wm_delete_window = XInternAtom(world.dis, "WM_DELETE_WINDOW", False); + XSetWMProtocols(world.dis, world.win, &wm_delete_window, 1); mouse_state_t mouse = {.click=0, .x0=0, .y0=0}; int tr = 0; @@ -80,7 +78,7 @@ void main_loop(object * ent, drawpars * dp, ptf kp[NKP]){ XEvent event_rec; XEvent * event = NULL; do{ - XNextEvent(dis, &event_rec); + XNextEvent(world.dis, &event_rec); #if 0 printf("%d\n", event_rec.type); #endif @@ -90,7 +88,7 @@ void main_loop(object * ent, drawpars * dp, ptf kp[NKP]){ if(event->type == ButtonPress || event->type == ButtonRelease){ break; } - } while(XEventsQueued(dis, QueuedAlready)); + } while(XEventsQueued(world.dis, QueuedAlready)); if (event->type == ClientMessage) { if ((Atom)event->xclient.data.l[0] == wm_delete_window) { @@ -103,8 +101,9 @@ void main_loop(object * ent, drawpars * dp, ptf kp[NKP]){ } else if(event->type == ConfigureNotify){ - W = event->xconfigure.width; - H = event->xconfigure.height; + world.W = event->xconfigure.width; + world.H = event->xconfigure.height; + world.size = MIN(world.H, world.W); dp->rend.xy0[0] = dp->rend.xy0[1] = 0.0; exp_redraw(ent, dp); } diff --git a/src/v/mode_read.c b/src/v/mode_read.c index 6723b93..90e257e 100644 --- a/src/v/mode_read.c +++ b/src/v/mode_read.c @@ -9,15 +9,13 @@ vibr_t * make_vibr_t(int n_modes, int n_atoms){ size_t freq_size = sizeof(double) * n_modes; size_t ints_size = sizeof(double) * n_modes; size_t mass_size = sizeof(double) * n_modes; - size_t r0_size = sizeof(double) * n_atoms*3; size_t disp_size = sizeof(double) * n_modes*n_atoms*3; - size_t size = sizeof(vibr_t) + freq_size + r0_size + disp_size + ints_size + mass_size; + size_t size = sizeof(vibr_t) + freq_size + disp_size + ints_size + mass_size; vibr_t * v = malloc(size); v->n = n_modes; v->freq = (double *) (v + 1); v->disp = (double *) MEM_END(v,freq); - v->r0 = (double *) MEM_END(v,disp); - v->ints = (double *) MEM_END(v,r0); + v->ints = (double *) MEM_END(v,disp); v->mass = (double *) MEM_END(v,ints); return v; } diff --git a/src/v/pars.h b/src/v/pars.h index a347ec1..a536b12 100644 --- a/src/v/pars.h +++ b/src/v/pars.h @@ -10,11 +10,11 @@ typedef enum { } colorscheme_t; typedef struct { + colorscheme_t colors; // colorscheme (v or cpk) int gui; // if gui is enabled - char * fontname; // font int input_files_n; // number of input files + char * fontname; // font char ** input_files; // input files - colorscheme_t colors; // colorscheme (v or cpk) } initpars; typedef struct { @@ -28,13 +28,12 @@ typedef struct { int bohr; // 0: Å 1: Bohr } geompars; - typedef struct { - int closed; // 1: time to go + char input_text[STRLEN]; char * com; // command string for gui:0 char * on_exit; // command string to run on exit - int input; // 0=no input regime, 1=jump, ... - char input_text[STRLEN]; + int closed; // 1: time to go + int input; // 0=no input regime, 1=jump, ... int modkey; // whether ctrl or shift are pressed } uipars; diff --git a/src/v/redraw.c b/src/v/redraw.c new file mode 100644 index 0000000..190b134 --- /dev/null +++ b/src/v/redraw.c @@ -0,0 +1,112 @@ +#include "v.h" +#include "evr.h" + +static void ac3_text(atcoord * ac, drawpars * dp){ + char text[32]; + char text_fname[STRLEN]; + char text_input[STRLEN]; + char text_coord[STRLEN]; + char text_point[32]; + + const char * lines[MAX_LINES] = {}; + int lines_red[MAX_LINES] = {}; + + int il=0; + snprintf(text, sizeof(text), "%*d / %d", 1+(int)(log10(dp->N)), dp->n+1, dp->N); + lines[il++] = text; + + if(ac->nf[1]==dp->N){ + lines[il++] = dp->read.fname; + } + else{ + snprintf(text_fname, sizeof(text_fname), "%s (%*d / %d)", ac->fname, 1+(int)(log10(ac->nf[1])), ac->nf[0]+1, ac->nf[1]); + lines[il++] = text_fname; + } + + if(dp->anal.intcoord[0]){ + double z = intcoord_calc(1, ac->n, dp->anal.intcoord, ac->r); + switch(dp->anal.intcoord[0]){ + case 1: + snprintf(text_coord, sizeof(text_coord), "bond %d-%d: %.3lf", dp->anal.intcoord[1], dp->anal.intcoord[2], z); + break; + case 2: + snprintf(text_coord, sizeof(text_coord), "angle %d-%d-%d: %.1lf", dp->anal.intcoord[1], dp->anal.intcoord[2], dp->anal.intcoord[3], z); + break; + case 3: + snprintf(text_coord, sizeof(text_coord), "dihedral %d-%d-%d-%d: % .1lf", dp->anal.intcoord[1], dp->anal.intcoord[2], dp->anal.intcoord[3], dp->anal.intcoord[4], z); + break; + default: + break; + } + lines[il++] = text_coord; + } + + if(ac->sym[0]){ + snprintf(text_point, sizeof(text_point), "point group: %s", ac->sym); + lines[il++] = text_point; + } + + if(dp->ui.input==1){ + snprintf(text_input, sizeof(text_input), "JUMP TO >>> %s", dp->ui.input_text); + lines_red[il] = 1; + lines[il++] = text_input; + } + + textincorner(lines, lines_red); + setcaption(ac->fname); + return; +} + +void vibro_text(vibr_t * ms, drawpars * dp){ + char text[STRLEN], text_inp[STRLEN]; + const char * lines[MAX_LINES] = {[0] = text, [1] = dp->read.fname}; + const int lines_red[MAX_LINES] = {[2] = 1}; + + double fq = ms->freq[dp->n]; + char i = fq > 0.0 ? ' ' : 'i'; + snprintf(text, sizeof(text), + "%*d / %d freq = %.1lf%c cm-1 int = %.1lf km/mole mass = %.1lf amu", + 1+(int)(log10(ms->n)), dp->n+1, ms->n, fabs(fq), i, ms->ints[dp->n], ms->mass[dp->n]); + if(dp->ui.input==1){ + snprintf(text_inp, sizeof(text_inp), "JUMP TO >>> %s", dp->ui.input_text); + lines[2] = text_inp; + } + textincorner(lines, lines_red); + return; +} + +void redraw_ac3(object * ent, drawpars * dp){ + atcoord * m = ent->m[dp->n]; + fill_bonds(m, dp); + rotate_mol(m, dp); + + clear_canv(); + ac3_draw(m, dp->rend); + ac3_text(m, dp); + if(dp->cell.vert == 1){ + double v[8*3]; + rot3d(8, v, dp->cell.vertices, dp->rend.ac3rmx); + drawvertices(v, dp->rend); + } + else if(dp->cell.vert == 2){ + drawshell(dp->cell.vertices, dp->rend); + } + fill_canv(); + return; +} + +void redraw_vibro(object * ent, drawpars * dp){ + + atcoord * m = ent->m[0]; + double * dr = ent->vib->disp + dp->n * m->n*3; + + fill_bonds(m, dp); + vecsums(m->n*3, m->r, m->r0, dr, VIBR_AMP*sqrt(m->n)*sin(dp->anim.t * 2.0*M_PI/TMAX)); + rot3d_inplace(m->n, m->r, dp->rend.ac3rmx); + + clear_canv(); + ac3_draw(m, dp->rend); + vibro_text(ent->vib, dp); + fill_canv(); + return; +} diff --git a/src/v/tools.c b/src/v/tools.c index d186adf..d700545 100644 --- a/src/v/tools.c +++ b/src/v/tools.c @@ -13,65 +13,6 @@ void obj_free(object * ent){ return; } -void newmol_prep(object * acs, drawpars * dp){ - for(int j=dp->N; jn; j++){ - atcoord * ac = acs->m[j]; - for(int i=0; in; i++){ - double v[3]; - r3mx(v, ac->r+3*i, dp->rend.ac3rmx); - r3cp(ac->r+3*i, v); - } - } - dp->N = acs->n; - return; -} - -void ac3_text(atcoord * ac, drawpars * dp){ - char text[STRLEN]; - int tp = snprintf(text, sizeof(text), - "%*d / %d r = %.1lf rl = %.1lf", - 1+(int)(log10(dp->N)), dp->n+1, dp->N, dp->rend.r, dp->bond.rl); - if( tpanal.intcoord[0] ){ - tp += snprintf(text+tp, sizeof(text)-tp, " | %d,%d,%d,%d,%d: %lf", dp->anal.intcoord[0], dp->anal.intcoord[1], dp->anal.intcoord[2], dp->anal.intcoord[3], dp->anal.intcoord[4], intcoord_calc(1, ac->n, dp->anal.intcoord, ac->r)); - } - if( tpsym[0] ){ - tp += snprintf(text+tp, sizeof(text)-tp, " | PG: %s", ac->sym); - } - if(ac->nf[1]==dp->N){ - textincorner(text, ac->fname); - } - else{ - char text2[STRLEN]; - snprintf(text2, sizeof(text2), "%s (%*d / %d)", ac->fname, 1+(int)(log10(ac->nf[1])), ac->nf[0]+1, ac->nf[1]); - textincorner(text, text2); - } - - if(dp->ui.input==1){ - char text3[STRLEN]; - snprintf(text3, sizeof(text3), "JUMP TO >>> %s", dp->ui.input_text); - textincorner2(text3); - } - - setcaption(ac->fname); - return; -} - -void vibro_text(vibr_t * ms, drawpars * dp){ - char text[STRLEN]; - double fq = ms->freq[dp->n]; - char i = fq > 0.0 ? ' ' : 'i'; - snprintf(text, sizeof(text), - "%*d / %d freq = %.1lf%c cm-1 int = %.1lf km/mole mass = %.1lf amu | r = %.1lf rl = %.1lf", - 1+(int)(log10(ms->n)), dp->n+1, ms->n, fabs(fq), i, ms->ints[dp->n], ms->mass[dp->n], dp->rend.r, dp->bond.rl); - textincorner(text, dp->read.fname); - if(dp->ui.input==1){ - char text3[STRLEN]; - snprintf(text3, sizeof(text3), "JUMP TO >>> %s", dp->ui.input_text); - textincorner2(text3); - } - return; -} - void pg(atcoord * a, double symtol){ int n = a->n; diff --git a/src/v/v.h b/src/v/v.h index f649ae8..05aecae 100644 --- a/src/v/v.h +++ b/src/v/v.h @@ -7,6 +7,7 @@ #define POINTER_SPEED 2.0 #define STRLEN 256 #define BIGSTRLEN 4096 +#define MAX_LINES 5 #include "pars.h" @@ -28,10 +29,13 @@ typedef struct { typedef struct { int n; // number of atoms - int * q; // charges of atoms - double * r; // coordinates of atoms + int * q; // atom charges + double * r; // atom coordinates (rotated) const char * fname; // file name + int rotated; // is `r` up-to-date + double * r0; // atom coordinates (original) + int nf[2]; // number of molecule in file, file size styp sym; // point group bondstr bonds; @@ -42,7 +46,6 @@ typedef struct { double * ints; // intensities double * disp; // displacements double * mass; // masses - double * r0; // atom configuration at the central point int n; // number of modes } vibr_t; @@ -79,6 +82,10 @@ allpars cli_parse(int argc, char ** argv); // loop.c void main_loop(object * ent, drawpars * dp, ptf kp[NKP]); +// redraw.c +void redraw_ac3(object * ent, drawpars * dp); +void redraw_vibro(object * ent, drawpars * dp); + // ac3_draw.c void ac3_draw (atcoord * ac, rendpars rend); // ac3_print.c @@ -98,20 +105,18 @@ int get_element(char * s); void close_x (void); void init_x (const char * const capt, const colorscheme_t colorscheme); void init_font (char * fontname); -void textincorner (const char * const text1, const char * const text2); -void textincorner2(const char * const text1); +void textincorner (const char * const lines[MAX_LINES], const int red[MAX_LINES]); void setcaption (const char * const capt); -void drawvertices (double * v, double scale, double xy0[2]); -void drawshell (double rmin, double rmax, double scale, double * xy0); +void drawvertices (double * v, rendpars rend); +void drawshell (double r[2], rendpars rend); int savepic (char * s); +void clear_canv(); +void fill_canv(); // xinput.c int process_x_input(char input_text[STRLEN], unsigned int keycode); // tools.c void obj_free(object * ent); -void newmol_prep(object * acs, drawpars * dp); -void ac3_text(atcoord * ac, drawpars * dp); -void vibro_text(vibr_t * ms, drawpars * dp); void pg(atcoord * a, double symtol); // headless.c diff --git a/src/v/x.c b/src/v/x.c index 74b436d..d28333a 100644 --- a/src/v/x.c +++ b/src/v/x.c @@ -1,32 +1,23 @@ #include "v.h" #include "x.h" -#include "vec2.h" -extern Display * dis; -extern int screen; -extern Window win; -extern GC gc_white, gc_black, gc_red, gc_dot[2], gcc[NCOLORS]; -extern Pixmap px; -extern Drawable canv; -extern XFontStruct * fontInfo; - -extern int W,H; +extern draw_world_t world; void close_x(void) { - XFreeGC(dis, gc_red); - XFreeGC(dis, gc_black); - XFreeGC(dis, gc_white); - XFreeGC(dis, gc_dot[0]); - XFreeGC(dis, gc_dot[1]); + XFreeGC(world.dis, world.gc_red); + XFreeGC(world.dis, world.gc_black); + XFreeGC(world.dis, world.gc_white); + XFreeGC(world.dis, world.gc_dot[0]); + XFreeGC(world.dis, world.gc_dot[1]); for(int i=0; iscreen_sizes[i]){ + if(world.size>screen_sizes[i]){ font_size = font_sizes[i]; break; } @@ -131,9 +123,10 @@ void init_font(char * fontname){ fontname = s; autosize_font(fontname); } - fontInfo = XLoadQueryFont(dis, fontname); - if(fontInfo){ - XSetFont (dis, gc_black, fontInfo->fid); + world.fontInfo = XLoadQueryFont(world.dis, fontname); + if(world.fontInfo){ + XSetFont (world.dis, world.gc_black, world.fontInfo->fid); + XSetFont (world.dis, world.gc_red, world.fontInfo->fid); } else{ PRINT_WARN("cannot load font '%s'\n", fontname); @@ -141,40 +134,34 @@ void init_font(char * fontname){ return; } -void textincorner(const char * const text1, const char * const text2){ - int voffset = fontInfo ? (fontInfo->ascent + fontInfo->descent + 5) : 20; - XDrawString(dis, win, gc_black, 10, voffset, text1, strlen(text1)); - if(text2){ - XDrawString(dis, win, gc_black, 10, voffset*2, text2, strlen(text2)); +void textincorner(const char * const lines[MAX_LINES], const int red[MAX_LINES]){ + XCharStruct _o; + int _d, font_ascent, font_descent; + XQueryTextExtents(world.dis, XGContextFromGC(world.gc_black), ".", 1, &_d, &font_ascent, &font_descent, &_o); + int voffset = font_ascent + font_descent + 5; + int hoffset = 10; + for(int i=0; iascent + fontInfo->descent + 5) : 20; - XDrawString(dis, win, gc_red, 10, voffset*3, text1, strlen(text1)); - return; -} - void setcaption(const char * const capt){ - XStoreName(dis, win, capt); + XStoreName(world.dis, world.win, capt); return; } -void draw_edge(double vi[3], double vj[3], double scale, double xy0[2]){ +void draw_edge(double vi[3], double vj[3], rendpars rend){ int iw = (vi[2]>0.0 || vj[2]>0.0) ? 0 : 1; - double pi[2], pj[2]; - r2sum(pi, xy0, vi); - r2sum(pj, xy0, vj); - XDrawLine(dis, win, gc_dot[iw], - W/2+scale*pi[0], H/2-scale*pi[1], - W/2+scale*pj[0], H/2-scale*pj[1]); + XDrawLine(world.dis, world.canv, world.gc_dot[iw], + SCREEN_X(vi[0]), SCREEN_Y(vi[1]), SCREEN_X(vj[0]), SCREEN_Y(vj[1])); return; } -void drawvertices(double * v, double scale, double xy0[2]){ - double d = MIN(H, W)*scale; -#define LINE(i,j) draw_edge(v+(i)*3, v+(j)*3, d, xy0) +void drawvertices(double * v, rendpars rend){ +#define LINE(i,j) draw_edge(v+(i)*3, v+(j)*3, rend) for(int i=0; i<8; i+=2){ LINE(i,i+1); // || z-axis } @@ -188,13 +175,12 @@ void drawvertices(double * v, double scale, double xy0[2]){ return; } -void drawshell(double rmin, double rmax, double scale, double xy0[2]){ - double d = MIN(H,W)*scale; - double r[] = {rmax*d, rmin*d}; - int x = W/2+d*xy0[0]; - int y = H/2-d*xy0[1]; +void drawshell(double r[2], rendpars rend){ + double d = world.size * rend.scale; for(int i=0; i<2; i++){ - XDrawArc(dis, win, gc_dot[i], x-r[i], y-r[i], 2*r[i], 2*r[i], 0, 360*64); + XDrawArc(world.dis, world.canv, world.gc_dot[1-i], + SCREEN_X(-r[i]), SCREEN_Y(r[i]), + 2*r[i]*d, 2*r[i]*d, 0, 360*64); } return; } @@ -202,9 +188,21 @@ void drawshell(double rmin, double rmax, double scale, double xy0[2]){ int savepic(char * s){ XpmAttributes a; a.valuemask = (0 | XpmSize) ; - a.width = W; - a.height = H; - XCopyArea (dis, win, px, gc_white, 0, 0, W, H, 0, 0); /* with text */ - return XpmWriteFileFromPixmap(dis, s, px, 0, &a); + a.width = world.W; + a.height = world.H; + return XpmWriteFileFromPixmap(world.dis, s, world.px, 0, &a)==XpmSuccess; +} + +void clear_canv(){ // TODO other canvases? + if(world.canv == world.px){ + XFillRectangle(world.dis, world.canv, world.gc_white, 0, 0, world.W, world.H);\ + } + return; } +void fill_canv(){ + if(world.canv == world.px){ // TODO other canvases? + XCopyArea(world.dis, world.canv, world.win, world.gc_white, 0, 0, world.W, world.H, 0, 0); + } + return; +} diff --git a/src/v/x.h b/src/v/x.h index a9d5fa5..17698c2 100644 --- a/src/v/x.h +++ b/src/v/x.h @@ -5,17 +5,17 @@ #include #define NCOLORS 110 +#define LINE_WIDTH 2 -#define CLEARCANV \ - if(canv == px){\ - XFillRectangle(dis, px, gc_white, 0, 0, W, H);\ - }\ - else if(canv == win){\ - XClearWindow(dis, win);\ - } - -#define FILLCANV \ - if(canv == px){\ - XCopyArea(dis, px, win, gc_white, 0, 0, W, H, 0, 0);\ - } +#define SCREEN_X(X) (world.W/2 + world.size * rend.scale*(rend.xy0[0] + (X))) +#define SCREEN_Y(Y) (world.H/2 - world.size * rend.scale*(rend.xy0[1] + (Y))) +typedef struct { + Display * dis; + Window win; + GC gc_white, gc_black, gc_red, gc_dot[2], gcc[NCOLORS]; + Pixmap px; + Drawable canv; + XFontStruct * fontInfo; + int W, H, size; +} draw_world_t; diff --git a/src/v/xinput.c b/src/v/xinput.c index 0e0aab6..4ac1994 100644 --- a/src/v/xinput.c +++ b/src/v/xinput.c @@ -1,11 +1,11 @@ #include "v.h" #include "x.h" -extern Display * dis; +extern draw_world_t world; int process_x_input(char input_text[STRLEN], unsigned int keycode){ int keysyms_per_keycode_return; - KeySym * keysym = XGetKeyboardMapping(dis, keycode, 1, &keysyms_per_keycode_return); + KeySym * keysym = XGetKeyboardMapping(world.dis, keycode, 1, &keysyms_per_keycode_return); int input_length = strlen(input_text); if(!((keysym[0]>='0' && keysym[0]<='9')||(keysym[0]>='a' && keysym[0]<='z'))){ if(keysym[0]==XK_Escape){