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