Toponaming/Part: Fix all getBaseTopoShape calls. Tests and missing code.

This commit is contained in:
bgbsww
2024-04-25 16:54:14 -04:00
committed by Chris Hennes
parent bff1efd665
commit fa8f29aed4
19 changed files with 791 additions and 49 deletions

View File

@@ -43,6 +43,7 @@
#include <Mod/Part/App/FaceMakerCheese.h>
#include "FeatureLoft.h"
#include "Mod/Part/App/TopoShapeOpCode.h"
using namespace PartDesign;
@@ -69,6 +70,7 @@ short Loft::mustExecute() const
return ProfileBased::mustExecute();
}
#ifndef FC_USE_TNP_FIX
App::DocumentObjectExecReturn *Loft::execute()
{
auto getSectionShape =
@@ -330,7 +332,215 @@ App::DocumentObjectExecReturn *Loft::execute()
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Loft: A fatal error occurred when making the loft"));
}
}
#else
std::vector<Part::TopoShape>
Loft::getSectionShape(const char *name,
App::DocumentObject *obj,
const std::vector<std::string> &subs,
size_t expected_size)
{
std::vector<TopoShape> shapes;
if (subs.empty() || std::find(subs.begin(), subs.end(), std::string()) != subs.end()) {
shapes.push_back(Part::Feature::getTopoShape(obj));
if (shapes.back().isNull())
FC_THROWM(Part::NullShapeException, "Failed to get shape of "
<< name << " " << App::SubObjectT(obj, "").getSubObjectFullName(obj->getDocument()->getName()));
} else {
for (const auto &sub : subs) {
shapes.push_back(Part::Feature::getTopoShape(obj, sub.c_str(), /*needSubElement*/true));
if (shapes.back().isNull())
FC_THROWM(Part::NullShapeException, "Failed to get shape of " << name << " "
<< App::SubObjectT(obj, sub.c_str()).getSubObjectFullName(obj->getDocument()->getName()));
}
}
auto compound = TopoShape().makeElementCompound(shapes, "", TopoShape::SingleShapeCompoundCreationPolicy::returnShape);
auto wires = compound.getSubTopoShapes(TopAbs_WIRE);
auto edges = compound.getSubTopoShapes(TopAbs_EDGE, TopAbs_WIRE); // get free edges and make wires from it
if (edges.size()) {
auto extra = TopoShape().makeElementWires(edges).getSubTopoShapes(TopAbs_WIRE);
wires.insert(wires.end(), extra.begin(), extra.end());
}
const char *msg = "Sections need to have the same amount of wires or vertices as the base section";
if (!wires.empty()) {
if (expected_size && expected_size != wires.size())
FC_THROWM(Base::CADKernelError, msg);
return wires;
}
auto vertices = compound.getSubTopoShapes(TopAbs_VERTEX);
if (vertices.empty())
FC_THROWM(Base::CADKernelError, "Invalid " << name << " shape, expecting either wires or vertices");
if (expected_size && expected_size != vertices.size())
FC_THROWM(Base::CADKernelError, msg);
return vertices;
}
App::DocumentObjectExecReturn *Loft::execute(void)
{
std::vector<TopoShape> wires;
try {
wires = getSectionShape("Profile", Profile.getValue(), Profile.getSubValues());
} catch (const Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());
}
// if the Base property has a valid shape, fuse the pipe into it
TopoShape base;
try {
base = getBaseTopoShape();
} catch (const Base::Exception&) {
}
try {
//setup the location
this->positionByPrevious();
auto invObjLoc = this->getLocation().Inverted();
if(!base.isNull())
base.move(invObjLoc);
//build up multisections
auto multisections = Sections.getSubListValues();
if(multisections.empty())
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Loft: At least one section is needed"));
std::vector<std::vector<TopoShape>> wiresections;
wiresections.reserve(wires.size());
for(auto& wire : wires)
wiresections.emplace_back(1, wire);
for (const auto &subSet : multisections) {
int i=0;
for (const auto &s : getSectionShape("Section", subSet.first, subSet.second, wiresections.size()))
wiresections[i++].push_back(s);
}
TopoShape result(0);
std::vector<TopoShape> shapes;
// if (SplitProfile.getValue()) {
// for (auto &wires : wiresections) {
// for(auto& wire : wires)
// wire.move(invObjLoc);
// shapes.push_back(TopoShape(0).makeElementLoft(
// wires, Part::IsSolid::solid, Ruled.getValue(), Closed.getValue()));
// }
// } else {
//build all shells
std::vector<TopoShape> shells;
for (auto &wires : wiresections) {
for(auto& wire : wires)
wire.move(invObjLoc);
shells.push_back(TopoShape(0).makeElementLoft(
wires, Part::IsSolid::notSolid, Ruled.getValue()? Part::IsRuled::ruled : Part::IsRuled::notRuled, Closed.getValue() ? Part::IsClosed::closed : Part::IsClosed::notClosed));
// }
//build the top and bottom face, sew the shell and build the final solid
TopoShape front;
if (wiresections[0].front().shapeType() != TopAbs_VERTEX) {
front = getVerifiedFace();
if (front.isNull())
return new App::DocumentObjectExecReturn(
QT_TRANSLATE_NOOP("Exception", "Loft: Creating a face from sketch failed"));
front.move(invObjLoc);
}
TopoShape back;
if (wiresections[0].back().shapeType() != TopAbs_VERTEX) {
std::vector<TopoShape> backwires;
for(auto& wires : wiresections)
backwires.push_back(wires.back());
back = TopoShape(0).makeElementFace(backwires);
}
if (!front.isNull() || !back.isNull()) {
BRepBuilderAPI_Sewing sewer;
sewer.SetTolerance(Precision::Confusion());
if (!front.isNull())
sewer.Add(front.getShape());
if (!back.isNull())
sewer.Add(back.getShape());
for(auto& s : shells)
sewer.Add(s.getShape());
sewer.Perform();
if (!front.isNull())
shells.push_back(front);
if (!back.isNull())
shells.push_back(back);
// result = result.makeElementShape(sewer,shells);
result = result.makeShapeWithElementMap(sewer.SewedShape(), Part::MapperSewing(sewer), shells, Part::OpCodes::Sewing);
}
if(!result.countSubShapes(TopAbs_SHELL))
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Loft: Failed to create shell"));
shapes = result.getSubTopoShapes(TopAbs_SHELL);
}
for (auto &s : shapes) {
//build the solid
s = s.makeElementSolid();
BRepClass3d_SolidClassifier SC(s.getShape());
SC.PerformInfinitePoint(Precision::Confusion());
if ( SC.State() == TopAbs_IN)
s.setShape(s.getShape().Reversed(),false);
}
AddSubShape.setValue(result.makeElementCompound(shapes, nullptr, Part::TopoShape::SingleShapeCompoundCreationPolicy::returnShape));
if (shapes.size() > 1)
result.makeElementFuse(shapes);
else
result = shapes.front();
if(base.isNull()) {
Shape.setValue(getSolid(result));
return App::DocumentObject::StdReturn;
}
result.Tag = -getID();
TopoShape boolOp(0,getDocument()->getStringHasher());
const char *maker;
switch(getAddSubType()) {
case Additive:
maker = Part::OpCodes::Fuse;
break;
case Subtractive:
maker = Part::OpCodes::Cut;
break;
// case Intersecting:
// maker = Part::OpCodes::Common;
// break;
default:
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Unknown operation type"));
}
try {
boolOp.makeElementBoolean(maker, {base,result});
}
catch(Standard_Failure &e) {
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Failed to perform boolean operation"));
}
boolOp = this->getSolid(boolOp);
// lets check if the result is a solid
if (boolOp.isNull())
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid"));
boolOp = refineShapeIfActive(boolOp);
Shape.setValue(getSolid(boolOp));
return App::DocumentObject::StdReturn;
}
catch (Standard_Failure& e) {
return new App::DocumentObjectExecReturn(e.GetMessageString());
}
catch (const Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());
}
catch (...) {
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Loft: A fatal error occurred when making the loft"));
}
}
#endif
PROPERTY_SOURCE(PartDesign::AdditiveLoft, PartDesign::Loft)
AdditiveLoft::AdditiveLoft() {