/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkBox.cxx,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkBox.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkBox, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkBox); // Construct the box centered at the origin and each side length 1.0. vtkBox::vtkBox() { this->XMin[0] = -0.5; this->XMin[1] = -0.5; this->XMin[2] = -0.5; this->XMax[0] = 0.5; this->XMax[1] = 0.5; this->XMax[2] = 0.5; } // Set the bounds in various ways void vtkBox::SetBounds(double xMin, double xMax, double yMin, double yMax, double zMin, double zMax) { if ( this->XMin[0] != xMin || this->XMax[0] != xMax || this->XMin[1] != yMin || this->XMax[1] != yMax || this->XMin[2] != zMin || this->XMax[2] != yMax ) { this->XMin[0] = xMin; this->XMax[0] = xMax; this->XMin[1] = yMin; this->XMax[1] = yMax; this->XMin[2] = zMin; this->XMax[2] = zMax; for (int i=0; i<3; i++) { if ( this->XMax[i] < this->XMin[i] ) { this->XMax[i] = this->XMin[i]; } } this->Modified(); } } void vtkBox::SetBounds(double bounds[6]) { this->SetBounds(bounds[0],bounds[1], bounds[2],bounds[3], bounds[4],bounds[5]); } void vtkBox::GetBounds(double &xMin, double &xMax, double &yMin, double &yMax, double &zMin, double &zMax) { xMin = this->XMin[0]; yMin = this->XMin[1]; zMin = this->XMin[2]; xMax = this->XMax[0]; yMax = this->XMax[1]; zMax = this->XMax[2]; } void vtkBox::GetBounds(double bounds[6]) { for (int i=0; i<3; i++) { bounds[2*i] = this->XMin[i]; bounds[2*i+1] = this->XMax[i]; } } // Evaluate box equation. This differs from the similar vtkPlanes // (with six planes) because of the "rounded" nature of the corners. double vtkBox::EvaluateFunction(double x[3]) { double diff, dist, minDistance=(-VTK_DOUBLE_MAX), t, distance=0.0; int inside=1; for (int i=0; i<3; i++) { diff = this->XMax[i] - this->XMin[i]; if ( diff != 0.0 ) { t = (x[i]-this->XMin[i]) / (this->XMax[i]-this->XMin[i]); if ( t < 0.0 ) { inside = 0; dist = this->XMin[i] - x[i]; } else if ( t > 1.0 ) { inside = 0; dist = x[i] - this->XMax[i]; } else {//want negative distance, we are inside if ( t <= 0.5 ) { dist = this->XMin[i] - x[i]; } else { dist = x[i] - this->XMax[i]; } if ( dist > minDistance ) //remember, it's negative { minDistance = dist; } }//if inside } else { dist = fabs(x[i]-this->XMin[i]); if ( x[i] != this->XMin[i] ) { inside = 0; } } if ( dist > 0.0 ) { distance += dist*dist; } }//for all coordinate directions distance = sqrt(distance); if ( inside ) { return minDistance; } else { return distance; } } // Evaluate box gradient. void vtkBox::EvaluateGradient(double x[3], double n[3]) { int i, loc[3], minAxis=0; double dist, minDist=VTK_DOUBLE_MAX, center[3]; double inDir[3], outDir[3]; // Compute the location of the point with respect to the box. // Ultimately the point will lie in one of 27 separate regions around // or within the box. The gradient vector is computed differently in // each of the regions. inDir[0] = inDir[1] = inDir[2] = 0.0; outDir[0] = outDir[1] = outDir[2] = 0.0; for (i=0; i<3; i++) { center[i] = (this->XMin[i] + this->XMax[i])/2.0; if ( x[i] < this->XMin[i] ) { loc[i] = 0; outDir[i] = -1.0; } else if ( x[i] > this->XMax[i] ) { loc[i] = 2; outDir[i] = 1.0; } else { loc[i] = 1; if ( x[i] <= center[i] ) { dist = x[i] - this->XMin[i]; inDir[i] = -1.0; } else { dist = this->XMax[i] - x[i]; inDir[i] = 1.0; } if ( dist < minDist ) //remember, it's negative { minDist = dist; minAxis = i; } }//if inside }//for all coordinate directions int indx = loc[0] + 3*loc[1] + 9*loc[2]; switch (indx) { // verts - gradient points away from center point case 0: case 2: case 6: case 8: case 18: case 20: case 24: case 26: for (i=0; i<3; i++) { n[i] = x[i] - center[i]; } vtkMath::Normalize(n); break; // edges - gradient points out from axis of cube case 1: case 3: case 5: case 7: case 9: case 11: case 15: case 17: case 19: case 21: case 23: case 25: for (i=0; i<3; i++) { if ( outDir[i] != 0.0 ) { n[i] = x[i] - center[i]; } else { n[i] = 0.0; } } vtkMath::Normalize(n); break; // faces - gradient points perpendicular to face case 4: case 10: case 12: case 14: case 16: case 22: for (i=0; i<3; i++) { n[i] = outDir[i]; } break; // interior - gradient is perpendicular to closest face case 13: n[0] = n[1] = n[2] = 0.0; n[minAxis] = inDir[minAxis]; break; } } #define VTK_RIGHT 0 #define VTK_LEFT 1 #define VTK_MIDDLE 2 // Bounding box intersection modified from Graphics Gems Vol I. The method // returns a non-zero value if the bounding box is hit. Origin[3] starts // the ray, dir[3] is the vector components of the ray in the x-y-z // directions, coord[3] is the location of hit, and t is the parametric // coordinate along line. (Notes: the intersection ray dir[3] is NOT // normalized. Valid intersections will only occur between 0<=t<=1.) char vtkBox::IntersectBox (double bounds[6], double origin[3], double dir[3], double coord[3], double& t) { char inside=1; char quadrant[3]; int i, whichPlane=0; double maxT[3], candidatePlane[3]; // First find closest planes // for (i=0; i<3; i++) { if ( origin[i] < bounds[2*i] ) { quadrant[i] = VTK_LEFT; candidatePlane[i] = bounds[2*i]; inside = 0; } else if ( origin[i] > bounds[2*i+1] ) { quadrant[i] = VTK_RIGHT; candidatePlane[i] = bounds[2*i+1]; inside = 0; } else { quadrant[i] = VTK_MIDDLE; } } // Check whether origin of ray is inside bbox // if (inside) { coord[0] = origin[0]; coord[1] = origin[1]; coord[2] = origin[2]; t = 0; return 1; } // Calculate parametric distances to plane // for (i=0; i<3; i++) { if ( quadrant[i] != VTK_MIDDLE && dir[i] != 0.0 ) { maxT[i] = (candidatePlane[i]-origin[i]) / dir[i]; } else { maxT[i] = -1.0; } } // Find the largest parametric value of intersection // for (i=0; i<3; i++) { if ( maxT[whichPlane] < maxT[i] ) { whichPlane = i; } } // Check for valid intersection along line // if ( maxT[whichPlane] > 1.0 || maxT[whichPlane] < 0.0 ) { return 0; } else { t = maxT[whichPlane]; } // Intersection point along line is okay. Check bbox. // for (i=0; i<3; i++) { if (whichPlane != i) { coord[i] = origin[i] + maxT[whichPlane]*dir[i]; if ( coord[i] < bounds[2*i] || coord[i] > bounds[2*i+1] ) { return 0; } } else { coord[i] = candidatePlane[i]; } } return 1; } #undef VTK_RIGHT #undef VTK_LEFT #undef VTK_MIDDLE void vtkBox::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "XMin: (" << this->XMin[0] << ", " << this->XMin[1] << ", " << this->XMin[2] << ")\n"; os << indent << "XMax: (" << this->XMax[0] << ", " << this->XMax[1] << ", " << this->XMax[2] << ")\n"; }