Beispiel #1
0
/// This is the actual fusing
void CFuseShapes::DoFuse()
{
    if (!_parent) {
        throw tigl::CTiglError("Null pointer for parent shape in CFuseShapes", TIGL_NULL_POINTER);
    }

    BRepBuilderAPI_Sewing shellMaker;

    _trimmedChilds.clear();
    ListPNamedShape::const_iterator childIter;

    TrimOperation childTrim  = EXCLUDE;
    TrimOperation parentTrim = EXCLUDE;

    // trim the childs with the parent and vice versa
    _trimmedParent = _parent->DeepCopy();
    for (childIter = _childs.begin(); childIter != _childs.end(); ++childIter) {
        const PNamedShape child = *childIter;
        if (!child) {
            continue;
        }

#ifdef DEBUG_BOP
        clock_t start, stop;
        start = clock();
#endif
        BOPCol_ListOfShape aLS;
        aLS.Append(_trimmedParent->Shape());
        aLS.Append(child->Shape());
        BOPAlgo_PaveFiller DSFill;
        DSFill.SetArguments(aLS);
        DSFill.Perform();
#ifdef DEBUG_BOP
        stop = clock();
        printf("dsfiller [ms]: %f\n", (stop-start)/(double)CLOCKS_PER_SEC * 1000.);

        start = clock();
#endif
        // calculate intersection
        // Todo: make a new BOP out of this
        TopoDS_Shape intersection = BRepAlgoAPI_Section(_trimmedParent->Shape(), child->Shape(), DSFill);
        PNamedShape intersectionShape(new CNamedShape(intersection, std::string("INT" + std::string(_parent->Name()) + child->Name()).c_str()));
        intersectionShape->SetShortName(std::string("INT" + std::string(_parent->ShortName()) + child->ShortName()).c_str());
        _intersections.push_back(intersectionShape);

#ifdef DEBUG_BOP
        stop = clock();
        printf("intersection [ms]: %f\n", (stop-start)/(double)CLOCKS_PER_SEC * 1000.);

        start = clock();
#endif
        _trimmedParent = CTrimShape(_trimmedParent, child, DSFill, parentTrim);

#ifdef DEBUG_BOP
        stop = clock();
        printf("parent split [ms]: %f\n", (stop-start)/(double)CLOCKS_PER_SEC * 1000.);

        start = clock();
#endif
        PNamedShape trimmedChild = CTrimShape(child, _parent, DSFill, childTrim);
        _trimmedChilds.push_back(trimmedChild);

#ifdef DEBUG_BOP
        stop = clock();
        printf("child split [ms]: %f\n", (stop-start)/(double)CLOCKS_PER_SEC * 1000.);
#endif
    } // trimming

    // add trimmed child faces to result
    for (childIter = _trimmedChilds.begin(); childIter != _trimmedChilds.end(); ++childIter) {
        shellMaker.Add((*childIter)->Shape());
    }

    // add trimmed parent faces to result
    shellMaker.Add(_trimmedParent->Shape());
    shellMaker.Perform();

    // make a solid out of the face collection
    TopoDS_Shape shell = shellMaker.SewedShape();


    BRepSewingToBRepBuilderShapeAdapter sewerAdapter(shellMaker);

    // map names to shell
    PNamedShape resultShell(new CNamedShape(shell, "BOP_FUSE"));
    for (childIter = _trimmedChilds.begin(); childIter != _trimmedChilds.end(); ++childIter) {
        const PNamedShape child = *childIter;
        PNamedShape tmpshape(new CNamedShape(*child));
        tmpshape->SetShape(shellMaker.ModifiedSubShape(child->Shape()));
        CBooleanOperTools::MapFaceNamesAfterBOP(sewerAdapter, tmpshape, resultShell);
    }
    PNamedShape tmpshape(new CNamedShape(*_trimmedParent));
    tmpshape->SetShape(shellMaker.ModifiedSubShape(_trimmedParent->Shape()));
    CBooleanOperTools::MapFaceNamesAfterBOP(sewerAdapter, tmpshape, resultShell);

    // map names to solid
    BRepBuilderAPI_MakeSolid solidmaker;
    TopTools_IndexedMapOfShape shellMap;
    TopExp::MapShapes(resultShell->Shape(), TopAbs_SHELL, shellMap);
    for (int ishell = 1; ishell <= shellMap.Extent(); ++ishell) {
        const TopoDS_Shell& shell = TopoDS::Shell(shellMap(ishell));
        solidmaker.Add(shell);
    }

    PNamedShape result(new CNamedShape(solidmaker.Solid(), resultShell->Name()));
    CBooleanOperTools::MapFaceNamesAfterBOP(solidmaker, resultShell, result);

    _resultshape = result;
}
//=======================================================================
//function : MakeScaledPrism
//purpose  :
//=======================================================================
TopoDS_Shape GEOMImpl_PrismDriver::MakeScaledPrism (const TopoDS_Shape& theShapeBase,
                                                    const gp_Vec&       theVector,
                                                    const Standard_Real theScaleFactor,
                                                    const gp_Pnt&       theCDG,
                                                    bool                isCDG)
{
  TopoDS_Shape aShape;
  BRep_Builder B;

  // 1. aCDG = geompy.MakeCDG(theBase)
  gp_Pnt aCDG = theCDG;
  if (!isCDG) {
    gp_Ax3 aPos = GEOMImpl_IMeasureOperations::GetPosition(theShapeBase);
    aCDG = aPos.Location();
  }
  TopoDS_Shape aShapeCDG_1 = BRepBuilderAPI_MakeVertex(aCDG).Shape();

  // Process case of several given shapes
  if (theShapeBase.ShapeType() == TopAbs_COMPOUND ||
      theShapeBase.ShapeType() == TopAbs_SHELL) {
    int nbSub = 0;
    TopoDS_Shape aShapeI;
    TopoDS_Compound aCompound;
    B.MakeCompound(aCompound);
    TopoDS_Iterator It (theShapeBase, Standard_True, Standard_True);
    for (; It.More(); It.Next()) {
      nbSub++;
      aShapeI = MakeScaledPrism(It.Value(), theVector, theScaleFactor, aCDG, true);
      B.Add(aCompound, aShapeI);
    }
    if (nbSub == 1)
      aShape = aShapeI;
    else if (nbSub > 1)
      aShape = GEOMImpl_GlueDriver::GlueFaces(aCompound, Precision::Confusion(), Standard_True);
    return aShape;
  }

  // 2. Scale = geompy.MakeScaleTransform(theBase, aCDG, theScaleFactor)

  // Bug 6839: Check for standalone (not included in faces) degenerated edges
  TopTools_IndexedDataMapOfShapeListOfShape aEFMap;
  TopExp::MapShapesAndAncestors(theShapeBase, TopAbs_EDGE, TopAbs_FACE, aEFMap);
  Standard_Integer i, nbE = aEFMap.Extent();
  for (i = 1; i <= nbE; i++) {
    TopoDS_Shape anEdgeSh = aEFMap.FindKey(i);
    if (BRep_Tool::Degenerated(TopoDS::Edge(anEdgeSh))) {
      const TopTools_ListOfShape& aFaces = aEFMap.FindFromIndex(i);
      if (aFaces.IsEmpty())
        Standard_ConstructionError::Raise
          ("Scaling aborted : cannot scale standalone degenerated edge");
    }
  }

  // Perform Scaling
  gp_Trsf aTrsf;
  aTrsf.SetScale(aCDG, theScaleFactor);
  BRepBuilderAPI_Transform aBRepTrsf (theShapeBase, aTrsf, Standard_False);
  TopoDS_Shape aScale = aBRepTrsf.Shape();

  // 3. aBase2 = geompy.MakeTranslationVectorDistance(Scale, theVec, theH)
  gp_Trsf aTrsf3;
  aTrsf3.SetTranslation(theVector);
  TopLoc_Location aLocOrig = aScale.Location();
  gp_Trsf aTrsfOrig = aLocOrig.Transformation();
  TopLoc_Location aLocRes (aTrsf3 * aTrsfOrig);
  TopoDS_Shape aBase2 = aScale.Located(aLocRes);

  // 4. aCDG_2 = geompy.MakeTranslationVectorDistance(aCDG, theVec, theH)
  gp_Pnt aCDG_2 = aCDG.Translated(theVector);
  TopoDS_Shape aShapeCDG_2 = BRepBuilderAPI_MakeVertex(aCDG_2).Shape();

  // 5. Vector = geompy.MakeVector(aCDG, aCDG_2)
  TopoDS_Shape aShapeVec = BRepBuilderAPI_MakeEdge(aCDG, aCDG_2).Shape();
  TopoDS_Edge anEdge = TopoDS::Edge(aShapeVec);
  TopoDS_Wire aWirePath = BRepBuilderAPI_MakeWire(anEdge);

  // 6. aPrism = geompy.MakePipeWithDifferentSections([theBase, aBase2], [aCDG, aCDG_2], Vector, False, False)
  Handle(TopTools_HSequenceOfShape) aBases = new TopTools_HSequenceOfShape;
  aBases->Append(theShapeBase);
  aBases->Append(aBase2);

  Handle(TopTools_HSequenceOfShape) aLocs = new TopTools_HSequenceOfShape;
  aLocs->Append(aShapeCDG_1);
  aLocs->Append(aShapeCDG_2);

  aShape = GEOMImpl_PipeDriver::CreatePipeWithDifferentSections(aWirePath, aBases, aLocs, false, false);

  // 7. Make a solid, if possible
  if (theShapeBase.ShapeType() == TopAbs_FACE) {
    BRepBuilderAPI_Sewing aSewing (Precision::Confusion()*10.0);
    TopExp_Explorer expF (aShape, TopAbs_FACE);
    Standard_Integer ifa = 0;
    for (; expF.More(); expF.Next()) {
      aSewing.Add(expF.Current());
      ifa++;
    }
    if (ifa > 0) {
      aSewing.Perform();
      TopoDS_Shape aShell;

      TopoDS_Shape sh = aSewing.SewedShape();
      if (sh.ShapeType() == TopAbs_FACE && ifa == 1) {
        // case for creation of shell from one face
        TopoDS_Shell ss;
        B.MakeShell(ss);
        B.Add(ss,sh);
        aShell = ss;
      }
      else {
        TopExp_Explorer exp (sh, TopAbs_SHELL);
        Standard_Integer ish = 0;
        for (; exp.More(); exp.Next()) {
          aShell = exp.Current();
          ish++;
        }
        if (ish != 1)
          aShell = sh;
      }
      BRepCheck_Shell chkShell (TopoDS::Shell(aShell));
      if (chkShell.Closed() == BRepCheck_NoError) {
        TopoDS_Solid Sol;
        B.MakeSolid(Sol);
        B.Add(Sol, aShell);
        BRepClass3d_SolidClassifier SC (Sol);
        SC.PerformInfinitePoint(Precision::Confusion());
        if (SC.State() == TopAbs_IN) {
          B.MakeSolid(Sol);
          B.Add(Sol, aShell.Reversed());
        }
        aShape = Sol;
      }
    }
  }

  return aShape;
}
Beispiel #3
0
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<FaceTypedBase *>::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
                    if (!temp.empty())
                    {
                        modifiedShapes.push_back(std::make_pair(temp.front(), newFace));
                        deletedShapes.insert(deletedShapes.end(), temp.begin()+1, temp.end());
                    }
                }
            }
        }
    }
    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();
            workShell = TopoDS::Shell(sew.SewedShape());
            // update the list of modifications
            for (std::vector<ShapePairType>::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, Standard_True);
        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 (std::vector<ShapePairType>::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it)
        {
            if (faceMap.IsBound(it->second))
            {
                const TopoDS_Shape& value = faceMap.Find(it->second);
                if (!value.IsSame(it->second))
                    it->second = value;
            }
        }
    }
    return true;
}
App::DocumentObjectExecReturn *Loft::execute(void)
{
   
    std::vector<TopoDS_Wire> wires;
    try {
        wires = getProfileWires();
    } catch (const Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }
    
    TopoDS_Shape sketchshape = getVerifiedFace();
    if (sketchshape.IsNull())
        return new App::DocumentObjectExecReturn("Loft: Creating a face from sketch failed");

    // if the Base property has a valid shape, fuse the pipe into it
    TopoDS_Shape base;
    try {
        base = getBaseShape();
    } catch (const Base::Exception&) {
        base = TopoDS_Shape();
    }
 
    try {
        //setup the location
        this->positionByPrevious();
        TopLoc_Location invObjLoc = this->getLocation().Inverted();
        if(!base.IsNull())
            base.Move(invObjLoc);
             
        //build up multisections
        auto multisections = Sections.getValues();
        if(multisections.empty())
            return new App::DocumentObjectExecReturn("Loft: At least one section is needed");
        
        std::vector<std::vector<TopoDS_Wire>> wiresections;
        for(TopoDS_Wire& wire : wires)
            wiresections.push_back(std::vector<TopoDS_Wire>(1, wire));
                
        for(App::DocumentObject* obj : multisections) {
            if(!obj->isDerivedFrom(Part::Feature::getClassTypeId()))
                return  new App::DocumentObjectExecReturn("Loft: All sections need to be part features");
            
            TopExp_Explorer ex;
            size_t i=0;
            for (ex.Init(static_cast<Part::Feature*>(obj)->Shape.getValue(), TopAbs_WIRE); ex.More(); ex.Next(), ++i) {
                if(i>=wiresections.size())
                    return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section");
                wiresections[i].push_back(TopoDS::Wire(ex.Current()));
            }
            if(i<wiresections.size())
                    return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section");
            
        }
        
        //build all shells
        std::vector<TopoDS_Shape> shells;
        for(std::vector<TopoDS_Wire>& wires : wiresections) {
            
            BRepOffsetAPI_ThruSections mkTS(false, Ruled.getValue(), Precision::Confusion());

            for(TopoDS_Wire& wire : wires)   {
                 wire.Move(invObjLoc);
                 mkTS.AddWire(wire);
            }

            mkTS.Build();
            if (!mkTS.IsDone())
                return new App::DocumentObjectExecReturn("Loft could not be build");
            
            //build the shell use simulate to get the top and bottom wires in an easy way
            shells.push_back(mkTS.Shape());
        }
        
        //build the top and bottom face, sew the shell and build the final solid
        TopoDS_Shape front = getVerifiedFace();
        front.Move(invObjLoc);
        std::vector<TopoDS_Wire> backwires;
        for(std::vector<TopoDS_Wire>& wires : wiresections)
            backwires.push_back(wires.back());
        
        TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires);
        
        BRepBuilderAPI_Sewing sewer;
        sewer.SetTolerance(Precision::Confusion());
        sewer.Add(front);
        sewer.Add(back);
        for(TopoDS_Shape& s : shells)
            sewer.Add(s);      
        
        sewer.Perform();
        
        //build the solid
        BRepBuilderAPI_MakeSolid mkSolid;
        mkSolid.Add(TopoDS::Shell(sewer.SewedShape()));
        if(!mkSolid.IsDone())
            return new App::DocumentObjectExecReturn("Loft: Result is not a solid");
        
        TopoDS_Shape result = mkSolid.Shape();
        BRepClass3d_SolidClassifier SC(result);
        SC.PerformInfinitePoint(Precision::Confusion());
        if ( SC.State() == TopAbs_IN) {
            result.Reverse();
        }

        AddSubShape.setValue(result);
        
        if(base.IsNull()) {
            Shape.setValue(getSolid(result));
            return App::DocumentObject::StdReturn;
        }
        
        if(getAddSubType() == FeatureAddSub::Additive) {
                       
            BRepAlgoAPI_Fuse mkFuse(base, result);
            if (!mkFuse.IsDone())
                return new App::DocumentObjectExecReturn("Loft: Adding the loft failed");
            // we have to get the solids (fuse sometimes creates compounds)
            TopoDS_Shape boolOp = this->getSolid(mkFuse.Shape());
            // lets check if the result is a solid
            if (boolOp.IsNull())
                return new App::DocumentObjectExecReturn("Loft: Resulting shape is not a solid");
            
            boolOp = refineShapeIfActive(boolOp);
            Shape.setValue(getSolid(boolOp));
        }
        else if(getAddSubType() == FeatureAddSub::Subtractive) {
            
            BRepAlgoAPI_Cut mkCut(base, result);
            if (!mkCut.IsDone())
                return new App::DocumentObjectExecReturn("Loft: Subtracting the loft failed");
            // we have to get the solids (fuse sometimes creates compounds)
            TopoDS_Shape boolOp = this->getSolid(mkCut.Shape());
            // lets check if the result is a solid
            if (boolOp.IsNull())
                return new App::DocumentObjectExecReturn("Loft: Resulting shape is not a solid");
            
            boolOp = refineShapeIfActive(boolOp);
            Shape.setValue(getSolid(boolOp));
        }
        
        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
    catch (...) {
        return new App::DocumentObjectExecReturn("Loft: A fatal error occurred when making the loft");
    }
}
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<FaceTypedBase *>::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<ShapePairType>::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<ShapePairType>::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;
}
Beispiel #6
0
App::DocumentObjectExecReturn *Pipe::execute(void)
{
    
    std::vector<TopoDS_Wire> wires;
    try {
        wires = getProfileWires();
    } catch (const Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }
    
    TopoDS_Shape sketchshape = getVerifiedFace();
    if (sketchshape.IsNull())
        return new App::DocumentObjectExecReturn("Pipe: No valid sketch or face as first section");
    else {
        //TODO: currently we only allow planar faces. the reason for this is that with other faces in front, we could 
        //not use the current simulate approach and build the start and end face from the wires. As the shell 
        //beginns always at the spine and not the profile, the sketchshape cannot be used directly as front face. 
        //We would need a method to translate the frontshape to match the shell starting position somehow...
        TopoDS_Face face = TopoDS::Face(sketchshape);
        BRepAdaptor_Surface adapt(face);
        if(adapt.GetType() != GeomAbs_Plane)
            return new App::DocumentObjectExecReturn("Pipe: Only planar faces supportet");
    }

    // if the Base property has a valid shape, fuse the pipe into it
    TopoDS_Shape base;
    try {
        base = getBaseShape();
    } catch (const Base::Exception&) {
        base = TopoDS_Shape();
    }
 
    try {
        //setup the location
        this->positionByPrevious();
        TopLoc_Location invObjLoc = this->getLocation().Inverted();
        if(!base.IsNull())
            base.Move(invObjLoc);
        
        //build the paths
        App::DocumentObject* spine = Spine.getValue();
        if (!(spine && spine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
            return new App::DocumentObjectExecReturn("No spine linked.");
        std::vector<std::string> subedge = Spine.getSubValues();
        TopoDS_Shape path;
        const Part::TopoShape& shape = static_cast<Part::Feature*>(spine)->Shape.getValue();
        buildPipePath(shape, subedge, path);
        path.Move(invObjLoc);
        
        
        TopoDS_Shape auxpath;
        if(Mode.getValue()==3) {
            App::DocumentObject* auxspine = AuxillerySpine.getValue();
            if (!(auxspine && auxspine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
                return new App::DocumentObjectExecReturn("No auxillery spine linked.");
            std::vector<std::string> auxsubedge = AuxillerySpine.getSubValues();
            TopoDS_Shape path;
            const Part::TopoShape& auxshape = static_cast<Part::Feature*>(auxspine)->Shape.getValue();
            buildPipePath(auxshape, auxsubedge, auxpath);
            auxpath.Move(invObjLoc);
        }        
        
        //build up multisections
        auto multisections = Sections.getValues();
        std::vector<std::vector<TopoDS_Wire>> wiresections;
        for(TopoDS_Wire& wire : wires)
            wiresections.push_back(std::vector<TopoDS_Wire>(1, wire));
        //maybe we need a sacling law
        Handle(Law_Function) scalinglaw;
        
        //see if we shall use multiple sections
        if(Transformation.getValue() == 1) {
            
            //TODO: we need to order the sections to prevent occ from crahsing, as makepieshell connects
            //the sections in the order of adding            
                
            for(App::DocumentObject* obj : multisections) {
                if(!obj->isDerivedFrom(Part::Feature::getClassTypeId()))
                    return  new App::DocumentObjectExecReturn("All sections need to be part features");
                
                TopExp_Explorer ex;
                size_t i=0;
                for (ex.Init(static_cast<Part::Feature*>(obj)->Shape.getValue(), TopAbs_WIRE); ex.More(); ex.Next()) {
                    wiresections[i].push_back(TopoDS::Wire(ex.Current()));
                    if(i>=wiresections.size())
                        return new App::DocumentObjectExecReturn("Multisections need to have the same amount of inner wires as the base section");
                    
                    ++i;
                }
                if(i<wiresections.size())
                        return new App::DocumentObjectExecReturn("Multisections need to have the same amount of inner wires as the base section");
                
            }
        }
        /*//build the law functions instead
        else if(Transformation.getValue() == 2) {
            if(ScalingData.getValues().size()<1)
                return new App::DocumentObjectExecReturn("No valid data given for liinear scaling mode");
            
            Handle(Law_Linear) lin = new Law_Linear();
            lin->Set(0,1,1,ScalingData[0].x);
            
            scalinglaw = lin;
        }
        else if(Transformation.getValue() == 3) {
            if(ScalingData.getValues().size()<1)
                return new App::DocumentObjectExecReturn("No valid data given for S-shape scaling mode");
            
            Handle(Law_S) s = new Law_S();
            s->Set(0,1,ScalingData[0].y, 1, ScalingData[0].x, ScalingData[0].z);
            
            scalinglaw = s;
        }*/
        
        //build all shells
        std::vector<TopoDS_Shape> shells;
        std::vector<TopoDS_Wire> frontwires, backwires;
        for(std::vector<TopoDS_Wire>& wires : wiresections) {
            
            BRepOffsetAPI_MakePipeShell mkPS(TopoDS::Wire(path));
            setupAlgorithm(mkPS, auxpath);
            
            if(!scalinglaw) {
                for(TopoDS_Wire& wire : wires) {
                    wire.Move(invObjLoc);
                    mkPS.Add(wire);
                }
            }
            else {
                for(TopoDS_Wire& wire : wires)  {
                    wire.Move(invObjLoc);
                    mkPS.SetLaw(wire, scalinglaw);
                }
            }

            if (!mkPS.IsReady())
                return new App::DocumentObjectExecReturn("pipe could not be build");
            
            //build the shell use simulate to get the top and bottom wires in an easy way
            shells.push_back(mkPS.Shape());
            TopTools_ListOfShape sim;
            mkPS.Simulate(2, sim);
            frontwires.push_back(TopoDS::Wire(sim.First()));
            backwires.push_back(TopoDS::Wire(sim.Last()));            
        }
        
        //build the top and bottom face, sew the shell and build the final solid
        TopoDS_Shape front = makeFace(frontwires);
        TopoDS_Shape back  = makeFace(backwires);
        
        BRepBuilderAPI_Sewing sewer;
        sewer.SetTolerance(Precision::Confusion());
        sewer.Add(front);
        sewer.Add(back);
        for(TopoDS_Shape& s : shells)
            sewer.Add(s);      
        
        sewer.Perform();
        
        //build the solid
        BRepBuilderAPI_MakeSolid mkSolid;
        mkSolid.Add(TopoDS::Shell(sewer.SewedShape()));
        if(!mkSolid.IsDone())
            return new App::DocumentObjectExecReturn("Result is not a solid");
        
        TopoDS_Shape result = mkSolid.Shape();
        BRepClass3d_SolidClassifier SC(result);
        SC.PerformInfinitePoint(Precision::Confusion());
        if ( SC.State() == TopAbs_IN) {
            result.Reverse();
        }
        
        //result.Move(invObjLoc);
        AddSubShape.setValue(result);
        
        if(base.IsNull()) {
            Shape.setValue(getSolid(result));
            return App::DocumentObject::StdReturn;
        }
        
        if(getAddSubType() == FeatureAddSub::Additive) {
                        
            BRepAlgoAPI_Fuse mkFuse(base, result);
            if (!mkFuse.IsDone())
                return new App::DocumentObjectExecReturn("Adding the pipe failed");
            // we have to get the solids (fuse sometimes creates compounds)
            TopoDS_Shape boolOp = this->getSolid(mkFuse.Shape());
            // lets check if the result is a solid
            if (boolOp.IsNull())
                return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
            
            boolOp = refineShapeIfActive(boolOp);
            Shape.setValue(getSolid(boolOp));
        }
        else if(getAddSubType() == FeatureAddSub::Subtractive) {
            
            BRepAlgoAPI_Cut mkCut(base, result);
            if (!mkCut.IsDone())
                return new App::DocumentObjectExecReturn("Subtracting the pipe failed");
            // we have to get the solids (fuse sometimes creates compounds)
            TopoDS_Shape boolOp = this->getSolid(mkCut.Shape());
            // lets check if the result is a solid
            if (boolOp.IsNull())
                return new App::DocumentObjectExecReturn("Resulting shape is not a solid");
            
            boolOp = refineShapeIfActive(boolOp);
            Shape.setValue(getSolid(boolOp));
        }
        
        return App::DocumentObject::StdReturn;
        
        return ProfileBased::execute();   
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e = Standard_Failure::Caught();
        return new App::DocumentObjectExecReturn(e->GetMessageString());
    }
    catch (...) {
        return new App::DocumentObjectExecReturn("A fatal error occurred when making the pipe");
    }
}