// constructor method int TopoShapeSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/) { PyObject *obj; if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &obj)) return -1; try { BRepBuilderAPI_MakeSolid mkSolid; const TopoDS_Shape& shape = static_cast<TopoShapePy*>(obj) ->getTopoShapePtr()->_Shape; TopExp_Explorer anExp (shape, TopAbs_SHELL); int count=0; for (; anExp.More(); anExp.Next()) { ++count; mkSolid.Add(TopoDS::Shell(anExp.Current())); } if (count == 0) Standard_Failure::Raise("No shells found in shape"); TopoDS_Solid solid = mkSolid.Solid(); BRepLib::OrientClosedSolid(solid); getTopoShapePtr()->_Shape = solid; } catch (Standard_Failure) { PyErr_SetString(PartExceptionOCCError, "creation of solid failed"); return -1; } return 0; }
// constructor method int TopoShapeSolidPy::PyInit(PyObject* args, PyObject* /*kwd*/) { PyObject *obj; if (!PyArg_ParseTuple(args, "O!", &(TopoShapePy::Type), &obj)) return -1; try { const TopoDS_Shape& shape = static_cast<TopoShapePy*>(obj) ->getTopoShapePtr()->getShape(); //first, if we were given a compsolid, try making a solid out of it TopExp_Explorer CSExp (shape, TopAbs_COMPSOLID); TopoDS_CompSolid compsolid; int count=0; for (; CSExp.More(); CSExp.Next()) { ++count; compsolid = TopoDS::CompSolid(CSExp.Current()); if (count > 1) break; } if (count == 0) { //no compsolids. Get shells... BRepBuilderAPI_MakeSolid mkSolid; TopExp_Explorer anExp (shape, TopAbs_SHELL); count=0; for (; anExp.More(); anExp.Next()) { ++count; mkSolid.Add(TopoDS::Shell(anExp.Current())); } if (count == 0)//no shells? Standard_Failure::Raise("No shells or compsolids found in shape"); TopoDS_Solid solid = mkSolid.Solid(); BRepLib::OrientClosedSolid(solid); getTopoShapePtr()->setShape(solid); } else if (count == 1) { BRepBuilderAPI_MakeSolid mkSolid(compsolid); TopoDS_Solid solid = mkSolid.Solid(); getTopoShapePtr()->setShape(solid); } else if (count > 1) { Standard_Failure::Raise("Only one compsolid can be accepted. Provided shape has more than one compsolid."); } } catch (Standard_Failure err) { std::stringstream errmsg; errmsg << "Creation of solid failed: " << err.GetMessageString(); PyErr_SetString(PartExceptionOCCError, errmsg.str().c_str()); return -1; } return 0; }
App::DocumentObjectExecReturn *Wedge::execute(void) { double xmin = Xmin.getValue(); double ymin = Ymin.getValue(); double zmin = Zmin.getValue(); double z2min = Z2min.getValue(); double x2min = X2min.getValue(); double xmax = Xmax.getValue(); double ymax = Ymax.getValue(); double zmax = Zmax.getValue(); double z2max = Z2max.getValue(); double x2max = X2max.getValue(); double dx = xmax-xmin; double dy = ymax-ymin; double dz = zmax-zmin; double dz2 = z2max-z2min; double dx2 = x2max-x2min; if (dx < Precision::Confusion()) return new App::DocumentObjectExecReturn("delta x of wedge too small"); if (dy < Precision::Confusion()) return new App::DocumentObjectExecReturn("delta y of wedge too small"); if (dz < Precision::Confusion()) return new App::DocumentObjectExecReturn("delta z of wedge too small"); if (dz2 < 0) return new App::DocumentObjectExecReturn("delta z2 of wedge is negative"); if (dx2 < 0) return new App::DocumentObjectExecReturn("delta x2 of wedge is negative"); try { gp_Pnt pnt(0.0,0.0,0.0); gp_Dir dir(0.0,0.0,1.0); BRepPrim_Wedge mkWedge(gp_Ax2(pnt,dir), xmin, ymin, zmin, z2min, x2min, xmax, ymax, zmax, z2max, x2max); BRepBuilderAPI_MakeSolid mkSolid; mkSolid.Add(mkWedge.Shell()); this->Shape.setValue(mkSolid.Solid()); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } return App::DocumentObject::StdReturn; }
/// 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; }
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"); } }
void Part::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(); }
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"); } }