[TD]Prevent ComplexSection creation without valid direction

This commit is contained in:
wandererfan
2022-11-06 08:26:11 -05:00
committed by WandererFan
parent 38f1906ae0
commit c5a263bdd8
8 changed files with 128 additions and 103 deletions

View File

@@ -80,6 +80,7 @@
#include <Bnd_OBB.hxx>
#include <GProp_GProps.hxx>
#include <Geom_Plane.hxx>
#include <HLRAlgo_Projector.hxx>
#include <ShapeExtend_WireData.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
@@ -219,7 +220,6 @@ TopoDS_Shape DrawComplexSection::makeCuttingTool(double dMax)
return TopoDS_Shape();
}
TopoDS_Wire profileWire = makeProfileWire(toolObj);
m_profileWire = profileWire;
BRepBuilderAPI_Copy BuilderCopy(profileWire);
m_profileWire = TopoDS::Wire(BuilderCopy.Shape());
if (debugSection()) {
@@ -306,7 +306,14 @@ TopoDS_Shape DrawComplexSection::prepareShape(const TopoDS_Shape &cutShape, doub
}
//"Aligned" projection (Aligned Section)
TopoDS_Shape alignedResult = makeAlignedPieces(cutShape, m_toolFaceShape, shapeSize);
TopoDS_Shape alignedResult;
try {
alignedResult = makeAlignedPieces(cutShape, m_toolFaceShape, shapeSize);
}
catch (Base::RuntimeError& e) {
Base::Console().Error("Complex Section - %s\n", e.what());
return TopoDS_Shape();
}
if (alignedResult.IsNull()) {
return TopoDS_Shape();
@@ -334,35 +341,29 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape,
gp_Ax3 stdCS; //OXYZ
gp_Vec gProjectionUnit = gp_Vec(getSectionCS().Direction());
//get a vector that describes the profile's orientation in paper space.
gp_Vec gProfileVec = projectProfileWire(m_profileWire, gp_Ax3(getSectionCS()));
if (fabs(gProfileVec.Dot(getProjectionCS().Direction()) == 1.0)) {
Base::Console().Error(
"DCS::makeAlignedPieces - %s - profile is parallel to SectionNormal\n",
getNameInDocument());
throw Base::RuntimeError("Profile orientation error");
//get a vector that describes the profile's orientation
gp_Vec gProfileVec = makeProfileVector(m_profileWire);
//now we want to know what the profileVector looks like on the page (only X,Y coords)
gProfileVec = projectVector(gProfileVec).Normalized();
if (!canBuild(getSectionCS(), CuttingToolWireObject.getValue())) {
throw Base::RuntimeError("Profile is parallel to Section Normal");
}
//convert the profileVector with OXYZ.
gp_Trsf xProfileOXYZ;
gp_Ax3 OXYZ;
xProfileOXYZ.SetTransformation(OXYZ, gp_Ax3(getSectionCS()));
gp_Vec profileVecOXYZ = gProfileVec.Transformed(xProfileOXYZ);
bool isVertical = true;
if (fabs(profileVecOXYZ.Dot(gp::OY().Direction().XYZ())) != 1.0) {
if (fabs(gProfileVec.Dot(gp::OY().Direction().XYZ())) != 1.0) {
//profile is not parallel with stdY (paper space Up).
//this test is not good enough for "vertical-ish" diagonal profiles
isVertical = false;
}
double leftToRight = 1.0;//profile vector points to right, so we move to right
if (profileVecOXYZ.Dot(gp_Vec(gp::OX().Direction().XYZ())) < 0.0) {
if (gProfileVec.Dot(gp_Vec(gp::OX().Direction().XYZ())) < 0.0) {
//profileVec does not point towards stdX (right in paper space)
leftToRight = -1.0;
}
double topToBottom = 1.0;//profile vector points to top, so we move to top
if (profileVecOXYZ.Dot(gp_Vec(gp::OY().Direction().XYZ())) < 0.0) {
if (gProfileVec.Dot(gp_Vec(gp::OY().Direction().XYZ())) < 0.0) {
//profileVec does not point towards stdY (up in paper space)
topToBottom = -1.0;
}
@@ -392,6 +393,7 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape,
if (intersect.IsNull()) {
continue;
}
double faceAngle =
gp_Vec(getSectionCS().Direction().Reversed()).AngleWithRef(segmentNormal, rotateAxis);
@@ -604,7 +606,7 @@ TopoDS_Compound DrawComplexSection::alignedToolIntersections(const TopoDS_Shape
TopoDS_Compound DrawComplexSection::alignSectionFaces(TopoDS_Shape faceIntersections)
{
// Base::Console().Message("DCS::alignSectionFaces()\n");
// Base::Console().Message("DCS::alignSectionFaces() - faceIntersections.null: %d\n", faceIntersections.IsNull());
if (ProjectionStrategy.getValue() == 0) {
//Offset. Use regular section behaviour
return DrawViewSection::alignSectionFaces(faceIntersections);
@@ -640,40 +642,17 @@ TopoDS_Wire DrawComplexSection::makeProfileWire(App::DocumentObject *toolObj)
return profileWire;
}
//methods related to section line
//project the profile onto the paper and convert to the working CS
gp_Dir DrawComplexSection::projectProfileWire(TopoDS_Wire profileWire, gp_Ax3 paperCS)
gp_Vec DrawComplexSection::makeProfileVector(TopoDS_Wire profileWire)
{
// Base::Console().Message("DCS::projectProfileWire()\n");
gp_Pln plane(paperCS);
TopoDS_Face paper = BRepBuilderAPI_MakeFace(plane);
BRepAlgo_NormalProjection projector(paper);
projector.Add(profileWire);
projector.Build();
TopoDS_Shape projectedShape = projector.Projection();
TopoDS_Edge projectedSegment;
//we only need 1 projected edge to determine direction
TopExp_Explorer expEdges(projectedShape, TopAbs_EDGE);
for (; expEdges.More(); expEdges.Next()) {
projectedSegment = TopoDS::Edge(expEdges.Current());
break;
}
if (debugSection()) {
BRepTools::Write(projectedSegment, "DCSprojectedSegment.brep");//debug
}
if (projectedSegment.IsNull()) {
Base::Console().Warning("DCS::projectProfileWire - projection of profile failed\n");
return gp_Dir(1.0, 0.0, 0.0);
}
gp_Pnt gpProfileFirst = BRep_Tool::Pnt(TopExp::FirstVertex(projectedSegment));
gp_Pnt gpProfileLast = BRep_Tool::Pnt(TopExp::LastVertex(projectedSegment));
gp_Vec gProfileVec(gpProfileFirst, gpProfileLast);
gProfileVec.Normalize();
return gp_Dir(gProfileVec);
TopoDS_Vertex tvFirst, tvLast;
TopExp::Vertices(profileWire, tvFirst, tvLast);
gp_Pnt gpFirst = BRep_Tool::Pnt(tvFirst);
gp_Pnt gpLast = BRep_Tool::Pnt(tvLast);
return (gp_Vec(gpLast.XYZ()) - gp_Vec(gpFirst.XYZ())).Normalized();
}
//methods related to section line
//make drawable td geometry for section line
BaseGeomPtrVector DrawComplexSection::makeSectionLineGeometry()
{
@@ -731,11 +710,7 @@ std::pair<Base::Vector3d, Base::Vector3d> DrawComplexSection::sectionArrowDirs()
return result;
}
TopoDS_Vertex tvFirst, tvLast;
TopExp::Vertices(profileWire, tvFirst, tvLast);
gp_Pnt gpFirst = BRep_Tool::Pnt(tvFirst);
gp_Pnt gpLast = BRep_Tool::Pnt(tvLast);
gp_Vec gProfileVector = gp_Vec(gpLast.XYZ()) - gp_Vec(gpFirst.XYZ());
gp_Vec gProfileVector = makeProfileVector(profileWire);
gp_Vec gSectionNormal = gp_Vec(DU::togp_Dir(SectionNormal.getValue()));
gp_Vec gExtrudeVector = (gSectionNormal.Crossed(gProfileVector)).Normalized();
Base::Vector3d vClosestBasis = DrawUtil::closestBasis(gp_Dir(gExtrudeVector), getSectionCS());
@@ -876,6 +851,24 @@ gp_Ax2 DrawComplexSection::getCSFromBase(const std::string sectionName) const
return DrawViewSection::getCSFromBase(sectionName);
}
//simple projection of a 3d vector onto the paper space
gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec) const
{
HLRAlgo_Projector projector( getProjectionCS() );
gp_Pnt2d prjPnt;
projector.Project(gp_Pnt(vec.XYZ()), prjPnt);
return gp_Vec(prjPnt.X(), prjPnt.Y(), 0.0);
}
//static
gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec, gp_Ax2 sectionCS)
{
HLRAlgo_Projector projector( sectionCS );
gp_Pnt2d prjPnt;
projector.Project(gp_Pnt(vec.XYZ()), prjPnt);
return gp_Vec(prjPnt.X(), prjPnt.Y(), 0.0);
}
//get the "effective" (flattened) section plane for Aligned and
//the regular sectionPlane for Offset.
gp_Pln DrawComplexSection::getSectionPlane() const
@@ -918,11 +911,10 @@ bool DrawComplexSection::validateProfilePosition(TopoDS_Wire profileWire, gp_Ax2
gp_Dir &gClosestBasis) const
{
// Base::Console().Message("DCS::validateProfilePosition()\n");
gp_Vec gProfileVector = makeProfileVector(profileWire);
TopoDS_Vertex tvFirst, tvLast;
TopExp::Vertices(profileWire, tvFirst, tvLast);
gp_Pnt gpFirst = BRep_Tool::Pnt(tvFirst);//a position point for the wire
gp_Pnt gpLast = BRep_Tool::Pnt(tvLast);
gp_Vec gProfileVector = gp_Vec(gpLast.XYZ()) - gp_Vec(gpFirst.XYZ());
gp_Pnt gpFirst = BRep_Tool::Pnt(tvFirst);
//since bounding boxes are aligned with the cardinal directions, we need to find
//the appropriate direction to use when validating the profile position
@@ -975,6 +967,22 @@ bool DrawComplexSection::showSegment(gp_Dir segmentNormal) const
return true;
}
//Can we make a ComplexSection using this profile and sectionNormal?
bool DrawComplexSection::canBuild(gp_Ax2 sectionCS, App::DocumentObject* profileObject)
{
// Base::Console().Message("DCS::canBuild()\n");
if (!isProfileObject(profileObject)) {
return false;
}
gp_Vec gProfileVec = makeProfileVector(makeProfileWire(profileObject));
gProfileVec = projectVector(gProfileVec, sectionCS).Normalized();
double dot = fabs(gProfileVec.Dot(sectionCS.Direction()));
if ( DU::fpCompare(dot, 1.0, EWTOLERANCE)) {
return false;
}
return true;
}
// general purpose geometry methods
//make a "face" (not necessarily a TopoDS_Face since the extrusion of a wire is a shell)

View File

@@ -94,19 +94,22 @@ public:
std::pair<Base::Vector3d, Base::Vector3d> sectionArrowDirs();
TopoDS_Wire makeSectionLineWire();
TopoDS_Wire makeProfileWire(App::DocumentObject *toolObj);
TopoDS_Wire makeNoseToTailWire(TopoDS_Wire inWire);
gp_Dir projectProfileWire(TopoDS_Wire profileWire, gp_Ax3 paperCS);
ChangePointVector getChangePointsFromSectionLine();
bool validateProfilePosition(TopoDS_Wire profileWire, gp_Ax2 sectionCS,
gp_Dir &gClosestBasis) const;
bool showSegment(gp_Dir segmentNormal) const;
gp_Vec projectVector(const gp_Vec& vec) const;
static TopoDS_Wire makeProfileWire(App::DocumentObject *toolObj);
static TopoDS_Wire makeNoseToTailWire(TopoDS_Wire inWire);
static gp_Vec makeProfileVector(TopoDS_Wire profileWire);
static bool isProfileObject(App::DocumentObject *obj);
static bool isMultiSegmentProfile(App::DocumentObject *obj);
static bool isLinearProfile(App::DocumentObject *obj);
static bool isTrulyEmpty(TopoDS_Shape inShape);
static bool canBuild(gp_Ax2 sectionCS, App::DocumentObject* profileObject);
static gp_Vec projectVector(const gp_Vec& vec, gp_Ax2 sectionCS);
private:
gp_Dir getFaceNormal(TopoDS_Face &face);

View File

@@ -149,6 +149,7 @@ class TechDrawExport DrawUtil {
static Base::Vector3d toVector3d(const gp_Dir gp) { return Base::Vector3d(gp.X(), gp.Y(), gp.Z()); }
static gp_Pnt togp_Pnt(const Base::Vector3d v) { return gp_Pnt(v.x, v.y, v.z); }
static gp_Dir togp_Dir(const Base::Vector3d v) { return gp_Dir(v.x, v.y, v.z); }
static gp_Vec togp_Vec(const Base::Vector3d v) { return gp_Vec(v.x, v.y, v.z); }
static std::string shapeToString(TopoDS_Shape s);
static TopoDS_Shape shapeFromString(std::string s);
static Base::Vector3d invertY(Base::Vector3d v);

View File

@@ -1027,6 +1027,13 @@ gp_Ax2 DrawViewPart::localVectorToCS(const Base::Vector3d localUnit) const
return { stdOrigin, gp_Dir(gLocalUnitOXYZ), gp_Dir(gLocalXOXYZ) };
}
Base::Vector3d DrawViewPart::localVectorToDirection(const Base::Vector3d localUnit) const
{
Base::Console().Message("DVP::localVectorToDirection() - localUnit: %s\n", DrawUtil::formatVector(localUnit).c_str());
gp_Ax2 cs = localVectorToCS(localUnit);
return DrawUtil::toVector3d(cs.Direction());
}
gp_Ax2 DrawViewPart::getProjectionCS(const Base::Vector3d pt) const
{
// Base::Console().Message("DVP::getProjectionCS() - %s - %s\n", getNameInDocument(), Label.getValue());

View File

@@ -155,7 +155,7 @@ public:
const Base::Vector3d& axis,
const bool flip = true) const;
gp_Ax2 localVectorToCS(const Base::Vector3d localUnit) const;
Base::Vector3d localVectorToDirection(const Base::Vector3d localUnit) const;
bool handleFaces();
bool newFaceFinder();

View File

@@ -638,7 +638,7 @@ TopoDS_Compound DrawViewSection::mapToPage(TopoDS_Shape& shapeToAlign)
// needs to be aligned to paper plane (origin, stdZ);
//project the faces in the shapeToAlign, build new faces from the resulting wires and
//combine everything into a compound of faces
// Base::Console().Message("DVS::mapToPage() - shapeToAlign.null: %d\n", shapeToAlign.IsNull());
BRep_Builder builder;
TopoDS_Compound result;
builder.MakeCompound(result);