void DisplayDevice::find_pbc_cells(const VMDDisplayList *cmdList, ResizeArray<int> &pbcCells) { int pbc = cmdList->pbc; if (pbc == PBC_NONE) { pbcCells.append(0); pbcCells.append(0); pbcCells.append(0); } else { int npbc = cmdList->npbc; int nx = pbc & PBC_X ? npbc : 0; int ny = pbc & PBC_Y ? npbc : 0; int nz = pbc & PBC_Z ? npbc : 0; int nox = pbc & PBC_OPX ? -npbc : 0; int noy = pbc & PBC_OPY ? -npbc : 0; int noz = pbc & PBC_OPZ ? -npbc : 0; int i, j, k; for (i=nox; i<=nx; i++) { for (j=noy; j<=ny; j++) { for (k=noz; k<=nz; k++) { if (! (pbc & PBC_NOSELF && !i && !j && !k)) { pbcCells.append(i); pbcCells.append(j); pbcCells.append(k); } } } } } }
void DisplayDevice::find_pbc_images (const VMDDisplayList *cmdList, ResizeArray<Matrix4> &pbcImages) { if (cmdList->pbc == PBC_NONE) { pbcImages.append (Matrix4 ()); return; } ResizeArray<int> pbcCells; find_pbc_cells (cmdList, pbcCells); for (int i = 0; i < pbcCells.num (); i += 3) { int nx = pbcCells[i]; int ny = pbcCells[i + 1]; int nz = pbcCells[i + 2]; Matrix4 mat; for (int i1 = 1; i1 <= nx; i1++) mat.multmatrix (cmdList->transX); for (int i2 = -1; i2 >= nx; i2--) mat.multmatrix (cmdList->transXinv); for (int i3 = 1; i3 <= ny; i3++) mat.multmatrix (cmdList->transY); for (int i4 = -1; i4 >= ny; i4--) mat.multmatrix (cmdList->transYinv); for (int i5 = 1; i5 <= nz; i5++) mat.multmatrix (cmdList->transZ); for (int i6 = -1; i6 >= nz; i6--) mat.multmatrix (cmdList->transZinv); pbcImages.append (mat); } }
static void mol_delete_cb(Fl_Widget *w, void *v) { VMDApp *app = (VMDApp *)w->user_data(); MolBrowser *browser = (MolBrowser *)v; ResizeArray<int> idlist; for (int i=0; i<browser->size(); i++) { if (browser->selected(i+1)) { idlist.append(app->molecule_id(i)); } } for (int j=0; j<idlist.num(); j++) app->molecule_delete(idlist[j]); }
ResizeArray<JString *> *generic_get_names(const T &devList) { ResizeArray<JString *> *names = SensorConfig::getnames(); ResizeArray<JString *> *devnames = new ResizeArray<JString *>; for (int i=0; i<names->num(); i++) { JString *jstr = (*names)[i]; SensorConfig config(*jstr); const char *type = config.gettype(); if (devList.typecode(type) >= 0) devnames->append(jstr); else delete jstr; } delete names; return devnames; }
extern "C" void * bondsearchthread(void *voidparms) { int i, j, aindex; int paircount = 0; bondsearchthrparms *parms = (bondsearchthrparms *) voidparms; const int threadid = parms->threadid; const int threadcount = parms->threadcount; wkf_mutex_t *pairlistmutex = parms->pairlistmutex; const float *pos = parms->pos; const float *radii = parms->radii; const int totb = parms->totb; const int **boxatom = (const int **) parms->boxatom; const int *numinbox = parms->numinbox; const int **nbrlist = (const int **) parms->nbrlist; const int maxpairs = parms->maxpairs; const float pairdist = parms->pairdist; ResizeArray<int> *pairs = new ResizeArray<int>; float sqdist = pairdist * pairdist; wkfmsgtimer *msgt = wkf_msg_timer_create(5); for (aindex = threadid; (aindex < totb) && (paircount < maxpairs); aindex+=threadcount) { const int *tmpbox, *nbr; tmpbox = boxatom[aindex]; int anbox = numinbox[aindex]; if (((aindex & 255) == 0) && wkf_msg_timer_timeout(msgt)) { char tmpbuf[128]; sprintf(tmpbuf, "%6.2f", (100.0f * aindex) / (float) totb); // XXX: we have to use printf here as msgInfo is not thread-safe. // msgInfo << "vmd_gridsearch_bonds (thread " << threadid << "): " // << tmpbuf << "% complete" << sendmsg; printf("vmd_gridsearch_bonds (thread %d): %s %% complete\n", threadid, tmpbuf); } for (nbr = nbrlist[aindex]; (*nbr != -1) && (paircount < maxpairs); nbr++) { int nnbr=*nbr; const int *nbrbox = boxatom[nnbr]; int nbox=numinbox[nnbr]; int self = (aindex == nnbr) ? 1 : 0; for (i=0; (i<anbox) && (paircount < maxpairs); i++) { int ind1 = tmpbox[i]; const float *p1 = pos + 3L*ind1; // skip over self and already-tested atoms int startj = (self) ? i+1 : 0; for (j=startj; (j<nbox) && (paircount < maxpairs); j++) { int ind2 = nbrbox[j]; const float *p2 = pos + 3L*ind2; float dx = p1[0] - p2[0]; float dy = p1[1] - p2[1]; float dz = p1[2] - p2[2]; float ds2 = dx*dx + dy*dy + dz*dz; // perform distance test, but ignore pairs between atoms // with nearly identical coords if ((ds2 > sqdist) || (ds2 < 0.001)) continue; if (radii) { // Do atom-specific distance check float cut = 0.6f * (radii[ind1] + radii[ind2]); if (ds2 > cut*cut) continue; } pairs->append(ind1); pairs->append(ind2); paircount++; } } } } // setup results pairlist node GridSearchPairlist *head; head = (GridSearchPairlist *) malloc(sizeof(GridSearchPairlist)); head->next = NULL; head->pairlist = pairs; wkf_mutex_lock(pairlistmutex); // lock pairlist before update parms->head = head; wkf_mutex_unlock(pairlistmutex); // unlock pairlist after update wkf_msg_timer_destroy(msgt); return NULL; }
// To write an X3DOM-compatible scene file, we cannot include // LineProperties nodes. void X3DOMDisplayDevice::text(float *pos, float size, float thickness, const char *str) { float textpos[3]; float textsize; hersheyhandle hh; // transform the world coordinates (transMat.top()).multpoint3d(pos, textpos); textsize = size * 1.5f; ResizeArray<int> idxs; ResizeArray<float> pnts; idxs.clear(); pnts.clear(); int idx=0; while (*str != '\0') { float lm, rm, x, y; int draw; x=y=0.0f; draw=0; hersheyDrawInitLetter(&hh, *str, &lm, &rm); textpos[0] -= lm * textsize; while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) { float pt[3]; if (draw) { // add another connected point to the line strip idxs.append(idx); pt[0] = textpos[0] + textsize * x; pt[1] = textpos[1] + textsize * y; pt[2] = textpos[2]; pnts.append(pt[0]); pnts.append(pt[1]); pnts.append(pt[2]); idx++; } else { idxs.append(-1); // pen-up, end of the line strip } } idxs.append(-1); // pen-up, end of the line strip textpos[0] += rm * textsize; str++; } fprintf(outfile, "<Shape>\n"); fprintf(outfile, " "); // // Emit the line properties // fprintf(outfile, "<Appearance><Material "); fprintf(outfile, "ambientIntensity='%g' ", mat_ambient); fprintf(outfile, "diffuseColor='0 0 0' "); const float *rgb = matData[colorIndex]; fprintf(outfile, "emissiveColor='%g %g %g' ", mat_diffuse * rgb[0], mat_diffuse * rgb[1], mat_diffuse * rgb[2]); fprintf(outfile, "/>"); #if 0 // XXX X3DOM v1.1 doesn't handle LineProperties nodes // emit a line thickness directive, if needed if (thickness < 0.99f || thickness > 1.01f) { fprintf(outfile, " <LineProperties linewidthScaleFactor=\"%g\" " "containerField=\"lineProperties\"/>\n", (double) thickness); } #endif fprintf(outfile, "</Appearance>\n"); // // Emit the line set // fprintf(outfile, " <IndexedLineSet coordIndex='"); int i, cnt; cnt = idxs.num(); for (i=0; i<cnt; i++) { fprintf(outfile, "%d ", idxs[i]); } fprintf(outfile, "'>\n"); fprintf(outfile, " <Coordinate point='"); cnt = pnts.num(); for (i=0; i<cnt; i+=3) { fprintf(outfile, "%c%g %g %g", (i==0) ? ' ' : ',', pnts[i], pnts[i+1], pnts[i+2]); } fprintf(outfile, "'/>\n"); fprintf(outfile, " </IndexedLineSet>\n"); fprintf(outfile, "</Shape>\n"); }
// look for all environment variables VMD can use, and initialize the // proper variables. If an env variable is not found, use a default value. // ENVIRONMENT VARIABLES USED BY VMD (default values set in config.h): // VMDDIR directory with VMD data files and utility programs // VMDTMPDIR directory in which to put temporary files (def: /tmp) static void VMDGetOptions(int argc, char **argv) { char *envtxt; // // VMDDISPLAYDEVICE: which display device to use by default // if((envtxt = getenv("VMDDISPLAYDEVICE"))) { for(int i=0; i < NUM_DISPLAY_TYPES; i++) { if(!strupcmp(envtxt, displayTypeNames[i])) { which_display = i; break; } } } // // VMDTITLE: whether to enable the title screen // if((envtxt = getenv("VMDTITLE"))) { for(int i=0; i < NUM_TITLE_TYPES; i++) { if(!strupcmp(envtxt, titleTypeNames[i])) { showTitle = i; break; } } } // // VMDSCRHEIGHT: height of the screen // if((envtxt = getenv("VMDSCRHEIGHT"))) displayHeight = (float) atof(envtxt); // // VMDSCRDIST: distance to the screen // if((envtxt = getenv("VMDSCRDIST"))) displayDist = (float) atof(envtxt); // // VMDSCRPOS: graphics window location // if((envtxt = getenv("VMDSCRPOS"))) { char * dispStr = NULL; char * dispArgv[64]; int dispArgc; if((dispStr = str_tokenize(envtxt, &dispArgc, dispArgv)) != NULL && dispArgc == 2) { displayLoc[0] = atoi(dispArgv[0]); displayLoc[1] = atoi(dispArgv[1]); } else { msgErr << "Illegal VMDSCRPOS environment variable setting '" << envtxt << "'." << sendmsg; } if(dispStr) delete [] dispStr; } // // VMDSCRSIZE: graphics window size // if((envtxt = getenv("VMDSCRSIZE"))) { char * dispStr = NULL; char * dispArgv[64]; int dispArgc; if((dispStr = str_tokenize(envtxt, &dispArgc, dispArgv)) != NULL && dispArgc == 2) { displaySize[0] = atoi(dispArgv[0]); displaySize[1] = atoi(dispArgv[1]); // force users to do something that makes sense if (displaySize[0] < 100) displaySize[0] = 100; // minimum sane width if (displaySize[1] < 100) displaySize[1] = 100; // minimum sane height } else { msgErr << "Illegal VMDSCRSIZE environment variable setting '" << envtxt << "'." << sendmsg; } if(dispStr) delete [] dispStr; } // initialize variables which indicate how VMD starts up, and // parse the command-line options // go through the arguments int ev = 1; while(ev < argc) { if(!strupcmp(argv[ev], "-dist")) { if(argc > (ev + 1)) { displayDist = (float) atof(argv[++ev]); } else msgErr << "-dist must also specify a distance." << sendmsg; } else if(!strupcmp(argv[ev], "-e")) { if(argc > (ev + 1)) { beginCmdFile = argv[++ev]; } else msgErr << "-e must also specify a filename." << sendmsg; } else if(!strupcmp(argv[ev], "-height")) { if(argc > (ev + 1)) { displayHeight = (float) atof(argv[++ev]); } else msgErr << "-height must also specify a distance." << sendmsg; } else if(!strupcmp(argv[ev], "-pos")) { if(argc > (ev + 2) && *(argv[ev+1]) != '-' && *(argv[ev+2]) != '-') { displayLoc[0] = atoi(argv[++ev]); displayLoc[1] = atoi(argv[++ev]); } else msgErr << "-pos must also specify an X Y pair." << sendmsg; } else if(!strupcmp(argv[ev], "-size")) { if(argc > (ev + 2) && *(argv[ev+1]) != '-' && *(argv[ev+2]) != '-') { displaySize[0] = atoi(argv[++ev]); displaySize[1] = atoi(argv[++ev]); } else msgErr << "-size must also specify an X Y pair." << sendmsg; } else if(!strupcmp(argv[ev], "-startup")) { // use next argument as startup config file name if(argc > (ev + 1)) startupFileStr = argv[++ev]; else msgErr << "-startup must also have a new file name specified." << sendmsg; } else if(!strupcmp(argv[ev], "-nt")) { // do not print out the program title showTitle = TITLE_OFF; } else if (!strupcmp(argv[ev], "-dispdev")) { // startup Display ev++; if (argc > ev) { if (!strupcmp(argv[ev], "cave")) { which_display = DISPLAY_CAVE; // use the CAVE } else if (!strupcmp(argv[ev], "win")) { which_display = DISPLAY_WIN; // use OpenGL, the default } else if (!strupcmp(argv[ev], "opengl")) { which_display = DISPLAY_WINOGL; // use OpenGL if available } else if (!strupcmp(argv[ev], "text")) { which_display = DISPLAY_TEXT; // use text console only } else if (!strupcmp(argv[ev], "caveforms")) { which_display = DISPLAY_CAVEFORMS; // use CAVE+Forms } else if (!strupcmp(argv[ev], "freevr")) { which_display = DISPLAY_FREEVR; // use FreeVR } else if (!strupcmp(argv[ev], "freevrforms")) { which_display = DISPLAY_FREEVRFORMS; // use FreeVR+Forms } else if (!strupcmp(argv[ev], "none")) { which_display = DISPLAY_TEXT; // use text console only } else { msgErr << "-dispdev options are 'win' (default), 'cave', 'caveforms', 'freevr', 'freevrforms', or 'text | none'" << sendmsg; } } else { msgErr << "-dispdev options are 'win' (default), 'cave', 'caveforms', 'freevr', 'freevrforms', or 'text | none'" << sendmsg; } } else if (!strupcmp(argv[ev], "-h") || !strupcmp(argv[ev], "--help")) { // print out command-line option summary msgInfo << "Available command-line options:" << sendmsg; msgInfo << "\t-dispdev <win | cave | text | none> Specify display device"; msgInfo << sendmsg; msgInfo << "\t-dist <d> Distance from origin to screen"; msgInfo << sendmsg; msgInfo << "\t-e <filename> Execute commands in <filename>\n"; msgInfo << "\t-python Use Python for -e file and subsequent text input\n"; msgInfo << "\t-eofexit Exit when end-of-file occurs on input\n"; msgInfo << "\t-h | --help Display this command-line summary\n"; msgInfo << "\t-height <h> Height of display screen"; msgInfo << sendmsg; msgInfo << "\t-pos <X> <Y> Lower-left corner position of display"; msgInfo << sendmsg; msgInfo << "\t-nt No title display at start" << sendmsg; msgInfo << "\t-size <X> <Y> Size of display" << sendmsg; msgInfo << "\t-startup <filename> Specify startup script file" << sendmsg; msgInfo << "\t-m Load subsequent files as separate molecules\n"; msgInfo << "\t-f Load subsequent files into the same molecule\n"; msgInfo << "\t<filename> Load file using best-guess file type\n"; msgInfo << "\t-<type> <filename> Load file using specified file type\n"; msgInfo << "\t-args Pass subsequent arguments to text interpreter\n"; msgInfo << sendmsg; just_print_help = 1; } else if (!strupcmp(argv[ev], "-eofexit")) { // exit on EOF eofexit = 1; } else if (!strupcmp(argv[ev], "-node")) { // start VMD process on a cluster node, next parm is node ID.. ev++; // skip node ID parm } else if (!strupcmp(argv[ev], "-webhelper")) { // Unix startup script doesn't run VMD in the background, so that // web browsers won't delete files out from under us until it really // exits. We don't do anything special inside VMD itself presently // however. } else if (!strupcmp(argv[ev], "-python")) { cmdFileUsesPython = 1; } else if (!strupcmp(argv[ev], "-args")) { // pass the rest of the command line arguments, and only those, // to the embedded text interpreters. while (++ev < argc) customArgv.append(argv[ev]); } else if (!strupcmp(argv[ev], "-m")) { loadAsMolecules = 1; startNewMolecule = 1; } else if (!strupcmp(argv[ev], "-f")) { loadAsMolecules = 0; startNewMolecule = 1; #ifdef VMDMPI } else if (!strupcmp(argv[ev], "-vmddir")) { ev++; // skip VMDDIR directory parm, since we already handled this // in MPI startup before we got to this loop... #endif } else { // any other argument is treated either as a filename or as a // filetype/filename pair of the form -filetype filename. const char *filename, *filetype; if (argv[ev][0] == '-') { // must be filetype/filename pair if (argc > ev+1) { filetype = argv[ev]+1; filename = argv[ev+1]; ev++; } else { msgErr << "filetype argument '" << argv[ev] << "' needs a filename." << sendmsg; ev++; // because we skip past the ev++ at the bottom of the loop. continue; } } else { // Given just a filename. The filetype will have to be guessed. filename = argv[ev]; filetype = NULL; } initFilenames.append(filename); initFiletypes.append(filetype); startNewMoleculeFlags.append(startNewMolecule); if (!loadAsMolecules) startNewMolecule = 0; } ev++; } // command-line options have been parsed ... any init status variables that // have been given initial values will have flags saying so, and their // values will not be changed when the init file(s) is parsed. }
int VMDinitialize(int *argc, char ***argv) { int i; #if defined VMDMPI // hack to fix up env vars if necessary for (i=0; i<(*argc); i++) { if(!strupcmp((*argv)[i], "-vmddir")) { if((*argc) > (i + 1)) { setenv("VMDDIR", (*argv)[++i], 1); } else { msgErr << "-vmddir must specify a fully qualified path." << sendmsg; } } } vmd_mpi_init(argc, argv); // initialize MPI, fix up env vars, etc. #endif #if defined(_MSC_VER) && !defined(VMDSEPARATESTARTUP) win32vmdstart(); // get registry info etc #endif #if !defined(VMDNOMACBUNDLE) && defined(__APPLE__) macosxvmdstart(*argc, *argv); // get env variables etc #endif // Tell Tcl where the executable is located const char *argv0 = vmd_initialize_tcl((*argv)[0]); #ifdef VMDTCL // register signal handler tclhandler = Tcl_AsyncCreate(VMDTclAsyncProc, (ClientData)NULL); signal(SIGINT, (sighandler_t) VMDTclSigHandler); #endif // Let people know who we are. VMDtitle(); // Tell the user what we think about the hardware we're running on. // If VMD is compiled for MPI, then we don't print any of the normal // standalone startup messages and instead we use the special MPI-specific // node scan startup messages only. #if !defined(VMDMPI) #if defined(VMDTHREADS) int vmdnumcpus = wkf_thread_numprocessors(); msgInfo << "Multithreading available, " << vmdnumcpus << ((vmdnumcpus > 1) ? " CPUs" : " CPU") << " detected." << sendmsg; #endif long vmdcorefree = vmd_get_avail_physmem_mb(); if (vmdcorefree >= 0) { long vmdcorepcnt = vmd_get_avail_physmem_percent(); msgInfo << "Free system memory: " << vmdcorefree << "MB (" << vmdcorepcnt << "%)" << sendmsg; } #endif // Read environment variables and command line options. // Initialize customArgv with just argv0 to avoid problems with // Tcl extension. customArgv.append((char *)argv0); VMDGetOptions(*argc, *argv); #if (!defined(__APPLE__) && !defined(_MSC_VER)) && (defined(VMDOPENGL) || defined(VMDFLTK)) // If we're using X-windows, we autodetect if the DISPLAY environment // variable is unset, and automatically switch back to text mode without // requiring the user to pass the "-dispdev text" command line parameters if ((which_display == DISPLAY_WIN) && (getenv("DISPLAY") == NULL)) { which_display = DISPLAY_TEXT; } #endif #if defined(VMDTKCON) vmdcon_init(); msgInfo << "Using VMD Console redirection interface." << sendmsg; // we default to a widget mode console, unless text mode is requested. // we don't have an tcl interpreter registered yet, so it is set to NULL. // flushing pending messages to the screen, is only in text mode possible. if ((which_display == DISPLAY_TEXT) || just_print_help) { vmdcon_use_text(NULL); vmdcon_purge(); } else { vmdcon_use_widget(NULL); } #endif #ifdef VMDFLTK // Do various special FLTK initialization stuff here if ((which_display != DISPLAY_TEXT)) { // Cause FLTK to to use 24-bit color for all windows if possible // This must be done before any FLTK windows are shown for the first time. if (!Fl::visual(FL_DOUBLE | FL_RGB8)) { if (!Fl::visual(FL_RGB8)) { Fl::visual(FL_RGB); } } // Disable the use of the arrow keys for navigating buttons and other // non-text widgets, we'll try it out and see how it pans out Fl::visible_focus(0); // Disable Drag 'n Drop since the only text field in VMD is the // atomselection input and DND severely gets in the way there. Fl::dnd_text_ops(0); } #endif // Quit now if the user just wanted a list of command line options. if (just_print_help) { vmd_sleep(10); // This is here so that the user can see the message // before the terminal/shell exits... return 0; } // Set up default allocators; these may be overridden by cave or freevr. vmd_alloc = malloc; // system malloc() in the default case vmd_dealloc = free; // system free() in the default case vmd_realloc = realloc; // system realloc(), set to NULL when not available // check for a CAVE display if (DISPLAY_USES_CAVE(which_display)) { #ifdef VMDCAVE // allocate shared memory pool used to communicate with child renderers int megs = 2048; if (getenv("VMDCAVEMEM") != NULL) { megs = atoi(getenv("VMDCAVEMEM")); } msgInfo << "Attempting to get " << megs << "MB of CAVE Shared Memory" << sendmsg; grab_CAVE_memory(megs); CAVEConfigure(argc, *argv, NULL); // configure cave walls and memory use // point VMD shared memory allocators to CAVE routines vmd_alloc = malloc_from_CAVE_memory; vmd_dealloc = free_to_CAVE_memory; vmd_realloc = NULL; // no realloc() functionality is available presently #else msgErr << "Not compiled with the CAVE options set." << sendmsg; which_display = DISPLAY_WIN; #endif } // check for a FreeVR display if (DISPLAY_USES_FREEVR(which_display)) { #ifdef VMDFREEVR int megs = 2048; if (getenv("VMDFREEVRMEM") != NULL) { megs = atoi(getenv("VMDFREEVRMEM")); } msgInfo << "Attempting to get " << megs << "MB of FreeVR Shared Memory" << sendmsg; grab_FreeVR_memory(megs); // have to do this *before* vrConfigure() if // we want more than the default shared mem. vrConfigure(NULL, NULL, NULL); // configure FreeVR walls // point shared memory allocators to FreeVR routines vmd_alloc = malloc_from_FreeVR_memory; vmd_dealloc = free_to_FreeVR_memory; vmd_realloc = NULL; // no realloc() functionality is available presently #else msgErr << "Not compiled with the FREEVR options set." << sendmsg; which_display = DISPLAY_WIN; #endif } // return custom argc/argv *argc = customArgv.num(); for (i=0; i<customArgv.num(); i++) { (*argv)[i] = customArgv[i]; } return 1; // successful startup }
// draw a 3-D field lines that follow the volume gradient void DrawMolItem::draw_volume_field_lines (int volid, float seedval, float minlen, float maxlen, float thickness) { const VolumetricData * v = NULL; v = mol->get_volume_data (volid); int printdonemesg = 0; if (v == NULL) { msgInfo << "No volume data loaded at index " << volid << sendmsg; return; } int seedcount = 0; int pointcount = 0; int totalpointcount = 0; int usecolor; ResizeArray<float> seeds; append (DMATERIALOFF); usecolor = draw_volume_get_colorid (); cmdColorIndex.putdata (usecolor, cmdList); seedcount = calcseeds_gradient_magnitude (v, &seeds, seedval * 0.5f, seedval * 1.5f); // Integrate field lines starting with each of the seeds to simulate // particle advection. // Uses Euler's approximation for solving the initial value problem. // We could get a more accurate solution using a fourth order Runge-Kutta // method, but with more math per iteration. We may want to implement // the integrator as a user selected option. // The choice of integration step size is currently arbitrary, // but will become a user-defined parameter, since it affects speed // and accuracy. A good default might be 0.25 times the smallest // grid cell spacing axis. float lx, ly, lz; v->cell_lengths (&lx, &ly, &lz); float mincelllen = lx; mincelllen = (mincelllen < ly) ? mincelllen : ly; mincelllen = (mincelllen < lz) ? mincelllen : lz; float delta = mincelllen * 0.25f; // delta per step (compensates gradient magnitude) // minimum gradient magnitude, before we consider that we've found // a critical point in the dataset. float mingmag = 0.0001f; // max gradient magnitude, before we consider it a source/sink float maxgmag = 5; ResizeArray<float> points; // For each seed point, integrate in both positive and // negative directions for a field line length up to // the maxlen criterion. msgtimer *msgt = msg_timer_create (1); int seed; for (seed = 0; seed < seedcount; seed++) { // emit UI messages as integrator runs, for long calculations... if (!(seed & 7) && msg_timer_timeout (msgt)) { char tmpbuf[128]; sprintf (tmpbuf, "%6.2f %% complete", (100.0f * seed) / (float) seedcount); msgInfo << "integrating " << seedcount << " field lines: " << tmpbuf << sendmsg; printdonemesg = 1; } int direction; for (direction = -1; direction != 1; direction = 1) { float pos[3], comsum[3]; vec_copy (pos, &seeds[seed * 3]); // integration starting point is the seed // init the arrays points.clear (); // main integration loop pointcount = 0; totalpointcount++; float len = 0; int iterations = 0; float dir = (float) direction; vec_zero (comsum); // clear center of mass accumulator while ((len < maxlen) && (totalpointcount < 100000000)) { float grad[3]; // sample gradient at the current position v->voxel_gradient_interpolate_from_coord (pos, grad); // Early-exit if we run out of bounds (gradient returned will // be a vector of NANs), run into a critical point (zero gradient) // or a huge gradient at a source/sink point in the dataset. float gmag = norm (grad); if (gmag < mingmag || gmag > maxgmag) break; // Draw the current point only after the gradient value // has been checked, so we don't end up with out-of-bounds // vertices. // Only emit a fraction of integration points for display since // the integrator stepsize needs to be small for more numerical // accuracy, but the field lines themselves can be well // represented with fewer sample points. if (!(iterations & 1)) { // Add a vertex for this field line points.append (pos[0]); points.append (pos[1]); points.append (pos[2]); vec_incr (comsum, pos); pointcount++; totalpointcount++; } // adjust integration stepsize so we never move more than // the distance specified by delta at each step, to compensate // for varying gradient magnitude vec_scaled_add (pos, dir * delta / gmag, grad); // integrate position len += delta; // accumulate distance iterations++; } int drawfieldline = 1; // only draw the field line for this seed if we have enough points. // If we haven't reached the minimum field line length, we'll // drop the whole field line. if (pointcount < 2 || len < minlen) drawfieldline = 0; // only draw if bounding sphere diameter exceeds minlen if (drawfieldline) { float com[3]; vec_scale (com, 1.0f / (float) pointcount, comsum); float minlen2 = minlen * minlen; drawfieldline = 0; int p; for (p = 0; p < pointcount; p++) { if ((2.0f * distance2 (com, &points[p * 3])) > minlen2) { drawfieldline = 1; break; } } } // only draw the field line if it met all selection criteria if (drawfieldline) { cmdLineType.putdata (SOLIDLINE, cmdList); cmdLineWidth.putdata ((int) thickness, cmdList); cmdColorIndex.putdata (usecolor, cmdList); DispCmdPolyLineArray cmdPolyLineArray; cmdPolyLineArray.putdata (&points[0], pointcount, cmdList); } } } msg_timer_destroy (msgt); if (printdonemesg) msgInfo << "field line integration complete." << sendmsg; }
void DrawMolItem::draw_volume_isosurface_lit_points (const VolumetricData * v, float isovalue, int stepsize, int thickness) { int x, y, z; float *addr; float pos[3]; float xax[3], yax[3], zax[3]; ResizeArray<float> centers; ResizeArray<float> normals; ResizeArray<float> colors; int i; float vorigin[3]; for (i = 0; i < 3; i++) { vorigin[i] = float (v->origin[i]); } int pointcount = 0; int usecolor; append (DMATERIALON); usecolor = draw_volume_get_colorid (); const float *cp = scene->color_value (usecolor); cmdColorIndex.putdata (usecolor, cmdList); // calculate cell axes v->cell_axes (xax, yax, zax); for (z = 0; z < v->zsize; z += stepsize) { for (y = 0; y < v->ysize; y += stepsize) { addr = &(v->data[(z * (v->xsize * v->ysize)) + (y * v->xsize)]); // loop through xsize - 1 rather than the full range for (x = 0; x < (v->xsize - 1); x += stepsize) { float diff, isodiff; // draw a point if the isovalue falls between neighboring X samples diff = addr[x] - addr[x + 1]; isodiff = addr[x] - isovalue; if ((fabs (diff) > fabs (isodiff)) && (MYSGN(diff) == MYSGN(isodiff))) { pos[0] = vorigin[0] + x * xax[0] + y * yax[0] + z * zax[0]; pos[1] = vorigin[1] + x * xax[1] + y * yax[1] + z * zax[1]; pos[2] = vorigin[2] + x * xax[2] + y * yax[2] + z * zax[2]; float norm[3]; vec_copy (norm, &v->gradient[(z * v->xsize * v->ysize + y * v->xsize + x) * 3]); // draw a point there. centers.append (pos[0]); centers.append (pos[1]); centers.append (pos[2]); normals.append (norm[0]); normals.append (norm[1]); normals.append (norm[2]); colors.append (cp[0]); colors.append (cp[1]); colors.append (cp[2]); pointcount++; } } } } if (pointcount > 0) { DispCmdLitPointArray cmdLitPointArray; cmdLitPointArray.putdata ((float *) ¢ers[0], (float *) &normals[0], (float *) &colors[0], (float) thickness, pointcount, cmdList); } }