1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // VISU OBJECT : interactive object for VISU entities implementation
25 #include "VISU_TableReader.hxx"
31 #include <QStringList>
37 #include <vtkPoints.h>
38 #include <vtkDoubleArray.h>
39 #include <vtkPointData.h>
40 #include <vtkCellData.h>
41 #include <vtkPolyData.h>
43 #include <vtkStructuredGrid.h>
44 #include <vtkStructuredGridGeometryFilter.h>
46 #include <Basics_Utils.hxx>
49 static int MYDEBUG = 0;
51 static int MYDEBUG = 0;
55 //---------------------------------------------------------------
63 int iEnd = myRows[0].myValues.size();
67 if ( myColumnTitles.size() != iEnd )
68 myColumnTitles.resize( iEnd );
70 if ( myColumnUnits.size() != iEnd )
71 myColumnUnits.resize( iEnd );
73 int jEnd = myRows.size();
74 for ( int j = 0; j < jEnd; j++ )
75 if ( myRows[j].myValues.size() != iEnd )
82 //---------------------------------------------------------------
85 ::getColumns(VISU::TTable2D& theTable2D) const
87 TRows& aRows = theTable2D.myRows;
92 int jEnd = myRows.size();
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;
103 int iEnd = myRows[0].myValues.size();
104 for ( int i = 0; i < iEnd; i++ ) {
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];
112 aRows.push_back(aNewRow);
117 //---------------------------------------------------------------
120 int getLine( std::ifstream& theStmIn, QString& theString )
123 std::ostringstream aStrOut;
125 while ( theStmIn.get( tmp ) ) {
132 theString = aStrOut.str().c_str();
134 return !theStmIn.eof();
137 //=======================================================================
138 //function : findNextCell
139 //purpose : auxilary for ImportCSVTable
140 //=======================================================================
141 bool findNextCell(std::ifstream& aStmIn, QString& aStr,
142 QString& aCell, const char theSeparator)
145 int index, tmpind = 0;
146 if( aStr.at(0) == theSeparator ) {
148 aStr = aStr.trimmed();
149 if(aStr.size()==0) return true;
152 if( aTmp.at(0) == '"' ) {
154 while( !aStmIn.eof() ) {
155 tmpind = aTmp.indexOf('"',1);
157 while( !aStmIn.eof() ) {
158 aCell.push_back(aTmp);
159 aCell.push_back('\n');
160 getLine( aStmIn, aTmp );
161 tmpind = aTmp.indexOf('"',1);
170 if( aTmp.at(tmpind+1) == '"' ) {
171 // "" is found => need to continue
172 aCell.push_back(aTmp.left(tmpind+1));
173 aTmp = aTmp.mid(tmpind+2);
175 else if( aTmp.at(tmpind+1) == theSeparator ) {
185 // find index for separator
186 index = aTmp.indexOf( theSeparator );
193 if(index>0) aCell += aTmp.left(index);
194 aStr = aTmp.mid(index).trimmed();
196 if( aCell.size()>0 && aCell.at(0) == '"' ) {
197 // remove first and last symbols
198 int last = aCell.size()-1;
199 aCell.remove(last,1);
202 // replace "" to " in aCell
206 index = aCell.indexOf(tmp);
208 aCell.remove(index,1);
209 index = aCell.indexOf(tmp);
217 //---------------------------------------------------------------
219 VISU::ImportTables( const char* theFileName, TTableContainer& theContainer,
220 bool theFirstStrAsTitle)
222 std::ifstream aStmIn;
223 QFileInfo aFileInfo( theFileName );
224 if( !aFileInfo.isFile() || !aFileInfo.isReadable() || !aFileInfo.size() )
227 QString tmp(theFileName);
229 tmp = tmp.right(3).trimmed();
231 if( tmp == QString("csv") ) {
232 const char separator = ',';
233 ImportCSVTable(theFileName, theContainer, theFirstStrAsTitle, separator);
237 aStmIn.open( theFileName );
240 // find beginning of table (tables are separated by empty lines)
241 while( getLine( aStmIn, aTmp ) && aTmp.trimmed() == "" );
243 PTableIDMapper aTableIDMapper( new TTableIDMapper() );
244 TTable2D& aTable2D = *aTableIDMapper;
245 if(MYDEBUG) std::cout << "New table is found" << std::endl;
248 while( !aStmIn.eof() && aTmp.trimmed() != "" ){
249 QString data = aTmp.trimmed();
251 QString keyword = "";
252 // split string to data and comment (comment starts from '#' symbol)
253 int index = aTmp.indexOf( "#" );
255 data = aTmp.left( index ).trimmed();
256 cmt = aTmp.mid( index+1 ).trimmed();
258 // if comment is not empty, try to get keyword from it (separated by ':' symbol)
259 if ( !cmt.isEmpty() ) {
260 int index1 = cmt.indexOf( ":" );
262 QString tmpstr = cmt.left( index1 ).trimmed();
263 if ( tmpstr == QString( "TITLE" ) ||
264 tmpstr == QString( "COLUMN_TITLES" ) ||
265 tmpstr == QString( "COLUMN_UNITS" ) ||
266 tmpstr == QString( "COMMENT" ) ) {
268 cmt = cmt.mid( index1+1 ).trimmed();
272 // if data is empty, process only comment
273 if ( data.isEmpty() ) {
274 // if keyword is found, try to process it
275 // elsewise it is a simple comment, just ignore it
276 if ( !keyword.isEmpty() ) {
277 if ( keyword == QString( "TITLE" ) ) {
279 if ( aTable2D.myTitle != "" )
280 title = QString( aTable2D.myTitle.c_str() ) + QString( " " ) + title;
281 if(MYDEBUG) std::cout << "...Table TITLE is: " << title.toLatin1().constData() << std::endl;
282 aTable2D.myTitle = title.toLatin1().constData();
284 else if ( keyword == QString( "COLUMN_TITLES" ) ) {
285 // comment may contain column headers
286 QStringList aStrList = cmt.split( "|", QString::SkipEmptyParts );
287 if(MYDEBUG) std::cout << "...Column TITLES are: ";
288 for ( int i = 0; i < aStrList.count(); i++ ) {
289 QString tmpstr = aStrList[ i ].trimmed();
290 if(MYDEBUG) std::cout << tmpstr.toLatin1().constData() << " ";
291 aTable2D.myColumnTitles.push_back( tmpstr.toLatin1().constData() );
293 if(MYDEBUG) std::cout << std::endl;
295 else if ( keyword == QString( "COLUMN_UNITS" ) ) {
296 // comment may contain column units
297 QStringList aStrList = cmt.split( " ", QString::SkipEmptyParts );
298 if(MYDEBUG) std::cout << "...Column UNITS are: ";
299 for ( int i = 0; i < aStrList.count(); i++ ) {
300 QString tmpstr = aStrList[ i ].trimmed();
301 if(MYDEBUG) std::cout << tmpstr.toLatin1().constData() << " ";
302 aTable2D.myColumnUnits.push_back( tmpstr.toLatin1().constData() );
304 if(MYDEBUG) std::cout << std::endl;
306 else if ( keyword == QString( "COMMENT" ) ) {
307 // keyword 'COMMENT' processing can be here
308 // currently it is ignored
309 if(MYDEBUG) std::cout << "...COMMENT: " << cmt.toLatin1().constData() << std::endl;
313 if(MYDEBUG) std::cout << "...comment: " << cmt.toLatin1().constData() << std::endl;
314 // simple comment processing can be here
315 // currently it is ignored
318 // if data is not empty, try to process it
321 if(MYDEBUG) std::cout << "...New row is found: " << std::endl;
322 QString datar1 = data.replace(QRegExp("\t"), " ");
323 QStringList aValList = datar1.split( " ", QString::SkipEmptyParts );
324 if( aTable2D.myColumnTitles.size()==0 && IsFirst && theFirstStrAsTitle ) {
325 for ( int i = 0; i < aValList.count(); i++ ) {
326 QString tmpstr = aValList[ i ].trimmed();
327 aTable2D.myColumnTitles.push_back( tmpstr.toLatin1().constData() );
331 if ( !cmt.isEmpty() ) {
332 aRow.myTitle = cmt.toLatin1().constData();
333 if(MYDEBUG) std::cout << "......ROW TITLE is: " << cmt.toLatin1().constData() << std::endl;
335 //QString datar1 = data.replace(QRegExp("\t"), " ");
336 //QStringList aValList = datar1.split( " ", QString::SkipEmptyParts );
337 for ( int i = 0; i < aValList.count(); i++ ) {
338 if ( aValList[i].trimmed() != "" ) {
339 TTable2D::TValue aVal = aValList[i].trimmed().toLatin1().constData();
340 aRow.myValues.push_back( aVal );
343 if( aRow.myValues.size() > 0 )
344 aTable2D.myRows.push_back( aRow );
347 // ************** OLD CODE ******************
350 istringstream aStream( data );
351 aStream.precision( STRPRECISION );
352 while( aStream >> aVal ) {
353 aRow.myValues.push_back( aVal );
355 if( aRow.myValues.size() > 0 )
356 aTable2D.myRows.push_back( aRow );
358 // ************** OLD CODE ******************
360 getLine( aStmIn, aTmp );
362 if( aTable2D.Check() ) {
363 if(MYDEBUG) std::cout << "aTable2D is checked OK " << aTable2D.myTitle << std::endl;
364 theContainer.push_back( aTableIDMapper );
366 } while ( !aStmIn.eof() );
369 if(MYDEBUG) std::cout << "After close" << std::endl;
373 //=======================================================================
374 //function : ImportCSVTable
376 //=======================================================================
377 void VISU::ImportCSVTable(const char* theFileName, TTableContainer& theContainer,
378 bool theFirstStrAsTitle, const char theSeparator)
380 std::ifstream aStmIn;
381 QFileInfo aFileInfo( theFileName );
382 if( !aFileInfo.isFile() || !aFileInfo.isReadable() || !aFileInfo.size() )
384 aStmIn.open( theFileName );
387 // find beginning of table (tables are separated by empty lines)
388 while( getLine( aStmIn, aTmp ) && aTmp.trimmed() == "" );
390 PTableIDMapper aTableIDMapper( new TTableIDMapper() );
391 TTable2D& aTable2D = *aTableIDMapper;
392 if(MYDEBUG) std::cout << "New table is found" << std::endl;
395 QStringList aValList;
397 while( !aStmIn.eof() ) {
399 if( !( findNextCell(aStmIn, aTmp, aCell, theSeparator)) ) {
402 if( aTmp.size()==0 ) {
404 aValList.push_back(aCell);
405 if( IsFirst && theFirstStrAsTitle ) {
406 for ( int i = 0; i < aValList.count(); i++ ) {
407 aTable2D.myColumnTitles.push_back( aValList[i].trimmed().toLatin1().constData() );
412 for ( int i = 0; i < aValList.count(); i++ ) {
413 if ( aValList[i].trimmed() != "" ) {
414 TTable2D::TValue aVal = aValList[i].trimmed().toLatin1().constData();
415 aRow.myValues.push_back( aVal );
418 aRow.myValues.push_back( "Empty" );
421 if( aRow.myValues.size() > 0 ) {
422 aTable2D.myRows.push_back( aRow );
425 // clear list of values and read next string
427 getLine( aStmIn, aTmp );
431 // put value to table cell
432 aValList.push_back(aCell);
436 if( aTable2D.Check() ) {
437 if(MYDEBUG) std::cout << "aTable2D is checked OK " << aTable2D.myTitle << std::endl;
438 theContainer.push_back( aTableIDMapper );
441 } while ( !aStmIn.eof() );
444 if(MYDEBUG) std::cout << "After close" << std::endl;
448 //---------------------------------------------------------------
451 myOutput( vtkPolyData::New() ),
452 myXAxisPosition( -1 )
463 ::GetPolyDataOutput()
465 if ( myXAxisPosition == -1 )
466 SetXAxisPosition( 0 );
475 return myOutput->GetActualMemorySize() * 1024;
480 ::SetXAxisPosition( vtkIdType theAxisPosition )
482 // Set "C" numeric locale to import numbers correctly
483 Kernel_Utils::Localizer loc;
485 if ( myXAxisPosition == theAxisPosition || !Check() )
488 myOutput->Initialize();
494 getColumns( aTable2D );
496 vtkIdType aXSize = aTable2D.myRows[0].myValues.size();
498 // It is necessary to decrease the size at 1 take intoa account X axis
499 vtkIdType anYSize = aTable2D.myRows.size() - 1;
501 vtkIdType aNbPoints = aXSize * anYSize;
503 std::vector<double> anXAxis(aXSize);
504 const TTable2D::TValues& aValues = aTable2D.myRows[theAxisPosition].myValues;
505 for ( vtkIdType aX = 0; aX < aXSize; aX++ )
506 anXAxis[aX] = atof( aValues[aX].c_str() );
508 double aXRange = anXAxis[aXSize - 1] - anXAxis[0];
509 double anYDelta = aXRange / anYSize;
510 std::vector<double> anYAxis(anYSize);
511 for ( vtkIdType anY = 0; anY < anYSize; anY++ )
512 anYAxis[anY] = anY * anYDelta;
514 vtkPoints* aPoints = vtkPoints::New();
515 aPoints->SetNumberOfPoints( aNbPoints );
517 vtkIntArray *aPointsIDMapper = vtkIntArray::New();
518 aPointsIDMapper->SetName("VISU_POINTS_MAPPER");
519 aPointsIDMapper->SetNumberOfComponents(2);
520 aPointsIDMapper->SetNumberOfTuples(aNbPoints);
521 int *aPointsIDMapperPtr = aPointsIDMapper->GetPointer(0);
523 //vtkIntArray *aCellIDMapper = vtkIntArray::New();
524 //aCellIDMapper->SetName("VISU_POINTS_MAPPER");
525 //aCellIDMapper->SetNumberOfComponents(2);
526 //aCellIDMapper->SetNumberOfTuples(aNbPoints);
527 //int *aCellIDMapperPtr = aCellIDMapper->GetPointer(0);
529 for ( vtkIdType aY = 0, aPntId = 0; aY < anYSize; aY++ ) {
530 for ( vtkIdType aX = 0; aX < aXSize; aX++, aPntId++ ) {
531 aPoints->SetPoint( aPntId, anXAxis[aX], anYAxis[aY], 0.0 );
533 *aPointsIDMapperPtr++ = aPntId;
534 *aPointsIDMapperPtr++ = 0;
536 //*aCellIDMapperPtr++ = aPntId;
537 //*aCellIDMapperPtr++ = 0;
541 std::vector<TValues> anYData;
542 for ( vtkIdType anY = 0; anY < anYSize + 1; anY++ ) {
543 if ( anY == theAxisPosition )
545 anYData.push_back( aTable2D.myRows[anY].myValues );
548 vtkDoubleArray* aScalars = vtkDoubleArray::New();
549 aScalars->SetNumberOfComponents( 1 );
550 aScalars->SetNumberOfTuples( aNbPoints );
551 double *aScalarsPtr = aScalars->GetPointer(0);
552 for ( vtkIdType anY = 0; anY < anYSize; anY++ ) {
553 const TTable2D::TValues& aValues = anYData[anY];
554 for ( vtkIdType aX = 0; aX < aXSize; aX++ ) {
555 double aValue = atof( aValues[aX].c_str() );
556 *aScalarsPtr++ = aValue;
560 vtkStructuredGrid* aStructuredGrid = vtkStructuredGrid::New();
561 aStructuredGrid->SetPoints( aPoints );
564 aStructuredGrid->SetDimensions( aXSize, anYSize, 1 );
566 aStructuredGrid->GetPointData()->AddArray( aPointsIDMapper );
567 aPointsIDMapper->Delete();
569 //aStructuredGrid->GetCellData()->AddArray( aCellIDMapper );
570 //aCellIDMapper->Delete();
572 aStructuredGrid->GetPointData()->SetScalars( aScalars );
575 vtkStructuredGridGeometryFilter* aFilter = vtkStructuredGridGeometryFilter::New();
576 aFilter->SetInput( aStructuredGrid );
578 myOutput->ShallowCopy( aFilter->GetOutput() );