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