Python Scripts that cut any element intersecting a reference plane

Hi All,
Has anyone ever tried writing a Python script that cuts any element in Revit which intersect with a reference plane?

Not quite sure how you’d cut a door or window.

not the doors, I mean walls, pipes, ducts, MEPs…floors…I have created separate scripts for each of these but they have their own limitations. I want to do it using REVIT API. Create a code that can cut almost everything on its way, excluding some elements as you mentioned.

You have separate scripts for each scenario and they work? Why can’t you just copy/paste into a single graph? As you said, they have their own limitations, so they’re going to have to be handled separately on at least some occasions. Best to keep them separate then. Are you worried about performance? Missing certain objects?

3 Likes

This is the class and method I’d start with:

Initially run a high level intersection to get all elements intersecting a plane (maybe a bounding box intersection collector?), then get the halfspace of their solid geometry. Finally get all their faces that are planar with the cutting plane.

2 Likes

Nick,

Since we need to split each model (Mechanical, Electrical,…) separately, I did not make one graph for the whole script. I am worried both regarding performance and missing objects! That’s why I need something more robust and powerful to do the job at first run.

I could split pipes and ducts super easily using ‘Split.ByPoints’ node. For cable trays, floors, and conduits, this node doesn’t work, so I copied the element at their original locations and used ‘curved.split.bypoints’ node to split these elements and delete the original element. For wall elements, the ‘Split.ByPoints’ node works but when the wall is hosting an element, dynamo removes or relocates that hosted element once the script is run. For floor elements, the script can not cut the sloped floors.

I can share all the scripts here if you like

Thanks, Gavin. I’d follow up what you proposed

Have used this script for spliting walls by level. its well commented should be able to adapt it to split by reference plane but need someone better at code then me (i am not the original auther no idea who is)

should be able to use something similiar for floors.

import clr
 
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument
 
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
 
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
 
import System
from System.Collections.Generic import *
 
############## Definitions Start ##############
# Convert to List if singleton...
def tolist(obj1):
    if hasattr(obj1,"__iter__"): return obj1
    else: return [obj1]
     
# Returns the index of the found level given a Level and a list of Levels...
def FindLevelIndex(levels, lev):
    ind = None
    i = 0
    for l in levels:
        if l.Id.ToString() == lev.Id.ToString():
            ind = i
        i = i+1
    return ind
 
# Copy the original wall and set it's levels using the Built-In Parameters for the Base and Top Constraints...
def CopyWallByLevel(wall, b, t):
    wallOut = None
    try:
        # Copy the Original Wall with a transformation vector of 0,0,0...
        w = ElementTransformUtils.CopyElement(doc,wall.Id,XYZ(0,0,0))
        # Since the CopyElements method returns the ElementId of the new wall we need to get this Element from the Document...
        w = doc.GetElement(w[0])
        # Update the Base and Top constraints Parameters using the Built-In Parameters.
        # Note: I have explicitly chosen the Overload as I was getting flaky behaviour where the wrong overload was being used...
        p = w.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT)
        p.Set.Overloads.Functions[2](b.Id)
        p = w.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE)
        p.Set.Overloads.Functions[2](t.Id)
        wallOut = w.ToDSType(True)
    # Write out any exceptions...
    except Exception, e:
        wallOut = e.message
    # Return new wall..
    return wallOut    
############## Definitions End ##############
 
# IN-Variables...
run = tolist(IN[0])[0]
walls = tolist(UnwrapElement(IN[1]))
 
# OUT-Variables...
outList = []
 
# Main Script...
# Test if user has selected Run as True...
if run:
    # Get All Levels in the Document and cast to .net List...
    levels = list([l for l in FilteredElementCollector(doc).OfClass(Level).ToElements()])
    # Sort Levels by Elevation using a lamda expression...
    levels.sort(key=lambda x: x.Elevation, reverse=False)
     
    # Start a new Transaction ready for modifying the Document...
    TransactionManager.Instance.EnsureInTransaction(doc)
    for w in walls:
        arr = []
        # Check if the Element is a Wall...
        if w.GetType() == Wall:
            # Get Base and Top Constraints as Levels...
            p = w.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT)
            base = doc.GetElement(p.AsElementId())
            p = w.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE)
            top = doc.GetElement(p.AsElementId())
            
            # Test whether walls Base and Top levels are NOT the same, if they are we will skip this wall, if they are not then we will get the Index of the Level in the sorted list of Levels we collected earlier for both the Base and Top of the wall...
            if not base.Id.IntegerValue == top.Id.IntegerValue:
                # Note: we are setting the bounds of the Loop below with the Indices of the found Levels so we will only loop through the Levels in between the Base and Top Levels...            
                i = FindLevelIndex(levels,base)
                j = FindLevelIndex(levels,top)
                
                # Loop through the Levels between the Base and Top Levels copying the original wall for each iteration and stepping up one Level...
                while i < j:
                    wCopy = CopyWallByLevel(w,levels[i], levels[i+1])
                    arr.append(wCopy)    
                    i = i+1
                outList.append(arr)
                # Delete original Wall as this has now been split by Level...
                doc.Delete(w.Id)
    # End the Transaction...
    TransactionManager.Instance.TransactionTaskDone()
    # Return the new Walls...
    OUT = outList
# Return if user has not set input Run to True...
else:
    OUT = "Please Set Run to True"
1 Like