/* ----- various useful routines ------- */ void rx(char *msg) { printf("Error: %s\n", msg); exit(1); } void cross(float a[3], float b[3], float c[3]) { c[0]=a[1]*b[2]-a[2]*b[1]; c[1]=a[2]*b[0]-a[0]*b[2]; c[2]=a[0]*b[1]-a[1]*b[0]; return; } float sp(float a[3], float b[3]) { float sp1; sp1=a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; return sp1; } void vscal(float a[3], float ca, float v[3]) { v[0]=a[0]*ca; v[1]=a[1]*ca; v[2]=a[2]*ca; return; } void vsum(float a[3], float b[3], float ca, float cb, float v[3]) { v[0]=ca*a[0]+cb*b[0]; v[1]=ca*a[1]+cb*b[1]; v[2]=ca*a[2]+cb*b[2]; return; } int parse_args (str,w) char str[],w[8][41]; { int i, num, reading, quoted; char *p; p=str; reading=quoted=0; num=-1; while (*p != 0) { if (reading) { if ((quoted&&(*p=='\'')) || ((!quoted) && (*p==' ')) ) { i++; w[num][i]=0; reading=0; } else { i++; w[num][i]=*p; } } else { if (*p != ' ') { num++; if (*p == '\'') { quoted=1; i=-1; } else { i=0; w[num][i]=*p; } reading=1; } } p++; } if (reading) { i++; w[num][i]=0; } num++; return num; } void strip (str1,str) char str[],str1[]; { int l,i,i1,i2; l=strlen(str); i1=0; for (i=0; i=0; i--) if ((str[i]!=' ') && (str[i]!='\n')) { i2=i+1; break; } for (i=i1;i <%s>\n", l, i1, i2, str, str1);*/ } int abbrev (str,ab,nchar) char str[],ab[]; int nchar; { int i,nc; if (strlen(str) > strlen(ab)) return 0; nc=strlen(str); if (nc0) q++; *q = 0; strcat(fid1,ext); } int match (char str[], char pat[]) { char *p,*s; p=pat; s=str; while (*p != 0) { if (*p == '*') { /* found wildcard '*' in pattern */ p++; while (*p == '*') p++; if (*p == 0) return 1; /* trailing '*' matches all */ for (;;) { /* find match to char after '*' */ if (*s == 0) return 0; if ((*s == *p) || (*p == '+')) if (match(s+1,p+1)) return 1; /* ok if rest matches */ s++; } return 0; /* tried all cases but none worked */ } else { /* no wildcard -- char must match */ if (*s == 0) return 0; if ((*p != *s) && (*p != '+')) return 0; s++; } p++; } if (*s != 0) return 0; /* pattern but not string exhausted */ return 1; } void get_extent(xx1,xx2,yy1,yy2,zz1,zz2) float *xx1,*xx2,*yy1,*yy2,*zz1,*zz2; { float big,x1,x2,y1,y2,z1,z2; int i; big=1000000; if (nbas==0) big=0; x1=y1=z1=big; x2=y2=z2=-big; for (i=0;ix2) x2=p[i][0]; if (p[i][1]y2) y2=p[i][1]; if (p[i][2]z2) z2=p[i][2]; } *xx1=x1+center[0]; *xx2=x2+center[0]; *yy1=y1+center[1]; *yy2=y2+center[1]; *zz1=z1+center[2]; *zz2=z2+center[2]; } void atompos (float fac, float p[3], float rad, float zp[2], float *zr) { float y[3], q[3], v1[3], v2[3]; float xxx, za1, za2, zb1, zb2, a, b, qn; if (pmode == 1) { zp[0] = fac*p[0]; zp[1] = fac*p[1]; *zr = fac*rad; *zr = MAXRAD; if (dist0 - p[2]>0) *zr = fac*rad*dist0 / (dist0-p[2]); if (*zr > MAXRAD) *zr = MAXRAD; return; } vscal (p, 1.0, q); q[2] = q[2] - dist; vscal (p, 1.0, y); xxx = -sp(y,q) / sp(q,q); qn = sqrt(sp(q,q)); vsum (y, q, 1.0, xxx, y); if (sp(y,y) <= 1e-3) { y[0] = 1.0; y[1] = 0.0; y[2] = 0.0; } /* detect pathological cases for true perspective */ if (pmode == 2) { /* viewpoint lies inside sphere */ if (qn <= rad) { *zr = -10; return; } /* atom lies behind viewpoint */ if (q[2] >= 0) { *zr = -1; return; } } a = -rad * rad / sp(q,q); b = rad * sqrt ((1+a) / sp(y,y)); vsum (q, y, a, b, v1); vsum (q, y, a, -b, v2); vsum (p, v1, 1.0, 1.0, v1); vsum (p, v2, 1.0, 1.0, v2); za1 = fac*v1[0]*dist / (dist-v1[2]); za2 = fac*v1[1]*dist / (dist-v1[2]); zb1 = fac*v2[0]*dist / (dist-v2[2]); zb2 = fac*v2[1]*dist / (dist-v2[2]); zp[0] = 0.5 * (za1 + zb1); zp[1] = 0.5 * (za2 + zb2); *zr = (zb1-za1)*(zb1-za1) + (zb2-za2)*(zb2-za2); *zr = 0.5 * sqrt(*zr); } int readclusterline(char str[], int helpme) { char token[81], cname[81]; float rval, bval, gval, gray; int l, n, i, k, nn, a[4]; float atcors[4][3]; l = strlen(str); if (l < 1) return 0; *token = 0; sscanf (str,"%s", token); if (! *token) return 0; /* empty line */ if (token[0]=='*') return 0; /* comment -- no error */ if (helpme) { if (abbrev(token,"spec",4)) sprintf(gmsg,"Usage: spec label radius color - define species"); else if (abbrev(token,"tell",4)) sprintf(gmsg,"Usage: tell i ... - tell xyz, distance, angle, or torsion"); else if (abbrev(token,"atom",4)) sprintf(gmsg,"Usage: atom label x y z - place atom at (x,y,z)"); else if (abbrev(token,"bonds",5)) sprintf(gmsg,"Usage: bonds pat1 pat2 min max rad color - select bonds"); else if (abbrev(token,"light",5)) sprintf(gmsg,"Usage: light vx vy vz - light along vector in bw mode)"); else if (abbrev(token,"inc",3)) sprintf(gmsg,"Usage: inc degrees - angle increment for rotation"); else if (abbrev(token,"dist",5)) sprintf(gmsg,"Usage: dist d - set distance for perspective"); else if (abbrev(token,"frm",3)) sprintf(gmsg,"Usage: frm n - goto frame n"); else if (abbrev(token,"step",4)) sprintf(gmsg,"Usage: step n - set step for frames"); else if (abbrev(token,"gramp",5)) sprintf(gmsg,"Usage: gramp slope [middle] - set gray ramp in bw mode)"); else if (abbrev(token,"scale",5)) sprintf(gmsg,"Usage: scale x - set overall scale factor"); else if (abbrev(token,"rfac",4)) sprintf(gmsg,"Usage: rfac x - scale all sphere radii by x"); else if (abbrev(token,"bfac",4)) sprintf(gmsg,"Usage: bfac x - scale all bond radii by x"); else if (abbrev(token,"pos",3)) sprintf(gmsg,"Usage: pos px py - set position on page"); else if (abbrev(token,"dpos",4)) sprintf(gmsg,"Usage: dpos x - set increment for position"); else sprintf(gmsg,"No help available on %s", token); return 0; } /* display coordinates, distance, angle, or torsion (Jan Labanowski) */ if (!strcmp(token,"tell")) { a[0] = a[1] = a[2] = a[3] = -1; sscanf(str,"%*s %d %d %d %d", &a[0], &a[1], &a[2], &a[3]); n = 0; for(i=0; i<4; i++) { if (a[i] > 0) { if (a[i] > nbas){ sprintf(gmsg, "Atom number %d at position %d is too large",a[i],i+1); return 0; } for (k=0; k<3; k++) { if (iframe == 0) atcors[i][k] = atom[a[i]-1].pos[k]; else atcors[i][k] = frame[k][iframe*nbas+a[i]-1]; } n++; } else break; } if (n == 0) { sprintf(gmsg,"Shows coordinates (for 1 atom), distance (2 atoms)," " angle (3), torsion (4)"); } if (n == 1) { sprintf(gmsg,"Coordinates X[%d]=%.4f Y[%d]=%.4f Z[%d]=%.4f", a[0], atcors[0][0], a[0], atcors[0][1], a[0], atcors[0][2]); } else if (n == 2) { sprintf(gmsg, "Distance %d:%d is %.4f", a[0], a[1], distance(atcors[0], atcors[1])); } else if (n == 3) { sprintf(gmsg, "Angle %d:%d:%d is %.4f deg", a[0], a[1], a[2], angle(atcors[0], atcors[1], atcors[2])); } else if (n == 4) { sprintf(gmsg, "Torsion angle %d:%d:%d:%d is %.4f deg", a[0], a[1], a[2], a[3], torsion(atcors[0], atcors[1], atcors[2], atcors[3])); } return 0; } if (!strcmp(token,"spec")) { sscanf(str,"%*s %s %f %n", spec[nspec].lab, &spec[nspec].rad, &n); strip (spec[nspec].cname, str+n); nspec++; if (nspec>NSPMAX) rx("increase internal dimension NSPMAX"); return 2; } if (!strcmp(token,"atom")) { atom[nbas].pol[0]=0; atom[nbas].pol[1]=0; atom[nbas].pol[2]=0; sscanf(str,"%*s %s %f %f %f %f %f %f", atom[nbas].lab, &atom[nbas].pos[0], &atom[nbas].pos[1], &atom[nbas].pos[2], &atom[nbas].pol[0], &atom[nbas].pol[1], &atom[nbas].pol[2]); nbas++; if (nbas>NAMAX) rx("increase internal dimension NAMAX"); return 2; } if (!strcmp(token,"bonds")) { sscanf(str,"%*s %s %s %f %f %f %n", bonds[nbonds].lab1, bonds[nbonds].lab2, &bonds[nbonds].min, &bonds[nbonds].max, &bonds[nbonds].rad, &n); strip (bonds[nbonds].cname, str+n); nbonds++; if (nbonds>NBTMAX) rx("increase internal dimension NBTMAX"); return 2; } if (!strcmp(token,"line")) { sscanf(str, "%*s %f %f %f %f %f %f", &xline[nxline].a[0],&xline[nxline].a[1],&xline[nxline].a[2], &xline[nxline].b[0],&xline[nxline].b[1],&xline[nxline].b[2]); nxline++; if (nxline>NLNMAX) rx("increase internal dimension NLNMAX"); return 1; } if (!strcmp(token,"tmat")) { sscanf(str, "%*s %f %f %f %f %f %f %f %f %f", &tmat[0][0], &tmat[0][1], &tmat[0][2], &tmat[1][0], &tmat[1][1], &tmat[1][2], &tmat[2][0], &tmat[2][1], &tmat[2][2]); return 1; } if (!strcmp(token,"dist") || !strcmp(token,"d")) { sscanf(str, "%*s %f", &dist0); return 1; } if (!strcmp(token,"inc")) {sscanf(str, "%*s %f", &dalfa); return 3;} if (!strcmp(token,"frm")) { sscanf(str, "%*s %d", &nn); if (nn>nframe || nn<1) { sprintf (emsg, "No frame %d available", nn); return 0; } if (iframe==nn-1) return 0; iframe=nn-1; return 2; } if (!strcmp(token,"light")) { light[0]=light[1]=light[2]=0.0; sscanf(str,"%*s %f %f %f", &light[0], &light[1], &light[2]); if (light[0]*light[0]+light[1]*light[1]+light[2]*light[2]<.01) { sprintf (gmsg, "Use standard coloring"); gmode=G_STD;; return 2; } if (color) { sprintf(emsg, "light: only works in b/w mode"); return 0; } gmode=G_LIGHT; return 2; } if (!strcmp(token,"step")) {sscanf(str,"%*s %d", &fstep); return 1;} if (!strcmp(token,"scale")) { sscanf(str,"%*s %f", &scale); scale=scale*igs; return 1; } if (!strcmp(token,"rfac")) {sscanf(str,"%*s %f", &radfac); return 1;} if (!strcmp(token,"bfac")) {sscanf(str,"%*s %f", &bndfac); return 1;} if (!strcmp(token,"amp")) {sscanf(str,"%*s %f", &); return 2;} if (!strcmp(token,"pos")) {sscanf(str,"%*s %f %f", &taux, &tauy); return 1;} if (!strcmp(token,"dpos")) { sscanf(str,"%*s %f", &dtaux); dtauy=dtaux; chginfo=1; return 0;} if (!strcmp(token,"gramp")) { gslope=gz0=0; sscanf(str, "%*s %f %f", &gslope, &gz0); if (gslope*gslope<0.1) { sprintf (gmsg, "Use standard coloring"); gmode=G_STD; return 2; } if (color) { sprintf(emsg, "gramp: only works in b/w mode"); return 0; } gmode=G_RAMP; return 2; } if (!strcmp(token,"switches")) { sscanf(str, "%*s %d %d %d %d %d %d %d %d %d", &usepixmap,&numbers,&grayvalues,&bline,&wire, &withbonds,&recenter,&pmode,&shadow); return 2; } sprintf(emsg,"Undefined command: %s", token); if (startup) printf ("Cannot understand line: %s\n", str); return 0; } int readclusterdata(char infile[]) { FILE *fp; char str[257]; char xxx [81]; char *p; int l, i, nn; if (!(fp=fopen(infile,"r"))) return 0; fgets (str, 256, fp); while (!feof(fp)) { l = strlen(str); str[l+1] = '\0'; if (p=strstr(str,"frame")) { if (nframe*nbas>FBMAX) rx("increase internal dimension FBMAX"); if (nframe>NFRMAX) rx("increase internal dimension NFRMAX"); p=p+6; sprintf(frstr[nframe], "%-80s", p); for (i=0;i1) { strext (nm, outfile, "mv", 1); if ((fp = fopen (nm,"w")) == NULL) { sprintf(emsg,"Cannot open file %s\n", nm); return;} nfrm=1; for (i=1;itop) top=sp; if (sp -1) { dis = 0.0; for (m=0; m<3; m++) { dd = ball[k].pos[m] - ball[l].pos[m]; dis = dis + dd*dd; } dis = alat * sqrt(dis); if ((dis >= bonds[kb].min) && (dis <= bonds[kb].max)) { i++; if (i > NBMAX) rx("increase internal dimension NBMAX"); stick[i].start = k; stick[i].end = l; stick[i].rad = bonds[kb].rad; stick[i].gray = bonds[kb].gray; stick[i].r = bonds[kb].r; stick[i].g = bonds[kb].g; stick[i].b = bonds[kb].b; stick[i].col = bonds[kb].col; } } } } nbond = i + 1; return nbond; } int duplicate_atoms(sh,helpme) float sh[3][6]; int helpme; { int k,l,iv,nbas1,ndup,fr,nn,nn1; float cx,cy,cz; if (helpme) { sprintf (gmsg,"Usage: dup vx vy vz - duplicate shifted by vector"); return 0; } ndup=0; for (iv=0;iv<6;iv++) { cx=sh[0][iv]; cy=sh[1][iv]; cz=sh[2][iv]; if (cx*cx+cy*cy+cz*cz>0.001) ndup++; } if (ndup==0) { sprintf (emsg, "Cannot dup for (0,0,0)"); return 0; } nbas1=nbas*(ndup+1); if (nframe*nbas1>FBMAX) { sprintf(emsg,"Cannot dup, internal dimension FBMAX too small"); return 0; } if (nbas*(ndup+1)>NAMAX) { sprintf(emsg,"Cannot dup, internal dimension NAMAX too small"); return 0; } for (iv=0;iv=0; fr--) { for (k=0;k\n", 1, frstr[0]); if (nframe>1) printf ("frame %-5d <%s>\n", 2, frstr[1]); if (nframe>2) printf ("frame %-5d <%s>\n", nframe, frstr[nframe-1]); return; } void draw_lines (int dash) { float p[3], q[3], fac, zp1[2], zp2[2], rad, r1, r2; int n,m; fac=scale; for(n=0;n 0) DrawArrow (tx, ty, z0[0]+tx, z0[1]+ty, r0, "100"); |*/ /*| if (i0 == 1 && r1 > 0) DrawArrow (tx, ty, z1[0]+tx, z1[1]+ty, r1, "010"); |*/ /*| if (i0 == 2 && r2 > 0) DrawArrow (tx, ty, z2[0]+tx, z2[1]+ty, r2, "001"); |*/ if (i0 == 0 && r0 > 0) DrawArrow (tx, ty, z0[0]+tx, z0[1]+ty, r0, "X"); if (i0 == 1 && r1 > 0) DrawArrow (tx, ty, z1[0]+tx, z1[1]+ty, r1, "Y"); if (i0 == 2 && r2 > 0) DrawArrow (tx, ty, z2[0]+tx, z2[1]+ty, r2, "Z"); zz[i0] = 1e10; } } void bs_transform (int natom, struct ballstr ball[]) { int m, n; for (n=0; n 0) { zr[k] = radfac * zr[k]; if (zp[k][0]-zr[k] < xbot) xbot = zp[k][0] - zr[k]; if (zp[k][0]+zr[k] > xtop) xtop = zp[k][0] + zr[k]; if (zp[k][1]-zr[k] < ybot) ybot = zp[k][1] - zr[k]; if (zp[k][1]+zr[k] > ytop) ytop = zp[k][1] + zr[k]; } } /* printf ("bounds x %.3f %.3f y %.3f %.3f\n", xbot,xtop,ybot,ytop); */ /* ------- start loop over atoms; plot ball first ----- */ for (n=0; n= 0) { br = bndfac * stick[ib].rad; bx = zp[kk][0] - zp[k][0]; by = zp[kk][1] - zp[k][1]; xx = sqrt (bx*bx + by*by); if ( xx*xx < 0.0001 ) continue; bx = bx/xx; by = by/xx; vsum (d, p[k], 1.0, -1.0, q1); vsum (d, p[kk], 1.0, -1.0, q2); vsum (p[kk], p[k], 1.0, -1.0, b); cth1 = sp(q1,b) / sqrt(sp(q1,q1)*sp(b,b)); cth2 = -sp(q2,b) / sqrt(sp(q2,q2)*sp(b,b)); th1 = acos(cth1); th2 = acos(cth2); crit1 = asin(br/rk) * fudgefac; if (crit1 < 0.0) crit1 = 0.0; crit2 = asin(br/rkk) * fudgefac; if (crit2 < 0.0) crit2 = 0.0; note = 0; if (th2-0.5*PI > crit2 && kkk) note = 2; /* ------- plot a stick ------ */ if (note==1 || note==2) { w = sqrt (rk*rk - br*br); sth1 = sqrt (1.0 - cth1*cth1); ww = w*sth1*zr[k]/rk; bb = br*zr[k]/rk; aa = br*cth1*zr[k]/rk; m1[0] = bx*aa; m1[1] = by*aa; m1[2] = -by*bb; m1[3] = bx*bb; m1[4] = zp[k][0] + bx*ww+taux; m1[5] = zp[k][1] + by*ww+tauy; w = sqrt (rkk*rkk - br*br); sth2 = sqrt(1.0 - cth2*cth2); ww = w*sth2*zr[kk]/rkk; bb = br*zr[kk]/rkk; aa = br*cth2*zr[kk]/rkk; m2[0] = bx*aa; m2[1] = by*aa; m2[2] = -by*bb; m2[3] = bx*bb; m2[4] = zp[kk][0] - bx*ww+taux; m2[5] = zp[kk][1] - by*ww+tauy; beta = exp (gslope*(0.5*(p[k][2]+p[kk][2])-gz0)*gslope); if (grayvalues) { if (gmode == G_STD) gray = stick[ib].gray; else if (gmode == G_LIGHT) gray = 0.5 * (ball[k].gray + ball[kk].gray); else if (gmode == G_RAMP) gray = beta*stick[ib].gray + (1-beta)*GRAY0; } else gray = 1.0; if (grayvalues && bline && (gray > 0.7)) gray = 0.7; if (!grayvalues && bline) gray = 0.0; if (grayvalues && wire) gray = 0.0; if (bline) gray=0.0; /* overrides... black if lines */ if (ball[k].special) dbond (1.0, m2, m1); else if (ball[kk].special) dbond (1.0, m1, m2); else { if (hardcopy) /*| hardcopy_stick (gray, m1, m2); |*/ hardcopy_stick(gray, stick[ib].r, stick[ib].g, stick[ib].b, m1, m2); else DrawStick (gray, stick[ib].col, m1, m2); } /* next part writes bond lengths onto the sticks */ if (bondnums) { bmidx = 0.5*(zp[k][0] + zp[kk][0]) + taux; bmidy = 0.5*(zp[k][1] + zp[kk][1]) + tauy; dd = 0; for (m=0; m<3; m++) dd = dd + pow(ball[k].pos[m]-ball[kk].pos[m],2); dd = sqrt(dd); sprintf(label, "%.2f", dd); if (hardcopy) hardcopy_label (bmidx, bmidy, label); else LabelBG (bmidx, bmidy, 0.0, 1.0, label); } } } /* if (ib!=0) */ } /* end loop over nn */ } /* end loop over n */ if (showaxes) draw_axes(); if (showlines == 1) draw_lines(0); if (showlines == 2) draw_lines(1); }