Creating Roof By Footprint in Dynamo

Hi all!
Just learning dynamo and wanted to create a roof by footprint python node (instead of using a package) but can’t seem to get it working?
My aim is to give it 4 walls to input, it takes to location of those walls and builds a roof from the top.
Any ideas! :slight_smile:

# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

# Place your code below this line
#from Autodesk.Revit.ApplicationServices import Application from Autodesk.Revit.DB import BuiltInParameter as Bip
from Autodesk.Revit.DB import Transaction
doc = __revit__.ActiveUIDocument.Document
t = Transaction(doc, "Foot Print")
walls = IN[0]
walls_lines = [wall.Location.Curve for wall in walls]
level = doc.GetElement(ElementId(694))
roofType = doc.GetElement(ElementId(45441))
footprint = doc.Application.Create.NewCurveArray()
for modelCurve in walls_lines:
    footprint.Append(modelCurve)
t.Start()
footPrintToModelCurvesMapping = clr.StrongBox[ModelCurveArray](ModelCurveArray())
footPrintRoof = doc.Create.NewFootPrintRoof(footprint, level, roofType, footPrintToModelCurvesMapping)
bbox = footPrintRoof.get_BoundingBox(doc.ActiveView)
bboxMax = bbox.Max
bboxMin = bbox.Min
corner1 = bboxMax
corner2 = XYZ(bboxMax.X, bboxMin.Y, bboxMax.Z)
corner3 = XYZ(bboxMin.X, bboxMax.Y, bboxMax.Z)
corner4 = XYZ(bboxMin.X, bboxMin.Y, bboxMax.Z)
bboxCenter = (bboxMax + bboxMin) / 2
bboxCenterPt = XYZ(bboxCenter.X, bboxCenter.Y, bboxMax.Z - 500 / 304.8)
sbeditor = footPrintRoof.SlabShapeEditor
vertex1 = sbeditor.DrawPoint(corner1)
vertex2 = sbeditor.DrawPoint(corner2)
vertex3 = sbeditor.DrawPoint(corner3)
vertex4 = sbeditor.DrawPoint(corner4)
vertex5 = sbeditor.DrawPoint(bboxCenterPt)
spLine1 = sbeditor.DrawSplitLine(vertex1, vertex5)
spLine2 = sbeditor.DrawSplitLine(vertex2, vertex5)  # Corrected variable name
spLine3 = sbeditor.DrawSplitLine(vertex3, vertex5)  # Corrected variable name
spLine4 = sbeditor.DrawSplitLine(vertex4, vertex5)  # Corrected variable name
t.Commit()

# Assign your output to the OUT variable.
OUT = footPrintRoof

Welcome to the community @kyle.crossleyEFJ2F. :slight_smile:

I did a slight edit to your post to keep the formatting. You can do this yourself in the future by wrapping your code in triple ` marks.

As far as your current code goes, I am not sure what the issue is - can you post the warning to describe the resulting issue? You might want to look for ways to set the slope of the roof’s perimeter curves rather than shape editing the roof, as that will likely be more aligned with the typical UI generated roof.

HI Jacob!
Thanks! There so much information on here! no doubt ill be here trying to sort out my messy posts.

Thanks for getting back so quickly! as for the current error is this, however i don’t understand how it doesn’t know what Revit is? :')

Thanks Jacob :slight_smile:

Ah! I see the issue now. You haven’t configured the Python environment.

You’re making a call to the Revit class in line 12, but the Revit class hasn’t been added to the environment yet.

See the post here for an example of why we make the various imports: Create and Export 2D Lines Loop Profile Family - #4 by jacob.small

A good boilerplate template for Revit interaction can be found here: dynamoPython/RevitPythontemplateFile at 883c11fd62c3a2b35790a5e3fed87720bcd6e557 · Amoursol/dynamoPython · GitHub

Those are so useful!! Why are they so diffcult to find on here! :slight_smile: Thanks Jacob!

After reading through these posts and adding the base revit interaction at the start of my code. I its not struggling to reference the wall location? Im using the wall.Location.Curve at the moment but i dont think this is the correct use. either that or im missing something to import? :confused: Any help would be amazing! :slight_smile:

import clr

# Import ToDSType(bool) extension method
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)

# Import geometry conversion extension methods
clr.ImportExtensions(Revit.GeometryConversion)

# Import DocumentManager and TransactionManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *
# Imports Ilists module into python
clr.AddReference("System")
from System.Collections.Generic import List as cList


# Standard areas for Current Document, Active UI and application
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

walls = IN[0]
walls_lines = [wall.Location.Curve for wall in walls]
level = doc.GetElement(ElementId(694))
roofType = doc.GetElement(ElementId(45441))
footprint = doc.Application.Create.NewCurveArray()

for modelCurve in walls_lines:
    footprint.Append(modelCurve)

t.Start()
footPrintToModelCurvesMapping = clr.StrongBox[ModelCurveArray](ModelCurveArray())
footPrintRoof = doc.Create.NewFootPrintRoof(footprint, level, roofType, footPrintToModelCurvesMapping) 
bbox = footPrintRoof.get_BoundingBox(doc.ActiveView)
bboxMax = bbox.Max
bboxMin = bbox.Min
corner1 = bbox.Max
corner2 = XYZ(bboxMax.X, bboxMin.Y, bboxMax.Z) 
corner3 = XYZ(bboxMin.X, bboxMax.Y, bboxMax.Z) 
corner4 = XYZ(bboxMin.X, bboxMin.Y, bboxMax.Z) 
bboxCenter = (bboxMax + bboxMin) / 2 
bboxCenterPt = XYZ(bboxCenter.X, bboxCenter.Y, bboxMax.Z - 500/304.8)

sbeditor = footPrintRoof.SlabShapeEditor 
vertex1 = sbeditor.DrawPoint(corner1) 
vertex2 = sbeditor.DrawPoint(corner2) 
vertex3 = sbeditor.DrawPoint(corner3)
vertex4 = sbeditor.DrawPoint(corner4) 
vertex5 = sbeditor.DrawPoint(bboxCenterPt)
spLine1 = sbeditor.DrawSplitLine(vertex1, vertex5)
spLine2 = sbeditor.DrawSplitLine(vertex2, vertex5)
spLine3 = sbeditor.DrawSplitLine(vertex3, vertex5)
spLine4 = sbeditor.DrawSplitLine(vertex4, vertex5)
t.Commit()

# Assign your output to the OUT variable.
OUT = footPrintRoof

There are a lot of resources out there for learning the Revit API and Python interaction. The hard part is that most people jump in to solve a problem rather than learn how to build a solution and why it’s done the way it is. Dynamo suffers the same. As a result when searching for stuff to help you leant, so the content which helps you learn the reasoning often gets suppressed below the content which gives an answer to a particular problem. It also doesn’t help that the API for Revit and Civil 3D and other tools are often so complex that experts need answers to build their implementations… :frowning:

It’s a holiday here for me, but I’ll try and have a look at this later today when I have to sign on to check some emails and video chat with a friend.

I understand! I’m starting off new completely, but i prefer to look at working code to understand how it works. Every job i seem to see is so niche, but i will get there eventually :slight_smile:
Thanks Jacob! Enjoy your holiday, no rush at all! :slight_smile:

After reading through tit here seemed to be # stopping some of the imports. Still not working properly but moving further down the code removing errors as we go :slight_smile: Here is what im up to now.

The issue im having at the moment is the Wall.Location.Line with Wall.Location not having a .Line attribute. Managed to find this website and its proving useful! :slight_smile:

import clr #adds the Common Language Runtime to the iron python environment so we can call .net code

clr.AddReference("System")
from System.Collections.Generic import List

clr.AddReference("RevitNodes") #adds the Revit nodes namespace to the CLR 
import Revit #imports the Revit namesapce into the iron python environment
#clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion) #adds the Revit Geometry Conversion namespace ot the CLR

from Revit import GeometryConversion as gc #imports the geometry conversion extension to facilitate changing form Dynamo geometry to Revit geometry

clr.AddReference("RevitServices") #adds the RevitServices namespace to the CLR
import RevitServices
from RevitServices.Persistence import DocumentManager #imports the document manager to the iron python environment
from RevitServices.Transactions import TransactionManager #imports the transaction manager to the iron python 
clr.AddReference("RevitAPI") #adds the revit api to the CLR
from Autodesk.Revit.DB import IFamilyLoadOptions, SaveAsOptions, FilteredElementCollector, View, Wall, Curve #adds the relevant sections of the Revit API to the iron python environment

activeDoc = DocumentManager.Instance.CurrentDBDocument #sets the active document variable to the current revit document
uiapp = DocumentManager.Instance.CurrentUIApplication #sets the uiapp variable to the current UI application - doing this so we can set up the current app
app = uiapp.Application #sets the app variable tot he current application of the uiapp



doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

wall = UnwrapElement(IN[0])
level = IN[1]
roofType = IN[2]

footprint = doc.Application.Create.NewCurveArray()

walls_lines = [Wall.Location.Line for wall in wall]

# Loop over the lines and convert them to curves
for modelcurve in walls_lines:
    footprint.modelcurve

TransactionManager.Instance.EnsureInTransaction(doc)

footPrintToModelCurvesMapping = ModelCurveArray()
footPrintRoof = doc.Create.NewFootPrintRoof(footprint, level, roofType, footPrintToModelCurvesMapping) 
bbox = footPrintRoof.get_BoundingBox(doc.ActiveView)
bboxMax = bbox.Max
bboxMin = bbox.Min
corner1 = bbox.Max
corner2 = XYZ(bboxMax.X, bboxMin.Y, bboxMax.Z) 
corner3 = XYZ(bboxMin.X, bboxMax.Y, bboxMax.Z) 
corner4 = XYZ(bboxMin.X, bboxMin.Y, bboxMax.Z) 
bboxCenter = (bboxMax + bboxMin) / 2 
bboxCenterPt = XYZ(bboxCenter.X, bboxCenter.Y, bboxMax.Z - 500/304.8)

sbeditor = footPrintRoof.SlabShapeEditor 
vertex1 = sbeditor.DrawPoint(corner1) 
vertex2 = sbeditor.DrawPoint(corner2) 
vertex3 = sbeditor.DrawPoint(corner3)
vertex4 = sbeditor.DrawPoint(corner4) 
vertex5 = sbeditor.DrawPoint(bboxCenterPt)
spLine1 = sbeditor.DrawSplitLine(vertex1, vertex5)
spLine2 = sbeditor.DrawSplitLine(vertex2, vertex5)
spLine3 = sbeditor.DrawSplitLine(vertex3, vertex5)
spLine4 = sbeditor.DrawSplitLine(vertex4, vertex5)

TransactionManager.Instance.TransactionTaskDone

OUT = footPrintRoof

Comment out all the lines after the one you are having the error with.

Then removing the ‘.Line’ from that line so it just reads Wall.Location.

Add a new line OUT = dir(walls_lines[0])

This will show you what you can do with the object type which you have.

Where did you get this base code by the way? Any chance Chat GPT was involved? Seems a bit complex relative to type of failure points we are seeing - I’d expect you to post ‘I am having a hard time’ at the first failure rather than write everything after that.

Hi Jacob! :slight_smile:
Base code is from here

Obviously its not in the same environment so its slightly different but apart from that, hes a really cool guy to follow! :slight_smile:
I’ll give those edits a go when i get home :slight_smile:
Thanks!

The forum is your friend, use it as such :slight_smile:

To find this post I simply searched for the method you are using: NewFootPrintRoof.

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from clr import StrongBox

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")
import Revit

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

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = uiapp.ActiveUIDocument

outline = IN[0]
level = UnwrapElement(IN[1])
roofType = UnwrapElement(IN[2])

footprint = CurveArray()

for o in outline:
    footprint.Append(o.ToRevitType(True) )
    
TransactionManager.Instance.EnsureInTransaction(doc)

# A strongbox containing a modelcurvearray
roofCurves = StrongBox[ModelCurveArray](ModelCurveArray())
New_Roof = doc.Create.NewFootPrintRoof(footprint, level, roofType, roofCurves)

TransactionManager.Instance.EnsureInTransaction(doc)

OUT = New_Roof

This code takes in the curves from Dynamo, extracted from the walls. If you wanted to take the geometry directly from the walls you would have to tweak it but I’m sure you can use the forum to help you get that :).

2 Likes

HI!
Thanks for you r help, however this is just creating a flat roof. I have seen many posts and even some basic nodes that do this. Roof.ByOutlineTypeAndLevel for Example. Im trying to make hipped roofs. Something that isn’t integrated into Dynamo. In revit you can either made a hipped roof by Extrusion or Hipped Roof Via Footprint. I’m trying to get the “Roof By Footprint” equivilent in a local Python Dynamo node without using a package.

Thanks for your Help though! These links are very descriptive and useful