Draft: new module for utility functions

Many auxiliary tools used by `Draft.py` can be defined
in another module. Many functions are moved to this module
so that `Draft.py` isn't as big and hard to maintain.

The following is a list of functions and attributes that were moved:
`stringencodecoin`, `arrowtypes`, `typecheck`,
`getParamType`, `getParam`, `setParam`, `precision`,
`tolerance`, `epsilon`, `getRealName`, `getType`,
`getObjectsOfType`, `isClone`, `getGroupNames`,
`ungroup`, `shapify`, `getGroupContents`,
`printShape`, `compareObjects`, `loadSvgPatterns`,
`svgpatterns`, `getMovableChildren`, `getWindows`,
`utf8_decode`.

Moreover, many of these functions were renamed
to comply better with PEP8 guidelines, particularly
the use of `snake_case`. For example, `getGroupNames`
is now `get_group_names`; `getMovableChildren`
is now `get_movable_children`.

Aliases are provided for the old names so that
other functions and classes that depend on these
won't break. The new names should be the official
programming interface, while the old names
should be deprecated at some point in the future.
This commit is contained in:
vocx-fc
2019-11-01 23:55:32 -06:00
committed by Yorik van Havre
parent ab6976c5db
commit 7721ca0157
5 changed files with 1103 additions and 376 deletions

View File

@@ -47,6 +47,11 @@ SET(Draft_tests
drafttests/test_airfoildat.py
)
SET(Draft_utilities
draftutils/__init__.py
draftutils/utils.py
)
SET(Draft_objects
draftobjects/__init__.py
draftobjects/circulararray.py
@@ -76,6 +81,7 @@ SET(Draft_SRCS_all
${Draft_SRCS_base}
${Draft_import}
${Draft_tests}
${Draft_utilities}
${Draft_objects}
${Draft_view_providers}
${Draft_GUI_tools}
@@ -118,6 +124,7 @@ INSTALL(
)
INSTALL(FILES ${Draft_tests} DESTINATION Mod/Draft/drafttests)
INSTALL(FILES ${Draft_utilities} DESTINATION Mod/Draft/draftutils)
INSTALL(FILES ${Draft_objects} DESTINATION Mod/Draft/draftobjects)
INSTALL(FILES ${Draft_view_providers} DESTINATION Mod/Draft/draftviewproviders)
INSTALL(FILES ${Draft_GUI_tools} DESTINATION Mod/Draft/draftguitools)

View File

@@ -63,8 +63,6 @@ else:
def translate(ctx,txt):
return txt
arrowtypes = ["Dot","Circle","Arrow","Tick","Tick-2"]
#---------------------------------------------------------------------------
# Backwards compatibility
#---------------------------------------------------------------------------
@@ -81,162 +79,37 @@ makeLayer = DraftLayer.makeLayer
#---------------------------------------------------------------------------
# General functions
#---------------------------------------------------------------------------
import draftutils.utils
arrowtypes = draftutils.utils.ARROW_TYPES
def stringencodecoin(ustr):
"""stringencodecoin(str): Encodes a unicode object to be used as a string in coin"""
try:
from pivy import coin
coin4 = coin.COIN_MAJOR_VERSION >= 4
except (ImportError, AttributeError):
coin4 = False
if coin4:
return ustr.encode('utf-8')
else:
return ustr.encode('latin1')
stringencodecoin = draftutils.utils.string_encode_coin
string_encode_coin = draftutils.utils.string_encode_coin
def typecheck (args_and_types, name="?"):
"""typecheck([arg1,type),(arg2,type),...]): checks arguments types"""
for v,t in args_and_types:
if not isinstance (v,t):
w = "typecheck[" + str(name) + "]: "
w += str(v) + " is not " + str(t) + "\n"
FreeCAD.Console.PrintWarning(w)
raise TypeError("Draft." + str(name))
typecheck = draftutils.utils.type_check
type_check = draftutils.utils.type_check
def getParamType(param):
if param in ["dimsymbol","dimPrecision","dimorientation","precision","defaultWP",
"snapRange","gridEvery","linewidth","UiMode","modconstrain","modsnap",
"maxSnapEdges","modalt","HatchPatternResolution","snapStyle",
"dimstyle","gridSize"]:
return "int"
elif param in ["constructiongroupname","textfont","patternFile","template",
"snapModes","FontFile","ClonePrefix","labeltype"] \
or "inCommandShortcut" in param:
return "string"
elif param in ["textheight","tolerance","gridSpacing","arrowsize","extlines","dimspacing",
"dimovershoot","extovershoot"]:
return "float"
elif param in ["selectBaseObjects","alwaysSnap","grid","fillmode","saveonexit","maxSnap",
"SvgLinesBlack","dxfStdSize","showSnapBar","hideSnapBar","alwaysShowGrid",
"renderPolylineWidth","showPlaneTracker","UsePartPrimitives","DiscretizeEllipses",
"showUnit"]:
return "bool"
elif param in ["color","constructioncolor","snapcolor","gridColor"]:
return "unsigned"
else:
return None
getParamType = draftutils.utils.get_param_type
get_param_type = draftutils.utils.get_param_type
def getParam(param,default=None):
"""getParam(parameterName): returns a Draft parameter value from the current config"""
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
t = getParamType(param)
#print("getting param ",param, " of type ",t, " default: ",str(default))
if t == "int":
if default is None:
default = 0
if param == "linewidth":
return FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").GetInt("DefaultShapeLineWidth",default)
return p.GetInt(param,default)
elif t == "string":
if default is None:
default = ""
return p.GetString(param,default)
elif t == "float":
if default is None:
default = 0
return p.GetFloat(param,default)
elif t == "bool":
if default is None:
default = False
return p.GetBool(param,default)
elif t == "unsigned":
if default is None:
default = 0
if param == "color":
return FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").GetUnsigned("DefaultShapeLineColor",default)
return p.GetUnsigned(param,default)
else:
return None
getParam = draftutils.utils.get_param
get_param = draftutils.utils.get_param
def setParam(param,value):
"""setParam(parameterName,value): sets a Draft parameter with the given value"""
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
t = getParamType(param)
if t == "int":
if param == "linewidth":
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").SetInt("DefaultShapeLineWidth",value)
else:
p.SetInt(param,value)
elif t == "string":
p.SetString(param,value)
elif t == "float":
p.SetFloat(param,value)
elif t == "bool":
p.SetBool(param,value)
elif t == "unsigned":
if param == "color":
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").SetUnsigned("DefaultShapeLineColor",value)
else:
p.SetUnsigned(param,value)
setParam = draftutils.utils.set_param
set_param = draftutils.utils.set_param
def precision():
"""precision(): returns the precision value from Draft user settings"""
return getParam("precision",6)
precision = draftutils.utils.precision
tolerance = draftutils.utils.tolerance
epsilon = draftutils.utils.epsilon
def tolerance():
"""tolerance(): returns the tolerance value from Draft user settings"""
return getParam("tolerance",0.05)
getRealName = draftutils.utils.get_real_name
get_real_name = draftutils.utils.get_real_name
def epsilon():
''' epsilon(): returns a small number based on Draft.tolerance() for use in
floating point comparisons. Use with caution. '''
return (1.0/(10.0**tolerance()))
getType = draftutils.utils.get_type
get_type = draftutils.utils.get_type
def getRealName(name):
"""getRealName(string): strips the trailing numbers from a string name"""
for i in range(1,len(name)):
if not name[-i] in '1234567890':
return name[:len(name)-(i-1)]
return name
getObjectsOfType = draftutils.utils.get_objects_of_type
get_objects_of_type = draftutils.utils.get_objects_of_type
def getType(obj):
"""getType(object): returns the Draft type of the given object"""
import Part
if not obj:
return None
if isinstance(obj,Part.Shape):
return "Shape"
if "Proxy" in obj.PropertiesList:
if hasattr(obj.Proxy,"Type"):
return obj.Proxy.Type
if obj.isDerivedFrom("Sketcher::SketchObject"):
return "Sketch"
if (obj.TypeId == "Part::Line"):
return "Part::Line"
if (obj.TypeId == "Part::Offset2D"):
return "Offset2D"
if obj.isDerivedFrom("Part::Feature"):
return "Part"
if (obj.TypeId == "App::Annotation"):
return "Annotation"
if obj.isDerivedFrom("Mesh::Feature"):
return "Mesh"
if obj.isDerivedFrom("Points::Feature"):
return "Points"
if (obj.TypeId == "App::DocumentObjectGroup"):
return "Group"
if (obj.TypeId == "App::Part"):
return "App::Part"
return "Unknown"
def getObjectsOfType(objectslist,typ):
"""getObjectsOfType(objectslist,typ): returns a list of objects of type "typ" found
in the given object list"""
objs = []
for o in objectslist:
if getType(o) == typ:
objs.append(o)
return objs
def get3DView():
"""get3DView(): returns the current view if it is 3D, or the first 3D view found, or None"""
@@ -251,40 +124,15 @@ def get3DView():
return v[0]
return None
def isClone(obj,objtype,recursive=False):
"""isClone(obj,objtype,[recursive]): returns True if the given object is
a clone of an object of the given type. If recursive is True, also check if
the clone is a clone of clone (of clone...) of the given type."""
if isinstance(objtype,list):
return any([isClone(obj,t,recursive) for t in objtype])
if getType(obj) == "Clone":
if len(obj.Objects) == 1:
if getType(obj.Objects[0]) == objtype:
return True
elif recursive and (getType(obj.Objects[0]) == "Clone"):
return isClone(obj.Objects[0],objtype,recursive)
elif hasattr(obj,"CloneOf"):
if obj.CloneOf:
return True
return False
def getGroupNames():
"""returns a list of existing groups in the document"""
glist = []
doc = FreeCAD.ActiveDocument
for obj in doc.Objects:
if obj.isDerivedFrom("App::DocumentObjectGroup") or (getType(obj) in ["Floor","Building","Site"]):
glist.append(obj.Name)
return glist
isClone = draftutils.utils.is_clone
is_clone = draftutils.utils.is_clone
getGroupNames = draftutils.utils.get_group_names
get_group_names = draftutils.utils.get_group_names
ungroup = draftutils.utils.ungroup
def ungroup(obj):
"""removes the current object from any group it belongs to"""
for g in getGroupNames():
grp = FreeCAD.ActiveDocument.getObject(g)
if obj in grp.Group:
g = grp.Group
g.remove(obj)
grp.Group = g
def autogroup(obj):
"""adds a given object to the autogroup, if applicable"""
@@ -361,91 +209,12 @@ def dimDash(p1, p2):
dash.addChild(l)
return dash
def shapify(obj):
"""shapify(object): transforms a parametric shape object into
non-parametric and returns the new object"""
try:
shape = obj.Shape
except Exception:
return None
if len(shape.Faces) == 1:
name = "Face"
elif len(shape.Solids) == 1:
name = "Solid"
elif len(shape.Solids) > 1:
name = "Compound"
elif len(shape.Faces) > 1:
name = "Shell"
elif len(shape.Wires) == 1:
name = "Wire"
elif len(shape.Edges) == 1:
import DraftGeomUtils
if DraftGeomUtils.geomType(shape.Edges[0]) == "Line":
name = "Line"
else:
name = "Circle"
else:
name = getRealName(obj.Name)
FreeCAD.ActiveDocument.removeObject(obj.Name)
newobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name)
newobj.Shape = shape
return newobj
shapify = draftutils.utils.shapify
def getGroupContents(objectslist,walls=False,addgroups=False,spaces=False,noarchchild=False):
"""getGroupContents(objectlist,[walls,addgroups]): if any object of the given list
is a group, its content is appended to the list, which is returned. If walls is True,
walls and structures are also scanned for included windows or rebars. If addgroups
is true, the group itself is also included in the list."""
def getWindows(obj):
l = []
if getType(obj) in ["Wall","Structure"]:
for o in obj.OutList:
l.extend(getWindows(o))
for i in obj.InList:
if (getType(i) in ["Window"]) or isClone(obj,"Window"):
if hasattr(i,"Hosts"):
if obj in i.Hosts:
l.append(i)
elif (getType(i) in ["Rebar"]) or isClone(obj,"Rebar"):
if hasattr(i,"Host"):
if obj == i.Host:
l.append(i)
elif (getType(obj) in ["Window","Rebar"]) or isClone(obj,["Window","Rebar"]):
l.append(obj)
return l
getGroupContents = draftutils.utils.get_group_contents
get_group_contents = draftutils.utils.get_group_contents
newlist = []
if not isinstance(objectslist,list):
objectslist = [objectslist]
for obj in objectslist:
if obj:
if obj.isDerivedFrom("App::DocumentObjectGroup") or ((getType(obj) in ["App::Part","Building","BuildingPart","Space","Site"]) and hasattr(obj,"Group")):
if getType(obj) == "Site":
if obj.Shape:
newlist.append(obj)
if obj.isDerivedFrom("Drawing::FeaturePage"):
# skip if the group is a page
newlist.append(obj)
else:
if addgroups or (spaces and (getType(obj) == "Space")):
newlist.append(obj)
if noarchchild and (getType(obj) in ["Building","BuildingPart"]):
pass
else:
newlist.extend(getGroupContents(obj.Group,walls,addgroups))
else:
#print("adding ",obj.Name)
newlist.append(obj)
if walls:
newlist.extend(getWindows(obj))
# cleaning possible duplicates
cleanlist = []
for obj in newlist:
if not obj in cleanlist:
cleanlist.append(obj)
return cleanlist
def removeHidden(objectslist):
"""removeHidden(objectslist): removes hidden objects from the list"""
@@ -456,47 +225,13 @@ def removeHidden(objectslist):
newlist.remove(o)
return newlist
def printShape(shape):
"""prints detailed information of a shape"""
print("solids: ", len(shape.Solids))
print("faces: ", len(shape.Faces))
print("wires: ", len(shape.Wires))
print("edges: ", len(shape.Edges))
print("verts: ", len(shape.Vertexes))
if shape.Faces:
for f in range(len(shape.Faces)):
print("face ",f,":")
for v in shape.Faces[f].Vertexes:
print(" ",v.Point)
elif shape.Wires:
for w in range(len(shape.Wires)):
print("wire ",w,":")
for v in shape.Wires[w].Vertexes:
print(" ",v.Point)
else:
for v in shape.Vertexes:
print(" ",v.Point)
def compareObjects(obj1,obj2):
"""Prints the differences between 2 objects"""
printShape = draftutils.utils.print_shape
print_shape = draftutils.utils.print_shape
compareObjects = draftutils.utils.compare_objects
compare_objects = draftutils.utils.compare_objects
if obj1.TypeId != obj2.TypeId:
print(obj1.Name + " and " + obj2.Name + " are of different types")
elif getType(obj1) != getType(obj2):
print(obj1.Name + " and " + obj2.Name + " are of different types")
else:
for p in obj1.PropertiesList:
if p in obj2.PropertiesList:
if p in ["Shape","Label"]:
pass
elif p == "Placement":
delta = str((obj1.Placement.Base.sub(obj2.Placement.Base)).Length)
print("Objects have different placements. Distance between the 2: " + delta + " units")
else:
if getattr(obj1,p) != getattr(obj2,p):
print("Property " + p + " has a different value")
else:
print("Property " + p + " doesn't exist in one of the objects")
def formatObject(target,origin=None):
"""
@@ -582,42 +317,13 @@ def select(objs=None):
if obj:
FreeCADGui.Selection.addSelection(obj)
def loadSvgPatterns():
"""loads the default Draft SVG patterns and custom patters if available"""
import importSVG
from PySide import QtCore
FreeCAD.svgpatterns = {}
# getting default patterns
patfiles = QtCore.QDir(":/patterns").entryList()
for fn in patfiles:
fn = ":/patterns/"+str(fn)
f = QtCore.QFile(fn)
f.open(QtCore.QIODevice.ReadOnly)
p = importSVG.getContents(str(f.readAll()),'pattern',True)
if p:
for k in p:
p[k] = [p[k],fn]
FreeCAD.svgpatterns.update(p)
# looking for user patterns
altpat = getParam("patternFile","")
if os.path.isdir(altpat):
for f in os.listdir(altpat):
if f[-4:].upper() == ".SVG":
p = importSVG.getContents(altpat+os.sep+f,'pattern')
if p:
for k in p:
p[k] = [p[k],altpat+os.sep+f]
FreeCAD.svgpatterns.update(p)
def svgpatterns():
"""svgpatterns(): returns a dictionary with installed SVG patterns"""
if hasattr(FreeCAD,"svgpatterns"):
return FreeCAD.svgpatterns
else:
loadSvgPatterns()
if hasattr(FreeCAD,"svgpatterns"):
return FreeCAD.svgpatterns
return {}
loadSvgPatterns = draftutils.utils.load_svg_patterns
load_svg_patterns = draftutils.utils.load_svg_patterns
svgpatterns = draftutils.utils.svg_patterns
svg_patterns = draftutils.utils.svg_patterns
def loadTexture(filename,size=None):
"""loadTexture(filename,[size]): returns a SoSFImage from a file. If size
@@ -698,36 +404,10 @@ def loadTexture(filename,size=None):
return img
return None
def getMovableChildren(objectslist,recursive=True):
"""getMovableChildren(objectslist,[recursive]): extends the given list of objects
with all child objects that have a "MoveWithHost" property set to True. If
recursive is True, all descendents are considered, otherwise only direct children."""
added = []
if not isinstance(objectslist,list):
objectslist = [objectslist]
for obj in objectslist:
if not (getType(obj) in ["Clone","SectionPlane","Facebinder","BuildingPart"]):
# objects that should never move their children
children = obj.OutList
if hasattr(obj,"Proxy"):
if obj.Proxy:
if hasattr(obj.Proxy,"getSiblings") and not(getType(obj) in ["Window"]):
#children.extend(obj.Proxy.getSiblings(obj))
pass
for child in children:
if hasattr(child,"MoveWithHost"):
if child.MoveWithHost:
if hasattr(obj,"CloneOf"):
if obj.CloneOf:
if obj.CloneOf.Name != child.Name:
added.append(child)
else:
added.append(child)
else:
added.append(child)
if recursive:
added.extend(getMovableChildren(children))
return added
getMovableChildren = draftutils.utils.get_movable_children
get_movable_children = draftutils.utils.get_movable_children
def makeCircle(radius, placement=None, face=None, startangle=None, endangle=None, support=None):
"""makeCircle(radius,[placement,face,startangle,endangle])

View File

@@ -92,16 +92,8 @@ except AttributeError:
else:
return QtGui.QApplication.translate(context, text, None, _encoding).encode("utf8")
def utf8_decode(text):
"""py2: str -> unicode
unicode -> unicode
py3: str -> str
bytes -> str
"""
try:
return text.decode("utf-8")
except AttributeError:
return text
import draftutils.utils
utf8_decode = draftutils.utils.utf8_decode
# in-command shortcut definitions: Shortcut / Translation / related UI control

View File

File diff suppressed because it is too large Load Diff