Salome HOME
compilation on Linux
[modules/hydro.git] / src / HYDROData / HYDROData_Polyline.cxx
1 // Copyright (C) 2007-2015  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, or (at your option) any later version.
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
23 #include <HYDROData_Polyline.h>
24 #include <HYDROData_Iterator.h>
25
26 #include <HYDROData_BSplineOperation.h>
27
28 #include <ImageComposer_MetaTypes.h>
29
30 #include <BRepBuilderAPI_MakeEdge.hxx>
31 #include <BRepBuilderAPI_MakeWire.hxx>
32 #include <gp_Pnt.hxx>
33 #include <TDataStd_Name.hxx>
34 #include <TDataStd_Integer.hxx>
35 #include <TDataStd_ByteArray.hxx>
36 #include <TDataStd_BooleanArray.hxx>
37 #include <TDataStd_IntegerArray.hxx>
38 #include <TDataStd_Real.hxx>
39 #include <TDataStd_RealArray.hxx>
40 #include <TDataStd_ExtStringArray.hxx>
41 #include <TDataStd_UAttribute.hxx>
42 #include <TDF_ListIteratorOfLabelList.hxx>
43 #include <TNaming_Builder.hxx>
44 #include <TNaming_NamedShape.hxx>
45 #include <TopoDS.hxx>
46 #include <TopoDS_Edge.hxx>
47 #include <TopoDS_Wire.hxx>
48 #include <BRep_Builder.hxx>
49 #include <TopTools_ListIteratorOfListOfShape.hxx>
50
51 #include <QStringList>
52
53 #define PYTHON_POLYLINE_ID "KIND_POLYLINE"
54
55 IMPLEMENT_STANDARD_HANDLE(HYDROData_Polyline, HYDROData_Object)
56 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Polyline, HYDROData_Object)
57
58 HYDROData_Polyline::HYDROData_Polyline()
59 : HYDROData_Object()
60 {
61 }
62
63 HYDROData_Polyline::~HYDROData_Polyline()
64 {
65 }
66
67 TopoDS_Shape HYDROData_Polyline::GetTopShape() const
68 {
69   // TODO
70   return getTopShape();
71 }
72
73 TopoDS_Shape HYDROData_Polyline::GetShape3D() const
74 {
75   // TODO
76   return getTopShape();
77 }
78
79 /**
80  * Dump object to Python script representation.
81  */
82 QStringList HYDROData_Polyline::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
83 {
84   QStringList aResList;
85
86   Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
87   if ( aDocument.IsNull() )
88     return aResList;
89                              
90   QString aDocName = aDocument->GetDocPyName();
91   QString aPolylineName = GetName();
92
93   aResList << QString( "%1 = %2.CreateObject( %3 );" )
94               .arg( aPolylineName ).arg( aDocName ).arg( PYTHON_POLYLINE_ID );
95   aResList << QString( "%1.SetName( \"%1\" );" ).arg( aPolylineName );
96
97   // Set polilyne dimension
98
99   aResList << QString( "" );
100
101   int aDim = GetDimension();
102   aResList << QString( "%1.SetDimension( %2 );" )
103               .arg( aPolylineName ).arg( aDim );
104
105   // Set polilyne data
106
107   PolylineData aPolylineData = GetPolylineData();
108   if ( !aPolylineData.isEmpty() )
109   {
110     QString aPolylineDataName = "polyline_data";
111
112     aResList << QString( "" );
113     aResList << QString( "%1 = [];" ).arg( aPolylineDataName );
114
115     PolylineData::const_iterator aDataIt = aPolylineData.constBegin();
116     for ( ; aDataIt != aPolylineData.constEnd(); ++aDataIt )
117     {
118       const PolylineSection& aSection = *aDataIt;
119
120       QString aPolylineSectName = "polyline_section";
121
122       aResList << QString( "" );
123       aResList << QString( "%1 = PolylineSection();" ).arg( aPolylineSectName );
124
125       QString aCoordsStr;
126       foreach( const double& aCoordVal, aSection.myCoords )
127         aCoordsStr += QString::number( aCoordVal ) + ", ";
128       aCoordsStr.remove( aCoordsStr.length() - 2, 2 );
129
130       aResList << QString( "" );
131
132       aResList << QString( "%1.mySectionName = \"%2\";" )
133                   .arg( aPolylineSectName )
134                   .arg( TCollection_AsciiString( aSection.mySectionName ).ToCString() );
135       aResList << QString( "%1.myType = %2;" )
136                   .arg( aPolylineSectName ).arg( aSection.myType );
137       aResList << QString( "%1.myIsClosed = %2;" )
138                   .arg( aPolylineSectName ).arg( aSection.myIsClosed );
139       aResList << QString( "%1.myCoords = [ %2 ];" )
140                   .arg( aPolylineSectName ).arg( aCoordsStr );
141
142       aResList << QString( "%1.append( %2 );" )
143                   .arg( aPolylineDataName ).arg( aPolylineSectName );
144     }
145     aResList << QString( "" );
146
147     aResList << QString( "%1.SetPolylineData( %2 );" )
148                   .arg( aPolylineName ).arg( aPolylineDataName );
149   }
150
151   return aResList;
152 }
153
154 QVariant HYDROData_Polyline::GetDataVariant()
155 {
156   QPainterPath aPath = GetPainterPath();
157
158   QVariant aVarData;
159   aVarData.setValue<QPainterPath>( aPath );
160   
161   return aVarData;
162 }
163
164 /**
165  * Replace current polyline data by new sections list
166  * \param theSections the sections list
167  */
168 void HYDROData_Polyline::SetPolylineData( const PolylineData& theSections )
169 {
170 //Keep dimension
171   int aDim = GetDimension();
172   if( aDim == 0 )
173       return;
174   RemoveAll();
175   SetDimension(aDim);
176
177   if( theSections.size() == 0 )
178     return;
179   int aSectionsSize = theSections.size();
180
181   int aPointsCnt = 0;
182
183   TDF_Label aNameLab = myLab.FindChild(DataTag_SectionsName);
184   Handle(TDataStd_ExtStringArray) aSectsNameArray;
185   aSectsNameArray = TDataStd_ExtStringArray::Set(aNameLab, 0, aSectionsSize-1, false );
186
187   TDF_Label aSizeLab = myLab.FindChild(DataTag_SectionsSize);
188   Handle(TDataStd_IntegerArray) aSizeArray;
189   aSizeArray = TDataStd_IntegerArray::Set(aSizeLab, 0, aSectionsSize-1, false );
190
191   TDF_Label aClosedLab = myLab.FindChild(DataTag_SectionsClosed);
192   Handle(TDataStd_BooleanArray) aClosedArray;
193   aClosedArray = TDataStd_BooleanArray::Set(aClosedLab, 0, aSectionsSize-1 );
194
195   TDF_Label aTypeLab = myLab.FindChild(DataTag_SectionsType);
196   Handle(TDataStd_ByteArray) aTypeArray;
197   aTypeArray = TDataStd_ByteArray::Set(aTypeLab, 0, aSectionsSize-1, false );
198
199 //Extract sections parameters and count points
200   for( int i = 0 ; i < theSections.size() ; i++ ){
201     int aSectSize = theSections[i].myCoords.size();
202     aSectsNameArray->SetValue( i, theSections[i].mySectionName );
203     aSizeArray->SetValue( i, aSectSize );
204     aClosedArray->SetValue( i, theSections[i].myIsClosed );
205     char aType = (char)theSections[i].myType;
206     aTypeArray->SetValue( i, aType );
207     aPointsCnt += aSectSize;
208   }
209 //Don't create a points array
210   if( aPointsCnt == 0 )
211     return;
212 //Save coordinates
213   Handle(TDataStd_RealArray) anArray;
214   anArray = TDataStd_RealArray::Set( myLab, 0, aPointsCnt*aDim - 1 );
215   int aPtr = 0;
216   for( int i = 0 ; i < theSections.size() ; i++ ){
217     for( int j = 0 ; j < theSections[i].myCoords.size() ; j++ ){
218       anArray->SetValue(aPtr, theSections[i].myCoords[j]);
219       aPtr++;
220     }
221   }
222
223   UpdateWire( theSections );
224 }
225
226 /**
227  * Return polyline data
228  * \return polyline section list
229  */
230 HYDROData_Polyline::PolylineData HYDROData_Polyline::GetPolylineData() const
231 {
232   int aSectCnt;
233   PolylineData aRes;
234 //Get sections size array handle
235   TDF_Label aLab = myLab.FindChild( DataTag_SectionsSize );
236   Handle(TDataStd_IntegerArray) aSizeArray;
237   if (!aLab.FindAttribute(TDataStd_IntegerArray::GetID(), aSizeArray))
238     return aRes; // return empty if no array
239   aSectCnt = aSizeArray->Length();
240   if( aSectCnt == 0 )
241     return aRes;
242 //Get section type array handle
243   aLab = myLab.FindChild( DataTag_SectionsType );
244   Handle(TDataStd_ByteArray) aTypeArray;
245   if (!aLab.FindAttribute(TDataStd_ByteArray::GetID(), aTypeArray))
246     return aRes;
247   int aLen = aTypeArray->Length();
248   if( aLen != aSectCnt )
249     return aRes;
250 //Get section closed array handle
251   aLab = myLab.FindChild( DataTag_SectionsClosed );
252   Handle(TDataStd_BooleanArray) aClosedArray;
253   if (!aLab.FindAttribute(TDataStd_BooleanArray::GetID(), aClosedArray))
254     return aRes;
255   aLen = aClosedArray->Length();
256   if( aLen != aSectCnt )
257     return aRes;
258 //Get sections names
259   TDF_Label aNameLab = myLab.FindChild(DataTag_SectionsName);
260   Handle(TDataStd_ExtStringArray) aSectNamesArray;
261   if(!aNameLab.FindAttribute(TDataStd_ExtStringArray::GetID(), aSectNamesArray))
262     return aRes;
263   aLen = aSectNamesArray->Length();
264   if( aLen != aSectCnt )
265     return aRes;
266 //Get coordinates array
267   Handle(TDataStd_RealArray) aCoordsArray;
268   myLab.FindAttribute(TDataStd_RealArray::GetID(), aCoordsArray);
269
270   int aCoordPtr = 0;
271   for( int i = 0 ; i < aSectCnt ; i++ ){
272     PolylineSection aSect;
273     aSect.myIsClosed = aClosedArray->Value(i);
274     aSect.myType = (PolylineSection::SectionType)aTypeArray->Value(i);
275     aSect.mySectionName = aSectNamesArray->Value(i);
276     int aSectSize = aSizeArray->Value(i);
277     for( int j = 0 ; j < aSectSize ; j++ ){
278       double aCoord = aCoordsArray->Value(aCoordPtr);
279       aSect.myCoords << aCoord;
280       aCoordPtr++;
281     }
282     aRes << aSect;
283   }
284   return aRes;
285 }
286
287 /**
288  * Returns true if polyline is closed
289  */
290 bool HYDROData_Polyline::IsClosed() const
291 {
292   int aDim = GetDimension();
293   PolylineData aPolylineData = GetPolylineData();
294
295   if ( aDim == 0 || aPolylineData.isEmpty() )
296     return false;
297
298   PolylineData::const_iterator anIt = aPolylineData.constBegin();
299   for ( ; anIt != aPolylineData.constEnd(); ++anIt )
300   {
301     const PolylineSection& aSection = *anIt;
302     if ( !aSection.myIsClosed )
303       return false;
304   }
305
306   return true;
307 }
308
309 /**
310  * Return polyline dimension
311  * \return polyline dimension. 2 or 3 is valid. 0 is invalid.
312  */
313 int HYDROData_Polyline::GetDimension() const
314 {
315     Handle(TDataStd_Integer) aDim;
316     if(!myLab.FindAttribute(TDataStd_Integer::GetID(), aDim))
317       return 0;
318     return aDim->Get();
319 }
320
321 /**
322  * Set polyline dimension. Should be 2 or 3.
323  * \param theDimension the polyline dimension
324  */
325 void HYDROData_Polyline::SetDimension( int theDimension )
326 {
327     RemoveAll();
328     int aDim=0;
329     if( theDimension == 2 || theDimension == 3){
330         aDim = theDimension;
331     }
332     TDataStd_Integer::Set(myLab, aDim);
333 }
334
335 /**
336  * Remove all polyline attributes except dimension.
337  */
338 void HYDROData_Polyline::RemoveAll()
339 {
340 //Remove only section data
341   TDF_Label aLab = myLab.FindChild( DataTag_SectionsSize );
342   aLab.ForgetAllAttributes();
343
344   aLab = myLab.FindChild( DataTag_SectionsType );
345   aLab.ForgetAllAttributes();
346
347   aLab = myLab.FindChild( DataTag_SectionsClosed );
348   aLab.ForgetAllAttributes();
349
350   myLab.ForgetAttribute(TDataStd_RealArray::GetID());
351   return;
352 }
353
354 /**
355  * Returns the painter path.
356  * Note: currently only the first section of the polyline data is taken into account.
357  * \return polyline painter path.
358  */
359 QPainterPath HYDROData_Polyline::GetPainterPath() const
360 {
361   QPainterPath aPath;
362   int aDim = GetDimension();
363   if( aDim != 2 && aDim != 3 )
364     return aPath;
365
366   PolylineData aSects = GetPolylineData();
367   if( aSects.isEmpty() )
368     return aPath;
369
370   PolylineSection aSection = aSects.first();
371   int aPntCount = aSection.myCoords.size() / aDim;
372   PolylineSection::SectionType aSectionType = aSection.myType;
373   bool anIsSectionClosed = aSection.myIsClosed;
374   if( aSectionType == PolylineSection::SECTION_POLYLINE )
375   {
376     if( aPntCount )
377       aPath.moveTo( aSection.myCoords[0], aSection.myCoords[1] );
378     for( int i = 1; i < aPntCount; i++ )
379     {
380       int anIndex = i * aDim;
381       aPath.lineTo( aSection.myCoords[ anIndex ], aSection.myCoords[ anIndex + 1 ] );
382     }
383     if( anIsSectionClosed )
384       aPath.closeSubpath();
385   }
386   else //if( aSectionType == PolylineSection::SECTION_SPLINE )
387   {
388     QList<double> aPoints;
389     for( int i = 0; i < aPntCount; i++ )
390     {
391       int anIndex = i * aDim;
392       aPoints << aSection.myCoords[ anIndex ] << aSection.myCoords[ anIndex + 1 ];
393     }
394     HYDROData_BSplineOperation aBSpline( aPoints, 0, anIsSectionClosed );
395     aPath = aBSpline.ComputePath();
396   }
397   return aPath;
398 }
399
400 void HYDROData_Polyline::SetZValue( const double theZValue )
401 {
402   TDataStd_Real::Set(myLab.FindChild(DataTag_ZValue), theZValue);
403 }
404
405 double HYDROData_Polyline::ZValue() const
406 {
407   Handle(TDataStd_Real) aZValue;
408   if(myLab.FindChild(DataTag_ZValue).FindAttribute(TDataStd_Real::GetID(), aZValue))
409     return aZValue->Get();
410   return 0;
411 }
412
413 void HYDROData_Polyline::UpdateWire( const PolylineData& theSections )
414 {
415   BRepBuilderAPI_MakeWire aMakeWire;
416
417   int aDim = GetDimension();
418
419   double aZValue = ZValue();
420
421   TopTools_ListOfShape aSectionWiresList;
422
423   int aSectionCount = theSections.size();
424   for( int aSectionId = 0; aSectionId < aSectionCount; aSectionId++ )
425   {
426     const PolylineSection& aSection = theSections[ aSectionId ];
427     PolylineSection::SectionType aSectionType = aSection.myType;
428     bool anIsSectionClosed = aSection.myIsClosed;
429     int aPointCount = aSection.myCoords.size() / aDim;
430     if( aPointCount > 1 )
431     {
432       BRepBuilderAPI_MakeWire aMakeSectionWire;
433       if( aSectionType == PolylineSection::SECTION_POLYLINE )
434       {
435         for( int aPointId = 0; aPointId < aPointCount; aPointId++ )
436         {
437           int anId1 = aDim * aPointId;
438           int anId2 = aDim * ( aPointId + 1 );
439           if( aPointId == aPointCount - 1 )
440           {
441             if( anIsSectionClosed )
442               anId2 = 0;
443             else
444               break;
445           }
446
447           gp_Pnt aPnt1( aSection.myCoords[ anId1 ], aSection.myCoords[ anId1 + 1 ], aZValue );
448           gp_Pnt aPnt2( aSection.myCoords[ anId2 ], aSection.myCoords[ anId2 + 1 ], aZValue );
449
450           TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aPnt1, aPnt2 ).Edge();
451           aMakeSectionWire.Add( anEdge );
452         }
453       }
454       else //if( aSectionType == PolylineSection::SECTION_SPLINE )
455       {
456         QList<double> aPoints;
457         for( int aPointId = 0; aPointId < aPointCount; aPointId++ )
458         {
459           int anId = aPointId * aDim;
460           double x = aSection.myCoords[ anId ];
461           double y = aSection.myCoords[ anId+1 ];
462           aPoints << x << y;
463         }
464
465         HYDROData_BSplineOperation aBSpline( aPoints, aZValue, anIsSectionClosed );
466         TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aBSpline.Curve() ).Edge();
467         aMakeSectionWire.Add( anEdge );
468       }
469       TopoDS_Wire aSectionWire = aMakeSectionWire.Wire();
470       aSectionWiresList.Append( aSectionWire );
471       aMakeWire.Add( aSectionWire );
472     }
473   }
474
475   TopoDS_Shape aShape;
476   if ( aMakeWire.IsDone() ) {
477     aShape = aMakeWire.Shape();
478   } else {
479     // build compound
480     TopoDS_Compound aCompound;
481     BRep_Builder aBuilder;
482     aBuilder.MakeCompound( aCompound );
483     TopTools_ListIteratorOfListOfShape anIter( aSectionWiresList );
484     for ( ; anIter.More(); anIter.Next() ) {
485       aBuilder.Add( aCompound, anIter.Value() );
486     }
487     aShape = aCompound;
488   }
489
490   SetTopShape( aShape );
491 }