Une fonction du moment décorée |
if this article is not in your language, use the Google Translate widget ⬈ (bottom of page for Mobile version ⬇)
Rappel Définition
Un décorateur est une fonction qui modifie le comportement d'autres
fonctions.
Un bon exemple est l'utilisation des Transactions dans le contexte de l'API
Revit.
Une transaction est un contexte requis pour apporter des modifications à un
modèle Revit.
Transaction Start
↓
Modification du Modèle
↓
Transaction End
Généralement 1 seule Transaction suffit par nœud Python, mais il
peut s'avérés qu'il soit nécessaire d'implémenter plusieurs Transactions.
Pour un premier exemple prenons une création d'une ligne de
Modèle basée sur un plan de construction (plan de la vue active à laquelle on ajoute une élévation).
Bien qu'une seule Transaction pourrait suffire nous en mettons 2 pour
l'exemple.
-
Exemple avec les Transactions Dynamo
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
def decoTransaction(func):
def wrapper(*args, **kwargs):
TransactionManager.Instance.ForceCloseTransaction()
TransactionManager.Instance.EnsureInTransaction(doc)
ret = func(*args, **kwargs)
TransactionManager.Instance.TransactionTaskDone()
return ret
return wrapper
@decoTransaction
def create_planarRef():
"""
create a plane to allow pickPoint (split Point) in 3D View
"""
new_plan = Plane.CreateByNormalAndOrigin(doc.ActiveView.ViewDirection, doc.ActiveView.Origin + XYZ(0,0,1))
sp = SketchPlane.Create(doc, new_plan)
#active the SketchPlane
doc.ActiveView.SketchPlane = sp
return sp
@decoTransaction
def drawModelLine(Skplan):
"""
create model Line
"""
pt1 = uidoc.Selection.PickPoint(Selection.ObjectSnapTypes.Nearest, "choisir le 1er Point ")
pt2 = uidoc.Selection.PickPoint(Selection.ObjectSnapTypes.Nearest, "choisir le 2e Point ")
lineBase = Line.CreateBound(pt1,pt2)
modelCurv = doc.Create.NewModelCurve(lineBase, Skplan)
return modelCurv
skPlan = create_planarRef()
modelLine = drawModelLine(skPlan)
OUT = modelLine
- Le même exemple avec les Transactions de l'API Revit, où l'on passe le nom de la fonction à décorer au nom de la Transaction avec la propriété __name__
import clr
import clr
import sys
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
sys.path.append(pf_path + '\\IronPython 2.7\\Lib')
import functools
def decoTransaction(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
t = Transaction(doc, func.__name__)
t.Start()
ret = func(*args, **kwargs)
doc.Regenerate()
t.Commit()
t.Dispose()
return ret
return wrapper
@decoTransaction
def create_planarRef():
"""
create a plane to allow pickPoint (split Point) in 3D View
"""
new_plan = Plane.CreateByNormalAndOrigin(doc.ActiveView.ViewDirection, doc.ActiveView.Origin + XYZ(0,0,1))
sp = SketchPlane.Create(doc, new_plan)
#active the SketchPlane
doc.ActiveView.SketchPlane = sp
return sp
@decoTransaction
def drawModelLine(Skplan):
"""
create model Line
"""
pt1 = uidoc.Selection.PickPoint(Selection.ObjectSnapTypes.Nearest, "choisir le 1er Point ")
pt2 = uidoc.Selection.PickPoint(Selection.ObjectSnapTypes.Nearest, "choisir le 2e Point ")
lineBase = Line.CreateBound(pt1,pt2)
modelCurv = doc.Create.NewModelCurve(lineBase, Skplan)
return modelCurv
skPlan = create_planarRef()
modelLine = drawModelLine(skPlan)
OUT = modelLine
- Un second exemple avec une version plus poussée ou l'on passe un argument au décorateur, ici on choisit si l'on doit valider la Transaction (Commit) ou revenir en arrière (Rollback).
Le script efface temporairement un sol afin de récupérer sa géométrie
d'esquisse pour ensuite créer une hachure correspondante.
import clr
import sys
import System
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
from System.Collections.Generic import List
pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
sys.path.append('%sIronPython 2.7Lib' % pf_path)
import functools
def decoTransaction(commit):
def subDecoTransaction(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
TransactionManager.Instance.ForceCloseTransaction()
t = Transaction(doc, func.__name__)
t.Start()
ret = func(*args, **kwargs)
if commit:
t.Commit()
else:
t.RollBack()
t.Dispose()
return ret
return wrapper
return subDecoTransaction
def getPerimeterFloor(floor):
#subfunction
@decoTransaction(commit = False)
def tempDelete(elem):
deleted = doc.Delete(elem.Id)
return deleted
#main function
for d in tempDelete(floor):
test_el = doc.GetElement(d)
if isinstance(test_el, Sketch):
profileArry = test_el.Profile
return profileArry
@decoTransaction(commit = True)
def drawhatchfromLoop(arrayCurves, filledRegionName):
"""
create hatch from Loop
"""
lstCurveLoop = [CurveLoop.Create([x for x in sublst]) for sublst in arrayCurves]
boundariesLoop = List[CurveLoop](lstCurveLoop)
filledType = FilteredElementCollector(doc).OfClass(FilledRegionType).ToElements().Find(lambda x : Element.Name.GetValue(x) == filledRegionName)
filled = FilledRegion.Create(doc, filledType.Id, doc.ActiveView.Id, boundariesLoop)
return filled
floor = UnwrapElement(IN[0])
filledRegionName = IN[1]
arrayCurves = getPerimeterFloor(floor)
if arrayCurves is not None:
OUT = drawhatchfromLoop(arrayCurves, filledRegionName)
Note :
Le décorateur @functools.wraps(func) est optionnel, il permet de conserver la chaine de documentation de la fonction décorée. (voir module functools)
Voici deux très bons articles sur le sujet
À vos décorateurs ! Ou à vos décorations 🎄🎄🎅
0 commentaires:
Enregistrer un commentaire