[Draft] Split Dimension object and reorganize of annotation objects
part 1
This commit is contained in:
committed by
Yorik van Havre
parent
0bc6e4cddc
commit
637c45733e
@@ -251,79 +251,14 @@ def makeRectangle(length, height, placement=None, face=None, support=None):
|
||||
|
||||
return obj
|
||||
|
||||
def makeDimension(p1,p2,p3=None,p4=None):
|
||||
"""makeDimension(p1,p2,[p3]) or makeDimension(object,i1,i2,p3)
|
||||
or makeDimension(objlist,indices,p3): Creates a Dimension object with
|
||||
the dimension line passign through p3.The current line width and color
|
||||
will be used. There are multiple ways to create a dimension, depending on
|
||||
the arguments you pass to it:
|
||||
- (p1,p2,p3): creates a standard dimension from p1 to p2
|
||||
- (object,i1,i2,p3): creates a linked dimension to the given object,
|
||||
measuring the distance between its vertices indexed i1 and i2
|
||||
- (object,i1,mode,p3): creates a linked dimension
|
||||
to the given object, i1 is the index of the (curved) edge to measure,
|
||||
and mode is either "radius" or "diameter".
|
||||
"""
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Dimension")
|
||||
_Dimension(obj)
|
||||
if gui:
|
||||
_ViewProviderDimension(obj.ViewObject)
|
||||
if isinstance(p1,Vector) and isinstance(p2,Vector):
|
||||
obj.Start = p1
|
||||
obj.End = p2
|
||||
if not p3:
|
||||
p3 = p2.sub(p1)
|
||||
p3.multiply(0.5)
|
||||
p3 = p1.add(p3)
|
||||
elif isinstance(p2,int) and isinstance(p3,int):
|
||||
l = []
|
||||
idx = (p2,p3)
|
||||
l.append((p1,"Vertex"+str(p2+1)))
|
||||
l.append((p1,"Vertex"+str(p3+1)))
|
||||
obj.LinkedGeometry = l
|
||||
obj.Support = p1
|
||||
p3 = p4
|
||||
if not p3:
|
||||
v1 = obj.Base.Shape.Vertexes[idx[0]].Point
|
||||
v2 = obj.Base.Shape.Vertexes[idx[1]].Point
|
||||
p3 = v2.sub(v1)
|
||||
p3.multiply(0.5)
|
||||
p3 = v1.add(p3)
|
||||
elif isinstance(p3,str):
|
||||
l = []
|
||||
l.append((p1,"Edge"+str(p2+1)))
|
||||
if p3 == "radius":
|
||||
#l.append((p1,"Center"))
|
||||
if FreeCAD.GuiUp:
|
||||
obj.ViewObject.Override = "R $dim"
|
||||
obj.Diameter = False
|
||||
elif p3 == "diameter":
|
||||
#l.append((p1,"Diameter"))
|
||||
if FreeCAD.GuiUp:
|
||||
obj.ViewObject.Override = "Ø $dim"
|
||||
obj.Diameter = True
|
||||
obj.LinkedGeometry = l
|
||||
obj.Support = p1
|
||||
p3 = p4
|
||||
if not p3:
|
||||
p3 = p1.Shape.Edges[p2].Curve.Center.add(Vector(1,0,0))
|
||||
obj.Dimline = p3
|
||||
if hasattr(FreeCAD,"DraftWorkingPlane"):
|
||||
normal = FreeCAD.DraftWorkingPlane.axis
|
||||
else:
|
||||
normal = FreeCAD.Vector(0,0,1)
|
||||
if gui:
|
||||
# invert the normal if we are viewing it from the back
|
||||
vnorm = get3DView().getViewDirection()
|
||||
if vnorm.getAngle(normal) < math.pi/2:
|
||||
normal = normal.negative()
|
||||
obj.Normal = normal
|
||||
if gui:
|
||||
formatObject(obj)
|
||||
select(obj)
|
||||
from draftobjects.dimension import make_dimension
|
||||
makeDimension = make_dimension
|
||||
|
||||
from draftobjects.dimension import LinearDimension
|
||||
_Dimension = LinearDimension
|
||||
|
||||
from draftviewproviders.view_dimension import ViewProviderLinearDimension
|
||||
_ViewProviderDimension = ViewProviderLinearDimension
|
||||
|
||||
return obj
|
||||
|
||||
@@ -3368,722 +3303,6 @@ class _ViewProviderDraftLink:
|
||||
else:
|
||||
return obj.ElementList
|
||||
|
||||
class _Dimension(_DraftObject):
|
||||
"""The Draft Dimension object"""
|
||||
def __init__(self, obj):
|
||||
_DraftObject.__init__(self,obj,"Dimension")
|
||||
|
||||
# Annotation
|
||||
obj.addProperty("App::PropertyLink","DimensionStyle",
|
||||
"Annotation",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Link dimension style"))
|
||||
|
||||
# Draft
|
||||
obj.addProperty("App::PropertyVectorDistance","Start",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Startpoint of dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVectorDistance","End",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Endpoint of dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVector","Normal",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The normal direction of this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVector","Direction",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The normal direction of this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVectorDistance","Dimline",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Point through which the dimension line passes"))
|
||||
|
||||
obj.addProperty("App::PropertyLink","Support",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The object measured by this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyLinkSubList","LinkedGeometry",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The geometry this dimension is linked to"))
|
||||
|
||||
obj.addProperty("App::PropertyLength","Distance",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The measurement of this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyBool","Diameter",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"For arc/circle measurements, false = radius, true = diameter"))
|
||||
obj.Start = FreeCAD.Vector(0,0,0)
|
||||
obj.End = FreeCAD.Vector(1,0,0)
|
||||
obj.Dimline = FreeCAD.Vector(0,1,0)
|
||||
obj.Normal = FreeCAD.Vector(0,0,1)
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
if hasattr(obj, "Distance"):
|
||||
obj.setEditorMode('Distance', 1)
|
||||
#if hasattr(obj,"Normal"):
|
||||
# obj.setEditorMode('Normal', 2)
|
||||
if hasattr(obj, "Support"):
|
||||
obj.setEditorMode('Support', 2)
|
||||
if prop == "DimensionStyle":
|
||||
if hasattr(obj, "DimensionStyle"):
|
||||
from draftutils import gui_utils
|
||||
gui_utils.format_object(target = obj, origin = obj.DimensionStyle)
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
import DraftGeomUtils
|
||||
# set start point and end point according to the linked geometry
|
||||
if obj.LinkedGeometry:
|
||||
if len(obj.LinkedGeometry) == 1:
|
||||
lobj = obj.LinkedGeometry[0][0]
|
||||
lsub = obj.LinkedGeometry[0][1]
|
||||
if len(lsub) == 1:
|
||||
if "Edge" in lsub[0]:
|
||||
n = int(lsub[0][4:])-1
|
||||
edge = lobj.Shape.Edges[n]
|
||||
if DraftGeomUtils.geomType(edge) == "Line":
|
||||
obj.Start = edge.Vertexes[0].Point
|
||||
obj.End = edge.Vertexes[-1].Point
|
||||
elif DraftGeomUtils.geomType(edge) == "Circle":
|
||||
c = edge.Curve.Center
|
||||
r = edge.Curve.Radius
|
||||
a = edge.Curve.Axis
|
||||
ray = obj.Dimline.sub(c).projectToPlane(Vector(0,0,0),a)
|
||||
if (ray.Length == 0):
|
||||
ray = a.cross(Vector(1,0,0))
|
||||
if (ray.Length == 0):
|
||||
ray = a.cross(Vector(0,1,0))
|
||||
ray = DraftVecUtils.scaleTo(ray,r)
|
||||
if hasattr(obj,"Diameter"):
|
||||
if obj.Diameter:
|
||||
obj.Start = c.add(ray.negative())
|
||||
obj.End = c.add(ray)
|
||||
else:
|
||||
obj.Start = c
|
||||
obj.End = c.add(ray)
|
||||
elif len(lsub) == 2:
|
||||
if ("Vertex" in lsub[0]) and ("Vertex" in lsub[1]):
|
||||
n1 = int(lsub[0][6:])-1
|
||||
n2 = int(lsub[1][6:])-1
|
||||
obj.Start = lobj.Shape.Vertexes[n1].Point
|
||||
obj.End = lobj.Shape.Vertexes[n2].Point
|
||||
elif len(obj.LinkedGeometry) == 2:
|
||||
lobj1 = obj.LinkedGeometry[0][0]
|
||||
lobj2 = obj.LinkedGeometry[1][0]
|
||||
lsub1 = obj.LinkedGeometry[0][1]
|
||||
lsub2 = obj.LinkedGeometry[1][1]
|
||||
if (len(lsub1) == 1) and (len(lsub2) == 1):
|
||||
if ("Vertex" in lsub1[0]) and ("Vertex" in lsub2[1]):
|
||||
n1 = int(lsub1[0][6:])-1
|
||||
n2 = int(lsub2[0][6:])-1
|
||||
obj.Start = lobj1.Shape.Vertexes[n1].Point
|
||||
obj.End = lobj2.Shape.Vertexes[n2].Point
|
||||
# set the distance property
|
||||
total_len = (obj.Start.sub(obj.End)).Length
|
||||
if round(obj.Distance.Value, precision()) != round(total_len, precision()):
|
||||
obj.Distance = total_len
|
||||
if gui:
|
||||
if obj.ViewObject:
|
||||
obj.ViewObject.update()
|
||||
|
||||
|
||||
class _ViewProviderDimension(_ViewProviderDraft):
|
||||
"""
|
||||
A View Provider for the Draft Dimension object
|
||||
|
||||
DIMENSION VIEW PROVIDER:
|
||||
|
||||
| txt | e
|
||||
----o--------------------------------o-----
|
||||
| |
|
||||
| | d
|
||||
| |
|
||||
|
||||
a b c b a
|
||||
|
||||
a = DimOvershoot (vobj)
|
||||
b = Arrows (vobj)
|
||||
c = Dimline (obj)
|
||||
d = ExtLines (vobj)
|
||||
e = ExtOvershoot (vobj)
|
||||
txt = label (vobj)
|
||||
|
||||
STRUCTURE:
|
||||
vobj.node.color
|
||||
.drawstyle
|
||||
.lineswitch1.coords
|
||||
.line
|
||||
.marks
|
||||
.marksDimOvershoot
|
||||
.marksExtOvershoot
|
||||
.label.textpos
|
||||
.color
|
||||
.font
|
||||
.text
|
||||
|
||||
vobj.node3d.color
|
||||
.drawstyle
|
||||
.lineswitch3.coords
|
||||
.line
|
||||
.marks
|
||||
.marksDimOvershoot
|
||||
.marksExtOvershoot
|
||||
.label3d.textpos
|
||||
.color
|
||||
.font3d
|
||||
.text3d
|
||||
|
||||
"""
|
||||
def __init__(self, obj):
|
||||
# annotation properties
|
||||
obj.addProperty("App::PropertyFloat","ScaleMultiplier",
|
||||
"Annotation",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Dimension size overall multiplier"))
|
||||
|
||||
# text properties
|
||||
obj.addProperty("App::PropertyFont","FontName",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property","Font name"))
|
||||
obj.addProperty("App::PropertyLength","FontSize",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property","Font size"))
|
||||
obj.addProperty("App::PropertyLength","TextSpacing",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The spacing between the text and the dimension line"))
|
||||
obj.addProperty("App::PropertyBool","FlipText",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Rotate the dimension text 180 degrees"))
|
||||
obj.addProperty("App::PropertyVectorDistance","TextPosition",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The position of the text. Leave (0,0,0) for automatic position"))
|
||||
obj.addProperty("App::PropertyString","Override",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Text override. Use $dim to insert the dimension length"))
|
||||
# units properties
|
||||
obj.addProperty("App::PropertyInteger","Decimals",
|
||||
"Units",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The number of decimals to show"))
|
||||
obj.addProperty("App::PropertyBool","ShowUnit",
|
||||
"Units",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Show the unit suffix"))
|
||||
obj.addProperty("App::PropertyString","UnitOverride",
|
||||
"Units",QT_TRANSLATE_NOOP("App::Property",
|
||||
"A unit to express the measurement. Leave blank for system default"))
|
||||
# graphics properties
|
||||
obj.addProperty("App::PropertyFloat","LineWidth",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Line width"))
|
||||
obj.addProperty("App::PropertyColor","LineColor",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Line color"))
|
||||
obj.addProperty("App::PropertyLength","ArrowSize",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Arrow size"))
|
||||
obj.addProperty("App::PropertyEnumeration","ArrowType",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Arrow type"))
|
||||
obj.addProperty("App::PropertyBool","FlipArrows",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Rotate the dimension arrows 180 degrees"))
|
||||
obj.addProperty("App::PropertyDistance","DimOvershoot",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The distance the dimension line is extended past the extension lines"))
|
||||
obj.addProperty("App::PropertyDistance","ExtLines",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Length of the extension lines"))
|
||||
obj.addProperty("App::PropertyDistance","ExtOvershoot",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Length of the extension line above the dimension line"))
|
||||
obj.addProperty("App::PropertyBool","ShowLine",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Shows the dimension line and arrows"))
|
||||
|
||||
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
annotation_scale = param.GetFloat("DraftAnnotationScale", 1.0)
|
||||
obj.ScaleMultiplier = 1 / annotation_scale
|
||||
obj.FontSize = getParam("textheight",0.20)
|
||||
obj.TextSpacing = getParam("dimspacing",0.05)
|
||||
obj.FontName = getParam("textfont","")
|
||||
obj.ArrowSize = getParam("arrowsize",0.1)
|
||||
obj.ArrowType = arrowtypes
|
||||
obj.ArrowType = arrowtypes[getParam("dimsymbol",0)]
|
||||
obj.ExtLines = getParam("extlines",0.3)
|
||||
obj.DimOvershoot = getParam("dimovershoot",0)
|
||||
obj.ExtOvershoot = getParam("extovershoot",0)
|
||||
obj.Decimals = getParam("dimPrecision",2)
|
||||
obj.ShowUnit = getParam("showUnit",True)
|
||||
obj.ShowLine = True
|
||||
_ViewProviderDraft.__init__(self,obj)
|
||||
|
||||
def attach(self, vobj):
|
||||
"""called on object creation"""
|
||||
from pivy import coin
|
||||
self.Object = vobj.Object
|
||||
self.color = coin.SoBaseColor()
|
||||
self.font = coin.SoFont()
|
||||
self.font3d = coin.SoFont()
|
||||
self.text = coin.SoAsciiText()
|
||||
self.text3d = coin.SoText2()
|
||||
self.text.string = "d" # some versions of coin crash if string is not set
|
||||
self.text3d.string = "d"
|
||||
self.textpos = coin.SoTransform()
|
||||
self.text.justification = self.text3d.justification = coin.SoAsciiText.CENTER
|
||||
label = coin.SoSeparator()
|
||||
label.addChild(self.textpos)
|
||||
label.addChild(self.color)
|
||||
label.addChild(self.font)
|
||||
label.addChild(self.text)
|
||||
label3d = coin.SoSeparator()
|
||||
label3d.addChild(self.textpos)
|
||||
label3d.addChild(self.color)
|
||||
label3d.addChild(self.font3d)
|
||||
label3d.addChild(self.text3d)
|
||||
self.coord1 = coin.SoCoordinate3()
|
||||
self.trans1 = coin.SoTransform()
|
||||
self.coord2 = coin.SoCoordinate3()
|
||||
self.trans2 = coin.SoTransform()
|
||||
self.transDimOvershoot1 = coin.SoTransform()
|
||||
self.transDimOvershoot2 = coin.SoTransform()
|
||||
self.transExtOvershoot1 = coin.SoTransform()
|
||||
self.transExtOvershoot2 = coin.SoTransform()
|
||||
self.marks = coin.SoSeparator()
|
||||
self.marksDimOvershoot = coin.SoSeparator()
|
||||
self.marksExtOvershoot = coin.SoSeparator()
|
||||
self.drawstyle = coin.SoDrawStyle()
|
||||
self.line = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
|
||||
self.coords = coin.SoCoordinate3()
|
||||
self.node = coin.SoGroup()
|
||||
self.node.addChild(self.color)
|
||||
self.node.addChild(self.drawstyle)
|
||||
self.lineswitch2 = coin.SoSwitch()
|
||||
self.lineswitch2.whichChild = -3
|
||||
self.node.addChild(self.lineswitch2)
|
||||
self.lineswitch2.addChild(self.coords)
|
||||
self.lineswitch2.addChild(self.line)
|
||||
self.lineswitch2.addChild(self.marks)
|
||||
self.lineswitch2.addChild(self.marksDimOvershoot)
|
||||
self.lineswitch2.addChild(self.marksExtOvershoot)
|
||||
self.node.addChild(label)
|
||||
self.node3d = coin.SoGroup()
|
||||
self.node3d.addChild(self.color)
|
||||
self.node3d.addChild(self.drawstyle)
|
||||
self.lineswitch3 = coin.SoSwitch()
|
||||
self.lineswitch3.whichChild = -3
|
||||
self.node3d.addChild(self.lineswitch3)
|
||||
self.lineswitch3.addChild(self.coords)
|
||||
self.lineswitch3.addChild(self.line)
|
||||
self.lineswitch3.addChild(self.marks)
|
||||
self.lineswitch3.addChild(self.marksDimOvershoot)
|
||||
self.lineswitch3.addChild(self.marksExtOvershoot)
|
||||
self.node3d.addChild(label3d)
|
||||
vobj.addDisplayMode(self.node,"2D")
|
||||
vobj.addDisplayMode(self.node3d,"3D")
|
||||
self.updateData(vobj.Object,"Start")
|
||||
self.onChanged(vobj,"FontSize")
|
||||
self.onChanged(vobj,"FontName")
|
||||
self.onChanged(vobj,"ArrowType")
|
||||
self.onChanged(vobj,"LineColor")
|
||||
self.onChanged(vobj,"DimOvershoot")
|
||||
self.onChanged(vobj,"ExtOvershoot")
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
"""called when the base object is changed"""
|
||||
import DraftGui
|
||||
if prop in ["Start","End","Dimline","Direction"]:
|
||||
|
||||
if obj.Start == obj.End:
|
||||
return
|
||||
|
||||
if not hasattr(self,"node"):
|
||||
return
|
||||
|
||||
import Part, DraftGeomUtils
|
||||
from pivy import coin
|
||||
|
||||
# calculate the 4 points
|
||||
self.p1 = obj.Start
|
||||
self.p4 = obj.End
|
||||
base = None
|
||||
if hasattr(obj,"Direction"):
|
||||
if not DraftVecUtils.isNull(obj.Direction):
|
||||
v2 = self.p1.sub(obj.Dimline)
|
||||
v3 = self.p4.sub(obj.Dimline)
|
||||
v2 = DraftVecUtils.project(v2,obj.Direction)
|
||||
v3 = DraftVecUtils.project(v3,obj.Direction)
|
||||
self.p2 = obj.Dimline.add(v2)
|
||||
self.p3 = obj.Dimline.add(v3)
|
||||
if DraftVecUtils.equals(self.p2,self.p3):
|
||||
base = None
|
||||
proj = None
|
||||
else:
|
||||
base = Part.LineSegment(self.p2,self.p3).toShape()
|
||||
proj = DraftGeomUtils.findDistance(self.p1,base)
|
||||
if proj:
|
||||
proj = proj.negative()
|
||||
if not base:
|
||||
if DraftVecUtils.equals(self.p1,self.p4):
|
||||
base = None
|
||||
proj = None
|
||||
else:
|
||||
base = Part.LineSegment(self.p1,self.p4).toShape()
|
||||
proj = DraftGeomUtils.findDistance(obj.Dimline,base)
|
||||
if proj:
|
||||
self.p2 = self.p1.add(proj.negative())
|
||||
self.p3 = self.p4.add(proj.negative())
|
||||
else:
|
||||
self.p2 = self.p1
|
||||
self.p3 = self.p4
|
||||
if proj:
|
||||
if hasattr(obj.ViewObject,"ExtLines") and hasattr(obj.ViewObject,"ScaleMultiplier"):
|
||||
dmax = obj.ViewObject.ExtLines.Value * obj.ViewObject.ScaleMultiplier
|
||||
if dmax and (proj.Length > dmax):
|
||||
if (dmax > 0):
|
||||
self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,dmax))
|
||||
self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,dmax))
|
||||
else:
|
||||
rest = proj.Length + dmax
|
||||
self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,rest))
|
||||
self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,rest))
|
||||
else:
|
||||
proj = (self.p3.sub(self.p2)).cross(Vector(0,0,1))
|
||||
|
||||
# calculate the arrows positions
|
||||
self.trans1.translation.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.coord1.point.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.trans2.translation.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
self.coord2.point.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
|
||||
# calculate dimension and extension lines overshoots positions
|
||||
self.transDimOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.transDimOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
self.transExtOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.transExtOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
|
||||
# calculate the text position and orientation
|
||||
if hasattr(obj,"Normal"):
|
||||
if DraftVecUtils.isNull(obj.Normal):
|
||||
if proj:
|
||||
norm = (self.p3.sub(self.p2).cross(proj)).negative()
|
||||
else:
|
||||
norm = Vector(0,0,1)
|
||||
else:
|
||||
norm = FreeCAD.Vector(obj.Normal)
|
||||
else:
|
||||
if proj:
|
||||
norm = (self.p3.sub(self.p2).cross(proj)).negative()
|
||||
else:
|
||||
norm = Vector(0,0,1)
|
||||
if not DraftVecUtils.isNull(norm):
|
||||
norm.normalize()
|
||||
u = self.p3.sub(self.p2)
|
||||
u.normalize()
|
||||
v1 = norm.cross(u)
|
||||
rot1 = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u,v1,norm)).Rotation.Q
|
||||
self.transDimOvershoot1.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3]))
|
||||
self.transDimOvershoot2.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3]))
|
||||
if hasattr(obj.ViewObject,"FlipArrows"):
|
||||
if obj.ViewObject.FlipArrows:
|
||||
u = u.negative()
|
||||
v2 = norm.cross(u)
|
||||
rot2 = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u,v2,norm)).Rotation.Q
|
||||
self.trans1.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3]))
|
||||
self.trans2.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3]))
|
||||
if self.p1 != self.p2:
|
||||
u3 = self.p1.sub(self.p2)
|
||||
u3.normalize()
|
||||
v3 = norm.cross(u3)
|
||||
rot3 = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u3,v3,norm)).Rotation.Q
|
||||
self.transExtOvershoot1.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3]))
|
||||
self.transExtOvershoot2.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3]))
|
||||
if hasattr(obj.ViewObject,"TextSpacing") and hasattr(obj.ViewObject,"ScaleMultiplier"):
|
||||
ts = obj.ViewObject.TextSpacing.Value * obj.ViewObject.ScaleMultiplier
|
||||
offset = DraftVecUtils.scaleTo(v1,ts)
|
||||
else:
|
||||
offset = DraftVecUtils.scaleTo(v1,0.05)
|
||||
rott = rot1
|
||||
if hasattr(obj.ViewObject,"FlipText"):
|
||||
if obj.ViewObject.FlipText:
|
||||
rott = FreeCAD.Rotation(*rott).multiply(FreeCAD.Rotation(norm,180)).Q
|
||||
offset = offset.negative()
|
||||
# setting text
|
||||
try:
|
||||
m = obj.ViewObject.DisplayMode
|
||||
except: # swallow all exceptions here since it always fails on first run (Displaymode enum no set yet)
|
||||
m = ["2D","3D"][getParam("dimstyle",0)]
|
||||
if m == "3D":
|
||||
offset = offset.negative()
|
||||
self.tbase = (self.p2.add((self.p3.sub(self.p2).multiply(0.5)))).add(offset)
|
||||
if hasattr(obj.ViewObject,"TextPosition"):
|
||||
if not DraftVecUtils.isNull(obj.ViewObject.TextPosition):
|
||||
self.tbase = obj.ViewObject.TextPosition
|
||||
self.textpos.translation.setValue([self.tbase.x,self.tbase.y,self.tbase.z])
|
||||
self.textpos.rotation = coin.SbRotation(rott[0],rott[1],rott[2],rott[3])
|
||||
su = True
|
||||
if hasattr(obj.ViewObject,"ShowUnit"):
|
||||
su = obj.ViewObject.ShowUnit
|
||||
# set text value
|
||||
l = self.p3.sub(self.p2).Length
|
||||
unit = None
|
||||
if hasattr(obj.ViewObject,"UnitOverride"):
|
||||
unit = obj.ViewObject.UnitOverride
|
||||
# special representation if "Building US" scheme
|
||||
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("UserSchema",0) == 5:
|
||||
s = FreeCAD.Units.Quantity(l,FreeCAD.Units.Length).UserString
|
||||
self.string = s.replace("' ","'- ")
|
||||
self.string = s.replace("+"," ")
|
||||
elif hasattr(obj.ViewObject,"Decimals"):
|
||||
self.string = DraftGui.displayExternal(l,obj.ViewObject.Decimals,'Length',su,unit)
|
||||
else:
|
||||
self.string = DraftGui.displayExternal(l,None,'Length',su,unit)
|
||||
if hasattr(obj.ViewObject,"Override"):
|
||||
if obj.ViewObject.Override:
|
||||
self.string = obj.ViewObject.Override.replace("$dim",\
|
||||
self.string)
|
||||
self.text.string = self.text3d.string = stringencodecoin(self.string)
|
||||
|
||||
# set the lines
|
||||
if m == "3D":
|
||||
# calculate the spacing of the text
|
||||
textsize = (len(self.string)*obj.ViewObject.FontSize.Value)/4.0
|
||||
spacing = ((self.p3.sub(self.p2)).Length/2.0) - textsize
|
||||
self.p2a = self.p2.add(DraftVecUtils.scaleTo(self.p3.sub(self.p2),spacing))
|
||||
self.p2b = self.p3.add(DraftVecUtils.scaleTo(self.p2.sub(self.p3),spacing))
|
||||
self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z],
|
||||
[self.p2.x,self.p2.y,self.p2.z],
|
||||
[self.p2a.x,self.p2a.y,self.p2a.z],
|
||||
[self.p2b.x,self.p2b.y,self.p2b.z],
|
||||
[self.p3.x,self.p3.y,self.p3.z],
|
||||
[self.p4.x,self.p4.y,self.p4.z]])
|
||||
#self.line.numVertices.setValues([3,3])
|
||||
self.line.coordIndex.setValues(0,7,(0,1,2,-1,3,4,5))
|
||||
else:
|
||||
self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z],
|
||||
[self.p2.x,self.p2.y,self.p2.z],
|
||||
[self.p3.x,self.p3.y,self.p3.z],
|
||||
[self.p4.x,self.p4.y,self.p4.z]])
|
||||
#self.line.numVertices.setValue(4)
|
||||
self.line.coordIndex.setValues(0,4,(0,1,2,3))
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
"""called when a view property has changed"""
|
||||
if prop == "ScaleMultiplier" and hasattr(vobj,"ScaleMultiplier"):
|
||||
# update all dimension values
|
||||
if hasattr(self,"font"):
|
||||
self.font.size = vobj.FontSize.Value*vobj.ScaleMultiplier
|
||||
if hasattr(self,"font3d"):
|
||||
self.font3d.size = vobj.FontSize.Value*100*vobj.ScaleMultiplier
|
||||
if hasattr(self,"node") and hasattr(self,"p2") and hasattr(vobj,"ArrowSize"):
|
||||
self.remove_dim_arrows()
|
||||
self.draw_dim_arrows(vobj)
|
||||
if hasattr(vobj,"DimOvershoot"):
|
||||
self.remove_dim_overshoot()
|
||||
self.draw_dim_overshoot(vobj)
|
||||
if hasattr(vobj,"ExtOvershoot"):
|
||||
self.remove_ext_overshoot()
|
||||
self.draw_ext_overshoot(vobj)
|
||||
self.updateData(vobj.Object,"Start")
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "FontSize") and hasattr(vobj,"FontSize"):
|
||||
if hasattr(self,"font") and hasattr(vobj,"ScaleMultiplier"):
|
||||
self.font.size = vobj.FontSize.Value*vobj.ScaleMultiplier
|
||||
if hasattr(self,"font3d") and hasattr(vobj,"ScaleMultiplier"):
|
||||
self.font3d.size = vobj.FontSize.Value*100*vobj.ScaleMultiplier
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "FontName") and hasattr(vobj,"FontName"):
|
||||
if hasattr(self,"font") and hasattr(self,"font3d"):
|
||||
self.font.name = self.font3d.name = str(vobj.FontName)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "LineColor") and hasattr(vobj,"LineColor"):
|
||||
if hasattr(self,"color"):
|
||||
c = vobj.LineColor
|
||||
self.color.rgb.setValue(c[0],c[1],c[2])
|
||||
|
||||
elif (prop == "LineWidth") and hasattr(vobj,"LineWidth"):
|
||||
if hasattr(self,"drawstyle"):
|
||||
self.drawstyle.lineWidth = vobj.LineWidth
|
||||
|
||||
elif (prop in ["ArrowSize","ArrowType"]) and hasattr(vobj,"ArrowSize"):
|
||||
if hasattr(self,"node") and hasattr(self,"p2"):
|
||||
if hasattr(vobj,"ScaleMultiplier"):
|
||||
self.remove_dim_arrows()
|
||||
self.draw_dim_arrows(vobj)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "DimOvershoot") and hasattr(vobj,"DimOvershoot"):
|
||||
if hasattr(vobj,"ScaleMultiplier"):
|
||||
self.remove_dim_overshoot()
|
||||
self.draw_dim_overshoot(vobj)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "ExtOvershoot") and hasattr(vobj,"ExtOvershoot"):
|
||||
if hasattr(vobj,"ScaleMultiplier"):
|
||||
self.remove_ext_overshoot()
|
||||
self.draw_ext_overshoot(vobj)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "ShowLine") and hasattr(vobj,"ShowLine"):
|
||||
if vobj.ShowLine:
|
||||
self.lineswitch2.whichChild = -3
|
||||
self.lineswitch3.whichChild = -3
|
||||
else:
|
||||
self.lineswitch2.whichChild = -1
|
||||
self.lineswitch3.whichChild = -1
|
||||
else:
|
||||
self.updateData(vobj.Object,"Start")
|
||||
|
||||
def remove_dim_arrows(self):
|
||||
# remove existing nodes
|
||||
self.node.removeChild(self.marks)
|
||||
self.node3d.removeChild(self.marks)
|
||||
|
||||
def draw_dim_arrows(self, vobj):
|
||||
from pivy import coin
|
||||
|
||||
if not hasattr(vobj,"ArrowType"):
|
||||
return
|
||||
|
||||
if self.p3.x < self.p2.x:
|
||||
inv = False
|
||||
else:
|
||||
inv = True
|
||||
|
||||
# set scale
|
||||
symbol = arrowtypes.index(vobj.ArrowType)
|
||||
s = vobj.ArrowSize.Value * vobj.ScaleMultiplier
|
||||
self.trans1.scaleFactor.setValue((s,s,s))
|
||||
self.trans2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
|
||||
# set new nodes
|
||||
self.marks = coin.SoSeparator()
|
||||
self.marks.addChild(self.color)
|
||||
s1 = coin.SoSeparator()
|
||||
if symbol == "Circle":
|
||||
s1.addChild(self.coord1)
|
||||
else:
|
||||
s1.addChild(self.trans1)
|
||||
s1.addChild(dimSymbol(symbol,invert=not(inv)))
|
||||
self.marks.addChild(s1)
|
||||
s2 = coin.SoSeparator()
|
||||
if symbol == "Circle":
|
||||
s2.addChild(self.coord2)
|
||||
else:
|
||||
s2.addChild(self.trans2)
|
||||
s2.addChild(dimSymbol(symbol,invert=inv))
|
||||
self.marks.addChild(s2)
|
||||
self.node.insertChild(self.marks,2)
|
||||
self.node3d.insertChild(self.marks,2)
|
||||
|
||||
def remove_dim_overshoot(self):
|
||||
self.node.removeChild(self.marksDimOvershoot)
|
||||
self.node3d.removeChild(self.marksDimOvershoot)
|
||||
|
||||
|
||||
def draw_dim_overshoot(self, vobj):
|
||||
from pivy import coin
|
||||
|
||||
# set scale
|
||||
s = vobj.DimOvershoot.Value * vobj.ScaleMultiplier
|
||||
self.transDimOvershoot1.scaleFactor.setValue((s,s,s))
|
||||
self.transDimOvershoot2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
# remove existing nodes
|
||||
|
||||
# set new nodes
|
||||
self.marksDimOvershoot = coin.SoSeparator()
|
||||
if vobj.DimOvershoot.Value:
|
||||
self.marksDimOvershoot.addChild(self.color)
|
||||
s1 = coin.SoSeparator()
|
||||
s1.addChild(self.transDimOvershoot1)
|
||||
s1.addChild(dimDash((-1,0,0),(0,0,0)))
|
||||
self.marksDimOvershoot.addChild(s1)
|
||||
s2 = coin.SoSeparator()
|
||||
s2.addChild(self.transDimOvershoot2)
|
||||
s2.addChild(dimDash((0,0,0),(1,0,0)))
|
||||
self.marksDimOvershoot.addChild(s2)
|
||||
self.node.insertChild(self.marksDimOvershoot,2)
|
||||
self.node3d.insertChild(self.marksDimOvershoot,2)
|
||||
|
||||
|
||||
def remove_ext_overshoot(self):
|
||||
self.node.removeChild(self.marksExtOvershoot)
|
||||
self.node3d.removeChild(self.marksExtOvershoot)
|
||||
|
||||
|
||||
def draw_ext_overshoot(self, vobj):
|
||||
from pivy import coin
|
||||
|
||||
# set scale
|
||||
s = vobj.ExtOvershoot.Value * vobj.ScaleMultiplier
|
||||
self.transExtOvershoot1.scaleFactor.setValue((s,s,s))
|
||||
self.transExtOvershoot2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
# set new nodes
|
||||
self.marksExtOvershoot = coin.SoSeparator()
|
||||
if vobj.ExtOvershoot.Value:
|
||||
self.marksExtOvershoot.addChild(self.color)
|
||||
s1 = coin.SoSeparator()
|
||||
s1.addChild(self.transExtOvershoot1)
|
||||
s1.addChild(dimDash((0,0,0),(-1,0,0)))
|
||||
self.marksExtOvershoot.addChild(s1)
|
||||
s2 = coin.SoSeparator()
|
||||
s2.addChild(self.transExtOvershoot2)
|
||||
s2.addChild(dimDash((0,0,0),(-1,0,0)))
|
||||
self.marksExtOvershoot.addChild(s2)
|
||||
self.node.insertChild(self.marksExtOvershoot,2)
|
||||
self.node3d.insertChild(self.marksExtOvershoot,2)
|
||||
|
||||
|
||||
def doubleClicked(self,vobj):
|
||||
self.setEdit(vobj)
|
||||
|
||||
def getDisplayModes(self,vobj):
|
||||
return ["2D","3D"]
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
if hasattr(self,"defaultmode"):
|
||||
return self.defaultmode
|
||||
else:
|
||||
return ["2D","3D"][getParam("dimstyle",0)]
|
||||
|
||||
def setDisplayMode(self,mode):
|
||||
return mode
|
||||
|
||||
def is_linked_to_circle(self):
|
||||
import DraftGeomUtils
|
||||
_obj = self.Object
|
||||
if _obj.LinkedGeometry and len(_obj.LinkedGeometry) == 1:
|
||||
lobj = _obj.LinkedGeometry[0][0]
|
||||
lsub = _obj.LinkedGeometry[0][1]
|
||||
if len(lsub) == 1 and "Edge" in lsub[0]:
|
||||
n = int(lsub[0][4:]) - 1
|
||||
edge = lobj.Shape.Edges[n]
|
||||
if DraftGeomUtils.geomType(edge) == "Circle":
|
||||
return True
|
||||
return False
|
||||
|
||||
def getIcon(self):
|
||||
if self.is_linked_to_circle():
|
||||
return ":/icons/Draft_DimensionRadius.svg"
|
||||
return ":/icons/Draft_Dimension_Tree.svg"
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Object.ViewObject.DisplayMode
|
||||
|
||||
def __setstate__(self,state):
|
||||
if state:
|
||||
self.defaultmode = state
|
||||
self.setDisplayMode(state)
|
||||
|
||||
class _AngularDimension(_DraftObject):
|
||||
"""The Draft AngularDimension object"""
|
||||
def __init__(self, obj):
|
||||
|
||||
@@ -32,6 +32,99 @@ import FreeCADGui as Gui
|
||||
import draftutils.todo as todo
|
||||
|
||||
|
||||
class GuiCommandSimplest:
|
||||
"""Simplest base class for GuiCommands.
|
||||
|
||||
This class only sets up the command name and the document object
|
||||
to use for the command.
|
||||
When it is executed, it logs the command name to the log file,
|
||||
and prints the command name to the console.
|
||||
|
||||
It implements the `IsActive` method, which must return `True`
|
||||
when the command should be available.
|
||||
It should return `True` when there is an active document,
|
||||
otherwise the command (button or menu) should be disabled.
|
||||
|
||||
This class is meant to be inherited by other GuiCommand classes
|
||||
to quickly log the command name, and set the correct document object.
|
||||
|
||||
Parameter
|
||||
---------
|
||||
name: str, optional
|
||||
It defaults to `'None'`.
|
||||
The name of the action that is being run,
|
||||
for example, `'Heal'`, `'Flip dimensions'`,
|
||||
`'Line'`, `'Circle'`, etc.
|
||||
|
||||
doc: App::Document, optional
|
||||
It defaults to the value of `App.activeDocument()`.
|
||||
The document object itself, which indicates where the actions
|
||||
of the command will be executed.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
command_name: str
|
||||
This is the command name, which is assigned by `name`.
|
||||
|
||||
doc: App::Document
|
||||
This is the document object itself, which is assigned by `doc`.
|
||||
|
||||
This attribute should be used by functions to make sure
|
||||
that the operations are performed in the correct document
|
||||
and not in other documents.
|
||||
To set the active document we can use
|
||||
|
||||
>>> App.setActiveDocument(self.doc.Name)
|
||||
"""
|
||||
|
||||
def __init__(self, name="None", doc=App.activeDocument()):
|
||||
self.command_name = name
|
||||
self.doc = doc
|
||||
|
||||
def IsActive(self):
|
||||
"""Return True when this command should be available.
|
||||
|
||||
It is `True` when there is a document.
|
||||
"""
|
||||
if App.activeDocument():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called.
|
||||
|
||||
Log the command name to the log file and console.
|
||||
Also update the `doc` attribute.
|
||||
"""
|
||||
self.doc = App.activeDocument()
|
||||
_log("Document: {}".format(self.doc.Label))
|
||||
_log("GuiCommand: {}".format(self.command_name))
|
||||
_msg("{}".format(16*"-"))
|
||||
_msg("GuiCommand: {}".format(self.command_name))
|
||||
|
||||
|
||||
class GuiCommandNeedsSelection(GuiCommandSimplest):
|
||||
"""Base class for GuiCommands that need a selection to be available.
|
||||
|
||||
It re-implements the `IsActive` method to return `True`
|
||||
when there is both an active document and an active selection.
|
||||
|
||||
It inherits `GuiCommandSimplest` to set up the document
|
||||
and other behavior. See this class for more information.
|
||||
"""
|
||||
|
||||
def IsActive(self):
|
||||
"""Return True when this command should be available.
|
||||
|
||||
It is `True` when there is a selection.
|
||||
"""
|
||||
if App.activeDocument() and Gui.Selection.getSelection():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class GuiCommandBase:
|
||||
"""Generic class that is the basis of all Gui commands.
|
||||
|
||||
|
||||
@@ -32,18 +32,78 @@ import FreeCADGui as Gui
|
||||
from PySide import QtCore
|
||||
from . import gui_base
|
||||
from draftutils import utils
|
||||
from draftobjects.style_dimension import make_dimension_style
|
||||
from draftobjects.dimensionstyle import make_dimension_style
|
||||
|
||||
class GuiCommandDimensionStyle(gui_base.GuiCommandBase):
|
||||
|
||||
'''
|
||||
class AnnotationStylesContainer:
|
||||
"""The Layer Container"""
|
||||
|
||||
def __init__(self, obj):
|
||||
|
||||
self.Type = "AnnotationContainer"
|
||||
obj.Proxy = self
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
g = obj.Group
|
||||
g.sort(key=lambda o: o.Label)
|
||||
obj.Group = g
|
||||
|
||||
def __getstate__(self):
|
||||
|
||||
if hasattr(self, "Type"):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
|
||||
class ViewProviderAnnotationStylesContainer:
|
||||
"""A View Provider for the Layer Container"""
|
||||
|
||||
def __init__(self, vobj):
|
||||
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
|
||||
return ":/icons/Draft_Annotation_Style.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
|
||||
self.Object = vobj.Object
|
||||
|
||||
def __getstate__(self):
|
||||
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
|
||||
return None
|
||||
|
||||
|
||||
'''
|
||||
|
||||
|
||||
|
||||
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
class GuiCommandDimensionStyle(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
The command creates a dimension style object
|
||||
"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.command_name = "DimensionStyle"
|
||||
|
||||
def GetResources(self):
|
||||
_msg = ("Creates a new dimension style.\n"
|
||||
"The object stores dimension preferences into the document."
|
||||
)
|
||||
return {'Pixmap' : 'Draft_AutoGroup',
|
||||
return {'Pixmap' : 'Draft_Annotation_Style',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft", "Dimension Style"),
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft", _msg)}
|
||||
|
||||
@@ -59,10 +119,8 @@ class GuiCommandDimensionStyle(gui_base.GuiCommandBase):
|
||||
if len(sel) == 1:
|
||||
if utils.get_type(sel[0]) == 'Dimension':
|
||||
make_dimension_style(sel[0])
|
||||
return self.finish()
|
||||
|
||||
make_dimension_style()
|
||||
return self.finish()
|
||||
|
||||
|
||||
Gui.addCommand('Draft_DimensionStyle', GuiCommandDimensionStyle())
|
||||
235
src/Mod/Draft/draftobjects/dimension.py
Normal file
235
src/Mod/Draft/draftobjects/dimension.py
Normal file
@@ -0,0 +1,235 @@
|
||||
# ***************************************************************************
|
||||
# * (c) 2020 Carlo Pavan *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * FreeCAD 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 FreeCAD; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
"""This module provides the object code for Draft DimensionStyle.
|
||||
"""
|
||||
## @package style_dimension
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the object code for Draft DimensionStyle.
|
||||
|
||||
import FreeCAD as App
|
||||
import math
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import draftutils.utils as utils
|
||||
from draftobjects.draft_annotation import DimensionBase
|
||||
from draftviewproviders.view_dimension import ViewProviderLinearDimension
|
||||
|
||||
def make_dimension(p1,p2,p3=None,p4=None):
|
||||
"""makeDimension(p1,p2,[p3]) or makeDimension(object,i1,i2,p3)
|
||||
or makeDimension(objlist,indices,p3): Creates a Dimension object with
|
||||
the dimension line passign through p3.The current line width and color
|
||||
will be used. There are multiple ways to create a dimension, depending on
|
||||
the arguments you pass to it:
|
||||
- (p1,p2,p3): creates a standard dimension from p1 to p2
|
||||
- (object,i1,i2,p3): creates a linked dimension to the given object,
|
||||
measuring the distance between its vertices indexed i1 and i2
|
||||
- (object,i1,mode,p3): creates a linked dimension
|
||||
to the given object, i1 is the index of the (curved) edge to measure,
|
||||
and mode is either "radius" or "diameter".
|
||||
"""
|
||||
if not App.ActiveDocument:
|
||||
App.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
obj = App.ActiveDocument.addObject("App::FeaturePython","Dimension")
|
||||
LinearDimension(obj)
|
||||
if App.GuiUp:
|
||||
ViewProviderLinearDimension(obj.ViewObject)
|
||||
if isinstance(p1,App.Vector) and isinstance(p2,App.Vector):
|
||||
obj.Start = p1
|
||||
obj.End = p2
|
||||
if not p3:
|
||||
p3 = p2.sub(p1)
|
||||
p3.multiply(0.5)
|
||||
p3 = p1.add(p3)
|
||||
elif isinstance(p2,int) and isinstance(p3,int):
|
||||
l = []
|
||||
idx = (p2,p3)
|
||||
l.append((p1,"Vertex"+str(p2+1)))
|
||||
l.append((p1,"Vertex"+str(p3+1)))
|
||||
obj.LinkedGeometry = l
|
||||
obj.Support = p1
|
||||
p3 = p4
|
||||
if not p3:
|
||||
v1 = obj.Base.Shape.Vertexes[idx[0]].Point
|
||||
v2 = obj.Base.Shape.Vertexes[idx[1]].Point
|
||||
p3 = v2.sub(v1)
|
||||
p3.multiply(0.5)
|
||||
p3 = v1.add(p3)
|
||||
elif isinstance(p3,str):
|
||||
l = []
|
||||
l.append((p1,"Edge"+str(p2+1)))
|
||||
if p3 == "radius":
|
||||
#l.append((p1,"Center"))
|
||||
if App.GuiUp:
|
||||
obj.ViewObject.Override = "R $dim"
|
||||
obj.Diameter = False
|
||||
elif p3 == "diameter":
|
||||
#l.append((p1,"Diameter"))
|
||||
if App.GuiUp:
|
||||
obj.ViewObject.Override = "Ø $dim"
|
||||
obj.Diameter = True
|
||||
obj.LinkedGeometry = l
|
||||
obj.Support = p1
|
||||
p3 = p4
|
||||
if not p3:
|
||||
p3 = p1.Shape.Edges[p2].Curve.Center.add(App.Vector(1,0,0))
|
||||
obj.Dimline = p3
|
||||
if hasattr(App,"DraftWorkingPlane"):
|
||||
normal = App.DraftWorkingPlane.axis
|
||||
else:
|
||||
normal = App.Vector(0,0,1)
|
||||
if App.GuiUp:
|
||||
# invert the normal if we are viewing it from the back
|
||||
vnorm = gui_utils.get3DView().getViewDirection()
|
||||
if vnorm.getAngle(normal) < math.pi/2:
|
||||
normal = normal.negative()
|
||||
obj.Normal = normal
|
||||
if App.GuiUp:
|
||||
gui_utils.format_object(obj)
|
||||
gui_utils.select(obj)
|
||||
|
||||
return obj
|
||||
|
||||
class LinearDimension(DimensionBase):
|
||||
"""The Draft Dimension object"""
|
||||
def __init__(self, obj):
|
||||
DimensionBase.__init__(self,obj,"Dimension")
|
||||
|
||||
# Draft
|
||||
obj.addProperty("App::PropertyVectorDistance","Start",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Startpoint of dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVectorDistance","End",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Endpoint of dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVector","Normal",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The normal direction of this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVector","Direction",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The normal direction of this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyVectorDistance","Dimline",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Point through which the dimension line passes"))
|
||||
|
||||
obj.addProperty("App::PropertyLink","Support",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The object measured by this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyLinkSubList","LinkedGeometry",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The geometry this dimension is linked to"))
|
||||
|
||||
obj.addProperty("App::PropertyLength","Distance",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"The measurement of this dimension"))
|
||||
|
||||
obj.addProperty("App::PropertyBool","Diameter",
|
||||
"Draft",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"For arc/circle measurements, false = radius, true = diameter"))
|
||||
obj.Start = App.Vector(0,0,0)
|
||||
obj.End = App.Vector(1,0,0)
|
||||
obj.Dimline = App.Vector(0,1,0)
|
||||
obj.Normal = App.Vector(0,0,1)
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
if hasattr(obj, "Distance"):
|
||||
obj.setEditorMode('Distance', 1)
|
||||
#if hasattr(obj,"Normal"):
|
||||
# obj.setEditorMode('Normal', 2)
|
||||
if hasattr(obj, "Support"):
|
||||
obj.setEditorMode('Support', 2)
|
||||
if prop == "DimensionStyle":
|
||||
if hasattr(obj, "DimensionStyle"):
|
||||
gui_utils.format_object(target = obj, origin = obj.DimensionStyle)
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
import DraftGeomUtils
|
||||
# set start point and end point according to the linked geometry
|
||||
if obj.LinkedGeometry:
|
||||
if len(obj.LinkedGeometry) == 1:
|
||||
lobj = obj.LinkedGeometry[0][0]
|
||||
lsub = obj.LinkedGeometry[0][1]
|
||||
if len(lsub) == 1:
|
||||
if "Edge" in lsub[0]:
|
||||
n = int(lsub[0][4:])-1
|
||||
edge = lobj.Shape.Edges[n]
|
||||
if DraftGeomUtils.geomType(edge) == "Line":
|
||||
obj.Start = edge.Vertexes[0].Point
|
||||
obj.End = edge.Vertexes[-1].Point
|
||||
elif DraftGeomUtils.geomType(edge) == "Circle":
|
||||
c = edge.Curve.Center
|
||||
r = edge.Curve.Radius
|
||||
a = edge.Curve.Axis
|
||||
ray = obj.Dimline.sub(c).projectToPlane(App.Vector(0,0,0),a)
|
||||
if (ray.Length == 0):
|
||||
ray = a.cross(App.Vector(1,0,0))
|
||||
if (ray.Length == 0):
|
||||
ray = a.cross(App.Vector(0,1,0))
|
||||
ray = DraftVecUtils.scaleTo(ray,r)
|
||||
if hasattr(obj,"Diameter"):
|
||||
if obj.Diameter:
|
||||
obj.Start = c.add(ray.negative())
|
||||
obj.End = c.add(ray)
|
||||
else:
|
||||
obj.Start = c
|
||||
obj.End = c.add(ray)
|
||||
elif len(lsub) == 2:
|
||||
if ("Vertex" in lsub[0]) and ("Vertex" in lsub[1]):
|
||||
n1 = int(lsub[0][6:])-1
|
||||
n2 = int(lsub[1][6:])-1
|
||||
obj.Start = lobj.Shape.Vertexes[n1].Point
|
||||
obj.End = lobj.Shape.Vertexes[n2].Point
|
||||
elif len(obj.LinkedGeometry) == 2:
|
||||
lobj1 = obj.LinkedGeometry[0][0]
|
||||
lobj2 = obj.LinkedGeometry[1][0]
|
||||
lsub1 = obj.LinkedGeometry[0][1]
|
||||
lsub2 = obj.LinkedGeometry[1][1]
|
||||
if (len(lsub1) == 1) and (len(lsub2) == 1):
|
||||
if ("Vertex" in lsub1[0]) and ("Vertex" in lsub2[1]):
|
||||
n1 = int(lsub1[0][6:])-1
|
||||
n2 = int(lsub2[0][6:])-1
|
||||
obj.Start = lobj1.Shape.Vertexes[n1].Point
|
||||
obj.End = lobj2.Shape.Vertexes[n2].Point
|
||||
# set the distance property
|
||||
total_len = (obj.Start.sub(obj.End)).Length
|
||||
if round(obj.Distance.Value, utils.precision()) != round(total_len, utils.precision()):
|
||||
obj.Distance = total_len
|
||||
if App.GuiUp:
|
||||
if obj.ViewObject:
|
||||
obj.ViewObject.update()
|
||||
@@ -28,13 +28,12 @@
|
||||
# \brief This module provides the object code for Draft DimensionStyle.
|
||||
|
||||
import FreeCAD as App
|
||||
import Draft
|
||||
from Draft import _DraftObject
|
||||
from draftobjects.draft_annotation import DraftAnnotation
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
if App.GuiUp:
|
||||
import FreeCADGui as Gui
|
||||
from draftviewproviders.view_style_dimension import ViewProviderDraftDimensionStyle
|
||||
from draftviewproviders.view_dimensionstyle import ViewProviderDraftDimensionStyle
|
||||
|
||||
def make_dimension_style(existing_dimension = None):
|
||||
"""
|
||||
@@ -49,6 +48,6 @@ def make_dimension_style(existing_dimension = None):
|
||||
ViewProviderDraftDimensionStyle(obj.ViewObject, existing_dimension)
|
||||
return obj
|
||||
|
||||
class DimensionStyle(_DraftObject):
|
||||
class DimensionStyle(DraftAnnotation):
|
||||
def __init__(self, obj):
|
||||
_DraftObject.__init__(self, obj, "DimensionStyle")
|
||||
DraftAnnotation.__init__(self, obj, "DimensionStyle")
|
||||
78
src/Mod/Draft/draftobjects/draft_annotation.py
Normal file
78
src/Mod/Draft/draftobjects/draft_annotation.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# ***************************************************************************
|
||||
# * (c) 2020 Carlo Pavan *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * FreeCAD 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 FreeCAD; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
"""This module provides the object code for Draft DimensionStyle.
|
||||
"""
|
||||
## @package style_dimension
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the object code for Draft DimensionStyle.
|
||||
|
||||
import FreeCAD as App
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
from draftutils import gui_utils
|
||||
|
||||
class DraftAnnotation:
|
||||
"""The Draft Annotation Base object"""
|
||||
def __init__(self,obj,tp="Unknown"):
|
||||
if obj:
|
||||
obj.Proxy = self
|
||||
self.Type = tp
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Type
|
||||
|
||||
def __setstate__(self,state):
|
||||
if state:
|
||||
self.Type = state
|
||||
|
||||
def execute(self,obj):
|
||||
pass
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class DimensionBase(DraftAnnotation):
|
||||
"""The Draft Dimension Base object"""
|
||||
|
||||
def __init__(self, obj, tp = "Dimension"):
|
||||
"Initialize common properties for dimension objects"
|
||||
DraftAnnotation.__init__(self,obj, tp)
|
||||
|
||||
# Annotation
|
||||
obj.addProperty("App::PropertyLink","DimensionStyle",
|
||||
"Annotation",
|
||||
QT_TRANSLATE_NOOP("App::Property",
|
||||
"Link dimension style"))
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
|
||||
if prop == "DimensionStyle":
|
||||
if hasattr(obj, "DimensionStyle"):
|
||||
gui_utils.format_object(target = obj, origin = obj.DimensionStyle)
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
return
|
||||
549
src/Mod/Draft/draftviewproviders/view_dimension.py
Normal file
549
src/Mod/Draft/draftviewproviders/view_dimension.py
Normal file
@@ -0,0 +1,549 @@
|
||||
# ***************************************************************************
|
||||
# * (c) 2019 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * FreeCAD 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 FreeCAD; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the Draft Annotations view provider base classes
|
||||
"""
|
||||
## @package polararray
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the view provider code for Draft PolarArray.
|
||||
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import DraftVecUtils
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import draftutils.utils as utils
|
||||
import draftutils.gui_utils as gui_utils
|
||||
from draftviewproviders.view_draft_annotation import ViewProviderDimensionBase
|
||||
|
||||
class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
"""
|
||||
A View Provider for the Draft Dimension object
|
||||
|
||||
DIMENSION VIEW PROVIDER:
|
||||
|
||||
| txt | e
|
||||
----o--------------------------------o-----
|
||||
| |
|
||||
| | d
|
||||
| |
|
||||
|
||||
a b c b a
|
||||
|
||||
a = DimOvershoot (vobj)
|
||||
b = Arrows (vobj)
|
||||
c = Dimline (obj)
|
||||
d = ExtLines (vobj)
|
||||
e = ExtOvershoot (vobj)
|
||||
txt = label (vobj)
|
||||
|
||||
STRUCTURE:
|
||||
vobj.node.color
|
||||
.drawstyle
|
||||
.lineswitch1.coords
|
||||
.line
|
||||
.marks
|
||||
.marksDimOvershoot
|
||||
.marksExtOvershoot
|
||||
.label.textpos
|
||||
.color
|
||||
.font
|
||||
.text
|
||||
|
||||
vobj.node3d.color
|
||||
.drawstyle
|
||||
.lineswitch3.coords
|
||||
.line
|
||||
.marks
|
||||
.marksDimOvershoot
|
||||
.marksExtOvershoot
|
||||
.label3d.textpos
|
||||
.color
|
||||
.font3d
|
||||
.text3d
|
||||
|
||||
"""
|
||||
def __init__(self, vobj):
|
||||
ViewProviderDimensionBase.__init__(self,vobj)
|
||||
|
||||
def attach(self, vobj):
|
||||
"""called on object creation"""
|
||||
from pivy import coin
|
||||
self.Object = vobj.Object
|
||||
self.color = coin.SoBaseColor()
|
||||
self.font = coin.SoFont()
|
||||
self.font3d = coin.SoFont()
|
||||
self.text = coin.SoAsciiText()
|
||||
self.text3d = coin.SoText2()
|
||||
self.text.string = "d" # some versions of coin crash if string is not set
|
||||
self.text3d.string = "d"
|
||||
self.textpos = coin.SoTransform()
|
||||
self.text.justification = self.text3d.justification = coin.SoAsciiText.CENTER
|
||||
label = coin.SoSeparator()
|
||||
label.addChild(self.textpos)
|
||||
label.addChild(self.color)
|
||||
label.addChild(self.font)
|
||||
label.addChild(self.text)
|
||||
label3d = coin.SoSeparator()
|
||||
label3d.addChild(self.textpos)
|
||||
label3d.addChild(self.color)
|
||||
label3d.addChild(self.font3d)
|
||||
label3d.addChild(self.text3d)
|
||||
self.coord1 = coin.SoCoordinate3()
|
||||
self.trans1 = coin.SoTransform()
|
||||
self.coord2 = coin.SoCoordinate3()
|
||||
self.trans2 = coin.SoTransform()
|
||||
self.transDimOvershoot1 = coin.SoTransform()
|
||||
self.transDimOvershoot2 = coin.SoTransform()
|
||||
self.transExtOvershoot1 = coin.SoTransform()
|
||||
self.transExtOvershoot2 = coin.SoTransform()
|
||||
self.marks = coin.SoSeparator()
|
||||
self.marksDimOvershoot = coin.SoSeparator()
|
||||
self.marksExtOvershoot = coin.SoSeparator()
|
||||
self.drawstyle = coin.SoDrawStyle()
|
||||
self.line = coin.SoType.fromName("SoBrepEdgeSet").createInstance()
|
||||
self.coords = coin.SoCoordinate3()
|
||||
self.node = coin.SoGroup()
|
||||
self.node.addChild(self.color)
|
||||
self.node.addChild(self.drawstyle)
|
||||
self.lineswitch2 = coin.SoSwitch()
|
||||
self.lineswitch2.whichChild = -3
|
||||
self.node.addChild(self.lineswitch2)
|
||||
self.lineswitch2.addChild(self.coords)
|
||||
self.lineswitch2.addChild(self.line)
|
||||
self.lineswitch2.addChild(self.marks)
|
||||
self.lineswitch2.addChild(self.marksDimOvershoot)
|
||||
self.lineswitch2.addChild(self.marksExtOvershoot)
|
||||
self.node.addChild(label)
|
||||
self.node3d = coin.SoGroup()
|
||||
self.node3d.addChild(self.color)
|
||||
self.node3d.addChild(self.drawstyle)
|
||||
self.lineswitch3 = coin.SoSwitch()
|
||||
self.lineswitch3.whichChild = -3
|
||||
self.node3d.addChild(self.lineswitch3)
|
||||
self.lineswitch3.addChild(self.coords)
|
||||
self.lineswitch3.addChild(self.line)
|
||||
self.lineswitch3.addChild(self.marks)
|
||||
self.lineswitch3.addChild(self.marksDimOvershoot)
|
||||
self.lineswitch3.addChild(self.marksExtOvershoot)
|
||||
self.node3d.addChild(label3d)
|
||||
vobj.addDisplayMode(self.node,"2D")
|
||||
vobj.addDisplayMode(self.node3d,"3D")
|
||||
self.updateData(vobj.Object,"Start")
|
||||
self.onChanged(vobj,"FontSize")
|
||||
self.onChanged(vobj,"FontName")
|
||||
self.onChanged(vobj,"ArrowType")
|
||||
self.onChanged(vobj,"LineColor")
|
||||
self.onChanged(vobj,"DimOvershoot")
|
||||
self.onChanged(vobj,"ExtOvershoot")
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
"""called when the base object is changed"""
|
||||
import DraftGui
|
||||
if prop in ["Start","End","Dimline","Direction"]:
|
||||
|
||||
if obj.Start == obj.End:
|
||||
return
|
||||
|
||||
if not hasattr(self,"node"):
|
||||
return
|
||||
|
||||
import Part, DraftGeomUtils
|
||||
from pivy import coin
|
||||
|
||||
# calculate the 4 points
|
||||
self.p1 = obj.Start
|
||||
self.p4 = obj.End
|
||||
base = None
|
||||
if hasattr(obj,"Direction"):
|
||||
if not DraftVecUtils.isNull(obj.Direction):
|
||||
v2 = self.p1.sub(obj.Dimline)
|
||||
v3 = self.p4.sub(obj.Dimline)
|
||||
v2 = DraftVecUtils.project(v2,obj.Direction)
|
||||
v3 = DraftVecUtils.project(v3,obj.Direction)
|
||||
self.p2 = obj.Dimline.add(v2)
|
||||
self.p3 = obj.Dimline.add(v3)
|
||||
if DraftVecUtils.equals(self.p2,self.p3):
|
||||
base = None
|
||||
proj = None
|
||||
else:
|
||||
base = Part.LineSegment(self.p2,self.p3).toShape()
|
||||
proj = DraftGeomUtils.findDistance(self.p1,base)
|
||||
if proj:
|
||||
proj = proj.negative()
|
||||
if not base:
|
||||
if DraftVecUtils.equals(self.p1,self.p4):
|
||||
base = None
|
||||
proj = None
|
||||
else:
|
||||
base = Part.LineSegment(self.p1,self.p4).toShape()
|
||||
proj = DraftGeomUtils.findDistance(obj.Dimline,base)
|
||||
if proj:
|
||||
self.p2 = self.p1.add(proj.negative())
|
||||
self.p3 = self.p4.add(proj.negative())
|
||||
else:
|
||||
self.p2 = self.p1
|
||||
self.p3 = self.p4
|
||||
if proj:
|
||||
if hasattr(obj.ViewObject,"ExtLines") and hasattr(obj.ViewObject,"ScaleMultiplier"):
|
||||
dmax = obj.ViewObject.ExtLines.Value * obj.ViewObject.ScaleMultiplier
|
||||
if dmax and (proj.Length > dmax):
|
||||
if (dmax > 0):
|
||||
self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,dmax))
|
||||
self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,dmax))
|
||||
else:
|
||||
rest = proj.Length + dmax
|
||||
self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,rest))
|
||||
self.p4 = self.p3.add(DraftVecUtils.scaleTo(proj,rest))
|
||||
else:
|
||||
proj = (self.p3.sub(self.p2)).cross(App.Vector(0,0,1))
|
||||
|
||||
# calculate the arrows positions
|
||||
self.trans1.translation.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.coord1.point.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.trans2.translation.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
self.coord2.point.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
|
||||
# calculate dimension and extension lines overshoots positions
|
||||
self.transDimOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.transDimOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
self.transExtOvershoot1.translation.setValue((self.p2.x,self.p2.y,self.p2.z))
|
||||
self.transExtOvershoot2.translation.setValue((self.p3.x,self.p3.y,self.p3.z))
|
||||
|
||||
# calculate the text position and orientation
|
||||
if hasattr(obj,"Normal"):
|
||||
if DraftVecUtils.isNull(obj.Normal):
|
||||
if proj:
|
||||
norm = (self.p3.sub(self.p2).cross(proj)).negative()
|
||||
else:
|
||||
norm = App.Vector(0,0,1)
|
||||
else:
|
||||
norm = App.Vector(obj.Normal)
|
||||
else:
|
||||
if proj:
|
||||
norm = (self.p3.sub(self.p2).cross(proj)).negative()
|
||||
else:
|
||||
norm = App.Vector(0,0,1)
|
||||
if not DraftVecUtils.isNull(norm):
|
||||
norm.normalize()
|
||||
u = self.p3.sub(self.p2)
|
||||
u.normalize()
|
||||
v1 = norm.cross(u)
|
||||
rot1 = App.Placement(DraftVecUtils.getPlaneRotation(u,v1,norm)).Rotation.Q
|
||||
self.transDimOvershoot1.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3]))
|
||||
self.transDimOvershoot2.rotation.setValue((rot1[0],rot1[1],rot1[2],rot1[3]))
|
||||
if hasattr(obj.ViewObject,"FlipArrows"):
|
||||
if obj.ViewObject.FlipArrows:
|
||||
u = u.negative()
|
||||
v2 = norm.cross(u)
|
||||
rot2 = App.Placement(DraftVecUtils.getPlaneRotation(u,v2,norm)).Rotation.Q
|
||||
self.trans1.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3]))
|
||||
self.trans2.rotation.setValue((rot2[0],rot2[1],rot2[2],rot2[3]))
|
||||
if self.p1 != self.p2:
|
||||
u3 = self.p1.sub(self.p2)
|
||||
u3.normalize()
|
||||
v3 = norm.cross(u3)
|
||||
rot3 = App.Placement(DraftVecUtils.getPlaneRotation(u3,v3,norm)).Rotation.Q
|
||||
self.transExtOvershoot1.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3]))
|
||||
self.transExtOvershoot2.rotation.setValue((rot3[0],rot3[1],rot3[2],rot3[3]))
|
||||
if hasattr(obj.ViewObject,"TextSpacing") and hasattr(obj.ViewObject,"ScaleMultiplier"):
|
||||
ts = obj.ViewObject.TextSpacing.Value * obj.ViewObject.ScaleMultiplier
|
||||
offset = DraftVecUtils.scaleTo(v1,ts)
|
||||
else:
|
||||
offset = DraftVecUtils.scaleTo(v1,0.05)
|
||||
rott = rot1
|
||||
if hasattr(obj.ViewObject,"FlipText"):
|
||||
if obj.ViewObject.FlipText:
|
||||
rott = App.Rotation(*rott).multiply(App.Rotation(norm,180)).Q
|
||||
offset = offset.negative()
|
||||
# setting text
|
||||
try:
|
||||
m = obj.ViewObject.DisplayMode
|
||||
except: # swallow all exceptions here since it always fails on first run (Displaymode enum no set yet)
|
||||
m = ["2D","3D"][utils.get_param("dimstyle",0)]
|
||||
if m == "3D":
|
||||
offset = offset.negative()
|
||||
self.tbase = (self.p2.add((self.p3.sub(self.p2).multiply(0.5)))).add(offset)
|
||||
if hasattr(obj.ViewObject,"TextPosition"):
|
||||
if not DraftVecUtils.isNull(obj.ViewObject.TextPosition):
|
||||
self.tbase = obj.ViewObject.TextPosition
|
||||
self.textpos.translation.setValue([self.tbase.x,self.tbase.y,self.tbase.z])
|
||||
self.textpos.rotation = coin.SbRotation(rott[0],rott[1],rott[2],rott[3])
|
||||
su = True
|
||||
if hasattr(obj.ViewObject,"ShowUnit"):
|
||||
su = obj.ViewObject.ShowUnit
|
||||
# set text value
|
||||
l = self.p3.sub(self.p2).Length
|
||||
unit = None
|
||||
if hasattr(obj.ViewObject,"UnitOverride"):
|
||||
unit = obj.ViewObject.UnitOverride
|
||||
# special representation if "Building US" scheme
|
||||
if App.ParamGet("User parameter:BaseApp/Preferences/Units").GetInt("UserSchema",0) == 5:
|
||||
s = App.Units.Quantity(l,App.Units.Length).UserString
|
||||
self.string = s.replace("' ","'- ")
|
||||
self.string = s.replace("+"," ")
|
||||
elif hasattr(obj.ViewObject,"Decimals"):
|
||||
self.string = DraftGui.displayExternal(l,obj.ViewObject.Decimals,'Length',su,unit)
|
||||
else:
|
||||
self.string = DraftGui.displayExternal(l,None,'Length',su,unit)
|
||||
if hasattr(obj.ViewObject,"Override"):
|
||||
if obj.ViewObject.Override:
|
||||
self.string = obj.ViewObject.Override.replace("$dim",\
|
||||
self.string)
|
||||
self.text.string = self.text3d.string = utils.string_encode_coin(self.string)
|
||||
|
||||
# set the lines
|
||||
if m == "3D":
|
||||
# calculate the spacing of the text
|
||||
textsize = (len(self.string)*obj.ViewObject.FontSize.Value)/4.0
|
||||
spacing = ((self.p3.sub(self.p2)).Length/2.0) - textsize
|
||||
self.p2a = self.p2.add(DraftVecUtils.scaleTo(self.p3.sub(self.p2),spacing))
|
||||
self.p2b = self.p3.add(DraftVecUtils.scaleTo(self.p2.sub(self.p3),spacing))
|
||||
self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z],
|
||||
[self.p2.x,self.p2.y,self.p2.z],
|
||||
[self.p2a.x,self.p2a.y,self.p2a.z],
|
||||
[self.p2b.x,self.p2b.y,self.p2b.z],
|
||||
[self.p3.x,self.p3.y,self.p3.z],
|
||||
[self.p4.x,self.p4.y,self.p4.z]])
|
||||
#self.line.numVertices.setValues([3,3])
|
||||
self.line.coordIndex.setValues(0,7,(0,1,2,-1,3,4,5))
|
||||
else:
|
||||
self.coords.point.setValues([[self.p1.x,self.p1.y,self.p1.z],
|
||||
[self.p2.x,self.p2.y,self.p2.z],
|
||||
[self.p3.x,self.p3.y,self.p3.z],
|
||||
[self.p4.x,self.p4.y,self.p4.z]])
|
||||
#self.line.numVertices.setValue(4)
|
||||
self.line.coordIndex.setValues(0,4,(0,1,2,3))
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
"""called when a view property has changed"""
|
||||
if prop == "ScaleMultiplier" and hasattr(vobj,"ScaleMultiplier"):
|
||||
# update all dimension values
|
||||
if hasattr(self,"font"):
|
||||
self.font.size = vobj.FontSize.Value*vobj.ScaleMultiplier
|
||||
if hasattr(self,"font3d"):
|
||||
self.font3d.size = vobj.FontSize.Value*100*vobj.ScaleMultiplier
|
||||
if hasattr(self,"node") and hasattr(self,"p2") and hasattr(vobj,"ArrowSize"):
|
||||
self.remove_dim_arrows()
|
||||
self.draw_dim_arrows(vobj)
|
||||
if hasattr(vobj,"DimOvershoot"):
|
||||
self.remove_dim_overshoot()
|
||||
self.draw_dim_overshoot(vobj)
|
||||
if hasattr(vobj,"ExtOvershoot"):
|
||||
self.remove_ext_overshoot()
|
||||
self.draw_ext_overshoot(vobj)
|
||||
self.updateData(vobj.Object,"Start")
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "FontSize") and hasattr(vobj,"FontSize"):
|
||||
if hasattr(self,"font") and hasattr(vobj,"ScaleMultiplier"):
|
||||
self.font.size = vobj.FontSize.Value*vobj.ScaleMultiplier
|
||||
if hasattr(self,"font3d") and hasattr(vobj,"ScaleMultiplier"):
|
||||
self.font3d.size = vobj.FontSize.Value*100*vobj.ScaleMultiplier
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "FontName") and hasattr(vobj,"FontName"):
|
||||
if hasattr(self,"font") and hasattr(self,"font3d"):
|
||||
self.font.name = self.font3d.name = str(vobj.FontName)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "LineColor") and hasattr(vobj,"LineColor"):
|
||||
if hasattr(self,"color"):
|
||||
c = vobj.LineColor
|
||||
self.color.rgb.setValue(c[0],c[1],c[2])
|
||||
|
||||
elif (prop == "LineWidth") and hasattr(vobj,"LineWidth"):
|
||||
if hasattr(self,"drawstyle"):
|
||||
self.drawstyle.lineWidth = vobj.LineWidth
|
||||
|
||||
elif (prop in ["ArrowSize","ArrowType"]) and hasattr(vobj,"ArrowSize"):
|
||||
if hasattr(self,"node") and hasattr(self,"p2"):
|
||||
if hasattr(vobj,"ScaleMultiplier"):
|
||||
self.remove_dim_arrows()
|
||||
self.draw_dim_arrows(vobj)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "DimOvershoot") and hasattr(vobj,"DimOvershoot"):
|
||||
if hasattr(vobj,"ScaleMultiplier"):
|
||||
self.remove_dim_overshoot()
|
||||
self.draw_dim_overshoot(vobj)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "ExtOvershoot") and hasattr(vobj,"ExtOvershoot"):
|
||||
if hasattr(vobj,"ScaleMultiplier"):
|
||||
self.remove_ext_overshoot()
|
||||
self.draw_ext_overshoot(vobj)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "ShowLine") and hasattr(vobj,"ShowLine"):
|
||||
if vobj.ShowLine:
|
||||
self.lineswitch2.whichChild = -3
|
||||
self.lineswitch3.whichChild = -3
|
||||
else:
|
||||
self.lineswitch2.whichChild = -1
|
||||
self.lineswitch3.whichChild = -1
|
||||
else:
|
||||
self.updateData(vobj.Object,"Start")
|
||||
|
||||
def remove_dim_arrows(self):
|
||||
# remove existing nodes
|
||||
self.node.removeChild(self.marks)
|
||||
self.node3d.removeChild(self.marks)
|
||||
|
||||
def draw_dim_arrows(self, vobj):
|
||||
from pivy import coin
|
||||
|
||||
if not hasattr(vobj,"ArrowType"):
|
||||
return
|
||||
|
||||
if self.p3.x < self.p2.x:
|
||||
inv = False
|
||||
else:
|
||||
inv = True
|
||||
|
||||
# set scale
|
||||
symbol = utils.ARROW_TYPES.index(vobj.ArrowType)
|
||||
s = vobj.ArrowSize.Value * vobj.ScaleMultiplier
|
||||
self.trans1.scaleFactor.setValue((s,s,s))
|
||||
self.trans2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
|
||||
# set new nodes
|
||||
self.marks = coin.SoSeparator()
|
||||
self.marks.addChild(self.color)
|
||||
s1 = coin.SoSeparator()
|
||||
if symbol == "Circle":
|
||||
s1.addChild(self.coord1)
|
||||
else:
|
||||
s1.addChild(self.trans1)
|
||||
s1.addChild(gui_utils.dim_symbol(symbol,invert=not(inv)))
|
||||
self.marks.addChild(s1)
|
||||
s2 = coin.SoSeparator()
|
||||
if symbol == "Circle":
|
||||
s2.addChild(self.coord2)
|
||||
else:
|
||||
s2.addChild(self.trans2)
|
||||
s2.addChild(gui_utils.dim_symbol(symbol,invert=inv))
|
||||
self.marks.addChild(s2)
|
||||
self.node.insertChild(self.marks,2)
|
||||
self.node3d.insertChild(self.marks,2)
|
||||
|
||||
def remove_dim_overshoot(self):
|
||||
self.node.removeChild(self.marksDimOvershoot)
|
||||
self.node3d.removeChild(self.marksDimOvershoot)
|
||||
|
||||
|
||||
def draw_dim_overshoot(self, vobj):
|
||||
from pivy import coin
|
||||
|
||||
# set scale
|
||||
s = vobj.DimOvershoot.Value * vobj.ScaleMultiplier
|
||||
self.transDimOvershoot1.scaleFactor.setValue((s,s,s))
|
||||
self.transDimOvershoot2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
# remove existing nodes
|
||||
|
||||
# set new nodes
|
||||
self.marksDimOvershoot = coin.SoSeparator()
|
||||
if vobj.DimOvershoot.Value:
|
||||
self.marksDimOvershoot.addChild(self.color)
|
||||
s1 = coin.SoSeparator()
|
||||
s1.addChild(self.transDimOvershoot1)
|
||||
s1.addChild(gui_utils.dimDash((-1,0,0),(0,0,0)))
|
||||
self.marksDimOvershoot.addChild(s1)
|
||||
s2 = coin.SoSeparator()
|
||||
s2.addChild(self.transDimOvershoot2)
|
||||
s2.addChild(gui_utils.dimDash((0,0,0),(1,0,0)))
|
||||
self.marksDimOvershoot.addChild(s2)
|
||||
self.node.insertChild(self.marksDimOvershoot,2)
|
||||
self.node3d.insertChild(self.marksDimOvershoot,2)
|
||||
|
||||
|
||||
def remove_ext_overshoot(self):
|
||||
self.node.removeChild(self.marksExtOvershoot)
|
||||
self.node3d.removeChild(self.marksExtOvershoot)
|
||||
|
||||
|
||||
def draw_ext_overshoot(self, vobj):
|
||||
from pivy import coin
|
||||
|
||||
# set scale
|
||||
s = vobj.ExtOvershoot.Value * vobj.ScaleMultiplier
|
||||
self.transExtOvershoot1.scaleFactor.setValue((s,s,s))
|
||||
self.transExtOvershoot2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
# set new nodes
|
||||
self.marksExtOvershoot = coin.SoSeparator()
|
||||
if vobj.ExtOvershoot.Value:
|
||||
self.marksExtOvershoot.addChild(self.color)
|
||||
s1 = coin.SoSeparator()
|
||||
s1.addChild(self.transExtOvershoot1)
|
||||
s1.addChild(gui_utils.dimDash((0,0,0),(-1,0,0)))
|
||||
self.marksExtOvershoot.addChild(s1)
|
||||
s2 = coin.SoSeparator()
|
||||
s2.addChild(self.transExtOvershoot2)
|
||||
s2.addChild(gui_utils.dimDash((0,0,0),(-1,0,0)))
|
||||
self.marksExtOvershoot.addChild(s2)
|
||||
self.node.insertChild(self.marksExtOvershoot,2)
|
||||
self.node3d.insertChild(self.marksExtOvershoot,2)
|
||||
|
||||
|
||||
def doubleClicked(self,vobj):
|
||||
self.setEdit(vobj)
|
||||
|
||||
def getDisplayModes(self,vobj):
|
||||
return ["2D","3D"]
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
if hasattr(self,"defaultmode"):
|
||||
return self.defaultmode
|
||||
else:
|
||||
return ["2D","3D"][utils.get_param("dimstyle",0)]
|
||||
|
||||
def setDisplayMode(self,mode):
|
||||
return mode
|
||||
|
||||
def is_linked_to_circle(self):
|
||||
_obj = self.Object
|
||||
if _obj.LinkedGeometry and len(_obj.LinkedGeometry) == 1:
|
||||
lobj = _obj.LinkedGeometry[0][0]
|
||||
lsub = _obj.LinkedGeometry[0][1]
|
||||
if len(lsub) == 1 and "Edge" in lsub[0]:
|
||||
n = int(lsub[0][4:]) - 1
|
||||
edge = lobj.Shape.Edges[n]
|
||||
if DraftGeomUtils.geomType(edge) == "Circle":
|
||||
return True
|
||||
return False
|
||||
|
||||
def getIcon(self):
|
||||
if self.is_linked_to_circle():
|
||||
return ":/icons/Draft_DimensionRadius.svg"
|
||||
return ":/icons/Draft_Dimension_Tree.svg"
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Object.ViewObject.DisplayMode
|
||||
|
||||
def __setstate__(self,state):
|
||||
if state:
|
||||
self.defaultmode = state
|
||||
self.setDisplayMode(state)
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
# \brief This module provides the view provider code for Draft DimensionStyle.
|
||||
|
||||
import FreeCAD as App
|
||||
import Draft
|
||||
from Draft import _ViewProviderDraft
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import draftutils.utils as utils
|
||||
from pivy import coin
|
||||
|
||||
class ViewProviderDraftDimensionStyle(_ViewProviderDraft):
|
||||
"""
|
||||
@@ -190,6 +190,9 @@ class ViewProviderDraftDimensionStyle(_ViewProviderDraft):
|
||||
if hasattr(vobj, "AutoUpdate"):
|
||||
if vobj.AutoUpdate:
|
||||
self.update_related_dimensions(vobj)
|
||||
if hasattr(vobj, "Visibility"):
|
||||
if prop == "Visibility":
|
||||
print(vobj.Visibility)
|
||||
|
||||
def doubleClicked(self,vobj):
|
||||
self.set_current(vobj)
|
||||
@@ -228,3 +231,19 @@ class ViewProviderDraftDimensionStyle(_ViewProviderDraft):
|
||||
from draftutils import gui_utils
|
||||
for dim in vobj.Object.InList:
|
||||
gui_utils.format_object(target = dim, origin = vobj.Object)
|
||||
|
||||
def getIcon(self):
|
||||
import Draft_rc
|
||||
return ":/icons/Draft_Dimension_Tree_Style.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
self.standard = coin.SoGroup()
|
||||
vobj.addDisplayMode(self.standard,"Standard")
|
||||
|
||||
def getDisplayModes(self,obj):
|
||||
"'''Return a list of display modes.'''"
|
||||
return ["Standard"]
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
"'''Return the name of the default display mode. It must be defined in getDisplayModes.'''"
|
||||
return "Standard"
|
||||
263
src/Mod/Draft/draftviewproviders/view_draft_annotation.py
Normal file
263
src/Mod/Draft/draftviewproviders/view_draft_annotation.py
Normal file
@@ -0,0 +1,263 @@
|
||||
# ***************************************************************************
|
||||
# * (c) 2019 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * FreeCAD 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 FreeCAD; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""This module provides the Draft Annotations view provider base classes
|
||||
"""
|
||||
## @package polararray
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the view provider code for Draft PolarArray.
|
||||
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
import draftutils.utils as utils
|
||||
|
||||
|
||||
class ViewProviderDraftAnnotation:
|
||||
"""The base class for Draft Annotation Viewproviders"""
|
||||
|
||||
def __init__(self, vobj):
|
||||
vobj.Proxy = self
|
||||
self.Object = vobj.Object
|
||||
|
||||
# annotation properties
|
||||
vobj.addProperty("App::PropertyFloat","ScaleMultiplier",
|
||||
"Annotation",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Dimension size overall multiplier"))
|
||||
|
||||
# graphics properties
|
||||
vobj.addProperty("App::PropertyFloat","LineWidth",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Line width"))
|
||||
vobj.addProperty("App::PropertyColor","LineColor",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Line color"))
|
||||
|
||||
param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
annotation_scale = param.GetFloat("DraftAnnotationScale", 1.0)
|
||||
vobj.ScaleMultiplier = 1 / annotation_scale
|
||||
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self, state):
|
||||
return None
|
||||
|
||||
def attach(self,vobj):
|
||||
self.Object = vobj.Object
|
||||
return
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
return
|
||||
|
||||
def getDisplayModes(self, vobj):
|
||||
modes=[]
|
||||
return modes
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
return mode
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
return
|
||||
|
||||
def execute(self,vobj):
|
||||
return
|
||||
|
||||
def setEdit(self,vobj,mode=0):
|
||||
if mode == 0:
|
||||
Gui.runCommand("Draft_Edit")
|
||||
return True
|
||||
return False
|
||||
|
||||
def unsetEdit(self,vobj,mode=0):
|
||||
if App.activeDraftCommand:
|
||||
App.activeDraftCommand.finish()
|
||||
Gui.Control.closeDialog()
|
||||
return False
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/Draft_Draft.svg"
|
||||
|
||||
def claimChildren(self):
|
||||
"""perhaps this is not useful???"""
|
||||
objs = []
|
||||
if hasattr(self.Object,"Base"):
|
||||
objs.append(self.Object.Base)
|
||||
if hasattr(self.Object,"Objects"):
|
||||
objs.extend(self.Object.Objects)
|
||||
if hasattr(self.Object,"Components"):
|
||||
objs.extend(self.Object.Components)
|
||||
if hasattr(self.Object,"Group"):
|
||||
objs.extend(self.Object.Group)
|
||||
return objs
|
||||
|
||||
|
||||
class ViewProviderDimensionBase(ViewProviderDraftAnnotation):
|
||||
"""
|
||||
A View Provider for the Draft Dimension object
|
||||
|
||||
DIMENSION VIEW PROVIDER:
|
||||
|
||||
| txt | e
|
||||
----o--------------------------------o-----
|
||||
| |
|
||||
| | d
|
||||
| |
|
||||
|
||||
a b c b a
|
||||
|
||||
a = DimOvershoot (vobj)
|
||||
b = Arrows (vobj)
|
||||
c = Dimline (obj)
|
||||
d = ExtLines (vobj)
|
||||
e = ExtOvershoot (vobj)
|
||||
txt = label (vobj)
|
||||
|
||||
STRUCTURE:
|
||||
vobj.node.color
|
||||
.drawstyle
|
||||
.lineswitch1.coords
|
||||
.line
|
||||
.marks
|
||||
.marksDimOvershoot
|
||||
.marksExtOvershoot
|
||||
.label.textpos
|
||||
.color
|
||||
.font
|
||||
.text
|
||||
|
||||
vobj.node3d.color
|
||||
.drawstyle
|
||||
.lineswitch3.coords
|
||||
.line
|
||||
.marks
|
||||
.marksDimOvershoot
|
||||
.marksExtOvershoot
|
||||
.label3d.textpos
|
||||
.color
|
||||
.font3d
|
||||
.text3d
|
||||
|
||||
"""
|
||||
def __init__(self, vobj):
|
||||
# text properties
|
||||
vobj.addProperty("App::PropertyFont","FontName",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property","Font name"))
|
||||
vobj.addProperty("App::PropertyLength","FontSize",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property","Font size"))
|
||||
vobj.addProperty("App::PropertyLength","TextSpacing",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The spacing between the text and the dimension line"))
|
||||
vobj.addProperty("App::PropertyBool","FlipText",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Rotate the dimension text 180 degrees"))
|
||||
vobj.addProperty("App::PropertyVectorDistance","TextPosition",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The position of the text. Leave (0,0,0) for automatic position"))
|
||||
vobj.addProperty("App::PropertyString","Override",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Text override. Use $dim to insert the dimension length"))
|
||||
# units properties
|
||||
vobj.addProperty("App::PropertyInteger","Decimals",
|
||||
"Units",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The number of decimals to show"))
|
||||
vobj.addProperty("App::PropertyBool","ShowUnit",
|
||||
"Units",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Show the unit suffix"))
|
||||
vobj.addProperty("App::PropertyString","UnitOverride",
|
||||
"Units",QT_TRANSLATE_NOOP("App::Property",
|
||||
"A unit to express the measurement. Leave blank for system default"))
|
||||
# graphics properties
|
||||
vobj.addProperty("App::PropertyLength","ArrowSize",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Arrow size"))
|
||||
vobj.addProperty("App::PropertyEnumeration","ArrowType",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property","Arrow type"))
|
||||
vobj.addProperty("App::PropertyBool","FlipArrows",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Rotate the dimension arrows 180 degrees"))
|
||||
vobj.addProperty("App::PropertyDistance","DimOvershoot",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The distance the dimension line is extended past the extension lines"))
|
||||
vobj.addProperty("App::PropertyDistance","ExtLines",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Length of the extension lines"))
|
||||
vobj.addProperty("App::PropertyDistance","ExtOvershoot",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Length of the extension line above the dimension line"))
|
||||
vobj.addProperty("App::PropertyBool","ShowLine",
|
||||
"Graphics",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Shows the dimension line and arrows"))
|
||||
|
||||
vobj.FontSize = utils.get_param("textheight",0.20)
|
||||
vobj.TextSpacing = utils.get_param("dimspacing",0.05)
|
||||
vobj.FontName = utils.get_param("textfont","")
|
||||
vobj.ArrowSize = utils.get_param("arrowsize",0.1)
|
||||
vobj.ArrowType = utils.ARROW_TYPES
|
||||
vobj.ArrowType = utils.ARROW_TYPES[utils.get_param("dimsymbol",0)]
|
||||
vobj.ExtLines = utils.get_param("extlines",0.3)
|
||||
vobj.DimOvershoot = utils.get_param("dimovershoot",0)
|
||||
vobj.ExtOvershoot = utils.get_param("extovershoot",0)
|
||||
vobj.Decimals = utils.get_param("dimPrecision",2)
|
||||
vobj.ShowUnit = utils.get_param("showUnit",True)
|
||||
vobj.ShowLine = True
|
||||
ViewProviderDraftAnnotation.__init__(self,vobj)
|
||||
|
||||
def attach(self, vobj):
|
||||
"""called on object creation"""
|
||||
return
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
"""called when the base object is changed"""
|
||||
return
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
"""called when a view property has changed"""
|
||||
return
|
||||
|
||||
def doubleClicked(self,vobj):
|
||||
self.setEdit(vobj)
|
||||
|
||||
def getDisplayModes(self,vobj):
|
||||
return ["2D","3D"]
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
if hasattr(self,"defaultmode"):
|
||||
return self.defaultmode
|
||||
else:
|
||||
return ["2D","3D"][utils.get_param("dimstyle",0)]
|
||||
|
||||
def setDisplayMode(self,mode):
|
||||
return mode
|
||||
|
||||
def getIcon(self):
|
||||
if self.is_linked_to_circle():
|
||||
return ":/icons/Draft_DimensionRadius.svg"
|
||||
return ":/icons/Draft_Dimension_Tree.svg"
|
||||
|
||||
def __getstate__(self):
|
||||
return self.Object.ViewObject.DisplayMode
|
||||
|
||||
def __setstate__(self,state):
|
||||
if state:
|
||||
self.defaultmode = state
|
||||
self.setDisplayMode(state)
|
||||
|
||||
Reference in New Issue
Block a user