Commit e7b39312 authored by Will Schroeder's avatar Will Schroeder Committed by Kitware Robot

Merge topic 'Unstructured-Plane-Cutter'

87a3eafb Address instability problem
3d0a8892 Addressing regression failures
51679f7d Addressing regression failures
f07455cf Anothe valid regression image
b67264b6 New regression test image
fe82cebb Fixed hierarchy delete [] memory issue
c5b89cba Created sphere tree class (vtkSphereTree)
3894dfb5 Added sphere tree for plane cutting
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Reviewed-by: Utkarsh Ayachit's avatarUtkarsh Ayachit <utkarsh.ayachit@kitware.com>
Merge-request: !2563
parents 2a071b76 87a3eafb
......@@ -381,13 +381,13 @@ void vtkBoundingBox::Scale(double s[3])
// ---------------------------------------------------------------------------
// Desciption:
// Intersect this box with the half space defined by plane.
//Returns 1 if there is intersection---which implies that the box has been modified
// Returns 1 if there is intersection---which implies that the box has been modified
// Returns 0 otherwise
// The algorithm:
// Because the change can only happens in one axis aligned direction,
// we first figure out which direction it is (stored in dir), then
// update the bounding interval in that direction based on intersection
// of the plane with the four edges
// we first figure out which direction it is (stored in dir), then
// update the bounding interval in that direction based on intersection
// of the plane with the four edges
bool vtkBoundingBox::IntersectPlane(double origin[3],double normal[3])
{
......
......@@ -111,10 +111,11 @@ public:
*/
void AddBounds(const double bounds[]);
// Desciption:
// Intersect this box with bbox. The method returns 1 if
// both boxes are valid and they do have overlap else it will return 0.
// If 0 is returned the box has not been modified
/**
* Intersect this box with bbox. The method returns 1 if
* both boxes are valid and they do have overlap else it will return 0.
* If 0 is returned the box has not been modified.
*/
int IntersectBox(const vtkBoundingBox &bbox);
/**
......@@ -122,14 +123,13 @@ public:
*/
int Intersects(const vtkBoundingBox &bbox) const;
// Desciption:
// Intersect this box with the half space defined by plane.
//Returns true if there is intersection---which implies that the box has been modified
// Returns false otherwise
/**
* Intersect this box with the half space defined by plane.
* Returns true if there is intersection---which implies that the box has been modified
* Returns false otherwise
*/
bool IntersectPlane(double origin[3],double normal[3]);
/**
* Returns 1 if the min and max points of bbox are contained
* within the bounds of this box, else returns 0.
......
......@@ -16,6 +16,7 @@
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkBoundingBox.h"
#include "vtkPlane.h"
#include <cassert>
vtkStandardNewMacro(vtkBox);
......@@ -506,6 +507,43 @@ int vtkBox::IntersectWithLine(const double bounds[6],
return 1;
}
//----------------------------------------------------------------------------
int vtkBox::
IntersectWithPlane(double bounds[6], double origin[3], double normal[3])
{
// Evaluate the eight points. If there is a sign change, then there is an
// intersection.
double p[3], d;
int x, y, z, sign=1, firstOne=1;
for (z=4; z <= 5; ++z)
{
p[2] = bounds[z];
for (y=2; y <= 3; ++y)
{
p[1] = bounds[y];
for (x=0; x <= 1; ++x)
{
p[0] = bounds[x];
d = vtkPlane::Evaluate(normal,origin,p);
if ( firstOne )
{
sign = ( d >= 0 ? 1 : -1 );
firstOne = 0;
}
if ( d == 0.0 || (sign > 0 && d < 0.0) ||
(sign < 0 && d > 0.0) )
{
return 1;
}
}//x
}//y
}//z
return 0; //no intersection
}
//----------------------------------------------------------------------------
void vtkBox::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -91,12 +91,13 @@ public:
void AddBounds(const double bounds[6]);
/**
* 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.)
* Bounding box intersection with line 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.)
*/
static char IntersectBox(double bounds[6], double origin[3], double dir[3],
double coord[3], double& t);
......@@ -119,6 +120,16 @@ public:
double x1[3], double x2[3],
int &plane1, int &plane2);
/**
* Plane intersection with the box. The plane is infinite in extent and
* defined by an origin and normal. The function indicates whether the
* plane intersects, not the particulars of intersection points and such.
* The function returns non-zero if the plane and box intersect; zero
* otherwise.
*/
static int IntersectWithPlane(double bounds[6], double origin[3],
double normal[3]);
protected:
vtkBox();
~vtkBox() VTK_OVERRIDE;
......@@ -145,5 +156,3 @@ inline void vtkBox::SetXMax(double p[3])
#endif
......@@ -127,7 +127,7 @@ void vtkDataSetCellIterator::SetDataSet(vtkDataSet *ds)
{
this->DataSet = ds;
this->CellId = 0;
cerr << "setting data set\n";
if (vtkRectilinearGrid* rg = vtkRectilinearGrid::SafeDownCast(ds))
{
SetArrayType(rg, this->Points);
......
......@@ -25,6 +25,7 @@
vtkStandardNewMacro(vtkPlane);
//-----------------------------------------------------------------------------
// Construct plane passing through origin and normal to z-axis.
vtkPlane::vtkPlane()
{
......@@ -37,11 +38,13 @@ vtkPlane::vtkPlane()
this->Origin[2] = 0.0;
}
//-----------------------------------------------------------------------------
double vtkPlane::DistanceToPlane(double x[3])
{
return this->DistanceToPlane(x, this->GetNormal(), this->GetOrigin());
}
//-----------------------------------------------------------------------------
void vtkPlane::ProjectPoint(double x[3], double origin[3],
double normal[3], double xproj[3])
{
......@@ -58,11 +61,13 @@ void vtkPlane::ProjectPoint(double x[3], double origin[3],
xproj[2] = x[2] - t * normal[2];
}
//-----------------------------------------------------------------------------
void vtkPlane::ProjectPoint(double x[3], double xproj[3])
{
this->ProjectPoint(x, this->GetOrigin(), this->GetNormal(), xproj);
}
//-----------------------------------------------------------------------------
void vtkPlane::ProjectVector(
double v[3], double vtkNotUsed(origin)[3], double normal[3],
double vproj[3])
......@@ -78,12 +83,14 @@ void vtkPlane::ProjectVector(
vproj[2] = v[2] - t * normal[2] / n2;
}
//-----------------------------------------------------------------------------
void vtkPlane::ProjectVector(double v[3], double vproj[3])
{
this->ProjectVector(v, this->GetOrigin(), this->GetNormal(), vproj);
}
//-----------------------------------------------------------------------------
void vtkPlane::Push(double distance)
{
int i;
......@@ -99,6 +106,7 @@ void vtkPlane::Push(double distance)
this->Modified();
}
//-----------------------------------------------------------------------------
// Project a point x onto plane defined by origin and normal. The
// projected point is returned in xproj. NOTE : normal NOT required to
// have magnitude 1.
......@@ -128,11 +136,13 @@ void vtkPlane::GeneralizedProjectPoint(double x[3], double origin[3],
}
}
//-----------------------------------------------------------------------------
void vtkPlane::GeneralizedProjectPoint(double x[3], double xproj[3])
{
this->GeneralizedProjectPoint(x, this->GetOrigin(), this->GetNormal(), xproj);
}
//-----------------------------------------------------------------------------
// Evaluate plane equation for point x[3].
double vtkPlane::EvaluateFunction(double x[3])
{
......@@ -141,6 +151,7 @@ double vtkPlane::EvaluateFunction(double x[3])
this->Normal[2]*(x[2]-this->Origin[2]) );
}
//-----------------------------------------------------------------------------
// Evaluate function gradient at point x[3].
void vtkPlane::EvaluateGradient(double vtkNotUsed(x)[3], double n[3])
{
......@@ -152,6 +163,7 @@ void vtkPlane::EvaluateGradient(double vtkNotUsed(x)[3], double n[3])
#define VTK_PLANE_TOL 1.0e-06
//-----------------------------------------------------------------------------
// Given a line defined by the two points p1,p2; and a plane defined by the
// normal n and point p0, compute an intersection. The parametric
// coordinate along the line is returned in t, and the coordinates of
......@@ -219,6 +231,7 @@ int vtkPlane::IntersectWithLine(double p1[3], double p2[3], double n[3],
}
}
// Accelerate plane cutting operation
namespace {
template <typename InputArrayType, typename OutputArrayType> struct CutWorker
{
......@@ -282,11 +295,13 @@ void vtkPlane::EvaluateFunction(vtkDataArray* input, vtkDataArray* output)
}
}
//-----------------------------------------------------------------------------
int vtkPlane::IntersectWithLine(double p1[3], double p2[3], double& t, double x[3])
{
return this->IntersectWithLine(p1, p2, this->GetNormal(), this->GetOrigin(), t, x);
}
//-----------------------------------------------------------------------------
void vtkPlane::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
......
......@@ -150,6 +150,7 @@ private:
void operator=(const vtkPlane&) VTK_DELETE_FUNCTION;
};
// Generally the normal should be normalized
inline double vtkPlane::Evaluate(double normal[3],
double origin[3], double x[3])
{
......@@ -157,6 +158,7 @@ inline double vtkPlane::Evaluate(double normal[3],
normal[2]*(x[2]-origin[2]);
}
// Assumes normal is normalized
inline double vtkPlane::DistanceToPlane(double x[3], double n[3], double p0[3])
{
#define vtkPlaneAbs(x) ((x)<0?-(x):(x))
......@@ -165,5 +167,3 @@ inline double vtkPlane::DistanceToPlane(double x[3], double n[3], double p0[3])
}
#endif
......@@ -197,12 +197,13 @@ void vtkSphereComputeBoundingSphere(T **spheres, vtkIdType numSpheres, T sphere[
else //no hints provided, compute an initial guess
{
T xMin[4], xMax[4], yMin[4], yMax[4], zMin[4], zMax[4];
xMin[0] = xMin[1] = xMin[2] = xMin[3] = VTK_FLOAT_MAX;
yMin[0] = yMin[1] = yMin[2] = yMin[3] = VTK_FLOAT_MAX;
zMin[0] = zMin[1] = zMin[2] = zMin[3] = VTK_FLOAT_MAX;
xMax[0] = xMax[1] = xMax[2] = xMax[3] = -VTK_FLOAT_MAX;
yMax[0] = yMax[1] = yMax[2] = yMax[3] = -VTK_FLOAT_MAX;
zMax[0] = zMax[1] = zMax[2] = zMax[3] = -VTK_FLOAT_MAX;
xMin[0] = xMin[1] = xMin[2] = VTK_FLOAT_MAX;
yMin[0] = yMin[1] = yMin[2] = VTK_FLOAT_MAX;
zMin[0] = zMin[1] = zMin[2] = VTK_FLOAT_MAX;
xMax[0] = xMax[1] = xMax[2] = -VTK_FLOAT_MAX;
yMax[0] = yMax[1] = yMax[2] = -VTK_FLOAT_MAX;
zMax[0] = zMax[1] = zMax[2] = -VTK_FLOAT_MAX;
xMin[3] = xMax[3] = yMin[3] = yMax[3] = zMin[3] = zMax[3] = 0.0;
// First part: Estimate the points furthest apart to define the largest sphere.
// Find the points that span the greatest distance on the x-y-z axes. Use these
......@@ -210,12 +211,12 @@ void vtkSphereComputeBoundingSphere(T **spheres, vtkIdType numSpheres, T sphere[
for (i=0; i<numSpheres; ++i)
{
s = spheres[i];
if ((s[0]-s[3]) < xMin[0] ) VTK_ASSIGN_SPHERE(xMin,s);
if ((s[0]+s[3]) > xMax[0] ) VTK_ASSIGN_SPHERE(xMax,s);
if ((s[1]-s[3]) < yMin[1] ) VTK_ASSIGN_SPHERE(yMin,s);
if ((s[1]+s[3]) > yMax[1] ) VTK_ASSIGN_SPHERE(yMax,s);
if ((s[2]-s[3]) < zMin[2] ) VTK_ASSIGN_SPHERE(zMin,s);
if ((s[2]+s[3]) > zMax[2] ) VTK_ASSIGN_SPHERE(zMax,s);
if ((s[0]-s[3]) < (xMin[0]-xMin[3]) ) VTK_ASSIGN_SPHERE(xMin,s);
if ((s[0]+s[3]) > (xMax[0]+xMax[3]) ) VTK_ASSIGN_SPHERE(xMax,s);
if ((s[1]-s[3]) < (yMin[1]-yMin[3]) ) VTK_ASSIGN_SPHERE(yMin,s);
if ((s[1]+s[3]) > (yMax[1]+yMax[3]) ) VTK_ASSIGN_SPHERE(yMax,s);
if ((s[2]-s[3]) < (zMin[2]-zMin[3]) ) VTK_ASSIGN_SPHERE(zMin,s);
if ((s[2]+s[3]) > (zMax[2]+zMax[3]) ) VTK_ASSIGN_SPHERE(zMax,s);
}
T xSpan = (xMax[0]+xMax[3]-xMin[0]-xMin[3])*(xMax[0]+xMax[3]-xMin[0]-xMin[3]) +
(xMax[1]+xMax[3]-xMin[1]-xMin[3])*(xMax[1]+xMax[3]-xMin[1]-xMin[3]) +
......
......@@ -41,6 +41,7 @@ SET(Module_SRCS
vtkSimpleImageToImageFilter.cxx
vtkSimpleScalarTree.cxx
vtkSpanSpace.cxx
vtkSphereTree.cxx
vtkStreamingDemandDrivenPipeline.cxx
vtkStructuredGridAlgorithm.cxx
vtkTableAlgorithm.cxx
......
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkSphereTree.h
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.
=========================================================================*/
/**
* @class vtkSphereTree
* @brief class to build and traverse sphere trees
*
* vtkSphereTree is a helper class used to build and traverse sphere
* trees. Various types of trees can be constructed for different VTK
* dataset types, as well well as different approaches to organize
* the tree into hierarchies.
*
* Typically building a complete sphere tree consists of two parts: 1)
* creating spheres for each cell in the dataset, then 2) creating an
* organizing hierarchy. The structure of the hierarchy varies depending on
* the topological characteristics of the dataset.
*
* Once the tree is constructed, various geometric operations are available
* for quickly selecting cells based on sphere tree operations; for example,
* process all cells intersecting a plane (i.e., use the sphere tree to identify
* candidate cells for plane intersection).
*
* This class does not necessarily create optimal sphere trees because
* some of its requirements (fast build time, provide simple reference
* code, a single bounding sphere per cell, etc.) precludes optimal
* performance. It is also oriented to computing on cells versus the
* classic problem of collision detection for polygonal models. For
* more information you want to read Gareth Bradshaw's PhD thesis
* "Bounding Volume Hierarchies for Level-of-Detail Collision
* Handling" which does a nice job of laying out the challenges and
* important algorithms relative to sphere trees and BVH (bounding
* volume hierarchies).
*
* @sa
* vtkSphereTreeFilter vtkPlaneCutter
*/
#ifndef vtkSphereTree_h
#define vtkSphereTree_h
#include "vtkCommonExecutionModelModule.h" // For export macro
#include "vtkPlane.h" // to specify the cutting plane
#include "vtkObject.h"
class vtkDoubleArray;
class vtkDataArray;
class vtkIdList;
class vtkDataSet;
class vtkStructuredGrid;
class vtkUnstructuredGrid;
class vtkTimeStamp;
struct vtkSphereTreeHierarchy;
#define VTK_MAX_SPHERE_TREE_RESOLUTION 10
#define VTK_MAX_SPHERE_TREE_LEVELS 20
// VTK Class proper
class VTKCOMMONEXECUTIONMODEL_EXPORT vtkSphereTree : public vtkObject
{
public:
/**
* Instantiate the sphere tree.
*/
static vtkSphereTree *New();
//@{
/**
* Standard type related macros and PrintSelf() method.
*/
vtkTypeMacro(vtkSphereTree,vtkObject);
void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE;
//@}
//@{
/**
* Specify the dataset from which to build the sphere tree.
*/
virtual void SetDataSet(vtkDataSet*);
vtkGetObjectMacro(DataSet,vtkDataSet);
//@}
//@{
/**
* Build the sphere tree (if necessary) from the data set specified. The
* build time is recorded so the sphere tree will only build if something has
* changed. An alternative method is available to both set the dataset and
* then build the sphere tree.
*/
void Build();
void Build(vtkDataSet *input);
//@}
//@{
/**
* Control whether the tree hierarchy is built. If not, then just
* cell spheres are created (one for each cell).
*/
vtkSetMacro(BuildHierarchy,int);
vtkGetMacro(BuildHierarchy,int);
vtkBooleanMacro(BuildHierarchy,int);
//@}
//@{
/**
* Methods for cell selection based on a geometric query. Internally
* different methods are used depending on the dataset type. The array
* returned is set to non-zero for each cell that intersects the geometric
* entity. SelectPoint marks all cells with a non-zero value that may
* contain a point. SelectLine marks all cells that may intersect an
* infinite line. SelectPlane marks all cells that may intersect with an
* infinite plane.
*/
const unsigned char *SelectPoint(double point[3],
vtkIdType &numSelected);
const unsigned char *SelectLine(double origin[3], double ray[3],
vtkIdType &numSelected);
const unsigned char *SelectPlane(double origin[3], double normal[3],
vtkIdType &numSelected);
//@}
//@{
/**
* Methods for cell selection based on a geometric query. Internally
* different methods are used depending on the dataset type. The method
* pupulates an vtkIdList with cell ids that may satisfy the geometric
* query (the user must provide a vtkLdList which the methods fill in).
* SelectPoint lists all cells with a non-zero value that may contain a
* point. SelectLine lists all cells that may intersect an infinite
* line. SelectPlane lists all cells that may intersect with an infinite
* plane.
*/
void SelectPoint(double point[3], vtkIdList *cellIds);
void SelectLine(double origin[3], double ray[3], vtkIdList *cellIds);
void SelectPlane(double origin[3], double normal[3], vtkIdList *cellIds);
//@}
//@{
/**
* Sphere tree creation requires gathering spheres into groups. The
* Resolution variable is a rough guide to the size of each group (the size
* different meanings depending on the type of data (structured versus
* unstructured). For example, in 3D structured data, blocks of resolution
* Resolution^3 are created. By default the Resolution is three.
*/
vtkSetClampMacro(Resolution,int,2,VTK_MAX_SPHERE_TREE_RESOLUTION);
vtkGetMacro(Resolution,int);
//@}
//@{
/**
* Specify the maximum number of levels for the tree. By default, the
* number of levels is set to ten. If the number of levels is set to one or
* less, then no hierarchy is built (i.e., just the spheres for each cell
* are created). Note that the actual level of the tree may be less than
* this value depending on the number of cells and Resolution factor.
*/
vtkSetClampMacro(MaxLevel,int,1,VTK_MAX_SPHERE_TREE_LEVELS);
vtkGetMacro(MaxLevel,int);
//@}
/**
* Get the current depth of the sphere tree. This value may change each
* time the sphere tree is built and the branching factor (i.e.,
* resolution) changes. Note that after building the sphere tree there are
* [0,this->NumberOfLevels) defined levels.
*/
vtkGetMacro(NumberOfLevels,int);
//@{
/**
* Special methods to retrieve the sphere tree data. This is
* generally used for debugging or with filters like
* vtkSphereTreeFilter. Both methods return an array of double*
* where four doubles represent a sphere (center + radius). In the
* first method a sphere per cell is returned. In the second method
* the user must also specify a level in the sphere tree (used to
* retrieve the hierarchy of the tree). Note that null pointers can
* be returned if the request is not consistent with the state of
* the sphere tree.
*/
const double *GetCellSpheres();
const double *GetTreeSpheres(int level, vtkIdType &numSpheres);
//@}
protected:
vtkSphereTree();
~vtkSphereTree() VTK_OVERRIDE;
// Data members
vtkDataSet *DataSet;
unsigned char *Selected;
int Resolution;
int MaxLevel;
int NumberOfLevels;
int BuildHierarchy;
// The tree and its hierarchy
vtkDoubleArray *Tree;
double *TreePtr;
vtkSphereTreeHierarchy *Hierarchy;
// Supporting data members
double AverageRadius; //average radius of cell sphere
double SphereBounds[6]; //the dataset bounds computed from cell spheres
vtkTimeStamp BuildTime; //time at which tree was built
// Supporting methods
vtkDoubleArray *BuildTreeSpheres(vtkDataSet *input);
void ExtractCellIds(const unsigned char *selected, vtkIdList *cellIds,
vtkIdType numSelected);
void BuildTreeHierarchy(vtkDataSet *input);
void BuildStructuredHierarchy(vtkStructuredGrid *input, double *tree);
void BuildUnstructuredHierarchy(vtkDataSet *input, double *tree);
int SphereTreeType; //keep track of the type of tree hierarchy generated
private:
vtkSphereTree(const vtkSphereTree&) VTK_DELETE_FUNCTION;
void operator=(const vtkSphereTree&) VTK_DELETE_FUNCTION;
};
#endif
......@@ -44,6 +44,7 @@ set(Module_SRCS
vtkMergeDataObjectFilter.cxx
vtkMergeFields.cxx
vtkMergeFilter.cxx
vtkPlaneCutter.cxx
vtkPointDataToCellData.cxx
vtkPolyDataConnectivityFilter.cxx
vtkPolyDataNormals.cxx
......@@ -56,6 +57,7 @@ set(Module_SRCS
vtkReverseSense.cxx
vtkSimpleElevationFilter.cxx
vtkSmoothPolyDataFilter.cxx
vtkSphereTreeFilter.cxx
vtkStripper.cxx
vtkStructuredGridOutlineFilter.cxx
vtkSynchronizedTemplates2D.cxx
......
......@@ -28,6 +28,9 @@ vtk_add_test_python(
TestProbeFilterImageInput.py
TestRectilinearSynchronizedTemplates.py
TestScalarTrees.py
TestSphereTreeFilter.py
TestSphereTreeFilter2.py
TestStructuredGridPlaneCutter.py
TestSynchronizedTemplates2D.py
TestSynchronizedTemplates3D.py
TestContourGrid.py,NO_VALID
......@@ -35,6 +38,7 @@ vtk_add_test_python(
TestTensorGlyph.py,NO_RT
TestTextureGlyph.py
TestTriangleFilter.py
TestUnstructuredGridPlaneCutter.py
TestVectorDotNorm.py
capCow.py
capSphere.py
......
#!/usr/bin/env python
import vtk
from vtk.test import Testing
from vtk.util.misc import vtkGetDataRoot
VTK_DATA_ROOT = vtkGetDataRoot()
# Control debugging parameters
res = 25
# Create the RenderWindow, Renderer
#
ren0 = vtk.vtkRenderer()
ren1 = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.SetMultiSamples(0)
renWin.AddRenderer(ren0)
renWin.AddRenderer(ren1)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
# Create a synthetic source: sample a sphere across a volume
sphere = vtk.vtkSphere()
sphere.SetCenter(0.0,0.0,0.0)
sphere.SetRadius(0.25)
sample = vtk.vtkSampleFunction()
sample.SetImplicitFunction(sphere)
sample.SetModelBounds(-0.5,0.5, -0.5,0.5, -0.5,0.5)
sample.SetSampleDimensions(res,res,res)
# Handy dandy filter converts image data to structured grid
convert = vtk.vtkImageDataToPointSet()
convert.SetInputConnection(sample.GetOutputPort())
# Create a sphere tree and see what it look like
# (structured sphere tree)
stf = vtk.vtkSphereTreeFilter()
stf.SetInputConnection(convert.GetOutputPort())
stf.SetLevel(0);
sph = vtk.vtkSphereSource()
sph.SetPhiResolution(8)
sph.SetThetaResolution(16)
sph.SetRadius(1)
stfGlyphs = vtk.vtkGlyph3D()
stfGlyphs.SetInputConnection(stf.GetOutputPort())
stfGlyphs.SetSourceConnection(sph.GetOutputPort())
stfMapper = vtk.vtkPolyDataMapper()
stfMapper.SetInputConnection(stfGlyphs.GetOutputPort())
stfMapper.ScalarVisibilityOff()
stfActor = vtk.vtkActor()
stfActor.SetMapper(stfMapper)
stfActor.GetProperty().SetColor(1,1,1)
# Throw in an outline
outline = vtk.vtkOutlineFilter()
outline.SetInputConnection(sample.GetOutputPort())
outlineMapper = vtk.vtkPolyDataMapper()
outlineMapper.SetInputConnection(outline.GetOutputPort())
outlineActor = vtk.vtkActor()
outlineActor.SetMapper(outlineMapper)
# Convert the image data to unstructured grid
extractionSphere = vtk.vtkSphere()
extractionSphere.SetRadius(100)
extractionSphere.SetCenter(0,0,0)
extract = vtk.vtkExtractGeometry()
extract.SetImplicitFunction(extractionSphere)
extract.SetInputConnection(sample.GetOutputPort())
extract.Update()
# This time around create a sphere tree, assign it to the filter, and see
# what it look like (unstructured sphere tree)
ust = vtk.vtkSphereTree()
ust.BuildHierarchyOn()
ust.Build(extract.GetOutput())
print (ust)
ustf = vtk.vtkSphereTreeFilter()
ustf.SetSphereTree(ust)
ustf.SetLevel(0);
ustfGlyphs = vtk</