diff --git a/src/dump_image.cpp b/src/dump_image.cpp index 3dbf9f6ae..d41be6a33 100644 --- a/src/dump_image.cpp +++ b/src/dump_image.cpp @@ -1,2311 +1,2311 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Nathan Fabian (Sandia) ------------------------------------------------------------------------- */ #include "mpi.h" #include "math.h" #include "ctype.h" #include "stdlib.h" #include "string.h" #include "dump_image.h" #include "math_extra.h" #include "atom.h" #include "domain.h" #include "group.h" #include "force.h" #include "comm.h" #include "input.h" #include "variable.h" #include "random_mars.h" #include "error.h" #include "memory.h" #ifdef LAMMPS_JPEG #include "jpeglib.h" #endif using namespace LAMMPS_NS; #define NCOLORS 140 #define NELEMENTS 109 #define BIG 1.0e20 enum{PPM,JPG}; enum{NUMERIC,ATOM,TYPE,ELEMENT,ATTRIBUTE,MINVALUE,MAXVALUE}; enum{STATIC,DYNAMIC}; enum{CONTINUOUS,DISCRETE,SEQUENTIAL}; enum{ABSOLUTE,FRACTIONAL}; enum{NO,YES}; #define MIN(A,B) ((A) < (B)) ? (A) : (B) #define MAX(A,B) ((A) > (B)) ? (A) : (B) /* ---------------------------------------------------------------------- */ DumpImage::DumpImage(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg) { if (binary || multiproc) error->all("Invalid dump image filename"); PI = 4.0*atan(1.0); // set filetype based on filename suffix int n = strlen(filename); if (strlen(filename) > 4 && strcmp(&filename[n-4],".jpg") == 0) filetype = JPG; else if (strlen(filename) > 5 && strcmp(&filename[n-5],".jpeg") == 0) filetype = JPG; else filetype = PPM; #ifndef LAMMPS_JPEG if (filetype == JPG) error->all("Cannot dump JPG file"); #endif // atom color,diameter settings if (nfield != 2) error->all("Illegal dump image command"); acolor = ATTRIBUTE; if (strcmp(arg[5],"type") == 0) acolor = TYPE; else if (strcmp(arg[5],"element") == 0) acolor = ELEMENT; adiam = ATTRIBUTE; if (strcmp(arg[6],"type") == 0) adiam = TYPE; else if (strcmp(arg[6],"element") == 0) adiam = ELEMENT; // set defaults for optional args atomflag = YES; if (atom->nbondtypes == 0) bondflag = NO; else { bondflag = YES; bcolor = ATOM; bdiam = NUMERIC; bdiamvalue = 0.5; } width = height = 512; theta = 60.0 * PI/180.0; phi = 30.0 * PI/180.0; thetastr = phistr = NULL; cflag = STATIC; cx = cy = cz = 0.5; cxstr = cystr = czstr = NULL; if (domain->dimension == 3) { up[0] = 0.0; up[1] = 0.0; up[2] = 1.0; } else { up[0] = 0.0; up[1] = 1.0; up[2] = 0.0; } upxstr = upystr = upzstr = NULL; zoom = 1.0; zoomstr = NULL; persp = 0.0; perspstr = NULL; boxflag = YES; boxdiam = 0.02; axesflag = NO; shiny = 1.0; ssao = NO; // parse optional args int iarg = ioptional; while (iarg < narg) { if (strcmp(arg[iarg],"adiam") == 0) { if (iarg+2 > narg) error->all("Illegal dump image command"); adiam = NUMERIC; adiamvalue = atof(arg[iarg+1]); if (adiamvalue <= 0.0) error->all("Illegal dump image command"); iarg += 2; } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+2 > narg) error->all("Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) atomflag = YES; else if (strcmp(arg[iarg+1],"no") == 0) atomflag = NO; else error->all("Illegal dump image command"); iarg += 2; } else if (strcmp(arg[iarg],"bond") == 0) { if (iarg+3 > narg) error->all("Illegal dump image command"); if (atom->nbondtypes == 0) error->all("Dump image bond not allowed with no bond types"); bondflag = YES; if (strcmp(arg[iarg+1],"none") == 0) bondflag = NO; else if (strcmp(arg[iarg+1],"atom") == 0) bcolor = ATOM; else if (strcmp(arg[iarg+1],"type") == 0) bcolor = TYPE; else error->all("Illegal dump image command"); if (!islower(arg[iarg+2][0])) { bdiam = NUMERIC; bdiamvalue = atof(arg[iarg+2]); if (bdiamvalue <= 0.0) error->all("Illegal dump image command"); } else if (strcmp(arg[iarg+2],"atom") == 0) bdiam = ATOM; else if (strcmp(arg[iarg+2],"type") == 0) bdiam = TYPE; else if (strcmp(arg[iarg+2],"none") == 0) bondflag = NO; else error->all("Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"size") == 0) { if (iarg+3 > narg) error->all("Illegal dump image command"); width = atoi(arg[iarg+1]); height = atoi(arg[iarg+2]); if (width <= 0 || height <= 0) error->all("Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"view") == 0) { if (iarg+3 > narg) error->all("Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; thetastr = new char[n]; strcpy(thetastr,&arg[iarg+1][2]); } else { theta = atof(arg[iarg+1]); if (theta < 0.0 || theta > 180.0) error->all("Invalid dump image theta value"); theta *= PI/180.0; } - if (strstr(arg[iarg+1],"v_") == arg[iarg+2]) { + if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; phistr = new char[n]; strcpy(phistr,&arg[iarg+2][2]); } else { phi = atof(arg[iarg+2]); phi *= PI/180.0; } iarg += 3; } else if (strcmp(arg[iarg],"center") == 0) { if (iarg+5 > narg) error->all("Illegal dump image command"); if (strcmp(arg[iarg+1],"s") == 0) cflag = STATIC; else if (strcmp(arg[iarg+1],"d") == 0) cflag = DYNAMIC; else error->all("Illegal dump image command"); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; cxstr = new char[n]; strcpy(cxstr,&arg[iarg+2][2]); cflag = DYNAMIC; } else cx = atof(arg[iarg+2]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) { int n = strlen(&arg[iarg+3][2]) + 1; cystr = new char[n]; strcpy(cystr,&arg[iarg+3][2]); cflag = DYNAMIC; } else cy = atof(arg[iarg+3]); if (strstr(arg[iarg+4],"v_") == arg[iarg+4]) { int n = strlen(&arg[iarg+4][2]) + 1; czstr = new char[n]; strcpy(czstr,&arg[iarg+4][2]); cflag = DYNAMIC; } else cz = atof(arg[iarg+4]); iarg += 5; } else if (strcmp(arg[iarg],"up") == 0) { if (iarg+4 > narg) error->all("Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; upxstr = new char[n]; strcpy(upxstr,&arg[iarg+1][2]); } else up[0] = atof(arg[iarg+1]); if (strstr(arg[iarg+2],"v_") == arg[iarg+2]) { int n = strlen(&arg[iarg+2][2]) + 1; upystr = new char[n]; strcpy(upystr,&arg[iarg+2][2]); } else up[1] = atof(arg[iarg+1]); if (strstr(arg[iarg+3],"v_") == arg[iarg+3]) { int n = strlen(&arg[iarg+3][2]) + 1; upzstr = new char[n]; strcpy(upzstr,&arg[iarg+3][2]); } else up[2] = atof(arg[iarg+3]); iarg += 4; } else if (strcmp(arg[iarg],"zoom") == 0) { if (iarg+2 > narg) error->all("Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; zoomstr = new char[n]; strcpy(zoomstr,&arg[iarg+1][2]); } else { zoom = atof(arg[iarg+1]); if (zoom <= 0.0) error->all("Illegal dump image command"); } iarg += 2; } else if (strcmp(arg[iarg],"persp") == 0) { error->all("Dump image persp option is not yet supported"); if (iarg+2 > narg) error->all("Illegal dump image command"); if (strstr(arg[iarg+1],"v_") == arg[iarg+1]) { int n = strlen(&arg[iarg+1][2]) + 1; perspstr = new char[n]; strcpy(perspstr,&arg[iarg+1][2]); } else { persp = atof(arg[iarg+1]); if (persp < 0.0) error->all("Illegal dump image command"); } iarg += 2; } else if (strcmp(arg[iarg],"box") == 0) { if (iarg+3 > narg) error->all("Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) boxflag = YES; else if (strcmp(arg[iarg+1],"no") == 0) boxflag = NO; else error->all("Illegal dump image command"); boxdiam = atof(arg[iarg+2]); if (boxdiam < 0.0) error->all("Illegal dump image command"); iarg += 3; } else if (strcmp(arg[iarg],"axes") == 0) { if (iarg+3 > narg) error->all("Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) axesflag = YES; else if (strcmp(arg[iarg+1],"no") == 0) axesflag = NO; else error->all("Illegal dump image command"); axeslen = atof(arg[iarg+2]); axesdiam = atof(arg[iarg+3]); if (axeslen < 0.0 || axesdiam < 0.0) error->all("Illegal dump image command"); iarg += 4; } else if (strcmp(arg[iarg],"shiny") == 0) { if (iarg+2 > narg) error->all("Illegal dump image command"); shiny = atof(arg[iarg+1]); if (shiny < 0.0 || shiny > 1.0) error->all("Illegal dump image command"); iarg += 2; } else if (strcmp(arg[iarg],"ssao") == 0) { if (iarg+4 > narg) error->all("Illegal dump image command"); if (strcmp(arg[iarg+1],"yes") == 0) ssao = YES; else if (strcmp(arg[iarg+1],"no") == 0) ssao = NO; else error->all("Illegal dump image command"); seed = atoi(arg[iarg+2]); if (seed <= 0) error->all("Illegal dump image command"); ssaoint = atof(arg[iarg+3]); if (ssaoint < 0.0 || ssaoint > 1.0) error->all("Illegal dump image command"); iarg += 4; } else error->all("Illegal dump image command"); } // params based on args npixels = width * height; if (bondflag) { if (bcolor == ATOM || bdiam == ATOM) comm_forward = 3; else comm_forward = 1; } // additional defaults for dump_modify options ncolors = 0; username = NULL; userrgb = NULL; diamtype = new double[ntypes+1]; diamelement = new double[ntypes+1]; colortype = new double*[ntypes+1]; colorelement = new double*[ntypes+1]; for (int i = 1; i <= ntypes; i++) { diamtype[i] = 1.0; if (i % 6 == 1) colortype[i] = color2rgb("red"); else if (i % 6 == 2) colortype[i] = color2rgb("green"); else if (i % 6 == 3) colortype[i] = color2rgb("blue"); else if (i % 6 == 4) colortype[i] = color2rgb("yellow"); else if (i % 6 == 5) colortype[i] = color2rgb("aqua"); else if (i % 6 == 0) colortype[i] = color2rgb("cyan"); } if (bondflag) { bdiamtype = new double[atom->nbondtypes+1]; bcolortype = new double*[atom->nbondtypes+1]; for (int i = 1; i <= atom->nbondtypes; i++) { bdiamtype[i] = 0.5; if (i % 6 == 1) bcolortype[i] = color2rgb("red"); else if (i % 6 == 2) bcolortype[i] = color2rgb("green"); else if (i % 6 == 3) bcolortype[i] = color2rgb("blue"); else if (i % 6 == 4) bcolortype[i] = color2rgb("yellow"); else if (i % 6 == 5) bcolortype[i] = color2rgb("aqua"); else if (i % 6 == 0) bcolortype[i] = color2rgb("cyan"); } } else { bdiamtype = NULL; bcolortype = NULL; } boxcolor = color2rgb("yellow"); background[0] = background[1] = background[2] = 0; mlo = MINVALUE; mhi = MAXVALUE; mstyle = CONTINUOUS; mrange = FRACTIONAL; nentry = 2; mentry = new MapEntry[nentry]; mentry[0].svalue = 0.0; mentry[0].color = color2rgb("blue"); mentry[1].svalue = 1.0; mentry[1].color = color2rgb("red"); // static parameters FOV = PI/6.0; // 30 degrees ambientColor[0] = 0.0; ambientColor[1] = 0.0; ambientColor[2] = 0.0; keyLightPhi = -PI/4.0; // -45 degrees keyLightTheta = PI/6.0; // 30 degrees keyLightColor[0] = 0.9; keyLightColor[1] = 0.9; keyLightColor[2] = 0.9; fillLightPhi = PI/6.0; // 30 degrees fillLightTheta = 0; fillLightColor[0] = 0.9; fillLightColor[1] = 0.9; fillLightColor[2] = 0.9; backLightPhi = PI; // 180 degrees backLightTheta = PI/12.0; // 15 degrees backLightColor[0] = 0.9; backLightColor[1] = 0.9; backLightColor[2] = 0.9; // viewflag = DYNAMIC if any view parameter is dynamic viewflag = STATIC; if (thetastr || phistr || cflag == DYNAMIC || upxstr || upystr || upzstr || zoomstr || perspstr) viewflag = DYNAMIC; if (cflag == STATIC) box_center(); if (viewflag == STATIC) view_params(); // image and depth buffers depthBuffer = (double *) memory->smalloc(npixels*sizeof(double), "dump:depthBuffer"); surfaceBuffer = (double *) memory->smalloc(2*npixels*sizeof(double), "dump:surfaceBuffer"); imageBuffer = (char *) memory->smalloc(3*npixels*sizeof(char), "dump:imageBuffer"); depthcopy = (double *) memory->smalloc(npixels*sizeof(double), "dump:depthcopy"); surfacecopy = (double *) memory->smalloc(npixels*2*sizeof(double), "dump:surfacecopy"); rgbcopy = (char *) memory->smalloc(3*npixels*sizeof(char), "dump:rgbcopy"); maxbufcopy = 0; bufcopy = NULL; // RNG for SSAO depth shading if (ssao) random = new RanMars(lmp,seed+me); else random = NULL; } /* ---------------------------------------------------------------------- */ DumpImage::~DumpImage() { delete [] diamtype; delete [] diamelement; delete [] colortype; delete [] colorelement; delete [] bdiamtype; delete [] bcolortype; for (int i = 0; i < ncolors; i++) delete [] username[i]; memory->sfree(username); memory->destroy(userrgb); delete [] mentry; memory->sfree(depthBuffer); memory->sfree(surfaceBuffer); memory->sfree(imageBuffer); memory->sfree(depthcopy); memory->sfree(surfacecopy); memory->sfree(rgbcopy); memory->destroy(bufcopy); delete random; } /* ---------------------------------------------------------------------- */ void DumpImage::init_style() { if (multifile == 0) error->all("Dump image requires one snapshot per file"); if (sort_flag) error->all("Dump image cannot perform sorting"); DumpCustom::init_style(); // check variables if (thetastr) { thetavar = input->variable->find(thetastr); if (thetavar < 0) error->all("Variable name for dump image theta does not exist"); if (!input->variable->equalstyle(thetavar)) error->all("Variable for dump image theta is invalid style"); } if (phistr) { phivar = input->variable->find(phistr); if (phivar < 0) error->all("Variable name for dump image phi does not exist"); if (!input->variable->equalstyle(phivar)) error->all("Variable for dump image phi is invalid style"); } if (cxstr) { cxvar = input->variable->find(cxstr); if (cxvar < 0) error->all("Variable name for dump image center does not exist"); if (!input->variable->equalstyle(cxvar)) error->all("Variable for dump image center is invalid style"); } if (cystr) { cyvar = input->variable->find(cystr); if (cyvar < 0) error->all("Variable name for dump image center does not exist"); if (!input->variable->equalstyle(cyvar)) error->all("Variable for dump image center is invalid style"); } if (czstr) { czvar = input->variable->find(czstr); if (czvar < 0) error->all("Variable name for dump image center does not exist"); if (!input->variable->equalstyle(czvar)) error->all("Variable for dump image center is invalid style"); } if (upxstr) { upxvar = input->variable->find(upxstr); if (upxvar < 0) error->all("Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upxvar)) error->all("Variable for dump image center is invalid style"); } if (upystr) { upyvar = input->variable->find(upystr); if (upyvar < 0) error->all("Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upyvar)) error->all("Variable for dump image center is invalid style"); } if (upzstr) { upzvar = input->variable->find(upzstr); if (upzvar < 0) error->all("Variable name for dump image center does not exist"); if (!input->variable->equalstyle(upzvar)) error->all("Variable for dump image center is invalid style"); } if (zoomstr) { zoomvar = input->variable->find(zoomstr); if (zoomvar < 0) error->all("Variable name for dump image zoom does not exist"); if (!input->variable->equalstyle(zoomvar)) error->all("Variable for dump image zoom is invalid style"); } if (perspstr) { perspvar = input->variable->find(perspstr); if (perspvar < 0) error->all("Variable name for dump image persp does not exist"); if (!input->variable->equalstyle(perspvar)) error->all("Variable for dump image persp is invalid style"); } // set up type -> element mapping if (atomflag && acolor == ELEMENT) { for (int i = 1; i <= ntypes; i++) { colorelement[i] = element2color(typenames[i]); if (colorelement[i] == NULL) error->all("Invalid dump image element name"); } } if (atomflag && adiam == ELEMENT) { for (int i = 1; i <= ntypes; i++) { diamelement[i] = element2diam(typenames[i]); if (diamelement[i] == 0.0) error->all("Invalid dump image element name"); } } } /* ---------------------------------------------------------------------- */ void DumpImage::write() { MPI_Request requests[3]; MPI_Status statuses[3]; // open new file openfile(); // reset box center and view parameters if dynamic if (cflag == DYNAMIC) box_center(); if (viewflag == DYNAMIC) view_params(); // nme = # of atoms this proc will contribute to dump // pack buf with x,y,z,color,diameter // set minmax color range if using color map // create my portion of image for my particles nme = count(); if (nme > maxbuf) { maxbuf = nme; memory->destroy(buf); memory->create(buf,maxbuf*size_one,"dump:buf"); } pack(NULL); if (acolor == ATTRIBUTE) color_minmax(); create_image(); // merge images across procs using depth buffer // hi procs send to lo procs, cascading down logarithmically int nhalf = 1; while (nhalf < nprocs) nhalf *= 2; nhalf /= 2; while (nhalf) { if (me < nhalf && me+nhalf < nprocs) { MPI_Irecv(rgbcopy,npixels*3,MPI_BYTE,me+nhalf,0,world,&requests[0]); MPI_Irecv(depthcopy,npixels,MPI_DOUBLE,me+nhalf,0,world,&requests[1]); if (ssao) MPI_Irecv(surfacecopy,npixels*2,MPI_DOUBLE, me+nhalf,0,world,&requests[2]); if (ssao) MPI_Waitall(3,requests,statuses); else MPI_Waitall(2,requests,statuses); for (int i = 0; i < npixels; i++) { if (depthBuffer[i] < 0 || (depthcopy[i] >= 0 && depthcopy[i] < depthBuffer[i])) { depthBuffer[i] = depthcopy[i]; imageBuffer[i*3+0] = rgbcopy[i*3+0]; imageBuffer[i*3+1] = rgbcopy[i*3+1]; imageBuffer[i*3+2] = rgbcopy[i*3+2]; if (ssao) { surfaceBuffer[i*2+0] = surfacecopy[i*2+0]; surfaceBuffer[i*2+1] = surfacecopy[i*2+1]; } } } } else if (me >= nhalf && me < 2*nhalf) { MPI_Send(imageBuffer,npixels*3,MPI_BYTE,me-nhalf,0,world); MPI_Send(depthBuffer,npixels,MPI_DOUBLE,me-nhalf,0,world); if (ssao) MPI_Send(surfaceBuffer,npixels*2,MPI_DOUBLE,me-nhalf,0,world); } nhalf /= 2; } // extra SSAO enhancement // bcast full image to all procs // each works on subset of pixels // gather result back to proc 0 if (ssao) { MPI_Bcast(imageBuffer,npixels*3,MPI_BYTE,0,world); MPI_Bcast(surfaceBuffer,npixels*2,MPI_DOUBLE,0,world); MPI_Bcast(depthBuffer,npixels,MPI_DOUBLE,0,world); compute_SSAO(); int pixelPart = height/nprocs * width*3; MPI_Gather(imageBuffer+me*pixelPart,pixelPart,MPI_BYTE, rgbcopy,pixelPart,MPI_BYTE,0,world); writeBuffer = rgbcopy; } else { writeBuffer = imageBuffer; } // write image file if (me == 0) { if (filetype == JPG) write_JPG(); else write_PPM(); fclose(fp); } } /* ---------------------------------------------------------------------- reset view parameters called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::box_center() { box_bounds(); if (cxstr) phi = input->variable->compute_equal(cxvar); if (cystr) phi = input->variable->compute_equal(cyvar); if (czstr) phi = input->variable->compute_equal(czvar); xctr = boxxlo + cx*(boxxhi-boxxlo); yctr = boxylo + cy*(boxyhi-boxylo); zctr = boxzlo + cz*(boxzhi-boxzlo); } /* ---------------------------------------------------------------------- reset view parameters called once from constructor if view is STATIC called every snapshot from write() if view is DYNAMIC ------------------------------------------------------------------------- */ void DumpImage::view_params() { // camDir = camera direction if (thetastr) { theta = input->variable->compute_equal(thetavar); if (theta < 0.0 || theta > 180.0) error->all("Invalid dump image theta value"); theta *= PI/180.0; } if (phistr) { phi = input->variable->compute_equal(phivar); phi *= PI/180.0; } camDir[0] = sin(theta)*cos(phi); camDir[1] = sin(theta)*sin(phi); camDir[2] = cos(theta); // up vector if (upxstr) up[0] = input->variable->compute_equal(upxvar); if (upystr) up[1] = input->variable->compute_equal(upyvar); if (upzstr) up[2] = input->variable->compute_equal(upzvar); // zdist = camera distance = function of zoom & bounding box // camPos = camera position = function of camDir and zdist box_bounds(); if (zoomstr) zoom = input->variable->compute_equal(zoomvar); if (zoom <= 0.0) error->all("Invalid dump image zoom value"); if (perspstr) persp = input->variable->compute_equal(perspvar); if (persp < 0.0) error->all("Invalid dump image persp value"); double delx = 2.0*(boxxhi-boxxlo); double dely = 2.0*(boxyhi-boxylo); double delz = 2.0*(boxzhi-boxzlo); double maxdel = MAX(delx,dely); maxdel = MAX(maxdel,delz); zdist = maxdel; zdist /= tan(FOV); zdist += 0.5 * (delx*camDir[0] + dely*camDir[1] + delz*camDir[2]); zdist /= zoom; camPos[0] = camDir[0] * zdist; camPos[1] = camDir[1] * zdist; camPos[2] = camDir[2] * zdist; // camUp = camDir x (Up x camDir) // camDir points at the camera, view direction = -camDir if (camDir[0] == up[0] && camDir[1] == up[1] && camDir[2] == up[2]) { double tmp = up[0]; up[0] = up[1]; up[1] = up[2]; up[2] = tmp; } MathExtra::cross3(up,camDir,camRight); MathExtra::norm3(camRight); MathExtra::cross3(camDir,camRight,camUp); if (camUp[0] == 0.0 && camUp[1] == 0.0 && camUp[2] == 0.0) error->all("Invalid dump image up vector"); MathExtra::norm3(camUp); // light directions in terms of -camDir = z keyLightDir[0] = cos(keyLightTheta) * sin(keyLightPhi); keyLightDir[1] = sin(keyLightTheta); keyLightDir[2] = cos(keyLightTheta) * cos(keyLightPhi); fillLightDir[0] = cos(fillLightTheta) * sin(fillLightPhi); fillLightDir[1] = sin(fillLightTheta); fillLightDir[2] = cos(fillLightTheta) * cos(fillLightPhi); backLightDir[0] = cos(backLightTheta) * sin(backLightPhi); backLightDir[1] = sin(backLightTheta); backLightDir[2] = cos(backLightTheta) * cos(backLightPhi); keyHalfDir[0] = 0 + keyLightDir[0]; keyHalfDir[1] = 0 + keyLightDir[1]; keyHalfDir[2] = 1 + keyLightDir[2]; MathExtra::norm3(keyHalfDir); // adjust shinyness of the reflection specularHardness = 16.0 * shiny; specularIntensity = shiny; // adjust strength of the SSAO if (ssao) { SSAORadius = maxdel * 0.05 * ssaoint; SSAOSamples = static_cast<int> (8.0 + 32.0*ssaoint); SSAOJitter = PI / 12; ambientColor[0] = 0.5; ambientColor[1] = 0.5; ambientColor[2] = 0.5; } // param for rasterizing spheres tanPerPixel = -(maxdel / (double) height); } /* ---------------------------------------------------------------------- simulation box bounds ------------------------------------------------------------------------- */ void DumpImage::box_bounds() { if (domain->triclinic == 0) { boxxlo = domain->boxlo[0]; boxxhi = domain->boxhi[0]; boxylo = domain->boxlo[1]; boxyhi = domain->boxhi[1]; boxzlo = domain->boxlo[2]; boxzhi = domain->boxhi[2]; } else { boxxlo = domain->boxlo_bound[0]; boxxhi = domain->boxhi_bound[0]; boxylo = domain->boxlo_bound[1]; boxyhi = domain->boxhi_bound[1]; boxzlo = domain->boxlo_bound[2]; boxzhi = domain->boxhi_bound[2]; boxxy = domain->xy; boxxz = domain->xz; boxyz = domain->yz; } } /* ---------------------------------------------------------------------- set explicit values for all min/max settings in color map lo/hi current and lvalue/hvalue settings for lo/hi = MIN/MAX VALUE in entries if mlo/mhi = MIN/MAX VALUE, compute bounds on just the atoms being visualized ------------------------------------------------------------------------- */ void DumpImage::color_minmax() { double two[2],twoall[2]; if (mlo == MINVALUE || mhi == MAXVALUE) { double lo = BIG; double hi = -BIG; int m = 0; for (int i = 0; i < nchoose; i++) { lo = MIN(lo,buf[m]); hi = MAX(hi,buf[m+1]); m += size_one; } two[0] = -lo; two[1] = hi; MPI_Allreduce(two,twoall,2,MPI_DOUBLE,MPI_MAX,world); } if (mlo == MINVALUE) locurrent = -twoall[0]; else locurrent = mlovalue; if (mhi == MAXVALUE) hicurrent = twoall[1]; else hicurrent = mhivalue; if (locurrent > hicurrent) error->all("Invalid dump image color range"); if (mstyle == CONTINUOUS) { if (mrange == ABSOLUTE) mentry[0].svalue = locurrent; else mentry[0].svalue = 0.0; if (mrange == ABSOLUTE) mentry[nentry-1].svalue = hicurrent; else mentry[nentry-1].svalue = 1.0; } else if (mstyle == DISCRETE) { for (int i = 0; i < nentry; i++) { if (mentry[i].lo == MINVALUE) { if (mrange == ABSOLUTE) mentry[i].lvalue = locurrent; else mentry[i].lvalue = 0.0; } if (mentry[i].hi == MAXVALUE) { if (mrange == ABSOLUTE) mentry[i].hvalue = hicurrent; else mentry[i].hvalue = 1.0; } } } } /* ---------------------------------------------------------------------- create image for atoms on this proc every pixel has depth ------------------------------------------------------------------------- */ void DumpImage::create_image() { int i,j,m,itype,atom1,atom2; double diameter,delx,dely,delz; double *color,*color1,*color2; double xmid[3]; // initialze image buffers // no need to init surfaceBuffer, since will be based on depth int red = background[0]; int green = background[1]; int blue = background[2]; int ix,iy; for (iy = 0; iy < height; iy ++) { for (ix = 0; ix < width; ix ++) { imageBuffer[iy * width * 3 + ix * 3 + 0] = red; imageBuffer[iy * width * 3 + ix * 3 + 1] = green; imageBuffer[iy * width * 3 + ix * 3 + 2] = blue; depthBuffer[iy * width + ix] = -1; } } // render my atoms if (atomflag) { double **x = atom->x; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; if (acolor == TYPE) { itype = static_cast<int> (buf[m]); color = colortype[itype]; } else if (acolor == ELEMENT) { itype = static_cast<int> (buf[m]); color = colorelement[itype]; } else if (acolor == ATTRIBUTE) { color = value2color(buf[m]); } if (adiam == NUMERIC) { diameter = adiamvalue; } else if (adiam == TYPE) { itype = static_cast<int> (buf[m+1]); diameter = diamtype[itype]; } else if (adiam == ELEMENT) { itype = static_cast<int> (buf[m+1]); diameter = diamelement[itype]; } else if (adiam == ATTRIBUTE) { diameter = buf[m+1]; } draw_sphere(x[j],color,diameter); m += size_one; } } // render bonds for my atoms // both atoms in bond must be selected for bond to be rendered // if newton_bond is off, only render bond once // render bond in 2 pieces if crosses periodic boundary // if bond is deleted (type = 0), do not render // if bond is turned off (type < 0), still render if (bondflag) { double **x = atom->x; int *tag = atom->tag; int **bond_atom = atom->bond_atom; int **bond_type = atom->bond_type; int *num_bond = atom->num_bond; int *type = atom->type; int nlocal = atom->nlocal; int nall = atom->nlocal + atom->nghost; int newton_bond = force->newton_bond; // communicate choose flag for ghost atoms to know if they are selected // if bcolor/bdiam = ATOM, setup bufcopy to comm atom color/diam attributes if (comm_forward == 3) { if (nall > maxbufcopy) { maxbufcopy = atom->nmax; memory->destroy(bufcopy); memory->create(bufcopy,maxbufcopy,2,"dump:bufcopy"); } for (i = 0; i < nlocal; i++) bufcopy[i][0] = bufcopy[i][1] = 0.0; m = 0; for (i = 0; i < nchoose; i++) { j = clist[i]; bufcopy[j][0] = buf[m]; bufcopy[j][1] = buf[m+1]; m += size_one; } } comm->forward_comm_dump(this); for (i = 0; i < nchoose; i++) { atom1 = clist[i]; for (m = 0; m < num_bond[atom1]; m++) { atom2 = atom->map(bond_atom[atom1][m]); if (atom2 < 0 || !choose[atom2]) continue; if (newton_bond == 0 && tag[atom1] > tag[atom2]) continue; if (bond_type[atom1][m] == 0) continue; if (bcolor == ATOM) { if (acolor == TYPE) { color1 = colortype[type[atom1]]; color2 = colortype[type[atom2]]; } else if (acolor == ELEMENT) { color1 = colorelement[type[atom1]]; color2 = colorelement[type[atom2]]; } else if (acolor == ATTRIBUTE) { color1 = value2color(bufcopy[atom1][0]); color2 = value2color(bufcopy[atom2][0]); } } else if (bcolor == TYPE) { itype = bond_type[atom1][m]; if (itype < 0) itype = -itype; color = bcolortype[itype]; } if (bdiam == NUMERIC) { diameter = bdiamvalue; } else if (bdiam == ATOM) { if (adiam == NUMERIC) { diameter = adiamvalue; } else if (adiam == TYPE) { diameter = MIN(diamtype[type[atom1]],diamtype[type[atom1]]); } else if (adiam == ELEMENT) { diameter = MIN(diamelement[type[atom1]],diamelement[type[atom1]]); } else if (adiam == ATTRIBUTE) { diameter = MIN(bufcopy[atom1][1],bufcopy[atom2][1]); } } else if (bdiam == TYPE) { itype = bond_type[atom1][m]; if (itype < 0) itype = -itype; diameter = bdiamtype[itype]; } // draw cylinder in 2 pieces if bcolor = ATOM // or bond crosses periodic boundary delx = x[atom2][0] - x[atom1][0]; dely = x[atom2][1] - x[atom1][1]; delz = x[atom2][2] - x[atom1][2]; if (bcolor == ATOM || domain->minimum_image_check(delx,dely,delz)) { domain->minimum_image(delx,dely,delz); xmid[0] = x[atom1][0] + 0.5*delx; xmid[1] = x[atom1][1] + 0.5*dely; xmid[2] = x[atom1][2] + 0.5*delz; if (bcolor == ATOM) draw_cylinder(x[atom1],xmid,color1,diameter,3); else draw_cylinder(x[atom1],xmid,color,diameter,3); xmid[0] = x[atom2][0] - 0.5*delx; xmid[1] = x[atom2][1] - 0.5*dely; xmid[2] = x[atom2][2] - 0.5*delz; if (bcolor == ATOM) draw_cylinder(xmid,x[atom2],color2,diameter,3); else draw_cylinder(xmid,x[atom2],color,diameter,3); } else draw_cylinder(x[atom1],x[atom2],color,diameter,3); } } } // render outline of simulation box, orthogonal or triclinic if (boxflag) { double diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= boxdiam; double (*corners)[3]; double corner[8][3]; if (domain->triclinic == 0) { corner[0][0] = boxxlo; corner[0][1] = boxylo; corner[0][2] = boxzlo; corner[1][0] = boxxhi; corner[1][1] = boxylo; corner[1][2] = boxzlo; corner[2][0] = boxxlo; corner[2][1] = boxyhi; corner[2][2] = boxzlo; corner[3][0] = boxxhi; corner[3][1] = boxyhi; corner[3][2] = boxzlo; corner[4][0] = boxxlo; corner[4][1] = boxylo; corner[4][2] = boxzhi; corner[5][0] = boxxhi; corner[5][1] = boxylo; corner[5][2] = boxzhi; corner[6][0] = boxxlo; corner[6][1] = boxyhi; corner[6][2] = boxzhi; corner[7][0] = boxxhi; corner[7][1] = boxyhi; corner[7][2] = boxzhi; corners = corner; } else { domain->box_corners(); corners = domain->corners; } draw_cylinder(corners[0],corners[1],boxcolor,diameter,3); draw_cylinder(corners[2],corners[3],boxcolor,diameter,3); draw_cylinder(corners[0],corners[2],boxcolor,diameter,3); draw_cylinder(corners[1],corners[3],boxcolor,diameter,3); draw_cylinder(corners[0],corners[4],boxcolor,diameter,3); draw_cylinder(corners[1],corners[5],boxcolor,diameter,3); draw_cylinder(corners[2],corners[6],boxcolor,diameter,3); draw_cylinder(corners[3],corners[7],boxcolor,diameter,3); draw_cylinder(corners[4],corners[5],boxcolor,diameter,3); draw_cylinder(corners[6],corners[7],boxcolor,diameter,3); draw_cylinder(corners[4],corners[6],boxcolor,diameter,3); draw_cylinder(corners[5],corners[7],boxcolor,diameter,3); } // render XYZ axes in red/green/blue // offset by 10% of box size and scale by axeslen if (axesflag) { double diameter = MIN(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) diameter = MIN(diameter,boxzhi-boxzlo); diameter *= axesdiam; double (*corners)[3]; double corner[8][3]; if (domain->triclinic == 0) { corner[0][0] = boxxlo; corner[0][1] = boxylo; corner[0][2] = boxzlo; corner[1][0] = boxxhi; corner[1][1] = boxylo; corner[1][2] = boxzlo; corner[2][0] = boxxlo; corner[2][1] = boxyhi; corner[2][2] = boxzlo; corner[4][0] = boxxlo; corner[4][1] = boxylo; corner[4][2] = boxzhi; corners = corner; } else { domain->box_corners(); corners = domain->corners; } double offset = MAX(boxxhi-boxxlo,boxyhi-boxylo); if (domain->dimension == 3) offset = MAX(offset,boxzhi-boxzlo); offset *= 0.1; corners[0][0] -= offset; corners[0][1] -= offset; corners[0][2] -= offset; corners[1][0] -= offset; corners[1][1] -= offset; corners[1][2] -= offset; corners[2][0] -= offset; corners[2][1] -= offset; corners[2][2] -= offset; corners[4][0] -= offset; corners[4][1] -= offset; corners[4][2] -= offset; corners[1][0] = corners[0][0] + axeslen*(corners[1][0]-corners[0][0]); corners[1][1] = corners[0][1] + axeslen*(corners[1][1]-corners[0][1]); corners[1][2] = corners[0][2] + axeslen*(corners[1][2]-corners[0][2]); corners[2][0] = corners[0][0] + axeslen*(corners[2][0]-corners[0][0]); corners[2][1] = corners[0][1] + axeslen*(corners[2][1]-corners[0][1]); corners[2][2] = corners[0][2] + axeslen*(corners[2][2]-corners[0][2]); corners[4][0] = corners[0][0] + axeslen*(corners[4][0]-corners[0][0]); corners[4][1] = corners[0][1] + axeslen*(corners[4][1]-corners[0][1]); corners[4][2] = corners[0][2] + axeslen*(corners[4][2]-corners[0][2]); draw_cylinder(corners[0],corners[1],color2rgb("red"),diameter,3); draw_cylinder(corners[0],corners[2],color2rgb("green"),diameter,3); draw_cylinder(corners[0],corners[4],color2rgb("blue"),diameter,3); } } /* ---------------------------------------------------------------------- draw sphere at x with surfaceColor and diameter render pixel by pixel onto image plane with depth buffering ------------------------------------------------------------------------- */ void DumpImage::draw_sphere(double *x, double *surfaceColor, double diameter) { int ix,iy; double projRad; double xlocal[3],surface[3]; double depth; xlocal[0] = x[0] - xctr; xlocal[1] = x[1] - yctr; xlocal[2] = x[2] - zctr; double xmap = MathExtra::dot3(camRight,xlocal); double ymap = MathExtra::dot3(camUp,xlocal); double dist = MathExtra::dot3(camPos,camDir) - MathExtra::dot3(xlocal,camDir); double radius = 0.5*diameter; double radsq = radius*radius; double pixelWidth = (tanPerPixel > 0) ? tanPerPixel * dist : -tanPerPixel / zoom; double pixelRadiusFull = radius / pixelWidth; int pixelRadius = static_cast<int> (pixelRadiusFull + 0.5) + 1; double xf = xmap / pixelWidth; double yf = ymap / pixelWidth; int xc = static_cast<int> (xf); int yc = static_cast<int> (yf); double width_error = xf - xc; double height_error = yf - yc; // shift 0,0 to screen center (vs lower left) xc += width / 2; yc += height / 2; for (iy = yc - pixelRadius; iy <= yc + pixelRadius; iy++) { for (ix = xc - pixelRadius; ix <= xc + pixelRadius; ix++) { if (iy < 0 || iy >= height || ix < 0 || ix >= width) continue; surface[1] = ((iy - yc) - height_error) * pixelWidth; surface[0] = ((ix - xc) - width_error) * pixelWidth; projRad = surface[0]*surface[0] + surface[1]*surface[1]; // outside the sphere in the projected image if (projRad > radsq) continue; surface[2] = sqrt(radsq - projRad); depth = dist - surface[2]; surface[0] /= radius; surface[1] /= radius; surface[2] /= radius; draw_pixel (ix, iy, depth, surface, surfaceColor); } } } /* ---------------------------------------------------------------------- draw cylinder from x to y with surfaceColor and diameter render pixel by pixel onto image plane with depth buffering if sflag = 0, draw no end spheres if sflag = 1, draw 1st end sphere if sflag = 2, draw 2nd end sphere if sflag = 3, draw both end spheres ------------------------------------------------------------------------- */ void DumpImage::draw_cylinder(double *x, double *y, double *surfaceColor, double diameter, int sflag) { double surface[3], normal[3]; double mid[3],xaxis[3],yaxis[3],zaxis[3]; double camLDir[3], camLRight[3], camLUp[3]; double zmin, zmax; if (sflag % 2) draw_sphere(x,surfaceColor,diameter); if (sflag/2) draw_sphere(y,surfaceColor,diameter); double radius = 0.5*diameter; double radsq = radius*radius; zaxis[0] = y[0] - x[0]; zaxis[1] = y[1] - x[1]; zaxis[2] = y[2] - x[2]; double rasterWidth = fabs(MathExtra::dot3(zaxis, camRight)) + diameter; double rasterHeight = fabs(MathExtra::dot3(zaxis, camUp)) + diameter; mid[0] = (y[0] + x[0]) * 0.5 - xctr; mid[1] = (y[1] + x[1]) * 0.5 - yctr; mid[2] = (y[2] + x[2]) * 0.5 - zctr; double len = MathExtra::len3(zaxis); MathExtra::scale3(1.0/len,zaxis); len *= 0.5; zmax = len; zmin = -len; double xmap = MathExtra::dot3(camRight,mid); double ymap = MathExtra::dot3(camUp,mid); double dist = MathExtra::dot3(camPos,camDir) - MathExtra::dot3(mid,camDir); double pixelWidth = (tanPerPixel > 0) ? tanPerPixel * dist : -tanPerPixel / zoom; double xf = xmap / pixelWidth; double yf = ymap / pixelWidth; int xc = static_cast<int> (xf); int yc = static_cast<int> (yf); double width_error = xf - xc; double height_error = yf - yc; // shift 0,0 to screen center (vs lower left) xc += width / 2; yc += height / 2; double pixelHalfWidthFull = (rasterWidth * 0.5) / pixelWidth; double pixelHalfHeightFull = (rasterHeight * 0.5) / pixelWidth; int pixelHalfWidth = static_cast<int> (pixelHalfWidthFull + 0.5); int pixelHalfHeight = static_cast<int> (pixelHalfHeightFull + 0.5); if (zaxis[0] == camDir[0] && zaxis[1] == camDir[1] && zaxis[2] == camDir[2]) return; MathExtra::cross3(zaxis,camDir,yaxis); MathExtra::norm3(yaxis); MathExtra::cross3(yaxis,zaxis,xaxis); MathExtra::norm3(xaxis); camLDir[0] = MathExtra::dot3(camDir,xaxis); camLDir[1] = 0.0; camLDir[2] = MathExtra::dot3(camDir,zaxis); camLRight[0] = MathExtra::dot3(camRight,xaxis); camLRight[1] = MathExtra::dot3(camRight,yaxis); camLRight[2] = MathExtra::dot3(camRight,zaxis); MathExtra::norm3(camLRight); camLUp[0] = MathExtra::dot3(camUp,xaxis); camLUp[1] = MathExtra::dot3(camUp,yaxis); camLUp[2] = MathExtra::dot3(camUp,zaxis); MathExtra::norm3(camLUp); double a = camLDir[0] * camLDir[0]; for (int iy = yc - pixelHalfHeight; iy <= yc + pixelHalfHeight; iy ++) { for (int ix = xc - pixelHalfWidth; ix <= xc + pixelHalfWidth; ix ++) { if (iy < 0 || iy >= height || ix < 0 || ix >= width) continue; double sy = ((iy - yc) - height_error) * pixelWidth; double sx = ((ix - xc) - width_error) * pixelWidth; surface[0] = camLRight[0] * sx + camLUp[0] * sy; surface[1] = camLRight[1] * sx + camLUp[1] * sy; surface[2] = camLRight[2] * sx + camLUp[2] * sy; double b = 2 * camLDir[0] * surface[0]; double c = surface[0] * surface[0] + surface[1] * surface[1] - radsq; double partial = b*b - 4*a*c; if (partial < 0) continue; partial = sqrt (partial); double t = (-b + partial) / (2*a); double t2 = (-b - partial) / (2*a); if (t2 > t) { t = t2; } surface[0] += t * camLDir[0]; surface[1] += t * camLDir[1]; surface[2] += t * camLDir[2]; if (surface[2] > zmax || surface[2] < zmin) continue; // convert surface into the surface normal normal[0] = surface[0] / radius; normal[1] = surface[1] / radius; normal[2] = 0.0; // in camera space surface[0] = MathExtra::dot3 (normal, camLRight); surface[1] = MathExtra::dot3 (normal, camLUp); surface[2] = MathExtra::dot3 (normal, camLDir); double depth = dist - t; draw_pixel (ix, iy, depth, surface, surfaceColor); } } } /* ---------------------------------------------------------------------- */ void DumpImage::draw_pixel(int ix, int iy, double depth, double *surface, double *surfaceColor) { double diffuseKey,diffuseFill,diffuseBack,specularKey; if (depth < 0 || (depthBuffer[ix + iy*width] >= 0 && depth >= depthBuffer[ix + iy*width])) return; depthBuffer[ix + iy*width] = depth; // store only the tangent relative to the camera normal (0,0,-1) surfaceBuffer[0 + ix * 2 + iy*width * 2] = surface[1]; surfaceBuffer[1 + ix * 2 + iy*width * 2] = -surface[0]; diffuseKey = saturate(MathExtra::dot3(surface, keyLightDir)); diffuseFill = saturate(MathExtra::dot3(surface, fillLightDir)); diffuseBack = saturate(MathExtra::dot3(surface, backLightDir)); specularKey = pow(saturate(MathExtra::dot3(surface, keyHalfDir)), specularHardness) * specularIntensity; double c[3]; c[0] = surfaceColor[0] * ambientColor[0]; c[1] = surfaceColor[1] * ambientColor[1]; c[2] = surfaceColor[2] * ambientColor[2]; c[0] += surfaceColor[0] * keyLightColor[0] * diffuseKey; c[1] += surfaceColor[1] * keyLightColor[1] * diffuseKey; c[2] += surfaceColor[2] * keyLightColor[2] * diffuseKey; c[0] += keyLightColor[0] * specularKey; c[1] += keyLightColor[1] * specularKey; c[2] += keyLightColor[2] * specularKey; c[0] += surfaceColor[0] * fillLightColor[0] * diffuseFill; c[1] += surfaceColor[1] * fillLightColor[1] * diffuseFill; c[2] += surfaceColor[2] * fillLightColor[2] * diffuseFill; c[0] += surfaceColor[0] * backLightColor[0] * diffuseBack; c[1] += surfaceColor[1] * backLightColor[1] * diffuseBack; c[2] += surfaceColor[2] * backLightColor[2] * diffuseBack; c[0] = saturate(c[0]); c[1] = saturate(c[1]); c[2] = saturate(c[2]); imageBuffer[0 + ix*3 + iy*width*3] = static_cast<int>(c[0] * 255.0); imageBuffer[1 + ix*3 + iy*width*3] = static_cast<int>(c[1] * 255.0); imageBuffer[2 + ix*3 + iy*width*3] = static_cast<int>(c[2] * 255.0); } /* ---------------------------------------------------------------------- */ void DumpImage::compute_SSAO() { // used for rasterizing the spheres double delTheta = 2.0*PI / SSAOSamples; // typical neighborhood value for shading double pixelWidth = (tanPerPixel > 0) ? tanPerPixel : -tanPerPixel / zoom; int pixelRadius = (int) trunc (SSAORadius / pixelWidth + 0.5); int x,y,s; int hPart = height / nprocs; int index = me * hPart * width; for (y = me * hPart; y < (me + 1) * hPart; y ++) { for (x = 0; x < width; x ++, index ++) { double cdepth = depthBuffer[index]; if (cdepth < 0) { continue; } double sx = surfaceBuffer[index * 2 + 0]; double sy = surfaceBuffer[index * 2 + 1]; double sin_t = -sqrt(sx*sx + sy*sy); double theta = random->uniform() * SSAOJitter; double ao = 0.0; for (s = 0; s < SSAOSamples; s ++) { double hx = cos(theta); double hy = sin(theta); theta += delTheta; // multiply by z cross surface tangent // so that dot (aka cos) works here double scaled_sin_t = sin_t * (hx*sy + hy*sx); // Bresenham's line algorithm to march over depthBuffer int dx = static_cast<int> (hx * pixelRadius); int dy = static_cast<int> (hy * pixelRadius); int ex = x + dx; if (ex < 0) { ex = 0; } if (ex >= width) { ex = width - 1; } int ey = y + dy; if (ey < 0) { ey = 0; } if (ey >= height) { ey = height - 1; } double delta; int small, large; double lenIncr; if (fabs(hx) > fabs(hy)) { small = (hx > 0) ? 1 : -1; large = (hy > 0) ? width : -width; delta = fabs(hy / hx); } else { small = (hy > 0) ? width : -width; large = (hx > 0) ? 1 : -1; delta = fabs(hx / hy); } lenIncr = sqrt (1 + delta * delta) * pixelWidth; // initialize with one step // because the center point doesn't need testing int end = ex + ey * width; int ind = index + small; double len = lenIncr; double err = delta; if (err >= 1.0) { ind += large; err -= 1.0; } double minPeak = -1; double peakLen = 0.0; int stepsTaken = 1; while ((small > 0 && ind <= end) || (small < 0 && ind >= end)) { if (ind < 0 || ind >= (width*height)) { break; } // cdepth - depthBuffer B/C we want it in the negative z direction if (minPeak < 0 || (depthBuffer[ind] >= 0 && depthBuffer[ind] < minPeak)) { minPeak = depthBuffer[ind]; peakLen = len; } ind += small; len += lenIncr; err += delta; if (err >= 1.0) { ind += large; err -= 1.0; } stepsTaken ++; } if (peakLen > 0) { double h = atan ((cdepth - minPeak) / peakLen); ao += saturate(sin (h) - scaled_sin_t); } else { ao += saturate(-scaled_sin_t); } } ao /= (double)SSAOSamples; double c[3]; c[0] = (double) (*(unsigned char *) &imageBuffer[index * 3 + 0]); c[1] = (double) (*(unsigned char *) &imageBuffer[index * 3 + 1]); c[2] = (double) (*(unsigned char *) &imageBuffer[index * 3 + 2]); c[0] *= (1.0 - ao); c[1] *= (1.0 - ao); c[2] *= (1.0 - ao); imageBuffer[index * 3 + 0] = (int) c[0]; imageBuffer[index * 3 + 1] = (int) c[1]; imageBuffer[index * 3 + 2] = (int) c[2]; } } } /* ---------------------------------------------------------------------- */ void DumpImage::write_JPG() { #ifdef LAMMPS_JPEG struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 100, 1); jpeg_start_compress(&cinfo, 1); while (cinfo.next_scanline < cinfo.image_height) { row_pointer = (JSAMPROW) &writeBuffer[(cinfo.image_height - 1 - cinfo.next_scanline) * 3 * width]; jpeg_write_scanlines(&cinfo, &row_pointer, 1); } jpeg_finish_compress(&cinfo); #endif } /* ---------------------------------------------------------------------- */ void DumpImage::write_PPM() { int x,y; fprintf (fp,"P6\n%d %d\n255\n",width,height); for (y = height-1; y >= 0; y --) for (x = 0; x < width; x ++) fprintf (fp,"%c%c%c", writeBuffer[0 + x*3 + y*width*3], writeBuffer[1 + x*3 + y*width*3], writeBuffer[2 + x*3 + y*width*3]); } /* ---------------------------------------------------------------------- */ int DumpImage::pack_comm(int n, int *list, double *buf, int pbc_flag, int *pbc) { int i,j,m; m = 0; if (comm_forward == 1) { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = choose[j]; } } else { for (i = 0; i < n; i++) { j = list[i]; buf[m++] = choose[j]; buf[m++] = bufcopy[j][0]; buf[m++] = bufcopy[j][1]; } } return comm_forward; } /* ---------------------------------------------------------------------- */ void DumpImage::unpack_comm(int n, int first, double *buf) { int i,m,last; m = 0; last = first + n; if (comm_forward == 1) for (i = first; i < last; i++) choose[i] = static_cast<int> (buf[m++]); else { for (i = first; i < last; i++) { choose[i] = static_cast<int> (buf[m++]); bufcopy[i][0] = buf[m++]; bufcopy[i][1] = buf[m++]; } } } /* ---------------------------------------------------------------------- */ int DumpImage::modify_param(int narg, char **arg) { int n = DumpCustom::modify_param(narg,arg); if (n) return n; if (strcmp(arg[0],"acolor") == 0) { if (narg < 3) error->all("Illegal dump_modify command"); int nlo,nhi; force->bounds(arg[1],atom->ntypes,nlo,nhi); // ptrs = list of ncount colornames separated by '/' int ncount = 1; char *nextptr; char *ptr = arg[2]; while (nextptr = strchr(ptr,'/')) { ptr = nextptr + 1; ncount++; } char **ptrs = new char*[ncount+1]; ncount = 0; ptrs[ncount++] = strtok(arg[2],"/"); while (ptrs[ncount++] = strtok(NULL,"/")); ncount--; // assign each of ncount colors in round-robin fashion to types int m = 0; for (int i = nlo; i <= nhi; i++) { colortype[i] = color2rgb(ptrs[m%ncount]); if (colortype[i] == NULL) error->all("Invalid color in dump_modify command"); m++; } delete [] ptrs; return 3; } else if (strcmp(arg[0],"adiam") == 0) { if (narg < 3) error->all("Illegal dump_modify command"); int nlo,nhi; force->bounds(arg[1],atom->ntypes,nlo,nhi); double diam = atof(arg[2]); if (diam <= 0.0) error->all("Illegal dump_modify command"); for (int i = nlo; i <= nhi; i++) diamtype[i] = diam; return 3; } else if (strcmp(arg[0],"amap") == 0) { if (narg < 6) error->all("Illegal dump_modify command"); if (!islower(arg[1][0])) { mlo = NUMERIC; mlovalue = atof(arg[1]); } else if (strcmp(arg[1],"min") == 0) mlo = MINVALUE; else error->all("Illegal dump_modify command"); if (!islower(arg[2][0])) { mhi = NUMERIC; mhivalue = atof(arg[2]); } else if (strcmp(arg[2],"max") == 0) mhi = MAXVALUE; else error->all("Illegal dump_modify command"); if (mlo == NUMERIC && mhi == NUMERIC && mlovalue >= mhivalue) error->all("Illega dump_modify command"); if (strlen(arg[3]) != 2) error->all("Illegal dump_modify command"); if (arg[3][0] == 'c') mstyle = CONTINUOUS; else if (arg[3][0] == 'd') mstyle = DISCRETE; else if (arg[3][0] == 's') mstyle = SEQUENTIAL; else error->all("Illegal dump_modify command"); if (arg[3][1] == 'a') mrange = ABSOLUTE; else if (arg[3][1] == 'f') mrange = FRACTIONAL; else error->all("Illegal dump_modify command"); if (mstyle == SEQUENTIAL) { mbinsize = atof(arg[4]); if (mbinsize <= 0.0) error->all("Illegal dump_modify command"); } mbinsizeinv = 1.0/mbinsize; nentry = atoi(arg[5]); mentry = new MapEntry[nentry]; int n = 6; for (int i = 0; i < nentry; i++) { if (mstyle == CONTINUOUS) { if (n+2 > narg) error->all("Illegal dump_modify command"); if (!islower(arg[n][0])) { mentry[i].single = NUMERIC; mentry[i].svalue = atof(arg[n]); } else if (strcmp(arg[n],"min") == 0) mentry[i].single = MINVALUE; else if (strcmp(arg[n],"max") == 0) mentry[i].single = MAXVALUE; else error->all("Illegal dump_modify command"); mentry[i].color = color2rgb(arg[n+1]); n += 2; } else if (mstyle == DISCRETE) { if (n+3 > narg) error->all("Illegal dump_modify command"); if (!islower(arg[n][0])) { mentry[i].lo = NUMERIC; mentry[i].lvalue = atof(arg[n]); } else if (strcmp(arg[n],"min") == 0) mentry[i].single = MINVALUE; else if (strcmp(arg[n],"max") == 0) mentry[i].single = MAXVALUE; else error->all("Illegal dump_modify command"); if (!islower(arg[n+1][0])) { mentry[i].hi = NUMERIC; mentry[i].hvalue = atof(arg[n+1]); } else if (strcmp(arg[n+1],"min") == 0) mentry[i].single = MINVALUE; else if (strcmp(arg[n+1],"max") == 0) mentry[i].single = MAXVALUE; else error->all("Illegal dump_modify command"); mentry[i].color = color2rgb(arg[n+2]); n += 3; } else if (mstyle == SEQUENTIAL) { if (n+1 > narg) error->all("Illegal dump_modify command"); mentry[i].color = color2rgb(arg[n]); n += 1; } if (mentry[i].color == NULL) error->all("Invalid color in dump_modify command"); } if (mstyle == CONTINUOUS) { if (nentry < 2) error->all("Invalid color map in dump_modify command"); if (mentry[0].single != MINVALUE || mentry[nentry-1].single != MAXVALUE) error->all("Invalid color map in dump_modify command"); for (int i = 2; i < nentry-1; i++) if (mentry[i].svalue <= mentry[i-1].svalue) error->all("Invalid color map in dump_modify command"); } else if (mstyle == DISCRETE) { if (nentry < 1) error->all("Invalid color map in dump_modify command"); if (mentry[nentry-1].lo != MINVALUE || mentry[nentry-1].hi != MAXVALUE) error->all("Invalid color map in dump_modify command"); } else if (mstyle == SEQUENTIAL) { if (nentry < 1) error->all("Invalid color map in dump_modify command"); } return n; } else if (strcmp(arg[0],"bcolor") == 0) { if (narg < 3) error->all("Illegal dump_modify command"); if (atom->nbondtypes == 0) error->all("Dump modify bcolor not allowed with no bond types"); int nlo,nhi; force->bounds(arg[1],atom->nbondtypes,nlo,nhi); // ptrs = list of ncount colornames separated by '/' int ncount = 1; char *nextptr; char *ptr = arg[2]; while (nextptr = strchr(ptr,'/')) { ptr = nextptr + 1; ncount++; } char **ptrs = new char*[ncount+1]; ncount = 0; ptrs[ncount++] = strtok(arg[2],"/"); while (ptrs[ncount++] = strtok(NULL,"/")); ncount--; // assign each of ncount colors in round-robin fashion to types int m = 0; for (int i = nlo; i <= nhi; i++) { bcolortype[i] = color2rgb(ptrs[m%ncount]); if (bcolortype[i] == NULL) error->all("Invalid color in dump_modify command"); m++; } delete [] ptrs; return 3; } else if (strcmp(arg[0],"bdiam") == 0) { if (narg < 3) error->all("Illegal dump_modify command"); if (atom->nbondtypes == 0) error->all("Dump modify bdiam not allowed with no bond types"); int nlo,nhi; force->bounds(arg[1],atom->ntypes,nlo,nhi); double diam = atof(arg[2]); if (diam <= 0.0) error->all("Illegal dump_modify command"); for (int i = nlo; i <= nhi; i++) bdiamtype[i] = diam; return 3; } else if (strcmp(arg[0],"backcolor") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); double *color = color2rgb(arg[1]); if (color == NULL) error->all("Invalid color in dump_modify command"); background[0] = static_cast<int> (color[0]*255.0); background[1] = static_cast<int> (color[1]*255.0); background[2] = static_cast<int> (color[2]*255.0); return 2; } else if (strcmp(arg[0],"boxcolor") == 0) { if (narg < 2) error->all("Illegal dump_modify command"); boxcolor = color2rgb(arg[1]); if (boxcolor == NULL) error->all("Invalid color in dump_modify command"); return 2; } else if (strcmp(arg[0],"color") == 0) { if (narg < 5) error->all("Illegal dump_modify command"); username = (char **) memory->srealloc(username,(ncolors+1)*sizeof(char *),"dump:username"); memory->grow(userrgb,ncolors+1,3,"dump:userrgb"); int n = strlen(arg[1]) + 1; username[ncolors] = new char[n]; strcpy(username[ncolors],arg[1]); userrgb[ncolors][0] = atof(arg[2]); userrgb[ncolors][1] = atof(arg[3]); userrgb[ncolors][2] = atof(arg[4]); if (userrgb[ncolors][0] < 0.0 || userrgb[ncolors][0] > 1.0 || userrgb[ncolors][1] < 0.0 || userrgb[ncolors][1] > 1.0 || userrgb[ncolors][2] < 0.0 || userrgb[ncolors][2] > 1.0) error->all("Illegal dump_modify command"); ncolors++; return 5; } return 0; } /* ---------------------------------------------------------------------- convert value into an RGB color via color map ------------------------------------------------------------------------- */ double *DumpImage::value2color(double value) { double lo,hi; value = MAX(value,locurrent); value = MIN(value,hicurrent); if (mrange == FRACTIONAL) { if (locurrent == hicurrent) value = 0.0; else value = (value-locurrent) / (hicurrent-locurrent); lo = 0.0; hi = 1.0; } else { lo = locurrent; hi = hicurrent; } if (mstyle == CONTINUOUS) { for (int i = 0; i < nentry-1; i++) if (value >= mentry[i].svalue && value <= mentry[i+1].svalue) { double fraction = (value-mentry[i].svalue) / (mentry[i+1].svalue-mentry[i].svalue); interpolate[0] = mentry[i].color[0] + fraction*(mentry[i+1].color[0]-mentry[i].color[0]); interpolate[1] = mentry[i].color[1] + fraction*(mentry[i+1].color[1]-mentry[i].color[1]); interpolate[2] = mentry[i].color[2] + fraction*(mentry[i+1].color[2]-mentry[i].color[2]); return interpolate; } } else if (mstyle == DISCRETE) { for (int i = 0; i < nentry; i++) if (value >= mentry[i].lvalue && value <= mentry[i].hvalue) return mentry[i].color; } else { int ibin = static_cast<int> ((value-lo) * mbinsizeinv); return mentry[ibin%nentry].color; } return NULL; } /* ---------------------------------------------------------------------- search the list of color names for the string color return a pointer to the 3 floating point RGB values search user-defined color names first, then the list of NCOLORS names ------------------------------------------------------------------------- */ double *DumpImage::color2rgb(char *color) { static char *name[NCOLORS] = { "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen" }; static double rgb[NCOLORS][3] = { {240/255.0, 248/255.0, 255/255.0}, {250/255.0, 235/255.0, 215/255.0}, {0/255.0, 255/255.0, 255/255.0}, {127/255.0, 255/255.0, 212/255.0}, {240/255.0, 255/255.0, 255/255.0}, {245/255.0, 245/255.0, 220/255.0}, {255/255.0, 228/255.0, 196/255.0}, {0/255.0, 0/255.0, 0/255.0}, {255/255.0, 255/255.0, 205/255.0}, {0/255.0, 0/255.0, 255/255.0}, {138/255.0, 43/255.0, 226/255.0}, {165/255.0, 42/255.0, 42/255.0}, {222/255.0, 184/255.0, 135/255.0}, {95/255.0, 158/255.0, 160/255.0}, {127/255.0, 255/255.0, 0/255.0}, {210/255.0, 105/255.0, 30/255.0}, {255/255.0, 127/255.0, 80/255.0}, {100/255.0, 149/255.0, 237/255.0}, {255/255.0, 248/255.0, 220/255.0}, {220/255.0, 20/255.0, 60/255.0}, {0/255.0, 255/255.0, 255/255.0}, {0/255.0, 0/255.0, 139/255.0}, {0/255.0, 139/255.0, 139/255.0}, {184/255.0, 134/255.0, 11/255.0}, {169/255.0, 169/255.0, 169/255.0}, {0/255.0, 100/255.0, 0/255.0}, {189/255.0, 183/255.0, 107/255.0}, {139/255.0, 0/255.0, 139/255.0}, {85/255.0, 107/255.0, 47/255.0}, {255/255.0, 140/255.0, 0/255.0}, {153/255.0, 50/255.0, 204/255.0}, {139/255.0, 0/255.0, 0/255.0}, {233/255.0, 150/255.0, 122/255.0}, {143/255.0, 188/255.0, 143/255.0}, {72/255.0, 61/255.0, 139/255.0}, {47/255.0, 79/255.0, 79/255.0}, {0/255.0, 206/255.0, 209/255.0}, {148/255.0, 0/255.0, 211/255.0}, {255/255.0, 20/255.0, 147/255.0}, {0/255.0, 191/255.0, 255/255.0}, {105/255.0, 105/255.0, 105/255.0}, {30/255.0, 144/255.0, 255/255.0}, {178/255.0, 34/255.0, 34/255.0}, {255/255.0, 250/255.0, 240/255.0}, {34/255.0, 139/255.0, 34/255.0}, {255/255.0, 0/255.0, 255/255.0}, {220/255.0, 220/255.0, 220/255.0}, {248/255.0, 248/255.0, 255/255.0}, {255/255.0, 215/255.0, 0/255.0}, {218/255.0, 165/255.0, 32/255.0}, {128/255.0, 128/255.0, 128/255.0}, {0/255.0, 128/255.0, 0/255.0}, {173/255.0, 255/255.0, 47/255.0}, {240/255.0, 255/255.0, 240/255.0}, {255/255.0, 105/255.0, 180/255.0}, {205/255.0, 92/255.0, 92/255.0}, {75/255.0, 0/255.0, 130/255.0}, {255/255.0, 240/255.0, 240/255.0}, {240/255.0, 230/255.0, 140/255.0}, {230/255.0, 230/255.0, 250/255.0}, {255/255.0, 240/255.0, 245/255.0}, {124/255.0, 252/255.0, 0/255.0}, {255/255.0, 250/255.0, 205/255.0}, {173/255.0, 216/255.0, 230/255.0}, {240/255.0, 128/255.0, 128/255.0}, {224/255.0, 255/255.0, 255/255.0}, {250/255.0, 250/255.0, 210/255.0}, {144/255.0, 238/255.0, 144/255.0}, {211/255.0, 211/255.0, 211/255.0}, {255/255.0, 182/255.0, 193/255.0}, {255/255.0, 160/255.0, 122/255.0}, {32/255.0, 178/255.0, 170/255.0}, {135/255.0, 206/255.0, 250/255.0}, {119/255.0, 136/255.0, 153/255.0}, {176/255.0, 196/255.0, 222/255.0}, {255/255.0, 255/255.0, 224/255.0}, {0/255.0, 255/255.0, 0/255.0}, {50/255.0, 205/255.0, 50/255.0}, {250/255.0, 240/255.0, 230/255.0}, {255/255.0, 0/255.0, 255/255.0}, {128/255.0, 0/255.0, 0/255.0}, {102/255.0, 205/255.0, 170/255.0}, {0/255.0, 0/255.0, 205/255.0}, {186/255.0, 85/255.0, 211/255.0}, {147/255.0, 112/255.0, 219/255.0}, {60/255.0, 179/255.0, 113/255.0}, {123/255.0, 104/255.0, 238/255.0}, {0/255.0, 250/255.0, 154/255.0}, {72/255.0, 209/255.0, 204/255.0}, {199/255.0, 21/255.0, 133/255.0}, {25/255.0, 25/255.0, 112/255.0}, {245/255.0, 255/255.0, 250/255.0}, {255/255.0, 228/255.0, 225/255.0}, {255/255.0, 228/255.0, 181/255.0}, {255/255.0, 222/255.0, 173/255.0}, {0/255.0, 0/255.0, 128/255.0}, {253/255.0, 245/255.0, 230/255.0}, {128/255.0, 128/255.0, 0/255.0}, {107/255.0, 142/255.0, 35/255.0}, {255/255.0, 165/255.0, 0/255.0}, {255/255.0, 69/255.0, 0/255.0}, {218/255.0, 112/255.0, 214/255.0}, {238/255.0, 232/255.0, 170/255.0}, {152/255.0, 251/255.0, 152/255.0}, {175/255.0, 238/255.0, 238/255.0}, {219/255.0, 112/255.0, 147/255.0}, {255/255.0, 239/255.0, 213/255.0}, {255/255.0, 239/255.0, 213/255.0}, {205/255.0, 133/255.0, 63/255.0}, {255/255.0, 192/255.0, 203/255.0}, {221/255.0, 160/255.0, 221/255.0}, {176/255.0, 224/255.0, 230/255.0}, {128/255.0, 0/255.0, 128/255.0}, {255/255.0, 0/255.0, 0/255.0}, {188/255.0, 143/255.0, 143/255.0}, {65/255.0, 105/255.0, 225/255.0}, {139/255.0, 69/255.0, 19/255.0}, {250/255.0, 128/255.0, 114/255.0}, {244/255.0, 164/255.0, 96/255.0}, {46/255.0, 139/255.0, 87/255.0}, {255/255.0, 245/255.0, 238/255.0}, {160/255.0, 82/255.0, 45/255.0}, {192/255.0, 192/255.0, 192/255.0}, {135/255.0, 206/255.0, 235/255.0}, {106/255.0, 90/255.0, 205/255.0}, {112/255.0, 128/255.0, 144/255.0}, {255/255.0, 250/255.0, 250/255.0}, {0/255.0, 255/255.0, 127/255.0}, {70/255.0, 130/255.0, 180/255.0}, {210/255.0, 180/255.0, 140/255.0}, {0/255.0, 128/255.0, 128/255.0}, {216/255.0, 191/255.0, 216/255.0}, {253/255.0, 99/255.0, 71/255.0}, {64/255.0, 224/255.0, 208/255.0}, {238/255.0, 130/255.0, 238/255.0}, {245/255.0, 222/255.0, 179/255.0}, {255/255.0, 255/255.0, 255/255.0}, {245/255.0, 245/255.0, 245/255.0}, {255/255.0, 255/255.0, 0/255.0}, {154/255.0, 205/255.0, 50/255.0} }; for (int i = 0; i < ncolors; i++) if (strcmp(color,username[i]) == 0) return userrgb[i]; for (int i = 0; i < NCOLORS; i++) if (strcmp(color,name[i]) == 0) return rgb[i]; return NULL; } /* ---------------------------------------------------------------------- search the list of element names for the string element return a pointer to the 3 floating point RGB values this list is used by AtomEye and is taken from its Mendeleyev.c file ------------------------------------------------------------------------- */ double *DumpImage::element2color(char *element) { static char *name[NELEMENTS] = { "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt" }; static double rgb[NELEMENTS][3] = { {0.8, 0.8, 0.8}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.7, 0.7, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0.4, 0}, {0.35, 0.35, 0.35}, {0.2, 0.2, 0.8}, {0.8, 0.2, 0.2}, {0.7, 0.85, 0.45}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6, 0.6, 0.6}, {0.6, 0.6, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6901960784, 0.768627451, 0.8705882353}, {0.1, 0.7, 0.3}, {0.95, 0.9, 0.2}, {0.15, 0.5, 0.1}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5, 0.5, 0.5}, {0.8, 0.8, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5176470588, 0.5764705882, 0.6529411765}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.257254902, 0.2666666667, 0.271372549}, {0.95, 0.7900735294, 0.01385869565}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0, 1}, {0.6431372549, 0.6666666667, 0.6784313725}, {1, 1, 0.3}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5, 0.08, 0.12}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.5, 0.1, 0.5}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.8, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {1, 0.8431372549, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.8, 0.2, 0.2}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.1, 0.7, 0.3}, {0.1, 0.3, 0.7}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.9, 0.8, 0}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725}, {0.6431372549, 0.6666666667, 0.6784313725} }; for (int i = 0; i < NELEMENTS; i++) if (strcmp(element,name[i]) == 0) return rgb[i]; return NULL; } /* ---------------------------------------------------------------------- search the list of element names for the string element return a pointer to the 3 floating point RGB values this list is used by AtomEye and is taken from its Mendeleyev.c file ------------------------------------------------------------------------- */ double DumpImage::element2diam(char *element) { static char *name[NELEMENTS] = { "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt" }; static double diameter[NELEMENTS] = { 0.35, 1.785, 1.45, 1.05, 0.85, 0.72, 0.65, 0.6, 0.5, 1.5662, 1.8, 1.5, 1.4255, 1.07, 1, 1, 1, 1.8597, 2.2, 1.8, 1.6, 1.4, 1.51995, 1.44225, 1.4, 1.43325, 1.35, 1.35, 1.278, 1.35, 1.3, 1.25, 1.15, 1.15, 1.15, 2.0223, 2.35, 2, 1.8, 1.55, 1.6504, 1.3872, 1.35, 1.3, 1.35, 1.4, 1.6, 1.55, 1.55, 1.45, 1.45, 1.4, 1.4, 2.192, 2.6, 2.15, 1.95, 1.85, 1.85, 1.85, 1.85, 1.85, 1.85, 1.8, 1.75, 1.75, 1.75, 1.75, 1.75, 1.75, 1.75, 1.55, 1.6529, 1.5826, 1.35, 1.3, 1.35, 1.35, 1.35, 1.5, 1.9, 1.8, 1.6, 1.9, 1.6, 1.0, 1.0, 2.15, 1.95, 1.8, 1.8, 1.75, 1.75, 1.75, 1.75, 1.0, 1.0, 1.6, 1.6, 1.0, 1.0, 1.0, 1.0, 1.0, 1.6, 1.0, 1.0, 1.0, 1.0 }; for (int i = 0; i < NELEMENTS; i++) if (strcmp(element,name[i]) == 0) return diameter[i]; return 0.0; }