Hi everyone,
I would like to know how can I implement this Interface (IFailuresPreprocessor) from the revit API in Python. Actually I need to write the following C# class in Python:
class MyFailureProcessor : IFailuresPreprocessor
{
public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor)
{
return FailureProcessingResult.Continue;
}
}
Thanks a lot for your proposal @Archibum!
I will explain better what I’m triing to achieve maybe you could help me better. I am writing a scrip to modify the elevation of all the points in a TopographycSurface (TS). I need to move vertically all the points of a TS a same distance.
To edit de TS you have to call a the TopographyEditScope class and call a .start() and .commit() method like you would do with a Transaction. My problem comes with the TopographyEditScope.Commit() method.It needs the IFailuresPreprocessor interface to be passed. I found on the net this issue that handles a similar problem, here is where I found the definition of the class.
I leave my code below (with your definition of the class) if you want to test. For the moment I get no errors from pyRevit but it fails and I get this error (see image below) from Revit itself. I suspect that something goes wrong with the TopographyEditScope.Commit() method.
# coding=utf-8
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import TopographyEditScope
from Autodesk.Revit.UI import *
from Autodesk.Revit.UI.Selection import ObjectType
from System.Collections.Generic import List
# Helper classes
class MyFailureProcessor(IFailuresPreprocessor):
def FailureProcessingResult(self, FailuresAccessor):
return FailureProcessingResult.Continue
# 0 - initial statements
uiapp = __revit__
uidoc = uiapp.ActiveUIDocument
doc = uiapp.ActiveUIDocument.Document
scriptName = 'SetTopoPointsElevation'
refPick = uidoc.Selection.PickObject(ObjectType.Element, "Pick an element")
TopoSurface = doc.GetElement(refPick)
TopoSurfaceId = TopoSurface.Id
## Here, it would be nice to be able to pick just TopographySurface object.
#Define offset elevation
OffsetElevation = 10.00
TopoSurfacePoints = TopoSurface.GetPoints()
TopoEditScope = TopographyEditScope(doc,"Edit Points Elevation")
TopoEditScope.Start(TopoSurfaceId)
t = Transaction (doc,scriptName)
t.Start()
for point in TopoSurfacePoints:
PointElevation = point.Z
NewPointElevation = PointElevation + OffsetElevation
TopoSurface.ChangePointElevation(point, NewPointElevation)
failProc = MyFailureProcessor()
t.Commit()
TopoEditScope.Commit(failProc)
# N - OUTPUT
print('Nom: ' + TopoSurface.Name + '\n')
print('Nombre de punts: ' + str(TopoSurfacePoints.Count))
Hi @Jean-Marc . I’ve already tried what you suggested and it doesn’t work. I really don’t understand what’s going on.
If I set the t.start() before the TopoEditScope.Start() I get this error:
I also tried to finish the Transaction before finishing de TopoEditScope and I get this error:
“Autodesk.Revit.Exceptions.InvalidOperationException: EditScope cannot be closed, for there is a transaction group still open in the document.”
I am not sure but it seems somehow it doesn’t close the transaction or the TopoEditScope.
I don’t understand why the helper class MyFailureProcessor defines the function FailureProcessingResult()
class MyFailureProcessor(IFailuresPreprocessor):
def FailureProcessingResult(self, FailuresAccessor):
return FailureProcessingResult.Continue
It’s not used in the main code and maybe the FailureProcessingResult.Continue is the way to close/commit succesfully the TopoEditScope…
I’ll keep triing.
The function inside the MyFailureProcessor class should be PreprocessFailures(self, failuresAccessor), not FailureProcessingResult(self, FailuresAccessor) as you have in your code.
Also, if you want to add a filter to select only topo surfaces, you can add this class:
class topo_filter(Selection.ISelectionFilter):
def AllowElement(self, element):
if isinstance(element, Architecture.TopographySurface):
return True
def AllowReference(self, ref, point):
return True
and then edit your PickObject method to include that filter, like this:
refPick = uidoc.Selection.PickObject(ObjectType.Element, topo_filter(), "Pick an element")
// Edit scope for all changes
using (TopographyEditScope editScope = new TopographyEditScope(doc, "Edit TS"))
{
editScope.Start(toposurface.Id);
using (Transaction t = new Transaction(doc, "Normalize terrain"))
{
t.Start();
// Change all points to same elevation
toposurface.ChangePointsElevation(points, elevation);
t.Commit();
}
editScope.Commit(new TopographyEditFailuresPreprocessor());
}
}
Great @Jean-Marc !
I’ve added the UnitUtils.ConvertToInternalUnits() method because I work in meters. It is writen for Revit2020, I think in Revit2022 it has change the implementation (I leave it below).
I’ll learn many things from you code. I am new coding with pyRevit, just a question; Why do you import from the pyRevit library? Is it faster?? Is it better??
And by the way, there is in the pyRevit library a form to ask the user to write an imput (in this case the OffsetElevation)?
Thanks!
from Autodesk.Revit.DB.Architecture import TopographyEditScope
from Autodesk.Revit.DB import UnitUtils, DisplayUnitType
from pyrevit import revit, DB, forms, script, UI
from pyrevit.revit.selection import pick_element_by_category
# Helper classes
class MyFailureProcessor(DB.IFailuresPreprocessor):
def PreprocessFailures(self, failuresAccessor):
return DB.FailureProcessingResult.Continue
# initial statements
doc = revit.doc
with forms.WarningBar(title='Select Topography Surface'):
try:
TopoSurface = pick_element_by_category(DB.BuiltInCategory.OST_Topography, 'Select Topography Surface')
TopoSurfaceId = TopoSurface.Id
except:
script.exit()
#Define offset elevation (in meters)
OffsetElevation = 10.00
OffsetElevationInternalUnits = UnitUtils.ConvertToInternalUnits(OffsetElevation,DisplayUnitType.DUT_METERS)
TopoSurfacePoints = TopoSurface.GetPoints()
# Main transaction getting to the topo edition mode
TopoEditScope = TopographyEditScope(doc,"Edit Points Elevation")
TopoEditScope.Start(TopoSurfaceId)
# sub transaction assigning the elevation to the points
# handling of commiting the transaction is done with pyrevit revit.Transaction
with revit.Transaction("Move Points Elevation"):
for point in TopoSurfacePoints:
PointElevation = point.Z
NewPointElevation = PointElevation + OffsetElevationInternalUnits
TopoSurface.ChangePointElevation(point, NewPointElevation)
# sub transaction is ended
# Closing the topo edition mode
failProc = MyFailureProcessor()
TopoEditScope.Commit(failProc)
output = script.get_output()
output.close_others()
# N - OUTPUT
forms.alert(msg = 'Nom de la surface: ' + TopoSurface.Name + '\n' + 'Nombre de points: ' + str(TopoSurfacePoints.Count), title = 'Nombre de points')