diff --git a/src/Mod/TechDraw/App/DimensionFormatter.cpp b/src/Mod/TechDraw/App/DimensionFormatter.cpp index 1c78d2357e..0b9b756d09 100644 --- a/src/Mod/TechDraw/App/DimensionFormatter.cpp +++ b/src/Mod/TechDraw/App/DimensionFormatter.cpp @@ -63,16 +63,19 @@ std::string DimensionFormatter::formatValue(const qreal value, { // Base::Console().Message("DF::formatValue() - %s isRestoring: %d\n", // m_dimension->getNameInDocument(), m_dimension->isRestoring()); - bool angularMeasure = false; + bool angularMeasure = m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt"); + bool areaMeasure = m_dimension->Type.isValue("Area"); QLocale loc; Base::Quantity asQuantity; asQuantity.setValue(value); - if ( (m_dimension->Type.isValue("Angle")) || - (m_dimension->Type.isValue("Angle3Pt")) ) { - angularMeasure = true; + if (angularMeasure) { asQuantity.setUnit(Base::Unit::Angle); - } else { + } + else if (areaMeasure) { + asQuantity.setUnit(Base::Unit::Area); + } + else { asQuantity.setUnit(Base::Unit::Length); } @@ -88,6 +91,9 @@ std::string DimensionFormatter::formatValue(const qreal value, QString qMultiValueStr; QString qBasicUnit = Base::Tools::fromStdString(Base::UnitsApi::getBasicLengthUnit()); + if (areaMeasure) { + qBasicUnit = qBasicUnit + QString::fromUtf8("²"); + } QString formattedValue; if (isMultiValueSchema() && partial == 0) { @@ -128,7 +134,8 @@ std::string DimensionFormatter::formatValue(const qreal value, if (angularMeasure) { userVal = asQuantity.getValue(); qBasicUnit = QString::fromUtf8("°"); - } else { + } + else { double convertValue = Base::Quantity::parse(QString::fromLatin1("1") + qBasicUnit).getValue(); userVal = asQuantity.getValue() / convertValue; } @@ -153,37 +160,44 @@ std::string DimensionFormatter::formatValue(const qreal value, return Base::Tools::toStdString(formatPrefix) + Base::Tools::toStdString(qUserString) + Base::Tools::toStdString(formatSuffix); - } else if (partial == 1) { // prefix number[unit] suffix + } + else if (partial == 1) { // prefix number[unit] suffix if (angularMeasure) { //always insert unit after value return Base::Tools::toStdString(formatPrefix) + formattedValueString + "°" + Base::Tools::toStdString(formatSuffix); - } else if (m_dimension->showUnits()){ + } + else if (m_dimension->showUnits() || areaMeasure){ if (isDim && m_dimension->haveTolerance()) { //unit will be included in tolerance so don't repeat it here return Base::Tools::toStdString(formatPrefix) + formattedValueString + Base::Tools::toStdString(formatSuffix); - } else { + } + else { //no tolerance, so we need to include unit return Base::Tools::toStdString(formatPrefix) + formattedValueString + " " + Base::Tools::toStdString(qBasicUnit) + Base::Tools::toStdString(formatSuffix); } - } else { + } + else { //showUnits is false return Base::Tools::toStdString(formatPrefix) + formattedValueString + Base::Tools::toStdString(formatSuffix); } - } else if (partial == 2) { // just the unit + } + else if (partial == 2) { // just the unit if (angularMeasure) { return Base::Tools::toStdString(qBasicUnit); - } else if (m_dimension->showUnits()) { + } + else if (m_dimension->showUnits() || areaMeasure) { return Base::Tools::toStdString(qBasicUnit); - } else { + } + else { return ""; } } diff --git a/src/Mod/TechDraw/App/DimensionGeometry.cpp b/src/Mod/TechDraw/App/DimensionGeometry.cpp index 60186d6b96..fad87f1308 100644 --- a/src/Mod/TechDraw/App/DimensionGeometry.cpp +++ b/src/Mod/TechDraw/App/DimensionGeometry.cpp @@ -361,3 +361,35 @@ void arcPoints::dump(const std::string& text) const DrawUtil::formatVector(arcEnds.second()).c_str()); Base::Console().Message("arcPoints - midArc: %s\n", DrawUtil::formatVector(midArc).c_str()); } + + +areaPoint::areaPoint() : + area(0.0), + center(Base::Vector3d()) +{ +} + +areaPoint& areaPoint::operator=(const areaPoint& ap) +{ + area = ap.area; + center = ap.center; + return *this; +} + +void areaPoint::move(const Base::Vector3d& offset) +{ + center = center - offset; +} + +void areaPoint::project(const DrawViewPart* dvp) +{ + area = area * dvp->getScale(); + center = dvp->projectPoint(center) * dvp->getScale(); +} + +void areaPoint::dump(const std::string& text) const +{ + Base::Console().Message("areaPoint - %s\n", text.c_str()); + Base::Console().Message("areaPoint - area: %.3f center: %s\n", area, + DrawUtil::formatVector(center).c_str()); +} diff --git a/src/Mod/TechDraw/App/DimensionGeometry.h b/src/Mod/TechDraw/App/DimensionGeometry.h index 3a651dbe48..0a74b2e2eb 100644 --- a/src/Mod/TechDraw/App/DimensionGeometry.h +++ b/src/Mod/TechDraw/App/DimensionGeometry.h @@ -156,6 +156,24 @@ public: bool arcCW; }; +//a convenient container for area dimension +class TechDrawExport areaPoint +{ +public: + areaPoint(); + areaPoint(const areaPoint& ap) = default; + + areaPoint& operator= (const areaPoint& ap); + + void move(const Base::Vector3d& offset); + void project(const DrawViewPart* dvp); + void dump(const std::string& text) const; + +//TODO: setters and getters + double area; + Base::Vector3d center; +}; + } //end namespace TechDraw #endif diff --git a/src/Mod/TechDraw/App/DimensionReferences.cpp b/src/Mod/TechDraw/App/DimensionReferences.cpp index 0ff93e4819..68a1176986 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.cpp +++ b/src/Mod/TechDraw/App/DimensionReferences.cpp @@ -212,6 +212,10 @@ Part::TopoShape ReferenceEntry::asTopoShape() const TopoDS_Edge edge = TopoDS::Edge(geom); return asTopoShapeEdge(edge); } + if (geom.ShapeType() == TopAbs_FACE) { + TopoDS_Face face = TopoDS::Face(geom); + return asTopoShapeFace(face); + } throw Base::RuntimeError("Dimension Reference has unsupported geometry"); } @@ -259,6 +263,19 @@ Part::TopoShape ReferenceEntry::asTopoShapeEdge(const TopoDS_Edge &edge) return { edge }; } +Part::TopoShape ReferenceEntry::asTopoShapeFace(const TopoDS_Face &face) +{ +// Base::Console().Message("RE::asTopoShapeFace()\n"); + TopoDS_Face unscaledFace = face; + if (!is3d()) { + // 2d reference - projected and scaled. scale might have changed, so we need to unscale + auto dvp = static_cast(getObject()); + TopoDS_Shape unscaledShape = ShapeUtils::scaleShape(face, 1.0 / dvp->getScale()); + unscaledFace = TopoDS::Face(unscaledShape); + } + return { unscaledFace }; +} + std::string ReferenceEntry::geomType() const { // Base::Console().Message("RE::geomType() - subName: **%s**\n", getSubName().c_str()); @@ -333,12 +350,19 @@ bool ReferenceEntry::hasGeometry2d() const if (vert) { return true; } - } else if (gType == "Edge") { + } + else if (gType == "Edge") { auto edge = dvp->getGeomByIndex(geomNumber); if (edge) { return true; } } + else if (gType == "Face") { + auto face = dvp->getFace(getSubName()); + if (face) { + return true; + } + } return false; } diff --git a/src/Mod/TechDraw/App/DimensionReferences.h b/src/Mod/TechDraw/App/DimensionReferences.h index 47943623f6..faa5fd769c 100644 --- a/src/Mod/TechDraw/App/DimensionReferences.h +++ b/src/Mod/TechDraw/App/DimensionReferences.h @@ -90,6 +90,7 @@ private: static Part::TopoShape asTopoShapeVertex(const TopoDS_Vertex &vert); static Part::TopoShape asTopoShapeEdge(const TopoDS_Edge& edge); + static Part::TopoShape asTopoShapeFace(const TopoDS_Face& edge); App::DocumentObject* m_object{nullptr}; std::string m_subName; diff --git a/src/Mod/TechDraw/App/DrawViewDimension.cpp b/src/Mod/TechDraw/App/DrawViewDimension.cpp index 45c158a043..4f37c84be3 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.cpp +++ b/src/Mod/TechDraw/App/DrawViewDimension.cpp @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include #include @@ -93,6 +95,7 @@ const char* DrawViewDimension::TypeEnums[] = {"Distance", "Diameter", "Angle", "Angle3Pt", + "Area", nullptr}; const char* DrawViewDimension::MeasureTypeEnums[] = {"True", "Projected", nullptr}; @@ -267,6 +270,12 @@ void DrawViewDimension::resetArc() m_arcPoints.arcCW = false; } +void DrawViewDimension::resetArea() +{ + m_areaPoint.center = Base::Vector3d(0, 0, 0); + m_areaPoint.area = 0.0; +} + void DrawViewDimension::onChanged(const App::Property* prop) { if (prop == &References3D) { @@ -461,6 +470,7 @@ App::DocumentObjectExecReturn* DrawViewDimension::execute() resetLinear(); resetAngular(); resetArc(); + resetArea(); // we have either or both valid References3D and References2D ReferenceVector references = getEffectiveReferences(); @@ -499,6 +509,13 @@ App::DocumentObjectExecReturn* DrawViewDimension::execute() m_anglePoints = getAnglePointsThreeVerts(references); m_hasGeometry = true; } + else if (Type.isValue("Area")) { + if (getRefType() != oneFace) { + throw Base::RuntimeError("area dimension has non-face references"); + } + m_areaPoint = getAreaParameters(references); + m_hasGeometry = true; + } overrideKeepUpdated(false); return DrawView::execute(); @@ -679,6 +696,9 @@ double DrawViewDimension::getTrueDimValue() const else if (Type.isValue("Angle") || Type.isValue("Angle3Pt")) { result = measurement->angle(); } + else if (Type.isValue("Area")) { + result = measurement->area(); + } else { // tarfu throw Base::ValueError("getDimValue() - Unknown Dimension Type (3)"); } @@ -721,9 +741,8 @@ double DrawViewDimension::getProjectedDimValue() const } } else if (Type.isValue("Radius")) { - arcPoints pts = m_arcPoints; - result = - pts.radius / getViewPart()->getScale(); // Projected BaseGeom is scaled for drawing + // Projected BaseGeom is scaled for drawing + result = m_arcPoints.radius / getViewPart()->getScale(); } else if (Type.isValue("Diameter")) { arcPoints pts = m_arcPoints; @@ -738,6 +757,9 @@ double DrawViewDimension::getProjectedDimValue() const double legAngle = Base::toDegrees(leg0.GetAngle(leg1)); result = legAngle; } + else if (Type.isValue("Area")) { + result = m_areaPoint.area / getViewPart()->getScale(); + } return result; } @@ -927,7 +949,7 @@ arcPoints DrawViewDimension::getArcParameters(ReferenceVector references) ssMessage << getNameInDocument() << " can not find geometry for 2d reference (4)"; throw Base::RuntimeError(ssMessage.str()); } - return arcPointsFromBaseGeom(getViewPart()->getGeomByIndex(iSubelement)); + return arcPointsFromBaseGeom(geom); } // this is a 3d reference @@ -1324,6 +1346,40 @@ anglePoints DrawViewDimension::getAnglePointsThreeVerts(ReferenceVector referenc return pts; } +areaPoint DrawViewDimension::getAreaParameters(ReferenceVector references) +{ + areaPoint pts; + + App::DocumentObject* refObject = references.front().getObject(); + if (refObject->isDerivedFrom() && !references[0].getSubName().empty()) { + // this is a 2d object (a DVP + subelements) + TechDraw::FacePtr face = getViewPart()->getFace(references[0].getSubName()); + if (!face) { + std::stringstream ssMessage; + ssMessage << getNameInDocument() << " can not find geometry for 2d reference (4)"; + throw Base::RuntimeError(ssMessage.str()); + } + + pts.area = face->getArea(); + pts.center = face->getCenter(); + } + else { + // this is a 3d reference + TopoDS_Shape geometry = references[0].getGeometry(); + if (geometry.IsNull() || geometry.ShapeType() != TopAbs_FACE) { + throw Base::RuntimeError("Geometry for dimension reference is null."); + } + const TopoDS_Face& face = TopoDS::Face(geometry); + + GProp_GProps props; + BRepGProp::SurfaceProperties(face, props); + pts.area = props.Mass(); + pts.center = DrawUtil::toVector3d(props.CentreOfMass()); + } + + return pts; +} + DrawViewPart* DrawViewDimension::getViewPart() const { if (References2D.getValues().empty()) { @@ -1411,6 +1467,7 @@ int DrawViewDimension::getRefTypeSubElements(const std::vector& sub int refType = invalidRef; int refEdges{0}; int refVertices{0}; + int refFaces{0}; for (const auto& se : subElements) { if (DrawUtil::getGeomTypeFromName(se) == "Vertex") { @@ -1419,23 +1476,29 @@ int DrawViewDimension::getRefTypeSubElements(const std::vector& sub if (DrawUtil::getGeomTypeFromName(se) == "Edge") { refEdges++; } + if (DrawUtil::getGeomTypeFromName(se) == "Face") { + refFaces++; + } } - if (refEdges == 0 && refVertices == 2) { + if (refEdges == 0 && refVertices == 2 && refFaces == 0) { refType = twoVertex; } - if (refEdges == 0 && refVertices == 3) { + if (refEdges == 0 && refVertices == 3 && refFaces == 0) { refType = threeVertex; } - if (refEdges == 1 && refVertices == 0) { + if (refEdges == 1 && refVertices == 0 && refFaces == 0) { refType = oneEdge; } - if (refEdges == 1 && refVertices == 1) { + if (refEdges == 1 && refVertices == 1 && refFaces == 0) { refType = vertexEdge; } - if (refEdges == 2 && refVertices == 0) { + if (refEdges == 2 && refVertices == 0 && refFaces == 0) { refType = twoEdge; } + if (refEdges == 0 && refVertices == 0 && refFaces == 1) { + refType = oneFace; + } return refType; } @@ -1749,6 +1812,17 @@ bool DrawViewDimension::validateReferenceForm() const return (subGeom0 == "Vertex" && subGeom1 == "Vertex" && subGeom2 == "Vertex"); } + if (Type.isValue("Area")) { + if (references.size() != 1) { + return false; + } + std::string subGeom = DrawUtil::getGeomTypeFromName(references.front().getSubName()); + if (subGeom != "Face") { + return false; + } + return true; + } + return false; } diff --git a/src/Mod/TechDraw/App/DrawViewDimension.h b/src/Mod/TechDraw/App/DrawViewDimension.h index c7d687ab2b..56836c7ae9 100644 --- a/src/Mod/TechDraw/App/DrawViewDimension.h +++ b/src/Mod/TechDraw/App/DrawViewDimension.h @@ -101,6 +101,7 @@ public: twoVertex, vertexEdge, threeVertex, + oneFace, extent }; @@ -178,6 +179,10 @@ public: { return m_anglePoints; } + areaPoint getAreaPoint() + { + return m_areaPoint; + } bool leaderIntersectsArc(Base::Vector3d s, Base::Vector3d pointOnCircle); @@ -228,6 +233,8 @@ protected: virtual anglePoints getAnglePointsTwoEdges(ReferenceVector references); virtual anglePoints getAnglePointsThreeVerts(ReferenceVector references); + virtual areaPoint getAreaParameters(ReferenceVector references); + Measure::Measurement* measurement; double dist2Segs(Base::Vector3d s1, Base::Vector3d e1, Base::Vector3d s2, Base::Vector3d e2) const; @@ -236,6 +243,7 @@ protected: void resetLinear(); void resetAngular(); void resetArc(); + void resetArea(); bool okToProceed(); void updateSavedGeometry(); @@ -252,6 +260,7 @@ private: pointPair m_arrowPositions; arcPoints m_arcPoints; anglePoints m_anglePoints; + areaPoint m_areaPoint; bool m_hasGeometry; friend class DimensionFormatter; diff --git a/src/Mod/TechDraw/App/Geometry.cpp b/src/Mod/TechDraw/App/Geometry.cpp index e73a2faf1a..5c768e7541 100644 --- a/src/Mod/TechDraw/App/Geometry.cpp +++ b/src/Mod/TechDraw/App/Geometry.cpp @@ -168,6 +168,13 @@ Base::Vector3d Face::getCenter() const { return DrawUtil::toVector3d(faceProps.CentreOfMass()); } +double Face::getArea() const { + GProp_GProps faceProps; + BRepGProp::SurfaceProperties(toOccFace(), faceProps); + + return faceProps.Mass(); +} + Face::~Face() { for(auto it : wires) { diff --git a/src/Mod/TechDraw/App/Geometry.h b/src/Mod/TechDraw/App/Geometry.h index 759e9d18ed..86be92638d 100644 --- a/src/Mod/TechDraw/App/Geometry.h +++ b/src/Mod/TechDraw/App/Geometry.h @@ -348,6 +348,7 @@ class TechDrawExport Face TopoDS_Face toOccFace() const; std::vector wires; + double getArea() const; Base::Vector3d getCenter() const; }; using FacePtr = std::shared_ptr; diff --git a/src/Mod/TechDraw/App/GeometryMatcher.cpp b/src/Mod/TechDraw/App/GeometryMatcher.cpp index 004e195860..e7ba33dffa 100644 --- a/src/Mod/TechDraw/App/GeometryMatcher.cpp +++ b/src/Mod/TechDraw/App/GeometryMatcher.cpp @@ -26,6 +26,8 @@ #include "PreCompiled.h" #ifndef _PreComp_ +#include +#include #endif #include @@ -75,9 +77,13 @@ bool GeometryMatcher::compareGeometry(const Part::TopoShape &shape1, const Part: if (geom1.ShapeType() == TopAbs_EDGE) { return compareEdges(geom1, geom2); } + if (geom1.ShapeType() == TopAbs_FACE) { + return compareFaces(geom1, geom2); + } return false; } + bool GeometryMatcher::comparePoints(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) { // Base::Console().Message("GM::comparePoints()\n"); @@ -92,6 +98,27 @@ bool GeometryMatcher::comparePoints(const TopoDS_Shape& shape1, const TopoDS_Sha return point1.IsEqual(point2, EWTOLERANCE); } +bool GeometryMatcher::compareFaces(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) +{ + // Base::Console().Message("GM::compareFaces()\n"); + + if (shape1.ShapeType() != TopAbs_FACE || shape2.ShapeType() != TopAbs_FACE) { + // can not compare these shapes + return false; + } + TopoDS_Face face1 = TopoDS::Face(shape1); + TopoDS_Face face2 = TopoDS::Face(shape2); + + //Note: face1.IsSame(face2) and face1.IsEqual(face2) do not work. + + GProp_GProps props1, props2; + BRepGProp::SurfaceProperties(face1, props1); + BRepGProp::SurfaceProperties(face2, props2); + + // Check if areas are approximately equal + return fabs(props1.Mass() - props2.Mass()) < 1e-5; +} + bool GeometryMatcher::compareEdges(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2) { // Base::Console().Message("GM::compareEdges()\n"); diff --git a/src/Mod/TechDraw/App/GeometryMatcher.h b/src/Mod/TechDraw/App/GeometryMatcher.h index 00dd3028dc..9b2d16f929 100644 --- a/src/Mod/TechDraw/App/GeometryMatcher.h +++ b/src/Mod/TechDraw/App/GeometryMatcher.h @@ -58,6 +58,7 @@ public: private: static bool comparePoints(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); static bool compareEdges(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); + static bool compareFaces(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2); static bool compareLines(const TopoDS_Edge& edge1, const TopoDS_Edge& edge2); static bool compareCircles(const TopoDS_Edge& edge1, const TopoDS_Edge& edge2); diff --git a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp index 14a565a303..d4d69cc47b 100644 --- a/src/Mod/TechDraw/Gui/CommandCreateDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandCreateDims.cpp @@ -89,6 +89,7 @@ void execAngle(Gui::Command* cmd); void execAngle3Pt(Gui::Command* cmd); void execRadius(Gui::Command* cmd); void execDiameter(Gui::Command* cmd); +void execArea(Gui::Command* cmd); void execExtent(Gui::Command* cmd, const std::string& dimType); @@ -395,7 +396,7 @@ public: bool mouseReleaseEvent(QMouseEvent* event) override { - //Base::Console().Warning("mouseReleaseEvent TH\n"); + // Base::Console().Warning("mouseReleaseEvent TH\n"); bool finalize = true; if (removedRef.hasGeometry()) { @@ -429,7 +430,6 @@ public: } } else { - Base::Console().Warning("h4\n"); ReferenceVector& selVector = getSelectionVector(addedRef); selVector.push_back(addedRef); @@ -464,7 +464,7 @@ public: void onSelectionChanged(const Gui::SelectionChanges& msg) { - Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); + //Base::Console().Warning("onSelectionChanged %d - --%s--\n", (int)msg.Type, msg.pSubName); if (msg.Type == Gui::SelectionChanges::ClrSelection) { //clearAndRestartCommand(); @@ -568,6 +568,9 @@ protected: availableDimension = AvailableDimension::FIRST; + partFeat = dynamic_cast(initialSelection[0].getObject()); + if (!partFeat) { return; } + // Add the selected elements to their corresponding selection vectors for (auto& ref : initialSelection) { ReferenceVector& selVector = getSelectionVector(ref); @@ -707,7 +710,8 @@ protected: GeomSelectionSizes selection(selPoints.size(), selLine.size(), selCircleArc.size(), selEllipseArc.size(), selSplineAndCo.size(), selFaces.size()); if (selection.hasFaces()) { - makeCts_Faces(selAllowed, pos); + if (selection.has1Face()) { makeCts_Faces(selAllowed, pos); } + else { return false; } // nothing else with face works } else if (selection.hasPoints()) { if (selection.has1Point()) { selAllowed = true; } @@ -739,15 +743,14 @@ protected: return selAllowed; } - // TODO void makeCts_Faces(bool& selAllowed, QPoint& pos) { //area if (availableDimension == AvailableDimension::FIRST) { - /*restartCommand(QT_TRANSLATE_NOOP("Command", "Add Area dimension")); - createAreaDimension(pos); + restartCommand(QT_TRANSLATE_NOOP("Command", "Add Area dimension")); + createAreaDimension(selFaces[0], pos); selAllowed = true; - availableDimension = AvailableDimension::RESET;*/ + availableDimension = AvailableDimension::RESET; } } @@ -997,31 +1000,12 @@ protected: } } - //TODO - void createAreaDimension(QPoint& pos) + void createAreaDimension(ReferenceEntry ref, QPoint& pos) { - /*// see CmdTechDrawExtensionAreaAnnotation::activated - Base::Vector3d center; - double totalArea = 0.0; - for (auto& ref : selFaces) { - TechDraw::FacePtr face = partFeat->getFace(ref.getSubName()); - if (!face) { - continue; - } + DrawViewDimension* dim = dimMaker(partFeat, "Area", { ref }, {}); - GProp_GProps faceProps; - BRepGProp::SurfaceProperties(face->toOccFace(), faceProps); - - double faceArea = faceProps.Mass(); - totalArea += faceArea; - center += faceArea * DrawUtil::toVector3d(faceProps.CentreOfMass()); - } - if (totalArea > 0.0) { - center /= totalArea; - } - - //function (and file) to create in CommandExtensionPack.h - auto* areaBalloon = createAreaBalloon(totalArea, center);*/ + dims.push_back(dim); + moveDimension(pos, dim); } void createRadiusDiameterDimension(ReferenceEntry ref, QPoint& pos, bool firstCstr) { @@ -1366,6 +1350,7 @@ public: addCommand("TechDraw_DiameterDimension"); addCommand("TechDraw_AngleDimension"); addCommand("TechDraw_3PtAngleDimension"); + addCommand("TechDraw_AreaDimension"); addCommand("TechDraw_ExtensionCreateLengthArc"); addCommand(); //separator addCommand("TechDraw_HorizontalExtentDimension"); @@ -2095,6 +2080,95 @@ void execAngle3Pt(Gui::Command* cmd) positionDimText(dim); } +//=========================================================================== +// TechDraw_AreaDimension +//=========================================================================== + +DEF_STD_CMD_A(CmdTechDrawAreaDimension) + +CmdTechDrawAreaDimension::CmdTechDrawAreaDimension() + : Command("TechDraw_AreaDimension") +{ + sAppModule = "TechDraw"; + sGroup = QT_TR_NOOP("TechDraw"); + sMenuText = QT_TR_NOOP("Insert Area Dimension"); + sToolTipText = sMenuText; + sWhatsThis = "TechDraw_AreaDimension"; + sStatusTip = sToolTipText; + sPixmap = "TechDraw_AreaDimension"; +} + +void CmdTechDrawAreaDimension::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (dlg) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Task In Progress"), + QObject::tr("Close active task dialog and try again.")); + return; + } + + execArea(this); +} + +bool CmdTechDrawAreaDimension::isActive() +{ + bool havePage = DrawGuiUtil::needPage(this); + bool haveView = DrawGuiUtil::needView(this); + return (havePage && haveView); +} + +void execArea(Gui::Command* cmd) +{ + bool result = _checkDrawViewPart(cmd); + if (!result) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Incorrect selection"), + QObject::tr("No View of a Part in selection.")); + return; + } + + ReferenceVector references2d; + ReferenceVector references3d; + TechDraw::DrawViewPart* partFeat = + TechDraw::getReferencesFromSelection(references2d, references3d); + + //Define the geometric configuration required for a length dimension + StringVector acceptableGeometry({"Face"}); + std::vector minimumCounts({1}); + std::vector acceptableDimensionGeometrys({isFace}); + + //what 2d geometry configuration did we receive? + DimensionGeometryType geometryRefs2d = validateDimSelection( + references2d, acceptableGeometry, minimumCounts, acceptableDimensionGeometrys); + if (geometryRefs2d == TechDraw::isInvalid) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Incorrect Selection"), + QObject::tr("Can not make 2d angle dimension from selection")); + return; + } + + //what 3d geometry configuration did we receive? + DimensionGeometryType geometryRefs3d; + if (geometryRefs2d == TechDraw::isViewReference && !references3d.empty()) { + geometryRefs3d = validateDimSelection3d(partFeat, + references3d, + acceptableGeometry, + minimumCounts, + acceptableDimensionGeometrys); + if (geometryRefs3d == TechDraw::isInvalid) { + QMessageBox::warning(Gui::getMainWindow(), + QObject::tr("Incorrect Selection"), + QObject::tr("Can not make 3d angle dimension from selection")); + return; + } + } + + //build the dimension + dimensionMaker(partFeat, "Area", references2d, references3d); +} + // TechDraw_LinkDimension is DEPRECATED. Use TechDraw_DimensionRepair instead. //! link 3D geometry to Dimension(s) on a Page @@ -2593,6 +2667,7 @@ void CreateTechDrawCommandsDims() rcCmdMgr.addCommand(new CmdTechDrawVerticalDimension()); rcCmdMgr.addCommand(new CmdTechDrawAngleDimension()); rcCmdMgr.addCommand(new CmdTechDraw3PtAngleDimension()); + rcCmdMgr.addCommand(new CmdTechDrawAreaDimension()); rcCmdMgr.addCommand(new CmdTechDrawExtentGroup()); rcCmdMgr.addCommand(new CmdTechDrawVerticalExtentDimension()); rcCmdMgr.addCommand(new CmdTechDrawHorizontalExtentDimension()); @@ -2646,8 +2721,7 @@ DrawViewDimension* dimMaker(TechDraw::DrawViewPart* dvp, std::string dimType, dimName.c_str(), "Projected"); - auto* dim = - dynamic_cast(dvp->getDocument()->getObject(dimName.c_str())); + auto* dim = dynamic_cast(dvp->getDocument()->getObject(dimName.c_str())); if (!dim) { throw Base::TypeError("CmdTechDrawNewDiameterDimension - dim not found\n"); } diff --git a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp index 5a777b5b5f..abe41eeb39 100644 --- a/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp +++ b/src/Mod/TechDraw/Gui/CommandExtensionDims.cpp @@ -25,6 +25,8 @@ # include # include # include +# include +# include #endif # include diff --git a/src/Mod/TechDraw/Gui/DimensionValidators.cpp b/src/Mod/TechDraw/Gui/DimensionValidators.cpp index e991a938a6..0e2daadc29 100644 --- a/src/Mod/TechDraw/Gui/DimensionValidators.cpp +++ b/src/Mod/TechDraw/Gui/DimensionValidators.cpp @@ -116,7 +116,7 @@ DimensionGeometryType TechDraw::validateDimSelection( StringVector subNames; TechDraw::DrawViewPart* dvpSave(nullptr); for (auto& ref : references) { - TechDraw::DrawViewPart* dvp = dynamic_cast(ref.getObject()); + auto* dvp = dynamic_cast(ref.getObject()); if (dvp) { dvpSave = dvp; if (!ref.getSubName().empty()) { @@ -295,6 +295,10 @@ DimensionGeometryType TechDraw::getGeometryConfiguration(ReferenceVector valid2d if (config > isInvalid) { return config; } + config = isValidSingleFace(valid2dReferences.front()); + if (config > isInvalid) { + return config; + } // no valid configuration found return isInvalid; @@ -336,6 +340,10 @@ DimensionGeometryType TechDraw::getGeometryConfiguration3d(DrawViewPart* dvp, if (config > isInvalid) { return config; } + config = isValidSingleFace3d(dvp, valid3dReferences.front()); + if (config > isInvalid) { + return config; + } config = isValidHybrid3d(dvp, valid3dReferences); if (config > isInvalid) { return config; @@ -461,6 +469,47 @@ DimensionGeometryType TechDraw::isValidSingleEdge3d(DrawViewPart* dvp, Reference return isInvalid; } +//! verify that Selection contains a valid Geometry for a single Edge Dimension +DimensionGeometryType TechDraw::isValidSingleFace(ReferenceEntry ref) +{ + auto objFeat(dynamic_cast(ref.getObject())); + if (!objFeat) { + return isInvalid; + } + + //the Name starts with "Edge" + std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName()); + if (geomName != "Face") { + return isInvalid; + } + + auto geom = objFeat->getFace(ref.getSubName()); + if (!geom) { + return isInvalid; + } + + return isFace; +} + +//! verify that Selection contains a valid Geometry for a single Edge Dimension +DimensionGeometryType TechDraw::isValidSingleFace3d(DrawViewPart* dvp, ReferenceEntry ref) +{ + (void)dvp; + //the Name starts with "Edge" + std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName()); + if (geomName != "Face") { + return isInvalid; + } + + TopoDS_Shape refShape = ref.getGeometry(); + if (refShape.IsNull() || refShape.ShapeType() != TopAbs_FACE) { + Base::Console().Warning("Geometry for reference is not a face.\n"); + return isInvalid; + } + + return isFace; +} + //! verify that the edge references can make a dimension. Currently only extent //! dimensions support more than 2 edges DimensionGeometryType TechDraw::isValidMultiEdge(ReferenceVector refs) diff --git a/src/Mod/TechDraw/Gui/DimensionValidators.h b/src/Mod/TechDraw/Gui/DimensionValidators.h index 7f371670bd..339f734556 100644 --- a/src/Mod/TechDraw/Gui/DimensionValidators.h +++ b/src/Mod/TechDraw/Gui/DimensionValidators.h @@ -60,6 +60,7 @@ enum DimensionGeometryEnum { isMultiEdge, isZLimited, isHybrid, + isFace, isViewReference //never needs to be specified in the acceptable list }; @@ -89,11 +90,13 @@ bool checkGeometryOccurrences(StringVector subNames, GeomCountMap keyedMinimumCo DimensionGeometryType isValidVertexes(ReferenceVector refs); DimensionGeometryType isValidMultiEdge(ReferenceVector refs); DimensionGeometryType isValidSingleEdge(ReferenceEntry ref); +DimensionGeometryType isValidSingleFace(ReferenceEntry ref); DimensionGeometryType isValidHybrid(ReferenceVector refs); DimensionGeometryType isValidVertexes3d(DrawViewPart* dvp, ReferenceVector refs); DimensionGeometryType isValidMultiEdge3d(DrawViewPart* dvp, ReferenceVector refs); DimensionGeometryType isValidSingleEdge3d(DrawViewPart* dvp, ReferenceEntry ref); +DimensionGeometryType isValidSingleFace3d(DrawViewPart* dvp, ReferenceEntry ref); DimensionGeometryType isValidHybrid3d(DrawViewPart* dvp, ReferenceVector refs); long int mapGeometryTypeToDimType(long int dimType, DimensionGeometryType geometry2d, diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp index 6a3e7d139d..86aaa7fc9a 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.cpp @@ -717,9 +717,9 @@ void QGIViewDimension::draw() return; } - TechDraw::DrawViewDimension* dim = dynamic_cast(getViewObject()); + auto* dim = dynamic_cast(getViewObject()); if (!dim ||//nothing to draw, don't try - !dim->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId()) + !dim->isDerivedFrom() || !dim->has2DReferences()) { datumLabel->hide(); hide(); @@ -767,6 +767,9 @@ void QGIViewDimension::draw() else if (strcmp(dimType, "Angle") == 0 || strcmp(dimType, "Angle3Pt") == 0) { drawAngle(dim, vp); } + else if (strcmp(dimType, "Area") == 0) { + drawArea(dim, vp); + } else { Base::Console().Error("QGIVD::draw - this DimensionType is unknown: %s\n", dimType); } @@ -2085,6 +2088,75 @@ void QGIViewDimension::drawRadiusExecutive(const Base::Vector2d& centerPoint, dimLines->setPath(radiusPath); } +void QGIViewDimension::drawAreaExecutive(const Base::Vector2d& centerPoint, double area, + const Base::BoundBox2d& labelRectangle, + double centerOverhang, int standardStyle, + int renderExtent, bool flipArrow) const +{ + QPainterPath areaPath; + + Base::Vector2d labelCenter(labelRectangle.GetCenter()); + double labelAngle = 0.0; + + if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING + || standardStyle == ViewProviderDimension::STD_STYLE_ASME_REFERENCING) { + // The dimensional value text must stay horizontal + + bool left = labelCenter.x < centerPoint.x; + + Base::Vector2d jointDirection; + if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING) { + jointDirection = getIsoRefJointPoint(labelRectangle, left) - centerPoint; + } + else { + jointDirection = getAsmeRefJointPoint(labelRectangle, left) - centerPoint; + } + + double lineAngles = jointDirection.Angle(); + double jointPositions = jointDirection.Length(); + + drawDimensionLine(areaPath, centerPoint, lineAngles, 0.0, + jointPositions, labelRectangle, 1, standardStyle, flipArrow); + + Base::Vector2d outsetPoint(standardStyle == ViewProviderDimension::STD_STYLE_ISO_REFERENCING + ? getIsoRefOutsetPoint(labelRectangle, left) + : getAsmeRefOutsetPoint(labelRectangle, left)); + + areaPath.moveTo(toQtGui(outsetPoint)); + areaPath.lineTo(toQtGui(centerPoint + jointDirection)); + } + else if (standardStyle == ViewProviderDimension::STD_STYLE_ISO_ORIENTED) { + // We may rotate the label so no reference line is needed + double lineAngle; + double devAngle = computeLineAndLabelAngles(centerPoint, labelCenter, + labelRectangle.Height() * 0.5 + getIsoDimensionLineSpacing(), + lineAngle, labelAngle); + + lineAngle = lineAngle - M_PI; + double labelPosition = -cos(devAngle) * ((labelCenter - centerPoint).Length()); + + drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow); + } + else if (standardStyle == ViewProviderDimension::STD_STYLE_ASME_INLINED) { + // Text must remain horizontal, but it may split the leader line + Base::Vector2d labelDirection(labelCenter - centerPoint); + double lineAngle = labelDirection.Angle(); + double labelPosition = labelDirection.Length(); + + drawDimensionLine(areaPath, centerPoint, lineAngle, 0.0, labelPosition, labelRectangle, 1, standardStyle, flipArrow); + } + else { + Base::Console().Error( + "QGIVD::drawRadiusExecutive - this Standard&Style is not supported: %d\n", + standardStyle); + } + + datumLabel->setTransformOriginPoint(datumLabel->boundingRect().center()); + datumLabel->setRotation(toQtDeg(labelAngle)); + + dimLines->setPath(areaPath); +} + void QGIViewDimension::drawDistance(TechDraw::DrawViewDimension* dimension, ViewProviderDimension* viewProvider) const { @@ -2510,6 +2582,21 @@ void QGIViewDimension::drawAngle(TechDraw::DrawViewDimension* dimension, dimLines->setPath(anglePath); } +void QGIViewDimension::drawArea(TechDraw::DrawViewDimension* dimension, + ViewProviderDimension* viewProvider) const +{ + Base::BoundBox2d labelRectangle( + fromQtGui(mapRectFromItem(datumLabel, datumLabel->boundingRect()))); + areaPoint areaPoint = dimension->getAreaPoint(); + + double endAngle; + double startRotation; + + drawAreaExecutive( + fromQtApp(areaPoint.center), areaPoint.area, labelRectangle, 0.0, viewProvider->StandardAndStyle.getValue(), + viewProvider->RenderingExtent.getValue(), viewProvider->FlipArrowheads.getValue()); +} + QColor QGIViewDimension::prefNormalColor() { setNormalColor(PreferencesGui::getAccessibleQColor(PreferencesGui::dimQColor())); diff --git a/src/Mod/TechDraw/Gui/QGIViewDimension.h b/src/Mod/TechDraw/Gui/QGIViewDimension.h index 891260abb8..34524c1410 100644 --- a/src/Mod/TechDraw/Gui/QGIViewDimension.h +++ b/src/Mod/TechDraw/Gui/QGIViewDimension.h @@ -261,10 +261,14 @@ protected: double endAngle, double startRotation, const Base::BoundBox2d &labelRectangle, double centerOverhang, int standardStyle, int renderExtent, bool flipArrow) const; + void drawAreaExecutive(const Base::Vector2d ¢erPoint, double area, const Base::BoundBox2d &labelRectangle, + double centerOverhang, int standardStyle, int renderExtent, bool flipArrow) const; + void drawDistance(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; void drawRadius(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; void drawDiameter(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; void drawAngle(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; + void drawArea(TechDraw::DrawViewDimension *dimension, ViewProviderDimension *viewProvider) const; QVariant itemChange( GraphicsItemChange change, const QVariant &value ) override; diff --git a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc index 19cbeef03b..132fcfc226 100644 --- a/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc +++ b/src/Mod/TechDraw/Gui/Resources/TechDraw.qrc @@ -86,6 +86,7 @@ icons/square.svg icons/TechDraw_3PtAngleDimension.svg icons/TechDraw_AngleDimension.svg + icons/TechDraw_AreaDimension.svg icons/TechDraw_Balloon.svg icons/TechDraw_CameraOrientation.svg icons/TechDraw_DiameterDimension.svg diff --git a/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_AreaDimension.svg b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_AreaDimension.svg new file mode 100644 index 0000000000..534f53298b --- /dev/null +++ b/src/Mod/TechDraw/Gui/Resources/icons/TechDraw_AreaDimension.svg @@ -0,0 +1,88 @@ + + + diff --git a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp index a08b4fccf3..d40b75a455 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderDimension.cpp @@ -196,6 +196,8 @@ void ViewProviderDimension::setPixmapForType() sPixmap = "TechDraw_AngleDimension"; } else if (getViewObject()->Type.isValue("Angle3Pt")) { sPixmap = "TechDraw_3PtAngleDimension"; + } else if (getViewObject()->Type.isValue("Area")) { + sPixmap = "TechDraw_ExtensionAreaAnnotation"; } } diff --git a/src/Mod/TechDraw/Gui/Workbench.cpp b/src/Mod/TechDraw/Gui/Workbench.cpp index a3abac5e24..21e17082d2 100644 --- a/src/Mod/TechDraw/Gui/Workbench.cpp +++ b/src/Mod/TechDraw/Gui/Workbench.cpp @@ -91,6 +91,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const *dimensions << "TechDraw_DiameterDimension"; *dimensions << "TechDraw_AngleDimension"; *dimensions << "TechDraw_3PtAngleDimension"; + *dimensions << "TechDraw_AreaDimension"; *dimensions << "TechDraw_HorizontalExtentDimension"; *dimensions << "TechDraw_VerticalExtentDimension"; // TechDraw_LinkDimension is DEPRECATED. Use TechDraw_DimensionRepair instead. @@ -327,6 +328,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *dims << "TechDraw_DiameterDimension"; *dims << "TechDraw_AngleDimension"; *dims << "TechDraw_3PtAngleDimension"; + *dims << "TechDraw_AreaDimension"; *dims << "TechDraw_ExtentGroup"; } @@ -346,8 +348,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *extattribs << "TechDraw_ExtensionPositionSectionView"; *extattribs << "TechDraw_ExtensionPosChainDimensionGroup"; *extattribs << "TechDraw_ExtensionCascadeDimensionGroup"; - *extattribs << "TechDraw_ExtensionAreaAnnotation"; if (separatedTools) { + *extattribs << "TechDraw_ExtensionAreaAnnotation"; *extattribs << "TechDraw_ExtensionArcLengthAnnotation"; } *extattribs << "TechDraw_ExtensionCustomizeFormat";