Salome HOME
[EDF23711] : ContactReader is now ready to deal with time
[tools/paravisaddons_common.git] / src / ContactReader / plugin / ContactReaderModule / vtkContactReader.cxx
1 // Copyright (C) 2021  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "vtkContactReader.h"
21
22 #include <vtkArrowSource.h>
23 #include <vtkCellArray.h>
24 #include <vtkCellData.h>
25 #include <vtkDelimitedTextReader.h>
26 #include <vtkDoubleArray.h>
27 #include <vtkErrorCode.h>
28 #include <vtkInformation.h>
29 #include <vtkInformationVector.h>
30 #include <vtkIntArray.h>
31 #include <vtkNew.h>
32 #include <vtkObjectFactory.h>
33 #include <vtkPointData.h>
34 #include <vtkPolyData.h>
35 #include <vtkPVGlyphFilter.h>
36 #include <vtkStreamingDemandDrivenPipeline.h>
37 #include <vtkTable.h>
38 #include <vtkVariant.h>
39 #include <vtkVariantArray.h>
40
41 #include <exception>
42 #include <fstream>
43 #include <sstream>
44 #include <string>
45 #include <vector>
46 #include <set>
47
48 constexpr char INST_TAG[] = "INST";
49
50 class MyException : public std::exception
51 {
52 public:
53   MyException(const char *what) : _what(what) {}
54   MyException(const std::string &what) : _what(what) {}
55   ~MyException() throw() {}
56   const char *what() const throw() { return _what.c_str(); }
57
58 private:
59   std::string _what;
60 };
61
62 template <class T>
63 class AutoPtr
64 {
65 public:
66   AutoPtr(T *ptr = 0) : _ptr(ptr) {}
67   ~AutoPtr() { destroyPtr(); }
68   bool isNull() const { return _ptr == 0; }
69   bool isNotNull() const { return !isNull(); }
70   AutoPtr &operator=(T *ptr)
71   {
72     if (_ptr != ptr)
73     {
74       destroyPtr();
75       _ptr = ptr;
76     }
77     return *this;
78   }
79   T *operator->() { return _ptr; }
80   const T *operator->() const { return _ptr; }
81   T &operator*() { return *_ptr; }
82   const T &operator*() const { return *_ptr; }
83   operator T *() { return _ptr; }
84   operator const T *() const { return _ptr; }
85
86 private:
87   void destroyPtr() { delete[] _ptr; }
88
89 private:
90   T *_ptr;
91 };
92
93 bool PresenceOf(const std::vector<std::string> &arr, const std::string &what)
94 {
95   auto pos = std::find(arr.begin(), arr.end(), what);
96   return pos!=arr.end();
97 }
98
99 vtkIdType PosOf(const std::vector<std::string> &arr, const std::string &what)
100 {
101   auto pos = std::find(arr.begin(), arr.end(), what);
102   if (pos == arr.end())
103   {
104     std::ostringstream oss;
105     oss << "vtkContactReader::PosOf : Fail to locate \"" << what << "\" in array !";
106     throw MyException(oss.str());
107   }
108   return std::distance(arr.begin(), pos);
109 }
110
111 double InstValueOf(vtkTable *table, vtkIdType iRow, vtkIdType iCol)
112 {
113   vtkVariantArray *row(table->GetRow(iRow));
114   vtkVariant *elt(row->GetPointer(iCol));
115   return elt->ToDouble();
116 }
117
118 vtkSmartPointer<vtkTable> LoadDataFromFile(const char *FileName)
119 {
120   vtkNew<vtkDelimitedTextReader> reader;
121   reader->SetFileName(FileName);
122   reader->SetDetectNumericColumns(true);
123   reader->SetUseStringDelimiter(true);
124   reader->SetHaveHeaders(true);
125   reader->SetFieldDelimiterCharacters(" ");
126   reader->SetAddTabFieldDelimiter(true);
127   reader->SetMergeConsecutiveDelimiters(true);
128   reader->Update();
129   vtkTable *table(reader->GetOutput());
130   vtkSmartPointer<vtkTable> ret(table);
131   return ret;
132 }
133
134 std::vector<std::string> GetColumnNames(vtkTable *table)
135 {
136   vtkIdType nbCols(table->GetNumberOfColumns());
137   std::vector<std::string> colNames(nbCols);
138   for (vtkIdType iCol = 0; iCol < nbCols; iCol++)
139   {
140     colNames[iCol] = table->GetColumnName(iCol);
141   }
142   return colNames;
143 }
144
145 void FillValue(vtkVariantArray *row, double *ptToFeed, std::size_t ipos, vtkIdType pos)
146 {
147   bool isOK(false);
148   vtkVariant *elt(row->GetPointer(pos));
149   ptToFeed[ipos] = elt->ToDouble(&isOK);
150   if (!isOK)
151   {
152     std::ostringstream oss;
153     oss << "vtkContactReader::FillValue : Error during analyze content of file ! Float64 expected !";
154     throw MyException(oss.str());
155   }
156 }
157
158 vtkStandardNewMacro(vtkContactReader);
159
160 vtkContactReader::vtkContactReader() : FileName(NULL), ScaleFactor(0.02),IsTimed(false)
161 {
162   this->SetNumberOfInputPorts(0);
163 }
164
165 vtkContactReader::~vtkContactReader()
166 {
167 }
168
169 int vtkContactReader::RequestInformation(vtkInformation *vtkNotUsed(request),
170                                          vtkInformationVector **vtkNotUsed(inputVector),
171                                          vtkInformationVector *outputVector)
172 {
173   vtkInformation *outInfo(outputVector->GetInformationObject(0));
174   //
175   vtkSmartPointer<vtkTable> table(LoadDataFromFile(this->FileName));
176   std::vector<std::string> colNames(GetColumnNames(table));
177   this->IsTimed = PresenceOf(colNames,INST_TAG);
178   vtkIdType nbRows(table->GetNumberOfRows());
179   if(!this->IsTimed)
180     return 1;
181   vtkIdType InstPos = PosOf(colNames, INST_TAG);
182   std::set<double> allInsts;
183   for (vtkIdType iRow = 0; iRow < nbRows; iRow++)
184   {
185     vtkVariantArray *row(table->GetRow(iRow));
186     vtkVariant *elt(row->GetPointer(InstPos));
187     allInsts.insert(elt->ToDouble());
188   }
189   std::vector<double> allInstsV(allInsts.begin(),allInsts.end());
190   double timeRange[2];
191   timeRange[0]=allInstsV.front();
192   timeRange[1]=allInstsV.back();
193   outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(),allInstsV.data(),(int)allInstsV.size());
194   outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(),timeRange,2);
195   std::for_each(colNames.begin(),colNames.end(),[](const std::string& elt) { std::cerr << elt << " ";});
196   return 1;
197 }
198
199
200 int vtkContactReader::RequestData(vtkInformation *vtkNotUsed(request),
201                                   vtkInformationVector **vtkNotUsed(inputVector),
202                                   vtkInformationVector *outputVector)
203 {
204   vtkInformation *outInfo(outputVector->GetInformationObject(0));
205   vtkPolyData *output(vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())));
206   //
207   try
208   {
209     vtkSmartPointer<vtkTable> table(LoadDataFromFile(this->FileName));
210     vtkIdType nbRows(table->GetNumberOfRows()), nbCols(table->GetNumberOfColumns());
211     std::vector<std::string> colNames(GetColumnNames(table));
212     vtkIdType XPos(PosOf(colNames, "X")), YPos(PosOf(colNames, "Y")), ZPos(PosOf(colNames, "Z")), DXPos(PosOf(colNames, "DX")), DYPos(PosOf(colNames, "DY")), DZPos(PosOf(colNames, "DZ"));
213     // check of presence of INST. If yes -> it means that input file is on different time steps.
214     vtkIdType InstPos(std::numeric_limits<vtkIdType>::max());
215     //
216     vtkSmartPointer<vtkDoubleArray> coords(vtkSmartPointer<vtkDoubleArray>::New()), vectArr(vtkSmartPointer<vtkDoubleArray>::New());
217     //
218     vtkIdType nbTuples(nbRows),startRow(0);
219     double reqTS(0.0);
220     if(this->IsTimed)
221     {
222       InstPos = PosOf(colNames, INST_TAG);
223       if(outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()))
224         reqTS=outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
225       vtkIdType iRow = 0;
226       for (; iRow < nbRows && InstValueOf(table,iRow,InstPos)!=reqTS; iRow++);
227       startRow = iRow;
228       for (; iRow < nbRows && InstValueOf(table,iRow,InstPos)==reqTS; iRow++);
229       nbTuples = iRow-startRow;
230     }
231     //
232     vectArr->SetNumberOfComponents(3);
233     coords->SetNumberOfComponents(3);
234     coords->SetNumberOfTuples(nbTuples);
235     vectArr->SetNumberOfTuples(nbTuples);
236     double *ptToFeed1(coords->Begin()), *ptToFeed2(vectArr->Begin());
237     const vtkIdType POS[3] = {XPos, YPos, ZPos}, DX[3] = {DXPos, DYPos, DZPos};
238     for (vtkIdType iRow = startRow; iRow < startRow+nbTuples; iRow++, ptToFeed1 += 3, ptToFeed2 += 3)
239     {
240       vtkVariantArray *row(table->GetRow(iRow));
241       for (std::size_t ipos = 0; ipos < 3; ipos++)
242       {
243         FillValue(row, ptToFeed1, ipos, POS[ipos]);
244         FillValue(row, ptToFeed2, ipos, DX[ipos]);
245       }
246       std::for_each(ptToFeed2, ptToFeed2 + 3, [](double &v) { v = -v; });
247     }
248     vectArr->SetName("Resultante");
249     vtkNew<vtkPolyData> ret;
250     vtkSmartPointer<vtkPoints> pts(vtkSmartPointer<vtkPoints>::New());
251     pts->SetData(coords);
252     ret->SetPoints(pts);
253     ret->GetPointData()->AddArray(vectArr);
254     //
255     vtkNew<vtkPVGlyphFilter> glyph;
256     glyph->SetInputData(ret);
257     glyph->SetGlyphMode(0);       //vtkPVGlyphFilter::ALL_POINTS
258     glyph->SetVectorScaleMode(0); //vtkPVGlyphFilter::SCALE_BY_MAGNITUDE
259     //
260     vtkNew<vtkArrowSource> arrow;
261     arrow->SetTipResolution(6);
262     arrow->SetTipRadius(0.1);
263     arrow->SetTipLength(0.35);
264     arrow->SetShaftResolution(6);
265     arrow->SetShaftRadius(0.03);
266     glyph->SetSourceConnection(arrow->GetOutputPort());
267     //idx,port,connection,fieldAssociation,name
268     glyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Resultante"); //idx==0 -> scaleArray
269     glyph->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Resultante"); //idx==1 -> orientationArray
270     glyph->SetScaleFactor(this->ScaleFactor);
271     glyph->Update();
272     output->ShallowCopy(glyph->GetOutput());
273     if(this->IsTimed)
274       output->GetInformation()->Set(vtkDataObject::DATA_TIME_STEP(),reqTS);
275     output->GetPointData()->SetActiveAttribute(0, vtkDataSetAttributes::SCALARS);
276     //output->ShallowCopy(ret);
277   }
278   catch (MyException &e)
279   {
280     vtkErrorMacro(<< "vtkContactReader::RequestData : during read of " << this->FileName << " : " << e.what());
281     return 0;
282   }
283   return 1;
284 }
285
286 void vtkContactReader::SetScaleFactor(double newScaleFactor)
287 {
288   if (this->ScaleFactor != newScaleFactor)
289   {
290     this->ScaleFactor = newScaleFactor;
291     this->Modified();
292   }
293 }
294
295 void vtkContactReader::PrintSelf(ostream &os, vtkIndent indent)
296 {
297   this->Superclass::PrintSelf(os, indent);
298 }