Merge pull request #13525 from Ondsel-Development/td_dimension

TechDraw: Smart dimension tool
This commit is contained in:
WandererFan
2024-05-13 12:31:32 -04:00
committed by GitHub
44 changed files with 3614 additions and 780 deletions

View File

@@ -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);
}
@@ -128,9 +131,14 @@ 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;
if (areaMeasure) {
userVal = userVal / convertValue; // divide again as area is length²
qBasicUnit = qBasicUnit + QString::fromUtf8("²");
}
}
if (isTooSmall(userVal, formatSpecifier)) {
@@ -153,37 +161,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 "";
}
}

View File

@@ -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());
}

View File

@@ -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

View File

@@ -86,6 +86,12 @@ ReferenceEntry& ReferenceEntry::operator=(const ReferenceEntry& otherRef)
}
bool ReferenceEntry::operator==(const ReferenceEntry& otherRef) const
{
return getObjectName() == otherRef.getObjectName() && getSubName() == otherRef.getSubName();
}
TopoDS_Shape ReferenceEntry::getGeometry() const
{
// Base::Console().Message("RE::getGeometry() - objectName: %s sub: **%s**\n",
@@ -206,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");
}
@@ -253,12 +263,30 @@ Part::TopoShape ReferenceEntry::asTopoShapeEdge(const TopoDS_Edge &edge)
return { edge };
}
Part::TopoShape ReferenceEntry::asTopoShapeFace(const TopoDS_Face &face)
{
return { face };
}
std::string ReferenceEntry::geomType() const
{
// Base::Console().Message("RE::geomType() - subName: **%s**\n", getSubName().c_str());
return DrawUtil::getGeomTypeFromName(getSubName());
}
GeomType ReferenceEntry::geomEdgeType() const
{
int geoId = TechDraw::DrawUtil::getIndexFromName(getSubName());
auto dvp = static_cast<TechDraw::DrawViewPart*>(getObject());
BaseGeomPtr geom = dvp->getGeomByIndex(geoId);
if (geomType() == "Edge" && geom) {
return geom->getGeomType();
}
return GeomType::NOTDEF;
}
bool ReferenceEntry::isWholeObject() const
{
return getSubName().empty();
@@ -314,12 +342,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;
}

View File

@@ -33,6 +33,7 @@
#include <TopoDS_Vertex.hxx>
#include <Mod/Part/App/TopoShape.h>
#include <Mod/TechDraw/App/Geometry.h>
namespace App
{
@@ -59,6 +60,7 @@ public:
~ReferenceEntry() = default;
ReferenceEntry& operator= (const ReferenceEntry& otherRef);
bool operator== (const ReferenceEntry& otherRef) const;
App::DocumentObject* getObject() const;
void setObject(App::DocumentObject* docObj) { m_object = docObj; }
@@ -71,6 +73,8 @@ public:
TopoDS_Shape getGeometry() const;
std::string geomType() const;
GeomType geomEdgeType() const;
bool isWholeObject() const;
Part::TopoShape asTopoShape() const;
@@ -86,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;

View File

@@ -59,13 +59,31 @@
using namespace TechDraw;
void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector<std::string> edgeNames,
DrawViewDimension* DrawDimHelper::makeExtentDim(DrawViewPart* dvp,
const std::string& dimType, ReferenceVector references2d)
{
std::vector<std::string> edgeNames;
for (auto& ref : references2d) {
if (ref.getSubName().empty()) {
continue;
}
std::string geomType = DrawUtil::getGeomTypeFromName(ref.getSubName());
if (geomType == "Edge") {
edgeNames.push_back(ref.getSubName());
}
}
int direction = dimType == "DistanceX" ? 0 : dimType == "DistanceY" ? 1 : 2;
return makeExtentDim(dvp, edgeNames, direction);
}
DrawViewDimension* DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector<std::string> edgeNames,
int direction)
{
// Base::Console().Message("DDH::makeExtentDim() - dvp: %s edgeNames: %d\n",
// dvp->Label.getValue(), edgeNames.size());
if (!dvp) {
return;
return nullptr;
}
std::string dimType = "DistanceX";
@@ -74,8 +92,12 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector<std::string> ed
dimType = "DistanceY";
dimNum = 1;
}
else if (direction == LENGTH) {
dimType = "Distance";
dimNum = 2;
}
TechDraw::DrawPage* page = dvp->findParentPage();
DrawPage* page = dvp->findParentPage();
std::string pageName = page->getNameInDocument();
App::Document* doc = dvp->getDocument();
@@ -89,8 +111,7 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector<std::string> ed
Base::Interpreter().runStringArg(
"App.activeDocument().%s.DirExtent = %d", dimName.c_str(), dimNum);
TechDraw::DrawViewDimExtent* dimExt =
dynamic_cast<TechDraw::DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
auto* dimExt = dynamic_cast<DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
if (!dimExt) {
throw Base::TypeError("Dim extent not found");
}
@@ -113,6 +134,14 @@ void DrawDimHelper::makeExtentDim(DrawViewPart* dvp, std::vector<std::string> ed
dimName.c_str());
dimExt->recomputeFeature();
return dimExt;
}
void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, const std::string& dimType, ReferenceVector references3d)
{
int direction = dimType == "DistanceX" ? 0 : dimType == "DistanceY" ? 1 : 2;
return makeExtentDim3d(dvp, references3d, direction);
}
void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, ReferenceVector references, int direction)
@@ -130,7 +159,7 @@ void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, ReferenceVector reference
dimNum = 1;
}
TechDraw::DrawPage* page = dvp->findParentPage();
DrawPage* page = dvp->findParentPage();
std::string pageName = page->getNameInDocument();
App::Document* doc = dvp->getDocument();
@@ -144,8 +173,7 @@ void DrawDimHelper::makeExtentDim3d(DrawViewPart* dvp, ReferenceVector reference
Base::Interpreter().runStringArg(
"App.activeDocument().%s.DirExtent = %d", dimName.c_str(), dimNum);
TechDraw::DrawViewDimExtent* dimExt =
dynamic_cast<TechDraw::DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
auto* dimExt = dynamic_cast<DrawViewDimExtent*>(doc->getObject(dimName.c_str()));
if (!dimExt) {
throw Base::TypeError("Dim extent not found");
}

View File

@@ -44,9 +44,18 @@ class DrawViewDimension;
/// Additional functions for working with Dimensions
class TechDrawExport DrawDimHelper {
public:
static void makeExtentDim(DrawViewPart* dvp,
static DrawViewDimension* makeExtentDim(DrawViewPart* dvp,
const std::string& dimType,
ReferenceVector references2d);
static DrawViewDimension* makeExtentDim(DrawViewPart* dvp,
std::vector<std::string> edgeNames,
int direction);
static void makeExtentDim3d(DrawViewPart* dvp,
const std::string& dimType,
ReferenceVector references2d);
static void makeExtentDim3d(DrawViewPart* dvp,
ReferenceVector references,
int direction);
@@ -55,7 +64,7 @@ class TechDrawExport DrawDimHelper {
TopoDS_Edge& boundary);
static TechDraw::DrawViewDimension* makeDistDim(DrawViewPart* dvp,
static DrawViewDimension* makeDistDim(DrawViewPart* dvp,
std::string dimType,
Base::Vector3d refMin,
Base::Vector3d refMax,

View File

@@ -31,6 +31,8 @@
#include <QString>
#include <QStringList>
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
@@ -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<DrawViewPart>() && !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<std::string>& 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<std::string>& 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;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -348,6 +348,7 @@ class TechDrawExport Face
TopoDS_Face toOccFace() const;
std::vector<Wire *> wires;
double getArea() const;
Base::Vector3d getCenter() const;
};
using FacePtr = std::shared_ptr<Face>;

View File

@@ -26,6 +26,8 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <BRepGProp.hxx>
#include <GProp_GProps.hxx>
#endif
#include <BRepAdaptor_Curve.hxx>
@@ -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");

View File

@@ -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);