diff --git a/src/Mod/TechDraw/App/DrawComplexSection.cpp b/src/Mod/TechDraw/App/DrawComplexSection.cpp index c77e3df3e5..167b8f442d 100644 --- a/src/Mod/TechDraw/App/DrawComplexSection.cpp +++ b/src/Mod/TechDraw/App/DrawComplexSection.cpp @@ -337,14 +337,16 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, { // Base::Console().Message("DCS::makeAlignedPieces()\n"); std::vector pieces; - std::vector pieceXSize;//size in sectionCS.XDirection (width) - std::vector pieceYSize;//size in sectionCS.Direction (depth) - std::vector pieceZSize;//size in sectionCS.YDirection (height) - std::vector pieceDirections; - //make a "real" CS from the section projection CS + 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 + //the effective section plane for cut surface identification. gp_Ax3 alignedCS(gp_Pnt(0.0, 0.0, 0.0), - getSectionCS().YDirection(), //up and down - getSectionCS().XDirection());//left to right + getSectionCS().YDirection(), //section up and down >> alignedCS.z + getSectionCS().XDirection());//section left to right >> alignedCS.x gp_Ax3 stdCS; //OXYZ gp_Vec gProjectionUnit = gp_Vec(getSectionCS().Direction()); @@ -357,22 +359,22 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, throw Base::RuntimeError("Profile is parallel to Section Normal"); } - bool isVertical = true; + 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 - isVertical = false; + isProfileVertical = false; } - double leftToRight = 1.0;//profile vector points to right, so we move to right + 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) - leftToRight = -1.0; + horizReverser = -1.0; } - double topToBottom = 1.0;//profile vector points to top, so we move to top + 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) - topToBottom = -1.0; + verticalReverser = -1.0; } gp_Vec rotateAxis = getSectionCS().Direction().Crossed(gProfileVec); @@ -401,9 +403,6 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, continue; } - double faceAngle = - gp_Vec(getSectionCS().Direction().Reversed()).AngleWithRef(segmentNormal, rotateAxis); - //move intersection shape to the origin gp_Trsf xPieceCenter; xPieceCenter.SetTranslation(gp_Vec(findCentroid(intersect).XYZ()) * -1.0); @@ -411,6 +410,8 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, TopoDS_Shape pieceCentered = mkTransXLate.Shape(); //rotate the intersection so interesting face is aligned with 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;//XYZ tipped so face is aligned with sectionCS pieceCS.Rotate(faceAxis, faceAngle); @@ -434,22 +435,24 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, 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 pieceWidth(xMax - xMin); - double pieceDepth(yMax - yMin); - double pieceHeight(zMax - zMin); - pieceXSize.push_back(pieceWidth); - pieceYSize.push_back(pieceDepth); - pieceZSize.push_back(pieceHeight); + double pieceXSize(xMax - xMin); + double pieceYSize(yMax - yMin); + double pieceZSize(zMax - zMin); + + pieceXSizeAll.push_back(pieceXSize); + 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 - gp_Vec depthVector(gp::OY().Direction().XYZ() * pieceDepth / 2.0);//move "back" - //only aligned to paper plane - gp_Vec netDisplacement = -1.0 * gp_Vec(findCentroid(pieceAligned).XYZ()) + depthVector; - //if we are going to space along X, we need to bring the pieces into alignment - //with the XY plane. - gp_Vec xyDisplacement = isVertical ? gp_Vec(0.0, 0.0, 0.0) : gp_Vec(gp::OZ().Direction()); - xyDisplacement = xyDisplacement * topToBottom * pieceHeight / 2.0; + //yVector is movement of cut face to paperPlane (XZ) + gp_Vec yVector(gp::OY().Direction().XYZ() * pieceYSize / 2.0);//move "back" + 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()); + double dot = gp_Vec(gp::OZ().Direction()).Dot(alignedCS.Direction()); + xyDisplacement = xyDisplacement * dot * (pieceZSize / 2.0); netDisplacement = netDisplacement + xyDisplacement; gp_Trsf xPieceDisplace; @@ -472,17 +475,17 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, } //space the pieces "horizontally" (stdX) or "vertically" (stdZ) - double movementReverser = isVertical ? topToBottom : leftToRight; + double movementReverser = isProfileVertical ? verticalReverser : horizReverser; //TODO: non-cardinal profiles! - gp_Vec movementAxis = isVertical ? 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(); double distanceToMove = 0.0; for (int iPiece = 0; iPiece < stopAt; iPiece++) { - double pieceSize = pieceXSize.at(iPiece); - if (isVertical) { - pieceSize = pieceZSize.at(iPiece); + double pieceSize = pieceXSizeAll.at(iPiece); + if (isProfileVertical) { + pieceSize = pieceZSizeAll.at(iPiece); } double myDistanceToMove = distanceToMove + pieceSize / 2.0; gp_Trsf xPieceDistribute; @@ -496,14 +499,17 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, BRep_Builder builder; TopoDS_Compound comp; builder.MakeCompound(comp); - for (auto &piece : pieces) { builder.Add(comp, piece); } + for (auto &piece : pieces) { + builder.Add(comp, piece); + } //center the compound along SectionCS XDirection Base::Vector3d centerVector = DU::toVector3d(gMovementVector) * distanceToMove / -2.0; TopoDS_Shape centeredCompound = moveShape(comp, centerVector); if (debugSection()) { - BRepTools::Write(centeredCompound, "DCSfinCenteredCompound.brep");//debug + BRepTools::Write(centeredCompound, "DCSmap40CenteredCompound.brep");//debug } + //realign with SectionCS gp_Trsf xPieceAlign; xPieceAlign.SetTransformation(alignedCS, stdCS); @@ -511,7 +517,7 @@ TopoDS_Shape DrawComplexSection::makeAlignedPieces(const TopoDS_Shape &rawShape, TopoDS_Shape alignedCompound = mkTransAlign.Shape(); if (debugSection()) { - BRepTools::Write(alignedCompound, "DCSAlignedResult.brep");//debug + BRepTools::Write(alignedCompound, "DCSmap50AlignedCompound.brep");//debug } return alignedCompound; @@ -633,6 +639,7 @@ TopoDS_Shape DrawComplexSection::getShapeToIntersect() TopoDS_Wire DrawComplexSection::makeProfileWire(App::DocumentObject *toolObj) { +// Base::Console().Message("DCS::makeProfileWire()\n"); TopoDS_Shape toolShape = Part::Feature::getShape(toolObj); if (toolShape.IsNull()) { return TopoDS_Wire(); @@ -651,6 +658,7 @@ TopoDS_Wire DrawComplexSection::makeProfileWire(App::DocumentObject *toolObj) gp_Vec DrawComplexSection::makeProfileVector(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); @@ -870,6 +878,7 @@ gp_Vec DrawComplexSection::projectVector(const gp_Vec& vec) const //static 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 ); gp_Pnt2d prjPnt; projector.Project(gp_Pnt(vec.XYZ()), prjPnt); @@ -981,6 +990,11 @@ bool DrawComplexSection::canBuild(gp_Ax2 sectionCS, App::DocumentObject* profile 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())); diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index c60dd6b08f..bcba41d982 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -1012,16 +1012,20 @@ bool DrawViewPart::hasGeometry(void) const //in the derived view. gp_Ax2 DrawViewPart::localVectorToCS(const Base::Vector3d localUnit) const { +// Base::Console().Message("DVP::localVectorToCS(%s)\n", DU::formatVector((localUnit)).c_str()); double angle = atan2(localUnit.y, localUnit.x); //radians gp_Ax1 rotateAxisDir(gp_Pnt(0.0, 0.0, 0.0), getProjectionCS().Direction()); - gp_Vec gNewDirection = getProjectionCS().XDirection().Rotated(rotateAxisDir, angle); - - gp_Vec crossDirs = getProjectionCS().Direction().Crossed(gNewDirection); - gp_Vec gNewX = getProjectionCS().XDirection(); - gp_Vec triple = crossDirs.Crossed(getProjectionCS().XDirection()); - if (!DU::fpCompare(triple.Magnitude(), 0.0, EWTOLERANCE)) { - gNewX = triple; + gp_Vec gOldX = getProjectionCS().XDirection(); + gp_Vec gNewDirection = gOldX.Rotated(rotateAxisDir, angle); + gp_Vec gNewY = getProjectionCS().Direction(); + gp_Vec gNewX = (gNewDirection.Crossed(gNewY).Reversed()); + if (gNewX.IsParallel(gOldX, EWTOLERANCE)) { + //if the X directions are parallel, the view is rotating around X, so + //we should use the original X to prevent unwanted mirroring. + //There might be a better choice of tolerance than EWTOLERANCE + gNewX = gOldX; } + return { gp_Pnt(0.0, 0.0, 0.0), gp_Dir(gNewDirection), gp_Dir(gNewX) }; }