Salome HOME
58df66860e8f4a711fe7aac6e799e811c138c3e4
[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   return 1;
196 }
197
198
199 int vtkContactReader::RequestData(vtkInformation *vtkNotUsed(request),
200                                   vtkInformationVector **vtkNotUsed(inputVector),
201                                   vtkInformationVector *outputVector)
202 {
203   vtkInformation *outInfo(outputVector->GetInformationObject(0));
204   vtkPolyData *output(vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())));
205   //
206   try
207   {
208     vtkSmartPointer<vtkTable> table(LoadDataFromFile(this->FileName));
209     vtkIdType nbRows(table->GetNumberOfRows()), nbCols(table->GetNumberOfColumns());
210     std::vector<std::string> colNames(GetColumnNames(table));
211     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"));
212     // check of presence of INST. If yes -> it means that input file is on different time steps.
213     vtkIdType InstPos(std::numeric_limits<vtkIdType>::max());
214     //
215     vtkSmartPointer<vtkDoubleArray> coords(vtkSmartPointer<vtkDoubleArray>::New()), vectArr(vtkSmartPointer<vtkDoubleArray>::New());
216     //
217     vtkIdType nbTuples(nbRows),startRow(0);
218     double reqTS(0.0);
219     if(this->IsTimed)
220     {
221       InstPos = PosOf(colNames, INST_TAG);
222       if(outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()))
223         reqTS=outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
224       vtkIdType iRow = 0;
225       for (; iRow < nbRows && InstValueOf(table,iRow,InstPos)!=reqTS; iRow++);
226       startRow = iRow;
227       for (; iRow < nbRows && InstValueOf(table,iRow,InstPos)==reqTS; iRow++);
228       nbTuples = iRow-startRow;
229     }
230     //
231     vectArr->SetNumberOfComponents(3);
232     coords->SetNumberOfComponents(3);
233     coords->SetNumberOfTuples(nbTuples);
234     vectArr->SetNumberOfTuples(nbTuples);
235     double *ptToFeed1(coords->Begin()), *ptToFeed2(vectArr->Begin());
236     const vtkIdType POS[3] = {XPos, YPos, ZPos}, DX[3] = {DXPos, DYPos, DZPos};
237     for (vtkIdType iRow = startRow; iRow < startRow+nbTuples; iRow++, ptToFeed1 += 3, ptToFeed2 += 3)
238     {
239       vtkVariantArray *row(table->GetRow(iRow));
240       for (std::size_t ipos = 0; ipos < 3; ipos++)
241       {
242         FillValue(row, ptToFeed1, ipos, POS[ipos]);
243         FillValue(row, ptToFeed2, ipos, DX[ipos]);
244       }
245       std::for_each(ptToFeed2, ptToFeed2 + 3, [](double &v) { v = -v; });
246     }
247     vectArr->SetName("Resultante");
248     vtkNew<vtkPolyData> ret;
249     vtkSmartPointer<vtkPoints> pts(vtkSmartPointer<vtkPoints>::New());
250     pts->SetData(coords);
251     ret->SetPoints(pts);
252     ret->GetPointData()->AddArray(vectArr);
253     //
254     vtkNew<vtkPVGlyphFilter> glyph;
255     glyph->SetInputData(ret);
256     glyph->SetGlyphMode(0);       //vtkPVGlyphFilter::ALL_POINTS
257     glyph->SetVectorScaleMode(0); //vtkPVGlyphFilter::SCALE_BY_MAGNITUDE
258     //
259     vtkNew<vtkArrowSource> arrow;
260     arrow->SetTipResolution(6);
261     arrow->SetTipRadius(0.1);
262     arrow->SetTipLength(0.35);
263     arrow->SetShaftResolution(6);
264     arrow->SetShaftRadius(0.03);
265     glyph->SetSourceConnection(arrow->GetOutputPort());
266     //idx,port,connection,fieldAssociation,name
267     glyph->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Resultante"); //idx==0 -> scaleArray
268     glyph->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Resultante"); //idx==1 -> orientationArray
269     glyph->SetScaleFactor(this->ScaleFactor);
270     glyph->Update();
271     output->ShallowCopy(glyph->GetOutput());
272     if(this->IsTimed)
273       output->GetInformation()->Set(vtkDataObject::DATA_TIME_STEP(),reqTS);
274     output->GetPointData()->SetActiveAttribute(0, vtkDataSetAttributes::SCALARS);
275     //output->ShallowCopy(ret);
276   }
277   catch (MyException &e)
278   {
279     vtkErrorMacro(<< "vtkContactReader::RequestData : during read of " << this->FileName << " : " << e.what());
280     return 0;
281   }
282   return 1;
283 }
284
285 void vtkContactReader::SetScaleFactor(double newScaleFactor)
286 {
287   if (this->ScaleFactor != newScaleFactor)
288   {
289     this->ScaleFactor = newScaleFactor;
290     this->Modified();
291   }
292 }
293
294 void vtkContactReader::PrintSelf(ostream &os, vtkIndent indent)
295 {
296   this->Superclass::PrintSelf(os, indent);
297 }