Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

offplugin.C

Go to the documentation of this file.
00001 /*
00002  *  Object File Format (.off)
00003  *
00004  *  Represent surfaces composed of polygons. It is documented there:
00005  *  http://people.sc.fsu.edu/~jburkardt/data/off/off.html
00006  *  http://shape.cs.princeton.edu/benchmark/documentation/off_format.html
00007  *
00008  *  Contributed by Francois-Xavier Coudert (fxcoudert@gmail.com)
00009  *
00010  */
00011 
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <ctype.h>
00015 #include <math.h>
00016 #include <string.h>
00017 
00018 #if defined(_AIX)
00019 #include <strings.h>
00020 #endif
00021 
00022 #if defined(WIN32) || defined(WIN64)
00023 #define strcasecmp stricmp
00024 #endif
00025 
00026 #include "molfile_plugin.h"
00027 
00028 // internal buffer size used in read_rawgraphics()
00029 #define BUFFLEN 1024
00030 
00031 static void *open_file_read(const char *filepath, const char *filetype,
00032                             int *natoms) {
00033   FILE *f;
00034   
00035   f = fopen(filepath, "rb");
00036   if (!f) {
00037     fprintf(stderr, "offplugin) Error opening file.\n");
00038     return NULL;
00039   }
00040   *natoms = 0;
00041   return f;
00042 }
00043 
00044 
00045 static char *nextNoncommentLine(char *buff, int bufflen, FILE *f) {
00046   while (1) {
00047     char *res = fgets(buff, bufflen, f);
00048     if (!res || (res[0] != '#' && res[0] != '\n' && res[0] != '\r'))
00049       return res;
00050   };
00051 }
00052 
00053 
00054 static void calcNormals (float vert[9], float norm[9]) {
00055   float x1 = vert[3] - vert[0];
00056   float y1 = vert[4] - vert[1];
00057   float z1 = vert[5] - vert[2];
00058   float x2 = vert[6] - vert[0];
00059   float y2 = vert[7] - vert[1];
00060   float z2 = vert[8] - vert[2];
00061   float nx = y1 * z2 - z1 * y2;
00062   float ny = z1 * x2 - x1 * z2;
00063   float nz = x1 * y2 - y1 * x2;
00064   float n = 1 / sqrtf(nx*nx+ny*ny+nz*nz);
00065   norm[0] = norm[3] = norm[6] = n * nx;
00066   norm[1] = norm[4] = norm[7] = n * ny;
00067   norm[2] = norm[5] = norm[8] = n * nz;
00068 }
00069 
00070 
00071 static int read_rawgraphics(void *v, int *nelem, 
00072                             const molfile_graphics_t **data) {
00073   int i, k, n;
00074   int nVert, nFaces, nEdges;
00075   float *vertices = NULL, *vertColors = NULL;
00076   char *vertHasColor = NULL;
00077   molfile_graphics_t *graphics = NULL;
00078   int j=0;
00079 
00080   char buff[BUFFLEN+1];
00081   FILE *infile = (FILE *)v;
00082 
00083   // First line is the header: "OFF"
00084   nextNoncommentLine(buff, BUFFLEN, infile);
00085   if (buff[0] != 'O' || buff[1] != 'F' || buff[2] != 'F') {
00086     fprintf(stderr, "offplugin) error: expected \"OFF\" header.\n");
00087     goto error;
00088   }
00089 
00090   // Second line: numVertices numFaces numEdges
00091   nextNoncommentLine(buff, BUFFLEN, infile);
00092   if (sscanf (buff, " %d %d %d", &nVert, &nFaces, &nEdges) < 2 || 
00093       nVert <= 0 || nFaces <= 0) {
00094     fprintf(stderr, "offplugin) error: wrong number of elements.\n");
00095     goto error;
00096   }
00097 
00098   // Read vertices
00099   vertices = (float *) calloc (3 * nVert, sizeof(float));
00100   vertHasColor = (char *) calloc (nVert, sizeof(char));
00101   vertColors = (float *) calloc (3 * nVert, sizeof(float));
00102   for (i = 0; i < nVert; i++) {
00103     nextNoncommentLine(buff, BUFFLEN, infile);
00104     int n = sscanf (buff, " %g %g %g %g %g %g", 
00105                     &vertices[3*i], &vertices[3*i+1], &vertices[3*i+2],
00106                     &vertColors[3*i], &vertColors[3*i+1], &vertColors[3*i+2]);
00107     if (n != 3 && n != 6) {
00108       fprintf(stderr, "offplugin) error: not enough data.\n");
00109       goto error;
00110     }
00111     vertHasColor[i] = (n == 6);
00112   }
00113 
00114   // Read faces
00115   // We alloc 6 times the memory because:
00116   //   -- a quadrangle will be transformed into two triangles.
00117   //   -- each triangle may have color, and then also its norm will be specified
00118   graphics = (molfile_graphics_t *) calloc(6*nFaces, sizeof(molfile_graphics_t));
00119   n = 0;
00120   for (i = 0; i < nFaces; i++) {
00121     int idx[4];
00122     float c[3];
00123     nextNoncommentLine(buff, BUFFLEN, infile);
00124 
00125     if (sscanf (buff, "%d", &k) != 1 || k < 3) {
00126       fprintf(stderr, "offplugin) error: not enough data.\n");
00127       goto error;
00128     }
00129 
00130     if (k > 4) {
00131       // TODO -- handle polygon decomposition into triangles
00132       // Follow the algorithm there:
00133       // http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
00134       fprintf(stderr, "offplugin) error: TODO -- handling polygons with more than 4 vertices.\n");
00135       goto error;
00136     }
00137 
00138     if (k == 3) {
00139       j = sscanf (buff, "%d %d %d %d %g %g %g", &k, &idx[0], &idx[1], &idx[2], &c[0], &c[1], &c[2]);
00140       bool hasColor = ((j == 7) || (vertHasColor[idx[0]] && vertHasColor[idx[1]] && vertHasColor[idx[2]]));
00141 
00142       graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
00143       graphics[n].data[0] = vertices[3*idx[0]  ];
00144       graphics[n].data[1] = vertices[3*idx[0]+1];
00145       graphics[n].data[2] = vertices[3*idx[0]+2];
00146       graphics[n].data[3] = vertices[3*idx[1]  ];
00147       graphics[n].data[4] = vertices[3*idx[1]+1];
00148       graphics[n].data[5] = vertices[3*idx[1]+2];
00149       graphics[n].data[6] = vertices[3*idx[2]  ];
00150       graphics[n].data[7] = vertices[3*idx[2]+1];
00151       graphics[n].data[8] = vertices[3*idx[2]+2];
00152       n++;
00153 
00154       if (j == 7) {
00155         // The facet has a specific color, use it.
00156         graphics[n].type = MOLFILE_NORMS;
00157         calcNormals (graphics[n-1].data, graphics[n].data);
00158         n++;
00159 
00160         graphics[n].type = MOLFILE_COLOR;
00161         graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
00162         graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
00163         graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
00164         n++;
00165       } else if (hasColor) {
00166         // All three vertices have a color attribute
00167         graphics[n].type = MOLFILE_NORMS;
00168         calcNormals (graphics[n-1].data, graphics[n].data);
00169         n++;
00170 
00171         graphics[n].type = MOLFILE_COLOR;
00172         graphics[n].data[0] = vertColors[3*idx[0]  ];
00173         graphics[n].data[1] = vertColors[3*idx[0]+1];
00174         graphics[n].data[2] = vertColors[3*idx[0]+2];
00175         graphics[n].data[3] = vertColors[3*idx[1]  ];
00176         graphics[n].data[4] = vertColors[3*idx[1]+1];
00177         graphics[n].data[5] = vertColors[3*idx[1]+2];
00178         graphics[n].data[6] = vertColors[3*idx[2]  ];
00179         graphics[n].data[7] = vertColors[3*idx[2]+1];
00180         graphics[n].data[8] = vertColors[3*idx[2]+2];
00181         n++;
00182       }
00183     } else if (k == 4) {
00184       j = sscanf (buff, "%d %d %d %d %d %g %g %g", &k, &idx[0], &idx[1], &idx[2], &idx[3], &c[0], &c[1], &c[2]);
00185       bool hasColor = ((j == 8) || (vertHasColor[idx[0]] && vertHasColor[idx[1]] && vertHasColor[idx[2]] && vertHasColor[idx[3]]));
00186 
00187       // Split a quadrangle into two triangles
00188       graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
00189       graphics[n].data[0] = vertices[3*idx[0]  ];
00190       graphics[n].data[1] = vertices[3*idx[0]+1];
00191       graphics[n].data[2] = vertices[3*idx[0]+2];
00192       graphics[n].data[3] = vertices[3*idx[1]  ];
00193       graphics[n].data[4] = vertices[3*idx[1]+1];
00194       graphics[n].data[5] = vertices[3*idx[1]+2];
00195       graphics[n].data[6] = vertices[3*idx[2]  ];
00196       graphics[n].data[7] = vertices[3*idx[2]+1];
00197       graphics[n].data[8] = vertices[3*idx[2]+2];
00198       n++;
00199 
00200       if (j == 8) {
00201         graphics[n].type = MOLFILE_NORMS;
00202         calcNormals (graphics[n-1].data, graphics[n].data);
00203         n++;
00204       
00205         graphics[n].type = MOLFILE_COLOR;
00206         graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
00207         graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
00208         graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
00209         n++;
00210       } else if (hasColor) {
00211         graphics[n].type = MOLFILE_NORMS;
00212         calcNormals (graphics[n-1].data, graphics[n].data);
00213         n++;
00214 
00215         graphics[n].type = MOLFILE_COLOR;
00216         graphics[n].data[0] = vertColors[3*idx[0]];
00217         graphics[n].data[1] = vertColors[3*idx[0]+1];
00218         graphics[n].data[2] = vertColors[3*idx[0]+2];
00219         graphics[n].data[3] = vertColors[3*idx[1]];
00220         graphics[n].data[4] = vertColors[3*idx[1]+1];
00221         graphics[n].data[5] = vertColors[3*idx[1]+2];
00222         graphics[n].data[6] = vertColors[3*idx[2]];
00223         graphics[n].data[7] = vertColors[3*idx[2]+1];
00224         graphics[n].data[8] = vertColors[3*idx[2]+2];
00225         n++;
00226       }
00227 
00228       graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
00229       graphics[n].data[0] = vertices[3*idx[2]];
00230       graphics[n].data[1] = vertices[3*idx[2]+1];
00231       graphics[n].data[2] = vertices[3*idx[2]+2];
00232       graphics[n].data[3] = vertices[3*idx[3]];
00233       graphics[n].data[4] = vertices[3*idx[3]+1];
00234       graphics[n].data[5] = vertices[3*idx[3]+2];
00235       graphics[n].data[6] = vertices[3*idx[0]];
00236       graphics[n].data[7] = vertices[3*idx[0]+1];
00237       graphics[n].data[8] = vertices[3*idx[0]+2];
00238       n++;
00239 
00240       if (j == 8) {
00241         graphics[n].type = MOLFILE_NORMS;
00242         calcNormals (graphics[n-1].data, graphics[n].data);
00243         n++;
00244 
00245         graphics[n].type = MOLFILE_COLOR;
00246         graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
00247         graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
00248         graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
00249         n++;
00250       } else if (hasColor) {
00251         graphics[n].type = MOLFILE_NORMS;
00252         calcNormals (graphics[n-1].data, graphics[n].data);
00253         n++;
00254 
00255         graphics[n].type = MOLFILE_COLOR;
00256         graphics[n].data[0] = vertColors[3*idx[2]];
00257         graphics[n].data[1] = vertColors[3*idx[2]+1];
00258         graphics[n].data[2] = vertColors[3*idx[2]+2];
00259         graphics[n].data[3] = vertColors[3*idx[3]];
00260         graphics[n].data[4] = vertColors[3*idx[3]+1];
00261         graphics[n].data[5] = vertColors[3*idx[3]+2];
00262         graphics[n].data[6] = vertColors[3*idx[0]];
00263         graphics[n].data[7] = vertColors[3*idx[0]+1];
00264         graphics[n].data[8] = vertColors[3*idx[0]+2];
00265         n++;
00266       }
00267     }
00268   }
00269 
00270   *nelem = n;
00271   *data = (molfile_graphics_t *) realloc(graphics, n*sizeof(molfile_graphics_t));
00272   return MOLFILE_SUCCESS;
00273 
00274   // goto jump target for disaster handling: free memory and bail out
00275   error:
00276     free (graphics);
00277     free (vertices);
00278     return MOLFILE_ERROR;
00279 }
00280 
00281 
00282 static void close_file_read(void *v) {
00283   fclose((FILE *)v);
00284 }
00285 
00286 
00287 /*
00288  * Initialization stuff here
00289  */
00290 static molfile_plugin_t plugin;
00291 
00292 VMDPLUGIN_API int VMDPLUGIN_init(void) {
00293   memset(&plugin, 0, sizeof(molfile_plugin_t));
00294   plugin.abiversion = vmdplugin_ABIVERSION;
00295   plugin.type = MOLFILE_PLUGIN_TYPE;
00296   plugin.name = "off";
00297   plugin.prettyname = "Object File Format (OFF)";
00298   plugin.author = "Francois-Xavier Coudert";
00299   plugin.majorv = 0;
00300   plugin.minorv = 4;
00301   plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
00302   plugin.filename_extension = "off";
00303   plugin.open_file_read = open_file_read;
00304   plugin.read_rawgraphics = read_rawgraphics;
00305   plugin.close_file_read = close_file_read;
00306   return VMDPLUGIN_SUCCESS;
00307 }
00308 
00309 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00310   (*cb)(v, (vmdplugin_t *)&plugin);
00311   return VMDPLUGIN_SUCCESS;
00312 }
00313 
00314 VMDPLUGIN_API int VMDPLUGIN_fini(void) { return VMDPLUGIN_SUCCESS; }
00315 

Generated on Fri Jan 17 02:57:48 2020 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002