layer0/Map.cpp (857 lines of code) (raw):
/*
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* Copyright (c) Schrodinger, LLC.
D* -------------------------------------------------------------------
E* It is unlawful to modify or remove this copyright notice.
F* -------------------------------------------------------------------
G* Please see the accompanying LICENSE file for further information.
H* -------------------------------------------------------------------
I* Additional authors of this source file include:
-* Larry Coopet (various optimizations)
-*
-*
Z* ------------------------------------------------------------------- */
#include"os_python.h"
#include"os_predef.h"
#include"os_std.h"
#include"MemoryDebug.h"
#include"Err.h"
#include"OOMac.h"
#include"Map.h"
#include"Setting.h"
#include"Feedback.h"
#include"MemoryCache.h"
#include"Base.h"
static MapType *_MapNew(PyMOLGlobals * G, float range, float *vert, int nVert,
float *extent, int *flag, int group_id, int block_id);
float MapGetDiv(MapType * I)
{
return I->Div;
}
void MapFree(MapType * I)
{
if(I) {
CacheFreeP(I->G, I->Head, I->group_id, I->block_base + cCache_map_head_offset, false);
CacheFreeP(I->G, I->Link, I->group_id, I->block_base + cCache_map_link_offset, false);
CacheFreeP(I->G, I->EHead, I->group_id, I->block_base + cCache_map_ehead_offset,
false);
CacheFreeP(I->G, I->EMask, I->group_id, I->block_base + cCache_map_emask_offset,
false);
VLACacheFreeP(I->G, I->EList, I->group_id, I->block_base + cCache_map_elist_offset,
false);
}
OOFreeP(I);
}
int MapCacheInit(MapCache * M, MapType * I, int group_id, int block_base)
{
PyMOLGlobals *G = I->G;
int ok = true;
M->G = G;
M->block_base = I->block_base;
M->Cache =
CacheCalloc(G, int, I->NVert, group_id, block_base + cCache_map_cache_offset);
CHECKOK(ok, M->Cache);
if (ok)
M->CacheLink =
CacheAlloc(G, int, I->NVert, group_id, block_base + cCache_map_cache_link_offset);
CHECKOK(ok, M->CacheLink);
M->CacheStart = -1;
return ok;
/* p=M->Cache;
for(a=0;a<I->NVert;a++)
*(p++) = 0; */
}
void MapCacheReset(MapCache * M)
{
int i = M->CacheStart;
int *cachep = M->Cache;
int *clinkp = M->CacheLink;
int i1 = 0, i2 = 0, i3 = 0, i4 = 0, ii;
while(i >= 0) { /* believe it or not, unrolling gives us almost 10%!!! */
ii = clinkp[i];
i1 = i;
i = ii;
if(ii >= 0) {
ii = clinkp[ii];
i2 = i;
i = ii;
}
cachep[i1] = 0; /* this doesn't look safe, but it is. i1-i4 are always valid indices */
if(ii >= 0) {
ii = clinkp[ii];
i3 = i;
i = ii;
}
cachep[i2] = 0; /* this doesn't look safe, but it is. i1-i4 are always valid indices */
if(ii >= 0) {
ii = clinkp[ii];
i4 = i;
i = ii;
}
cachep[i3] = 0; /* this doesn't look safe, but it is. i1-i4 are always valid indices */
cachep[i4] = 0; /* this doesn't look safe, but it is. i1-i4 are always valid indices */
}
M->CacheStart = -1;
}
void MapCacheFree(MapCache * M, int group_id, int block_base)
{
CacheFreeP(M->G, M->Cache, group_id, block_base + cCache_map_cache_offset, false);
CacheFreeP(M->G, M->CacheLink, group_id, block_base + cCache_map_cache_link_offset,
false);
}
#define MapSafety 0.01F
int MapInside(MapType * I, const float *v, int *a, int *b, int *c)
{ /* special version for ray-tracing */
int atmp, btmp, ctmp;
float iDiv = I->recipDiv;
atmp = (int) ((v[0] - I->Min[0]) * iDiv) + MapBorder;
btmp = (int) ((v[1] - I->Min[1]) * iDiv) + MapBorder;
ctmp = (int) ((v[2] - I->Min[2]) * iDiv) + MapBorder;
if(atmp < I->iMin[0]) {
if((I->iMin[0] - atmp) > 3)
return (-1);
else
atmp = I->iMin[0];
} else if(atmp > I->iMax[0]) {
if((atmp - I->iMax[0]) > 3)
return (-1);
else
atmp = I->iMax[0];
}
if(btmp < I->iMin[1]) {
if((I->iMin[1] - btmp) > 3)
return (-1);
else
btmp = I->iMin[1];
} else if(btmp > I->iMax[1]) {
if((btmp - I->iMax[1]) > 3)
return (-1);
else
btmp = I->iMax[1];
}
/* printf("%d %d %d\n",ctmp,I->iMin[2],I->iMax[2]); */
if(ctmp < I->iMin[2]) {
if((I->iMin[2] - ctmp) > 3)
return (-1);
else
ctmp = I->iMin[2];
} else if(ctmp > I->iMax[2]) {
if((ctmp - I->iMax[2]) > 3)
return (0); /* just keep searching... */
else
ctmp = I->iMax[2];
}
/* printf("%d %d %d %d %d %d %d %d %d\n",
atmp,I->iMin[0],I->iMax[0],
btmp,I->iMin[1],I->iMax[1],
ctmp,I->iMin[2],I->iMax[2]);
*/
if(!*(MapEStart(I, atmp, btmp, ctmp)))
return (0);
*a = atmp;
*b = btmp;
*c = ctmp;
return (1);
}
int MapInsideXY(MapType * I, const float *v, int *a, int *b, int *c)
{ /* special version for ray-tracing */
int atmp, btmp, ctmp;
const float iDiv = I->recipDiv;
atmp = (int) ((v[0] - I->Min[0]) * iDiv) + MapBorder;
btmp = (int) ((v[1] - I->Min[1]) * iDiv) + MapBorder;
ctmp = (int) ((v[2] - I->Min[2]) * iDiv) + MapBorder + 1;
if(atmp < I->iMin[0]) {
if((I->iMin[0] - atmp) > 1)
return (false);
else
atmp = I->iMin[0];
} else if(atmp > I->iMax[0]) {
if((atmp - I->iMax[0]) > 1)
return (false);
else
atmp = I->iMax[0];
}
if(btmp < I->iMin[1]) {
if((I->iMin[1] - btmp) > 1)
return (false);
else
btmp = I->iMin[1];
} else if(btmp > I->iMax[1]) {
if((btmp - I->iMax[1]) > 1)
return (false);
else
btmp = I->iMax[1];
}
if(!*(I->EMask + I->Dim[1] * atmp + btmp))
return (false);
if(ctmp < I->iMin[2])
ctmp = I->iMin[2];
else if(ctmp > I->iMax[2])
ctmp = I->iMax[2];
*a = atmp;
*b = btmp;
*c = ctmp;
return (true);
}
#define ELIST_GROW_FACTOR 3
int MapSetupExpressXY(MapType * I, int n_vert, int negative_start)
{ /* setup a list of XY neighbors for each square */
PyMOLGlobals *G = I->G;
int n, a, b, c, flag;
int d, e, i;
unsigned int mapSize;
int st, dim2;
int n_alloc = n_vert * 15; /* emprical est. */
int ok = true;
PRINTFD(G, FB_Map)
" MapSetupExpressXY-Debug: entered.\n" ENDFD;
mapSize = I->Dim[0] * I->Dim[1] * I->Dim[2];
I->EHead =
CacheCalloc(G, int, mapSize, I->group_id, I->block_base + cCache_map_ehead_offset);
CHECKOK(ok, I->EHead);
if (ok)
I->EList = (int*) VLACacheMalloc(G, n_alloc, sizeof(int), ELIST_GROW_FACTOR, 0,
I->group_id, I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
if (ok)
I->EMask = CacheCalloc(G, int, I->Dim[0] * I->Dim[1],
I->group_id, I->block_base + cCache_map_emask_offset);
CHECKOK(ok, I->EMask);
n = 1;
dim2 = I->Dim[2];
for(a = I->iMin[0]; ok && a <= I->iMax[0]; a++) {
for(b = I->iMin[1]; ok && b <= I->iMax[1]; b++) {
for(c = I->iMin[2]; ok && c <= I->iMax[2]; c++) { /* a better alternative exists... */
int *iPtr1 = (I->Head + ((a - 1) * I->D1D2) + ((b - 1) * dim2) + c);
st = n;
flag = false;
for(d = a - 1; d <= a + 1; d++) {
/*int *iPtr2 = (I->Head + (d * I->D1D2) + ((b-1)*dim2) + c); */
int *iPtr2 = iPtr1;
for(e = b - 1; e <= b + 1; e++) {
/*i = *MapFirst(I,d,e,c); */
i = *iPtr2;
if(i >= 0) {
flag = true;
while(i >= 0) {
VLACacheCheck(G, I->EList, int, n, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
I->EList[n] = i;
n++;
i = MapNext(I, i);
}
}
iPtr2 += dim2;
}
iPtr1 += I->D1D2;
}
if(ok && flag) {
*(I->EMask + I->Dim[1] * a + b) = true;
*(MapEStart(I, a, b, c)) = negative_start ? -st : st;
VLACacheCheck(G, I->EList, int, n, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
I->EList[n] = -1;
n++;
}
}
}
}
PRINTFB(G, FB_Map, FB_Blather)
" MapSetupExpressXY: %d rows in express table\n", n ENDFB(G);
if (ok){
I->NEElem = n;
VLACacheSize(G, I->EList, int, I->NEElem, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
}
PRINTFD(G, FB_Map)
" MapSetupExpressXY-Debug: leaving...\n" ENDFD;
return ok;
}
int MapSetupExpressXYVert(MapType * I, float *vert, int n_vert, int negative_start)
{ /* setup a list of XY neighbors for each square */
PyMOLGlobals *G = I->G;
int h, n, a, b, c;
int j, k, dim2;
float *v;
int *eBase, *hBase;
int n_alloc = n_vert * 15; /* emprical est. */
int ok = true;
PRINTFD(G, FB_Map)
" MapSetupExpressXYVert-Debug: entered n_vert = %d negative_start = %d\n", n_vert,
negative_start ENDFD;
/*mapSize = I->Dim[0]*I->Dim[1]*I->Dim[2]; */
I->EHead = CacheCalloc(G, int, I->Dim[0] * I->Dim[1] * I->Dim[2],
I->group_id, I->block_base + cCache_map_ehead_offset);
CHECKOK(ok, I->EHead);
if (ok)
I->EMask = CacheCalloc(G, int, I->Dim[0] * I->Dim[1],
I->group_id, I->block_base + cCache_map_emask_offset);
CHECKOK(ok, I->EMask);
if (ok)
I->EList = (int*) VLACacheMalloc(G, n_alloc, sizeof(int), ELIST_GROW_FACTOR, 0, I->group_id, I->block_base + cCache_map_elist_offset); /* autozero */
CHECKOK(ok, I->EList);
n = 1;
v = vert;
dim2 = I->Dim[2];
for(h = 0; h < n_vert; h++) {
MapLocus(I, v, &j, &k, &c);
eBase = I->EHead + ((j - 1) * I->D1D2) + ((k - 1) * dim2) + c;
hBase = I->Head + (((j - 1) - 1) * I->D1D2);
for(a = j - 1; ok && a <= j + 1; a++) {
int *ePtr1 = eBase;
for(b = k - 1; ok && b <= k + 1; b++) {
if(*ePtr1 == 0) { /* if we haven't yet expanded this voxel... */
int st = n;
int flag = false;
int *hPtr1 = hBase + dim2 * (b - 1) + (c - 1);
int d, e, f;
for(d = a - 1; ok && d <= a + 1; d++) {
int *hPtr2 = hPtr1;
for(e = b - 1; ok && e <= b + 1; e++) {
int *hPtr3 = hPtr2;
for(f = c - 1; ok && f <= c + 1; f++) {
/* register int i = *MapFirst(I,d,e,f); */
int i = *hPtr3;
if(i > -1) {
flag = true;
while(ok && i > -1) {
VLACacheCheck(G, I->EList, int, n, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
I->EList[n] = i;
n++;
i = MapNext(I, i);
}
}
hPtr3++;
}
hPtr2 += dim2;
}
hPtr1 += I->D1D2;
}
if(flag) {
*(I->EMask + I->Dim[1] * a + b) = true;
*(MapEStart(I, a, b, c)) = negative_start ? -st : st;
VLACacheCheck(G, I->EList, int, n, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
I->EList[n] = -1;
n++;
}
}
ePtr1 += dim2;
}
eBase += I->D1D2;
hBase += I->D1D2;
}
v += 3;
}
PRINTFB(G, FB_Map, FB_Blather)
" MapSetupExpressXYVert: %d rows in express table\n", n ENDFB(G);
if (ok){
I->NEElem = n;
VLACacheSize(G, I->EList, int, I->NEElem, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
}
PRINTFD(G, FB_Map)
" MapSetupExpressXYVert-Debug: leaving...\n" ENDFD;
return ok;
}
int MapSetupExpressPerp(MapType * I, float *vert, float front, int nVertHint,
int negative_start, int *spanner)
{
PyMOLGlobals *G = I->G;
int n = 0;
int a, b, c, i;
unsigned int mapSize;
int st;
int n_alloc = nVertHint * 15; /* emprical est. */
int ok = true;
int iMin0 = I->iMin[0];
int iMin1 = I->iMin[1];
int iMax0 = I->iMax[0];
int iMax1 = I->iMax[1];
float iDiv = I->recipDiv;
float min0 = I->Min[0] * iDiv;
float min1 = I->Min[1] * iDiv;
float base0, base1;
float perp_factor, premult, *v0;
int *emask, dim1, *link, *ptr1, *ptr2;
PRINTFD(G, FB_Map)
" MapSetupExpress-Debug: entered.\n" ENDFD;
mapSize = I->Dim[0] * I->Dim[1] * I->Dim[2];
I->EHead = CacheCalloc(G, int, mapSize,
I->group_id, I->block_base + cCache_map_ehead_offset);
CHECKOK(ok, I->EHead);
if (ok)
I->EList = (int*) VLACacheMalloc(G, n_alloc, sizeof(int), ELIST_GROW_FACTOR, 0,
I->group_id, I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
if (ok)
I->EMask = CacheCalloc(G, int, I->Dim[0] * I->Dim[1],
I->group_id, I->block_base + cCache_map_emask_offset);
CHECKOK(ok, I->EMask);
emask = I->EMask;
dim1 = I->Dim[1];
link = I->Link;
premult = -front * iDiv;
n = 1;
for(a = (iMin0 - 1); ok && a <= (iMax0 + 1); a++)
for(b = (iMin1 - 1); ok && b <= (iMax1 + 1); b++)
for(c = (I->iMin[2] - 1); ok && c <= (I->iMax[2] + 1); c++) {
int d, e, f;
/* compute a "shadow" mask for all vertices */
i = *MapFirst(I, a, b, c);
while(i >= 0) {
v0 = vert + 3 * i;
perp_factor = premult / v0[2];
base0 = v0[0] * perp_factor;
base1 = v0[1] * perp_factor;
d = (int) (base0 - min0);
e = (int) (base1 - min1);
d += MapBorder;
e += MapBorder;
if(d < iMin0) {
d = iMin0;
} else if(d > iMax0) {
d = iMax0;
}
if(e < iMin1) {
e = iMin1;
} else if(e > iMax1) {
e = iMax1;
}
i = link[i];
ptr2 = (ptr1 = emask + dim1 * (d - 1) + (e - 1));
*(ptr2++) = true;
*(ptr2++) = true;
*(ptr2++) = true;
ptr2 = (ptr1 += dim1);
*(ptr2++) = true;
*(ptr2++) = true;
*(ptr2++) = true;
ptr2 = (ptr1 += dim1);
*(ptr2++) = true;
*(ptr2++) = true;
*(ptr2++) = true;
}
{
const int am1 = a - 1, ap1 = a + 1, bm1 = b - 1, bp1 = b + 1, cm1 = c - 1, cp1 =
c + 1;
const int dim2 = I->Dim[2];
int flag = false;
int *hPtr1 = I->Head + ((am1) * I->D1D2) + ((bm1) * dim2) + cm1;
st = n;
for(d = am1; ok && d <= ap1; d++) {
int *hPtr2 = hPtr1;
for(e = bm1; ok && e <= bp1; e++) {
int *hPtr3 = hPtr2;
for(f = cm1; ok && f <= cp1; f++) {
i = *(hPtr3++);
/* i=*MapFirst(I,d,e,f); */
if(i >= 0) {
flag = true;
while(ok && i >= 0) {
if((!spanner) || (f == c) || spanner[i]) {
/* for non-voxel-spanners, only spread in the XY plane (memory use ~ 9X instead of 27X -- a big difference!) */
VLACacheCheck(G, I->EList, int, n, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
I->EList[n] = i;
n++;
}
i = link[i];
}
}
}
hPtr2 += dim2;
}
hPtr1 += I->D1D2;
}
if(ok && flag) {
*(MapEStart(I, a, b, c)) = negative_start ? -st : st;
VLACacheCheck(G, I->EList, int, n, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
I->EList[n] = -1;
n++;
}
}
}
PRINTFB(G, FB_Map, FB_Blather)
" MapSetupExpressPerp: %d rows in express table \n", n ENDFB(G);
if (ok){
I->NEElem = n;
VLACacheSize(G, I->EList, int, I->NEElem, I->group_id,
I->block_base + cCache_map_elist_offset);
CHECKOK(ok, I->EList);
}
PRINTFD(G, FB_Map)
" MapSetupExpress-Debug: leaving...n=%d\n", n ENDFD;
return ok;
}
int MapSetupExpress(MapType * I)
{ /* setup a list of neighbors for each square */
PyMOLGlobals *G = I->G;
int n = 0;
int c, d, e, f, i, cm1, cp2, D1D2 = I->D1D2, D2 = I->Dim[2];
int mx2 = I->iMax[2];
int *link = I->Link;
int st, flag;
int *i_ptr3, *i_ptr4, *i_ptr5;
int *e_list = NULL;
int mx0 = I->iMax[0], mx1 = I->iMax[1], a, am1, ap2, *i_ptr1, b, bm1, bp2, *i_ptr2;
unsigned int mapSize;
int ok = true;
PRINTFD(G, FB_Map)
" MapSetupExpress-Debug: entered.\n" ENDFD;
mapSize = I->Dim[0] * I->Dim[1] * I->Dim[2];
I->EHead =
CacheCalloc(G, int, mapSize, group_id, I->block_base + cCache_map_ehead_offset);
CHECKOK(ok, I->EHead);
if (ok)
e_list = (int*) VLACacheMalloc(G, 1000, sizeof(int), 5, 0, group_id, block_offset);
CHECKOK(ok, e_list);
n = 1;
for(a = (I->iMin[0] - 1); ok && a <= mx0; a++) {
am1 = a - 1;
ap2 = a + 2;
i_ptr1 = I->Head + am1 * D1D2;
for(b = (I->iMin[1] - 1); ok && b <= mx1; b++) {
bm1 = b - 1;
bp2 = b + 2;
i_ptr2 = i_ptr1 + bm1 * D2;
for(c = (I->iMin[2] - 1); ok && c <= mx2; c++) {
st = n;
cm1 = c - 1;
cp2 = c + 2;
flag = false;
i_ptr5 = (i_ptr4 = (i_ptr3 = i_ptr2 + cm1));
for(d = am1; ok && d < ap2; d++) {
for(e = bm1; ok && e < bp2; e++) {
for(f = cm1; ok && f < cp2; f++) {
/*i=*MapFirst(I,d,e,f); */
if((i = *(i_ptr5++)) >= 0) {
flag = true;
do {
VLACacheCheck(G, e_list, int, n, group_id, block_offset);
CHECKOK(ok, e_list);
if (ok)
e_list[n++] = i;
/*i=MapNext(I,i); */
} while(ok && (i = link[i]) >= 0);
}
ok &= !G->Interrupt;
}
if (ok)
i_ptr5 = (i_ptr4 += D2);
}
if (ok)
i_ptr5 = (i_ptr4 = (i_ptr3 += D1D2));
}
if (ok){
if(flag) {
*(MapEStart(I, a, b, c)) = st;
VLACacheCheck(G, e_list, int, n, group_id, block_offset);
CHECKOK(ok, e_list);
e_list[n] = -1;
n++;
} else {
*(MapEStart(I, a, b, c)) = 0;
}
}
}
}
}
if (ok){
I->EList = e_list;
I->NEElem = n;
VLACacheSize(G, I->EList, int, I->NEElem, group_id, block_offset);
CHECKOK(ok, I->EList);
}
PRINTFD(G, FB_Map)
" MapSetupExpress-Debug: leaving...n=%d\n", n ENDFD;
return ok;
}
void MapLocus(MapType * I, const float *v, int *a, int *b, int *c)
{
int at, bt, ct;
float invDiv = I->recipDiv;
at = (int) ((v[0] - I->Min[0]) * invDiv) + MapBorder;
bt = (int) ((v[1] - I->Min[1]) * invDiv) + MapBorder;
ct = (int) ((v[2] - I->Min[2]) * invDiv) + MapBorder;
/* range checking... */
if(at < I->iMin[0])
at = I->iMin[0];
else if(at > I->iMax[0])
at = I->iMax[0];
if(bt < I->iMin[1])
bt = I->iMin[1];
else if(bt > I->iMax[1])
bt = I->iMax[1];
if(ct < I->iMin[2])
ct = I->iMin[2];
else if(ct > I->iMax[2])
ct = I->iMax[2];
*a = at;
*b = bt;
*c = ct;
}
int *MapLocusEStart(MapType * I, const float *v)
{
int a, b, c;
float invDiv = I->recipDiv;
a = (int) (((v[0] - I->Min[0]) * invDiv) + MapBorder);
b = (int) (((v[1] - I->Min[1]) * invDiv) + MapBorder);
c = (int) (((v[2] - I->Min[2]) * invDiv) + MapBorder);
if(a < I->iMin[0])
a = I->iMin[0];
else if(a > I->iMax[0])
a = I->iMax[0];
if(b < I->iMin[1])
b = I->iMin[1];
else if(b > I->iMax[1])
b = I->iMax[1];
if(c < I->iMin[2])
c = I->iMin[2];
else if(c > I->iMax[2])
c = I->iMax[2];
return (I->EHead + ((a) * I->D1D2) + ((b) * I->Dim[2]) + (c));
}
int MapExclLocus(MapType * I, const float *v, int *a, int *b, int *c)
{
float invDiv = I->recipDiv;
*a = (int) (((v[0] - I->Min[0]) * invDiv) + MapBorder);
if(*a < I->iMin[0])
return (0);
else if(*a > I->iMax[0])
return (0);
*b = (int) (((v[1] - I->Min[1]) * invDiv) + MapBorder);
if(*b < I->iMin[1])
return (0);
else if(*b > I->iMax[1])
return (0);
*c = (int) (((v[2] - I->Min[2]) * invDiv) + MapBorder);
if(*c < I->iMin[2])
return (0);
else if(*c > I->iMax[2])
return (0);
return (1);
}
float MapGetSeparation(PyMOLGlobals * G, float range, const float *mx, const float *mn,
float *diagonal)
{
float maxSize;
float size, maxSubDiv, divSize, subDiv[3];
float maxCubed, subDivCubed;
int a;
maxSize = SettingGetGlobal_i(G, cSetting_hash_max);
maxCubed = maxSize * maxSize * maxSize;
/* find longest axis: diagonal = max-min, for
* each axis and find the largest */
subtract3f(mx, mn, diagonal);
diagonal[0] = (float) fabs(diagonal[0]);
diagonal[1] = (float) fabs(diagonal[1]);
diagonal[2] = (float) fabs(diagonal[2]);
/* find largest */
size = diagonal[0];
if(diagonal[1] > size)
size = diagonal[1];
if(diagonal[2] > size)
size = diagonal[2];
/* err check size and diagonal */
if(size == 0.0) {
diagonal[0] = 1.0;
diagonal[1] = 1.0;
diagonal[2] = 1.0;
size = 1.0;
}
/* compute maximum number of subdivisions */
maxSubDiv = (float) (size / (range + MapSafety));
if(maxSubDiv < 1.0F)
maxSubDiv = 1.0F;
/* find resulting divSize */
divSize = size / maxSubDiv;
if(divSize < MapSafety)
divSize = MapSafety;
for(a = 0; a < 3; a++) {
subDiv[a] = (float) ((int) ((diagonal[a] / divSize) + 0.5F));
subDiv[a] = (subDiv[a] < 1.0F) ? 1.0F : subDiv[a];
}
subDivCubed = subDiv[0] * subDiv[1] * subDiv[2];
if(subDivCubed > maxCubed) {
divSize = (float) (divSize / pow(maxCubed / subDivCubed, 0.33333F));
} else if(subDivCubed < maxCubed) {
divSize = (float) (divSize * pow(subDivCubed / maxCubed, 0.33333F));
}
if(divSize < (range + MapSafety))
divSize = range + MapSafety;
if(Feedback(G, FB_Map, FB_Debugging)) {
PRINTF
" MapGetSeparation: range %8.3f divSize %8.3f size %8.3f\n", range, divSize, size
ENDF(G);
/* dump3f(mx,"mx");
dump3f(mn,"mn");
dump3f(diagonal,"diagonal");
printf("%8.3f\n",divSize);
printf("divSize %8.3f\n",divSize);
*/
}
return (divSize);
}
MapType *MapNew(PyMOLGlobals * G, float range, float *vert, int nVert, float *extent)
{
return (_MapNew(G, range, vert, nVert, extent, NULL, -1, 0));
}
MapType *MapNewCached(PyMOLGlobals * G, float range, float *vert, int nVert,
float *extent, int group_id, int block_id)
{
return (_MapNew(G, range, vert, nVert, extent, NULL, group_id, block_id));
}
MapType *MapNewFlagged(PyMOLGlobals * G, float range, float *vert, int nVert,
float *extent, int *flag)
{
return (_MapNew(G, range, vert, nVert, extent, flag, -1, 0));
}
static MapType *_MapNew(PyMOLGlobals * G, float range, float *vert, int nVert,
float *extent, int *flag, int group_id, int block_base)
{
int a, c;
int mapSize;
int h, k, l;
int *list;
float *v, tmp_f;
int firstFlag;
Vector3f diagonal;
int ok = true;
/* allocate space for a MapType
* "I" is now defined */
OOAlloc(G, MapType);
PRINTFD(G, FB_Map)
" MapNew-Debug: entered.\n" ENDFD;
CHECKOK(ok, I);
if (!ok){
return NULL;
}
/* Initialize */
I->G = G;
I->group_id = group_id;
I->block_base = block_base;
I->Head = NULL;
I->Link = NULL;
I->EHead = NULL;
I->EList = NULL;
I->EMask = NULL;
I->NEElem = 0;
/* initialize an empty cache for the map */
I->Link = CacheAlloc(G, int, nVert, group_id, block_base + cCache_map_link_offset);
CHECKOK(ok, I->Link);
if (!ok){
MapFree(I);
return NULL;
}
for(a = 0; a < nVert; a++)
I->Link[a] = -1;
/* map extents; set if valid, otherwise determine based on the flagged vertices */
if(extent) {
/* valid, so copy */
I->Min[0] = extent[0];
I->Max[0] = extent[1];
I->Min[1] = extent[2];
I->Max[1] = extent[3];
I->Min[2] = extent[4];
I->Max[2] = extent[5];
} else {
/* blank, so determine */
I->Min[0] = 0.0F;
I->Max[0] = 0.0F;
I->Min[1] = 0.0F;
I->Max[1] = 0.0F;
I->Min[2] = 0.0F;
I->Max[2] = 0.0F;
/* flag is an array of ints, one per vertex to signify inclusion for consideration in this map */
if(flag) {
firstFlag = true;
v = vert;
for(a = 0; a < nVert; a++) {
/* if we consider this vertex */
if(flag[a]) {
/* first-time setup*/
if(firstFlag) {
for(c = 0; c < 3; c++) {
I->Min[c] = v[c];
I->Max[c] = v[c];
}
firstFlag = false;
} else {
/* min/max extents, over all vertices */
for(c = 0; c < 3; c++) {
if(I->Min[c] > v[c])
I->Min[c] = v[c];
if(I->Max[c] < v[c])
I->Max[c] = v[c];
}
}
}
v += 3;
}
} else {
/* no flag: do all vertices in the list */
if(nVert) {
v = vert;
for(c = 0; c < 3; c++) {
I->Min[c] = v[c];
I->Max[c] = v[c];
}
v += 3;
for(a = 1; a < nVert; a++) {
for(c = 0; c < 3; c++) {
if(I->Min[c] > v[c])
I->Min[c] = v[c];
if(I->Max[c] < v[c])
I->Max[c] = v[c];
}
v += 3;
}
}
}
}
/* sanity check */
for(a = 0; a < 3; a++) {
if(I->Min[a] > I->Max[a]) {
tmp_f = I->Min[a];
I->Max[a] = I->Min[a];
I->Min[a] = tmp_f;
}
// empirical limit to avoid crash in PYMOL-3002
const float SANITY_LIMIT = 1e10;
if(I->Min[a] < -SANITY_LIMIT) {
PRINTFB(G, FB_Map, FB_Warnings)
" %s-Warning: clamping Min %e -> %e\n", __FUNCTION__,
I->Min[a], -SANITY_LIMIT ENDFB(G);
I->Min[a] = -SANITY_LIMIT;
}
if(I->Max[a] > SANITY_LIMIT) {
PRINTFB(G, FB_Map, FB_Warnings)
" %s-Warning: clamping Max %e -> %e\n", __FUNCTION__,
I->Max[a], SANITY_LIMIT ENDFB(G);
I->Max[a] = SANITY_LIMIT;
}
}
if(Feedback(G, FB_Map, FB_Debugging)) {
printf(" MapSetup: %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
I->Min[0], I->Min[1], I->Min[2], I->Max[0], I->Max[1], I->Max[2]);
}
/* interesting */
for(c = 0; c < 3; c++) {
I->Min[c] -= MapSafety;
I->Max[c] += MapSafety;
}
/* pad the boundaries by "range" */
if(range < 0.0) { /* negative range is a flag to expand edges using "range". */
range = -range;
for(c = 0; c < 3; c++) {
I->Min[c] -= range;
I->Max[c] += range;
}
}
/* compute final box size ..................... */
I->Div = MapGetSeparation(G, range, I->Max, I->Min, diagonal);
I->recipDiv = 1.0F / (I->Div); /* cache this */
/* add borders to avoid special edge cases */
I->Dim[0] = (int) ((diagonal[0] / I->Div) + 1 + (2 * MapBorder));
I->Dim[1] = (int) ((diagonal[1] / I->Div) + 1 + (2 * MapBorder));
I->Dim[2] = (int) ((diagonal[2] / I->Div) + 1 + (2 * MapBorder));
if(Feedback(G, FB_Map, FB_Debugging)) {
printf(" MapSetup: nVert: %d\n", nVert);
printf(" MapSetup: I->Div: %8.3f\n", I->Div);
printf(" MapSetup: %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f\n",
I->Min[0], I->Min[1], I->Min[2], I->Max[0], I->Max[1], I->Max[2]);
printf(" MapSetup: %8d %8d %8d\n", I->Dim[0], I->Dim[1], I->Dim[2]);
}
I->D1D2 = I->Dim[1] * I->Dim[2];
I->iMin[0] = MapBorder;
I->iMin[1] = MapBorder;
I->iMin[2] = MapBorder;
I->iMax[0] = I->Dim[0] - (1 + MapBorder);
I->iMax[1] = I->Dim[1] - (1 + MapBorder);
I->iMax[2] = I->Dim[2] - (1 + MapBorder);
/* compute size and allocate */
mapSize = I->Dim[0] * I->Dim[1] * I->Dim[2];
I->Head = CacheAlloc(G, int, mapSize, group_id, block_base + cCache_map_head_offset);
CHECKOK(ok, I->Head);
if (!ok){
MapFree(I);
return NULL;
}
/* initialize */
/* for(a=0;a<I->Dim[0];a++)
for(b=0;b<I->Dim[1];b++)
for(c=0;c<I->Dim[2];c++)
*(MapFirst(I,a,b,c))=-1; */
/* Trick for fast clearing to -1! */
memset(I->Head, 0xFF, mapSize * sizeof(int));
I->NVert = nVert;
PRINTFD(G, FB_Map)
" MapNew-Debug: creating 3D hash...\n" ENDFD;
/* create 3-D hash of the vertices */
if(flag) {
v = vert;
for(a = 0; a < nVert; a++) {
if(flag[a])
if(MapExclLocus(I, v, &h, &k, &l)) {
list = MapFirst(I, h, k, l);
I->Link[a] = *list;
*list = a; /*add to top of list */
}
v += 3;
}
} else {
v = vert;
for(a = 0; a < nVert; a++) {
if(MapExclLocus(I, v, &h, &k, &l)) {
list = MapFirst(I, h, k, l);
/* printf("LINK %d %d %d %d %5.2f %5.2f %5.2f\n",a,h,k,l,v[0],v[1],v[2]); */
I->Link[a] = *list;
*list = a; /*add to top of list */
}
v += 3;
}
}
PRINTFD(G, FB_Map)
" MapNew-Debug: leaving...\n" ENDFD;
return (I);
}