TopoNaming/Part: cleanups and tests
This commit is contained in:
@@ -115,6 +115,26 @@ App::DocumentObjectExecReturn *RuledSurface::execute()
|
||||
{
|
||||
try {
|
||||
#ifdef FC_USE_TNP_FIX
|
||||
std::vector<TopoShape> shapes;
|
||||
std::array<App::PropertyLinkSub*,2> 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<TopoShape> shapes;
|
||||
std::array<App::PropertyLinkSub*,2> 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) {
|
||||
|
||||
@@ -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<TopoShape> &source, int orientation=0, const char *op=nullptr);
|
||||
TopoShape &makeElementRuledSurface(const std::vector<TopoShape> &source, int orientation=0, const char *op=nullptr);
|
||||
|
||||
/** Core function to generate mapped element names from shape history
|
||||
*
|
||||
|
||||
@@ -27,9 +27,16 @@
|
||||
#ifndef _PreComp_
|
||||
#include <cmath>
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepAdaptor_CompCurve.hxx>
|
||||
# if OCC_VERSION_HEX < 0x070600
|
||||
# include <BRepAdaptor_HCurve.hxx>
|
||||
# include <BRepAdaptor_HCompCurve.hxx>
|
||||
# endif
|
||||
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
#include <BRepFill.hxx>
|
||||
#include <BRepFill_Generator.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
@@ -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<TopoShape> &shapes,
|
||||
int orientation, const char *op)
|
||||
TopoShape& TopoShape::makeElementRuledSurface(const std::vector<TopoShape>& 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<TopoShape> 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<TopoShape> &shapes,
|
||||
|
||||
TopoShape res(ruledShape.Located(TopLoc_Location()));
|
||||
std::vector<TopoShape> 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<TopoShape>& shapes,
|
||||
|
||||
@@ -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<TopoShape> subEdges = cube1TS.getSubTopoShapes(TopAbs_EDGE);
|
||||
std::vector<TopoShape> 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<TopoShape> subWires = cube1TS.getSubTopoShapes(TopAbs_WIRE);
|
||||
std::vector<TopoShape> 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)
|
||||
|
||||
Reference in New Issue
Block a user