Change the Curve that determines the 2D extents of Grids in Each View

This is an awesome thread, back on the project where I have time to work this out. Can someone point me to like a python for dummies or basic learning website? so I can try to follow along with the information in this thread.

I get this error when I try to use the script Cyril wrote:

Warning: AttributeError : module ‘clr’ has no attribute ‘Reference’ [’ File “”, line 80, in \n’, ’ File “”, line 37, in createDatumLine\n’]

This works :slight_smile:

activView = UnwrapElement(IN[0])
lstInputViews = UnwrapElement(IN[0])
TransactionManager.Instance.EnsureInTransaction(doc)

for activView in lstInputViews:

	#
	activView.CropBoxVisible = True
	doc.Regenerate()
	#
	cropBox = activView.CropBox 

	fecGrids = FilteredElementCollector(doc, activView.Id).OfClass(DatumPlane).ToElements()
	cutOffset = fecGrids[0].GetCurvesInView(DatumExtentType.ViewSpecific, activView)[0].GetEndPoint(0).Z
	fecGrids = [x for x in fecGrids if isinstance(x, DB.Grid)]

	outLst = []
	shpManager = activView.GetCropRegionShapeManager()
	boundLines = shpManager.GetCropShape()[0]


	if activView.ViewDirection.IsAlmostEqualTo(XYZ(0,0,1)):
		# get Current Elevation of boundLines
		currentZ = list(boundLines)[0].GetEndPoint(0).Z
		# transform boundLines CurveLoop
		tf = Transform.CreateTranslation( XYZ(0,0, cutOffset - currentZ))
		boundLines = CurveLoop.CreateViaTransform(boundLines, tf)
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
	else:
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
TransactionManager.Instance.TransactionTaskDone()

But i don`t understand it. Why do we have to give the input views two different names? lstInputViews and activView? And now we are looping the list of views with…itselfe? :thinking:

1 Like
1 Like

@c.poupin

I would like the python script not to throw an error if the input is an empty list.
Can you tell me how to do this?
This is the error:

image

Kind regards :slight_smile:

1 Like

declare your variable outLst = [] outside the floor loop
(for activView in lstInputViews)

2 Likes

Hello @c.poupin, thanks for your reply!

I also had to declare “shpManager” and “boundLines” outside of the loop because they also gave an error. Now the code is not working anymore: " line 58, in
AttributeError: ‘List[object]’ object has no attribute ‘GetCropRegionShapeManager’"

activView = UnwrapElement(IN[0])
lstInputViews = UnwrapElement(IN[0])
TransactionManager.Instance.EnsureInTransaction(doc)
outLst = []
shpManager = activView.GetCropRegionShapeManager()
boundLines = shpManager.GetCropShape()[0]
	
for activView in lstInputViews:

	#
	activView.CropBoxVisible = True
	doc.Regenerate()
	#
	cropBox = activView.CropBox 

	fecGrids = FilteredElementCollector(doc, activView.Id).OfClass(DatumPlane).ToElements()
	cutOffset = fecGrids[0].GetCurvesInView(DatumExtentType.ViewSpecific, activView)[0].GetEndPoint(0).Z
	fecGrids = [x for x in fecGrids if isinstance(x, DB.Grid)]

	if activView.ViewDirection.IsAlmostEqualTo(XYZ(0,0,1)):
		# get Current Elevation of boundLines
		currentZ = list(boundLines)[0].GetEndPoint(0).Z
		# transform boundLines CurveLoop
		tf = Transform.CreateTranslation( XYZ(0,0, cutOffset - currentZ))
		boundLines = CurveLoop.CreateViaTransform(boundLines, tf)
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
	else:
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
TransactionManager.Instance.TransactionTaskDone()

OUT =  lstInputViews, outLst, [x.ToProtoType() for x in boundLines], cutOffset,

So i just removed all the output because i don`t need them, and now it works fine :slight_smile:

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

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
sdkNumber = int(app.VersionNumber)


clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)


def createDatumLine(boundLines, grid):
	gridLine = None
	curveG = grid.Curve#.ToProtoType()
	vectGrid = curveG.Direction
	lstPtToLine = []
	for lineBound in boundLines:
		rayc = DB.Line.CreateUnbound(XYZ(curveG.Origin.X, curveG.Origin.Y, lineBound.GetEndPoint(0).Z) , vectGrid)
		outInterR = clr.Reference[IntersectionResultArray]()
		result = rayc.Intersect(lineBound, outInterR)
		print(result)
		if result == SetComparisonResult.Overlap:
			interResult = outInterR.Value
			lstPtToLine.append(interResult[0].XYZPoint)
	print(lstPtToLine)
	if len(lstPtToLine) == 2:
		P1 = lstPtToLine[0].ToPoint()
		P2 = lstPtToLine[1].ToPoint()
		TransXYZ1 = Geometry.Translate(P1 ,0,0,1)
		TransXYZ2 = Geometry.Translate(P2 ,0,0,-0.5)
		TransPoint1 = TransXYZ1.ToXyz()
		TransPoint2 = TransXYZ2.ToXyz()
		gridLine = Autodesk.Revit.DB.Line.CreateBound(TransPoint1, TransPoint2)
	return gridLine
	
activView = UnwrapElement(IN[0])
lstInputViews = UnwrapElement(IN[0])
TransactionManager.Instance.EnsureInTransaction(doc)

for activView in lstInputViews:

	#
	activView.CropBoxVisible = True
	doc.Regenerate()
	#
	cropBox = activView.CropBox 

	fecGrids = FilteredElementCollector(doc, activView.Id).OfClass(DatumPlane).ToElements()
	cutOffset = fecGrids[0].GetCurvesInView(DatumExtentType.ViewSpecific, activView)[0].GetEndPoint(0).Z
	fecGrids = [x for x in fecGrids if isinstance(x, DB.Grid)]

	outLst = []
	shpManager = activView.GetCropRegionShapeManager()
	boundLines = shpManager.GetCropShape()[0]


	if activView.ViewDirection.IsAlmostEqualTo(XYZ(0,0,1)):
		# get Current Elevation of boundLines
		currentZ = list(boundLines)[0].GetEndPoint(0).Z
		# transform boundLines CurveLoop
		tf = Transform.CreateTranslation( XYZ(0,0, cutOffset - currentZ))
		boundLines = CurveLoop.CreateViaTransform(boundLines, tf)
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
	else:
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
TransactionManager.Instance.TransactionTaskDone()

OUT =  lstInputViews
2 Likes

So now as it works for sectionviews to give an offset by calculating the points i would like to add an offset to planviews also.

The offset should be the same on all sides, but calculating the points would be too complex for planviews because the grids won`t be just horizontal and vertikal.

So for planviews i would need a method to give the grid curve an offset, right ?

1 Like

Trying to figure out your working script here. Figured out its in German lol and raster means grid :-). Hello from Newfoundland, Canada.

What are the two custom python nodes I assume the one at the end is the script you shared in the posts below but what does the first one mean or do? Maybe I can recreate somehow.

Realizing going to take me more than a few hours to pick up this python stuff haha

The direction of grids (curves) can be help you

1 Like

Hello from Vienna @jeremy.colombe :smiley:

Find the script with more Information attached.
I use it to set the grid extents to the cropbox and then set the grid bubbles. The two “Grid to Cropbox” nodes are different in the offset. In SectionViews i use a z-value of 1 for the upper end and a z-value of -0.5 for the bottom end. In PlanViews i use no offset (because i cant^^)´
In SectionViews i only want the upper bubbles. In PlanViews i want the left and upper bubbles, therefore i need to calculate the right bool values, that is something thats missing right now.

It makes a difference if a grid is drawn from top to bottom, bottom to top, left to right, right to left. Thats why we have to add this bool calculation depending on the grid curve. See this thread:
Turn On Top & Left Grid Bubbles Only - Revit - Dynamo (dynamobim.com)

For setting the bubbles see this thread for interesting explanaitions on python, by @Nick_Boyts and @Mark.Ackerley:
Python for Loop - Hide Grid Bubbles - Dynamo (dynamobim.com)


Grids.dyn (67.7 KB)

Thanks for the help will look at this soon as I was hauled off that job again to help someone with something more pressing. Appreciate the reply and will update this forum when I get back at it within the next few days

Thanks, for now i will go for the workaround, setting the Cropbox to a bigger one, set grids and then the cropbox back.

@c.poupin

I have still hope that there is some way to determine which end is End0 and End1.

As this is not possible with curve end/start but it is possible with your “newGLine”, could it be that if i can get the Revit.DB.Line from a grid, that would solve this problem?

So how to get a Revit.DB.Line from a grid?

Hi
if necessary, you can try to reverse TransPoint1 and TransPoint2

That may be the explanaition why the grids get “flipped” with your code. I will try that, but the combination of your script, your newgridlines and setting bubbles works fine.

My question was more about just setting bubbles with a python code. Without setting the datumends before.
All the codes for setting bubbles use the unreliable grid curves. I would like to know if there would be another method. So if there is no method to get the End0 and End1 of datumplane, i thought it would be worth a try see if a Autodesk.Revit.DB.Line will give better results. But how to get this element from a grid…

with Curve property
curveG = grid.Curve

1 Like

Here is a version that allows an input for Top and Bottom Offset:

ezgif.com-gif-maker

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

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
sdkNumber = int(app.VersionNumber)


clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

TopOffset = UnwrapElement(IN[1])
BottomOffset = UnwrapElement(IN[2])

def createDatumLine(boundLines, grid):
	gridLine = None
	curveG = grid.Curve#.ToProtoType()
	vectGrid = curveG.Direction
	lstPtToLine = []
	for lineBound in boundLines:
		rayc = DB.Line.CreateUnbound(XYZ(curveG.Origin.X, curveG.Origin.Y, lineBound.GetEndPoint(0).Z) , vectGrid)
		outInterR = clr.Reference[IntersectionResultArray]()
		result = rayc.Intersect(lineBound, outInterR)
		print(result)
		if result == SetComparisonResult.Overlap:
			interResult = outInterR.Value
			lstPtToLine.append(interResult[0].XYZPoint)
	print(lstPtToLine)
	if len(lstPtToLine) == 2:
		P1 = lstPtToLine[0].ToPoint()
		P2 = lstPtToLine[1].ToPoint()
		TransXYZ1 = Geometry.Translate(P1 ,0,0,TopOffset)
		TransXYZ2 = Geometry.Translate(P2 ,0,0,BottomOffset)
		TransPoint1 = TransXYZ1.ToXyz()
		TransPoint2 = TransXYZ2.ToXyz()
		gridLine = Autodesk.Revit.DB.Line.CreateBound(TransPoint1, TransPoint2)
	return gridLine
	
activView = UnwrapElement(IN[0])
lstInputViews = UnwrapElement(IN[0])
TransactionManager.Instance.EnsureInTransaction(doc)

for activView in lstInputViews:

	#
	activView.CropBoxVisible = True
	doc.Regenerate()
	#
	cropBox = activView.CropBox 

	fecGrids = FilteredElementCollector(doc, activView.Id).OfClass(DatumPlane).ToElements()
	cutOffset = fecGrids[0].GetCurvesInView(DatumExtentType.ViewSpecific, activView)[0].GetEndPoint(0).Z
	fecGrids = [x for x in fecGrids if isinstance(x, DB.Grid)]

	outLst = []
	shpManager = activView.GetCropRegionShapeManager()
	boundLines = shpManager.GetCropShape()[0]


	if activView.ViewDirection.IsAlmostEqualTo(XYZ(0,0,1)):
		# get Current Elevation of boundLines
		currentZ = list(boundLines)[0].GetEndPoint(0).Z
		# transform boundLines CurveLoop
		tf = Transform.CreateTranslation( XYZ(0,0, cutOffset - currentZ))
		boundLines = CurveLoop.CreateViaTransform(boundLines, tf)
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
	else:
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
TransactionManager.Instance.TransactionTaskDone()

OUT =  lstInputViewsimport clr
import System
clr.AddReference('ProtoGeometry')
import Autodesk.DesignScript.Geometry as DSGeo
from Autodesk.DesignScript.Geometry import *

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
sdkNumber = int(app.VersionNumber)


clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

TopOffset = UnwrapElement(IN[1])
BottomOffset = UnwrapElement(IN[2])

def createDatumLine(boundLines, grid):
	gridLine = None
	curveG = grid.Curve#.ToProtoType()
	vectGrid = curveG.Direction
	lstPtToLine = []
	for lineBound in boundLines:
		rayc = DB.Line.CreateUnbound(XYZ(curveG.Origin.X, curveG.Origin.Y, lineBound.GetEndPoint(0).Z) , vectGrid)
		outInterR = clr.Reference[IntersectionResultArray]()
		result = rayc.Intersect(lineBound, outInterR)
		print(result)
		if result == SetComparisonResult.Overlap:
			interResult = outInterR.Value
			lstPtToLine.append(interResult[0].XYZPoint)
	print(lstPtToLine)
	if len(lstPtToLine) == 2:
		P1 = lstPtToLine[0].ToPoint()
		P2 = lstPtToLine[1].ToPoint()
		TransXYZ1 = Geometry.Translate(P1 ,0,0,TopOffset)
		TransXYZ2 = Geometry.Translate(P2 ,0,0,BottomOffset)
		TransPoint1 = TransXYZ1.ToXyz()
		TransPoint2 = TransXYZ2.ToXyz()
		gridLine = Autodesk.Revit.DB.Line.CreateBound(TransPoint1, TransPoint2)
	return gridLine
	
activView = UnwrapElement(IN[0])
lstInputViews = UnwrapElement(IN[0])
TransactionManager.Instance.EnsureInTransaction(doc)

for activView in lstInputViews:

	#
	activView.CropBoxVisible = True
	doc.Regenerate()
	#
	cropBox = activView.CropBox 

	fecGrids = FilteredElementCollector(doc, activView.Id).OfClass(DatumPlane).ToElements()
	cutOffset = fecGrids[0].GetCurvesInView(DatumExtentType.ViewSpecific, activView)[0].GetEndPoint(0).Z
	fecGrids = [x for x in fecGrids if isinstance(x, DB.Grid)]

	outLst = []
	shpManager = activView.GetCropRegionShapeManager()
	boundLines = shpManager.GetCropShape()[0]


	if activView.ViewDirection.IsAlmostEqualTo(XYZ(0,0,1)):
		# get Current Elevation of boundLines
		currentZ = list(boundLines)[0].GetEndPoint(0).Z
		# transform boundLines CurveLoop
		tf = Transform.CreateTranslation( XYZ(0,0, cutOffset - currentZ))
		boundLines = CurveLoop.CreateViaTransform(boundLines, tf)
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
	else:
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
TransactionManager.Instance.TransactionTaskDone()

OUT =  lstInputViews
1 Like

Hi guys, sorry to extend this further. I have tried the python script, which allows for offsets of the grid heads off the crop box. I have used the filtered element collector to get the views and grids on a sheet in my edit. However, I get the error in the attached image.
Thanks for the help. @c.poupin

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

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
sdkNumber = int(app.VersionNumber)


clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

TopOffset = UnwrapElement(IN[1])
BottomOffset = UnwrapElement(IN[2])

def createDatumLine(boundLines, grid):
	gridLine = None
	curveG = grid.Curve#.ToProtoType()
	vectGrid = curveG.Direction
	lstPtToLine = []
	for lineBound in boundLines:
		rayc = DB.Line.CreateUnbound(XYZ(curveG.Origin.X, curveG.Origin.Y, lineBound.GetEndPoint(0).Z) , vectGrid)
		outInterR = clr.Reference[IntersectionResultArray]()
		result = rayc.Intersect(lineBound, outInterR)
		print(result)
		if result == SetComparisonResult.Overlap:
			interResult = outInterR.Value
			lstPtToLine.append(interResult[0].XYZPoint)
	print(lstPtToLine)
	if len(lstPtToLine) == 2:
		P1 = lstPtToLine[0].ToPoint()
		P2 = lstPtToLine[1].ToPoint()
		TransXYZ1 = Geometry.Translate(P1 ,0,0,TopOffset)
		TransXYZ2 = Geometry.Translate(P2 ,0,0,BottomOffset)
		TransPoint1 = TransXYZ1.ToXyz()
		TransPoint2 = TransXYZ2.ToXyz()
		gridLine = Autodesk.Revit.DB.Line.CreateBound(TransPoint2, TransPoint1)
	return gridLine
	
# Get Viewports on Sheet	
all_viewports = FilteredElementCollector(doc, doc.ActiveView.Id).OfCategory(BuiltInCategory.OST_Viewports).WhereElementIsNotElementType().ToElements()


#Get Views from Viewports
all_views = []
for viewport in all_viewports:
        viewId = viewport.ViewId
        all_views.append(doc.GetElement(viewId))

#Remove Legend and 3D Views from List
all_views_clean = []
for view in all_views:
        if isinstance (view,(Autodesk.Revit.DB.View3D)):
                continue
        if view.ViewType == ViewType.Legend:
                continue
        all_views_clean.append(view)
        

TransactionManager.Instance.EnsureInTransaction(doc)

for activView in all_views_clean:

	#
	activView.CropBoxVisible = True
	doc.Regenerate()
	#
	cropBox = activView.CropBox 

	fecGrids = FilteredElementCollector(doc, activView.Id).OfClass(DatumPlane).ToElements()
	cutOffset = fecGrids[0].GetCurvesInView(DatumExtentType.ViewSpecific, activView)[0].GetEndPoint(0).Z
	fecGrids = [x for x in fecGrids if isinstance(x, DB.Grid)]

	outLst = []
	shpManager = activView.GetCropRegionShapeManager()
	boundLines = shpManager.GetCropShape()[0]


	if activView.ViewDirection.IsAlmostEqualTo(XYZ(0,0,1)):
		# get Current Elevation of boundLines
		currentZ = list(boundLines)[0].GetEndPoint(0).Z
		# transform boundLines CurveLoop
		tf = Transform.CreateTranslation( XYZ(0,0, cutOffset - currentZ))
		boundLines = CurveLoop.CreateViaTransform(boundLines, tf)
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
	else:
		for grid in fecGrids:
			outLst.append(grid.Curve.ToProtoType())
			newGLine = createDatumLine(boundLines, grid)
			if newGLine is not None:
				grid.SetCurveInView(DatumExtentType.ViewSpecific, activView, newGLine)
			
TransactionManager.Instance.TransactionTaskDone()

OUT =  all_views_clean,fecGrids

Sometimes I got an error but it still worked as intended not sure if that’s the case with your situation

Hi Jeremy, thanks so much for the response. It works well to snap the grid heads to the crop boxes, but the offsets are not being created. I also just realized that the plans I have on my sheet are not responding to the code. I’m sure I am missing something.