From 693d66eb7e51ae0bdba732a4dc53900314dd1fba Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Fri, 1 Jun 2018 11:05:15 -0300 Subject: [PATCH] Draft: Support new-style Draft texts in TechDraw --- src/Mod/Draft/Draft.py | 90 ++++++++++++++++++++++--------------- src/Mod/Draft/DraftTools.py | 45 ++++++++++--------- 2 files changed, 76 insertions(+), 59 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 4ed7df5cf6..677e6b2e2d 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -253,7 +253,7 @@ def ungroup(obj): g = grp.Group g.remove(obj) grp.Group = g - + def autogroup(obj): "adds a given object to the autogroup, if applicable" if FreeCAD.GuiUp: @@ -357,7 +357,7 @@ def shapify(obj): def getGroupContents(objectslist,walls=False,addgroups=False,spaces=False): '''getGroupContents(objectlist,[walls,addgroups]): if any object of the given list is a group, its content is appened to the list, which is returned. If walls is True, - walls and structures are also scanned for included windows or rebars. If addgroups + walls and structures are also scanned for included windows or rebars. If addgroups is true, the group itself is also included in the list.''' def getWindows(obj): l = [] @@ -1159,9 +1159,9 @@ def makeArray(baseobject,arg1,arg2,arg3,arg4=None,arg5=None,arg6=None,name="Arra makeArray(object,center,totalangle,totalnum,[name]) for polar array: Creates an array of the given object with, in case of rectangular array, xnum of iterations in the x direction - at xvector distance between iterations, same for y direction with yvector and ynum, - same for z direction with zvector and znum. In case of polar array, center is a vector, - totalangle is the angle to cover (in degrees) and totalnum is the number of objects, + at xvector distance between iterations, same for y direction with yvector and ynum, + same for z direction with zvector and znum. In case of polar array, center is a vector, + totalangle is the angle to cover (in degrees) and totalnum is the number of objects, including the original. The result is a parametric Draft Array.''' if not FreeCAD.ActiveDocument: FreeCAD.Console.PrintError("No active document. Aborting\n") @@ -1400,7 +1400,7 @@ def move(objectslist,vector,copy=False): newobj.End = obj.End.add(vector) newobj.Dimline = obj.Dimline.add(vector) else: - if copy and obj.isDerivedFrom("Mesh::Feature"): + if copy and obj.isDerivedFrom("Mesh::Feature"): print("Mesh copy not supported at the moment") # TODO newobj = obj if "Placement" in obj.PropertiesList: @@ -1416,19 +1416,19 @@ def move(objectslist,vector,copy=False): if copy and getParam("selectBaseObjects",False): select(objectslist) else: - select(newobjlist) + select(newobjlist) if len(newobjlist) == 1: return newobjlist[0] return newobjlist def array(objectslist,arg1,arg2,arg3,arg4=None,arg5=None,arg6=None): - '''array(objectslist,xvector,yvector,xnum,ynum) for rectangular array, + '''array(objectslist,xvector,yvector,xnum,ynum) for rectangular array, array(objectslist,xvector,yvector,zvector,xnum,ynum,znum) for rectangular array, or array(objectslist,center,totalangle,totalnum) for polar array: Creates an array of the objects contained in list (that can be an object or a list of objects) with, in case of rectangular array, xnum of iterations in the x direction at xvector distance between iterations, and same for y and z directions with yvector - and ynum and zvector and znum. In case of polar array, center is a vector, totalangle - is the angle to cover (in degrees) and totalnum is the number of objects, including + and ynum and zvector and znum. In case of polar array, center is a vector, totalangle + is the angle to cover (in degrees) and totalnum is the number of objects, including the original. This function creates an array of independent objects. Use makeArray() to create a @@ -1609,7 +1609,7 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy newobj.ViewObject.FontSize = factor d = obj.Position.sub(center) newobj.Position = center.add(Vector(d.x*delta.x,d.y*delta.y,d.z*delta.z)) - if copy: + if copy: formatObject(newobj,obj) newobjlist.append(newobj) if copy and getParam("selectBaseObjects",False): @@ -2274,6 +2274,16 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct return svg def getText(color,fontsize,fontname,angle,base,text,linespacing=0.5,align="center",flip=True): + if isinstance(angle,FreeCAD.Rotation): + if not plane: + angle = angle.Angle + else: + if plane.axis.getAngle(angle.Axis) < 0.001: + angle = angle.Angle + elif abs(plane.axis.getAngle(angle.Axis)-math.pi) < 0.001: + return "" # text is perpendicular to view, so it shouldn't appear + else: + angle = 0 #TODO maybe there is something better to do here? if not isinstance(text,list): text = text.split("\n") if align.lower() == "center": @@ -2487,16 +2497,22 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct tbase = getProj(prx.tbase) svg += getText(stroke,fontsize,obj.ViewObject.FontName,tangle,tbase,prx.string) - elif getType(obj) == "Annotation": + elif getType(obj) in ["Annotation","DraftText"]: "returns an svg representation of a document annotation" if not obj.ViewObject: print ("export of texts to SVG is only available in GUI mode") else: n = obj.ViewObject.FontName - a = obj.ViewObject.Rotation.getValueAs("rad") - t = obj.LabelText + if getType(obj) == "Annotation": + p = getProj(obj.Position) + r = obj.ViewObject.Rotation.getValueAs("rad") + t = obj.LabelText + else: # DraftText + p = getProj(obj.Placement.Base) + r = obj.Placement.Rotation + t = obj.Text j = obj.ViewObject.Justification - svg += getText(stroke,fontsize,n,a,getProj(obj.Position),t,linespacing,j) + svg += getText(stroke,fontsize,n,r,p,t,linespacing,j) elif getType(obj) == "Axis": "returns the SVG representation of an Arch Axis system" @@ -2551,7 +2567,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct if len(f.Edges) == 1: if isinstance(f.Edges[0].Curve,Part.Circle): svg += getCircle(f.Edges[0]) - + elif getType(obj) == "Rebar": fill = "none" lstyle = getLineStyle() @@ -2645,7 +2661,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct angle = -DraftVecUtils.angle(p2.sub(p1)) arrowsize = obj.ViewObject.ArrowSize.Value/pointratio svg += getArrow(obj.ViewObject.ArrowType,p2,arrowsize,stroke,linewidth,angle) - + # techdraw expects bottom-to-top coordinates if techdraw: svg = ''+svg+'' @@ -2744,23 +2760,23 @@ def makeShape2DView(baseobj,projectionVector=None,facenumbers=[]): def makeSketch(objectslist,autoconstraints=False,addTo=None, delete=False,name="Sketch",radiusPrecision=-1): - '''makeSketch(objectslist,[autoconstraints],[addTo],[delete],[name],[radiusPrecision]): + '''makeSketch(objectslist,[autoconstraints],[addTo],[delete],[name],[radiusPrecision]): - Makes a Sketch objectslist with the given Draft objects. + Makes a Sketch objectslist with the given Draft objects. * objectlist: can be single or list of objects of Draft type objects, Part::Feature, Part.Shape, or mix of them. * autoconstraints(False): if True, constraints will be automatically added to - wire nodes, rectangles and circles. - + wire nodes, rectangles and circles. + * addTo(None) : if set to an existing sketch, geometry will be added to it instead of creating a new one. - - * delete(False): if True, the original object will be deleted. + + * delete(False): if True, the original object will be deleted. If set to a string 'all' the object and all its linked object will be deleted - + * name('Sketch'): the name for the new sketch object * radiusPrecision(-1): If <0, disable radius constraint. If =0, add indiviaul @@ -6084,7 +6100,7 @@ class _Clone(_DraftObject): obj.addProperty("App::PropertyVector","Scale","Draft",QT_TRANSLATE_NOOP("App::Property","The scale factor of this clone")) obj.addProperty("App::PropertyBool","Fuse","Draft",QT_TRANSLATE_NOOP("App::Property","If this clones several objects, this specifies if the result is a fusion or a compound")) obj.Scale = Vector(1,1,1) - + def join(self,obj,shapes): if len(shapes) < 2: return shapes[0] @@ -6214,7 +6230,7 @@ class _ViewProviderDraftArray(_ViewProviderDraft): def getIcon(self): return ":/icons/Draft_Array.svg" - + def resetColors(self, vobj): colors = [] if vobj.Object.Base: @@ -6550,9 +6566,9 @@ class _ViewProviderVisGroup: class WorkingPlaneProxy: - + "The Draft working plane proxy object" - + def __init__(self,obj): obj.Proxy = self obj.addProperty("App::PropertyPlacement","Placement","Base",QT_TRANSLATE_NOOP("App::Property","The placement of this object")) @@ -6615,11 +6631,11 @@ class ViewProviderWorkingPlaneProxy: def claimChildren(self): return [] - + def doubleClicked(self,vobj): FreeCADGui.runCommand("Draft_SelectPlane") return True - + def setupContextMenu(self,vobj,menu): from PySide import QtCore,QtGui action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectPlane.svg"),"Write camera position",menu) @@ -6628,7 +6644,7 @@ class ViewProviderWorkingPlaneProxy: action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectPlane.svg"),"Write objects state",menu) QtCore.QObject.connect(action2,QtCore.SIGNAL("triggered()"),self.writeState) menu.addAction(action2) - + def writeCamera(self): if hasattr(self,"Object"): from pivy import coin @@ -6647,7 +6663,7 @@ class ViewProviderWorkingPlaneProxy: cdata.append(n.heightAngle.getValue()) cdata.append(1.0) # perspective camera self.Object.ViewObject.ViewData = cdata - + def writeState(self): if hasattr(self,"Object"): FreeCAD.Console.PrintMessage(QT_TRANSLATE_NOOP("Draft","Writing objects shown/hidden state")+"\n") @@ -6787,9 +6803,9 @@ def makeLabel(targetpoint=None,target=None,direction=None,distance=None,labeltyp class DraftLabel: - + "The Draft Label object" - + def __init__(self,obj): obj.Proxy = self obj.addProperty("App::PropertyPlacement","Placement","Base",QT_TRANSLATE_NOOP("App::Property","The placement of this object")) @@ -6988,7 +7004,7 @@ class ViewProviderDraftLabel: self.text2d.string.setValues([l.encode("utf8") for l in obj.Text if l]) self.text3d.string.setValues([l.encode("utf8") for l in obj.Text if l]) self.onChanged(obj.ViewObject,"TextAlignment") - + def getTextSize(self,vobj): from pivy import coin if vobj.DisplayMode == "3D text": @@ -7081,9 +7097,9 @@ class ViewProviderDraftLabel: class DraftText: - + "The Draft Text object" - + def __init__(self,obj): obj.Proxy = self obj.addProperty("App::PropertyPlacement","Placement","Base",QT_TRANSLATE_NOOP("App::Property","The placement of this object")) diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 3eaf97ad11..94419928ea 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -436,7 +436,7 @@ class SelectPlane(DraftTool): self.finish() except: pass - + def getCenterPoint(self,x,y,z): if not self.ui.isCenterPlane: return "0,0,0" @@ -503,7 +503,7 @@ class SelectPlane(DraftTool): def redraw3DView(): """redraw3DView(): forces a redraw of 3d view.""" try: - FreeCADGui.ActiveDocument.ActiveView.redraw() + FreeCADGui.ActiveDocument.ActiveView.redraw() except AttributeError as err: pass @@ -1811,6 +1811,7 @@ class Text(Creator): self.commit(translate("draft","Create Text"), ['text = Draft.makeText('+tx+',point='+DraftVecUtils.toString(self.node[0])+')', 'Draft.autogroup(text)']) + FreeCAD.ActiveDocument.recompute() self.finish(cont=True) @@ -1889,7 +1890,7 @@ class Dimension(Creator): self.setFromSelection() msg(translate("draft", "Pick first point:")+"\n") FreeCADGui.draftToolBar.show() - + def setFromSelection(self): "If we already have selected geometry, fill the nodes accordingly" sel = FreeCADGui.Selection.getSelectionEx() @@ -2158,7 +2159,7 @@ class Dimension(Creator): elif (len(self.node) == 2) and self.cont: self.node.append(self.cont) self.createObject() - if not self.cont: + if not self.cont: self.finish() elif (len(self.node) == 3): # for unlinked arc mode: @@ -2168,7 +2169,7 @@ class Dimension(Creator): # cen = self.node[0].add(v) # self.node = [self.node[0],self.node[1],cen] self.createObject() - if not self.cont: + if not self.cont: self.finish() elif self.angledata: self.node.append(self.point) @@ -2184,7 +2185,7 @@ class Dimension(Creator): self.dimtrack.on() elif (len(self.node) == 3): self.createObject() - if not self.cont: + if not self.cont: self.finish() class ShapeString(Creator): @@ -2837,7 +2838,7 @@ class Offset(Modifier): d = DraftVecUtils.toString(self.dvec) copymode = False occmode = self.ui.occOffset.isChecked() - if self.ui.isCopy.isChecked(): + if self.ui.isCopy.isChecked(): copymode = True FreeCADGui.addModule("Draft") self.commit(translate("draft","Offset"), @@ -2864,9 +2865,9 @@ class Stretch(Modifier): self.call = self.view.addEventCallback("SoEvent",selectObject) else: self.proceed() - + def proceed(self): - if self.call: + if self.call: self.view.removeEventCallback("SoEvent",self.call) self.sel = FreeCADGui.Selection.getSelection() if self.ui and self.sel: @@ -3497,7 +3498,7 @@ class Trimex(Modifier): self.doc.commitTransaction() self.doc.recompute() for g in self.ghost: g.off() - + def trimObjects(self,objectslist): "attempts to trim two objects together" import Part @@ -3563,7 +3564,7 @@ class Trimex(Modifier): else: obj.FirstAngle = ang self.doc.recompute() - + def finish(self,closed=False): Modifier.finish(self) @@ -3984,7 +3985,7 @@ class Edit(Modifier): self.obj.ViewObject.NodeSize = 1 self.obj.ViewObject.ShowNodes = True for p in self.obj.Nodes: - if self.pl: + if self.pl: p = self.pl.multVec(p) self.editpoints.append(p) elif Draft.getType(self.obj) == "PanelCut": @@ -4066,7 +4067,7 @@ class Edit(Modifier): # commented out the following line to disable updating # the object during edit, otherwise it confuses the snapper #self.update(self.trackers[self.editing].get()) - redraw3DView() + redraw3DView() elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): self.ui.redraw() @@ -4237,7 +4238,7 @@ class Edit(Modifier): else: self.obj.Group[self.editing-1].Placement.Base = self.invpl.multVec(v) try: - FreeCADGui.ActiveDocument.ActiveView.redraw() + FreeCADGui.ActiveDocument.ActiveView.redraw() except AttributeError as err: pass @@ -5231,7 +5232,7 @@ class SetAutoGroup(): self.labels = ["None"] for g in gn: o = FreeCAD.ActiveDocument.getObject(g) - if o: + if o: self.labels.append(o.Label) self.ui.sourceCmd = self self.ui.popupMenu(self.labels) @@ -5293,7 +5294,7 @@ class Draft_Label(Creator): self.call = self.view.addEventCallback("SoEvent",self.action) msg(translate("draft", "Pick target point:")+"\n") self.ui.isCopy.hide() - + def setmode(self,i): self.labeltype = ["Custom","Name","Label","Position","Length","Area","Volume","Tag","Material"][i] Draft.setParam("labeltype",self.labeltype) @@ -5302,7 +5303,7 @@ class Draft_Label(Creator): if self.ghost: self.ghost.finalize() Creator.finish(self) - + def create(self): if len(self.node) == 3: targetpoint = self.node[0] @@ -5350,7 +5351,7 @@ class Draft_Label(Creator): self.finish() elif arg["Type"] == "SoLocation2Event": if hasattr(FreeCADGui,"Snapper"): - FreeCADGui.Snapper.affinity = None # don't keep affinity + FreeCADGui.Snapper.affinity = None # don't keep affinity if len(self.node) == 2: setMod(arg,MODCONSTRAIN,True) self.point,ctrlPoint,info = getPoint(self,arg) @@ -5422,13 +5423,13 @@ class Draft_AddConstruction(): for obj in FreeCADGui.Selection.getSelection(): grp.addObject(obj) obrep = obj.ViewObject - if "TextColor" in obrep.PropertiesList: + if "TextColor" in obrep.PropertiesList: obrep.TextColor = col - if "PointColor" in obrep.PropertiesList: + if "PointColor" in obrep.PropertiesList: obrep.PointColor = col - if "LineColor" in obrep.PropertiesList: + if "LineColor" in obrep.PropertiesList: obrep.LineColor = col - if "ShapeColor" in obrep.PropertiesList: + if "ShapeColor" in obrep.PropertiesList: obrep.ShapeColor = col if hasattr(obrep,"Transparency"): obrep.Transparency = 80