TechDraw: Axo Dimension Fixes (#26445)

* [TD]fix dim text on wrong side of dim line

- this fixes the problem when the dimension line is +/- vertical

* [TD]Avoid use of CosmeticVertex for Axo Dimension

* [TD]fix CI warnings re unused variable

* Update DrawViewPyImp.cpp per review comments.
This commit is contained in:
WandererFan
2026-01-05 14:31:17 -05:00
committed by GitHub
parent a985f63e25
commit cc707c98eb
4 changed files with 150 additions and 10 deletions

View File

@@ -4,7 +4,7 @@ from __future__ import annotations
from typing import Any
from Base.Metadata import export
from Base.Metadata import export, constmethod
from App.DocumentObject import DocumentObject
@@ -27,10 +27,19 @@ class DrawView(DocumentObject):
No return value. Replace the current label with a translated version where possible.
"""
...
@constmethod
def getScale(self) -> Any:
"""
float scale = getScale(). Returns the correct scale for this view. Handles whether to
use this view's scale property or a parent's view (as in a projection group).
"""
...
@constmethod
def findParentPage(self) -> Any:
"""
DrawPage parent = findParentPage(). Returns the parent page that contains this view.
"""
...

View File

@@ -25,6 +25,7 @@
// inclusion of the generated files (generated out of DrawViewPy.xml)
#include <Mod/TechDraw/App/DrawViewPy.h>
#include <Mod/TechDraw/App/DrawViewPy.cpp>
#include <Mod/TechDraw/App/DrawPagePy.h>
using namespace TechDraw;
@@ -78,7 +79,7 @@ PyObject* DrawViewPy::translateLabel(PyObject *args)
}
//! return the correct scale for this view
PyObject* DrawViewPy::getScale(PyObject *args)
PyObject* DrawViewPy::getScale(PyObject *args) const
{
if (!PyArg_ParseTuple(args, "")) {
throw Py::TypeError("Do not understand passed parameter.");
@@ -89,6 +90,18 @@ PyObject* DrawViewPy::getScale(PyObject *args)
return PyFloat_FromDouble(dv->getScale());
}
//! return the correct scale for this view
PyObject* DrawViewPy::findParentPage(PyObject *args) const
{
if (!PyArg_ParseTuple(args, "")) {
throw Py::TypeError("Do not understand passed parameter.");
}
DrawView* dv = getDrawViewPtr();
DrawPage* parent = dv->findParentPage();
return Py::new_reference_to(parent->getPyObject());
}
PyObject *DrawViewPy::getCustomAttributes(const char* /*attr*/) const

View File

@@ -38,7 +38,24 @@ import FreeCADGui as Gui
import TechDrawTools.TDToolsUtil as Utils
import TechDraw
from math import degrees
import math
# A hack to deal with garbage in the low bits causing wrong decisions. dimensionLineAngle is in radians. If
# dimensionLineAngle is 90deg +/- AngularTolerance, we treat it as a vertical dimension line. This affects which
# side of the dimension line is used for the dimension text.
def makePlumb(dimensionLineAngle):
HalfPi = math.pi / 2.0
AngularTolerance = 0.01 # This value is a guess. It works for the file in issue #16172, but
# seems small (~0.5deg).
if math.isclose(dimensionLineAngle, HalfPi, abs_tol=AngularTolerance):
return HalfPi
elif math.isclose(dimensionLineAngle, -HalfPi, abs_tol=AngularTolerance):
return -HalfPie
return dimensionLineAngle
class CommandAxoLengthDimension:
"""Creates a 3D length dimension."""
@@ -68,33 +85,57 @@ class CommandAxoLengthDimension:
edges = Utils.getSelEdges(2)
vertexes = Utils.getSelVertexes(0)
vertNames = list()
edgeNames = list()
if len(vertexes)<2:
vertexes.append(edges[0].Vertexes[0])
vertexes.append(edges[0].Vertexes[1])
edgeNames = Utils.getSelEdgeNames(2)
else:
vertNames = Utils.getSelVertexNames(2)
view = Utils.getSelView()
page = view.findParentPage()
scale = view.getScale()
StartPt, EndPt = edges[1].Vertexes[0].Point, edges[1].Vertexes[1].Point
extLineVec = EndPt.sub(StartPt)
StartPt, EndPt = edges[0].Vertexes[0].Point, edges[0].Vertexes[1].Point
dimLineVec = EndPt.sub(StartPt)
xAxis = App.Vector(1,0,0)
extAngle = degrees(extLineVec.getAngle(xAxis))
lineAngle = degrees(dimLineVec.getAngle(xAxis))
extAngle = math.degrees(extLineVec.getAngle(xAxis))
lineAngle = math.degrees(makePlumb(dimLineVec.getAngle(xAxis)))
if extLineVec.y < 0.0:
extAngle = 180-extAngle
if dimLineVec.y < 0.0:
lineAngle = 180-lineAngle
if abs(extAngle-lineAngle)>0.1:
distanceDim=TechDraw.makeDistanceDim(view,'Distance',vertexes[0].Point*scale,vertexes[1].Point*scale)
# re issue: https://github.com/FreeCAD/FreeCAD/issues/13677
# Instead of using makeDistanceDim (which is meant for extent dimensions), we use the
# same steps as in CommandCreateDims.cpp to create a regular length dimension. This avoids
# the creation of CosmeticVertex objects to serve as dimension points. These CosmeticVertex
# objects are never deleted, but are no longer used once their dimension is deleted.
# distanceDim=TechDraw.makeDistanceDim(view,'Distance',vertexes[0].Point*scale,vertexes[1].Point*scale)
distanceDim = view.Document.addObject("TechDraw::DrawViewDimension", "Dimension")
distanceDim.Type = "Distance"
distanceDim.MeasureType = "Projected" #should this not be True?
self.setReferences(distanceDim, view, edgeNames, vertNames)
page.addView(distanceDim)
distanceDim.AngleOverride = True
distanceDim.LineAngle = lineAngle
distanceDim.ExtensionAngle = extAngle
distanceDim.X = scale*(vertexes[0].Point.x+vertexes[1].Point.x)/2
distanceDim.Y = scale*(vertexes[0].Point.y+vertexes[1].Point.y)/2
distanceDim.recompute()
distanceDim.recompute() # ensure linearPoints has been set
# as in CmdCreateDims::positionDimText:
linearPoints = distanceDim.getLinearPoints()
mid = (linearPoints[0] + linearPoints[1]) / 2
distanceDim.X = mid.x
distanceDim.Y = -mid.y
(px,py,pz) = Utils.getCoordinateVectors(view)
arrowTips = distanceDim.getArrowPositions()
@@ -114,8 +155,10 @@ class CommandAxoLengthDimension:
distanceDim.recompute()
view.requestPaint()
Gui.Selection.clearSelection()
App.closeActiveTransaction()
view.touch() # make view claim its new child
def IsActive(self):
"""Return True when the command should be active or False when it should be disabled (greyed)."""
@@ -146,6 +189,16 @@ class CommandAxoLengthDimension:
else:
return formatSpec.format(value)
def setReferences(self, dimension, view, edgeNameList, vertexNameList):
references = list()
if vertexNameList:
for vert in vertexNameList:
references.append((view, vert))
else:
references.append((view, edgeNameList[0]))
dimension.References2D = references
#
# The command must be "registered" with a unique name by calling its class.
Gui.addCommand('TechDraw_AxoLengthDimension', CommandAxoLengthDimension())

View File

@@ -155,3 +155,68 @@ def getCoordinateVectors(view):
py = wire2D.Edges[1].Vertexes[0].Point
pz = wire2D.Edges[2].Vertexes[0].Point
return (px,py,pz)
# +/- the same as getSelVertexes, but returns the vertex name instead of the vertex object.
def getSelVertexNames(nVertex=1, nSel=0):
'''
vertexNames = getSelVertexNames(nVertex)
nVertex=1 ... min. number of selected vertexes
nSel=0 ... number of selected view, 0 = first selected
Return a list of the names of the selected vertexes if at least nVertex vertexes are selected, otherwise return False
'''
view = getSelView(nSel)
if not view:
return False
if not Gui.Selection.getSelectionEx():
displayMessage('TechDraw_Utils',
QT_TRANSLATE_NOOP('TechDraw_Utils','No vertex selected'))
return False
objectList = Gui.Selection.getSelectionEx()[nSel].SubElementNames
vertexNames = []
for objectString in objectList:
if objectString[0:6] == 'Vertex':
vertexNames.append(objectString)
if (len(vertexNames) < nVertex):
displayMessage('TechDraw_Utils',
QT_TRANSLATE_NOOP('TechDraw_Utils','Select at least ')+
str(nVertex)+
QT_TRANSLATE_NOOP('TechDraw_Utils',' vertexes'))
return False
return vertexNames
# +/- the same as getSelEdges, but returns the edge name instead of the vertex object.
def getSelEdgeNames(nEdge=1, nSel=0):
'''
edges = getSelEdgeNames(nEdge)
nEdge=1 ... min. number of selected edges
nSel=0 ... number of selected view, 0 = first selected
Return a list of names for selected edges if at least nedge edges are selected, otherwise return False
'''
view = getSelView(nSel)
if not view:
return False
if not Gui.Selection.getSelectionEx():
displayMessage('TechDraw_Utils',
QT_TRANSLATE_NOOP('TechDraw_Utils','No edge selected'))
return False
objectList = Gui.Selection.getSelectionEx()[nSel].SubElementNames
edgeNames = []
for objectString in objectList:
if objectString[0:4] == 'Edge':
edgeNames.append(objectString)
if (len(edgeNames) < nEdge):
displayMessage('TechDraw_Utils',
QT_TRANSLATE_NOOP('TechDraw_Utils','Select at least ')+
str(nEdge)+
QT_TRANSLATE_NOOP('TechDraw_Utils',' edges'))
return False
else:
return edgeNames