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

utilities.C

Go to the documentation of this file.
00001 /***************************************************************************
00002 *cr 
00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 
00004 *cr University of Illinois 
00005 *cr All Rights Reserved 
00006 *cr 
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 * $RCSfile: utilities.C,v $
00013 * $Author: johns $ $Locker: $ $State: Exp $
00014 * $Revision: 1.177 $ $Date: 2021年09月23日 15:20:20 $
00015 *
00016 ***************************************************************************
00017 * DESCRIPTION:
00018 *
00019 * General utility routines and definitions.
00020 *
00021 ***************************************************************************/
00022 
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <math.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 
00029 #if defined(_MSC_VER)
00030 #include <windows.h>
00031 #include <conio.h>
00032 #else
00033 #include <unistd.h>
00034 #include <sys/time.h>
00035 #include <errno.h>
00036 
00037 #if defined(ARCH_AIX4)
00038 #include <strings.h>
00039 #endif
00040 
00041 #if defined(__irix)
00042 #include <bstring.h>
00043 #endif
00044 
00045 #if defined(__hpux)
00046 #include <time.h>
00047 #endif // HPUX
00048 #endif // _MSC_VER
00049 
00050 #if defined(AIXUSEPERFSTAT)
00051 #include <libperfstat.h>
00052 #endif
00053 
00054 #if defined(__APPLE__)
00055 #include <sys/sysctl.h>
00056 #endif
00057 
00058 #include "utilities.h"
00059 
00060 // given an argc, argv pair, take all the arguments from the Nth one on
00061 // and combine them into a single string with spaces separating words. This
00062 // allocates space for the string, which must be freed by the user.
00063 char *combine_arguments(int argc, const char **argv, int n) {
00064 char *newstr = NULL;
00065 
00066 if(argc > 0 && n < argc && n >= 0) {
00067 int i, sl = 0;
00068 // find out the length of the words we must combine
00069 for(i=n; i < argc; i++)
00070 sl += strlen(argv[i]);
00071 
00072 // combine the words together
00073 if(sl) {
00074 newstr = new char[sl + 8 + argc - n]; // extra buffer added
00075 *newstr = '0円';
00076 for(i=n; i < argc; i++) {
00077 if(i != n)
00078 strcat(newstr," ");
00079 strcat(newstr, argv[i]);
00080 }
00081 }
00082 }
00083 
00084 // return the string, or NULL if a problem occurred
00085 return newstr;
00086 }
00087 
00088 
00089 // duplicate a string using c++ new call
00090 char *stringdup(const char *s) {
00091 char *rs;
00092 
00093 if(!s)
00094 return NULL;
00095 
00096 rs = new char[strlen(s) + 1];
00097 strcpy(rs,s);
00098 
00099 return rs;
00100 }
00101 
00102 
00103 // convert a string to upper case
00104 char *stringtoupper(char *s) {
00105 if (s != NULL) {
00106 int i;
00107 int sz = strlen(s);
00108 for(i=0; i<sz; i++)
00109 s[i] = toupper(s[i]);
00110 }
00111 
00112 return s;
00113 }
00114 
00115 void stripslashes(char *str) {
00116 while (strlen(str) > 0 && str[strlen(str) - 1] == '/') {
00117 str[strlen(str) - 1] = '0円';
00118 }
00119 }
00120 
00121 // do upper-case comparison
00122 int strupcmp(const char *a, const char *b) {
00123 char *ua, *ub;
00124 int retval;
00125 
00126 ua = stringtoupper(stringdup(a));
00127 ub = stringtoupper(stringdup(b));
00128 
00129 retval = strcmp(ua,ub);
00130 
00131 delete [] ub;
00132 delete [] ua;
00133 
00134 return retval;
00135 }
00136 
00137 
00138 // do upper-case comparison, up to n characters
00139 int strupncmp(const char *a, const char *b, int n) {
00140 #if defined(ARCH_AIX3) || defined(ARCH_AIX4) || defined(_MSC_VER)
00141 while (n-- > 0) {
00142 if (toupper(*a) != toupper(*b)) {
00143 return toupper(*b) - toupper(*a);
00144 }
00145 if (*a == 0) return 0;
00146 a++; b++;
00147 }
00148 return 0;
00149 #else
00150 return strncasecmp(a, b, n);
00151 #endif
00152 }
00153 
00154 
00155 // break a file name up into path + name, returning both in the specified
00156 // character pointers. This creates storage for the new strings
00157 // by allocating space for them.
00158 void breakup_filename(const char *full, char **path, char **name) {
00159 const char *namestrt;
00160 int pathlen;
00161 
00162 if(full == NULL) {
00163 *path = *name = NULL;
00164 return;
00165 } else if (strlen(full) == 0) {
00166 *path = new char[1];
00167 *name = new char[1];
00168 (*path)[0] = (*name)[0] = '0円';
00169 return;
00170 }
00171 
00172 // find start of final file name
00173 if((namestrt = strrchr(full,'/')) != NULL && strlen(namestrt) > 0) {
00174 namestrt++;
00175 } else {
00176 namestrt = full;
00177 }
00178 
00179 // make a copy of the name
00180 *name = stringdup(namestrt);
00181 
00182 // make a copy of the path
00183 pathlen = strlen(full) - strlen(*name);
00184 *path = new char[pathlen + 1];
00185 strncpy(*path,full,pathlen);
00186 (*path)[pathlen] = '0円';
00187 } 
00188 
00189 // break a configuration line up into tokens.
00190 char *str_tokenize(const char *newcmd, int *argc, char *argv[]) {
00191 char *cmd; 
00192 const char *cmdstart;
00193 cmdstart = newcmd;
00194 
00195 // guarantee that the command string we return begins on the first
00196 // character returned by strtok(), otherwise the subsequent delete[]
00197 // calls will reference invalid memory blocks
00198 while (cmdstart != NULL &&
00199 (*cmdstart == ' ' ||
00200 *cmdstart == ',' ||
00201 *cmdstart == ';' ||
00202 *cmdstart == '\t' ||
00203 *cmdstart == '\n')) {
00204 cmdstart++; // advance pointer to first command character
00205 } 
00206 
00207 cmd = stringdup(cmdstart);
00208 *argc = 0;
00209 
00210 // initialize tokenizing calls
00211 argv[*argc] = strtok(cmd, " ,;\t\n");
00212 
00213 // loop through words until end-of-string, or comment character, found
00214 while(argv[*argc] != NULL) {
00215 // see if the token starts with '#'
00216 if(argv[*argc][0] == '#') {
00217 break; // don't process any further tokens
00218 } else {
00219 (*argc)++; // another token in list
00220 }
00221 
00222 // scan for next token
00223 argv[*argc] = strtok(NULL," ,;\t\n");
00224 }
00225 
00226 return (*argc > 0 ? argv[0] : (char *) NULL);
00227 }
00228 
00229 
00230 // get the time of day from the system clock, and store it (in seconds)
00231 double time_of_day(void) {
00232 #if defined(_MSC_VER)
00233 double t;
00234 
00235 t = GetTickCount(); 
00236 t = t / 1000.0;
00237 
00238 return t;
00239 #else
00240 struct timeval tm;
00241 struct timezone tz;
00242 
00243 gettimeofday(&tm, &tz);
00244 return((double)(tm.tv_sec) + (double)(tm.tv_usec)/1000000.0);
00245 #endif
00246 }
00247 
00248 
00249 int vmd_check_stdin(void) {
00250 #if defined(_MSC_VER)
00251 if (_kbhit() != 0)
00252 return TRUE;
00253 else
00254 return FALSE;
00255 #else
00256 fd_set readvec;
00257 struct timeval timeout;
00258 int ret, stdin_fd;
00259 
00260 timeout.tv_sec = 0;
00261 timeout.tv_usec = 0;
00262 stdin_fd = 0;
00263 FD_ZERO(&readvec);
00264 FD_SET(stdin_fd, &readvec);
00265 
00266 #if !defined(ARCH_AIX3)
00267 ret = select(16, &readvec, NULL, NULL, &timeout);
00268 #else
00269 ret = select(16, (int *)(&readvec), NULL, NULL, &timeout);
00270 #endif
00271 
00272 if (ret == -1) { // got an error
00273 if (errno != EINTR) // XXX: this is probably too lowlevel to be converted to Inform.h
00274 printf("select() error while attempting to read text input.\n");
00275 return FALSE;
00276 } else if (ret == 0) {
00277 return FALSE; // select timed out
00278 }
00279 return TRUE;
00280 #endif
00281 }
00282 
00283 
00284 // return the username of the currently logged-on user
00285 char *vmd_username(void) {
00286 #if defined(_MSC_VER)
00287 char username[1024];
00288 unsigned long size = 1023;
00289 
00290 if (GetUserName((char *) &username, &size)) {
00291 return stringdup(username);
00292 }
00293 else { 
00294 return stringdup("Windows User");
00295 }
00296 #else
00297 #if defined(ARCH_FREEBSD) || defined(ARCH_FREEBSDAMD64) || defined(__APPLE__) || defined(__linux)
00298 return stringdup(getlogin());
00299 #else
00300 return stringdup(cuserid(NULL));
00301 #endif 
00302 #endif
00303 }
00304 
00305 int vmd_getuid(void) {
00306 #if defined(_MSC_VER)
00307 return 0;
00308 #else
00309 return getuid(); 
00310 #endif
00311 }
00312 
00313 
00314 // take three 3-vectors and compute x2 cross x3; with the results
00315 // in x1. x1 must point to different memory than x2 or x3
00316 // This returns a pointer to x1
00317 float * cross_prod(float *x1, const float *x2, const float *x3)
00318 {
00319 x1[0] = x2[1]*x3[2] - x3[1]*x2[2];
00320 x1[1] = -x2[0]*x3[2] + x3[0]*x2[2];
00321 x1[2] = x2[0]*x3[1] - x3[0]*x2[1];
00322 return x1;
00323 }
00324 
00325 // normalize a vector, and return a pointer to it
00326 // Warning: it changes the value of the vector!!
00327 float * vec_normalize(float *vect) {
00328 float len2 = vect[0]*vect[0] + vect[1]*vect[1] + vect[2]*vect[2];
00329 
00330 // prevent division by zero
00331 if (len2 > 0) {
00332 float rescale = 1.0f / sqrtf(len2);
00333 vect[0] *= rescale;
00334 vect[1] *= rescale;
00335 vect[2] *= rescale;
00336 }
00337 
00338 return vect;
00339 }
00340 
00341 
00342 // find and return the norm of a 3-vector
00343 float norm(const float *vect) {
00344 return sqrtf(vect[0]*vect[0] + vect[1]*vect[1] + vect[2]*vect[2]);
00345 }
00346 
00347 
00348 // determine if a triangle is degenerate or not
00349 int tri_degenerate(const float * v0, const float * v1, const float * v2) {
00350 float s1[3], s2[3], s1_length, s2_length;
00351 
00352 /*
00353 various rendering packages have amusingly different ideas about what
00354 constitutes a degenerate triangle. -1 and 1 work well. numbers
00355 below 0.999 and -0.999 show up in OpenGL
00356 numbers as low as 0.98 have worked in POVRay with certain models while
00357 numbers as high as 0.999999 have produced massive holes in other
00358 models
00359 -matt 11/13/96
00360 */
00361 
00362 /**************************************************************/
00363 /* turn the triangle into 2 normalized vectors. */
00364 /* If the dot product is 1 or -1 then */
00365 /* the triangle is degenerate */
00366 /**************************************************************/
00367 s1[0] = v0[0] - v1[0];
00368 s1[1] = v0[1] - v1[1];
00369 s1[2] = v0[2] - v1[2];
00370 
00371 s2[0] = v0[0] - v2[0];
00372 s2[1] = v0[1] - v2[1];
00373 s2[2] = v0[2] - v2[2];
00374 
00375 s1_length = sqrtf(s1[0]*s1[0] + s1[1]*s1[1] + s1[2]*s1[2]);
00376 s2_length = sqrtf(s2[0]*s2[0] + s2[1]*s2[1] + s2[2]*s2[2]);
00377 
00378 /**************************************************************/
00379 /* invert to avoid divides: */
00380 /* 1.0/v1_length * 1.0/v2_length */
00381 /**************************************************************/
00382 
00383 s2_length = 1.0f / (s1_length*s2_length);
00384 s1_length = s2_length * (s1[0]*s2[0] + s1[1]*s2[1] + s1[2]*s2[2]);
00385 
00386 // and add it to the list if it's not degenerate
00387 if ((s1_length >= 1.0f ) || (s1_length <= -1.0f)) 
00388 return 1;
00389 else
00390 return 0;
00391 }
00392 
00393 
00394 // compute the angle (in degrees 0 to 180 ) between two vectors a & b
00395 float angle(const float *a, const float *b) {
00396 float ab[3];
00397 cross_prod(ab, a, b);
00398 float psin = sqrtf(dot_prod(ab, ab));
00399 float pcos = dot_prod(a, b);
00400 return 57.2958f * (float) atan2(psin, pcos);
00401 }
00402 
00403 
00404 // Compute the dihedral angle for the given atoms, returning a value between
00405 // -180 and 180.
00406 // faster, cleaner implementation based on atan2
00407 float dihedral(const float *a1,const float *a2,const float *a3,const float *a4)
00408 {
00409 float r1[3], r2[3], r3[3], n1[3], n2[3];
00410 vec_sub(r1, a2, a1);
00411 vec_sub(r2, a3, a2);
00412 vec_sub(r3, a4, a3);
00413 
00414 cross_prod(n1, r1, r2);
00415 cross_prod(n2, r2, r3);
00416 
00417 float psin = dot_prod(n1, r3) * sqrtf(dot_prod(r2, r2));
00418 float pcos = dot_prod(n1, n2);
00419 
00420 // atan2f would be faster, but we'll have to workaround the lack
00421 // of existence on some platforms.
00422 return 57.2958f * (float) atan2(psin, pcos);
00423 }
00424 
00425 // compute the distance between points a & b
00426 float distance(const float *a, const float *b) {
00427 return sqrtf(distance2(a,b));
00428 }
00429 
00430 char *vmd_tempfile(const char *s) {
00431 char *envtxt, *TempDir;
00432 
00433 if((envtxt = getenv("VMDTMPDIR")) != NULL) {
00434 TempDir = stringdup(envtxt);
00435 } else {
00436 #if defined(_MSC_VER)
00437 if ((envtxt = getenv("TMP")) != NULL) {
00438 TempDir = stringdup(envtxt);
00439 }
00440 else if ((envtxt = getenv("TEMP")) != NULL) {
00441 TempDir = stringdup(envtxt);
00442 }
00443 else {
00444 TempDir = stringdup("c:\\\\");
00445 }
00446 #else
00447 TempDir = stringdup("/tmp");
00448 #endif
00449 }
00450 stripslashes(TempDir); // strip out ending '/' chars.
00451 
00452 char *tmpfilebuf = new char[1024];
00453 
00454 // copy in temp string
00455 strcpy(tmpfilebuf, TempDir);
00456 
00457 #if defined(_MSC_VER)
00458 strcat(tmpfilebuf, "\\");
00459 strncat(tmpfilebuf, s, 1022 - strlen(TempDir));
00460 #else
00461 strcat(tmpfilebuf, "/");
00462 strncat(tmpfilebuf, s, 1022 - strlen(TempDir));
00463 #endif
00464 
00465 tmpfilebuf[1023] = '0円';
00466 
00467 delete [] TempDir;
00468 
00469 // return converted string
00470 return tmpfilebuf;
00471 }
00472 
00473 
00474 int vmd_delete_file(const char * path) {
00475 #if defined(_MSC_VER)
00476 if (DeleteFile(path) == 0) 
00477 return -1;
00478 else 
00479 return 0; 
00480 #else
00481 return unlink(path);
00482 #endif
00483 }
00484 
00485 void vmd_sleep(int secs) {
00486 #if defined(_MSC_VER)
00487 Sleep(secs * 1000);
00488 #else 
00489 sleep(secs);
00490 #endif
00491 }
00492 
00493 void vmd_msleep(int msecs) {
00494 #if defined(_MSC_VER)
00495 Sleep(msecs);
00496 #else 
00497 struct timeval timeout;
00498 timeout.tv_sec = 0;
00499 timeout.tv_usec = 1000 * msecs;
00500 select(0, NULL, NULL, NULL, &timeout);
00501 #endif // _MSC_VER
00502 }
00503 
00504 int vmd_system(const char* cmd) {
00505 return system(cmd);
00506 }
00507 
00508 
00512 long vmd_random(void) {
00513 #ifdef _MSC_VER
00514 return rand();
00515 #else
00516 return random();
00517 #endif
00518 }
00519 
00520 void vmd_srandom(unsigned int seed) {
00521 #ifdef _MSC_VER
00522 srand(seed);
00523 #else
00524 srandom(seed);
00525 #endif
00526 }
00527 
00530 float vmd_random_gaussian() {
00531 static bool cache = false;
00532 static float cached_value;
00533 const float RAND_FACTOR = 2.f/float(VMD_RAND_MAX);
00534 float r, s, w;
00535 
00536 if (cache) {
00537 cache = false;
00538 return cached_value;
00539 }
00540 do {
00541 r = RAND_FACTOR*vmd_random()-1.f; 
00542 s = RAND_FACTOR*vmd_random()-1.f;
00543 w = r*r+s*s;
00544 } while (w >= 1.f);
00545 w = sqrtf(-2.f*logf(w)/w);
00546 cached_value = s * w;
00547 cache = true;
00548 return (r*w);
00549 }
00550 
00551 
00554 long vmd_get_total_physmem_mb(void) {
00555 #if defined(_MSC_VER)
00556 MEMORYSTATUS memstat;
00557 GlobalMemoryStatus(&memstat);
00558 if (memstat.dwLength != sizeof(memstat))
00559 return -1; /* memstat result is wrong size! */
00560 return memstat.dwTotalPhys/(1024 * 1024);
00561 #elif defined(__linux)
00562 FILE *fp;
00563 char meminfobuf[1024], *pos;
00564 size_t len;
00565 
00566 fp = fopen("/proc/meminfo", "r");
00567 if (fp != NULL) {
00568 len = fread(meminfobuf,1,1024, fp);
00569 meminfobuf[1023] = 0;
00570 fclose(fp);
00571 if (len > 0) {
00572 pos=strstr(meminfobuf,"MemTotal:");
00573 if (pos == NULL) 
00574 return -1;
00575 pos += 9; /* skip tag */;
00576 return strtol(pos, (char **)NULL, 10)/1024L;
00577 }
00578 } 
00579 return -1;
00580 #elif defined(AIXUSEPERFSTAT) && defined(_AIX)
00581 perfstat_memory_total_t minfo;
00582 perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);
00583 return minfo.real_total*(4096/1024)/1024;
00584 #elif defined(_AIX)
00585 return (sysconf(_SC_AIX_REALMEM) / 1024);
00586 #elif defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
00587 /* SysV Unix */
00588 long pgsz = sysconf(_SC_PAGESIZE);
00589 long physpgs = sysconf(_SC_PHYS_PAGES);
00590 return ((pgsz / 1024) * physpgs) / 1024;
00591 #elif defined(__APPLE__)
00592 /* MacOS X uses BSD sysctl */
00593 /* use hw.memsize, as it's a 64-bit value */
00594 int rc;
00595 uint64_t membytes;
00596 size_t len = sizeof(membytes);
00597 if (sysctlbyname("hw.memsize", &membytes, &len, NULL, 0)) 
00598 return -1;
00599 return (membytes / (1024*1024));
00600 #else
00601 return -1; /* unrecognized system, no method to get this info */
00602 #endif
00603 }
00604 
00605 
00606 
00609 long vmd_get_avail_physmem_mb(void) {
00610 #if defined(_MSC_VER)
00611 MEMORYSTATUS memstat;
00612 GlobalMemoryStatus(&memstat);
00613 if (memstat.dwLength != sizeof(memstat))
00614 return -1; /* memstat result is wrong size! */ 
00615 return memstat.dwAvailPhys / (1024 * 1024);
00616 #elif defined(__linux)
00617 FILE *fp;
00618 char meminfobuf[1024], *pos;
00619 size_t len;
00620 long val;
00621 
00622 fp = fopen("/proc/meminfo", "r");
00623 if (fp != NULL) {
00624 len = fread(meminfobuf,1,1024, fp);
00625 meminfobuf[1023] = 0;
00626 fclose(fp);
00627 if (len > 0) {
00628 val = 0L;
00629 pos=strstr(meminfobuf,"MemFree:");
00630 if (pos != NULL) {
00631 pos += 8; /* skip tag */;
00632 val += strtol(pos, (char **)NULL, 10);
00633 }
00634 pos=strstr(meminfobuf,"Buffers:");
00635 if (pos != NULL) {
00636 pos += 8; /* skip tag */;
00637 val += strtol(pos, (char **)NULL, 10);
00638 }
00639 pos=strstr(meminfobuf,"Cached:");
00640 if (pos != NULL) {
00641 pos += 8; /* skip tag */;
00642 val += strtol(pos, (char **)NULL, 10);
00643 }
00644 return val/1024L;
00645 } else {
00646 return -1;
00647 }
00648 } else {
00649 return -1;
00650 }
00651 #elif defined(AIXUSEPERFSTAT) && defined(_AIX)
00652 perfstat_memory_total_t minfo;
00653 perfstat_memory_total(NULL, &minfo, sizeof(perfstat_memory_total_t), 1);
00654 return minfo.real_free*(4096/1024)/1024;
00655 #elif defined(_SC_PAGESIZE) && defined(_SC_AVPHYS_PAGES)
00656 /* SysV Unix */
00657 long pgsz = sysconf(_SC_PAGESIZE);
00658 long avphyspgs = sysconf(_SC_AVPHYS_PAGES);
00659 return ((pgsz / 1024) * avphyspgs) / 1024;
00660 #elif defined(__APPLE__)
00661 #if 0
00662 /* BSD sysctl */
00663 /* hw.usermem isn't really the amount of free memory, it's */
00664 /* really more a measure of the non-kernel memory */
00665 int rc;
00666 int membytes;
00667 size_t len = sizeof(membytes);
00668 if (sysctlbyname("hw.usermem", &membytes, &len, NULL, 0)) 
00669 return -1;
00670 return (membytes / (1024*1024));
00671 #else
00672 return -1;
00673 #endif
00674 #else
00675 return -1; /* unrecognized system, no method to get this info */
00676 #endif
00677 }
00678 
00679 
00681 long vmd_get_avail_physmem_percent(void) {
00682 double total, avail;
00683 total = (double) vmd_get_total_physmem_mb();
00684 avail = (double) vmd_get_avail_physmem_mb();
00685 if (total > 0.0 && avail >= 0.0)
00686 return (long) (avail / (total / 100.0));
00687 
00688 return -1; /* return an error */
00689 }
00690 
00691 
00692 // returns minimum distance for Poisson disk sampler
00693 float correction(int nrays) {
00694 float N=(float)nrays;
00695 float eightPi=VMD_PIF*8.0f;
00696 float denom=(float)( N*(3.0f*sqrtf(3)) );
00697 float ans=sqrtf(eightPi/denom);
00698 float minD=sqrtf((ans*ans) + powf(((VMD_PIF/6.0f)*ans),2) );
00699 
00700 return 1.1275f*minD; //with padding
00701 }
00702 
00703 // print poisson points to .xyz file
00704 void print_xyz(float* population, int nrays) {
00705 float x,y,z;
00706 FILE* fp=fopen("validate.xyz","w");
00707 fprintf(fp,"%d\n",nrays);
00708 for (int i=0; i<=nrays; i++) {
00709 x=cosf(population[i*2+0])*sinf(population[i*2+1]);
00710 y=sinf(population[i*2+0])*sinf(population[i*2+1]);
00711 z=cosf(population[i*2+1]);
00712 fprintf(fp,"C %2.6f %2.6f %2.6f\n",x,y,z);
00713 }
00714 fclose(fp);
00715 return;
00716 }
00717 
00718 // compute arc distance between two points on unit sphere
00719 float arcdistance(float lambda1, float lambda2, float phi1, float phi2) {
00720 float sl1,cl1,sl2,cl2;
00721 float sp1,cp1,sp2,cp2;
00722 
00723 sincosf(lambda1, &sl1, &cl1);
00724 sincosf(phi1, &sp1, &cp1);
00725 sincosf(lambda2, &sl2, &cl2);
00726 sincosf(phi2, &sp2, &cp2);
00727 
00728 float cos_Ang=(float)( ((cl1*sp1)*(cl2*sp2)) + ((sl1*sp1)*(sl2*sp2)) + (cp1*cp2) );
00729 
00730 return acosf(cos_Ang);
00731 }
00732 
00733 // generate K candidates, return the farthest from all previously
00734 // committed samples
00735 int k_candidates(int k, int nrays, int idx, int testpt, float minD, float* candidates, float* population) {
00736 static const float RAND_MAX_INV=1.0f/float(VMD_RAND_MAX);
00737 int bestIdx=-1;
00738 int count=0; //score for each test point
00739 float bestDist=0.0f;
00740 float lambda1=population[testpt*2+0];
00741 float phi1=population[testpt*2+1];
00742 float currDist;
00743 
00744 float minLambda=VMD_TWOPIF*minD;
00745 float minPhi=VMD_PIF*minD;
00746 
00747 float dp, dl;
00748 for (int i=0; i<k; i++) {
00749 dl=(float)(lambda1-(minLambda+((float)(RAND_MAX_INV*vmd_random()))*minLambda));
00750 dp=(float)(phi1-(minPhi+((float)(RAND_MAX_INV*vmd_random()))*minPhi));
00751 
00752 candidates[i*2+0]=(float)(lambda1+(dl));
00753 candidates[i*2+1]=(float)(phi1+(dp));
00754 }
00755 
00756 for (int j=0; j<k; j++) {
00757 currDist=0.0f;
00758 count=0;
00759 for(int jj=0; jj<idx; jj++) {
00760 float dist=arcdistance(population[jj*2+0],candidates[j*2+0],
00761 population[jj*2+1],candidates[j*2+1]);
00762 
00763 if ((dist-minD)>0.00000001f) {
00764 currDist+=dist;
00765 count++;
00766 }
00767 }
00768 
00769 //pick best candidate
00770 if (count==idx) {
00771 if (currDist>bestDist) {
00772 bestIdx=j;
00773 bestDist=currDist;
00774 count=0;
00775 }
00776 count=0;
00777 }
00778 }
00779 return bestIdx;
00780 }
00781 
00782 // Poisson disk sampler -- fills 2D array with N 
00783 // lambda phi pairs which embed in the unit sphere when 
00784 // converted to cartesian coordinates
00785 int poisson_sample_on_sphere(float *population, int N, int k, int verbose) {
00786 int converged=0; 
00787 int result=0; 
00788 int popul=0;
00789 int fc=0; 
00790 int testpt=0; 
00791 int attempts=0;
00792 int tr=0;
00793 
00794 float minD=correction(N);
00795 static const float RAND_MAX_INV=1.0f/float(VMD_RAND_MAX);
00796 
00797 float *candidates=NULL;
00798 int *activelist=NULL;
00799 
00800 candidates=new float[k*2];
00801 activelist=new int[N];
00802 for (int ii=0; ii<k; ii++) {
00803 candidates[ii*2+0]=0.0f;
00804 candidates[ii*2+1]=0.0f;
00805 }
00806 for (int jj=0; jj<N; jj++) {
00807 population[jj*2+0]=0.0f;
00808 population[jj*2+1]=0.0f;
00809 activelist[jj]=1; //set all to active
00810 }
00811 int numactive=N;
00812 
00813 vmd_srandom(512346);
00814 population[0]=(float)((RAND_MAX_INV*vmd_random())*VMD_TWOPI);
00815 population[1]=(float)((RAND_MAX_INV*vmd_random())*VMD_PI);
00816 popul++; //for consistency -- popul incremented after each addition
00817 
00818 while (converged==0) {
00819 while (activelist[testpt]==1) {
00820 result=k_candidates(k,N,popul,testpt,minD,candidates,population);
00821 if (result!=-1) {
00822 population[popul*2+0]=candidates[result*2+0];
00823 population[popul*2+1]=candidates[result*2+1];
00824 popul++;
00825 if (popul==(N+1)) { converged=1; break; }
00826 testpt=vmd_random()%popul; //pick new test pt
00827 } else {
00828 activelist[testpt]=0; //if a new pt can't be added around testpt, deactivate
00829 numactive--;
00830 break;
00831 }
00832 if (popul==(N+1)) {
00833 converged=1;
00834 break;
00835 }
00836 }
00837 
00838 if (popul==(N+1)) {
00839 converged=1;
00840 break;
00841 } else if (fc==N*N) {
00842 if (verbose) printf("Poisson sampler failed at population=%d\n",popul);
00843 break;
00844 } else if (numactive>=2) {
00845 while (activelist[testpt]!=1) {
00846 testpt=vmd_random()%popul;
00847 tr++;
00848 if (tr>N*1000) { break; }
00849 }
00850 } else {
00851 if (verbose) printf("Error in Poisson disk sampling procedure.\n");
00852 }
00853 
00854 if (numactive<=2 && popul!=(N+1)) {
00855 for (int f=0; f<N; f++)
00856 activelist[f]=1;
00857 
00858 popul=1; fc=0; numactive=N; testpt=0; //failed to converge, reset
00859 attempts++;
00860 } else if (popul==(N+1)) {
00861 converged=1;
00862 break;
00863 }
00864 if (attempts>10) { //hard exit after 10 attempts
00865 if (verbose) printf("Poisson sampler failed to converge (population=%d)\n",popul);
00866 break;
00867 }
00868 }
00869 
00870 delete [] candidates;
00871 delete [] activelist;
00872 
00873 if (popul==(N+1) && converged==1) {
00874 if (verbose) printf("Poisson sampler done. (%d/10 attempts)\n",attempts+1);
00875 return 1;
00876 }
00877 
00878 if (converged==0) {
00879 if (verbose) printf("Poisson sampler failed -- exiting.");
00880 return -1;
00881 }
00882 
00883 return 0;
00884 }
00885 

Generated on Tue Nov 18 02:48:14 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /