diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index cdba29b292..6085ec5ae9 100644 --- a/src/Mod/Part/App/PartFeatures.cpp +++ b/src/Mod/Part/App/PartFeatures.cpp @@ -115,6 +115,26 @@ App::DocumentObjectExecReturn *RuledSurface::execute() { try { #ifdef FC_USE_TNP_FIX + std::vector shapes; + std::array links = {&Curve1,&Curve2}; + for(auto link : links) { + const auto &subs = link->getSubValues(); + if(subs.empty()) + shapes.push_back(getTopoShape(link->getValue())); + else if(subs.size()!=1) + return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); + else + shapes.push_back(getTopoShape(link->getValue(), + subs.front().c_str(),true)); + if(shapes.back().isNull()) + return new App::DocumentObjectExecReturn("Invalid link."); + } + TopoShape res(0);//, getDocument()->getStringHasher()); + res.makeElementRuledSurface(shapes, Orientation.getValue()); + this->Shape.setValue(res); + return Part::Feature::execute(); + +#else App::DocumentObjectExecReturn* ret; // get the first input shape @@ -232,25 +252,6 @@ App::DocumentObjectExecReturn *RuledSurface::execute() this->Shape.setValue(ruledShape); return App::DocumentObject::StdReturn; -#else - std::vector shapes; - std::array links = {&Curve1,&Curve2}; - for(auto link : links) { - const auto &subs = link->getSubValues(); - if(subs.empty()) - shapes.push_back(getTopoShape(link->getValue())); - else if(subs.size()!=1) - return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); - else - shapes.push_back(getTopoShape(link->getValue(), - subs.front().c_str(),true)); - if(shapes.back().isNull()) - return new App::DocumentObjectExecReturn("Invalid link."); - } - TopoShape res(0, getDocument()->getStringHasher()); - res.makERuledSurface(shapes, Orientation.getValue()); - this->Shape.setValue(res); - return Part::Feature::execute(); #endif } catch (Standard_Failure& e) { diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 52d1374660..13803bf0b6 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -790,14 +790,7 @@ public: * * @param sources: the source shapes, each of which must contain either a * single edge or a single wire. - * @param orientation: - * @param isSolid: whether to make a solid - * @param isRuled: If true, then the faces generated between the edges of - * two consecutive section wires are ruled surfaces. If - * false, then they are smoothed out by approximation - * @param isClosed: If true, then the first section is duplicated to close - * the loft as the last section - * @param maxDegree: define the maximal U degree of the result surface + * @param orientation: A Qt::Orientation, where Qt::Horizontal is 1 and Qt::Vertical is 2. * @param op: optional string to be encoded into topo naming for indicating * the operation * @@ -806,7 +799,7 @@ public: * a self reference so that multiple operations can be carried out * for the same shape in the same line of code. */ - TopoShape &makERuledSurface(const std::vector &source, int orientation=0, const char *op=nullptr); + TopoShape &makeElementRuledSurface(const std::vector &source, int orientation=0, const char *op=nullptr); /** Core function to generate mapped element names from shape history * diff --git a/src/Mod/Part/App/TopoShapeExpansion.cpp b/src/Mod/Part/App/TopoShapeExpansion.cpp index 76ebe54daf..69d666ae3f 100644 --- a/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -27,9 +27,16 @@ #ifndef _PreComp_ #include +#include +#include +# if OCC_VERSION_HEX < 0x070600 +# include +# include +# endif #include #include +#include #include #include #include @@ -77,6 +84,12 @@ FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT +#if OCC_VERSION_HEX >= 0x070600 +using Adaptor3d_HCurve = Adaptor3d_Curve; +using BRepAdaptor_HCurve = BRepAdaptor_Curve; +using BRepAdaptor_HCompCurve = BRepAdaptor_CompCurve; +#endif + namespace Part { @@ -1653,79 +1666,88 @@ TopoShape TopoShape::getSubTopoShape(TopAbs_ShapeEnum type, int idx, bool silent return shapeMap.getTopoShape(*this, idx); } -TopoShape &TopoShape::makERuledSurface(const std::vector &shapes, - int orientation, const char *op) +TopoShape& TopoShape::makeElementRuledSurface(const std::vector& shapes, + int orientation, + const char* op) { - if(!op) + if (!op) { op = Part::OpCodes::RuledSurface; + } - if(shapes.size()!=2) - FC_THROWM(Base::CADKernelError,"Wrong number of input shape"); + if (shapes.size() != 2) { + FC_THROWM(Base::CADKernelError, "Wrong number of input shapes"); + } std::vector curves(2); - int i=0; - for(auto &s : shapes) { - if(s.isNull()) - HANDLE_NULL_INPUT; + int i = 0; + for (auto& s : shapes) { + if (s.isNull()) { + FC_THROWM(NullShapeException, "Null input shape"); + } auto type = s.shapeType(); - if(type == TopAbs_WIRE || type == TopAbs_EDGE) { + if (type == TopAbs_WIRE || type == TopAbs_EDGE) { curves[i++] = s; continue; } - auto count = s.countSubShapes(TopAbs_WIRE); - if(count>1) - FC_THROWM(Base::CADKernelError,"Input shape has more than one wire"); - if(count==1) { - curves[i++] = s.getSubTopoShape(TopAbs_WIRE,1); + auto countOfWires = s.countSubShapes(TopAbs_WIRE); + if (countOfWires > 1) { + FC_THROWM(Base::CADKernelError, "Input shape has more than one wire"); + } + if (countOfWires == 1) { + curves[i++] = s.getSubTopoShape(TopAbs_WIRE, 1); continue; } - count = s.countSubShapes(TopAbs_EDGE); - if(count==0) - FC_THROWM(Base::CADKernelError,"Input shape has no edge"); - if(count == 1) { - curves[i++] = s.getSubTopoShape(TopAbs_EDGE,1); + auto countOfEdges = s.countSubShapes(TopAbs_EDGE); + if (countOfEdges == 0) { + FC_THROWM(Base::CADKernelError, "Input shape has no edge"); + } + if (countOfEdges == 1) { + curves[i++] = s.getSubTopoShape(TopAbs_EDGE, 1); continue; } - curves[i] = s.makEWires(); - if(curves[i].isNull()) - HANDLE_NULL_INPUT; - if(curves[i].shapeType()!=TopAbs_WIRE) - FC_THROWM(Base::CADKernelError,"Input shape forms more than one wire"); + curves[i] = s.makeElementWires(); + if (curves[i].isNull()) { + FC_THROWM(NullShapeException, "Null input shape"); + } + if (curves[i].shapeType() != TopAbs_WIRE) { + FC_THROWM(Base::CADKernelError, "Input shape forms more than one wire"); + } ++i; } - if(curves[0].shapeType()!=curves[1].shapeType()) { - for(auto &curve : curves) { - if(curve.shapeType() == TopAbs_EDGE) - curve = curve.makEWires(); + if (curves[0].shapeType() != curves[1].shapeType()) { + for (auto& curve : curves) { + if (curve.shapeType() == TopAbs_EDGE) { + curve = curve.makeElementWires(); + } } } - auto &S1 = curves[0]; - auto &S2 = curves[1]; - bool isWire = S1.shapeType()==TopAbs_WIRE; + auto& S1 = curves[0]; + auto& S2 = curves[1]; + bool isWire = S1.shapeType() == TopAbs_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 copy the sub-shape - S1 = S1.makECopy(); - S2 = S2.makECopy(); + S1 = S1.makeElementCopy(); + S2 = S2.makeElementCopy(); if (orientation == 0) { // Automatic Handle(Adaptor3d_HCurve) a1; Handle(Adaptor3d_HCurve) a2; if (!isWire) { - BRepAdaptor_Curve adapt1(TopoDS::Edge(S1.getShape())); - BRepAdaptor_Curve adapt2(TopoDS::Edge(S2.getShape())); + BRepAdaptor_HCurve adapt1(TopoDS::Edge(S1.getShape())); + BRepAdaptor_HCurve adapt2(TopoDS::Edge(S2.getShape())); a1 = new BRepAdaptor_HCurve(adapt1); a2 = new BRepAdaptor_HCurve(adapt2); } else { - BRepAdaptor_CompCurve adapt1(TopoDS::Wire(S1.getShape())); - BRepAdaptor_CompCurve adapt2(TopoDS::Wire(S2.getShape())); + BRepAdaptor_HCompCurve adapt1(TopoDS::Wire(S1.getShape())); + BRepAdaptor_HCompCurve adapt2(TopoDS::Wire(S2.getShape())); a1 = new BRepAdaptor_HCompCurve(adapt1); a2 = new BRepAdaptor_HCompCurve(adapt2); } @@ -1780,17 +1802,17 @@ TopoShape &TopoShape::makERuledSurface(const std::vector &shapes, TopoShape res(ruledShape.Located(TopLoc_Location())); std::vector edges; - for (const auto &c : curves) { - for (const auto &e : c.getSubTopoShapes(TopAbs_EDGE)) { - auto found = res.searchSubShape(e); + for (const auto& c : curves) { + for (const auto& e : c.getSubTopoShapes(TopAbs_EDGE)) { + auto found = res.findSubShapesWithSharedVertex(e); if (found.size() > 0) { found.front().resetElementMap(e.elementMap()); edges.push_back(found.front()); } } } - // Use empty mapper and let makEShape name the created surface with lower elements. - return makESHAPE(res.getShape(),Mapper(),edges,op); + // Use empty mapper and let makeShapeWithElementMap name the created surface with lower elements. + return makeShapeWithElementMap(res.getShape(), Mapper(), edges, op); } TopoShape& TopoShape::makeElementCompound(const std::vector& shapes, diff --git a/tests/src/Mod/Part/App/TopoShapeExpansion.cpp b/tests/src/Mod/Part/App/TopoShapeExpansion.cpp index 25f81a5b6a..aa86b7dab7 100644 --- a/tests/src/Mod/Part/App/TopoShapeExpansion.cpp +++ b/tests/src/Mod/Part/App/TopoShapeExpansion.cpp @@ -1157,5 +1157,32 @@ TEST_F(TopoShapeExpansionTest, makeElementLinearizeFace) EXPECT_EQ(surface2.GetType(), GeomAbs_Plane); } +TEST_F(TopoShapeExpansionTest, makeElementRuledSurfaceEdges) +{ + // Arrange + auto [cube1, cube2] = CreateTwoCubes(); + TopoShape cube1TS {cube1, 1L}; + std::vector subEdges = cube1TS.getSubTopoShapes(TopAbs_EDGE); + std::vector shapes2 = {subEdges[0], subEdges[1]}; + // Act + TopoShape result2 = cube1TS.makeElementRuledSurface(shapes2, 0); // TODO: direction as enum? + // Assert + EXPECT_EQ(result2.countSubElements("Wire"), 1); + EXPECT_FLOAT_EQ(getArea(result2.getShape()), 0.32953611); +} + +TEST_F(TopoShapeExpansionTest, makeElementRuledSurfaceWires) +{ + // Arrange + auto [cube1, cube2] = CreateTwoCubes(); + TopoShape cube1TS {cube1, 1L}; + std::vector subWires = cube1TS.getSubTopoShapes(TopAbs_WIRE); + std::vector shapes = {subWires[0], subWires[1]}; + // Act + TopoShape result = cube1TS.makeElementRuledSurface(shapes, 0); // TODO: direction as enum? + // Assert + EXPECT_EQ(result.countSubElements("Wire"), 4); + EXPECT_FLOAT_EQ(getArea(result.getShape()), 2.023056); +} // NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)