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