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