Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Geometry of View Extents

9 REPLIES 9
SOLVED
Reply
Message 1 of 10
Mark.Ackerley
1355 Views, 9 Replies

Geometry of View Extents

Hi All,

 

Just a little advice wanted if that's ok...

 

I have a linked file, I want the user to have the option to select all linked walls in the active view.  The active view FEC doesn't work for links. So we need have to have a geometric solution.

 

If the crop box is turned on, that's great, I can use that to make a solid and run an intersect.

 

If the crop box is turned off however, using it might give unexpected results to the user... 

 

So I want to get the boundary extents of the active view as geometry or coordinates.   

 

Obviously Revit knows the view extents because I can ZoomToFit().

 

So I'm looking for a way to define that geometrically. 

 

I tried taking the view > plane > maximise extents but that failed.

 

MaxWindowExtents doesn't seem to return model coordinates.

 

I could obviously get a kind of result by collecting all elements (or just walls say) in the model and the max and min points of their bounding boxes, but it seems pretty inefficient.

 

There doesn't seem to be any kind of model extents parameter I can find.

 

Any other ideas greatfully received!

 

Cheers,

 

Mark

9 REPLIES 9
Message 2 of 10
Message 3 of 10

hey,

 

thanks for the reply, yes I am aware of those posts, however my question is a little different...

 

my query is to retrieve the extent of linked elements in the active view (a floor plan) where the crop box has not been set (we could set the crop box to the extents if that’s an option)

 

cheers,

 

Mark

Message 4 of 10

 

Retrieve all Walls of the Link, calculate the extends using boundingbox

Doesn't need to be accurated, just needs the minimal extends to include all walls.

 

Next use this extends (Xmin/max and Ymin/max) to generate a "Virtual" Solid using the host viewsettings for level, cutheight etc. (Z Min/Max). This will filter out all linked walls not in the viewrange of the host.

 

As stated in other posts this retrieves all walls intersecting the  "virtual" solid, Phasing, User hidden nested elements and or filters may need to be included as well

Some settings regarding links can'be retrieved like Linked instance custom overrides or linked view etc.

 

- Michel

Message 5 of 10

I dipped into that area once... here is part of my research back then:

 

https://thebuildingcoder.typepad.com/blog/2014/04/determining-the-size-and-location-of-viewports-on-...

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 6 of 10


I could obviously get a kind of result by collecting all elements (or just walls say) in the model and the max and min points of their bounding boxes, but it seems pretty inefficient.


Didn't notice this before, it's not inefficient. The collection and ordering of the min/max is fast, could even be faster then Zoom Max-extends (refreshing view) converting UIview coordinates to Model Coordinates and then creating the virtual solid selecting linked elements and then maybe zoom back to previous view range?

 

The collection of elements and the ordering of the boundingbox in the link can be optimized by determining the Zmin/max in advance and filtering out any boundingbox not within that range.

 

- Michel

Message 7 of 10

Thanks Everyone, 

 

I'll have a play this evening once the kids are in bed 🙂

Message 8 of 10

This seemed to work! Will check it through more thoroughly tomorrow....

 

Thanks again, I'm sure it's obvious which of the other forum posts have aided me 🙂

 

Obviously this is (Dynamo) Python code.

 

All comments welcome.

 

Cheers,

 

Mark

 

#thanks for all the help everyone
import clr

# Import RevitAPI
clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *
import System


# Import Element wrapper extension methods
clr.AddReference("RevitNodes")
import Revit
from Autodesk.Revit.DB import *


clr.AddReference("RevitAPIUI")
from Autodesk.Revit.UI.Selection import ObjectType

#for our selection
from Autodesk.Revit.UI.Selection import *

# Import DocumentManager and TransactionManager #
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
uiApp = DocumentManager.Instance.CurrentUIApplication

class selFilt(ISelectionFilter):
    #"__init__" is a reseved method in python classes. It is called as a constructor in object oriented terminology. This method is called when an object is created from a class and it allows the class to initialize the attributes of the class.
    #it's almost like the self is implied? it has to be there but has no variable, we can't use the allow element function without a separate init, we then must have an equation to keep the code format
	def __init__(self, element):
		e = element
	def AllowElement(self, e):
		if e.ToString() == 'Autodesk.Revit.DB.Wall':
			return True
		else:
			return False
	def AllowReference(self, ref, point):
		return true


	
#so to compensate for different shared position heights, we need the Internal Project Point, even if it's not current!
#otherwise our cutting line will not have the correct Z value
locName = IN[3]
projectLocs = doc.ProjectLocations
for loc in projectLocs:
    if loc.Name == locName:
        pos = XYZ(0,0,0)
        locPosition = loc.GetProjectPosition(pos).Elevation
solidBaseHtZ = doc.ActiveView.GenLevel.ProjectElevation
solidBaseXYZ = XYZ(0,0,1)
if solidBaseXYZ.Z < 1:
    solidBaseXYZ == XYZ(0,0,1)
#get the cut plane offset of the view
solidTopHt= doc.ActiveView.GetViewRange().GetOffset(PlanViewPlane.CutPlane)
cropSh = doc.ActiveView.GetCropRegionShapeManager().GetCropShape()


targetWalls = []

obt = ObjectType.LinkedElement
refElemsLinked = uidoc.Selection.PickObjects(obt, "Please pick elements in the linked model")
refElemLinked = refElemsLinked[0]
for refElemLinked in refElemsLinked:
    elem = doc.GetElement(refElemLinked.ElementId)
    docLinked = elem.GetLinkDocument()
    linkedElement = docLinked.GetElement(refElemLinked.LinkedElementId)
    targetWalls.append(linkedElement)
    collector  = FilteredElementCollector(doc)
    elem = doc.GetElement(refElemLinked.ElementId)
    docLinked = elem.GetLinkDocument()

#let's go get all walls in the link for use in defining extents of area to interrogate
activeViewId = doc.ActiveView.Id	
fec=ElementCategoryFilter(BuiltInCategory.OST_Walls)
#walls in link
targetWalls = FilteredElementCollector(docLinked,doc.ActiveView.Id).WherePasses(fec).WhereElementIsNotElementType().ToElements()
#walls in model
wallsinDoc = FilteredElementCollector(doc, doc.ActiveView.Id).WherePasses(fec).WhereElementIsNotElementType().ToElements()

allWallsInLnkNDoc = []

if docLinked != None and doc.ActiveView.CropBoxVisible:
    #Creation of the intersecting solid box for the link (in this case almost in origin)
    linkInst = doc.GetElement(refElemLinked.ElementId)
    virtualSolid = GeometryCreationUtilities.CreateExtrusionGeometry(cropSh, solidBaseXYZ, solidTopHt)
    virtualLinkSolid = SolidUtils.CreateTransformed(virtualSolid, linkInst.GetTotalTransform().Inverse)
    solidIntersecFil = Autodesk.Revit.DB.ElementIntersectsSolidFilter(virtualLinkSolid)
    instanceElementsInViewRvL = FilteredElementCollector(docLinked).WhereElementIsNotElementType().WherePasses(solidIntersecFil)

else:
    #so we want to get all walls in the extent of the view if the view is not cropped.
    #we don't want to use the crop region, because that might have been left at some tiny
    #part of the screen.
    #so we will get all the walls in the model, get the max and min of their bounding box
    #and create a new bounding box which spans all of them
    #we can then create a solid from it using the level offset and cutplane, and run an intersect on that
    #Bounding boxes of walls in link 
    allWallsInLnkNDocBB = []    
    for lnkWall in targetWalls:
        lnkWallBB = lnkWall.get_BoundingBox(None)
        allWallsInLnkNDocBB.append(lnkWallBB)        
    #Bounding boxes of walls in doc
    #seems like it will be handy for when we don't want links
    for wallInDoc in wallsinDoc:
        wallBB = wallInDoc.get_BoundingBox(None)
        allWallsInLnkNDocBB.append(wallBB)
    #get bb max and mins
    bBMaxX, bBMaxY, bBMinX, bBMinY = [],[],[],[]   
    for wallBB in allWallsInLnkNDocBB:
        bBMinX.append(wallBB.Min.X)
        bBMinY.append(wallBB.Min.Y)
        bBMaxX.append(wallBB.Max.X)
        bBMaxY.append(wallBB.Max.Y)
    #now input the max and min values        
    pt0 = XYZ(min(bBMinX), min(bBMinY), solidBaseHtZ)
    pt1 = XYZ(max(bBMaxX), min(bBMinY), solidBaseHtZ)
    pt2 = XYZ(max(bBMaxX), max(bBMaxY), solidBaseHtZ)
    pt3 = XYZ(min(bBMinX), max(bBMaxY), solidBaseHtZ)
    #edges in BBox coords
    edge0 = Line.CreateBound(pt0, pt1)
    edge1 = Line.CreateBound(pt1, pt2)
    edge2 = Line.CreateBound(pt2, pt3)
    edge3 = Line.CreateBound(pt3, pt0)
    #create loop, still in BBox coords
    edges =list()
    edges.Add(edge0);
    edges.Add(edge1);
    edges.Add(edge2);
    edges.Add(edge3);
    baseLoop = CurveLoop.Create(edges)
    loopList = list()
    loopList.Add(baseLoop)
    linkInst = doc.GetElement(refElemLinked.ElementId)
    VirtualSolid = GeometryCreationUtilities.CreateExtrusionGeometry(loopList, solidBaseXYZ, 5)
    VirtualLinkSolid = SolidUtils.CreateTransformed(VirtualSolid, linkInst.GetTotalTransform().Inverse)
    solidIntersecFil = Autodesk.Revit.DB.ElementIntersectsSolidFilter(VirtualLinkSolid)
    #we used all the walls to make our filter, but for this, we are only returning linked walls
    instanceElementsInViewRvL = FilteredElementCollector(docLinked).WhereElementIsNotElementType().WherePasses(solidIntersecFil)
    

OUT = instanceElementsInViewRvL

 

 

 

Message 9 of 10

Looking good to me.

 

On e little optimisation possibility that struck me is to avoid the string conversion in AllowElement.

 

Instead, you can check check the type directly, something like e.GetType() === Autodesk.Revit.DB.Wall.

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 10 of 10
p_smithBVN
in reply to: jeremytammik

Hi @Mark.Ackerley 

 

Thanks for sharing your code on this. I have been looking for something that does the "if" part of your if/else to help when the FilteredElementCollector(doc, target_view) overload is too expensive from a performance point of view.

 

Out of interest, did you have any odd things happen when you were creating that solid? Even though the crop region XYZs look correct by numbers they end up producing a solid much larger and unrelated to the crop region. My debug environment should be easier still as I'm only working in host model so not transforming the solid. 

 

Was just wondering if you had to make subsequent mods to the above or if that did the trick for you?

 

Cheers, Pete

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community