From 6c9951deec7f25d38bc0e24819af359a517194b4 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Sat, 26 Apr 2025 18:48:05 -0400 Subject: [PATCH 1/3] [TD]improve ComplexSection handling of bad section normal choice --- src/Mod/TechDraw/App/DrawComplexSection.cpp | 943 ++++++++++++-------- src/Mod/TechDraw/App/DrawComplexSection.h | 79 +- src/Mod/TechDraw/App/DrawViewPart.cpp | 14 +- src/Mod/TechDraw/App/DrawViewPart.h | 2 +- src/Mod/TechDraw/App/DrawViewSection.cpp | 112 ++- src/Mod/TechDraw/App/DrawViewSection.h | 28 +- 6 files changed, 754 insertions(+), 424 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawComplexSection.cpp b/src/Mod/TechDraw/App/DrawComplexSection.cpp index 29cc3de7a3..de5fe95b09 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.cpp +++ b/src/Mod/TechDraw/App/DrawComplexSection.cpp @@ -78,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -131,26 +132,30 @@ using DU = DrawUtil; // DrawComplexSection //=========================================================================== +//NOLINTBEGIN PROPERTY_SOURCE(TechDraw::DrawComplexSection, TechDraw::DrawViewSection) const char* DrawComplexSection::ProjectionStrategyEnums[] = {"Offset", "Aligned", "NoParallel", nullptr}; +//NOLINTEND -DrawComplexSection::DrawComplexSection() +DrawComplexSection::DrawComplexSection() : + m_waitingForAlign(false) { static const char* fgroup = "Cutting Tool"; +//NOLINTBEGIN ADD_PROPERTY_TYPE(CuttingToolWireObject, (nullptr), fgroup, App::Prop_None, "A sketch that describes the cutting tool"); CuttingToolWireObject.setScope(App::LinkScope::Global); ProjectionStrategy.setEnums(ProjectionStrategyEnums); ADD_PROPERTY_TYPE(ProjectionStrategy, ((long)0), fgroup, App::Prop_None, "Make a single cut, or use the profile in pieces"); +//NOLINTEND } TopoDS_Shape DrawComplexSection::makeCuttingTool(double dMax) { - // Base::Console().Message("DCS::makeCuttingTool()\n"); TopoDS_Wire profileWire = makeProfileWire(); if (profileWire.IsNull()) { throw Base::RuntimeError("Can not make wire from cutting tool (1)"); @@ -161,9 +166,12 @@ TopoDS_Shape DrawComplexSection::makeCuttingTool(double dMax) BRepTools::Write(profileWire, "DCSProfileWire.brep");//debug } - gp_Ax2 sectionCS = getSectionCS(); - gp_Dir gClosestBasis;//direction perpendicular to profile & section normal - bool isPositionOK = validateProfilePosition(profileWire, sectionCS, gClosestBasis); + gp_Ax2 sectionCS = getSectionCS(); // should validate this some where + + auto uSectionNormal = SectionNormal.getValue(); + uSectionNormal.Normalize(); + auto gWireToFaceDirection = Base::convertTo(getReferenceAxis()); + bool isPositionOK = validateProfilePosition(profileWire, sectionCS); if (!isPositionOK) { //profile is not in a good position. Result might not be right. Base::Console().Warning("DCS::makeCuttingTool - %s - profile is outside shape box\n", @@ -172,69 +180,69 @@ TopoDS_Shape DrawComplexSection::makeCuttingTool(double dMax) //move the profile wire to one side of the shape gp_Trsf mov; - mov.SetTranslation(gp_Vec(gClosestBasis) * (-dMax)); + mov.SetTranslation(gp_Vec(gWireToFaceDirection) * (-dMax)); TopLoc_Location loc(mov); profileWire.Move(loc); - gp_Vec extrudeDir(0.0, 0.0, 1.0);//arbitrary default if (BRep_Tool::IsClosed(profileWire)) { + // TopoDS_Shape makePrismForClosedProfile(profileWire) // Wire is closed, so make a face from it and extrude "vertically" BRepBuilderAPI_MakeFace mkFace(profileWire); TopoDS_Face toolFace = mkFace.Face(); if (toolFace.IsNull()) { - return TopoDS_Shape(); + return {}; } gp_Dir gpNormal = getFaceNormal(toolFace); - extrudeDir = 2.0 * dMax * gpNormal; + auto extrudeDir = 2 * dMax * gpNormal; return BRepPrimAPI_MakePrism(toolFace, extrudeDir).Shape(); } - // if the wire is open (the normal case of a more or less linear profile), - // we need to make a "face" from the wire by extruding it - // in the direction of gClosestBasis , then extrude the face in the direction of the section normal - if (ProjectionStrategy.getValue() == 0) { // Offset. Warn if profile is not quite aligned with section normal. if // the profile and normal are misaligned, the check below for empty "solids" // will not be correct. - double angleThresholdDeg = 5.0; + constexpr double AngleThresholdDeg{5.0}; // bool isOK = - validateOffsetProfile(profileWire, SectionNormal.getValue(), angleThresholdDeg); + validateOffsetProfile(profileWire, SectionNormal.getValue(), AngleThresholdDeg); } - m_toolFaceShape = extrudeWireToFace(profileWire, gClosestBasis, 2.0 * dMax); + m_toolFaceShape = extrudeWireToFace(profileWire, gWireToFaceDirection, 2 * dMax); if (debugSection()) { BRepTools::Write(m_toolFaceShape, "DCSToolFaceShape.brep");//debug } - extrudeDir = dMax * sectionCS.Direction(); - TopoDS_Shape roughTool = BRepPrimAPI_MakePrism(m_toolFaceShape, extrudeDir).Shape(); + + // should this use the circular arc closing method as in closeProfile()?? + auto points = getPointsForClosingProfile(profileWire, dMax); + + BRepBuilderAPI_MakeWire mkWire(profileWire); + + for(size_t iFrom = 0; iFrom < points.size() - 1 ; iFrom++) { + size_t jTo = iFrom + 1; + BRepBuilderAPI_MakeEdge mkEdge(Base::convertTo(points.at(iFrom)), + Base::convertTo(points.at(jTo))); + mkWire.Add(mkEdge.Edge()); + } + + BRepBuilderAPI_MakeFace mkFace(mkWire.Wire()); + if (debugSection()) { + BRepTools::Write(mkFace.Face(), "DCSToolPlan.brep"); //debug + } + auto padVector = gWireToFaceDirection * dMax * 2; + TopoDS_Shape roughTool = BRepPrimAPI_MakePrism(mkFace.Face(), padVector).Shape(); + if (roughTool.ShapeType() == TopAbs_COMPSOLID || roughTool.ShapeType() == TopAbs_COMPOUND) { //Composite Solids do not cut well if they contain "solids" with no volume. This //happens if the profile has segments parallel to the extrude direction. //We need to disassemble it and only keep the real solids. - BRep_Builder builder; - TopoDS_Compound comp; - builder.MakeCompound(comp); - TopExp_Explorer expSolids(roughTool, TopAbs_SOLID); - for (; expSolids.More(); expSolids.Next()) { - TopoDS_Solid solid = TopoDS::Solid(expSolids.Current()); - GProp_GProps gprops; - BRepGProp::VolumeProperties(solid, gprops); - double volume = gprops.Mass(); - if (volume > EWTOLERANCE) { - builder.Add(comp, solid); - } - } - return comp; + return removeEmptyShapes(roughTool); } - return BRepPrimAPI_MakePrism(m_toolFaceShape, extrudeDir).Shape(); + return roughTool; } TopoDS_Shape DrawComplexSection::getShapeToPrepare() const { - // Base::Console().Message("DCS::getShapeToPrepare()\n"); if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour return DrawViewSection::getShapeToPrepare(); @@ -246,7 +254,6 @@ TopoDS_Shape DrawComplexSection::getShapeToPrepare() const //get the shape ready for projection and cut surface finding TopoDS_Shape DrawComplexSection::prepareShape(const TopoDS_Shape& cutShape, double shapeSize) { - // Base::Console().Message("DCS::prepareShape() - strategy: %d\n", ProjectionStrategy.getValue()); if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour return DrawViewSection::prepareShape(cutShape, shapeSize); @@ -254,7 +261,7 @@ TopoDS_Shape DrawComplexSection::prepareShape(const TopoDS_Shape& cutShape, doub //"Aligned" projection (Aligned Section) if (m_alignResult.IsNull()) { - return TopoDS_Shape(); + return {}; } // our shape is already centered "left/right" and "up/down" so we don't need to @@ -276,8 +283,6 @@ TopoDS_Shape DrawComplexSection::prepareShape(const TopoDS_Shape& cutShape, doub void DrawComplexSection::makeSectionCut(const TopoDS_Shape& baseShape) { - // Base::Console().Message("DCS::makeSectionCut() - %s - baseShape.IsNull: %d\n", - // getNameInDocument(), baseShape.IsNull()); if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour return DrawViewSection::makeSectionCut(baseShape); @@ -307,8 +312,6 @@ void DrawComplexSection::makeSectionCut(const TopoDS_Shape& baseShape) void DrawComplexSection::onSectionCutFinished() { - // Base::Console().Message("DCS::onSectionCutFinished() - %s - cut: %d align: %d\n", - // getNameInDocument(), m_cutFuture.isRunning(), m_alignFuture.isRunning()); if (m_cutFuture.isRunning() || //waitingForCut() m_alignFuture.isRunning()) {//waitingForAlign() //can not continue yet. return until the other thread ends @@ -321,185 +324,76 @@ void DrawComplexSection::onSectionCutFinished() } //for Aligned strategy, cut the rawShape by each segment of the tool -//TODO: this process should replace the "makeSectionCut" from DVS void DrawComplexSection::makeAlignedPieces(const TopoDS_Shape& rawShape) { - // Base::Console().Message("DCS::makeAlignedPieces() - rawShape.isNull: %d\n", rawShape.IsNull()); if (!canBuild(getSectionCS(), CuttingToolWireObject.getValue())) { throw Base::RuntimeError("Profile is parallel to Section Normal"); } - std::vector pieces; - std::vector pieceXSizeAll;//size in sectionCS.XDirection (width) - std::vector pieceYSizeAll;//size in sectionCS.YDirection (height) - std::vector pieceZSizeAll; //size in sectionCS.Direction (depth) - std::vector pieceVerticalAll; // displacement of piece in vertical direction + if (debugSection()) { + BRepTools::Write(rawShape, "DCSRawShape.brep");//debug + } + auto uSectionNormal = SectionNormal.getValue(); + uSectionNormal.Normalize(); - //make a CS from the section CS ZX plane to allow piece positioning (left-right) - //with the section view vertical centerline and (in-out, forward-backward) with - //the effective section plane for cut surface identification. - gp_Ax3 stdCS; //OXYZ - gp_Vec gProjectionUnit = gp_Vec(getSectionCS().Direction()); - - //get a vector that describes the profile's 3d gross orientation TopoDS_Wire profileWire = makeProfileWire(); if (profileWire.IsNull()) { - throw Base::RuntimeError("Can not make wire from cutting tool (2)"); + throw Base::RuntimeError("ComplexSection failed to make profileWire"); } + + auto uRotateAxis = getReferenceAxis(); + uRotateAxis.Normalize(); + + + // the reversers control left to right vs right to left (or top to bottom vs botttom to top) + // arrangement of the cut pieces. + double horizReverser{1.0}; + double verticalReverser{1.0}; gp_Vec gProfileVec = makeProfileVector(profileWire); + auto isProfileVertical = getReversers(gProfileVec, horizReverser, verticalReverser); - // we will rotate the pieces around a line perpendicular to both section - // normal and the profile vector - gp_Vec rotateAxis = (getSectionCS().Direction()).Crossed(gProfileVec); - - //now we want to know what the profileVector looks like on the page (only X,Y coords) - //so we know if we are going to stack views vertically or horizontally and if the segments - //will occur (left to right or right to left) or (top to bottom or bottom to top) - gProfileVec = projectVector(gProfileVec).Normalized(); - - bool isProfileVertical = true; - 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 - isProfileVertical = false; - } - - double horizReverser = 1.0;//profile vector points to right, so we move to right - if (gProfileVec.Dot(gp_Vec(gp::OX().Direction().XYZ())) < 0.0) { - //profileVec does not point towards stdX (right in paper space) - horizReverser = -1.0; - } - double verticalReverser = 1.0;//profile vector points to top, so we move to top - if (gProfileVec.Dot(gp_Vec(gp::OY().Direction().XYZ())) < 0.0) { - //profileVec does not point towards stdY (up in paper space) - verticalReverser = -1.0; - } + std::vector pieces; // results of cutting source with each segment's tool shape + std::vector pieceXSizeAll; //size in sectionCS.XDirection (width) + std::vector pieceYSizeAll; //size in sectionCS.YDirection (height) + std::vector pieceZSizeAll; //size in sectionCS.Direction (depth) + std::vector pieceVerticalAll; // displacement of piece in vertical direction + auto faceNormals = getSegmentViewDirections(profileWire, uSectionNormal, uRotateAxis); TopExp_Explorer expFaces(m_toolFaceShape, TopAbs_FACE); for (int iPiece = 0; expFaces.More(); expFaces.Next(), iPiece++) { TopoDS_Face face = TopoDS::Face(expFaces.Current()); - gp_Vec segmentNormal = gp_Vec(getFaceNormal(face)); - if (!showSegment(gp_Dir(segmentNormal))) { + auto segmentNormal = Base::convertTo(faceNormals.at(iPiece).second); + if (!showSegment(segmentNormal)) { //skip this segment of the profile continue; } - //we only want to reverse the segment normal if it is not perpendicular to section normal - if (segmentNormal.Dot(gProjectionUnit) != 0.0 - && segmentNormal.Angle(gProjectionUnit) <= std::numbers::pi/2) { - segmentNormal.Reverse(); - } - gp_Vec extrudeDir = segmentNormal * m_shapeSize; - BRepPrimAPI_MakePrism mkPrism(face, extrudeDir); - TopoDS_Shape segmentTool = mkPrism.Shape(); - TopoDS_Shape intersect = shapeShapeIntersect(segmentTool, rawShape); - if (intersect.IsNull()) { - continue; - } - if (debugSection()) { - stringstream ss; - ss << "DCSAintersect" << iPiece << ".brep"; - BRepTools::Write(intersect, ss.str().c_str());//debug - ss.clear(); - ss.str(std::string()); - } + double pieceVertical{0}; + auto rotatedPiece = cutAndRotatePiece(rawShape, face, iPiece, faceNormals.at(iPiece).second, uRotateAxis, pieceVertical); - // move intersection shape to the origin so we can rotate it without worrying about - // center of rotation. - gp_Trsf xPieceCenter; - gp_Vec pieceCentroid = gp_Vec(ShapeUtils::findCentroid(intersect).XYZ()); - - // save the amount we moved this piece in the vertical direction so we can - // put it back in the right place later - gp_Vec maskedVertical = DU::maskDirection(pieceCentroid, rotateAxis); - maskedVertical = pieceCentroid - maskedVertical; - double verticalDisplacement = maskedVertical.X() + maskedVertical.Y() + maskedVertical.Z(); - pieceVerticalAll.push_back(verticalDisplacement); - - xPieceCenter.SetTranslation(pieceCentroid * -1.0); - BRepBuilderAPI_Transform mkTransXLate(intersect, xPieceCenter, true); - TopoDS_Shape pieceCentered = mkTransXLate.Shape(); - if (debugSection()) { - stringstream ss; - ss << "DCSBpieceCentered" << iPiece << ".brep"; - BRepTools::Write(pieceCentered, ss.str().c_str());//debug - ss.clear(); - ss.str(std::string()); - } - - //rotate the intersection so interesting face is aligned with what will - // become the paper plane. - double faceAngle = - gp_Vec(getSectionCS().Direction().Reversed()).AngleWithRef(segmentNormal, rotateAxis); - gp_Ax1 faceAxis(gp_Pnt(0.0, 0.0, 0.0), rotateAxis); - gp_Ax3 pieceCS;// OXYZ - pieceCS.Rotate(faceAxis, faceAngle); - gp_Trsf xPieceRotate; - xPieceRotate.SetTransformation(stdCS, pieceCS); - BRepBuilderAPI_Transform mkTransRotate(pieceCentered, xPieceRotate, true); - TopoDS_Shape pieceRotated = mkTransRotate.Shape(); + auto sizeResponse = getAlignedSize(rotatedPiece, iPiece); + auto pieceSize = sizeResponse.pieceSize; + pieceXSizeAll.push_back(pieceSize.x); // size in ProjectionCS. + pieceYSizeAll.push_back(pieceSize.y); + pieceZSizeAll.push_back(pieceSize.z); + pieceVerticalAll.push_back(pieceVertical); if (debugSection()) { stringstream ss; - ss << "DCSCpieceRotated" << iPiece << ".brep"; - BRepTools::Write(pieceRotated, ss.str().c_str());//debug - ss.clear(); - ss.str(std::string()); + ss << "DCSAlignedPiece" << iPiece << ".brep"; + BRepTools::Write(sizeResponse.alignedPiece, ss.str().c_str());//debug } - //align a copy of the piece with OXYZ so we can use bounding box to get - //width, depth, height of the piece. We copy the piece so the transformation - //does not affect the original. - BRepBuilderAPI_Copy BuilderPieceCopy(pieceRotated); - TopoDS_Shape copyPieceRotatedShape = BuilderPieceCopy.Shape(); - gp_Trsf xPieceAlign; - xPieceAlign.SetTransformation(stdCS, getProjectionCS()); - BRepBuilderAPI_Transform mkTransAlign(copyPieceRotatedShape, xPieceAlign); - TopoDS_Shape pieceAligned = mkTransAlign.Shape(); - // we may have shifted our piece off center, so we better recenter here - gp_Trsf xPieceRecenter; - gp_Vec rotatedCentroid = gp_Vec(ShapeUtils::findCentroid(pieceAligned).XYZ()); - xPieceRecenter.SetTranslation(rotatedCentroid * -1.0); - BRepBuilderAPI_Transform mkTransRecenter(pieceAligned, xPieceRecenter, true); - pieceAligned = mkTransRecenter.Shape(); - + auto pieceOnPlane = movePieceToPaperPlane(sizeResponse.alignedPiece, sizeResponse.zMax); if (debugSection()) { stringstream ss; - ss << "DCSDpieceAligned" << iPiece << ".brep"; - BRepTools::Write(pieceAligned, ss.str().c_str());//debug - ss.clear(); - ss.str(std::string()); + ss << "DCSEpieceOnPlane" << iPiece << ".brep"; + BRepTools::Write(pieceOnPlane, ss.str().c_str());//debug } - Bnd_Box shapeBox; - shapeBox.SetGap(0.0); - BRepBndLib::AddOptimal(pieceAligned, shapeBox); - double xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0; - shapeBox.Get(xMin, yMin, zMin, xMax, yMax, zMax); - double pieceXSize(xMax - xMin); - double pieceYSize(yMax - yMin); - double pieceZSize(zMax - zMin); - - pieceXSizeAll.push_back(pieceXSize); // size in ProjectionCS. - pieceYSizeAll.push_back(pieceYSize); - pieceZSizeAll.push_back(pieceZSize); - - //now we need to move the piece so that the interesting face is coincident - //with the paper plane (stdXY). This will be a move along stdZ by -zMax. - gp_Vec toPaperPlane = gp::OZ().Direction().XYZ() * zMax * -1.0; - gp_Trsf xPieceToPlane; - xPieceToPlane.SetTranslation(toPaperPlane); - BRepBuilderAPI_Transform mkTransDisplace(pieceAligned, xPieceToPlane, true); - TopoDS_Shape pieceToPlane = mkTransDisplace.Shape(); - - if (debugSection()) { - stringstream ss; - ss << "DCSEpieceToPlane" << iPiece << ".brep"; - BRepTools::Write(pieceToPlane, ss.str().c_str());//debug - } - pieces.push_back(pieceToPlane); - // piece is on the paper plane, with piece centroid at the origin + // pieceOnPlane is on the paper plane, with piece centroid at the origin + pieces.push_back(pieceOnPlane); } if (pieces.empty()) { @@ -509,35 +403,29 @@ void DrawComplexSection::makeAlignedPieces(const TopoDS_Shape& rawShape) //space the pieces "horizontally" or "vertically" in OXYZ double movementReverser = isProfileVertical ? verticalReverser : horizReverser; - gp_Vec movementAxis = gp_Vec(gp::OX().Direction()); - gp_Vec alignmentAxis = gp_Vec(gp::OY().Direction().Reversed()); + auto movementAxis = gp_Vec(gp::OX().Direction()); + auto alignmentAxis = gp_Vec(gp::OY().Direction().Reversed()); if (isProfileVertical) { movementAxis = gp_Vec(gp::OY().Direction()); alignmentAxis = gp_Vec(gp::OX().Direction()); } gp_Vec gMovementVector = movementAxis * movementReverser; - int stopAt = pieces.size(); - double distanceToMove = 0.0; - for (int iPiece = 0; iPiece < stopAt; iPiece++) { - // this movement needs to be smarter about what direction is L/R and which - // is up/down? + size_t stopAt = pieces.size(); + double cursorPosition = 0.0; + for (size_t iPiece = 0; iPiece < stopAt; iPiece++) { double pieceSizeMoveDist = pieceXSizeAll.at(iPiece); if (isProfileVertical) { - pieceSizeMoveDist = pieceYSizeAll.at(iPiece); // for spacing + pieceSizeMoveDist = pieceYSizeAll.at(iPiece); } - double myDistanceToMove = distanceToMove + pieceSizeMoveDist / 2.0; - gp_Vec alignmentVector = alignmentAxis * pieceVerticalAll.at(iPiece) * -1.0; - gp_Vec netDisplacementVector = gMovementVector * myDistanceToMove + alignmentVector; - gp_Trsf xPieceDistribute; - xPieceDistribute.SetTranslation(netDisplacementVector); - BRepBuilderAPI_Transform mkTransDistribute(pieces.at(iPiece), xPieceDistribute, true); - pieces.at(iPiece) = mkTransDistribute.Shape(); - distanceToMove += pieceSizeMoveDist; + auto movedPiece = distributePiece(pieces.at(iPiece), pieceSizeMoveDist, pieceVerticalAll.at(iPiece), + alignmentAxis, gMovementVector, cursorPosition); + pieces.at(iPiece) = movedPiece; + cursorPosition += pieceSizeMoveDist; if (debugSection()) { stringstream ss; - ss << "DCSFpieceSpaced" << iPiece << ".brep"; + ss << "DCSMovedPiece" << iPiece << ".brep"; BRepTools::Write(pieces.at(iPiece), ss.str().c_str());//debug } } @@ -551,7 +439,7 @@ void DrawComplexSection::makeAlignedPieces(const TopoDS_Shape& rawShape) } //center the compound along SectionCS XDirection - Base::Vector3d centerVector = Base::convertTo(gMovementVector) * distanceToMove / -2.0; + Base::Vector3d centerVector = Base::convertTo(gMovementVector) * cursorPosition / -2; TopoDS_Shape centeredCompound = ShapeUtils::moveShape(comp, centerVector); if (debugSection()) { @@ -559,6 +447,7 @@ void DrawComplexSection::makeAlignedPieces(const TopoDS_Shape& rawShape) } // re-align our shape with the projection CS + gp_Ax3 stdCS; //OXYZ gp_Trsf xPieceAlign; xPieceAlign.SetTransformation(getProjectionCS(), stdCS); BRepBuilderAPI_Transform mkTransAlign(centeredCompound, xPieceAlign); @@ -578,12 +467,11 @@ void DrawComplexSection::makeAlignedPieces(const TopoDS_Shape& rawShape) TopoDS_Compound DrawComplexSection::findSectionPlaneIntersections(const TopoDS_Shape& shapeToIntersect) { - // Base::Console().Message("DCS::findSectionPlaneIntersections() - %s\n", getNameInDocument()); if (shapeToIntersect.IsNull()) { // this shouldn't happen Base::Console().Warning("DCS::findSectionPlaneInter - %s - cut shape is Null\n", getNameInDocument()); - return TopoDS_Compound(); + return {}; } if (ProjectionStrategy.getValue() == 0) {//Offset return singleToolIntersections(shapeToIntersect); @@ -595,7 +483,6 @@ DrawComplexSection::findSectionPlaneIntersections(const TopoDS_Shape& shapeToInt //Intersect cutShape with each segment of the cutting tool TopoDS_Compound DrawComplexSection::singleToolIntersections(const TopoDS_Shape& cutShape) { - // Base::Console().Message("DCS::singleToolInterSections()\n"); App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); if (!isLinearProfile(toolObj)) { //TODO: special handling here @@ -629,17 +516,16 @@ TopoDS_Compound DrawComplexSection::singleToolIntersections(const TopoDS_Shape& return result; } -//Intersect cutShape with the effective (flattened) cutting plane to generate cut surface faces +//Intersect cutShape with the effective (flattened paper plane) cutting plane to generate cut surface faces TopoDS_Compound DrawComplexSection::alignedToolIntersections(const TopoDS_Shape& cutShape) { - // Base::Console().Message("DCS::alignedToolIntersections()\n"); BRep_Builder builder; TopoDS_Compound result; builder.MakeCompound(result); App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); if (!isLinearProfile(toolObj)) { - //TODO: special handling here + //TODO: special handling here? // Base::Console().Message("DCS::alignedToolIntersection - profile has curves\n"); } @@ -671,7 +557,6 @@ TopoDS_Compound DrawComplexSection::alignedToolIntersections(const TopoDS_Shape& TopoDS_Compound DrawComplexSection::alignSectionFaces(TopoDS_Shape faceIntersections) { - // Base::Console().Message("DCS::alignSectionFaces() - faceIntersections.null: %d\n", faceIntersections.IsNull()); if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour return DrawViewSection::alignSectionFaces(faceIntersections); @@ -706,14 +591,13 @@ TopoDS_Wire DrawComplexSection::makeProfileWire() const TopoDS_Wire DrawComplexSection::makeProfileWire(App::DocumentObject* toolObj) { - // Base::Console().Message("DCS::makeProfileWire()\n"); if (!isProfileObject(toolObj)) { - return TopoDS_Wire(); + return {}; } TopoDS_Shape toolShape = Part::Feature::getShape(toolObj); if (toolShape.IsNull()) { - return TopoDS_Wire(); + return {}; } TopoDS_Wire profileWire; @@ -727,14 +611,12 @@ TopoDS_Wire DrawComplexSection::makeProfileWire(App::DocumentObject* toolObj) return profileWire; } -gp_Vec DrawComplexSection::makeProfileVector(TopoDS_Wire profileWire) +gp_Vec DrawComplexSection::makeProfileVector(const TopoDS_Wire& profileWire) { - // Base::Console().Message("DCS::makeProfileVector()\n"); - 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(); + auto ends = getWireEnds(profileWire); + auto vec = ends.second - ends.first; + vec.Normalize(); + return Base::convertTo(vec); } //methods related to section line @@ -744,7 +626,7 @@ BaseGeomPtrVector DrawComplexSection::makeSectionLineGeometry() { // Base::Console().Message("DCS::makeSectionLineGeometry()\n"); BaseGeomPtrVector result; - DrawViewPart* baseDvp = freecad_cast(BaseView.getValue()); + auto* baseDvp = freecad_cast(BaseView.getValue()); if (baseDvp) { TopoDS_Wire lineWire = makeSectionLineWire(); TopoDS_Shape projectedWire = @@ -768,14 +650,11 @@ std::pair DrawComplexSection::sectionLineEnds() return result; } - TopoDS_Vertex vFirst, vLast; - TopExp::Vertices(lineWire, vFirst, vLast); - gp_Pnt gpFirst = BRep_Tool::Pnt(vFirst); - gp_Pnt gpLast = BRep_Tool::Pnt(vLast); - Base::Vector3d first = Base::Vector3d(gpFirst.X(), gpFirst.Y(), gpFirst.Z()); - Base::Vector3d last = Base::Vector3d(gpLast.X(), gpLast.Y(), gpLast.Z()); + auto ends = getWireEnds(lineWire); + Base::Vector3d first = ends.first; + Base::Vector3d last = ends.second; - DrawViewPart* baseDvp = freecad_cast(BaseView.getValue()); + auto* baseDvp = freecad_cast(BaseView.getValue()); if (baseDvp) { first = baseDvp->projectPoint(first); last = baseDvp->projectPoint(last); @@ -785,10 +664,12 @@ std::pair DrawComplexSection::sectionLineEnds() return result; } -//get directions of the section line arrows +// get the directions of the section line arrows. +// the arrows on the section line are line of sight - from eye to preserved material. In a simple section, +// this is opposite to the section normal. In the complex section, we need a perpendicular direction most +// opposite to the SectionNormal. std::pair DrawComplexSection::sectionArrowDirs() { - // Base::Console().Message("DCS::sectionArrowDirs()\n"); std::pair result; App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); TopoDS_Wire profileWire = makeProfileWire(toolObj); @@ -796,52 +677,34 @@ std::pair DrawComplexSection::sectionArrowDirs() return result; } - gp_Vec gProfileVector = makeProfileVector(profileWire); - gp_Vec gSectionNormal = gp_Vec(Base::convertTo(SectionNormal.getValue())); - gp_Vec gExtrudeVector = (gSectionNormal.Crossed(gProfileVector)).Normalized(); - Base::Vector3d vClosestBasis = DrawUtil::closestBasis(gp_Dir(gExtrudeVector), getSectionCS()); - gp_Dir gExtrudeDir = gp_Dir(vClosestBasis.x, vClosestBasis.y, vClosestBasis.z); + auto lineOfSight = SectionNormal.getValue() * -1; + lineOfSight.Normalize(); - TopoDS_Shape toolFaceShape = extrudeWireToFace(profileWire, gExtrudeDir, 100.0); - if (toolFaceShape.IsNull()) { - return result; - } + auto referenceAxis = getReferenceAxis(); - std::vector faces; - TopExp_Explorer expl(toolFaceShape, TopAbs_FACE); - for (; expl.More(); expl.Next()) { - faces.push_back(TopoDS::Face(expl.Current())); + auto uSectionNormal = SectionNormal.getValue(); + uSectionNormal.Normalize(); + auto segmentViewDirections = getSegmentViewDirections(profileWire, uSectionNormal, referenceAxis); + if (segmentViewDirections.empty()) { + throw Base::RuntimeError("A complex section failed to create profile segment view directions"); } + Base::Vector3d firstArrowDir = segmentViewDirections.front().second; + Base::Vector3d lastArrowDir = segmentViewDirections.back().second; - gp_Vec gDir0 = gp_Vec(getFaceNormal(faces.front())); - gp_Vec gDir1 = gp_Vec(getFaceNormal(faces.back())); - if (gDir0.Dot(gSectionNormal) > 0.0) { - //face normal is pointing generally in section normal direction, so we - //want the reverse for a view direction - gDir0.Reverse(); - } - if (gDir1.Dot(gSectionNormal) > 0.0) { - //face normal is pointing generally in section normal direction, so we - //want the reverse for a view direction - gDir1.Reverse(); - } - - //TODO: similar code elsewhere. Opportunity for reuse. - Base::Vector3d vDir0 = Base::convertTo(gDir0); - Base::Vector3d vDir1 = Base::convertTo(gDir1); - vDir0.Normalize(); - vDir1.Normalize(); - DrawViewPart* baseDvp = freecad_cast(BaseView.getValue()); - if (baseDvp) { - vDir0 = baseDvp->projectPoint(vDir0, true); - vDir1 = baseDvp->projectPoint(vDir1, true); - } - - result.first = vDir0; - result.second = vDir1; - return result; + return { firstArrowDir, lastArrowDir }; } + +//! find an axis for measuring rotation vs the line of sight +Base::Vector3d DrawComplexSection::getReferenceAxis() +{ + auto csDir = getBaseDVP()->getProjectionCS().Direction(); + auto rawDirection = Base::convertTo(csDir); + rawDirection.Normalize(); + return DU::closestBasisOriented(rawDirection); +} + + //make a wire suitable for projection on a base view TopoDS_Wire DrawComplexSection::makeSectionLineWire() { @@ -931,7 +794,7 @@ ChangePointVector DrawComplexSection::getChangePointsFromSectionLine() return result; } -gp_Ax2 DrawComplexSection::getCSFromBase(const std::string sectionName) const +gp_Ax2 DrawComplexSection::getCSFromBase(const std::string& sectionName) const { // Base::Console().Message("DCS::getCSFromBase()\n"); App::DocumentObject* base = BaseView.getValue(); @@ -943,21 +806,13 @@ 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); -} - // check for profile segments that are almost, but not quite in the same direction // as the section normal direction. this often indicates a problem with the direction // being slightly wrong. see https://forum.freecad.org/viewtopic.php?t=79017&sid=612a62a60f5db955ee071a7aaa362dbb bool DrawComplexSection::validateOffsetProfile(TopoDS_Wire profile, Base::Vector3d direction, double angleThresholdDeg) const { - double angleThresholdRad = Base::toRadians(angleThresholdDeg); // 5 degrees + constexpr double HalfCircleDegrees{180.0}; + double angleThresholdRad = angleThresholdDeg * std::numbers::pi / HalfCircleDegrees; TopExp_Explorer explEdges(profile, TopAbs_EDGE); for (; explEdges.More(); explEdges.Next()) { std::pair segmentEnds = getSegmentEnds(TopoDS::Edge(explEdges.Current())); @@ -974,10 +829,13 @@ bool DrawComplexSection::validateOffsetProfile(TopoDS_Wire profile, Base::Vector return true; } -std::pair DrawComplexSection::getSegmentEnds(TopoDS_Edge segment) const + +// next two methods could be templated (??) to handle edge/wire +std::pair + DrawComplexSection::getSegmentEnds(const TopoDS_Edge& segment) { - // Base::Console().Message("DCS::getSegmentEnds()\n"); - TopoDS_Vertex tvFirst, tvLast; + TopoDS_Vertex tvFirst; + TopoDS_Vertex tvLast; TopExp::Vertices(segment, tvFirst, tvLast); gp_Pnt gpFirst = BRep_Tool::Pnt(tvFirst); gp_Pnt gpLast = BRep_Tool::Pnt(tvLast); @@ -987,18 +845,36 @@ std::pair DrawComplexSection::getSegmentEnds(Top return result; } -//static -//TODO: centralize all the projection routines scattered around the module! -gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec, gp_Ax2 sectionCS) +std::pair + DrawComplexSection::getWireEnds(const TopoDS_Wire& wire) { - // Base::Console().Message("DCS::projectVector(%s, CS)\n", DU::formatVector(vec).c_str()); - HLRAlgo_Projector projector(sectionCS); - gp_Pnt2d prjPnt; - projector.Project(gp_Pnt(vec.XYZ()), prjPnt); - return gp_Vec(prjPnt.X(), prjPnt.Y(), 0.0); + TopoDS_Vertex tvFirst; + TopoDS_Vertex tvLast; + TopExp::Vertices(wire, tvFirst, tvLast); + gp_Pnt gpFirst = BRep_Tool::Pnt(tvFirst); + gp_Pnt gpLast = BRep_Tool::Pnt(tvLast); + std::pair result; + result.first = Base::convertTo(gpFirst); + result.second = Base::convertTo(gpLast); + return result; } -//get the "effective" (flattened) section plane for Aligned and + +gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec, gp_Ax2 sectionCS) +{ + HLRAlgo_Projector projector(sectionCS); + gp_Pnt2d prjPoint; + projector.Project(gp_Pnt(vec.XYZ()), prjPoint); + return {prjPoint.X(), prjPoint.Y(), 0}; +} + +//simple projection of a 3d vector onto the paper space +gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec) const +{ + return projectVector(vec, getProjectionCS()); +} + +//get the "effective" (flattened paper plane) section plane for Aligned and //the regular sectionPlane for Offset. gp_Pln DrawComplexSection::getSectionPlane() const { @@ -1014,7 +890,7 @@ gp_Pln DrawComplexSection::getSectionPlane() const gp_Pnt gOrigin(0.0, 0.0, 0.0); gp_Ax3 gPlaneCS(gOrigin, gSectionNormal); - return gp_Pln(gPlaneCS); + return {gPlaneCS}; } bool DrawComplexSection::isBaseValid() const @@ -1036,26 +912,23 @@ bool DrawComplexSection::isBaseValid() const //if the profile is not nicely positioned within the vertical span of the shape, we might not overlap //the shape after extrusion. As long as the profile is within the extent of the shape in the //extrude direction we should be ok. the extrude direction has to be perpendicular to the profile and SectionNormal -bool DrawComplexSection::validateProfilePosition(TopoDS_Wire profileWire, gp_Ax2 sectionCS, - gp_Dir& gClosestBasis) const +bool DrawComplexSection::validateProfilePosition(const TopoDS_Wire& profileWire, const gp_Ax2& sectionCS) const { - // Base::Console().Message("DCS::validateProfilePosition()\n"); + auto wireEnds = getWireEnds(profileWire); + auto gpFirst = Base::convertTo(wireEnds.first); gp_Vec gProfileVector = makeProfileVector(profileWire); - TopoDS_Vertex tvFirst, tvLast; - TopExp::Vertices(profileWire, tvFirst, tvLast); - 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 gp_Vec gSectionVector = getSectionCS().Direction().Reversed(); gp_Vec gExtrudeVector = gSectionVector.Crossed(gProfileVector); Base::Vector3d vClosestBasis = DrawUtil::closestBasis(gp_Dir(gExtrudeVector), sectionCS); - gClosestBasis = gp_Dir(vClosestBasis.x, vClosestBasis.y, vClosestBasis.z); + auto gClosestBasis = gp_Dir(vClosestBasis.x, vClosestBasis.y, vClosestBasis.z); Bnd_Box shapeBox; shapeBox.SetGap(0.0); BRepBndLib::AddOptimal(m_saveShape, shapeBox); - double xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0; + double xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0; //NOLINT shapeBox.Get(xMin, yMin, zMin, xMax, yMax, zMax); double spanLow = xMin; double spanHigh = xMax; @@ -1088,33 +961,27 @@ bool DrawComplexSection::showSegment(gp_Dir segmentNormal) const Base::Vector3d vSectionNormal = SectionNormal.getValue(); gp_Dir gSectionNormal(vSectionNormal.x, vSectionNormal.y, vSectionNormal.z); - if (DU::fpCompare(fabs(gSectionNormal.Dot(segmentNormal)), 0.0)) { - //segment normal is perpendicular to section normal, so segment is parallel to section normal, - //and for ProjectionStrategy "NoParallel", we don't display these segments. - return false; - } - return true; + //segment normal is perpendicular to section normal, so segment is parallel to section normal, + //and for ProjectionStrategy "NoParallel", we don't display these segments. + return !DU::fpCompare(fabs(gSectionNormal.Dot(segmentNormal)), 0.0); } //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; } + TopoDS_Shape shape = Part::Feature::getShape(profileObject); if (BRep_Tool::IsClosed(shape)) { //closed profiles don't have a profile vector but should always make a section? return true; } + 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; + return !DU::fpCompare(dot, 1.0, EWTOLERANCE); } // general purpose geometry methods @@ -1124,12 +991,7 @@ bool DrawComplexSection::canBuild(gp_Ax2 sectionCS, App::DocumentObject* profile TopoDS_Shape DrawComplexSection::extrudeWireToFace(TopoDS_Wire& wire, gp_Dir extrudeDir, double extrudeDist) { - gp_Trsf mov; - mov.SetTranslation(gp_Vec(extrudeDir) * (-extrudeDist)); - TopLoc_Location loc(mov); - wire.Move(loc); - - BRepPrimAPI_MakePrism mkPrism(wire, gp_Vec(extrudeDir) * 2.0 * extrudeDist); + BRepPrimAPI_MakePrism mkPrism(wire, gp_Vec(extrudeDir) * extrudeDist * 2); return mkPrism.Shape(); } @@ -1143,10 +1005,11 @@ gp_Dir DrawComplexSection::getFaceNormal(TopoDS_Face& face) double uParmLast = adapt.LastUParameter(); double vParmFirst = adapt.FirstVParameter(); double vParmLast = adapt.LastVParameter(); - double uMid = (uParmFirst + uParmLast) / 2.0; - double vMid = (vParmFirst + vParmLast) / 2.0; + double uMid = (uParmFirst + uParmLast) / 2; + double vMid = (vParmFirst + vParmLast) / 2; - BRepLProp_SLProps prop(adapt, uMid, vMid, 1, 0.01); + constexpr double PropTolerance{0.01}; + BRepLProp_SLProps prop(adapt, uMid, vMid, 1, PropTolerance); gp_Dir normalDir(0.0, 0.0, 1.0);//default if (prop.IsNormalDefined()) { normalDir = prop.Normal(); @@ -1156,15 +1019,14 @@ gp_Dir DrawComplexSection::getFaceNormal(TopoDS_Face& face) bool DrawComplexSection::boxesIntersect(TopoDS_Face& face, TopoDS_Shape& shape) { - Bnd_Box box0, box1; + constexpr double OverlapTolerance{0.1}; + Bnd_Box box0; + Bnd_Box box1; BRepBndLib::Add(face, box0); - box0.SetGap(0.1);//generous + box0.SetGap(OverlapTolerance);//generous BRepBndLib::Add(shape, box1); - box1.SetGap(0.1); - if (box0.IsOut(box1)) { - return false;//boxes don't intersect - } - return true; + box1.SetGap(OverlapTolerance); + return !box0.IsOut(box1); } TopoDS_Shape DrawComplexSection::shapeShapeIntersect(const TopoDS_Shape& shape0, @@ -1172,7 +1034,8 @@ TopoDS_Shape DrawComplexSection::shapeShapeIntersect(const TopoDS_Shape& shape0, { FCBRepAlgoAPI_Common anOp; anOp.SetFuzzyValue(EWTOLERANCE); - TopTools_ListOfShape anArg1, anArg2; + TopTools_ListOfShape anArg1; + TopTools_ListOfShape anArg2; anArg1.Append(shape0); anArg2.Append(shape1); anOp.SetArguments(anArg1); @@ -1180,7 +1043,7 @@ TopoDS_Shape DrawComplexSection::shapeShapeIntersect(const TopoDS_Shape& shape0, anOp.Build(); TopoDS_Shape result = anOp.Shape();//always a compound if (isTrulyEmpty(result)) { - return TopoDS_Shape(); + return {}; } return result; } @@ -1192,7 +1055,7 @@ std::vector DrawComplexSection::faceShapeIntersect(const TopoDS_Fac // Base::Console().Message("DCS::faceShapeIntersect()\n"); TopoDS_Shape intersect = shapeShapeIntersect(face, shape); if (intersect.IsNull()) { - return std::vector(); + return {}; } std::vector intersectFaceList; TopExp_Explorer expFaces(intersect, TopAbs_FACE); @@ -1203,7 +1066,7 @@ std::vector DrawComplexSection::faceShapeIntersect(const TopoDS_Fac } //ensure that the edges in the output wire are in nose to tail order -TopoDS_Wire DrawComplexSection::makeNoseToTailWire(TopoDS_Wire inWire) +TopoDS_Wire DrawComplexSection::makeNoseToTailWire(const TopoDS_Wire& inWire) { if (inWire.IsNull()) { return inWire; @@ -1220,10 +1083,8 @@ TopoDS_Wire DrawComplexSection::makeNoseToTailWire(TopoDS_Wire inWire) if (inList.empty() || inList.size() == 1) { return inWire; } - else { - sortedList = DrawUtil::sort_Edges(EWTOLERANCE, inList); - } + sortedList = DrawUtil::sort_Edges(EWTOLERANCE, inList); BRepBuilderAPI_MakeWire mkWire; for (auto& edge : sortedList) { mkWire.Add(edge); @@ -1285,10 +1146,7 @@ bool DrawComplexSection::isLinearProfile(App::DocumentObject* obj) //only have 1 edge TopoDS_Edge edge = TopoDS::Edge(shape); BRepAdaptor_Curve adapt(edge); - if (adapt.GetType() == GeomAbs_Line) { - return true; - } - return false; + return (adapt.GetType() == GeomAbs_Line); } if (shape.ShapeType() == TopAbs_WIRE) { @@ -1312,14 +1170,401 @@ bool DrawComplexSection::isLinearProfile(App::DocumentObject* obj) //a compound with no content is not considered IsNull by OCC. A more thorough check //is required. //https://dev.opencascade.org/content/compound-empty -bool DrawComplexSection::isTrulyEmpty(TopoDS_Shape inShape) +bool DrawComplexSection::isTrulyEmpty(const TopoDS_Shape& inShape) { - if (!inShape.IsNull() && TopoDS_Iterator(inShape).More()) { - return false; - } - return true; + bool hasContent = !inShape.IsNull() && TopoDS_Iterator(inShape).More(); + return !hasContent; } + +// this is a slightly different closed profile than getSegmentViewDirections uses. Should we use that +// here?? +std::vector + DrawComplexSection::getPointsForClosingProfile(const TopoDS_Wire& profileWire, double dMax) +{ + auto ends = getWireEnds(profileWire); + auto firstPoint = ends.first; + auto lastPoint = ends.second; + auto midPoint = (firstPoint + lastPoint) / 2; // midpoint of profile vector + + auto arrows = sectionArrowDirs(); + auto pseudoSectionNormal = ((arrows.first + arrows.second) / 2) * -1; + pseudoSectionNormal.Normalize(); + auto extraPoint = midPoint + pseudoSectionNormal * dMax * 2; + + std::vector points; + auto pointFromLast = lastPoint + (arrows.second * -1) * dMax; + auto pointToFirst = firstPoint + (arrows.first * -1) * dMax; + points.emplace_back(lastPoint); + points.emplace_back(pointFromLast); + points.emplace_back(extraPoint); + points.emplace_back(pointToFirst); + points.emplace_back(firstPoint); + return points; +} + +TopoDS_Shape DrawComplexSection::removeEmptyShapes(const TopoDS_Shape& roughTool) +{ + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + TopExp_Explorer expSolids(roughTool, TopAbs_SOLID); + for (; expSolids.More(); expSolids.Next()) { + TopoDS_Solid solid = TopoDS::Solid(expSolids.Current()); + GProp_GProps gprops; + BRepGProp::VolumeProperties(solid, gprops); + double volume = gprops.Mass(); + if (volume > EWTOLERANCE) { + builder.Add(comp, solid); + } + } + return comp; +} + +//! reversers determine if the cut pieces are arranged left to right or right to left (down to up/up to down) +//! returns true if the profile vector is vertical. +bool DrawComplexSection::getReversers(const gp_Vec& gProfileVec, double& horizReverser, double& verticalReverser) +{ + bool isProfileVertical = true; + auto sectionCS = getSectionCS(); + auto sectionCSX = sectionCS.XDirection(); + auto sectionCSY = sectionCS.YDirection(); + auto verticalDot = gProfileVec.Dot(sectionCSY); + if (DU::fpCompare(fabs(verticalDot), 0, EWTOLERANCE)) { + //profile is +/- normal to Y. + isProfileVertical = false; + } + + horizReverser = 1.0; //profile vector points to right, so we move to right + if (gProfileVec.Dot(sectionCSX) < 0.0) { + //profileVec does not point towards stdX (right in paper space) + horizReverser = -1.0; + } + + verticalReverser = 1.0;//profile vector points to top, so we will move pieces upwards + if (gProfileVec.Dot(sectionCSY) < 0.0) { + //profileVec does not point towards stdY (up in paper space) + verticalReverser = -1.0; + } + + return isProfileVertical; +} + + +//! align a copy of the piece with OXYZ so we can use bounding box to get +//! width, depth, height of the piece. We copy the piece so the transformation +//! does not affect the original. +AlignedSizeResponse DrawComplexSection::getAlignedSize(const TopoDS_Shape& pieceRotated, + int iPiece) const +{ + gp_Ax3 stdCS; //OXYZ + BRepBuilderAPI_Copy BuilderPieceCopy(pieceRotated); + TopoDS_Shape copyPieceRotatedShape = BuilderPieceCopy.Shape(); + gp_Trsf xPieceAlign; + xPieceAlign.SetTransformation(stdCS, getProjectionCS()); + BRepBuilderAPI_Transform mkTransAlign(copyPieceRotatedShape, xPieceAlign); + TopoDS_Shape pieceAligned = mkTransAlign.Shape(); + // we may have shifted our piece off center, so we better recenter here + gp_Trsf xPieceRecenter; + gp_Vec rotatedCentroid = gp_Vec(ShapeUtils::findCentroid(pieceAligned).XYZ()); + xPieceRecenter.SetTranslation(rotatedCentroid * -1.0); + BRepBuilderAPI_Transform mkTransRecenter(pieceAligned, xPieceRecenter, true); + pieceAligned = mkTransRecenter.Shape(); + + if (debugSection()) { + stringstream ss; + ss << "DCSDpieceAligned" << iPiece << ".brep"; + BRepTools::Write(pieceAligned, ss.str().c_str());//debug + ss.clear(); + ss.str(std::string()); + } + Bnd_Box shapeBox; + shapeBox.SetGap(0.0); + BRepBndLib::AddOptimal(pieceAligned, shapeBox); + double xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0; //NOLINT + shapeBox.Get(xMin, yMin, zMin, xMax, yMax, zMax); + double pieceXSize(xMax - xMin); + double pieceYSize(yMax - yMin); + double pieceZSize(zMax - zMin); + Base::Vector3d pieceSize{pieceXSize, pieceYSize, pieceZSize}; + return {pieceAligned, pieceSize, zMax}; +} + +//! cut the rawShape with a tool derived from the segmentFace and align the result with the +//! page plane. Also supplies the piece size. +TopoDS_Shape DrawComplexSection::cutAndRotatePiece(const TopoDS_Shape& rawShape, + const TopoDS_Face& segmentFace, + int iPiece, + Base::Vector3d uOrientedSegmentNormal, + Base::Vector3d uRotateAxis, + double& pieceVertical) +{ + auto segmentNormal = Base::convertTo(uOrientedSegmentNormal); + auto rotateAxis = Base::convertTo(uRotateAxis); + gp_Vec extrudeDir = segmentNormal * m_shapeSize; + BRepPrimAPI_MakePrism mkPrism(segmentFace, extrudeDir); + TopoDS_Shape segmentTool = mkPrism.Shape(); + TopoDS_Shape intersect = shapeShapeIntersect(segmentTool, rawShape); + if (intersect.IsNull()) { + return {}; + } + if (debugSection()) { + stringstream ss; + ss << "DCSAintersect" << iPiece << ".brep"; + BRepTools::Write(intersect, ss.str().c_str());//debug + ss.clear(); + ss.str(std::string()); + } + + // move intersection shape to the origin so we can rotate it without worrying about + // center of rotation. + gp_Trsf xPieceCenter; + gp_Vec pieceCentroid = gp_Vec(ShapeUtils::findCentroid(intersect).XYZ()); + + // save the amount we moved this piece in the vertical direction so we can + // put it back in the right place later + gp_Vec maskedVertical = DU::maskDirection(pieceCentroid, rotateAxis); + maskedVertical = pieceCentroid - maskedVertical; + pieceVertical = maskedVertical.X() + maskedVertical.Y() + maskedVertical.Z(); + + xPieceCenter.SetTranslation(pieceCentroid * -1.0); + BRepBuilderAPI_Transform mkTransXLate(intersect, xPieceCenter, true); + TopoDS_Shape pieceCentered = mkTransXLate.Shape(); + if (debugSection()) { + stringstream ss; + ss << "DCSBpieceCentered" << iPiece << ".brep"; + BRepTools::Write(pieceCentered, ss.str().c_str());//debug + ss.clear(); + ss.str(std::string()); + } + + //rotate the intersection so interesting face is aligned with what will + // become the paper plane. + double faceAngle = + gp_Vec(getSectionCS().Direction().Reversed()).AngleWithRef(segmentNormal, rotateAxis); + gp_Ax1 faceAxis(gp_Pnt(0.0, 0.0, 0.0), rotateAxis); + gp_Ax3 stdCS; + gp_Ax3 pieceCS; + pieceCS.Rotate(faceAxis, faceAngle); + gp_Trsf xPieceRotate; + xPieceRotate.SetTransformation(stdCS, pieceCS); + BRepBuilderAPI_Transform mkTransRotate(pieceCentered, xPieceRotate, true); + TopoDS_Shape pieceRotated = mkTransRotate.Shape(); + + return pieceRotated; +} + +TopoDS_Shape DrawComplexSection::movePieceToPaperPlane(const TopoDS_Shape& piece, double sizeMax) +{ + //now we need to move the piece so that the interesting face is coincident + //with the paper plane (stdXY). This will be a move along stdZ by -zMax. + gp_Vec toPaperPlane = gp::OZ().Direction().XYZ() * sizeMax * -1.0; + gp_Trsf xPieceToPlane; + xPieceToPlane.SetTranslation(toPaperPlane); + BRepBuilderAPI_Transform mkTransDisplace(piece, xPieceToPlane, true); + TopoDS_Shape pieceToPlane = mkTransDisplace.Shape(); + + // piece is on the paper plane, with piece centroid at the origin + return pieceToPlane; +} + +//! move the piece to its position across the page (X for a left right profile) +TopoDS_Shape DrawComplexSection::distributePiece(const TopoDS_Shape& piece, + double pieceSizeInDirection, + double verticalDisplace, + const gp_Vec& alignmentAxis, + const gp_Vec& gMovementVector, + double cursorPosition) +{ + double pieceTotalDistanceToMove = cursorPosition + pieceSizeInDirection / 2; + gp_Vec alignmentVector = alignmentAxis * verticalDisplace * -1; + gp_Vec netDisplacementVector = gMovementVector * pieceTotalDistanceToMove + alignmentVector; + + gp_Trsf xPieceDistribute; + xPieceDistribute.SetTranslation(netDisplacementVector); + BRepBuilderAPI_Transform mkTransDistribute(piece, xPieceDistribute, true); + auto distributedPiece = mkTransDistribute.Shape(); + + return distributedPiece; +} + + +// ?? are these in the correct order?? profile wires are in nose to tail order +std::vector DrawComplexSection::getUniqueEdges(const TopoDS_Wire& wireIn) +{ + std::vector ret; + TopTools_IndexedMapOfShape shapeMap; + TopExp_Explorer Ex(wireIn, TopAbs_EDGE); + while (Ex.More()) { + shapeMap.Add(Ex.Current()); + Ex.Next(); + } + + for (Standard_Integer k = 1; k <= shapeMap.Extent(); k++) { + const TopoDS_Shape& shape = shapeMap(k); + auto edge = TopoDS::Edge(shape); + ret.push_back(edge); + } + + return ret; +} + +//! Find the correct view directions for the profile segments by making a face from the profile and +//! extruding it into a solid, then examining the faces of the solid. +std::vector> DrawComplexSection::getSegmentViewDirections(const TopoDS_Wire& profileWire, + Base::Vector3d sectionNormal, + Base::Vector3d referenceAxis) const +{ + auto edgesAll = getUniqueEdges(profileWire); + if (edgesAll.empty()) { + // this is bad! + throw Base::RuntimeError("Complex section: profile wire has no edges."); + } + + if (!checkSectionCS()) { + // results will likely be incorrect + // this message will show for every recompute of the complex section. + Base::Console().Warning("Coordinate system for ComplexSection is invalid. Check SectionNormal, Direction or XDirection.\n"); + } + + auto profileVector = Base::convertTo(makeProfileVector(profileWire)); + auto parallelDot = profileVector.Dot(sectionNormal); + if (DU::fpCompare(std::fabs(parallelDot), 1, EWTOLERANCE)) { + Base::Console().Warning("Section normal is parallel to profile vector. Results may be incorrect.\n"); + } + auto profilePlanWire = closeProfile(profileWire, sectionNormal, m_shapeSize); + + auto profileSolid = profileToSolid(profilePlanWire, referenceAxis, m_shapeSize); + if (debugSection()) { + BRepTools::Write(profileSolid, "DCSProfileSolid.brep");//debug + } + + std::vector profileNormals; + std::vector> normalKV; + TopExp_Explorer expFaces(profileSolid, TopAbs_FACE); + // no guarantee of order from TopExp_Explorer?? Need to match faces to the profile segment that + // generated it? + for (int iFace = 0; expFaces.More(); expFaces.Next(), iFace++) { + auto shape = expFaces.Current(); + auto face = TopoDS::Face(shape); + auto normal = Base::convertTo(getFaceNormal(face)); + if (face.Orientation() == TopAbs_FORWARD) { + // face on solid with Forward orientation will have a normal that points out of the + // solid. With Reverse orientation the normal will point into the solid. We want the + // direction into the solid. + // "Face normal shows where body material is – it lies ‘behind' the face. In a correct solid body all face normals go ‘outward' (see below):" + // https://opencascade.blogspot.com/2009/02/continued.html + normal *= -1; + } + auto topOrBottomDot = std::fabs(normal.Dot(referenceAxis)); + if (DU::fpCompare(topOrBottomDot, 1, EWTOLERANCE)) { + continue; + } + BRepAdaptor_Surface adaptSurface(face); + auto surfaceType = adaptSurface.GetType(); + if (surfaceType != GeomAbs_SurfaceType::GeomAbs_Plane) { + continue; + } + // this is an interesting face, get the normal and edge + int iSegment{0}; + for (auto& segment : edgesAll) { + if (faceContainsEndpoints(segment, face)) { + std::pair newEntry; + newEntry.first = iSegment; + newEntry.second = normal; + normalKV.push_back(newEntry); + break; + } + iSegment++; + } + } + std::sort(normalKV.begin(), normalKV.end(), DrawComplexSection::normalLess); + return normalKV; +} + +//! true if the endpoints of edgeToMatch are vertexes of faceToSearch +bool DrawComplexSection::faceContainsEndpoints(const TopoDS_Edge& edgeToMatch, const TopoDS_Face& faceToSearch) +{ + bool matchedFirst{false}; + bool matchedLast{false}; + + std::pair edgeEnds = getSegmentEnds(edgeToMatch); + TopExp_Explorer expVerts(faceToSearch, TopAbs_VERTEX); + int iFace = 0; + for (; expVerts.More(); expVerts.Next(), iFace++) { + auto shape = expVerts.Current(); + auto vertex = TopoDS::Vertex(shape); + auto point = Base::convertTo(BRep_Tool::Pnt(vertex)); + if (point.IsEqual(edgeEnds.first, EWTOLERANCE)) { + matchedFirst = true; + } + if (point.IsEqual(edgeEnds.second, EWTOLERANCE)) { + matchedLast = true; + } + if (matchedFirst && matchedLast) { + break; + } + } + return matchedFirst && matchedLast; +} + + +//! forms a closed wire by connecting the end points of the profile wire with an arc. +TopoDS_Wire DrawComplexSection::closeProfile(const TopoDS_Wire& profileWire, + Base::Vector3d sectionNormal, + double dMax) +{ + auto pvEnds = getWireEnds(profileWire); + auto firstPWPoint = pvEnds.first; + auto lastPWPoint = pvEnds.second; + auto midPWPoint = (firstPWPoint + lastPWPoint) / 2; + auto SNPoint = sectionNormal * dMax; + auto awayDirection = midPWPoint - SNPoint; + awayDirection.Normalize(); + auto radius = (midPWPoint - lastPWPoint).Length(); + auto pointOnArc = midPWPoint + awayDirection * radius; + + GC_MakeArcOfCircle mkArc(Base::convertTo(lastPWPoint), + Base::convertTo(pointOnArc), + Base::convertTo(firstPWPoint)); + auto circleArc = mkArc.Value(); + if (!mkArc.IsDone()) { + throw Base::RuntimeError("Complex section failed to create arc"); + } + auto circleEdge = BRepBuilderAPI_MakeEdge(circleArc); + + BRepBuilderAPI_MakeWire mkWire(profileWire); + mkWire.Add(circleEdge); + return mkWire.Wire(); +} + + +//! extrudes a face made from a wire along the reference axis +TopoDS_Shape DrawComplexSection::profileToSolid(const TopoDS_Wire& closedProfileWire, + Base::Vector3d referenceAxis, + double dMax) +{ + BRepBuilderAPI_MakeFace mkFace(closedProfileWire); + if (!mkFace.IsDone()) { + throw Base::RuntimeError("Complex section could not create face from closed profile"); + } + + auto extrudeVector = referenceAxis * dMax; + + BRepPrimAPI_MakePrism mkPrism(mkFace.Face(), Base::convertTo(extrudeVector)); + auto profileSolid = mkPrism.Shape(); + + return profileSolid; +} + + +//! compare 2 normal entries for sorting on segment index +bool DrawComplexSection::normalLess(const std::pair& n1, const std::pair& n2) +{ + return n1.first < n2.first; +} + + // Python Drawing feature --------------------------------------------------------- namespace App diff --git a/src/Mod/TechDraw/App/DrawComplexSection.h b/src/Mod/TechDraw/App/DrawComplexSection.h index b1de8c0f38..7ec068e77e 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.h +++ b/src/Mod/TechDraw/App/DrawComplexSection.h @@ -35,19 +35,36 @@ namespace TechDraw { +class TechDrawExport AlignedSizeResponse +{ +public: + AlignedSizeResponse(const TopoDS_Shape& piece, Base::Vector3d size, double zvalue) : + alignedPiece(piece), + pieceSize(size), + zMax(zvalue) {} + + TopoDS_Shape alignedPiece; + Base::Vector3d pieceSize; + double zMax; +}; + +//NOLINTBEGIN class TechDrawExport DrawComplexSection: public DrawViewSection { PROPERTY_HEADER_WITH_OVERRIDE(TechDraw::DrawComplexSection); +//NOLINTEND public: DrawComplexSection(); ~DrawComplexSection() override = default; +//NOLINTBEGIN App::PropertyLink CuttingToolWireObject; App::PropertyEnumeration ProjectionStrategy;//Offset or Aligned +//NOLINTEND TopoDS_Shape makeCuttingTool(double dMax) override; - gp_Ax2 getCSFromBase(const std::string sectionName) const override; + gp_Ax2 getCSFromBase(const std::string& sectionName) const override; bool isBaseValid() const override; TopoDS_Compound findSectionPlaneIntersections(const TopoDS_Shape& cutShape) override; TopoDS_Shape prepareShape(const TopoDS_Shape& cutShape, double shapeSize) override; @@ -60,13 +77,10 @@ public: void makeSectionCut(const TopoDS_Shape& baseShape) override; void waitingForAlign(bool s) { m_waitingForAlign = s; } - bool waitingForAlign(void) const { return m_waitingForAlign; } + bool waitingForAlign() const { return m_waitingForAlign; } TopoDS_Shape getShapeForDetail() const override; -public Q_SLOTS: - void onSectionCutFinished(void) override; - bool boxesIntersect(TopoDS_Face& face, TopoDS_Shape& shape); TopoDS_Shape shapeShapeIntersect(const TopoDS_Shape& shape0, const TopoDS_Shape& shape1); std::vector faceShapeIntersect(const TopoDS_Face& face, const TopoDS_Shape& shape); @@ -81,26 +95,65 @@ public Q_SLOTS: ChangePointVector getChangePointsFromSectionLine() override; - bool validateProfilePosition(TopoDS_Wire profileWire, gp_Ax2 sectionCS, - gp_Dir& gClosestBasis) const; + bool validateProfilePosition(const TopoDS_Wire& profileWire, const gp_Ax2& sectionCS) const; bool showSegment(gp_Dir segmentNormal) const; gp_Vec projectVector(const gp_Vec& vec) const; TopoDS_Wire makeProfileWire() const; static TopoDS_Wire makeProfileWire(App::DocumentObject* toolObj); - static TopoDS_Wire makeNoseToTailWire(TopoDS_Wire inWire); - static gp_Vec makeProfileVector(TopoDS_Wire profileWire); + static TopoDS_Wire makeNoseToTailWire(const TopoDS_Wire& inWire); + static gp_Vec makeProfileVector(const 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 isTrulyEmpty(const TopoDS_Shape& inShape); static bool canBuild(gp_Ax2 sectionCS, App::DocumentObject* profileObject); static gp_Vec projectVector(const gp_Vec& vec, gp_Ax2 sectionCS); + static std::pair getSegmentEnds(const TopoDS_Edge& segment); + static std::pair getWireEnds(const TopoDS_Wire& wire); + +public Q_SLOTS: + void onSectionCutFinished() override; private: - gp_Dir getFaceNormal(TopoDS_Face& face); bool validateOffsetProfile(TopoDS_Wire profile, Base::Vector3d direction, double angleThresholdDeg) const; - std::pair getSegmentEnds(TopoDS_Edge segment) const; + Base::Vector3d getReferenceAxis(); + + // methods refactored out of makeAlignedPieces + bool getReversers(const gp_Vec& gProfileVector, double& horizReverser, double& verticalReverser); + AlignedSizeResponse getAlignedSize(const TopoDS_Shape& pieceRotated, int iPiece) const; + TopoDS_Shape cutAndRotatePiece(const TopoDS_Shape& rawShape, + const TopoDS_Face& segmentFace, + int iPiece, + Base::Vector3d uOrientedSegmentNormal, + Base::Vector3d uRotateAxis, + double& pieceVertical); + TopoDS_Shape movePieceToPaperPlane(const TopoDS_Shape& piece, double sizeMax); + TopoDS_Shape distributePiece(const TopoDS_Shape& piece, + double pieceSize, + double verticalDisplace, + const gp_Vec& alignmentAxis, + const gp_Vec& gMovementVector, + double baseDistance); + + + std::vector > + getSegmentViewDirections(const TopoDS_Wire& profileWire, + Base::Vector3d sectionNormal, + Base::Vector3d referenceAxis) const; + + std::vector getPointsForClosingProfile(const TopoDS_Wire& profileWire, + double dMax); + + static std::vector getUniqueEdges(const TopoDS_Wire& wireIn); + static TopoDS_Shape removeEmptyShapes(const TopoDS_Shape& roughTool); + static gp_Dir getFaceNormal(TopoDS_Face& face); + static bool faceContainsEndpoints(const TopoDS_Edge& edgeToMatch, + const TopoDS_Face& faceToSearch); + static bool normalLess(const std::pair& n1, + const std::pair& n2); + static TopoDS_Wire closeProfile(const TopoDS_Wire& profileWire, Base::Vector3d referenceAxis, double dMax); + static TopoDS_Shape profileToSolid(const TopoDS_Wire& closedProfileWire, Base::Vector3d referenceAxis, double dMax); TopoDS_Shape m_toolFaceShape; TopoDS_Shape m_alignResult; @@ -111,7 +164,7 @@ private: QFuture m_alignFuture; bool m_waitingForAlign; - static const char* ProjectionStrategyEnums[]; + static const char* ProjectionStrategyEnums[]; //NOLINT }; using DrawComplexSectionPython = App::FeaturePythonT; diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index c479e98f21..00175978c3 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -119,7 +119,7 @@ DrawViewPart::DrawViewPart() ADD_PROPERTY_TYPE(Direction, (0.0, -1.0, 0.0), group, App::Prop_None, "Projection Plane normal. The direction you are looking from."); - ADD_PROPERTY_TYPE(XDirection, (0.0, 0.0, 0.0), group, App::Prop_None, + ADD_PROPERTY_TYPE(XDirection, (1.0, 0.0, 0.0), group, App::Prop_None, "Projection Plane X Axis in R3. Rotates/Mirrors View"); ADD_PROPERTY_TYPE(Perspective, (false), group, App::Prop_None, "Perspective(true) or Orthographic(false) projection"); @@ -170,17 +170,17 @@ DrawViewPart::~DrawViewPart() //! returns a compound of all the shapes from the DocumentObjects in the Source & //! XSource property lists -TopoDS_Shape DrawViewPart::getSourceShape(bool fuse) const +TopoDS_Shape DrawViewPart::getSourceShape(bool fuse, bool allow2d) const { // Base::Console().Message("DVP::getSourceShape()\n"); const std::vector& links = getAllSources(); if (links.empty()) { - return TopoDS_Shape(); + return {}; } if (fuse) { return ShapeExtractor::getShapesFused(links); } - return ShapeExtractor::getShapes(links); + return ShapeExtractor::getShapes(links, allow2d); } //! deliver a shape appropriate for making a detail view based on this view @@ -278,8 +278,14 @@ void DrawViewPart::onChanged(const App::Property* prop) // Otherwise bad things will happen because there'll be a normalization for direction calculations later. Base::Vector3d dir = Direction.getValue(); if (DrawUtil::fpCompare(dir.Length(), 0.0)) { + Base::Console().Warning("%s Direction is null. Using (0, -1, 0).\n", Label.getValue()); Direction.setValue(Base::Vector3d(0.0, -1.0, 0.0)); } + Base::Vector3d xdir = XDirection.getValue(); + if (DrawUtil::fpCompare(xdir.Length(), 0.0)) { + Base::Console().Warning("%s XDirection is null. Using (1, 0, 0).\n", Label.getValue()); + XDirection.setValue(Base::Vector3d(1.0, 0.0, 0.0)); + } DrawView::onChanged(prop); } diff --git a/src/Mod/TechDraw/App/DrawViewPart.h b/src/Mod/TechDraw/App/DrawViewPart.h index c1bf992e5c..4b29b9db30 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.h +++ b/src/Mod/TechDraw/App/DrawViewPart.h @@ -212,7 +212,7 @@ public: bool newFaceFinder(); bool isUnsetting() { return nowUnsetting; } - virtual TopoDS_Shape getSourceShape(bool fuse = false) const; + virtual TopoDS_Shape getSourceShape(bool fuse = false, bool allow2d = true) const; virtual TopoDS_Shape getShapeForDetail() const; std::vector getAllSources() const; diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index dd2ffc1691..994e50ace8 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -161,8 +161,10 @@ DrawViewSection::DrawViewSection() App::Prop_None, "2D View source for this Section"); BaseView.setScope(App::LinkScope::Global); + + // default of (0, -1, 0) matches 'Front' direction in DVP ADD_PROPERTY_TYPE(SectionNormal, - (0, 0, 1.0), + (0, -1, 0), sgroup, App::Prop_None, "Section Plane normal direction");// direction of extrusion @@ -250,8 +252,11 @@ DrawViewSection::DrawViewSection() SvgIncluded.setStatus(App::Property::ReadOnly, true); PatIncluded.setStatus(App::Property::ReadOnly, true); + // SectionNormal is used instead to Direction Direction.setStatus(App::Property::ReadOnly, true); + Direction.setValue(SectionNormal.getValue()); + SectionDirection.setStatus(App::Property::Hidden, true); SectionDirection.setStatus(App::Property::ReadOnly, true); } @@ -260,7 +265,6 @@ DrawViewSection::~DrawViewSection() { // don't destroy this object while it has dependent threads running if (m_cutFuture.isRunning()) { - Base::Console().Message("%s is waiting for tasks to complete\n", Label.getValue()); m_cutFuture.waitForFinished(); } } @@ -268,7 +272,7 @@ DrawViewSection::~DrawViewSection() short DrawViewSection::mustExecute() const { if (isRestoring()) { - return TechDraw::DrawView::mustExecute(); + return TechDraw::DrawView::mustExecute(); //NOLINT } if (Scale.isTouched() || Direction.isTouched() || BaseView.isTouched() @@ -276,7 +280,7 @@ short DrawViewSection::mustExecute() const return 1; } - return TechDraw::DrawView::mustExecute(); + return TechDraw::DrawView::mustExecute(); //NOLINT } void DrawViewSection::onChanged(const App::Property* prop) @@ -293,40 +297,47 @@ void DrawViewSection::onChanged(const App::Property* prop) return; } - if (prop == &SectionNormal) { + if (prop == &SectionNormal || + prop == &XDirection) { Direction.setValue(SectionNormal.getValue()); return; } - else if (prop == &SectionSymbol) { + + if (prop == &SectionSymbol) { if (getBaseDVP()) { getBaseDVP()->requestPaint(); } return; } - else if (prop == &CutSurfaceDisplay) { + + if (prop == &CutSurfaceDisplay) { if (CutSurfaceDisplay.isValue("PatHatch")) { makeLineSets(); } requestPaint(); return; } - else if (prop == &FileHatchPattern) { + + if (prop == &FileHatchPattern) { replaceSvgIncluded(FileHatchPattern.getValue()); requestPaint(); return; } - else if (prop == &FileGeomPattern) { + + if (prop == &FileGeomPattern) { replacePatIncluded(FileGeomPattern.getValue()); makeLineSets(); requestPaint(); return; } - else if (prop == &NameGeomPattern) { + + if (prop == &NameGeomPattern) { makeLineSets(); requestPaint(); return; } - else if (prop == &BaseView) { + + if (prop == &BaseView) { // if the BaseView is a Section, then the option of using UsePreviousCut is // valid. if (BaseView.getValue() && BaseView.getValue()->isDerivedFrom()) { @@ -335,17 +346,17 @@ void DrawViewSection::onChanged(const App::Property* prop) else { UsePreviousCut.setStatus(App::Property::ReadOnly, true); } - } else if (prop == &SectionLineStretch) { + } + + if (prop == &SectionLineStretch) { BaseView.getValue()->touch(); } - DrawView::onChanged(prop); + DrawView::onChanged(prop); //NOLINT } TopoDS_Shape DrawViewSection::getShapeToCut() { - // Base::Console().Message("DVS::getShapeToCut() - %s\n", - // getNameInDocument()); App::DocumentObject* base = BaseView.getValue(); TechDraw::DrawViewPart* dvp = nullptr; TechDraw::DrawViewSection* dvs = nullptr; @@ -368,9 +379,11 @@ TopoDS_Shape DrawViewSection::getShapeToCut() } else if (base->isDerivedFrom()) { dvp = static_cast(base); - shapeToCut = dvp->getSourceShape(); + constexpr bool fuseBefore{true}; + constexpr bool allow2d{false}; + shapeToCut = dvp->getSourceShape(!fuseBefore, allow2d); if (FuseBeforeCut.getValue()) { - shapeToCut = dvp->getSourceShape(true); + shapeToCut = dvp->getSourceShape(fuseBefore); } } else { @@ -387,7 +400,6 @@ TopoDS_Shape DrawViewSection::getShapeForDetail() const App::DocumentObjectExecReturn* DrawViewSection::execute() { - // Base::Console().Message("DVS::execute() - %s\n", Label.getValue()); if (!keepUpdated()) { return App::DocumentObject::StdReturn; } @@ -993,29 +1005,27 @@ ChangePointVector DrawViewSection::getChangePointsFromSectionLine() // this should really be in BoundBox.h //! check if point is in box or on boundary of box //! compare to isInBox which doesn't allow on boundary -bool DrawViewSection::isReallyInBox(const Base::Vector3d v, const Base::BoundBox3d bb) const +bool DrawViewSection::isReallyInBox(const Base::Vector3d vec, const Base::BoundBox3d bb) const { - if (v.x <= bb.MinX || v.x >= bb.MaxX) { + if (vec.x <= bb.MinX || vec.x >= bb.MaxX) { return false; } - if (v.y <= bb.MinY || v.y >= bb.MaxY) { + if (vec.y <= bb.MinY || vec.y >= bb.MaxY) { return false; } - if (v.z <= bb.MinZ || v.z >= bb.MaxZ) { + if (vec.z <= bb.MinZ || vec.z >= bb.MaxZ) { return false; } return true; } -bool DrawViewSection::isReallyInBox(const gp_Pnt p, const Bnd_Box& bb) const +bool DrawViewSection::isReallyInBox(const gp_Pnt& point, const Bnd_Box& bb) const { - return !bb.IsOut(p); + return !bb.IsOut(point); } Base::Vector3d DrawViewSection::getXDirection() const { - // Base::Console().Message("DVS::getXDirection() - %s\n", - // Label.getValue()); App::Property* prop = getPropertyByName("XDirection"); if (!prop) { // No XDirection property. can this happen? @@ -1038,7 +1048,7 @@ Base::Vector3d DrawViewSection::getXDirection() const return XDirection.getValue(); } -void DrawViewSection::setCSFromBase(const std::string sectionName) +void DrawViewSection::setCSFromBase(const std::string& sectionName) { // Base::Console().Message("DVS::setCSFromBase(%s)\n", // sectionName.c_str()); @@ -1052,10 +1062,8 @@ void DrawViewSection::setCSFromBase(const std::string sectionName) } // set the section CS based on an XY vector in BaseViews CS -void DrawViewSection::setCSFromBase(const Base::Vector3d localUnit) +void DrawViewSection::setCSFromBase(const Base::Vector3d& localUnit) { - // Base::Console().Message("DVS::setCSFromBase(%s)\n", - // DrawUtil::formatVector(localUnit).c_str()); gp_Ax2 newSectionCS = getBaseDVP()->localVectorToCS(localUnit); Base::Vector3d vDir(newSectionCS.Direction().X(), @@ -1070,10 +1078,8 @@ void DrawViewSection::setCSFromBase(const Base::Vector3d localUnit) } // reset the section CS based on an XY vector in current section CS -void DrawViewSection::setCSFromLocalUnit(const Base::Vector3d localUnit) +void DrawViewSection::setCSFromLocalUnit(const Base::Vector3d& localUnit) { - // Base::Console().Message("DVS::setCSFromLocalUnit(%s)\n", - // DrawUtil::formatVector(localUnit).c_str()); gp_Dir verticalDir = getSectionCS().YDirection(); gp_Ax1 verticalAxis(Base::convertTo(SectionOrigin.getValue()), verticalDir); gp_Dir oldNormal = getSectionCS().Direction(); @@ -1084,10 +1090,8 @@ void DrawViewSection::setCSFromLocalUnit(const Base::Vector3d localUnit) XDirection.setValue(Base::convertTo(newCS.XDirection())); } -gp_Ax2 DrawViewSection::getCSFromBase(const std::string sectionName) const +gp_Ax2 DrawViewSection::getCSFromBase(const std::string& sectionName) const { - // Base::Console().Message("DVS::getCSFromBase(%s)\n", - // sectionName.c_str()); Base::Vector3d origin(0.0, 0.0, 0.0); Base::Vector3d sectOrigin = SectionOrigin.getValue(); @@ -1143,7 +1147,6 @@ gp_Ax2 DrawViewSection::getCSFromBase(const std::string sectionName) const // returns current section cs gp_Ax2 DrawViewSection::getSectionCS() const { - // Base::Console().Message("DVS::getSectionCS()\n"); Base::Vector3d vNormal = SectionNormal.getValue(); gp_Dir gNormal(vNormal.x, vNormal.y, vNormal.z); Base::Vector3d vXDir = getXDirection(); @@ -1172,7 +1175,6 @@ Base::Vector3d DrawViewSection::getCutCentroid() const std::vector DrawViewSection::getDrawableLines(int i) { - // Base::Console().Message("DVS::getDrawableLines(%d) - lineSets: %d\n", i, m_lineSets.size()); if (m_lineSets.empty()) { makeLineSets(); } @@ -1260,12 +1262,38 @@ void DrawViewSection::handleChangedPropertyType(Base::XMLReader &reader, const c } } +// checks that SectionNormal and XDirection are perpendicular and that Direction is the same as +// SectionNormal +bool DrawViewSection::checkSectionCS() const +{ + auto vNormal = SectionNormal.getValue(); + vNormal.Normalize(); + auto vXDirection = XDirection.getValue(); + vXDirection.Normalize(); + auto vDirection = Direction.getValue(); + + if (vNormal.Length() == 0 || + vXDirection.Length() == 0 || + vDirection.Length() == 0) { + return false; + } + + if (!vNormal.IsEqual(vDirection, EWTOLERANCE)) { + return false; + } + + auto orthoDot = std::fabs(vNormal.Dot(vXDirection)); + if (orthoDot > EWTOLERANCE) { + return false; + } + return true; +} + // hatch file routines // create geometric hatch lines void DrawViewSection::makeLineSets(void) { - // Base::Console().Message("DVS::makeLineSets()\n"); if (PatIncluded.isEmpty()) { return; } @@ -1289,8 +1317,6 @@ void DrawViewSection::makeLineSets(void) void DrawViewSection::replaceSvgIncluded(std::string newSvgFile) { - // Base::Console().Message("DVS::replaceSvgIncluded(%s)\n", - // newSvgFile.c_str()); if (newSvgFile.empty()) { return; } @@ -1306,7 +1332,6 @@ void DrawViewSection::replaceSvgIncluded(std::string newSvgFile) void DrawViewSection::replacePatIncluded(std::string newPatFile) { - // Base::Console().Message("DVS::replacePatIncluded(%s)\n", newPatFile.c_str()); if (newPatFile.empty()) { return; } @@ -1324,7 +1349,6 @@ void DrawViewSection::replacePatIncluded(std::string newPatFile) void DrawViewSection::getParameters() { - // Base::Console().Message("DVS::getParameters()\n"); bool fuseFirst = Preferences::getPreferenceGroup("General")->GetBool("SectionFuseFirst", false); FuseBeforeCut.setValue(fuseFirst); } @@ -1336,8 +1360,6 @@ bool DrawViewSection::debugSection(void) const int DrawViewSection::prefCutSurface(void) const { - // Base::Console().Message("DVS::prefCutSurface()\n"); - return Preferences::getPreferenceGroup("Decorations") ->GetInt("CutSurfaceDisplay", 2);// default to SvgHatch } diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index d1c816c0c2..b38e6b8329 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -75,14 +75,17 @@ private: using ChangePointVector = std::vector; +//NOLINTBEGIN class TechDrawExport DrawViewSection: public DrawViewPart { PROPERTY_HEADER_WITH_OVERRIDE(TechDraw::DrawViewSection); +//NOLINTEND public: DrawViewSection(); ~DrawViewSection() override; +//NOLINTBEGIN App::PropertyLink BaseView; App::PropertyDirection SectionNormal; App::PropertyPosition SectionOrigin; @@ -105,10 +108,10 @@ public: App::PropertyBool UsePreviousCut; // new v022 App::PropertyFloatConstraint SectionLineStretch; // new v022 +//NOLINTEND - - bool isReallyInBox(const Base::Vector3d v, const Base::BoundBox3d bb) const; - bool isReallyInBox(const gp_Pnt p, const Bnd_Box& bb) const; + bool isReallyInBox(const Base::Vector3d vec, const Base::BoundBox3d bb) const; + bool isReallyInBox(const gp_Pnt& point, const Bnd_Box& bb) const; App::DocumentObjectExecReturn* execute() override; void onChanged(const App::Property* prop) override; @@ -123,10 +126,10 @@ public: void sectionExec(TopoDS_Shape& s); virtual void makeSectionCut(const TopoDS_Shape& baseShape); - void postHlrTasks(void) override; + void postHlrTasks() override; virtual void postSectionCutTasks(); void waitingForCut(bool s) { m_waitingForCut = s; } - bool waitingForCut(void) const { return m_waitingForCut; } + bool waitingForCut() const { return m_waitingForCut; } bool waitingForResult() const override; virtual TopoDS_Shape makeCuttingTool(double shapeSize); @@ -136,10 +139,10 @@ public: virtual TopoDS_Shape getShapeToPrepare() const { return m_cutPieces; } //CS related methods - void setCSFromBase(const std::string sectionName); - void setCSFromBase(Base::Vector3d localUnit); - void setCSFromLocalUnit(const Base::Vector3d localUnit); - virtual gp_Ax2 getCSFromBase(const std::string sectionName) const; + void setCSFromBase(const std::string& sectionName); + void setCSFromBase(const Base::Vector3d& localUnit); + void setCSFromLocalUnit(const Base::Vector3d& localUnit); + virtual gp_Ax2 getCSFromBase(const std::string& sectionName) const; gp_Ax2 getSectionCS() const; Base::Vector3d getXDirection() const override;//don't use XDirection.getValue() @@ -153,7 +156,7 @@ public: virtual std::vector makeTDSectionFaces(TopoDS_Compound topoDSFaces); virtual TopoDS_Shape getShapeToIntersect() { return m_cutPieces; } - void makeLineSets(void); + void makeLineSets(); std::vector getDrawableLines(int i = 0); std::vector getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern); @@ -169,14 +172,15 @@ public: Base::Vector3d getSectionDirectionOnBaseView(); virtual ChangePointVector getChangePointsFromSectionLine(); - bool showSectionEdges(void); + bool showSectionEdges(); TopoDS_Shape makeFaceFromWires(std::vector &inWires); Base::Vector3d getCutCentroid() const; + bool checkSectionCS() const; public Q_SLOTS: - virtual void onSectionCutFinished(void); + virtual void onSectionCutFinished(); protected: TopoDS_Compound m_sectionTopoDSFaces;//needed for hatching From 59801c8366b87ab23d50cb9eb024ce117985a6ab Mon Sep 17 00:00:00 2001 From: wandererfan Date: Sun, 27 Apr 2025 13:31:00 -0400 Subject: [PATCH 2/3] [TD]Add check for invalid section coordinate system --- src/Mod/TechDraw/Gui/QGIViewPart.cpp | 2 - src/Mod/TechDraw/Gui/TaskComplexSection.cpp | 93 ++++++++++----------- src/Mod/TechDraw/Gui/TaskComplexSection.h | 6 +- 3 files changed, 47 insertions(+), 54 deletions(-) diff --git a/src/Mod/TechDraw/Gui/QGIViewPart.cpp b/src/Mod/TechDraw/Gui/QGIViewPart.cpp index c90cee99a1..b1d179875c 100644 --- a/src/Mod/TechDraw/Gui/QGIViewPart.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewPart.cpp @@ -836,8 +836,6 @@ void QGIViewPart::drawComplexSectionLine(TechDraw::DrawViewSection* viewSection, } else { std::pair dirsAligned = dcs->sectionArrowDirs(); - dirsAligned.first = DrawUtil::invertY(dirsAligned.first); - dirsAligned.second = DrawUtil::invertY(dirsAligned.second); sectionLine->setArrowDirections(dirsAligned.first, dirsAligned.second); } diff --git a/src/Mod/TechDraw/Gui/TaskComplexSection.cpp b/src/Mod/TechDraw/Gui/TaskComplexSection.cpp index 5312b8684b..4fb7846c7e 100644 --- a/src/Mod/TechDraw/Gui/TaskComplexSection.cpp +++ b/src/Mod/TechDraw/Gui/TaskComplexSection.cpp @@ -24,7 +24,6 @@ #ifndef _PreComp_ #include #include -#include #endif// #ifndef _PreComp_ #include @@ -104,6 +103,8 @@ TaskComplexSection::TaskComplexSection(TechDraw::DrawComplexSection* complexSect m_section(complexSection), m_profileObject(nullptr), m_dirName("Aligned"), + m_sectionName(m_section->getNameInDocument()), + m_savePageName(m_section->findParentPage()->getNameInDocument()), m_createMode(false), m_applyDeferred(0), m_angle(0.0), @@ -111,10 +112,8 @@ TaskComplexSection::TaskComplexSection(TechDraw::DrawComplexSection* complexSect m_modelIsDirty(false), m_scaleEdited(false) { - m_sectionName = m_section->getNameInDocument(); m_doc = m_section->getDocument(); m_page = m_section->findParentPage(); - m_savePageName = m_page->getNameInDocument(); m_baseView = dynamic_cast(m_section->BaseView.getValue()); if (m_baseView) { @@ -244,7 +243,6 @@ void TaskComplexSection::setUiCommon() //save the start conditions void TaskComplexSection::saveSectionState() { - // Base::Console().Message("TCS::saveSectionState()\n"); if (m_section) { m_saveSymbol = m_section->SectionSymbol.getValue(); m_saveScale = m_section->getScale(); @@ -265,9 +263,9 @@ void TaskComplexSection::saveSectionState() //restore the start conditions void TaskComplexSection::restoreSectionState() { - // Base::Console().Message("TCS::restoreSectionState()\n"); - if (!m_section) + if (!m_section){ return; + } m_section->SectionSymbol.setValue(m_saveSymbol); m_section->Scale.setValue(m_saveScale); @@ -302,8 +300,6 @@ void TaskComplexSection::onSectionObjectsUseSelectionClicked() //the VectorEditWidget reports a change in direction void TaskComplexSection::slotViewDirectionChanged(Base::Vector3d newDirection) { - // Base::Console().Message("TCS::slotViewDirectionChanged(%s)\n", - // DrawUtil::formatVector(newDirection).c_str()); Base::Vector3d projectedViewDirection = newDirection; if (m_baseView) { projectedViewDirection = m_baseView->projectPoint(newDirection, false); @@ -319,7 +315,6 @@ void TaskComplexSection::slotViewDirectionChanged(Base::Vector3d newDirection) //SectionNormal void TaskComplexSection::slotChangeAngle(double newAngle) { - // Base::Console().Message("TCS::slotAngleChanged(%.3f)\n", newAngle); double angleRadians = Base::toRadians(newAngle); double unitX = cos(angleRadians); double unitY = sin(angleRadians); @@ -331,7 +326,6 @@ void TaskComplexSection::slotChangeAngle(double newAngle) void TaskComplexSection::onUpClicked() { - // Base::Console().Message("TCS::onUpClicked()\n"); checkAll(false); m_compass->setToNorth(); m_viewDirectionWidget->setValueNoNotify(Base::Vector3d(0.0, 1.0, 0.0)); @@ -340,7 +334,6 @@ void TaskComplexSection::onUpClicked() void TaskComplexSection::onDownClicked() { - // Base::Console().Message("TCS::onDownClicked()\n"); checkAll(false); m_compass->setToSouth(); m_viewDirectionWidget->setValueNoNotify(Base::Vector3d(0.0, -1.0, 0.0)); @@ -349,7 +342,6 @@ void TaskComplexSection::onDownClicked() void TaskComplexSection::onLeftClicked() { - // Base::Console().Message("TCS::onLeftClicked()\n"); checkAll(false); m_compass->setToWest(); m_viewDirectionWidget->setValueNoNotify(Base::Vector3d(-1.0, 0.0, 0.0)); @@ -358,7 +350,6 @@ void TaskComplexSection::onLeftClicked() void TaskComplexSection::onRightClicked() { - // Base::Console().Message("TCS::onRightClicked()\n"); checkAll(false); m_compass->setToEast(); m_viewDirectionWidget->setValueNoNotify(Base::Vector3d(1.0, 0.0, 0.0)); @@ -481,13 +472,11 @@ QString TaskComplexSection::sourcesToString() //****************************************************************************** bool TaskComplexSection::apply(bool forceUpdate) { - // Base::Console().Message("TCS::apply() - liveUpdate: %d force: %d\n", - // ui->cbLiveUpdate->isChecked(), forceUpdate); if (!ui->cbLiveUpdate->isChecked() && !forceUpdate) { //nothing to do m_applyDeferred++; QString msgLiteral = - QString::fromUtf8(QT_TRANSLATE_NOOP("TaskPojGroup", " updates pending")); + QString::fromUtf8(QT_TRANSLATE_NOOP("TaskComplexSection", " updates pending")); QString msgNumber = QString::number(m_applyDeferred); ui->lPendingUpdates->setText(msgNumber + msgLiteral); return false; @@ -518,6 +507,9 @@ bool TaskComplexSection::apply(bool forceUpdate) if (!m_section) { createComplexSection(); + if (!isSectionValid()) { + return false; + } } if (isSectionValid()) { @@ -531,6 +523,11 @@ bool TaskComplexSection::apply(bool forceUpdate) if (isBaseValid()) { m_baseView->requestPaint(); } + if (!m_section->checkSectionCS()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Possible Coordinate System Error"), + QObject::tr("Check SectionNormal, Direction and/or XDirection.")); + } + enableAll(true); checkAll(false); @@ -543,7 +540,6 @@ bool TaskComplexSection::apply(bool forceUpdate) void TaskComplexSection::applyAligned() { - // Base::Console().Message("TCS::applyAligned()\n"); m_dirName = "Aligned"; enableAll(true); m_directionIsSet = true; @@ -557,8 +553,6 @@ void TaskComplexSection::applyAligned() //pointer to created view is not returned, but stored in m_section void TaskComplexSection::createComplexSection() { - // Base::Console().Message("TCS::createComplexSection()\n"); - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Create ComplexSection")); if (!m_section) { const std::string objectName{QT_TR_NOOP("ComplexSection")}; @@ -571,6 +565,7 @@ void TaskComplexSection::createComplexSection() // unique Labels QString qTemp = ui->leSymbol->text(); std::string temp = qTemp.toStdString(); + //NOLINTBEGIN Command::doCommand(Command::Doc, "App.ActiveDocument.%s.SectionSymbol = '%s'", m_sectionName.c_str(), temp.c_str()); @@ -583,8 +578,6 @@ void TaskComplexSection::createComplexSection() Command::doCommand(Command::Doc, "App.ActiveDocument.%s.Scale = %0.6f", m_sectionName.c_str(), ui->sbScale->value()); - std::string baseName = m_baseView->getNameInDocument(); - Command::doCommand(Command::Doc, "App.ActiveDocument.%s.Scale = %0.7f", m_sectionName.c_str(), ui->sbScale->value()); @@ -600,6 +593,7 @@ void TaskComplexSection::createComplexSection() m_sectionName.c_str()); Command::doCommand(Command::Doc, "App.activeDocument().%s.SectionDirection = 'Aligned'", m_sectionName.c_str()); + //NOLINTEND App::DocumentObject* newObj = m_page->getDocument()->getObject(m_sectionName.c_str()); m_section = dynamic_cast(newObj); @@ -608,6 +602,7 @@ void TaskComplexSection::createComplexSection() } Base::Vector3d localUnit = m_viewDirectionWidget->value(); if (m_baseView) { + //NOLINTNEXTLINE Command::doCommand(Command::Doc, "App.ActiveDocument.%s.BaseView = App.ActiveDocument.%s", m_sectionName.c_str(), m_baseView->getNameInDocument()); @@ -624,6 +619,7 @@ void TaskComplexSection::createComplexSection() //if we have not changed the direction, we should use the 3d directions saved in the //constructor m_section->SectionNormal.setValue(m_saveNormal); + m_section->Direction.setValue(m_saveNormal); m_section->XDirection.setValue(m_saveXDir); } m_section->Source.setValues(m_shapes); @@ -637,6 +633,7 @@ void TaskComplexSection::createComplexSection() //auto orientation of view relative to base view double viewDirectionAngle = m_compass->positiveValue(); double rotation = requiredRotation(viewDirectionAngle); + //NOLINTNEXTLINE Command::doCommand(Command::Doc, "App.ActiveDocument.%s.Rotation = %.6f", m_sectionName.c_str(), rotation); @@ -646,7 +643,6 @@ void TaskComplexSection::createComplexSection() void TaskComplexSection::updateComplexSection() { - // Base::Console().Message("TCS:;updateComplexSection()\n"); if (!isSectionValid()) { failNoObject(); return; @@ -656,6 +652,7 @@ void TaskComplexSection::updateComplexSection() if (m_section) { QString qTemp = ui->leSymbol->text(); std::string temp = qTemp.toStdString(); + //NOLINTBEGIN Command::doCommand(Command::Doc, "App.ActiveDocument.%s.SectionSymbol = '%s'", m_sectionName.c_str(), temp.c_str()); @@ -665,8 +662,6 @@ void TaskComplexSection::updateComplexSection() Command::doCommand(Command::Doc, "App.activeDocument().%s.translateLabel('DrawViewSection', 'Section', '%s')", m_sectionName.c_str(), makeSectionLabel(qTemp).c_str()); - std::string baseName = m_baseView->getNameInDocument(); - Command::doCommand(Command::Doc, "App.ActiveDocument.%s.Scale = %0.7f", m_sectionName.c_str(), ui->sbScale->value()); @@ -678,6 +673,8 @@ void TaskComplexSection::updateComplexSection() m_sectionName.c_str(), projectionStrategy); Command::doCommand(Command::Doc, "App.activeDocument().%s.SectionDirection = 'Aligned'", m_sectionName.c_str()); + //NOLINTEND + m_section->CuttingToolWireObject.setValue(m_profileObject); m_section->SectionDirection.setValue("Aligned"); Base::Vector3d localUnit = m_viewDirectionWidget->value(); @@ -695,13 +692,15 @@ void TaskComplexSection::updateComplexSection() //auto orientation of view relative to base view double viewDirectionAngle = m_compass->positiveValue(); double rotation = requiredRotation(viewDirectionAngle); + + //NOLINTNEXTLINE Command::doCommand(Command::Doc, "App.ActiveDocument.%s.Rotation = %.6f", m_sectionName.c_str(), rotation); } Gui::Command::commitCommand(); } -std::string TaskComplexSection::makeSectionLabel(QString symbol) +std::string TaskComplexSection::makeSectionLabel(const QString& symbol) { const std::string objectName{QT_TR_NOOP("ComplexSection")}; std::string uniqueSuffix{m_sectionName.substr(objectName.length(), std::string::npos)}; @@ -710,7 +709,7 @@ std::string TaskComplexSection::makeSectionLabel(QString symbol) return ( uniqueLabel + " " + temp + " - " + temp ); } -void TaskComplexSection::failNoObject(void) +void TaskComplexSection::failNoObject() { QString qsectionName = QString::fromStdString(m_sectionName); QString qbaseName = QString::fromStdString(m_saveBaseName); @@ -721,34 +720,32 @@ void TaskComplexSection::failNoObject(void) bool TaskComplexSection::isBaseValid() { - if (!m_baseView) + if (!m_baseView) { return false; + } App::DocumentObject* baseObj = m_doc->getObject(m_saveBaseName.c_str()); - if (!baseObj) - return false; - - return true; + return baseObj != nullptr; } bool TaskComplexSection::isSectionValid() { - if (!m_section) + if (!m_section) { return false; + } App::DocumentObject* sectionObj = m_doc->getObject(m_sectionName.c_str()); - if (!sectionObj) - return false; - - return true; + return sectionObj != nullptr; } //get required rotation from input angle in [0, 360] //NOTE: shared code with simple section - reuse opportunity -double TaskComplexSection::requiredRotation(double inputAngle) +double TaskComplexSection::requiredRotation(double inputAngleDeg) { - double rotation = inputAngle - 90.0; - if (rotation == 180.0) { + constexpr double PiOver4Degrees{90}; + constexpr double PiOver2Degrees{180}; + double rotation = inputAngleDeg - PiOver4Degrees; + if (rotation == PiOver2Degrees) { //if the view direction is 90/270, then the section is drawn properly and no //rotation is needed. 90.0 becomes 0.0, but 270.0 needs special handling. rotation = 0.0; @@ -759,16 +756,15 @@ double TaskComplexSection::requiredRotation(double inputAngle) //****************************************************************************** bool TaskComplexSection::accept() { - // Base::Console().Message("TCS::accept()\n"); apply(true); - Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); + Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); //NOLINT return true; } bool TaskComplexSection::reject() { if (!m_section) {//no section created, nothing to undo - Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); + Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); //NOLINT return false; } @@ -776,17 +772,19 @@ bool TaskComplexSection::reject() if (isBaseValid()) { m_baseView->requestPaint(); } - Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); + Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); //NOLINT return false; } if (m_createMode) { std::string SectionName = m_section->getNameInDocument(); + //NOLINTBEGIN Gui::Command::doCommand(Gui::Command::Gui, "App.ActiveDocument.%s.removeView(App.ActiveDocument.%s)", m_savePageName.c_str(), SectionName.c_str()); Gui::Command::doCommand(Gui::Command::Gui, "App.ActiveDocument.removeObject('%s')", SectionName.c_str()); + //NOLINTEND } else { if (m_modelIsDirty) { restoreSectionState(); @@ -799,7 +797,7 @@ bool TaskComplexSection::reject() m_baseView->requestPaint(); } Gui::Command::updateActive(); - Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); + Gui::Command::doCommand(Gui::Command::Gui, "Gui.ActiveDocument.resetEdit()"); //NOLINT return false; } @@ -818,7 +816,6 @@ TaskDlgComplexSection::TaskDlgComplexSection(TechDraw::DrawPage* page, std::vector xShapes, App::DocumentObject* profileObject, std::vector profileSubs) - : TaskDialog() { widget = new TaskComplexSection(page, baseView, shapes, xShapes, profileObject, profileSubs); taskbox = @@ -829,9 +826,8 @@ TaskDlgComplexSection::TaskDlgComplexSection(TechDraw::DrawPage* page, } TaskDlgComplexSection::TaskDlgComplexSection(TechDraw::DrawComplexSection* complexSection) - : TaskDialog() + : widget(new TaskComplexSection(complexSection)) { - widget = new TaskComplexSection(complexSection); taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("actions/TechDraw_ComplexSection"), widget->windowTitle(), true, nullptr); @@ -839,8 +835,6 @@ TaskDlgComplexSection::TaskDlgComplexSection(TechDraw::DrawComplexSection* compl Content.push_back(taskbox); } -TaskDlgComplexSection::~TaskDlgComplexSection() {} - void TaskDlgComplexSection::update() { // widget->updateTask(); @@ -861,4 +855,5 @@ bool TaskDlgComplexSection::reject() return true; } +//NOLINTNEXTLINE #include diff --git a/src/Mod/TechDraw/Gui/TaskComplexSection.h b/src/Mod/TechDraw/Gui/TaskComplexSection.h index 49ed6b7e67..ba80c36ee7 100644 --- a/src/Mod/TechDraw/Gui/TaskComplexSection.h +++ b/src/Mod/TechDraw/Gui/TaskComplexSection.h @@ -107,7 +107,7 @@ protected Q_SLOTS: private: double requiredRotation(double inputAngle); - std::string makeSectionLabel(QString symbol); + std::string makeSectionLabel(const QString& symbol); void createComplexSection(); void updateComplexSection(); @@ -161,8 +161,8 @@ public: std::vector xShapes, App::DocumentObject* profileObject, std::vector profileSubs); - TaskDlgComplexSection(TechDraw::DrawComplexSection* page); - ~TaskDlgComplexSection() override; + explicit TaskDlgComplexSection(TechDraw::DrawComplexSection* page) ; + ~TaskDlgComplexSection() override = default; public: /// is called the TaskView when the dialog is opened From b4a9c2222c1336f8381724eecb6426ce78927242 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Tue, 29 Apr 2025 09:22:11 -0400 Subject: [PATCH 3/3] [TD]Lint brushing --- src/Mod/TechDraw/App/DrawComplexSection.cpp | 7 +- src/Mod/TechDraw/App/DrawComplexSection.h | 2 +- src/Mod/TechDraw/App/DrawViewSection.cpp | 115 +++++++++----------- src/Mod/TechDraw/App/DrawViewSection.h | 12 +- src/Mod/TechDraw/Gui/TaskComplexSection.cpp | 4 +- 5 files changed, 63 insertions(+), 77 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawComplexSection.cpp b/src/Mod/TechDraw/App/DrawComplexSection.cpp index de5fe95b09..76425f6a30 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.cpp +++ b/src/Mod/TechDraw/App/DrawComplexSection.cpp @@ -555,7 +555,7 @@ TopoDS_Compound DrawComplexSection::alignedToolIntersections(const TopoDS_Shape& return result; } -TopoDS_Compound DrawComplexSection::alignSectionFaces(TopoDS_Shape faceIntersections) +TopoDS_Compound DrawComplexSection::alignSectionFaces(const TopoDS_Shape& faceIntersections) { if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour @@ -624,7 +624,6 @@ gp_Vec DrawComplexSection::makeProfileVector(const TopoDS_Wire& profileWire) //make drawable td geometry for section line BaseGeomPtrVector DrawComplexSection::makeSectionLineGeometry() { - // Base::Console().Message("DCS::makeSectionLineGeometry()\n"); BaseGeomPtrVector result; auto* baseDvp = freecad_cast(BaseView.getValue()); if (baseDvp) { @@ -643,7 +642,6 @@ BaseGeomPtrVector DrawComplexSection::makeSectionLineGeometry() //get the end points of the section wire std::pair DrawComplexSection::sectionLineEnds() { - // Base::Console().Message("DCS::sectionLineEnds()\n"); std::pair result; TopoDS_Wire lineWire = makeSectionLineWire(); if (lineWire.IsNull()) { @@ -744,7 +742,6 @@ TopoDS_Wire DrawComplexSection::makeSectionLineWire() //of the profile before and after the point ChangePointVector DrawComplexSection::getChangePointsFromSectionLine() { - // Base::Console().Message("DCS::getChangePointsFromSectionLine()\n"); ChangePointVector result; std::vector allPoints; DrawViewPart* baseDvp = freecad_cast(BaseView.getValue()); @@ -796,7 +793,6 @@ ChangePointVector DrawComplexSection::getChangePointsFromSectionLine() gp_Ax2 DrawComplexSection::getCSFromBase(const std::string& sectionName) const { - // Base::Console().Message("DCS::getCSFromBase()\n"); App::DocumentObject* base = BaseView.getValue(); if (!base || !base->isDerivedFrom()) {//is second clause necessary? @@ -1052,7 +1048,6 @@ TopoDS_Shape DrawComplexSection::shapeShapeIntersect(const TopoDS_Shape& shape0, std::vector DrawComplexSection::faceShapeIntersect(const TopoDS_Face& face, const TopoDS_Shape& shape) { - // Base::Console().Message("DCS::faceShapeIntersect()\n"); TopoDS_Shape intersect = shapeShapeIntersect(face, shape); if (intersect.IsNull()) { return {}; diff --git a/src/Mod/TechDraw/App/DrawComplexSection.h b/src/Mod/TechDraw/App/DrawComplexSection.h index 7ec068e77e..83f3a9852d 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.h +++ b/src/Mod/TechDraw/App/DrawComplexSection.h @@ -71,7 +71,7 @@ public: TopoDS_Shape getShapeToPrepare() const override; TopoDS_Shape getShapeToIntersect() override; gp_Pln getSectionPlane() const override; - TopoDS_Compound alignSectionFaces(TopoDS_Shape faceIntersections) override; + TopoDS_Compound alignSectionFaces(const TopoDS_Shape& faceIntersections) override; std::pair sectionLineEnds() override; void makeSectionCut(const TopoDS_Shape& baseShape) override; diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index 994e50ace8..8f6e5dd597 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -100,11 +100,11 @@ using namespace TechDraw; using DU = DrawUtil; // class to store geometry of points where the section line changes direction -ChangePoint::ChangePoint(QPointF location, QPointF preDirection, QPointF postDirection) +ChangePoint::ChangePoint(QPointF location, QPointF preDirection, QPointF postDirection) : + m_location(location), + m_preDirection(preDirection), + m_postDirection(postDirection) { - m_location = location; - m_preDirection = preDirection; - m_postDirection = postDirection; } ChangePoint::ChangePoint(gp_Pnt location, gp_Dir preDirection, gp_Dir postDirection) @@ -122,10 +122,12 @@ void ChangePoint::scale(double scaleFactor) m_location = m_location * scaleFactor; } +//NOLINTBEGIN const char* DrawViewSection::SectionDirEnums[] = {"Right", "Left", "Up", "Down", "Aligned", nullptr}; const char* DrawViewSection::CutSurfaceEnums[] = {"Hide", "Color", "SvgHatch", "PatHatch", nullptr}; +//NOLINTEND constexpr double stretchMinimum{EWTOLERANCE}; constexpr double stretchMaximum{std::numeric_limits::max()}; @@ -174,7 +176,7 @@ DrawViewSection::DrawViewSection() // TODO: SectionDirection is a legacy from when SectionViews were only // available along cardinal directions. It should be made obsolete and // replaced with Aligned sections and local unit vectors. - SectionDirection.setEnums(SectionDirEnums); + SectionDirection.setEnums(SectionDirEnums); //NOLINT ADD_PROPERTY_TYPE(SectionDirection, ((long)0), sgroup, @@ -199,7 +201,7 @@ DrawViewSection::DrawViewSection() "Use the cut shape from the base view instead of the original object"); // properties related to the display of the cut surface - CutSurfaceDisplay.setEnums(CutSurfaceEnums); + CutSurfaceDisplay.setEnums(CutSurfaceEnums); //NOLINT ADD_PROPERTY_TYPE(CutSurfaceDisplay, (prefCutSurface()), fgroup, @@ -362,7 +364,7 @@ TopoDS_Shape DrawViewSection::getShapeToCut() TechDraw::DrawViewSection* dvs = nullptr; TechDraw::DrawViewDetail* dvd = nullptr; if (!base) { - return TopoDS_Shape(); + return {}; } TopoDS_Shape shapeToCut; @@ -388,7 +390,7 @@ TopoDS_Shape DrawViewSection::getShapeToCut() } else { Base::Console().Message("DVS::getShapeToCut - base is weird\n"); - return TopoDS_Shape(); + return {}; } return shapeToCut; } @@ -409,13 +411,13 @@ App::DocumentObjectExecReturn* DrawViewSection::execute() } if (waitingForCut() || waitingForHlr()) { - return DrawView::execute(); + return DrawView::execute(); //NOLINT } TopoDS_Shape baseShape = getShapeToCut(); if (baseShape.IsNull()) { - return DrawView::execute(); + return DrawView::execute(); //NOLINT } // is SectionOrigin valid? @@ -445,16 +447,13 @@ App::DocumentObjectExecReturn* DrawViewSection::execute() sectionExec(baseShape); addPoints(); - return DrawView::execute(); + return DrawView::execute(); //NOLINT } bool DrawViewSection::isBaseValid() const { App::DocumentObject* base = BaseView.getValue(); - if (base && base->isDerivedFrom()) { - return true; - } - return false; + return base && base->isDerivedFrom(); } void DrawViewSection::sectionExec(TopoDS_Shape& baseShape) @@ -613,15 +612,14 @@ TopoDS_Shape DrawViewSection::makeCuttingTool(double shapeSize) gp_Pln pln = getSectionPlane(); gp_Dir gpNormal = pln.Axis().Direction(); BRepBuilderAPI_MakeFace mkFace(pln, -shapeSize, shapeSize, -shapeSize, shapeSize); - TopoDS_Face aProjFace = mkFace.Face(); - if (aProjFace.IsNull()) { - return TopoDS_Shape(); + if (mkFace.Face().IsNull()) { + return {}; } if (debugSection()) { - BRepTools::Write(aProjFace, "DVSSectionFace.brep");// debug + BRepTools::Write(mkFace.Face(), "DVSSectionFace.brep");// debug } gp_Vec extrudeDir = shapeSize * gp_Vec(gpNormal); - return BRepPrimAPI_MakePrism(aProjFace, extrudeDir, false, true).Shape(); + return BRepPrimAPI_MakePrism(mkFace.Face(), extrudeDir, false, true).Shape(); } void DrawViewSection::onSectionCutFinished() @@ -646,7 +644,7 @@ void DrawViewSection::onSectionCutFinished() } // activities that depend on updated geometry object -void DrawViewSection::postHlrTasks(void) +void DrawViewSection::postHlrTasks() { DrawViewPart::postHlrTasks(); @@ -683,7 +681,7 @@ void DrawViewSection::postHlrTasks(void) } m_tdSectionFaces = makeTDSectionFaces(m_sectionTopoDSFaces); - TechDraw::DrawViewPart* dvp = dynamic_cast(BaseView.getValue()); + auto* dvp = dynamic_cast(BaseView.getValue()); if (dvp) { dvp->requestPaint();// to refresh section line } @@ -705,10 +703,7 @@ void DrawViewSection::postSectionCutTasks() bool DrawViewSection::waitingForResult() const { - if (DrawViewPart::waitingForResult() || waitingForCut()) { - return true; - } - return false; + return DrawViewPart::waitingForResult() || waitingForCut(); } gp_Pln DrawViewSection::getSectionPlane() const @@ -716,7 +711,7 @@ gp_Pln DrawViewSection::getSectionPlane() const gp_Ax2 viewAxis = getSectionCS(); gp_Ax3 viewAxis3(viewAxis); - return gp_Pln(viewAxis3); + return {viewAxis3}; } //! tries to find the intersection of the section plane with the shape giving a @@ -732,7 +727,7 @@ TopoDS_Compound DrawViewSection::findSectionPlaneIntersections(const TopoDS_Shap Base::Console().Warning( "DrawViewSection::findSectionPlaneInter - %s - input shape is Null\n", getNameInDocument()); - return TopoDS_Compound(); + return {}; } gp_Pln plnSection = getSectionPlane(); @@ -765,7 +760,7 @@ TopoDS_Compound DrawViewSection::findSectionPlaneIntersections(const TopoDS_Shap } // move section faces to line up with cut shape -TopoDS_Compound DrawViewSection::alignSectionFaces(TopoDS_Shape faceIntersections) +TopoDS_Compound DrawViewSection::alignSectionFaces(const TopoDS_Shape& faceIntersections) { TopoDS_Compound sectionFaces; TopoDS_Shape centeredShape = @@ -784,7 +779,7 @@ TopoDS_Compound DrawViewSection::alignSectionFaces(TopoDS_Shape faceIntersection return mapToPage(scaledSection); } -TopoDS_Compound DrawViewSection::mapToPage(TopoDS_Shape& shapeToAlign) +TopoDS_Compound DrawViewSection::mapToPage(const TopoDS_Shape& shapeToAlign) { // shapeToAlign is compound of TopoDS_Face intersections, but aligned to // pln(origin, sectionNormal) needs to be aligned to paper plane (origin, @@ -829,7 +824,7 @@ TopoDS_Compound DrawViewSection::mapToPage(TopoDS_Shape& shapeToAlign) wireEdges.push_back(edge); } - TopoDS_Wire cleanWire = EdgeWalker::makeCleanWire(wireEdges, 2.0 * EWTOLERANCE); + TopoDS_Wire cleanWire = EdgeWalker::makeCleanWire(wireEdges, 2 * EWTOLERANCE); faceWires.push_back(cleanWire); } @@ -890,14 +885,14 @@ TopoDS_Shape DrawViewSection::makeFaceFromWires(std::vector& inWire TopoDS_Wire orientedWire = TopoDS::Wire(orientedShape); orientedWire.Orientation(TopAbs_FORWARD); TopoDS_Face blankFace = BRepBuilderAPI_MakeFace(orientedWire); - int wireCount = goodWires.size(); + size_t wireCount = goodWires.size(); if (wireCount < 2) { faceToFix = blankFace; } else { // add the holes BRepBuilderAPI_MakeFace mkFace(blankFace); - for (int iWire = 1; iWire < wireCount; iWire++) { + for (size_t iWire = 1; iWire < wireCount; iWire++) { // make holes in the face with the rest of the wires orientedShape = goodWires.at(iWire).Oriented(TopAbs_REVERSED); orientedWire = TopoDS::Wire(orientedShape); @@ -907,7 +902,7 @@ TopoDS_Shape DrawViewSection::makeFaceFromWires(std::vector& inWire if (!mkFace.IsDone()) { Base::Console().Warning("DVS::makeFaceFromWires - %s - failed to make section face.\n", getNameInDocument()); - return TopoDS_Shape(); + return {}; } faceToFix = mkFace.Face(); } @@ -921,7 +916,7 @@ TopoDS_Shape DrawViewSection::makeFaceFromWires(std::vector& inWire } // turn OCC section faces into TD geometry -std::vector DrawViewSection::makeTDSectionFaces(TopoDS_Compound topoDSFaces) +std::vector DrawViewSection::makeTDSectionFaces(const TopoDS_Compound& topoDSFaces) { // Base::Console().Message("DVS::makeTDSectionFaces()\n"); std::vector tdSectionFaces; @@ -931,7 +926,7 @@ std::vector DrawViewSection::makeTDSectionFaces(TopoDS_Compou TechDraw::FacePtr sectionFace(std::make_shared()); TopExp_Explorer expFace(face, TopAbs_WIRE); for (; expFace.More(); expFace.Next()) { - TechDraw::Wire* w = new TechDraw::Wire(); + auto* w = new TechDraw::Wire(); const TopoDS_Wire& wire = TopoDS::Wire(expFace.Current()); TopExp_Explorer expWire(wire, TopAbs_EDGE); for (; expWire.More(); expWire.Next()) { @@ -958,7 +953,7 @@ std::pair DrawViewSection::sectionLineEnds() Base::Vector3d sectionOrg = SectionOrigin.getValue() - getBaseDVP()->getOriginalCentroid(); sectionOrg = getBaseDVP()->projectPoint(sectionOrg);// convert to base view CS - double halfSize = (getBaseDVP()->getSizeAlongVector(dir) / 2.0) * SectionLineStretch.getValue(); + double halfSize = (getBaseDVP()->getSizeAlongVector(dir) / 2) * SectionLineStretch.getValue(); result.first = sectionOrg + dir * halfSize; result.second = sectionOrg - dir * halfSize; @@ -984,14 +979,14 @@ ChangePointVector DrawViewSection::getChangePointsFromSectionLine() // Base::Console().Message("Dvs::getChangePointsFromSectionLine()\n"); ChangePointVector result; std::vector allPoints; - DrawViewPart* baseDvp = freecad_cast(BaseView.getValue()); + auto* baseDvp = freecad_cast(BaseView.getValue()); if (baseDvp) { std::pair lineEnds = sectionLineEnds(); // make start and end marks - gp_Pnt location0 = Base::convertTo(lineEnds.first); - gp_Pnt location1 = Base::convertTo(lineEnds.second); - gp_Dir postDir = gp_Dir(location1.XYZ() - location0.XYZ()); - gp_Dir preDir = postDir.Reversed(); + auto location0 = Base::convertTo(lineEnds.first); + auto location1 = Base::convertTo(lineEnds.second); + auto postDir = gp_Dir(location1.XYZ() - location0.XYZ()); + auto preDir = postDir.Reversed(); ChangePoint startPoint(location0, preDir, postDir); result.push_back(startPoint); preDir = gp_Dir(location0.XYZ() - location1.XYZ()); @@ -1005,7 +1000,7 @@ ChangePointVector DrawViewSection::getChangePointsFromSectionLine() // this should really be in BoundBox.h //! check if point is in box or on boundary of box //! compare to isInBox which doesn't allow on boundary -bool DrawViewSection::isReallyInBox(const Base::Vector3d vec, const Base::BoundBox3d bb) const +bool DrawViewSection::isReallyInBox(const Base::Vector3d& vec, const Base::BoundBox3d& bb) const { if (vec.x <= bb.MinX || vec.x >= bb.MaxX) { return false; @@ -1050,8 +1045,6 @@ Base::Vector3d DrawViewSection::getXDirection() const void DrawViewSection::setCSFromBase(const std::string& sectionName) { - // Base::Console().Message("DVS::setCSFromBase(%s)\n", - // sectionName.c_str()); gp_Dir gDir = getCSFromBase(sectionName).Direction(); Base::Vector3d vDir(gDir.X(), gDir.Y(), gDir.Z()); Direction.setValue(vDir); @@ -1080,12 +1073,12 @@ void DrawViewSection::setCSFromBase(const Base::Vector3d& localUnit) // reset the section CS based on an XY vector in current section CS void DrawViewSection::setCSFromLocalUnit(const Base::Vector3d& localUnit) { - gp_Dir verticalDir = getSectionCS().YDirection(); + auto verticalDir = getSectionCS().YDirection(); gp_Ax1 verticalAxis(Base::convertTo(SectionOrigin.getValue()), verticalDir); - gp_Dir oldNormal = getSectionCS().Direction(); - gp_Dir newNormal = Base::convertTo(projectPoint(localUnit)); - double angle = oldNormal.AngleWithRef(newNormal, verticalDir); - gp_Ax2 newCS = getSectionCS().Rotated(verticalAxis, angle); + auto oldNormal = getSectionCS().Direction(); + auto newNormal = Base::convertTo(projectPoint(localUnit)); + auto angle = oldNormal.AngleWithRef(newNormal, verticalDir); + auto newCS = getSectionCS().Rotated(verticalAxis, angle); SectionNormal.setValue(Base::convertTo(newCS.Direction())); XDirection.setValue(Base::convertTo(newCS.XDirection())); } @@ -1196,14 +1189,14 @@ TopoDS_Face DrawViewSection::getSectionTopoDSFace(int i) return TopoDS::Face(expl.Current()); } } - return TopoDS_Face(); + return {}; } TechDraw::DrawViewPart* DrawViewSection::getBaseDVP() const { App::DocumentObject* base = BaseView.getValue(); if (base && base->isDerivedFrom()) { - TechDraw::DrawViewPart* baseDVP = static_cast(base); + auto* baseDVP = static_cast(base); return baseDVP; } return nullptr; @@ -1283,16 +1276,13 @@ bool DrawViewSection::checkSectionCS() const } auto orthoDot = std::fabs(vNormal.Dot(vXDirection)); - if (orthoDot > EWTOLERANCE) { - return false; - } - return true; + return orthoDot <= EWTOLERANCE; } // hatch file routines // create geometric hatch lines -void DrawViewSection::makeLineSets(void) +void DrawViewSection::makeLineSets() { if (PatIncluded.isEmpty()) { return; @@ -1315,7 +1305,7 @@ void DrawViewSection::makeLineSets(void) } } -void DrawViewSection::replaceSvgIncluded(std::string newSvgFile) +void DrawViewSection::replaceSvgIncluded(const std::string& newSvgFile) { if (newSvgFile.empty()) { return; @@ -1330,7 +1320,7 @@ void DrawViewSection::replaceSvgIncluded(std::string newSvgFile) } } -void DrawViewSection::replacePatIncluded(std::string newPatFile) +void DrawViewSection::replacePatIncluded(const std::string& newPatFile) { if (newPatFile.empty()) { return; @@ -1353,18 +1343,19 @@ void DrawViewSection::getParameters() FuseBeforeCut.setValue(fuseFirst); } -bool DrawViewSection::debugSection(void) const +bool DrawViewSection::debugSection() const { return Preferences::getPreferenceGroup("debug")->GetBool("debugSection", false); } -int DrawViewSection::prefCutSurface(void) const +int DrawViewSection::prefCutSurface() const { + //NOLINTNEXTLINE return Preferences::getPreferenceGroup("Decorations") ->GetInt("CutSurfaceDisplay", 2);// default to SvgHatch } -bool DrawViewSection::showSectionEdges(void) +bool DrawViewSection::showSectionEdges() { return Preferences::getPreferenceGroup("General")->GetBool("ShowSectionEdges", true); } diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index b38e6b8329..5d85978511 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -110,7 +110,7 @@ public: App::PropertyFloatConstraint SectionLineStretch; // new v022 //NOLINTEND - bool isReallyInBox(const Base::Vector3d vec, const Base::BoundBox3d bb) const; + bool isReallyInBox(const Base::Vector3d& vec, const Base::BoundBox3d& bb) const; bool isReallyInBox(const gp_Pnt& point, const Bnd_Box& bb) const; App::DocumentObjectExecReturn* execute() override; @@ -151,9 +151,9 @@ public: //section face related methods std::vector getTDFaceGeometry() { return m_tdSectionFaces; } TopoDS_Face getSectionTopoDSFace(int i); - virtual TopoDS_Compound alignSectionFaces(TopoDS_Shape faceIntersections); - TopoDS_Compound mapToPage(TopoDS_Shape& shapeToAlign); - virtual std::vector makeTDSectionFaces(TopoDS_Compound topoDSFaces); + virtual TopoDS_Compound alignSectionFaces(const TopoDS_Shape& faceIntersections); + TopoDS_Compound mapToPage(const TopoDS_Shape& shapeToAlign); + virtual std::vector makeTDSectionFaces(const TopoDS_Compound& topoDSFaces); virtual TopoDS_Shape getShapeToIntersect() { return m_cutPieces; } void makeLineSets(); @@ -200,8 +200,8 @@ protected: void onDocumentRestored() override; void setupObject() override; - void replaceSvgIncluded(std::string newSvgFile); - void replacePatIncluded(std::string newPatFile); + void replaceSvgIncluded(const std::string& newSvgFile); + void replacePatIncluded(const std::string& newPatFile); TopoDS_Shape m_cutPieces;//the shape after cutting, but before centering & scaling gp_Ax2 m_projectionCS; diff --git a/src/Mod/TechDraw/Gui/TaskComplexSection.cpp b/src/Mod/TechDraw/Gui/TaskComplexSection.cpp index 4fb7846c7e..a62a1fa41c 100644 --- a/src/Mod/TechDraw/Gui/TaskComplexSection.cpp +++ b/src/Mod/TechDraw/Gui/TaskComplexSection.cpp @@ -166,7 +166,7 @@ void TaskComplexSection::setUiPrimary() std::pair dirs = DrawGuiUtil::get3DDirAndRot(); m_saveNormal = dirs.first; m_saveXDir = dirs.second; - m_viewDirectionWidget->setValue(m_saveNormal * -1.0);//this will propagate to m_compass + m_viewDirectionWidget->setValue(m_saveNormal * -1);//this will propagate to m_compass } //don't allow updates until a direction is picked @@ -195,7 +195,7 @@ void TaskComplexSection::setUiEdit() Base::Vector3d projectedViewDirection = m_baseView->projectPoint(sectionNormalVec, false); double viewAngle = atan2(-projectedViewDirection.y, -projectedViewDirection.x); m_compass->setDialAngle(Base::toDegrees(viewAngle)); - m_viewDirectionWidget->setValueNoNotify(projectedViewDirection * -1.0); + m_viewDirectionWidget->setValueNoNotify(projectedViewDirection * -1); } else { //no local angle makes sense if there is no baseView?