From b9fa9cb33e0e913fa3187543805bf1fac9440d5a Mon Sep 17 00:00:00 2001 From: wandererfan Date: Mon, 13 Mar 2023 19:01:31 -0400 Subject: [PATCH] [TD]corrupt dim reference detect and correct --- src/Mod/TechDraw/App/AppTechDrawPy.cpp | 3 +- src/Mod/TechDraw/App/CMakeLists.txt | 3 + src/Mod/TechDraw/App/DimensionGeometry.cpp | 24 +- src/Mod/TechDraw/App/DimensionReferences.cpp | 74 ++++ src/Mod/TechDraw/App/DimensionReferences.h | 17 +- src/Mod/TechDraw/App/DrawViewDimension.cpp | 387 +++++++++++++++++-- src/Mod/TechDraw/App/DrawViewDimension.h | 26 +- src/Mod/TechDraw/App/DrawViewPart.cpp | 5 +- src/Mod/TechDraw/App/Geometry.cpp | 21 + src/Mod/TechDraw/App/Geometry.h | 6 + src/Mod/TechDraw/App/GeometryMatcher.cpp | 262 +++++++++++++ src/Mod/TechDraw/App/GeometryMatcher.h | 64 +++ src/Mod/TechDraw/Gui/Command.cpp | 9 +- src/Mod/TechDraw/Gui/QGIView.cpp | 2 +- src/Mod/TechDraw/Gui/QGIViewDimension.cpp | 15 + src/Mod/TechDraw/Gui/QGIViewDimension.h | 5 + 16 files changed, 859 insertions(+), 64 deletions(-) create mode 100644 src/Mod/TechDraw/App/GeometryMatcher.cpp create mode 100644 src/Mod/TechDraw/App/GeometryMatcher.h diff --git a/src/Mod/TechDraw/App/AppTechDrawPy.cpp b/src/Mod/TechDraw/App/AppTechDrawPy.cpp index 300cd6bc25..eb8d2a5bb7 100644 --- a/src/Mod/TechDraw/App/AppTechDrawPy.cpp +++ b/src/Mod/TechDraw/App/AppTechDrawPy.cpp @@ -87,6 +87,7 @@ using Import::ImpExpDxfWrite; using TechDraw::ProjectionAlgos; using namespace std; +using namespace Part; namespace TechDraw { @@ -271,7 +272,7 @@ private: } else { for (auto& w : sortedWires) { - PyObject* wire = new TopoShapeWirePy(new TopoShape(w)); + PyObject* wire = new TopoShapeWirePy(new Part::TopoShape(w)); result.append(Py::asObject(wire)); } } diff --git a/src/Mod/TechDraw/App/CMakeLists.txt b/src/Mod/TechDraw/App/CMakeLists.txt index 52e8f1c43c..d30055d7a2 100644 --- a/src/Mod/TechDraw/App/CMakeLists.txt +++ b/src/Mod/TechDraw/App/CMakeLists.txt @@ -24,6 +24,7 @@ set(TechDrawLIBS Part Spreadsheet Import + PartDesign ) if(FREECAD_QT_MAJOR_VERSION EQUAL 5) @@ -114,6 +115,8 @@ SET(Draw_SRCS DimensionReferences.h DimensionFormatter.cpp DimensionFormatter.h + GeometryMatcher.cpp + GeometryMatcher.h DrawViewBalloon.cpp DrawViewBalloon.h DrawViewSection.cpp diff --git a/src/Mod/TechDraw/App/DimensionGeometry.cpp b/src/Mod/TechDraw/App/DimensionGeometry.cpp index a7de94494b..9246ddbad2 100644 --- a/src/Mod/TechDraw/App/DimensionGeometry.cpp +++ b/src/Mod/TechDraw/App/DimensionGeometry.cpp @@ -53,10 +53,8 @@ void pointPair::move(Base::Vector3d offset) // project the points onto the dvp's paper plane. Points are still in R3 coords. void pointPair::project(DrawViewPart* dvp) { - Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction()); - Base::Vector3d stdOrigin(0.0, 0.0, 0.0); - m_first = m_first.ProjectToPlane(stdOrigin, normal) * dvp->getScale(); - m_second = m_second.ProjectToPlane(stdOrigin, normal) * dvp->getScale(); + m_first = dvp->projectPoint(m_first) * dvp->getScale(); + m_second = dvp->projectPoint(m_second) * dvp->getScale(); } // map the points onto the dvp's XY coordinate system @@ -111,10 +109,8 @@ void anglePoints::move(Base::Vector3d offset) // project the points onto the dvp's paper plane. Points are still in R3 coords. void anglePoints::project(DrawViewPart* dvp) { - Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction()); - Base::Vector3d stdOrigin(0.0, 0.0, 0.0); m_ends.project(dvp); - m_vertex = m_vertex.ProjectToPlane(stdOrigin, normal) * dvp->getScale(); + m_vertex = dvp->projectPoint(m_vertex) * dvp->getScale(); } // map the points onto the dvp's XY coordinate system @@ -187,14 +183,12 @@ void arcPoints::move(Base::Vector3d offset) void arcPoints::project(DrawViewPart* dvp) { radius = radius * dvp->getScale(); - Base::Vector3d normal = DrawUtil::toVector3d(dvp->getProjectionCS().Direction()); - Base::Vector3d stdOrigin(0.0, 0.0, 0.0); - center = center.ProjectToPlane(stdOrigin, normal) * dvp->getScale(); - onCurve.first(onCurve.first().ProjectToPlane(stdOrigin, normal) * dvp->getScale()); - onCurve.second(onCurve.second().ProjectToPlane(stdOrigin, normal) * dvp->getScale()); - arcEnds.first(arcEnds.first().ProjectToPlane(stdOrigin, normal) * dvp->getScale()); - arcEnds.second(arcEnds.second().ProjectToPlane(stdOrigin, normal) * dvp->getScale()); - midArc = midArc.ProjectToPlane(stdOrigin, normal) * dvp->getScale(); + center = dvp->projectPoint(center) * dvp->getScale(); + onCurve.first(dvp->projectPoint(onCurve.first()) * dvp->getScale()); + onCurve.second(dvp->projectPoint(onCurve.second()) * dvp->getScale()); + arcEnds.first(dvp->projectPoint(arcEnds.first()) * dvp->getScale()); + arcEnds.second(dvp->projectPoint(arcEnds.second()) * dvp->getScale()); + midArc = dvp->projectPoint(midArc) * dvp->getScale(); } void arcPoints::mapToPage(DrawViewPart* dvp) diff --git a/src/Mod/TechDraw/App/DimensionReferences.cpp b/src/Mod/TechDraw/App/DimensionReferences.cpp index 52e979ef1b..97433a74ce 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.cpp +++ b/src/Mod/TechDraw/App/DimensionReferences.cpp @@ -25,18 +25,29 @@ # include #endif +#include +#include +#include +#include + #include +#include #include +#include +#include #include "DimensionReferences.h" #include "DrawUtil.h" #include "DrawViewPart.h" +#include "GeometryObject.h" using namespace TechDraw; +using DU = DrawUtil; TopoDS_Shape ReferenceEntry::getGeometry() const { +// Base::Console().Message("RE::getGeometry()\n"); if ( getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) ) { TechDraw::DrawViewPart* dvp = static_cast(getObject()); std::string gType = geomType(); @@ -50,6 +61,7 @@ TopoDS_Shape ReferenceEntry::getGeometry() const auto fgeom = dvp->getFace(getSubName()); return fgeom->toOccFace(); } + //Base::Console().Message("RE::getGeometry - returns null shape! - gType: %s\n", gType.c_str()); return TopoDS_Shape(); } @@ -62,6 +74,7 @@ TopoDS_Shape ReferenceEntry::getGeometry() const if (getSubName().empty()) { return shape.getShape(); } + // TODO: what happens if the subelement is no longer present? return shape.getSubShape(getSubName().c_str()); } @@ -78,6 +91,58 @@ std::string ReferenceEntry::getSubName(bool longForm) const return workingSubName; } +App::DocumentObject* ReferenceEntry::getObject() const +{ + // For PartDesign objects, when the reference is created from a selection, + // the SelectionObject is a Feature within the Body. + PartDesign::Body* pdBody = PartDesign::Body::findBodyOf(m_object); + if (pdBody && pdBody->Tip.getValue()) { + return pdBody->Tip.getValue(); + } + return m_object; +} + +Part::TopoShape ReferenceEntry::asTopoShape() +{ +// Base::Console().Message("RE::asTopoShape()\n"); + TopoDS_Shape geom = getGeometry(); + + if (geom.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex vert = TopoDS::Vertex(geom); + return asTopoShapeVertex(vert); + } else if (geom.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge edge = TopoDS::Edge(geom); + return asTopoShapeEdge(edge); + } else { + throw Base::RuntimeError("Dimension Reference has unsupported geometry"); + } + return Part::TopoShape(); +} + +Part::TopoShape ReferenceEntry::asTopoShapeVertex(TopoDS_Vertex vert) +{ + Base::Vector3d point = DU::toVector3d(BRep_Tool::Pnt(vert)); + if (!is3d()) { + TechDraw::DrawViewPart* dvp = static_cast(getObject()); + point = point / dvp->getScale(); + } + BRepBuilderAPI_MakeVertex mkVert(DU::togp_Pnt(point)); + return Part::TopoShape(mkVert.Vertex()); +} + +Part::TopoShape ReferenceEntry::asTopoShapeEdge(TopoDS_Edge edge) +{ +// Base::Console().Message("RE::asTopoShapeEdge()\n"); + TopoDS_Edge unscaledEdge = edge; + if (!is3d()) { + // 2d reference - projected and scaled. scale might have changed, so we need to unscale + TechDraw::DrawViewPart* dvp = static_cast(getObject()); + TopoDS_Shape unscaledShape = TechDraw::scaleShape(edge, 1.0 / dvp->getScale()); + unscaledEdge = TopoDS::Edge(unscaledShape); + } + return Part::TopoShape(unscaledEdge); +} + std::string ReferenceEntry::geomType() const { return DrawUtil::getGeomTypeFromName(getSubName()); @@ -87,3 +152,12 @@ bool ReferenceEntry::isWholeObject() const { return getSubName().empty(); } + +bool ReferenceEntry::is3d() const +{ + if ( getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()) ) { + return false; + } + return true; +} + diff --git a/src/Mod/TechDraw/App/DimensionReferences.h b/src/Mod/TechDraw/App/DimensionReferences.h index 166860e821..c4115b45bb 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.h +++ b/src/Mod/TechDraw/App/DimensionReferences.h @@ -29,13 +29,21 @@ #include #include +#include +#include +#include namespace App { class DocumentObject; } +namespace Part +{ +class TopoShape; +} + namespace TechDraw { @@ -53,7 +61,7 @@ public: } ~ReferenceEntry() = default; - App::DocumentObject* getObject() const { return m_object; } + App::DocumentObject* getObject() const; void setObject(App::DocumentObject* docObj) { m_object = docObj; } std::string getSubName(bool longForm = false) const; void setSubName(std::string subName) { m_subName = subName; } @@ -61,8 +69,13 @@ public: std::string geomType() const; bool isWholeObject() const; + Part::TopoShape asTopoShape(); + Part::TopoShape asTopoShapeVertex(TopoDS_Vertex vert); + Part::TopoShape asTopoShapeEdge(TopoDS_Edge edge); + + bool is3d() const; + private: - bool is3d(); App::DocumentObject* m_object; std::string m_subName; }; diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index c4e0cc5fd3..644716634e 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -55,7 +55,11 @@ #include #include #include + #include +#include +#include + #include // generated from DrawViewDimensionPy.xml #include "DrawViewDimension.h" @@ -63,10 +67,12 @@ #include "DrawUtil.h" #include "DrawViewPart.h" #include "Geometry.h" +#include "GeometryMatcher.h" #include "Preferences.h" - using namespace TechDraw; +using namespace Part; +using DU = DrawUtil; //=========================================================================== // DrawViewDimension @@ -135,6 +141,9 @@ DrawViewDimension::DrawViewDimension() ADD_PROPERTY_TYPE(LineAngle, (0.0), "Override", App::Prop_Output, "Dimension line angle"); ADD_PROPERTY_TYPE(ExtensionAngle, (0.0), "Override", App::Prop_Output, "Extension line angle"); + ADD_PROPERTY_TYPE(SavedGeometry, () ,"References",(App::PropertyType)(App::Prop_None),"Reference Geometry"); + SavedGeometry.setOrderRelevant(true); + // hide the DrawView properties that don't apply to Dimensions ScaleType.setStatus(App::Property::ReadOnly, true); ScaleType.setStatus(App::Property::Hidden, true); @@ -158,7 +167,8 @@ DrawViewDimension::DrawViewDimension() resetAngular(); resetArc(); m_hasGeometry = false; - m_formatter = new DimensionFormatter(this); + m_matcher = new GeometryMatcher(this); + m_referencesCorrect = true; } DrawViewDimension::~DrawViewDimension() @@ -166,6 +176,7 @@ DrawViewDimension::~DrawViewDimension() delete measurement; measurement = nullptr; delete m_formatter; + delete m_matcher; } void DrawViewDimension::resetLinear() @@ -208,14 +219,19 @@ void DrawViewDimension::onChanged(const App::Property* prop) return; } - if (prop == &References3D) {//have to rebuild the Measurement object - clear3DMeasurements(); //Measurement object + if (prop == &References2D) { + updateSavedGeometry(); + } else if (prop == &References3D) { + // remove the old measurement object + clear3DMeasurements(); if (!(References3D.getValues()).empty()) { + // rebuild the Measurement object setAll3DMeasurement(); } else if (MeasureType.isValue("True")) {//empty 3dRefs, but True MeasureType.touch(); //run MeasureType logic for this case } + updateSavedGeometry(); return; } else if (prop == &Type) {//why?? @@ -370,37 +386,26 @@ short DrawViewDimension::mustExecute() const App::DocumentObjectExecReturn* DrawViewDimension::execute() { - // Base::Console().Message("DVD::execute() - %s\n", getNameInDocument()); - if (!keepUpdated()) { +// Base::Console().Message("DVD::execute() - %s\n", getNameInDocument()); + if (!okToProceed()) { return App::DocumentObject::StdReturn; } - DrawViewPart* dvp = getViewPart(); - if (!dvp) - return App::DocumentObject::StdReturn; - - if (!has2DReferences() && !has3DReferences()) { - //no references, can't do anything - return App::DocumentObject::StdReturn; - } - - if (!getViewPart()->hasGeometry()) { - //can't do anything until Source has geometry - return App::DocumentObject::StdReturn; - } - - if (References3D.getValues().empty() && !checkReferences2D()) { - Base::Console().Warning("DVD::execute - %s has invalid 2D References\n", - getNameInDocument()); - return App::DocumentObject::StdReturn; - } - - //we have either or both valid References3D and References2D - ReferenceVector references = getEffectiveReferences(); resetLinear(); resetAngular(); resetArc(); + m_referencesCorrect = compareSavedGeometry(); + if (!m_referencesCorrect) { + m_referencesCorrect = fixExactMatch(); + if (!m_referencesCorrect) { + handleNoExactMatch(); + } + } + + //we have either or both valid References3D and References2D + ReferenceVector references = getEffectiveReferences(); + if (Type.isValue("Distance") || Type.isValue("DistanceX") || Type.isValue("DistanceY")) { if (getRefType() == oneEdge) { m_linearPoints = getPointsOneEdge(references); @@ -443,6 +448,35 @@ App::DocumentObjectExecReturn* DrawViewDimension::execute() return DrawView::execute(); } +// true if we have enough information to execute, false otherwise +bool DrawViewDimension::okToProceed() +{ + if (!keepUpdated()) { + return false; + } + DrawViewPart* dvp = getViewPart(); + if (!dvp) + return false; + + if (!has2DReferences() && !has3DReferences()) { + //no references, can't do anything + return App::DocumentObject::StdReturn; + } + + if (!getViewPart()->hasGeometry()) { + //can't do anything until Source has geometry + return false; + } + + if (References3D.getValues().empty() && !checkReferences2D()) { + Base::Console().Warning("DVD::execute - %s has invalid 2D References\n", + getNameInDocument()); + return false; + } + + return true; +} + ////TODO: schema not report their multiValue status bool DrawViewDimension::isMultiValueSchema() const { return m_formatter->isMultiValueSchema(); } @@ -615,7 +649,6 @@ pointPair DrawViewDimension::getPointsOneEdge(ReferenceVector references) pts.move(getViewPart()->getOriginalCentroid()); pts.project(getViewPart()); pts.mapToPage(getViewPart()); - pts.invertY(); return pts; } @@ -650,7 +683,6 @@ pointPair DrawViewDimension::getPointsTwoEdges(ReferenceVector references) pts.move(getViewPart()->getOriginalCentroid()); pts.project(getViewPart()); pts.mapToPage(getViewPart()); - pts.invertY(); return pts; } @@ -690,7 +722,6 @@ pointPair DrawViewDimension::getPointsTwoVerts(ReferenceVector references) pts.move(getViewPart()->getOriginalCentroid()); pts.project(getViewPart()); pts.mapToPage(getViewPart()); - pts.invertY(); return pts; } @@ -731,7 +762,6 @@ pointPair DrawViewDimension::getPointsEdgeVert(ReferenceVector references) pts.move(getViewPart()->getOriginalCentroid()); pts.project(getViewPart()); pts.mapToPage(getViewPart()); - pts.invertY(); return pts; } @@ -762,7 +792,6 @@ arcPoints DrawViewDimension::getArcParameters(ReferenceVector references) pts.move(getViewPart()->getOriginalCentroid()); pts.project(getViewPart()); pts.mapToPage(getViewPart()); - pts.invertY(); return pts; } @@ -1089,7 +1118,6 @@ anglePoints DrawViewDimension::getAnglePointsTwoEdges(ReferenceVector references pts.move(getViewPart()->getOriginalCentroid()); pts.project(getViewPart()); pts.mapToPage(getViewPart()); - pts.invertY(); return pts; } @@ -1137,7 +1165,6 @@ anglePoints DrawViewDimension::getAnglePointsThreeVerts(ReferenceVector referenc pts.move(getViewPart()->getOriginalCentroid()); pts.project(getViewPart()); pts.mapToPage(getViewPart()); - pts.invertY(); return pts; } @@ -1206,6 +1233,21 @@ ReferenceVector DrawViewDimension::getReferences3d() const return refs3d; } +void DrawViewDimension::replaceReferenceSubElement2d(int iRef, std::string newSubelement) +{ +// Base::Console().Message("DVD::replaceReferenceSubElement2d(%d, %s)\n", iRef, newSubelement.c_str()); + ReferenceVector refs = getReferences2d(); + refs.at(iRef).setSubName(newSubelement); + setReferences2d(refs); +} + +void DrawViewDimension::replaceReferenceSubElement3d(int iRef, std::string newSubelement) +{ + ReferenceVector refs = getReferences3d(); + refs.at(iRef).setSubName(newSubelement); + setReferences3d(refs); +} + //what configuration of references do we have - Vertex-Vertex, Edge-Vertex, Edge, ... int DrawViewDimension::getRefType() const { @@ -1313,6 +1355,275 @@ bool DrawViewDimension::checkReferences2D() const return true; } +void DrawViewDimension::updateSavedGeometry() +{ +// Base::Console().Message("DVD::updateSavedGeometry() - %s - savedGeometry: %d\n", +// getNameInDocument(), SavedGeometry.getValues().size()); + ReferenceVector references = getEffectiveReferences(); + std::vector newGeometry; + const std::vector oldGeometry = SavedGeometry.getValues(); + //need to clean up old geometry objects here? + + for (auto& entry : references) { + if (entry.getSubName().empty()) { + // view only reference has no geometry. + continue; + } + newGeometry.push_back(entry.asTopoShape()); +// Base::Console().Message("DVD::updateSavedGeometry - entry.isNull: %d\n", entry.asTopoShape().isNull()); + } + if (newGeometry.empty()) { + //clear out the old SavedGeometry + SavedGeometry.clear(); + } else { + SavedGeometry.setValues(newGeometry); + } +} + +// routines related to detecting that references no longer point to the same geometry as +// when they were created. +// returns true if the saved geometry is the same as the current reference geometry +// returns false if the saved geometry is different from the the current reference geometry +bool DrawViewDimension::compareSavedGeometry() +{ +// Base::Console().Message("DVD::compareSavedGeometry() - isRestoring: %d\n", isRestoring()); + const std::vector savedGeometry = SavedGeometry.getValues(); + if (savedGeometry.empty()) { + // no saved geometry, so we have nothing to compare, so we don't know if there has been a change + return true; + } + + ReferenceVector references = getEffectiveReferences(); + std::vector referenceGeometry; + for (auto& entry : references) { + referenceGeometry.push_back(entry.asTopoShape()); + } + if (savedGeometry.size() != referenceGeometry.size()) { +// Base::Console().Message("DVD::compareSavedGeometry - geometry sizes have changed\n"); + return false; + } + int geometryCount = savedGeometry.size(); + int iGeom = 0; + for ( ; iGeom < geometryCount; iGeom++) { + if (savedGeometry.at(iGeom).getTypeId() != referenceGeometry.at(iGeom).getTypeId()) { +// Base::Console().Message("DVD::compareSavedGeometry - saved geometry (%d) has different type\n", iGeom); + return false; + } + } + //saved and reference geometry have same count and types + for (iGeom = 0; iGeom < geometryCount; iGeom++) { + Part::TopoShape temp = savedGeometry.at(iGeom); + if (!m_matcher->compareGeometry(temp, referenceGeometry.at(iGeom)) ) { +// Base::Console().Message("DVD::compareSavedGeometry - saved geometry (%d) does not match current geometry\n", iGeom); + return false; + } + } + + //free the reference geometry? + return true; +} + +// deal with the situation where references do not point to the same geometry as +// when they were created. +bool DrawViewDimension::fixExactMatch() +{ +// Base::Console().Message("DVD::fixExactMatch() - reference geometry has changed\n"); + if (!Preferences::autoCorrectDimRefs()) { + return false; + } + ReferenceVector references = getEffectiveReferences(); + std::vector< std::pair > refsToFix2d; + std::vector< std::pair > refsToFix3d; + bool success(true); + int referenceCount = references.size(); + int iRef = 0; + for ( ; iRef < referenceCount; iRef++) { + std::string newReference(""); + TopoDS_Shape geomShape = references.at(iRef).getGeometry(); + if (references.at(iRef).is3d()) { + if (geomShape.ShapeType() == TopAbs_VERTEX) { + newReference = recoverChangedVertex3d(iRef); + } else { + newReference = recoverChangedEdge3d(iRef); + } + if (!newReference.empty()) { + std::pair toFix(iRef, newReference); + refsToFix3d.push_back(toFix); + } else { + Base::Console().Warning("%s - no exact match for changed 3d reference: %d\n", getNameInDocument(), iRef); + success = false; + } + } else { + if (geomShape.ShapeType() == TopAbs_VERTEX) { + newReference = recoverChangedVertex2d(iRef); + } else { + newReference = recoverChangedEdge2d(iRef); + } + if (!newReference.empty()) { + std::pair toFix(iRef, newReference); + refsToFix2d.push_back(toFix); + } else { + Base::Console().Warning("%s - no exact match for changed 2d reference: %d\n", getNameInDocument(), iRef); + success = false; + } + } + } + + for (auto& fix : refsToFix2d) { + replaceReferenceSubElement2d(fix.first, fix.second); + } + for (auto& fix : refsToFix3d) { + replaceReferenceSubElement3d(fix.first, fix.second); + } + + return success; +} + +// deal with situation where the current geometry does not match the saved geometry, +// but we did not find an exact match in the geometry pile +void DrawViewDimension::handleNoExactMatch() +{ +// Base::Console().Message("DVD::handleNoExactMatch()\n"); + Base::Console().Message("%s - trying to match changed geometry - stage 2\n", getNameInDocument()); + // this is where we insert the clever logic to determine that the changed geometry + // actually still represents the "front top left" edge. + updateSavedGeometry(); + m_referencesCorrect = true; +} + +//find an edge in the view that matches the reference entry's type and characteristics +std::string DrawViewDimension::recoverChangedEdge2d(int iReference) +{ +// Base::Console().Message("DVD::recoverChangedEdge2d(ref: %d)\n", iReference); + double scale = getViewPart()->getScale(); + Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference); + std::vector gEdges = getViewPart()->getEdgeGeometry(); + int iEdge = 0; + for (auto& edge : gEdges) { + Part::TopoShape temp = edge->asTopoShape(scale); + if (savedGeometryItem.getTypeId() != temp.getTypeId()) { + // if the typeIds don't match, we can not compare the geometry +// Base::Console().Message("DVD::recoverChangedEdge2d - types do not match\n"); + iEdge++; + continue; + } + bool isSame = m_matcher->compareGeometry(savedGeometryItem, temp); +// Base::Console().Message("DVD::recoverChangedEdge2d - iEdge: %d isSame: %d\n", iEdge, isSame); + if (isSame) { + return std::string("Edge") + std::to_string(iEdge); + } + iEdge++; + } + return std::string(""); +} + +std::string DrawViewDimension::recoverChangedVertex2d(int iReference) +{ +// Base::Console().Message("DVD::recoverChangedVertex2d(%d)\n", iReference); + double scale = getViewPart()->getScale(); + Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference); + std::vector gVertexAll = getViewPart()->getVertexGeometry(); + int iVertex = 0; + for (auto& vert : gVertexAll) { + Part::TopoShape temp = vert->asTopoShape(scale); + bool isSame = m_matcher->compareGeometry(savedGeometryItem, temp); + if (isSame) { + return std::string("Vertex") + std::to_string(iVertex); + } + iVertex++; + } + return std::string(""); +} + +std::string DrawViewDimension::recoverChangedEdge3d(int iReference) +{ +// Base::Console().Message("DVD::recoverChangedEdge3d(%d)\n", iReference); + Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference); + ReferenceVector references = getEffectiveReferences(); + App::DocumentObject* searchObject = references.at(iReference).getObject(); + Part::TopoShape shape = Part::Feature::getTopoShape(searchObject); + App::GeoFeature* geoFeat = dynamic_cast(searchObject); + //does a feature in a body get the body's globalPlacement?? + if (geoFeat) { + shape.setPlacement(geoFeat->globalPlacement()); + } + //TODO: these TopoShapes will have to be released when we are finished with them + std::vector edgesAll = getEdges(shape); + int iEdge = 1; //note that edge numbering starts at 1! + for (auto& edge : edgesAll) { + bool isSame = m_matcher->compareGeometry(savedGeometryItem, edge); + if (isSame) { + return std::string("Edge") + std::to_string(iEdge); + } + iEdge++; + } + return std::string(""); +} + +// based on Part::TopoShapePyImp::getShapes. Produces a vector of unique edges within the shape +std::vector DrawViewDimension::getEdges(const TopoShape& inShape) +{ + std::vector ret; + TopTools_IndexedMapOfShape M; + TopExp_Explorer Ex(inShape.getShape(), TopAbs_EDGE); + while (Ex.More()) { + M.Add(Ex.Current()); + Ex.Next(); + } + + for (Standard_Integer k = 1; k <= M.Extent(); k++) { + const TopoDS_Shape& shape = M(k); + ret.push_back(TopoShape(shape)); + } + + return ret; +} + +// as recoverChangedVertex2d, but 3d references do not need to be unscaled +std::string DrawViewDimension::recoverChangedVertex3d(int iReference) +{ +// Base::Console().Message("DVD::recoverChangedVertex3d(%d)\n", iReference); + Part::TopoShape savedGeometryItem = SavedGeometry.getValues().at(iReference); + ReferenceVector references = getEffectiveReferences(); + App::DocumentObject* searchObject = references.at(iReference).getObject(); + Part::TopoShape shape = Part::Feature::getTopoShape(searchObject); + App::GeoFeature* geoFeat = dynamic_cast(searchObject); + if (geoFeat) { + shape.setPlacement(geoFeat->globalPlacement()); + } + + //TODO: these TopoShapes will have to be released when we are finished with them + std::vector vertsAll = getVertexes(shape); + int iVert = 1; //note that vertex numbering starts at 1! + for (auto& vert : vertsAll) { + bool isSame = m_matcher->compareGeometry(savedGeometryItem, vert); + if (isSame) { + return std::string("Vertex") + std::to_string(iVert); + } + iVert++; + } + return std::string(""); +} + +// based on Part::TopoShapePyImp::getShapes +std::vector DrawViewDimension::getVertexes(const TopoShape& inShape) +{ + std::vector ret; + TopTools_IndexedMapOfShape M; + TopExp_Explorer Ex(inShape.getShape(), TopAbs_VERTEX); + while (Ex.More()) { + M.Add(Ex.Current()); + Ex.Next(); + } + + for (Standard_Integer k = 1; k <= M.Extent(); k++) { + const TopoDS_Shape& shape = M(k); + ret.push_back(TopoShape(shape)); + } + + return ret; +} + pointPair DrawViewDimension::closestPoints(TopoDS_Shape s1, TopoDS_Shape s2) const { pointPair result; @@ -1334,6 +1645,7 @@ pointPair DrawViewDimension::closestPoints(TopoDS_Shape s1, TopoDS_Shape s2) con //set the reference property from a reference vector void DrawViewDimension::setReferences2d(ReferenceVector refs) { +// Base::Console().Message("DVD::setReferences2d(%d)\n", refs.size()); std::vector objects; std::vector subNames; if (objects.size() != subNames.size()) { @@ -1351,6 +1663,11 @@ void DrawViewDimension::setReferences2d(ReferenceVector refs) //set the reference property from a reference vector void DrawViewDimension::setReferences3d(ReferenceVector refs) { + if (refs.empty() && !References3D.getValues().empty()) { + //clear the property of any old links + References3D.setValue(nullptr, nullptr); + return; + } std::vector objects; std::vector subNames; if (objects.size() != subNames.size()) { diff --git a/src/Mod/TechDraw/App/DrawViewDimension.h b/src/Mod/TechDraw/App/DrawViewDimension.h index bdd3c29a1b..84cba20003 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.h +++ b/src/Mod/TechDraw/App/DrawViewDimension.h @@ -27,6 +27,8 @@ #include #include +#include + #include #include "DimensionGeometry.h" @@ -35,7 +37,6 @@ #include "DrawView.h" #include "DrawViewPart.h" - class TopoDS_Shape; namespace Measure { @@ -45,6 +46,7 @@ namespace TechDraw { class DrawViewPart; class DimensionFormatter; +class GeometryMatcher; class TechDrawExport DrawViewDimension : public TechDraw::DrawView { @@ -88,6 +90,8 @@ enum DimensionType { App::PropertyAngle LineAngle; App::PropertyAngle ExtensionAngle; + Part::PropertyTopoShapeList SavedGeometry; + enum RefType{ invalidRef, oneEdge, @@ -157,6 +161,7 @@ enum DimensionType { bool useDecimals() const; bool isExtentDim() const; virtual ReferenceVector getEffectiveReferences() const; + bool goodReferenceGeometry() const { return m_referencesCorrect; } protected: void handleChangedPropertyType(Base::XMLReader &, const char * , App::Property * ) override; @@ -177,7 +182,6 @@ protected: virtual anglePoints getAnglePointsTwoEdges(ReferenceVector references); virtual anglePoints getAnglePointsThreeVerts(ReferenceVector references); -protected: Measure::Measurement *measurement; double dist2Segs(Base::Vector3d s1, Base::Vector3d e1, @@ -190,6 +194,21 @@ protected: void resetAngular(); void resetArc(); + bool okToProceed(); + void updateSavedGeometry(); + bool compareSavedGeometry(); + bool fixExactMatch(); + void handleNoExactMatch(); + std::string recoverChangedEdge2d(int iReference); + std::string recoverChangedEdge3d(int iReference); + std::string recoverChangedVertex2d(int iReference); + std::string recoverChangedVertex3d(int iReference); + void replaceReferenceSubElement2d(int iRef, std::string newSubelement); + void replaceReferenceSubElement3d(int iRef, std::string newSubelement); + + std::vector getEdges(const Part::TopoShape& inShape); + std::vector getVertexes(const Part::TopoShape& inShape); + private: static const char* TypeEnums[]; static const char* MeasureTypeEnums[]; @@ -203,6 +222,9 @@ private: friend class DimensionFormatter; DimensionFormatter* m_formatter; + GeometryMatcher* m_matcher; + + bool m_referencesCorrect; }; } //namespace TechDraw diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index daf79c2beb..d0bb12735d 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -1336,9 +1336,8 @@ Base::Vector3d DrawViewPart::getXDirection() const Base::Vector3d dir = Direction.getValue(); //make a sensible default Base::Vector3d org(0.0, 0.0, 0.0); result = getLegacyX(org, dir); - } - else { - result = propVal;//normal case. XDirection is set. + } else { + result = propVal; //normal case. XDirection is set. } } else { //no Property. can this happen? diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index d5eb694332..0dbc91777e 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -74,13 +74,18 @@ #include #include +#include +#include + #include "Geometry.h" #include "GeometryObject.h" #include "DrawUtil.h" using namespace TechDraw; +using namespace Part; using namespace std; +using DU = DrawUtil; #if OCC_VERSION_HEX >= 0x070600 using BRepAdaptor_HCurve = BRepAdaptor_Curve; @@ -704,6 +709,14 @@ void BaseGeom::intersectionCC(TechDraw::BaseGeomPtr geom1, } } +TopoShape BaseGeom::asTopoShape(double scale) +{ +// Base::Console().Message("BG::asTopoShape(%.3f) - dump: %s\n", scale, dump().c_str()); + TopoDS_Shape unscaledShape = TechDraw::scaleShape(getOCCEdge(), 1.0 / scale); + TopoDS_Edge unscaledEdge = TopoDS::Edge(unscaledShape); + return unscaledEdge; +} + Ellipse::Ellipse(const TopoDS_Edge &e) { geomType = ELLIPSE; @@ -1496,6 +1509,14 @@ void Vertex::dump(const char* title) cosmeticTag.c_str()); } +TopoShape Vertex::asTopoShape(double scale) +{ + Base::Vector3d point = DU::toVector3d(BRep_Tool::Pnt(getOCCVertex())); + point = point / scale; + BRepBuilderAPI_MakeVertex mkVert(DU::togp_Pnt(point)); + return TopoShape(mkVert.Vertex()); +} + /*static*/ BaseGeomPtrVector GeometryUtils::chainGeoms(BaseGeomPtrVector geoms) diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h index af2b810da7..606409dd9a 100644 --- a/src/Mod/TechDraw/App/Geometry.h +++ b/src/Mod/TechDraw/App/Geometry.h @@ -36,6 +36,9 @@ #include #include +namespace Part { +class TopoShape; +} namespace TechDraw { @@ -142,6 +145,7 @@ class TechDrawExport BaseGeom : public std::enable_shared_from_this void sourceIndex(int si) { m_sourceIndex = si; } std::string getCosmeticTag() { return cosmeticTag; } void setCosmeticTag(std::string t) { cosmeticTag = t; } + Part::TopoShape asTopoShape(double scale); protected: void createNewTag(); @@ -377,6 +381,8 @@ class TechDrawExport Vertex bool isReference() { return m_reference; } void isReference(bool state) { m_reference = state; } + Part::TopoShape asTopoShape(double scale); + protected: //Uniqueness void createNewTag(); diff --git a/src/Mod/TechDraw/App/GeometryMatcher.cpp b/src/Mod/TechDraw/App/GeometryMatcher.cpp new file mode 100644 index 0000000000..a06126e0f9 --- /dev/null +++ b/src/Mod/TechDraw/App/GeometryMatcher.cpp @@ -0,0 +1,262 @@ +/*************************************************************************** + * Copyright (c) 2023 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ +// a class to handle changes to dimension reference geometry + +// detects changes in reference geometry (2d & 3d) that would invalidate a dimension +// identifies replacement view/model geometry + +#include "PreCompiled.h" +#ifndef _PreComp_ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "GeometryMatcher.h" +#include "DrawUtil.h" + +using namespace TechDraw; +using DU = DrawUtil; + +// a set of routines for comparing geometry for equality. + +bool GeometryMatcher::compareGeometry(Part::TopoShape shape1, Part::TopoShape shape2) +{ +// Base::Console().Message("GM::compareGeometry()\n"); + if (shape1.isNull() || shape2.isNull()) { + Base::Console().Message("GM::compareGeometry - one or more shapes are null\n"); + } + TopoDS_Shape geom1 = shape1.getShape(); + TopoDS_Shape geom2 = shape2.getShape(); + if (geom1.ShapeType() == TopAbs_VERTEX) { + return comparePoints(geom1, geom2); + } + if (geom1.ShapeType() == TopAbs_EDGE) { + return compareEdges(geom1, geom2); + } + return false; +} + +bool GeometryMatcher::comparePoints(TopoDS_Shape shape1, TopoDS_Shape shape2) +{ +// Base::Console().Message("GM::comparePoints()\n"); + if (shape1.ShapeType() != TopAbs_VERTEX || + shape2.ShapeType() != TopAbs_VERTEX) { + // can not compare these shapes + return false; + } + auto vert1 = TopoDS::Vertex(shape1); + Base::Vector3d point1 = DU::toVector3d(BRep_Tool::Pnt(vert1)); + auto vert2 = TopoDS::Vertex(shape2); + Base::Vector3d point2 = DU::toVector3d(BRep_Tool::Pnt(vert2)); + if (point1.IsEqual(point2, EWTOLERANCE)) { + return true; + } + return false; +} + +bool GeometryMatcher::compareEdges(TopoDS_Shape shape1, TopoDS_Shape shape2) +{ +// Base::Console().Message("GM::compareEdges()\n"); + if (shape1.ShapeType() != TopAbs_EDGE || + shape2.ShapeType() != TopAbs_EDGE) { + // can not compare these shapes +// Base::Console().Message("GM::compareEdges - shape is not an edge\n"); + return false; + } + TopoDS_Edge edge1 = TopoDS::Edge(shape1); + TopoDS_Edge edge2 = TopoDS::Edge(shape2); + BRepAdaptor_Curve adapt1(edge1); + BRepAdaptor_Curve adapt2(edge2); + + if (adapt1.GetType() == GeomAbs_Line && + adapt2.GetType() == GeomAbs_Line) { + return compareLines(edge1, edge2); + } + + if (adapt1.GetType() == GeomAbs_Circle && + adapt2.GetType() == GeomAbs_Circle) { + if (adapt1.IsClosed() && adapt2.IsClosed()) { + return compareCircles(edge1, edge2); + } else { + return compareCircleArcs(edge1, edge2); + } + } + + if (adapt1.GetType() == GeomAbs_Ellipse && + adapt2.GetType() == GeomAbs_Ellipse) { + if (adapt1.IsClosed() && adapt2.IsClosed()) { + return compareEllipses(edge1, edge2); + } else { + return compareEllipseArcs(edge1, edge2); + } + } + + if (adapt1.GetType() == GeomAbs_BSplineCurve && + adapt2.GetType() == GeomAbs_BSplineCurve) { + return compareBSplines(edge1, edge2); + } + + // if we reach this point, we have dissimilar geometry types + return compareDifferent(edge1, edge2); +} + +bool GeometryMatcher::compareLines(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ +// Base::Console().Message("GM::compareLines()\n"); + auto start1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edge1))); + auto end1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edge1))); + auto start2 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edge2))); + auto end2 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edge2))); + if (start1.IsEqual(start2, EWTOLERANCE) && + end1.IsEqual(end2, EWTOLERANCE)) { + //exact match + return true; + } + return false; +} + +bool GeometryMatcher::compareCircles(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ +// Base::Console().Message("GM::compareCircles()\n"); + BRepAdaptor_Curve adapt1(edge1); + BRepAdaptor_Curve adapt2(edge2); + gp_Circ circle1 = adapt1.Circle(); + gp_Circ circle2 = adapt2.Circle(); + double radius1 = circle1.Radius(); + double radius2 = circle2.Radius(); + auto center1 = DU::toVector3d(circle1.Location()); + auto center2 = DU::toVector3d(circle2.Location()); + if (DU::fpCompare(radius1, radius2, EWTOLERANCE) && + center1.IsEqual(center2, EWTOLERANCE)) { + //exact match + return true; + } + return false; +} + +bool GeometryMatcher::compareEllipses(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ + BRepAdaptor_Curve adapt1(edge1); + BRepAdaptor_Curve adapt2(edge2); + gp_Elips ellipse1 = adapt1.Ellipse(); + gp_Elips ellipse2 = adapt2.Ellipse(); + double major1 = ellipse1.MajorRadius(); + double minor1 = ellipse1.MinorRadius(); + double major2 = ellipse2.MajorRadius(); + double minor2 = ellipse2.MinorRadius(); + auto center1 = DU::toVector3d(ellipse1.Location()); + auto center2 = DU::toVector3d(ellipse2.Location()); + if (DU::fpCompare(major1, major2, EWTOLERANCE) && + DU::fpCompare(minor1, minor2, EWTOLERANCE) && + center1.IsEqual(center2, EWTOLERANCE)) { + // exact match + return true; + } + return false; + } + +// for our purposes, only circles masquerading as bsplines are of interest +bool GeometryMatcher::compareBSplines(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ + BRepAdaptor_Curve adapt1(edge1); + BRepAdaptor_Curve adapt2(edge2); + bool isArc1(false); + bool isArc2(false); + TopoDS_Edge circleEdge1; + TopoDS_Edge circleEdge2; + try { + circleEdge1 = GeometryUtils::asCircle(edge1, isArc1); + circleEdge2 = GeometryUtils::asCircle(edge2, isArc1); + } + catch (Base::RuntimeError& e) { + Base::Console().Error("GeometryMatcher failed to make circles from splines\n"); + return false; + } + if (!isArc1 && !isArc2) { + // full circles + return compareCircles(circleEdge1, circleEdge2); + } + if (isArc1 && isArc2) { + // circular arcs + return compareCircleArcs(circleEdge1, circleEdge2); + } + + return false; +} + +// this is a weak comparison. we should also check center & radius? +bool GeometryMatcher::compareCircleArcs(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ + return compareEndPoints(edge1, edge2); +} + +bool GeometryMatcher::compareEllipseArcs(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ + return compareEndPoints(edge1, edge2); + } + +// this is where we would try to match a bspline against a line or a circle. +// not sure how successful this would be. For now, we just say it doesn't match +bool GeometryMatcher::compareDifferent(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ + BRepAdaptor_Curve adapt1(edge1); + BRepAdaptor_Curve adapt2(edge2); + return false; +} + +bool GeometryMatcher::compareEndPoints(TopoDS_Edge edge1, TopoDS_Edge edge2) +{ + BRepAdaptor_Curve adapt1(edge1); + BRepAdaptor_Curve adapt2(edge2); + double pFirst1 = adapt1.FirstParameter(); + double pLast1 = adapt1.LastParameter(); + BRepLProp_CLProps props1(adapt1, pFirst1, 0, Precision::Confusion()); + auto begin1 = DU::toVector3d(props1.Value()); + props1.SetParameter(pLast1); + auto end1 = DU::toVector3d(props1.Value()); + double pFirst2 = adapt2.FirstParameter(); + double pLast2 = adapt2.LastParameter(); + BRepLProp_CLProps props2(adapt2, pFirst2, 0, Precision::Confusion()); + auto begin2 = DU::toVector3d(props2.Value()); + props2.SetParameter(pLast2); + auto end2 = DU::toVector3d(props2.Value()); + + if (begin1.IsEqual(begin2, EWTOLERANCE) && + end1.IsEqual(end2, EWTOLERANCE)) { + //exact match + return true; + } + return false; +} diff --git a/src/Mod/TechDraw/App/GeometryMatcher.h b/src/Mod/TechDraw/App/GeometryMatcher.h new file mode 100644 index 0000000000..3b4fc2d0b8 --- /dev/null +++ b/src/Mod/TechDraw/App/GeometryMatcher.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (c) 2023 WandererFan * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ +// a class to handle changes to dimension reference geometry + +#ifndef GEOMETRYMATCHER_H +#define GEOMETRYMATCHER_H + +#include + +#include + +namespace Part +{ +class TopoShape; +} + +namespace TechDraw { + +class TechDrawExport GeometryMatcher { +public: + GeometryMatcher() {} + GeometryMatcher(DrawViewDimension* dim) { m_dimension = dim; } + ~GeometryMatcher() = default; + + bool compareGeometry(Part::TopoShape geom1, Part::TopoShape geom2); + bool comparePoints(TopoDS_Shape shape1, TopoDS_Shape shape2); + bool compareEdges(TopoDS_Shape shape1, TopoDS_Shape shape2); + + bool compareLines(TopoDS_Edge edge1, TopoDS_Edge edge2); + bool compareCircles(TopoDS_Edge edge1, TopoDS_Edge edge2); + bool compareEllipses(TopoDS_Edge edge1, TopoDS_Edge edge2); + bool compareBSplines(TopoDS_Edge edge1, TopoDS_Edge edge2); + bool compareDifferent(TopoDS_Edge edge1, TopoDS_Edge edge2); + bool compareCircleArcs(TopoDS_Edge edge1, TopoDS_Edge edge2); + bool compareEllipseArcs(TopoDS_Edge edge1, TopoDS_Edge edge2); + +private: + bool compareEndPoints(TopoDS_Edge edge1, TopoDS_Edge edge2); + + DrawViewDimension* m_dimension; +}; + +} //end namespace TechDraw +#endif + diff --git a/src/Mod/TechDraw/Gui/Command.cpp b/src/Mod/TechDraw/Gui/Command.cpp index 35b483372c..e88d55fbf0 100644 --- a/src/Mod/TechDraw/Gui/Command.cpp +++ b/src/Mod/TechDraw/Gui/Command.cpp @@ -1044,11 +1044,9 @@ void CmdTechDrawBalloon::activated(int iMsg) { Q_UNUSED(iMsg); bool result = _checkSelectionBalloon(this, 1); - if (!result) + if (!result) { return; - // result = _checkDrawViewPartBalloon(this); - // if (!result) - // return; + } std::vector selection = getSelection().getSelectionEx(); @@ -1085,7 +1083,8 @@ bool CmdTechDrawBalloon::isActive() { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this, false); - return (havePage && haveView); + bool taskInProgress = Gui::Control().activeDialog(); + return (havePage && haveView && !taskInProgress); } //=========================================================================== diff --git a/src/Mod/TechDraw/Gui/QGIView.cpp b/src/Mod/TechDraw/Gui/QGIView.cpp index f8de2bcd14..f3363621bb 100644 --- a/src/Mod/TechDraw/Gui/QGIView.cpp +++ b/src/Mod/TechDraw/Gui/QGIView.cpp @@ -536,6 +536,7 @@ void QGIView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q QRectF QGIView::customChildrenBoundingRect() const { QList children = childItems(); + // exceptions not to be included in determining the frame rectangle int dimItemType = QGraphicsItem::UserType + 106; // TODO: Get magic number from include by name int borderItemType = QGraphicsItem::UserType + 136; // TODO: Magic number warning int labelItemType = QGraphicsItem::UserType + 135; // TODO: Magic number warning @@ -563,7 +564,6 @@ QRectF QGIView::customChildrenBoundingRect() const (child->type() != centerMarkItemType)) { QRectF childRect = mapFromItem(child, child->boundingRect()).boundingRect(); result = result.united(childRect); - //result = result.united((*it)->boundingRect()); } } return result; diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index e0df6582f3..6a355ac433 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -52,6 +52,7 @@ #include "QGIArrow.h" #include "QGIDimLines.h" #include "QGIVertex.h" +#include "QGCustomSvg.h" #include "ViewProviderDimension.h" #include "ZVALUE.h" @@ -512,6 +513,12 @@ QGIViewDimension::QGIViewDimension() : dvDimension(nullptr), hasHover(false), m_ setZValue(ZVALUE::DIMENSION);//note: this won't paint dimensions over another View if it stacks //above this Dimension's parent view. need Layers? hideFrame(); + + m_refFlag = new QGCustomSvg(); + m_refFlag->setParentItem(this); + m_refFlag->load(QString::fromUtf8(":/icons/TechDraw_RefError.svg")); + m_refFlag->setZValue(ZVALUE::LOCK); + m_refFlag->hide(); } QVariant QGIViewDimension::itemChange(GraphicsItemChange change, const QVariant& value) @@ -637,6 +644,14 @@ void QGIViewDimension::updateView(bool update) updateDim(); } + if (dim->goodReferenceGeometry()) { + m_refFlag->hide(); + } else { +// m_refFlag->setPos(datumLabel->pos()); + m_refFlag->centerAt(datumLabel->pos() + datumLabel->boundingRect().center()); + m_refFlag->show(); + } + draw(); } diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.h b/src/Mod/TechDraw/Gui/QGIViewDimension.h index 77a929e61d..bef1415889 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.h +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.h @@ -53,6 +53,7 @@ class QGCustomText; class QGIArrow; class QGIDimLines; class QGIViewDimension; +class QGCustomSvg; class ViewProviderDimension; class QGIDatumLabel : public QGraphicsObject @@ -134,6 +135,7 @@ private: QGCustomText* m_tolTextOver; QGCustomText* m_tolTextUnder; QGCustomText* m_unitText; + QGCustomText* m_referenceFlag; QColor m_colNormal; bool m_ctrl; @@ -303,6 +305,9 @@ private: QGIArrow* aHead1; QGIArrow* aHead2; double m_lineWidth; + + QGCustomSvg* m_refFlag; + }; } // namespace MDIViewPageGui