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

Here is the one I use but its no offset input. I select the views from the sheet and then run script. I use it for sections as my plan grids are controlled by scope boxes.

SetGridsToCropRegion.dyn (67.1 KB)

1 Like

Thanks so much for the script much appreciated. However, need to be able to do this without manual selection for efficiency reasons. I am busy making a script that dimensions all views on a sheet and I need to move the grid bubbles above the dimensions automatically. I will keep trying.
Thanks a lot.

No problem you’re welcome. If it is a plan scope box may be an easier option and then use automation to place the dimensions

You are probably right. Some simplicity might be needed here.

I have found personally that its easier to have four scripts do four steps then have one script do four steps. I use them like building blocks then. The biggest problem being not able to have two scripts open to copy between them.

1 Like

I figured it out! Haha.
The error was because of the plan views in the view list, so I have filtered the plans out. I was also inputting offset values that were too small. I worked with the view scale on the sheet instead of a 1:1 offset. Here is the code. Thank you all for this excellent tread.

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,Autodesk.Revit.DB.ViewPlan)):
                continue
        if view.ViewType == ViewType.Legend:
                continue
        all_views_clean.append(view)
        

#activView = UnwrapElement(IN[0])
#lstInputViews = UnwrapElement(IN[0])

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
2 Likes

That’s fantastic! Great work

2 Likes

Hello guys,
do you have any idea how to extend just one side of a segemen in a multi segment grid?

Did you try deleting the part of the code out that references the 2nd point?

Then I get an error about unbounded line…

Yeah its a bit beyond my coding level. It seems like you need to stop it from from doing one of these offsets:

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

Maybe try deleting one. I usually just copy pasta ninja it until I get somewhere sorry I could not be more help

Thanks for your efforts but it’s not about offsetting :slight_smile:
I am considering to filter single grid lines of multi segment grids, those have only one point to extend. It is too much geometric check :slight_smile:

I just use a scope box offset from my “view” scope box to control grid extents. If I need more control I just add another scope box. Not much of an issue for me as a mechanical designer

This code works perfectly for active view. I have tried to update this for multiple views as per below comments. But I am unable to update this due to poor knowledge in coding. It will be helpful If you can update this code for aligning grids to crop box for list of views.
Thank you.

Here is an update for multiple views,
for multiseqmentGrids it’s more complicated, need a different process

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:
		gridLine = Autodesk.Revit.DB.Line.CreateBound(lstPtToLine[0], lstPtToLine[1])
	return gridLine
	

toList = lambda x : x if hasattr(x, '__iter__') else [x]
lstView = toList(UnwrapElement(IN[0]))
offset_number = IN[1]

TransactionManager.Instance.EnsureInTransaction(doc)
#
for activView in lstView:
	activView.CropBoxVisible = True
	doc.Regenerate()
	cropBox = activView.CropBox 
	
	fecMultiGrids_Ids = [id for m in FilteredElementCollector(doc).OfClass(MultiSegmentGrid).WhereElementIsNotElementType() for id in m.GetGridIds()]
	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) and x.Id not in fecMultiGrids_Ids]
	
	outLst = []
	shpManager = activView.GetCropRegionShapeManager()
	boundLines = shpManager.GetCropShape()[0]
	boundLines = CurveLoop.CreateViaOffset(boundLines, offset_number, activView.ViewDirection.Negate())
	
	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 =  lstView
3 Likes

Wow!!! Its working perfectly. :star_struck: :star_struck: :star_struck:
Thank you very much.

1 Like

Hello Deniz, i also wanted to takle this problem for month but never had the time.

But it seems like @c.poupin already solved this? Or did you just filter the multi segment grids?

I will test and post my result. Please mind that segmented grids also make trouble in section views! While the result looks ok, the grids cant be manipulated later manually cause they are a little messed up. I have to use “set back to crop” to make them work again properly.

Hallo Gerhard,

@c.poupin had filtered them out for now because it could take time until he solved it. For me it’s necessary in ViewPlans. I tried to sort points over a geometric way but I did not have time to achieve it. Please let me know, if you code works for ViewPlans.

Ok, i want to mention another problem. The code does not work if both grid ends are out of the crop box, thats a big problem for me i need to fix.

I have a script that moves the cropboxes of sectionviews with detailing to another “level”, only the grids dont follow. And because both ends are then out of the cropbox, the python code here doesnt work.

A workaround with '“reset to crop” or “reset to 3d extents” is not possible because these methods are not available in the revit API.

I will look up those problems in the next days and get back with more info and hopefully with ideas for solving this issues.

1 Like

So first thing first, getting curves of multi segment grids need a special method, first getting the grid-ID an then calling that element by ID. This will “split up” the multi grid in single grids and you can get the curve from them.

x = UnwrapElement(IN[0])

ids = x.GetGridIds()
grids = []
for i in ids:
	grids.append(doc.GetElement(i))

OUT = grids

For more info see this post by @Konrad_K_Sobon: