1 #include "vtkF3DGenericImporter.h"
2 
3 #include "F3DLog.h"
4 #include "F3DOptions.h"
5 
6 #include <vtkActor.h>
7 #include <vtkAppendPolyData.h>
8 #include <vtkBoundingBox.h>
9 #include <vtkCellData.h>
10 #include <vtkDataObjectTreeIterator.h>
11 #include <vtkDataSetSurfaceFilter.h>
12 #include <vtkDoubleArray.h>
13 #include <vtkEventForwarderCommand.h>
14 #include <vtkImageData.h>
15 #include <vtkImageReader2.h>
16 #include <vtkImageReader2Factory.h>
17 #include <vtkImageToPoints.h>
18 #include <vtkInformation.h>
19 #include <vtkLightKit.h>
20 #include <vtkMultiBlockDataSet.h>
21 #include <vtkObjectFactory.h>
22 #include <vtkPiecewiseFunction.h>
23 #include <vtkPointData.h>
24 #include <vtkPointGaussianMapper.h>
25 #include <vtkPolyDataMapper.h>
26 #include <vtkProperty.h>
27 #include <vtkRectilinearGrid.h>
28 #include <vtkRectilinearGridToPointSet.h>
29 #include <vtkRenderer.h>
30 #include <vtkScalarBarActor.h>
31 #include <vtkScalarsToColors.h>
32 #include <vtkSmartPointer.h>
33 #include <vtkSmartVolumeMapper.h>
34 #include <vtkStreamingDemandDrivenPipeline.h>
35 #include <vtkTexture.h>
36 #include <vtkVertexGlyphFilter.h>
37 #include <vtkVolumeProperty.h>
38 #include <vtksys/SystemTools.hxx>
39 
40 #include "vtkF3DPostProcessFilter.h"
41 
42 vtkStandardNewMacro(vtkF3DGenericImporter);
43 
44 //----------------------------------------------------------------------------
UpdateTemporalInformation()45 void vtkF3DGenericImporter::UpdateTemporalInformation()
46 {
47   if (!this->TemporalInformationUpdated)
48   {
49     if (!this->Reader->IsReaderValid())
50     {
51       F3DLog::Print(F3DLog::Severity::Info, "Reader is not valid");
52       return;
53     }
54     this->Reader->UpdateInformation();
55     vtkInformation* readerInfo = this->Reader->GetOutputInformation(0);
56 
57     this->NbTimeSteps = readerInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
58     this->TimeRange = readerInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_RANGE());
59     this->TimeSteps = readerInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS());
60     this->TemporalInformationUpdated = true;
61   }
62 }
63 
64 //----------------------------------------------------------------------------
GetNumberOfAnimations()65 vtkIdType vtkF3DGenericImporter::GetNumberOfAnimations()
66 {
67   this->UpdateTemporalInformation();
68   return this->NbTimeSteps > 0 ? 1 : 0;
69 }
70 
71 //----------------------------------------------------------------------------
GetAnimationName(vtkIdType animationIndex)72 std::string vtkF3DGenericImporter::GetAnimationName(vtkIdType animationIndex)
73 {
74   return animationIndex < this->GetNumberOfAnimations() ? "default" : "";
75 }
76 
77 //----------------------------------------------------------------------------
EnableAnimation(vtkIdType animationIndex)78 void vtkF3DGenericImporter::EnableAnimation(vtkIdType animationIndex)
79 {
80   if (animationIndex < this->GetNumberOfAnimations())
81   {
82     this->AnimationEnabled = true;
83   }
84 }
85 
86 //----------------------------------------------------------------------------
DisableAnimation(vtkIdType animationIndex)87 void vtkF3DGenericImporter::DisableAnimation(vtkIdType animationIndex)
88 {
89   if (animationIndex < this->GetNumberOfAnimations())
90   {
91     this->AnimationEnabled = false;
92   }
93 }
94 
95 //----------------------------------------------------------------------------
IsAnimationEnabled(vtkIdType animationIndex)96 bool vtkF3DGenericImporter::IsAnimationEnabled(vtkIdType animationIndex)
97 {
98   return animationIndex < this->GetNumberOfAnimations() ? this->AnimationEnabled : false;
99 }
100 
101 //----------------------------------------------------------------------------
102 #if VTK_VERSION_NUMBER >= VTK_VERSION_CHECK(9, 0, 20201016)
GetTemporalInformation(vtkIdType animationIndex,double vtkNotUsed (frameRate),int & nbTimeSteps,double timeRange[2],vtkDoubleArray * timeSteps)103 bool vtkF3DGenericImporter::GetTemporalInformation(vtkIdType animationIndex,
104   double vtkNotUsed(frameRate), int& nbTimeSteps, double timeRange[2], vtkDoubleArray* timeSteps)
105 #else
106 bool vtkF3DGenericImporter::GetTemporalInformation(vtkIdType animationIndex,
107   int& nbTimeSteps, double timeRange[2], vtkDoubleArray* timeSteps)
108 #endif
109 {
110   if (animationIndex < this->GetNumberOfAnimations())
111   {
112     nbTimeSteps = this->NbTimeSteps;
113     timeRange[0] = this->TimeRange[0];
114     timeRange[1] = this->TimeRange[1];
115     timeSteps->SetArray(this->TimeSteps, this->NbTimeSteps, 1);
116     return true;
117   }
118   return false;
119 }
120 
121 //----------------------------------------------------------------------------
ImportActors(vtkRenderer * ren)122 void vtkF3DGenericImporter::ImportActors(vtkRenderer* ren)
123 {
124   if (!this->Reader->IsReaderValid())
125   {
126     F3DLog::Print(
127       F3DLog::Severity::Error, "File '", this->Reader->GetFileName(), "' cannot be read.");
128     return;
129   }
130 
131   // forward progress event
132   vtkNew<vtkEventForwarderCommand> forwarder;
133   forwarder->SetTarget(this);
134   this->Reader->AddObserver(vtkCommand::ProgressEvent, forwarder);
135 
136   this->PostPro->SetInputConnection(this->Reader->GetOutputPort());
137   bool ret = this->PostPro->GetExecutive()->Update();
138 
139   if (!ret)
140   {
141     F3DLog::Print(
142       F3DLog::Severity::Error, "File '", this->Reader->GetFileName(), "' cannot be read.");
143     return;
144   }
145 
146   bool print = (this->Options->Verbose || this->Options->NoRender);
147   if (print)
148   {
149     this->OutputDescription =
150       vtkF3DGenericImporter::GetDataObjectDescription(this->Reader->GetOutput());
151   }
152 
153   if (this->Options->NoRender)
154   {
155     return;
156   }
157 
158   vtkPolyData* surface = vtkPolyData::SafeDownCast(this->PostPro->GetOutput());
159   vtkImageData* image = vtkImageData::SafeDownCast(this->PostPro->GetOutput(2));
160 
161   // Configure volume mapper
162   this->VolumeMapper->SetInputConnection(this->PostPro->GetOutputPort(2));
163   this->VolumeMapper->SetRequestedRenderModeToGPU();
164 
165   // Configure polydata mapper
166   this->PolyDataMapper->InterpolateScalarsBeforeMappingOn();
167   this->PolyDataMapper->SetInputConnection(this->PostPro->GetOutputPort(0));
168 
169   // Configure Point Gaussian mapper
170   double bounds[6];
171   surface->GetBounds(bounds);
172   vtkBoundingBox bbox(bounds);
173 
174   double pointSize = 1.0;
175   if (bbox.IsValid())
176   {
177     pointSize = this->Options->PointSize * bbox.GetDiagonalLength() * 0.001;
178   }
179   this->PointGaussianMapper->SetInputConnection(this->PostPro->GetOutputPort(1));
180   this->PointGaussianMapper->SetScaleFactor(pointSize);
181   this->PointGaussianMapper->EmissiveOff();
182   this->PointGaussianMapper->SetSplatShaderCode(
183     "//VTK::Color::Impl\n"
184     "float dist = dot(offsetVCVSOutput.xy, offsetVCVSOutput.xy);\n"
185     "if (dist > 1.0) {\n"
186     "  discard;\n"
187     "} else {\n"
188     "  float scale = (1.0 - dist);\n"
189     "  ambientColor *= scale;\n"
190     "  diffuseColor *= scale;\n"
191     "}\n");
192 
193   //
194   vtkDataSet* dataSet = vtkImageData::SafeDownCast(this->PostPro->GetInput())
195     ? vtkDataSet::SafeDownCast(image)
196     : vtkDataSet::SafeDownCast(surface);
197 
198   std::string usedArray = this->Options->Scalars;
199   this->PointDataForColoring = vtkDataSetAttributes::SafeDownCast(dataSet->GetPointData());
200   this->CellDataForColoring = vtkDataSetAttributes::SafeDownCast(dataSet->GetCellData());
201   vtkDataSetAttributes* dataForColoring =
202     this->Options->Cells ? this->CellDataForColoring : this->PointDataForColoring;
203 
204   // Recover an array for coloring if we ever need it
205   this->ArrayIndexForColoring = -1;
206   if (usedArray.empty())
207   {
208     vtkDataArray* array = dataForColoring->GetScalars();
209     if (array)
210     {
211       const char* arrayName = array->GetName();
212       if (arrayName)
213       {
214         usedArray = arrayName;
215       }
216       if (print)
217       {
218         F3DLog::Print(F3DLog::Severity::Info, "Using default scalar array: ", usedArray);
219       }
220     }
221     else
222     {
223       for (int i = 0; i < dataForColoring->GetNumberOfArrays(); i++)
224       {
225         array = dataForColoring->GetArray(i);
226         if (array)
227         {
228           this->ArrayIndexForColoring = i;
229           const char* arrayName = array->GetName();
230           if (arrayName)
231           {
232             usedArray = arrayName;
233           }
234           if (print)
235           {
236             F3DLog::Print(F3DLog::Severity::Info, "Using first found array: ", usedArray);
237           }
238           break;
239         }
240       }
241     }
242   }
243   if (this->ArrayIndexForColoring == -1)
244   {
245     dataForColoring->GetArray(usedArray.c_str(), this->ArrayIndexForColoring);
246   }
247   if (this->ArrayIndexForColoring == -1 && !usedArray.empty() &&
248     usedArray != f3d::F3DReservedString)
249   {
250     F3DLog::Print(F3DLog::Severity::Warning, "Unknown scalar array: ", usedArray);
251   }
252   if (this->ArrayIndexForColoring == -1 && print)
253   {
254     F3DLog::Print(
255       F3DLog::Severity::Info, "No array found for scalar coloring and volume rendering");
256   }
257 
258   // configure props
259   this->VolumeProp->SetMapper(this->VolumeMapper);
260 
261   this->GeometryActor->SetMapper(this->PolyDataMapper);
262   this->GeometryActor->GetProperty()->SetInterpolationToPBR();
263 
264   double col[3];
265   std::copy(this->Options->SolidColor.begin(), this->Options->SolidColor.end(), col);
266 
267   this->GeometryActor->GetProperty()->SetColor(col);
268   this->GeometryActor->GetProperty()->SetOpacity(this->Options->Opacity);
269   this->GeometryActor->GetProperty()->SetRoughness(this->Options->Roughness);
270   this->GeometryActor->GetProperty()->SetMetallic(this->Options->Metallic);
271   this->GeometryActor->GetProperty()->SetPointSize(this->Options->PointSize);
272   this->GeometryActor->GetProperty()->SetLineWidth(this->Options->LineWidth);
273 
274   this->PointSpritesActor->SetMapper(this->PointGaussianMapper);
275   this->PointSpritesActor->GetProperty()->SetColor(col);
276   this->PointSpritesActor->GetProperty()->SetOpacity(this->Options->Opacity);
277 
278   // Textures
279   this->GeometryActor->GetProperty()->SetBaseColorTexture(
280     this->GetTexture(this->Options->BaseColorTex, true));
281   this->GeometryActor->GetProperty()->SetORMTexture(this->GetTexture(this->Options->ORMTex));
282   this->GeometryActor->GetProperty()->SetEmissiveTexture(
283     this->GetTexture(this->Options->EmissiveTex, true));
284   this->GeometryActor->GetProperty()->SetEmissiveFactor(this->Options->EmissiveFactor.data());
285   this->GeometryActor->GetProperty()->SetNormalTexture(this->GetTexture(this->Options->NormalTex));
286   this->GeometryActor->GetProperty()->SetNormalScale(this->Options->NormalScale);
287 
288   // add props
289   ren->AddActor2D(this->ScalarBarActor);
290   ren->AddActor(this->GeometryActor);
291   ren->AddActor(this->PointSpritesActor);
292   ren->AddVolume(this->VolumeProp);
293 }
294 
295 //----------------------------------------------------------------------------
296 // TODO : add this function in a utils file for rendering in VTK directly
GetTexture(const std::string & fileName,bool isSRGB)297 vtkSmartPointer<vtkTexture> vtkF3DGenericImporter::GetTexture(
298   const std::string& fileName, bool isSRGB)
299 {
300   vtkSmartPointer<vtkTexture> texture;
301   if (!fileName.empty())
302   {
303     std::string fullPath = vtksys::SystemTools::CollapseFullPath(fileName);
304 
305     auto reader = vtkSmartPointer<vtkImageReader2>::Take(
306       vtkImageReader2Factory::CreateImageReader2(fullPath.c_str()));
307     if (reader)
308     {
309       reader->SetFileName(fullPath.c_str());
310       reader->Update();
311       texture = vtkSmartPointer<vtkTexture>::New();
312       texture->SetInputConnection(reader->GetOutputPort());
313       if (isSRGB)
314       {
315         texture->UseSRGBColorSpaceOn();
316       }
317       texture->InterpolateOn();
318       return texture;
319     }
320     else
321     {
322       F3DLog::Print(F3DLog::Severity::Warning, "Cannot open texture file ", fullPath);
323     }
324   }
325 
326   return texture;
327 }
328 
329 //----------------------------------------------------------------------------
ImportLights(vtkRenderer * ren)330 void vtkF3DGenericImporter::ImportLights(vtkRenderer* ren)
331 {
332   ren->RemoveAllLights();
333   ren->AutomaticLightCreationOff();
334 
335   if (!ren->GetUseImageBasedLighting())
336   {
337     vtkNew<vtkLightKit> lightKit;
338     lightKit->AddLightsToRenderer(ren);
339   }
340 }
341 
342 //----------------------------------------------------------------------------
ImportProperties(vtkRenderer * vtkNotUsed (ren))343 void vtkF3DGenericImporter::ImportProperties(vtkRenderer* vtkNotUsed(ren)) {}
344 
345 //----------------------------------------------------------------------------
PrintSelf(std::ostream & os,vtkIndent indent)346 void vtkF3DGenericImporter::PrintSelf(std::ostream& os, vtkIndent indent)
347 {
348   vtkImporter::PrintSelf(os, indent);
349 }
350 
351 //----------------------------------------------------------------------------
SetFileName(const char * arg)352 void vtkF3DGenericImporter::SetFileName(const char* arg)
353 {
354   this->TemporalInformationUpdated = false;
355   this->Reader->SetFileName(std::string(arg));
356 }
357 
358 //----------------------------------------------------------------------------
SetOptions(const F3DOptions & options)359 void vtkF3DGenericImporter::SetOptions(const F3DOptions& options)
360 {
361   this->Options = &options;
362 }
363 
364 //----------------------------------------------------------------------------
CanReadFile()365 bool vtkF3DGenericImporter::CanReadFile()
366 {
367   return this->Reader->IsReaderValid();
368 }
369 
370 //----------------------------------------------------------------------------
GetOutputsDescription()371 std::string vtkF3DGenericImporter::GetOutputsDescription()
372 {
373   return this->OutputDescription;
374 }
375 
376 //----------------------------------------------------------------------------
GetMultiBlockDescription(vtkMultiBlockDataSet * mb,vtkIndent indent)377 std::string vtkF3DGenericImporter::GetMultiBlockDescription(
378   vtkMultiBlockDataSet* mb, vtkIndent indent)
379 {
380   std::stringstream ss;
381   for (vtkIdType i = 0; i < mb->GetNumberOfBlocks(); i++)
382   {
383     const char* blockName = mb->GetMetaData(i)->Get(vtkCompositeDataSet::NAME());
384     ss << indent << "Block: " << (blockName ? std::string(blockName) : std::to_string(i)) << "\n";
385     vtkDataObject* object = mb->GetBlock(i);
386     vtkMultiBlockDataSet* mbChild = vtkMultiBlockDataSet::SafeDownCast(object);
387     vtkDataSet* ds = vtkDataSet::SafeDownCast(object);
388     if (mbChild)
389     {
390       ss << vtkF3DGenericImporter::GetMultiBlockDescription(mbChild, indent.GetNextIndent());
391     }
392     else if (ds)
393     {
394       ss << vtkImporter::GetDataSetDescription(ds, indent.GetNextIndent());
395     }
396   }
397   return ss.str();
398 }
399 
400 //----------------------------------------------------------------------------
GetDataObjectDescription(vtkDataObject * object)401 std::string vtkF3DGenericImporter::GetDataObjectDescription(vtkDataObject* object)
402 {
403   vtkMultiBlockDataSet* mb = vtkMultiBlockDataSet::SafeDownCast(object);
404   vtkDataSet* ds = vtkDataSet::SafeDownCast(object);
405   if (mb)
406   {
407     return vtkF3DGenericImporter::GetMultiBlockDescription(mb, vtkIndent(0));
408   }
409   else if (ds)
410   {
411     return vtkImporter::GetDataSetDescription(ds, vtkIndent(0));
412   }
413   return "";
414 }
415 
416 //----------------------------------------------------------------------------
UpdateTimeStep(double timestep)417 void vtkF3DGenericImporter::UpdateTimeStep(double timestep)
418 {
419   this->PostPro->UpdateTimeStep(timestep);
420 }
421