How to filter for detail items in a dependent view?

How to filter for detail items in a dependent view?

JJamesHillGrp
Contributor Contributor
477 Views
3 Replies
Message 1 of 4

How to filter for detail items in a dependent view?

JJamesHillGrp
Contributor
Contributor

I am trying to filter for detail items in a cropped dependent view, but the filtered element collector picks up the detail items from the parent view as well. I tried to use the ElementIntersectsSolidFilter but it doesn't work with detail items. I tried to use the outline of the dependent view, but if the crop area of the dependent view is rotated then it doesn't work correctly. Is there another way to do this?

I have some examples of my codes below. I also attached a Revit file with some macros that include this code so that the problem can be reproduced along with a video.  The macros find and delete existing details in the active view, finds sprinklers in that active view, and places a detail item on top of the sprinklers.

 

This is the code that I started with but it does not filter correctly for dependent views (Macro Test1)

 

Dim foundTags = (From t As FamilyInstance In New FilteredElementCollector(m_rvtDoc, aView.Id).OfCategory(BuiltInCategory.OST_DetailComponents).OfClass(GetType(FamilyInstance))
                 Where t.LookupParameter("Family").AsValueString.StartsWith("HF Sprinkler Head"))

 

I tired this so that I could filter by the name afterwards but it has the same result

 

Dim foundTags = New FilteredElementCollector(m_rvtDoc, aView.Id).OfCategory(BuiltInCategory.OST_DetailComponents)

 

 

I tried the ElementIntersectsSolidFilter but it doesn't work with detail items (Macro Test2)

I am currently trying to use the outline but it does not work if the dependent view has a rotated crop box. (Macro Test3)  The code for this is below and it also draws the outline in the view for testing purposes. When the crop box is rotated the drawn box does not match, similar to the problem to this article https://thebuildingcoder.typepad.com/blog/2018/04/bounding-box-filter-always-axis-aligned.html 

 

Dim aView As View = m_rvtDoc.ActiveView	
If TryCast(aView, ViewPlan) IsNot Nothing Then
	Dim sprinklers = New FilteredElementCollector(m_rvtDoc, aView.Id).OfCategory(BuiltInCategory.OST_Sprinklers).OfClass(GetType(FamilyInstance)).Cast(Of FamilyInstance)()
	Dim v As ViewPlan = TryCast(aView, ViewPlan)
	
	Using trans As New Transaction(m_rvtDoc, "Place Sloped Sprinkler Symbols")
	    trans.Start()
	    'remove all existing symbols
		 Dim foundTags = (From t As FamilyInstance In New FilteredElementCollector(m_rvtDoc, aView.Id).OfCategory(BuiltInCategory.OST_DetailComponents).OfClass(GetType(FamilyInstance))
		 Where t.LookupParameter("Family").AsValueString.StartsWith("HF Sprinkler Head"))
	    			 
	    If v.GetPrimaryViewId IsNot Nothing AndAlso v.CropBoxActive Then  'is a cropped dependent, filter for within the view
			  Dim getZ As Double = TryCast(foundTags(0).Location, LocationPoint).Point.Z
			  Dim bottomZ As Double = getZ - 1
			    
		      Dim trf As autodesk.Revit.DB.Transform = v.CropBox.Transform.Inverse
			  Dim cbMax As XYZ = trf.OfPoint(v.CropBox.Max)
			  Dim cbMin As XYZ = trf.OfPoint(v.CropBox.Min)
			
			  Dim ol0 As New XYZ(cbMin.X, cbMin.Y, bottomZ)
			  Dim ol1 As New XYZ(cbMax.X, cbMax.Y, bottomZ + 2)
			  Dim ol As Outline = New Outline(ol0, ol1)
			
			'draw outline for checking
			  Dim pt0 As New XYZ(cbMin.X, cbMin.Y, bottomZ)
			  Dim pt1 As New XYZ(cbMax.X, cbMin.Y, bottomZ)
			  Dim pt2 As New XYZ(cbMax.X, cbMax.Y, bottomZ)
			  Dim pt3 As New XYZ(cbMin.X, cbMax.Y, bottomZ)
			  Dim edge0 As Line = Line.CreateBound(pt0, pt1)
			  Dim edge1 As Line = Line.CreateBound(pt1, pt2)
			  Dim edge2 As Line = Line.CreateBound(pt2, pt3)
			  Dim edge3 As Line = Line.CreateBound(pt3, pt0)
			  m_rvtDoc.Create.NewDetailCurve(v, edge0)
			  m_rvtDoc.Create.NewDetailCurve(v, edge1)
			  m_rvtDoc.Create.NewDetailCurve(v, edge2)
			  m_rvtDoc.Create.NewDetailCurve(v, edge3)
			
			  Dim deleteIDS As New List(Of ElementId)
			  For Each t In foundTags
			      Dim pnt As LocationPoint = TryCast(t.Location, LocationPoint)
			      If ol.Contains(pnt.Point, 0) Then
			          deleteIDS.Add(t.Id)
			      End If
			  Next
		    
		    TaskDialog.Show("Debug", "Active View - " & aView.Name & ", Sprinklers Found: " & sprinklers.Count &  ", Symbols Found: " & deleteIDS.Count)
		    
		     m_rvtDoc.Delete(deleteIDS)
		
		    Dim i = 0
		Else
		    Dim deleteIDS As New List(Of ElementId)
		    For Each t In foundTags
		        Dim i = 0
		        deleteIDS.Add(t.Id)
		    Next
		    TaskDialog.Show("Debug", "Active View - " & aView.Name & ", Sprinklers Found: " & sprinklers.Count &  ", Symbols Found: " & deleteIDS.Count)
		    m_rvtDoc.Delete(deleteIDS)
		End If
	
		PlaceNewSymbols(m_rvtDoc,sprinklers)
	    
	    trans.Commit()
	End Using
 Else
     TaskDialog.Show("Error", "Head symbols cannot be placed in this view - " & aView.Name)
 End If

 

 

The article also mentions transforming the target elements to check and see if they are in an outline that has been rotated. I was able to get that to work a little bit better, but it is still picking up detail items that are not visible in the cropped view (Macro Test4) 

		Dim aView As View = m_rvtDoc.ActiveView
		
		If TryCast(aView, ViewPlan) IsNot Nothing Then
		Dim sprinklers = New FilteredElementCollector(m_rvtDoc, aView.Id).OfCategory(BuiltInCategory.OST_Sprinklers).OfClass(GetType(FamilyInstance)).Cast(Of FamilyInstance)()
		Dim v As ViewPlan = TryCast(aView, ViewPlan)
		
		Using trans As New Transaction(m_rvtDoc, "Place Sloped Sprinkler Symbols")
		    trans.Start()
		    'remove all existing symbols
			 Dim foundTags = (From t As FamilyInstance In New FilteredElementCollector(m_rvtDoc, aView.Id).OfCategory(BuiltInCategory.OST_DetailComponents).OfClass(GetType(FamilyInstance))
			 Where t.LookupParameter("Family").AsValueString.StartsWith("HF Sprinkler Head"))
			 
			 If foundTags.Count > 0 Then
			 	If v.GetPrimaryViewId IsNot Nothing AndAlso v.CropBoxActive Then  'is a cropped dependent, filter for within the view
					  Dim getZ As Double = TryCast(foundTags(0).Location, LocationPoint).Point.Z
					  Dim bottomZ As Double = getZ - 1
					    
				      Dim trf As autodesk.Revit.DB.Transform = v.CropBox.Transform
					  Dim cbMax As XYZ = v.CropBox.Max
					  Dim cbMin As XYZ = v.CropBox.Min
					
					  Dim ol0 As New XYZ(cbMin.X, cbMin.Y, bottomZ)
					  Dim ol1 As New XYZ(cbMax.X, cbMax.Y, bottomZ + 2)
					  Dim ol As Outline = New Outline(ol0, ol1)
					
					
					  Dim deleteIDS As New List(Of ElementId)
					  For Each t In foundTags
					     Dim pnt As LocationPoint = TryCast(t.Location, LocationPoint)
					     Dim chkPnt As XYZ = trf.OfPoint(pnt.Point)
					     
					      If ol.Contains(chkPnt, 0) Then
					          deleteIDS.Add(t.Id)
					      End If
					  Next
			    
				    TaskDialog.Show("Debug", "Active View - " & aView.Name & ", Sprinklers Found: " & sprinklers.Count &  ", Symbols Found: " & deleteIDS.Count)
				    
				     m_rvtDoc.Delete(deleteIDS)
				
				    Dim i = 0
				Else
				    Dim deleteIDS As New List(Of ElementId)
				    For Each t In foundTags
				        Dim i = 0
				        deleteIDS.Add(t.Id)
				    Next
				    TaskDialog.Show("Debug", "Active View - " & aView.Name & ", Sprinklers Found: " & sprinklers.Count &  ", Symbols Found: " & deleteIDS.Count)
				    m_rvtDoc.Delete(deleteIDS)
				End If
			 End If
		    
		
			PlaceNewSymbols(m_rvtDoc,sprinklers)
		    
		    trans.Commit()
		End Using
	 Else
	     TaskDialog.Show("Error", "Head symbols cannot be placed in this view - " & aView.Name)
	 End If	

 

 

0 Likes
Accepted solutions (1)
478 Views
3 Replies
Replies (3)
Message 2 of 4

ctm_mka
Collaborator
Collaborator

So interesting note, even selecting all element in view manually returns the incorrect result for detail components in a dependent view. Returns correct results for Symbols, but that's not really helpful. Instead of your outline, try a boudingboxintersectfilter using the active views boundingbox. Since boundingbox's are always un-rotated, but always contain everything in them, it could work.

0 Likes
Message 3 of 4

JJamesHillGrp
Contributor
Contributor
Accepted solution

Its interesting to see that manually selecting All Elements in View for the detail items is also incorrect, I didn't even think to look at that! When using the bounding box I run into the problem from the original article that I linked and end up with elements outside of the view if the crop area is rotated. 

I ended up going in a different direction to solve this. I modified the code from this comment to create a function that determines if the location point of the detail item is inside of the crop box outline.

Public Function PointInsidePolygon(point As XYZ, polygonLines As List(Of CurveLoop)) As Boolean
    Dim intersects As Integer = 0

    ' Iterate through each edge of the polygon
    For Each p In polygonLines
        Dim cle As CurveLoopIterator = p.GetCurveLoopIterator
        While cle.MoveNext()
            Dim l As Line = TryCast(cle.Current, Line)
            If l IsNot Nothing Then
                Dim p1 = l.GetEndPoint(0)
                Dim p2 = l.GetEndPoint(1)

                ' Check if the point is on the edge
                If (point.Y > Math.Min(p1.Y, p2.Y)) AndAlso (point.Y <= Math.Max(p1.Y, p2.Y)) AndAlso (point.X <= Math.Max(p1.X, p2.X)) AndAlso (p1.Y <> p2.Y) Then
                    Dim xinters As Single = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X
                    If (p1.X = p2.X) OrElse (point.X <= xinters) Then
                        intersects += 1
                    End If
                End If
            End If
            cle.MoveNext()
        End While
    Next

    If intersects = 0 Then Return False

    ' Return True if the number of intersections is odd
    Return (intersects Mod 2 = 1)
End Function

Here is how I use it with the collection of detail items. I ended up needing to filer the collection of sprinklers this way too because the rotated crop box was also messing up that number.

Dim foundTags = (From t As FamilyInstance In New FilteredElementCollector(m_rvtDoc, aView.Id).OfCategory(BuiltInCategory.OST_DetailComponents).OfClass(GetType(FamilyInstance))
                 Where t.LookupParameter("Family").AsValueString.StartsWith("HF Sprinkler Head"))
Dim cropShape = Nothing
Dim deleteIDS As New List(Of ElementId)
If v.GetPrimaryViewId IsNot Nothing AndAlso v.CropBoxActive AndAlso foundTags.Count > 0 Then  'is a cropped dependent, filter again to make sure they're in the view
    cropShape = aView.GetCropRegionShapeManager.GetCropShape
    For Each t In foundTags
        Dim pnt As LocationPoint = TryCast(t.Location, LocationPoint)
        If PointInsidePolygon(pnt.Point, cropShape) Then
            deleteIDS.Add(t.Id)
        End If
    Next
Else
    For Each t In foundTags
        Debug.WriteLine(t.Category.Name)
        Dim i = 0
        deleteIDS.Add(t.Id)
    Next
End If

m_rvtDoc.Delete(deleteIDS)

 

Message 4 of 4

jeremy_tammik
Alumni
Alumni

Thank you for raising your issue here in the discussion forum and congratulations on the effective solution!

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes