#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 "FITKOCCModelRefine.h" using namespace ModelRefine; void ModelRefine::getFaceEdges(const TopoDS_Face &face, EdgeVectorType &edges) { TopExp_Explorer it; for (it.Init(face, TopAbs_EDGE); it.More(); it.Next()) edges.push_back(TopoDS::Edge(it.Current())); } void ModelRefine::boundaryEdges(const FaceVectorType &faces, EdgeVectorType &edgesOut) { //this finds all the boundary edges. Maybe more than one boundary. std::list edges; FaceVectorType::const_iterator faceIt; for (faceIt = faces.begin(); faceIt != faces.end(); ++faceIt) { EdgeVectorType faceEdges; EdgeVectorType::iterator faceEdgesIt; getFaceEdges(*faceIt, faceEdges); for (faceEdgesIt = faceEdges.begin(); faceEdgesIt != faceEdges.end(); ++faceEdgesIt) { bool foundSignal(false); std::list::iterator edgesIt; for (edgesIt = edges.begin(); edgesIt != edges.end(); ++edgesIt) { if ((*edgesIt).IsSame(*faceEdgesIt)) { edgesIt = edges.erase(edgesIt); foundSignal = true; break; } } if (!foundSignal) edges.push_back(*faceEdgesIt); } } edgesOut.reserve(edges.size()); std::copy(edges.begin(), edges.end(), back_inserter(edgesOut)); } TopoDS_Shell ModelRefine::removeFaces(const TopoDS_Shell &shell, const FaceVectorType &faces) { ShapeBuild_ReShape rebuilder; FaceVectorType::const_iterator it; for (it = faces.begin(); it != faces.end(); ++it) rebuilder.Remove(*it); return TopoDS::Shell(rebuilder.Apply(shell)); } namespace ModelRefine { class WireSort { public: bool operator() (const TopoDS_Wire& wire1, const TopoDS_Wire& wire2) { Bnd_Box box1, box2; BRepBndLib::Add(wire1, box1); BRepBndLib::Add(wire2, box2); // Note: This works because we can be sure that the wires do not intersect return box2.SquareExtent() < box1.SquareExtent(); } }; } //////////////////////////////////////////////////////////////////////////////////////////// void FaceTypeSplitter::addShell(const TopoDS_Shell &shellIn) { shell = shellIn; } void FaceTypeSplitter::registerType(const GeomAbs_SurfaceType &type) { typeMap.insert(SplitMapType::value_type(type, FaceVectorType())); } bool FaceTypeSplitter::hasType(const GeomAbs_SurfaceType &type) const { return typeMap.find(type) != typeMap.end(); } void FaceTypeSplitter::split() { TopExp_Explorer shellIt; for (shellIt.Init(shell, TopAbs_FACE); shellIt.More(); shellIt.Next()) { TopoDS_Face tempFace(TopoDS::Face(shellIt.Current())); GeomAbs_SurfaceType currentType = FaceTypedBase::getFaceType(tempFace); SplitMapType::iterator mapIt = typeMap.find(currentType); if (mapIt == typeMap.end()) continue; (*mapIt).second.push_back(tempFace); } } const FaceVectorType& FaceTypeSplitter::getTypedFaceVector(const GeomAbs_SurfaceType &type) const { if (this->hasType(type)) return (*(typeMap.find(type))).second; //error here. static FaceVectorType error; return error; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// FaceAdjacencySplitter::FaceAdjacencySplitter(const TopoDS_Shell &shell) { TopExp_Explorer shellIt; for (shellIt.Init(shell, TopAbs_FACE); shellIt.More(); shellIt.Next()) { TopTools_ListOfShape shapeList; TopExp_Explorer it; for (it.Init(shellIt.Current(), TopAbs_EDGE); it.More(); it.Next()) shapeList.Append(it.Current()); faceToEdgeMap.Add(shellIt.Current(), shapeList); } TopExp::MapShapesAndAncestors(shell, TopAbs_EDGE, TopAbs_FACE, edgeToFaceMap); } void FaceAdjacencySplitter::split(const FaceVectorType &facesIn) { facesInMap.Clear(); processedMap.Clear(); adjacencyArray.clear(); FaceVectorType::const_iterator it; for (it = facesIn.begin(); it != facesIn.end(); ++it) facesInMap.Add(*it); //the reserve call guarantees the vector will never get "pushed back" in the //recursiveFind calls, thus invalidating the iterators. We can be sure of this as any one //matched set can't be bigger than the set passed in. if we have seg faults, we will //want to turn this tempFaces vector back into a std::list ensuring valid iterators //at the expense of std::find speed. FaceVectorType tempFaces; tempFaces.reserve(facesIn.size() + 1); for (it = facesIn.begin(); it != facesIn.end(); ++it) { //skip already processed shapes. if (processedMap.Contains(*it)) continue; tempFaces.clear(); processedMap.Add(*it); recursiveFind(*it, tempFaces); if (tempFaces.size() > 1) { adjacencyArray.push_back(tempFaces); } } } void FaceAdjacencySplitter::recursiveFind(const TopoDS_Face &face, FaceVectorType &outVector) { outVector.push_back(face); const TopTools_ListOfShape &edges = faceToEdgeMap.FindFromKey(face); TopTools_ListIteratorOfListOfShape edgeIt; for (edgeIt.Initialize(edges); edgeIt.More(); edgeIt.Next()) { //don't try to join across seams. // Note: BRep_Tool::IsClosed(TopoDS::Edge(edgeIt.Value()), face) is also possible? ShapeAnalysis_Edge edgeCheck; if(edgeCheck.IsSeam(TopoDS::Edge(edgeIt.Value()), face)) continue; const TopTools_ListOfShape &faces = edgeToFaceMap.FindFromKey(edgeIt.Value()); TopTools_ListIteratorOfListOfShape faceIt; for (faceIt.Initialize(faces); faceIt.More(); faceIt.Next()) { if (!facesInMap.Contains(faceIt.Value())) continue; if (processedMap.Contains(faceIt.Value())) continue; processedMap.Add(faceIt.Value()); recursiveFind(TopoDS::Face(faceIt.Value()), outVector); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////// void FaceEqualitySplitter::split(const FaceVectorType &faces, FaceTypedBase *object) { std::vector tempVector; tempVector.reserve(faces.size()); FaceVectorType::const_iterator faceIt; for (faceIt = faces.begin(); faceIt != faces.end(); ++faceIt) { bool foundMatch(false); std::vector::iterator tempIt; for (tempIt = tempVector.begin(); tempIt != tempVector.end(); ++tempIt) { if (object->isEqual((*tempIt).front(), *faceIt)) { (*tempIt).push_back(*faceIt); foundMatch = true; break; } } if (!foundMatch) { FaceVectorType another; another.reserve(faces.size()); another.push_back(*faceIt); tempVector.push_back(another); } } std::vector::iterator it; for (it = tempVector.begin(); it != tempVector.end(); ++it) { if ((*it).size() < 2) continue; equalityVector.push_back(*it); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// GeomAbs_SurfaceType FaceTypedBase::getFaceType(const TopoDS_Face &faceIn) { Handle(Geom_Surface) surface = BRep_Tool::Surface(faceIn); GeomAdaptor_Surface surfaceTest(surface); return surfaceTest.GetType(); } void FaceTypedBase::boundarySplit(const FaceVectorType &facesIn, std::vector &boundariesOut) const { EdgeVectorType bEdges; boundaryEdges(facesIn, bEdges); std::list edges; std::copy(bEdges.begin(), bEdges.end(), back_inserter(edges)); while(!edges.empty()) { TopoDS_Vertex destination = TopExp::FirstVertex(edges.front(), Standard_True); TopoDS_Vertex lastVertex = TopExp::LastVertex(edges.front(), Standard_True); EdgeVectorType boundary; boundary.push_back(edges.front()); edges.pop_front(); //single edge closed check. if (destination.IsSame(lastVertex)) { boundariesOut.push_back(boundary); continue; } bool closedSignal(false); std::list::iterator it; for (it = edges.begin(); it != edges.end();) { TopoDS_Vertex currentVertex = TopExp::FirstVertex(*it, Standard_True); if (lastVertex.IsSame(currentVertex)) { boundary.push_back(*it); lastVertex = TopExp::LastVertex(*it, Standard_True); edges.erase(it); it = edges.begin(); if (lastVertex.IsSame(destination)) { closedSignal = true; break; } continue; } ++it; } if (closedSignal) boundariesOut.push_back(boundary); } } /////////////////////////////////////////////////////////////////////////////////////////////////////// FaceTypedPlane::FaceTypedPlane() : FaceTypedBase(GeomAbs_Plane) { } bool FaceTypedPlane::isEqual(const TopoDS_Face &faceOne, const TopoDS_Face &faceTwo) const { Handle(Geom_Plane) planeSurfaceOne = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(faceOne)); Handle(Geom_Plane) planeSurfaceTwo = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(faceTwo)); if (planeSurfaceOne.IsNull() || planeSurfaceTwo.IsNull()) return false;//error? gp_Pln planeOne(planeSurfaceOne->Pln()); gp_Pln planeTwo(planeSurfaceTwo->Pln()); return (planeOne.Position().Direction().IsParallel(planeTwo.Position().Direction(), Precision::Confusion()) && planeOne.Distance(planeTwo.Position().Location()) < Precision::Confusion()); } GeomAbs_SurfaceType FaceTypedPlane::getType() const { return GeomAbs_Plane; } TopoDS_Face FaceTypedPlane::buildFace(const FaceVectorType &faces) const { std::vector wires; std::vector splitEdges; this->boundarySplit(faces, splitEdges); if (splitEdges.empty()) return TopoDS_Face(); std::vector::iterator splitIt; for (splitIt = splitEdges.begin(); splitIt != splitEdges.end(); ++splitIt) { BRepLib_MakeWire wireMaker; EdgeVectorType::iterator it; for (it = (*splitIt).begin(); it != (*splitIt).end(); ++it) wireMaker.Add(*it); TopoDS_Wire currentWire = wireMaker.Wire(); wires.push_back(currentWire); } std::sort(wires.begin(), wires.end(), ModelRefine::WireSort()); BRepLib_MakeFace faceMaker(wires.at(0), Standard_True); if (faceMaker.Error() != BRepLib_FaceDone) return TopoDS_Face(); TopoDS_Face current = faceMaker.Face(); if (wires.size() > 1) { ShapeFix_Face faceFix(current); faceFix.SetContext(new ShapeBuild_ReShape()); for (size_t index(1); indexCylinder(); gp_Cylinder cylinderTwo = surfaceTwo->Cylinder(); if (cylinderOne.Radius() != cylinderTwo.Radius()) return false; if (!cylinderOne.Axis().IsCoaxial(cylinderTwo.Axis(), Precision::Confusion(), Precision::Confusion())) return false; return true; } GeomAbs_SurfaceType FaceTypedCylinder::getType() const { return GeomAbs_Cylinder; } TopoDS_Face FaceTypedCylinder::buildFace(const FaceVectorType &faces) const { static TopoDS_Face dummy; std::vector boundaries; boundarySplit(faces, boundaries); if (boundaries.size() < 1) return dummy; //make wires std::vector wires; std::vector::iterator boundaryIt; for (boundaryIt = boundaries.begin(); boundaryIt != boundaries.end(); ++boundaryIt) { BRepLib_MakeWire wireMaker; EdgeVectorType::iterator it; for (it = (*boundaryIt).begin(); it != (*boundaryIt).end(); ++it) wireMaker.Add(*it); if (wireMaker.Error() != BRepLib_WireDone) return dummy; wires.push_back(wireMaker.Wire()); } if (wires.size() < 1) return dummy; std::sort(wires.begin(), wires.end(), ModelRefine::WireSort()); //make face from surface and outer wire. Handle(Geom_CylindricalSurface) surface = Handle(Geom_CylindricalSurface)::DownCast(BRep_Tool::Surface(faces.at(0))); std::vector::iterator wireIt; wireIt = wires.begin(); BRepBuilderAPI_MakeFace faceMaker(surface, *wireIt); if (!faceMaker.IsDone()) return dummy; //add additional boundaries. for (wireIt++; wireIt != wires.end(); ++wireIt) { faceMaker.Add(*wireIt); if (!faceMaker.IsDone()) return dummy; } //fix newly constructed face. Orientation doesn't seem to get fixed the first call. ShapeFix_Face faceFixer(faceMaker.Face()); faceFixer.SetContext(new ShapeBuild_ReShape()); faceFixer.Perform(); if (faceFixer.Status(ShapeExtend_FAIL)) return dummy; faceFixer.FixOrientation(); faceFixer.Perform(); if (faceFixer.Status(ShapeExtend_FAIL)) return dummy; return faceFixer.Face(); } void FaceTypedCylinder::boundarySplit(const FaceVectorType &facesIn, std::vector &boundariesOut) const { //get all the seam edges EdgeVectorType seamEdges; FaceVectorType::const_iterator faceIt; for (faceIt = facesIn.begin(); faceIt != facesIn.end(); ++faceIt) { TopExp_Explorer explorer; for (explorer.Init(*faceIt, TopAbs_EDGE); explorer.More(); explorer.Next()) { ShapeAnalysis_Edge edgeCheck; if(edgeCheck.IsSeam(TopoDS::Edge(explorer.Current()), *faceIt)) seamEdges.push_back(TopoDS::Edge(explorer.Current())); } } //normal edges. EdgeVectorType normalEdges; ModelRefine::boundaryEdges(facesIn, normalEdges); //put seam edges in front.the idea is that we always want to traverse along a seam edge if possible. std::list sortedEdges; std::copy(normalEdges.begin(), normalEdges.end(), back_inserter(sortedEdges)); std::copy(seamEdges.begin(), seamEdges.end(), front_inserter(sortedEdges)); while (!sortedEdges.empty()) { //detecting closed boundary works best if we start off of the seam edges. TopoDS_Vertex destination = TopExp::FirstVertex(sortedEdges.back(), Standard_True); TopoDS_Vertex lastVertex = TopExp::LastVertex(sortedEdges.back(), Standard_True); bool closedSignal(false); std::list boundary; boundary.push_back(sortedEdges.back()); sortedEdges.pop_back(); std::list::iterator sortedIt; for (sortedIt = sortedEdges.begin(); sortedIt != sortedEdges.end();) { TopoDS_Vertex currentVertex = TopExp::FirstVertex(*sortedIt, Standard_True); //Seam edges lie on top of each other. i.e. same. and we remove every match from the list //so we don't actually ever compare the same edge. if ((*sortedIt).IsSame(boundary.back())) { ++sortedIt; continue; } if (lastVertex.IsSame(currentVertex)) { boundary.push_back(*sortedIt); lastVertex = TopExp::LastVertex(*sortedIt, Standard_True); if (lastVertex.IsSame(destination)) { closedSignal = true; sortedEdges.erase(sortedIt); break; } sortedEdges.erase(sortedIt); sortedIt = sortedEdges.begin(); continue; } ++sortedIt; } if (closedSignal) { EdgeVectorType temp; std::copy(boundary.begin(), boundary.end(), std::back_inserter(temp)); boundariesOut.push_back(temp); } } } FaceTypedCylinder& ModelRefine::getCylinderObject() { static FaceTypedCylinder object; return object; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: change this version after occ fix. Freecad Mantis 1450 #if OCC_VERSION_HEX <= 0x070000 void collectConicEdges(const TopoDS_Shell &shell, TopTools_IndexedMapOfShape &map) { TopTools_IndexedMapOfShape edges; TopExp::MapShapes(shell, TopAbs_EDGE, edges); for (int index = 1; index <= edges.Extent(); ++index) { const TopoDS_Edge ¤tEdge = TopoDS::Edge(edges.FindKey(index)); if (currentEdge.IsNull()) continue; TopLoc_Location location; Standard_Real first, last; const Handle_Geom_Curve &curve = BRep_Tool::Curve(currentEdge, location, first, last); if (curve.IsNull()) continue; if (curve->IsKind(STANDARD_TYPE(Geom_Conic))) map.Add(currentEdge); } } #endif FaceUniter::FaceUniter(const TopoDS_Shell &shellIn) : modifiedSignal(false) { workShell = shellIn; } bool FaceUniter::process() { if (workShell.IsNull()) return false; modifiedShapes.clear(); deletedShapes.clear(); typeObjects.push_back(&getPlaneObject()); typeObjects.push_back(&getCylinderObject()); //add more face types. ModelRefine::FaceTypeSplitter splitter; splitter.addShell(workShell); std::vector::iterator typeIt; for(typeIt = typeObjects.begin(); typeIt != typeObjects.end(); ++typeIt) splitter.registerType((*typeIt)->getType()); splitter.split(); ModelRefine::FaceVectorType facesToRemove; ModelRefine::FaceVectorType facesToSew; ModelRefine::FaceAdjacencySplitter adjacencySplitter(workShell); for(typeIt = typeObjects.begin(); typeIt != typeObjects.end(); ++typeIt) { ModelRefine::FaceVectorType typedFaces = splitter.getTypedFaceVector((*typeIt)->getType()); ModelRefine::FaceEqualitySplitter equalitySplitter; equalitySplitter.split(typedFaces, *typeIt); for (std::size_t indexEquality(0); indexEquality < equalitySplitter.getGroupCount(); ++indexEquality) { adjacencySplitter.split(equalitySplitter.getGroup(indexEquality)); // std::cout << " adjacency group count: " << adjacencySplitter.getGroupCount() << std::endl; for (std::size_t adjacentIndex(0); adjacentIndex < adjacencySplitter.getGroupCount(); ++adjacentIndex) { // std::cout << " face count is: " << adjacencySplitter.getGroup(adjacentIndex).size() << std::endl; TopoDS_Face newFace = (*typeIt)->buildFace(adjacencySplitter.getGroup(adjacentIndex)); if (!newFace.IsNull()) { facesToSew.push_back(newFace); if (facesToRemove.capacity() <= facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()) facesToRemove.reserve(facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()); FaceVectorType temp = adjacencySplitter.getGroup(adjacentIndex); facesToRemove.insert(facesToRemove.end(), temp.begin(), temp.end()); // the first shape will be marked as modified, i.e. replaced by newFace, all others are marked as deleted // jrheinlaender: IMHO this is not correct because references to the deleted faces will be broken, whereas they should // be replaced by references to the new face. To achieve this all shapes should be marked as // modified, producing one single new face. This is the inverse behaviour to faces that are split e.g. // by a boolean cut, where one old shape is marked as modified, producing multiple new shapes if (!temp.empty()) { for (FaceVectorType::iterator f = temp.begin(); f != temp.end(); ++f) modifiedShapes.push_back(std::make_pair(*f, newFace)); } } } } } if (facesToSew.size() > 0) { modifiedSignal = true; workShell = ModelRefine::removeFaces(workShell, facesToRemove); TopExp_Explorer xp; bool emptyShell = true; for (xp.Init(workShell, TopAbs_FACE); xp.More(); xp.Next()) { emptyShell = false; break; } if (!emptyShell || facesToSew.size() > 1) { BRepBuilderAPI_Sewing sew; sew.Add(workShell); FaceVectorType::iterator sewIt; for(sewIt = facesToSew.begin(); sewIt != facesToSew.end(); ++sewIt) sew.Add(*sewIt); sew.Perform(); try { workShell = TopoDS::Shell(sew.SewedShape()); } catch (Standard_Failure) { return false; } // update the list of modifications for (std::vector::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) { if (sew.IsModified(it->second)) { it->second = sew.Modified(it->second); break; } } } else { // workShell has no more faces and we add exactly one face BRep_Builder builder; builder.MakeShell(workShell); FaceVectorType::iterator sewIt; for(sewIt = facesToSew.begin(); sewIt != facesToSew.end(); ++sewIt) builder.Add(workShell, *sewIt); } BRepLib_FuseEdges edgeFuse(workShell); // TODO: change this version after occ fix. Freecad Mantis 1450 #if OCC_VERSION_HEX <= 0x070000 TopTools_IndexedMapOfShape map; collectConicEdges(workShell, map); edgeFuse.AvoidEdges(map); #endif TopTools_DataMapOfShapeShape affectedFaces; edgeFuse.Faces(affectedFaces); TopTools_DataMapIteratorOfDataMapOfShapeShape mapIt; for (mapIt.Initialize(affectedFaces); mapIt.More(); mapIt.Next()) { ShapeFix_Face faceFixer(TopoDS::Face(mapIt.Value())); faceFixer.Perform(); } workShell = TopoDS::Shell(edgeFuse.Shape()); // update the list of modifications TopTools_DataMapOfShapeShape faceMap; edgeFuse.Faces(faceMap); for (mapIt.Initialize(faceMap); mapIt.More(); mapIt.Next()) { bool isModifiedFace = false; for (std::vector::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) { if (mapIt.Key().IsSame(it->second)) { // Note: IsEqual() for some reason does not work it->second = mapIt.Value(); isModifiedFace = true; } } if (!isModifiedFace) { // Catch faces that were not united but whose boundary was changed (probably because // several adjacent faces were united) // See https://sourceforge.net/apps/mantisbt/free-cad/view.php?id=873 modifiedShapes.push_back(std::make_pair(mapIt.Key(), mapIt.Value())); } } // Handle edges that were fused. See https://sourceforge.net/apps/mantisbt/free-cad/view.php?id=873 TopTools_DataMapOfIntegerListOfShape oldEdges; TopTools_DataMapOfIntegerShape newEdges; edgeFuse.Edges(oldEdges); edgeFuse.ResultEdges(newEdges); TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape edgeMapIt; for (edgeMapIt.Initialize(oldEdges); edgeMapIt.More(); edgeMapIt.Next()) { const TopTools_ListOfShape& edges = edgeMapIt.Value(); int idx = edgeMapIt.Key(); TopTools_ListIteratorOfListOfShape edgeIt; for (edgeIt.Initialize(edges); edgeIt.More(); edgeIt.Next()) { modifiedShapes.push_back(std::make_pair(edgeIt.Value(), newEdges(idx))); } // TODO: Handle vertices that have disappeared in the fusion of the edges } } return true; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// //BRepBuilderAPI_RefineModel implement a way to log all modifications on the faces namespace OCC { BRepBuilderAPI_RefineModel::BRepBuilderAPI_RefineModel(const TopoDS_Shape& shape) { myShape = shape; Build(); } void BRepBuilderAPI_RefineModel::Build() { if (myShape.IsNull()) Standard_Failure::Raise("Cannot remove splitter from empty shape"); if (myShape.ShapeType() == TopAbs_SOLID) { const TopoDS_Solid &solid = TopoDS::Solid(myShape); BRepBuilderAPI_MakeSolid mkSolid; TopExp_Explorer it; for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); ModelRefine::FaceUniter uniter(currentShell); if (uniter.process()) { if (uniter.isModified()) { const TopoDS_Shell &newShell = uniter.getShell(); mkSolid.Add(newShell); LogModifications(uniter); } else { mkSolid.Add(currentShell); } } else { Standard_Failure::Raise("Removing splitter failed"); } } myShape = mkSolid.Solid(); } else if (myShape.ShapeType() == TopAbs_SHELL) { const TopoDS_Shell& shell = TopoDS::Shell(myShape); ModelRefine::FaceUniter uniter(shell); if (uniter.process()) { // TODO: Why not check for uniter.isModified()? myShape = uniter.getShell(); LogModifications(uniter); } else { Standard_Failure::Raise("Removing splitter failed"); } } else if (myShape.ShapeType() == TopAbs_COMPOUND) { BRep_Builder builder; TopoDS_Compound comp; builder.MakeCompound(comp); TopExp_Explorer xp; // solids for (xp.Init(myShape, TopAbs_SOLID); xp.More(); xp.Next()) { const TopoDS_Solid &solid = TopoDS::Solid(xp.Current()); BRepTools_ReShape reshape; TopExp_Explorer it; for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); ModelRefine::FaceUniter uniter(currentShell); if (uniter.process()) { if (uniter.isModified()) { const TopoDS_Shell &newShell = uniter.getShell(); reshape.Replace(currentShell, newShell); LogModifications(uniter); } } } builder.Add(comp, reshape.Apply(solid)); } // free shells for (xp.Init(myShape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next()) { const TopoDS_Shell& shell = TopoDS::Shell(xp.Current()); ModelRefine::FaceUniter uniter(shell); if (uniter.process()) { builder.Add(comp, uniter.getShell()); LogModifications(uniter); } } // the rest for (xp.Init(myShape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } for (xp.Init(myShape, TopAbs_WIRE, TopAbs_FACE); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } for (xp.Init(myShape, TopAbs_EDGE, TopAbs_WIRE); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } for (xp.Init(myShape, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } myShape = comp; } Done(); } void BRepBuilderAPI_RefineModel::LogModifications(const ModelRefine::FaceUniter& uniter) { const std::vector& modShapes = uniter.getModifiedShapes(); for (std::vector::const_iterator it = modShapes.begin(); it != modShapes.end(); ++it) { TopTools_ListOfShape list; list.Append(it->second); myModified.Bind(it->first, list); } const ShapeVectorType& delShapes = uniter.getDeletedShapes(); for (ShapeVectorType::const_iterator it = delShapes.begin(); it != delShapes.end(); ++it) { myDeleted.Append(*it); } } const TopTools_ListOfShape& BRepBuilderAPI_RefineModel::Modified(const TopoDS_Shape& S) { if (myModified.IsBound(S)) return myModified.Find(S); else return myEmptyList; } Standard_Boolean BRepBuilderAPI_RefineModel::IsDeleted(const TopoDS_Shape& S) { TopTools_ListIteratorOfListOfShape it; for (it.Initialize(myDeleted); it.More(); it.Next()) { if (it.Value().IsSame(S)) return Standard_True; } return Standard_False; } }