Tool to create generic annotations in drafting views of type based on name
Version 2.05 Working
- Gets all gen anos in project
- gets drafting view corresponding to the family name of the gen anno
- gets the types
- Creates the types in the drafting view to use as a reference for schedule manipulaiton
Adding types after run:
Update includes moving exsinting (sorted) annotations to their exact spot in the list:
##https://gist.github.com/gtalarico/e6be055472dfcb6f597e3dcd20d11f37
#import System.Collections.Generic
#from System.Collections.Generic import List
##clr.AddReference('RevitAPIUI')
##from Autodesk.Revit.UI import *
import clr
clr.AddReference('System')
clr.AddReference('RevitAPI')
##clr.AddReference('RevitNodes')
##clr.ImportExtensions(Revit.Elements)
##clr.ImportExtensions(Revit.GeometryConversion)
###Creates a Drafting View###
from Autodesk.Revit.DB import Transaction, Element, ElementTransformUtils
##https://forum.dynamobim.com/t/collecting-all-elements-of-family-types-in-active-view/19838/2
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory, BuiltInParameter, ParameterValueProvider, ElementId, ElementParameterFilter, FilterNumericEquals, FilterElementIdRule, ElementTransformUtils
# Drafting Views
from Autodesk.Revit.DB import ViewFamilyType, ViewDrafting, Element
from Autodesk.Revit.DB import ViewFamily
clr.AddReference('RevitServices') ##May need to re-add for Document Manager
import sys
import System ##filterAnnot = System.Predicate
from System.Collections.Generic import List ##Not same as type() = List
import math ##For truncate to integer-RA
import re ##Regular expressions for 'natural' sort
from itertools import groupby
#from Autodesk.Revit.DB import *
from Autodesk.Revit.DB import FamilySymbol, FamilyInstance, XYZ, AnnotationSymbol
#import Revit
#from Revit import *
#from Autodesk.DesignScript.Geometry import * ##Point(X,Y,Z) ##cannot use for PY nodes outside Dynamo
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
##uidoc = __revit__.ActiveUIDocument
##doc = __revit__.ActiveUIDocument.Document
#####################################################################################
##Create a Drafting View#
def get_drafting_type_id(DraftingType):
##Selects First available ViewType that Matches Drafting Type.## ##https://mgfx.co.za/blog/building-architectural-design/revit-view-type-creation-using-excel-with-dynamo-and-python/
viewfamily_types = FilteredElementCollector(doc).OfClass(ViewFamilyType)
for i in viewfamily_types:
if i.ViewFamily == ViewFamily.Drafting: ##*.ViewFamily Backwards 'parent' ref I've been looking for!##<<<<<<<<<<<<<<<<<<<<<<<<<<HERE
return i.Id
def GetDraftingViews():
##https://forums.autodesk.com/t5/revit-api-forum/view3d-collector/td-p/5277451
DraftingViewsList = FilteredElementCollector(doc).OfClass(ViewDrafting).ToElements()
##DraftingViewTemplates = [v.Id for v in DraftingViewsList if v.IsTemplate == True]
DraftingViewsList = [v for v in DraftingViewsList if v.IsTemplate == False]
return [DraftingViewsList]
def GetDraftingViewTemplates():
##https://forums.autodesk.com/t5/revit-api-forum/view3d-collector/td-p/5277451
DraftingViewsList = FilteredElementCollector(doc).OfClass(ViewDrafting).ToElements()
DraftingViewTemplates = [v for v in DraftingViewsList if v.IsTemplate == True]
##DraftingViewsList = [v.Id for v in DraftingViewsList if v.IsTemplate == False]
return [DraftingViewTemplates]
def GetDraftingViewByBame(strName=""): ##Check if drafting view existds = if not, create it and assign view name
if not strName == "": ##If string name is set look for the drafting view
DraftingView = FilteredElementCollector(doc).OfClass(ViewDrafting).ToElements() ##Get all drafting views
DraftingView = [v for v in DraftingView if v.Name == strName] ##Return Drafting view for each Drafting view eq. Name
if DraftingView:
DraftingView =DraftingView[0] ##Return single item not list<<<<<<<<<<<<<<<
if not DraftingView: ##If no drafting view found
drafting_type_id = get_drafting_type_id() ##Get TYPE ID
DraftingView = ViewDrafting.Create(doc, drafting_type_id) ##Create View
##After creating view-
if not strName=="" : ##IF string is not null set the name of the new view
DraftingView.Name = strName
return DraftingView ##Return single value
def GetGenericAnnotationTypes():
##BAsed in part
##https://forum.dynamobim.com/t/how-can-i-collect-all-family-types-that-are-considered-annotation-symbols-in-revit/37480/10
##https://forum.dynamobim.com/t/get-all-generic-annotations-in-a-view/80514/2
filterAnnot = System.Predicate[System.Object](lambda x : x.Family.FamilyCategory.Name == "Generic Annotations")
symbAnnot = List[Element](FilteredElementCollector(doc).OfClass(FamilySymbol).ToElements()).FindAll(filterAnnot)
return symbAnnot
def Lambda_Natural_sort(l): ##Slow 50x but effective ##ORiginal function doesn't work with Objects.
ConvertText = lambda ConvertText: int(ConvertText) if ConvertText.isdigit() else ConvertText.lower()
alphanum_key = lambda key: [ ConvertText(c) for c in re.split('([0-9]+)', key) ]
return sorted(l, key = alphanum_key)
def Lambda_GenAnno_Sort_w_fam_name(lstObj):
ConvertText = lambda ConvertText: int(ConvertText) if ConvertText.isdigit() else ConvertText.lower()
alphanum_key = lambda i: [ ConvertText(c) for c in re.split('(\d+)', i) ]
##GenAnnoTypeName##https://forum.dynamobim.com/t/python-script-to-get-type-name-from-an-element/63306/2
GAstrName = lambda j: [ alphanum_key(c) for c in (j.Family.Name + GetGAName(j))]
return sorted(lstObj, key = GAstrName)
def GetGAName(GA): ##GenericAnnotationFamilyType".Name"
return doc.GetElement(GA.Id).get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString()
def GroupGenAnnos(lstElems):
##test to Group By Key https://forum.dynamobim.com/t/group-by-key-in-python/39145/2
grp=[]
ukey=[]
##Presorted by genannolistfort_w_family_name
for k, g in groupby(lstElems, lambda x:x.Family.Name):
grp.append(list(g))
ukey.append(k)
#Assign your output to the OUT variable.
return grp
def GetAnnosInView(viewView):
##https://forum.dynamobim.com/t/get-all-generic-annotations-in-a-view/80514/2
symbAnnot = [x for x in FilteredElementCollector(doc,viewDraft.Id).OfCategory(BuiltInCategory.OST_GenericAnnotation).WhereElementIsNotElementType()]
def ListConv(x): ## Returns list if single item
if type(x) is list :
return x ##Leave as list if laready list
else:
try:
z=iter(x) ##if element is iterable- e.g. Generic.List - it can be converted to regular list
return [x for x in x] ##Convert to list if single item
except:
return[x] ##Convert single element to list
def ListOfList1InList2(list1,list2):
list1Out=[]
for x in list1: ##For each element in 1st list (Check against elements in 2nd list)
found = False ##Reset to not found for next element
for y in list2:
if x==y: ##If found,
found =True ##Set founc to TRUE
break ##Can stop looking in second list this round
list1Out.append(found) ##Append result
return list1Out
def List1InList2(list1,list2): ##If any of list 1 in list 2 return TRUE else False
for x in list1: ##For each element in 1st list (Check against elements in 2nd list)
for y in list2:
if x==y: ##If found,
return True ##Return True
return False ##Return false
def GenAnnosInView(viewView):
##GET ANNOTATIONSIN VIEW
##https://forum.dynamobim.com/t/get-all-generic-annotations-in-a-view/80514/2
FEC=FilteredElementCollector(doc,viewView).OfCategory(BuiltInCategory.OST_GenericAnnotation).WhereElementIsNotElementType()
return FEC
def PlaceGenAnnoArray(GAFamTypes, viewView): #Single family of generic annotaiton types to place
##cast CONSTANTS
xSpace = 8.5/12.0 ##Horizontal spacing 8-1/2" Wide
ySpace = 3.0/8.0/12.0 ##Vertical spacing 3/16" tall (Text is 3/32" high)
yLimit = 10.0/12.0 ##Limit of Y column height 10" (8-1/2"x11" Guide to format into sheet size references)
yCount = int(math.floor(yLimit/ySpace)) ##Number of rows in a column for reset y value
column = 0 ##Column location
count = 1 ##Count position in array of all family types
AnnoEXST=[] ##Existing annotaitons in view
AnnoNEWW=[] ##New annotaitons creted
##get AllGenAnnosInView - if any...
AnnosInView =[]
#AnnosInView = FilteredElementCollector(doc,viewView.Id).OfCategory(BuiltInCategory.OST_GenericAnnotation).WhereElementIsNotElementType().ToElements
##https://forum.dynamobim.com/t/get-all-generic-annotations-in-a-view/80514/13 SeanP
filterAnnot = System.Predicate[System.Object](lambda x : doc.GetElement(x.GetTypeId()).Family.FamilyCategory.Name == "Generic Annotations")
AnnosInView = List[Element](FilteredElementCollector(doc, viewView.Id).OfClass(FamilyInstance).ToElements()).FindAll(filterAnnot)
AnnosInView = UnwrapElement(AnnosInView) ##Unwrap to get to get to Revit Type Elements
for GAFamType in GAFamTypes :
#from 0,0 run down then over for simplicity. These typically will NOT end up on printed sheets
#But are head to use to schedule. Any object in any view will schedule regardless of on/off sheet palcement.
column = math.floor( yLimit / count * ySpace) ##Get column based on placed elements and Y limit sizes
x= column * xSpace ##Get x location
y= -ySpace * (count-1 - (column * yCount)) ##Offset Y by column displacemnet
objPoint = XYZ(x, y, 0) ##GET POINT
#return List1InList2([GetGAName(GAFamType)], [x.Name for x in AnnosInView]) ##DEBUG
##if List1InList2([GetGAName(GAFamType)], [x.Name for x in AnnosInView]): ##if GAFamType Name in list of names in view
#return 3
GAiv = None
if AnnosInView : ##If ther eare annos in the view
for GAivx in AnnosInView: ##For each Gen Anno in view
Found = False ##Reset Found
for y in GAFamTypes:
if GetGAName(GAFamType)==GAivx.Name: ##If found,
Found = True ##Return True
GAiv=GAivx
break ##Break with Found set
if Found: ##If found (after for y)
break ##Exit out of outer loop with GAiv (Gen Anno In View) set
else:
GAiv=None
if GAiv:
AnnoEXST.append(GAFamType) ##Add it to the existing list
for GAinVIew in AnnosInView: ##Cycle through to set it
if GAinVIew.Name==GetGAName(GAFamType): ##GenericAnnotaitonFamilyTypeCompare
GAiv.Location.Point = objPoint ##Sets Fixed Position for element in list.
break
else: ##Not List1InList2
GAinVIew = doc.Create.NewFamilyInstance(objPoint, GAFamType, viewView) ##Create NEW annotaiton in its loaiton
AnnoNEWW.append(GAinVIew) ##Append it to the new list as a double check
count +=1 ##increment counter
return [AnnoNEWW,AnnoEXST] ##Return the New and Existing. Re-running should only return existing.
####
###
#######################################################################################
def Main(): ###Entry point to procedures
t = Transaction (doc, 'Create Drafting View')
t.Start()
outNEWW=[]
outEXST=[]
GenAnnoTypes = []
GenAnnoTypes = GetGenericAnnotationTypes() ##LIST of FAMILY TYPE of GenAnnoTypes
GenAnnoTypes = Lambda_GenAnno_Sort_w_fam_name(GenAnnoTypes) ##Sort in natural order- numbers as numbers text as text
GenAnnoTypes = GroupGenAnnos(GenAnnoTypes) ##Create nested list by Family and Types
for GAFamType in GenAnnoTypes: ##2D list [1.GenAnnoFamilies][2.GenAnnoTypes]
DraftViewName = ""
DraftViewName = GAFamType[0].Family.Name ##FAmily name used for drafting view name
viewDraft = GetDraftingViewByBame(DraftViewName) ##Get or create drafting view by name
OUT = PlaceGenAnnoArray (GAFamType, viewDraft) ##Place or update gfams per view
##Separate lists into NEW and EXISTING##
#outNEWW.append(OUT[0]) ##New is index 0
#outEXST.append(OUT[1]) ##Existing is index 1
#OUT=[outNEWW,outEXST] ##Set final OUT to [NEW,Existing] Lists
t.Commit()
return OUT
############################################################################################
############################################################################################
OUT=Main () ##Entry point to run all scripts
############################################################################################
############################################################################################
Comments
Post a Comment