Merge branch 'master' into Draft_addgroup
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@ open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
liberapay: FreeCAD
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ['https://www.patreon.com/yorikvanhavre', 'https://www.patreon.com/kkremitzki', 'https://www.patreon.com/thundereal']
|
||||
|
||||
@@ -974,8 +974,8 @@ void NaviCubeImplementation::drawNaviCube(bool pickMode) {
|
||||
static GLubyte xbmp[] = { 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11 };
|
||||
glColor3f(1, 0, 0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(-1.1 , -1.1, -1.1);
|
||||
glVertex3f(+0.5 , -1.1, -1.1);
|
||||
glVertex3f(-1.1f, -1.1f, -1.1f);
|
||||
glVertex3f(+0.5f, -1.1f, -1.1f);
|
||||
glEnd();
|
||||
glRasterPos3d(a, -a, -a);
|
||||
glBitmap(8, 7, 0, 0, 0, 0, xbmp);
|
||||
@@ -983,8 +983,8 @@ void NaviCubeImplementation::drawNaviCube(bool pickMode) {
|
||||
static GLubyte ybmp[] = { 0x04,0x04,0x04,0x04,0x0a,0x11,0x11 };
|
||||
glColor3f(0, 1, 0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(-1.1 , -1.1, -1.1);
|
||||
glVertex3f(-1.1 , +0.5, -1.1);
|
||||
glVertex3f(-1.1f, -1.1f, -1.1f);
|
||||
glVertex3f(-1.1f, +0.5f, -1.1f);
|
||||
glEnd();
|
||||
glRasterPos3d( -a, a, -a);
|
||||
glBitmap(8, 7, 0, 0, 0, 0, ybmp);
|
||||
@@ -992,8 +992,8 @@ void NaviCubeImplementation::drawNaviCube(bool pickMode) {
|
||||
static GLubyte zbmp[] = { 0x1f,0x10,0x08,0x04,0x02,0x01,0x1f };
|
||||
glColor3f(0, 0, 1);
|
||||
glBegin(GL_LINES);
|
||||
glVertex3f(-1.1 , -1.1, -1.1);
|
||||
glVertex3f(-1.1 , -1.1, +0.5);
|
||||
glVertex3f(-1.1f, -1.1f, -1.1f);
|
||||
glVertex3f(-1.1f, -1.1f, +0.5f);
|
||||
glEnd();
|
||||
glRasterPos3d( -a, -a, a);
|
||||
glBitmap(8, 7, 0, 0, 0, 0, zbmp);
|
||||
|
||||
@@ -7,26 +7,17 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>463</width>
|
||||
<height>421</height>
|
||||
<height>466</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>IFC-Export</string>
|
||||
<string>IFC export</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
|
||||
@@ -7,26 +7,17 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>463</width>
|
||||
<height>495</height>
|
||||
<height>577</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>IFC</string>
|
||||
<string>IFC import</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -394,6 +385,22 @@ FreeCAD object properties</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="checkBox">
|
||||
<property name="toolTip">
|
||||
<string>If this option is checked, the default Project, Site, Building and Storeys objects that are usually found in an IFC file are not imported, and all objects are placed in a Group. Buildins ans storeys are still imported if there is more than one.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Replace Project, Site, Buiding and Storey by Group</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>ifcReplaceProject</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Arch</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -161,7 +161,8 @@ def getPreferences():
|
||||
'IMPORT_PROPERTIES': p.GetBool("ifcImportProperties",False),
|
||||
'SPLIT_LAYERS': p.GetBool("ifcSplitLayers",False),
|
||||
'FITVIEW_ONIMPORT': p.GetBool("ifcFitViewOnImport",False),
|
||||
'ALLOW_INVALID': p.GetBool("ifcAllowInvalid",False)
|
||||
'ALLOW_INVALID': p.GetBool("ifcAllowInvalid",False),
|
||||
'REPLACE_PROJECT': p.GetBool("ifcReplaceProject",False)
|
||||
}
|
||||
|
||||
if preferences['MERGE_MODE_ARCH'] > 0:
|
||||
@@ -299,23 +300,24 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None):
|
||||
FreeCADGui.ActiveDocument.activeView().viewAxonometric()
|
||||
|
||||
# Create the base project object
|
||||
if len(ifcfile.by_type("IfcProject")) > 0:
|
||||
projectImporter = importIFCHelper.ProjectImporter(ifcfile, objects)
|
||||
projectImporter.execute()
|
||||
else:
|
||||
# https://forum.freecadweb.org/viewtopic.php?f=39&t=40624
|
||||
print("No IfcProject found in the ifc file. Nothing imported")
|
||||
return doc
|
||||
if not preferences['REPLACE_PROJECT']:
|
||||
if len(ifcfile.by_type("IfcProject")) > 0:
|
||||
projectImporter = importIFCHelper.ProjectImporter(ifcfile, objects)
|
||||
projectImporter.execute()
|
||||
else:
|
||||
# https://forum.freecadweb.org/viewtopic.php?f=39&t=40624
|
||||
print("No IfcProject found in the ifc file. Nothing imported")
|
||||
return doc
|
||||
|
||||
# handle IFC products
|
||||
|
||||
for product in products:
|
||||
|
||||
count += 1
|
||||
|
||||
pid = product.id()
|
||||
guid = product.GlobalId
|
||||
ptype = product.is_a()
|
||||
|
||||
if preferences['DEBUG']: print(count,"/",len(products),"object #"+str(pid),":",ptype,end="")
|
||||
|
||||
# build list of related property sets
|
||||
@@ -382,6 +384,20 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None):
|
||||
if ptype in preferences['SKIP']: # preferences-set type skip list
|
||||
if preferences['DEBUG']: print(" skipped.")
|
||||
continue
|
||||
if preferences['REPLACE_PROJECT']: # options-enabled project/site/building skip
|
||||
if ptype in ['IfcProject','IfcSite']:
|
||||
if preferences['DEBUG']: print(" skipped.")
|
||||
continue
|
||||
elif ptype in ['IfcBuilding']:
|
||||
if len(ifcfile.by_type("IfcBuilding")) == 1:
|
||||
# let multiple buildings through...
|
||||
if preferences['DEBUG']: print(" skipped.")
|
||||
continue
|
||||
elif ptype in ['IfcBuildingStorey']:
|
||||
if len(ifcfile.by_type("IfcBuildingStorey")) == 1:
|
||||
# let multiple storeys through...
|
||||
if preferences['DEBUG']: print(" skipped.")
|
||||
continue
|
||||
|
||||
# check if this object is sharing its shape (mapped representation)
|
||||
clone = None
|
||||
@@ -1220,6 +1236,15 @@ def insert(filename,docname,skip=[],only=[],root=None,preferences=None):
|
||||
if l:
|
||||
setattr(p[0],p[1],l)
|
||||
|
||||
# Grouping everything if required
|
||||
if preferences['REPLACE_PROJECT']:
|
||||
rootgroup = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup","Group")
|
||||
rootgroup.Label = os.path.basename(filename)
|
||||
for key,obj in objects.items():
|
||||
# only add top-level objects
|
||||
if not obj.InList:
|
||||
rootgroup.addObject(obj)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
if ZOOMOUT and FreeCAD.GuiUp:
|
||||
|
||||
@@ -72,14 +72,23 @@ def getIndices(obj,shape,offsetv,offsetvn):
|
||||
try:
|
||||
if not isinstance(e.Curve,Part.LineSegment):
|
||||
if not curves:
|
||||
myshape = obj.Shape.copy(False)
|
||||
myshape.Placement=obj.getGlobalPlacement()
|
||||
if obj.isDerivedFrom("App::Link"):
|
||||
myshape = obj.LinkedObject.Shape.copy(False)
|
||||
myshape.Placement=obj.LinkPlacement
|
||||
else:
|
||||
myshape = obj.Shape.copy(False)
|
||||
myshape.Placement=obj.getGlobalPlacement()
|
||||
mesh=MeshPart.meshFromShape(Shape=myshape, LinearDeflection=0.1, AngularDeflection=0.7, Relative=True)
|
||||
FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n")
|
||||
break
|
||||
except: # unimplemented curve type
|
||||
myshape = obj.Shape.copy(False)
|
||||
myshape.Placement=obj.getGlobalPlacement()
|
||||
if obj.isDerivedFrom("App::Link"):
|
||||
if obj.Shape:
|
||||
myshape = obj.Shape.copy(False)
|
||||
myshape.Placement=obj.LinkPlacement
|
||||
else:
|
||||
myshape = obj.Shape.copy(False)
|
||||
myshape.Placement=obj.getGlobalPlacement()
|
||||
mesh=MeshPart.meshFromShape(Shape=myshape, LinearDeflection=0.1, AngularDeflection=0.7, Relative=True)
|
||||
FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n")
|
||||
break
|
||||
@@ -157,7 +166,7 @@ def export(exportList,filename,colors=None):
|
||||
materials = []
|
||||
outfile.write("mtllib " + os.path.basename(filenamemtl) + "\n")
|
||||
for obj in objectslist:
|
||||
if obj.isDerivedFrom("Part::Feature") or obj.isDerivedFrom("Mesh::Feature"):
|
||||
if obj.isDerivedFrom("Part::Feature") or obj.isDerivedFrom("Mesh::Feature") or obj.isDerivedFrom("App::Link"):
|
||||
hires = None
|
||||
if FreeCAD.GuiUp:
|
||||
visible = obj.ViewObject.isVisible()
|
||||
|
||||
@@ -86,6 +86,8 @@ SET(Draft_view_providers
|
||||
SET(Draft_GUI_tools
|
||||
draftguitools/__init__.py
|
||||
draftguitools/gui_base.py
|
||||
draftguitools/gui_base_original.py
|
||||
draftguitools/gui_tool_utils.py
|
||||
draftguitools/gui_circulararray.py
|
||||
draftguitools/gui_orthoarray.py
|
||||
draftguitools/gui_polararray.py
|
||||
|
||||
@@ -514,7 +514,7 @@ def makeCopy(obj,force=None,reparent=False):
|
||||
_Point(newobj)
|
||||
if gui:
|
||||
_ViewProviderPoint(newobj.ViewObject)
|
||||
elif (getType(obj) == "Dimension") or (force == "Dimension"):
|
||||
elif (getType(obj) in ["Dimension","LinearDimension"]) or (force == "Dimension"):
|
||||
newobj = FreeCAD.ActiveDocument.addObject(obj.TypeId,getRealName(obj.Name))
|
||||
_Dimension(newobj)
|
||||
if gui:
|
||||
@@ -1025,7 +1025,7 @@ def move(objectslist,vector,copy=False):
|
||||
else:
|
||||
newobj = obj
|
||||
newobj.Placement.Base = obj.Placement.Base.add(real_vector)
|
||||
elif getType(obj) == "Dimension":
|
||||
elif getType(obj) in ["Dimension","LinearDimension"]:
|
||||
if copy:
|
||||
newobj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",getRealName(obj.Name))
|
||||
_Dimension(newobj)
|
||||
@@ -1589,7 +1589,7 @@ def getDXF(obj,direction=None):
|
||||
ny = DraftVecUtils.project(vec,plane.v)
|
||||
return Vector(nx.Length,ny.Length,0)
|
||||
|
||||
if getType(obj) == "Dimension":
|
||||
if getType(obj) in ["Dimension","LinearDimension"]:
|
||||
p1 = getProj(obj.Start)
|
||||
p2 = getProj(obj.End)
|
||||
p3 = getProj(obj.Dimline)
|
||||
|
||||
@@ -1893,8 +1893,7 @@ class DraftToolBar:
|
||||
return str(a)
|
||||
|
||||
def togglesnap(self):
|
||||
if hasattr(FreeCADGui,"Snapper"):
|
||||
FreeCADGui.Snapper.toggle()
|
||||
FreeCADGui.doCommand('FreeCADGui.runCommand("Draft_Snap_Lock")')
|
||||
|
||||
def togglenearsnap(self):
|
||||
if hasattr(FreeCADGui,"Snapper"):
|
||||
|
||||
+32
-256
@@ -114,276 +114,42 @@ elif defaultWP == 3: plane.alignToPointAndAxis(Vector(0,0,0), Vector(1,0,0), 0)
|
||||
# last snapped objects, for quick intersection calculation
|
||||
lastObj = [0,0]
|
||||
|
||||
# set modifier keys
|
||||
MODS = ["shift","ctrl","alt"]
|
||||
MODCONSTRAIN = MODS[Draft.getParam("modconstrain",0)]
|
||||
MODSNAP = MODS[Draft.getParam("modsnap",1)]
|
||||
MODALT = MODS[Draft.getParam("modalt",2)]
|
||||
# Set modifier keys
|
||||
from draftguitools.gui_tool_utils import MODCONSTRAIN
|
||||
from draftguitools.gui_tool_utils import MODSNAP
|
||||
from draftguitools.gui_tool_utils import MODALT
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# General functions
|
||||
# ---------------------------------------------------------------------------
|
||||
def formatUnit(exp,unit="mm"):
|
||||
'''returns a formatting string to set a number to the correct unit'''
|
||||
return FreeCAD.Units.Quantity(exp,FreeCAD.Units.Length).UserString
|
||||
from draftguitools.gui_tool_utils import formatUnit
|
||||
|
||||
def selectObject(arg):
|
||||
'''this is a scene even handler, to be called from the Draft tools
|
||||
when they need to select an object'''
|
||||
if (arg["Type"] == "SoKeyboardEvent"):
|
||||
if (arg["Key"] == "ESCAPE"):
|
||||
FreeCAD.activeDraftCommand.finish()
|
||||
# TODO : this part raises a coin3D warning about scene traversal, to be fixed.
|
||||
elif (arg["Type"] == "SoMouseButtonEvent"):
|
||||
if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
|
||||
cursor = arg["Position"]
|
||||
snapped = Draft.get3DView().getObjectInfo((cursor[0],cursor[1]))
|
||||
if snapped:
|
||||
obj = FreeCAD.ActiveDocument.getObject(snapped['Object'])
|
||||
FreeCADGui.Selection.addSelection(obj)
|
||||
FreeCAD.activeDraftCommand.component=snapped['Component']
|
||||
FreeCAD.activeDraftCommand.proceed()
|
||||
from draftguitools.gui_tool_utils import selectObject
|
||||
|
||||
def getPoint(target,args,mobile=False,sym=False,workingplane=True,noTracker=False):
|
||||
"""Function used by the Draft Tools.
|
||||
returns a constrained 3d point and its original point.
|
||||
if mobile=True, the constraining occurs from the location of
|
||||
mouse cursor when Shift is pressed, otherwise from last entered
|
||||
point. If sym=True, x and y values stay always equal. If workingplane=False,
|
||||
the point won't be projected on the Working Plane. if noTracker is True, the
|
||||
tracking line will not be displayed
|
||||
"""
|
||||
from draftguitools.gui_tool_utils import getPoint
|
||||
|
||||
ui = FreeCADGui.draftToolBar
|
||||
from draftguitools.gui_tool_utils import getSupport
|
||||
|
||||
if target.node:
|
||||
last = target.node[-1]
|
||||
else:
|
||||
last = None
|
||||
from draftguitools.gui_tool_utils import setWorkingPlaneToObjectUnderCursor
|
||||
|
||||
amod = hasMod(args, MODSNAP)
|
||||
cmod = hasMod(args, MODCONSTRAIN)
|
||||
point = None
|
||||
from draftguitools.gui_tool_utils import setWorkingPlaneToSelectedObject
|
||||
|
||||
if hasattr(FreeCADGui, "Snapper"):
|
||||
point = FreeCADGui.Snapper.snap(args["Position"],lastpoint=last,active=amod,constrain=cmod,noTracker=noTracker)
|
||||
info = FreeCADGui.Snapper.snapInfo
|
||||
mask = FreeCADGui.Snapper.affinity
|
||||
if not point:
|
||||
p = FreeCADGui.ActiveDocument.ActiveView.getCursorPos()
|
||||
point = FreeCADGui.ActiveDocument.ActiveView.getPoint(p)
|
||||
info = FreeCADGui.ActiveDocument.ActiveView.getObjectInfo(p)
|
||||
mask = None
|
||||
|
||||
ctrlPoint = Vector(point)
|
||||
if target.node:
|
||||
if target.featureName == "Rectangle":
|
||||
ui.displayPoint(point, target.node[0], plane=plane, mask=mask)
|
||||
else:
|
||||
ui.displayPoint(point, target.node[-1], plane=plane, mask=mask)
|
||||
else:
|
||||
ui.displayPoint(point, plane=plane, mask=mask)
|
||||
return point,ctrlPoint,info
|
||||
|
||||
def getSupport(mouseEvent=None):
|
||||
"""returns the supporting object and sets the working plane"""
|
||||
plane.save()
|
||||
if mouseEvent:
|
||||
return setWorkingPlaneToObjectUnderCursor(mouseEvent)
|
||||
return setWorkingPlaneToSelectedObject()
|
||||
|
||||
def setWorkingPlaneToObjectUnderCursor(mouseEvent):
|
||||
objectUnderCursor = Draft.get3DView().getObjectInfo((
|
||||
mouseEvent["Position"][0],
|
||||
mouseEvent["Position"][1]))
|
||||
|
||||
if not objectUnderCursor:
|
||||
return None
|
||||
|
||||
try:
|
||||
componentUnderCursor = getattr(
|
||||
FreeCAD.ActiveDocument.getObject(
|
||||
objectUnderCursor['Object']
|
||||
).Shape,
|
||||
objectUnderCursor["Component"])
|
||||
|
||||
if not plane.weak:
|
||||
return None
|
||||
|
||||
if "Face" in objectUnderCursor["Component"]:
|
||||
plane.alignToFace(componentUnderCursor)
|
||||
else:
|
||||
plane.alignToCurve(componentUnderCursor)
|
||||
plane.weak = True
|
||||
return objectUnderCursor
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def setWorkingPlaneToSelectedObject():
|
||||
sel = FreeCADGui.Selection.getSelectionEx()
|
||||
if len(sel) != 1:
|
||||
return None
|
||||
sel = sel[0]
|
||||
if sel.HasSubObjects \
|
||||
and len(sel.SubElementNames) == 1 \
|
||||
and "Face" in sel.SubElementNames[0]:
|
||||
if plane.weak:
|
||||
plane.alignToFace(sel.SubObjects[0])
|
||||
plane.weak = True
|
||||
return sel.Object
|
||||
return None
|
||||
|
||||
def hasMod(args,mod):
|
||||
"""checks if args has a specific modifier"""
|
||||
if mod == "shift":
|
||||
return args["ShiftDown"]
|
||||
elif mod == "ctrl":
|
||||
return args["CtrlDown"]
|
||||
elif mod == "alt":
|
||||
return args["AltDown"]
|
||||
|
||||
def setMod(args,mod,state):
|
||||
"""sets a specific modifier state in args"""
|
||||
if mod == "shift":
|
||||
args["ShiftDown"] = state
|
||||
elif mod == "ctrl":
|
||||
args["CtrlDown"] = state
|
||||
elif mod == "alt":
|
||||
args["AltDown"] = state
|
||||
from draftguitools.gui_tool_utils import hasMod
|
||||
|
||||
from draftguitools.gui_tool_utils import setMod
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Base Class
|
||||
# ---------------------------------------------------------------------------
|
||||
class DraftTool:
|
||||
"""The base class of all Draft Tools"""
|
||||
|
||||
def __init__(self):
|
||||
self.commitList = []
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCADGui.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self, name="None", noplanesetup=False, is_subtool=False):
|
||||
if FreeCAD.activeDraftCommand and not is_subtool:
|
||||
FreeCAD.activeDraftCommand.finish()
|
||||
|
||||
global Part, DraftGeomUtils
|
||||
import Part, DraftGeomUtils
|
||||
|
||||
self.ui = None
|
||||
self.call = None
|
||||
self.support = None
|
||||
self.point = None
|
||||
self.commitList = []
|
||||
self.doc = FreeCAD.ActiveDocument
|
||||
if not self.doc:
|
||||
self.finish()
|
||||
return
|
||||
|
||||
FreeCAD.activeDraftCommand = self
|
||||
self.view = Draft.get3DView()
|
||||
self.ui = FreeCADGui.draftToolBar
|
||||
self.featureName = name
|
||||
self.ui.sourceCmd = self
|
||||
self.ui.setTitle(name)
|
||||
self.ui.show()
|
||||
if not noplanesetup:
|
||||
plane.setup()
|
||||
self.node = []
|
||||
self.pos = []
|
||||
self.constrain = None
|
||||
self.obj = None
|
||||
self.extendedCopy = False
|
||||
self.ui.setTitle(name)
|
||||
self.planetrack = None
|
||||
if Draft.getParam("showPlaneTracker",False):
|
||||
self.planetrack = trackers.PlaneTracker()
|
||||
if hasattr(FreeCADGui,"Snapper"):
|
||||
FreeCADGui.Snapper.setTrackers()
|
||||
|
||||
def finish(self,close=False):
|
||||
self.node = []
|
||||
FreeCAD.activeDraftCommand = None
|
||||
if self.ui:
|
||||
self.ui.offUi()
|
||||
self.ui.sourceCmd = None
|
||||
if self.planetrack:
|
||||
self.planetrack.finalize()
|
||||
plane.restore()
|
||||
if hasattr(FreeCADGui,"Snapper"):
|
||||
FreeCADGui.Snapper.off()
|
||||
if self.call:
|
||||
try:
|
||||
self.view.removeEventCallback("SoEvent",self.call)
|
||||
except RuntimeError:
|
||||
# the view has been deleted already
|
||||
pass
|
||||
self.call = None
|
||||
if self.commitList:
|
||||
ToDo.delayCommit(self.commitList)
|
||||
self.commitList = []
|
||||
|
||||
def commit(self,name,func):
|
||||
"""stores actions to be committed to the FreeCAD document"""
|
||||
self.commitList.append((name,func))
|
||||
|
||||
def getStrings(self,addrot=None):
|
||||
"""returns a couple of useful strings for building python commands"""
|
||||
|
||||
# current plane rotation
|
||||
p = plane.getRotation()
|
||||
qr = p.Rotation.Q
|
||||
qr = '('+str(qr[0])+','+str(qr[1])+','+str(qr[2])+','+str(qr[3])+')'
|
||||
|
||||
# support object
|
||||
if self.support and FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft").GetBool("useSupport",False):
|
||||
sup = 'FreeCAD.ActiveDocument.getObject("' + self.support.Name + '")'
|
||||
else:
|
||||
sup = 'None'
|
||||
|
||||
# contents of self.node
|
||||
points='['
|
||||
for n in self.node:
|
||||
if len(points) > 1:
|
||||
points += ','
|
||||
points += DraftVecUtils.toString(n)
|
||||
points += ']'
|
||||
|
||||
# fill mode
|
||||
if self.ui:
|
||||
fil = str(bool(self.ui.fillmode))
|
||||
else:
|
||||
fil = "True"
|
||||
|
||||
return qr,sup,points,fil
|
||||
|
||||
from draftguitools.gui_base_original import DraftTool
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Geometry constructors
|
||||
# ---------------------------------------------------------------------------
|
||||
def redraw3DView():
|
||||
"""redraw3DView(): forces a redraw of 3d view."""
|
||||
try:
|
||||
FreeCADGui.ActiveDocument.ActiveView.redraw()
|
||||
except AttributeError as err:
|
||||
pass
|
||||
from draftguitools.gui_tool_utils import redraw3DView
|
||||
|
||||
class Creator(DraftTool):
|
||||
"""A generic Draft Creator Tool used by creation tools such as line or arc"""
|
||||
from draftguitools.gui_base_original import Creator
|
||||
|
||||
def __init__(self):
|
||||
DraftTool.__init__(self)
|
||||
|
||||
def Activated(self,name="None",noplanesetup=False):
|
||||
DraftTool.Activated(self,name,noplanesetup)
|
||||
if not noplanesetup:
|
||||
self.support = getSupport()
|
||||
|
||||
class Line(Creator):
|
||||
"""The Line FreeCAD command definition"""
|
||||
@@ -497,6 +263,7 @@ class Line(Creator):
|
||||
|
||||
def undolast(self):
|
||||
"""undoes last line segment"""
|
||||
import Part
|
||||
if (len(self.node) > 1):
|
||||
self.node.pop()
|
||||
last = self.node[-1]
|
||||
@@ -513,6 +280,7 @@ class Line(Creator):
|
||||
|
||||
def drawSegment(self,point):
|
||||
"""draws a new segment"""
|
||||
import Part
|
||||
if self.planetrack and self.node:
|
||||
self.planetrack.set(self.node[-1])
|
||||
if (len(self.node) == 1):
|
||||
@@ -665,6 +433,7 @@ class BSpline(Line):
|
||||
|
||||
def undolast(self):
|
||||
"""undoes last line segment"""
|
||||
import Part
|
||||
if (len(self.node) > 1):
|
||||
self.node.pop()
|
||||
self.bsplinetrack.update(self.node)
|
||||
@@ -674,6 +443,7 @@ class BSpline(Line):
|
||||
FreeCAD.Console.PrintMessage(translate("draft", "Last point has been removed")+"\n")
|
||||
|
||||
def drawUpdate(self,point):
|
||||
import Part
|
||||
if (len(self.node) == 1):
|
||||
self.bsplinetrack.on()
|
||||
if self.planetrack:
|
||||
@@ -785,6 +555,7 @@ class BezCurve(Line):
|
||||
|
||||
def updateShape(self, pts):
|
||||
'''creates shape for display during creation process.'''
|
||||
import Part
|
||||
edges = []
|
||||
if len(pts) >= 2: #allow lower degree segment
|
||||
poles=pts[1:]
|
||||
@@ -939,7 +710,8 @@ class CubicBezCurve(Line):
|
||||
|
||||
def updateShape(self, pts):
|
||||
'''creates shape for display during creation process.'''
|
||||
# not quite right. draws 1 big bez. sb segmented
|
||||
import Part
|
||||
# not quite right. draws 1 big bez. sb segmented
|
||||
edges = []
|
||||
|
||||
if len(pts) >= 2: #allow lower degree segment
|
||||
@@ -1182,6 +954,7 @@ class Arc(Creator):
|
||||
|
||||
def action(self,arg):
|
||||
"""scene event handler"""
|
||||
import DraftGeomUtils
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
@@ -1397,6 +1170,7 @@ class Arc(Creator):
|
||||
FreeCAD.Console.PrintMessage(translate("draft", "Pick radius")+"\n")
|
||||
|
||||
def numericRadius(self,rad):
|
||||
import DraftGeomUtils
|
||||
"""this function gets called by the toolbar when valid radius have been entered there"""
|
||||
if (self.step == 1):
|
||||
self.rad = rad
|
||||
@@ -1496,6 +1270,7 @@ class Polygon(Creator):
|
||||
|
||||
def action(self,arg):
|
||||
"""scene event handler"""
|
||||
import DraftGeomUtils
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
@@ -1626,6 +1401,7 @@ class Polygon(Creator):
|
||||
|
||||
def numericRadius(self,rad):
|
||||
"""this function gets called by the toolbar when valid radius have been entered there"""
|
||||
import DraftGeomUtils
|
||||
self.rad = rad
|
||||
if len(self.tangents) == 2:
|
||||
cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad)
|
||||
@@ -2329,13 +2105,8 @@ class ShapeString(Creator):
|
||||
#---------------------------------------------------------------------------
|
||||
# Modifier functions
|
||||
#---------------------------------------------------------------------------
|
||||
from draftguitools.gui_base_original import Modifier
|
||||
|
||||
class Modifier(DraftTool):
|
||||
"""A generic Modifier Tool, used by modification tools such as move"""
|
||||
|
||||
def __init__(self):
|
||||
DraftTool.__init__(self)
|
||||
self.copymode = False
|
||||
|
||||
class Move(Modifier):
|
||||
"""The Draft_Move FreeCAD command definition"""
|
||||
@@ -2911,6 +2682,7 @@ class Offset(Modifier):
|
||||
|
||||
def action(self,arg):
|
||||
"""scene event handler"""
|
||||
import DraftGeomUtils
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
self.finish()
|
||||
@@ -3522,6 +3294,7 @@ class Trimex(Modifier):
|
||||
self.linetrack = trackers.lineTracker()
|
||||
|
||||
import DraftGeomUtils
|
||||
import Part
|
||||
|
||||
if not "Shape" in self.obj.PropertiesList: return
|
||||
if "Placement" in self.obj.PropertiesList:
|
||||
@@ -3640,6 +3413,7 @@ class Trimex(Modifier):
|
||||
if real: newedges = []
|
||||
|
||||
import DraftGeomUtils
|
||||
import Part
|
||||
|
||||
# finding the active point
|
||||
vlist = []
|
||||
@@ -3754,6 +3528,7 @@ class Trimex(Modifier):
|
||||
|
||||
def trimObject(self):
|
||||
"""trims the actual object"""
|
||||
import Part
|
||||
if self.extrudeMode:
|
||||
delta = self.extrude(self.shift,real=True)
|
||||
#print("delta",delta)
|
||||
@@ -3816,6 +3591,7 @@ class Trimex(Modifier):
|
||||
def trimObjects(self,objectslist):
|
||||
"""attempts to trim two objects together"""
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
wires = []
|
||||
for obj in objectslist:
|
||||
if not Draft.getType(obj) in ["Wire","Circle"]:
|
||||
|
||||
@@ -116,6 +116,7 @@ class DraftWorkbench(FreeCADGui.Workbench):
|
||||
if hasattr(FreeCADGui, "draftToolBar"):
|
||||
if not hasattr(FreeCADGui.draftToolBar, "loadedPreferences"):
|
||||
FreeCADGui.addPreferencePage(":/ui/preferences-draft.ui", QT_TRANSLATE_NOOP("Draft", "Draft"))
|
||||
FreeCADGui.addPreferencePage(":/ui/preferences-draftinterface.ui", QT_TRANSLATE_NOOP("Draft", "Draft"))
|
||||
FreeCADGui.addPreferencePage(":/ui/preferences-draftsnap.ui", QT_TRANSLATE_NOOP("Draft", "Draft"))
|
||||
FreeCADGui.addPreferencePage(":/ui/preferences-draftvisual.ui", QT_TRANSLATE_NOOP("Draft", "Draft"))
|
||||
FreeCADGui.addPreferencePage(":/ui/preferences-drafttexts.ui", QT_TRANSLATE_NOOP("Draft", "Draft"))
|
||||
@@ -140,7 +141,7 @@ class DraftWorkbench(FreeCADGui.Workbench):
|
||||
if hasattr(FreeCADGui, "Snapper"):
|
||||
FreeCADGui.Snapper.hide()
|
||||
import draftutils.init_draft_statusbar as dsb
|
||||
dsb.hide_draft_statusbar()
|
||||
dsb.hide_draft_statusbar()
|
||||
FreeCAD.Console.PrintLog("Draft workbench deactivated.\n")
|
||||
|
||||
def ContextMenu(self, recipient):
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
<file>translations/Draft_zh-CN.qm</file>
|
||||
<file>translations/Draft_zh-TW.qm</file>
|
||||
<file>ui/preferences-draft.ui</file>
|
||||
<file>ui/preferences-draftinterface.ui</file>
|
||||
<file>ui/preferences-draftsnap.ui</file>
|
||||
<file>ui/preferences-drafttexts.ui</file>
|
||||
<file>ui/preferences-draftvisual.ui</file>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,975 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Gui::Dialog::DlgSettingsDraft</class>
|
||||
<widget class="QWidget" name="Gui::Dialog::DlgSettingsDraft">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>456</width>
|
||||
<height>338</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>User interface settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>In-Command Shortcuts</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="4" column="1">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_8">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>`</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutCycleSnap</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_9">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>S</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutSnap</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Relative</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_2">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>R</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutRelative</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_4">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>O</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutClose</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_3">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>T</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutContinue</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Continue</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Copy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Increase Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>Cycle Snap</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="3">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_19">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>[</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutIncreaseRadius</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="5">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_17">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>]</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutDecreaseRadius</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Snap</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="4">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Decrease Radius</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Length</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Wipe</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_11">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>D</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutSubelementMode</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Add Hold</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_12">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>L</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutFill</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_5">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>P</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutCopy</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Fill</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Subelement Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_13">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>E</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutSelectEdge</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_7">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>H</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutLength</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>Select Edge</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_14">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>W</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutWipe</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_6">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>A</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutExit</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="5">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_15">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Q</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutAddHold</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>Set WP</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="5">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_16">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>U</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutSetWP</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>Restrict X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_10">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutRestrictX</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string>Restrict Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="3">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_20">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>inCommandShortcutRestrictY</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="4">
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="text">
|
||||
<string>Restrict Z</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="5">
|
||||
<widget class="Gui::PrefLineEdit" name="lineEdit_18">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Z</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>RestrictZ</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enable draft statusbar customization</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Draft Statusbar</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<string notr="true">DisplayStatusbar</string>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<string notr="true">Mod/Draft</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="Gui::PrefCheckBox" name="gui::prefcheckbox_3">
|
||||
<property name="toolTip">
|
||||
<string>Enable snap statusbar widget</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Draft snap widget</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DisplayStatusbarSnapWidget</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefCheckBox" name="gui::prefcheckbox_13">
|
||||
<property name="toolTip">
|
||||
<string>Enable draft statusbar annotation scale widget</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Annotation scale widget</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>DisplayStatusbarScaleWidget</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Draft</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::PrefCheckBox</class>
|
||||
<extends>QCheckBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -139,7 +139,7 @@ class Arc_3Points(gui_base.GuiCommandSimplest):
|
||||
Parameters
|
||||
----------
|
||||
point: Base::Vector
|
||||
The dynamic point pased by the callback
|
||||
The dynamic point passed by the callback
|
||||
as we move the pointer in the 3D view.
|
||||
|
||||
info: str
|
||||
|
||||
@@ -33,99 +33,6 @@ import draftutils.todo as todo
|
||||
from draftutils.messages import _msg, _log
|
||||
|
||||
|
||||
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 GuiCommandSimplest:
|
||||
"""Simplest base class for GuiCommands.
|
||||
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
# ***************************************************************************
|
||||
# * (c) 2009 Yorik van Havre <[email protected]> *
|
||||
# * (c) 2010 Ken Cline <[email protected]> *
|
||||
# * (c) 2020 Eliud Cabrera Castillo <[email protected]> *
|
||||
# * *
|
||||
# * 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 *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides the Base object for most old Draft Gui Commands.
|
||||
|
||||
This class is used by Gui Commands to set up some properties
|
||||
of the DraftToolBar, the Snapper, and the working plane.
|
||||
"""
|
||||
## @package gui_base_original
|
||||
# \ingroup DRAFT
|
||||
# \brief Provides the Base object for most old Draft Gui Commands.
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import DraftVecUtils
|
||||
import draftutils.utils as utils
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import draftutils.todo as todo
|
||||
import draftguitools.gui_trackers as trackers
|
||||
import draftguitools.gui_tool_utils as gui_tool_utils
|
||||
from draftutils.messages import _msg, _log
|
||||
|
||||
|
||||
class DraftTool:
|
||||
"""The base class of all Draft Tools.
|
||||
|
||||
This is the original class that was defined in `DraftTools.py`
|
||||
before any re-organization of the code.
|
||||
It must be preserved exactly like this to keep the original tools
|
||||
running without problems.
|
||||
|
||||
This class is subclassed by `Creator` and `Modifier`
|
||||
to set up a few additional properties of these two types.
|
||||
|
||||
This class connects with the `draftToolBar` and `Snapper` classes
|
||||
that are installed in the `FreeCADGui` namespace in order to set up some
|
||||
properties of the running tools such as the task panel, the snapping
|
||||
functions, and the grid trackers.
|
||||
|
||||
It also connects with the `DraftWorkingPlane` class
|
||||
that is installed in the `FreeCAD` namespace in order to set up
|
||||
the working plane if it doesn't exist.
|
||||
|
||||
This class is intended to be replaced by newer classes inside the
|
||||
`gui_base` module, in particular, `GuiCommandBase`.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.commitList = []
|
||||
|
||||
def IsActive(self):
|
||||
"""Return True when this command should be available.
|
||||
|
||||
It is `True` when there is a document.
|
||||
"""
|
||||
if Gui.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def Activated(self, name="None", noplanesetup=False, is_subtool=False):
|
||||
"""Execute when the command is called.
|
||||
|
||||
If an active Gui Command exists, it will call the `finish` method
|
||||
of it to terminate it.
|
||||
|
||||
If no active Gui Command exists, it will proceed with configuration
|
||||
of the tool. The child class that subclasses this class
|
||||
then should continue with its own Activated method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str, optional
|
||||
It defaults to `'None'`.
|
||||
It is the `featureName` of the object, to know what is being run.
|
||||
|
||||
noplanesetup: bool, optional
|
||||
It defaults to `False`.
|
||||
If it is `False` it will set up the working plane
|
||||
by running `App.DraftWorkingPlane.setup()`.
|
||||
|
||||
is_subtool: bool, optional
|
||||
It defaults to `False`.
|
||||
This is set to `True` when we want to modify an object
|
||||
by using the mechanism of a `subtool`, introduced
|
||||
through the `Draft_SubelementHighlight` command.
|
||||
That is, first we run `Draft_SubelementHighlight`
|
||||
then we can use `Draft_Move` while setting `is_subtool` to `True`.
|
||||
"""
|
||||
if App.activeDraftCommand and not is_subtool:
|
||||
App.activeDraftCommand.finish()
|
||||
|
||||
# The Part module is first initialized when using any Gui Command
|
||||
# for the first time.
|
||||
global Part, DraftGeomUtils
|
||||
import Part
|
||||
import DraftGeomUtils
|
||||
|
||||
self.ui = None
|
||||
self.call = None
|
||||
self.support = None
|
||||
self.point = None
|
||||
self.commitList = []
|
||||
self.doc = App.ActiveDocument
|
||||
if not self.doc:
|
||||
self.finish()
|
||||
return
|
||||
|
||||
App.activeDraftCommand = self
|
||||
self.view = gui_utils.get_3d_view()
|
||||
self.ui = Gui.draftToolBar
|
||||
self.featureName = name
|
||||
self.ui.sourceCmd = self
|
||||
self.ui.setTitle(name)
|
||||
self.ui.show()
|
||||
if not noplanesetup:
|
||||
App.DraftWorkingPlane.setup()
|
||||
self.node = []
|
||||
self.pos = []
|
||||
self.constrain = None
|
||||
self.obj = None
|
||||
self.extendedCopy = False
|
||||
self.ui.setTitle(name)
|
||||
self.planetrack = None
|
||||
if utils.get_param("showPlaneTracker", False):
|
||||
self.planetrack = trackers.PlaneTracker()
|
||||
if hasattr(Gui, "Snapper"):
|
||||
Gui.Snapper.setTrackers()
|
||||
|
||||
_log("GuiCommand: {}".format(self.featureName))
|
||||
_msg("{}".format(16*"-"))
|
||||
_msg("GuiCommand: {}".format(self.featureName))
|
||||
|
||||
def finish(self, close=False):
|
||||
"""Finish the current command.
|
||||
|
||||
These are general cleaning tasks that are performed
|
||||
when terminating all commands.
|
||||
|
||||
These include setting the node list to empty,
|
||||
setting to `None` the active command,
|
||||
turning off the graphical interface (task panel),
|
||||
finishing the plane tracker, restoring the working plane,
|
||||
turning off the snapper.
|
||||
|
||||
If a callback is installed in the 3D view, the callback is removed,
|
||||
and set to `None`.
|
||||
|
||||
If the commit list is non-empty it will commit the instructions on
|
||||
the list with `draftutils.todo.ToDo.delayCommit`,
|
||||
and the list will be set to empty.
|
||||
"""
|
||||
self.node = []
|
||||
App.activeDraftCommand = None
|
||||
if self.ui:
|
||||
self.ui.offUi()
|
||||
self.ui.sourceCmd = None
|
||||
if self.planetrack:
|
||||
self.planetrack.finalize()
|
||||
App.DraftWorkingPlane.restore()
|
||||
if hasattr(Gui, "Snapper"):
|
||||
Gui.Snapper.off()
|
||||
if self.call:
|
||||
try:
|
||||
self.view.removeEventCallback("SoEvent", self.call)
|
||||
except RuntimeError:
|
||||
# the view has been deleted already
|
||||
pass
|
||||
self.call = None
|
||||
if self.commitList:
|
||||
todo.ToDo.delayCommit(self.commitList)
|
||||
self.commitList = []
|
||||
|
||||
def commit(self, name, func):
|
||||
"""Store actions in the commit list to be run later.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
An arbitraty string that indicates the name of the operation
|
||||
to run.
|
||||
|
||||
func: list of str
|
||||
Each element of the list is a string that will be run by
|
||||
`Gui.doCommand`.
|
||||
|
||||
See the complete information in the `draftutils.todo.ToDo` class.
|
||||
"""
|
||||
self.commitList.append((name, func))
|
||||
|
||||
def getStrings(self, addrot=None):
|
||||
"""Return useful strings that will be used to build commands.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str, str, str, str
|
||||
A tuple of four strings that represent useful information.
|
||||
|
||||
* the current working plane rotation quaternion as a string
|
||||
* the support object if available as a string
|
||||
* the list of nodes inside the `node` attribute as a string
|
||||
* the string `'True'` or `'False'` depending on the fill mode
|
||||
of the current tool
|
||||
"""
|
||||
# Current plane rotation as a string
|
||||
p = App.DraftWorkingPlane.getRotation()
|
||||
qr = p.Rotation.Q
|
||||
qr = "({0}, {1}, {2}, {3})".format(qr[0], qr[1], qr[2], qr[3])
|
||||
|
||||
# Support object
|
||||
_params = "User parameter:BaseApp/Preferences/Mod/Draft"
|
||||
_params_group = App.ParamGet(_params)
|
||||
if self.support and _params_group.GetBool("useSupport", False):
|
||||
sup = 'FreeCAD.ActiveDocument.getObject'
|
||||
sup += '("{}")'.format(self.support.Name)
|
||||
else:
|
||||
sup = 'None'
|
||||
|
||||
# Contents of self.node
|
||||
points = '['
|
||||
for n in self.node:
|
||||
if len(points) > 1:
|
||||
points += ', '
|
||||
points += DraftVecUtils.toString(n)
|
||||
points += ']'
|
||||
|
||||
# Fill mode
|
||||
if self.ui:
|
||||
fil = str(bool(self.ui.fillmode))
|
||||
else:
|
||||
fil = "True"
|
||||
|
||||
return qr, sup, points, fil
|
||||
|
||||
|
||||
class Creator(DraftTool):
|
||||
"""A generic Creator tool, used by creation tools such as line or arc.
|
||||
|
||||
It runs the Activated method from the parent class.
|
||||
If `noplanesetup` is `False`, it sets the appropriate `support` attribute
|
||||
and sets the working plane with `gui_tool_utils.get_support`.
|
||||
|
||||
It inherits `DraftTool`, which sets up the majority of the behavior
|
||||
of this class.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def Activated(self, name="None", noplanesetup=False):
|
||||
"""Execute when the command is called.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str, optional
|
||||
It defaults to `'None'`.
|
||||
It is the `featureName` of the object, to know what is being run.
|
||||
|
||||
noplanesetup: bool, optional
|
||||
It defaults to `False`.
|
||||
If it is `False` it will set up the working plane
|
||||
by running `App.DraftWorkingPlane.setup()`.
|
||||
"""
|
||||
super().Activated(name, noplanesetup)
|
||||
if not noplanesetup:
|
||||
self.support = gui_tool_utils.get_support()
|
||||
|
||||
|
||||
class Modifier(DraftTool):
|
||||
"""A generic Modifier tool, used by modification tools such as move.
|
||||
|
||||
After initializing the parent class, it sets the `copymode` attribute
|
||||
to `False`.
|
||||
|
||||
It inherits `DraftTool`, which sets up the majority of the behavior
|
||||
of this class.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.copymode = False
|
||||
@@ -53,7 +53,7 @@ class AddToGroup(gui_base.GuiCommandNeedsSelection):
|
||||
|
||||
It adds selected objects to a group, or removes them from any group.
|
||||
|
||||
It inherits `GuiCommandNeedsSelection` to only be availbale
|
||||
It inherits `GuiCommandNeedsSelection` to only be available
|
||||
when there is a document and a selection.
|
||||
See this class for more information.
|
||||
"""
|
||||
@@ -169,7 +169,7 @@ class SelectGroup(gui_base.GuiCommandNeedsSelection):
|
||||
in this case it works in an intuitive manner, selecting
|
||||
only the objects under the group.
|
||||
|
||||
It inherits `GuiCommandNeedsSelection` to only be availbale
|
||||
It inherits `GuiCommandNeedsSelection` to only be available
|
||||
when there is a document and a selection.
|
||||
See this class for more information.
|
||||
"""
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,13 +28,74 @@
|
||||
# \brief Provide the Draft_Snap commands used by the snapping mechanism
|
||||
# in Draft.
|
||||
|
||||
from PySide import QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import FreeCADGui as Gui
|
||||
|
||||
import draftguitools.gui_base as gui_base
|
||||
from draftutils.translate import _tr
|
||||
|
||||
|
||||
# UTILITIES -----------------------------------------------------------------
|
||||
|
||||
|
||||
def get_snap_statusbar_widget():
|
||||
"""Return snap statusbar button."""
|
||||
mw = Gui.getMainWindow()
|
||||
if mw:
|
||||
sb = mw.statusBar()
|
||||
if sb:
|
||||
return sb.findChild(QtGui.QToolBar,"draft_snap_widget")
|
||||
return None
|
||||
|
||||
|
||||
def sync_snap_toolbar_button(button, status):
|
||||
"""Set snap toolbar button to given state."""
|
||||
snap_toolbar = Gui.Snapper.get_snap_toolbar()
|
||||
if not snap_toolbar:
|
||||
return
|
||||
for a in snap_toolbar.actions():
|
||||
if a.objectName() == button:
|
||||
if button == "Draft_Snap_Lock_Button":
|
||||
# for lock button
|
||||
snap_toolbar.actions()[0].setChecked(status)
|
||||
for a in snap_toolbar.actions()[1:]:
|
||||
a.setEnabled(status)
|
||||
else:
|
||||
# for every other button
|
||||
a.setChecked(status)
|
||||
if a.isChecked():
|
||||
a.setToolTip(a.toolTip().replace("OFF","ON"))
|
||||
else:
|
||||
a.setToolTip(a.toolTip().replace("ON","OFF"))
|
||||
|
||||
|
||||
def sync_snap_statusbar_button(button, status):
|
||||
"""Set snap statusbar button to given state."""
|
||||
ssw = get_snap_statusbar_widget()
|
||||
if not ssw:
|
||||
return
|
||||
for child in ssw.children():
|
||||
if child.objectName() == "Snap_Statusbutton":
|
||||
ssb = child
|
||||
actions = []
|
||||
for a in ssb.menu().actions() + ssw.children()[-6:]:
|
||||
actions.append(a)
|
||||
|
||||
if button == "Draft_Snap_Lock_Statusbutton":
|
||||
ssb.setChecked(status)
|
||||
for a in actions[1:]:
|
||||
a.setEnabled(status)
|
||||
else:
|
||||
for a in actions:
|
||||
if a.objectName() == button:
|
||||
a.setChecked(status)
|
||||
|
||||
|
||||
# SNAP GUI TOOLS ------------------------------------------------------------
|
||||
|
||||
|
||||
class Draft_Snap_Lock(gui_base.GuiCommandSimplest):
|
||||
"""GuiCommand for the Draft_Snap_Lock tool.
|
||||
|
||||
@@ -42,7 +103,7 @@ class Draft_Snap_Lock(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Main toggle snap"))
|
||||
super(Draft_Snap_Lock, self).__init__(name=_tr("Main toggle snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -57,11 +118,13 @@ class Draft_Snap_Lock(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
|
||||
super(Draft_Snap_Lock, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "masterbutton"):
|
||||
Gui.Snapper.masterbutton.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Lock')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Lock"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Lock"+"_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Lock', Draft_Snap_Lock())
|
||||
@@ -74,7 +137,7 @@ class Draft_Snap_Midpoint(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Midpoint snap"))
|
||||
super(Draft_Snap_Midpoint, self).__init__(name=_tr("Midpoint snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -87,13 +150,13 @@ class Draft_Snap_Midpoint(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Midpoint, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonmidpoint":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Midpoint')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Midpoint"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Midpoint_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Midpoint', Draft_Snap_Midpoint())
|
||||
@@ -106,7 +169,7 @@ class Draft_Snap_Perpendicular(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Perpendicular snap"))
|
||||
super(Draft_Snap_Perpendicular, self).__init__(name=_tr("Perpendicular snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -121,13 +184,13 @@ class Draft_Snap_Perpendicular(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Perpendicular, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonperpendicular":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Perpendicular')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Perpendicular"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Perpendicular_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Perpendicular', Draft_Snap_Perpendicular())
|
||||
@@ -140,7 +203,7 @@ class Draft_Snap_Grid(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Grid snap"))
|
||||
super(Draft_Snap_Grid, self).__init__(name=_tr("Grid snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -152,13 +215,13 @@ class Draft_Snap_Grid(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Grid, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtongrid":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Grid')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Grid"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Grid_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Grid', Draft_Snap_Grid())
|
||||
@@ -171,7 +234,7 @@ class Draft_Snap_Intersection(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Intersection snap"))
|
||||
super(Draft_Snap_Intersection, self).__init__(name=_tr("Intersection snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -186,13 +249,13 @@ class Draft_Snap_Intersection(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Intersection, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonintersection":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Intersection')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Intersection"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Intersection_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Intersection', Draft_Snap_Intersection())
|
||||
@@ -205,7 +268,7 @@ class Draft_Snap_Parallel(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Parallel snap"))
|
||||
super(Draft_Snap_Parallel, self).__init__(name=_tr("Parallel snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -218,13 +281,13 @@ class Draft_Snap_Parallel(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Parallel, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonparallel":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Parallel')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Parallel"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Parallel_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Parallel', Draft_Snap_Parallel())
|
||||
@@ -237,7 +300,7 @@ class Draft_Snap_Endpoint(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Endpoint snap"))
|
||||
super(Draft_Snap_Endpoint, self).__init__(name=_tr("Endpoint snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -250,13 +313,13 @@ class Draft_Snap_Endpoint(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Endpoint, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonendpoint":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Endpoint')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Endpoint"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Endpoint_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Endpoint', Draft_Snap_Endpoint())
|
||||
@@ -270,7 +333,7 @@ class Draft_Snap_Angle(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Angle snap (30 and 45 degrees)"))
|
||||
super(Draft_Snap_Angle, self).__init__(name=_tr("Angle snap (30 and 45 degrees)"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -284,13 +347,13 @@ class Draft_Snap_Angle(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Angle, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonangle":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Angle')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Angle"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Angle_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Angle', Draft_Snap_Angle())
|
||||
@@ -303,7 +366,7 @@ class Draft_Snap_Center(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Arc center snap"))
|
||||
super(Draft_Snap_Center, self).__init__(name=_tr("Arc center snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -315,13 +378,13 @@ class Draft_Snap_Center(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Center, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtoncenter":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Center')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Center"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Center_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Center', Draft_Snap_Center())
|
||||
@@ -334,7 +397,7 @@ class Draft_Snap_Extension(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Edge extension snap"))
|
||||
super(Draft_Snap_Extension, self).__init__(name=_tr("Edge extension snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -347,13 +410,13 @@ class Draft_Snap_Extension(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Extension, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonextension":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Extension')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Extension"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Extension_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Extension', Draft_Snap_Extension())
|
||||
@@ -366,7 +429,7 @@ class Draft_Snap_Near(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Near snap"))
|
||||
super(Draft_Snap_Near, self).__init__(name=_tr("Near snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -378,13 +441,13 @@ class Draft_Snap_Near(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Near, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonpassive":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Near')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Near"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Near_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Near', Draft_Snap_Near())
|
||||
@@ -398,7 +461,7 @@ class Draft_Snap_Ortho(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Orthogonal snap"))
|
||||
super(Draft_Snap_Ortho, self).__init__(name=_tr("Orthogonal snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -412,13 +475,13 @@ class Draft_Snap_Ortho(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Ortho, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonortho":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Ortho')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Ortho"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Ortho"+"_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Ortho', Draft_Snap_Ortho())
|
||||
@@ -431,7 +494,7 @@ class Draft_Snap_Special(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Special point snap"))
|
||||
super(Draft_Snap_Special, self).__init__(name=_tr("Special point snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -444,13 +507,13 @@ class Draft_Snap_Special(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Special, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonspecial":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Special')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Special"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Special_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Special', Draft_Snap_Special())
|
||||
@@ -464,7 +527,7 @@ class Draft_Snap_Dimensions(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Dimension display"))
|
||||
super(Draft_Snap_Dimensions, self).__init__(name=_tr("Dimension display"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -478,13 +541,13 @@ class Draft_Snap_Dimensions(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_Dimensions, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonDimensions":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('Dimensions')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_Dimensions"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_Dimensions"+"_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_Dimensions', Draft_Snap_Dimensions())
|
||||
@@ -500,7 +563,7 @@ class Draft_Snap_WorkingPlane(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Working plane snap"))
|
||||
super(Draft_Snap_WorkingPlane, self).__init__(name=_tr("Working plane snap"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -520,13 +583,13 @@ class Draft_Snap_WorkingPlane(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(Draft_Snap_WorkingPlane, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
if hasattr(Gui.Snapper, "toolbarButtons"):
|
||||
for b in Gui.Snapper.toolbarButtons:
|
||||
if b.objectName() == "SnapButtonWorkingPlane":
|
||||
b.toggle()
|
||||
status = Gui.Snapper.toggle_snap('WorkingPlane')
|
||||
# change interface consistently
|
||||
sync_snap_toolbar_button("Draft_Snap_WorkingPlane"+"_Button", status)
|
||||
sync_snap_statusbar_button("Draft_Snap_WorkingPlane_Statusbutton", status)
|
||||
|
||||
|
||||
Gui.addCommand('Draft_Snap_WorkingPlane', Draft_Snap_WorkingPlane())
|
||||
@@ -539,7 +602,7 @@ class ShowSnapBar(gui_base.GuiCommandSimplest):
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(name=_tr("Show snap toolbar"))
|
||||
super(ShowSnapBar, self).__init__(name=_tr("Show snap toolbar"))
|
||||
|
||||
def GetResources(self):
|
||||
"""Set icon, menu and tooltip."""
|
||||
@@ -553,7 +616,7 @@ class ShowSnapBar(gui_base.GuiCommandSimplest):
|
||||
|
||||
def Activated(self):
|
||||
"""Execute when the command is called."""
|
||||
super().Activated()
|
||||
super(ShowSnapBar, self).Activated()
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
Gui.Snapper.show()
|
||||
|
||||
@@ -160,7 +160,7 @@ class ToggleDisplayMode(gui_base.GuiCommandNeedsSelection):
|
||||
Switches the display mode of selected objects from flatlines
|
||||
to wireframe and back.
|
||||
|
||||
It inherits `GuiCommandNeedsSelection` to only be availbale
|
||||
It inherits `GuiCommandNeedsSelection` to only be available
|
||||
when there is a document and a selection.
|
||||
See this class for more information.
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,389 @@
|
||||
# ***************************************************************************
|
||||
# * (c) 2009 Yorik van Havre <[email protected]> *
|
||||
# * (c) 2010 Ken Cline <[email protected]> *
|
||||
# * (c) 2020 Eliud Cabrera Castillo <[email protected]> *
|
||||
# * *
|
||||
# * 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 *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Provides the utility functions for Draft Gui Commands.
|
||||
|
||||
These functions are used by different command classes in the `DraftTools`
|
||||
module. We assume that the graphical interface was already loaded
|
||||
as they operate on selections and graphical properties.
|
||||
"""
|
||||
## @package gui_tool_utils
|
||||
# \ingroup DRAFT
|
||||
# \brief Provides the utility functions for Draft Gui Commands.
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import draftutils.gui_utils as gui_utils
|
||||
import draftutils.utils as utils
|
||||
from draftutils.messages import _wrn
|
||||
|
||||
# Set modifier keys from the parameter database
|
||||
MODS = ["shift", "ctrl", "alt"]
|
||||
MODCONSTRAIN = MODS[utils.get_param("modconstrain", 0)]
|
||||
MODSNAP = MODS[utils.get_param("modsnap", 1)]
|
||||
MODALT = MODS[utils.get_param("modalt", 2)]
|
||||
|
||||
|
||||
def format_unit(exp, unit="mm"):
|
||||
"""Return a formatting string to set a number to the correct unit."""
|
||||
return App.Units.Quantity(exp, App.Units.Length).UserString
|
||||
|
||||
|
||||
formatUnit = format_unit
|
||||
|
||||
|
||||
def select_object(arg):
|
||||
"""Handle the selection of objects depending on buttons pressed.
|
||||
|
||||
This is a scene event handler, to be called from the Draft tools
|
||||
when they need to select an object.
|
||||
::
|
||||
self.call = self.view.addEventCallback("SoEvent", select_object)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg: Coin event
|
||||
The Coin event received from the 3D view.
|
||||
|
||||
If it is of type Keyboard and the `ESCAPE` key, it runs the `finish`
|
||||
method of the active command.
|
||||
|
||||
If it is of type Mouse button and `BUTTON1` press,
|
||||
it captures the position of the cursor (x, y)
|
||||
and the object below that cursor to add it to the active selection;
|
||||
then it runs the `proceed` method of the active command
|
||||
to continue with the command's logic.
|
||||
"""
|
||||
if arg["Type"] == "SoKeyboardEvent":
|
||||
if arg["Key"] == "ESCAPE":
|
||||
App.activeDraftCommand.finish()
|
||||
# TODO: this part raises a coin3D warning about scene traversal.
|
||||
# It needs to be fixed.
|
||||
elif arg["Type"] == "SoMouseButtonEvent":
|
||||
if arg["State"] == "DOWN" and arg["Button"] == "BUTTON1":
|
||||
cursor = arg["Position"]
|
||||
snapped = gui_utils.get_3d_view().getObjectInfo((cursor[0],
|
||||
cursor[1]))
|
||||
if snapped:
|
||||
obj = App.ActiveDocument.getObject(snapped['Object'])
|
||||
Gui.Selection.addSelection(obj)
|
||||
App.activeDraftCommand.component = snapped['Component']
|
||||
App.activeDraftCommand.proceed()
|
||||
|
||||
|
||||
selectObject = select_object
|
||||
|
||||
|
||||
def has_mod(args, mod):
|
||||
"""Check if args has a specific modifier.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
args: Coin event
|
||||
The Coin event received from the 3D view.
|
||||
|
||||
mod: str
|
||||
A string indicating the modifier, either `'shift'`, `'ctrl'`,
|
||||
or `'alt'`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
It returns `args["ShiftDown"]`, `args["CtrlDown"]`,
|
||||
or `args["AltDown"]`, depending on the passed value of `mod`.
|
||||
"""
|
||||
if mod == "shift":
|
||||
return args["ShiftDown"]
|
||||
elif mod == "ctrl":
|
||||
return args["CtrlDown"]
|
||||
elif mod == "alt":
|
||||
return args["AltDown"]
|
||||
|
||||
|
||||
hasMod = has_mod
|
||||
|
||||
|
||||
def set_mod(args, mod, state):
|
||||
"""Set a specific modifier state in args.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
args: Coin event
|
||||
The Coin event received from the 3D view.
|
||||
|
||||
mod: str
|
||||
A string indicating the modifier, either `'shift'`, `'ctrl'`,
|
||||
or `'alt'`.
|
||||
|
||||
state: bool
|
||||
The boolean value of `state` is assigned to `args["ShiftDown"]`,
|
||||
`args["CtrlDown"]`, or `args["AltDown"]`
|
||||
depending on `mod`.
|
||||
"""
|
||||
if mod == "shift":
|
||||
args["ShiftDown"] = state
|
||||
elif mod == "ctrl":
|
||||
args["CtrlDown"] = state
|
||||
elif mod == "alt":
|
||||
args["AltDown"] = state
|
||||
|
||||
|
||||
setMod = set_mod
|
||||
|
||||
|
||||
def get_point(target, args,
|
||||
mobile=False, sym=False, workingplane=True, noTracker=False):
|
||||
"""Return a constrained 3D point and its original point.
|
||||
|
||||
It is used by the Draft tools.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
target: object (class)
|
||||
The target object with a `node` attribute. If this is present,
|
||||
return the last node, otherwise return `None`.
|
||||
|
||||
In the Draft tools, `target` is essentially the same class
|
||||
of the Gui command, that is, `self`. Therefore, this method
|
||||
probably makes more sense as a class method.
|
||||
|
||||
args: Coin event
|
||||
The Coin event received from the 3D view.
|
||||
|
||||
mobile: bool, optional
|
||||
It defaults to `False`.
|
||||
If it is `True` the constraining occurs from the location of
|
||||
the mouse cursor when `Shift` is pressed; otherwise from the last
|
||||
entered point.
|
||||
|
||||
sym: bool, optional
|
||||
It defaults to `False`.
|
||||
If it is `True`, the x and y values always stay equal.
|
||||
|
||||
workingplane: bool, optional
|
||||
It defaults to `True`.
|
||||
If it is `False`, the point won't be projected on the currently
|
||||
active working plane.
|
||||
|
||||
noTracker: bool, optional
|
||||
It defaults to `False`.
|
||||
If it is `True`, the tracking line will not be displayed.
|
||||
|
||||
Returns
|
||||
-------
|
||||
CoinPoint, Base::Vector3, str
|
||||
It returns a tuple with some information.
|
||||
|
||||
The first is the Coin point returned by `Snapper.snap`
|
||||
or by the `ActiveView`; the second is that same point
|
||||
turned into an `App.Vector`,
|
||||
and the third is some information of the point
|
||||
returned by the `Snapper` or by the `ActiveView`.
|
||||
"""
|
||||
ui = Gui.draftToolBar
|
||||
|
||||
if target.node:
|
||||
last = target.node[-1]
|
||||
else:
|
||||
last = None
|
||||
|
||||
amod = hasMod(args, MODSNAP)
|
||||
cmod = hasMod(args, MODCONSTRAIN)
|
||||
point = None
|
||||
|
||||
if hasattr(Gui, "Snapper"):
|
||||
point = Gui.Snapper.snap(args["Position"],
|
||||
lastpoint=last,
|
||||
active=amod,
|
||||
constrain=cmod,
|
||||
noTracker=noTracker)
|
||||
info = Gui.Snapper.snapInfo
|
||||
mask = Gui.Snapper.affinity
|
||||
if not point:
|
||||
p = Gui.ActiveDocument.ActiveView.getCursorPos()
|
||||
point = Gui.ActiveDocument.ActiveView.getPoint(p)
|
||||
info = Gui.ActiveDocument.ActiveView.getObjectInfo(p)
|
||||
mask = None
|
||||
|
||||
ctrlPoint = App.Vector(point)
|
||||
if target.node:
|
||||
if target.featureName == "Rectangle":
|
||||
ui.displayPoint(point, target.node[0],
|
||||
plane=App.DraftWorkingPlane, mask=mask)
|
||||
else:
|
||||
ui.displayPoint(point, target.node[-1],
|
||||
plane=App.DraftWorkingPlane, mask=mask)
|
||||
else:
|
||||
ui.displayPoint(point, plane=App.DraftWorkingPlane, mask=mask)
|
||||
return point, ctrlPoint, info
|
||||
|
||||
|
||||
getPoint = get_point
|
||||
|
||||
|
||||
def set_working_plane_to_object_under_cursor(mouseEvent):
|
||||
"""Set the working plane to the object under the cursor.
|
||||
|
||||
It tests for an object under the cursor.
|
||||
If it is found, it checks whether a `'face'` or `'curve'` component
|
||||
is selected in the object's `Shape`.
|
||||
Then it tries to align the working plane to that face or curve.
|
||||
|
||||
The working plane is only aligned to the face if
|
||||
the working plane is not `'weak'`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mouseEvent: Coin event
|
||||
Coin event with the mouse, that is, a click.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
If no object was found in the 3D view under the cursor.
|
||||
Or if the working plane is not `weak`.
|
||||
Or if there was an exception with aligning the working plane
|
||||
to the component under the cursor.
|
||||
|
||||
Coin info
|
||||
The `getObjectInfo` of the object under the cursor.
|
||||
"""
|
||||
objectUnderCursor = gui_utils.get_3d_view().getObjectInfo((
|
||||
mouseEvent["Position"][0],
|
||||
mouseEvent["Position"][1]))
|
||||
|
||||
if not objectUnderCursor:
|
||||
return None
|
||||
|
||||
try:
|
||||
# Get the component "face" or "curve" under the "Shape"
|
||||
# of the selected object
|
||||
componentUnderCursor = getattr(
|
||||
App.ActiveDocument.getObject(objectUnderCursor['Object']).Shape,
|
||||
objectUnderCursor["Component"])
|
||||
|
||||
if not App.DraftWorkingPlane.weak:
|
||||
return None
|
||||
|
||||
if "Face" in objectUnderCursor["Component"]:
|
||||
App.DraftWorkingPlane.alignToFace(componentUnderCursor)
|
||||
else:
|
||||
App.DraftWorkingPlane.alignToCurve(componentUnderCursor)
|
||||
App.DraftWorkingPlane.weak = True
|
||||
return objectUnderCursor
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
setWorkingPlaneToObjectUnderCursor = set_working_plane_to_object_under_cursor
|
||||
|
||||
|
||||
def set_working_plane_to_selected_object():
|
||||
"""Set the working plane to the selected object's face.
|
||||
|
||||
The working plane is only aligned to the face if
|
||||
the working plane is `'weak'`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
If more than one object was selected.
|
||||
Or if the selected object has many subelements.
|
||||
Or if the single subelement is not a `'Face'`.
|
||||
|
||||
App::DocumentObject
|
||||
The single object that contains a single selected face.
|
||||
"""
|
||||
sel = Gui.Selection.getSelectionEx()
|
||||
if len(sel) != 1:
|
||||
return None
|
||||
sel = sel[0]
|
||||
if (sel.HasSubObjects
|
||||
and len(sel.SubElementNames) == 1
|
||||
and "Face" in sel.SubElementNames[0]):
|
||||
if App.DraftWorkingPlane.weak:
|
||||
App.DraftWorkingPlane.alignToFace(sel.SubObjects[0])
|
||||
App.DraftWorkingPlane.weak = True
|
||||
return sel.Object
|
||||
return None
|
||||
|
||||
|
||||
setWorkingPlaneToSelectedObject = set_working_plane_to_selected_object
|
||||
|
||||
|
||||
def get_support(mouseEvent=None):
|
||||
"""Return the supporting object and set the working plane.
|
||||
|
||||
It saves the current working plane, then sets it to the selected object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mouseEvent: Coin event, optional
|
||||
It defaults to `None`.
|
||||
Coin event with the mouse, that is, a click.
|
||||
|
||||
If there is a mouse event it calls
|
||||
`set_working_plane_to_object_under_cursor`.
|
||||
Otherwise, it calls `set_working_plane_to_selected_object`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
If there was a mouse event, but there was nothing under the cursor.
|
||||
Or if the working plane is not `weak`.
|
||||
Or if there was an exception with aligning the working plane
|
||||
to the component under the cursor.
|
||||
Or if more than one object was selected.
|
||||
Or if the selected object has many subelements.
|
||||
Or if the single subelement is not a `'Face'`.
|
||||
|
||||
Coin info
|
||||
If there was a mouse event, the `getObjectInfo`
|
||||
of the object under the cursor.
|
||||
|
||||
App::DocumentObject
|
||||
If there was no mouse event, the single selected object
|
||||
that contains the single selected face that was used
|
||||
to align the working plane.
|
||||
"""
|
||||
App.DraftWorkingPlane.save()
|
||||
if mouseEvent:
|
||||
return setWorkingPlaneToObjectUnderCursor(mouseEvent)
|
||||
return setWorkingPlaneToSelectedObject()
|
||||
|
||||
|
||||
getSupport = get_support
|
||||
|
||||
|
||||
def redraw_3d_view():
|
||||
"""Force a redraw of 3D view or do nothing if it fails."""
|
||||
try:
|
||||
Gui.ActiveDocument.ActiveView.redraw()
|
||||
except AttributeError as err:
|
||||
_wrn(err)
|
||||
|
||||
|
||||
redraw3DView = redraw_3d_view
|
||||
@@ -62,7 +62,7 @@ def make_label(targetpoint=None, target=None, direction=None,
|
||||
["Horizontal","Vertical","Custom"]
|
||||
|
||||
distance : Quantity
|
||||
Lenght of the straight segment of label leader line
|
||||
Length of the straight segment of label leader line
|
||||
|
||||
labeltype : String
|
||||
Label type in
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
"""Draft Statusbar commands.
|
||||
|
||||
This module provide the code for the Draft Statusbar, activated by initGui
|
||||
"""
|
||||
## @package init_draft_statusbar
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the code for the Draft Statusbar.
|
||||
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2020 Carlo Pavan <[email protected]> *
|
||||
@@ -29,12 +21,22 @@ This module provide the code for the Draft Statusbar, activated by initGui
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Draft Statusbar commands.
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
This module provide the code for the Draft Statusbar, activated by initGui
|
||||
"""
|
||||
## @package init_draft_statusbar
|
||||
# \ingroup DRAFT
|
||||
# \brief This module provides the code for the Draft Statusbar.
|
||||
|
||||
from PySide import QtCore
|
||||
from PySide import QtGui
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
|
||||
from draftutils.init_tools import get_draft_snap_commands
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# SCALE WIDGET FUNCTIONS
|
||||
@@ -124,7 +126,8 @@ def label_to_scale(label):
|
||||
return scale
|
||||
except:
|
||||
err = QT_TRANSLATE_NOOP("draft",
|
||||
"Unable to convert input into a scale factor")
|
||||
"Unable to convert input into a "
|
||||
"scale factor")
|
||||
App.Console.PrintWarning(err)
|
||||
return None
|
||||
|
||||
@@ -137,22 +140,25 @@ def _set_scale(action):
|
||||
|
||||
mw = Gui.getMainWindow()
|
||||
sb = mw.statusBar()
|
||||
statuswidget = sb.findChild(QtGui.QToolBar,"draft_status_widget")
|
||||
scale_widget = sb.findChild(QtGui.QToolBar,"draft_status_scale_widget")
|
||||
if action.text() == QT_TRANSLATE_NOOP("draft","custom"):
|
||||
dialog_text = QT_TRANSLATE_NOOP("draft",
|
||||
"Set custom annotation scale in format x:x, x=x"
|
||||
"Set custom annotation scale in "
|
||||
"format x:x, x=x"
|
||||
)
|
||||
custom_scale = QtGui.QInputDialog.getText(None, "Set custom scale", dialog_text)
|
||||
custom_scale = QtGui.QInputDialog.getText(None, "Set custom scale",
|
||||
dialog_text)
|
||||
if custom_scale[1]:
|
||||
print(custom_scale[0])
|
||||
scale = label_to_scale(custom_scale[0])
|
||||
if scale is None: return
|
||||
if scale is None:
|
||||
return
|
||||
param.SetFloat("DraftAnnotationScale", scale)
|
||||
cs = scale_to_label(scale)
|
||||
statuswidget.scaleLabel.setText(cs)
|
||||
scale_widget.scaleLabel.setText(cs)
|
||||
else:
|
||||
text_scale = action.text()
|
||||
statuswidget.scaleLabel.setText(text_scale)
|
||||
scale_widget.scaleLabel.setText(text_scale)
|
||||
scale = label_to_scale(text_scale)
|
||||
param.SetFloat("DraftAnnotationScale", scale)
|
||||
|
||||
@@ -164,21 +170,131 @@ def init_draft_statusbar(sb):
|
||||
"""
|
||||
this function initializes draft statusbar
|
||||
"""
|
||||
param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
|
||||
# SNAP WIDGET - init ----------------------------------------------------
|
||||
|
||||
statuswidget = QtGui.QToolBar()
|
||||
statuswidget.setObjectName("draft_status_widget")
|
||||
snap_widget = QtGui.QToolBar()
|
||||
snap_widget.setObjectName("draft_snap_widget")
|
||||
snap_widget.setIconSize(QtCore.QSize(16,16))
|
||||
|
||||
# GRID BUTTON - init
|
||||
gridbutton = QtGui.QPushButton(snap_widget)
|
||||
gridbutton.setIcon(QtGui.QIcon.fromTheme("Draft",
|
||||
QtGui.QIcon(":/icons/"
|
||||
"Draft_Grid.svg")))
|
||||
gridbutton.setToolTip(QT_TRANSLATE_NOOP("Draft",
|
||||
"Toggles Grid On/Off"))
|
||||
gridbutton.setObjectName("Grid_Statusbutton")
|
||||
gridbutton.setWhatsThis("Draft_ToggleGrid")
|
||||
gridbutton.setFlat(True)
|
||||
QtCore.QObject.connect(gridbutton,QtCore.SIGNAL("clicked()"),
|
||||
lambda f=Gui.doCommand,
|
||||
arg='Gui.runCommand("Draft_ToggleGrid")':f(arg))
|
||||
snap_widget.addWidget(gridbutton)
|
||||
|
||||
# SNAP BUTTON - init
|
||||
snappref = param.GetString("snapModes","111111111101111")[0]
|
||||
snapbutton = QtGui.QPushButton(snap_widget)
|
||||
snapbutton.setIcon(QtGui.QIcon.fromTheme("Draft",
|
||||
QtGui.QIcon(":/icons/"
|
||||
"Snap_Lock.svg")))
|
||||
snapbutton.setObjectName("Snap_Statusbutton")
|
||||
snapbutton.setWhatsThis("Draft_ToggleLockSnap")
|
||||
snapbutton.setToolTip(QT_TRANSLATE_NOOP("Draft",
|
||||
"Object snapping"))
|
||||
snapbutton.setCheckable(True)
|
||||
snapbutton.setChecked(bool(int(snappref)))
|
||||
snapbutton.setFlat(True)
|
||||
|
||||
snaps_menu = QtGui.QMenu(snapbutton)
|
||||
snaps_menu.setObjectName("draft_statusbar_snap_toolbar")
|
||||
|
||||
snap_gui_commands = get_draft_snap_commands()
|
||||
if 'Draft_Snap_Ortho' in snap_gui_commands:
|
||||
snap_gui_commands.remove('Draft_Snap_Ortho')
|
||||
if 'Draft_Snap_WorkingPlane' in snap_gui_commands:
|
||||
snap_gui_commands.remove('Draft_Snap_WorkingPlane')
|
||||
if 'Draft_Snap_Dimensions' in snap_gui_commands:
|
||||
snap_gui_commands.remove('Draft_Snap_Dimensions')
|
||||
Gui.Snapper.init_draft_snap_buttons(snap_gui_commands,snaps_menu, "_Statusbutton")
|
||||
Gui.Snapper.restore_snap_buttons_state(snaps_menu, "_Statusbutton")
|
||||
|
||||
snapbutton.setMenu(snaps_menu)
|
||||
snap_widget.addWidget(snapbutton)
|
||||
|
||||
|
||||
# DIMENSION BUTTON - init
|
||||
dimpref = param.GetString("snapModes","111111111101111")[13]
|
||||
dimbutton = QtGui.QPushButton(snap_widget)
|
||||
dimbutton.setIcon(QtGui.QIcon.fromTheme("Draft",
|
||||
QtGui.QIcon(":/icons/"
|
||||
"Snap_Dimensions.svg")))
|
||||
dimbutton.setToolTip(QT_TRANSLATE_NOOP("Draft",
|
||||
"Toggles Visual Aid Dimensions On/Off"))
|
||||
dimbutton.setObjectName("Draft_Snap_Dimensions_Statusbutton")
|
||||
dimbutton.setWhatsThis("Draft_ToggleDimensions")
|
||||
dimbutton.setFlat(True)
|
||||
dimbutton.setCheckable(True)
|
||||
dimbutton.setChecked(bool(int(dimpref)))
|
||||
QtCore.QObject.connect(dimbutton,QtCore.SIGNAL("clicked()"),
|
||||
lambda f=Gui.doCommand,
|
||||
arg='Gui.runCommand("Draft_Snap_Dimensions")':f(arg))
|
||||
snap_widget.addWidget(dimbutton)
|
||||
|
||||
# ORTHO BUTTON - init
|
||||
ortopref = param.GetString("snapModes","111111111101111")[10]
|
||||
orthobutton = QtGui.QPushButton(snap_widget)
|
||||
orthobutton.setIcon(QtGui.QIcon.fromTheme("Draft",
|
||||
QtGui.QIcon(":/icons/"
|
||||
"Snap_Ortho.svg")))
|
||||
orthobutton.setObjectName("Draft_Snap_Ortho"+"_Statusbutton")
|
||||
orthobutton.setWhatsThis("Draft_ToggleOrtho")
|
||||
orthobutton.setToolTip(QT_TRANSLATE_NOOP("Draft",
|
||||
"Toggles Ortho On/Off"))
|
||||
orthobutton.setFlat(True)
|
||||
orthobutton.setCheckable(True)
|
||||
orthobutton.setChecked(bool(int(ortopref)))
|
||||
QtCore.QObject.connect(orthobutton,QtCore.SIGNAL("clicked()"),
|
||||
lambda f=Gui.doCommand,
|
||||
arg='Gui.runCommand("Draft_Snap_Ortho")':f(arg))
|
||||
snap_widget.addWidget(orthobutton)
|
||||
|
||||
# WORKINGPLANE BUTTON - init
|
||||
wppref = param.GetString("snapModes","111111111101111")[14]
|
||||
wpbutton = QtGui.QPushButton(snap_widget)
|
||||
wpbutton.setIcon(QtGui.QIcon.fromTheme("Draft",
|
||||
QtGui.QIcon(":/icons/"
|
||||
"Snap_WorkingPlane.svg")))
|
||||
wpbutton.setObjectName("Draft_Snap_WorkingPlane_Statusbutton")
|
||||
wpbutton.setWhatsThis("Draft_ToggleWorkingPlaneSnap")
|
||||
wpbutton.setToolTip(QT_TRANSLATE_NOOP("Draft",
|
||||
"Toggles Constrain to Working Plane On/Off"))
|
||||
wpbutton.setFlat(True)
|
||||
wpbutton.setCheckable(True)
|
||||
wpbutton.setChecked(bool(int(wppref)))
|
||||
QtCore.QObject.connect(wpbutton,QtCore.SIGNAL("clicked()"),
|
||||
lambda f=Gui.doCommand,
|
||||
arg='Gui.runCommand("Draft_Snap_WorkingPlane")':f(arg))
|
||||
snap_widget.addWidget(wpbutton)
|
||||
|
||||
# add snap widget to the statusbar
|
||||
sb.insertPermanentWidget(2, snap_widget)
|
||||
snap_widget.show()
|
||||
|
||||
|
||||
# SCALE TOOL -------------------------------------------------------------
|
||||
# SCALE WIDGET ----------------------------------------------------------
|
||||
scale_widget = QtGui.QToolBar()
|
||||
scale_widget.setObjectName("draft_status_scale_widget")
|
||||
|
||||
# get scales list according to system units
|
||||
draft_scales = get_scales()
|
||||
|
||||
# get draft annotation scale
|
||||
param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
draft_annotation_scale = param.GetFloat("DraftAnnotationScale", 1.0)
|
||||
|
||||
# initializes scale widget
|
||||
statuswidget.draft_scales = draft_scales
|
||||
scale_widget.draft_scales = draft_scales
|
||||
scaleLabel = QtGui.QPushButton("Scale")
|
||||
scaleLabel.setObjectName("ScaleLabel")
|
||||
scaleLabel.setFlat(True)
|
||||
@@ -194,39 +310,70 @@ def init_draft_statusbar(sb):
|
||||
scaleLabel.setText(scale_label)
|
||||
tooltip = "Set the scale used by draft annotation tools"
|
||||
scaleLabel.setToolTip(QT_TRANSLATE_NOOP("draft",tooltip))
|
||||
statuswidget.addWidget(scaleLabel)
|
||||
statuswidget.scaleLabel = scaleLabel
|
||||
scale_widget.addWidget(scaleLabel)
|
||||
scale_widget.scaleLabel = scaleLabel
|
||||
|
||||
# ADD TOOLS TO STATUS BAR ------------------------------------------------
|
||||
sb.addPermanentWidget(statuswidget)
|
||||
statuswidget.show()
|
||||
# add scale widget to the statusbar
|
||||
sb.insertPermanentWidget(3, scale_widget)
|
||||
scale_widget.show()
|
||||
|
||||
def show_draft_statusbar():
|
||||
"""
|
||||
shows draft statusbar if present or initializes it
|
||||
"""
|
||||
params = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
display_statusbar = params.GetBool("DisplayStatusbar", True)
|
||||
|
||||
if not display_statusbar:
|
||||
return
|
||||
|
||||
mw = Gui.getMainWindow()
|
||||
if mw:
|
||||
sb = mw.statusBar()
|
||||
statuswidget = sb.findChild(QtGui.QToolBar,"draft_status_widget")
|
||||
if statuswidget:
|
||||
statuswidget.show()
|
||||
else:
|
||||
|
||||
scale_widget = sb.findChild(QtGui.QToolBar,
|
||||
"draft_status_scale_widget")
|
||||
if scale_widget:
|
||||
scale_widget.show()
|
||||
elif params.GetBool("DisplayStatusbarScaleWidget", True):
|
||||
init_draft_statusbar(sb)
|
||||
|
||||
snap_widget = sb.findChild(QtGui.QToolBar,"draft_snap_widget")
|
||||
if snap_widget:
|
||||
snap_widget.show()
|
||||
elif params.GetBool("DisplayStatusbarSnapWidget", True):
|
||||
init_draft_statusbar(sb)
|
||||
|
||||
|
||||
def hide_draft_statusbar():
|
||||
"""
|
||||
hides draft statusbar if present
|
||||
"""
|
||||
mw = Gui.getMainWindow()
|
||||
if mw:
|
||||
sb = mw.statusBar()
|
||||
statuswidget = sb.findChild(QtGui.QToolBar,"draft_status_widget")
|
||||
if statuswidget:
|
||||
statuswidget.hide()
|
||||
else:
|
||||
# when switching workbenches, the toolbar sometimes "jumps"
|
||||
# out of the status bar to any other dock area...
|
||||
statuswidget = mw.findChild(QtGui.QToolBar,"draft_status_widget")
|
||||
if statuswidget:
|
||||
statuswidget.hide()
|
||||
if not mw:
|
||||
return
|
||||
sb = mw.statusBar()
|
||||
|
||||
# hide scale widget
|
||||
scale_widget = sb.findChild(QtGui.QToolBar,
|
||||
"draft_status_scale_widget")
|
||||
if scale_widget:
|
||||
scale_widget.hide()
|
||||
else:
|
||||
# when switching workbenches, the toolbar sometimes "jumps"
|
||||
# out of the status bar to any other dock area...
|
||||
scale_widget = mw.findChild(QtGui.QToolBar,
|
||||
"draft_status_scale_widget")
|
||||
if scale_widget:
|
||||
scale_widget.hide()
|
||||
|
||||
# hide snap widget
|
||||
snap_widget = sb.findChild(QtGui.QToolBar,"draft_snap_widget")
|
||||
if snap_widget:
|
||||
snap_widget.hide()
|
||||
else:
|
||||
# when switching workbenches, the toolbar sometimes "jumps"
|
||||
# out of the status bar to any other dock area...
|
||||
snap_widget = mw.findChild(QtGui.QToolBar,"draft_snap_widget")
|
||||
if snap_widget:
|
||||
snap_widget.hide()
|
||||
@@ -116,15 +116,15 @@ def get_draft_utility_commands():
|
||||
|
||||
def get_draft_snap_commands():
|
||||
"""Return the snapping commands list."""
|
||||
return ['Draft_Snap_Lock', 'Draft_Snap_Midpoint',
|
||||
'Draft_Snap_Perpendicular',
|
||||
'Draft_Snap_Grid', 'Draft_Snap_Intersection',
|
||||
'Draft_Snap_Parallel',
|
||||
'Draft_Snap_Endpoint', 'Draft_Snap_Angle',
|
||||
'Draft_Snap_Center',
|
||||
'Draft_Snap_Extension', 'Draft_Snap_Near',
|
||||
'Draft_Snap_Ortho', 'Draft_Snap_Special',
|
||||
'Draft_Snap_Dimensions', 'Draft_Snap_WorkingPlane']
|
||||
return ['Draft_Snap_Lock',
|
||||
'Draft_Snap_Endpoint', 'Draft_Snap_Midpoint',
|
||||
'Draft_Snap_Center', 'Draft_Snap_Angle',
|
||||
'Draft_Snap_Intersection', 'Draft_Snap_Perpendicular',
|
||||
'Draft_Snap_Extension', 'Draft_Snap_Parallel',
|
||||
'Draft_Snap_Special', 'Draft_Snap_Near',
|
||||
'Draft_Snap_Ortho', 'Draft_Snap_Grid',
|
||||
'Draft_Snap_WorkingPlane', 'Draft_Snap_Dimensions',
|
||||
]
|
||||
|
||||
|
||||
def init_draft_toolbars(workbench):
|
||||
|
||||
@@ -225,6 +225,10 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
|
||||
def attach(self, vobj):
|
||||
'''Setup the scene sub-graph of the view provider'''
|
||||
|
||||
# backwards compatibility
|
||||
self.ScaleMultiplier = 1.00
|
||||
|
||||
self.Object = vobj.Object
|
||||
self.color = coin.SoBaseColor()
|
||||
self.font = coin.SoFont()
|
||||
@@ -341,8 +345,8 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
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 hasattr(obj.ViewObject,"ExtLines"):
|
||||
dmax = obj.ViewObject.ExtLines.Value * self.ScaleMultiplier
|
||||
if dmax and (proj.Length > dmax):
|
||||
if (dmax > 0):
|
||||
self.p1 = self.p2.add(DraftVecUtils.scaleTo(proj,dmax))
|
||||
@@ -402,8 +406,8 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
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
|
||||
if hasattr(obj.ViewObject,"TextSpacing"):
|
||||
ts = obj.ViewObject.TextSpacing.Value * self.ScaleMultiplier
|
||||
offset = DraftVecUtils.scaleTo(v1,ts)
|
||||
else:
|
||||
offset = DraftVecUtils.scaleTo(v1,0.05)
|
||||
@@ -474,11 +478,13 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
def onChanged(self, vobj, prop):
|
||||
"""called when a view property has changed"""
|
||||
if prop == "ScaleMultiplier" and hasattr(vobj,"ScaleMultiplier"):
|
||||
if vobj.ScaleMultiplier: # don't set if zero
|
||||
self.ScaleMultiplier = vobj.ScaleMultiplier
|
||||
# update all dimension values
|
||||
if hasattr(self,"font"):
|
||||
self.font.size = vobj.FontSize.Value*vobj.ScaleMultiplier
|
||||
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
|
||||
if hasattr(self,"font3d"):
|
||||
self.font3d.size = vobj.FontSize.Value*100*vobj.ScaleMultiplier
|
||||
self.font3d.size = vobj.FontSize.Value * 100 * self.ScaleMultiplier
|
||||
if hasattr(self,"node") and hasattr(self,"p2") and hasattr(vobj,"ArrowSize"):
|
||||
self.remove_dim_arrows()
|
||||
self.draw_dim_arrows(vobj)
|
||||
@@ -492,10 +498,10 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
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
|
||||
if hasattr(self,"font"):
|
||||
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
|
||||
if hasattr(self,"font3d"):
|
||||
self.font3d.size = vobj.FontSize.Value * 100 * self.ScaleMultiplier
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "FontName") and hasattr(vobj,"FontName"):
|
||||
@@ -514,22 +520,19 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
|
||||
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()
|
||||
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()
|
||||
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()
|
||||
self.remove_ext_overshoot()
|
||||
self.draw_ext_overshoot(vobj)
|
||||
vobj.Object.touch()
|
||||
|
||||
elif (prop == "ShowLine") and hasattr(vobj,"ShowLine"):
|
||||
if vobj.ShowLine:
|
||||
@@ -559,7 +562,7 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
|
||||
# set scale
|
||||
symbol = utils.ARROW_TYPES.index(vobj.ArrowType)
|
||||
s = vobj.ArrowSize.Value * vobj.ScaleMultiplier
|
||||
s = vobj.ArrowSize.Value * self.ScaleMultiplier
|
||||
self.trans1.scaleFactor.setValue((s,s,s))
|
||||
self.trans2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
@@ -593,7 +596,7 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
from pivy import coin
|
||||
|
||||
# set scale
|
||||
s = vobj.DimOvershoot.Value * vobj.ScaleMultiplier
|
||||
s = vobj.DimOvershoot.Value * self.ScaleMultiplier
|
||||
self.transDimOvershoot1.scaleFactor.setValue((s,s,s))
|
||||
self.transDimOvershoot2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
@@ -624,7 +627,7 @@ class ViewProviderLinearDimension(ViewProviderDimensionBase):
|
||||
from pivy import coin
|
||||
|
||||
# set scale
|
||||
s = vobj.ExtOvershoot.Value * vobj.ScaleMultiplier
|
||||
s = vobj.ExtOvershoot.Value * self.ScaleMultiplier
|
||||
self.transExtOvershoot1.scaleFactor.setValue((s,s,s))
|
||||
self.transExtOvershoot2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
@@ -728,6 +731,8 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
|
||||
self.onChanged(vobj,"FontName")
|
||||
self.onChanged(vobj,"ArrowType")
|
||||
self.onChanged(vobj,"LineColor")
|
||||
# backwards compatibility
|
||||
self.ScaleMultiplier = 1.00
|
||||
|
||||
def updateData(self, obj, prop):
|
||||
if hasattr(self,"arc"):
|
||||
@@ -853,21 +858,23 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
|
||||
|
||||
def onChanged(self, vobj, prop):
|
||||
if prop == "ScaleMultiplier" and hasattr(vobj,"ScaleMultiplier"):
|
||||
if vobj.ScaleMultiplier:
|
||||
self.ScaleMultiplier = vobj.ScaleMultiplier
|
||||
# update all dimension values
|
||||
if hasattr(self,"font"):
|
||||
self.font.size = vobj.FontSize.Value*vobj.ScaleMultiplier
|
||||
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
|
||||
if hasattr(self,"font3d"):
|
||||
self.font3d.size = vobj.FontSize.Value*100*vobj.ScaleMultiplier
|
||||
self.font3d.size = vobj.FontSize.Value * 100 * self.ScaleMultiplier
|
||||
if hasattr(self,"node") and hasattr(self,"p2") and hasattr(vobj,"ArrowSize"):
|
||||
self.remove_dim_arrows()
|
||||
self.draw_dim_arrows(vobj)
|
||||
self.updateData(vobj.Object,"Start")
|
||||
vobj.Object.touch()
|
||||
elif prop == "FontSize" and hasattr(vobj,"ScaleMultiplier"):
|
||||
elif prop == "FontSize":
|
||||
if hasattr(self,"font"):
|
||||
self.font.size = vobj.FontSize.Value*vobj.ScaleMultiplier
|
||||
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
|
||||
if hasattr(self,"font3d"):
|
||||
self.font3d.size = vobj.FontSize.Value*100*vobj.ScaleMultiplier
|
||||
self.font3d.size = vobj.FontSize.Value * 100 * self.ScaleMultiplier
|
||||
vobj.Object.touch()
|
||||
elif prop == "FontName":
|
||||
if hasattr(self,"font") and hasattr(self,"font3d"):
|
||||
@@ -880,7 +887,7 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
|
||||
elif prop == "LineWidth":
|
||||
if hasattr(self,"drawstyle"):
|
||||
self.drawstyle.lineWidth = vobj.LineWidth
|
||||
elif prop in ["ArrowSize","ArrowType"] and hasattr(vobj,"ScaleMultiplier"):
|
||||
elif prop in ["ArrowSize","ArrowType"]:
|
||||
if hasattr(self,"node") and hasattr(self,"p2"):
|
||||
self.remove_dim_arrows()
|
||||
self.draw_dim_arrows(vobj)
|
||||
@@ -901,7 +908,7 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
|
||||
|
||||
# set scale
|
||||
symbol = utils.ARROW_TYPES.index(vobj.ArrowType)
|
||||
s = vobj.ArrowSize.Value * vobj.ScaleMultiplier
|
||||
s = vobj.ArrowSize.Value * self.ScaleMultiplier
|
||||
self.trans1.scaleFactor.setValue((s,s,s))
|
||||
self.trans2.scaleFactor.setValue((s,s,s))
|
||||
|
||||
@@ -926,4 +933,4 @@ class ViewProviderAngularDimension(ViewProviderDimensionBase):
|
||||
self.node3d.insertChild(self.marks,2)
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/Draft_DimensionAngular.svg"
|
||||
return ":/icons/Draft_DimensionAngular.svg"
|
||||
|
||||
@@ -54,10 +54,6 @@ class ViewProviderText(ViewProviderDraftAnnotation):
|
||||
|
||||
def set_properties(self, vobj):
|
||||
|
||||
vobj.addProperty("App::PropertyFloat","ScaleMultiplier",
|
||||
"Annotation",QT_TRANSLATE_NOOP("App::Property",
|
||||
"Dimension size overall multiplier"))
|
||||
|
||||
vobj.addProperty("App::PropertyLength","FontSize",
|
||||
"Text",QT_TRANSLATE_NOOP("App::Property",
|
||||
"The size of the text"))
|
||||
@@ -93,6 +89,10 @@ class ViewProviderText(ViewProviderDraftAnnotation):
|
||||
|
||||
def attach(self,vobj):
|
||||
'''Setup the scene sub-graph of the view provider'''
|
||||
|
||||
# backwards compatibility
|
||||
self.ScaleMultiplier = 1.00
|
||||
|
||||
self.mattext = coin.SoMaterial()
|
||||
textdrawstyle = coin.SoDrawStyle()
|
||||
textdrawstyle.style = coin.SoDrawStyle.FILLED
|
||||
@@ -123,7 +123,6 @@ class ViewProviderText(ViewProviderDraftAnnotation):
|
||||
self.onChanged(vobj,"Justification")
|
||||
self.onChanged(vobj,"LineSpacing")
|
||||
|
||||
|
||||
def getDisplayModes(self,vobj):
|
||||
return ["2D text","3D text"]
|
||||
|
||||
@@ -148,8 +147,11 @@ class ViewProviderText(ViewProviderDraftAnnotation):
|
||||
|
||||
def onChanged(self,vobj,prop):
|
||||
if prop == "ScaleMultiplier":
|
||||
if "ScaleMultiplier" in vobj.PropertiesList and "FontSize" in vobj.PropertiesList:
|
||||
self.font.size = vobj.FontSize.Value * vobj.ScaleMultiplier
|
||||
if "ScaleMultiplier" in vobj.PropertiesList:
|
||||
if vobj.ScaleMultiplier:
|
||||
self.ScaleMultiplier = vobj.ScaleMultiplier
|
||||
if "FontSize" in vobj.PropertiesList:
|
||||
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
|
||||
elif prop == "TextColor":
|
||||
if "TextColor" in vobj.PropertiesList:
|
||||
l = vobj.TextColor
|
||||
@@ -158,8 +160,8 @@ class ViewProviderText(ViewProviderDraftAnnotation):
|
||||
if "FontName" in vobj.PropertiesList:
|
||||
self.font.name = vobj.FontName.encode("utf8")
|
||||
elif prop == "FontSize":
|
||||
if "FontSize" in vobj.PropertiesList and "ScaleMultiplier" in vobj.PropertiesList:
|
||||
self.font.size = vobj.FontSize.Value * vobj.ScaleMultiplier
|
||||
if "FontSize" in vobj.PropertiesList:
|
||||
self.font.size = vobj.FontSize.Value * self.ScaleMultiplier
|
||||
elif prop == "Justification":
|
||||
try:
|
||||
if getattr(vobj, "Justification", None) is not None:
|
||||
@@ -177,4 +179,4 @@ class ViewProviderText(ViewProviderDraftAnnotation):
|
||||
elif prop == "LineSpacing":
|
||||
if "LineSpacing" in vobj.PropertiesList:
|
||||
self.text2d.spacing = vobj.LineSpacing
|
||||
self.text3d.spacing = vobj.LineSpacing
|
||||
self.text3d.spacing = vobj.LineSpacing
|
||||
|
||||
@@ -485,7 +485,7 @@ def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direct
|
||||
svg += getPath(obj.Edges,pathname="")
|
||||
|
||||
|
||||
elif getType(obj) == "Dimension":
|
||||
elif getType(obj) in ["Dimension","LinearDimension"]:
|
||||
if gui:
|
||||
if not obj.ViewObject:
|
||||
print ("export of dimensions to SVG is only available in GUI mode")
|
||||
|
||||
@@ -3817,7 +3817,7 @@ def export(objectslist, filename, nospline=False, lwPoly=False):
|
||||
style='STANDARD',
|
||||
layer=getStrGroup(ob)))
|
||||
|
||||
elif Draft.getType(ob) == "Dimension":
|
||||
elif Draft.getType(ob) in ["Dimension","LinearDimension"]:
|
||||
p1 = DraftVecUtils.tup(ob.Start)
|
||||
p2 = DraftVecUtils.tup(ob.End)
|
||||
base = Part.LineSegment(ob.Start, ob.End).toShape()
|
||||
|
||||
@@ -1526,7 +1526,7 @@ class svgHandler(xml.sax.ContentHandler):
|
||||
# see issue #2062
|
||||
sh = sh.transformGeometry(transform)
|
||||
return sh
|
||||
elif Draft.getType(sh) == "Dimension":
|
||||
elif Draft.getType(sh) in ["Dimension","LinearDimension"]:
|
||||
pts = []
|
||||
for p in [sh.Start, sh.End, sh.Dimline]:
|
||||
cp = Vector(p)
|
||||
|
||||
@@ -703,6 +703,8 @@ def get_displacement_scale_factor(res_obj):
|
||||
z_span = abs(p_z_max - p_z_min)
|
||||
span = max(x_span, y_span, z_span)
|
||||
max_disp = max(x_max, y_max, z_max)
|
||||
if max_disp == 0.0:
|
||||
return 0.0 # avoid float division by zero
|
||||
# FIXME - add max_allowed_disp to Preferences
|
||||
max_allowed_disp = 0.01 * span
|
||||
scale = max_allowed_disp / max_disp
|
||||
|
||||
@@ -1426,6 +1426,7 @@ def build_mesh_faces_of_volume_elements(
|
||||
FreeCAD.Console.PrintLog("VolElement: {}\n".format(veID))
|
||||
vol_node_ct = len(femelement_table[veID])
|
||||
face_node_indexs = sorted(face_nodenumber_table[veID])
|
||||
node_numbers = ()
|
||||
if vol_node_ct == 10:
|
||||
FreeCAD.Console.PrintLog(" --> tetra10 --> tria6 face\n")
|
||||
# node order of face in tetra10 volume element
|
||||
@@ -1441,7 +1442,7 @@ def build_mesh_faces_of_volume_elements(
|
||||
else:
|
||||
FreeCAD.Console.PrintError(
|
||||
"Error in build_mesh_faces_of_volume_elements(): "
|
||||
"hexa20: face not found! {}\n"
|
||||
"tetra10: face not found! {}\n"
|
||||
.format(face_node_indexs)
|
||||
)
|
||||
elif vol_node_ct == 4:
|
||||
@@ -1459,7 +1460,7 @@ def build_mesh_faces_of_volume_elements(
|
||||
else:
|
||||
FreeCAD.Console.PrintError(
|
||||
"Error in build_mesh_faces_of_volume_elements(): "
|
||||
"hexa20: face not found! {}\n"
|
||||
"tetra4: face not found! {}\n"
|
||||
.format(face_node_indexs)
|
||||
)
|
||||
elif vol_node_ct == 20:
|
||||
@@ -1503,7 +1504,7 @@ def build_mesh_faces_of_volume_elements(
|
||||
else:
|
||||
FreeCAD.Console.PrintError(
|
||||
"Error in build_mesh_faces_of_volume_elements(): "
|
||||
"hexa20: face not found! {}\n"
|
||||
"hexa8: face not found! {}\n"
|
||||
.format(face_node_indexs)
|
||||
)
|
||||
elif vol_node_ct == 15:
|
||||
@@ -1543,7 +1544,7 @@ def build_mesh_faces_of_volume_elements(
|
||||
else:
|
||||
FreeCAD.Console.PrintError(
|
||||
"Error in build_mesh_faces_of_volume_elements(): "
|
||||
"pent6: face not found! {}\n"
|
||||
"penta6: face not found! {}\n"
|
||||
.format(face_node_indexs)
|
||||
)
|
||||
else:
|
||||
|
||||
@@ -469,7 +469,7 @@ an empty dictionary if there is no intersection.
|
||||
<UserDocu>getPlanarSegments(dev,[min faces=0]) -> list
|
||||
Get all planes of the mesh as segment.
|
||||
In the worst case each triangle can be regarded as single
|
||||
plane if none of its neighours is coplanar.</UserDocu>
|
||||
plane if none of its neighbors are coplanar.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getSegmentsOfType" Const="true">
|
||||
|
||||
@@ -750,7 +750,7 @@ private:
|
||||
p1.Transform(loc.Transformation());
|
||||
p2.Transform(loc.Transformation());
|
||||
p3.Transform(loc.Transformation());
|
||||
// TODO: verify if tolerence should be hard coded
|
||||
// TODO: verify if tolerance should be hard coded
|
||||
if (!p1.IsEqual(p2, 0.01) && !p2.IsEqual(p3, 0.01) && !p3.IsEqual(p1, 0.01)) {
|
||||
PyObject *t1 = PyTuple_Pack(3, PyFloat_FromDouble(p1.X()), PyFloat_FromDouble(p1.Y()), PyFloat_FromDouble(p1.Z()));
|
||||
PyObject *t2 = PyTuple_Pack(3, PyFloat_FromDouble(p2.X()), PyFloat_FromDouble(p2.Y()), PyFloat_FromDouble(p2.Z()));
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
<property name="toolTip">
|
||||
<string>The default color for new shapes</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>204</red>
|
||||
<green>204</green>
|
||||
@@ -89,7 +89,7 @@
|
||||
<property name="toolTip">
|
||||
<string>The default line color for new shapes</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>25</red>
|
||||
<green>25</green>
|
||||
@@ -157,7 +157,7 @@
|
||||
<property name="toolTip">
|
||||
<string>The default color for new vertices</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>25</red>
|
||||
<green>25</green>
|
||||
@@ -225,7 +225,7 @@
|
||||
<property name="toolTip">
|
||||
<string>The color of bounding boxes in the 3D view</string>
|
||||
</property>
|
||||
<property name="color" stdset="0">
|
||||
<property name="color">
|
||||
<color>
|
||||
<red>255</red>
|
||||
<green>255</green>
|
||||
@@ -248,6 +248,12 @@
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Bottom side of surface will be rendered the same way than top.
|
||||
If not checked, it depends on the option "Backlight color"
|
||||
(preferences section Display -> 3D View); either the backlight color
|
||||
will be used or black.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Two-side rendering</string>
|
||||
</property>
|
||||
@@ -303,6 +309,9 @@
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefColorButton" name="AnnotationTextColor">
|
||||
<property name="toolTip">
|
||||
<string>Text color for document annotations</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>AnnotationTextColor</cstring>
|
||||
</property>
|
||||
|
||||
@@ -16,6 +16,8 @@ if(BUILD_GUI)
|
||||
TestPartDesignGui.py
|
||||
InvoluteGearFeature.py
|
||||
InvoluteGearFeature.ui
|
||||
SprocketFeature.py
|
||||
SprocketFeature.ui
|
||||
)
|
||||
endif(BUILD_GUI)
|
||||
|
||||
@@ -60,6 +62,13 @@ set(PartDesign_GearScripts
|
||||
fcgear/svggear.py
|
||||
)
|
||||
|
||||
set(PartDesign_SprocketScripts
|
||||
fcsprocket/__init__.py
|
||||
fcsprocket/fcsprocket.py
|
||||
fcsprocket/fcsprocketdialog.py
|
||||
fcsprocket/sprocket.py
|
||||
)
|
||||
|
||||
set(PartDesign_WizardShaft
|
||||
WizardShaft/__init__.py
|
||||
WizardShaft/WizardShaft.svg
|
||||
@@ -76,6 +85,7 @@ add_custom_target(PartDesignScripts ALL SOURCES
|
||||
${PartDesign_OtherScripts}
|
||||
${PartDesign_TestScripts}
|
||||
${PartDesign_GearScripts}
|
||||
${PartDesign_SprocketScripts}
|
||||
)
|
||||
|
||||
fc_target_copy_resource(PartDesignScripts
|
||||
@@ -85,6 +95,7 @@ fc_target_copy_resource(PartDesignScripts
|
||||
${PartDesign_OtherScripts}
|
||||
${PartDesign_TestScripts}
|
||||
${PartDesign_GearScripts}
|
||||
${PartDesign_SprocketScripts}
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
@@ -113,7 +124,13 @@ INSTALL(
|
||||
${PartDesign_GearScripts}
|
||||
DESTINATION
|
||||
Mod/PartDesign/fcgear
|
||||
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${PartDesign_SprocketScripts}
|
||||
DESTINATION
|
||||
Mod/PartDesign/fcsprocket
|
||||
)
|
||||
|
||||
if(BUILD_FEM)
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<file>icons/PartDesign_Revolution.svg</file>
|
||||
<file>icons/PartDesign_Scaled.svg</file>
|
||||
<file>icons/PartDesign_ShapeBinder.svg</file>
|
||||
<file>icons/PartDesign_Sprocket.svg</file>
|
||||
<file>icons/PartDesign_SubShapeBinder.svg</file>
|
||||
<file>icons/PartDesign_Subtractive_Box.svg</file>
|
||||
<file>icons/PartDesign_Subtractive_Cone.svg</file>
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 89 KiB |
@@ -509,9 +509,10 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
<< "PartDesign_Boolean"
|
||||
<< "Separator"
|
||||
//<< "PartDesign_Hole"
|
||||
<< "PartDesign_InvoluteGear"
|
||||
<< "Separator"
|
||||
<< "PartDesign_Migrate";
|
||||
<< "PartDesign_Migrate"
|
||||
<< "PartDesign_Sprocket"
|
||||
<< "PartDesign_InvoluteGear";
|
||||
|
||||
|
||||
// For 0.13 a couple of python packages like numpy, matplotlib and others
|
||||
// are not deployed with the installer on Windows. Thus, the WizardShaft is
|
||||
|
||||
@@ -51,6 +51,7 @@ class PartDesignWorkbench ( Workbench ):
|
||||
import PartDesign
|
||||
try:
|
||||
from PartDesign import InvoluteGearFeature
|
||||
from PartDesign import SprocketFeature
|
||||
except ImportError:
|
||||
print("Involute gear module cannot be loaded")
|
||||
#try:
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2020 Adam Spontarelli <[email protected]> *
|
||||
#* *
|
||||
#* 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. *
|
||||
#* *
|
||||
#* This program 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 this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD, Part
|
||||
from fcsprocket import fcsprocket
|
||||
from fcsprocket import sprocket
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from FreeCADGui import PySideUic as uic
|
||||
|
||||
__title__="PartDesign SprocketObject management"
|
||||
__author__ = "Adam Spontarelli"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
def makeSprocket(name):
|
||||
"""
|
||||
makeSprocket(name): makes a Sprocket
|
||||
"""
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",name)
|
||||
Sprocket(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
ViewProviderSprocket(obj.ViewObject)
|
||||
#FreeCAD.ActiveDocument.recompute()
|
||||
if FreeCAD.GuiUp:
|
||||
body=FreeCADGui.ActiveDocument.ActiveView.getActiveObject("pdbody")
|
||||
part=FreeCADGui.ActiveDocument.ActiveView.getActiveObject("part")
|
||||
if body:
|
||||
body.Group=body.Group+[obj]
|
||||
elif part:
|
||||
part.Group=part.Group+[obj]
|
||||
return obj
|
||||
|
||||
class CommandSprocket:
|
||||
|
||||
"""
|
||||
the Fem Sprocket command definition
|
||||
"""
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'PartDesign_Sprocket',
|
||||
'MenuText': QtCore.QT_TRANSLATE_NOOP("PartDesign_Sprocket","Sprocket..."),
|
||||
'Accel': "",
|
||||
'ToolTip': QtCore.QT_TRANSLATE_NOOP("PartDesign_Sprocket","Creates or edit the sprocket definition.")}
|
||||
|
||||
def Activated(self):
|
||||
|
||||
FreeCAD.ActiveDocument.openTransaction("Create Sprocket")
|
||||
FreeCADGui.addModule("SprocketFeature")
|
||||
FreeCADGui.doCommand("SprocketFeature.makeSprocket('Sprocket')")
|
||||
FreeCADGui.doCommand("Gui.activeDocument().setEdit(App.ActiveDocument.ActiveObject.Name,0)")
|
||||
|
||||
def IsActive(self):
|
||||
if FreeCAD.ActiveDocument:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Sprocket:
|
||||
"""
|
||||
The Sprocket object
|
||||
"""
|
||||
|
||||
def __init__(self,obj):
|
||||
self.Type = "Sprocket"
|
||||
obj.addProperty("App::PropertyInteger","NumberOfTeeth","Sprocket","Number of gear teeth")
|
||||
obj.addProperty("App::PropertyLength","Pitch","Sprocket","Chain Pitch")
|
||||
obj.addProperty("App::PropertyLength","RollerDiameter","Sprocket","Roller Diameter")
|
||||
obj.addProperty("App::PropertyString","ANSISize","Sprocket","ANSI Size")
|
||||
|
||||
obj.NumberOfTeeth = 50
|
||||
obj.Pitch = "0.375 in"
|
||||
obj.RollerDiameter = "0.20 in"
|
||||
obj.ANSISize = "35"
|
||||
|
||||
obj.Proxy = self
|
||||
|
||||
|
||||
def execute(self,obj):
|
||||
w = fcsprocket.FCWireBuilder()
|
||||
sprocket.CreateSprocket(w, obj.Pitch.Value, obj.NumberOfTeeth, obj.RollerDiameter.Value)
|
||||
|
||||
sprocketw = Part.Wire([o.toShape() for o in w.wire])
|
||||
obj.Shape = sprocketw
|
||||
obj.positionBySupport();
|
||||
return
|
||||
|
||||
|
||||
class ViewProviderSprocket:
|
||||
"""
|
||||
A View Provider for the Sprocket object
|
||||
"""
|
||||
|
||||
def __init__(self,vobj):
|
||||
vobj.Proxy = self
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/PartDesign_Sprocket.svg"
|
||||
|
||||
def attach(self, vobj):
|
||||
self.ViewObject = vobj
|
||||
self.Object = vobj.Object
|
||||
|
||||
def setEdit(self,vobj,mode):
|
||||
taskd = SprocketTaskPanel(self.Object,mode)
|
||||
taskd.obj = vobj.Object
|
||||
taskd.update()
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
return True
|
||||
|
||||
def unsetEdit(self,vobj,mode):
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return
|
||||
|
||||
def __getstate__(self):
|
||||
return None
|
||||
|
||||
def __setstate__(self,state):
|
||||
return None
|
||||
|
||||
|
||||
class SprocketTaskPanel:
|
||||
"""
|
||||
The editmode TaskPanel for Sprocket objects
|
||||
"""
|
||||
|
||||
def __init__(self,obj,mode):
|
||||
self.obj = obj
|
||||
|
||||
self.form=FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/PartDesign/SprocketFeature.ui")
|
||||
self.form.setWindowIcon(QtGui.QIcon(":/icons/PartDesign_Sprocket.svg"))
|
||||
|
||||
QtCore.QObject.connect(self.form.Quantity_Pitch, QtCore.SIGNAL("valueChanged(double)"), self.pitchChanged)
|
||||
QtCore.QObject.connect(self.form.Quantity_RollerDiameter, QtCore.SIGNAL("valueChanged(double)"), self.rollerDiameterChanged)
|
||||
QtCore.QObject.connect(self.form.spinBox_NumberOfTeeth, QtCore.SIGNAL("valueChanged(int)"), self.numTeethChanged)
|
||||
QtCore.QObject.connect(self.form.comboBox_ANSISize, QtCore.SIGNAL("currentTextChanged(const QString)"), self.ANSISizeChanged)
|
||||
|
||||
self.update()
|
||||
|
||||
if mode == 0: # fresh created
|
||||
self.obj.Proxy.execute(self.obj) # calculate once
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def transferTo(self):
|
||||
"""
|
||||
Transfer from the dialog to the object
|
||||
"""
|
||||
self.obj.NumberOfTeeth = self.form.spinBox_NumberOfTeeth.value()
|
||||
self.obj.Pitch = self.form.Quantity_Pitch.text()
|
||||
self.obj.RollerDiameter = self.form.Quantity_RollerDiameter.text()
|
||||
self.obj.ANSISize = self.form.comboBox_ANSISize.currentText()
|
||||
|
||||
def transferFrom(self):
|
||||
"""
|
||||
Transfer from the object to the dialog
|
||||
"""
|
||||
self.form.spinBox_NumberOfTeeth.setValue(self.obj.NumberOfTeeth)
|
||||
self.form.Quantity_Pitch.setText(self.obj.Pitch.UserString)
|
||||
self.form.Quantity_RollerDiameter.setText(self.obj.RollerDiameter.UserString)
|
||||
self.form.comboBox_ANSISize.setCurrentText(self.obj.ANSISize)
|
||||
|
||||
def pitchChanged(self, value):
|
||||
self.obj.Pitch = value
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def ANSISizeChanged(self, size):
|
||||
"""
|
||||
ANSI B29.1-2011 standard roller chain sizes in USCS units (inches)
|
||||
{size: [Pitch, Roller Diameter]}
|
||||
"""
|
||||
ANSIRollerTable = {"25": [0.250, 0.130],
|
||||
"35": [0.375, 0.200],
|
||||
"41": [0.500, 0.306],
|
||||
"40": [0.500, 0.312],
|
||||
"50": [0.625, 0.400],
|
||||
"60": [0.750, 0.469],
|
||||
"80": [1.000, 0.625],
|
||||
"100":[1.250, 0.750],
|
||||
"120":[1.500, 0.875],
|
||||
"140":[1.750, 1.000],
|
||||
"160":[2.000, 1.125],
|
||||
"180":[2.250, 1.460],
|
||||
"200":[2.500, 1.562],
|
||||
"240":[3.000, 1.875]}
|
||||
|
||||
self.obj.Pitch = str(ANSIRollerTable[size][0]) + " in"
|
||||
self.obj.RollerDiameter = str(ANSIRollerTable[size][1]) + " in"
|
||||
self.form.Quantity_Pitch.setText(self.obj.Pitch.UserString)
|
||||
self.form.Quantity_RollerDiameter.setText(self.obj.RollerDiameter.UserString)
|
||||
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def rollerDiameterChanged(self, value):
|
||||
self.obj.RollerDiameter = value
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def numTeethChanged(self, value):
|
||||
self.obj.NumberOfTeeth = value
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||
|
||||
def getStandardButtons(self):
|
||||
return int(QtGui.QDialogButtonBox.Ok) | int(QtGui.QDialogButtonBox.Cancel)| int(QtGui.QDialogButtonBox.Apply)
|
||||
|
||||
def clicked(self,button):
|
||||
if button == QtGui.QDialogButtonBox.Apply:
|
||||
self.transferTo()
|
||||
self.obj.Proxy.execute(self.obj)
|
||||
|
||||
def update(self):
|
||||
self.transferFrom()
|
||||
|
||||
def accept(self):
|
||||
self.transferTo()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
|
||||
def reject(self):
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
FreeCAD.ActiveDocument.abortTransaction()
|
||||
|
||||
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('PartDesign_Sprocket', CommandSprocket())
|
||||
@@ -0,0 +1,232 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SprocketParameter</class>
|
||||
<widget class="QWidget" name="SprocketParameter">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>195</width>
|
||||
<height>142</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Sprocket parameter</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Number of teeth:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_NumberOfTeeth">
|
||||
<property name="minimum">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>ANSI Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboBox_ANSISize">
|
||||
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>25</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>35</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>41</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>40</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>50</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>60</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>80</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>100</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>120</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>140</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>160</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>180</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>200</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>240</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="2" column="0">
|
||||
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Chain Pitch:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="2" column="1">
|
||||
|
||||
<widget class="Gui::InputField" name="Quantity_Pitch">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">in</string>
|
||||
</property>
|
||||
<property name="decimals" stdset="0">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum" stdset="0">
|
||||
<double>2000.000000000000000</double>
|
||||
</property>
|
||||
<property name="minimum" stdset="0">
|
||||
<double>0.01</double>
|
||||
</property>
|
||||
|
||||
<property name="singleStep" stdset="0">
|
||||
<double>0.001</double>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<double>0.375</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="3" column="0">
|
||||
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Roller Diameter:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::InputField" name="Quantity_RollerDiameter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true">in</string>
|
||||
</property>
|
||||
<property name="decimals" stdset="0">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="maximum" stdset="0">
|
||||
<double>50.000000000000000</double>
|
||||
</property>
|
||||
<property name="minimum" stdset="0">
|
||||
<double>0.01</double>
|
||||
</property>
|
||||
|
||||
<property name="singleStep" stdset="0">
|
||||
<double>0.01</double>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<double>0.20</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::InputField</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>Gui/InputField.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,24 @@
|
||||
================================================
|
||||
FCSprocket: a Sprocket Generator for FreeCAD
|
||||
================================================
|
||||
|
||||
This is a simple sprocket generation tool. Sprockets are used in combination
|
||||
with roller chain to transmit power. The tooth profiles are drawn according
|
||||
to ANSI standards from the methods outlined in:
|
||||
|
||||
Standard handbook of chains : chains for power transmission and material
|
||||
handling. Boca Raton: Taylor & Francis, 2006. Print.
|
||||
|
||||
AND
|
||||
|
||||
Oberg, Erik, et al. Machinery's handbook : a reference book for the
|
||||
mechanical engineer, designer, manufacturing engineer, draftsman,
|
||||
toolmaker, and machinist. New York: Industrial Press, 2016. Print.
|
||||
|
||||
|
||||
This code is based on the work of David Douard and his implementation of the
|
||||
gear generator (fcgear) found in FreeCAD.
|
||||
|
||||
|
||||
Copyright 2020 Adam Spontarelli <adam@vector-space.org>.
|
||||
Distributed under the LGPL licence.
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
# (c) 2014 David Douard <[email protected]>
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# FCGear 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 FCGear; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
|
||||
from math import cos, sin, pi, acos, asin, atan, sqrt
|
||||
|
||||
import FreeCAD, Part
|
||||
from FreeCAD import Base, Console
|
||||
from . import sprocket
|
||||
rotate = sprocket.rotate
|
||||
|
||||
def makeSprocket(P, N, Dr):
|
||||
if FreeCAD.ActiveDocument is None:
|
||||
FreeCAD.newDocument("Sprocket")
|
||||
doc = FreeCAD.ActiveDocument
|
||||
w = FCWireBuilder()
|
||||
sprocket.CreateSprocket(w, P, N, Dr)
|
||||
sprocketw = Part.Wire([o.toShape() for o in w.wire])
|
||||
sprocket = doc.addObject("Part::Feature", "Sprocket")
|
||||
sprocket.Shape = sprocketw
|
||||
return sprocket
|
||||
|
||||
class FCWireBuilder(object):
|
||||
"""A helper class to prepare a Part.Wire object"""
|
||||
def __init__(self):
|
||||
self.pos = None
|
||||
self.theta = 0.0
|
||||
self.wire = []
|
||||
|
||||
def move(self, p):
|
||||
"""set current position"""
|
||||
self.pos = Base.Vector(*p)
|
||||
|
||||
def line(self, p):
|
||||
"""Add a segment between self.pos and p"""
|
||||
p = rotate(p, self.theta)
|
||||
end = Base.Vector(*p)
|
||||
self.wire.append(Part.LineSegment(self.pos, end))
|
||||
self.pos = end
|
||||
|
||||
def arc(self, p, r, sweep):
|
||||
""""Add an arc from self.pos to p which radius is r
|
||||
sweep (0 or 1) determine the orientation of the arc
|
||||
"""
|
||||
p = rotate(p, self.theta)
|
||||
end = Base.Vector(*p)
|
||||
mid = Base.Vector(*(midpoints(p, self.pos, r)[sweep]))
|
||||
self.wire.append(Part.Arc(self.pos, mid, end))
|
||||
self.pos = end
|
||||
|
||||
def curve(self, *points):
|
||||
"""Add a Bezier curve from self.pos to points[-1]
|
||||
every other points are the control points of the Bezier curve (which
|
||||
will thus be of degree len(points) )
|
||||
"""
|
||||
points = [Base.Vector(*rotate(p, self.theta)) for p in points]
|
||||
bz = Part.BezierCurve()
|
||||
bz.setPoles([self.pos] + points)
|
||||
self.wire.append(bz)
|
||||
self.pos = points[-1]
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def midpoints(p1, p2, r):
|
||||
"""A very ugly function that returns the midpoint of a p1 and p2
|
||||
on the circle which radius is r and which pass through p1 and
|
||||
p2
|
||||
|
||||
Return the 2 possible solutions
|
||||
"""
|
||||
vx, vy = p2[0]-p1[0], p2[1]-p1[1]
|
||||
b = (vx**2 + vy**2)**.5
|
||||
v = (vx/b, vy/b)
|
||||
cosA = b**2 / (2*b*r)
|
||||
A = acos(cosA)
|
||||
|
||||
vx, vy = rotate(v, A)
|
||||
c1 = (p1[0]+r*vx, p1[1]+r*vy)
|
||||
m1x, m1y = ((p1[0]+p2[0])/2 - c1[0], (p1[1]+p2[1])/2 - c1[1])
|
||||
dm1 = (m1x**2+m1y**2)**.5
|
||||
m1x, m1y = (c1[0] + r*m1x/dm1, c1[1] + r*m1y/dm1)
|
||||
m1 = (m1x, m1y)
|
||||
|
||||
vx, vy = rotate(v, -A)
|
||||
c2 = (p1[0]+r*vx, p1[1]+r*vy)
|
||||
m2x, m2y = ((p1[0]+p2[0])/2 - c2[0], (p1[1]+p2[1])/2 - c2[1])
|
||||
dm2 = (m2x**2+m2y**2)**.5
|
||||
m2x, m2y = (c2[0] + r*m2x/dm2, c2[1] + r*m2y/dm2)
|
||||
m2 = (m2x, m2y)
|
||||
|
||||
return m1, m2
|
||||
@@ -0,0 +1,66 @@
|
||||
# (c) 2020 Adam Spontarelli <[email protected]>
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# FCGear 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 FCGear; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
|
||||
from PySide import QtGui as qt
|
||||
import fcsprocket
|
||||
import FreeCAD, FreeCADGui
|
||||
|
||||
class SprocketCreationFrame(qt.QFrame):
|
||||
def __init__(self, parent=None):
|
||||
super(SprocketCreationFrame, self).__init__(parent)
|
||||
self.P = qt.QSpinBox(value=0.375)
|
||||
self.N = qt.QDoubleSpinBox(value=45)
|
||||
self.Dr = qt.QDoubleSpinBox(value=0.20)
|
||||
|
||||
l = qt.QFormLayout(self)
|
||||
l.setFieldGrowthPolicy(l.ExpandingFieldsGrow)
|
||||
l.addRow('Number of teeth:', self.N)
|
||||
l.addRow('Chain Pitch (in):', self.P)
|
||||
l.addRow('Roller Diameter (in):', self.Dr)
|
||||
|
||||
|
||||
class SprocketDialog(qt.QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super(SprocketDialog, self).__init__(parent)
|
||||
self.gc = SprocketCreationFrame()
|
||||
|
||||
btns = qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel
|
||||
buttonBox = qt.QDialogButtonBox(btns,
|
||||
accepted=self.accept,
|
||||
rejected=self.reject)
|
||||
l = qt.QVBoxLayout(self)
|
||||
l.addWidget(self.gc)
|
||||
l.addWidget(buttonBox)
|
||||
self.setWindowTitle('Sprocket creation dialog')
|
||||
|
||||
def accept(self):
|
||||
if FreeCAD.ActiveDocument is None:
|
||||
FreeCAD.newDocument("Sprocket")
|
||||
|
||||
gear = fcgear.makeSprocket(self.gc.m.value(),
|
||||
self.gc.Z.value(),
|
||||
self.gc.angle.value(),
|
||||
not self.gc.split.currentIndex())
|
||||
FreeCADGui.SendMsgToActiveView("ViewFit")
|
||||
return super(SprocketDialog, self).accept()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
a = qt.QApplication([])
|
||||
w = SprocketDialog()
|
||||
w.show()
|
||||
a.exec_()
|
||||
@@ -0,0 +1,139 @@
|
||||
# (c) 2020 Adam Spontarelli <[email protected]>
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# FCGear 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 FCGear; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
|
||||
from math import cos, sin, tan, sqrt, radians, acos, atan, asin, degrees
|
||||
|
||||
|
||||
def CreateSprocket(w, P, N, Dr):
|
||||
"""
|
||||
Create a sprocket
|
||||
|
||||
w is the wirebuilder object (in which the sprocket will be constructed)
|
||||
P is the chain pitch
|
||||
N is the number of teeth
|
||||
Dr is the roller diameter
|
||||
|
||||
Remaining variables can be found in Standard Handbook of Chains
|
||||
"""
|
||||
Ds = 1.005 * Dr + (0.003 * 25.4)
|
||||
R = Ds / 2
|
||||
alpha = 35 + 60/N
|
||||
beta = 18 - 56 / N
|
||||
M = 0.8 * Dr * cos(radians(35) + radians(60/N))
|
||||
T = 0.8 * Dr * sin(radians(35) + radians(60/N))
|
||||
E = 1.3025 * Dr + (0.0015 * 25.4)
|
||||
W = 1.4 * Dr * cos(radians(180/N))
|
||||
V = 1.4 * Dr * sin(radians(180/N))
|
||||
F = Dr * (0.8 * cos(radians(18) - radians(56)/N) + 1.4 *
|
||||
cos(radians(17) - radians(64) / N) - 1.3025) - (0.0015 * 25.4)
|
||||
PD = P / (sin(radians(180)/N))
|
||||
H = sqrt(F**2 - (1.4 * Dr - P/2)**2)
|
||||
OD = P * (0.6 + 1/tan(radians(180/N)))
|
||||
|
||||
# The sprocket tooth gullet consists of four segments
|
||||
x0 = 0
|
||||
y0 = PD/2 - R
|
||||
|
||||
# ---- Segment 1 -----
|
||||
alpha = 35 + 60/N
|
||||
x1 = -R * cos(radians(alpha))
|
||||
y1 = PD/2 - R * sin(radians(alpha))
|
||||
arc_end = [x1, y1]
|
||||
|
||||
# ---- Segment 2 -----
|
||||
alpha = 35 + 60/N
|
||||
beta = 18 - 56 / N
|
||||
x2 = M - E * cos(radians(alpha-beta))
|
||||
y2 = T - E * sin(radians(alpha-beta)) + PD/2
|
||||
|
||||
# # ---- Segment 3 -----
|
||||
y2o = y2 - PD/2
|
||||
hyp = sqrt((-W-x2)**2 + (-V-y2o)**2)
|
||||
AP = sqrt(hyp**2 - F**2)
|
||||
gamma = atan((y2o + V)/(x2 + W))
|
||||
alpha = asin(AP / hyp)
|
||||
beta = 180 - (90 - degrees(alpha)) - (90 - degrees(gamma))
|
||||
x3o = AP * sin(radians(beta))
|
||||
y3o = AP * cos(radians(beta))
|
||||
x3 = x2 - x3o
|
||||
y3 = y2 + y3o
|
||||
|
||||
# ---- Segment 4 -----
|
||||
alpha = 180/N
|
||||
m = -1/tan(radians(alpha))
|
||||
yf = PD/2 - V
|
||||
A = 1 + m**2
|
||||
B = 2*m*yf - 2*W
|
||||
C = W**2 + yf**2 - F**2
|
||||
# x4a = (-B - sqrt(B**2 - 4 * A * C)) / (2*A)
|
||||
x4b = (-B + sqrt(B**2 - 4 * A * C)) / (2*A)
|
||||
x4 = -x4b
|
||||
y4 = m * x4
|
||||
|
||||
p0 = [x0,y0]
|
||||
p1 = [x1,y1]
|
||||
p2 = [x2,y2]
|
||||
p3 = [x3,y3]
|
||||
p4 = [x4,y4]
|
||||
p5 = [-x1,y1]
|
||||
p6 = [-x2,y2]
|
||||
p7 = [-x3,y3]
|
||||
p8 = [-x4,y4]
|
||||
|
||||
w.move(p4) # vectors are lists [x,y]
|
||||
w.arc(p3, F, 0)
|
||||
w.line(p2)
|
||||
w.arc(p1, E, 1)
|
||||
w.arc(p0, R, 1)
|
||||
|
||||
# ---- Mirror -----
|
||||
w.arc(p5, R, 1)
|
||||
w.arc(p6, E, 1)
|
||||
w.line(p7)
|
||||
w.arc(p8, F, 0)
|
||||
|
||||
# ---- Polar Array ----
|
||||
alpha = -radians(360/N)
|
||||
for n in range(1,N):
|
||||
# falling gullet slope
|
||||
w.arc(rotate(p3, alpha*n), F, 0)
|
||||
w.line(rotate(p2, alpha*n))
|
||||
w.arc(rotate(p1, alpha*n), E, 1)
|
||||
w.arc(rotate(p0, alpha*n), R, 1)
|
||||
|
||||
# rising gullet slope
|
||||
w.arc(rotate(p5, alpha*n), R, 1)
|
||||
w.line(rotate(p6, alpha*n))
|
||||
w.arc(rotate(p7, alpha*n), E, 0)
|
||||
w.arc(rotate(p8, alpha*n), F, 0)
|
||||
|
||||
w.close()
|
||||
|
||||
return w
|
||||
|
||||
|
||||
def rotate(pt, rads):
|
||||
"""
|
||||
rotate pt by rads radians about origin
|
||||
"""
|
||||
sinA = sin(rads)
|
||||
cosA = cos(rads)
|
||||
return (pt[0] * cosA - pt[1] * sinA,
|
||||
pt[0] * sinA + pt[1] * cosA)
|
||||
|
||||
|
||||
|
||||
@@ -255,9 +255,9 @@ void DrawViewDetail::detailExec(TopoDS_Shape shape,
|
||||
double scale = getScale();
|
||||
|
||||
BRepBuilderAPI_Copy BuilderCopy(shape);
|
||||
TopoDS_Shape copyShape = BuilderCopy.Shape();
|
||||
TopoDS_Shape myShape = BuilderCopy.Shape();
|
||||
|
||||
gp_Pnt gpCenter = TechDraw::findCentroid(copyShape,
|
||||
gp_Pnt gpCenter = TechDraw::findCentroid(myShape,
|
||||
dirDetail);
|
||||
Base::Vector3d shapeCenter = Base::Vector3d(gpCenter.X(),gpCenter.Y(),gpCenter.Z());
|
||||
m_saveCentroid = shapeCenter; //centroid of original shape
|
||||
@@ -265,7 +265,7 @@ void DrawViewDetail::detailExec(TopoDS_Shape shape,
|
||||
if (dvs != nullptr) {
|
||||
//section cutShape should already be on origin
|
||||
} else {
|
||||
copyShape = TechDraw::moveShape(copyShape, //centre shape on origin
|
||||
myShape = TechDraw::moveShape(myShape, //centre shape on origin
|
||||
-shapeCenter);
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ void DrawViewDetail::detailExec(TopoDS_Shape shape,
|
||||
|
||||
Bnd_Box bbxSource;
|
||||
bbxSource.SetGap(0.0);
|
||||
BRepBndLib::Add(copyShape, bbxSource);
|
||||
BRepBndLib::Add(myShape, bbxSource);
|
||||
double diag = sqrt(bbxSource.SquareExtent());
|
||||
|
||||
Base::Vector3d toolPlaneOrigin = anchorOffset3d + dirDetail * diag * -1.0; //center tool about anchor
|
||||
@@ -301,33 +301,47 @@ void DrawViewDetail::detailExec(TopoDS_Shape shape,
|
||||
gp_Vec extrudeDir(extrudeVec.x,extrudeVec.y,extrudeVec.z);
|
||||
TopoDS_Shape tool = BRepPrimAPI_MakePrism(aProjFace, extrudeDir, false, true).Shape();
|
||||
|
||||
BRepAlgoAPI_Common mkCommon(copyShape,tool);
|
||||
if (!mkCommon.IsDone()) {
|
||||
Base::Console().Warning("DVD::execute - %s - detail cut operation failed (1)\n", getNameInDocument());
|
||||
return;
|
||||
}
|
||||
if (mkCommon.Shape().IsNull()) {
|
||||
Base::Console().Warning("DVD::execute - %s - detail cut operation failed (2)\n", getNameInDocument());
|
||||
return;
|
||||
}
|
||||
|
||||
//Did we get a solid?
|
||||
TopExp_Explorer xp;
|
||||
xp.Init(mkCommon.Shape(),TopAbs_SOLID);
|
||||
if (!(xp.More() == Standard_True)) {
|
||||
Base::Console().Warning("DVD::execute - mkCommon.Shape is not a solid!\n");
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound pieces;
|
||||
builder.MakeCompound(pieces);
|
||||
TopExp_Explorer expl(myShape, TopAbs_SOLID);
|
||||
int indb = 0;
|
||||
int outdb = 0;
|
||||
for (; expl.More(); expl.Next()) {
|
||||
indb++;
|
||||
const TopoDS_Solid& s = TopoDS::Solid(expl.Current());
|
||||
|
||||
BRepAlgoAPI_Common mkCommon(s,tool);
|
||||
if (!mkCommon.IsDone()) {
|
||||
// Base::Console().Warning("DVD::execute - %s - detail cut operation failed (1)\n", getNameInDocument());
|
||||
continue;
|
||||
}
|
||||
if (mkCommon.Shape().IsNull()) {
|
||||
// Base::Console().Warning("DVD::execute - %s - detail cut operation failed (2)\n", getNameInDocument());
|
||||
continue;
|
||||
}
|
||||
//this might be overkill for piecewise algo
|
||||
//Did we get at least 1 solid?
|
||||
TopExp_Explorer xp;
|
||||
xp.Init(mkCommon.Shape(),TopAbs_SOLID);
|
||||
if (!(xp.More() == Standard_True)) {
|
||||
// Base::Console().Warning("DVD::execute - mkCommon.Shape is not a solid!\n");
|
||||
continue;
|
||||
}
|
||||
builder.Add(pieces, mkCommon.Shape());
|
||||
outdb++;
|
||||
}
|
||||
TopoDS_Shape detail = mkCommon.Shape();
|
||||
|
||||
if (debugDetail()) {
|
||||
BRepTools::Write(tool, "DVDTool.brep"); //debug
|
||||
BRepTools::Write(copyShape, "DVDCopy.brep"); //debug
|
||||
BRepTools::Write(detail, "DVDCommon.brep"); //debug
|
||||
BRepTools::Write(myShape, "DVDCopy.brep"); //debug
|
||||
BRepTools::Write(pieces, "DVDCommon.brep"); //debug
|
||||
}
|
||||
|
||||
Bnd_Box testBox;
|
||||
testBox.SetGap(0.0);
|
||||
BRepBndLib::Add(detail, testBox);
|
||||
BRepBndLib::Add(pieces, testBox);
|
||||
if (testBox.IsVoid()) {
|
||||
TechDraw::GeometryObject* go = getGeometryObject();
|
||||
if (go != nullptr) {
|
||||
@@ -343,7 +357,7 @@ void DrawViewDetail::detailExec(TopoDS_Shape shape,
|
||||
// TopoDS_Compound Comp;
|
||||
// builder.MakeCompound(Comp);
|
||||
// builder.Add(Comp, tool);
|
||||
// builder.Add(Comp, copyShape);
|
||||
// builder.Add(Comp, myShape);
|
||||
|
||||
gp_Pnt inputCenter;
|
||||
try {
|
||||
@@ -358,7 +372,8 @@ void DrawViewDetail::detailExec(TopoDS_Shape shape,
|
||||
gp_Ax2 viewAxis = dvp->getProjectionCS(stdOrg); //sb same CS as base view.
|
||||
|
||||
//center shape on origin
|
||||
TopoDS_Shape centeredShape = TechDraw::moveShape(detail,
|
||||
// TopoDS_Shape centeredShape = TechDraw::moveShape(detail,
|
||||
TopoDS_Shape centeredShape = TechDraw::moveShape(pieces,
|
||||
centroid * -1.0);
|
||||
|
||||
TopoDS_Shape scaledShape = TechDraw::scaleShape(centeredShape,
|
||||
|
||||
@@ -347,7 +347,6 @@ App::DocumentObjectExecReturn *DrawViewSection::execute(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dvp->requestPaint(); //to refresh section line
|
||||
return DrawView::execute();
|
||||
}
|
||||
@@ -382,13 +381,26 @@ void DrawViewSection::sectionExec(TopoDS_Shape baseShape)
|
||||
BRepBuilderAPI_Copy BuilderCopy(baseShape);
|
||||
TopoDS_Shape myShape = BuilderCopy.Shape();
|
||||
|
||||
BRepAlgoAPI_Cut mkCut(myShape, prism);
|
||||
if (!mkCut.IsDone()) {
|
||||
Base::Console().Warning("DVS: Section cut has failed in %s\n",getNameInDocument());
|
||||
return;
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound pieces;
|
||||
builder.MakeCompound(pieces);
|
||||
TopExp_Explorer expl(myShape, TopAbs_SOLID);
|
||||
int indb = 0;
|
||||
int outdb = 0;
|
||||
for (; expl.More(); expl.Next()) {
|
||||
indb++;
|
||||
const TopoDS_Solid& s = TopoDS::Solid(expl.Current());
|
||||
BRepAlgoAPI_Cut mkCut(s, prism);
|
||||
if (!mkCut.IsDone()) {
|
||||
Base::Console().Warning("DVS: Section cut has failed in %s\n",getNameInDocument());
|
||||
continue;
|
||||
}
|
||||
TopoDS_Shape cut = mkCut.Shape();
|
||||
builder.Add(pieces, cut);
|
||||
outdb++;
|
||||
}
|
||||
|
||||
TopoDS_Shape rawShape = mkCut.Shape();
|
||||
TopoDS_Shape rawShape = pieces;
|
||||
if (debugSection()) {
|
||||
BRepTools::Write(myShape, "DVSCopy.brep"); //debug
|
||||
BRepTools::Write(aProjFace, "DVSFace.brep"); //debug
|
||||
|
||||
Reference in New Issue
Block a user