bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { TopoDS_Shape halfspace; if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; TopoDS_Wire wire; if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; gp_Trsf trsf; if ( ! convert(l->Position(),trsf) ) return false; TColgp_SequenceOfPnt points; if (wire_to_sequence_of_point(wire, points)) { remove_duplicate_points_from_loop(points, wire.Closed()); // Note: wire always closed, as per if statement above remove_collinear_points_from_loop(points, wire.Closed()); sequence_of_point_to_wire(points, wire, wire.Closed()); } TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); // `trsf` and `down` both have a unit scale factor prism.Move(trsf*down); shape = BRepAlgoAPI_Common(halfspace,prism); return true; }
BldElement::BldElement(int id, string guid, string name, string type, const IfcGeomObjects::IfcGeomShapeModelObject *o):id(id),guid(guid),name(name),type(type),geomtool(new Geometry){ BRep_Builder builder; builder.MakeCompound(shape); for (IfcGeom::IfcRepresentationShapeItems::const_iterator it = o->mesh().begin(); it != o->mesh().end(); ++ it) { TopoDS_Shape brep = it->Shape(); gp_Trsf trsf = it->Placement().Trsf(); brep.Move(trsf); // FIXME are the shells in the shape fixed by ifcopenshell? builder.Add(shape,brep); } shape_original=shape; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolygonalBoundedHalfSpace* l, TopoDS_Shape& shape) { TopoDS_Shape halfspace; if ( ! IfcGeom::Kernel::convert((IfcSchema::IfcHalfSpaceSolid*)l,halfspace) ) return false; TopoDS_Wire wire; if ( ! convert_wire(l->PolygonalBoundary(),wire) || ! wire.Closed() ) return false; gp_Trsf trsf; convert(l->Position(),trsf); TopoDS_Shape prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(wire),gp_Vec(0,0,200)); gp_Trsf down; down.SetTranslation(gp_Vec(0,0,-100.0)); prism.Move(trsf*down); shape = BRepAlgoAPI_Common(halfspace,prism); return true; }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); if (height < getValue(GV_PRECISION)) { Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l->entity); return false; } TopoDS_Shape face; if ( !convert_face(l->SweptArea(),face) ) return false; gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); gp_Dir dir; convert(l->ExtrudedDirection(),dir); shape.Nullify(); if (face.ShapeType() == TopAbs_COMPOUND) { // For compounds (most likely the result of a IfcCompositeProfileDef) // create a compound solid shape. TopExp_Explorer exp(face, TopAbs_FACE); TopoDS_CompSolid compound; BRep_Builder builder; builder.MakeCompSolid(compound); int num_faces_extruded = 0; for (; exp.More(); exp.Next(), ++num_faces_extruded) { builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir)); } if (num_faces_extruded) { shape = compound; } } if (shape.IsNull()) { shape = BRepPrimAPI_MakePrism(face, height*dir); } // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D // and therefore has a unit scale factor shape.Move(trsf); return ! shape.IsNull(); }
void BRepOffsetAPI_MakeOffsetFix::MakeWire(TopoDS_Shape& wire) { // get the edges of the wire and check which of the stored edges // serve as input of the wire TopTools_MapOfShape aMap; TopExp_Explorer xp(wire, TopAbs_EDGE); while (xp.More()) { aMap.Add(xp.Current()); xp.Next(); } std::list<TopoDS_Edge> edgeList; for (auto itLoc : myLocations) { const TopTools_ListOfShape& newShapes = mkOffset.Generated(itLoc.first); for (TopTools_ListIteratorOfListOfShape it(newShapes); it.More(); it.Next()) { TopoDS_Shape newShape = it.Value(); if (aMap.Contains(newShape)) { newShape.Move(itLoc.second); edgeList.push_back(TopoDS::Edge(newShape)); } } } if (!edgeList.empty()) { BRepBuilderAPI_MakeWire mkWire; mkWire.Add(edgeList.front()); edgeList.pop_front(); wire = mkWire.Wire(); bool found = false; do { found = false; for (std::list<TopoDS_Edge>::iterator pE = edgeList.begin(); pE != edgeList.end(); ++pE) { mkWire.Add(*pE); if (mkWire.Error() != BRepBuilderAPI_DisconnectedWire) { // edge added ==> remove it from list found = true; edgeList.erase(pE); wire = mkWire.Wire(); break; } } } while (found); } }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfLinearExtrusion* l, TopoDS_Shape& shape) { TopoDS_Wire wire; if ( !convert_wire(l->SweptCurve(), wire) ) { TopoDS_Face face; if ( !convert_face(l->SweptCurve(),face) ) return false; TopExp_Explorer exp(face, TopAbs_WIRE); wire = TopoDS::Wire(exp.Current()); } const double height = l->Depth() * getValue(GV_LENGTH_UNIT); gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); gp_Dir dir; convert(l->ExtrudedDirection(),dir); shape = BRepPrimAPI_MakePrism(wire, height*dir); shape.Move(trsf); return !shape.IsNull(); }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcExtrudedAreaSolid* l, TopoDS_Shape& shape) { TopoDS_Shape face; if ( !convert_face(l->SweptArea(),face) ) return false; const double height = l->Depth() * getValue(GV_LENGTH_UNIT); gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); gp_Dir dir; convert(l->ExtrudedDirection(),dir); shape.Nullify(); if (face.ShapeType() == TopAbs_COMPOUND) { // For compounds (most likely the result of a IfcCompositeProfileDef) // create a compound solid shape. TopExp_Explorer exp(face, TopAbs_FACE); TopoDS_CompSolid compound; BRep_Builder builder; builder.MakeCompSolid(compound); int num_faces_extruded = 0; for (; exp.More(); exp.Next(), ++num_faces_extruded) { builder.Add(compound, BRepPrimAPI_MakePrism(exp.Current(), height*dir)); } if (num_faces_extruded) { shape = compound; } } if (shape.IsNull()) { shape = BRepPrimAPI_MakePrism(face, height*dir); } shape.Move(trsf); return ! shape.IsNull(); }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceOfRevolution* l, TopoDS_Shape& shape) { TopoDS_Wire wire; if ( !convert_wire(l->SweptCurve(), wire) ) { TopoDS_Face face; if ( !convert_face(l->SweptCurve(),face) ) return false; TopExp_Explorer exp(face, TopAbs_WIRE); wire = TopoDS::Wire(exp.Current()); } gp_Ax1 ax1; IfcGeom::Kernel::convert(l->AxisPosition(), ax1); gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); shape = BRepPrimAPI_MakeRevol(wire, ax1); shape.Move(trsf); return !shape.IsNull(); }
bool IfcGeom::Kernel::convert(const IfcSchema::IfcRevolvedAreaSolid* l, TopoDS_Shape& shape) { const double ang = l->Angle() * getValue(GV_PLANEANGLE_UNIT); TopoDS_Face face; if ( ! convert_face(l->SweptArea(),face) ) return false; gp_Ax1 ax1; IfcGeom::Kernel::convert(l->Axis(), ax1); gp_Trsf trsf; IfcGeom::Kernel::convert(l->Position(),trsf); if (ang >= M_PI * 2. - ALMOST_ZERO) { shape = BRepPrimAPI_MakeRevol(face, ax1); } else { shape = BRepPrimAPI_MakeRevol(face, ax1, ang); } shape.Move(trsf); return !shape.IsNull(); }
App::DocumentObjectExecReturn *Pad::execute(void) { // Validate parameters double L = Length.getValue(); if ((std::string(Type.getValueAsString()) == "Length") && (L < Precision::Confusion())) return new App::DocumentObjectExecReturn("Length of pad too small"); double L2 = Length2.getValue(); if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion())) return new App::DocumentObjectExecReturn("Second length of pad too small"); Part::Part2DObject* sketch = 0; std::vector<TopoDS_Wire> wires; try { sketch = getVerifiedSketch(); wires = getSketchWires(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } TopoDS_Shape support; try { support = getSupportShape(); } catch (const Base::Exception&) { // ignore, because support isn't mandatory support = TopoDS_Shape(); } // get the Sketch plane Base::Placement SketchPos = sketch->Placement.getValue(); Base::Rotation SketchOrientation = SketchPos.getRotation(); Base::Vector3d SketchVector(0,0,1); SketchOrientation.multVec(SketchVector,SketchVector); this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); try { support.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); dir.Transform(invObjLoc.Transformation()); TopoDS_Shape sketchshape = makeFace(wires); if (sketchshape.IsNull()) return new App::DocumentObjectExecReturn("Pad: Creating a face from sketch failed"); sketchshape.Move(invObjLoc); TopoDS_Shape prism; std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") { TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); if (Reversed.getValue()) dir.Reverse(); // Find a valid face to extrude up to TopoDS_Face upToFace; if (method == "UpToFace") { getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } getUpToFace(upToFace, support, supportface, sketchshape, method, dir); // A support object is always required and we need to use BRepFeat_MakePrism // Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid // because the feature does not add any material. This only happens with the "2" option, though // Note: It might be possible to pass a shell or a compound containing multiple faces // as the Until parameter of Perform() BRepFeat_MakePrism PrismMaker; PrismMaker.Init(support, sketchshape, supportface, dir, 2, 1); PrismMaker.Perform(upToFace); if (!PrismMaker.IsDone()) return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); prism = PrismMaker.Shape(); } else { generatePrism(prism, sketchshape, method, dir, L, L2, Midplane.getValue(), Reversed.getValue()); } if (prism.IsNull()) return new App::DocumentObjectExecReturn("Pad: Resulting shape is empty"); // set the additive shape property for later usage in e.g. pattern this->AddShape.setValue(prism); // if the sketch has a support fuse them to get one result object if (!support.IsNull()) { // Let's call algorithm computing a fuse operation: BRepAlgoAPI_Fuse mkFuse(support, prism); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) return new App::DocumentObjectExecReturn("Pad: Fusion with support failed"); TopoDS_Shape result = mkFuse.Shape(); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(result); // lets check if the result is a solid if (solRes.IsNull()) return new App::DocumentObjectExecReturn("Pad: Resulting shape is not a solid"); this->Shape.setValue(solRes); } else { this->Shape.setValue(prism); } return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face") return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } }
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"); } }
App::DocumentObjectExecReturn *RuledSurface::execute(void) { try { App::DocumentObjectExecReturn* ret; // get the first input shape TopoDS_Shape S1; ret = getShape(Curve1, S1); if (ret) return ret; // get the second input shape TopoDS_Shape S2; ret = getShape(Curve2, S2); if (ret) return ret; // check for expected type if (S1.IsNull() || S2.IsNull()) return new App::DocumentObjectExecReturn("Linked shapes are empty."); if (S1.ShapeType() != TopAbs_EDGE && S1.ShapeType() != TopAbs_WIRE) return new App::DocumentObjectExecReturn("Linked shape is neither edge nor wire."); if (S2.ShapeType() != TopAbs_EDGE && S2.ShapeType() != TopAbs_WIRE) return new App::DocumentObjectExecReturn("Linked shape is neither edge nor wire."); // https://forum.freecadweb.org/viewtopic.php?f=8&t=24052 // // if both shapes are sub-elements of one common shape then the fill algorithm // leads to problems if the shape has set a placement // The workaround is to reset the placement before calling BRepFill and then // applying the placement to the output shape TopLoc_Location Loc; if (Curve1.getValue() == Curve2.getValue()) { Loc = S1.Location(); if (!Loc.IsIdentity() && Loc == S2.Location()) { S1.Location(TopLoc_Location()); S2.Location(TopLoc_Location()); } } // make both shapes to have the same type Standard_Boolean isWire = Standard_False; if (S1.ShapeType() == TopAbs_WIRE) isWire = Standard_True; if (isWire) { if (S2.ShapeType() == TopAbs_EDGE) S2 = BRepLib_MakeWire(TopoDS::Edge(S2)); } else { // S1 is an edge, if S2 is a wire convert S1 to a wire, too if (S2.ShapeType() == TopAbs_WIRE) { S1 = BRepLib_MakeWire(TopoDS::Edge(S1)); isWire = Standard_True; } } if (Orientation.getValue() == 0) { // Automatic Handle(Adaptor3d_HCurve) a1; Handle(Adaptor3d_HCurve) a2; if (!isWire) { BRepAdaptor_Curve adapt1(TopoDS::Edge(S1)); BRepAdaptor_Curve adapt2(TopoDS::Edge(S2)); a1 = new BRepAdaptor_HCurve(adapt1); a2 = new BRepAdaptor_HCurve(adapt2); } else { BRepAdaptor_CompCurve adapt1(TopoDS::Wire(S1)); BRepAdaptor_CompCurve adapt2(TopoDS::Wire(S2)); a1 = new BRepAdaptor_HCompCurve(adapt1); a2 = new BRepAdaptor_HCompCurve(adapt2); } if (!a1.IsNull() && !a2.IsNull()) { // get end points of 1st curve Standard_Real first, last; first = a1->FirstParameter(); last = a1->LastParameter(); if (S1.Closed()) last = (first + last)/2; gp_Pnt p1 = a1->Value(first); gp_Pnt p2 = a1->Value(last); if (S1.Orientation() == TopAbs_REVERSED) { std::swap(p1, p2); } // get end points of 2nd curve first = a2->FirstParameter(); last = a2->LastParameter(); if (S2.Closed()) last = (first + last)/2; gp_Pnt p3 = a2->Value(first); gp_Pnt p4 = a2->Value(last); if (S2.Orientation() == TopAbs_REVERSED) { std::swap(p3, p4); } // Form two triangles (P1,P2,P3) and (P4,P3,P2) and check their normals. // If the dot product is negative then it's assumed that the resulting face // is twisted, hence the 2nd edge is reversed. gp_Vec v1(p1, p2); gp_Vec v2(p1, p3); gp_Vec n1 = v1.Crossed(v2); gp_Vec v3(p4, p3); gp_Vec v4(p4, p2); gp_Vec n2 = v3.Crossed(v4); if (n1.Dot(n2) < 0) { S2.Reverse(); } } } else if (Orientation.getValue() == 2) { // Reverse S2.Reverse(); } TopoDS_Shape ruledShape; if (!isWire) { ruledShape = BRepFill::Face(TopoDS::Edge(S1), TopoDS::Edge(S2)); } else { ruledShape = BRepFill::Shell(TopoDS::Wire(S1), TopoDS::Wire(S2)); } // re-apply the placement in case we reset it if (!Loc.IsIdentity()) ruledShape.Move(Loc); Loc = ruledShape.Location(); if (!Loc.IsIdentity()) { // reset the placement of the shape because the Placement // property will be changed ruledShape.Location(TopLoc_Location()); Base::Matrix4D transform; TopoShape::convertToMatrix(Loc.Transformation(), transform); this->Placement.setValue(Base::Placement(transform)); } this->Shape.setValue(ruledShape); return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } catch (...) { return new App::DocumentObjectExecReturn("General error in RuledSurface::execute()"); } }
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 IfcGeom::Kernel::convert(const IfcSchema::IfcSurfaceCurveSweptAreaSolid* l, TopoDS_Shape& shape) { gp_Trsf directrix, position; TopoDS_Shape face; TopoDS_Wire wire, section; if (!l->ReferenceSurface()->is(IfcSchema::Type::IfcPlane)) { Logger::Message(Logger::LOG_WARNING, "Reference surface not supported", l->ReferenceSurface()->entity); return false; } if (!IfcGeom::Kernel::convert(l->Position(), position) || !convert_face(l->SweptArea(), face) || !convert_wire(l->Directrix(), wire) ) { return false; } gp_Pln pln; gp_Pnt directrix_origin; gp_Vec directrix_tangent; bool directrix_on_plane = true; IfcGeom::Kernel::convert((IfcSchema::IfcPlane*) l->ReferenceSurface(), pln); // As per Informal propositions 2: The Directrix shall lie on the ReferenceSurface. // This is not always the case with the test files in the repository. I am not sure // how to deal with this and whether my interpretation of the propositions is // correct. However, if it has been asserted that the vertices of the directrix do // not conform to the ReferenceSurface, the ReferenceSurface is ignored. { for (TopExp_Explorer exp(wire, TopAbs_VERTEX); exp.More(); exp.Next()) { if (pln.Distance(BRep_Tool::Pnt(TopoDS::Vertex(exp.Current()))) > ALMOST_ZERO) { directrix_on_plane = false; Logger::Message(Logger::LOG_WARNING, "The Directrix does not lie on the ReferenceSurface", l->entity); break; } } } { TopExp_Explorer exp(wire, TopAbs_EDGE); TopoDS_Edge edge = TopoDS::Edge(exp.Current()); double u0, u1; Handle(Geom_Curve) crv = BRep_Tool::Curve(edge, u0, u1); crv->D1(u0, directrix_origin, directrix_tangent); } if (pln.Axis().Direction().IsNormal(directrix_tangent, Precision::Approximation()) && directrix_on_plane) { directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent, pln.Axis().Direction()), gp::XOY()); } else { directrix.SetTransformation(gp_Ax3(directrix_origin, directrix_tangent), gp::XOY()); } face = BRepBuilderAPI_Transform(face, directrix); // NB: Note that StartParam and EndParam param are ignored and the assumption is // made that the parametric range over which to be swept matches the IfcCurve in // its entirety. BRepOffsetAPI_MakePipeShell builder(wire); { TopExp_Explorer exp(face, TopAbs_WIRE); section = TopoDS::Wire(exp.Current()); } builder.Add(section); builder.SetTransitionMode(BRepBuilderAPI_RightCorner); if (directrix_on_plane) { builder.SetMode(pln.Axis().Direction()); } builder.Build(); builder.MakeSolid(); shape = builder.Shape(); shape.Move(position); return true; }
//======================================================================= // profile // command to build a profile //======================================================================= Sketcher_Profile::Sketcher_Profile(const char* aCmd) { enum {line, circle, point, none} move; Standard_Integer i = 1; Standard_Real x0, y0, x, y, dx, dy; x0 = y0 = x = y = dy = 0; dx = 1; Standard_Boolean first, stayfirst, face, close; first = Standard_True; stayfirst = face = close = Standard_False; Standard_Integer reversed = 0; Standard_Integer control_Tolerance = 0; TopoDS_Shape S; TopoDS_Vertex MP; BRepBuilderAPI_MakeWire MW; gp_Ax3 DummyHP(gp::XOY()); gp_Pln P(DummyHP); TopLoc_Location TheLocation; Handle(Geom_Surface) Surface; myOK = Standard_False; myError = 0; //TCollection_AsciiString aCommand(CORBA::string_dup(aCmd)); TCollection_AsciiString aCommand ((char*)aCmd); TCollection_AsciiString aToken = aCommand.Token(":", 1); int n = 0; // porting to WNT TColStd_Array1OfAsciiString aTab (0, aCommand.Length() - 1); if ( aCommand.Length() ) { while(aToken.Length() != 0) { if(aCommand.Token(":", n + 1).Length() > 0) aTab(n) = aCommand.Token(":", n + 1); aToken = aCommand.Token(":", ++n); } n = n - 1; } if ( aTab.Length() && aTab(0).Length() ) while(i < n) { Standard_Real length = 0, radius = 0, angle = 0; move = point; int n1 = 0; TColStd_Array1OfAsciiString a (0, aTab(0).Length()); aToken = aTab(i).Token(" ", 1); while (aToken.Length() != 0) { if (aTab(i).Token(" ", n1 + 1).Length() > 0) a(n1) = aTab(i).Token(" ", n1 + 1); aToken = aTab(i).Token(" ", ++n1); } n1 = n1 - 1; switch(a(0).Value(1)) { case 'F': { if (n1 != 3) goto badargs; if (!first) { MESSAGE("profile : The F instruction must precede all moves"); return; } x0 = x = a(1).RealValue(); y0 = y = a(2).RealValue(); stayfirst = Standard_True; break; } case 'O': { if (n1 != 4) goto badargs; P.SetLocation(gp_Pnt(a(1).RealValue(), a(2).RealValue(), a(3).RealValue())); stayfirst = Standard_True; break; } case 'P': { if (n1 != 7) goto badargs; gp_Vec vn(a(1).RealValue(), a(2).RealValue(), a(3).RealValue()); gp_Vec vx(a(4).RealValue(), a(5).RealValue(), a(6).RealValue()); if (vn.Magnitude() <= Precision::Confusion() || vx.Magnitude() <= Precision::Confusion()) { MESSAGE("profile : null direction"); return; } gp_Ax2 ax(P.Location(), vn, vx); P.SetPosition(ax); stayfirst = Standard_True; break; } case 'X': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (a(0) == "XX") length -= x; dx = 1; dy = 0; move = line; break; } case 'Y': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (a(0) == "YY") length -= y; dx = 0; dy = 1; move = line; break; } case 'L': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (Abs(length) > Precision::Confusion()) move = line; else move = none; break; } case 'T': { if (n1 != 3) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); if (a(0) == "TT") { vx -= x; vy -= y; } length = Sqrt(vx * vx + vy * vy); if (length > Precision::Confusion()) { move = line; dx = vx / length; dy = vy / length; } else move = none; break; } case 'R': { if (n1 != 2) goto badargs; angle = a(1).RealValue() * PI180; if (a(0) == "RR") { dx = Cos(angle); dy = Sin(angle); } else { Standard_Real c = Cos(angle); Standard_Real s = Sin(angle); Standard_Real t = c * dx - s * dy; dy = s * dx + c * dy; dx = t; } break; } case 'D': { if (n1 != 3) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); length = Sqrt(vx * vx + vy * vy); if (length > Precision::Confusion()) { dx = vx / length; dy = vy / length; } else move = none; break; } case 'C': { if (n1 != 3) goto badargs; radius = a(1).RealValue(); if (Abs(radius) > Precision::Confusion()) { angle = a(2).RealValue() * PI180; move = circle; } else move = none; break; } case 'A': // TAngential arc by end point { if (n1 != 3) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); if (a(0) == "AA") { vx -= x; vy -= y; } Standard_Real det = dx * vy - dy * vx; if ( Abs(det) > Precision::Confusion()) { Standard_Real c = (dx * vx + dy * vy) / Sqrt((dx * dx + dy * dy) * (vx * vx + vy * vy)); // Cosine of alpha = arc of angle / 2 , alpha in [0,Pi] radius = (vx * vx + vy * vy)* Sqrt(dx * dx + dy * dy) // radius = distance between start and end point / 2 * sin(alpha) / (2.0 * det); // radius is > 0 or < 0 if (Abs(radius) > Precision::Confusion()) { angle = 2.0 * acos(c); // angle in [0,2Pi] move = circle; } else move = none; break; } else move = none; break; } case 'U': // Arc by end point and radiUs { if (n1 != 5) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); radius = a(3).RealValue(); reversed = a(4).IntegerValue(); if (a(0) == "UU") { // Absolute vx -= x; vy -= y; } Standard_Real length = Sqrt(vx * vx + vy * vy); if ( (4.0 - (vx * vx + vy * vy) / (radius * radius) >= 0.0 ) && (length > Precision::Confusion()) ) { Standard_Real c = 0.5 * Sqrt(4.0 - (vx * vx + vy * vy) / (radius * radius)); // Cosine of alpha = arc angle / 2 , alpha in [0,Pi/2] angle = 2.0 * acos(c); // angle in [0,Pi] if ( reversed == 2 ) angle = angle - 2 * PI; dx = 0.5 * ( vy * 1.0/radius + vx * Sqrt(4.0 / (vx * vx + vy * vy) - 1.0 / (radius * radius))); dy = - 0.5 * ( vx * 1.0/radius - vy * Sqrt(4.0 / (vx * vx + vy * vy) - 1.0 / (radius * radius))); move = circle; } else{ move = none; } break; } case 'E': // Arc by end point and cEnter { if (n1 != 7) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); Standard_Real vxc = a(3).RealValue(); Standard_Real vyc = a(4).RealValue(); reversed = a(5).IntegerValue(); control_Tolerance = a(6).IntegerValue(); if (a(0) == "EE") { // Absolute vx -= x; vy -= y; vxc -= x; vyc -= y; } radius = Sqrt( vxc * vxc + vyc * vyc ); Standard_Real det = vx * vyc - vy * vxc; Standard_Real length = Sqrt(vx * vx + vy * vy); Standard_Real length2 = Sqrt((vx-vxc) * (vx-vxc) + (vy-vyc) * (vy-vyc)); Standard_Real length3 = Sqrt(vxc * vxc + vyc * vyc); Standard_Real error = Abs(length2 - radius); myError = error; if ( error > Precision::Confusion() ){ MESSAGE("Warning : The specified end point is not on the Arc, distance = "<<error); } if ( error > Precision::Confusion() && control_Tolerance == 1) // Don't create the arc if the end point move = none; // is too far from it else if ( (length > Precision::Confusion()) && (length2 > Precision::Confusion()) && (length3 > Precision::Confusion()) ) { Standard_Real c = ( radius * radius - (vx * vxc + vy * vyc) ) / ( radius * Sqrt((vx-vxc) * (vx-vxc) + (vy-vyc) * (vy-vyc)) ) ; // Cosine of arc angle angle = acos(c); // angle in [0,Pi] if ( reversed == 2 ) angle = angle - 2 * PI; if (det < 0) angle = -angle; dx = vyc / radius; dy = -vxc / radius; move = circle; } else { move = none; } break; } case 'I': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (a(0) == "IX") { if (Abs(dx) < Precision::Confusion()) { MESSAGE("profile : cannot intersect, arg "<<i-1); return; } length = (length - x) / dx; } else if (a(0) == "IY") { if (Abs(dy) < Precision::Confusion()) { MESSAGE("profile : cannot intersect, arg "<<i-1); return; } length = (length - y) / dy; } if (Abs(length) > Precision::Confusion()) move = line; else move = none; break; } case 'W': { if (a(0) == "WW") close = Standard_True; else if(a(0) == "WF") { close = Standard_True; face = Standard_True; } i = n - 1; break; } default: { MESSAGE("profile : unknown code " << a(i)); return; } } again : switch (move) { case line : { if (length < 0) { length = -length; dx = -dx; dy = -dy; } Handle(Geom2d_Line) l = new Geom2d_Line(gp_Pnt2d(x,y),gp_Dir2d(dx,dy)); BRepBuilderAPI_MakeEdge ME (GeomAPI::To3d(l,P),0,length); if (!ME.IsDone()) return; MW.Add(ME); x += length*dx; y += length*dy; break; } case circle : { Standard_Boolean sense = Standard_True; if (radius < 0) { radius = -radius; sense = !sense; dx = -dx; dy = -dy; } gp_Ax2d ax(gp_Pnt2d(x-radius*dy,y+radius*dx),gp_Dir2d(dy,-dx)); if (angle < 0) { angle = -angle; sense = !sense; } Handle(Geom2d_Circle) c = new Geom2d_Circle(ax,radius,sense); BRepBuilderAPI_MakeEdge ME (GeomAPI::To3d(c,P),0,angle); if (!ME.IsDone()) return; MW.Add(ME); gp_Pnt2d p; gp_Vec2d v; c->D1(angle,p,v); x = p.X(); y = p.Y(); dx = v.X() / radius; dy = v.Y() / radius; break; } case point: { MP = BRepBuilderAPI_MakeVertex(gp_Pnt(x, y, 0.0)); break; } case none: { i = n - 1; break; } } // update first first = stayfirst; stayfirst = Standard_False; if(!(dx == 0 && dy == 0)) myLastDir.SetCoord(dx, dy, 0.0); else return; myLastPoint.SetX(x); myLastPoint.SetY(y); // next segment.... i++; if ((i == n) && close) { // the closing segment dx = x0 - x; dy = y0 - y; length = Sqrt(dx * dx + dy * dy); move = line; if (length > Precision::Confusion()) { dx = dx / length; dy = dy / length; goto again; } } } // get the result, face or wire if (move == none) { return; } else if (move == point) { S = MP; } else if (face) { if (!MW.IsDone()) { return; } BRepBuilderAPI_MakeFace MF (P, MW.Wire()); if (!MF.IsDone()) { return; } S = MF; } else { if (!MW.IsDone()) { return; } S = MW; } if(!TheLocation.IsIdentity()) S.Move(TheLocation); myShape = S; myOK = true; return; badargs : MESSAGE("profile : bad number of arguments"); return; }
App::DocumentObjectExecReturn *Groove::execute(void) { // Validate parameters double angle = Angle.getValue(); if (angle < Precision::Confusion()) return new App::DocumentObjectExecReturn("Angle of groove too small"); if (angle > 360.0) return new App::DocumentObjectExecReturn("Angle of groove too large"); angle = Base::toRadians<double>(angle); // Reverse angle if selected if (Reversed.getValue() && !Midplane.getValue()) angle *= (-1.0); Part::Part2DObject* sketch = 0; std::vector<TopoDS_Wire> wires; TopoDS_Shape support; try { sketch = getVerifiedSketch(); wires = getSketchWires(); support = getSupportShape(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } // get the Sketch plane Base::Placement SketchPlm = sketch->Placement.getValue(); // get reference axis App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue(); const std::vector<std::string> &subReferenceAxis = ReferenceAxis.getSubValues(); if (pcReferenceAxis && pcReferenceAxis == sketch) { bool hasValidAxis=false; Base::Axis axis; if (subReferenceAxis[0] == "V_Axis") { hasValidAxis = true; axis = sketch->getAxis(Part::Part2DObject::V_Axis); } else if (subReferenceAxis[0] == "H_Axis") { hasValidAxis = true; axis = sketch->getAxis(Part::Part2DObject::H_Axis); } else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") { int AxId = std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); if (AxId >= 0 && AxId < sketch->getAxisCount()) { hasValidAxis = true; axis = sketch->getAxis(AxId); } } if (hasValidAxis) { axis *= SketchPlm; Base::Vector3d base=axis.getBase(); Base::Vector3d dir=axis.getDirection(); Base.setValue(base.x,base.y,base.z); Axis.setValue(dir.x,dir.y,dir.z); } } // get revolve axis Base::Vector3f b = Base.getValue(); gp_Pnt pnt(b.x,b.y,b.z); Base::Vector3f v = Axis.getValue(); gp_Dir dir(v.x,v.y,v.z); try { TopoDS_Shape sketchshape = makeFace(wires); if (sketchshape.IsNull()) return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); // Rotate the face by half the angle to get Groove symmetric to sketch plane if (Midplane.getValue()) { gp_Trsf mov; mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians<double>(Angle.getValue()) * (-1.0) / 2.0); TopLoc_Location loc(mov); sketchshape.Move(loc); } this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); pnt.Transform(invObjLoc.Transformation()); dir.Transform(invObjLoc.Transformation()); support.Move(invObjLoc); sketchshape.Move(invObjLoc); // Check distance between sketchshape and axis - to avoid failures and crashes if (checkLineCrossesFace(gp_Lin(pnt, dir), TopoDS::Face(sketchshape))) return new App::DocumentObjectExecReturn("Revolve axis intersects the sketch"); // revolve the face to a solid BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); if (RevolMaker.IsDone()) { TopoDS_Shape result = RevolMaker.Shape(); // set the subtractive shape property for later usage in e.g. pattern this->SubShape.setValue(result); // cut out groove to get one result object BRepAlgoAPI_Cut mkCut(support, result); // Let's check if the fusion has been successful if (!mkCut.IsDone()) throw Base::Exception("Cut out of support failed"); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(mkCut.Shape()); if (solRes.IsNull()) return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); this->Shape.setValue(solRes); } else return new App::DocumentObjectExecReturn("Could not revolve the sketch!"); return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face") return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } }
App::DocumentObjectExecReturn *Revolution::execute(void) { // Validate parameters double angle = Angle.getValue(); if (angle < Precision::Confusion()) return new App::DocumentObjectExecReturn("Angle of revolution too small"); if (angle > 360.0) return new App::DocumentObjectExecReturn("Angle of revolution too large"); angle = Base::toRadians<double>(angle); // Reverse angle if selected if (Reversed.getValue() && !Midplane.getValue()) angle *= (-1.0); std::vector<TopoDS_Wire> wires; try { wires = getSketchWires(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } TopoDS_Shape support; try { support = getSupportShape(); } catch (const Base::Exception&) { // ignore, because support isn't mandatory support = TopoDS_Shape(); } // update Axis from ReferenceAxis updateAxis(); // get revolve axis Base::Vector3d b = Base.getValue(); gp_Pnt pnt(b.x,b.y,b.z); Base::Vector3d v = Axis.getValue(); gp_Dir dir(v.x,v.y,v.z); try { TopoDS_Shape sketchshape = makeFace(wires); if (sketchshape.IsNull()) return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); // Rotate the face by half the angle to get Revolution symmetric to sketch plane if (Midplane.getValue()) { gp_Trsf mov; mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians<double>(Angle.getValue()) * (-1.0) / 2.0); TopLoc_Location loc(mov); sketchshape.Move(loc); } this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); pnt.Transform(invObjLoc.Transformation()); dir.Transform(invObjLoc.Transformation()); support.Move(invObjLoc); sketchshape.Move(invObjLoc); // Check distance between sketchshape and axis - to avoid failures and crashes if (checkLineCrossesFace(gp_Lin(pnt, dir), TopoDS::Face(sketchshape))) return new App::DocumentObjectExecReturn("Revolve axis intersects the sketch"); // revolve the face to a solid BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); if (RevolMaker.IsDone()) { TopoDS_Shape result = RevolMaker.Shape(); result = refineShapeIfActive(result); // set the additive shape property for later usage in e.g. pattern this->AddShape.setValue(result); // if the sketch has a support fuse them to get one result object (PAD!) if (!support.IsNull()) { // Let's call algorithm computing a fuse operation: BRepAlgoAPI_Fuse mkFuse(support, result); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) throw Base::Exception("Fusion with support failed"); result = mkFuse.Shape(); result = refineShapeIfActive(result); } this->Shape.setValue(result); } else return new App::DocumentObjectExecReturn("Could not revolve the sketch!"); return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face") return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } }
TopoShape Extrusion::extrudeShape(const TopoShape source, Extrusion::ExtrusionParameters params) { TopoDS_Shape result; gp_Vec vec = gp_Vec(params.dir).Multiplied(params.lengthFwd+params.lengthRev);//total vector of extrusion if (std::fabs(params.taperAngleFwd) >= Precision::Angular() || std::fabs(params.taperAngleRev) >= Precision::Angular() ) { //Tapered extrusion! #if defined(__GNUC__) && defined (FC_OS_LINUX) Base::SignalException se; #endif TopoDS_Shape myShape = source.getShape(); if (myShape.IsNull()) Standard_Failure::Raise("Cannot extrude empty shape"); // #0000910: Circles Extrude Only Surfaces, thus use BRepBuilderAPI_Copy myShape = BRepBuilderAPI_Copy(myShape).Shape(); std::list<TopoDS_Shape> drafts; makeDraft(params, myShape, drafts); if (drafts.empty()) { Standard_Failure::Raise("Drafting shape failed"); } else if (drafts.size() == 1) { result = drafts.front(); } else { TopoDS_Compound comp; BRep_Builder builder; builder.MakeCompound(comp); for (std::list<TopoDS_Shape>::iterator it = drafts.begin(); it != drafts.end(); ++it) builder.Add(comp, *it); result = comp; } } else { //Regular (non-tapered) extrusion! TopoDS_Shape myShape = source.getShape(); if (myShape.IsNull()) Standard_Failure::Raise("Cannot extrude empty shape"); // #0000910: Circles Extrude Only Surfaces, thus use BRepBuilderAPI_Copy myShape = BRepBuilderAPI_Copy(myShape).Shape(); //apply reverse part of extrusion by shifting the source shape if (fabs(params.lengthRev)>Precision::Confusion() ){ gp_Trsf mov; mov.SetTranslation(gp_Vec(params.dir)*(-params.lengthRev)); TopLoc_Location loc(mov); myShape.Move(loc); } //make faces from wires if (params.solid) { //test if we need to make faces from wires. If there are faces - we don't. TopExp_Explorer xp(myShape, TopAbs_FACE); if (xp.More()){ //source shape has faces. Just extrude as-is. } else { std::unique_ptr<FaceMaker> mkFace = FaceMaker::ConstructFromType(params.faceMakerClass.c_str()); if (myShape.ShapeType() == TopAbs_COMPOUND) mkFace->useCompound(TopoDS::Compound(myShape)); else mkFace->addShape(myShape); mkFace->Build(); myShape = mkFace->Shape(); } } //extrude! BRepPrimAPI_MakePrism mkPrism(myShape, vec); result = mkPrism.Shape(); } if (result.IsNull()) throw Base::Exception("Result of extrusion is null shape."); return TopoShape(result); }
App::DocumentObjectExecReturn *Pocket::execute(void) { // Handle legacy features, these typically have Type set to 3 (previously NULL, now UpToFace), // empty FaceName (because it didn't exist) and a value for Length if (std::string(Type.getValueAsString()) == "UpToFace" && (UpToFace.getValue() == NULL && Length.getValue() > Precision::Confusion())) Type.setValue("Length"); // Validate parameters double L = Length.getValue(); if ((std::string(Type.getValueAsString()) == "Length") && (L < Precision::Confusion())) return new App::DocumentObjectExecReturn("Pocket: Length of pocket too small"); Part::Part2DObject* sketch = 0; std::vector<TopoDS_Wire> wires; TopoDS_Shape support; try { sketch = getVerifiedSketch(); wires = getSketchWires(); support = getSupportShape(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } // get the Sketch plane Base::Placement SketchPos = sketch->Placement.getValue(); Base::Rotation SketchOrientation = SketchPos.getRotation(); Base::Vector3d SketchVector(0,0,1); SketchOrientation.multVec(SketchVector,SketchVector); // turn around for pockets SketchVector *= -1; this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); try { support.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); dir.Transform(invObjLoc.Transformation()); TopoDS_Shape sketchshape = makeFace(wires); if (sketchshape.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Creating a face from sketch failed"); sketchshape.Move(invObjLoc); std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToFace") { TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); // Find a valid face to extrude up to TopoDS_Face upToFace; if (method == "UpToFace") { getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } getUpToFace(upToFace, support, supportface, sketchshape, method, dir); // Special treatment because often the created stand-alone prism is invalid (empty) because // BRepFeat_MakePrism(..., 2, 1) is buggy BRepFeat_MakePrism PrismMaker; PrismMaker.Init(support, sketchshape, supportface, dir, 0, 1); PrismMaker.Perform(upToFace); if (!PrismMaker.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not extrude the sketch!"); TopoDS_Shape prism = PrismMaker.Shape(); prism = refineShapeIfActive(prism); // And the really expensive way to get the SubShape... BRepAlgoAPI_Cut mkCut(support, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not get SubShape!"); // FIXME: In some cases this affects the Shape property: It is set to the same shape as the SubShape!!!! TopoDS_Shape result = refineShapeIfActive(mkCut.Shape()); this->SubShape.setValue(result); this->Shape.setValue(prism); } else { TopoDS_Shape prism; generatePrism(prism, sketchshape, method, dir, L, 0.0, Midplane.getValue(), Reversed.getValue()); if (prism.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Resulting shape is empty"); // set the subtractive shape property for later usage in e.g. pattern prism = refineShapeIfActive(prism); this->SubShape.setValue(prism); // Cut the SubShape out of the support BRepAlgoAPI_Cut mkCut(support, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Cut out of support failed"); TopoDS_Shape result = mkCut.Shape(); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(result); if (solRes.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Resulting shape is not a solid"); solRes = refineShapeIfActive(solRes); remapSupportShape(solRes); this->Shape.setValue(solRes); } return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face" && (std::string(Type.getValueAsString()) == "UpToFirst" || std::string(Type.getValueAsString()) == "UpToFace")) return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed " "for making a pocket up to a face."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } }
App::DocumentObjectExecReturn *Revolution::execute(void) { App::DocumentObject* link = Sketch.getValue(); if (!link) return new App::DocumentObjectExecReturn("No sketch linked"); if (!link->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) return new App::DocumentObjectExecReturn("Linked object is not a Sketch or Part2DObject"); Part::Part2DObject* pcSketch=static_cast<Part::Part2DObject*>(link); TopoDS_Shape shape = pcSketch->Shape.getShape()._Shape; if (shape.IsNull()) return new App::DocumentObjectExecReturn("Linked shape object is empty"); // this is a workaround for an obscure OCC bug which leads to empty tessellations // for some faces. Making an explicit copy of the linked shape seems to fix it. // The error only happens when re-computing the shape. if (!this->Shape.getValue().IsNull()) { BRepBuilderAPI_Copy copy(shape); shape = copy.Shape(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Linked shape object is empty"); } TopExp_Explorer ex; std::vector<TopoDS_Wire> wires; for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { wires.push_back(TopoDS::Wire(ex.Current())); } if (wires.empty()) // there can be several wires return new App::DocumentObjectExecReturn("Linked shape object is not a wire"); // get the Sketch plane Base::Placement SketchPlm = pcSketch->Placement.getValue(); // get reference axis App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue(); const std::vector<std::string> &subReferenceAxis = ReferenceAxis.getSubValues(); if (pcReferenceAxis && pcReferenceAxis == pcSketch) { bool hasValidAxis=false; Base::Axis axis; if (subReferenceAxis[0] == "V_Axis") { hasValidAxis = true; axis = pcSketch->getAxis(Part::Part2DObject::V_Axis); } else if (subReferenceAxis[0] == "H_Axis") { hasValidAxis = true; axis = pcSketch->getAxis(Part::Part2DObject::H_Axis); } else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") { int AxId = std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); if (AxId >= 0 && AxId < pcSketch->getAxisCount()) { hasValidAxis = true; axis = pcSketch->getAxis(AxId); } } if (hasValidAxis) { axis *= SketchPlm; Base::Vector3d base=axis.getBase(); Base::Vector3d dir=axis.getDirection(); Base.setValue(base.x,base.y,base.z); Axis.setValue(dir.x,dir.y,dir.z); } } // get revolve axis Base::Vector3f b = Base.getValue(); gp_Pnt pnt(b.x,b.y,b.z); Base::Vector3f v = Axis.getValue(); gp_Dir dir(v.x,v.y,v.z); // get the support of the Sketch if any App::DocumentObject* pcSupport = pcSketch->Support.getValue(); Part::Feature *SupportObject = 0; if (pcSupport && pcSupport->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) SupportObject = static_cast<Part::Feature*>(pcSupport); TopoDS_Shape aFace = makeFace(wires); if (aFace.IsNull()) return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); // Rotate the face by half the angle to get revolution symmetric to sketch plane if (Midplane.getValue()) { gp_Trsf mov; mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians<double>(Angle.getValue()) * (-1.0) / 2.0); TopLoc_Location loc(mov); aFace.Move(loc); } this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); pnt.Transform(invObjLoc.Transformation()); dir.Transform(invObjLoc.Transformation()); // Reverse angle if selected double angle = Base::toRadians<double>(Angle.getValue()); if (Reversed.getValue() && !Midplane.getValue()) angle *= (-1.0); try { // revolve the face to a solid BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), angle); if (RevolMaker.IsDone()) { TopoDS_Shape result = RevolMaker.Shape(); // if the sketch has a support fuse them to get one result object (PAD!) if (SupportObject) { const TopoDS_Shape& support = SupportObject->Shape.getValue(); if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) { // set the additive shape property for later usage in e.g. pattern this->AddShape.setValue(result); // Let's call algorithm computing a fuse operation: BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) throw Base::Exception("Fusion with support failed"); result = mkFuse.Shape(); } } this->Shape.setValue(result); } else return new App::DocumentObjectExecReturn("Could not revolve the sketch!"); return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } }
App::DocumentObjectExecReturn *Pocket::execute(void) { // Handle legacy features, these typically have Type set to 3 (previously NULL, now UpToFace), // empty FaceName (because it didn't exist) and a value for Length if (std::string(Type.getValueAsString()) == "UpToFace" && (UpToFace.getValue() == NULL && Length.getValue() > Precision::Confusion())) Type.setValue("Length"); // Validate parameters double L = Length.getValue(); if ((std::string(Type.getValueAsString()) == "Length") && (L < Precision::Confusion())) return new App::DocumentObjectExecReturn("Pocket: Length of pocket too small"); Part::Feature* obj = 0; TopoDS_Face face; try { obj = getVerifiedObject(); face = getVerifiedFace(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } // if the Base property has a valid shape, fuse the prism into it TopoDS_Shape base; try { base = getBaseShape(); } catch (const Base::Exception&) { return new App::DocumentObjectExecReturn("No sketch support and no base shape: Please tell me where to remove the material of the pocket!"); } // get the Sketch plane Base::Placement SketchPos = obj->Placement.getValue(); Base::Vector3d SketchVector = getProfileNormal(); // turn around for pockets SketchVector *= -1; try { this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); base.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); dir.Transform(invObjLoc.Transformation()); if (face.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Creating a face from sketch failed"); face.Move(invObjLoc); std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToFace") { if (base.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Extruding up to a face is only possible if the sketch is located on a face"); // Note: This will return an unlimited planar face if support is a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); if (Reversed.getValue()) dir.Reverse(); // Find a valid face or datum plane to extrude up to TopoDS_Face upToFace; if (method == "UpToFace") { getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } getUpToFace(upToFace, base, supportface, face, method, dir, Offset.getValue()); // BRepFeat_MakePrism(..., 2, 1) in combination with PerForm(upToFace) is buggy when the // prism that is being created is contained completely inside the base solid // In this case the resulting shape is empty. This is not a problem for the Pad or Pocket itself // but it leads to an invalid SubShape // The bug only occurs when the upToFace is limited (by a wire), not for unlimited upToFace. But // other problems occur with unlimited concave upToFace so it is not an option to always unlimit upToFace // Check supportface for limits, otherwise Perform() throws an exception TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) supportface = TopoDS_Face(); BRepFeat_MakePrism PrismMaker; PrismMaker.Init(base, face, supportface, dir, 0, 1); PrismMaker.Perform(upToFace); if (!PrismMaker.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not extrude the sketch!"); TopoDS_Shape prism = PrismMaker.Shape(); // And the really expensive way to get the SubShape... BRepAlgoAPI_Cut mkCut(base, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not get SubShape!"); // FIXME: In some cases this affects the Shape property: It is set to the same shape as the SubShape!!!! TopoDS_Shape result = refineShapeIfActive(mkCut.Shape()); this->AddSubShape.setValue(result); this->Shape.setValue(prism); } else { TopoDS_Shape prism; generatePrism(prism, face, method, dir, L, 0.0, Midplane.getValue(), Reversed.getValue()); if (prism.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Resulting shape is empty"); // set the subtractive shape property for later usage in e.g. pattern prism = refineShapeIfActive(prism); this->AddSubShape.setValue(prism); // Cut the SubShape out of the base feature BRepAlgoAPI_Cut mkCut(base, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Cut out of base feature failed"); TopoDS_Shape result = mkCut.Shape(); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(result); if (solRes.IsNull()) return new App::DocumentObjectExecReturn("Pocket: Resulting shape is not a solid"); solRes = refineShapeIfActive(solRes); remapSupportShape(solRes); this->Shape.setValue(solRes); } return App::DocumentObject::StdReturn; } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face" && (std::string(Type.getValueAsString()) == "UpToFirst" || std::string(Type.getValueAsString()) == "UpToFace")) return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed " "for making a pocket up to a face."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); } catch (Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } }