Salome HOME
Merge from BR_V5_DEV 16Feb09
[modules/visu.git] / src / CONVERTOR / VISU_TableReader.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  VISU OBJECT : interactive object for VISU entities implementation
23 //  File:
24 //  Author:
25 //  Module : VISU
26 //
27 #include "VISU_TableReader.hxx"
28
29 #include <QFileInfo>
30 #include <QString>
31 #include <QRegExp>
32 #include <QFile>
33 #include <QStringList>
34
35 #include <fstream>
36 #include <iostream>
37 #include <strstream>
38
39 #include <vtkPoints.h>
40 #include <vtkDoubleArray.h>
41 #include <vtkPointData.h>
42 #include <vtkCellData.h>
43 #include <vtkPolyData.h>
44
45 #include <vtkStructuredGrid.h>
46 #include <vtkStructuredGridGeometryFilter.h>
47
48 #ifdef _DEBUG_
49 static int MYDEBUG = 0;
50 #else
51 static int MYDEBUG = 0;
52 #endif
53
54
55 //---------------------------------------------------------------
56 int
57 VISU::TTable2D
58 ::Check()
59 {
60   if ( myRows.empty() ) 
61     return 0;
62
63   int iEnd = myRows[0].myValues.size();
64   if ( iEnd == 0 )
65     return 0;
66
67   if ( myColumnTitles.size() != iEnd ) 
68     myColumnTitles.resize( iEnd );
69
70   if ( myColumnUnits.size() != iEnd )
71     myColumnUnits.resize( iEnd );
72
73   int jEnd = myRows.size();
74   for ( int j = 0; j < jEnd; j++ )
75     if ( myRows[j].myValues.size() != iEnd )
76       return 0;
77
78   return 1;
79 }
80
81
82 //---------------------------------------------------------------
83 void
84 VISU::TTable2D
85 ::getColumns(VISU::TTable2D& theTable2D) const
86 {
87   TRows& aRows = theTable2D.myRows;
88   aRows.clear();
89   if ( myRows.empty() )
90     return;
91
92   int jEnd = myRows.size();
93
94   //Define Titles & Units
95   theTable2D.myColumnTitles.resize(jEnd);
96   theTable2D.myColumnUnits.resize(jEnd);
97   for ( int j = 0; j < jEnd; j++ ) {
98     theTable2D.myColumnTitles[j] = myRows[j].myTitle;
99     theTable2D.myColumnUnits[j] = myRows[j].myUnit;
100   }
101
102   //Define Rows
103   int iEnd = myRows[0].myValues.size();
104   for ( int i = 0; i < iEnd; i++ ) {
105     TRow aNewRow;
106     aNewRow.myTitle = myColumnTitles[i];
107     aNewRow.myUnit = myColumnUnits[i];
108     aNewRow.myValues.resize(jEnd);
109     for ( int j = 0; j < jEnd; j++ ) {
110       aNewRow.myValues[j] = myRows[j].myValues[i];
111     }
112     aRows.push_back(aNewRow);
113   }
114 }
115
116
117 //---------------------------------------------------------------
118 namespace
119 {
120   int getLine( std::ifstream& theStmIn, QString& theString )
121   {
122     char tmp;
123     std::ostrstream aStrOut;
124
125     while ( theStmIn.get( tmp ) ) {
126       aStrOut<<tmp;
127       if ( tmp == '\n' ) 
128         break;
129     }
130
131     aStrOut<<std::ends;
132     theString = aStrOut.str();
133
134     return !theStmIn.eof();
135   }
136 }
137
138
139 //---------------------------------------------------------------
140 void 
141 VISU::ImportTables( const char* theFileName, TTableContainer& theContainer )
142 {
143   std::ifstream aStmIn;
144   QFileInfo aFileInfo( theFileName );
145   if( !aFileInfo.isFile() || !aFileInfo.isReadable() || !aFileInfo.size() )
146     return;
147
148   aStmIn.open( theFileName );
149   QString aTmp;
150   do {
151     // find beginning of table (tables are separated by empty lines)
152     while( ::getLine( aStmIn, aTmp ) && aTmp.trimmed() == "");
153
154     PTableIDMapper aTableIDMapper( new TTableIDMapper() );
155     TTable2D& aTable2D = *aTableIDMapper;
156     if(MYDEBUG) std::cout << "New table is found" << std::endl;
157
158     while( !aStmIn.eof() && aTmp.trimmed() != "" ){
159       QString data = aTmp.trimmed();
160       QString cmt = "";
161       QString keyword = "";
162       // split string to data and comment (comment starts from '#' symbol)
163       int index = aTmp.indexOf( "#" );
164       if ( index >= 0 ) {
165         data = aTmp.left( index ).trimmed();
166         cmt = aTmp.mid( index+1 ).trimmed();
167       }
168       // if comment is not empty, try to get keyword from it (separated by ':' symbol)
169       if ( !cmt.isEmpty() ) {
170         int index1 = cmt.indexOf( ":" );
171         if ( index1 >= 0 ) {
172           QString tmpstr = cmt.left( index1 ).trimmed();
173           if ( tmpstr == QString( "TITLE" ) ||
174                tmpstr == QString( "COLUMN_TITLES" ) ||
175                tmpstr == QString( "COLUMN_UNITS" ) ||
176                tmpstr == QString( "COMMENT" ) ) {
177             keyword = tmpstr;
178             cmt = cmt.mid( index1+1 ).trimmed();
179           }
180         }
181       }
182       // if data is empty, process only comment
183       if ( data.isEmpty() ) {
184         // if keyword is found, try to process it
185         // elsewise it is a simple comment, just ignore it
186         if ( !keyword.isEmpty() ) {
187           if ( keyword == QString( "TITLE" ) ) {
188             QString title = cmt;
189             if ( aTable2D.myTitle != "" )
190               title = QString( aTable2D.myTitle.c_str() ) + QString( " " ) + title;
191             if(MYDEBUG) std::cout << "...Table TITLE is: " << title.toLatin1().constData() << std::endl;
192             aTable2D.myTitle = title.toLatin1().constData();
193           }
194           else if ( keyword == QString( "COLUMN_TITLES" ) ) {
195             // comment may contain column headers
196             QStringList aStrList = cmt.split( "|", QString::SkipEmptyParts );
197             if(MYDEBUG) std::cout << "...Column TITLES are: ";
198             for ( int i = 0; i < aStrList.count(); i++ ) {
199               QString tmpstr = aStrList[ i ].trimmed();
200               if(MYDEBUG) std::cout << tmpstr.toLatin1().constData() << " ";
201               aTable2D.myColumnTitles.push_back( tmpstr.toLatin1().constData() );
202             }
203             if(MYDEBUG) std::cout << std::endl;
204           }
205           else if ( keyword == QString( "COLUMN_UNITS" ) ) {
206             // comment may contain column units
207             QStringList aStrList = cmt.split( " ", QString::SkipEmptyParts );
208             if(MYDEBUG) std::cout << "...Column UNITS are: ";
209             for ( int i = 0; i < aStrList.count(); i++ ) {
210               QString tmpstr = aStrList[ i ].trimmed();
211               if(MYDEBUG) std::cout << tmpstr.toLatin1().constData() << " ";
212               aTable2D.myColumnUnits.push_back( tmpstr.toLatin1().constData() );
213             }
214             if(MYDEBUG) std::cout << std::endl;
215           }
216           else if ( keyword == QString( "COMMENT" ) ) {
217             // keyword 'COMMENT' processing can be here
218             // currently it is ignored
219             if(MYDEBUG) std::cout << "...COMMENT: " << cmt.toLatin1().constData() << std::endl;
220           }
221         }
222         else {
223           if(MYDEBUG) std::cout << "...comment: " << cmt.toLatin1().constData() << std::endl;
224           // simple comment processing can be here
225           // currently it is ignored
226         }
227       }
228       // if data is not empty, try to process it
229       else {
230         TTable2D::TRow aRow;
231         if(MYDEBUG) std::cout << "...New row is found: " << std::endl;
232         if ( !cmt.isEmpty() ) {
233           aRow.myTitle = cmt.toLatin1().constData();
234           if(MYDEBUG) std::cout << "......ROW TITLE is: " << cmt.toLatin1().constData() << std::endl;
235         }
236         QString datar1 = data.replace(QRegExp("\t"), " ");
237         QStringList aValList = datar1.split( " ", QString::SkipEmptyParts );
238         for ( int i = 0; i < aValList.count(); i++ ) {
239           if ( aValList[i].trimmed() != "" ) {
240             TTable2D::TValue aVal = aValList[i].trimmed().toLatin1().constData();
241             aRow.myValues.push_back( aVal );
242           }
243         }
244         if( aRow.myValues.size() > 0 )
245           aTable2D.myRows.push_back( aRow );
246         // ************** OLD CODE ******************
247         /*
248         TValue aVal;
249         istrstream aStream( data );
250         aStream.precision( STRPRECISION );
251         while( aStream >> aVal ) {
252           aRow.myValues.push_back( aVal );
253         }
254         if( aRow.myValues.size() > 0 )
255           aTable2D.myRows.push_back( aRow );
256         */
257         // ************** OLD CODE ******************
258       }
259       ::getLine( aStmIn, aTmp );
260     }
261     if( aTable2D.Check() ) {
262       if(MYDEBUG) std::cout << "aTable2D is checked OK " << aTable2D.myTitle << std::endl;
263       theContainer.push_back( aTableIDMapper );
264     }
265   } while ( !aStmIn.eof() );
266   aStmIn.close();
267
268   if(MYDEBUG) std::cout << "After close" << std::endl;
269 }
270
271
272 //---------------------------------------------------------------
273 VISU::TTableIDMapper
274 ::TTableIDMapper():
275   myOutput( vtkPolyData::New() ),
276   myXAxisPosition( -1 )
277 {}
278
279 VISU::TTableIDMapper
280 ::~TTableIDMapper()
281 {
282   myOutput->Delete();
283 }
284
285 vtkPolyData*
286 VISU::TTableIDMapper
287 ::GetPolyDataOutput()
288 {
289   if ( myXAxisPosition == -1 )
290     SetXAxisPosition( 0 );
291
292   return myOutput;
293 }
294
295 long unsigned int
296 VISU::TTableIDMapper
297 ::GetMemorySize()
298 {
299   return myOutput->GetActualMemorySize() * 1024;
300 }
301
302 void
303 VISU::TTableIDMapper
304 ::SetXAxisPosition( vtkIdType theAxisPosition )
305 {
306   if ( myXAxisPosition == theAxisPosition || !Check() )
307     return;
308
309   myOutput->Initialize();
310
311   if ( !Check() )
312     return;
313
314   TTable2D aTable2D;
315   getColumns( aTable2D );
316   
317   vtkIdType aXSize = aTable2D.myRows[0].myValues.size();
318
319   // It is necessary to decrease the size at 1 take intoa account X axis
320   vtkIdType anYSize = aTable2D.myRows.size() - 1; 
321
322   vtkIdType aNbPoints = aXSize * anYSize;
323
324   std::vector<double> anXAxis(aXSize);
325   const TTable2D::TValues& aValues = aTable2D.myRows[theAxisPosition].myValues;
326   for ( vtkIdType aX = 0; aX < aXSize; aX++ )
327     anXAxis[aX] = atof( aValues[aX].c_str() );
328
329   double aXRange = anXAxis[aXSize - 1] - anXAxis[0];
330   double anYDelta = aXRange / anYSize;
331   std::vector<double> anYAxis(anYSize);
332   for ( vtkIdType anY = 0; anY < anYSize; anY++ )
333     anYAxis[anY] = anY * anYDelta;
334
335   vtkPoints* aPoints = vtkPoints::New();
336   aPoints->SetNumberOfPoints( aNbPoints );
337
338   vtkIntArray *aPointsIDMapper = vtkIntArray::New();
339   aPointsIDMapper->SetName("VISU_POINTS_MAPPER");
340   aPointsIDMapper->SetNumberOfComponents(2);
341   aPointsIDMapper->SetNumberOfTuples(aNbPoints);
342   int *aPointsIDMapperPtr = aPointsIDMapper->GetPointer(0);
343
344   //vtkIntArray *aCellIDMapper = vtkIntArray::New();
345   //aCellIDMapper->SetName("VISU_POINTS_MAPPER");
346   //aCellIDMapper->SetNumberOfComponents(2);
347   //aCellIDMapper->SetNumberOfTuples(aNbPoints);
348   //int *aCellIDMapperPtr = aCellIDMapper->GetPointer(0);
349
350   for ( vtkIdType aY = 0, aPntId = 0; aY < anYSize; aY++ ) {
351     for ( vtkIdType aX = 0; aX < aXSize; aX++, aPntId++ ) {
352       aPoints->SetPoint( aPntId, anXAxis[aX], anYAxis[aY], 0.0 );
353
354       *aPointsIDMapperPtr++ = aPntId;
355       *aPointsIDMapperPtr++ = 0;
356
357       //*aCellIDMapperPtr++ = aPntId;
358       //*aCellIDMapperPtr++ = 0;
359     }
360   }
361
362   std::vector<TValues> anYData;
363   for ( vtkIdType anY = 0; anY < anYSize + 1; anY++ ) {
364     if ( anY == theAxisPosition )
365       continue;
366     anYData.push_back( aTable2D.myRows[anY].myValues );
367   }
368
369   vtkDoubleArray* aScalars = vtkDoubleArray::New();
370   aScalars->SetNumberOfComponents( 1 );
371   aScalars->SetNumberOfTuples( aNbPoints );
372   double *aScalarsPtr = aScalars->GetPointer(0);
373   for ( vtkIdType anY = 0; anY < anYSize; anY++ ) {
374     const TTable2D::TValues& aValues = anYData[anY];
375     for ( vtkIdType aX = 0; aX < aXSize; aX++ ) {
376       double aValue = atof( aValues[aX].c_str() );
377       *aScalarsPtr++ = aValue;
378     }
379   }
380
381   vtkStructuredGrid* aStructuredGrid = vtkStructuredGrid::New();
382   aStructuredGrid->SetPoints( aPoints );
383   aPoints->Delete();
384
385   aStructuredGrid->SetDimensions( aXSize, anYSize, 1 );
386
387   aStructuredGrid->GetPointData()->AddArray( aPointsIDMapper );
388   aPointsIDMapper->Delete();
389
390   //aStructuredGrid->GetCellData()->AddArray( aCellIDMapper );
391   //aCellIDMapper->Delete();
392
393   aStructuredGrid->GetPointData()->SetScalars( aScalars );
394   aScalars->Delete();
395
396   vtkStructuredGridGeometryFilter* aFilter = vtkStructuredGridGeometryFilter::New();
397   aFilter->SetInput( aStructuredGrid );
398   aFilter->Update();
399   myOutput->ShallowCopy( aFilter->GetOutput() );
400   aFilter->Delete();
401 }