[Draft] Split Dimension object and reorganize of annotation objects

part 1
This commit is contained in:
carlopav
2020-03-21 19:36:33 +01:00
committed by Yorik van Havre
parent 0bc6e4cddc
commit 637c45733e
9 changed files with 1313 additions and 800 deletions

View File

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

View File

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

View File

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

View 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()

View File

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

View 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

View 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)

View File

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

View 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)