git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@3633 f3b2605a-c512-4ea7-a41b-209d697bcdaa
This commit is contained in:
@ -15,6 +15,7 @@
|
||||
Contributing author: Pieter in 't Veld (SNL)
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "math.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include "region_prism.h"
|
||||
@ -83,21 +84,45 @@ RegPrism::RegPrism(LAMMPS *lmp, int narg, char **arg) : Region(lmp, narg, arg)
|
||||
|
||||
// error check
|
||||
// prism cannot be 0 thickness in any dim, else inverse blows up
|
||||
// non-zero tilt values cannot be used if either dim is INF on both ends
|
||||
|
||||
if (xlo >= xhi || ylo >= yhi || zlo >= zhi)
|
||||
error->all("Illegal region prism command");
|
||||
|
||||
if (xy != 0.0 && xlo == -BIG && xhi == BIG)
|
||||
error->all("Illegal region prism command");
|
||||
if (xy != 0.0 && ylo == -BIG && yhi == BIG)
|
||||
error->all("Illegal region prism command");
|
||||
|
||||
if (xz != 0.0 && xlo == -BIG && xhi == BIG)
|
||||
error->all("Illegal region prism command");
|
||||
if (xz != 0.0 && zlo == -BIG && zhi == BIG)
|
||||
error->all("Illegal region prism command");
|
||||
|
||||
if (yz != 0.0 && ylo == -BIG && yhi == BIG)
|
||||
error->all("Illegal region prism command");
|
||||
if (yz != 0.0 && zlo == -BIG && zhi == BIG)
|
||||
error->all("Illegal region prism command");
|
||||
|
||||
// extent of prism
|
||||
|
||||
extent_xlo = MIN(xlo,xlo+xy);
|
||||
extent_xlo = MIN(extent_xlo,extent_xlo+xz);
|
||||
extent_ylo = MIN(ylo,ylo+yz);
|
||||
extent_zlo = zlo;
|
||||
if (interior) {
|
||||
bboxflag = 1;
|
||||
extent_xlo = MIN(xlo,xlo+xy);
|
||||
extent_xlo = MIN(extent_xlo,extent_xlo+xz);
|
||||
extent_ylo = MIN(ylo,ylo+yz);
|
||||
extent_zlo = zlo;
|
||||
|
||||
extent_xhi = MAX(xhi,xhi+xy);
|
||||
extent_xhi = MAX(extent_xhi,extent_xhi+xz);
|
||||
extent_yhi = MAX(yhi,yhi+yz);
|
||||
extent_zhi = zhi;
|
||||
} else bboxflag = 0;
|
||||
|
||||
extent_xhi = MAX(xhi,xhi+xy);
|
||||
extent_xhi = MAX(extent_xhi,extent_xhi+xz);
|
||||
extent_yhi = MAX(yhi,yhi+yz);
|
||||
extent_zhi = zhi;
|
||||
// particle could contact all 6 planes
|
||||
|
||||
cmax = 6;
|
||||
contact = new Contact[cmax];
|
||||
|
||||
// h = transformation matrix from tilt coords (0-1) to box coords (xyz)
|
||||
// columns of h are edge vectors of tilted box
|
||||
@ -119,10 +144,95 @@ RegPrism::RegPrism(LAMMPS *lmp, int narg, char **arg) : Region(lmp, narg, arg)
|
||||
hinv[1][1] = 1.0/h[1][1];
|
||||
hinv[1][2] = -h[1][2] / (h[1][1]*h[2][2]);
|
||||
hinv[2][2] = 1.0/h[2][2];
|
||||
|
||||
// corners = 8 corner points of prism
|
||||
// order = x varies fastest, then y, finally z
|
||||
// clo/chi = lo and hi corner pts of prism
|
||||
|
||||
a[0] = xhi-xlo;
|
||||
a[1] = 0.0;
|
||||
a[2] = 0.0;
|
||||
b[0] = xy;
|
||||
b[1] = yhi-ylo;
|
||||
b[2] = 0.0;
|
||||
c[0] = xz;
|
||||
c[1] = yz;
|
||||
c[2] = zhi-zlo;
|
||||
|
||||
clo[0] = corners[0][0] = xlo;
|
||||
clo[1] = corners[0][1] = ylo;
|
||||
clo[2] = corners[0][2] = zlo;
|
||||
|
||||
corners[1][0] = xlo + a[0];
|
||||
corners[1][1] = ylo + a[1];
|
||||
corners[1][2] = zlo + a[2];
|
||||
|
||||
corners[2][0] = xlo + b[0];
|
||||
corners[2][1] = ylo + b[1];
|
||||
corners[2][2] = zlo + b[2];
|
||||
|
||||
corners[3][0] = xlo + a[0] + b[0];
|
||||
corners[3][1] = ylo + a[1] + b[1];
|
||||
corners[3][2] = zlo + a[2] + b[2];
|
||||
|
||||
corners[4][0] = xlo + c[0];
|
||||
corners[4][1] = ylo + c[1];
|
||||
corners[4][2] = zlo + c[2];
|
||||
|
||||
corners[5][0] = xlo + a[0] + c[0];
|
||||
corners[5][1] = ylo + a[1] + c[1];
|
||||
corners[5][2] = zlo + a[2] + c[2];
|
||||
|
||||
corners[6][0] = xlo + b[0] + c[0];
|
||||
corners[6][1] = ylo + b[1] + c[1];
|
||||
corners[6][2] = zlo + b[2] + c[2];
|
||||
|
||||
chi[0] = corners[7][0] = xlo + a[0] + b[0] + c[0];
|
||||
chi[1] = corners[7][1] = ylo + a[1] + b[1] + c[1];
|
||||
chi[2] = corners[7][2] = zlo + a[2] + b[2] + c[2];
|
||||
|
||||
// face = 6 inward-facing unit normals to prism faces
|
||||
// order = xy plane, xz plane, yz plane
|
||||
|
||||
cross(a,b,face[0]);
|
||||
cross(b,a,face[1]);
|
||||
cross(c,a,face[2]);
|
||||
cross(a,c,face[3]);
|
||||
cross(b,c,face[4]);
|
||||
cross(c,b,face[5]);
|
||||
|
||||
for (int i = 0; i < 6; i++) normalize(face[i]);
|
||||
|
||||
// tri = 3 vertices (0-7) in each of 12 triangles on 6 faces
|
||||
// verts in each tri are ordered so that right-hand rule gives inward norm
|
||||
// order = xy plane, xz plane, yz plane
|
||||
|
||||
tri[0][0] = 0; tri[0][1] = 1; tri[0][2] = 3;
|
||||
tri[1][0] = 0; tri[1][1] = 3; tri[1][2] = 2;
|
||||
tri[2][0] = 4; tri[2][1] = 7; tri[2][2] = 5;
|
||||
tri[3][0] = 4; tri[3][1] = 6; tri[3][2] = 7;
|
||||
|
||||
tri[4][0] = 0; tri[4][1] = 4; tri[4][2] = 5;
|
||||
tri[5][0] = 0; tri[5][1] = 5; tri[5][2] = 1;
|
||||
tri[6][0] = 2; tri[6][1] = 7; tri[6][2] = 6;
|
||||
tri[7][0] = 2; tri[7][1] = 3; tri[7][2] = 7;
|
||||
|
||||
tri[8][0] = 2; tri[8][1] = 6; tri[8][2] = 4;
|
||||
tri[9][0] = 2; tri[9][1] = 4; tri[9][2] = 0;
|
||||
tri[10][0] = 1; tri[10][1] = 5; tri[10][2] = 7;
|
||||
tri[11][0] = 1; tri[11][1] = 7; tri[11][2] = 3;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
RegPrism::~RegPrism()
|
||||
{
|
||||
delete [] contact;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
check xyz against prism
|
||||
inside = 1 if x,y,z is inside or on surface
|
||||
inside = 0 if x,y,z is outside and not on surface
|
||||
abc = Hinv * (xyz - xyz/lo)
|
||||
abc = tilt coords (0-1)
|
||||
Hinv = transformation matrix from box coords to tilt coords
|
||||
@ -136,10 +246,270 @@ int RegPrism::match(double x, double y, double z)
|
||||
double b = hinv[1][1]*(y-ylo) + hinv[1][2]*(z-zlo);
|
||||
double c = hinv[2][2]*(z-zlo);
|
||||
|
||||
int inside;
|
||||
int inside = 0;
|
||||
if (a >= 0.0 && a <= 1.0 && b >= 0.0 && b <= 1.0 && c >= 0.0 && c <= 1.0)
|
||||
inside = 1;
|
||||
else inside = 0;
|
||||
|
||||
return !(inside ^ interior); // 1 if same, 0 if different
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
contact if 0 <= x < cutoff from one or more inner surfaces of prism
|
||||
can be one contact for each of 6 faces
|
||||
no contact if outside (possible if called from union/intersect)
|
||||
delxyz = vector from nearest point on prism to x
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int RegPrism::surface_interior(double *x, double cutoff)
|
||||
{
|
||||
int i;
|
||||
double dot;
|
||||
double *corner;
|
||||
|
||||
// x is exterior to prism
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (i % 2) corner = chi;
|
||||
else corner = clo;
|
||||
dot = (x[0]-corner[0])*face[i][0] + (x[1]-corner[1])*face[i][1] +
|
||||
(x[2]-corner[2])*face[i][2];
|
||||
if (dot < 0.0) return 0;
|
||||
}
|
||||
|
||||
// x is interior to prism or on its surface
|
||||
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (i % 2) corner = chi;
|
||||
else corner = clo;
|
||||
dot = (x[0]-corner[0])*face[i][0] + (x[1]-corner[1])*face[i][1] +
|
||||
(x[2]-corner[2])*face[i][2];
|
||||
if (dot < cutoff) {
|
||||
contact[n].r = dot;
|
||||
contact[n].delx = dot*face[i][0];
|
||||
contact[n].dely = dot*face[i][1];
|
||||
contact[n].delz = dot*face[i][2];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
one contact if 0 <= x < cutoff from outer surface of prism
|
||||
no contact if inside (possible if called from union/intersect)
|
||||
delxyz = vector from nearest point on prism to x
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int RegPrism::surface_exterior(double *x, double cutoff)
|
||||
{
|
||||
int i;
|
||||
double dot,delta;
|
||||
double *corner;
|
||||
double xp,yp,zp;
|
||||
|
||||
// x is far enough from prism that there is no contact
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (i % 2) corner = chi;
|
||||
else corner = clo;
|
||||
dot = (x[0]-corner[0])*face[i][0] + (x[1]-corner[1])*face[i][1] +
|
||||
(x[2]-corner[2])*face[i][2];
|
||||
if (dot <= -cutoff) return 0;
|
||||
}
|
||||
|
||||
// x is interior to prism
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
if (i % 2) corner = chi;
|
||||
else corner = clo;
|
||||
dot = (x[0]-corner[0])*face[i][0] + (x[1]-corner[1])*face[i][1] +
|
||||
(x[2]-corner[2])*face[i][2];
|
||||
if (dot <= 0.0) break;
|
||||
}
|
||||
|
||||
if (i == 6) return 0;
|
||||
|
||||
// x is exterior to prism or on its surface
|
||||
// xp,yp,zp = point on surface of prism that x is closest to
|
||||
// could be edge or corner pt of prism
|
||||
// do not add contact point if r >= cutoff
|
||||
|
||||
find_nearest(x,xp,yp,zp);
|
||||
add_contact(0,x,xp,yp,zp);
|
||||
if (contact[0].r < cutoff) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
x is exterior to prism or on its surface
|
||||
return (xp,yp,zp) = nearest pt to x that is on surface of prism
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void RegPrism::find_nearest(double *x, double &xp, double &yp, double &zp)
|
||||
{
|
||||
int i,j,k,iface;
|
||||
double xproj[3],xline[3],nearest[3];
|
||||
double dot;
|
||||
|
||||
// generate successive xnear points, one nearest to x is (xp,yp,zp)
|
||||
// loop over 6 faces and 2 triangles in each face
|
||||
// xproj = x projected to plane of triangle
|
||||
// if xproj is inside or on triangle boundary, that is xnear
|
||||
// else: loop over 3 edges of triangle
|
||||
// compute distance to edge line
|
||||
// xnear = nearest point on line to xproj, bounded by segment end pts
|
||||
|
||||
double distsq = BIG;
|
||||
|
||||
for (int itri = 0; itri < 12; itri++) {
|
||||
iface = itri/2;
|
||||
i = tri[itri][0];
|
||||
j = tri[itri][1];
|
||||
k = tri[itri][2];
|
||||
dot = (x[0]-corners[i][0])*face[iface][0] +
|
||||
(x[1]-corners[i][1])*face[iface][1] +
|
||||
(x[2]-corners[i][2])*face[iface][2];
|
||||
xproj[0] = x[0] - dot*face[iface][0];
|
||||
xproj[1] = x[1] - dot*face[iface][1];
|
||||
xproj[2] = x[2] - dot*face[iface][2];
|
||||
if (inside_tri(xproj,corners[i],corners[j],corners[k],face[iface]))
|
||||
distsq = closest(x,xproj,nearest,distsq);
|
||||
else {
|
||||
point_on_line_segment(corners[i],corners[j],xproj,xline);
|
||||
distsq = closest(x,xline,nearest,distsq);
|
||||
point_on_line_segment(corners[j],corners[k],xproj,xline);
|
||||
distsq = closest(x,xline,nearest,distsq);
|
||||
point_on_line_segment(corners[i],corners[k],xproj,xline);
|
||||
distsq = closest(x,xline,nearest,distsq);
|
||||
}
|
||||
}
|
||||
|
||||
xp = nearest[0];
|
||||
yp = nearest[1];
|
||||
zp = nearest[2];
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
test if x is inside triangle with vertices v1,v2,v3
|
||||
norm = normal to triangle, defined by right-hand rule for v1,v2,v3 ordering
|
||||
edge = edge vector of triangle
|
||||
pvec = vector from vertex to x
|
||||
xproduct = cross product of edge with pvec
|
||||
if xproduct dot norm < 0.0 for any of 3 edges, then x is outside triangle
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
int RegPrism::inside_tri(double *x, double *v1, double *v2, double *v3,
|
||||
double *norm)
|
||||
{
|
||||
double edge[3],pvec[3],xproduct[3];
|
||||
|
||||
subtract(v1,v2,edge);
|
||||
subtract(v1,x,pvec);
|
||||
cross(edge,pvec,xproduct);
|
||||
if (dotproduct(xproduct,norm) < 0.0) return 0;
|
||||
|
||||
subtract(v2,v3,edge);
|
||||
subtract(v2,x,pvec);
|
||||
cross(edge,pvec,xproduct);
|
||||
if (dotproduct(xproduct,norm) < 0.0) return 0;
|
||||
|
||||
subtract(v3,v1,edge);
|
||||
subtract(v3,x,pvec);
|
||||
cross(edge,pvec,xproduct);
|
||||
if (dotproduct(xproduct,norm) < 0.0) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
find nearest point to C on line segment A,B and return it as D
|
||||
project (C-A) onto (B-A)
|
||||
t = length of that projection, normalized by length of (B-A)
|
||||
t <= 0, C is closest to A
|
||||
t >= 1, C is closest to B
|
||||
else closest point is between A and B
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void RegPrism::point_on_line_segment(double *a, double *b,
|
||||
double *c, double *d)
|
||||
{
|
||||
double ba[3],ca[3];
|
||||
|
||||
subtract(a,b,ba);
|
||||
subtract(a,c,ca);
|
||||
double t = dotproduct(ca,ba) / dotproduct(ba,ba);
|
||||
|
||||
if (t <= 0.0) {
|
||||
d[0] = a[0];
|
||||
d[1] = a[1];
|
||||
d[2] = a[2];
|
||||
} else if (t >= 1.0) {
|
||||
d[0] = b[0];
|
||||
d[1] = b[1];
|
||||
d[2] = b[2];
|
||||
} else {
|
||||
d[0] = a[0] + t*ba[0];
|
||||
d[1] = a[1] + t*ba[1];
|
||||
d[2] = a[2] + t*ba[2];
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
double RegPrism::closest(double *x, double *near, double *nearest, double dsq)
|
||||
{
|
||||
double delx = x[0] - near[0];
|
||||
double dely = x[1] - near[1];
|
||||
double delz = x[2] - near[2];
|
||||
double rsq = delx*delx + dely*dely + delz*delz;
|
||||
if (rsq >= dsq) return dsq;
|
||||
|
||||
nearest[0] = near[0];
|
||||
nearest[1] = near[1];
|
||||
nearest[2] = near[2];
|
||||
return rsq;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
v3 = v2 - v1
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void RegPrism::subtract(double *v1, double *v2, double *v3)
|
||||
{
|
||||
v3[0] = v2[0] - v1[0];
|
||||
v3[1] = v2[1] - v1[1];
|
||||
v3[2] = v2[2] - v1[2];
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
v3 = v1 x v2
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
void RegPrism::cross(double *v1, double *v2, double *v3)
|
||||
{
|
||||
v3[0] = v1[1]*v2[2] - v1[2]*v2[1];
|
||||
v3[1] = v1[2]*v2[0] - v1[0]*v2[2];
|
||||
v3[2] = v1[0]*v2[1] - v1[1]*v2[0];
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
return dotproduct = v1 dot v2
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
double RegPrism::dotproduct(double *v1, double *v2)
|
||||
{
|
||||
return (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void RegPrism::normalize(double *x)
|
||||
{
|
||||
double invlen = 1.0/sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
|
||||
x[0] *= invlen;
|
||||
x[1] *= invlen;
|
||||
x[2] *= invlen;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user