Salome HOME
Comments moved.
[modules/hydro.git] / src / HYDROData / HYDROData_CalculationCase.cxx
index af132d34c4fc6c8469451f726f33791b7d8d9a69..5a5b3ad2dc78fe86434a6d11b93dcf041520135c 100644 (file)
@@ -2,14 +2,29 @@
 #include "HYDROData_CalculationCase.h"
 
 #include "HYDROData_ArtificialObject.h"
+#include "HYDROData_Bathymetry.h"
 #include "HYDROData_Document.h"
 #include "HYDROData_Iterator.h"
 #include "HYDROData_NaturalObject.h"
+#include "HYDROData_PolylineXY.h"
 #include "HYDROData_SplitToZonesTool.h"
 #include "HYDROData_Region.h"
 #include "HYDROData_Tool.h"
 #include "HYDROData_Zone.h"
 
+#include <TopoDS.hxx>
+#include <TopoDS_Shell.hxx>
+#include <BRep_Builder.hxx>
+#include <BRepBuilderAPI_Sewing.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopExp.hxx>
+#include <TopTools_ListOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <BRepTopAdaptor_FClass2d.hxx>
+#include <TopAbs.hxx>
+#define CALCULATION_REGIONS_PREF GetName() + "_Reg"
+#define CALCULATION_ZONES_PREF GetName() + "_Zone"
+
 #define PYTHON_CALCULATION_ID "KIND_CALCULATION"
 
 IMPLEMENT_STANDARD_HANDLE(HYDROData_CalculationCase, HYDROData_Entity)
@@ -24,11 +39,55 @@ HYDROData_CalculationCase::~HYDROData_CalculationCase()
 {
 }
 
+void HYDROData_CalculationCase::SetName( const QString& theName )
+{
+  QString anOldCaseName = GetName();
+  if ( anOldCaseName != theName )
+  {
+    HYDROData_SequenceOfObjects aRegions = GetRegions();
+
+    HYDROData_SequenceOfObjects::Iterator anIter( aRegions );
+    for ( ; anIter.More(); anIter.Next() )
+    {
+      Handle(HYDROData_Region) aRegion =
+        Handle(HYDROData_Region)::DownCast( anIter.Value() );
+      if ( aRegion.IsNull() )
+        continue;
+
+      QString aRegionName = aRegion->GetName();
+      if ( aRegionName.startsWith( anOldCaseName ) )
+      {
+        aRegionName.replace( anOldCaseName, theName );
+        aRegion->SetName( aRegionName );
+      }
+
+      HYDROData_SequenceOfObjects aZones = aRegion->GetZones();
+      HYDROData_SequenceOfObjects::Iterator anIter( aZones );
+      for ( ; anIter.More(); anIter.Next() )
+      {
+        Handle(HYDROData_Zone) aRegZone =
+          Handle(HYDROData_Zone)::DownCast( anIter.Value() );
+        if ( aRegZone.IsNull() )
+          continue;
+
+        QString aRegionZoneName = aRegZone->GetName();
+        if ( aRegionZoneName.startsWith( anOldCaseName ) )
+        {
+          aRegionZoneName.replace( anOldCaseName, theName );
+          aRegZone->SetName( aRegionZoneName );
+        }
+      }
+    }
+  }
+
+  HYDROData_Entity::SetName( theName );
+}
+
 QStringList HYDROData_CalculationCase::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const
 {
   QStringList aResList;
 
-  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( this );
+  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
   if ( aDocument.IsNull() )
     return aResList;
                              
@@ -72,24 +131,44 @@ QStringList HYDROData_CalculationCase::DumpToPython( MapOfTreatedObjects& theTre
   return aResList;
 }
 
-void HYDROData_CalculationCase::SplitGeometryObjects()
+HYDROData_SequenceOfObjects HYDROData_CalculationCase::GetAllReferenceObjects() const
+{
+  HYDROData_SequenceOfObjects aResSeq = HYDROData_Entity::GetAllReferenceObjects();
+
+  Handle(HYDROData_PolylineXY) aBoundaryPolyline = GetBoundaryPolyline();
+  if ( !aBoundaryPolyline.IsNull() )
+    aResSeq.Append( aBoundaryPolyline );
+
+  HYDROData_SequenceOfObjects aSeqOfRegions = GetRegions();
+  aResSeq.Append( aSeqOfRegions );
+
+  return aResSeq;
+}
+
+void HYDROData_CalculationCase::Update()
 {
+  HYDROData_Entity::Update();
+
   // At first we remove previously created regions
   RemoveRegions();
 
-  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( this );
+  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
   if ( aDocument.IsNull() )
     return;
 
+  Handle(HYDROData_PolylineXY) aBoundaryPolyline = GetBoundaryPolyline();
   HYDROData_SequenceOfObjects aGeomObjects = GetGeometryObjects();
   if ( aGeomObjects.IsEmpty() )
     return;
 
   HYDROData_SplitToZonesTool::SplitDataList aSplitedZones =
-    HYDROData_SplitToZonesTool::SplitToZones( aGeomObjects );
+    HYDROData_SplitToZonesTool::SplitToZones( aGeomObjects, aBoundaryPolyline );
   if ( aSplitedZones.isEmpty() )
     return;
 
+  QString aRegsPref = CALCULATION_REGIONS_PREF;
+  QString aZonesPref = CALCULATION_ZONES_PREF;
+
   // Create result regions for case, by default one zone for one region
   HYDROData_SplitToZonesTool::SplitDataListIterator anIter( aSplitedZones );
   while( anIter.hasNext() )
@@ -99,13 +178,13 @@ void HYDROData_CalculationCase::SplitGeometryObjects()
     // Create new region
     Handle(HYDROData_Region) aRegion = addNewRegion();
 
-    QString aRegionName = HYDROData_Tool::GenerateObjectName( aDocument, "Region" );
+    QString aRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
     aRegion->SetName( aRegionName );
 
     // Add the zone for region
     Handle(HYDROData_Zone) aRegionZone = aRegion->addNewZone();
 
-    QString aZoneName = HYDROData_Tool::GenerateObjectName( aDocument, "Zone" );
+    QString aZoneName = HYDROData_Tool::GenerateObjectName( aDocument, aZonesPref );
     aRegionZone->SetName( aZoneName );
 
     aRegionZone->SetShape( aSplitData.Face() );
@@ -127,17 +206,17 @@ void HYDROData_CalculationCase::SplitGeometryObjects()
 
 bool HYDROData_CalculationCase::AddGeometryObject( const Handle(HYDROData_Object)& theObject )
 {
-  if ( theObject.IsNull() )
-    return false;
-  
-  if ( !theObject->IsKind( STANDARD_TYPE(HYDROData_ArtificialObject) ) &&
-       !theObject->IsKind( STANDARD_TYPE(HYDROData_NaturalObject) ) )
+  if ( !HYDROData_Tool::IsGeometryObject( theObject ) )
     return false; // Wrong type of object
 
   if ( HasReference( theObject, DataTag_GeometryObject ) )
     return false; // Object is already in reference list
 
   AddReferenceObject( theObject, DataTag_GeometryObject );
+  
+  // Indicate model of the need to update zones splitting
+  SetToUpdate( true );
+
   return true;
 }
 
@@ -152,11 +231,43 @@ void HYDROData_CalculationCase::RemoveGeometryObject( const Handle(HYDROData_Obj
     return;
 
   RemoveReferenceObject( theObject->Label(), DataTag_GeometryObject );
+
+  // Indicate model of the need to update zones splitting
+  SetToUpdate( true );
 }
 
 void HYDROData_CalculationCase::RemoveGeometryObjects()
 {
   ClearReferenceObjects( DataTag_GeometryObject );
+
+  // Indicate model of the need to update zones splitting
+  SetToUpdate( true );
+}
+
+void HYDROData_CalculationCase::SetBoundaryPolyline( const Handle(HYDROData_PolylineXY)& thePolyline )
+{
+  Handle(HYDROData_PolylineXY) aPrevPolyline = GetBoundaryPolyline();
+
+  SetReferenceObject( thePolyline, DataTag_Polyline );
+
+  // Indicate model of the need to update zones splitting
+  SetToUpdate( !IsEqual( aPrevPolyline, thePolyline ) || IsMustBeUpdated() );
+}
+
+Handle(HYDROData_PolylineXY) HYDROData_CalculationCase::GetBoundaryPolyline() const
+{
+  return Handle(HYDROData_PolylineXY)::DownCast( 
+           GetReferenceObject( DataTag_Polyline ) );
+}
+
+void HYDROData_CalculationCase::RemoveBoundaryPolyline()
+{
+  Handle(HYDROData_PolylineXY) aPrevPolyline = GetBoundaryPolyline();
+
+  ClearReferenceObjects( DataTag_Polyline );
+
+  // Indicate model of the need to update zones splitting
+  SetToUpdate( !aPrevPolyline.IsNull() || IsMustBeUpdated() );
 }
 
 Handle(HYDROData_Region) HYDROData_CalculationCase::AddNewRegion( const Handle(HYDROData_Zone)& theZone )
@@ -166,10 +277,12 @@ Handle(HYDROData_Region) HYDROData_CalculationCase::AddNewRegion( const Handle(H
     return aNewRegion;
 
   // Generate new name for new region
-  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( this );
+  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
   if ( !aDocument.IsNull() )
   {
-    QString aNewRegionName = HYDROData_Tool::GenerateObjectName( aDocument, "Region" );
+    QString aRegsPref = CALCULATION_REGIONS_PREF;
+
+    QString aNewRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
     aNewRegion->SetName( aNewRegionName );
   }
 
@@ -198,8 +311,11 @@ bool HYDROData_CalculationCase::AddRegion( const Handle(HYDROData_Region)& theRe
 
     theRegion->SetLabel( aNewRegion->Label() );
   }
+  else
+  {
+    AddReferenceObject( theRegion, DataTag_Region );
+  }
 
-  AddReferenceObject( theRegion, DataTag_Region );
   return true;
 }
 
@@ -208,6 +324,40 @@ HYDROData_SequenceOfObjects HYDROData_CalculationCase::GetRegions() const
   return GetReferenceObjects( DataTag_Region );
 }
 
+void HYDROData_CalculationCase::UpdateRegionsOrder()
+{
+  Handle(HYDROData_Document) aDocument = HYDROData_Document::Document( myLab );
+  if ( aDocument.IsNull() )
+    return;
+
+  HYDROData_SequenceOfObjects aRegions = GetRegions();
+
+  HYDROData_SequenceOfObjects::Iterator anIter( aRegions );
+  for ( ; anIter.More(); anIter.Next() )
+  {
+    Handle(HYDROData_Region) aRegion =
+      Handle(HYDROData_Region)::DownCast( anIter.Value() );
+    if ( aRegion.IsNull() )
+      continue;
+
+    aRegion->SetName( "" );
+  }
+
+  QString aRegsPref = CALCULATION_REGIONS_PREF;
+
+  anIter.Init( aRegions );
+  for ( ; anIter.More(); anIter.Next() )
+  {
+    Handle(HYDROData_Region) aRegion =
+      Handle(HYDROData_Region)::DownCast( anIter.Value() );
+    if ( aRegion.IsNull() )
+      continue;
+
+    QString aRegionName = HYDROData_Tool::GenerateObjectName( aDocument, aRegsPref );
+    aRegion->SetName( aRegionName );
+  }
+}
+
 void HYDROData_CalculationCase::RemoveRegion( const Handle(HYDROData_Region)& theRegion )
 {
   if ( theRegion.IsNull() )
@@ -239,3 +389,257 @@ Handle(HYDROData_Region) HYDROData_CalculationCase::addNewRegion()
   return aNewRegion;
 }
 
+TopoDS_Shell HYDROData_CalculationCase::GetShell()
+{
+  TopoDS_Shell aShell;
+
+  TopTools_ListOfShape aFacesList;
+
+  // Make shell containing all region shapes
+  BRepBuilderAPI_Sewing aSewing( Precision::Confusion()*10.0 );
+
+  HYDROData_SequenceOfObjects aCaseRegions = GetRegions();
+  HYDROData_SequenceOfObjects::Iterator aRegionIter( aCaseRegions );
+  for ( ; aRegionIter.More(); aRegionIter.Next() ) {
+    Handle(HYDROData_Region) aRegion =
+      Handle(HYDROData_Region)::DownCast( aRegionIter.Value() );
+    if( aRegion.IsNull() ) {
+      continue;
+    }
+
+    TopoDS_Shape aRegionShape = aRegion->GetShape();
+    if( !aRegionShape.IsNull() ) {
+      if ( aRegionShape.ShapeType() == TopAbs_FACE ) {
+        TopoDS_Face aFace = TopoDS::Face( aRegionShape );
+        if ( !aFace.IsNull() ) {
+          aFacesList.Append( aFace );
+          aSewing.Add( aFace );
+        }
+      } else {
+        TopExp_Explorer anExp( aRegionShape, TopAbs_FACE );
+        for ( ; anExp.More(); anExp.Next() ) {
+          TopoDS_Face aFace = TopoDS::Face( anExp.Current() );
+          if ( !aFace.IsNull() ) {
+            aFacesList.Append( aFace );
+            aSewing.Add( aFace );
+          }
+        }
+      }
+    }
+  } // regions iterator
+  
+  aSewing.Perform();
+  TopoDS_Shape aSewedShape = aSewing.SewedShape();
+
+  if ( !aSewedShape.IsNull() )
+  {
+    if ( aSewedShape.ShapeType() == TopAbs_FACE && aCaseRegions.Length() ==1 ) {
+      // create shell from one face
+      BRep_Builder aBuilder;
+      aBuilder.MakeShell( aShell );
+      aBuilder.Add( aShell, aSewedShape);
+    } else {
+      TopExp_Explorer anExpShells( aSewedShape, TopAbs_SHELL );
+      Standard_Integer aNbOfShells = 0;
+      for ( ; anExpShells.More(); anExpShells.Next() ) {
+        aShell = TopoDS::Shell( anExpShells.Current() );
+        aNbOfShells++;
+      }
+
+      if ( aNbOfShells != 1 ) {
+        aShell.Nullify();
+        BRep_Builder aBuilder;
+        aBuilder.MakeShell( aShell );
+
+        TopExp_Explorer anExpFaces( aSewedShape, TopAbs_FACE );
+        for ( ; anExpFaces.More(); anExpFaces.Next() ) {
+          TopoDS_Face aFace = TopoDS::Face( anExpFaces.Current() );
+          if ( !aFace.IsNull() ) {
+            aBuilder.Add( aShell, aFace );
+          }
+        }
+      }
+    }
+  }
+
+  if ( !aShell.IsNull() ) {
+    TopTools_IndexedMapOfShape aMapOfFaces;
+    TopExp::MapShapes( aShell, TopAbs_FACE, aMapOfFaces );
+    if ( aMapOfFaces.Extent() != aFacesList.Extent() ) {
+      aShell.Nullify();
+      BRep_Builder aBuilder;
+      aBuilder.MakeShell( aShell );
+
+      TopTools_ListIteratorOfListOfShape anIter( aFacesList );
+      for ( ; anIter.More(); anIter.Next() ) {
+        TopoDS_Face aFace = TopoDS::Face( anIter.Value() );
+        aBuilder.Add( aShell, aFace );
+      }
+    }
+  }
+
+/* TODO: old version
+  // Make shell
+  BRep_Builder aBuilder;
+  aBuilder.MakeShell( aShell );
+
+  // Make shell containing all region shapes
+  HYDROData_SequenceOfObjects aCaseRegions = GetRegions();
+  HYDROData_SequenceOfObjects::Iterator aRegionIter( aCaseRegions );
+  for ( ; aRegionIter.More(); aRegionIter.Next() ) {
+    Handle(HYDROData_Region) aRegion =
+      Handle(HYDROData_Region)::DownCast( aRegionIter.Value() );
+    if( aRegion.IsNull() ) {
+      continue;
+    }
+
+    TopoDS_Shape aRegionShape = aRegion->GetShape();
+
+    // Add shape (face or shell) corresponding to the region into the shell
+    if( !aRegionShape.IsNull() ) {
+      if ( aRegionShape.ShapeType() == TopAbs_FACE ) {
+        aBuilder.Add( aShell, aRegionShape );
+      } else {
+        TopExp_Explorer anExp( aRegionShape, TopAbs_FACE );
+        for( ; anExp.More(); anExp.Next() ) {
+          TopoDS_Face aFace = TopoDS::Face( anExp.Current() );
+          if( !aFace.IsNull() ) {
+            aBuilder.Add( aShell, aFace );
+          }
+        }
+      }
+    }
+  } // regions iterator
+*/
+
+  // Nullify shell if it is empty
+  if ( !aShell.IsNull() && !TopoDS_Iterator(aShell).More() ) {
+    aShell.Nullify();
+  }
+
+  return aShell;
+}
+
+double HYDROData_CalculationCase::GetAltitudeForPoint( const gp_XY& thePoint ) const
+{
+  double aResAltitude = HYDROData_Bathymetry::GetInvalidAltitude();
+
+  Handle(HYDROData_Zone) aZone = GetZoneFromPoint( thePoint );
+  if ( aZone.IsNull() )
+    return aResAltitude;
+
+  HYDROData_Zone::MergeBathymetriesType aZoneMergeType = aZone->GetMergeType();
+  if ( !aZone->IsMergingNeed() )
+  {
+    aZoneMergeType = HYDROData_Zone::Merge_UNKNOWN;
+  }
+  else if ( aZoneMergeType == HYDROData_Zone::Merge_UNKNOWN )
+  {
+    return aResAltitude;
+  }
+
+  if ( aZoneMergeType == HYDROData_Zone::Merge_Object )
+  {
+    Handle(HYDROData_Bathymetry) aMergeBathymetry = aZone->GetMergeBathymetry();
+    if ( !aMergeBathymetry.IsNull() )
+      aResAltitude = aMergeBathymetry->GetAltitudeForPoint( thePoint );
+  }
+  else
+  {
+    HYDROData_SequenceOfObjects aZoneObjects = aZone->GetGeometryObjects();
+    HYDROData_SequenceOfObjects::Iterator anIter( aZoneObjects );
+    for ( ; anIter.More(); anIter.Next() )
+    {
+      Handle(HYDROData_Object) aZoneObj =
+        Handle(HYDROData_Object)::DownCast( anIter.Value() );
+      if ( aZoneObj.IsNull() )
+        continue;
+
+      Handle(HYDROData_Bathymetry) anObjBathymetry = aZoneObj->GetBathymetry();
+      if ( anObjBathymetry.IsNull() )
+        continue;
+
+      double aPointAltitude = anObjBathymetry->GetAltitudeForPoint( thePoint );
+      if ( ValuesEquals( aPointAltitude, HYDROData_Bathymetry::GetInvalidAltitude() ) )
+        continue;
+
+      if ( aZoneMergeType == HYDROData_Zone::Merge_UNKNOWN )
+      {
+        aResAltitude = aPointAltitude;
+        break;
+      }
+      else if ( aZoneMergeType == HYDROData_Zone::Merge_ZMIN )
+      {
+        if ( ValuesEquals( aResAltitude, HYDROData_Bathymetry::GetInvalidAltitude() ) ||
+             aResAltitude > aPointAltitude )
+        {
+          aResAltitude = aPointAltitude;
+        }
+      }
+      else if ( aZoneMergeType == HYDROData_Zone::Merge_ZMAX )
+      {
+        if ( ValuesEquals( aResAltitude, HYDROData_Bathymetry::GetInvalidAltitude() ) ||
+             aResAltitude < aPointAltitude )
+        {
+          aResAltitude = aPointAltitude;
+        }
+      }
+    }
+  }
+
+  return aResAltitude;
+}
+
+Handle(HYDROData_Zone) HYDROData_CalculationCase::GetZoneFromPoint( const gp_XY& thePoint ) const
+{
+  Handle(HYDROData_Zone) aResZone;
+
+  HYDROData_SequenceOfObjects aRegions = GetRegions();
+
+  HYDROData_SequenceOfObjects::Iterator anIter( aRegions );
+  for ( ; anIter.More() && aResZone.IsNull(); anIter.Next() )
+  {
+    Handle(HYDROData_Region) aRegion =
+      Handle(HYDROData_Region)::DownCast( anIter.Value() );
+    if ( aRegion.IsNull() )
+      continue;
+
+    HYDROData_SequenceOfObjects aZones = aRegion->GetZones();
+    HYDROData_SequenceOfObjects::Iterator aZonesIter( aZones );
+    for ( ; aZonesIter.More() && aResZone.IsNull(); aZonesIter.Next() )
+    {
+      Handle(HYDROData_Zone) aRegZone =
+        Handle(HYDROData_Zone)::DownCast( aZonesIter.Value() );
+      if ( aRegZone.IsNull() )
+        continue;
+
+      PointClassification aPointRelation = GetPointClassification( thePoint, aRegZone );
+      if ( aPointRelation != POINT_OUT )
+        aResZone = aRegZone; // We found the desired zone
+    }
+  }
+
+  return aResZone;
+}
+HYDROData_CalculationCase::PointClassification HYDROData_CalculationCase::GetPointClassification(
+  const gp_XY&                  thePoint,
+  const Handle(HYDROData_Zone)& theZone ) const
+{
+  PointClassification aRes = POINT_OUT;
+  if ( theZone.IsNull() )
+    return aRes;
+
+  TopoDS_Face aZoneFace = TopoDS::Face( theZone->GetShape() );
+  if ( aZoneFace.IsNull() )
+    return aRes;
+
+  BRepTopAdaptor_FClass2d aClassifier( aZoneFace, Precision::Confusion() );
+  TopAbs_State State = aClassifier.Perform( gp_Pnt2d(thePoint), Standard_False );
+  if (State == TopAbs_OUT)
+       aRes =  POINT_OUT;
+  else if(State == TopAbs_IN)
+    aRes =  POINT_IN;
+  else if(State == TopAbs_ON)
+    aRes =  POINT_ON;    
+  return aRes;
+}