1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPolyDataWriter.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 "vtkHoudiniPolyDataWriter.h"
16 
17 #include <algorithm>
18 
19 #include "vtkAbstractArray.h"
20 #include "vtkCellData.h"
21 #include "vtkCharArray.h"
22 #include "vtkInformation.h"
23 #include "vtkIntArray.h"
24 #include "vtkDoubleArray.h"
25 #include "vtkFloatArray.h"
26 #include "vtkLongArray.h"
27 #include "vtkLongLongArray.h"
28 #include "vtkNew.h"
29 #include "vtkPointData.h"
30 #include "vtkPoints.h"
31 #include "vtkPolyData.h"
32 #include "vtkSetGet.h"
33 #include "vtkSignedCharArray.h"
34 #include "vtkShortArray.h"
35 #include "vtkStdString.h"
36 #include "vtkStringArray.h"
37 #include "vtkUnsignedIntArray.h"
38 #include "vtkUnsignedLongArray.h"
39 #include "vtkUnsignedLongLongArray.h"
40 #include "vtkUnsignedShortArray.h"
41 
42 vtkStandardNewMacro(vtkHoudiniPolyDataWriter);
43 
44 namespace
45 {
46   // Houdini geometry files store point/cell data in-line with the point/cell
47   // definition. So, the point data access pattern is to write a point's
48   // coordinates, followed by its data values for each point data attribute.
49   // This storage pattern differs from VTK's, where all points are
50   // logically held in a contiguous memory block, followed by all of the values
51   // for a single data attribute. To accommodate this discrepancy in data
52   // access, we construct a facade for point/cell attributes that allows us to
53   // stream all of the values associated with a single point/cell.
54 
55   struct AttributeBase
56   {
57     virtual ~AttributeBase() = default;
58     virtual void StreamHeader(std::ostream&) const = 0;
59     virtual void StreamData(std::ostream&, vtkIdType) const = 0;
60   };
61 
62   template <int AttributeId>
63   struct AttributeTrait;
64 
65 #define DefineAttributeTrait(attId, attType, attName, vtkArray, attDefault) \
66   template <>                                                           \
67   struct AttributeTrait<attId>                                          \
68   {                                                                     \
69     typedef attType Type;                                               \
70     typedef vtkArray vtkArrayType;                                      \
71     std::string Name() const { return std::string(attName); }           \
72     attType Default() const { return static_cast<attType>(attDefault); } \
73     static void Get(vtkIdType index, attType* in, vtkArray* array)      \
74     { array->GetTypedTuple(index, in); }                                \
75     static void Stream(std::ostream& out, attType t) { out << t; }      \
76   }
77 
78   DefineAttributeTrait(VTK_DOUBLE, double, "float", vtkDoubleArray, 0.0);
79   DefineAttributeTrait(VTK_FLOAT, float, "float", vtkFloatArray, 0.0);
80   DefineAttributeTrait(VTK_LONG_LONG, long long, "int", vtkLongLongArray, 0);
81   DefineAttributeTrait(VTK_UNSIGNED_LONG_LONG, unsigned long long, "int", vtkUnsignedLongLongArray, 0);
82   DefineAttributeTrait(VTK_ID_TYPE, vtkIdType, "int", vtkIdTypeArray, 0);
83   DefineAttributeTrait(VTK_LONG, long, "int", vtkLongArray, 0);
84   DefineAttributeTrait(VTK_UNSIGNED_LONG, unsigned long, "int", vtkUnsignedLongArray, 0);
85   DefineAttributeTrait(VTK_INT, int, "int", vtkIntArray, 0);
86   DefineAttributeTrait(VTK_UNSIGNED_INT, unsigned int, "int", vtkUnsignedIntArray, 0);
87   DefineAttributeTrait(VTK_SHORT, short, "int", vtkShortArray, 0);
88   DefineAttributeTrait(VTK_UNSIGNED_SHORT, unsigned short, "int", vtkUnsignedShortArray, 0);
89 
90 #undef DefineAttributeTrait
91 
92   template <>
93   struct AttributeTrait<VTK_CHAR>
94   {
95     typedef char Type;
96     typedef vtkCharArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait97     std::string Name() const { return std::string("int"); }
Default__anonac7eafc90111::AttributeTrait98     int Default() const { return static_cast<int>('0'); }
Get__anonac7eafc90111::AttributeTrait99     static void Get(vtkIdType index, char* in, vtkCharArray* array)
100     { array->GetTypedTuple(index, in); }
Stream__anonac7eafc90111::AttributeTrait101     static void Stream(std::ostream& out, char t)
102     {
103       out << static_cast<int>(t);
104     }
105   };
106 
107   template <>
108   struct AttributeTrait<VTK_SIGNED_CHAR>
109   {
110     typedef signed char Type;
111     typedef vtkSignedCharArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait112     std::string Name() const { return std::string("int"); }
Default__anonac7eafc90111::AttributeTrait113     int Default() const { return static_cast<int>('0'); }
Get__anonac7eafc90111::AttributeTrait114     static void Get(vtkIdType index, signed char* in, vtkSignedCharArray* array)
115     { array->GetTypedTuple(index, in); }
Stream__anonac7eafc90111::AttributeTrait116     static void Stream(std::ostream& out, signed char t)
117     {
118       out << static_cast<int>(t);
119     }
120   };
121 
122   template <>
123   struct AttributeTrait<VTK_UNSIGNED_CHAR>
124   {
125     typedef unsigned char Type;
126     typedef vtkUnsignedCharArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait127     std::string Name() const { return std::string("int"); }
Default__anonac7eafc90111::AttributeTrait128     int Default() const { return static_cast<int>('0'); }
Get__anonac7eafc90111::AttributeTrait129     static void Get(vtkIdType index, unsigned char* in,
130                     vtkUnsignedCharArray* array)
131     { array->GetTypedTuple(index, in); }
Stream__anonac7eafc90111::AttributeTrait132     static void Stream(std::ostream& out, unsigned char t)
133     {
134       out << static_cast<int>(t);
135     }
136   };
137 
138   template <>
139   struct AttributeTrait<VTK_STRING>
140   {
141     typedef vtkStdString Type;
142     typedef vtkStringArray vtkArrayType;
Name__anonac7eafc90111::AttributeTrait143     std::string Name() const { return std::string("string"); }
Default__anonac7eafc90111::AttributeTrait144     vtkStdString Default() const { return vtkStdString("None"); }
Get__anonac7eafc90111::AttributeTrait145     static void Get(vtkIdType index, vtkStdString* in, vtkStringArray* array)
146     {
147       assert(array->GetNumberOfComponents() == 1);
148       *in = array->GetValue(index);
149     }
Stream__anonac7eafc90111::AttributeTrait150     static void Stream(std::ostream& out, const vtkStdString& t)
151     {
152       std::size_t i = 0;
153       out << "\'";
154       for (; i < (t.size() < 32 ? t.size() : 32); i++)
155       {
156         out << t[i];
157       }
158       for (; i < 32; i++)
159       {
160         out << " ";
161       }
162       out << "\'";
163     }
164   };
165 
166   template <int AttributeId>
167   struct Attribute : public AttributeBase
168   {
169     typedef typename AttributeTrait<AttributeId>::vtkArrayType vtkArrayType;
170 
Attribute__anonac7eafc90111::Attribute171     Attribute(vtkAbstractArray* array) : AttributeBase()
172     {
173       this->Array = vtkArrayType::SafeDownCast(array);
174       assert(this->Array != nullptr);
175       this->Value.resize(this->Array->GetNumberOfComponents());
176     }
177 
StreamHeader__anonac7eafc90111::Attribute178     void StreamHeader(std::ostream& out) const override
179     {
180       std::string s = this->Array->GetName();
181       std::replace(s.begin(), s.end(), ' ', '_');
182       std::replace(s.begin(), s.end(), '\t', '-');
183 
184       AttributeTrait<AttributeId> trait;
185       out << s << " " << this->Array->GetNumberOfComponents() << " "
186           << trait.Name() << " " << trait.Default();
187       for (int i = 1; i < this->Array->GetNumberOfComponents(); i++)
188       {
189         out << " ";
190         AttributeTrait<AttributeId>::Stream(out, trait.Default());
191       }
192     }
193 
StreamData__anonac7eafc90111::Attribute194     void StreamData(std::ostream& out, vtkIdType index) const override
195     {
196       assert(index < this->Array->GetNumberOfTuples());
197 
198       AttributeTrait<AttributeId>::Get(index, &this->Value[0], this->Array);
199       AttributeTrait<AttributeId>::Stream(out, this->Value[0]);
200 
201       for (int i = 1; i < this->Array->GetNumberOfComponents(); i++)
202       {
203           out << " ";
204         AttributeTrait<AttributeId>::Stream(out, this->Value[i]);
205       }
206     }
207 
208   protected:
209     mutable std::vector<typename AttributeTrait<AttributeId>::Type> Value;
210     mutable vtkArrayType* Array;
211   };
212 
213   class Attributes
214   {
215   public:
216     typedef std::vector<AttributeBase*>::iterator AttIt;
217 
218     class Header
219     {
220       friend class Attributes;
Header(Attributes * atts)221       Header(Attributes* atts) : Atts(atts) {}
222       void operator=(const Attributes::Header&) = delete;
223 
operator <<(ostream & out,const Attributes::Header & header)224       friend ostream& operator<<(ostream& out, const Attributes::Header& header)
225       {
226         for (Attributes::AttIt it=header.Atts->AttVec.begin();
227              it != header.Atts->AttVec.end(); ++it)
228         {
229           (*it)->StreamHeader(out);
230           out << endl;
231         }
232         return out;
233       }
234     public:
235       Attributes* Atts;
236     };
237 
238     class Component
239     {
240       friend class Attributes;
241 
Component(Attributes * atts,vtkIdType index)242       Component(Attributes* atts, vtkIdType index) : Atts(atts),
243                                                      Index(index) {}
244 
245       Attributes* Atts;
246       vtkIdType Index;
247 
operator <<(ostream & out,const Attributes::Component & component)248       friend ostream& operator<<(ostream& out,
249                                  const Attributes::Component& component)
250       {
251         for (Attributes::AttIt it=component.Atts->AttVec.begin();
252              it != component.Atts->AttVec.end(); ++it)
253         {
254           (*it)->StreamData(out, component.Index);
255 
256           if (it + 1 != component.Atts->AttVec.end())
257           {
258             out << " ";
259           }
260         }
261         return out;
262       }
263     };
264 
Attributes()265     Attributes() : Hdr(nullptr) { this->Hdr.Atts = this; }
~Attributes()266     virtual ~Attributes()
267     {
268       for (AttIt it=this->AttVec.begin(); it != this->AttVec.end(); ++it)
269       {
270         delete *it;
271       }
272     }
273 
GetHeader()274     Header& GetHeader() { return this->Hdr; }
275 
operator [](vtkIdType i)276     Component operator[](vtkIdType i)
277     {
278       return Attributes::Component(this, i);
279     }
280 
281     template <int TypeId>
AddAttribute(vtkAbstractArray * array)282     void AddAttribute(vtkAbstractArray* array)
283     {
284       this->AttVec.push_back(new Attribute<TypeId>(array));
285     }
286 
287     Header Hdr;
288     std::vector<AttributeBase*> AttVec;
289   };
290 
291   template <int TypeId>
AddAttribute(Attributes & atts,vtkAbstractArray * array)292   void AddAttribute(Attributes& atts, vtkAbstractArray* array)
293   {
294     atts.AddAttribute<TypeId>(array);
295   }
296 }
297 
298 //----------------------------------------------------------------------------
vtkHoudiniPolyDataWriter()299 vtkHoudiniPolyDataWriter::vtkHoudiniPolyDataWriter()
300 {
301   this->FileName = nullptr;
302 }
303 
304 //----------------------------------------------------------------------------
~vtkHoudiniPolyDataWriter()305 vtkHoudiniPolyDataWriter::~vtkHoudiniPolyDataWriter()
306 {
307   this->SetFileName(nullptr);
308 }
309 
310 //----------------------------------------------------------------------------
WriteData()311 void vtkHoudiniPolyDataWriter::WriteData()
312 {
313   // Grab the input data
314   vtkPolyData* input = vtkPolyData::SafeDownCast(this->GetInput());
315   if (!input)
316   {
317     vtkErrorMacro(<< "Missing input polydata!");
318     return;
319   }
320 
321   // Open the file for streaming
322   std::ofstream file(this->FileName, std::ofstream::out);
323 
324   if (file.fail())
325   {
326     vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
327     return;
328   }
329 
330   vtkIdType nPrims = 0;
331   {
332     nPrims += input->GetNumberOfVerts();
333     nPrims += input->GetNumberOfLines();
334     nPrims += input->GetNumberOfPolys();
335 
336     vtkCellArray* stripArray = input->GetStrips();
337     vtkIdType nPts, *pts;
338 
339     stripArray->InitTraversal();
340     while (stripArray->GetNextCell(nPts, pts))
341     {
342       nPrims += nPts - 2;
343     }
344   }
345 
346   // Write generic header info
347   file << "PGEOMETRY V2" << endl;
348   file << "NPoints " << input->GetNumberOfPoints() << " "
349        << "NPrims " << nPrims << endl;
350   file << "NPointGroups " << 0 << " NPrimGroups " << 0 << endl;
351   file << "NPointAttrib " << input->GetPointData()->GetNumberOfArrays()<< " "
352        << "NVertexAttrib " << 0 << " "
353        << "NPrimAttrib " << input->GetCellData()->GetNumberOfArrays() << " "
354        << "NAttrib " << 0 << endl;
355 
356 #define vtkHoudiniTemplateMacroCase(typeN, atts, arr)           \
357   case typeN: { AddAttribute<typeN>(atts, arr); }; break
358 #define vtkHoudiniTemplateMacro(atts, arr)                              \
359   vtkHoudiniTemplateMacroCase(VTK_DOUBLE, atts, arr);                   \
360   vtkHoudiniTemplateMacroCase(VTK_FLOAT, atts, arr);                    \
361   vtkHoudiniTemplateMacroCase(VTK_LONG_LONG, atts, arr);                \
362   vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_LONG_LONG, atts, arr);       \
363   vtkHoudiniTemplateMacroCase(VTK_ID_TYPE, atts, arr);                  \
364   vtkHoudiniTemplateMacroCase(VTK_LONG, atts, arr);                     \
365   vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_LONG, atts, arr);            \
366   vtkHoudiniTemplateMacroCase(VTK_INT, atts, arr);                      \
367   vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_INT, atts, arr);             \
368   vtkHoudiniTemplateMacroCase(VTK_SHORT, atts, arr);                    \
369   vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_SHORT, atts, arr);           \
370   vtkHoudiniTemplateMacroCase(VTK_CHAR, atts, arr);                     \
371   vtkHoudiniTemplateMacroCase(VTK_SIGNED_CHAR, atts, arr);              \
372   vtkHoudiniTemplateMacroCase(VTK_UNSIGNED_CHAR, atts, arr)
373 
374   // Construct Attributes instance for points
375   Attributes pointAttributes;
376   for (vtkIdType i = 0; i < input->GetPointData()->GetNumberOfArrays(); i++)
377   {
378     vtkAbstractArray* array = input->GetPointData()->GetAbstractArray(i);
379     switch (array->GetDataType())
380     {
381       vtkHoudiniTemplateMacro(pointAttributes, array);
382 #if 0
383     case VTK_STRING: { AddAttribute<VTK_STRING>(pointAttributes, array); }; break;
384 #endif
385     default:
386       vtkGenericWarningMacro(<<"Unsupported data type!");
387     }
388   }
389 
390   // Write point attributes header info
391   if (input->GetPointData()->GetNumberOfArrays() != 0)
392   {
393     file << "PointAttrib" << endl;
394     file << pointAttributes.GetHeader();
395   }
396 
397   // Write point data
398   vtkPoints* points = input->GetPoints();
399   double xyz[3];
400   for (vtkIdType i = 0; i < input->GetNumberOfPoints(); i++)
401   {
402     points->GetPoint(i, xyz);
403     file << xyz[0] << " " << xyz[1] << " " << xyz[2] << " "
404          << 1;
405     if (input->GetPointData()->GetNumberOfArrays() != 0)
406     {
407       file << " (" << pointAttributes[i] << ")";
408     }
409     file << endl;
410   }
411 
412   // Construct Attributes instance for cells
413   Attributes cellAttributes;
414   for (vtkIdType i = 0; i < input->GetCellData()->GetNumberOfArrays(); i++)
415   {
416     vtkAbstractArray* array = input->GetCellData()->GetAbstractArray(i);
417     switch (array->GetDataType())
418     {
419       vtkHoudiniTemplateMacro(cellAttributes, array);
420 #if 0
421     case VTK_STRING: { AddAttribute<VTK_STRING>(cellAttributes, array); }; break;
422 #endif
423     default:
424       vtkGenericWarningMacro(<<"Unsupported data type!");
425     }
426   }
427 
428 #undef vtkHoudiniTemplateMacro
429 #undef vtkHoudiniTemplateMacroCase
430 
431   // Write cell attributes header info
432   if (input->GetCellData()->GetNumberOfArrays() != 0 &&
433       input->GetNumberOfCells() != 0)
434   {
435     file << "PrimitiveAttrib" << endl;
436     file << cellAttributes.GetHeader();
437   }
438 
439   if (input->GetNumberOfVerts() != 0)
440   {
441     // Write vertex data as a particle system
442     vtkCellArray* vertArray = input->GetVerts();
443     vtkIdType nPts, *pts, cellId;
444 
445     if (input->GetNumberOfVerts() > 1)
446     {
447       file << "Run " << input->GetNumberOfVerts() << " Part" << endl;
448     }
449     else
450     {
451       file << "Part ";
452     }
453     cellId = 0;
454 
455     vertArray->InitTraversal();
456     while (vertArray->GetNextCell(nPts, pts))
457     {
458       file << nPts;
459       for (vtkIdType i = 0; i < nPts; i++)
460       {
461         file << " " << pts[i];
462       }
463       if (input->GetCellData()->GetNumberOfArrays() != 0)
464       {
465         file << " [" << cellAttributes[cellId] << "]";
466       }
467       file << endl;
468       cellId++;
469     }
470   }
471 
472   if (input->GetNumberOfLines() != 0)
473   {
474     // Write line data as open polygons
475     file << "Run " << input->GetNumberOfLines() << " Poly" <<endl;
476 
477     vtkCellArray* lineArray = input->GetLines();
478     vtkIdType nPts, *pts, cellId;
479 
480     cellId = input->GetNumberOfVerts();
481 
482     lineArray->InitTraversal();
483     while (lineArray->GetNextCell(nPts, pts))
484     {
485       file << nPts << " : " << pts[0];
486       for (vtkIdType i = 1; i < nPts; i++)
487       {
488         file << " " << pts[i];
489       }
490       if (input->GetCellData()->GetNumberOfArrays() != 0)
491       {
492         file << " [" << cellAttributes[cellId++] << "]";
493       }
494       file << endl;
495     }
496   }
497 
498   if (input->GetNumberOfPolys() != 0)
499   {
500     // Write polygon data
501     file << "Run " << input->GetNumberOfPolys() << " Poly" <<endl;
502 
503     vtkCellArray* polyArray = input->GetPolys();
504     vtkIdType nPts, *pts, cellId;
505 
506     cellId = (input->GetNumberOfVerts() + input->GetNumberOfLines());
507 
508     polyArray->InitTraversal();
509     while (polyArray->GetNextCell(nPts, pts))
510     {
511       file << nPts << " < " << pts[0];
512       for (vtkIdType i = 1; i < nPts; i++)
513       {
514         file << " " << pts[i];
515       }
516       if (input->GetCellData()->GetNumberOfArrays() != 0)
517       {
518         file << " [" << cellAttributes[cellId++] << "]";
519       }
520       file << endl;
521     }
522   }
523 
524   if (input->GetNumberOfStrips() != 0)
525   {
526     // Write triangle strip data as polygons
527     vtkCellArray* stripArray = input->GetStrips();
528     vtkIdType nPts, *pts, cellId;
529 
530     cellId = (input->GetNumberOfVerts() +
531               input->GetNumberOfLines() +
532               input->GetNumberOfPolys());
533 
534     stripArray->InitTraversal();
535     while (stripArray->GetNextCell(nPts, pts))
536     {
537       if (nPts > 3)
538       {
539         file << "Run " << nPts - 2 << " Poly" << endl;
540       }
541       else
542       {
543         file << "Poly ";
544       }
545 
546       for (vtkIdType i = 2; i < nPts; i++)
547       {
548         if (i%2 == 0)
549         {
550           file << "3 < "
551                << pts[i - 2] << " " << pts[i - 1] << " " << pts[i];
552         }
553         else
554         {
555           file << "3 < "
556                << pts[i - 1] << " " << pts[i - 2] << " " << pts[i];
557         }
558         if (input->GetCellData()->GetNumberOfArrays() != 0)
559         {
560           file << " [" << cellAttributes[cellId] << "]";
561         }
562         file << endl;
563       }
564       cellId++;
565     }
566   }
567 
568   file << "beginExtra" << endl;
569   file << "endExtra" << endl;
570 
571   file.close();
572 }
573 
574 //----------------------------------------------------------------------------
FillInputPortInformation(int,vtkInformation * info)575 int vtkHoudiniPolyDataWriter::FillInputPortInformation(int, vtkInformation *info)
576 {
577   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
578   return 1;
579 }
580 
581 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)582 void vtkHoudiniPolyDataWriter::PrintSelf(ostream& os, vtkIndent indent)
583 {
584   this->Superclass::PrintSelf(os, indent);
585   os << indent << "FileName: "
586      << (this->FileName? this->FileName:"(none)") << "\n";
587 }
588