Salome HOME
Insert single profiles in to the stream order.
[modules/hydro.git] / src / HYDROData / HYDROData_Stream.cxx
index 0512e90a24474f6bc725a619338f792daac1ab70..6a95bd0a69a94f730c791e599f126da3344d1cc4 100644 (file)
 #include <BRepBuilderAPI_MakeWire.hxx>
 #include <BRepBuilderAPI_MakeFace.hxx>
 
+#include <TDataStd_RealArray.hxx>
+
 #include <TopoDS.hxx>
 #include <TopoDS_Wire.hxx>
 #include <TopoDS_Shell.hxx>
 #include <TopoDS_Face.hxx>
-
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <BRepProj_Projection.hxx>
+#include <BRepExtrema_ExtCC.hxx>
+#include <gp_Ax1.hxx>
+#include <gp_Ax2.hxx>
+#include <gp_Ax3.hxx>
+#include <gp_Vec.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Pln.hxx>
+#include <gp.hxx>
+#include <Bnd_Box.hxx>
+#include <BRepBndLib.hxx>
+#include <TColStd_Array1OfReal.hxx>
+#include <Precision.hxx>
 #include <QStringList>
 
+#include <NCollection_DataMap.hxx>
+typedef NCollection_DataMap<Standard_Real, Handle(HYDROData_Profile)> HYDROData_DataMapOfRealOfHDProfile;
+//typedef HYDROData_DataMapOfRealOfHDProfile::Iterator HYDROData_DataMapIteratorOfDataMapOfRealOfHDProfile;
+#include <TColStd_ListOfReal.hxx>
+#include <TColStd_ListIteratorOfListOfReal.hxx>
+#include <TCollection_CompareOfReal.hxx>
+#include <SortTools_QuickSortOfReal.hxx>
+//#define DEB_HASINT 1
+#ifdef DEB_HASINT
+#include <BRepTools.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <BRep_Builder.hxx>
+#endif
+
 #define PYTHON_STREAM_ID "KIND_STREAM"
 
 IMPLEMENT_STANDARD_HANDLE(HYDROData_Stream,HYDROData_NaturalObject)
@@ -54,6 +86,20 @@ QStringList HYDROData_Stream::DumpToPython( MapOfTreatedObjects& theTreatedObjec
   return aResList;
 }
 
+HYDROData_SequenceOfObjects HYDROData_Stream::GetAllReferenceObjects() const
+{
+  HYDROData_SequenceOfObjects aResSeq = HYDROData_Object::GetAllReferenceObjects();
+
+  Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
+  if ( !aHydAxis.IsNull() )
+    aResSeq.Append( aHydAxis );
+
+  HYDROData_SequenceOfObjects aSeqOfProfiles = GetProfiles();
+  aResSeq.Append( aSeqOfProfiles );
+
+  return aResSeq;
+}
+
 TopoDS_Shape HYDROData_Stream::GetTopShape() const
 {
   return getTopShape();
@@ -66,8 +112,7 @@ TopoDS_Shape HYDROData_Stream::GetShape3D() const
 
 void HYDROData_Stream::Update()
 {
-  removeTopShape();
-  removeShape3D();
+  HYDROData_NaturalObject::Update();
 
   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
   HYDROData_SequenceOfObjects aRefProfiles = GetProfiles();
@@ -181,31 +226,127 @@ void HYDROData_Stream::RemoveHydraulicAxis()
   SetToUpdate( true );
 }
 
-bool HYDROData_Stream::HasIntersection( const Handle(HYDROData_Profile)& theProfile ) const
+bool HYDROData_Stream::HasIntersection( const Handle(HYDROData_Profile)& theProfile, const TopoDS_Face& thePlane,
+                                                                          Standard_Real& outPar ) const
 {
   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
   if ( theProfile.IsNull() || aHydAxis.IsNull() )
     return false; 
 
-  TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() );
+  TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() ); //guide line
   TopoDS_Wire aProfileWire = TopoDS::Wire( theProfile->GetTopShape() );
   if ( aHydraulicWire.IsNull() || aProfileWire.IsNull() )
     return false;
 
-  // TODO
-
-  return true;
+  BRepProj_Projection aProjector (aProfileWire, thePlane, gp::OZ().Direction());
+  if(!aProjector.IsDone())
+    return false;
+  TopoDS_Shape aPrjProfile = aProjector.Shape();
+  if(aPrjProfile.IsNull())
+    return false;
+  TopoDS_Vertex aV1, aV2;
+  if(aPrjProfile.ShapeType() == TopAbs_EDGE)
+         TopExp::Vertices(TopoDS::Edge(aPrjProfile), aV1, aV2);          
+  else if(aPrjProfile.ShapeType() == TopAbs_WIRE)  
+         TopExp::Vertices(TopoDS::Wire(aPrjProfile), aV1, aV2);          
+  else if(aPrjProfile.ShapeType() == TopAbs_COMPOUND){
+    TopExp_Explorer anExp(aPrjProfile, TopAbs_WIRE);
+       if(anExp.More()) {
+               TopExp::Vertices(TopoDS::Wire(anExp.Current()), aV1, aV2);        
+       } else {
+         anExp.Init(aPrjProfile, TopAbs_EDGE);
+         if(anExp.More()) {
+               TopExp::Vertices(TopoDS::Edge(anExp.Current()), aV1, aV2);        
+         }
+       }
+  }
+  if(aV1.IsNull() || aV2.IsNull())
+       return false;
+  gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1);
+  gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2);
+  aPnt1.SetZ(0.0);
+  aPnt2.SetZ(0.0);
+  BRepBuilderAPI_MakeEdge aMk(aPnt1, aPnt2); 
+  if(!aMk.IsDone())
+    return false;
+  const TopoDS_Edge& anEdg2 = aMk.Edge();//Section edge
+  Standard_Integer aNum(0);
+  
+  TopExp_Explorer anExplo(aHydraulicWire, TopAbs_EDGE);
+  for(;anExplo.More();anExplo.Next()) aNum++;
+  // check for self-intersection
+  const Standard_Real SquareTolerance = Precision::Confusion()*Precision::Confusion();
+  Standard_Boolean hasInt(false);
+  Standard_Real aSqDist(DBL_MAX);
+  Standard_Integer anIndx(0);
+  BRepExtrema_ExtCC aCC;
+  aCC.Initialize(anEdg2);
+  outPar = 0.0;
+  anExplo.Init(aHydraulicWire, TopAbs_EDGE);
+  for(Standard_Integer j=1;anExplo.More();anExplo.Next(),j++) {
+       const TopoDS_Edge& anEdg1 = TopoDS::Edge(anExplo.Current());
+       if(anEdg1.IsNull())
+         continue;     
+       Standard_Boolean hasSol(false);
+       aCC.Perform(anEdg1);
+    if(aCC.IsDone()) {
+       // find minimal dist
+    for(Standard_Integer i=1; i<= aCC.NbExt();i++)
+      if(aCC.SquareDistance(i) < aSqDist) {
+        aSqDist = aCC.SquareDistance(i);
+        anIndx = i;
+               hasSol = true;          
+         }  
+       }
+       if(hasSol) {   
+               if(aSqDist <= SquareTolerance) { // hasInt
+        const gp_Pnt& aPnt = aCC.PointOnE1(anIndx);
+        if(aNum > 1) {
+          TopExp::Vertices(anEdg1, aV1, aV2, Standard_True);
+                 outPar += BRep_Tool::Pnt(aV1).Distance(aPnt);
+           } else {
+          Standard_Real aPar = aCC.ParameterOnE1(anIndx);
+                 outPar = aPar;
+           }
+               hasInt = true;
+           break;
+               } else {
+                 // no ints-n
+        if(aNum > 1) {
+          TopExp::Vertices(anEdg1, aV1, aV2);
+             outPar += BRep_Tool::Pnt(aV1).Distance(BRep_Tool::Pnt(aV2));
+           }
+         }
+       } else if(aNum > 1) {
+          TopExp::Vertices(anEdg1, aV1, aV2);
+             outPar += BRep_Tool::Pnt(aV1).Distance(BRep_Tool::Pnt(aV2));
+       }
+  }
+  if(hasInt)
+    return true;
+  return false;
 }
 
+
 bool HYDROData_Stream::AddProfile( const Handle(HYDROData_Profile)& theProfile )
 {
   if ( theProfile.IsNull() )
-    return false; 
+    return false;
 
-  if ( HasReference( theProfile, DataTag_Profile ) || !HasIntersection( theProfile ) )
-    return false; // Object is already in reference list or it has no intersection
+  Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
+  if ( aHydAxis.IsNull() )
+    return false;
 
-  insertProfileInToOrder( theProfile );
+  TopoDS_Face aPlane;
+  if(!BuildFace(aHydAxis, aPlane))
+    return false;
+
+  Standard_Real aPar(.0);
+  if ( HasReference( theProfile, DataTag_Profile ) || !HasIntersection( theProfile, aPlane, aPar ) )
+    return false; // Object is already in reference list or it has no intersection
+  
+  int aProfileIndex = insertParameter( aPar );
+  insertProfileInToOrder( theProfile, aProfileIndex );
   
   // Indicate model of the need to update the stream presentation
   SetToUpdate( true );
@@ -220,11 +361,35 @@ HYDROData_SequenceOfObjects HYDROData_Stream::GetProfiles() const
 
 bool HYDROData_Stream::RemoveProfile( const Handle(HYDROData_Profile)& theProfile )
 {
-  if ( theProfile.IsNull() || !HasReference( theProfile, DataTag_Profile ) )
+  if ( theProfile.IsNull() )
+    return false;
+
+  int aProfileIndex = -1;
+
+  HYDROData_SequenceOfObjects aRefProfiles = GetProfiles();
+  HYDROData_SequenceOfObjects::Iterator anIter( aRefProfiles );
+  for ( int i = 0 ; anIter.More(); anIter.Next(), ++i )
+  {
+    Handle(HYDROData_Profile) aProfile =
+      Handle(HYDROData_Profile)::DownCast( anIter.Value() );
+    if ( aProfile.IsNull() )
+      continue;
+
+    if ( IsEqual( theProfile, aProfile ) )
+    {
+      aProfileIndex = i;
+      break;
+    }
+  }
+
+  if ( aProfileIndex == -1 )
     return false;
 
   RemoveReferenceObject( theProfile->Label(), DataTag_Profile );
 
+  // Remove parameter for removed profile
+  removeParameter( aProfileIndex );
+
   // Indicate model of the need to update the stream presentation
   SetToUpdate( true );
 
@@ -237,11 +402,15 @@ void HYDROData_Stream::RemoveProfiles()
 
   ClearReferenceObjects( DataTag_Profile );
 
+  // Remove the parameters array
+  removeParametersArray();
+
   // Indicate model of the need to update the stream presentation
   SetToUpdate( anIsToUpdate );
 }
 
-void HYDROData_Stream::insertProfileInToOrder( const Handle(HYDROData_Profile)& theProfile )
+void HYDROData_Stream::insertProfileInToOrder( const Handle(HYDROData_Profile)& theProfile,
+                                               const int                        theBeforeIndex )
 {
   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
   if ( theProfile.IsNull() || aHydAxis.IsNull() )
@@ -252,8 +421,28 @@ void HYDROData_Stream::insertProfileInToOrder( const Handle(HYDROData_Profile)&
   if ( aHydraulicWire.IsNull() || aProfileWire.IsNull() )
     return;
 
-  // TODO
-  AddReferenceObject( theProfile, DataTag_Profile ); // temporary for testing only
+  if ( theBeforeIndex == -1 )
+    AddReferenceObject( theProfile, DataTag_Profile );
+  else
+    InsertReferenceObject( theProfile, DataTag_Profile, theBeforeIndex );
+}
+
+bool HYDROData_Stream::BuildFace( const Handle(HYDROData_PolylineXY)& theHydAxis, TopoDS_Face& thePlane) const
+{
+  if ( theHydAxis.IsNull() ) return false;
+  TopoDS_Wire aHydraulicWire = TopoDS::Wire( theHydAxis->GetShape() );
+  if(aHydraulicWire.IsNull()) return false;
+  gp_Ax2 aX2(gp::XOY());
+  gp_Ax3 aX3(aX2);
+  gp_Pln aPln(aX3);   
+  Bnd_Box B;
+  BRepBndLib::Add(aHydraulicWire,B);
+  Standard_Real axmin,aymin,azmin,axmax,aymax,azmax;
+  B.Get(axmin,aymin,azmin,axmax,aymax,azmax);
+  BRepBuilderAPI_MakeFace aMkr(aPln, axmin-500., axmax+500., aymin-500., aymax+500.); // to be tuned later according max/ Profile deviation
+  if(!aMkr.IsDone() || aMkr.Shape().IsNull()) return false;
+  thePlane = TopoDS::Face(aMkr.Shape());
+  return true;
 }
 
 void HYDROData_Stream::updateProfilesOrder()
@@ -267,17 +456,194 @@ void HYDROData_Stream::updateProfilesOrder()
 
   Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis();
   if ( aHydAxis.IsNull() )
+    return; 
+
+  TopoDS_Face aPlane;
+  if ( !BuildFace( aHydAxis, aPlane ) )
     return;
 
+  Standard_Real aPar( .0 );
+
+#ifdef DEB_HASINT
+  BRep_Builder aBB;
+  TopoDS_Compound aCmp;
+  aBB.MakeCompound(aCmp);
+#endif
+
+  HYDROData_DataMapOfRealOfHDProfile aDM;  
+  TColStd_ListOfReal aList;
   HYDROData_SequenceOfObjects::Iterator anIter( aRefProfiles );
-  for ( ; anIter.More(); anIter.Next() )
+  for (int i = 1 ; anIter.More(); anIter.Next(), i++ )
   {
     Handle(HYDROData_Profile) aProfile =
       Handle(HYDROData_Profile)::DownCast( anIter.Value() );
-    if ( aProfile.IsNull() || !HasIntersection( aProfile ) )
+#ifdef DEB_HASINT
+  TopoDS_Wire aProfileWire = TopoDS::Wire( aProfile->GetTopShape() );
+  aBB.Add( aCmp, aProfileWire ); 
+#endif
+    if ( aProfile.IsNull() || !HasIntersection( aProfile, aPlane, aPar ) )
       continue;
+       
+    aDM.Bind( aPar, aProfile );
+         aList.Append( aPar );
+  }
+  
+  if ( aList.IsEmpty() )
+    return;
+
+  TColStd_Array1OfReal anArr( 1, aList.Extent() );
+
+  TColStd_ListIteratorOfListOfReal it( aList );
+  for ( int j = 1; it.More(); it.Next(), j++ )
+    anArr( j ) = it.Value();
+
+  // sorting
+  if ( aList.Extent() > 1 )
+  {
+    TCollection_CompareOfReal Compar;
+    SortTools_QuickSortOfReal::Sort( anArr, Compar );
+
+    for (int j = 1; j <= anArr.Length(); j++) {
+      const Standard_Real aKey =  anArr(j);
+      const Handle(HYDROData_Profile)& aProfile = aDM.Find(aKey);
+      insertProfileInToOrder( aProfile );
+    }
+  } else if ( aList.Extent() == 1 ) {
+     const Standard_Real aKey = aList.Last();
+     const Handle(HYDROData_Profile)& aProfile = aDM.Find(aKey);
+     insertProfileInToOrder( aProfile );
+  } 
 
-    insertProfileInToOrder( aProfile );
+  setParametersArray( anArr );
+
+#ifdef DEB_HASINT
+  TopoDS_Wire aHydraulicWire = TopoDS::Wire( aHydAxis->GetShape() );
+  BRepTools::Write(aHydraulicWire, "Path.brep");
+  BRepTools::Write(aCmp, "Prof.brep");
+#endif
+}
+
+void HYDROData_Stream::setParametersArray( const TColStd_Array1OfReal& theArray )
+{
+  if ( theArray.Length() == 0 )
+  {
+    removeParametersArray();
+    return;
+  }
+
+  TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray );
+  
+  Handle(TDataStd_RealArray) aParamsArray = 
+    TDataStd_RealArray::Set( aLabel, theArray.Lower(), theArray.Upper() );
+
+  for ( int i = theArray.Lower(), n = theArray.Upper(); i <= n; ++i )
+  {
+    const Standard_Real& aParam = theArray( i );
+    aParamsArray->SetValue( i, aParam );
   }
 }
 
+TColStd_Array1OfReal* HYDROData_Stream::getParametersArray() const
+{
+  TColStd_Array1OfReal* anArray = NULL;
+
+  TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray, false );
+  if ( !aLabel.IsNull() )
+  {
+    Handle(TDataStd_RealArray) aParamsArray;
+    if ( aLabel.FindAttribute( TDataStd_RealArray::GetID(), aParamsArray ) )
+    {
+      anArray = new TColStd_Array1OfReal( aParamsArray->Lower(), aParamsArray->Upper() );
+      for ( int i = aParamsArray->Lower(), n = aParamsArray->Upper(); i <= n; ++i )
+      {
+        const Standard_Real& aParam = aParamsArray->Value( i );
+        anArray->SetValue( i, aParam );
+      }
+    }
+  }
+
+  return anArray;
+}
+
+void HYDROData_Stream::removeParametersArray()
+{
+  TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray, false );
+  if ( !aLabel.IsNull() )
+    aLabel.ForgetAllAttributes();
+}
+
+int HYDROData_Stream::insertParameter( const Standard_Real& theParam )
+{
+  int aResIndex = -1;
+
+  TColStd_Array1OfReal* anArr = getParametersArray();
+  if ( anArr )
+  {
+    aResIndex = 0;
+
+    TColStd_Array1OfReal aNewArr( anArr->Lower(), anArr->Upper() + 1 );
+
+    bool isInserted = false;
+    for ( int i = anArr->Lower(), j = i, n = anArr->Upper(); i <= n; ++i, ++j )
+    {
+      const Standard_Real& aStoredParam = anArr->Value( i );
+      if ( !isInserted )
+      {
+        if ( theParam > aStoredParam )
+        {
+          aResIndex++;
+        }
+        else
+        {
+          aNewArr( j ) = theParam;
+          isInserted = true;
+          ++j;
+        }
+      }
+
+      aNewArr( j ) = aStoredParam;
+    }
+
+    if ( !isInserted )
+    {
+      aResIndex = -1;
+      aNewArr( aNewArr.Upper() ) = theParam;
+    }
+    
+    setParametersArray( aNewArr );
+    delete anArr;
+  }
+  else
+  {
+    TColStd_Array1OfReal aNewArr( 1, 1 );
+    aNewArr.SetValue( 1, theParam );
+    setParametersArray( aNewArr );
+  }
+
+  return aResIndex;
+}
+
+void HYDROData_Stream::removeParameter( const int& theIndex )
+{
+  TDF_Label aLabel = myLab.FindChild( DataTag_ParamsArray, false );
+  if ( aLabel.IsNull() )
+    return;
+
+  Handle(TDataStd_RealArray) aParamsArray;
+  if ( !aLabel.FindAttribute( TDataStd_RealArray::GetID(), aParamsArray ) )
+    return;
+
+  TColStd_Array1OfReal aNewArr( aParamsArray->Lower(), aParamsArray->Upper() - 1 );
+
+  for ( int i = aParamsArray->Lower(), j = i, k = 0, n = aParamsArray->Upper(); i <= n; ++i, ++k )
+  {
+    const Standard_Real& aStoredParam = aParamsArray->Value( i );
+    if ( k == theIndex )
+      continue;
+
+    aNewArr.SetValue( j, aStoredParam );
+    ++j;
+  }
+
+  setParametersArray( aNewArr );
+}