layer1/Basis.cpp (2,828 lines of code) (raw):
/*
A* -------------------------------------------------------------------
B* This file contains source code for the PyMOL computer program
C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
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* -------------------------------------------------------------------
*/
#ifndef _PYMOL_INLINE
#include"os_predef.h"
#include"os_std.h"
#include"MemoryDebug.h"
#include"Base.h"
#include"Basis.h"
#include"Err.h"
#include"Feedback.h"
#include"Util.h"
#include"MemoryCache.h"
#include"Character.h"
static const float kR_SMALL4 = 0.0001F;
static const float kR_SMALL5 = 0.0001F;
#define EPSILON 0.000001F
/*========================================================================*/
#ifdef _PYMOL_INLINE
__inline__
#endif
static int ZLineToSphere(float *base, float *point, float *dir, float radius,
float maxial, float *sphere, float *asum, float *pre)
{
/* Strategy - find an imaginary sphere that lies at the correct point on
the line segment, then treat as a sphere reflection */
float intra_p0, intra_p1, intra_p2;
float radial, axial, axial_sum, dangle, ab_dangle, axial_perp;
float radialsq, tan_acos_dangle;
float vradial0, vradial1, vradial2;
const float _0 = 0.0f;
float point0 = point[0];
float point1 = point[1];
float point2 = point[2];
float perpAxis0 = pre[0]; /* was cross_product(MinusZ,dir,perpAxis),normalize */
float perpAxis1 = pre[1];
float intra0 = point0 - base[0];
float intra1 = point1 - base[1];
const float dir0 = dir[0];
const float dir1 = dir[1];
const float dir2 = dir[2];
float dot, perpDist;
/* the perpAxis defines a perp-plane which includes the cyl-axis */
/* get minimum distance between the lines */
perpDist = intra0 * perpAxis0 + intra1 * perpAxis1;
/* was dot_product3f(intra,perpAxis); */
if((perpDist < _0 ? -perpDist : perpDist) > radius)
return 0;
/*if(fabs(perpDist) > radius) return 0; */
dangle = -dir2; /* was dot(MinusZ,dir) */
ab_dangle = (float) fabs(dangle);
if(ab_dangle > (1.0f - kR_SMALL4)) {
if(dangle > _0) {
sphere[0] = point0;
sphere[1] = point1;
sphere[2] = point2;
} else {
sphere[0] = dir0 * maxial + point0;
sphere[1] = dir1 * maxial + point1;
sphere[2] = dir2 * maxial + point2;
}
return (1);
}
if(ab_dangle > kR_SMALL4)
tan_acos_dangle = (float) (sqrt1d(1.0 - dangle * dangle) / dangle);
else
tan_acos_dangle = MAXFLOAT;
/* now we need to define the triangle in the perp-plane
to figure out where the projected line intersection point is */
intra_p2 = point2 - base[2];
/* first, compute radial distance in the perp-plane between the two starting points */
dot = intra0 * perpAxis0 + intra1 * perpAxis1;
intra_p0 = intra0 - perpAxis0 * dot;
intra_p1 = intra1 - perpAxis1 * dot;
dot = intra_p0 * dir0 + intra_p1 * dir1 + intra_p2 * dir2;
vradial0 = intra_p0 - dir0 * dot;
vradial1 = intra_p1 - dir1 * dot;
vradial2 = intra_p2 - dir2 * dot;
radialsq = ((vradial0 * vradial0) + (vradial1 * vradial1) + (vradial2 * vradial2));
/* now figure out the axial distance along the cyl-line that will give us
the point of closest approach */
if(ab_dangle < kR_SMALL4)
axial_perp = _0;
else
axial_perp = (float) (sqrt1f(radialsq) / tan_acos_dangle);
axial =
(float) sqrt1f(((intra_p0 * intra_p0) + (intra_p1 * intra_p1) + (intra_p2 * intra_p2))
- radialsq);
if((intra_p0 * dir0 + intra_p1 * dir1 + intra_p2 * dir2) >= _0)
axial = axial_perp - axial;
else
axial = axial_perp + axial;
/* now we have to think about where the vector will actually strike the cylinder */
/* by definition, it must be perpdist away from the perp-plane becuase the perp-plane
is parallel to the line, so we can compute the radial component to this point */
radial = radius * radius - perpDist * perpDist;
radial = (float) sqrt1f(radial);
/* now the trick is figuring out how to adjust the axial distance to get the actual
position along the cyl line which will give us a representative sphere */
if(ab_dangle > kR_SMALL4)
axial_sum = axial - radial / tan_acos_dangle;
else
axial_sum = axial;
/*
printf("radial2 %8.3f \n",radial); */
if(axial_sum < _0)
axial_sum = _0;
else if(axial_sum > maxial)
axial_sum = maxial;
sphere[0] = dir0 * axial_sum + point0;
sphere[1] = dir1 * axial_sum + point1;
sphere[2] = dir2 * axial_sum + point2;
*asum = axial_sum;
/* printf("==>%8.3f sphere %8.3f %8.3f %8.3f\n",base[1],sphere[1],axial_perp,axial); */
return (1);
}
#ifdef _PYMOL_INLINE
__inline__
#endif
static int LineToSphere(float *base, float *ray, float *point, float *dir, float radius,
float maxial, float *sphere, float *asum)
{
/* Strategy - find an imaginary sphere that lies at the correct point on
the line segment, then treat as a sphere reflection */
float perpDist, radial, axial, axial_sum, dangle, ab_dangle, axial_perp;
float radialsq, tan_acos_dangle;
float perpAxis0, perpAxis1, perpAxis2;
float intra0, intra1, intra2;
float intra_p0, intra_p1, intra_p2;
float vradial0, vradial1, vradial2;
float dir0 = dir[0], dir1 = dir[1], dir2 = dir[2];
float ray0 = ray[0], ray1 = ray[1], ray2 = ray[2];
float point0 = point[0], point1 = point[1], point2 = point[2];
float dot;
const float _0 = 0.0F;
const float _1 = 1.0F;
/* cross_product3f(ray,dir,perpAxis); */
perpAxis0 = ray1 * dir2 - ray2 * dir1;
perpAxis1 = ray2 * dir0 - ray0 * dir2;
perpAxis2 = ray0 * dir1 - ray1 * dir0;
/* subtract3f(point,base,intra); */
intra0 = point0 - base[0];
/* normalize3f(perpAxis) */
{
float len =
(float) sqrt1d((perpAxis0 * perpAxis0) + (perpAxis1 * perpAxis1) +
(perpAxis2 * perpAxis2));
intra1 = point1 - base[1];
/* subtract3f(point,base,intra); */
if(len > R_SMALL8) {
len = _1 / len;
intra2 = point2 - base[2];
perpAxis0 *= len;
perpAxis1 *= len;
perpAxis2 *= len;
} else {
intra2 = point2 - base[2];
}
}
/* the perpAxis defines a perp-plane which includes the cyl-axis */
/* get minimum distance between the lines */
/* dot_product3f(intra, perpAxis); */
perpDist = intra0 * perpAxis0;
perpDist += intra1 * perpAxis1 + intra2 * perpAxis2;
/*if(fabs(perpDist) > radius) return 0; */
dangle = ray0 * dir0;
if((perpDist < _0 ? -perpDist : perpDist) > radius)
return 0;
/* dangle = dot_product3f(ray, dir); */
dangle += ray1 * dir1 + ray2 * dir2;
ab_dangle = (float) fabs(dangle);
if(ab_dangle > (1.0f - kR_SMALL4)) {
if(dangle > _0) {
sphere[0] = point0;
sphere[1] = point1;
sphere[2] = point2;
} else {
sphere[0] = dir0 * maxial + point0;
sphere[1] = dir1 * maxial + point1;
sphere[2] = dir2 * maxial + point2;
}
return (1);
}
if(ab_dangle > kR_SMALL4)
tan_acos_dangle = (float) (sqrt1d(1.0 - dangle * dangle) / dangle);
else
tan_acos_dangle = MAXFLOAT;
/* now we need to define the triangle in the perp-plane
to figure out where the projected line intersection point is */
/* first, compute radial distance in the perp-plane between the two starting points */
/* dot = dot_product3f(intra,perpAxis); */
dot = intra0 * perpAxis0 + intra1 * perpAxis1 + intra2 * perpAxis2;
intra_p0 = intra0 - perpAxis0 * dot;
intra_p1 = intra1 - perpAxis1 * dot;
intra_p2 = intra2 - perpAxis2 * dot;
/* dot = dot_product3f(intra_p, dir); */
dot = intra_p0 * dir0 + intra_p1 * dir1 + intra_p2 * dir2;
vradial0 = intra_p0 - dir0 * dot;
vradial1 = intra_p1 - dir1 * dot;
vradial2 = intra_p2 - dir2 * dot;
radialsq = ((vradial0 * vradial0) + (vradial1 * vradial1) + (vradial2 * vradial2));
/* now figure out the axial distance along the cyl-line that will give us
the point of closest approach */
if(ab_dangle < kR_SMALL4)
axial_perp = _0;
else
axial_perp = (float) (sqrt1f(radialsq) / tan_acos_dangle);
axial = (float) sqrt1f(((intra_p0 * intra_p0) +
(intra_p1 * intra_p1) + (intra_p2 * intra_p2)) - radialsq);
if((intra_p0 * dir0 + intra_p1 * dir1 + intra_p2 * dir2) >= _0)
axial = axial_perp - axial;
else
axial = axial_perp + axial;
/* now we have to think about where the vector will actually strike the cylinder */
/* by definition, it must be perpdist away from the perp-plane becuase the perp-plane
is parallel to the line, so we can compute the radial component to this point */
radial = radius * radius - perpDist * perpDist;
radial = (float) sqrt1f(radial);
/* now the trick is figuring out how to adjust the axial distance to get the actual
position along the cyl line which will give us a representative sphere */
if(ab_dangle > kR_SMALL4)
axial_sum = axial - radial / tan_acos_dangle;
else
axial_sum = axial;
/*
printf("radial2 %8.3f \n",radial); */
if(axial_sum < _0)
axial_sum = _0;
else if(axial_sum > maxial)
axial_sum = maxial;
sphere[0] = dir0 * axial_sum + point0;
sphere[1] = dir1 * axial_sum + point1;
sphere[2] = dir2 * axial_sum + point2;
*asum = axial_sum;
/* printf("==>%8.3f sphere %8.3f %8.3f %8.3f\n",base[1],sphere[1],axial_perp,axial); */
return (1);
}
#ifdef _PYMOL_INLINE
__inline__
#endif
static int FrontToInteriorSphere(float *front,
float *point,
float *dir, float radius, float radius2, float maxial)
{
float intra_p[3];
float axial;
float intra[3], axis[3];
float sphere[3];
subtract3f(point, front, intra);
remove_component3f(intra, dir, intra_p);
add3f(front, intra_p, intra_p);
subtract3f(point, intra_p, axis);
axial = -dot_product3f(axis, dir);
if(axial < 0.0F)
axial = 0.0F;
else if(axial > maxial)
axial = maxial;
sphere[0] = axial * dir[0] + point[0];
sphere[1] = axial * dir[1] + point[1];
sphere[2] = axial * dir[2] + point[2];
return (diffsq3f(sphere, front) <= radius2);
}
/*========================================================================*/
#ifdef _PYMOL_INLINE
__inline__
#endif
static int ZLineToSphereCapped(float *base, float *point,
float *dir, float radius, float maxial,
float *sphere, float *asum, int cap1, int cap2, float *pre)
{
/* Strategy - find an imaginary sphere that lies at the correct point on
the line segment, then treat as a sphere reflection */
float perpAxis[3], intra_p[3];
float perpDist, radial, axial, axial_sum, dangle, ab_dangle, axial_perp;
float radialsq, tan_acos_dangle;
float len_proj;
float intra[3], vradial[3];
float diff[3], fpoint[3];
float proj[3];
perpAxis[0] = pre[0]; /* was cross_product(MinusZ,dir,perpAxis),normalize */
perpAxis[1] = pre[1];
/* the perpAxis defines a perp-plane which includes the cyl-axis */
intra[0] = point[0] - base[0];
intra[1] = point[1] - base[1];
/* get minimum distance between the lines */
perpDist = intra[0] * perpAxis[0] + intra[1] * perpAxis[1];
/* was dot_product3f(intra,perpAxis); */
if(fabs(perpDist) > radius) {
return (0);
}
perpAxis[2] = 0.0;
intra[2] = point[2] - base[2];
dangle = -dir[2]; /* was dot(MinusZ,dir) */
ab_dangle = (float) fabs(dangle);
if(ab_dangle > (1 - kR_SMALL4)) { /* vector inline with light ray... */
vradial[0] = point[0] - base[0];
vradial[1] = point[1] - base[1];
vradial[2] = 0.0F;
radial = (float) length3f(vradial);
if(radial > radius)
return 0;
if(dangle > 0.0) {
switch (cap1) {
case cCylCapFlat:
sphere[0] = base[0];
sphere[1] = base[1];
sphere[2] = point[2] - radius;
break;
case cCylCapRound:
sphere[0] = point[0];
sphere[1] = point[1];
sphere[2] = point[2];
}
return (1);
} else {
switch (cap1) {
case cCylCapFlat:
sphere[0] = base[0];
sphere[1] = base[1];
sphere[2] = dir[2] * maxial + point[2] - radius;
break;
case cCylCapRound:
sphere[0] = dir[0] * maxial + point[0];
sphere[1] = dir[1] * maxial + point[1];
sphere[2] = dir[2] * maxial + point[2];
}
return (1);
}
}
/*tan_acos_dangle = tan(acos(dangle)); */
tan_acos_dangle = (float) sqrt1f(1 - dangle * dangle) / dangle;
/*
printf("perpDist %8.3f\n",perpDist);
printf("dir %8.3f %8.3f %8.3f\n",dir[0],dir[1],dir[2]);
printf("base %8.3f %8.3f %8.3f\n",base[0],base[1],base[2]);
printf("point %8.3f %8.3f %8.3f\n",point[0],point[1],point[2]);
printf("intra %8.3f %8.3f %8.3f\n",intra[0],intra[1],intra[2]);
printf("perpAxis %8.3f %8.3f %8.3f\n",perpAxis[0],perpAxis[1],perpAxis[2]);
*/
/* now we need to define the triangle in the perp-plane
to figure out where the projected line intersection point is */
/* first, compute radial distance in the perp-plane between the two starting points */
remove_component3f(intra, perpAxis, intra_p);
remove_component3f(intra_p, dir, vradial);
radialsq = lengthsq3f(vradial);
/* now figure out the axial distance along the cyl-line that will give us
the point of closest approach */
if(ab_dangle < kR_SMALL4)
axial_perp = 0;
else
axial_perp = (float) sqrt1f(radialsq) / tan_acos_dangle;
axial = (float) lengthsq3f(intra_p) - radialsq;
axial = (float) sqrt1f(axial);
/*
printf("radial %8.3f\n",radial);
printf("vradial %8.3f %8.3f %8.3f\n",vradial[0],vradial[1],vradial[2]);
printf("radial %8.3f\n",radial);
printf("dangle %8.3f \n",dangle);
printf("axial_perp %8.3f \n",axial_perp);
printf("axial1 %8.3f \n",axial);
printf("%8.3f\n",dot_product3f(intra_p,dir));
*/
if(dot_product3f(intra_p, dir) >= 0.0)
axial = axial_perp - axial;
else
axial = axial_perp + axial;
/*
printf("axial2 %8.3f\n",axial);
*/
/* now we have to think about where the vector will actually strike the cylinder */
/* by definition, it must be perpdist away from the perp-plane becuase the perp-plane
is parallel to the line, so we can compute the radial component to this point */
radial = radius * radius - perpDist * perpDist;
radial = (float) sqrt1f(radial);
/* now the trick is figuring out how to adjust the axial distance to get the actual
position along the cyl line which will give us a representative sphere */
if(ab_dangle > kR_SMALL4)
axial_sum = axial - radial / tan_acos_dangle;
else
axial_sum = axial;
/* printf("ab_dangle %8.3f \n",ab_dangle);
printf("axial_sum %8.3f \n",axial_sum);
*/
if(axial_sum < 0) {
switch (cap1) {
case cCylCapFlat:
subtract3f(point, base, diff);
project3f(diff, dir, proj);
len_proj = (float) length3f(proj);
dangle = -proj[2] / len_proj;
if(fabs(dangle) < kR_SMALL4)
return 0;
sphere[0] = base[0];
sphere[1] = base[1];
sphere[2] = base[2] - len_proj / dangle;
if(diff3f(sphere, point) > radius)
return 0;
sphere[0] += dir[0] * radius;
sphere[1] += dir[1] * radius;
sphere[2] += dir[2] * radius;
*asum = 0;
break;
case cCylCapRound:
axial_sum = 0;
sphere[0] = point[0];
sphere[1] = point[1];
sphere[2] = point[2];
*asum = axial_sum;
break;
case cCylCapNone:
default:
return 0;
break;
}
} else if(axial_sum > maxial) {
switch (cap2) {
case cCylCapFlat:
scale3f(dir, maxial, fpoint);
add3f(fpoint, point, fpoint);
subtract3f(fpoint, base, diff);
project3f(diff, dir, proj);
len_proj = (float) length3f(proj);
dangle = -proj[2] / len_proj;
if(fabs(dangle) < kR_SMALL4)
return 0;
sphere[0] = base[0];
sphere[1] = base[1];
sphere[2] = base[2] - len_proj / dangle;
if(diff3f(sphere, fpoint) > radius)
return 0;
sphere[0] -= dir[0] * radius;
sphere[1] -= dir[1] * radius;
sphere[2] -= dir[2] * radius;
*asum = maxial;
break;
case cCylCapRound:
axial_sum = maxial;
sphere[0] = dir[0] * axial_sum + point[0];
sphere[1] = dir[1] * axial_sum + point[1];
sphere[2] = dir[2] * axial_sum + point[2];
*asum = axial_sum;
break;
case cCylCapNone:
default:
return 0;
break;
}
} else {
sphere[0] = dir[0] * axial_sum + point[0];
sphere[1] = dir[1] * axial_sum + point[1];
sphere[2] = dir[2] * axial_sum + point[2];
*asum = axial_sum;
/* printf("==>%8.3f sphere %8.3f %8.3f %8.3f\n",base[1],sphere[1],axial_perp,axial); */
}
return (1);
}
#ifdef _PYMOL_INLINE
__inline__
#endif
static int LineToSphereCapped(float *base, float *ray,
float *point, float *dir, float radius, float maxial,
float *sphere, float *asum, int cap1, int cap2)
{
/* Strategy - find an imaginary sphere that lies at the correct point on
the line segment, then treat as a sphere reflection */
float perpAxis[3], intra_p[3];
float perpDist, radial, axial, axial_sum, dangle, ab_dangle, axial_perp;
float radialsq, tan_acos_dangle;
float len_proj;
float intra[3], vradial[3];
float diff[3], fpoint[3];
float proj[3];
subtract3f(point, base, intra);
cross_product3f(ray, dir, perpAxis);
normalize3f(perpAxis);
/* the perpAxis defines a perp-plane which includes the cyl-axis */
/* get minimum distance between the lines */
perpDist = dot_product3f(intra, perpAxis);
/* was dot_product3f(intra,perpAxis); */
if(fabs(perpDist) > radius) {
return (0);
}
dangle = dot_product3f(ray, dir);
ab_dangle = (float) fabs(dangle);
if(ab_dangle > (1 - kR_SMALL4)) { /* vector inline with light ray... */
vradial[0] = point[0] - base[0];
vradial[1] = point[1] - base[1];
vradial[2] = point[2] - base[2];
radial = (float) length3f(vradial);
if(radial > radius)
return 0;
if(dangle > 0.0) {
switch (cap1) {
case cCylCapFlat:
sphere[0] = dir[0] * radius + point[0];
sphere[1] = dir[1] * radius + point[1];
sphere[2] = dir[2] * radius + point[2];
break;
case cCylCapRound:
sphere[0] = point[0];
sphere[1] = point[1];
sphere[2] = point[2];
}
return (1);
} else {
switch (cap1) {
case cCylCapFlat:
maxial -= radius;
break;
}
sphere[0] = dir[0] * maxial + point[0];
sphere[1] = dir[1] * maxial + point[1];
sphere[2] = dir[2] * maxial + point[2];
return (1);
}
}
/*tan_acos_dangle = tan(acos(dangle)); */
tan_acos_dangle = (float) sqrt1f(1 - dangle * dangle) / dangle;
/*
printf("perpDist %8.3f\n",perpDist);
printf("dir %8.3f %8.3f %8.3f\n",dir[0],dir[1],dir[2]);
printf("base %8.3f %8.3f %8.3f\n",base[0],base[1],base[2]);
printf("point %8.3f %8.3f %8.3f\n",point[0],point[1],point[2]);
printf("intra %8.3f %8.3f %8.3f\n",intra[0],intra[1],intra[2]);
printf("perpAxis %8.3f %8.3f %8.3f\n",perpAxis[0],perpAxis[1],perpAxis[2]);
*/
/* now we need to define the triangle in the perp-plane
to figure out where the projected line intersection point is */
/* first, compute radial distance in the perp-plane between the two starting points */
remove_component3f(intra, perpAxis, intra_p);
remove_component3f(intra_p, dir, vradial);
radialsq = lengthsq3f(vradial);
/* now figure out the axial distance along the cyl-line that will give us
the point of closest approach */
if(ab_dangle < kR_SMALL4)
axial_perp = 0;
else
axial_perp = (float) sqrt1f(radialsq) / tan_acos_dangle;
axial = (float) lengthsq3f(intra_p) - radialsq;
axial = (float) sqrt1f(axial);
/*
printf("radial %8.3f\n",radial);
printf("vradial %8.3f %8.3f %8.3f\n",vradial[0],vradial[1],vradial[2]);
printf("radial %8.3f\n",radial);
printf("dangle %8.3f \n",dangle);
printf("axial_perp %8.3f \n",axial_perp);
printf("axial1 %8.3f \n",axial);
printf("%8.3f\n",dot_product3f(intra_p,dir));
*/
if(dot_product3f(intra_p, dir) >= 0.0)
axial = axial_perp - axial;
else
axial = axial_perp + axial;
/*
printf("axial2 %8.3f\n",axial);
*/
/* now we have to think about where the vector will actually strike the cylinder */
/* by definition, it must be perpdist away from the perp-plane becuase the perp-plane
is parallel to the line, so we can compute the radial component to this point */
radial = radius * radius - perpDist * perpDist;
radial = (float) sqrt1f(radial);
/* now the trick is figuring out how to adjust the axial distance to get the actual
position along the cyl line which will give us a representative sphere */
if(ab_dangle > kR_SMALL4)
axial_sum = axial - radial / tan_acos_dangle;
else
axial_sum = axial;
/* printf("ab_dangle %8.3f \n",ab_dangle);
printf("axial_sum %8.3f \n",axial_sum);
*/
if(axial_sum < 0) {
switch (cap1) {
case cCylCapFlat:
subtract3f(point, base, diff);
project3f(diff, dir, proj);
len_proj = (float) length3f(proj);
dangle = dot_product3f(proj, ray) / len_proj;
if(fabs(dangle) < kR_SMALL4)
return 0;
len_proj /= dangle;
sphere[0] = base[0] + ray[0] * len_proj;
sphere[1] = base[1] + ray[1] * len_proj;
sphere[2] = base[2] + ray[2] * len_proj;
if(diff3f(sphere, point) > radius)
return 0;
sphere[0] += dir[0] * radius;
sphere[1] += dir[1] * radius;
sphere[2] += dir[2] * radius;
*asum = 0;
break;
case cCylCapRound:
axial_sum = 0;
sphere[0] = point[0];
sphere[1] = point[1];
sphere[2] = point[2];
*asum = axial_sum;
break;
case cCylCapNone:
default:
return 0;
break;
}
} else if(axial_sum > maxial) {
switch (cap2) {
case cCylCapFlat:
scale3f(dir, maxial, fpoint);
add3f(fpoint, point, fpoint);
subtract3f(fpoint, base, diff);
project3f(diff, dir, proj);
len_proj = (float) length3f(proj);
dangle = dot_product3f(proj, ray) / len_proj;
if(fabs(dangle) < kR_SMALL4)
return 0;
len_proj /= dangle;
sphere[0] = base[0] + ray[0] * len_proj;
sphere[1] = base[1] + ray[1] * len_proj;
sphere[2] = base[2] + ray[2] * len_proj;
if(diff3f(sphere, fpoint) > radius)
return 0;
sphere[0] -= dir[0] * radius;
sphere[1] -= dir[1] * radius;
sphere[2] -= dir[2] * radius;
*asum = maxial;
break;
case cCylCapRound:
axial_sum = maxial;
sphere[0] = dir[0] * axial_sum + point[0];
sphere[1] = dir[1] * axial_sum + point[1];
sphere[2] = dir[2] * axial_sum + point[2];
*asum = axial_sum;
break;
case cCylCapNone:
default:
return 0;
break;
}
} else {
sphere[0] = dir[0] * axial_sum + point[0];
sphere[1] = dir[1] * axial_sum + point[1];
sphere[2] = dir[2] * axial_sum + point[2];
*asum = axial_sum;
/* printf("==>%8.3f sphere %8.3f %8.3f %8.3f\n",base[1],sphere[1],axial_perp,axial); */
}
return (1);
}
static int ConeLineToSphereCapped(float *base, float *ray,
float *point, float *dir, float radius,
float small_radius, float maxial, float *sphere,
float *asum, float *sph_rad, float *sph_rad_sq,
int cap1, int cap2)
{
/* Strategy - find an imaginary sphere that lies at the correct point on
the line segment, then treat as a sphere reflection */
float axial_sum, dangle, ab_dangle;
float len_proj;
float diff[3], fpoint[3];
float proj[3];
{
float perp_axis[3];
float intra[3];
float perp_dist;
subtract3f(point, base, intra);
cross_product3f(ray, dir, perp_axis);
normalize3f(perp_axis);
/* the perp_axis defines a perp-plane which includes the cyl-axis */
/* get minimum distance between the lines */
perp_dist = fabs(dot_product3f(intra, perp_axis));
if(perp_dist > radius) {
/* the infinite ray and the cone direction lines don't pass close
enough to intersect within the bounding cylinder */
return 0;
}
}
dangle = dot_product3f(ray, dir);
ab_dangle = (float) fabs(dangle);
/* set up the cone */
{
double spread = (radius - small_radius) / maxial;
float orig_axial_len = radius / spread;
float base2orig_radial[3];
float base2orig_normal[3];
float base2orig_radial_len, base2orig_radial_len_sq;
float base2orig_len_sq;
float base2orig_axial_len, base2orig_spread;
float orig[3];
float base2orig[3];
float near_p[3];
int base_inside_cone = false;
float shift1, shift2; /* this is what we are solving for --
the distance along the cone axis to the point of intersection */
scale3f(dir, orig_axial_len, orig);
add3f(point, orig, orig);
subtract3f(orig, base, base2orig);
remove_component3f(base2orig, dir, base2orig_radial);
base2orig_radial_len_sq = lengthsq3f(base2orig_radial);
base2orig_len_sq = lengthsq3f(base2orig);
base2orig_axial_len = sqrt1f(base2orig_len_sq - base2orig_radial_len_sq);
base2orig_radial_len = sqrt1f(base2orig_radial_len_sq);
base2orig_spread = base2orig_radial_len / base2orig_axial_len;
base_inside_cone = (base2orig_spread < spread);
normalize23f(base2orig, base2orig_normal);
if(ab_dangle > kR_SMALL4) {
float ray_extend = base2orig_axial_len / dangle;
if(dot_product3f(base2orig_normal, dir) < 0.0)
ray_extend = -ray_extend;
scale3f(ray, ray_extend, near_p);
add3f(base, near_p, near_p);
/* Now we punt entirely and throw the solution of this quadratic
relationship over to Mathematica. Surely this calculation
could be significantly optimized... */
{
double partA, partB, partC;
double dir0 = dir[0], dir1 = dir[1], dir2 = dir[2];
double ray0 = ray[0], ray1 = ray[1], ray2 = ray[2];
double dir0Sq = dir0 * dir0, dir1Sq = dir1 * dir1, dir2Sq = dir2 * dir2;
double ray0Sq = ray0 * ray0, ray1Sq = ray1 * ray1, ray2Sq = ray2 * ray2;
double cone0 = orig[0], cone1 = orig[1], cone2 = orig[2];
double near0 = near_p[0], near1 = near_p[1], near2 = near_p[2];
double cone0Sq = cone0 * cone0, cone1Sq = cone1 * cone1, cone2Sq = cone2 * cone2;
double near0Sq = near0 * near0, near1Sq = near1 * near1, near2Sq = near2 * near2;
double dAngle = ray0 * dir0 + ray1 * dir1 + ray2 * dir2;
double spreadSq = spread * spread;
double dAngleSq = dAngle * dAngle;
partB = dAngleSq * (4 * pow(cone0 * dAngle * dir0 + cone1 * dAngle * dir1 +
cone2 * dAngle * dir2 - dAngle * dir0 * near0 -
dAngle * dir1 * near1 - dAngle * dir2 * near2 -
cone0 * ray0 + near0 * ray0 - cone1 * ray1 +
near1 * ray1 - cone2 * ray2 + near2 * ray2,
2.0) - 4 * (cone0Sq + cone1Sq + cone2Sq -
2 * cone0 * near0 + near0Sq -
2 * cone1 * near1 + near1Sq -
2 * cone2 * near2 + near2Sq) * (ray0Sq +
ray1Sq -
2 *
dAngle *
(dir0 *
ray0 +
dir1 *
ray1 +
dir2 *
ray2) +
ray2Sq +
dAngleSq *
(dir0Sq +
dir1Sq +
dir2Sq -
spreadSq)));
if(partB < 0.0) { /* negative? then there are NO real solutions */
return 0;
} else {
double partBroot = sqrt(partB);
partA = -(cone0 * dAngleSq * dir0) - cone1 * dAngleSq * dir1 -
cone2 * dAngleSq * dir2 + dAngleSq * dir0 * near0 + dAngleSq * dir1 * near1 +
dAngleSq * dir2 * near2 + cone0 * dAngle * ray0 - dAngle * near0 * ray0 +
cone1 * dAngle * ray1 - dAngle * near1 * ray1 + cone2 * dAngle * ray2 -
dAngle * near2 * ray2;
partC = (ray0Sq + ray1Sq -
2 * dAngle * (dir0 * ray0 + dir1 * ray1 + dir2 * ray2) + ray2Sq +
dAngleSq * (dir0Sq + dir1Sq + dir2Sq - spreadSq));
shift1 = (float) ((partA + partBroot * 0.5) / partC);
shift2 = (float) ((partA - partBroot * 0.5) / partC);
}
}
{
float axial_sum1 = orig_axial_len + shift1;
float axial_sum2 = orig_axial_len + shift2;
if(dangle > 0.0F) { /* cone is narrowing in parallel with ray */
if(shift1 < shift2) {
axial_sum = axial_sum1;
} else {
axial_sum = axial_sum2;
}
if((axial_sum < 0.0F) || (base_inside_cone && (axial_sum < orig_axial_len))) {
switch (cap1) {
case cCylCapFlat:
subtract3f(point, base, diff);
project3f(diff, dir, proj);
len_proj = (float) length3f(proj);
dangle = dot_product3f(proj, ray) / len_proj;
if(fabs(dangle) < kR_SMALL5)
return 0;
len_proj /= dangle;
sphere[0] = base[0] + ray[0] * len_proj;
sphere[1] = base[1] + ray[1] * len_proj;
sphere[2] = base[2] + ray[2] * len_proj;
if(diff3f(sphere, point) > radius)
return 0;
sphere[0] += dir[0] * radius;
sphere[1] += dir[1] * radius;
sphere[2] += dir[2] * radius;
*sph_rad = radius;
*sph_rad_sq = radius * radius;
*asum = 0;
return 1;
break;
case cCylCapNone:
default:
return 0;
break;
}
} else if(axial_sum > maxial) {
return 0;
}
} else { /* cone is narrowing against ray */
if(shift1 < shift2) {
axial_sum = axial_sum2;
if(axial_sum > orig_axial_len) {
axial_sum = axial_sum1;
}
} else {
axial_sum = axial_sum1;
if(axial_sum > orig_axial_len) {
axial_sum = axial_sum2;
}
}
if(axial_sum < 0.0F) {
return 0;
} else if(axial_sum >= maxial) {
switch (cap2) {
case cCylCapFlat:
scale3f(dir, maxial, fpoint);
add3f(fpoint, point, fpoint);
subtract3f(fpoint, base, diff);
project3f(diff, dir, proj);
len_proj = (float) length3f(proj);
dangle = dot_product3f(proj, ray) / len_proj;
if(fabs(dangle) < kR_SMALL5)
return 0;
len_proj /= dangle;
sphere[0] = base[0] + ray[0] * len_proj;
sphere[1] = base[1] + ray[1] * len_proj;
sphere[2] = base[2] + ray[2] * len_proj;
if(diff3f(sphere, fpoint) > small_radius)
/* need to handle this case */
return 0;
sphere[0] -= dir[0] * small_radius;
sphere[1] -= dir[1] * small_radius;
sphere[2] -= dir[2] * small_radius;
*sph_rad = small_radius;
*sph_rad_sq = small_radius * small_radius;
*asum = maxial;
return 1;
break;
case cCylCapNone:
default:
return 0;
break;
}
}
}
}
} else {
axial_sum = orig_axial_len - base2orig_axial_len;
if((axial_sum < 0.0F) || (axial_sum > maxial))
return 0;
}
/* normal hit in mid-section of the cone */
{
float radius_at_hit = radius - spread * axial_sum;
float adjustment = radius_at_hit * spread;
*asum = axial_sum; /* color blend based on actual hit location */
axial_sum -= adjustment;
/* printf(" %8.3f ",axial_sum); */
sphere[0] = dir[0] * axial_sum + point[0];
sphere[1] = dir[1] * axial_sum + point[1];
sphere[2] = dir[2] * axial_sum + point[2];
/* and provide virtual sphere radius info */
*sph_rad_sq = (float) ((radius_at_hit * radius_at_hit) + (adjustment * adjustment));
*sph_rad = (float) sqrt(*sph_rad_sq);
/* printf("%8.3f %8.3f ",*sph_rad, tan_acos_dangle); */
/* dump3f(sphere,"sph"); */
return 1;
}
}
return 0;
}
#ifdef _PYMOL_INLINE
__inline__
#endif
static int FrontToInteriorSphereCapped(float *front,
float *point,
float *dir,
float radius,
float radius2, float maxial, int cap1, int cap2)
{
float intra_p[3];
float axial;
float intra[3], axis[3];
float sphere[3];
subtract3f(point, front, intra);
remove_component3f(intra, dir, intra_p);
add3f(front, intra_p, intra_p);
subtract3f(point, intra_p, axis);
axial = -dot_product3f(axis, dir);
if(axial < 0.0F)
return 0;
else if(axial > maxial)
return 0;
sphere[0] = axial * dir[0] + point[0];
sphere[1] = axial * dir[1] + point[1];
sphere[2] = axial * dir[2] + point[2];
return (diffsq3f(sphere, front) < radius2);
}
/*========================================================================*/
#ifdef _PYMOL_INLINE
__inline__
#endif
static float ZLineClipPoint(float *base, float *point, float *alongNormalSq, float cutoff)
{
float hyp0, hyp1, hyp2;
float result = MAXFLOAT;
/* this routine determines whether or not a vector starting at "base"
heading in the direction "normal" intersects a sphere located at "point".
It returns how far along the vector the intersection with the plane is or
MAXFLOAT if there isn't a relevant intersection
NOTE: this routine has been optimized for normals along Z
Optimizes-out vectors that are more than "cutoff" from "point" in x,y plane
*/
hyp0 = point[0] - base[0];
if(fabs(hyp0) > cutoff)
return result;
hyp1 = point[1] - base[1];
if(fabs(hyp1) > cutoff)
return result;
hyp2 = point[2] - base[2];
if(hyp2 < 0.0) {
(*alongNormalSq) = (hyp2 * hyp2);
result = (hyp0 * hyp0) + (hyp1 * hyp1);
}
return result;
}
#ifdef _PYMOL_INLINE
__inline__
#endif
static float ZLineClipPointNoZCheck(float *base, float *point, float *alongNormalSq,
float cutoff)
{
float hyp0, hyp1, hyp2;
float result = MAXFLOAT;
/* this routine determines whether or not a vector starting at "base"
heading in the direction "normal" intersects a sphere located at "point".
It returns how far along the vector the intersection with the plane is or
MAXFLOAT if there isn't a relevant intersection
NOTE: this routine has been optimized for normals along Z
Optimizes-out vectors that are more than "cutoff" from "point" in x,y plane
*/
hyp0 = point[0] - base[0];
if(fabs(hyp0) > cutoff)
return result;
hyp1 = point[1] - base[1];
if(fabs(hyp1) > cutoff)
return result;
hyp2 = point[2] - base[2];
(*alongNormalSq) = (hyp2 * hyp2);
result = (hyp0 * hyp0) + (hyp1 * hyp1);
return result;
}
#ifdef _PYMOL_INLINE
__inline__
#endif
static int LineClipPoint(float *base, float *ray,
float *point, float *dist, float cutoff, float cutoff2)
{
float hyp0, hyp1, hyp2;
float opp0, opp1, opp2;
float adj0, adj1, adj2;
float ray0, ray1, ray2;
float proj;
double dcutoff = (double) cutoff;
float opp_len_sq;
/* this routine determines whether or not a vector starting at "base"
heading in the direction "ray" intersects a sphere located at "point".
It returns how far along the vector the intersection with the plane is or
MAXFLOAT if there isn't a relevant intersection
NOTE: this routine has been optimized for normals along Z
Optimizes-out vectors that are more than "cutoff" from "point"
*/
/* compute the hypo */
hyp2 = point[2] - base[2];
hyp1 = point[1] - base[1];
hyp0 = point[0] - base[0];
ray0 = ray[0];
ray1 = ray[1];
ray2 = ray[2];
/* compute the adjacent edge (dot-projection) */
proj = (ray0 * hyp0) + (ray1 * hyp1) + (ray2 * hyp2);
adj0 = ray0 * proj;
adj1 = ray1 * proj;
opp0 = hyp0 - adj0;
adj2 = ray2 * proj;
if(fabs(opp0) > dcutoff)
return 0;
opp1 = hyp1 - adj1;
opp2 = hyp2 - adj2;
if(fabs(opp1) > dcutoff)
return 0;
if(fabs(opp2) > dcutoff)
return 0;
opp_len_sq = (opp0 * opp0) + (opp1 * opp1) + (opp2 * opp2);
if(opp_len_sq <= cutoff2) {
*dist = proj - (float) sqrt1f(cutoff2 - opp_len_sq);
return 1;
}
return 0;
}
static int LineClipEllipsoidPoint(float *base, float *ray,
float *point, float *dist,
float cutoff, float cutoff2,
float *scale, float *n1, float *n2, float *n3)
{
float point_to_base[3];
float scaled_base[3];
float scaled_ray[3];
float d1, d2, d3, s1, s2, s3;
float comp1[3], comp2[3], comp3[3];
subtract3f(base, point, point_to_base);
/* project difference vector onto ellipsoid axes */
d1 = dot_product3f(point_to_base, n1);
d2 = dot_product3f(point_to_base, n2);
d3 = dot_product3f(point_to_base, n3);
s1 = d1 / scale[0];
s2 = d2 / scale[1];
s3 = d3 / scale[2];
scale3f(n1, s1, comp1);
scale3f(n2, s2, comp2);
scale3f(n3, s3, comp3);
copy3f(point, scaled_base);
add3f(comp1, scaled_base, scaled_base);
add3f(comp2, scaled_base, scaled_base);
add3f(comp3, scaled_base, scaled_base);
d1 = dot_product3f(ray, n1);
d2 = dot_product3f(ray, n2);
d3 = dot_product3f(ray, n3);
s1 = d1 / scale[0];
s2 = d2 / scale[1];
s3 = d3 / scale[2];
scale3f(n1, s1, comp1);
scale3f(n2, s2, comp2);
scale3f(n3, s3, comp3);
copy3f(comp1, scaled_ray);
add3f(comp2, scaled_ray, scaled_ray);
add3f(comp3, scaled_ray, scaled_ray);
d1 = length3f(scaled_ray);
normalize3f(scaled_ray);
/* dump3f(ray,"ray");
dump3f(scaled_ray,"scaled_ray");
*/
{
float hyp0, hyp1, hyp2;
float opp0, opp1, opp2;
float adj0, adj1, adj2;
float ray0, ray1, ray2;
float proj;
double dcutoff = (double) cutoff;
float opp_len_sq;
/* this routine determines whether or not a vector starting at "base"
heading in the direction "ray" intersects a sphere located at "point".
It returns how far along the vector the intersection with the plane is or
MAXFLOAT if there isn't a relevant intersection
*/
/* compute the hypo */
hyp2 = point[2] - scaled_base[2];
hyp1 = point[1] - scaled_base[1];
hyp0 = point[0] - scaled_base[0];
ray0 = scaled_ray[0];
ray1 = scaled_ray[1];
ray2 = scaled_ray[2];
/* compute the adjacent edge (dot-projection) */
proj = (ray0 * hyp0) + (ray1 * hyp1) + (ray2 * hyp2);
adj0 = ray0 * proj;
adj1 = ray1 * proj;
opp0 = hyp0 - adj0;
adj2 = ray2 * proj;
if(fabs(opp0) > dcutoff)
return 0;
opp1 = hyp1 - adj1;
opp2 = hyp2 - adj2;
if(fabs(opp1) > dcutoff)
return 0;
if(fabs(opp2) > dcutoff)
return 0;
opp_len_sq = (opp0 * opp0) + (opp1 * opp1) + (opp2 * opp2);
if(opp_len_sq <= cutoff2) { /* line hits the virtual sphere */
float scaled_dist = proj - (float) sqrt1f(cutoff2 - opp_len_sq);
*(dist) = scaled_dist / d1;
return 1;
}
return 0;
}
}
/*========================================================================*/
void BasisSetupMatrix(CBasis * I)
{
float oldZ[3] = { 0.0, 0.0, 1.0 };
float newY[3];
float dotgle, angle;
cross_product3f(oldZ, I->LightNormal, newY);
dotgle = dot_product3f(oldZ, I->LightNormal);
if((1.0 - fabs(dotgle)) < kR_SMALL4) {
dotgle = (float) (dotgle / fabs(dotgle));
newY[0] = 0.0;
newY[1] = 1.0;
newY[2] = 0.0;
}
normalize3f(newY);
angle = (float) (-acos(dotgle));
/* now all we gotta do is effect a rotation about the new Y axis to line up new Z with Z */
rotation_to_matrix33f(newY, angle, I->Matrix);
/*
printf("%8.3f %8.3f %8.3f %8.3f\n",angle*180.0/cPI,newY[0],newY[1],newY[2]);
matrix_transform33f3f(I->Matrix,newY,test);
printf(" %8.3f %8.3f %8.3f\n",test[0],test[1],test[2]);
printf(" %8.3f %8.3f %8.3f\n",I->LightNormal[0],I->LightNormal[1],I->LightNormal[2]);
matrix_transform33f3f(I->Matrix,I->LightNormal,test);
printf(" %8.3f %8.3f %8.3f\n",test[0],test[1],test[2]);
printf(">%8.3f %8.3f %8.3f\n",I->Matrix[0][0],I->Matrix[0][1],I->Matrix[0][2]);
printf(">%8.3f %8.3f %8.3f\n",I->Matrix[1][0],I->Matrix[1][1],I->Matrix[1][2]);
printf(">%8.3f %8.3f %8.3f\n",I->Matrix[2][0],I->Matrix[2][1],I->Matrix[2][2]);
*/
}
/*========================================================================*/
void BasisGetTriangleFlatDotgle(CBasis * I, RayInfo * r, int i)
{
float *n0 = I->Normal + (3 * I->Vert2Normal[i]);
r->flat_dotgle = n0[2];
}
void BasisGetTriangleFlatDotglePerspective(CBasis * I, RayInfo * r, int i)
{
float *n0 = I->Normal + (3 * I->Vert2Normal[i]);
r->flat_dotgle = -dot_product3f(r->dir, n0);
}
/*========================================================================*/
void BasisGetEllipsoidNormal(CBasis * I, RayInfo * r, int i, int perspective)
{
if(perspective) {
r->impact[0] = r->base[0] + r->dir[0] * r->dist;
r->impact[1] = r->base[1] + r->dir[1] * r->dist;
r->impact[2] = r->base[2] + r->dir[2] * r->dist;
} else {
r->impact[0] = r->base[0];
r->impact[1] = r->base[1];
r->impact[2] = r->base[2] - r->dist;
}
{
float *n1 = I->Normal + (3 * I->Vert2Normal[i]);
float *n2 = n1 + 3, *n3 = n1 + 6;
float *scale = r->prim->n0;
float d1, d2, d3, s1, s2, s3;
float comp1[3], comp2[3], comp3[3];
float direct[3], surfnormal[3];
direct[0] = r->impact[0] - r->sphere[0];
direct[1] = r->impact[1] - r->sphere[1];
direct[2] = r->impact[2] - r->sphere[2];
normalize3f(direct);
d1 = dot_product3f(direct, n1);
d2 = dot_product3f(direct, n2);
d3 = dot_product3f(direct, n3);
if(scale[0] > R_SMALL8) {
s1 = d1 / (scale[0] * scale[0]);
} else {
s1 = 0.0F;
}
if(scale[1] > R_SMALL8) {
s2 = d2 / (scale[1] * scale[1]);
} else {
s2 = 0.0F;
}
if(scale[2] > R_SMALL8) {
s3 = d3 / (scale[2] * scale[2]);
} else {
s3 = 0.0F;
}
scale3f(n1, s1, comp1);
scale3f(n2, s2, comp2);
scale3f(n3, s3, comp3);
copy3f(comp1, surfnormal);
add3f(comp2, surfnormal, surfnormal);
add3f(comp3, surfnormal, surfnormal);
normalize23f(surfnormal, r->surfnormal);
}
}
void BasisGetTriangleNormal(CBasis * I, RayInfo * r, int i, float *fc, int perspective)
{
float *n0, w2, fc0, fc1, fc2;
float vt1[3];
CPrimitive *lprim = r->prim;
if(perspective) {
r->impact[0] = r->base[0] + r->dir[0] * r->dist;
r->impact[1] = r->base[1] + r->dir[1] * r->dist;
r->impact[2] = r->base[2] + r->dir[2] * r->dist;
} else {
r->impact[0] = r->base[0];
r->impact[1] = r->base[1];
r->impact[2] = r->base[2] - r->dist;
}
n0 = I->Normal + (3 * I->Vert2Normal[i]) + 3; /* skip triangle normal */
w2 = 1.0F - (r->tri1 + r->tri2);
/* printf("%8.3f %8.3f\n",r->tri[1],r->tri[2]); */
fc0 = (lprim->c2[0] * r->tri1) + (lprim->c3[0] * r->tri2) + (lprim->c1[0] * w2);
fc1 = (lprim->c2[1] * r->tri1) + (lprim->c3[1] * r->tri2) + (lprim->c1[1] * w2);
fc2 = (lprim->c2[2] * r->tri1) + (lprim->c3[2] * r->tri2) + (lprim->c1[2] * w2);
r->trans = (lprim->tr[1] * r->tri1) + (lprim->tr[2] * r->tri2) + (lprim->tr[0] * w2);
scale3f(n0 + 3, r->tri1, r->surfnormal);
scale3f(n0 + 6, r->tri2, vt1);
add3f(vt1, r->surfnormal, r->surfnormal);
scale3f(n0, w2, vt1);
add3f(vt1, r->surfnormal, r->surfnormal);
normalize3f(r->surfnormal);
fc[0] = fc0;
fc[1] = fc1;
fc[2] = fc2;
}
/*========================================================================*/
#ifdef PROFILE_BASIS
int n_cells = 0;
int n_prims = 0;
int n_triangles = 0;
int n_spheres = 0;
int n_cylinders = 0;
int n_sausages = 0;
int n_skipped = 0;
#endif
#ifdef _PYMOL_INLINE
__inline__
#endif
int BasisHitPerspective(BasisCallRec * BC)
{
CBasis *BI = BC->Basis;
MapType *map = BI->Map;
int iMin0 = map->iMin[0];
int iMin1 = map->iMin[1];
int iMin2 = map->iMin[2];
int iMax0 = map->iMax[0];
int iMax1 = map->iMax[1];
int iMax2 = map->iMax[2];
int a, b, c;
float iDiv = map->recipDiv;
float base0, base1, base2;
float min0 = map->Min[0] * iDiv;
float min1 = map->Min[1] * iDiv;
float min2 = map->Min[2] * iDiv;
int new_ray = !BC->pass;
RayInfo *r = BC->rr;
MapCache *cache = &BC->cache;
int *cache_cache = cache->Cache;
int *cache_CacheLink = cache->CacheLink;
CPrimitive *r_prim = NULL;
if(new_ray) { /* see if we can eliminate this ray right away using the mask */
base0 = (r->base[0] * iDiv) - min0;
base1 = (r->base[1] * iDiv) - min1;
a = (int) base0;
b = (int) base1;
a += MapBorder;
b += MapBorder;
if(a < iMin0)
a = iMin0;
else if(a > iMax0)
a = iMax0;
if(b < iMin1)
b = iMin1;
else if(b > iMax1)
b = iMax1;
if(!*(map->EMask + a * map->Dim[1] + b))
return -1;
}
{
int last_a = -1, last_b = -1, last_c = -1;
int allow_break;
int minIndex = -1;
float step0, step1, step2;
float back_dist = BC->back_dist;
const float _0 = 0.0F, _1 = 1.0F;
float r_tri1 = _0, r_tri2 = _0, r_dist, dist; /* zero inits to suppress compiler warnings */
float r_sphere0 = _0, r_sphere1 = _0, r_sphere2 = _0;
int h, *ip;
int excl_trans_flag;
int *elist, local_iflag = false;
int terminal = -1;
int *ehead = map->EHead;
int d1d2 = map->D1D2;
int d2 = map->Dim[2];
const int *vert2prim = BC->vert2prim;
const float excl_trans = BC->excl_trans;
const float BasisFudge0 = BC->fudge0;
const float BasisFudge1 = BC->fudge1;
int v2p;
int i, ii;
int n_vert = BI->NVertex, n_eElem = map->NEElem;
int except1 = BC->except1;
int except2 = BC->except2;
int check_interior_flag = BC->check_interior && !BC->pass;
float sph[3], vt[3], tri1 = _0, tri2;
CPrimitive *BC_prim = BC->prim;
int *BI_Vert2Normal = BI->Vert2Normal;
float *BI_Vertex = BI->Vertex;
float *BI_Precomp = BI->Precomp;
float *BI_Normal = BI->Normal;
float *BI_Radius = BI->Radius;
float *BI_Radius2 = BI->Radius2;
copy3f(r->base, vt);
elist = map->EList;
r_dist = MAXFLOAT;
excl_trans_flag = (excl_trans != _0);
if(except1 >= 0)
except1 = vert2prim[except1];
if(except2 >= 0)
except2 = vert2prim[except2];
MapCacheReset(cache);
{ /* take steps with a Z-size equil to the grid spacing */
float div = iDiv * (-MapGetDiv(BI->Map) / r->dir[2]);
step0 = r->dir[0] * div;
step1 = r->dir[1] * div;
step2 = r->dir[2] * div;
}
base0 = (r->skip[0] * iDiv) - min0;
base1 = (r->skip[1] * iDiv) - min1;
base2 = (r->skip[2] * iDiv) - min2;
allow_break = false;
while(1) {
int inside_code;
int clamped;
a = ((int) base0);
b = ((int) base1);
c = ((int) base2);
inside_code = 1;
clamped = false;
a += MapBorder;
b += MapBorder;
c += MapBorder;
#define EDGE_ALLOWANCE 1
if(a < iMin0) {
if(((iMin0 - a) > EDGE_ALLOWANCE) && allow_break)
break;
else {
a = iMin0;
clamped = true;
}
} else if(a > iMax0) {
if(((a - iMax0) > EDGE_ALLOWANCE) && allow_break)
break;
else {
a = iMax0;
clamped = true;
}
}
if(b < iMin1) {
if(((iMin1 - b) > EDGE_ALLOWANCE) && allow_break)
break;
else {
b = iMin1;
clamped = true;
}
} else if(b > iMax1) {
if(((b - iMax1) > EDGE_ALLOWANCE) && allow_break)
break;
else {
b = iMax1;
clamped = true;
}
}
if(c < iMin2) {
if((iMin2 - c) > EDGE_ALLOWANCE)
break;
else {
c = iMin2;
clamped = true;
}
} else if(c > iMax2) {
if((c - iMax2) > EDGE_ALLOWANCE)
inside_code = 0;
else {
c = iMax2;
clamped = true;
}
}
if(inside_code && (((a != last_a) || (b != last_b) || (c != last_c)))) {
int new_min_index;
h = *(ehead + (d1d2 * a) + (d2 * b) + c);
new_min_index = -1;
if(!clamped) /* don't discard a ray until it has hit the objective at least once */
allow_break = true;
if((terminal > 0) && (last_c != c)) {
if(!terminal--)
break;
}
if((h > 0) && (h < n_eElem)) {
int do_loop;
ip = elist + h;
last_a = a;
i = *(ip++);
last_b = b;
do_loop = ((i >= 0) && (i < n_vert));
last_c = c;
while(do_loop) { /* n_vert checking is a bug workaround */
CPrimitive *prm;
v2p = vert2prim[i];
ii = *(ip++);
prm = BC_prim + v2p;
do_loop = ((ii >= 0) && (ii < n_vert));
/* if((v2p != except1) && (v2p != except2) && (!MapCached(cache, v2p))) { */
if((v2p != except1) && (v2p != except2) && (!cache_cache[v2p])) {
int prm_type = prm->type;
/*MapCache(cache,v2p); */
cache_cache[v2p] = 1;
cache_CacheLink[v2p] = cache->CacheStart;
cache->CacheStart = v2p;
switch (prm_type) {
case cPrimTriangle:
case cPrimCharacter:
{
float *dir = r->dir;
float *d10 = BI_Precomp + BI_Vert2Normal[i] * 3;
float *d20 = d10 + 3;
float *v0;
float det, inv_det;
float pvec0, pvec1, pvec2;
float dir0 = dir[0], dir1 = dir[1], dir2 = dir[2];
float d20_0 = d20[0], d20_1 = d20[1], d20_2 = d20[2];
float d10_0 = d10[0], d10_1 = d10[1], d10_2 = d10[2];
/* cross_product3f(dir, d20, pvec); */
pvec0 = dir1 * d20_2 - dir2 * d20_1;
pvec1 = dir2 * d20_0 - dir0 * d20_2;
pvec2 = dir0 * d20_1 - dir1 * d20_0;
/* det = dot_product3f(pvec, d10); */
det = pvec0 * d10_0 + pvec1 * d10_1 + pvec2 * d10_2;
v0 = BI_Vertex + prm->vert * 3;
if((det >= EPSILON) || (det <= -EPSILON)) {
float tvec0, tvec1, tvec2;
float qvec0, qvec1, qvec2;
inv_det = _1 / det;
/* subtract3f(vt,v0,tvec); */
tvec0 = vt[0] - v0[0];
tvec1 = vt[1] - v0[1];
tvec2 = vt[2] - v0[2];
/* dot_product3f(tvec,pvec) * inv_det; */
tri1 = (tvec0 * pvec0 + tvec1 * pvec1 + tvec2 * pvec2) * inv_det;
/* cross_product3f(tvec,d10,qvec); */
qvec0 = tvec1 * d10_2 - tvec2 * d10_1;
qvec1 = tvec2 * d10_0 - tvec0 * d10_2;
if((tri1 >= BasisFudge0) && (tri1 <= BasisFudge1)) {
qvec2 = tvec0 * d10_1 - tvec1 * d10_0;
/* dot_product3f(dir, qvec) * inv_det; */
tri2 = (dir0 * qvec0 + dir1 * qvec1 + dir2 * qvec2) * inv_det;
/* dot_product3f(d20, qvec) * inv_det; */
dist = (d20_0 * qvec0 + d20_1 * qvec1 + d20_2 * qvec2) * inv_det;
if((tri2 >= BasisFudge0) && (tri2 <= BasisFudge1)
&& ((tri1 + tri2) <= BasisFudge1)) {
if((dist < r_dist) && (dist >= _0) && (dist <= back_dist)
&& (prm->trans != _1)) {
new_min_index = prm->vert;
r_tri1 = tri1;
r_tri2 = tri2;
r_dist = dist;
}
}
}
}
}
break;
case cPrimSphere:
{
if(LineClipPoint(r->base, r->dir,
BI_Vertex + i * 3, &dist,
BI_Radius[i], BI_Radius2[i])) {
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
new_min_index = prm->vert;
r_dist = dist;
} else if(check_interior_flag && (dist <= back_dist)) {
if(diffsq3f(vt, BI_Vertex + i * 3) < BI_Radius2[i]) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
break;
case cPrimEllipsoid:
{
if(LineClipPoint(r->base, r->dir,
BI_Vertex + i * 3, &dist,
BI_Radius[i], BI_Radius2[i])) {
if((dist < r_dist) && (prm->trans != _1)) {
float *n1 = BI_Normal + BI_Vert2Normal[i] * 3;
if(LineClipEllipsoidPoint(r->base, r->dir,
BI_Vertex + i * 3, &dist,
BI_Radius[i], BI_Radius2[i],
prm->n0, n1, n1 + 3, n1 + 6)) {
if(dist < r_dist) {
if((dist >= _0) && (dist <= back_dist)) {
new_min_index = prm->vert;
r_dist = dist;
}
}
}
}
}
}
break;
case cPrimCylinder:
if(LineToSphereCapped(r->base, r->dir, BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], prm->l1, sph, &tri1,
prm->cap1, prm->cap2)) {
if(LineClipPoint
(r->base, r->dir, sph, &dist, BI_Radius[i], BI_Radius2[i])) {
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
new_min_index = prm->vert;
r_dist = dist;
} else if(check_interior_flag && (dist <= back_dist)) {
if(FrontToInteriorSphereCapped(vt,
BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i],
BI_Radius2[i],
prm->l1, prm->cap1, prm->cap2)) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
break;
case cPrimCone:
{
float sph_rad, sph_rad_sq;
if(ConeLineToSphereCapped(r->base, r->dir, BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], prm->r2, prm->l1, sph, &tri1,
&sph_rad, &sph_rad_sq,
prm->cap1, prm->cap2)) {
if(LineClipPoint(r->base, r->dir, sph, &dist, sph_rad, sph_rad_sq)) {
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1; /* color blending */
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
new_min_index = prm->vert;
r_dist = dist;
} else if(check_interior_flag && (dist <= back_dist)) {
if(FrontToInteriorSphereCapped(vt,
BI_Vertex + i * 3,
BI_Normal +
BI_Vert2Normal[i] * 3,
BI_Radius[i], BI_Radius2[i],
prm->l1, prm->cap1, prm->cap2)) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
}
break;
case cPrimSausage:
if(LineToSphere(r->base, r->dir,
BI_Vertex + i * 3, BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], prm->l1, sph, &tri1)) {
if(LineClipPoint
(r->base, r->dir, sph, &dist, BI_Radius[i], BI_Radius2[i])) {
int tmp_flag = false;
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= _0) && (dist <= back_dist)) {
tmp_flag = true;
if(excl_trans_flag) {
if((prm->trans > _0) && (dist < excl_trans))
tmp_flag = false;
}
if(tmp_flag) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
new_min_index = prm->vert;
r_dist = dist;
}
} else if(check_interior_flag && (dist <= back_dist)) {
if(FrontToInteriorSphere(vt, BI_Vertex + i * 3,
BI_Normal + BI_Vert2Normal[i] * 3,
BI_Radius[i], BI_Radius2[i], prm->l1)) {
local_iflag = true;
r_prim = prm;
r_dist = _0;
new_min_index = prm->vert;
}
}
}
}
}
break;
} /* end of switch */
}
/* end of if */
i = ii;
} /* end of while */
if(local_iflag) {
r->prim = r_prim;
r->dist = r_dist;
break;
}
if(new_min_index > -1) {
minIndex = new_min_index;
r_prim = BC_prim + vert2prim[minIndex];
if((r_prim->type == cPrimSphere) || (r_prim->type == cPrimEllipsoid)) {
const float *vv = BI->Vertex + minIndex * 3;
r_sphere0 = vv[0];
r_sphere1 = vv[1];
r_sphere2 = vv[2];
}
BC->interior_flag = local_iflag;
r->tri1 = r_tri1;
r->tri2 = r_tri2;
r->prim = r_prim;
r->dist = r_dist;
r->sphere[0] = r_sphere0;
r->sphere[1] = r_sphere1;
r->sphere[2] = r_sphere2;
}
} /* if -- h valid */
}
/* end of if */
if(minIndex > -1) {
if(terminal < 0)
terminal = EDGE_ALLOWANCE + 1;
}
base0 += step0;
base1 += step1;
base2 += step2;
/* advance through the map one block at a time -- note that this is a crappy way to walk through the map... */
}
BC->interior_flag = local_iflag;
return (minIndex);
}
}
#ifdef _PYMOL_INLINE
__inline__
#endif
int BasisHitOrthoscopic(BasisCallRec * BC)
{
const float _0 = 0.0F, _1 = 1.0F;
float oppSq, dist = _0, sph[3], vt[3], tri1, tri2;
int a, b, c, h, *ip;
int excl_trans_flag;
int check_interior_flag;
int *elist, local_iflag = false;
float minusZ[3] = { 0.0F, 0.0F, -1.0F };
CBasis *BI = BC->Basis;
RayInfo *r = BC->rr;
if(MapInsideXY(BI->Map, r->base, &a, &b, &c)) {
int minIndex = -1;
int v2p;
int i, ii;
int *xxtmp;
int do_loop;
int except1 = BC->except1;
int except2 = BC->except2;
int n_vert = BI->NVertex, n_eElem = BI->Map->NEElem;
const int *vert2prim = BC->vert2prim;
const float front = BC->front;
const float back = BC->back;
const float excl_trans = BC->excl_trans;
const float BasisFudge0 = BC->fudge0;
const float BasisFudge1 = BC->fudge1;
MapCache *cache = &BC->cache;
float r_tri1 = _0, r_tri2 = _0, r_dist = _0; /* zero inits to suppress compiler warnings */
float r_sphere0 = _0, r_sphere1 = _0, r_sphere2 = _0;
CPrimitive *r_prim = NULL;
check_interior_flag = BC->check_interior && (!BC->pass);
/* assumption: always heading in the negative Z direction with our vector... */
vt[0] = r->base[0];
vt[1] = r->base[1];
vt[2] = r->base[2] - front;
if(except1 >= 0)
except1 = vert2prim[except1];
if(except2 >= 0)
except2 = vert2prim[except2];
excl_trans_flag = (excl_trans != _0);
r_dist = MAXFLOAT;
xxtmp = BI->Map->EHead + (a * BI->Map->D1D2) + (b * BI->Map->Dim[2]) + c;
MapCacheReset(cache);
elist = BI->Map->EList;
while(c >= MapBorder) {
h = *xxtmp;
if((h > 0) && (h < n_eElem)) {
ip = elist + h;
i = *(ip++);
do_loop = ((i >= 0) && (i < n_vert));
while(do_loop) {
ii = *(ip++);
v2p = vert2prim[i];
do_loop = ((ii >= 0) && (ii < n_vert));
if((v2p != except1) && (v2p != except2) && (!MapCached(cache, v2p))) {
CPrimitive *prm = BC->prim + v2p;
MapCache(cache, v2p);
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
if(!prm->cull) {
float *pre = BI->Precomp + BI->Vert2Normal[i] * 3;
if(pre[6]) {
float *vert0 = BI->Vertex + prm->vert * 3;
float tvec0 = vt[0] - vert0[0];
float tvec1 = vt[1] - vert0[1];
tri1 = (tvec0 * pre[4] - tvec1 * pre[3]) * pre[7];
tri2 = -(tvec0 * pre[1] - tvec1 * pre[0]) * pre[7];
if(!((tri1 < BasisFudge0) || (tri2 < BasisFudge0) ||
(tri1 > BasisFudge1) || ((tri1 + tri2) > BasisFudge1))) {
dist = (r->base[2] - (tri1 * pre[2]) - (tri2 * pre[5]) - vert0[2]);
if((dist < r_dist) && (dist >= front) &&
(dist <= back) && (prm->trans != _1)) {
minIndex = prm->vert;
r_tri1 = tri1;
r_tri2 = tri2;
r_dist = dist;
}
}
}
}
break;
case cPrimSphere:
oppSq = ZLineClipPoint(r->base, BI->Vertex + i * 3, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= front) && (dist <= back)) {
minIndex = prm->vert;
r_dist = dist;
} else if(check_interior_flag) {
if(diffsq3f(vt, BI->Vertex + i * 3) < BI->Radius2[i]) {
local_iflag = true;
r_prim = prm;
r_dist = front;
minIndex = prm->vert;
}
}
}
}
break;
case cPrimEllipsoid:
oppSq = ZLineClipPoint(r->base, BI->Vertex + i * 3, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if((dist < r_dist) && (prm->trans != _1)) {
float *n1 = BI->Normal + BI->Vert2Normal[i] * 3;
if(LineClipEllipsoidPoint(r->base, minusZ,
BI->Vertex + i * 3, &dist,
BI->Radius[i], BI->Radius2[i],
prm->n0, n1, n1 + 3, n1 + 6)) {
if(dist < r_dist) {
if((dist >= _0) && (dist <= back)) {
minIndex = prm->vert;
r_dist = dist;
}
}
}
}
}
break;
case cPrimCylinder:
if(ZLineToSphereCapped(r->base, BI->Vertex + i * 3,
BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i], prm->l1, sph, &tri1, prm->cap1,
prm->cap2, BI->Precomp + BI->Vert2Normal[i] * 3)) {
oppSq = ZLineClipPoint(r->base, sph, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= front) && (dist <= back)) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r_dist = dist;
} else if(check_interior_flag) {
if(FrontToInteriorSphereCapped(vt,
BI->Vertex + i * 3,
BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i],
BI->Radius2[i],
prm->l1, prm->cap1, prm->cap2)) {
local_iflag = true;
r_prim = prm;
r_dist = front;
minIndex = prm->vert;
}
}
}
}
}
break;
case cPrimCone:
{
float sph_rad, sph_rad_sq;
if(ConeLineToSphereCapped(r->base, minusZ, BI->Vertex + i * 3,
BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i], prm->r2, prm->l1, sph, &tri1,
&sph_rad, &sph_rad_sq, prm->cap1, prm->cap2)) {
oppSq = ZLineClipPoint(r->base, sph, &dist, sph_rad);
if(oppSq <= sph_rad_sq) {
dist = (float) (sqrt1f(dist) - sqrt1f((sph_rad_sq - oppSq)));
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= front) && (dist <= back)) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r_dist = dist;
} else if(check_interior_flag) {
if(FrontToInteriorSphereCapped(vt,
BI->Vertex + i * 3,
BI->Normal +
BI->Vert2Normal[i] * 3, sph_rad,
sph_rad_sq, prm->l1, prm->cap1,
prm->cap2)) {
local_iflag = true;
r_prim = prm;
r_dist = front;
minIndex = prm->vert;
}
}
}
}
}
}
break;
case cPrimSausage:
if(ZLineToSphere
(r->base, BI->Vertex + i * 3, BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i], prm->l1, sph, &tri1,
BI->Precomp + BI->Vert2Normal[i] * 3)) {
oppSq = ZLineClipPoint(r->base, sph, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
int tmp_flag = false;
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if((dist < r_dist) && (prm->trans != _1)) {
if((dist >= front) && (dist <= back)) {
tmp_flag = true;
if(excl_trans_flag) {
if((prm->trans > _0) && (dist < excl_trans))
tmp_flag = false;
}
if(tmp_flag) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r_dist = dist;
}
} else if(check_interior_flag) {
if(FrontToInteriorSphere
(vt, BI->Vertex + i * 3, BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i], BI->Radius2[i], prm->l1)) {
local_iflag = true;
r_prim = prm;
r_dist = front;
minIndex = prm->vert;
}
}
}
}
}
break;
} /* end of switch */
}
/* end of if */
i = ii;
} /* end of while */
}
/* and of course stop when we hit the edge of the map */
if(local_iflag)
break;
/* we've processed all primitives associated with this voxel,
so if an intersection has been found which occurs in front of
the next voxel, then we can stop */
if(minIndex > -1) {
int aa, bb, cc;
vt[2] = r->base[2] - r_dist;
MapLocus(BI->Map, vt, &aa, &bb, &cc);
if(cc > c)
break;
else
vt[2] = r->base[2] - front;
}
c--;
xxtmp--;
} /* end of while */
if(minIndex > -1) {
r_prim = BC->prim + vert2prim[minIndex];
if((r_prim->type == cPrimSphere) || (r_prim->type == cPrimEllipsoid)) {
const float *vv = BI->Vertex + minIndex * 3;
r_sphere0 = vv[0];
r_sphere1 = vv[1];
r_sphere2 = vv[2];
}
}
BC->interior_flag = local_iflag;
r->tri1 = r_tri1;
r->tri2 = r_tri2;
r->prim = r_prim;
r->dist = r_dist;
r->sphere[0] = r_sphere0;
r->sphere[1] = r_sphere1;
r->sphere[2] = r_sphere2;
return (minIndex);
} /* end of if */
BC->interior_flag = local_iflag;
return (-1);
}
#ifdef _PYMOL_INLINE
__inline__
#endif
int BasisHitShadow(BasisCallRec * BC)
{
const float _0 = 0.0F;
const float _1 = 1.0F;
float oppSq, dist = _0, tri1, tri2;
float sph[3], vt[3];
int h, *ip;
int a, b, c;
int *elist, local_iflag = false;
float minusZ[3] = { 0.0F, 0.0F, -1.0F };
/* local copies (eliminate these extra copies later on) */
CBasis *BI = BC->Basis;
RayInfo *r = BC->rr;
if(MapInsideXY(BI->Map, r->base, &a, &b, &c)) {
int minIndex = -1;
int v2p;
int i, ii;
int *xxtmp;
int n_vert = BI->NVertex, n_eElem = BI->Map->NEElem;
int except1 = BC->except1;
int except2 = BC->except2;
const int *vert2prim = BC->vert2prim;
const int trans_shadows = BC->trans_shadows;
const int nearest_shadow = BC->nearest_shadow;
const float BasisFudge0 = BC->fudge0;
const float BasisFudge1 = BC->fudge1;
const int label_shadow_mode = BC->label_shadow_mode;
MapCache *cache = &BC->cache;
int *cache_cache = cache->Cache;
int *cache_CacheLink = cache->CacheLink;
CPrimitive *BC_prim = BC->prim;
float r_tri1 = _0, r_tri2 = _0, r_dist; /* zero inits to suppress compiler warnings */
float r_sphere0 = _0, r_sphere1 = _0, r_sphere2 = _0;
float r_trans = _0;
CPrimitive *r_prim = NULL;
/* assumption: always heading in the negative Z direction with our vector... */
vt[0] = r->base[0];
vt[1] = r->base[1];
if(except1 >= 0)
except1 = vert2prim[except1];
if(except2 >= 0)
except2 = vert2prim[except2];
r_trans = _1;
r_dist = MAXFLOAT;
xxtmp = BI->Map->EHead + (a * BI->Map->D1D2) + (b * BI->Map->Dim[2]) + c;
MapCacheReset(cache);
elist = BI->Map->EList;
while(c >= MapBorder) {
h = *xxtmp;
if((h > 0) && (h < n_eElem)) {
int do_loop;
ip = elist + h;
i = *(ip++);
do_loop = ((i >= 0) && (i < n_vert));
while(do_loop) {
ii = *(ip++);
v2p = vert2prim[i];
do_loop = ((ii >= 0) && (ii < n_vert));
if((v2p != except1) && (v2p != except2) && !MapCached(cache, v2p)) {
CPrimitive *prm = BC_prim + v2p;
int prm_type;
/*MapCache(cache,v2p); */
cache_cache[v2p] = 1;
prm_type = prm->type;
cache_CacheLink[v2p] = cache->CacheStart;
cache->CacheStart = v2p;
switch (prm_type) {
case cPrimCharacter: /* will need special handling for character shadows */
if(label_shadow_mode & 0x2) { /* if labels case shadows... */
float *pre = BI->Precomp + BI->Vert2Normal[i] * 3;
if(pre[6]) {
float *vert0 = BI->Vertex + prm->vert * 3;
float tvec0 = vt[0] - vert0[0];
float tvec1 = vt[1] - vert0[1];
tri1 = (tvec0 * pre[4] - tvec1 * pre[3]) * pre[7];
tri2 = -(tvec0 * pre[1] - tvec1 * pre[0]) * pre[7];
if(!((tri1 < BasisFudge0) ||
(tri2 < BasisFudge0) ||
(tri1 > BasisFudge1) || ((tri1 + tri2) > BasisFudge1))) {
dist = (r->base[2] - (tri1 * pre[2]) - (tri2 * pre[5]) - vert0[2]);
{
float fc[3];
float trans;
r->tri1 = tri1;
r->tri2 = tri2;
r->dist = dist;
r->prim = prm;
{
float w2;
w2 = _1 - (r->tri1 + r->tri2);
fc[0] =
(prm->c2[0] * r->tri1) + (prm->c3[0] * r->tri2) +
(prm->c1[0] * w2);
fc[1] =
(prm->c2[1] * r->tri1) + (prm->c3[1] * r->tri2) +
(prm->c1[1] * w2);
fc[2] =
(prm->c2[2] * r->tri1) + (prm->c3[2] * r->tri2) +
(prm->c1[2] * w2);
}
trans = CharacterInterpolate(BI->G, prm->char_id, fc);
if(trans == _0) { /* opaque? return immed. */
if(dist > -kR_SMALL4) {
if(nearest_shadow) {
if(dist < r_dist) {
minIndex = prm->vert;
r_tri1 = tri1;
r_tri2 = tri2;
r_dist = dist;
r_trans = (r->trans = trans);
}
} else {
r->prim = prm;
r->trans = _0;
r->dist = dist;
return (1);
}
}
} else if(trans_shadows) {
if((dist > -kR_SMALL4) &&
((r_trans > trans) ||
(nearest_shadow && (dist < r_dist) && (r_trans >= trans)))) {
minIndex = prm->vert;
r_tri1 = tri1;
r_tri2 = tri2;
r_dist = dist;
r_trans = (r->trans = trans);
}
}
}
}
}
}
break;
case cPrimTriangle:
{
float *pre = BI->Precomp + BI->Vert2Normal[i] * 3;
if(pre[6]) {
float *vert0 = BI->Vertex + prm->vert * 3;
float tvec0 = vt[0] - vert0[0];
float tvec1 = vt[1] - vert0[1];
tri1 = (tvec0 * pre[4] - tvec1 * pre[3]) * pre[7];
tri2 = -(tvec0 * pre[1] - tvec1 * pre[0]) * pre[7];
if(!((tri1 < BasisFudge0) ||
(tri2 < BasisFudge0) ||
(tri1 > BasisFudge1) || ((tri1 + tri2) > BasisFudge1))) {
float *tr = prm->tr;
float trans = _0;
dist = (r->base[2] - (tri1 * pre[2]) - (tri2 * pre[5]) - vert0[2]);
if(prm->trans != _0) {
trans =
(tr[1] * tri1) + (tr[2] * tri2) + (tr[0] * (_1 - (tri1 + tri2)));
}
if(trans == _0) {
if(dist > -kR_SMALL4) {
if(nearest_shadow) { /* do we need the nearest shadow? */
if(dist < r_dist) {
minIndex = prm->vert;
r_tri1 = tri1;
r_tri2 = tri2;
r_dist = dist;
r_trans = (r->trans = trans);
}
} else {
r->prim = prm;
r->trans = _0;
r->dist = dist;
return (1);
}
}
} else if(trans_shadows) {
if((dist > -kR_SMALL4) &&
((r_trans > trans) ||
(nearest_shadow && (dist < r_dist) && (r_trans >= trans)))) {
minIndex = prm->vert;
r_tri1 = tri1;
r_tri2 = tri2;
r_dist = dist;
r_trans = (r->trans = trans);
}
}
}
}
}
break;
case cPrimSphere:
oppSq = ZLineClipPoint(r->base, BI->Vertex + i * 3, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if(prm->trans == _0) {
if(dist > -kR_SMALL4) {
if(nearest_shadow) {
if(dist < r_dist) {
minIndex = prm->vert;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
} else {
r->prim = prm;
r->trans = prm->trans;
r->dist = dist;
return (1);
}
}
} else if(trans_shadows) {
if((dist > -kR_SMALL4) &&
((r_trans > prm->trans) ||
(nearest_shadow && (dist < r_dist) && (r_trans >= prm->trans)))) {
minIndex = prm->vert;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
}
}
break;
case cPrimEllipsoid:
oppSq =
ZLineClipPointNoZCheck(r->base, BI->Vertex + i * 3, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if((dist < r_dist) || (trans_shadows && (r_trans != _0))) {
float *n1 = BI->Normal + BI->Vert2Normal[i] * 3;
if(LineClipEllipsoidPoint(r->base, minusZ,
BI->Vertex + i * 3, &dist,
BI->Radius[i], BI->Radius2[i],
prm->n0, n1, n1 + 3, n1 + 6)) {
if(prm->trans == _0) {
if(dist > -kR_SMALL4) {
if(nearest_shadow) {
if(dist < r_dist) {
minIndex = prm->vert;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
} else {
r->prim = prm;
r->trans = prm->trans;
r->dist = dist;
return (1);
}
}
} else if(trans_shadows) {
if((dist > -kR_SMALL4) &&
((r_trans > prm->trans) ||
(nearest_shadow && (dist < r_dist)
&& (r_trans >= prm->trans)))) {
minIndex = prm->vert;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
}
}
}
}
break;
case cPrimCone:
{
float sph_rad, sph_rad_sq;
if(ConeLineToSphereCapped(r->base, minusZ, BI->Vertex + i * 3,
BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i], prm->r2, prm->l1, sph, &tri1,
&sph_rad, &sph_rad_sq, 1, 1)) {
oppSq = ZLineClipPoint(r->base, sph, &dist, sph_rad);
if(oppSq <= sph_rad_sq) {
dist = (float) (sqrt1f(dist) - sqrt1f((sph_rad_sq - oppSq)));
if(prm->trans == _0) {
if(dist > -kR_SMALL4) {
if(nearest_shadow) {
if(dist < r_dist) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r->trans = prm->trans;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
} else {
r->prim = prm;
r->trans = prm->trans;
r->dist = dist;
return (1);
}
}
} else if(trans_shadows) {
if((dist > -kR_SMALL4) &&
((r_trans > prm->trans) ||
(nearest_shadow && (dist < r_dist)
&& (r_trans >= prm->trans)))) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r->trans = prm->trans;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
}
}
}
}
break;
case cPrimCylinder:
if(ZLineToSphereCapped(r->base, BI->Vertex + i * 3,
BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i], prm->l1, sph, &tri1, prm->cap1,
prm->cap2, BI->Precomp + BI->Vert2Normal[i] * 3)) {
oppSq = ZLineClipPoint(r->base, sph, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if(prm->trans == _0) {
if(dist > -kR_SMALL4) {
if(nearest_shadow) {
if(dist < r_dist) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r->trans = prm->trans;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
} else {
r->prim = prm;
r->trans = prm->trans;
r->dist = dist;
return (1);
}
}
} else if(trans_shadows) {
if((dist > -kR_SMALL4) &&
((r_trans > prm->trans) ||
(nearest_shadow && (dist < r_dist) && (r_trans >= prm->trans)))) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r->trans = prm->trans;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
}
}
}
break;
case cPrimSausage:
if(ZLineToSphere
(r->base, BI->Vertex + i * 3, BI->Normal + BI->Vert2Normal[i] * 3,
BI->Radius[i], prm->l1, sph, &tri1,
BI->Precomp + BI->Vert2Normal[i] * 3)) {
oppSq = ZLineClipPoint(r->base, sph, &dist, BI->Radius[i]);
if(oppSq <= BI->Radius2[i]) {
dist = (float) (sqrt1f(dist) - sqrt1f((BI->Radius2[i] - oppSq)));
if(prm->trans == _0) {
if(dist > -kR_SMALL4) {
if(nearest_shadow) {
if(dist < r_dist) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
} else {
r->prim = prm;
r->trans = prm->trans;
r->dist = dist;
return (1);
}
}
} else if(trans_shadows) {
if((dist > -kR_SMALL4) &&
((r_trans > prm->trans) ||
(nearest_shadow && (dist < r_dist) && (r_trans >= prm->trans)))) {
if(prm->l1 > kR_SMALL4)
r_tri1 = tri1 / prm->l1;
r_sphere0 = sph[0];
r_sphere1 = sph[1];
r_sphere2 = sph[2];
minIndex = prm->vert;
r_dist = dist;
r_trans = (r->trans = prm->trans);
}
}
}
}
break;
} /* end of switch */
}
/* end of if */
i = ii;
} /* end of while */
}
/* and of course stop when we hit the edge of the map */
if(local_iflag)
break;
/* we've processed all primitives associated with this voxel,
so if an intersection has been found which occurs in front of
the next voxel, then we can stop */
/* this optimization invalid for transparent surfaces
if( minIndex > -1 )
{
int aa,bb,cc;
vt[2] = r->base[2] - r_dist;
MapLocus(BI->Map,vt,&aa,&bb,&cc);
if(cc > c)
break;
}
*/
c--;
xxtmp--;
} /* end of while */
if(minIndex > -1) {
r_prim = BC->prim + vert2prim[minIndex];
if((r_prim->type == cPrimSphere) || (r_prim->type == cPrimEllipsoid)) {
const float *vv = BI->Vertex + minIndex * 3;
r_sphere0 = vv[0];
r_sphere1 = vv[1];
r_sphere2 = vv[2];
}
}
BC->interior_flag = local_iflag;
r->tri1 = r_tri1;
r->tri2 = r_tri2;
r->prim = r_prim;
r->dist = r_dist;
r->trans = r_trans;
r->sphere[0] = r_sphere0;
r->sphere[1] = r_sphere1;
r->sphere[2] = r_sphere2;
return (minIndex);
} /* end of if */
BC->interior_flag = local_iflag;
return (-1);
}
/*========================================================================*/
int BasisMakeMap(CBasis * I, int *vert2prim, CPrimitive * prim, int n_prim,
float *volume,
int group_id, int block_base,
int perspective, float front, float size_hint)
{
float *v;
float ll;
CPrimitive *prm;
int i;
int *tempRef = NULL;
int n = 0, h, q, x, y, z, j, k, l, e;
int extra_vert = 0;
float p[3], dd[3], *d1, *d2, vd[3], cx[3], cy[3];
float *tempVertex = NULL;
float xs, ys;
int remapMode = true; /* remap mode means that some objects will span more
* than one voxel, so we have to worry about populating
* those voxels and also about eliminating duplicates
* when traversing the neighbor lists */
float min[3], max[3], extent[6];
float sep;
float diagonal[3];
float l1, l2;
float bh, ch;
int n_voxel;
int ok = true;
const float _0 = 0.0;
const float _p5 = 0.5;
PRINTFD(I->G, FB_Ray)
" BasisMakeMap: I->NVertex %d [(%8.3f, %8.3f, %8.3f),...]\n", I->NVertex,
I->Vertex[0], I->Vertex[1], I->Vertex[2]
ENDFD;
sep = I->MinVoxel;
if(sep == _0) {
remapMode = false;
sep = I->MaxRadius; /* also will imply no remapping of vertices */
}
/* we need to get a sense of the actual size in order to avoid sep being too small */
v = I->Vertex;
min[0] = max[0] = v[0];
min[1] = max[1] = v[1];
min[2] = max[2] = v[2];
v += 3;
{
int a;
for(a = 1; a < I->NVertex; a++) {
if(min[0] > v[0])
min[0] = v[0];
if(max[0] < v[0])
max[0] = v[0];
if(min[1] > v[1])
min[1] = v[1];
if(max[1] < v[1])
max[1] = v[1];
if(min[2] > v[2])
min[2] = v[2];
if(max[2] < v[2])
max[2] = v[2];
v += 3;
}
}
if(volume) {
/*
if(min[0] > volume[0]) min[0] = volume[0];
if(max[0] < volume[1]) max[0] = volume[1];
if(min[1] > volume[2]) min[1] = volume[2];
if(max[1] < volume[3]) max[1] = volume[3];
if(min[2] > (-volume[5])) min[2] = (-volume[5]);
if(max[2] < (-volume[4])) max[2] = (-volume[4]);
*/
if(min[0] < volume[0])
min[0] = volume[0];
if(max[0] > volume[1])
max[0] = volume[1];
if(min[1] < volume[2])
min[1] = volume[2];
if(max[1] > volume[3])
max[1] = volume[3];
if(min[2] > (-volume[5]))
min[2] = (-volume[5]);
if(max[2] < (-volume[4]))
max[2] = (-volume[4]);
PRINTFB(I->G, FB_Ray, FB_Debugging)
" BasisMakeMap: (%8.3f,%8.3f),(%8.3f,%8.3f),(%8.3f,%8.3f)\n",
volume[0], volume[1], volume[2], volume[3], volume[4], volume[5]
ENDFB(I->G);
}
/* don't break up space unnecessarily if we only have a few vertices... */
if(I->NVertex) {
l1 = (float) fabs(max[0] - min[0]);
l2 = (float) fabs(max[1] - min[1]);
if(l1 < l2)
l1 = l2;
l2 = (float) fabs(max[2] - min[2]);
if(l1 < l2)
l1 = l2;
if(l1 < kR_SMALL4)
l1 = 100.0;
if(I->NVertex < (l1 / sep))
sep = (l1 / I->NVertex);
}
if(Feedback(I->G, FB_Ray, FB_Debugging)) {
dump3f(min, " BasisMakeMap: min");
dump3f(max, " BasisMakeMap: max");
dump3f(I->Vertex, " BasisMakeMap: I->Vertex");
fflush(stdout);
}
sep = MapGetSeparation(I->G, sep, max, min, diagonal); /* this needs to be a minimum
* estimate of the actual value */
/* here we have to carry out a complicated work-around in order to
* efficiently encode our primitives into the map in a way that doesn't
* require expanding the map cutoff to the size of the largest object*/
if(remapMode) {
int a, b, c;
if(sep < size_hint) /* this keeps us from wasting time & memory on unnecessary subdivision */
sep = size_hint;
{
int *vert2prim_a = vert2prim;
for(a = 0; a < I->NVertex; a++) {
prm = prim + *(vert2prim_a++);
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
if(a == prm->vert) { /* only do this calculation for one of the three vertices */
l1 = (float) length3f(I->Precomp + I->Vert2Normal[a] * 3);
l2 = (float) length3f(I->Precomp + I->Vert2Normal[a] * 3 + 3);
if((l1 >= sep) || (l2 >= sep)) {
b = (int) ceil(l1 / sep) + 1;
c = (int) ceil(l2 / sep) + 1;
extra_vert += 4 * b * c;
}
}
break;
case cPrimCone:
case cPrimCylinder:
case cPrimSausage:
if((prm->l1 + 2 * prm->r1) >= sep) {
q = ((int) (2 * (floor(prm->r1 / sep) + 1))) + 1;
q = q * q * ((int) ceil((prm->l1 + 2 * prm->r1) / sep) + 2);
extra_vert += q;
}
break;
case cPrimEllipsoid:
case cPrimSphere:
if(prm->r1 >= sep) {
b = (int) (2 * floor(prm->r1 / sep) + 1);
extra_vert += (b * b * b);
}
break;
}
} /* for */
}
extra_vert += I->NVertex;
if (ok)
tempVertex =
CacheAlloc(I->G, float, extra_vert * 3, group_id, cCache_basis_tempVertex);
CHECKOK(ok, tempVertex);
if (ok)
tempRef = CacheAlloc(I->G, int, extra_vert, group_id, cCache_basis_tempRef);
CHECKOK(ok, tempRef);
ErrChkPtr(I->G, tempVertex); /* can happen if extra vert is unreasonable */
ErrChkPtr(I->G, tempRef);
/* lower indexes->flags, top is ref->lower index */
ok &= !I->G->Interrupt;
if (ok){
float *vv, *d;
int *vert2prim_a = vert2prim;
n = I->NVertex;
v = tempVertex;
vv = I->Vertex;
memcpy(v, vv, n * sizeof(float) * 3);
vv += n * 3;
v += n * 3;
for(a = 0; ok && a < I->NVertex; a++) {
prm = prim + *(vert2prim_a++);
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
if(a == prm->vert) {
/* only do this calculation for one of the three vertices */
d1 = I->Precomp + I->Vert2Normal[a] * 3;
d2 = I->Precomp + I->Vert2Normal[a] * 3 + 3;
vv = I->Vertex + a * 3;
l1 = (float) length3f(d1);
l2 = (float) length3f(d2);
if((l1 >= sep) || (l2 >= sep)) {
b = (int) floor(l1 / sep) + 1;
c = (int) floor(l2 / sep) + 1;
extra_vert += b * c;
bh = (float) (b / 2) + 1;
ch = (float) (c / 2) + 1;
for(x = 0; x < bh; x++) {
const float xb = (float) x / b;
for(y = 0; y < ch; y++) {
const float yc = (float) y / c;
*(v++) = vv[0] + (d1[0] * xb) + (d2[0] * yc);
*(v++) = vv[1] + (d1[1] * xb) + (d2[1] * yc);
*(v++) = vv[2] + (d1[2] * xb) + (d2[2] * yc);
tempRef[n++] = a;
}
}
for(x = 0; x < bh; x++) {
const float xb = (float) x / b;
for(y = 0; y < ch; y++) {
const float yc = (float) y / c;
if((xb + yc) < _p5) {
*(v++) = vv[0] + d1[0] * (_p5 + xb) + (d2[0] * yc);
*(v++) = vv[1] + d1[1] * (_p5 + xb) + (d2[1] * yc);
*(v++) = vv[2] + d1[2] * (_p5 + xb) + (d2[2] * yc);
tempRef[n++] = a;
*(v++) = vv[0] + (d1[0] * xb) + d2[0] * (_p5 + yc);
*(v++) = vv[1] + (d1[1] * xb) + d2[1] * (_p5 + yc);
*(v++) = vv[2] + (d1[2] * xb) + d2[2] * (_p5 + yc);
tempRef[n++] = a;
}
}
}
}
} /* if */
break;
case cPrimCone:
case cPrimCylinder:
case cPrimSausage:
ll = prm->l1 + 2 * prm->r1;
if(ll >= sep) {
d = I->Normal + 3 * I->Vert2Normal[a];
vv = I->Vertex + a * 3;
get_system1f3f(d, cx, cy); /* creates an orthogonal system about d */
p[0] = vv[0] - d[0] * prm->r1;
p[1] = vv[1] - d[1] * prm->r1;
p[2] = vv[2] - d[2] * prm->r1;
dd[0] = d[0] * sep;
dd[1] = d[1] * sep;
dd[2] = d[2] * sep;
q = (int) floor(prm->r1 / sep) + 1;
while(1) {
vd[0] = (p[0] += dd[0]);
vd[1] = (p[1] += dd[1]);
vd[2] = (p[2] += dd[2]);
for(x = -q; x <= q; x++) {
for(y = -q; y <= q; y++) {
xs = x * sep;
ys = y * sep;
*(v++) = vd[0] + xs * cx[0] + ys * cy[0];
*(v++) = vd[1] + xs * cx[1] + ys * cy[1];
*(v++) = vd[2] + xs * cx[2] + ys * cy[2];
tempRef[n++] = a;
}
}
if(ll <= _0)
break;
ll -= sep;
}
}
break;
case cPrimEllipsoid:
case cPrimSphere:
if(prm->r1 >= sep) {
q = (int) floor(prm->r1 / sep);
vv = I->Vertex + a * 3;
for(x = -q; x <= q; x++) {
for(y = -q; y <= q; y++) {
for(z = -q; z <= q; z++) {
*(v++) = vv[0] + x * sep;
*(v++) = vv[1] + y * sep;
*(v++) = vv[2] + z * sep;
tempRef[n++] = a;
}
}
}
}
break;
} /* end of switch */
ok &= !I->G->Interrupt;
}
}
if(n > extra_vert) {
printf("BasisMakeMap: %d>%d\n", n, extra_vert);
ErrFatal(I->G, "BasisMakeMap",
"used too many extra vertices (this indicates a bug)...\n");
}
PRINTFB(I->G, FB_Ray, FB_Blather)
" BasisMakeMap: %d total vertices\n", n ENDFB(I->G);
if (ok){
if(volume) {
v = tempVertex;
min[0] = max[0] = v[0];
min[1] = max[1] = v[1];
min[2] = max[2] = v[2];
v += 3;
if(Feedback(I->G, FB_Ray, FB_Debugging)) {
dump3f(min, " BasisMakeMap: remapped min");
dump3f(max, " BasisMakeMap: remapped max");
fflush(stdout);
}
for(a = 1; a < n; a++) {
if(min[0] > v[0])
min[0] = v[0];
if(max[0] < v[0])
max[0] = v[0];
if(min[1] > v[1])
min[1] = v[1];
if(max[1] < v[1])
max[1] = v[1];
if(min[2] > v[2])
min[2] = v[2];
if(max[2] < v[2])
max[2] = v[2];
v += 3;
}
if(Feedback(I->G, FB_Ray, FB_Debugging)) {
dump3f(min, " BasisMakeMap: remapped min");
dump3f(max, " BasisMakeMap: remapped max");
fflush(stdout);
}
if(min[0] < volume[0])
min[0] = volume[0];
if(max[0] > volume[1])
max[0] = volume[1];
if(min[1] < volume[2])
min[1] = volume[2];
if(max[1] > volume[3])
max[1] = volume[3];
if(min[2] < (-volume[5]))
min[2] = (-volume[5]);
if(max[2] > (-volume[4]))
max[2] = (-volume[4]);
extent[0] = min[0];
extent[1] = max[0];
extent[2] = min[1];
extent[3] = max[1];
extent[4] = min[2];
extent[5] = max[2];
PRINTFB(I->G, FB_Ray, FB_Blather)
" BasisMakeMap: Extent [%8.2f %8.2f] [%8.2f %8.2f] [%8.2f %8.2f]\n",
extent[0], extent[1], extent[2], extent[3], extent[4], extent[5]
ENDFB(I->G);
I->Map = MapNewCached(I->G, -sep, tempVertex, n, extent, group_id, block_base);
CHECKOK(ok, I->Map);
} else {
I->Map = MapNewCached(I->G, sep, tempVertex, n, NULL, group_id, block_base);
CHECKOK(ok, I->Map);
}
}
if (ok)
n_voxel = I->Map->Dim[0] * I->Map->Dim[1] * I->Map->Dim[2];
if (!ok){
} else if(perspective) {
/* this is a new optimization which prevents primitives
contained entirely within a single voxel from spilling over
into neighboring voxels for performance of intersection
checks (NOTE: this currently only helps with triangles, and
is only useful in optimizing between Z layers). The main
impact of this optimization is to reduce the size of the
express list (I->Map->Elist) array by about 3-fold */
int *prm_spanner = NULL;
int *spanner = NULL;
float *v = tempVertex;
int j, k, l, jj, kk, ll;
int nVertex = I->NVertex;
int prm_index;
MapType *map = I->Map;
prm_spanner = Calloc(int, n_prim);
CHECKOK(ok, prm_spanner);
if (ok)
spanner = Calloc(int, n);
CHECKOK(ok, spanner);
/* figure out which primitives span more than one voxel */
for(a = 0; ok && a < n; a++) {
if(a < nVertex)
prm_index = vert2prim[a];
else
prm_index = vert2prim[tempRef[a]];
if(!prm_spanner[prm_index]) {
prm = prim + prm_index;
{
float *vv = prm->vert * 3 + I->Vertex;
switch (prm->type) {
case cPrimTriangle:
case cPrimCharacter:
MapLocus(map, v, &j, &k, &l);
MapLocus(map, vv, &jj, &kk, &ll);
if((j != jj) || (k != kk) || (l != ll)) {
prm_spanner[prm_index] = 1;
}
break;
default: /* currently we aren't optimizing other primitives */
prm_spanner[prm_index] = 1;
break;
}
}
}
v += 3;
ok &= !I->G->Interrupt;
}
/* now flag associated vertices */
for(a = 0; ok && a < n; a++) {
if(a < nVertex)
prm_index = vert2prim[a];
else
prm_index = vert2prim[tempRef[a]];
spanner[a] = prm_spanner[prm_index];
ok &= !I->G->Interrupt;
}
/* and do the optimized expansion */
ok &= MapSetupExpressPerp(I->Map, tempVertex, front, n, true, spanner);
FreeP(spanner);
FreeP(prm_spanner);
} else if(n_voxel < (3 * n)) {
ok &= MapSetupExpressXY(I->Map, n, true);
} else {
ok &= MapSetupExpressXYVert(I->Map, tempVertex, n, true);
}
if (ok) {
MapType *map = I->Map;
int *sp, *ip, *ip0, ii;
int *elist = map->EList, *ehead = map->EHead;
int *elist_new = elist, *ehead_new = ehead;
int newelem = 0, neelem = -map->NEElem;
int i_nVertex = I->NVertex;
const int iMin0 = map->iMin[0];
const int iMin1 = map->iMin[1];
const int iMin2 = map->iMin[2];
const int iMax0 = map->iMax[0];
const int iMax1 = map->iMax[1];
const int iMax2 = map->iMax[2];
/* now do a filter-reassignment pass to remap fake vertices
to the original line vertex while deleting duplicate entries */
memset(tempRef, 0, sizeof(int) * i_nVertex);
if(n_voxel < (3 * n)) { /* faster to traverse the entire map */
int *start;
for(a = iMin0; a <= iMax0; a++) {
for(b = iMin1; b <= iMax1; b++) {
for(c = iMin2; c <= iMax2; c++) {
start = MapEStart(map, a, b, c);
h = *start;
if((h < 0) && (h >= neelem)) {
sp = elist - h;
*(start) = -h; /* flip sign */
i = *(sp++);
if(ehead_new != ehead) {
ehead_new[(start - ehead) - 1] = newelem;
ip = ip0 = (elist_new + newelem);
} else {
ip = ip0 = (sp - 1);
}
while(i >= 0) {
int ii = *(sp++);
if(i >= i_nVertex) /* reference -- remap */
i = tempRef[i];
if(!tempRef[i]) { /*eliminate duplicates */
tempRef[i] = 1;
*(ip++) = i;
}
i = ii;
}
*(ip++) = -1; /* terminate list */
newelem += (ip - ip0);
/* now reset flags efficiently */
i = *(ip0++);
while(i >= 0) { /* unroll */
ii = *(ip0++);
tempRef[i] = 0;
if((i = ii) >= 0) {
ii = *(ip0++);
tempRef[i] = 0;
if((i = ii) >= 0) {
ii = *(ip0++);
tempRef[i] = 0;
i = ii;
}
}
}
}
} /* for c */
} /* for b */
} /* for a */
} else {
int *start;
int jm1, jp1, km1, kp1, lm1, lp1;
MapType *map = I->Map;
v = tempVertex;
for(e = 0; e < n; e++) {
MapLocus(map, v, &j, &k, &l);
jm1 = j - 1;
jp1 = j + 1;
km1 = k - 1;
kp1 = k + 1;
lm1 = l - 1;
lp1 = l + 1;
if(perspective) { /* for normal maps */
int *iPtr1 =
map->EHead + ((j - 1) * map->D1D2) + ((k - 1) * map->Dim[2]) + (l - 1);
for(a = jm1; a <= jp1; a++) {
int *iPtr2 = iPtr1;
if((a >= iMin0) && (a <= iMax0)) {
for(b = km1; b <= kp1; b++) {
int *iPtr3 = iPtr2;
if((b >= iMin1) && (b <= iMax1)) {
for(c = lm1; c <= lp1; c++) {
if((c >= iMin2) && (c <= iMax2)) {
start = iPtr3;
/*start = MapEStart(map,a,b,c); */
h = *start;
if((h < 0) && (h >= neelem)) {
sp = elist - h;
(*start) = -h; /* no repeat visits */
i = *(sp++);
if(ehead_new != ehead) {
ehead_new[(start - ehead)] = newelem;
ip = ip0 = (elist_new + newelem);
} else {
ip = ip0 = (sp - 1);
}
while(i >= 0) {
int ii = *(sp++);
if(i >= i_nVertex)
i = tempRef[i];
if(!tempRef[i]) { /*eliminate duplicates */
tempRef[i] = 1;
*(ip++) = i;
}
i = ii;
}
*(ip++) = -1; /* terminate list */
newelem += (ip - ip0);
/* now reset flags efficiently */
i = *(ip0++);
while(i >= 0) { /* unroll */
ii = *(ip0++);
tempRef[i] = 0;
if((i = ii) >= 0) {
ii = *(ip0++);
tempRef[i] = 0;
if((i = ii) >= 0) {
ii = *(ip0++);
tempRef[i] = 0;
i = ii;
}
}
}
} /* h > 0 */
}
iPtr3++;
}
}
iPtr2 += map->Dim[2];
}
}
iPtr1 += map->D1D2;
}
} else { /* for XY maps... */
c = l;
{
int *iPtr1 =
ehead + ((j - 1) * map->D1D2) + ((k - 1) * map->Dim[2]) + c;
if((c >= iMin2) && (c <= iMax2)) {
for(a = jm1; a <= jp1; a++) {
int *iPtr2 = iPtr1;
if((a >= iMin0) && (a <= iMax0)) {
for(b = km1; b <= kp1; b++) {
if((b >= iMin1) && (b <= iMax1)) {
start = iPtr2;
/*start = MapEStart(map,a,b,c); */
h = *start;
if((h < 0) && (h >= neelem)) {
sp = elist - h;
(*start) = -h; /* no repeat visits */
i = *(sp++);
if(ehead_new != ehead) {
ehead_new[(start - ehead)] = newelem;
ip = ip0 = (elist_new + newelem);
} else {
ip = ip0 = sp - 1;
}
while(i >= 0) {
int ii = *(sp++);
if(i >= i_nVertex)
i = tempRef[i];
if(!tempRef[i]) { /*eliminate duplicates */
tempRef[i] = 1;
*(ip++) = i;
}
i = ii;
}
*(ip++) = -1; /* terminate list */
newelem += (ip - ip0);
/* now reset flags efficiently */
i = *(ip0++);
while(i >= 0) { /* unroll */
ii = *(ip0++);
tempRef[i] = 0;
if((i = ii) >= 0) {
ii = *(ip0++);
tempRef[i] = 0;
if((i = ii) >= 0) {
ii = *(ip0++);
tempRef[i] = 0;
i = ii;
}
}
}
} /* h > 0 */
}
iPtr2 += map->Dim[2];
} /* for b */
}
iPtr1 += map->D1D2;
} /* for a */
}
}
}
v += 3; /* happens for EVERY e! */
} /* for e */
}
if(ehead != ehead_new) {
CacheFreeP(I->G, map->EHead, group_id, block_base + cCache_map_ehead_offset,
false);
VLACacheFreeP(I->G, map->EList, group_id, block_base + cCache_map_elist_offset,
false);
map->EList = elist_new;
map->EHead = ehead_new;
map->NEElem = newelem;
MemoryCacheReplaceBlock(I->G, group_id, block_base + cCache_map_ehead_new_offset,
block_base + cCache_map_ehead_offset);
MemoryCacheReplaceBlock(I->G, group_id, block_base + cCache_map_elist_new_offset,
block_base + cCache_map_elist_offset);
VLACacheSize(G, map->EList, int, map->NEElem, group_id,
block_base + cCache_map_elist_offset);
}
}
CacheFreeP(I->G, tempVertex, group_id, cCache_basis_tempVertex, false);
CacheFreeP(I->G, tempRef, group_id, cCache_basis_tempRef, false);
} else {
/* simple sphere mode */
I->Map = MapNewCached(I->G, -sep, I->Vertex, I->NVertex, NULL, group_id, block_base);
CHECKOK(ok, I->Map);
if (ok){
if(perspective) {
ok &= MapSetupExpressPerp(I->Map, I->Vertex, front, I->NVertex, false, NULL);
} else {
ok &= MapSetupExpressXYVert(I->Map, I->Vertex, I->NVertex, false);
}
}
}
return ok;
}
/*========================================================================*/
int BasisInit(PyMOLGlobals * G, CBasis * I, int group_id)
{
int ok = true;
I->G = G;
I->Radius = NULL;
I->Radius2 = NULL;
I->Normal = NULL;
I->Vert2Normal = NULL;
I->Precomp = NULL;
I->Vertex = VLACacheAlloc(I->G, float, 1, group_id, cCache_basis_vertex);
CHECKOK(ok, I->Vertex);
if (ok)
I->Radius = VLACacheAlloc(I->G, float, 1, group_id, cCache_basis_radius);
CHECKOK(ok, I->Radius);
if (ok)
I->Radius2 = VLACacheAlloc(I->G, float, 1, group_id, cCache_basis_radius2);
CHECKOK(ok, I->Radius2);
if (ok)
I->Normal = VLACacheAlloc(I->G, float, 1, group_id, cCache_basis_normal);
CHECKOK(ok, I->Normal);
if (ok)
I->Vert2Normal = VLACacheAlloc(I->G, int, 1, group_id, cCache_basis_vert2normal);
CHECKOK(ok, I->Vert2Normal);
if (ok)
I->Precomp = VLACacheAlloc(I->G, float, 1, group_id, cCache_basis_precomp);
CHECKOK(ok, I->Precomp);
I->Map = NULL;
I->NVertex = 0;
I->NNormal = 0;
return ok;
}
/*========================================================================*/
void BasisFinish(CBasis * I, int group_id)
{
if(I->Map) {
MapFree(I->Map);
I->Map = NULL;
}
VLACacheFreeP(I->G, I->Radius2, group_id, cCache_basis_radius2, false);
VLACacheFreeP(I->G, I->Radius, group_id, cCache_basis_radius, false);
VLACacheFreeP(I->G, I->Vertex, group_id, cCache_basis_vertex, false);
VLACacheFreeP(I->G, I->Vert2Normal, group_id, cCache_basis_vert2normal, false);
VLACacheFreeP(I->G, I->Normal, group_id, cCache_basis_normal, false);
VLACacheFreeP(I->G, I->Precomp, group_id, cCache_basis_precomp, false);
I->Vertex = NULL;
}
/*========================================================================*/
void BasisTrianglePrecompute(float *v0, float *v1, float *v2, float *pre)
{
float det;
subtract3f(v1, v0, pre);
subtract3f(v2, v0, pre + 3);
det = pre[0] * pre[4] - pre[1] * pre[3];
if(fabs(det) < EPSILON)
*(pre + 6) = 0.0F;
else {
*(pre + 6) = 1.0F;
*(pre + 7) = 1.0F / det;
}
}
void BasisTrianglePrecomputePerspective(float *v0, float *v1, float *v2, float *pre)
{
subtract3f(v1, v0, pre);
subtract3f(v2, v0, pre + 3);
}
void BasisCylinderSausagePrecompute(float *dir, float *pre)
{
float ln = (float) (1.0f / sqrt1f(dir[1] * dir[1] + dir[0] * dir[0]));
pre[0] = dir[1] * ln;
pre[1] = -dir[0] * ln;
}
#else
typedef int this_file_is_no_longer_empty;
#endif