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: cmd_label.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.49 $ $Date: 2019年01月17日 21:21:03 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * text commands for label control 00019 ***************************************************************************/ 00020 00021 #include <string.h> 00022 #include <ctype.h> 00023 #include <stdio.h> 00024 #include <stdlib.h> 00025 #include <tcl.h> 00026 #include "config.h" 00027 #include "GeometryList.h" 00028 #include "GeometryMol.h" 00029 #include "utilities.h" 00030 #include "VMDApp.h" 00031 00032 static int find_atom_from_name(Tcl_Interp *interp, const char *str, int *molid, 00033 int *atomid) { 00034 // string must be of format ##/## where ## are numbers. 00035 00036 // find first occurence of '/' 00037 const char *slash = strchr(str, '/'); 00038 if (!slash) { 00039 Tcl_AppendResult(interp, "Illegal format: ", str, NULL); 00040 return -1; 00041 } 00042 00043 // make sure we have digits 00044 if (slash == str) { 00045 Tcl_AppendResult(interp, "Missing molecule specification: ", str, NULL); 00046 return -1; 00047 } 00048 if (strlen(slash+1) == 0) { 00049 Tcl_AppendResult(interp, "Missing atom specification: ", str, NULL); 00050 return -1; 00051 } 00052 const char *s; 00053 for (s = str; s < slash; s++) { 00054 if (!isdigit(*s)) { 00055 Tcl_AppendResult(interp, "Illegal molecule specification: ", str, NULL); 00056 return -1; 00057 } 00058 } 00059 for (s = slash+1; *s; s++) { 00060 if (!isdigit(*s)) { 00061 Tcl_AppendResult(interp, "Illegal atom specification: ", str, NULL); 00062 return -1; 00063 } 00064 } 00065 00066 // Looks ok; extract the molecule and atom 00067 char *buf = new char[slash-str + 1]; 00068 strncpy(buf, str, slash-str); 00069 buf[slash-str] = '0円'; 00070 *molid = atoi(buf); 00071 *atomid = atoi(slash+1); 00072 return 0; 00073 } 00074 00075 00076 int text_cmd_label(ClientData cd, Tcl_Interp *interp, int argc, 00077 const char *argv[]) { 00078 00079 VMDApp *app = (VMDApp *)cd; 00080 00081 if (argc < 2) { 00082 Tcl_SetResult(interp, 00083 (char *) 00084 "label add [Atoms|Bonds|Angles|Dihedrals] {atoms as <molid>/<atomid>}\n" 00085 "label addspring <molid> <atomid> <atomid> <k>\n" 00086 "label list -- return label categories\n" 00087 "label list <category> -- return id's of labels in given category\n" 00088 "label [show|hide|delete] <category> [index] -- \n\tControl specific label or all labels in category\n" 00089 "label graph <category> <index> -- Return a list of values for the given label\n\tfor all animation frames\n" 00090 "label textsize [<newsize>]\n" 00091 "label textthickness [<newthick>]\n" , 00092 TCL_STATIC); 00093 return TCL_ERROR; 00094 } 00095 if(!strupncmp(argv[1], "add", CMDLEN)) { 00096 if(argc > 3) { 00097 int n = argc-3; 00098 const char **items = argv+3; 00099 int *molid= new int[n]; 00100 int *atmid = new int[n]; 00101 int i; 00102 for(i=0; i < n; i++) { 00103 if (find_atom_from_name(interp, items[i], molid+i, atmid+i)) 00104 break; 00105 } 00106 int rc = -1; 00107 if(i == n) { // all successfully parsed 00108 rc = app->label_add(argv[2], argc-3, molid, atmid, NULL, 0.0f, 1); 00109 } 00110 delete [] molid; 00111 delete [] atmid; 00112 if (rc < 0) { 00113 Tcl_AppendResult(interp, "\nUnable to add label.", NULL); 00114 return TCL_ERROR; 00115 } 00116 } 00117 else 00118 return TCL_ERROR; 00119 00120 } 00121 else if(!strupncmp(argv[1],"addspring",CMDLEN)) { /* add a spring */ 00122 if(argc != 6) { 00123 Tcl_AppendResult(interp, "usage: label addspring <molid> <atomid> <atomid> <k>", NULL); 00124 return TCL_ERROR; 00125 } 00126 int molid[2]; 00127 int atomid[2]; 00128 float k; 00129 sscanf(argv[2],"%d",molid); /* convert all of the args to numbers */ 00130 sscanf(argv[3],"%d",atomid); 00131 sscanf(argv[4],"%d",atomid+1); 00132 sscanf(argv[5],"%f",&k); 00133 molid[1]=molid[0]; 00134 if (app->label_add("Springs", 2, molid, atomid, NULL, k, 1) < 0) { 00135 Tcl_AppendResult(interp, "Unable to add spring.", NULL); 00136 return TCL_ERROR; 00137 } 00138 } 00139 else if(!strupncmp(argv[1], "list", CMDLEN)) { 00140 if(argc == 3) { 00141 int cat = app->geometryList->geom_list_index(argv[2]); 00142 if (cat < 0) { 00143 Tcl_AppendResult(interp, "graph list category '", argv[2], 00144 "' was not found", NULL); 00145 return TCL_ERROR; 00146 } 00147 // go through the list by hand 00148 GeomListPtr glist = app->geometryList->geom_list(cat); 00149 int gnum = glist->num(); 00150 char s[30]; 00151 GeometryMol *g; 00152 for (int i=0; i<gnum; i++) { 00153 g = (*glist)[i]; 00154 Tcl_AppendResult(interp, i==0 ? "" : " ", "{", NULL); 00155 for (int j=0; j<g->items(); j++) { 00156 // append the molecule id/atom index 00157 sprintf(s, "%d %d", g -> obj_index(j), g -> com_index(j)); 00158 Tcl_AppendElement(interp, s); 00159 } 00160 // and the value and the status 00161 sprintf(s, "%f", g->ok() ? g->calculate() : 0.0); 00162 Tcl_AppendElement(interp, s); 00163 Tcl_AppendElement(interp, g -> displayed() ? "show" : "hide"); 00164 Tcl_AppendResult(interp, "}", NULL); 00165 } 00166 return TCL_OK; 00167 } 00168 else if (argc == 2) { 00169 // return the main categories 00170 for (int i=0; i<app->geometryList -> num_lists(); i++) { 00171 Tcl_AppendElement(interp, app->geometryList -> geom_list_name(i)); 00172 } 00173 return TCL_OK; 00174 } else 00175 return TCL_ERROR; 00176 00177 } else if(!strupncmp(argv[1], "show", CMDLEN) || 00178 !strupncmp(argv[1], "hide", CMDLEN)) { 00179 int item; 00180 if(argc == 3 || (argc == 4 && !strupncmp(argv[3], "all", CMDLEN))) 00181 item = (-1); 00182 else if(argc == 4) { 00183 if (Tcl_GetInt(interp, argv[3], &item) != TCL_OK) { 00184 Tcl_AppendResult(interp, " in label ", argv[1], NULL); 00185 return TCL_ERROR; 00186 } 00187 } else 00188 return TCL_ERROR; 00189 00190 app->label_show(argv[2], item, !strupncmp(argv[1], "show", CMDLEN)); 00191 // XXX check return code 00192 00193 } else if(!strupncmp(argv[1], "delete", CMDLEN)) { 00194 int item; 00195 if(argc == 3 || (argc == 4 && !strupncmp(argv[3], "all", CMDLEN))) { 00196 item = (-1); 00197 } else if(argc == 4) { 00198 if (Tcl_GetInt(interp, argv[3], &item) != TCL_OK) { 00199 Tcl_AppendResult(interp, " in label ", argv[1], NULL); 00200 return TCL_ERROR; 00201 } 00202 } else { 00203 return TCL_ERROR; 00204 } 00205 00206 app->label_delete(argv[2], item); 00207 // XXX check return code 00208 00209 } else if(!strupncmp(argv[1], "graph", CMDLEN) && argc > 3) { 00210 int item; 00211 if (Tcl_GetInt(interp, argv[3], &item) != TCL_OK) { 00212 return TCL_ERROR; 00213 }; 00214 // find the geometry 00215 int cat = app->geometryList->geom_list_index(argv[2]); 00216 if (cat < 0) { 00217 Tcl_AppendResult(interp, "Invalid geometry type: ", argv[2], NULL); 00218 return TCL_ERROR; 00219 } 00220 // get the correct geometry pointer 00221 GeomListPtr glist = app->geometryList -> geom_list(cat); 00222 int gnum = glist -> num(); 00223 if (item < 0 || item >= gnum) { 00224 char buf[512]; 00225 sprintf(buf, "label %s index %d out of range", argv[2], item); 00226 Tcl_SetResult(interp, buf, TCL_VOLATILE); 00227 return TCL_ERROR; 00228 } 00229 // compute all the values 00230 GeometryMol *g = (*glist)[item]; 00231 if (!g->has_value()) { 00232 Tcl_AppendResult(interp, "Geometry type ", argv[2], " has no values to graph.", NULL); 00233 return TCL_ERROR; 00234 } 00235 ResizeArray<float> gValues(1024); 00236 if (!g->calculate_all(gValues)) { 00237 Tcl_AppendResult(interp, "label has no value", NULL); 00238 return TCL_ERROR; 00239 } 00240 if (argc > 4) { 00241 // save the values in the given filename 00242 const char *filename = argv[4]; 00243 FILE *outfile = fopen(filename, "w"); 00244 if (!outfile) { 00245 Tcl_AppendResult(interp, "Cannot write graph data to file ", 00246 filename, NULL); 00247 return TCL_ERROR; 00248 } 00249 for (int i=0; i<gValues.num(); i++) { 00250 fprintf(outfile, "%f %f\n", float(i), gValues[i]); 00251 } 00252 fclose(outfile); 00253 } else { 00254 char s[20]; 00255 for (int count = 0; count < gValues.num(); count++) { 00256 sprintf(s, "%f", gValues[count]); 00257 Tcl_AppendElement(interp, s); 00258 } 00259 } 00260 } else if (!strupncmp(argv[1], "textsize", CMDLEN)) { 00261 if (argc == 2) { 00262 // return the current size 00263 Tcl_SetObjResult(interp, Tcl_NewDoubleObj(app->label_get_text_size())); 00264 return TCL_OK; 00265 } else if (argc == 3) { 00266 // set new size 00267 double newsize = 1; 00268 if (Tcl_GetDouble(interp, argv[2], &newsize) != TCL_OK) 00269 return TCL_ERROR; 00270 if (!app->label_set_text_size((float) newsize)) { 00271 Tcl_AppendResult(interp, "label textsize: Unable to set size to ", 00272 argv[2], NULL); 00273 return TCL_ERROR; 00274 } 00275 } else { 00276 Tcl_SetResult(interp, (char *) "label textsize: wrong number of arguments", 00277 TCL_STATIC); 00278 return TCL_ERROR; 00279 } 00280 } else if (!strupncmp(argv[1], "textthickness", CMDLEN)) { 00281 if (argc == 2) { 00282 // return the current thickness 00283 Tcl_SetObjResult(interp, Tcl_NewDoubleObj(app->label_get_text_thickness())); 00284 return TCL_OK; 00285 } else if (argc == 3) { 00286 // set new size 00287 double newthick = 1; 00288 if (Tcl_GetDouble(interp, argv[2], &newthick) != TCL_OK) 00289 return TCL_ERROR; 00290 if (!app->label_set_text_thickness((float) newthick)) { 00291 Tcl_AppendResult(interp, "label textthickness: Unable to set thickness to ", argv[2], NULL); 00292 return TCL_ERROR; 00293 } 00294 } else { 00295 Tcl_SetResult(interp, (char *) "label textthickness: wrong number of arguments", 00296 TCL_STATIC); 00297 return TCL_ERROR; 00298 } 00299 } else if (!strupncmp(argv[1], "textoffset", CMDLEN)) { 00300 if (argc == 4) { 00301 // return current offset; 00302 const char *geomtype = argv[2]; 00303 int geom; 00304 if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; 00305 const float *offset = app->geometryList->getTextOffset(geomtype, geom); 00306 if (!offset) { 00307 Tcl_SetResult(interp, (char *) "label textoffset: Invalid geometry specified", TCL_STATIC); 00308 return TCL_ERROR; 00309 } 00310 Tcl_Obj *result = Tcl_NewListObj(0, NULL); 00311 Tcl_ListObjAppendElement(interp, result, Tcl_NewDoubleObj(offset[0])); 00312 Tcl_ListObjAppendElement(interp, result, Tcl_NewDoubleObj(offset[1])); 00313 Tcl_SetObjResult(interp, result); 00314 } else if (argc == 5) { 00315 const char *geomtype = argv[2]; 00316 int geom; 00317 if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; 00318 float x, y; 00319 if (sscanf(argv[4], "%f %f", &x, &y) != 2) { 00320 Tcl_AppendResult(interp, "Could not understand argument to label textoffset:", argv[2], NULL); 00321 return TCL_ERROR; 00322 } 00323 if (!app->label_set_textoffset(geomtype, geom, x, y)) { 00324 Tcl_SetResult(interp, (char *) "label textoffset: Invalid geometry specified", TCL_STATIC); 00325 return TCL_ERROR; 00326 } 00327 } else { 00328 Tcl_SetResult(interp, (char *) "label textoffset: wrong number of arguments", 00329 TCL_STATIC); 00330 return TCL_ERROR; 00331 } 00332 } else if (!strupncmp(argv[1], "textformat", CMDLEN)) { 00333 if (argc == 4) { 00334 // return current format 00335 const char *geomtype = argv[2]; 00336 int geom; 00337 if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; 00338 const char *format = app->geometryList->getTextFormat(geomtype, geom); 00339 if (!format) { 00340 Tcl_SetResult(interp, (char *) "label textformat: Invalid geometry specified", TCL_STATIC); 00341 return TCL_ERROR; 00342 } 00343 Tcl_SetResult(interp, (char *)format, TCL_VOLATILE); 00344 } else if (argc == 5) { 00345 const char *geomtype = argv[2]; 00346 int geom; 00347 if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; 00348 if (!app->label_set_textformat(geomtype, geom, argv[4])) { 00349 Tcl_SetResult(interp, (char *) "label textformat failed.", TCL_STATIC); 00350 return TCL_ERROR; 00351 } 00352 } else { 00353 Tcl_SetResult(interp, (char *) "label textformat: wrong number of arguments", 00354 TCL_STATIC); 00355 return TCL_ERROR; 00356 } 00357 } 00358 return TCL_OK; 00359 }