You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
442 lines
11 KiB
442 lines
11 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkSTLReader.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 "vtkSTLReader.h"
|
|
|
|
#include "vtkByteSwap.h"
|
|
#include "vtkCellArray.h"
|
|
#include "vtkCellData.h"
|
|
#include "vtkFloatArray.h"
|
|
#include "vtkMergePoints.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkInformationVector.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPolyData.h"
|
|
#include "vtkStreamingDemandDrivenPipeline.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
vtkCxxRevisionMacro(vtkSTLReader, "$Revision: 1.71 $");
|
|
vtkStandardNewMacro(vtkSTLReader);
|
|
|
|
#define VTK_ASCII 0
|
|
#define VTK_BINARY 1
|
|
|
|
// Construct object with merging set to true.
|
|
vtkSTLReader::vtkSTLReader()
|
|
{
|
|
this->FileName = NULL;
|
|
this->Merging = 1;
|
|
this->ScalarTags = 0;
|
|
this->Locator = NULL;
|
|
|
|
this->SetNumberOfInputPorts(0);
|
|
}
|
|
|
|
vtkSTLReader::~vtkSTLReader()
|
|
{
|
|
if (this->FileName)
|
|
{
|
|
delete [] this->FileName;
|
|
}
|
|
if ( this->Locator )
|
|
{
|
|
this->Locator->UnRegister(this);
|
|
this->Locator = NULL;
|
|
}
|
|
}
|
|
|
|
// Overload standard modified time function. If locator is modified,
|
|
// then this object is modified as well.
|
|
unsigned long vtkSTLReader::GetMTime()
|
|
{
|
|
unsigned long mTime1=this->Superclass::GetMTime();
|
|
unsigned long mTime2;
|
|
|
|
if (this->Locator)
|
|
{
|
|
mTime2 = this->Locator->GetMTime();
|
|
mTime1 = ( mTime1 > mTime2 ? mTime1 : mTime2 );
|
|
}
|
|
|
|
return mTime1;
|
|
}
|
|
|
|
int vtkSTLReader::RequestData(
|
|
vtkInformation *vtkNotUsed(request),
|
|
vtkInformationVector **vtkNotUsed(inputVector),
|
|
vtkInformationVector *outputVector)
|
|
{
|
|
// get the info object
|
|
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
|
|
|
// get the ouptut
|
|
vtkPolyData *output = vtkPolyData::SafeDownCast(
|
|
outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
|
|
|
FILE *fp;
|
|
vtkPoints *newPts, *mergedPts;
|
|
vtkCellArray *newPolys, *mergedPolys;
|
|
vtkFloatArray *newScalars=0, *mergedScalars=0;
|
|
|
|
// All of the data in the first piece.
|
|
if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (!this->FileName)
|
|
{
|
|
vtkErrorMacro(<<"A FileName must be specified.");
|
|
return 0;
|
|
}
|
|
|
|
// Initialize
|
|
//
|
|
if ((fp = fopen(this->FileName, "r")) == NULL)
|
|
{
|
|
vtkErrorMacro(<< "File " << this->FileName << " not found");
|
|
return 0;
|
|
}
|
|
|
|
newPts = vtkPoints::New();
|
|
newPts->Allocate(5000,10000);
|
|
newPolys = vtkCellArray::New();
|
|
newPolys->Allocate(10000,20000);
|
|
|
|
// Depending upon file type, read differently
|
|
//
|
|
if ( this->GetSTLFileType(fp) == VTK_ASCII )
|
|
{
|
|
if (ScalarTags)
|
|
{
|
|
newScalars = vtkFloatArray::New();
|
|
newScalars->Allocate(5000,10000);
|
|
}
|
|
if ( this->ReadASCIISTL(fp,newPts,newPolys,newScalars) )
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fclose(fp);
|
|
fp = fopen(this->FileName, "rb");
|
|
if ( this->ReadBinarySTL(fp,newPts,newPolys) )
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
vtkDebugMacro(<< "Read: "
|
|
<< newPts->GetNumberOfPoints() << " points, "
|
|
<< newPolys->GetNumberOfCells() << " triangles");
|
|
|
|
fclose(fp);
|
|
//
|
|
// If merging is on, create hash table and merge points/triangles.
|
|
//
|
|
if ( this->Merging )
|
|
{
|
|
int i;
|
|
vtkIdType *pts = 0;
|
|
vtkIdType nodes[3];
|
|
vtkIdType npts;
|
|
double x[3];
|
|
int nextCell=0;
|
|
|
|
mergedPts = vtkPoints::New();
|
|
mergedPts->Allocate(newPts->GetNumberOfPoints()/2);
|
|
mergedPolys = vtkCellArray::New();
|
|
mergedPolys->Allocate(newPolys->GetSize());
|
|
if (newScalars)
|
|
{
|
|
mergedScalars = vtkFloatArray::New();
|
|
mergedScalars->Allocate(newPolys->GetSize());
|
|
}
|
|
|
|
if ( this->Locator == NULL )
|
|
{
|
|
this->CreateDefaultLocator();
|
|
}
|
|
this->Locator->InitPointInsertion (mergedPts, newPts->GetBounds());
|
|
|
|
for (newPolys->InitTraversal(); newPolys->GetNextCell(npts,pts); )
|
|
{
|
|
for (i=0; i < 3; i++)
|
|
{
|
|
newPts->GetPoint(pts[i],x);
|
|
this->Locator->InsertUniquePoint(x, nodes[i]);
|
|
}
|
|
|
|
if ( nodes[0] != nodes[1] &&
|
|
nodes[0] != nodes[2] &&
|
|
nodes[1] != nodes[2] )
|
|
{
|
|
mergedPolys->InsertNextCell(3,nodes);
|
|
if (newScalars)
|
|
{
|
|
mergedScalars->InsertNextValue(newScalars->GetValue(nextCell));
|
|
}
|
|
}
|
|
nextCell++;
|
|
}
|
|
|
|
newPts->Delete();
|
|
newPolys->Delete();
|
|
if (newScalars)
|
|
{
|
|
newScalars->Delete();
|
|
}
|
|
|
|
vtkDebugMacro(<< "Merged to: "
|
|
<< mergedPts->GetNumberOfPoints() << " points, "
|
|
<< mergedPolys->GetNumberOfCells() << " triangles");
|
|
}
|
|
else
|
|
{
|
|
mergedPts = newPts;
|
|
mergedPolys = newPolys;
|
|
mergedScalars = newScalars;
|
|
}
|
|
//
|
|
// Update ourselves
|
|
//
|
|
output->SetPoints(mergedPts);
|
|
mergedPts->Delete();
|
|
|
|
output->SetPolys(mergedPolys);
|
|
mergedPolys->Delete();
|
|
|
|
if (mergedScalars)
|
|
{
|
|
output->GetCellData()->SetScalars(mergedScalars);
|
|
mergedScalars->Delete();
|
|
}
|
|
|
|
if (this->Locator)
|
|
{
|
|
this->Locator->Initialize(); //free storage
|
|
}
|
|
|
|
output->Squeeze();
|
|
|
|
return 1;
|
|
}
|
|
|
|
int vtkSTLReader::ReadBinarySTL(FILE *fp, vtkPoints *newPts,
|
|
vtkCellArray *newPolys)
|
|
{
|
|
int i, numTris;
|
|
vtkIdType pts[3];
|
|
unsigned long ulint;
|
|
unsigned short ibuff2;
|
|
char header[81];
|
|
typedef struct {float n[3], v1[3], v2[3], v3[3];} facet_t;
|
|
facet_t facet;
|
|
|
|
vtkDebugMacro(<< " Reading BINARY STL file");
|
|
|
|
// File is read to obtain raw information as well as bounding box
|
|
//
|
|
fread (header, 1, 80, fp);
|
|
fread (&ulint, 1, 4, fp);
|
|
vtkByteSwap::Swap4LE(&ulint);
|
|
|
|
// Many .stl files contain bogus count. Hence we will ignore and read
|
|
// until end of file.
|
|
//
|
|
if ( (numTris = (int) ulint) <= 0 )
|
|
{
|
|
vtkDebugMacro(<< "Bad binary count: attempting to correct ("
|
|
<< numTris << ")");
|
|
}
|
|
|
|
for ( i=0; fread(&facet,48,1,fp) > 0; i++ )
|
|
{
|
|
fread(&ibuff2,2,1,fp); //read extra junk
|
|
|
|
vtkByteSwap::Swap4LE (facet.n);
|
|
vtkByteSwap::Swap4LE (facet.n+1);
|
|
vtkByteSwap::Swap4LE (facet.n+2);
|
|
|
|
vtkByteSwap::Swap4LE (facet.v1);
|
|
vtkByteSwap::Swap4LE (facet.v1+1);
|
|
vtkByteSwap::Swap4LE (facet.v1+2);
|
|
pts[0] = newPts->InsertNextPoint(facet.v1);
|
|
|
|
vtkByteSwap::Swap4LE (facet.v2);
|
|
vtkByteSwap::Swap4LE (facet.v2+1);
|
|
vtkByteSwap::Swap4LE (facet.v2+2);
|
|
pts[1] = newPts->InsertNextPoint(facet.v2);
|
|
|
|
vtkByteSwap::Swap4LE (facet.v3);
|
|
vtkByteSwap::Swap4LE (facet.v3+1);
|
|
vtkByteSwap::Swap4LE (facet.v3+2);
|
|
pts[2] = newPts->InsertNextPoint(facet.v3);
|
|
|
|
newPolys->InsertNextCell(3,pts);
|
|
|
|
if ( (i % 5000) == 0 && i != 0 )
|
|
{
|
|
vtkDebugMacro(<< "triangle# " << i);
|
|
this->UpdateProgress((i%50000)/50000.0);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int vtkSTLReader::ReadASCIISTL(FILE *fp, vtkPoints *newPts,
|
|
vtkCellArray *newPolys, vtkFloatArray *scalars)
|
|
{
|
|
char line[256];
|
|
float x[3];
|
|
vtkIdType pts[3];
|
|
int done;
|
|
int currentSolid = 0;
|
|
|
|
vtkDebugMacro(<< " Reading ASCII STL file");
|
|
|
|
// Ingest header and junk to get to first vertex
|
|
//
|
|
fgets (line, 255, fp);
|
|
|
|
done = (fscanf(fp,"%s %*s %f %f %f\n", line, x, x+1, x+2)==EOF);
|
|
|
|
// Go into loop, reading facet normal and vertices
|
|
//
|
|
// while (fscanf(fp,"%*s %*s %f %f %f\n", x, x+1, x+2)!=EOF)
|
|
while (!done)
|
|
{
|
|
//if (ctr>=253840) {
|
|
// fprintf(stdout, "Reading record %d\n", ctr);
|
|
//}
|
|
//ctr += 7;
|
|
fgets (line, 255, fp);
|
|
fscanf (fp, "%*s %f %f %f\n", x,x+1,x+2);
|
|
pts[0] = newPts->InsertNextPoint(x);
|
|
fscanf (fp, "%*s %f %f %f\n", x,x+1,x+2);
|
|
pts[1] = newPts->InsertNextPoint(x);
|
|
fscanf (fp, "%*s %f %f %f\n", x,x+1,x+2);
|
|
pts[2] = newPts->InsertNextPoint(x);
|
|
fgets (line, 255, fp); // end loop
|
|
fgets (line, 255, fp); // end facet
|
|
|
|
newPolys->InsertNextCell(3,pts);
|
|
if (scalars)
|
|
{
|
|
scalars->InsertNextValue(currentSolid);
|
|
}
|
|
|
|
if ( (newPolys->GetNumberOfCells() % 5000) == 0 )
|
|
{
|
|
vtkDebugMacro(<< "triangle# " << newPolys->GetNumberOfCells());
|
|
this->UpdateProgress((newPolys->GetNumberOfCells()%50000)/50000.0);
|
|
}
|
|
done = (fscanf(fp,"%s", line)==EOF);
|
|
if ((strcmp(line, "ENDSOLID") == 0) || (strcmp(line, "endsolid") == 0))
|
|
{
|
|
currentSolid++;
|
|
fgets(line, 255, fp);
|
|
done = feof(fp);
|
|
while ((strstr(line, "SOLID") == 0) && (strstr(line, "solid") == 0) && !done)
|
|
{
|
|
fgets(line, 255, fp);
|
|
done = feof(fp);
|
|
}
|
|
|
|
done = (fscanf(fp,"%s", line)==EOF);
|
|
}
|
|
if (!done) {
|
|
done = (fscanf(fp,"%*s %f %f %f\n", x, x+1, x+2)==EOF);
|
|
}
|
|
}
|
|
//fprintf(stdout, "Maximum ctr val %d\n", ctr);
|
|
return 0;
|
|
}
|
|
|
|
int vtkSTLReader::GetSTLFileType(FILE *fp)
|
|
{
|
|
unsigned char header[256];
|
|
int type, i;
|
|
int numChars;
|
|
|
|
// Read a little from the file to figure what type it is.
|
|
//
|
|
// skip 255 characters so we are past any first line comment */
|
|
numChars = static_cast<int>(fread ((unsigned char *)header, 1, 255, fp));
|
|
for (i = 0, type=VTK_ASCII; i< numChars && type == VTK_ASCII; i++) // don't test \0
|
|
{
|
|
if (header[i] > 127)
|
|
{
|
|
type = VTK_BINARY;
|
|
}
|
|
}
|
|
|
|
// Reset file for reading
|
|
//
|
|
rewind (fp);
|
|
return type;
|
|
}
|
|
|
|
// Specify a spatial locator for merging points. By
|
|
// default an instance of vtkMergePoints is used.
|
|
void vtkSTLReader::SetLocator(vtkPointLocator *locator)
|
|
{
|
|
if ( this->Locator == locator )
|
|
{
|
|
return;
|
|
}
|
|
if ( this->Locator )
|
|
{
|
|
this->Locator->UnRegister(this);
|
|
this->Locator = NULL;
|
|
}
|
|
if ( locator )
|
|
{
|
|
locator->Register(this);
|
|
}
|
|
this->Locator = locator;
|
|
this->Modified();
|
|
}
|
|
|
|
void vtkSTLReader::CreateDefaultLocator()
|
|
{
|
|
if ( this->Locator == NULL )
|
|
{
|
|
this->Locator = vtkMergePoints::New();
|
|
this->Locator->Register(this);
|
|
this->Locator->Delete();
|
|
}
|
|
}
|
|
|
|
void vtkSTLReader::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "File Name: "
|
|
<< (this->FileName ? this->FileName : "(none)") << "\n";
|
|
|
|
os << indent << "Merging: " << (this->Merging ? "On\n" : "Off\n");
|
|
os << indent << "ScalarTags: " << (this->ScalarTags ? "On\n" : "Off\n");
|
|
if ( this->Locator )
|
|
{
|
|
os << indent << "Locator: " << this->Locator << "\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Locator: (none)\n";
|
|
}
|
|
}
|
|
|