1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkSTLWriter.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkSTLWriter.h"
16 
17 #include "vtkByteSwap.h"
18 #include "vtkCellArray.h"
19 #include "vtkErrorCode.h"
20 #include "vtkInformation.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkPolyData.h"
23 #include "vtkTriangle.h"
24 #include <vtksys/SystemTools.hxx>
25 
26 #if !defined(_WIN32) || defined(__CYGWIN__)
27 # include <unistd.h> /* unlink */
28 #else
29 # include <io.h> /* unlink */
30 #endif
31 
32 vtkStandardNewMacro(vtkSTLWriter);
33 
34 static char header[]="Visualization Toolkit generated SLA File                                        ";
35 
vtkSTLWriter()36 vtkSTLWriter::vtkSTLWriter()
37 {
38   this->FileType = VTK_ASCII;
39   this->FileName = NULL;
40   this->Header = new char[257];
41   strcpy(this->Header, header);
42 }
43 
WriteData()44 void vtkSTLWriter::WriteData()
45 {
46   vtkPoints *pts;
47   vtkCellArray *polys;
48   vtkPolyData *input = this->GetInput();
49 
50   polys = input->GetPolys();
51   pts = input->GetPoints();
52   if (pts == NULL || polys == NULL )
53     {
54     vtkErrorMacro(<<"No data to write!");
55     return;
56     }
57 
58   if ( this->FileName == NULL)
59     {
60     vtkErrorMacro(<< "Please specify FileName to write");
61     this->SetErrorCode(vtkErrorCode::NoFileNameError);
62     return;
63     }
64 
65   if ( this->FileType == VTK_BINARY )
66     {
67     this->WriteBinarySTL(pts,polys);
68     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
69       {
70       vtkErrorMacro("Ran out of disk space; deleting file: "
71                     << this->FileName);
72       unlink(this->FileName);
73       }
74     }
75   else
76     {
77     this->WriteAsciiSTL(pts,polys);
78     if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
79       {
80       vtkErrorMacro("Ran out of disk space; deleting file: "
81                     << this->FileName);
82       unlink(this->FileName);
83       }
84     }
85 }
86 
WriteAsciiSTL(vtkPoints * pts,vtkCellArray * polys)87 void vtkSTLWriter::WriteAsciiSTL(vtkPoints *pts, vtkCellArray *polys)
88 {
89   FILE *fp;
90   double n[3], v1[3], v2[3], v3[3];
91   vtkIdType npts = 0;
92   vtkIdType *indx = 0;
93 
94   if ((fp = fopen(this->FileName, "w")) == NULL)
95     {
96     vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
97     this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
98     return;
99     }
100 //
101 //  Write header
102 //
103   vtkDebugMacro("Writing ASCII sla file");
104   if (fprintf (fp, "solid ascii\n") < 0)
105     {
106     fclose(fp);
107     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
108     return;
109     }
110 //
111 //  Write out triangle polygons.  In not a triangle polygon, only first
112 //  three vertices are written.
113 //
114   for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
115     {
116     if (npts > 3)
117       {
118       fclose(fp);
119       vtkErrorMacro(<<"STL file only supports triangles");
120       this->SetErrorCode(vtkErrorCode::FileFormatError);
121       return;
122       }
123 
124     pts->GetPoint(indx[0],v1);
125     pts->GetPoint(indx[1],v2);
126     pts->GetPoint(indx[2],v3);
127 
128     vtkTriangle::ComputeNormal(pts, npts, indx, n);
129 
130     if (fprintf (fp, " facet normal %.6g %.6g %.6g\n  outer loop\n",
131                  n[0], n[1], n[2]) < 0)
132       {
133       fclose(fp);
134       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
135       return;
136       }
137 
138     if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v1[0], v1[1], v1[2]) < 0)
139       {
140       fclose(fp);
141       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
142       return;
143       }
144     if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v2[0], v2[1], v2[2]) < 0)
145       {
146       fclose(fp);
147       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
148       return;
149       }
150     if (fprintf (fp, "   vertex %.6g %.6g %.6g\n", v3[0], v3[1], v3[2]) < 0)
151       {
152       fclose(fp);
153       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
154       return;
155       }
156 
157     if (fprintf (fp, "  endloop\n endfacet\n") < 0)
158       {
159       fclose(fp);
160       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
161       return;
162       }
163     }
164   if (fprintf (fp, "endsolid\n") < 0)
165     {
166     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
167     }
168   fclose (fp);
169 }
170 
WriteBinarySTL(vtkPoints * pts,vtkCellArray * polys)171 void vtkSTLWriter::WriteBinarySTL(vtkPoints *pts, vtkCellArray *polys)
172 {
173   FILE *fp;
174   double dn[3], v1[3], v2[3], v3[3];
175   vtkIdType npts = 0;
176   vtkIdType *indx = 0;
177   unsigned long ulint;
178   unsigned short ibuff2=0;
179 
180   if ((fp = fopen(this->FileName, "wb")) == NULL)
181     {
182     vtkErrorMacro(<< "Couldn't open file: " << this->FileName);
183     this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
184     return;
185     }
186 
187   //  Write header
188   //
189   vtkDebugMacro("Writing Binary STL file");
190 
191   char szHeader[80+1];
192 
193   // Check for STL ASCII format key word 'solid'. According to STL file format
194   // only ASCII files can have 'solid' as start key word, so we ignore it and
195   // use VTK string instead.
196   if (vtksys::SystemTools::StringStartsWith(this->Header, "solid"))
197   {
198     vtkDebugMacro("Invalid header for Binary STL file");
199     strcpy(szHeader, header);
200   }
201   else
202   {
203     memset(szHeader, 32, 80);  // fill with space (ASCII=>32)
204     sprintf(szHeader, "%s", this->Header);
205   }
206 
207   if (fwrite (szHeader, 1, 80, fp) < 80)
208     {
209     fclose(fp);
210     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
211     return;
212     }
213 
214   ulint = (unsigned long int) polys->GetNumberOfCells();
215   vtkByteSwap::Swap4LE(&ulint);
216   if (fwrite (&ulint, 1, 4, fp) < 4)
217     {
218     fclose(fp);
219     this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
220     return;
221     }
222 
223   //  Write out triangle polygons.  In not a triangle polygon, only first
224   //  three vertices are written.
225   //
226   for (polys->InitTraversal(); polys->GetNextCell(npts,indx); )
227     {
228     if (npts > 3)
229       {
230       fclose(fp);
231       vtkErrorMacro(<<"STL file only supports triangles");
232       this->SetErrorCode(vtkErrorCode::FileFormatError);
233       return;
234       }
235 
236     pts->GetPoint(indx[0],v1);
237     pts->GetPoint(indx[1],v2);
238     pts->GetPoint(indx[2],v3);
239 
240     vtkTriangle::ComputeNormal(pts, npts, indx, dn);
241     float n[3];
242     n[0] = (float)dn[0];
243     n[1] = (float)dn[1];
244     n[2] = (float)dn[2];
245     vtkByteSwap::Swap4LE(n);
246     vtkByteSwap::Swap4LE(n+1);
247     vtkByteSwap::Swap4LE(n+2);
248     if (fwrite (n, 4, 3, fp) < 3)
249       {
250       fclose(fp);
251       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
252       return;
253       }
254 
255     n[0] = (float)v1[0];  n[1] = (float)v1[1];  n[2] = (float)v1[2];
256     vtkByteSwap::Swap4LE(n);
257     vtkByteSwap::Swap4LE(n+1);
258     vtkByteSwap::Swap4LE(n+2);
259     if (fwrite (n, 4, 3, fp) < 3)
260       {
261       fclose(fp);
262       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
263       return;
264       }
265 
266     n[0] = (float)v2[0];  n[1] = (float)v2[1];  n[2] = (float)v2[2];
267     vtkByteSwap::Swap4LE(n);
268     vtkByteSwap::Swap4LE(n+1);
269     vtkByteSwap::Swap4LE(n+2);
270     if (fwrite (n, 4, 3, fp) < 3)
271       {
272       fclose(fp);
273       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
274       return;
275       }
276 
277     n[0] = (float)v3[0];  n[1] = (float)v3[1];  n[2] = (float)v3[2];
278     vtkByteSwap::Swap4LE(n);
279     vtkByteSwap::Swap4LE(n+1);
280     vtkByteSwap::Swap4LE(n+2);
281     if (fwrite (n, 4, 3, fp) < 3)
282       {
283       fclose(fp);
284       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
285       return;
286       }
287 
288     if (fwrite (&ibuff2, 2, 1, fp) < 1)
289       {
290       fclose(fp);
291       this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
292       return;
293       }
294     }
295   fclose (fp);
296 }
297 
298 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)299 void vtkSTLWriter::PrintSelf(ostream& os, vtkIndent indent)
300 {
301   this->Superclass::PrintSelf(os,indent);
302 }
303 
304 //----------------------------------------------------------------------------
GetInput()305 vtkPolyData* vtkSTLWriter::GetInput()
306 {
307   return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
308 }
309 
310 //----------------------------------------------------------------------------
GetInput(int port)311 vtkPolyData* vtkSTLWriter::GetInput(int port)
312 {
313   return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
314 }
315 
316 //----------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)317 int vtkSTLWriter::FillInputPortInformation(int, vtkInformation *info)
318 {
319   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
320   return 1;
321 }
322