One question that regularly comes up is how to determine whether certain building elements intersect. There are basically two approaches to this, either querying the elements for their pure geometry and making use of pure geometrical intersection methods, or using the higher-level FindReferencesByDirection method, which works on the building elements themselves. Here is a typical version of this question:
Question: I need to find out if any two elements in a project are interfering with each other. Searching the Revit API help, I found that the Intersect methods on the Autodesk.Revit.Geometry.GeometryObject can be used to calculate intersections.
So it seems that I need to find out the type of geometry for the given building element and then call the relevant intersection method. Is this correct? Is there any sample code available demonstrating this? Is there any API method which accepts two elements and finds out whether they are interfering?
Answer: There is no direct API method that calculates the intersection between two Revit building elements. One possibility is to query them for their geometry elements, and then use the geometry Intersect methods to determine intersection points.
Here is some sample code which shows how to find the intersection points of two geometry lines, excerpted from the Revit SDK sample CreateTruss:
private XYZ GetIntersection( Line line1, Line line2 ) { IntersectionResultArray results; SetComparisonResult result = line1.Intersect( line2, out results ); if( result != SetComparisonResult.Overlap ) throw new InvalidOperationException( "Input lines did not intersect." ); if( results == null || results.Size != 1 ) throw new InvalidOperationException( "Could not extract line intersection point." ); IntersectionResult iResult = results.get_Item( 0 ); return iResult.XYZPoint; }
A more advanced and complex use of the pure geometrical intersection methods is provided by the AreSolidsCut method defined by the Revit SDK RoomsRoofs sample.
While there is no direct method to determine whether two building elements intersect, one could implement such a method based on the FindReferencesByDirection method, as we suggested in the discussion on the analytical support tolerance. Several SDK samples demonstrate its use.
Hi Jeremy
You have mentioned elsewhere that FindReferencesByDirection() doesn't find intersections in linked elements. Does it also apply for these GeometryObject::intersect() functions (according to my experimentation it does)?
If does, is there ANY possible way to determine intersections via API with "local" and linked elements (as it is possible with GUI in Collaborate->Interference...)?
Posted by: Olli Kattelus | November 04, 2010 at 09:03
Dear Olli,
Sorry, I don't know off-hand. Please submit an ADN case for that, with an absolutely minimal sample Revit project and a minimal Visual Studio solution showing how you tested this, and we can take a closer look. Thank you!
Cheers, Jeremy.
Posted by: Jeremy Tammik | November 05, 2010 at 09:14
Hi Jeremy
I have a Model line that intersects multiple Revit doors, how do I get the element ID’s of the doors the line intersects in the order it intersects them down the line. This programme is for renumbering doors in the order they intersect the line, makes it easer if you have to add a door in. (is it also possible to do it with a detail line not a model line)
Posted by: nicholas B | December 12, 2010 at 23:28
Dear Nicholas,
I love this kind of question! There are of course an infinite number of ways to address this question.
One pretty simple solution is to use the FindReferencesByDirection method:
http://thebuildingcoder.typepad.com/blog/2010/01/findreferencesbydirection.html
The sample mentioned there was added to the Revit 2011 SDK as FindColumns. It retrieves all columns intersecting a wall, which is almost exactly the same as finding all doors intersecting your model line.
I am not certain that you can rely on FindReferencesByDirection returning the elements sorted by distance long the line, so you should first of all test whether it does and secondly possibly do it yourself, for instance by defining a sorting and comparison algorithm for 2D or 3D points as demonstrated by my XYZ Compare method and XyzEqualityComparer class:
http://thebuildingcoder.typepad.com/blog/2009/05/nested-instance-geometry.html
Cheers, Jeremy.
Posted by: Jeremy Tammik | December 13, 2010 at 11:36
Is there any way to find whether an a line intersects with any element in a linked file and return the point of intersection? I tried the ReferenceIntersector but it didn't work for all the three overloads with the FindReferencesInRevitLinks property set to true. Does anyone know any solution to this problem? Kindly help.
This is the method i wrote for finding it but couldn,t find a solution.
public double FindDistance(Element ele, XYZ point, IList ElementsLInked)
{
double proximity=0.0;
FilteredElementCollector collector = new FilteredElementCollector(m_document.Document);
Func isNotTemplate = v3 => !(v3.IsTemplate);
View3D view3D = collector.OfClass(typeof(View3D)).Cast().First(isNotTemplate);
ReferenceIntersector refIntersector = new ReferenceIntersector(view3D);
refIntersector.SetFilter(GetStructuralElements(m_document.Document));
refIntersector.TargetType = FindReferenceTarget.Element;
refIntersector.FindReferencesInRevitLinks=true;
ReferenceWithContext referenceWithContext = refIntersector.FindNearest(point, XYZ.BasisZ);
if (referenceWithContext!=null)
{
MessageBox.Show(m_document.Document.GetElement(referenceWithContext.GetReference()).GetType().Name);
proximity = referenceWithContext.Proximity;
}
else
{
MessageBox.Show("No intersecting element found. Cannot extend the rod!");
}
MessageBox.Show(proximity.ToString());
return proximity;
}
Posted by: Dickins John | October 23, 2013 at 08:06
I also tried retrieving the elements from the linked file and then find the element IDs. This too didn't work. Kindly help.
public double FindDistance(Element ele, XYZ point, IList ElementsLInked)
{
IList ElementIDLinked = new List();
foreach(Element elemLinked in ElementsLInked )
{
ElementIDLinked.Add(elemLinked.Id);
}
MessageBox.Show(ElementIDLinked.Count.ToString());
double proximity=0.0;
FilteredElementCollector collector = new FilteredElementCollector(m_document.Document);
Func isNotTemplate = v3 => !(v3.IsTemplate);
View3D view3D = collector.OfClass(typeof(View3D)).Cast().First(isNotTemplate);
ReferenceIntersector refIntersector = new ReferenceIntersector(ElementIDLinked, FindReferenceTarget.Element, view3D);
refIntersector.FindReferencesInRevitLinks=true;
ReferenceWithContext referenceWithContext = refIntersector.FindNearest(point, XYZ.BasisZ);
if (referenceWithContext!=null)
{
MessageBox.Show(m_document.Document.GetElement(referenceWithContext.GetReference()).GetType().Name);
proximity = referenceWithContext.Proximity;
}
else
{
MessageBox.Show("No intersecting element found. Cannot extend the rod!");
}
MessageBox.Show(proximity.ToString());
return proximity;
}
Posted by: Dickins John | October 23, 2013 at 08:10
Dear John,
It should be possible to achieve this.
Have you made any progress with it yet?
If not, could you please provide a really minimal sample situation and clear description of the issue and the exact expected results, like in this discussion on determining the host location of linked elements:
http://thebuildingcoder.typepad.com/blog/2013/11/determining-host-document-location-of-a-linked-element.html
Thank you!
Cheers, Jeremy.
Posted by: Jeremy Tammik | November 06, 2013 at 08:30
This problem has been solved. Don't apply any filter to the ReferenceIntersector because type (if you use GetType()) of instances returned by the intersector's find method is "Linked Instances" and not its original type. Even the element ID of the intersected element is different from the original element in the linked file.
This brings us to the new problem. How to find the type and original element id of the intersected element?
Any suggestions?
Posted by: Dickins John | November 07, 2013 at 03:55
can you show me intersect between curve and reference plane
Posted by: ko0ls | December 23, 2014 at 23:27
Dear Ko0ls,
You might be able to use the Face.Intersect(Curve) method.
Cheers, Jeremy.
Posted by: Jeremy Tammik | January 09, 2015 at 02:27