X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FHYDROData%2FHYDROData_LandCoverMap.cxx;h=969ce6d077423bc7f159fe8fedc31d29dfa19c82;hb=670039d7a5d25b1da51956b668f212756d31a86e;hp=c801780fd80cbb46cdd3d5aa249cecebac203bf1;hpb=b7783f8b6083202f887c371c74395cf7da13b990;p=modules%2Fhydro.git diff --git a/src/HYDROData/HYDROData_LandCoverMap.cxx b/src/HYDROData/HYDROData_LandCoverMap.cxx index c801780f..969ce6d0 100644 --- a/src/HYDROData/HYDROData_LandCoverMap.cxx +++ b/src/HYDROData/HYDROData_LandCoverMap.cxx @@ -17,89 +17,152 @@ // #include +#include +#include #include +#include +#include #include #include #include #include -#include -#include -#include +#include +#include +#include +#include #include #include +#include #include #include #include - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include #include +#include + +const char TELEMAC_FORMAT = 'f'; +const int TELEMAC_PRECISION = 3; + IMPLEMENT_STANDARD_HANDLE(HYDROData_LandCoverMap, HYDROData_Entity) IMPLEMENT_STANDARD_RTTIEXT(HYDROData_LandCoverMap, HYDROData_Entity) -class HYDROData_MapOfShapeToStricklerType : public NCollection_IndexedDataMap -{ -}; - /** Constructor @param theMap the land cover map to iterate through */ -HYDROData_LandCoverMap::Iterator::Iterator( const HYDROData_LandCoverMap& theMap ) +HYDROData_LandCoverMap::Explorer::Explorer( const HYDROData_LandCoverMap& theMap ) { Init( theMap ); } +HYDROData_LandCoverMap::Explorer::Explorer( const Handle( HYDROData_LandCoverMap )& theMap ) +{ + if( theMap.IsNull() ) + { + myExplorer = 0; + myIndex = -1; + } + else + Init( *theMap ); +} + /** Initialize the iterator @param theMap the land cover map to iterate through */ -void HYDROData_LandCoverMap::Iterator::Init( const HYDROData_LandCoverMap& theMap ) +void HYDROData_LandCoverMap::Explorer::Init( const HYDROData_LandCoverMap& theMap ) { - myIterator = new TopoDS_Iterator( theMap.GetShape() ); - myIndex = 0; + TopoDS_Shape aShape = theMap.GetShape(); + if( aShape.IsNull() ) + myExplorer = 0; + else + { + myExplorer = new TopExp_Explorer(); + myExplorer->Init( aShape, TopAbs_FACE ); + } + theMap.myLab.FindChild( DataTag_Types ).FindAttribute( TDataStd_ExtStringArray::GetID(), myArray ); + if( myArray.IsNull() ) + myIndex = -1; + else + myIndex = myArray->Lower(); } /** Destructor */ -HYDROData_LandCoverMap::Iterator::~Iterator() +HYDROData_LandCoverMap::Explorer::~Explorer() +{ + delete myExplorer; +} + +/** + Return the current 0-based index of the iterator + @return the current index +*/ +int HYDROData_LandCoverMap::Explorer::Index() const { - delete myIterator; + if( myArray.IsNull() ) + return -1; + else + return myIndex - myArray->Lower(); } /** Return if the iterator has more elements @return if the iterator has more elements */ -bool HYDROData_LandCoverMap::Iterator::More() const +bool HYDROData_LandCoverMap::Explorer::More() const { - return !myArray.IsNull() && myIterator->More(); + return !myArray.IsNull() && myExplorer && myExplorer->More(); } /** Move iterator to the next element */ -void HYDROData_LandCoverMap::Iterator::Next() +void HYDROData_LandCoverMap::Explorer::Next() { - myIterator->Next(); + if( myExplorer ) + { + myExplorer->Next(); + myIndex++; + } } /** Get the current land cover (face) @return the land cover's face */ -TopoDS_Face HYDROData_LandCoverMap::Iterator::Face() const +TopoDS_Face HYDROData_LandCoverMap::Explorer::Face() const { - return TopoDS::Face( myIterator->Value() ); + if( myExplorer ) + return TopoDS::Face( myExplorer->Current() ); + else + return TopoDS_Face(); } /** Get the current land cover's Strickler type @return the land cover's Strickler type */ -QString HYDROData_LandCoverMap::Iterator::StricklerType() const +QString HYDROData_LandCoverMap::Explorer::StricklerType() const { if( myArray.IsNull() || myIndex < myArray->Lower() || myIndex > myArray->Upper() ) return ""; @@ -107,10 +170,23 @@ QString HYDROData_LandCoverMap::Iterator::StricklerType() const return HYDROData_Tool::toQString( myArray->Value( myIndex ) ); } +/** + Set the Strickler type for the current land cover + @param theType the Strickler type +*/ +void HYDROData_LandCoverMap::Explorer::SetStricklerType( const QString& theType ) +{ + if( myArray.IsNull() || myIndex < myArray->Lower() || myIndex > myArray->Upper() ) + return; + else + myArray->SetValue( myIndex, HYDROData_Tool::toExtString( theType ) ); +} + /** Constructor */ HYDROData_LandCoverMap::HYDROData_LandCoverMap() + : HYDROData_Entity( Geom_No ) { } @@ -130,26 +206,137 @@ const ObjectKind HYDROData_LandCoverMap::GetKind() const return KIND_LAND_COVER_MAP; } +int HYDROData_LandCoverMap::GetLCCount() const +{ + Explorer anIt( *this ); + int i = 0; + for( ; anIt.More(); anIt.Next() ) + i++; + return i; +} + +bool HYDROData_LandCoverMap::IsEmpty() const +{ + Explorer anIt( *this ); + if ( !anIt.More() ) + return true; + else + return false; +} + /** - Import the land cover map from QGIS - @param theFileName the name of file - @return if the import is successful + Load attributes from DBF File +/// */ -bool HYDROData_LandCoverMap::ImportQGIS( const QString& theFileName ) +HYDROData_LandCoverMap::DBFStatus HYDROData_LandCoverMap::ImportDBF( const QString& theDBFFileName, + const QString& theFieldName, + const QStringList& theDBFValues, + const QStringList& theStricklerTypes, + const QList& theIndices ) { - //TODO - return false; + if (theDBFValues.size() != theStricklerTypes.size()) + return DBFStatus_DIFF_SIZE_ERROR; + HYDROData_ShapeFile aDBFImporter; + if (!aDBFImporter.DBF_OpenDBF(theDBFFileName)) + return DBFStatus_OPEN_FILE_ERROR; //cant open file + + QStringList FieldList = aDBFImporter.DBF_GetFieldList(); + int FieldNameIndex = FieldList.indexOf(theFieldName); + if (FieldNameIndex == -1) + return DBFStatus_NO_SUCH_FIELD_ERROR; //no such field + + std::vector theAttrV; + aDBFImporter.DBF_GetAttributeList(FieldNameIndex, theAttrV ); + + bool allOK = true; + Explorer anIt( *this ); + for( ; anIt.More(); anIt.Next() ) + { + int CurIndex = anIt.Index(); + HYDROData_ShapeFile::DBF_AttrValue AValue = theAttrV[theIndices[CurIndex]]; + int StricklerTypesInd = theDBFValues.indexOf(QString(AValue.myStrVal)); + if ( StricklerTypesInd != -1) + anIt.SetStricklerType(theStricklerTypes[StricklerTypesInd]); + else + allOK = false; + } + if (allOK) + return DBFStatus_OK; + else + return DBFStatus_NO_DBFVALUES_CORRESPONDENCE_WARNING; } /** - Export the land cover map to QGIS - @param theFileName the name of file - @return if the export is successful + Export attributes to DBF File +/// */ -bool HYDROData_LandCoverMap::ExportQGIS( const QString& theFileName ) const +void HYDROData_LandCoverMap::ExportDBF( const QString& theDBFFileName, + const QString& theFieldName, + const QStringList& theDBFValues, + const QStringList& theStricklerTypes) const { - //TODO - return false; + if (theDBFValues.size() != theStricklerTypes.size()) + return; + HYDROData_ShapeFile anExporter; + std::vector theAttrV; + Explorer anIt( *this ); + for( ; anIt.More(); anIt.Next() ) + { + QString CurST = anIt.StricklerType(); + HYDROData_ShapeFile::DBF_AttrValue aCurAttrV; + aCurAttrV.myIsNull = false; + int StricklerTypesInd = theStricklerTypes.indexOf(CurST); + if (StricklerTypesInd != -1) + { + aCurAttrV.myStrVal = theDBFValues[StricklerTypesInd]; + aCurAttrV.myFieldType = HYDROData_ShapeFile::DBF_FieldType_String; + theAttrV.push_back(aCurAttrV); + } + else + aCurAttrV.myIsNull = true; + } + //use actual str value; not the raw value + anExporter.DBF_WriteFieldAndValues(theDBFFileName, theFieldName, HYDROData_ShapeFile::DBF_FieldType_String, theAttrV, false); + +} + +int HashCode( const gp_Pnt& thePoint, const Standard_Integer theUpper ) +{ + int aHashX = HashCode( thePoint.X(), theUpper ); + int aHashY = HashCode( thePoint.Y(), theUpper ); + return (aHashX^aHashY)%theUpper; +} + +bool operator == ( const gp_Pnt& thePoint1, const gp_Pnt& thePoint2 ) +{ + return thePoint1.IsEqual( thePoint2, Precision::Confusion() ); +} + +bool EdgeDiscretization( const TopoDS_Edge& theEdge, + Standard_Real theDeflection, + NCollection_IndexedMap& theVerticesMap, + QList& theVerticesIds ) +{ + BRepAdaptor_Curve aCurve( theEdge ); + GCPnts_QuasiUniformDeflection aDiscrete( aCurve, theDeflection ); + if( !aDiscrete.IsDone() ) + return false; + + int n = aDiscrete.NbPoints(); + for( int i=1; i<=n; i++ ) + { + gp_Pnt aPnt = aDiscrete.Value( i ); + int anId; + if( theVerticesMap.Contains( aPnt ) ) + anId = theVerticesMap.FindIndex( aPnt ); + else + { + anId = theVerticesMap.Size(); + theVerticesMap.Add( aPnt ); + } + theVerticesIds.append( anId ); + } + return true; } /** @@ -157,10 +344,89 @@ bool HYDROData_LandCoverMap::ExportQGIS( const QString& theFileName ) const @param theFileName the name of file @return if the export is successful */ -bool HYDROData_LandCoverMap::ExportTelemac( const QString& theFileName ) const +bool HYDROData_LandCoverMap::ExportTelemac( const QString& theFileName, Standard_Real theDeflection ) const { - //TODO - return false; + TopoDS_Shape aLandCoverMapShape = GetShape(); + TopTools_ListOfShape aListOfFaces; + TopExp_Explorer anExp( aLandCoverMapShape, TopAbs_FACE ); + for( ; anExp.More(); anExp.Next() ) + aListOfFaces.Append( anExp.Current() ); + + TopoDS_Shape aShape = MergeFaces( aListOfFaces, false ); + + NCollection_IndexedMap aVerticesMap; + NCollection_IndexedDataMap< TopoDS_Edge, QList > anEdgesMap; + NCollection_IndexedDataMap< TopoDS_Face, QList > aFacesMap; + + // add into the map all edges existing in the shell + TopExp_Explorer anExp1( aShape, TopAbs_EDGE ); + for( ; anExp1.More(); anExp1.Next() ) + { + TopoDS_Edge anEdge = TopoDS::Edge( anExp1.Current() ); + QList aVerticesIdsList; + if( EdgeDiscretization( anEdge, theDeflection, aVerticesMap, aVerticesIdsList ) ) + anEdgesMap.Add( anEdge, aVerticesIdsList ); + } + + // add into the map all faces existing in the shell and correspondence between face and edges ids + TopExp_Explorer anExp2( aShape, TopAbs_FACE ); + for( ; anExp2.More(); anExp2.Next() ) + { + TopoDS_Face aFace = TopoDS::Face( anExp2.Current() ); + TopExp_Explorer anExp3( aFace, TopAbs_EDGE ); + QList anEdgesIdsList; + for( ; anExp3.More(); anExp3.Next() ) + { + TopoDS_Edge anEdge = TopoDS::Edge( anExp3.Current() ); + int anEdgeId = anEdgesMap.FindIndex( anEdge ); + anEdgesIdsList.append( anEdgeId ); + } + aFacesMap.Add( aFace, anEdgesIdsList ); + } + + QFile aFile( theFileName ); + if( !aFile.open( QFile::WriteOnly | QFile::Text ) ) + return false; + + QTextStream aStream( &aFile ); + aStream << "# nodes\n"; + NCollection_IndexedMap::Iterator anIt1( aVerticesMap ); + for( ; anIt1.More(); anIt1.Next() ) + { + gp_Pnt aPnt = anIt1.Value(); + aStream << QString::number( aPnt.X(), TELEMAC_FORMAT, TELEMAC_PRECISION ); + aStream << " "; + aStream << QString::number( aPnt.Y(), TELEMAC_FORMAT, TELEMAC_PRECISION ); + aStream << " "; + aStream << QString::number( aPnt.Z(), TELEMAC_FORMAT, TELEMAC_PRECISION ); + aStream << "\n"; + } + aStream << "\n"; + + aStream << "# edges\n"; + NCollection_IndexedDataMap< TopoDS_Edge, QList >::Iterator anIt2( anEdgesMap ); + for( ; anIt2.More(); anIt2.Next() ) + { + QList aVerticesIds = anIt2.Value(); + foreach( int anId, aVerticesIds ) + aStream << anId << " "; + aStream << "\n"; + } + aStream << "\n"; + + aStream << "# faces\n"; + NCollection_IndexedDataMap< TopoDS_Face, QList >::Iterator anIt3( aFacesMap ); + for( ; anIt3.More(); anIt3.Next() ) + { + QList anEdgesIds = anIt3.Value(); + foreach( int anId, anEdgesIds ) + aStream << anId << " "; + aStream << "\n"; + } + aStream << "\n"; + + aFile.close(); + return true; } /** @@ -171,8 +437,24 @@ bool HYDROData_LandCoverMap::ExportTelemac( const QString& theFileName ) const */ bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_Object )& theObject, const QString& theType ) { - //TODO - return false; + if( theObject.IsNull() ) + return false; + + TopoDS_Shape aShape = theObject->GetTopShape(); + if( aShape.ShapeType()!=TopAbs_FACE ) + return false; + + TopoDS_Face aFace = TopoDS::Face( aShape ); + return LocalPartition( aFace, theType ); +} + +bool HYDROData_LandCoverMap::Add( const TopoDS_Wire& theWire, const QString& theType ) +{ + if( !theWire.Closed() ) + return false; + + TopoDS_Face aFace = BRepBuilderAPI_MakeFace( theWire, Standard_True ).Face(); + return LocalPartition( aFace, theType ); } /** @@ -181,9 +463,27 @@ bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_Object )& theObject, c @param theType the Strickler type for the new land cover @return if the addition is successful */ -bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_Polyline )& thePolyline, const QString& theType ) +bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_PolylineXY )& thePolyline, const QString& theType ) { - //TODO + if( thePolyline.IsNull() ) + return false; + + TopoDS_Shape aShape = thePolyline->GetShape(); + if( aShape.ShapeType()==TopAbs_WIRE ) + return Add( TopoDS::Wire( aShape ), theType ); + + if( aShape.ShapeType()==TopAbs_COMPOUND ) + { + TopExp_Explorer anExp( aShape, TopAbs_WIRE ); + for( ; anExp.More(); anExp.Next() ) + { + TopoDS_Wire aPart = TopoDS::Wire( anExp.Current() ); + if( !Add( aPart, theType ) ) + return false; + } + return true; + } + return false; } @@ -194,8 +494,37 @@ bool HYDROData_LandCoverMap::Add( const Handle( HYDROData_Polyline )& thePolylin */ bool HYDROData_LandCoverMap::Remove( const TopoDS_Face& theFace ) { - //TODO - return false; + TopTools_ListOfShape aList; + aList.Append( theFace ); + return Remove( aList ); +} + +/** + Remove the given faces from land cover map + @param theFacesToRemove the face list to be removed + @return if the removing is successful +*/ +bool HYDROData_LandCoverMap::Remove( const TopTools_ListOfShape& theFacesToRemove ) +{ + HYDROData_MapOfFaceToStricklerType aFacesToRemove, aNewFaces; + TopTools_ListIteratorOfListOfShape aFIt( theFacesToRemove ); + for( ; aFIt.More(); aFIt.Next() ) + { + TopoDS_Shape aShape = aFIt.Value(); + if( aShape.ShapeType()==TopAbs_FACE ) + aFacesToRemove.Add( TopoDS::Face( aShape ), "" ); + } + + Explorer anIt( *this ); + for( ; anIt.More(); anIt.Next() ) + if( !aFacesToRemove.Contains( anIt.Face() ) ) + aNewFaces.Add( anIt.Face(), anIt.StricklerType() ); + + if ( aNewFaces.IsEmpty() ) + return false; + + StoreLandCovers( aNewFaces ); + return true; } /** @@ -203,12 +532,27 @@ bool HYDROData_LandCoverMap::Remove( const TopoDS_Face& theFace ) @param thePolyline the tool polyline to split the land cover map @return if the removing is successful */ -bool HYDROData_LandCoverMap::Split( const Handle( HYDROData_Polyline )& thePolyline ) +bool HYDROData_LandCoverMap::Split( const Handle( HYDROData_PolylineXY )& thePolyline ) { - //TODO - return false; + if( thePolyline.IsNull() ) + return false; + + TopoDS_Shape aShape = thePolyline->GetShape(); + return Split( aShape ); } + +/** + Split the land cover map by the given polyline + @param theShape the tool polyline to split the land cover map + @return if the removing is successful +*/ +bool HYDROData_LandCoverMap::Split( const TopoDS_Shape& theShape ) +{ + return LocalPartition( theShape, "" ); +} + + /** Merge the given faces in the land cover @param theFaces the faces to merge in the land cover map @@ -217,23 +561,169 @@ bool HYDROData_LandCoverMap::Split( const Handle( HYDROData_Polyline )& thePolyl */ bool HYDROData_LandCoverMap::Merge( const TopTools_ListOfShape& theFaces, const QString& theType ) { - //TODO + // 1. to fuse the faces into the new face + TopoDS_Shape aMergedFace = MergeFaces( theFaces, true ); + if( !aMergedFace.IsNull() && aMergedFace.ShapeType()==TopAbs_FACE ) + { + // 2. to remove the merged faces from the current map + Remove( theFaces ); + + // 3. to add the face into the map + return LocalPartition( TopoDS::Face( aMergedFace ), theType ); + } return false; } /** - Get the shape of the land cover map + Merge the given faces into the shell/face + @param theFaces the faces to merge + @param IsToUnify if the common edges should be removed (fused) + @param theTolerance the operation's tolerance + @return result shape (face or shell) */ -TopoDS_Shape HYDROData_LandCoverMap::GetShape() const +TopoDS_Shape HYDROData_LandCoverMap::MergeFaces( const TopTools_ListOfShape& theFaces, + bool IsToUnify, double theTolerance ) { - TDF_Label aLabel = myLab.FindChild( DataTag_Shape, false ); - if ( !aLabel.IsNull() ) + int anError; + TopTools_ListIteratorOfListOfShape anIt; + BOPCol_ListOfShape aLC; + anIt.Initialize(theFaces); + for( ; anIt.More(); anIt.Next() ) { - Handle(TNaming_NamedShape) aNamedShape; - if( aLabel.FindAttribute( TNaming_NamedShape::GetID(), aNamedShape ) ) - return aNamedShape->Get(); + if (anIt.Value().ShapeType() != TopAbs_FACE) + return TopoDS_Shape(); + aLC.Append( anIt.Value() ); } - return TopoDS_Shape(); + + BOPAlgo_PaveFiller aPF; + aPF.SetArguments( aLC ); + aPF.SetRunParallel( Standard_False ); + aPF.SetFuzzyValue( theTolerance ); + + aPF.Perform(); + anError = aPF.ErrorStatus(); + if( anError ) + return TopoDS_Shape(); + + BOPAlgo_Builder anAlgo; + anIt.Initialize( theFaces ); + for( ; anIt.More(); anIt.Next() ) + anAlgo.AddArgument( anIt.Value() ); + + anAlgo.PerformWithFiller( aPF ); + anError = anAlgo.ErrorStatus(); + if( anError ) + return TopoDS_Shape(); + + const TopoDS_Shape& aMergedShape = anAlgo.Shape(); + + BRep_Builder aBuilder; + TopoDS_Shell aShell; + aBuilder.MakeShell( aShell ); + aShell.Closed( Standard_False ); + TopExp_Explorer anExplorer( aMergedShape, TopAbs_FACE ); + for( ; anExplorer.More(); anExplorer.Next() ) + { + const TopoDS_Face& aFace = TopoDS::Face(anExplorer.Current()); + if( aFace.IsNull() ) + continue; + if( aFace.ShapeType() == TopAbs_FACE ) + { + aBuilder.Add( aShell, aFace ); + aShell.Closed( Standard_False ); + } + } + + TopoDS_Shape aResult; + if( IsToUnify ) + { + ShapeUpgrade_UnifySameDomain aUSD; + aUSD.Initialize( aShell ); + aUSD.Build(); + aResult = aUSD.Shape(); + } + else + aResult = aShell; + + anExplorer.Init( aResult, TopAbs_FACE ); + int n = 0; + TopoDS_Face anOneFace; + for( ; anExplorer.More(); anExplorer.Next(), n++ ) + anOneFace = TopoDS::Face( anExplorer.Current() ); + + if (n == 1) + aResult = anOneFace; + else if (aResult.ShapeType() == TopAbs_SHELL) + { + BRepCheck_Shell aBCS(TopoDS::Shell(aResult)); + if (aBCS.Status().First() != BRepCheck_NoError) + { + ShapeFix_Shell aFixer; + aFixer.FixFaceOrientation(TopoDS::Shell(aResult), 1); + aResult = aFixer.Shape(); + } + } + + return aResult; +} + +/** + Change Strickler type for the list of faces to the given one + @param theFaces the faces to change type + @param theType the Strickler type for the given land cover(s) + @return if the change type operation is successful +*/ +bool HYDROData_LandCoverMap::ChangeType( const TopTools_ListOfShape& theFaces, const QString& theType ) +{ + HYDROData_MapOfFaceToStricklerType aFacesToChangeType; + TopTools_ListIteratorOfListOfShape aFIt( theFaces ); + for( ; aFIt.More(); aFIt.Next() ) + { + TopoDS_Shape aShape = aFIt.Value(); + if( aShape.ShapeType()==TopAbs_FACE ) + aFacesToChangeType.Add( TopoDS::Face( aShape ), "" ); + } + + int aNbChanges = 0; + Explorer anIt( *this ); + for( ; anIt.More(); anIt.Next() ) + if( aFacesToChangeType.Contains( anIt.Face() ) ) + { + anIt.SetStricklerType( theType ); + aNbChanges++; + } + if ( aNbChanges != theFaces.Extent() ) + return false; + + return true; +} + +/** + Get the shape of the land cover map +*/ +TopoDS_Shape HYDROData_LandCoverMap::GetShape() const +{ + return HYDROData_Entity::GetShape( DataTag_Shape ); +} + +/** + Get Strickler type of the given land cover + @param theLandCover the land cover to get Strickler type of + @return name of Strickler type +*/ +QString HYDROData_LandCoverMap::StricklerType( const TopoDS_Face& theLandCover ) const +{ + QString aType = ""; + + Explorer anIt( *this ); + for( ; anIt.More(); anIt.Next() ) + if( anIt.Face().IsEqual( theLandCover) ) + { + aType = anIt.StricklerType(); + break; + } + + return aType; } /** @@ -242,8 +732,7 @@ TopoDS_Shape HYDROData_LandCoverMap::GetShape() const */ void HYDROData_LandCoverMap::SetShape( const TopoDS_Shape& theShape ) { - TNaming_Builder aBuilder( myLab.FindChild( DataTag_Shape ) ); - aBuilder.Generated( theShape ); + HYDROData_Entity::SetShape( DataTag_Shape, theShape ); } /** @@ -254,15 +743,26 @@ void HYDROData_LandCoverMap::SetShape( const TopoDS_Shape& theShape ) */ bool HYDROData_LandCoverMap::LocalPartition( const TopoDS_Shape& theNewShape, const QString& theNewType ) { + if( theNewShape.IsNull() ) + return false; + BOPCol_ListOfShape aShapesList; BOPAlgo_PaveFiller aPaveFiller; + HYDROData_MapOfFaceToStricklerType aNewFaces; // add faces to shapes list - Iterator anIt( *this ); + Explorer anIt( *this ); for( ; anIt.More(); anIt.Next() ) aShapesList.Append( anIt.Face() ); aShapesList.Append( theNewShape ); + if( aShapesList.Size()==1 && theNewShape.ShapeType()==TopAbs_FACE ) + { + aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType ); + StoreLandCovers( aNewFaces ); + return true; + } + // prepare pave filler aPaveFiller.SetArguments( aShapesList ); aPaveFiller.Perform(); @@ -283,33 +783,46 @@ bool HYDROData_LandCoverMap::LocalPartition( const TopoDS_Shape& theNewShape, co if( anError ) return false; + //std::cout << "History:" << std::endl; // analysis of the history - BOPCol_DataMapOfShapeListOfShape aSplits = aBuilder.Splits(); + // a. to fill map of shapes which come from the new face + NCollection_IndexedMap aShapesFromNewFace; + //std::cout << "from NEW " << theNewShape << ":" << theNewType << std::endl; + TopTools_ListOfShape aModified = aBuilder.Modified( theNewShape ); + TopTools_ListIteratorOfListOfShape aMIt( aModified ); + for( ; aMIt.More(); aMIt.Next() ) + { + //std::cout << " " << aMIt.Value() << std::endl; + int aKey = (int)(uintptr_t)aMIt.Value().TShape().operator->(); + aShapesFromNewFace.Add( aKey ); + } - // a. fill map of shape => type for initial faces - HYDROData_MapOfShapeToStricklerType anOldFaces; + // b. to fill map of parts except parts from new face anIt.Init( *this ); for( ; anIt.More(); anIt.Next() ) - anOldFaces.Add( anIt.Face(), anIt.StricklerType() ); - - // b. fill map of shape => type for split faces without the new face - HYDROData_MapOfShapeToStricklerType aNewFaces; - BOPCol_DataMapOfShapeListOfShape::Iterator aSplitIt( aSplits ); - for( ; aSplitIt.More(); aSplitIt.Next() ) { - TopoDS_Shape anInitial = aSplitIt.Key(); - if( anInitial==theNewShape ) - continue; - QString aType = anOldFaces.FindFromKey( anInitial ); - BOPCol_ListOfShape aSplitFaces = aSplitIt.Value(); - BOPCol_ListOfShape::Iterator aSFIt( aSplitFaces ); - for( ; aSFIt.More(); aSFIt.Next() ) - aNewFaces.Add( aSFIt.Value(), aType ); + QString aSType = anIt.StricklerType(); + //std::cout << "from " << anIt.Face() << ": " << anIt.StricklerType() << std::endl; + TopTools_ListOfShape aModified = aBuilder.Modified( anIt.Face() ); + if( aModified.Extent() == 0 ) + aModified.Append( anIt.Face() ); + + TopTools_ListIteratorOfListOfShape aMIt( aModified ); + for( ; aMIt.More(); aMIt.Next() ) + { + TopoDS_Shape aShape = aMIt.Value(); + bool isFace = aShape.ShapeType()==TopAbs_FACE; + int aKey = (int)(uintptr_t)aShape.TShape().operator->(); + bool isAlsoFromNew = aShapesFromNewFace.Contains( aKey ); + //std::cout << " " << aShape << " " << isAlsoFromNew << std::endl; + if( isFace && !isAlsoFromNew ) + aNewFaces.Add( TopoDS::Face( aShape ), aSType ); + } } // c. add the new shape if it is face with its type if( theNewShape.ShapeType()==TopAbs_FACE ) - aNewFaces.Add( theNewShape, theNewType ); + aNewFaces.Add( TopoDS::Face( theNewShape ), theNewType ); // convert map of shape to type to compound and list of types StoreLandCovers( aNewFaces ); @@ -320,21 +833,112 @@ bool HYDROData_LandCoverMap::LocalPartition( const TopoDS_Shape& theNewShape, co Replace the set of land covers in the land cover map @param theMap the map of shape (face) to Strickler type (string) */ -void HYDROData_LandCoverMap::StoreLandCovers( const HYDROData_MapOfShapeToStricklerType& theMap ) +void HYDROData_LandCoverMap::StoreLandCovers( const HYDROData_MapOfFaceToStricklerType& theMap ) { - TopoDS_Compound aCompound; - BRep_Builder aCompoundBuilder; - aCompoundBuilder.MakeCompound( aCompound ); + TopTools_ListOfShape aListOfFaces; int n = theMap.Size(); + Handle( TDataStd_ExtStringArray ) aTypes = TDataStd_ExtStringArray::Set( myLab.FindChild( DataTag_Types ), 0, n-1, Standard_True ); - HYDROData_MapOfShapeToStricklerType::Iterator aNFIt( theMap ); + + HYDROData_MapOfFaceToStricklerType::Iterator aNFIt( theMap ); for( int i=0; aNFIt.More(); aNFIt.Next(), i++ ) { - aCompoundBuilder.Add( aCompound, aNFIt.Key() ); - aTypes->SetValue( i, HYDROData_Tool::toExtString( aNFIt.Value() ) ); + TopoDS_Face aFace = aNFIt.Key(); + if( aFace.IsNull() ) + continue; + QString aType = aNFIt.Value(); + aListOfFaces.Append(aFace); + aTypes->SetValue( i, HYDROData_Tool::toExtString( aType ) ); + } + + TopoDS_Shape aResult; + if( aListOfFaces.Extent() == 1 ) + { + /*TopoDS_Shell aShell; + BRep_Builder aShellBuilder; + aShellBuilder.MakeShell( aShell ); + aShell.Closed( Standard_False ); + aShellBuilder.Add( aShell, aListOfFaces.First() );*/ + aResult = aListOfFaces.First(); //aShell; + } + else if( aListOfFaces.Extent() > 1 ) + aResult = MergeFaces( aListOfFaces, false ); + + //remove internal edges + aResult = RemoveInternal(aResult); + SetShape( aResult ); +} + +/** + Find the land cover for the given point + @param thePoint the point laying in some land cover + @param theType the returned type + @return the found land cover's face +*/ +TopoDS_Face HYDROData_LandCoverMap::FindByPoint( const gp_Pnt2d& thePoint, QString& theType ) const +{ + //TODO: some more optimal algorithm + Explorer anIt( *this ); + for( ; anIt.More(); anIt.Next() ) + if( HYDROData_Tool::ComputePointState( thePoint.XY(), anIt.Face() ) == TopAbs_IN ) + { + theType = anIt.StricklerType(); + return anIt.Face(); + } + + theType = ""; + return TopoDS_Face(); +} + +/** + Dump to Python + @param theTreatedObjects the map of treated objects +*/ +QStringList HYDROData_LandCoverMap::DumpToPython( MapOfTreatedObjects& theTreatedObjects ) const +{ + QStringList aResList = dumpObjectCreation( theTreatedObjects ); + QString aName = GetObjPyName(); + + //Handle(HYDROData_PolylineXY) aHydAxis = GetHydraulicAxis(); + //setPythonReferenceObject( theTreatedObjects, aResList, aHydAxis, "SetHydraulicAxis" ); + + //HYDROData_SequenceOfObjects aSeqOfProfiles = GetProfiles(); + //for ( int i = 1, aNb = aSeqOfProfiles.Size(); i <= aNb; ++i ) + //{ + //const Handle(HYDROData_Entity) aProfile = aSeqOfProfiles.Value( i ); + //setPythonReferenceObject( theTreatedObjects, aResList, aProfile, "AddProfile" ); + //} + + //TODO + + return aResList; +} + +TopoDS_Shape HYDROData_LandCoverMap::RemoveInternal(const TopoDS_Shape& InSh) +{ + //Shape must be topologically correct + TopExp_Explorer anExp(InSh, TopAbs_EDGE); + TopTools_ListOfShape anEdgesToRemove; + + for(; anExp.More(); anExp.Next() ) + { + TopoDS_Edge CurEdge = TopoDS::Edge(anExp.Current()); + if (CurEdge.Orientation() == TopAbs_INTERNAL) + anEdgesToRemove.Append(CurEdge); } + + Handle_ShapeBuild_ReShape aReshape = new ShapeBuild_ReShape(); + TopoDS_Shape OutSh = aReshape->Apply(InSh); + TopTools_ListIteratorOfListOfShape aIt(anEdgesToRemove); + for (; aIt.More(); aIt.Next()) + aReshape->Remove(aIt.Value()); + OutSh = aReshape->Apply(InSh); + + Handle(ShapeFix_Shape) sfs = new ShapeFix_Shape; + sfs->Init(OutSh); + sfs->Perform(); + return sfs->Shape(); - SetShape( aCompound ); }