My work on setting up a new PC is nearing completion.
There is also a need to clarify the use of the Face.Intersect(Face)
method:
Face.Intersect
methodSeveral Revit API discussion forum threads are discussing the status of the Face.Intersect (Face) method:
Face.Intersect(Face)
methodIntersect
method (Face
)Face
class Intersect
method problemBriefly, the main problem is this:
Question: This issue was mentioned in 2016, in the third thread listed above, but it is worth bringing up again, as the issue hasn't been resolved yet in 2018.
As far as I can tell, the Face.Intersect(face)
method always returns FaceIntersectionFaceResult.Intersecting
.
When I run the code below in a view with a single wall and single floor, each face to face test returns an intersection:
public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements ) { var list = new FilteredElementCollector( commandData.Application.ActiveUIDocument.Document, commandData.View.Id ) .WhereElementIsNotElementType() .Where( e => e is Wall || e is Floor ); foreach( var f1 in list.First() .get_Geometry( new Options() ) .OfType<Solid>().First() .Faces.OfType<Face>() ) { foreach( var f2 in list.Last() .get_Geometry( new Options() ) .OfType<Solid>().First() .Faces.OfType<Face>() ) { if( f1.Intersect( f2 ) == FaceIntersectionFaceResult.Intersecting ) { if( System.Windows.Forms.MessageBox.Show( "Intersects", "Continue", System.Windows.Forms.MessageBoxButtons.OKCancel, System.Windows.Forms.MessageBoxIcon.Exclamation ) == System.Windows.Forms.DialogResult.Cancel ) { return Result.Succeeded; } } } } return Result.Succeeded; }
Answer: Thank you for your report and reproducible case.
I see the same behaviour in Revit 2019 as well.
I added some code to The Building Coder samples in CmdIntersectJunctionBox.cs to test and report in more depth:
/// <summary> /// Return all faces from first solid /// of the given element. /// </summary> IEnumerable<Face> GetFaces( Element e ) { Options opt = new Options(); IEnumerable<Face> faces = e .get_Geometry( opt ) .OfType<Solid>() .First() .Faces .OfType<Face>(); int n = faces.Count(); Debug.Print( "{0} has {1} face{2}.", e.GetType().Name, n, Util.PluralSuffix( n ) ); return faces; } void TestIntersect( Document doc ) { View view = doc.ActiveView; var list = new FilteredElementCollector( doc, view.Id ) .WhereElementIsNotElementType() .Where( e => e is Wall || e is Floor ); int n = list.Count(); Element floor = null; Element wall = null; if( 2 == n ) { floor = list.First() as Floor; if( null == floor ) { floor = list.Last() as Floor; wall = list.First() as Wall; } else { wall = list.Last() as Wall; } } if( null == floor || null == wall ) { Util.ErrorMsg( "Please run this command in a " + "document with just one floor and one wall " + "with no mutual intersection" ); } else { Options opt = new Options(); IEnumerable<Face> floorFaces = GetFaces( floor ); IEnumerable<Face> wallFaces = GetFaces( wall ); n = 0; foreach( var f1 in floorFaces ) { foreach( var f2 in wallFaces ) { if( f1.Intersect( f2 ) == FaceIntersectionFaceResult.Intersecting ) { ++n; if( System.Windows.Forms.MessageBox.Show( "Intersects", "Continue", System.Windows.Forms.MessageBoxButtons.OKCancel, System.Windows.Forms.MessageBoxIcon.Exclamation ) == System.Windows.Forms.DialogResult.Cancel ) { return; } } } } Debug.Print( "{0} face-face intersection{1}.", n, Util.PluralSuffix( n ) ); } }
Here is a simple test model with a disjunct floor and wall:
My sample code reports:
Floor has 7 faces. Wall has 6 faces. 38 face-face intersections.
So, in fact, not every face-to-face test reports an intersection, because 7*6 equals 42.
Only the vast majority do :-)
I logged the issue REVIT-133627 [Face.Intersect returns false positives] with our development team to explore this further and provide an explanation.
This turned out to be a duplicate of an existing older issue, REVIT-58034 [API Face.Intersect(Face) returns true even if two faces don't intersect with each other] and was therefore closed again.
The development team replied:
We are aware of this issue. This function does indeed not do what one expects. At most, it computes intersections between the underlying (unbounded) surfaces, not the (bounded) faces lying in the surfaces. As a first step, the documentation will be updated to reflect this fact. Then, we'll see whether resources can be found to fully implement the face intersection functionality, or remove the incomplete functionality.
As a result, REVIT-58034 was renamed. Currently, the following related tickets have all been closed:
Frank @Fair59 Aarssen adds:
I have previously plotted the intersections using the ByRef
curve overload and found this to be the case, as explained in the thread
on the Face
class Intersect
method problem:
Apparently, the intersecting faces are considered infinite with therefore many possible intersections beyond the range of the element itself.
In this image, the green lines are plotted using curves from the overload
Face.Intersect(ByVal Face, ByRef Curve)
:
Hard to understand at first why they all exist, but once you trace along parallel to the faces, you can see all are valid.
In actual fact, an API user may prefer to find this form of intersection, rather than be told no intersection exists (due to the bounds of the face preventing it).
You can always compare points on the original face to those on the curve intersect result to check if there is an actual intersection.
However, if no results were given, then that would not be useful at all.
Probably, there should be a bound versus unbound option, perhaps.
The sample images shown above all include rectangular wall faces.
If the potentially intersecting faces are rectangular, the problem can presumably be reduced to a pretty simple query.
One approach would be to retrieve the intersection curves of the unbounded faces and test whether they lie on the bounded faces, as suggested above by Frank.
Alternatively, a DIY solution may also be feasible and more efficient.
After all, a rectangular face can be seen as two coplanar triangles, and the intersection of 3D triangles is a pretty common requirement.
Here are some useful-looking results that showed up in a couple of quick Internet searches:
If anyone would like to share a reliable, robust, and efficient 3D triangle or rectangle intersection algorithm, please let us know.
Thank you!
I implemented and installed a couple of different source code colourizer tools in the past.
This spring, I set up the PowerTools 2015 Copy HTML Markup functionality.
On the new computer, I updated to Visual Studio 2017 instead of Visual Studio 2015.
Accordingly, I update the code colouriser to Productivity Power Tools 2017/2019.
In the same vein, I reinstalled the Visual Studio Revit Add-In Wizards, again, slightly updated for Visual Studio 2017, captured in VisualStudioRevitAddinWizard release 2020.0.0.2).