@GavinCrump Sorry Gavin, I just have one more question.
In terms of the python code and using /t to create different columns. I understand that the way its coded is basically like pressing tab in excel and therefore moving to the next column?
Where do you think would be my best next page/website/tutorial in expanding on that to either add a “move down one” seperator Or even dictating which row certain elements go? Why I ask is that in my practice we use a template for drawing transmittals (screen shot is below) so id love to be able to manipulate the data so it pastes into our template cleanly, rather than adjusting our template to suit if that makes sense?
If it’s just a spare line then you could add a blank line whenever changing series also in the copy/paste structure. This could be done by continually checking each sheet’s series and adding a blank line, or the series header whenever it changes from the last checked sheet. Did that mod for a client, it isn’t too tricky.
If you want to write into a pre-formatted file it is much more difficult and bespoke to your company needs at that point. If not Bumbelebee, Microsoft Interop + Python or C# would be the next step. Have built tools of this nature where I work and it takes a lot more time/work than just my tutorial.
I much prefer just having architects copy/paste into a preformatted schedule. If that’s too much work for them, then they’re likely out of a job in near future.
After having a look at bumblebee I can see why in your tutorial you said you prefer this method haha. The architects will be fine with it, its the directors who still get the old t squares out that will have the trouble
In terms of adding blank lines into the script. I did a bit of digging and managed to add this to the code
That at least added a blank line between the header and the data, so at least I am off the mark so to speak. With how the script is colour coded. Am I right in thinking that green means its a method?
The next modification I wanted to try is to have a column at the start of the revisions called ‘Current Revision’ which has the current rev for each sheet.
When thinking how it might be done, I would assume that I would need to mod the code so that it creates a copy of the last indices in the list and puts it at 0?
But unfortunately I get a ‘Revision’ object has no attribute ‘GetCurrentRevision’
Which I assume means that how I have wrote it, its trying to get a method from the Revision class which issnt there? Which is correct because its in the ViewSheet class but I am not sure how to re-write to fix it up.
If its something that is simple and ive just missed it please feel free to respond but if its more complicated and you dont have time you are more than welcome to leave me to it haha
Thanks again!
here is the whole code if it helps
# Made by Gavin Crump
# Free for use
# BIM Guru, www.bimguru.com.au
# Boilerplate text
import clr
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference("System")
from System import TimeZoneInfo, DateTime
# Assuming utc_datetime is a UTC DateTime object
utc_datetime = DateTime.UtcNow
# Convert to local time
local_time = TimeZoneInfo.ConvertTimeFromUtc(utc_datetime, TimeZoneInfo.Local)
# Current doc/app/ui
doc = DocumentManager.Instance.CurrentDBDocument
# Define list/unwrap list functions
def uwlist(input):
result = input if isinstance(input, list) else [input]
return UnwrapElement(result)
# Preparing input from dynamo to revit
sheets = uwlist(IN[0])
# Get revision sequences and revisions
revSeqs = FilteredElementCollector(doc).OfClass(RevisionNumberingSequence).ToElements()
revIds = Revision.GetAllRevisionIds(doc)
revs = [doc.GetElement(i) for i in revIds]
# Get sequence name per revision
# Empty variable lists to store to
revSeqNames, revCharSeqs = [],[]
# Get sequence names and characters
for r in revs:
# Get sequence
rsId = r.RevisionNumberingSequenceId
rs = doc.GetElement(rsId)
# Append the name and start a sequence
try:
revSeqNames.append(rs.Name)
except:
continue
charSequence = []
# Get sequence characters for numeric...
if rs.NumberType == RevisionNumberType.Numeric:
settings = rs.GetNumericRevisionSettings()
minDigits = settings.MinimumDigits
prefix = settings.Prefix
suffix = settings.Suffix
for n in range(settings.StartNumber,99,1):
char_str = str(n)
pad_str = char_str.rjust(minDigits,"0")
char_seq = prefix + pad_str + suffix
charSequence.append(char_seq)
# ... or Alphanumeric
else:
settings = rs.GetAlphanumericRevisionSettings()
prefix = settings.Prefix
suffix = settings.Suffix
for a in settings.GetSequence():
char_seq = prefix + a + suffix
charSequence.append(char_seq)
# Append the character sequence
revCharSeqs.append(charSequence)
# Get revision sequences per sheet
rowsOut = []
sep = "\t"
sep_2 = "\n"
for s in sheets:
trackRevs = []
sheetRevs = s.GetAllRevisionIds()
rowOut = ""
rowOut += s.Name + sep + s.SheetNumber + sep
# current revision
for i in revIds:
if i in sheetRevs:
revision = doc.GetElement(i)
revision_date = revision.RevisionDate.ToLocalTime()
if most_recent_revision_date is None or revision_date > most_recent_revision_date:
most_recent_revision_date = revision_date
most_recent_revision_row = rowOut
# If a most recent revision is found, insert it at the beginning of the row
if most_recent_revision_row:
rowsOut.insert(0, most_recent_revision_row)
else:
rowsOut.append(rowOut)
# For each revision in the document
for i in revIds:
# Check if the sheet has it
if i in sheetRevs:
# Get the sequence Id name and get its name
r = doc.GetElement(i)
rsId = r.RevisionNumberingSequenceId
rs = doc.GetElement(rsId)
rsn = rs.Name
# Find the index of the sequence name
i_sq = revSeqNames.index(rsn)
# Find out how many times the sequence occurred so far
i_ch = trackRevs.count(rsn)
# Get the sequence character, then track the sequence
d = revCharSeqs[i_sq][i_ch] + sep
trackRevs.append(rsn)
else:
d = "" + sep
rowOut += d
# Add current revision to start
if current_revision_row:
rowsOut.insert(0, current_revision_row)
else:
rowsOut.append(rowOut)
# Add the value to the end
rowsOut.append(rowOut)
# Make the top header
header = sep + sep + sep.join([r.RevisionDate for r in revs]) + sep + sep_2
rowsOut.insert(0,header)
# Preparing output to Dynamo
Try using this method instead (I pinned in top comment for video too), it’s far easier than the approach I used at the time of the tutorial. I came across it afterwards unfortuntaely.
You can effectively just say:
for each sheet…
for each revision…
get revision number on sheet, write to a list (row)
Thanks for that Gavin. Might be a bit advanced for me at the moment as although I know the basics of python, so I can read code and follow it along in a way, I am very new to understanding how to use the Revit API.
But having a bit of a crack, using the GetRevisionNumberOnSheet method. I would be inserting it somewhere in this part of the code?
for s in sheets:
trackRevs = []
sheetRevs = s.GetAllRevisionIds() #get all the revisions ids on each sheet
rowOut = ""
rowOut += s.Name + sep + s.SheetNumber + sep
# For each revision in the document
for i in revIds: #uses that early variable that collects all the revision ids
# Check if the sheet has it
if i in sheetRevs:
# Get the sequence Id name and get its name
r = doc.GetElement(i)
rsId = r.RevisionNumberingSequenceId
rs = doc.GetElement(rsId)
rsn = rs.Name
# Find the index of the sequence name
i_sq = revSeqNames.index(rsn)
# Find out how many times the sequence occured so far
i_ch = trackRevs.count(rsn)
# Get the sequence character, then track the sequence
d = revCharSeqs[i_sq][i_ch] + sep
trackRevs.append(rsn)
else:
d = "" + sep
rowOut += d
# Add the value to the end
rowsOut.append(rowOut)
So my understanding of the above is (in simpleton language)
Starts a loop that goes over each element in sheets
Then starts a nested loop where for each element in the sheets loop
it goes through each element in revIds (so basically every revision id in the document)
if it comes across an element in revIds thats also in the sheetRevs variable
it then gets its revision sequence id (rsId)
then gets the sequence itself ( rs)
its name (rsn) by using the rs variable that contains its sequence
It then gets the index of each sequence name assigning it the variable i_sq
and then counts how many names in the element (or each sheet) and adds it to the list trackRevs
then gets the revCharSeqs variable in each element and creates a list of i_sq and i_ch
then uses the tab serperator and then ads the revision name to the trackRevs list
with else it then skips the element if there are no revisions in it (in other words, no revision on the sheet)
Then finally adds the rowOut to the empty list rowsOut which was created before the loop
Then goes through the next element in revIds
So based on that (if what I wrote above is correct) I would remove the for i in revIds loop (and the nested if statement) and replace it with a loop that iterates over each element ( s) in sheets and uses the GetRevisionNumberOnSheet method to build the rowsOut part at the bottom?
Man I hope what ive said here makes sense to you haha.
This workflow does away with the need for any revision sequence ID. The alternative method just takes a revision and returns its number on sheet if any.
You could iterate across each sheet, then each revision and check number on sheet for each. Append them to the sheets row and append the row to the report.
I’m adding a Node to Crumple to do this, see below code:
# Made by Gavin Crump
# Free for use
# BIM Guru, www.bimguru.com.au
# Boilerplate text
import clr
# Define list/unwrap list functions
def uwlist(input):
result = input if isinstance(input, list) else [input]
return UnwrapElement(result)
# Preparing input from dynamo to revit
sheets = uwlist(IN[0])
revisions = uwlist(IN[1])
noRev = IN[2]
# Revision Ids
revIds = [r.Id for r in revisions]
report = []
# For each sheet...
for s in sheets:
# Empty row
row = []
# For each revision Id
for r in revIds:
# Get number on sheet
numOnSht = s.GetRevisionNumberOnSheet(r)
# If it has one, append
if numOnSht:
row.append(numOnSht)
# If not append no rev
else:
row.append(noRev)
# If row is one object, we go to 1D
if len(row) == 1:
row = row[0]
# Append row
report.append(row)
# Preparing output to Dynamo
OUT = report
Thanks again for the reply. If I could ask one more thing, with what I described above, how what I thought that part of the code was doing, was I close to being correct?