I found an old script that creates and crops Floor plans based on Room Boundaries, and I have been trying to adapt it to work with Areas in the latest versions of python, dynamo, and revit. Here is the original script from archi-lab. I searched through the forum and the two relevant instances of this problem were never solved: 1 and 2
With my current string, I was able to create a list area keys of the first instance of every “Suite Type”, as well as find its are boundaries. Currently, I have the revit key for the area, and the boundaries of the area, but now I just need to automate the view creation. I made the boundaries separate, as I could not figure out how to implement them in the script.
I made some edits to the archi-lab script to adapt it to areas, but majority of the functions don’t translate automatically - see attached - any help is appreciated a TON.
By my parsing of the information, the script gets caught up with BoundingBox, which I know does not apply to area boundaries, but I cant find any function that produces the area boundaries in a way that the current function can read.
Here is the errors I get if i drop the “Areas” list into the archilab FloorPlan.ByRoom function without changes:
The errors would indicate that the bbox value is none - so i.BoundingBox[doc.ActiveView] is returning none.
From the API documentation
If the view box is not known or cannot be calculated, this will return the model box; if the model box is not known, this will return null reference
So it appears that areas do not have a bounding box - are the areas placed? You could check i.ViewSpecific parameter to see if it has a view associated
You could also try changing the method to i.get_BoundingBox(doc.ActiveView) see discussion on The Building Coder here
Thanks Mike. I decided to teach myself python in the last week as there seemed to be no movement, and came up with a solution. Fundamentally, areas and boundingbox werent linked, and that was the main issue. I adapted some old code for rooms to views from around 8 years ago, and made it work. the dynamo script + python looks convoluted, but the results were great. See below for my code, and attached for the definition - I guess this topic is technically closed now, even tho I am still adapting my code to automate more of the process.
I had to make individual lists for the Curves, Bounding Boxes, Areas, and Names of the areas, and reassign them back to the respective Areas in python as all of the built in parameters were coming up null.
Every parameter for Areas used is built in - except for “Suite Type” which is a project parameter assigned to units within my condos. Here is a proof of concept screengrab - the list filters only the first recurring instance of a “Suite Type”, and produces it as a view. I made “Unit 2” have the same “Suite Type” as “Unit 1” to show it.
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import Element wrapper extension methods
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
doc = DocumentManager.Instance.CurrentDBDocument
# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *
import System
from System import Array
from System.Collections.Generic import *
import sys
pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
sys.path.append(pyt_path)
#The inputs to this node will be stored as a list in the IN variable.
dataEnteringNode = IN
if isinstance(IN[0], list):
areas = UnwrapElement(IN[0])
else:
areas = [UnwrapElement(IN[0])]
if isinstance(IN[1], list):
unit = UnwrapElement(IN[1])
else:
unit = [UnwrapElement(IN[1])]
runMe = IN[2]
if isinstance(IN[3], list):
bb = UnwrapElement(IN[3])
else:
bb = [UnwrapElement(IN[3])]
if isinstance(IN[4], list):
lvl = UnwrapElement(IN[4])
else:
lvl = [UnwrapElement(IN[4])]
for i in range(len(areas)):
areas[i].BoundingBoxXYZ = bb[i].ToRevitType()
areas[i].Level.Name = lvl[i].Name
areas[i].Comments = unit[i]
try:
errorReport = None
if runMe:
viewTypes = FilteredElementCollector(doc).OfClass(ViewFamilyType)
for i in viewTypes:
if i.ViewFamily == ViewFamily.AreaPlan:
viewTypeId = i.Id
break
else:
continue
existingPlans = FilteredElementCollector(doc).OfClass(View).ToElements()
existingPlanNames, existingPlanElements = [], []
for i in existingPlans:
if not i.IsTemplate:
if i.ViewType == ViewType.AreaPlan:
existingPlanNames.append(i.ToDSType(True).Name)
existingPlanElements.append(i)
# Start Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
floorPlans = []
for i in areas:
levelId = i.LevelId
bbox = i.BoundingBoxXYZ
viewName = "Suite Type " + i.Comments + " - Unit " + i.Number
if viewName in existingPlanNames:
view = existingPlanElements[existingPlanNames.index(viewName)]
view.CropBox = bbox
view.CropBoxActive = True
view.CropBoxVisible = False
floorPlans.append(view)
else:
newView = ViewPlan.Create(doc, viewTypeId, levelId)
newView.Name = viewName
newView.CropBox = bbox
newView.CropBoxActive = True
newView.CropBoxVisible = False
floorPlans.append(newView)
# End Transaction
TransactionManager.Instance.TransactionTaskDone()
else:
errorReport = "Run Me set to False"
except:
# if error accurs anywhere in the process catch it
import traceback
errorReport = traceback.format_exc()
#Assign your output to the OUT variable
if errorReport == None:
OUT = areaplans
else:
OUT = errorReport