diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index 23fac580b8..4212df5fb8 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -566,6 +566,24 @@ TopoDS_Shape DrawUtil::vectorToCompound(std::vector vecIn, bool inv return compOut; } +// construct a compound shape from a list of shapes +// this version needs a different name since edges/wires are shapes +TopoDS_Shape DrawUtil::shapeVectorToCompound(std::vector vecIn, bool invert) +{ + BRep_Builder builder; + TopoDS_Compound compOut; + builder.MakeCompound(compOut); + for (auto& v : vecIn) { + if (!v.IsNull()) { + builder.Add(compOut, v); + } + } + if (invert) { + return TechDraw::mirrorShape(compOut); + } + return compOut; +} + //constructs a list of edges from a shape std::vector DrawUtil::shapeToVector(TopoDS_Shape shapeIn) { diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index 3d588984cc..0933fc909f 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -130,6 +130,7 @@ public: static TopoDS_Shape vectorToCompound(std::vector vecIn, bool invert = true); static TopoDS_Shape vectorToCompound(std::vector vecIn, bool invert = true); + static TopoDS_Shape shapeVectorToCompound(std::vector vecIn, bool invert = true); static std::vector shapeToVector(TopoDS_Shape shapeIn); static Base::Vector3d toR3(const gp_Ax2& fromSystem, const Base::Vector3d& fromPoint); diff --git a/src/Mod/TechDraw/App/DrawViewDetail.cpp b/src/Mod/TechDraw/App/DrawViewDetail.cpp index 45300755ce..5da9a48fde 100644 --- a/src/Mod/TechDraw/App/DrawViewDetail.cpp +++ b/src/Mod/TechDraw/App/DrawViewDetail.cpp @@ -60,6 +60,7 @@ #include "DrawViewSection.h" #include "GeometryObject.h" #include "Preferences.h" +#include "ShapeUtils.h" using namespace TechDraw; @@ -205,9 +206,6 @@ void DrawViewDetail::makeDetailShape(const TopoDS_Shape& shape, DrawViewPart* dv Base::Vector3d dirDetail = dvp->Direction.getValue(); double radius = getFudgeRadius(); - int solidCount = DrawUtil::countSubShapes(shape, TopAbs_SOLID); - int shellCount = DrawUtil::countSubShapes(shape, TopAbs_SHELL); - //make a copy of the input shape so we don't inadvertently change it BRepBuilderAPI_Copy BuilderCopy(shape); TopoDS_Shape copyShape = BuilderCopy.Shape(); @@ -230,12 +228,9 @@ void DrawViewDetail::makeDetailShape(const TopoDS_Shape& shape, DrawViewPart* dv m_viewAxis = dvp->getProjectionCS(shapeCenter);//save the CS for later Base::Vector3d anchor = AnchorPoint.getValue();//this is a 2D point in base view local coords - // double baseRotationRad = dvp->Rotation.getValue() * M_PI / 180.0; - // anchor.RotateZ(baseRotationRad); anchor = DrawUtil::toR3(m_viewAxis, anchor);//actual anchor coords in R3 - Bnd_Box bbxSource; bbxSource.SetGap(0.0); BRepBndLib::AddOptimal(copyShape, bbxSource); @@ -280,105 +275,38 @@ void DrawViewDetail::makeDetailShape(const TopoDS_Shape& shape, DrawViewPart* dv } } - //for each solid and shell in the input shape, make a common with the tool and - //add the result to a compound. This avoids issues with some geometry errors in the - //input shape. - BRep_Builder builder; - TopoDS_Compound pieces; - builder.MakeCompound(pieces); - if (solidCount > 0) { - TopExp_Explorer expl(copyShape, TopAbs_SOLID); - for (; expl.More(); expl.Next()) { - const TopoDS_Solid& s = TopoDS::Solid(expl.Current()); - - BRepAlgoAPI_Common mkCommon(s, tool); - if (!mkCommon.IsDone()) { - continue; - } - if (mkCommon.Shape().IsNull()) { - continue; - } - //this might be overkill for piecewise algo - //Did we get at least 1 solid? - TopExp_Explorer xp; - xp.Init(mkCommon.Shape(), TopAbs_SOLID); - if (xp.More() != Standard_True) { - continue; - } - builder.Add(pieces, mkCommon.Shape()); - } - } - - if (shellCount > 0) { - TopExp_Explorer expl(copyShape, TopAbs_SHELL); - for (; expl.More(); expl.Next()) { - const TopoDS_Shell& s = TopoDS::Shell(expl.Current()); - - BRepAlgoAPI_Common mkCommon(s, tool); - if (!mkCommon.IsDone()) { - continue; - } - if (mkCommon.Shape().IsNull()) { - continue; - } - //this might be overkill for piecewise algo - //Did we get at least 1 shell? - TopExp_Explorer xp; - xp.Init(mkCommon.Shape(), TopAbs_SHELL); - if (xp.More() != Standard_True) { - continue; - } - builder.Add(pieces, mkCommon.Shape()); - } + BRepAlgoAPI_Common mkCommon(copyShape, tool); + if (!mkCommon.IsDone() || mkCommon.Shape().IsNull()) { + Base::Console().Warning("DVD::detailExec - %s - failed to create detail shape\n", + getNameInDocument()); + return; } // save the detail shape for further processing - m_detailShape = pieces; + m_detailShape = mkCommon.Shape(); if (debugDetail()) { BRepTools::Write(tool, "DVDTool.brep"); //debug BRepTools::Write(copyShape, "DVDCopy.brep");//debug - BRepTools::Write(pieces, "DVDCommon.brep"); //debug + BRepTools::Write(m_detailShape, "DVDCommon.brep"); //debug } - gp_Pnt inputCenter; - try { - //centroid of result - inputCenter = ShapeUtils::findCentroid(pieces, dirDetail); - Base::Vector3d centroid(inputCenter.X(), inputCenter.Y(), inputCenter.Z()); - m_saveCentroid += centroid;//center of massaged shape + gp_Pnt inputCenter = ShapeUtils::findCentroid(m_detailShape, dirDetail); + Base::Vector3d centroid(inputCenter.X(), inputCenter.Y(), inputCenter.Z()); + m_saveCentroid += centroid;//center of massaged shape + //align shape with detail anchor + TopoDS_Shape centeredShape = ShapeUtils::moveShape(m_detailShape, anchor * -1.0); + m_scaledShape = ShapeUtils::scaleShape(centeredShape, getScale()); - if ((solidCount > 0) || (shellCount > 0)) { - //align shape with detail anchor - TopoDS_Shape centeredShape = ShapeUtils::moveShape(pieces, anchor * -1.0); - m_scaledShape = ShapeUtils::scaleShape(centeredShape, getScale()); - if (debugDetail()) { - BRepTools::Write(m_scaledShape, "DVDScaled.brep");//debug - } - } - else { - //no solids, no shells, do what you can with edges - TopoDS_Shape projectedEdges = projectEdgesOntoFace(copyShape, extrusionFace, gdir); - TopoDS_Shape centeredShape = ShapeUtils::moveShape(projectedEdges, anchor * -1.0); - if (debugDetail()) { - BRepTools::Write(projectedEdges, "DVDProjectedEdges.brep");//debug - BRepTools::Write(centeredShape, "DVDCenteredShape.brep"); //debug - } - m_scaledShape = ShapeUtils::scaleShape(centeredShape, getScale()); - } + if (debugDetail()) { + BRepTools::Write(m_scaledShape, "DVDScaled.brep");//debug + } - Base::Vector3d stdOrg(0.0, 0.0, 0.0); - m_viewAxis = dvp->getProjectionCS(stdOrg); + Base::Vector3d stdOrg(0.0, 0.0, 0.0); + m_viewAxis = dvp->getProjectionCS(stdOrg); - if (!DrawUtil::fpCompare(Rotation.getValue(), 0.0)) { - m_scaledShape = ShapeUtils::rotateShape(m_scaledShape, m_viewAxis, Rotation.getValue()); - } - }//end try block - - catch (Standard_Failure& e1) { - Base::Console().Message("DVD::makeDetailShape - failed to create detail %s - %s **\n", - getNameInDocument(), e1.GetMessageString()); - return; + if (!DrawUtil::fpCompare(Rotation.getValue(), 0.0)) { + m_scaledShape = ShapeUtils::rotateShape(m_scaledShape, m_viewAxis, Rotation.getValue()); } showProgressMessage(getNameInDocument(), "has finished making detail shape"); diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index 9787bcc71c..82a085a091 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -22,6 +22,18 @@ * * ***************************************************************************/ +//=========================================================================== +// DrawViewPart overview +//=========================================================================== +// +// 1) get the shapes from the source objects +// 2) center, scale and rotate the shapes +// 3) project the shape using the OCC HLR algorithms +// 4) add cosmetic and other objects that don't participate in hlr +// 5) find the closed regions (faces) in the edges returned by hlr +// everything else is mostly providing services to other objects, such as the +// actual drawing routines in Gui + #include "PreCompiled.h" #ifndef _PreComp_ @@ -82,11 +94,6 @@ using namespace TechDraw; using DU = DrawUtil; -//=========================================================================== -// DrawViewPart -//=========================================================================== - - PROPERTY_SOURCE_WITH_EXTENSIONS(TechDraw::DrawViewPart, TechDraw::DrawView) DrawViewPart::DrawViewPart(void) @@ -157,6 +164,8 @@ DrawViewPart::~DrawViewPart() removeAllReferencesFromGeom(); } +//! returns a compound of all the shapes from the DocumentObjects in the Source & +//! XSource property lists TopoDS_Shape DrawViewPart::getSourceShape(bool fuse) const { // Base::Console().Message("DVP::getSourceShape()\n"); @@ -170,15 +179,15 @@ TopoDS_Shape DrawViewPart::getSourceShape(bool fuse) const return ShapeExtractor::getShapes(links); } -// deliver a shape appropriate for making a detail view based on this view -// TODO: why does dvp do the thinking for detail, but section picks its own -// version of the shape? Should we have a getShapeForSection? +//! deliver a shape appropriate for making a detail view based on this view +//! TODO: why does dvp do the thinking for detail, but section picks its own +//! version of the shape? Should we have a getShapeForSection? TopoDS_Shape DrawViewPart::getShapeForDetail() const { return ShapeUtils::rotateShape(getSourceShape(true), getProjectionCS(), Rotation.getValue()); } -// combine the regular links and xlinks into a single list +//! combine the regular links and xlinks into a single list std::vector DrawViewPart::getAllSources() const { // Base::Console().Message("DVP::getAllSources()\n"); @@ -192,8 +201,8 @@ std::vector DrawViewPart::getAllSources() const return result; } -//pick supported 2d shapes out of the Source properties and -//add them directly to the geometry without going through HLR +//! pick supported 2d shapes out of the Source properties and +//! add them directly to the geometry without going through HLR void DrawViewPart::addShapes2d(void) { std::vector shapes = ShapeExtractor::getShapes2d(getAllSources()); @@ -300,7 +309,7 @@ void DrawViewPart::partExec(TopoDS_Shape& shape) } } -//prepare the shape for HLR processing by centering, scaling and rotating it +//! prepare the shape for HLR processing by centering, scaling and rotating it GeometryObjectPtr DrawViewPart::makeGeometryForShape(TopoDS_Shape& shape) { // Base::Console().Message("DVP::makeGeometryForShape() - %s\n", getNameInDocument()); @@ -320,7 +329,7 @@ GeometryObjectPtr DrawViewPart::makeGeometryForShape(TopoDS_Shape& shape) return buildGeometryObject(localShape, getProjectionCS()); } -//Modify a shape by centering, scaling and rotating and return the centered (but not rotated) shape +//! Modify a shape by centering, scaling and rotating and return the centered (but not rotated) shape TopoDS_Shape DrawViewPart::centerScaleRotate(DrawViewPart* dvp, TopoDS_Shape& inOutShape, Base::Vector3d centroid) { @@ -339,7 +348,7 @@ TopoDS_Shape DrawViewPart::centerScaleRotate(DrawViewPart* dvp, TopoDS_Shape& in return centeredShape; } -//create a geometry object and trigger the HLR process in another thread +//! create a geometry object and trigger the HLR process in another thread TechDraw::GeometryObjectPtr DrawViewPart::buildGeometryObject(TopoDS_Shape& shape, const gp_Ax2& viewAxis) { @@ -386,7 +395,7 @@ TechDraw::GeometryObjectPtr DrawViewPart::buildGeometryObject(TopoDS_Shape& shap return go; } -//continue processing after hlr thread completes +//! continue processing after hlr thread completes void DrawViewPart::onHlrFinished(void) { // Base::Console().Message("DVP::onHlrFinished() - %s\n", getNameInDocument()); @@ -436,7 +445,7 @@ void DrawViewPart::onHlrFinished(void) } } -//run any tasks that need to been done after geometry is available +//! run any tasks that need to been done after geometry is available void DrawViewPart::postHlrTasks(void) { // Base::Console().Message("DVP::postHlrTasks() - %s\n", getNameInDocument()); diff --git a/src/Mod/TechDraw/App/ShapeExtractor.cpp b/src/Mod/TechDraw/App/ShapeExtractor.cpp index f1704b57f3..0f0f659004 100644 --- a/src/Mod/TechDraw/App/ShapeExtractor.cpp +++ b/src/Mod/TechDraw/App/ShapeExtractor.cpp @@ -41,6 +41,7 @@ #include #include #include +//#include #include "ShapeExtractor.h" #include "DrawUtil.h" @@ -50,12 +51,12 @@ using namespace TechDraw; using DU = DrawUtil; -std::vector ShapeExtractor::getShapes2d(const std::vector links) +std::vector ShapeExtractor::getShapes2d(const std::vector links, bool overridePref) { // Base::Console().Message("SE::getShapes2d()\n"); std::vector shapes2d; - if (!prefAdd2d()) { + if (!prefAdd2d() && !overridePref) { return shapes2d; } for (auto& l:links) { @@ -89,12 +90,15 @@ std::vector ShapeExtractor::getShapes2d(const std::vector links) +TopoDS_Shape ShapeExtractor::getShapes(const std::vector links, bool include2d) { // Base::Console().Message("SE::getShapes() - links in: %d\n", links.size()); std::vector sourceShapes; for (auto& l:links) { + if (is2dObject(l) && !include2d) { + continue; + } if (l->getTypeId().isDerivedFrom(App::Link::getClassTypeId())) { App::Link* xLink = dynamic_cast(l); std::vector xShapes = getXShapes(xLink); @@ -313,7 +317,8 @@ std::vector ShapeExtractor::getShapesFromObject(const App::Documen TopoDS_Shape ShapeExtractor::getShapesFused(const std::vector links) { // Base::Console().Message("SE::getShapesFused()\n"); - TopoDS_Shape baseShape = getShapes(links); + // get only the 3d shapes and fuse them + TopoDS_Shape baseShape = getShapes(links, false); if (!baseShape.IsNull()) { TopoDS_Iterator it(baseShape); TopoDS_Shape fusedShape = it.Value(); @@ -330,6 +335,15 @@ TopoDS_Shape ShapeExtractor::getShapesFused(const std::vector shapes2d = getShapes2d(links, true); + if (!shapes2d.empty()) { + shapes2d.push_back(baseShape); + return DrawUtil::shapeVectorToCompound(shapes2d); + } + return baseShape; } @@ -361,11 +375,21 @@ TopoDS_Shape ShapeExtractor::stripInfiniteShapes(TopoDS_Shape inShape) bool ShapeExtractor::is2dObject(App::DocumentObject* obj) { - bool result = false; - if (isEdgeType(obj) || isPointType(obj)) { - result = true; +// TODO:: the check for an object being a sketch should be done as in the commented +// if statement below. To do this, we need to include Mod/Sketcher/SketchObject.h, +// but that makes TechDraw dependent on Eigen libraries which we don't use. As a +// workaround we will inspect the object's class name. +// if (obj->isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { + std::string objTypeName = obj->getTypeId().getName(); + std::string sketcherToken("Sketcher"); + if (objTypeName.find(sketcherToken) != std::string::npos) { + return true; } - return result; + + if (isEdgeType(obj) || isPointType(obj)) { + return true; + } + return false; } //skip edges for now. diff --git a/src/Mod/TechDraw/App/ShapeExtractor.h b/src/Mod/TechDraw/App/ShapeExtractor.h index c3ce016384..30aad1a5d8 100644 --- a/src/Mod/TechDraw/App/ShapeExtractor.h +++ b/src/Mod/TechDraw/App/ShapeExtractor.h @@ -39,8 +39,8 @@ namespace TechDraw class TechDrawExport ShapeExtractor { public: - static TopoDS_Shape getShapes(const std::vector links); - static std::vector getShapes2d(const std::vector links); + static TopoDS_Shape getShapes(const std::vector links, bool include2d = true); + static std::vector getShapes2d(const std::vector links, bool overridePref = false); static std::vector getXShapes(const App::Link* xLink); static std::vector getShapesFromObject(const App::DocumentObject* docObj); static TopoDS_Shape getShapesFused(const std::vector links);