Toposhape/Part: Cleanups and tests for makeElementSlice, makeElementSlices, and makeElementMirror

This commit is contained in:
bgbsww
2024-02-22 09:40:37 -05:00
parent 8e91aad2f0
commit dbe7c9d372
6 changed files with 250 additions and 78 deletions

View File

@@ -44,6 +44,7 @@
#endif
#include "CrossSection.h"
#include "TopoShapeOpCode.h"
using namespace Part;
@@ -224,87 +225,103 @@ TopoCrossSection::TopoCrossSection(double a, double b, double c, const TopoShape
{
}
void TopoCrossSection::slice(int idx, double d, std::vector<TopoShape> &wires) const {
void TopoCrossSection::slice(int idx, double d, std::vector<TopoShape>& wires) const
{
// Fixes: 0001228: Cross section of Torus in Part Workbench fails or give wrong results
// Fixes: 0001137: Incomplete slices when using Part.slice on a torus
bool found = false;
for(auto &s : shape.getSubTopoShapes(TopAbs_SOLID)) {
for (auto& s : shape.getSubTopoShapes(TopAbs_SOLID)) {
sliceSolid(idx, d, s, wires);
found = true;
}
if(!found) {
for(auto &s : shape.getSubTopoShapes(TopAbs_SHELL)) {
if (!found) {
for (auto& s : shape.getSubTopoShapes(TopAbs_SHELL)) {
sliceNonSolid(idx, d, s, wires);
found = true;
}
if(!found) {
for(auto &s : shape.getSubTopoShapes(TopAbs_FACE))
if (!found) {
for (auto& s : shape.getSubTopoShapes(TopAbs_FACE)) {
sliceNonSolid(idx, d, s, wires);
}
}
}
}
TopoShape TopoCrossSection::slice(int idx, double d) const {
TopoShape TopoCrossSection::slice(int idx, double d) const
{
std::vector<TopoShape> wires;
slice(idx,d,wires);
return TopoShape().makECompound(wires,0,false);
slice(idx, d, wires);
return TopoShape().makeElementCompound(
wires,
0,
TopoShape::SingleShapeCompoundCreationPolicy::returnShape);
}
void TopoCrossSection::sliceNonSolid(int idx, double d,
const TopoShape& shape, std::vector<TopoShape>& wires) const
void TopoCrossSection::sliceNonSolid(int idx,
double d,
const TopoShape& shape,
std::vector<TopoShape>& wires) const
{
BRepAlgoAPI_Section cs(shape.getShape(), gp_Pln(a,b,c,-d));
BRepAlgoAPI_Section cs(shape.getShape(), gp_Pln(a, b, c, -d));
if (cs.IsDone()) {
std::string prefix(op);
if(idx>1) {
if (idx > 1) {
prefix += '_';
prefix += std::to_string(idx);
}
auto res = TopoShape().makEShape(cs,shape,prefix.c_str()).makEWires().getSubTopoShapes(TopAbs_WIRE);
wires.insert(wires.end(),res.begin(),res.end());
auto res = TopoShape()
.makeElementShape(cs, shape, prefix.c_str())
.makeElementWires()
.getSubTopoShapes(TopAbs_WIRE);
wires.insert(wires.end(), res.begin(), res.end());
}
}
void TopoCrossSection::sliceSolid(int idx, double d,
const TopoShape& shape, std::vector<TopoShape>& wires) const
void TopoCrossSection::sliceSolid(int idx,
double d,
const TopoShape& shape,
std::vector<TopoShape>& wires) const
{
gp_Pln slicePlane(a,b,c,-d);
gp_Pln slicePlane(a, b, c, -d);
BRepBuilderAPI_MakeFace mkFace(slicePlane);
TopoShape face(idx);
face.setShape(mkFace.Face());
// Make sure to choose a point that does not lie on the plane (fixes #0001228)
gp_Vec tempVector(a,b,c);
tempVector.Normalize();//just in case.
tempVector *= (d+1.0);
gp_Vec tempVector(a, b, c);
tempVector.Normalize(); // just in case.
tempVector *= (d + 1.0);
gp_Pnt refPoint(0.0, 0.0, 0.0);
refPoint.Translate(tempVector);
BRepPrimAPI_MakeHalfSpace mkSolid(TopoDS::Face(face.getShape()), refPoint);
TopoShape solid(idx);
std::string prefix(op);
if(idx>1) {
if (idx > 1) {
prefix += '_';
prefix += std::to_string(idx);
}
solid.makEShape(mkSolid,face,prefix.c_str());
solid.makeElementShape(mkSolid, face, prefix.c_str());
BRepAlgoAPI_Cut mkCut(shape.getShape(), solid.getShape());
if (mkCut.IsDone()) {
TopoShape res(shape.Tag,shape.Hasher);
TopoShape res(shape.Tag, shape.Hasher);
std::vector<TopoShape> shapes;
shapes.push_back(shape);
shapes.push_back(solid);
res.makEShape(mkCut,shapes,prefix.c_str());
for(auto &face : res.getSubTopoShapes(TopAbs_FACE)) {
res.makeElementShape(mkCut, shapes, prefix.c_str());
for (auto& face : res.getSubTopoShapes(TopAbs_FACE)) {
BRepAdaptor_Surface adapt(TopoDS::Face(face.getShape()));
if (adapt.GetType() == GeomAbs_Plane) {
gp_Pln plane = adapt.Plane();
if (plane.Axis().IsParallel(slicePlane.Axis(), Precision::Confusion()) &&
plane.Distance(slicePlane.Location()) < Precision::Confusion()) {
auto repaired_wires = TopoShape(face.Tag).makEWires(
face.getSubTopoShapes(TopAbs_EDGE),prefix.c_str(),true).getSubTopoShapes(TopAbs_WIRE);
wires.insert(wires.end(),repaired_wires.begin(),repaired_wires.end());
if (plane.Axis().IsParallel(slicePlane.Axis(), Precision::Confusion())
&& plane.Distance(slicePlane.Location()) < Precision::Confusion()) {
auto repaired_wires = TopoShape(face.Tag)
.makeElementWires(face.getSubTopoShapes(TopAbs_EDGE),
prefix.c_str(),
true)
.getSubTopoShapes(TopAbs_WIRE);
wires.insert(wires.end(), repaired_wires.begin(), repaired_wires.end());
}
}
}

View File

@@ -56,8 +56,8 @@ private:
class PartExport TopoCrossSection
{
public:
TopoCrossSection(double a, double b, double c, const TopoShape& s, const char *op=0);
void slice(int idx, double d, std::vector<TopoShape> &wires) const;
TopoCrossSection(double a, double b, double c, const TopoShape& s, const char* op = 0);
void slice(int idx, double d, std::vector<TopoShape>& wires) const;
TopoShape slice(int idx, double d) const;
private:
@@ -65,11 +65,11 @@ private:
void sliceSolid(int idx, double d, const TopoShape&, std::vector<TopoShape>& wires) const;
private:
double a,b,c;
double a, b, c;
const TopoShape& shape;
const char *op;
const char* op;
};
}
} // namespace Part
#endif // PART_CROSSSECTION_H

View File

@@ -1342,7 +1342,8 @@ public:
* a self reference so that multiple operations can be carried out
* for the same shape in the same line of code.
*/
TopoShape &makEMirror(const TopoShape &source, const gp_Ax2& axis, const char *op=nullptr);
TopoShape&
makeElementMirror(const TopoShape& source, const gp_Ax2& axis, const char* op = nullptr);
/** Make a mirrored shape
*
* @param source: the source shape
@@ -1352,15 +1353,16 @@ public:
*
* @return Return the new shape. The TopoShape itself is not modified.
*/
TopoShape makEMirror(const gp_Ax2& ax, const char *op=nullptr) const {
return TopoShape(0,Hasher).makEMirror(*this,ax,op);
TopoShape makeElementMirror(const gp_Ax2& ax, const char* op = nullptr) const
{
return TopoShape(0, Hasher).makeElementMirror(*this, ax, op);
}
/** Make a cross section slice
*
* @param source: the source shape
* @param dir: direction of the normal of the section plane
* @param d: distance to move the section plane
* @param distance: distance to move the section plane
* @param op: optional string to be encoded into topo naming for indicating
* the operation
*
@@ -1369,19 +1371,23 @@ public:
* a self reference so that multiple operations can be carried out
* for the same shape in the same line of code.
*/
TopoShape &makESlice(const TopoShape &source, const Base::Vector3d& dir, double d, const char *op=nullptr);
TopoShape& makeElementSlice(const TopoShape& source,
const Base::Vector3d& dir,
double distance,
const char* op = nullptr);
/** Make a cross section slice
*
* @param source: the source shape
* @param dir: direction of the normal of the section plane
* @param d: distance to move the section plane
* @param distance: distance to move the section plane
* @param op: optional string to be encoded into topo naming for indicating
* the operation
*
* @return Return the new shape. The TopoShape itself is not modified.
*/
TopoShape makESlice(const Base::Vector3d& dir, double d, const char *op=nullptr) const {
return TopoShape(0,Hasher).makESlice(*this,dir,d,op);
TopoShape makeElementSlice(const Base::Vector3d& dir, double distance, const char* op = nullptr) const
{
return TopoShape(0, Hasher).makeElementSlice(*this, dir, distance, op);
}
/** Make multiple cross section slices
@@ -1397,8 +1403,10 @@ public:
* a self reference so that multiple operations can be carried out
* for the same shape in the same line of code.
*/
TopoShape &makESlices(const TopoShape &source, const Base::Vector3d& dir,
const std::vector<double> &distances, const char *op=nullptr);
TopoShape& makeElementSlices(const TopoShape& source,
const Base::Vector3d& dir,
const std::vector<double>& distances,
const char* op = nullptr);
/** Make multiple cross section slices
*
* @param source: the source shape
@@ -1409,8 +1417,11 @@ public:
*
* @return Return the new shape. The TopoShape itself is not modified.
*/
TopoShape makESlices(const Base::Vector3d &dir, const std::vector<double> &distances, const char *op=nullptr) const {
return TopoShape(0,Hasher).makESlices(*this,dir,distances,op);
TopoShape makeElementSlices(const Base::Vector3d& dir,
const std::vector<double>& distances,
const char* op = nullptr) const
{
return TopoShape(0, Hasher).makeElementSlices(*this, dir, distances, op);
}
/* Make fillet shape

View File

@@ -49,6 +49,7 @@
#include <BRepAlgoAPI_Section.hxx>
#include <BRepBuilderAPI_Copy.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <BRepFilletAPI_MakeChamfer.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepLib.hxx>
@@ -75,6 +76,7 @@
#endif
#include "modelRefine.h"
#include "CrossSection.h"
#include "TopoShape.h"
#include "TopoShapeOpCode.h"
#include "TopoShapeCache.h"
@@ -2596,28 +2598,52 @@ struct MapperThruSections: MapperMaker
}
};
TopoShape &TopoShape::makESlice(const TopoShape &shape,
const Base::Vector3d& dir, double d, const char *op)
TopoShape& TopoShape::makeElementMirror(const TopoShape& shape, const gp_Ax2& ax2, const char* op)
{
if(shape.isNull())
HANDLE_NULL_SHAPE;
TopoCrossSection cs(dir.x, dir.y, dir.z,shape,op);
TopoShape res = cs.slice(1,d);
if (!op) {
op = Part::OpCodes::Mirror;
}
if (shape.isNull()) {
FC_THROWM(NullShapeException, "Null shape");
}
gp_Trsf mat;
mat.SetMirror(ax2);
TopLoc_Location loc = shape.getShape().Location();
gp_Trsf placement = loc.Transformation();
mat = placement * mat;
BRepBuilderAPI_Transform mkTrf(shape.getShape(), mat);
return makeElementShape(mkTrf, shape, op);
}
TopoShape& TopoShape::makeElementSlice(const TopoShape& shape,
const Base::Vector3d& dir,
double distance,
const char* op)
{
if (shape.isNull()) {
FC_THROWM(NullShapeException, "Null shape");
}
TopoCrossSection cs(dir.x, dir.y, dir.z, shape, op);
TopoShape res = cs.slice(1, distance);
setShape(res._Shape);
Hasher = res.Hasher;
resetElementMap(res.elementMap());
return *this;
}
TopoShape &TopoShape::makESlices(const TopoShape &shape,
const Base::Vector3d& dir, const std::vector<double> &d, const char *op)
TopoShape& TopoShape::makeElementSlices(const TopoShape& shape,
const Base::Vector3d& dir,
const std::vector<double>& distances,
const char* op)
{
std::vector<TopoShape> wires;
TopoCrossSection cs(dir.x, dir.y, dir.z, shape,op);
int i=0;
for(auto &dd : d)
cs.slice(++i,dd,wires);
return makECompound(wires,op,false);
TopoCrossSection cs(dir.x, dir.y, dir.z, shape, op);
int index = 0;
for (auto& distance : distances) {
cs.slice(++index, distance, wires);
}
return makeElementCompound(wires, op, SingleShapeCompoundCreationPolicy::returnShape);
}
TopoShape& TopoShape::makeElementFillet(const TopoShape& shape,
@@ -2774,7 +2800,14 @@ TopoShape& TopoShape::makeElementShape(BRepBuilderAPI_MakeShape& mkShape,
const std::vector<TopoShape>& shapes,
const char* op)
{
return makeShapeWithElementMap(mkShape.Shape(), MapperMaker(mkShape), shapes, op);
TopoDS_Shape shape;
// OCCT 7.3.x requires calling Solid() and not Shape() to function correctly
if ( typeid(mkShape) == typeid(BRepPrimAPI_MakeHalfSpace) ) {
shape = static_cast<BRepPrimAPI_MakeHalfSpace&>(mkShape).Solid();
} else {
shape = mkShape.Shape();
}
return makeShapeWithElementMap(shape, MapperMaker(mkShape), shapes, op);
}
TopoShape& TopoShape::makeElementLoft(const std::vector<TopoShape>& shapes,