/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkLinearExtrusionFilter.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 "vtkLinearExtrusionFilter.h" #include "vtkCell.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkGenericCell.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPolyData.h" vtkCxxRevisionMacro(vtkLinearExtrusionFilter, "$Revision: 1.62 $"); vtkStandardNewMacro(vtkLinearExtrusionFilter); // Create object with normal extrusion type, capping on, scale factor=1.0, // vector (0,0,1), and extrusion point (0,0,0). vtkLinearExtrusionFilter::vtkLinearExtrusionFilter() { this->ExtrusionType = VTK_NORMAL_EXTRUSION; this->Capping = 1; this->ScaleFactor = 1.0; this->Vector[0] = this->Vector[1] = 0.0; this->Vector[2] = 1.0; this->ExtrusionPoint[0] = this->ExtrusionPoint[1] = this->ExtrusionPoint[2] = 0.0; } double *vtkLinearExtrusionFilter::ViaNormal(double x[3], vtkIdType id, vtkDataArray *n) { static double xNew[3], normal[3]; int i; n->GetTuple(id, normal); for (i=0; i<3; i++) { xNew[i] = x[i] + this->ScaleFactor*normal[i]; } return xNew; } double *vtkLinearExtrusionFilter::ViaVector(double x[3], vtkIdType vtkNotUsed(id), vtkDataArray *vtkNotUsed(n)) { static double xNew[3]; int i; for (i=0; i<3; i++) { xNew[i] = x[i] + this->ScaleFactor*this->Vector[i]; } return xNew; } double *vtkLinearExtrusionFilter::ViaPoint(double x[3], vtkIdType vtkNotUsed(id), vtkDataArray *vtkNotUsed(n)) { static double xNew[3]; int i; for (i=0; i<3; i++) { xNew[i] = x[i] + this->ScaleFactor*(x[i] - this->ExtrusionPoint[i]); } return xNew; } int vtkLinearExtrusionFilter::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector) { // get the info objects vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the input and ouptut vtkPolyData *input = vtkPolyData::SafeDownCast( inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkIdType numPts, numCells; vtkPointData *pd=input->GetPointData(); vtkDataArray *inNormals=NULL; vtkPolyData *mesh; vtkPoints *inPts; vtkCellArray *inVerts, *inLines, *inPolys, *inStrips; vtkIdType inCellId, outCellId; int numEdges, dim; vtkIdType *pts = 0; vtkIdType npts = 0; vtkIdType ptId, ncells, p1, p2; int i, j; double x[3]; vtkPoints *newPts; vtkCellArray *newLines=NULL, *newPolys=NULL, *newStrips; vtkCell *edge; vtkIdList *cellIds, *cellPts; vtkPointData *outputPD = output->GetPointData(); // Here is a big pain about ordering of cells. (Copy CellData) vtkIdList *lineIds; vtkIdList *polyIds; vtkIdList *stripIds; // Initialize / check input // vtkDebugMacro(<<"Linearly extruding data"); numPts=input->GetNumberOfPoints(); numCells=input->GetNumberOfCells(); if (numPts < 1 || numCells < 1) { vtkErrorMacro(<<"No data to extrude!"); return 1; } // // Decide which vector to use for extrusion // if ( this->ExtrusionType == VTK_POINT_EXTRUSION ) { this->ExtrudePoint = &vtkLinearExtrusionFilter::ViaPoint; } else if ( this->ExtrusionType == VTK_NORMAL_EXTRUSION && (inNormals = pd->GetNormals()) != NULL ) { this->ExtrudePoint = &vtkLinearExtrusionFilter::ViaNormal; inNormals = pd->GetNormals(); } else // VTK_VECTOR_EXTRUSION { this->ExtrudePoint = &vtkLinearExtrusionFilter::ViaVector; } // Build cell data structure. // mesh = vtkPolyData::New(); inPts = input->GetPoints(); inVerts = input->GetVerts(); inLines = input->GetLines(); inPolys = input->GetPolys(); inStrips = input->GetStrips(); mesh->SetPoints(inPts); mesh->SetVerts(inVerts); mesh->SetLines(inLines); mesh->SetPolys(inPolys); mesh->SetStrips(inStrips); if (inPolys->GetNumberOfCells() || inStrips->GetNumberOfCells()) { mesh->BuildLinks(); } cellIds = vtkIdList::New(); cellIds->Allocate(VTK_CELL_SIZE); // Allocate memory for output. We don't copy normals because surface geometry // is modified. Copy all points - this is the usual requirement and it makes // creation of skirt much easier. // output->GetCellData()->CopyNormalsOff(); output->GetCellData()->CopyAllocate(input->GetCellData(), 3*input->GetNumberOfCells()); outputPD->CopyNormalsOff(); outputPD->CopyAllocate(pd,2*numPts); newPts = vtkPoints::New(); newPts->SetNumberOfPoints(2*numPts); if ( (ncells=inVerts->GetNumberOfCells()) > 0 ) { newLines = vtkCellArray::New(); newLines->Allocate(newLines->EstimateSize(ncells,2)); } // arbitrary initial allocation size ncells = inLines->GetNumberOfCells() + inPolys->GetNumberOfCells()/10 + inStrips->GetNumberOfCells()/10; ncells = (ncells < 100 ? 100 : ncells); newStrips = vtkCellArray::New(); newStrips->Allocate(newStrips->EstimateSize(ncells,4)); vtkIdType progressInterval=numPts/10+1; int abort=0; // copy points for (ptId=0; ptId < numPts; ptId++) { if ( ! (ptId % progressInterval) ) //manage progress / early abort { this->UpdateProgress (0.25*ptId/numPts); } inPts->GetPoint(ptId, x); newPts->SetPoint(ptId,x); newPts->SetPoint(ptId+numPts, (this->*(this->ExtrudePoint))(x,ptId,inNormals)); outputPD->CopyData(pd,ptId,ptId); outputPD->CopyData(pd,ptId,ptId+numPts); } // We need the cellid to copy cell data. Skip points and lines. inCellId = outCellId =0; if (input->GetVerts()) { inCellId += input->GetVerts()->GetNumberOfCells(); } if (input->GetLines()) { inCellId += input->GetLines()->GetNumberOfCells(); } // We need to keep track of input cell ids used to generate // output cells so that we can copy cell data at the end. // We do not know how many lines, polys and strips we will get // before hand. lineIds = vtkIdList::New(); polyIds = vtkIdList::New(); stripIds = vtkIdList::New(); // If capping is on, copy 2D cells to output (plus create cap) // if ( this->Capping ) { if ( inPolys->GetNumberOfCells() > 0 ) { newPolys = vtkCellArray::New(); newPolys->Allocate(inPolys->GetSize()); for ( inPolys->InitTraversal(); inPolys->GetNextCell(npts,pts); ) { newPolys->InsertNextCell(npts,pts); polyIds->InsertNextId(inCellId); newPolys->InsertNextCell(npts); for (i=0; i < npts; i++) { newPolys->InsertCellPoint(pts[i] + numPts); } polyIds->InsertNextId(inCellId); ++inCellId; } } if ( inStrips->GetNumberOfCells() > 0 ) { for ( inStrips->InitTraversal(); inStrips->GetNextCell(npts,pts); ) { newStrips->InsertNextCell(npts,pts); stripIds->InsertNextId(inCellId); newStrips->InsertNextCell(npts); for (i=0; i < npts; i++) { newStrips->InsertCellPoint(pts[i] + numPts); } stripIds->InsertNextId(inCellId); ++inCellId; } } } this->UpdateProgress (0.4); // Loop over all polygons and triangle strips searching for boundary edges. // If boundary edge found, extrude triangle strip. // progressInterval=numCells/10+1; vtkGenericCell *cell = vtkGenericCell::New(); for ( inCellId=0; inCellId < numCells && !abort; inCellId++) { if ( ! (inCellId % progressInterval) ) //manage progress / early abort { this->UpdateProgress (0.4 + 0.6*inCellId/numCells); abort = this->GetAbortExecute(); } mesh->GetCell(inCellId,cell); cellPts = cell->GetPointIds(); if ( (dim=cell->GetCellDimension()) == 0 ) //create lines from points { for (i=0; iGetNumberOfIds(); i++) { newLines->InsertNextCell(2); ptId = cellPts->GetId(i); newLines->InsertCellPoint(ptId); newLines->InsertCellPoint(ptId+numPts); lineIds->InsertNextId(inCellId); } } else if ( dim == 1 ) // create strips from lines { for (i=0; i < (cellPts->GetNumberOfIds()-1); i++) { p1 = cellPts->GetId(i); p2 = cellPts->GetId(i+1); newStrips->InsertNextCell(4); newStrips->InsertCellPoint(p1); newStrips->InsertCellPoint(p2); newStrips->InsertCellPoint(p1+numPts); newStrips->InsertCellPoint(p2+numPts); stripIds->InsertNextId(inCellId); } } else if ( dim == 2 ) // create strips from boundary edges { numEdges = cell->GetNumberOfEdges(); for (i=0; iGetEdge(i); for (j=0; j<(edge->GetNumberOfPoints()-1); j++) { p1 = edge->PointIds->GetId(j); p2 = edge->PointIds->GetId(j+1); mesh->GetCellEdgeNeighbors(inCellId, p1, p2, cellIds); if ( cellIds->GetNumberOfIds() < 1 ) //generate strip { newStrips->InsertNextCell(4); newStrips->InsertCellPoint(p1); newStrips->InsertCellPoint(p2); newStrips->InsertCellPoint(p1+numPts); newStrips->InsertCellPoint(p2+numPts); stripIds->InsertNextId(inCellId); } } //for each sub-edge } //for each edge } //for each polygon or triangle strip } //for each cell cell->Delete(); // Now Copy cell data. outCellId = 0; j = lineIds->GetNumberOfIds(); for (i = 0; i < j; ++i) { output->GetCellData()->CopyData(input->GetCellData(), lineIds->GetId(i),outCellId); ++outCellId; } j = polyIds->GetNumberOfIds(); for (i = 0; i < j; ++i) { output->GetCellData()->CopyData(input->GetCellData(), polyIds->GetId(i),outCellId); ++outCellId; } j = stripIds->GetNumberOfIds(); for (i = 0; i < j; ++i) { output->GetCellData()->CopyData(input->GetCellData(), stripIds->GetId(i),outCellId); ++outCellId; } lineIds->Delete(); stripIds->Delete(); polyIds->Delete(); polyIds = NULL; // Send data to output and release memory // output->SetPoints(newPts); newPts->Delete(); cellIds->Delete(); mesh->Delete(); if ( newLines ) { output->SetLines(newLines); newLines->Delete(); } if ( newPolys ) { output->SetPolys(newPolys); newPolys->Delete(); } output->SetStrips(newStrips); newStrips->Delete(); output->Squeeze(); return 1; } void vtkLinearExtrusionFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if ( this->ExtrusionType == VTK_VECTOR_EXTRUSION ) { os << indent << "Extrusion Type: Extrude along vector\n"; os << indent << "Vector: (" << this->Vector[0] << ", " << this->Vector[1] << ", " << this->Vector[2] << ")\n"; } else if ( this->ExtrusionType == VTK_NORMAL_EXTRUSION ) { os << indent << "Extrusion Type: Extrude along vertex normals\n"; } else //POINT_EXTRUSION { os << indent << "Extrusion Type: Extrude towards point\n"; os << indent << "Extrusion Point: (" << this->ExtrusionPoint[0] << ", " << this->ExtrusionPoint[1] << ", " << this->ExtrusionPoint[2] << ")\n"; } os << indent << "Capping: " << (this->Capping ? "On\n" : "Off\n"); os << indent << "Scale Factor: " << this->ScaleFactor << "\n"; }