From 02386e31500edbf3f92227b2be25cf4cfd8a3b49 Mon Sep 17 00:00:00 2001 From: wandererfan Date: Mon, 5 Dec 2022 13:11:30 -0500 Subject: [PATCH] [TD]move makeAlignedPieces to separate thread - correct ComplexSection rotation - fix fail to load CS for some profiles and directions --- src/Mod/TechDraw/App/DrawComplexSection.cpp | 218 +++++++++++------- src/Mod/TechDraw/App/DrawComplexSection.h | 21 +- src/Mod/TechDraw/App/DrawViewDimension.cpp | 47 ++-- src/Mod/TechDraw/App/DrawViewPart.cpp | 8 +- src/Mod/TechDraw/App/DrawViewSection.cpp | 54 +++-- src/Mod/TechDraw/App/DrawViewSection.h | 2 +- src/Mod/TechDraw/Gui/TaskComplexSection.cpp | 28 +++ src/Mod/TechDraw/Gui/TaskComplexSection.h | 2 + .../TechDraw/Gui/ViewProviderDimension.cpp | 23 +- 9 files changed, 250 insertions(+), 153 deletions(-) diff --git a/src/Mod/TechDraw/App/DrawComplexSection.cpp b/src/Mod/TechDraw/App/DrawComplexSection.cpp index cc3de3c2ec..e31b6fd0e3 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.cpp +++ b/src/Mod/TechDraw/App/DrawComplexSection.cpp @@ -81,6 +81,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -129,12 +132,12 @@ using DU = DrawUtil; PROPERTY_SOURCE(TechDraw::DrawComplexSection, TechDraw::DrawViewSection) -const char *DrawComplexSection::ProjectionStrategyEnums[] = {"Offset", "Aligned", "NoParallel", +const char* DrawComplexSection::ProjectionStrategyEnums[] = {"Offset", "Aligned", "NoParallel", nullptr}; DrawComplexSection::DrawComplexSection() { - static const char *fgroup = "Cutting Tool"; + static const char* fgroup = "Cutting Tool"; ADD_PROPERTY_TYPE(CuttingToolWireObject, (nullptr), fgroup, App::Prop_None, "A sketch that describes the cutting tool"); @@ -147,7 +150,7 @@ DrawComplexSection::DrawComplexSection() TopoDS_Shape DrawComplexSection::getShapeToCut() { // Base::Console().Message("DCS::getShapeToCut()\n"); - App::DocumentObject *base = BaseView.getValue(); + App::DocumentObject* base = BaseView.getValue(); TopoDS_Shape shapeToCut; if (base && base == this) { shapeToCut = getSourceShape(); @@ -172,7 +175,7 @@ TopoDS_Shape DrawComplexSection::getShapeToCut() TopoDS_Shape DrawComplexSection::makeCuttingTool(double dMax) { - // Base::Console().Message("DCS::makeCuttingTool()\n"); +// Base::Console().Message("DCS::makeCuttingTool()\n"); TopoDS_Wire profileWire = makeProfileWire(); if (profileWire.IsNull()) { throw Base::RuntimeError("Can not make wire from cutting tool (1)"); @@ -244,6 +247,7 @@ TopoDS_Shape DrawComplexSection::makeCuttingTool(double dMax) TopoDS_Shape DrawComplexSection::getShapeToPrepare() const { + // Base::Console().Message("DCS::getShapeToPrepare()\n"); if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour return DrawViewSection::getShapeToPrepare(); @@ -253,49 +257,84 @@ 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) +TopoDS_Shape DrawComplexSection::prepareShape(const TopoDS_Shape& cutShape, double shapeSize) { -// Base::Console().Message("DCS::prepareShape() - strategy: %d\n", ProjectionStrategy.getValue()); + // Base::Console().Message("DCS::prepareShape() - strategy: %d\n", ProjectionStrategy.getValue()); if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour return DrawViewSection::prepareShape(cutShape, shapeSize); } //"Aligned" projection (Aligned Section) - TopoDS_Shape alignedResult; - try { - alignedResult = makeAlignedPieces(cutShape, m_toolFaceShape, shapeSize); - } - catch (Base::RuntimeError& e) { - Base::Console().Error("Complex Section - %s\n", e.what()); + if (m_alignResult.IsNull()) { return TopoDS_Shape(); } - if (alignedResult.IsNull()) { - return TopoDS_Shape(); - } - - TopoDS_Shape preparedShape = scaleShape(alignedResult, getScale()); + TopoDS_Shape preparedShape = scaleShape(m_alignResult, getScale()); if (!DrawUtil::fpCompare(Rotation.getValue(), 0.0)) { - preparedShape = TechDraw::rotateShape(preparedShape, - getProjectionCS(), - Rotation.getValue()); + preparedShape = + TechDraw::rotateShape(preparedShape, getProjectionCS(), Rotation.getValue()); } return preparedShape; } + +void DrawComplexSection::makeSectionCut(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); + } + + try { + connectAlignWatcher = + QObject::connect(&m_alignWatcher, &QFutureWatcherBase::finished, &m_alignWatcher, + [this] { this->onSectionCutFinished(); }); + m_alignFuture = QtConcurrent::run(this, &DrawComplexSection::makeAlignedPieces, baseShape); + m_alignWatcher.setFuture(m_alignFuture); + waitingForAlign(true); + } + catch (...) { + Base::Console().Message("DCS::makeSectionCut - failed to make alignedPieces"); + return; + } + + return DrawViewSection::makeSectionCut(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 + return; + } + + DrawViewSection::onSectionCutFinished(); + + QObject::disconnect(connectAlignWatcher); +} + //for Aligned strategy, cut the rawShape by each segment of the tool //TODO: this process should replace the "makeSectionCut" from DVS -TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, - const TopoDS_Shape &toolFaceShape, - double extrudeDistance) +void DrawComplexSection::makeAlignedPieces(const TopoDS_Shape& rawShape) { -// Base::Console().Message("DCS::makeAlignedPieces()\n"); +// 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.Direction (depth) - std::vector pieceZSizeAll; //size in sectionCS.YDirection (height) + std::vector pieceXSizeAll;//size in sectionCS.XDirection (width) + std::vector pieceYSizeAll;//size in sectionCS.Direction (depth) + std::vector pieceZSizeAll;//size in sectionCS.YDirection (height) //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 @@ -312,12 +351,12 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, throw Base::RuntimeError("Can not make wire from cutting tool (2)"); } gp_Vec gProfileVec = makeProfileVector(profileWire); - //now we want to know what the profileVector looks like on the page (only X,Y coords) - gProfileVec = projectVector(gProfileVec).Normalized(); + gp_Vec rotateAxis = (getSectionCS().Direction()).Crossed(gProfileVec); - if (!canBuild(getSectionCS(), CuttingToolWireObject.getValue())) { - throw Base::RuntimeError("Profile is parallel to Section Normal"); - } + //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) { @@ -337,11 +376,9 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, verticalReverser = -1.0; } - gp_Vec rotateAxis = getSectionCS().Direction().Crossed(gProfileVec); - //make a tool for each segment of the toolFaceShape and intersect it with the //raw shape - TopExp_Explorer expFaces(toolFaceShape, TopAbs_FACE); + 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)); @@ -350,12 +387,12 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, continue; } //we only want to reverse the segment normal if it is not perpendicular to section normal - if (segmentNormal.Dot(-gProjectionUnit) != 0.0 + if (segmentNormal.Dot(gProjectionUnit) != 0.0 && segmentNormal.Angle(gProjectionUnit) <= M_PI_2) { segmentNormal.Reverse(); } - gp_Vec extrudeDir = segmentNormal * extrudeDistance; + gp_Vec extrudeDir = segmentNormal * m_shapeSize; BRepPrimAPI_MakePrism mkPrism(face, extrudeDir); TopoDS_Shape segmentTool = mkPrism.Shape(); TopoDS_Shape intersect = shapeShapeIntersect(segmentTool, rawShape); @@ -410,7 +447,8 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, gp_Vec netDisplacement = -1.0 * gp_Vec(findCentroid(pieceAligned).XYZ()) + yVector; //if we are going to space along X, we need to bring the pieces back into alignment //with the XY plane. If we are stacking the pieces along Z, we don't want a vertical adjustment. - gp_Vec xyDisplacement = isProfileVertical ? gp_Vec(0.0, 0.0, 0.0) : gp_Vec(gp::OZ().Direction()); + gp_Vec xyDisplacement = + isProfileVertical ? gp_Vec(0.0, 0.0, 0.0) : gp_Vec(gp::OZ().Direction()); double dot = gp_Vec(gp::OZ().Direction()).Dot(alignedCS.Direction()); xyDisplacement = xyDisplacement * dot * (pieceZSize / 2.0); netDisplacement = netDisplacement + xyDisplacement; @@ -425,19 +463,22 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, } if (pieces.empty()) { - return TopoDS_Compound(); + m_alignResult = TopoDS_Compound(); + return; } int pieceCount = pieces.size(); if (pieceCount < 2) { //no need to space out the pieces - return TopoDS::Compound(pieces.front()); + m_alignResult = TopoDS::Compound(pieces.front()); + return; } //space the pieces "horizontally" (stdX) or "vertically" (stdZ) double movementReverser = isProfileVertical ? verticalReverser : horizReverser; //TODO: non-cardinal profiles! - gp_Vec movementAxis = isProfileVertical ? gp_Vec(gp::OZ().Direction()) : gp_Vec(gp::OX().Direction()); + gp_Vec movementAxis = + isProfileVertical ? gp_Vec(gp::OZ().Direction()) : gp_Vec(gp::OX().Direction()); gp_Vec gMovementVector = movementAxis * movementReverser; int stopAt = pieces.size(); @@ -459,7 +500,7 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, BRep_Builder builder; TopoDS_Compound comp; builder.MakeCompound(comp); - for (auto &piece : pieces) { + for (auto& piece : pieces) { builder.Add(comp, piece); } @@ -480,7 +521,7 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, BRepTools::Write(alignedCompound, "DCSmap50AlignedCompound.brep");//debug } - return alignedCompound; + m_alignResult = alignedCompound; } //! tries to find the intersection faces of the cut shape and the cutting tool. @@ -488,9 +529,9 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, //! case is a compound of individual cuts) with the "effective" (flattened) section plane. //! Profiles containing curves need special handling. TopoDS_Compound -DrawComplexSection::findSectionPlaneIntersections(const TopoDS_Shape &shapeToIntersect) +DrawComplexSection::findSectionPlaneIntersections(const TopoDS_Shape& shapeToIntersect) { -// Base::Console().Message("DCS::findSectionPlaneIntersections() - %s\n", getNameInDocument()); + // 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", @@ -505,10 +546,10 @@ DrawComplexSection::findSectionPlaneIntersections(const TopoDS_Shape &shapeToInt } //Intersect cutShape with each segment of the cutting tool -TopoDS_Compound DrawComplexSection::singleToolIntersections(const TopoDS_Shape &cutShape) +TopoDS_Compound DrawComplexSection::singleToolIntersections(const TopoDS_Shape& cutShape) { // Base::Console().Message("DCS::singleToolInterSections()\n"); - App::DocumentObject *toolObj = CuttingToolWireObject.getValue(); + App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); if (!isLinearProfile(toolObj)) { //TODO: special handling here // Base::Console().Message("DCS::singleToolIntersection - profile has curves\n"); @@ -534,20 +575,22 @@ TopoDS_Compound DrawComplexSection::singleToolIntersections(const TopoDS_Shape & continue; } std::vector commonFaces = faceShapeIntersect(face, m_toolFaceShape); - for (auto &cFace : commonFaces) { builder.Add(result, cFace); } + for (auto& cFace : commonFaces) { + builder.Add(result, cFace); + } } return result; } //Intersect cutShape with the effective (flattened) cutting plane to generate cut surface faces -TopoDS_Compound DrawComplexSection::alignedToolIntersections(const TopoDS_Shape &cutShape) +TopoDS_Compound DrawComplexSection::alignedToolIntersections(const TopoDS_Shape& cutShape) { -// Base::Console().Message("DCS::alignedToolIntersections()\n"); + // Base::Console().Message("DCS::alignedToolIntersections()\n"); BRep_Builder builder; TopoDS_Compound result; builder.MakeCompound(result); - App::DocumentObject *toolObj = CuttingToolWireObject.getValue(); + App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); if (!isLinearProfile(toolObj)) { //TODO: special handling here // Base::Console().Message("DCS::alignedToolIntersection - profile has curves\n"); @@ -567,7 +610,9 @@ TopoDS_Compound DrawComplexSection::alignedToolIntersections(const TopoDS_Shape continue; } std::vector commonFaces = faceShapeIntersect(face, cuttingFace); - for (auto &cFace : commonFaces) { builder.Add(result, cFace); } + for (auto& cFace : commonFaces) { + builder.Add(result, cFace); + } } if (debugSection()) { BRepTools::Write(cuttingFace, "DCSAlignedCuttingFace.brep"); //debug @@ -579,7 +624,7 @@ 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()); + // Base::Console().Message("DCS::alignSectionFaces() - faceIntersections.null: %d\n", faceIntersections.IsNull()); if (ProjectionStrategy.getValue() == 0) { //Offset. Use regular section behaviour return DrawViewSection::alignSectionFaces(faceIntersections); @@ -598,13 +643,13 @@ TopoDS_Shape DrawComplexSection::getShapeToIntersect() } TopoDS_Wire DrawComplexSection::makeProfileWire() const { - App::DocumentObject *toolObj = CuttingToolWireObject.getValue(); + App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); return makeProfileWire(toolObj); } -TopoDS_Wire DrawComplexSection::makeProfileWire(App::DocumentObject *toolObj) +TopoDS_Wire DrawComplexSection::makeProfileWire(App::DocumentObject* toolObj) { -// Base::Console().Message("DCS::makeProfileWire()\n"); + // Base::Console().Message("DCS::makeProfileWire()\n"); if (!isProfileObject(toolObj)) { return TopoDS_Wire(); } @@ -642,7 +687,7 @@ BaseGeomPtrVector DrawComplexSection::makeSectionLineGeometry() { // Base::Console().Message("DCS::makeSectionLineGeometry()\n"); BaseGeomPtrVector result; - DrawViewPart *baseDvp = dynamic_cast(BaseView.getValue()); + DrawViewPart* baseDvp = dynamic_cast(BaseView.getValue()); if (baseDvp) { TopoDS_Wire lineWire = makeSectionLineWire(); TopoDS_Shape projectedWire = @@ -673,7 +718,7 @@ std::pair DrawComplexSection::sectionLineEnds() Base::Vector3d first = Base::Vector3d(gpFirst.X(), gpFirst.Y(), gpFirst.Z()); Base::Vector3d last = Base::Vector3d(gpLast.X(), gpLast.Y(), gpLast.Z()); - DrawViewPart *baseDvp = dynamic_cast(BaseView.getValue()); + DrawViewPart* baseDvp = dynamic_cast(BaseView.getValue()); if (baseDvp) { first = baseDvp->projectPoint(first); last = baseDvp->projectPoint(last); @@ -688,7 +733,7 @@ std::pair DrawComplexSection::sectionArrowDirs() { // Base::Console().Message("DCS::sectionArrowDirs()\n"); std::pair result; - App::DocumentObject *toolObj = CuttingToolWireObject.getValue(); + App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); TopoDS_Wire profileWire = makeProfileWire(toolObj); if (profileWire.IsNull()) { return result; @@ -707,7 +752,9 @@ std::pair DrawComplexSection::sectionArrowDirs() std::vector faces; TopExp_Explorer expl(toolFaceShape, TopAbs_FACE); - for (; expl.More(); expl.Next()) { faces.push_back(TopoDS::Face(expl.Current())); } + for (; expl.More(); expl.Next()) { + faces.push_back(TopoDS::Face(expl.Current())); + } gp_Vec gDir0 = gp_Vec(getFaceNormal(faces.front())); gp_Vec gDir1 = gp_Vec(getFaceNormal(faces.back())); @@ -727,7 +774,7 @@ std::pair DrawComplexSection::sectionArrowDirs() Base::Vector3d vDir1 = DU::toVector3d(gDir1); vDir0.Normalize(); vDir1.Normalize(); - DrawViewPart *baseDvp = dynamic_cast(BaseView.getValue()); + DrawViewPart* baseDvp = dynamic_cast(BaseView.getValue()); if (baseDvp) { vDir0 = baseDvp->projectPoint(vDir0, true); vDir1 = baseDvp->projectPoint(vDir1, true); @@ -742,8 +789,8 @@ std::pair DrawComplexSection::sectionArrowDirs() TopoDS_Wire DrawComplexSection::makeSectionLineWire() { TopoDS_Wire lineWire; - App::DocumentObject *toolObj = CuttingToolWireObject.getValue(); - DrawViewPart *baseDvp = dynamic_cast(BaseView.getValue()); + App::DocumentObject* toolObj = CuttingToolWireObject.getValue(); + DrawViewPart* baseDvp = dynamic_cast(BaseView.getValue()); if (baseDvp) { Base::Vector3d centroid = baseDvp->getCurrentCentroid(); TopoDS_Shape sTrans = @@ -775,7 +822,7 @@ ChangePointVector DrawComplexSection::getChangePointsFromSectionLine() // Base::Console().Message("DCS::getChangePointsFromSectionLine()\n"); ChangePointVector result; std::vector allPoints; - DrawViewPart *baseDvp = dynamic_cast(BaseView.getValue()); + DrawViewPart* baseDvp = dynamic_cast(BaseView.getValue()); if (baseDvp) { TopoDS_Wire lineWire = makeSectionLineWire(); TopoDS_Shape projectedWire = @@ -825,7 +872,7 @@ ChangePointVector DrawComplexSection::getChangePointsFromSectionLine() gp_Ax2 DrawComplexSection::getCSFromBase(const std::string sectionName) const { // Base::Console().Message("DCS::getCSFromBase()\n"); - App::DocumentObject *base = BaseView.getValue(); + App::DocumentObject* base = BaseView.getValue(); if (!base || !base->getTypeId().isDerivedFrom( TechDraw::DrawViewPart::getClassTypeId())) {//is second clause necessary? @@ -838,17 +885,18 @@ gp_Ax2 DrawComplexSection::getCSFromBase(const std::string sectionName) const //simple projection of a 3d vector onto the paper space gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec) const { - HLRAlgo_Projector projector( getProjectionCS() ); + HLRAlgo_Projector projector(getProjectionCS()); gp_Pnt2d prjPnt; projector.Project(gp_Pnt(vec.XYZ()), prjPnt); return gp_Vec(prjPnt.X(), prjPnt.Y(), 0.0); } //static +//TODO: centralize all the projection routines scattered around the module! gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec, gp_Ax2 sectionCS) { -// Base::Console().Message("DCS::projectVector(%s, CS)\n", DU::formatVector(vec).c_str()); - HLRAlgo_Projector projector( sectionCS ); + // 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); @@ -875,7 +923,7 @@ gp_Pln DrawComplexSection::getSectionPlane() const bool DrawComplexSection::isBaseValid() const { - App::DocumentObject *base = BaseView.getValue(); + App::DocumentObject* base = BaseView.getValue(); if (!base) { //complex section is not based on an existing DVP return true; @@ -893,7 +941,7 @@ bool DrawComplexSection::isBaseValid() const //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 + gp_Dir& gClosestBasis) const { // Base::Console().Message("DCS::validateProfilePosition()\n"); gp_Vec gProfileVector = makeProfileVector(profileWire); @@ -965,9 +1013,9 @@ bool DrawComplexSection::canBuild(gp_Ax2 sectionCS, App::DocumentObject* profile return true; } gp_Vec gProfileVec = makeProfileVector(makeProfileWire(profileObject)); - gProfileVec = projectVector(gProfileVec, sectionCS).Normalized(); + // gProfileVec = projectVector(gProfileVec, sectionCS).Normalized(); double dot = fabs(gProfileVec.Dot(sectionCS.Direction())); - if ( DU::fpCompare(dot, 1.0, EWTOLERANCE)) { + if (DU::fpCompare(dot, 1.0, EWTOLERANCE)) { return false; } return true; @@ -977,7 +1025,7 @@ bool DrawComplexSection::canBuild(gp_Ax2 sectionCS, App::DocumentObject* profile //make a "face" (not necessarily a TopoDS_Face since the extrusion of a wire is a shell) //from a single open wire by displacing the wire extruding it -TopoDS_Shape DrawComplexSection::extrudeWireToFace(TopoDS_Wire &wire, gp_Dir extrudeDir, +TopoDS_Shape DrawComplexSection::extrudeWireToFace(TopoDS_Wire& wire, gp_Dir extrudeDir, double extrudeDist) { gp_Trsf mov; @@ -992,7 +1040,7 @@ TopoDS_Shape DrawComplexSection::extrudeWireToFace(TopoDS_Wire &wire, gp_Dir ext //returns the normal of the face to be extruded into a cutting tool //the face is expected to be planar -gp_Dir DrawComplexSection::getFaceNormal(TopoDS_Face &face) +gp_Dir DrawComplexSection::getFaceNormal(TopoDS_Face& face) { BRepAdaptor_Surface adapt(face); double uParmFirst = adapt.FirstUParameter(); @@ -1010,7 +1058,7 @@ gp_Dir DrawComplexSection::getFaceNormal(TopoDS_Face &face) return normalDir; } -bool DrawComplexSection::boxesIntersect(TopoDS_Face &face, TopoDS_Shape &shape) +bool DrawComplexSection::boxesIntersect(TopoDS_Face& face, TopoDS_Shape& shape) { Bnd_Box box0, box1; BRepBndLib::Add(face, box0); @@ -1023,8 +1071,8 @@ bool DrawComplexSection::boxesIntersect(TopoDS_Face &face, TopoDS_Shape &shape) return true; } -TopoDS_Shape DrawComplexSection::shapeShapeIntersect(const TopoDS_Shape &shape0, - const TopoDS_Shape &shape1) +TopoDS_Shape DrawComplexSection::shapeShapeIntersect(const TopoDS_Shape& shape0, + const TopoDS_Shape& shape1) { BRepAlgoAPI_Common anOp; anOp.SetFuzzyValue(EWTOLERANCE); @@ -1042,8 +1090,8 @@ TopoDS_Shape DrawComplexSection::shapeShapeIntersect(const TopoDS_Shape &shape0, } //find all the intersecting regions of face and shape -std::vector DrawComplexSection::faceShapeIntersect(const TopoDS_Face &face, - const TopoDS_Shape &shape) +std::vector DrawComplexSection::faceShapeIntersect(const TopoDS_Face& face, + const TopoDS_Shape& shape) { // Base::Console().Message("DCS::faceShapeIntersect()\n"); TopoDS_Shape intersect = shapeShapeIntersect(face, shape); @@ -1081,12 +1129,14 @@ TopoDS_Wire DrawComplexSection::makeNoseToTailWire(TopoDS_Wire inWire) } BRepBuilderAPI_MakeWire mkWire; - for (auto &edge : sortedList) { mkWire.Add(edge); } + for (auto& edge : sortedList) { + mkWire.Add(edge); + } return mkWire.Wire(); } //static -bool DrawComplexSection::isProfileObject(App::DocumentObject *obj) +bool DrawComplexSection::isProfileObject(App::DocumentObject* obj) { //if the object's shape is a wire or an edge, then it can be a profile object TopoDS_Shape shape = Part::Feature::getShape(obj); @@ -1100,7 +1150,7 @@ bool DrawComplexSection::isProfileObject(App::DocumentObject *obj) return false; } -bool DrawComplexSection::isMultiSegmentProfile(App::DocumentObject *obj) +bool DrawComplexSection::isMultiSegmentProfile(App::DocumentObject* obj) { //if the object's shape is a wire or an edge, then it can be a profile object TopoDS_Shape shape = Part::Feature::getShape(obj); @@ -1129,7 +1179,7 @@ bool DrawComplexSection::isMultiSegmentProfile(App::DocumentObject *obj) } //check if the profile has curves in it -bool DrawComplexSection::isLinearProfile(App::DocumentObject *obj) +bool DrawComplexSection::isLinearProfile(App::DocumentObject* obj) { TopoDS_Shape shape = Part::Feature::getShape(obj); if (shape.IsNull()) { @@ -1180,7 +1230,7 @@ namespace App { /// @cond DOXERR PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawComplexSectionPython, TechDraw::DrawComplexSection) -template<> const char *TechDraw::DrawComplexSectionPython::getViewProviderName() const +template<> const char* TechDraw::DrawComplexSectionPython::getViewProviderName() const { return "TechDrawGui::ViewProviderDrawingView"; } diff --git a/src/Mod/TechDraw/App/DrawComplexSection.h b/src/Mod/TechDraw/App/DrawComplexSection.h index 146f288329..8593e38d19 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.h +++ b/src/Mod/TechDraw/App/DrawComplexSection.h @@ -58,13 +58,22 @@ public: TopoDS_Compound alignSectionFaces(TopoDS_Shape faceIntersections) override; std::pair sectionLineEnds() override; + void makeSectionCut(TopoDS_Shape &baseShape) override; + + void waitingForAlign(bool s) { m_waitingForAlign = s; } + bool waitingForAlign(void) const { return m_waitingForAlign; } + + +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); TopoDS_Shape extrudeWireToFace(TopoDS_Wire &wire, gp_Dir extrudeDir, double extrudeDist); - TopoDS_Shape makeAlignedPieces(const TopoDS_Shape &rawShape, const TopoDS_Shape &toolFaceShape, - double extrudeDistance); - TopoDS_Shape distributeAlignedPieces(std::vector pieces); +// void makeAlignedPieces(const TopoDS_Shape &rawShape, const TopoDS_Shape &toolFaceShape, +// double extrudeDistance); + void makeAlignedPieces(const TopoDS_Shape &rawShape); TopoDS_Compound singleToolIntersections(const TopoDS_Shape &cutShape); TopoDS_Compound alignedToolIntersections(const TopoDS_Shape &cutShape); @@ -94,6 +103,12 @@ private: gp_Dir getFaceNormal(TopoDS_Face &face); TopoDS_Shape m_toolFaceShape; + TopoDS_Shape m_alignResult; + + QMetaObject::Connection connectAlignWatcher; + QFutureWatcher m_alignWatcher; + QFuture m_alignFuture; + bool m_waitingForAlign; static const char *ProjectionStrategyEnums[]; }; diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index 30f9f1320d..aecea1d530 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -193,6 +193,7 @@ void DrawViewDimension::onChanged(const App::Property* prop) Base::Console().Warning("%s has no 3D References but is Type: True\n", getNameInDocument()); MeasureType.setValue("Projected"); } + return; } else if (prop == &References3D) { //have to rebuild the Measurement object // Base::Console().Message("DVD::onChanged - References3D\n"); @@ -202,6 +203,7 @@ void DrawViewDimension::onChanged(const App::Property* prop) } else if (MeasureType.isValue("True")) { //empty 3dRefs, but True MeasureType.touch(); //run MeasureType logic for this case } + return; } else if (prop == &Type) { //why?? FormatSpec.setValue(getDefaultFormatSpec().c_str()); @@ -215,6 +217,7 @@ void DrawViewDimension::onChanged(const App::Property* prop) OverTolerance.setUnit(Base::Unit::Length); UnderTolerance.setUnit(Base::Unit::Length); } + return; } else if (prop == &TheoreticalExact) { // if TheoreticalExact disable tolerances and set them to zero @@ -237,7 +240,7 @@ void DrawViewDimension::onChanged(const App::Property* prop) FormatSpecUnderTolerance.setReadOnly(false); } } - requestPaint(); + return; } else if (prop == &EqualTolerance) { // if EqualTolerance set negated overtolerance for untertolerance @@ -261,7 +264,7 @@ void DrawViewDimension::onChanged(const App::Property* prop) FormatSpecUnderTolerance.setReadOnly(false); } } - requestPaint(); + return; } else if (prop == &OverTolerance) { // if EqualTolerance set negated overtolerance for untertolerance @@ -269,27 +272,19 @@ void DrawViewDimension::onChanged(const App::Property* prop) UnderTolerance.setValue(-1.0 * OverTolerance.getValue()); UnderTolerance.setUnit(OverTolerance.getUnit()); } - requestPaint(); + return; } else if (prop == &FormatSpecOverTolerance) { if (!ArbitraryTolerances.getValue()) { FormatSpecUnderTolerance.setValue(FormatSpecOverTolerance.getValue()); } - requestPaint(); + return; } else if (prop == &FormatSpecUnderTolerance) { if (!ArbitraryTolerances.getValue()) { FormatSpecOverTolerance.setValue(FormatSpecUnderTolerance.getValue()); } - requestPaint(); - } - else if ( (prop == &FormatSpec) || - (prop == &Arbitrary) || - (prop == &ArbitraryTolerances) || - (prop == &MeasureType) || - (prop == &UnderTolerance) || - (prop == &Inverted) ) { - requestPaint(); + return; } } @@ -353,21 +348,9 @@ void DrawViewDimension::handleChangedPropertyType(Base::XMLReader &reader, const short DrawViewDimension::mustExecute() const { if (!isRestoring()) { - if ( - References2D.isTouched() || - Type.isTouched() || - FormatSpec.isTouched() || - Arbitrary.isTouched() || - FormatSpecOverTolerance.isTouched() || - FormatSpecUnderTolerance.isTouched() || - ArbitraryTolerances.isTouched() || - MeasureType.isTouched() || - TheoreticalExact.isTouched() || - EqualTolerance.isTouched() || - OverTolerance.isTouched() || - UnderTolerance.isTouched() || - Inverted.isTouched() - ) { + if (References2D.isTouched() || + References3D.isTouched() || + Type.isTouched() ) { return true; } } @@ -377,6 +360,7 @@ short DrawViewDimension::mustExecute() const App::DocumentObjectExecReturn *DrawViewDimension::execute() { +// Base::Console().Message("DVD::execute() - %s\n", getNameInDocument()); if (!keepUpdated()) { return App::DocumentObject::StdReturn; } @@ -396,12 +380,7 @@ App::DocumentObjectExecReturn *DrawViewDimension::execute() //can't do anything until Source has geometry if (!getViewPart()->hasGeometry()) { //happens when loading saved document - //if (isRestoring() || - // getDocument()->testStatus(App::Document::Status::Restoring)) { - return App::DocumentObject::StdReturn; - //} else { - // return App::DocumentObject::StdReturn; - //} + return App::DocumentObject::StdReturn; } //now we can check if Reference2ds have valid targets. diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index 509e8ec1d8..7d3cffa4bd 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -438,8 +438,7 @@ void DrawViewPart::postHlrTasks(void) for (auto& b : bals) { b->recomputeFeature(); } - // Dimensions need to be recomputed now, unless their recomputation must be postponed - // until face creation, in which case they are recomputed after that + // Dimensions need to be recomputed now if face finding is not going to take place. if (!handleFaces() || CoarseView.getValue()) { std::vector dims = getDimensions(); for (auto& d : dims) { @@ -467,9 +466,8 @@ void DrawViewPart::postFaceExtractionTasks(void) // Some centerlines depend on faces so we could not add CL geometry before now addCenterLinesToGeom(); - // Dimensions need to be recomputed here because their - // references will be invalid until all the geometry exists, - // specifically cosmetic centerlines + // Dimensions need to be recomputed because their references will be invalid + // until all the geometry (including centerlines dependent on faces) exists. std::vector dims = getDimensions(); for (auto& d : dims) { d->recomputeFeature(); diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index b69c3a01a4..15ca2ee352 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -146,7 +146,7 @@ DrawViewSection::DrawViewSection() : static const char *ggroup = "Cut Operation"; //general section properties - ADD_PROPERTY_TYPE(SectionSymbol ,(""), sgroup, App::Prop_None, "The identifier for this section"); + ADD_PROPERTY_TYPE(SectionSymbol ,(""), sgroup, App::Prop_Output, "The identifier for this section"); ADD_PROPERTY_TYPE(BaseView ,(nullptr), sgroup, App::Prop_None, "2D View source for this Section"); BaseView.setScope(App::LinkScope::Global); ADD_PROPERTY_TYPE(SectionNormal ,(0, 0,1.0) ,sgroup, App::Prop_None, @@ -234,23 +234,31 @@ void DrawViewSection::onChanged(const App::Property* prop) if (prop == &SectionNormal) { Direction.setValue(SectionNormal.getValue()); + return; } else if (prop == &SectionSymbol) { - std::string lblText = "Section " + - std::string(SectionSymbol.getValue()) + - " - " + - std::string(SectionSymbol.getValue()); - Label.setValue(lblText); + if (getBaseDVP()) { + getBaseDVP()->requestPaint(); + } + return; } else if (prop == &CutSurfaceDisplay) { if (CutSurfaceDisplay.isValue("PatHatch")) { makeLineSets(); } + requestPaint(); + return; } else if (prop == &FileHatchPattern) { replaceSvgIncluded(FileHatchPattern.getValue()); + requestPaint(); + return; } else if (prop == &FileGeomPattern) { replacePatIncluded(FileGeomPattern.getValue()); makeLineSets(); + requestPaint(); + return; } else if (prop == &NameGeomPattern ) { makeLineSets(); + requestPaint(); + return; } DrawView::onChanged(prop); @@ -286,13 +294,29 @@ App::DocumentObjectExecReturn *DrawViewSection::execute() return new App::DocumentObjectExecReturn("BaseView object not found"); } + if (waitingForCut() || waitingForHlr()) { + return DrawView::execute(); + } + TopoDS_Shape baseShape = getShapeToCut(); if (baseShape.IsNull()) { return DrawView::execute(); } - m_saveShape = baseShape; //save shape for 2nd pass + //is SectionOrigin valid? + Bnd_Box centerBox; + BRepBndLib::AddOptimal(baseShape, centerBox); + centerBox.SetGap(0.0); + Base::Vector3d orgPnt = SectionOrigin.getValue(); + + if(!isReallyInBox(gp_Pnt(orgPnt.x, orgPnt.y, orgPnt.z), centerBox)) { + Base::Console().Warning("DVS: SectionOrigin doesn't intersect part in %s\n", getNameInDocument()); + } + + //save important info for later use + m_shapeSize = sqrt(centerBox.SquareExtent()); + m_saveShape = baseShape; bool haveX = checkXDirection(); if (!haveX) { @@ -334,6 +358,8 @@ void DrawViewSection::sectionExec(TopoDS_Shape& baseShape) return; } + m_cuttingTool = makeCuttingTool(m_shapeSize); + try { //note that &m_cutWatcher in the third parameter is not strictly required, but using the //4 parameter signature instead of the 3 parameter signature prevents clazy warning: @@ -357,18 +383,6 @@ void DrawViewSection::makeSectionCut(TopoDS_Shape &baseShape) showProgressMessage(getNameInDocument(), "is making section cut"); -// cut base shape with tool - //is SectionOrigin valid? - Bnd_Box centerBox; - BRepBndLib::AddOptimal(baseShape, centerBox); - centerBox.SetGap(0.0); - Base::Vector3d orgPnt = SectionOrigin.getValue(); - - if(!isReallyInBox(gp_Pnt(orgPnt.x, orgPnt.y, orgPnt.z), centerBox)) { - Base::Console().Warning("DVS: SectionOrigin doesn't intersect part in %s\n", getNameInDocument()); - } - m_shapeSize = sqrt(centerBox.SquareExtent()); - // We need to copy the shape to not modify the BRepstructure BRepBuilderAPI_Copy BuilderCopy(baseShape); TopoDS_Shape myShape = BuilderCopy.Shape(); @@ -378,8 +392,6 @@ void DrawViewSection::makeSectionCut(TopoDS_Shape &baseShape) BRepTools::Write(myShape, "DVSCopy.brep"); //debug } - m_cuttingTool = makeCuttingTool(m_shapeSize); - if (debugSection()) { BRepTools::Write(m_cuttingTool, "DVSTool.brep"); //debug } diff --git a/src/Mod/TechDraw/App/DrawViewSection.h b/src/Mod/TechDraw/App/DrawViewSection.h index 14d4545fb7..5eba26c2c6 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.h +++ b/src/Mod/TechDraw/App/DrawViewSection.h @@ -170,7 +170,7 @@ public: bool showSectionEdges(void); public Q_SLOTS: - void onSectionCutFinished(void); + virtual void onSectionCutFinished(void); protected: TopoDS_Compound m_sectionTopoDSFaces; //needed for hatching diff --git a/src/Mod/TechDraw/Gui/TaskComplexSection.cpp b/src/Mod/TechDraw/Gui/TaskComplexSection.cpp index 29300f24fd..809c31280d 100644 --- a/src/Mod/TechDraw/Gui/TaskComplexSection.cpp +++ b/src/Mod/TechDraw/Gui/TaskComplexSection.cpp @@ -514,6 +514,8 @@ bool TaskComplexSection::apply(bool forceUpdate) } Gui::WaitCursor wc; + m_modelIsDirty = true; + if (!m_section) { createComplexSection(); } @@ -622,6 +624,12 @@ void TaskComplexSection::createComplexSection() m_section->SectionDirection.setValue("Aligned"); m_section->Source.setValues(m_shapes); m_section->XSource.setValues(m_xShapes); + + //auto orientation of view relative to base view + double viewDirectionAngle = m_compass->positiveValue(); + double rotation = requiredRotation(viewDirectionAngle); + Command::doCommand(Command::Doc, "App.ActiveDocument.%s.Rotation = %.6f", + m_sectionName.c_str(), rotation); } Gui::Command::commitCommand(); } @@ -667,6 +675,12 @@ void TaskComplexSection::updateComplexSection() m_section->Source.setValues(m_shapes); m_section->XSource.setValues(m_xShapes); } + + //auto orientation of view relative to base view + double viewDirectionAngle = m_compass->positiveValue(); + double rotation = requiredRotation(viewDirectionAngle); + Command::doCommand(Command::Doc, "App.ActiveDocument.%s.Rotation = %.6f", + m_sectionName.c_str(), rotation); } Gui::Command::commitCommand(); } @@ -703,6 +717,20 @@ bool TaskComplexSection::isSectionValid() return true; } + +//get required rotation from input angle in [0, 360] +//NOTE: shared code with simple section - reuse opportunity +double TaskComplexSection::requiredRotation(double inputAngle) +{ + double rotation = inputAngle - 90.0; + if (rotation == 180.0) { + //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; + } + return rotation; +} + //****************************************************************************** bool TaskComplexSection::accept() { diff --git a/src/Mod/TechDraw/Gui/TaskComplexSection.h b/src/Mod/TechDraw/Gui/TaskComplexSection.h index 65c899f43f..a6f2498072 100644 --- a/src/Mod/TechDraw/Gui/TaskComplexSection.h +++ b/src/Mod/TechDraw/Gui/TaskComplexSection.h @@ -106,6 +106,8 @@ protected Q_SLOTS: void slotViewDirectionChanged(Base::Vector3d newDirection); private: + double requiredRotation(double inputAngle); + void createComplexSection(); void updateComplexSection(); diff --git a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp index b299a9fbc4..fb82514f8c 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp @@ -138,9 +138,9 @@ bool ViewProviderDimension::setEdit(int ModNum) return true; } -void ViewProviderDimension::updateData(const App::Property* p) +void ViewProviderDimension::updateData(const App::Property* prop) { - if (p == &(getViewObject()->Type)) { + if (prop == &(getViewObject()->Type)) { if (getViewObject()->Type.isValue("DistanceX")) { sPixmap = "TechDraw_HorizontalDimension"; } else if (getViewObject()->Type.isValue("DistanceY")) { @@ -154,20 +154,33 @@ void ViewProviderDimension::updateData(const App::Property* p) } else if (getViewObject()->Type.isValue("Angle3Pt")) { sPixmap = "TechDraw_3PtAngleDimension"; } + return; } //Dimension handles X, Y updates differently that other QGIView //call QGIViewDimension::updateView - if (p == &(getViewObject()->X) || - p == &(getViewObject()->Y) ){ + if (prop == &(getViewObject()->X) || + prop == &(getViewObject()->Y) || + prop == &(getViewObject()->FormatSpec) || + prop == &(getViewObject()->Arbitrary) || + prop == &(getViewObject()->FormatSpecOverTolerance) || + prop == &(getViewObject()->FormatSpecUnderTolerance) || + prop == &(getViewObject()->ArbitraryTolerances) || + prop == &(getViewObject()->MeasureType) || + prop == &(getViewObject()->TheoreticalExact) || + prop == &(getViewObject()->EqualTolerance) || + prop == &(getViewObject()->OverTolerance) || + prop == &(getViewObject()->UnderTolerance) || + prop == &(getViewObject()->Inverted) ){ QGIView* qgiv = getQView(); if (qgiv) { qgiv->updateView(true); } + return; } //Skip QGIView X, Y processing - do not call ViewProviderDrawingView - Gui::ViewProviderDocumentObject::updateData(p); + Gui::ViewProviderDocumentObject::updateData(prop); } void ViewProviderDimension::onChanged(const App::Property* p)