Cut sloped floors intersecting with a plane

Hi there,
@Nick_Boyts

After reading the following post.

Cut all elements intersecting with a plane - Revit - Dynamo (dynamobim.com)

I made this script to cut floors by a project-wide grid.

split test 02.rvt (512 KB)
vloeren splitsen 03.dyn (102.6 KB)

I have two questions.

  1. Is there a way to manipulate planes by reference planes rather than to define them by Coordinates?
    2.As mentioned in the post, angled or non planar floors are not accepted as the curves do not define a horizontal loop. Any ideas on how to take this further?

I understand System-family-Floors have some restrictions, but any quantifiable copy will do.

The purpose is quantification and phasing on a dedicated model.

Kind regards,

Willem

Do you really want to overlap floors on top of floors like this? Seems like creating parts and splitting those would be better here as they’d keep the original geometry and not insert new warnings.

1 Like

Hi @jacob.small

very generous to give the solution to 2 questions by making only 1 suggestion!

This covers already 50 % of the needs.

And as it appears, the first solutions covers non-planar floors too.

The fact that we have two Floors in the same place in the same place is not really an issues, I would consider a separate model for quantification.

1.If there is a way to use the parts-strategy for non-planar Floors, do not hesitate to share.
2.If no, is there a way to tie geometry to a reference plane, so reference planes can serve both strategies?

Kind regards,

Willem

So the advantage with parts is that it’s already pretty automated in the user interface -

  1. Draw and name your reference planes
  2. Select your floors to make parts from
  3. Make the floor into parts
  4. Select the parts to split the parts by the reference plans by selecting the reference planes by name.

This covers pretty much any shape which can make parts, so most floors, and in the sample you provided is a total of 10 clicks, and likely runs faster than it’ll take to open Dynamo. That said you might want to automate it all the same, so…

The API and therefore Dynamo also enable the same sequence; I recall there are packages to do this but I couldn’t remember what they were and didn’t have them in my library so I built some Python.

The graph:

I used filters for the comment parameter of the floor and the name of the reference planes; you might want another method (select model elements might work better here instead). Then the first bit of Python creates parts from the floors.

Create or Get Parts From Element
########################################
############## Properties ##############
########################################
__author__ = 'Jacob Small'
__version__ = '0.1.0'
__description__ = "Generate or get the parts from an element."
__RevitBuilds__ = "2023.1"
__DynamoBuilds__ = "2.16"
__ReleaseNotes__ = "POC only - review and test closely before using in production."
__Dependancies__ = "None"
__Copyright__ = "2024, Autodesk Inc."
__License__ = "Apache 3"



########################################
### Configure the Python environment ###
########################################
### standard imports ###
import sys #add the sys class to the Python environment so we can work with the sys objects
import clr #add the CLR (common language runtime) class to the Python environment so we can work with .net libraries

### Dynamo Revit imports ###
clr.AddReference("RevitNodes") #add Dynamo's Revit nodes library to the clr
import Revit #import Dynamo's Revit node class
clr.ImportExtensions(Revit.Elements) #add the element conversion methods to the CLR
clr.AddReference("RevitServices") #add the Revit services library to the CLR
import RevitServices #import the Revit services class to the Python environment
from RevitServices.Persistence import DocumentManager #import the document manager class to the Python environment 
from RevitServices.Transactions import TransactionManager #import the transaction manager class to the Python environment 

### Revit API imports ###
clr.AddReference("RevitAPI") #add the Revit API to the CLR
import Autodesk #add the Autodesk class to the Python environment 
from Autodesk.Revit.DB import * #import every class of the Revit API to the Python environment

### .net imports ###
clr.AddReference("System") #add the .net System library to the CLR
from System.Collections.Generic import List as NetList #imports the .net list module to the Python environment as the alias NetList



#########################################
###### Global variables and inputs ######
#########################################
### documents and standard variables ###
doc = DocumentManager.Instance.CurrentDBDocument #the current Revit document
### imports and unwrapping ###
floors = UnwrapElement(IN[0]) #import the floors from IN[0] of the Dynamo environment and convert to native Revit elements
if not floors.__class__ == [].__class__ : floors = [floors] #ensure that floors is a list, not an individual object, so that we can always prepare for a loop

OUT = [] #set the OUTput to an empty list

TransactionManager.Instance.EnsureInTransaction(doc) #start transaction
for floor in floors: #for eachf loor
    hasParts = PartUtils.HasAssociatedParts(doc,floor.Id) #check if the floor has aprts
    if not hasParts: #if not
        makeParts = PartUtils.CreateParts(doc, NetList[ElementId]([floor.Id])) #make parts from the element
        doc.Regenerate() #regenerate the document
    partIds = PartUtils.GetAssociatedParts(doc,floor.Id,True,True) #get the part ids from the element
    parts = [doc.GetElement(p) for p in partIds] #for each part from the part Id
    OUT.append(parts) #append the list of parts to the OUT list
TransactionManager.Instance.TransactionTaskDone() #end transaction

From there I used another bit of python to split the parts - you may want to filter some stuff out - perhaps only split parts which are finish floors, or which are a particular material, or something else.

Split Parts by Elements
########################################
############## Properties ##############
########################################
__author__ = 'Jacob Small'
__version__ = '0.1.0'
__description__ = "Splits each part in a list of parts by a list of datum elements."
__RevitBuilds__ = "2023.1"
__DynamoBuilds__ = "2.16"
__ReleaseNotes__ = "POC only - review and test closely before using in production."
__Dependancies__ = "None"
__Copyright__ = "2024, Autodesk Inc."
__License__ = "Apache 3"



########################################
### Configure the Python environment ###
########################################
### standard imports ###
import sys #add the sys class to the Python environment so we can work with the sys objects
import clr #add the CLR (common language runtime) class to the Python environment so we can work with .net libraries

### Dynamo Revit imports ###
clr.AddReference("RevitNodes") #add Dynamo's Revit nodes library to the clr
import Revit #import Dynamo's Revit node class
clr.ImportExtensions(Revit.Elements) #add the element conversion methods to the CLR
clr.AddReference("RevitServices") #add the Revit services library to the CLR
import RevitServices #import the Revit services class to the Python environment
from RevitServices.Persistence import DocumentManager #import the document manager class to the Python environment 
from RevitServices.Transactions import TransactionManager #import the transaction manager class to the Python environment 

### Revit API imports ###
clr.AddReference("RevitAPI") #add the Revit API to the CLR
import Autodesk #add the Autodesk class to the Python environment 
from Autodesk.Revit.DB import * #import every class of the Revit API to the Python environment

### .net imports ###
clr.AddReference("System") #add the .net System library to the CLR
from System.Collections.Generic import List as NetList #imports the .net list module to the Python environment as the alias NetList



#########################################
###### Global variables and inputs ######
#########################################
doc = DocumentManager.Instance.CurrentDBDocument #the current Revit document

parts = UnwrapElement(IN[0]) #import the parts from IN[0] of the Dynamo environment and convert to native Revit elements
if not parts.__class__ == list : parts = [parts] #ensure the parts variable is a list

splitters = UnwrapElement(IN[1]) #import the splitter elements from IN[1] of the Dynamo environment anc onvert to native Revit elements
if not splitters.__class__ == list : splitters = [splitters] #ensure the splitters variable is a list
splitters = [e.Id for e in splitters] #convert the splitter elements to a list of element IDs
splitters = NetList[ElementId] (splitters) #convert the splitters list to a .net list

defaultSketchPlane = FilteredElementCollector(doc).OfClass(SketchPlane).FirstElementId() #get a sketch plane to use when dividing parts

OUT = [] #set the OUTput to an empty list

TransactionManager.Instance.EnsureInTransaction(doc) #start transaction
for part in parts: #for each part
    partId = NetList[ElementId] ([part.Id]) #get the aprt ID as a .net list
    dividing = PartUtils.DivideParts(doc, partId, splitters, NetList[Curve](), defaultSketchPlane) #divide the part by the splitter elements
    OUT.append(dividing) #append the dividing result to the OUT list
TransactionManager.Instance.TransactionTaskDone() #end transaction

Thank you @jacob.small , this is really helpfull and gives an insight in how to tweak the script.

You are right that the user interface is straightforward and fast, the reason I look at Dynamo is that;
-I want to assign metadata both from the original element as from the reference planes.
-Both the original element and the data tend to change through iterations in the design process.

Therefore I would like to adress the non-coplanar copy accordingly, following the same reference planes.

What is the shortest way to get reference planes recognized as geometry?

Kind regards,

Willem

Split floors by reference planes.dyn (65.1 KB)
split test 03.rvt (468 KB)

Well that node shouldn’t be used - it is a stopgap at best as lunchbox hasn’t been supported for Dynamo in a half decade now as the owners abandoned the code base way back when.

You can pull the geometry from a reference plan using a property of the reference plane. In your library go to:
Revit > Elements > Reference Planes > ?

One of the items in the properties (the ? section) will have a ‘Plane’ or ‘Dynamo Plane’ or similar.

OK, there is a "ReferencePlane.Plane " Node indeed…I’ll try to build the habit of looking there first

Although it seems better practice to manage these routines separately, I post them together if anybody is interested.


Split floors by Floors and parts reference planes.dyn (92.9 KB)

1 Like

Hi @jacob.small

I try to run the same graph, but now on a linked model.

Creating floors goes well, but there is an issue with the parts.

Dividing Parts is not available in the user interface when I select a part on a linked model…so is it doable through script, or can they only be made in the original model?

Kind regards,

Willem
Split floors by Floors and parts reference planes gelinkte elementen 03.dyn (69.3 KB)

split test 03.rvt (508 KB)
copie voor P & F met eigen refplanes.rvt (492 KB)

Are you creating the floor in the link somehow? Or in your model?

If you’re trying to make parts in your model from an element in a link you need to make quite a few changes. The method for that requires a LinkElementId instead of a ElementId, which requires a different constructor.

The specific method to create parts form a linked element is shown here: CreateParts Method (Document, ICollection(LinkElementId))

And the constructor for a LinkedElementId which is required in that method is here: LinkElementId Constructor (ElementId, ElementId).

I don’t have time to rework the code for this added complexity, but if you give it a shot I can try to guide you along.