Salome HOME
middle z for 3D guideline
[modules/hydro.git] / src / HYDROData / HYDROData_Polyline.cxx
index 8b01e076bfbf845e6e903b2d33879876e017ef06..f9a4d7d5b1ae090795a38bce579cc39839011506 100755 (executable)
@@ -1,18 +1,58 @@
+// Copyright (C) 2014-2015  EDF-R&D
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
 #include <HYDROData_Polyline.h>
 #include <HYDROData_Iterator.h>
 
-#include <TDataStd_RealArray.hxx>
+#include <HYDROData_BSplineOperation.h>
+
+#include <ImageComposer_MetaTypes.h>
+
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <gp_Pnt.hxx>
 #include <TDataStd_Name.hxx>
+#include <TDataStd_Integer.hxx>
+#include <TDataStd_ByteArray.hxx>
+#include <TDataStd_BooleanArray.hxx>
+#include <TDataStd_IntegerArray.hxx>
+#include <TDataStd_Real.hxx>
+#include <TDataStd_RealArray.hxx>
+#include <TDataStd_ExtStringArray.hxx>
 #include <TDataStd_UAttribute.hxx>
 #include <TDF_ListIteratorOfLabelList.hxx>
+#include <TNaming_Builder.hxx>
+#include <TNaming_NamedShape.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Wire.hxx>
+#include <BRep_Builder.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+
+#include <QStringList>
 
-// tage of the child of my label that contains information about the operator
-static const Standard_GUID GUID_MUST_BE_UPDATED("80f2bb81-3873-4631-8ddd-940d2119f000");
+#define PYTHON_POLYLINE_ID "KIND_POLYLINE"
 
 IMPLEMENT_STANDARD_HANDLE(HYDROData_Polyline, HYDROData_Object)
 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Polyline, HYDROData_Object)
 
 HYDROData_Polyline::HYDROData_Polyline()
+: HYDROData_Object()
 {
 }
 
@@ -20,82 +60,428 @@ HYDROData_Polyline::~HYDROData_Polyline()
 {
 }
 
-void HYDROData_Polyline::setPoints( QList<QPointF> thePointsList )
+TopoDS_Shape HYDROData_Polyline::GetTopShape() const
 {
-  removeAllPoints();
-  if( thePointsList.isEmpty() )
-    return;
-  Handle(TDataStd_RealArray) anArray;
-  anArray = TDataStd_RealArray::Set( myLab, 0, thePointsList.size()*2-1 );
-  for( int i = 0 ; i < thePointsList.size() ; i++ ){
-    anArray->SetValue(i*2, thePointsList[i].x() );
-    anArray->SetValue(i*2+1, thePointsList[i].y() );
-  }
+  // TODO
+  return getTopShape();
 }
 
-void HYDROData_Polyline::addPoint( const QPointF& thePoint )
-{
-  QList<QPointF> aPointsArray = points();
-  aPointsArray.append( thePoint );
-  setPoints( aPointsArray );
-}
-   
-void HYDROData_Polyline::insertPoint( int theIndex, const QPointF& thePoint)
+TopoDS_Shape HYDROData_Polyline::GetShape3D() const
 {
-  QList<QPointF> aPointsArray = points();
-  aPointsArray.insert( theIndex, thePoint );
-  setPoints( aPointsArray );
+  // TODO
+  return getTopShape();
 }
 
-void HYDROData_Polyline::removePoint( int theIndex )
+/**
+ * Dump object to Python script representation.
+ */
+QStringList HYDROData_Polyline::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
 {
-  QList<QPointF> aPointsArray = points();
-  aPointsArray.removeAt( theIndex );
-  setPoints( aPointsArray );
+  QStringList aResList;
+
+  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
+  if ( aDocument.IsNull() )
+    return aResList;
+                             
+  QString aDocName = aDocument->GetDocPyName();
+  QString aPolylineName = GetName();
+
+  aResList << QString( "%1 = %2.CreateObject( %3 );" )
+              .arg( aPolylineName ).arg( aDocName ).arg( PYTHON_POLYLINE_ID );
+  aResList << QString( "%1.SetName( \"%1\" );" ).arg( aPolylineName );
+
+  // Set polilyne dimension
+
+  aResList << QString( "" );
+
+  int aDim = GetDimension();
+  aResList << QString( "%1.SetDimension( %2 );" )
+              .arg( aPolylineName ).arg( aDim );
+
+  // Set polilyne data
+
+  PolylineData aPolylineData = GetPolylineData();
+  if ( !aPolylineData.isEmpty() )
+  {
+    QString aPolylineDataName = "polyline_data";
+
+    aResList << QString( "" );
+    aResList << QString( "%1 = [];" ).arg( aPolylineDataName );
+
+    PolylineData::const_iterator aDataIt = aPolylineData.constBegin();
+    for ( ; aDataIt != aPolylineData.constEnd(); ++aDataIt )
+    {
+      const PolylineSection& aSection = *aDataIt;
+
+      QString aPolylineSectName = "polyline_section";
+
+      aResList << QString( "" );
+      aResList << QString( "%1 = PolylineSection();" ).arg( aPolylineSectName );
+
+      QString aCoordsStr;
+      foreach( const double& aCoordVal, aSection.myCoords )
+        aCoordsStr += QString::number( aCoordVal ) + ", ";
+      aCoordsStr.remove( aCoordsStr.length() - 2, 2 );
+
+      aResList << QString( "" );
+
+      aResList << QString( "%1.mySectionName = \"%2\";" )
+                  .arg( aPolylineSectName )
+                  .arg( TCollection_AsciiString( aSection.mySectionName ).ToCString() );
+      aResList << QString( "%1.myType = %2;" )
+                  .arg( aPolylineSectName ).arg( aSection.myType );
+      aResList << QString( "%1.myIsClosed = %2;" )
+                  .arg( aPolylineSectName ).arg( aSection.myIsClosed );
+      aResList << QString( "%1.myCoords = [ %2 ];" )
+                  .arg( aPolylineSectName ).arg( aCoordsStr );
+
+      aResList << QString( "%1.append( %2 );" )
+                  .arg( aPolylineDataName ).arg( aPolylineSectName );
+    }
+    aResList << QString( "" );
+
+    aResList << QString( "%1.SetPolylineData( %2 );" )
+                  .arg( aPolylineName ).arg( aPolylineDataName );
+  }
+
+  return aResList;
 }
 
-void HYDROData_Polyline::removeAllPoints()
+QVariant HYDROData_Polyline::GetDataVariant()
 {
-  myLab.ForgetAttribute(TDataStd_RealArray::GetID());
-  return;
+  QPainterPath aPath = GetPainterPath();
+
+  QVariant aVarData;
+  aVarData.setValue<QPainterPath>( aPath );
+  
+  return aVarData;
 }
 
-int HYDROData_Polyline::pointsCount()
+/**
+ * Replace current polyline data by new sections list
+ * \param theSections the sections list
+ */
+void HYDROData_Polyline::SetPolylineData( const PolylineData& theSections )
 {
+//Keep dimension
+  int aDim = GetDimension();
+  if( aDim == 0 )
+      return;
+  RemoveAll();
+  SetDimension(aDim);
+
+  if( theSections.size() == 0 )
+    return;
+  int aSectionsSize = theSections.size();
+
+  int aPointsCnt = 0;
+
+  TDF_Label aNameLab = myLab.FindChild(DataTag_SectionsName);
+  Handle(TDataStd_ExtStringArray) aSectsNameArray;
+  aSectsNameArray = TDataStd_ExtStringArray::Set(aNameLab, 0, aSectionsSize-1, false );
+
+  TDF_Label aSizeLab = myLab.FindChild(DataTag_SectionsSize);
+  Handle(TDataStd_IntegerArray) aSizeArray;
+  aSizeArray = TDataStd_IntegerArray::Set(aSizeLab, 0, aSectionsSize-1, false );
+
+  TDF_Label aClosedLab = myLab.FindChild(DataTag_SectionsClosed);
+  Handle(TDataStd_BooleanArray) aClosedArray;
+  aClosedArray = TDataStd_BooleanArray::Set(aClosedLab, 0, aSectionsSize-1 );
+
+  TDF_Label aTypeLab = myLab.FindChild(DataTag_SectionsType);
+  Handle(TDataStd_ByteArray) aTypeArray;
+  aTypeArray = TDataStd_ByteArray::Set(aTypeLab, 0, aSectionsSize-1, false );
+
+//Extract sections parameters and count points
+  for( int i = 0 ; i < theSections.size() ; i++ ){
+    int aSectSize = theSections[i].myCoords.size();
+    aSectsNameArray->SetValue( i, theSections[i].mySectionName );
+    aSizeArray->SetValue( i, aSectSize );
+    aClosedArray->SetValue( i, theSections[i].myIsClosed );
+    char aType = (char)theSections[i].myType;
+    aTypeArray->SetValue( i, aType );
+    aPointsCnt += aSectSize;
+  }
+//Don't create a points array
+  if( aPointsCnt == 0 )
+    return;
+//Save coordinates
   Handle(TDataStd_RealArray) anArray;
-  if(!myLab.FindAttribute(TDataStd_RealArray::GetID(), anArray))
-    return 0;
-  return anArray->Length()/2;
+  anArray = TDataStd_RealArray::Set( myLab, 0, aPointsCnt*aDim - 1 );
+  int aPtr = 0;
+  for( int i = 0 ; i < theSections.size() ; i++ ){
+    for( int j = 0 ; j < theSections[i].myCoords.size() ; j++ ){
+      anArray->SetValue(aPtr, theSections[i].myCoords[j]);
+      aPtr++;
+    }
+  }
+
+  UpdateWire( theSections );
 }
 
-QList<QPointF> HYDROData_Polyline::points()
+/**
+ * Return polyline data
+ * \return polyline section list
+ */
+HYDROData_Polyline::PolylineData HYDROData_Polyline::GetPolylineData() const
 {
-  QList<QPointF> aRes;
-  Handle(TDataStd_RealArray) anArray;
-  if(!myLab.FindAttribute(TDataStd_RealArray::GetID(), anArray))
+  int aSectCnt;
+  PolylineData aRes;
+//Get sections size array handle
+  TDF_Label aLab = myLab.FindChild( DataTag_SectionsSize );
+  Handle(TDataStd_IntegerArray) aSizeArray;
+  if (!aLab.FindAttribute(TDataStd_IntegerArray::GetID(), aSizeArray))
+    return aRes; // return empty if no array
+  aSectCnt = aSizeArray->Length();
+  if( aSectCnt == 0 )
+    return aRes;
+//Get section type array handle
+  aLab = myLab.FindChild( DataTag_SectionsType );
+  Handle(TDataStd_ByteArray) aTypeArray;
+  if (!aLab.FindAttribute(TDataStd_ByteArray::GetID(), aTypeArray))
+    return aRes;
+  int aLen = aTypeArray->Length();
+  if( aLen != aSectCnt )
+    return aRes;
+//Get section closed array handle
+  aLab = myLab.FindChild( DataTag_SectionsClosed );
+  Handle(TDataStd_BooleanArray) aClosedArray;
+  if (!aLab.FindAttribute(TDataStd_BooleanArray::GetID(), aClosedArray))
+    return aRes;
+  aLen = aClosedArray->Length();
+  if( aLen != aSectCnt )
     return aRes;
-  int anArraySize = anArray->Length();
-  for( int i = 0 ; i < anArraySize/2 ; i++ ){
-    qreal anX = anArray->Value( i*2 );
-    qreal anY = anArray->Value( i*2 + 1 );
-    QPointF aPoint( anX, anY );
-    aRes.append( aPoint );
+//Get sections names
+  TDF_Label aNameLab = myLab.FindChild(DataTag_SectionsName);
+  Handle(TDataStd_ExtStringArray) aSectNamesArray;
+  if(!aNameLab.FindAttribute(TDataStd_ExtStringArray::GetID(), aSectNamesArray))
+    return aRes;
+  aLen = aSectNamesArray->Length();
+  if( aLen != aSectCnt )
+    return aRes;
+//Get coordinates array
+  Handle(TDataStd_RealArray) aCoordsArray;
+  myLab.FindAttribute(TDataStd_RealArray::GetID(), aCoordsArray);
+
+  int aCoordPtr = 0;
+  for( int i = 0 ; i < aSectCnt ; i++ ){
+    PolylineSection aSect;
+    aSect.myIsClosed = aClosedArray->Value(i);
+    aSect.myType = (PolylineSection::SectionType)aTypeArray->Value(i);
+    aSect.mySectionName = aSectNamesArray->Value(i);
+    int aSectSize = aSizeArray->Value(i);
+    for( int j = 0 ; j < aSectSize ; j++ ){
+      double aCoord = aCoordsArray->Value(aCoordPtr);
+      aSect.myCoords << aCoord;
+      aCoordPtr++;
+    }
+    aRes << aSect;
   }
   return aRes;
 }
 
-QPainterPath HYDROData_Polyline::painterPathLinear()
+/**
+ * Returns true if polyline is closed
+ */
+bool HYDROData_Polyline::IsClosed() const
+{
+  int aDim = GetDimension();
+  PolylineData aPolylineData = GetPolylineData();
+
+  if ( aDim == 0 || aPolylineData.isEmpty() )
+    return false;
+
+  PolylineData::const_iterator anIt = aPolylineData.constBegin();
+  for ( ; anIt != aPolylineData.constEnd(); ++anIt )
+  {
+    const PolylineSection& aSection = *anIt;
+    if ( !aSection.myIsClosed )
+      return false;
+  }
+
+  return true;
+}
+
+/**
+ * Return polyline dimension
+ * \return polyline dimension. 2 or 3 is valid. 0 is invalid.
+ */
+int HYDROData_Polyline::GetDimension() const
+{
+    Handle(TDataStd_Integer) aDim;
+    if(!myLab.FindAttribute(TDataStd_Integer::GetID(), aDim))
+      return 0;
+    return aDim->Get();
+}
+
+/**
+ * Set polyline dimension. Should be 2 or 3.
+ * \param theDimension the polyline dimension
+ */
+void HYDROData_Polyline::SetDimension( int theDimension )
+{
+    RemoveAll();
+    int aDim=0;
+    if( theDimension == 2 || theDimension == 3){
+        aDim = theDimension;
+    }
+    TDataStd_Integer::Set(myLab, aDim);
+}
+
+/**
+ * Remove all polyline attributes except dimension.
+ */
+void HYDROData_Polyline::RemoveAll()
+{
+//Remove only section data
+  TDF_Label aLab = myLab.FindChild( DataTag_SectionsSize );
+  aLab.ForgetAllAttributes();
+
+  aLab = myLab.FindChild( DataTag_SectionsType );
+  aLab.ForgetAllAttributes();
+
+  aLab = myLab.FindChild( DataTag_SectionsClosed );
+  aLab.ForgetAllAttributes();
+
+  myLab.ForgetAttribute(TDataStd_RealArray::GetID());
+  return;
+}
+
+/**
+ * Returns the painter path.
+ * Note: currently only the first section of the polyline data is taken into account.
+ * \return polyline painter path.
+ */
+QPainterPath HYDROData_Polyline::GetPainterPath() const
 {
   QPainterPath aPath;
-  QList<QPointF> aPointsArray = points();
-  if( aPointsArray.size() == 0 )
+  int aDim = GetDimension();
+  if( aDim != 2 && aDim != 3 )
     return aPath;
-  aPath.moveTo( aPointsArray[0] );
-  for( int i = 0 ; i < aPointsArray.size() ; i++ ){
-    aPath.lineTo( aPointsArray[i] );
+
+  PolylineData aSects = GetPolylineData();
+  if( aSects.isEmpty() )
+    return aPath;
+
+  PolylineSection aSection = aSects.first();
+  int aPntCount = aSection.myCoords.size() / aDim;
+  PolylineSection::SectionType aSectionType = aSection.myType;
+  bool anIsSectionClosed = aSection.myIsClosed;
+  if( aSectionType == PolylineSection::SECTION_POLYLINE )
+  {
+    if( aPntCount )
+      aPath.moveTo( aSection.myCoords[0], aSection.myCoords[1] );
+    for( int i = 1; i < aPntCount; i++ )
+    {
+      int anIndex = i * aDim;
+      aPath.lineTo( aSection.myCoords[ anIndex ], aSection.myCoords[ anIndex + 1 ] );
+    }
+    if( anIsSectionClosed )
+      aPath.closeSubpath();
+  }
+  else //if( aSectionType == PolylineSection::SECTION_SPLINE )
+  {
+    QList<double> aPoints;
+    for( int i = 0; i < aPntCount; i++ )
+    {
+      int anIndex = i * aDim;
+      aPoints << aSection.myCoords[ anIndex ] << aSection.myCoords[ anIndex + 1 ];
+    }
+    HYDROData_BSplineOperation aBSpline( aPoints, 0, anIsSectionClosed );
+    aPath = aBSpline.ComputePath();
   }
-  aPath.lineTo( aPointsArray[0] );
-//I dont know is it need or not ???
-  aPath.closeSubpath();
   return aPath;
 }
+
+void HYDROData_Polyline::SetZValue( const double theZValue )
+{
+  TDataStd_Real::Set(myLab.FindChild(DataTag_ZValue), theZValue);
+}
+
+double HYDROData_Polyline::ZValue() const
+{
+  Handle(TDataStd_Real) aZValue;
+  if(myLab.FindChild(DataTag_ZValue).FindAttribute(TDataStd_Real::GetID(), aZValue))
+    return aZValue->Get();
+  return 0;
+}
+
+void HYDROData_Polyline::UpdateWire( const PolylineData& theSections )
+{
+  BRepBuilderAPI_MakeWire aMakeWire;
+
+  int aDim = GetDimension();
+
+  double aZValue = ZValue();
+
+  TopTools_ListOfShape aSectionWiresList;
+
+  int aSectionCount = theSections.size();
+  for( int aSectionId = 0; aSectionId < aSectionCount; aSectionId++ )
+  {
+    const PolylineSection& aSection = theSections[ aSectionId ];
+    PolylineSection::SectionType aSectionType = aSection.myType;
+    bool anIsSectionClosed = aSection.myIsClosed;
+    int aPointCount = aSection.myCoords.size() / aDim;
+    if( aPointCount > 1 )
+    {
+      BRepBuilderAPI_MakeWire aMakeSectionWire;
+      if( aSectionType == PolylineSection::SECTION_POLYLINE )
+      {
+        for( int aPointId = 0; aPointId < aPointCount; aPointId++ )
+        {
+          int anId1 = aDim * aPointId;
+          int anId2 = aDim * ( aPointId + 1 );
+          if( aPointId == aPointCount - 1 )
+          {
+            if( anIsSectionClosed )
+              anId2 = 0;
+            else
+              break;
+          }
+
+          gp_Pnt aPnt1( aSection.myCoords[ anId1 ], aSection.myCoords[ anId1 + 1 ], aZValue );
+          gp_Pnt aPnt2( aSection.myCoords[ anId2 ], aSection.myCoords[ anId2 + 1 ], aZValue );
+
+          TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aPnt1, aPnt2 ).Edge();
+          aMakeSectionWire.Add( anEdge );
+        }
+      }
+      else //if( aSectionType == PolylineSection::SECTION_SPLINE )
+      {
+        QList<double> aPoints;
+        for( int aPointId = 0; aPointId < aPointCount; aPointId++ )
+        {
+          int anId = aPointId * aDim;
+          double x = aSection.myCoords[ anId ];
+          double y = aSection.myCoords[ anId+1 ];
+          aPoints << x << y;
+        }
+
+        HYDROData_BSplineOperation aBSpline( aPoints, aZValue, anIsSectionClosed );
+        TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aBSpline.Curve() ).Edge();
+        aMakeSectionWire.Add( anEdge );
+      }
+      TopoDS_Wire aSectionWire = aMakeSectionWire.Wire();
+      aSectionWiresList.Append( aSectionWire );
+      aMakeWire.Add( aSectionWire );
+    }
+  }
+
+  TopoDS_Shape aShape;
+  if ( aMakeWire.IsDone() ) {
+    aShape = aMakeWire.Shape();
+  } else {
+    // build compound
+    TopoDS_Compound aCompound;
+    BRep_Builder aBuilder;
+    aBuilder.MakeCompound( aCompound );
+    TopTools_ListIteratorOfListOfShape anIter( aSectionWiresList );
+    for ( ; anIter.More(); anIter.Next() ) {
+      aBuilder.Add( aCompound, anIter.Value() );
+    }
+    aShape = aCompound;
+  }
+
+  SetTopShape( aShape );
+}