Erasing points inside a Toposurface using Python in Dynamo

In Python 3 inside Dynamo for Revit 2023 I am trying and failing to erase all the interior points inside a Toposurface using Python. My script goes as follows:


# Import necessary CLR assemblies and references
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')
clr.AddReference('RevitServices')

# Import Revit API namespaces
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import *
from Autodesk.Revit.UI import *

# Import RevitNodes to allow for Dynamo & Revit type conversions
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import RevitServices for Document and Transaction management
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Define a custom failure processor by implementing the IFailuresPreprocessor interface
class CustomFailureProcessor(IFailuresPreprocessor):
    def PreprocessFailures(self, failuresAccessor):
        # Ignore all failures for simplicity
        failures = list(failuresAccessor.GetFailureMessages())
        for failure in failures:
            failuresAccessor.DeleteWarning(failure)
        return FailureProcessingResult.Continue

# Get the current Revit document from the Document Manager
doc = DocumentManager.Instance.CurrentDBDocument

# Assuming the input is a topography surface element wrapped in Dynamo
topoSurface = UnwrapElement(IN[0])  # Unwrap the Dynamo element to get the Revit element

# Get the interior points of the topography surface
interiorPoints = topoSurface.GetInteriorPoints()

# Begin a transaction to modify the document
TransactionManager.Instance.EnsureInTransaction(doc)

# Define a scope for editing the topography, required for certain operations
topoEditScope = TopographyEditScope(doc, "Edit Topography Scope")
topoEditScope.Start(topoSurface.Id)

try:
    # Perform the operation: Delete interior points from the topography surface
    topoSurface.DeletePoints(interiorPoints)
    doc.Regenerate()
finally:
    # Always ensure to close the TopographyEditScope properly
    topoEditScope.Commit(CustomFailureProcessor())

# End the transaction
TransactionManager.Instance.TransactionTaskDone()

# Output the number of deleted points for verification
OUT = len(interiorPoints)

However I get the error “InvalidOperationException”: This TopographyEditScope is not permited to start at this moment for one of the possible reasons: The document is in read-only state, or the document is currently modifiable, or there already us another edit mode active in the document. And ok, I get it, I am already opening a transaction. However if I access the TopographyEditScope without the TransactionManager.Instance.EnsureInTransaction(doc) it says I need a previous transaction for the TopographyEditScope to start. Grouping the transactions does not seem to be working either. Has anyone solved a similar issue?
R23_TopographyEditScope.dyn (6.5 KB)

1 Like

@luisaECXV3 ,

here your clean code, at first view looks like AI generated and evaluated by a real brain. So i would not open a transaction in a transaction.


import clr
clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")
clr.AddReference("ProtoGeometry")
clr.AddReference("RevitNodes")
clr.AddReference("RevitServices")

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import *
from Autodesk.Revit.UI import *

import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

# 0️⃣ Define a custom failure processor by implementing the IFailuresPreprocessor interface
class CustomFailureProcessor(IFailuresPreprocessor):
    def PreprocessFailures(self, failuresAccessor):
    # 💤 Ignore all failures for simplicity
        failures = list(failuresAccessor.GetFailureMessages())
        for failure in failures:
            failuresAccessor.DeleteWarning(failure)
            return FailureProcessingResult.Continue 



# 1️⃣ Assuming the input is a topography surface element wrapped in Dynamo
topoSurface = UnwrapElement(IN[0]) 

# 2️⃣ Get the interior points of the topography surface
interiorPoints = topoSurface.GetInteriorPoints()

# 🔓 Begin a transaction to modify the document
TransactionManager.Instance.EnsureInTransaction(doc)

# Define a scope for editing the topography, required for certain operations
topoEditScope = TopographyEditScope(doc, “Edit Topography Scope”)
topoEditScope.Start(topoSurface.Id)

try:
    # Perform the operation: Delete interior points from the topography surface
    topoSurface.DeletePoints(interiorPoints)
    doc.Regenerate()
finally:
    # Always ensure to close the TopographyEditScope properly
    topoEditScope.Commit(CustomFailureProcessor())

# 🔒 End the transaction
TransactionManager.Instance.TransactionTaskDone()

# ✅ Output the number of deleted points for verification
OUT = len(interiorPoints)

i can not replicate your topic directly. will see what others write…

# 🔓 Begin a transaction to modify the document
t = Transaction(doc, "Edit Topography Scope")
t.Start()

# Define a scope for editing the topography, required for certain operations
topoEditScope = TopographyEditScope(doc)

try:
    # Perform the operation: Delete interior points from the topography surface
    topoSurface.DeletePoints(interiorPoints)
    doc.Regenerate()
except:
    # Always ensure to close the TopographyEditScope properly
    topoEditScope.Commit(CustomFailureProcessor())

# 🔒 End the transaction
t.Commit()

KR

Andreas

1 Like

First, thank you very much for replying, Andreas. So, I tried following the steps you mentioned for setting up the transactions, but for some reason, the DeletePoints method still isn’t playing ball. I went back, double-checked everything, and even swapped TopoSurface for Topography , making sure to pack the interior points into an IList since that seemed to be what DeletePoints was looking for. But, guess what? Those points are still there, as if they’re mocking me. I even went the extra mile to make sure they were actually gone, but no luck. So, what gives? Is the DeletePoints method just messing with me, or am I missing something obvious here?
R23_TopographyEditScope_V2.dyn (7.2 KB)
R23_Topo.rvt (4.4 MB)

# Import necessary CLR assemblies and references
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')
clr.AddReference('RevitServices')

# Import Revit API namespaces
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import *
from Autodesk.Revit.UI import *

# Import RevitNodes to allow for Dynamo & Revit type conversions
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import RevitServices for Document and Transaction management
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Add .NET collections import
from System.Collections.Generic import List

# Get the current Revit document from the Document Manager
doc = DocumentManager.Instance.CurrentDBDocument

# Getting the topography with a Filter. At first I tried getting the Toposurface directly and this gave me nothing, so new approach:
topoSurfaces = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Topography).ToElements() 


# Get the interior points of the topography surface
interiorPoints=[]
# Get the interior points of the topography surface and delete them
for topoSurface in topoSurfaces:
    pythonList = topoSurface.GetInteriorPoints()  # This gets the points as a Python list
    
    # Convert Python list to .NET IList[XYZ]. Realized this method needed an IList. Still not working anyway.
    interiorPoints = List[XYZ](pythonList)
    
    t = Transaction(doc, "Edit Topography Scope")
    t.Start()
    topoEditScope = TopographyEditScope(doc, "Topo")
    
    try:
        # Perform the operation: Delete interior points from the topography surface, this is what is not working and I can't guess what the problem is
        topoEditScope.Start()
        topoSurface.DeletePoints(interiorPoints)
        doc.Regenerate()
        topoEditScope.Commit()
    except Exception as e:
        OUT = e
        topoEditScope.Dispose() 
    finally:
        # End the transaction
        t.Commit()

newTopoPoints=topoSurface.GetInteriorPoints()
# Doble checking. Still no points deleted
OUT = pythonList,newTopoPoints, topoSurfaces

Can you send a link to which method you are attempting to use? I believe that delete points is a member of the TopographySurface class, not topographies in general.

Also I find it best to build your initial functions without a ‘try’ as it masks the errors which pop up. I would guess this is what you are seeing as you set OUT to the exception, but then later on redefine it as something else, thereby masking the exception entirely.

Of course. This is the method I am attempting to use DeletePoints Method it is indeed a TopographySurface Method, but so is GetInteriorPoints(), which is working correctly. When I remove the try and except like this:

# Import necessary CLR assemblies and references
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')
clr.AddReference('RevitServices')

# Import Revit API namespaces
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import *
from Autodesk.Revit.UI import *

# Import RevitNodes to allow for Dynamo & Revit type conversions
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import RevitServices for Document and Transaction management
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Add .NET collections import
from System.Collections.Generic import List

# Get the current Revit document from the Document Manager
doc = DocumentManager.Instance.CurrentDBDocument

# Getting the topography with a Filter. At first I tried getting the Toposurface directly and this gave me nothing, so new approach:
topoSurfaces = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Topography).ToElements() 


# Get the interior points of the topography surface
interiorPoints=[]
# Get the interior points of the topography surface and delete them
for topoSurface in topoSurfaces:
    pythonList = topoSurface.GetInteriorPoints()  # This gets the points as a Python list
    
    # Convert Python list to .NET IList[XYZ]. Realized this method needed an IList. Still not working anyway.
    interiorPoints = List[XYZ](pythonList)
    
    t = Transaction(doc, "Edit Topography Scope")
    t.Start()
    topoEditScope = TopographyEditScope(doc, "Topo")    
    topoEditScope.Start(topoSurface.Id)
    topoSurface.DeletePoints(interiorPoints)
    doc.Regenerate()
    topoEditScope.Commit()
    t.Commit()

newTopoPoints=topoSurface.GetInteriorPoints()
# Doble checking. Still no points deleted
OUT = pythonList,newTopoPoints, topoSurfaces

I get the error: “TopographyEditScope is not permitted to start at this moment for one of the following possible reasons: The document is in read-only state, or the document is currently modifiable, or there already is a topography surface edit mode active in the document.” Obviously the document is being edited, we started a transaction here. But if I remove the document transaction like this:

# Import necessary CLR assemblies and references
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')
clr.AddReference('RevitServices')

# Import Revit API namespaces
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import *
from Autodesk.Revit.UI import *

# Import RevitNodes to allow for Dynamo & Revit type conversions
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

# Import RevitServices for Document and Transaction management
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Add .NET collections import
from System.Collections.Generic import List

# Get the current Revit document from the Document Manager
doc = DocumentManager.Instance.CurrentDBDocument

# Getting the topography with a Filter. At first I tried getting the Toposurface directly and this gave me nothing, so new approach:
topoSurfaces = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Topography).ToElements() 


# Get the interior points of the topography surface
interiorPoints=[]
# Get the interior points of the topography surface and delete them
for topoSurface in topoSurfaces:
    pythonList = topoSurface.GetInteriorPoints()  # This gets the points as a Python list
    
    # Convert Python list to .NET IList[XYZ]. Realized this method needed an IList. Still not working anyway.
    interiorPoints = List[XYZ](pythonList)
    
    topoEditScope = TopographyEditScope(doc, "Topo")    
    topoEditScope.Start(topoSurface.Id)
    topoSurface.DeletePoints(interiorPoints)
    doc.Regenerate()
    topoEditScope.Commit()

newTopoPoints=topoSurface.GetInteriorPoints()
# Doble checking. Still no points deleted
OUT = pythonList,newTopoPoints, topoSurfaces

then I will get “Attempt to modify the model outside of transaction.” The topography edit scope documentation is here TopographyEditScope Constructor

Perhaps the solution would be to attempt to use a transaction group but this is still giving me the same problems.