Salome HOME
workaround for bug #16280 / #1514: tolerance for nodes on the border fixed to 0.01...
[modules/hydro.git] / src / HYDROData / HYDROData_SinusX.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include "HYDROData_SinusX.h"
20
21 #include <HYDROData_PolylineXY.h>
22 #include <HYDROData_Bathymetry.h>
23 #include <HYDROData_Entity.h>
24 #include <HYDROData_Document.h>
25 #include <HYDROData_Profile.h>
26 #include <HYDROData_Iterator.h>
27
28 #include <gp_XYZ.hxx>
29 #include <gp_XY.hxx>
30
31 #include <QFile>
32 #include <QFileInfo>
33 #include <QString>
34 #include <QStringList>
35 #include <QTextStream>
36 #include <QColor>
37
38 HYDROData_SinusX::HYDROData_SinusX( ) 
39 {
40 }
41
42 HYDROData_SinusX::~HYDROData_SinusX()
43 {
44 }
45
46 void HYDROData_SinusX::CollectExistingNames(Handle(HYDROData_Document) theDocument)
47 {
48   HYDROData_Iterator anIter( theDocument );
49   int anInd = 0;
50   myExistingNames.clear();
51   std::vector<int> anAllowedIndexes;
52   for( ; anIter.More(); anIter.Next() )
53     myExistingNames.push_back(anIter.Current()->GetName());
54 }
55
56 QString HYDROData_SinusX::GetName(const QString& theName)
57 {
58   if (myExistingNames.contains(theName))
59   { 
60     QString aName = theName; 
61     while (myExistingNames.contains(aName)) 
62     {
63       QStringList aList = aName.split("_");
64       int aLastInd = aName.lastIndexOf("_");
65       bool IsNum = false; 
66       int anInd = -1;
67       anInd = aList.last().toInt(&IsNum);
68       if (IsNum)
69       {
70         aName = aName.left(aLastInd) + "_";
71         aName+= QString::number(++anInd);
72       }
73       else
74         aName = theName + "_0";
75     }
76
77     myExistingNames.push_back(aName);
78     return aName;
79   }
80   else
81   {
82     myExistingNames.push_back(theName);
83     return theName;
84   }
85
86 }
87
88
89 bool HYDROData_SinusX::Import(const QString& theFilePath, Handle(HYDROData_Document) theDocument,
90   NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities)
91 {
92   if ( theFilePath.isEmpty() )
93   { 
94     return false;
95   }
96
97   QString anExt = theFilePath.split('.', QString::SkipEmptyParts).back();
98
99   if (anExt == "sx")
100   {
101     QFile aFile (theFilePath);
102     
103     aFile.open(QIODevice::ReadOnly);
104
105     Parse(aFile);
106    
107     CollectExistingNames(theDocument);
108     SXToHydro(theDocument, theEntities);
109     
110     aFile.close();
111     
112     return true;
113   }
114   else
115     return false;
116
117 }
118
119 void HYDROData_SinusX::SXToHydro(Handle(HYDROData_Document) theDocument, NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities)
120
121   for ( size_t i = 0; i < myCurveBlocks.size(); i++ )
122   {
123     if (myCurveBlocks[i].myType == 4) ///  scatter plot -> to bathy
124     {
125       Handle(HYDROData_Bathymetry) aBath = Handle(HYDROData_Bathymetry)::DownCast( theDocument->CreateObject( KIND_BATHYMETRY ) );
126       HYDROData_Bathymetry::AltitudePoints aAPoints;
127       size_t n = myCurveBlocks[i].myXYZPoints.size();
128       aAPoints.reserve( n );
129       for (size_t j = 0; j < n; j++)
130       {
131         gp_XYZ aLocalPoint = gp_XYZ (myCurveBlocks[i].myXYZPoints[j]);
132         theDocument->Transform(aLocalPoint, true);
133         HYDROData_Bathymetry::AltitudePoint p;
134         p.X = aLocalPoint.X();
135         p.Y = aLocalPoint.Y();
136         p.Z = aLocalPoint.Z();
137         aAPoints.push_back(p);
138       }
139
140       aBath->SetAltitudePoints(aAPoints);
141       aBath->SetName(GetName(myCurveBlocks[i].myName));
142       theEntities.Append(aBath);
143     }
144     if (myCurveBlocks[i].myType == 1 || myCurveBlocks[i].myType == 3) // XYZ curve or isocontour
145     {
146       NCollection_Sequence<gp_XYZ> aPoints;
147       for (size_t j = 0; j < myCurveBlocks[i].myXYZPoints.size(); j++)
148       {
149         gp_XYZ aLocalPoint = gp_XYZ (myCurveBlocks[i].myXYZPoints[j]);
150         theDocument->Transform(aLocalPoint, true);
151         aPoints.Append(aLocalPoint);
152       }
153       /*if (myCurveBlocks[i].myIsClosed)
154         aPoints.Append(gp_XYZ (myCurveBlocks[i].myXYZPoints[0]));*/
155       Handle(HYDROData_ProfileUZ) aProfileUZ = Handle(HYDROData_ProfileUZ)::DownCast( theDocument->CreateObject( KIND_PROFILEUZ ) );
156       Handle(HYDROData_PolylineXY) aPolyXY = Handle(HYDROData_PolylineXY)::DownCast( theDocument->CreateObject( KIND_POLYLINEXY ) );
157       aPolyXY->AddSection( "",  
158         myCurveBlocks[i].myIsSpline ? HYDROData_PolylineXY::SECTION_SPLINE : HYDROData_PolylineXY::SECTION_POLYLINE, 
159         myCurveBlocks[i].myIsClosed ? true : false); 
160       aProfileUZ->CalculateAndAddPoints(aPoints, aPolyXY);
161       Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast( theDocument->CreateObject( KIND_PROFILE ) );
162       aProfile->SetParametricPoints(aProfileUZ->GetPoints());
163       aPolyXY->SetName(GetName(myCurveBlocks[i].myName));
164       aProfileUZ->SetName(GetName(myCurveBlocks[i].myName));
165       aProfile->SetName(GetName(myCurveBlocks[i].myName));
166       aPolyXY->SetWireColor(HYDROData_PolylineXY::DefaultWireColor());
167       theEntities.Append(aPolyXY);
168       theEntities.Append(aProfileUZ);
169       theEntities.Append(aProfile);
170     }
171     if (myCurveBlocks[i].myType == 2) // XYZ profile
172     {
173       if (myCurveBlocks[i].myCurvePlane == 2) // plane XoZ
174       {
175         if (myCurveBlocks[i].myAdditionalCurveInfo.size() == 4)
176         {
177           Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast( theDocument->CreateObject( KIND_PROFILE ) );
178           HYDROData_ProfileUZ::PointsList aPointList;
179           for (size_t j = 0; j < myCurveBlocks[i].myXYZPoints.size(); j++)
180             aPointList.Append(gp_XY (myCurveBlocks[i].myXYZPoints[j].X(), myCurveBlocks[i].myXYZPoints[j].Z()));
181           aProfile->GetProfileUZ()->SetSectionType(0,  myCurveBlocks[i].myIsSpline ? HYDROData_PolylineXY::SECTION_SPLINE : HYDROData_PolylineXY::SECTION_POLYLINE);
182           aProfile->GetProfileUZ()->SetSectionClosed(0, myCurveBlocks[i].myIsClosed ? true : false);
183           aProfile->SetParametricPoints(aPointList);
184           if ( ! (myCurveBlocks[i].myAdditionalCurveInfo[0] == 0 &&  myCurveBlocks[i].myAdditionalCurveInfo[1] == 0 && 
185             myCurveBlocks[i].myAdditionalCurveInfo[2] == 0 && myCurveBlocks[i].myAdditionalCurveInfo[3] == 0) )
186           { // georeferenced profile
187             double xl = myCurveBlocks[i].myAdditionalCurveInfo[0];
188             double yl = myCurveBlocks[i].myAdditionalCurveInfo[1];
189             double xr = myCurveBlocks[i].myAdditionalCurveInfo[2];
190             double yr = myCurveBlocks[i].myAdditionalCurveInfo[3];
191             theDocument->Transform(xl, yl , true);
192             theDocument->Transform(xr, yr , true);
193             aProfile->SetLeftPoint(gp_XY(xl, yl));
194             aProfile->SetRightPoint(gp_XY(xr, yr));
195             aProfile->Update();
196           }
197           aProfile->SetName(GetName(myCurveBlocks[i].myName));
198           theEntities.Append(aProfile);
199         }
200       }
201       if (myCurveBlocks[i].myCurvePlane == 0) // plane XoY
202       {
203         Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast( theDocument->CreateObject( KIND_PROFILE ) );
204         HYDROData_Profile::ProfilePoints aPointList;
205         for (size_t j = 0; j < myCurveBlocks[i].myXYZPoints.size(); j++)
206         {
207           gp_XYZ aLocalPoint = gp_XYZ (myCurveBlocks[i].myXYZPoints[j]);
208           theDocument->Transform(aLocalPoint, true);
209           aPointList.Append(aLocalPoint);
210         }
211         aProfile->GetProfileUZ()->SetSectionType(0,  myCurveBlocks[i].myIsSpline ? HYDROData_PolylineXY::SECTION_SPLINE : HYDROData_PolylineXY::SECTION_POLYLINE);
212         aProfile->GetProfileUZ()->SetSectionClosed(0, myCurveBlocks[i].myIsClosed ? true : false);
213         aProfile->SetProfilePoints(aPointList);
214         aProfile->SetName(GetName(myCurveBlocks[i].myName));
215         theEntities.Append(aProfile);
216       }
217     }
218   }
219
220 }
221  
222
223 bool HYDROData_SinusX::Parse(QFile& theFile)
224 {
225   if ( !theFile.isOpen() )
226     return false;
227
228   QString aLine;
229   QString aBLine;
230   QStringList aList;
231   QStringList aBList;
232   myCurveBlocks.clear();
233   bool aTotStat = true;
234
235   aLine = theFile.readLine().simplified();
236   aList = aLine.split( ' ', QString::SkipEmptyParts );
237
238   for (;!theFile.atEnd();) 
239   {
240     if (aList[0] == "B" && (aList[1] == "C" || aList[1] == "P" || aList[1] == "N" || aList[1] == "S" ))
241     {  
242       HYDROGUI_CurveBlock aCurveBlockInfo;
243       if (aList[1] == "C")
244         aCurveBlockInfo.myType = 1; // XYZ curve
245       else if (aList[1] == "P")
246         aCurveBlockInfo.myType = 2; // XYZ profile
247       else if (aList[1] == "N")
248         aCurveBlockInfo.myType = 3; // isocontour
249       else if (aList[1] == "S")
250         aCurveBlockInfo.myType = 4; // Scatter plot
251
252       if (aList.size() == 9)
253       {
254         for (int j = 2; j < 8; j++)
255           aCurveBlockInfo.myRefCoords.push_back(aList[j].toDouble());
256         aCurveBlockInfo.myRefRatio = aList[8].toDouble();
257       }
258
259       QString Name;
260       do
261       {
262         aBLine = theFile.readLine().simplified();
263         aBList = aBLine.split( ' ', QString::SkipEmptyParts );
264          
265         if (aBList[0] == "CP")
266         {
267           if (aBList.size() == 2 && (aBList[1] == "0" || aBList[1] == "1" || aBList[1] == "2"))
268             aCurveBlockInfo.myCurvePlane = aBList[1].toInt();
269           else if (aBList.size() == 3 && (aBList[1] == "0" || aBList[1] == "1") && (aBList[2] == "0" || aBList[2] == "1"))
270           {
271             aCurveBlockInfo.myIsClosed = aBList[1].toInt();
272             aCurveBlockInfo.myIsSpline = aBList[2].toInt();
273           }
274           else
275           {
276             for (int j = 1; j < aBList.size(); j++)
277               aCurveBlockInfo.myAdditionalCurveInfo.push_back(aBList[j].toDouble());
278           }
279         }
280         if (aBList[0] == "CN")
281         {
282            for (int i = 1; i < aBList.size(); i++)
283              Name += aBList[i] + "_";
284            if (Name.size() <= 1)
285              Name = "noname_";
286            Name.remove(Name.size() - 1, 1);
287            aCurveBlockInfo.myName = Name;
288         }
289       } while (!theFile.atEnd() && aBLine[0] == 'C' );
290
291       bool aStat;
292       aTotStat = true;
293       do
294       {
295         if (aBList.size() >= 3 && aBLine[0] != 'B' && aBLine[0] != 'C') {
296           gp_XYZ anXYZ;
297           anXYZ.SetX (aBList[0].toDouble(&aStat));  
298           aTotStat = aTotStat && aStat;
299           anXYZ.SetY (aBList[1].toDouble(&aStat));
300           aTotStat = aTotStat && aStat;
301           anXYZ.SetZ (aBList[2].toDouble(&aStat));
302           aTotStat = aTotStat && aStat;
303
304           aCurveBlockInfo.myXYZPoints.push_back(anXYZ);
305           
306           aBLine = theFile.readLine().simplified();
307           aBList = aBLine.split( ' ', QString::SkipEmptyParts );
308         }
309         else 
310           break;
311     
312       } while (!theFile.atEnd() || !aBLine.isEmpty());
313       if (aTotStat)
314         myCurveBlocks.push_back(aCurveBlockInfo);
315
316       aLine = aBLine;
317       aList = aBList;
318
319     }
320     else
321     {
322       aLine = theFile.readLine().simplified();
323       aList = aLine.split( ' ', QString::SkipEmptyParts );
324     }
325
326   }
327
328   return true;
329
330 }
331
332 bool HYDROData_SinusX::Export(const QString& theFilePath, const NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities)
333 {
334   if ( theFilePath.isEmpty() )
335   { 
336     return false;
337   }
338
339   QString anExt = theFilePath.split('.', QString::SkipEmptyParts).back();
340
341   if (anExt == "sx")
342   {
343     QFile aFile (theFilePath);
344     
345     aFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
346
347     HydroToSX(aFile, theEntities);
348     
349     aFile.close();
350     
351     return true;
352   }
353   else
354     return false;
355
356 }
357
358 void HYDROData_SinusX::HydroToSX(QFile& theFile, const NCollection_Sequence<Handle(HYDROData_Entity)>& theEntities)
359 {
360   QTextStream aTextStream(&theFile);
361   aTextStream << "C  Generated by HYDRO Module\n";
362   aTextStream << "C\n";
363
364   for (int i = 1; i <= theEntities.Size(); i++)
365   {
366     Handle(HYDROData_Entity) anEnt = theEntities.Value(i);
367     if (anEnt->IsKind( STANDARD_TYPE(HYDROData_Bathymetry) ))
368     {
369       Handle(HYDROData_Bathymetry) aBathy = Handle(HYDROData_Bathymetry)::DownCast( anEnt );
370       HYDROData_Bathymetry::AltitudePoints anXYZPoints = aBathy->GetAltitudePoints(true);
371       //Write to stream
372       aTextStream << "B S\n";
373       aTextStream << "CN " << aBathy->GetName() << "\n";
374       aTextStream << "CP 0 0\n";
375       aTextStream << "CP 0\n";
376       for (size_t j = 0, m = anXYZPoints.size(); j < m; j++)
377         aTextStream << " " << QString::number(anXYZPoints[j].X, 'f', 3)  
378                     << " " << QString::number(anXYZPoints[j].Y, 'f', 3)  
379                     << " " << QString::number(anXYZPoints[j].Z, 'f', 3) << "\n"; 
380     }
381     else if (anEnt->IsKind( STANDARD_TYPE(HYDROData_PolylineXY) ))
382     {
383       Handle(HYDROData_PolylineXY) aPolyXY = Handle(HYDROData_PolylineXY)::DownCast( anEnt );
384       for (int j = 0; j < aPolyXY->NbSections(); j++)
385       { 
386         //Collect data
387         bool IsClosed = aPolyXY->IsClosedSection(j);
388         bool IsSpline = false;
389         if (aPolyXY->GetSectionType(j) == HYDROData_PolylineXY::SECTION_SPLINE)
390           IsSpline = true;
391         HYDROData_PolylineXY::PointsList anXYPoints = aPolyXY->GetPoints(j, true);
392         //Write to stream
393         aTextStream << "B N\n";
394         aTextStream << "CN " << aPolyXY->GetName() << "\n";
395         aTextStream << "CP " << IsClosed << " " << IsSpline << "\n";
396         aTextStream << "CP 0.0\n";
397         aTextStream << "CP 0\n";
398         if (aPolyXY->NbSections() > 1)
399           aTextStream << "C " << aPolyXY->GetName() << "_section_" << QString::number(j) << "\n";
400         for (int k = anXYPoints.Lower(); k <= anXYPoints.Upper(); k++)
401          aTextStream << " " << QString::number(anXYPoints(k).X(), 'f', 3)  
402                      << " " << QString::number(anXYPoints(k).Y(), 'f', 3)  
403                      << " 0.000\n"; 
404       }
405     }
406     else if (anEnt->IsKind( STANDARD_TYPE(HYDROData_Profile) ))
407     {
408       //Collect data
409       Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast( anEnt );
410       HYDROData_ProfileUZ::PointsList aPointList = aProfile->GetParametricPoints();
411       bool IsClosed = aProfile->GetProfileUZ(false)->IsClosedSection(0);;
412       bool IsSpline = false;
413       if (aProfile->GetProfileUZ(false)->GetSectionType(0) == HYDROData_PolylineXY::SECTION_SPLINE)
414         IsSpline = true;
415       //Write to stream
416       aTextStream << "B P\n";
417       aTextStream << "CN " << aProfile->GetName() << "\n";
418       aTextStream << "CP " << IsClosed << " " << IsSpline << "\n";
419       gp_XY aLeftPoint(0.0, 0.0);
420       gp_XY aRightPoint(0.0, 0.0);
421       if (aProfile->GetLeftPoint(aLeftPoint, true) && aProfile->GetRightPoint(aRightPoint, true))
422         aTextStream << "CP " << QString::number(aLeftPoint.X(), 'f', 3) << " " <<
423                                 QString::number(aLeftPoint.Y(), 'f', 3) << " " <<
424                                 QString::number(aRightPoint.X(), 'f', 3) << " " <<
425                                 QString::number(aRightPoint.Y(), 'f', 3) << "\n";
426       else
427         aTextStream << "CP 0.0 0.0 0.0 0.0\n";
428       aTextStream << "CP 2\n";
429       for (int k = aPointList.Lower(); k <= aPointList.Upper(); k++)
430          aTextStream << " " << QString::number(aPointList(k).X(), 'f', 3)  
431                      << " 0.000 "
432                      << QString::number(aPointList(k).Y(), 'f', 3) << "\n";  
433     }
434   }
435 }