[vtkusers] margin around polydata (expansion/extrusion)
gregthom
gregthom99 at yahoo.com
Wed Jul 22 09:04:07 EDT 2009
Hello fellow vtk users
I hvae been trying to implement a class to take polydata and expand it in x
y z directions by a given amount, sort of extrusion.
I found this reference :http://www.mlahanas.de/CompGeom/Margins.htm
Has anybody implemented this somewhere ? Is there another means of achieving
the same purpose ?
In my implementation from the above reference, I get a translation of my
polydata instead of and expansion/extrusion, Can someone take a look with me
?
Thank you:
Some code to work on:
/*=========================================================================
PURPOSE. Expands Polydata with given margins
=========================================================================*/
#ifndef __vtkPolyDataMargin_h
#define __vtkPolyDataMargin_h
#include "vtkPolyDataAlgorithm.h"
#include "vtkPolyData.h"
#include "vtkDoubleArray.h"
class vtkPolyData;
class vtkPoints;
class vtkThinPlateSplineTransform;
class vtkTransformPolyDataFilter;
class vtkGeneralTransform;
class vtkDoubleArray;
class vtkPolyDataMargin : public vtkPolyDataAlgorithm
{
public:
vtkTypeRevisionMacro(vtkPolyDataMargin,vtkPolyDataAlgorithm);
void PrintSelf(ostream& os, vtkIndent indent);
static vtkPolyDataMargin *New();
// Description:
// Set/Get the reference surface to compute distance from.
//see -> why ?
http://www.vtk.org/pipermail/vtk-developers/2002-May/001464.html
vtkSetObjectMacro(Margins,vtkDoubleArray);
vtkGetObjectMacro(Margins,vtkDoubleArray);
protected:
vtkPolyDataMargin();
~vtkPolyDataMargin();
virtual int RequestData(vtkInformation *, vtkInformationVector
**, vtkInformationVector *);
vtkPolyData *m_Input;
vtkDoubleArray *Margins;
//Object to be deformed
//vtkPolyData *Input;
//Spline transformation source points
vtkPoints *m_SourcePoints;
//Spline transformation target points
vtkPoints *m_TargetPoints;
//The Spline transformation source points
vtkThinPlateSplineTransform * m_ThinPlateTransform;
//The transformation used to rescale PTV points
vtkGeneralTransform * m_GeneralTransform;
//VTK class to perform transformation of PTV points
vtkTransformPolyDataFilter * m_TransformFilter;
//Set PTV input
//void SetInput(vtkPolyData * I);
//Constructor of objects and possible user interface
//void FormCreate();
//Deform object according to specified margins
private:
vtkPolyDataMargin(const vtkPolyDataMargin&); // Not
implemented.
void operator=(const vtkPolyDataMargin&); // Not
implemented.
};
#endif
/*=========================================================================
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "vtkPolyDataMargin.h"
#include "vtkCellLocator.h"
#include "vtkGenericCell.h"
#include "vtkPolyData.h"
#include "vtkPointData.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPoints.h"
#include "vtkThinPlateSplineTransform.h"
#include "vtkTransformPolyDataFilter.h"
#include "vtkGeneralTransform.h"
#include "vtkDoubleArray.h"
vtkCxxRevisionMacro(vtkPolyDataMargin, "$Revision: 1.3 $");
vtkStandardNewMacro(vtkPolyDataMargin);
vtkPolyDataMargin::vtkPolyDataMargin()
{
this->m_SourcePoints = NULL;
this->m_TargetPoints = NULL;
this->m_ThinPlateTransform = NULL;
this->m_GeneralTransform = NULL;
this->m_TransformFilter = NULL;
this->m_Input = NULL;
// initialize margins to zeros;
// margins are given as:
//(xm, xp) for the lower and upper x range
//(ym, yp) for the lower and upper y range
//(zm, zp) for the lower and upper z range
this->Margins = vtkDoubleArray::New();
this->Margins->SetNumberOfComponents(1);
this->Margins->SetNumberOfTuples(6);
this->Margins->FillComponent(0,0.0);
this->m_SourcePoints = vtkPoints::New();
this->m_TargetPoints = vtkPoints::New();
this->m_GeneralTransform = vtkGeneralTransform::New();
this->m_TransformFilter = vtkTransformPolyDataFilter::New();
this->m_ThinPlateTransform = vtkThinPlateSplineTransform::New();
}
vtkPolyDataMargin::~vtkPolyDataMargin()
{
if (this->m_SourcePoints)
{
this->m_SourcePoints->Delete();
this->m_SourcePoints = NULL;
}
if (this->m_TargetPoints)
{
this->m_TargetPoints->Delete();
this->m_TargetPoints = NULL;
}
if (this->m_ThinPlateTransform)
{
this->m_ThinPlateTransform->Delete();
this->m_ThinPlateTransform = NULL;
}
if (this->m_GeneralTransform)
{
this->m_GeneralTransform->Delete();
this->m_GeneralTransform = NULL;
}
if (this->m_TransformFilter)
{
this->m_TransformFilter->Delete();
this->m_TransformFilter = NULL;
}
if (this->Margins)
{
this->Margins->Delete();
this->Margins = NULL;
}
//if (this->m_Input)
//{
// this->m_Input->Delete();
// this->m_Input = NULL;
//}
}
int vtkPolyDataMargin::RequestData(vtkInformation
*vtkNotUsed(request),vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
vtkInformation *outInfo = outputVector->GetInformationObject(0);
vtkPolyData *input =
vtkPolyData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkPolyData *output =
vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
//Returns bounding box in the form (xmin, xmax, ymin, ymax, zmin, zmax)
= (b[0], b[1], b[2], b[3], b[4], b[5])
double b[6];
input->GetBounds(b);
//Take Source Points of bounding box
this->m_SourcePoints->SetNumberOfPoints( 8 );
this->m_SourcePoints->SetPoint( 0, b[0], b[3], b[5] );
this->m_SourcePoints->SetPoint( 1, b[1], b[3], b[5] );
this->m_SourcePoints->SetPoint( 2, b[0], b[3], b[4] );
this->m_SourcePoints->SetPoint( 3, b[1], b[3], b[4] );
this->m_SourcePoints->SetPoint( 4, b[0], b[2], b[5] );
this->m_SourcePoints->SetPoint( 5, b[1], b[2], b[5] );
this->m_SourcePoints->SetPoint( 6, b[0], b[2], b[4] );
this->m_SourcePoints->SetPoint( 7, b[1], b[2], b[4] );
// margins are given as:
//(xm, xp) for the lower and upper x range
//(ym, yp) for the lower and upper y range
//(zm, zp) for the lower and upper z range
unsigned int nc = this->Margins->GetNumberOfComponents();
unsigned int nt = this->Margins->GetNumberOfTuples();
double xm = this->Margins->GetTuple1(0);
double xp = this->Margins->GetTuple1(1);
double ym = this->Margins->GetTuple1(2);
double yp = this->Margins->GetTuple1(3);
double zm = this->Margins->GetTuple1(4);
double zp = this->Margins->GetTuple1(5);
//Give Coordinates of expanded bounding box
this->m_TargetPoints->SetNumberOfPoints( 8 );
this->m_TargetPoints->SetPoint( 0, b[0]+xm, b[3]+yp, b[5]+zp );
this->m_TargetPoints->SetPoint( 1, b[1]+xp, b[3]+yp, b[5]+zp );
this->m_TargetPoints->SetPoint( 2, b[0]+xm, b[3]+yp, b[4]+zm );
this->m_TargetPoints->SetPoint( 3, b[1]+xp, b[3]+yp, b[4]+zm );
this->m_TargetPoints->SetPoint( 4, b[0]+xm, b[2]+ym, b[5]+zp );
this->m_TargetPoints->SetPoint( 5, b[1]+xp, b[2]+ym, b[5]+zp );
this->m_TargetPoints->SetPoint( 6, b[0]+xm, b[2]+ym, b[4]+zm );
this->m_TargetPoints->SetPoint( 7, b[1]+xp, b[2]+ym, b[4]+zm );
//this->m_Input->DeepCopy(input);
this->m_ThinPlateTransform->SetSourceLandmarks( this->m_SourcePoints );
this->m_ThinPlateTransform->SetTargetLandmarks( this->m_TargetPoints );
this->m_GeneralTransform->SetInput( this->m_ThinPlateTransform );
this->m_GeneralTransform->Concatenate(
this->m_ThinPlateTransform->GetInverse());
this->m_GeneralTransform->Concatenate( this->m_ThinPlateTransform );
this->m_TransformFilter->SetInput(input);
this->m_TransformFilter->SetTransform( this->m_GeneralTransform);
//VTK class vtkTransformPolyDataFilter to perform transformation of
points
this->m_TransformFilter->SetInput( input );
//Update the modification time for this object. Many filters rely on the
modification time to determine if they need to recompute their data.
input->Modified();
//The Spline transformation source points vtkThinPlateSplineTransform
this->m_ThinPlateTransform->Modified();
//update filter
this->m_TransformFilter->Update();
output->DeepCopy(this->m_TransformFilter->GetOutput());
//output = this->m_TransformFilter->GetOutput();
return 1;
/*
vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
vtkInformation *outInfo = outputVector->GetInformationObject(0);
vtkPolyData *input = vtkPolyData::SafeDownCast(
inInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkPolyData *output = vtkPolyData::SafeDownCast(
outInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkIdType i, j;
vtkIdType numberOfPoints, numberOfCellPoints;
vtkIdType cellId, pointId;
int subId;
double point[3], closestPoint[3];
double distance2, distance, signedDistance;
double pcoords[3];
double pointNormal[3], *normal;
double distanceVector[3];
double *weights;
double dot;
bool computeDistance, computeDistanceVectors, computeSignedDistance;
vtkDoubleArray *distanceArray, *distanceVectorsArray,
*signedDistanceArray;
vtkDataArray *normals;
vtkCellLocator *locator;
vtkGenericCell *genericCell;
vtkCell *cell;
if (!this->ReferenceSurface)
{
vtkErrorMacro(<<"No reference surface!");
return 1;
}
if
((!this->DistanceArrayName)&&(!this->DistanceVectorsArrayName)&&(!this->SignedDistanceArrayName))
{
vtkErrorMacro(<<"No array names set!");
return 1;
}
distanceArray = vtkDoubleArray::New();
distanceVectorsArray = vtkDoubleArray::New();
signedDistanceArray = vtkDoubleArray::New();
normals = NULL;
locator = vtkCellLocator::New();
genericCell = vtkGenericCell::New();
numberOfPoints = input->GetNumberOfPoints();
computeDistance = false;
computeDistanceVectors = false;
computeSignedDistance = false;
if (this->DistanceArrayName)
{
computeDistance = true;
distanceArray->SetName(this->DistanceArrayName);
distanceArray->SetNumberOfComponents(1);
distanceArray->SetNumberOfTuples(numberOfPoints);
}
if (this->DistanceVectorsArrayName)
{
computeDistanceVectors = true;
distanceVectorsArray->SetName(this->DistanceVectorsArrayName);
distanceVectorsArray->SetNumberOfComponents(3);
distanceVectorsArray->SetNumberOfTuples(numberOfPoints);
}
if (this->SignedDistanceArrayName)
{
computeSignedDistance = true;
signedDistanceArray->SetName(this->SignedDistanceArrayName);
signedDistanceArray->SetNumberOfComponents(1);
signedDistanceArray->SetNumberOfTuples(numberOfPoints);
normals = this->ReferenceSurface->GetPointData()->GetNormals();
if (!normals)
{
vtkErrorMacro(<<"Signed distance requires point normals to be defined
over ReferenceSurface!");
return 1;
}
}
locator->SetDataSet(this->ReferenceSurface);
locator->BuildLocator();
for (i=0; i<numberOfPoints; i++)
{
input->GetPoint(i,point);
locator->FindClosestPoint(point,closestPoint,genericCell,cellId,subId,distance2);
distanceVector[0] = point[0] - closestPoint[0];
distanceVector[1] = point[1] - closestPoint[1];
distanceVector[2] = point[2] - closestPoint[2];
distance = sqrt(distance2);
if (computeDistance)
{
distanceArray->SetTuple1(i,distance);
}
if (computeDistanceVectors)
{
distanceVectorsArray->SetTuple3(i,-distanceVector[0],-distanceVector[1],-distanceVector[2]);
}
if (computeSignedDistance)
{
cell = this->ReferenceSurface->GetCell(cellId);
numberOfCellPoints = cell->GetNumberOfPoints();
weights = new double[numberOfCellPoints];
cell->EvaluatePosition(point,NULL,subId,pcoords,distance2,weights);
pointNormal[0] = 0.0;
pointNormal[1] = 0.0;
pointNormal[2] = 0.0;
for (j=0; j<numberOfCellPoints; j++)
{
pointId = cell->GetPointId(j);
normal = normals->GetTuple3(pointId);
pointNormal[0] += weights[j] * normal[0];
pointNormal[1] += weights[j] * normal[1];
pointNormal[2] += weights[j] * normal[2];
}
dot = vtkMath::Dot(distanceVector,pointNormal);
signedDistance = distance;
// distance is positive if distanceVector and normal have negative dot
if (dot>0.0)
{
signedDistance *= -1.0;
}
signedDistanceArray->SetTuple1(i,signedDistance);
delete[] weights;
}
}
output->DeepCopy(input);
if (computeDistance)
{
output->GetPointData()->AddArray(distanceArray);
}
if (computeDistanceVectors)
{
output->GetPointData()->AddArray(distanceVectorsArray);
}
if (computeSignedDistance)
{
output->GetPointData()->AddArray(signedDistanceArray);
}
distanceArray->Delete();
distanceVectorsArray->Delete();
signedDistanceArray->Delete();
locator->Delete();
genericCell->Delete();
return 1;
*/
}
void vtkPolyDataMargin::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
}
****************
Then use the above class like this :
vtkDoubleArray *margins = vtkDoubleArray::New();
margins->SetNumberOfComponents(1);
margins->SetNumberOfTuples(6);
margins->SetTuple1(0,5.0);
margins->SetTuple1(1,5.0);
margins->SetTuple1(2,5.0);
margins->SetTuple1(3,5.0);
margins->SetTuple1(4,5.0);
margins->SetTuple1(5,5.0]);
vtkPolyDataMargin * margincalculator = vtkPolyDataMargin::New();
margincalculator->SetInput(getpolydataSurfacefromsomewhere);
margincalculator->SetMargins(margins);
margincalculator->Update();
vtkPolyDataWriter* pwriter = vtkPolyDataWriter::New();
pwriter->SetInput(margincalculator->GetOutput());
pwriter->SetFileName( "testmarginexpansion.vtk" );
pwriter->Update();
PS: The above gives me a somewhat translated surface instead of an
extruded/expanded surface.
I hope to hear from someone with some insight.
GT.
--
View this message in context: http://www.nabble.com/margin-around-polydata-%28expansion-extrusion%29-tp24605713p24605713.html
Sent from the VTK - Users mailing list archive at Nabble.com.
More information about the vtkusers
mailing list