Intersection between Plane (View) and PlanarFace (extracted from floor)

Intersection between Plane (View) and PlanarFace (extracted from floor)

bixilix
Contributor Contributor
1,200 Views
10 Replies
Message 1 of 11

Intersection between Plane (View) and PlanarFace (extracted from floor)

bixilix
Contributor
Contributor

Hi everyone 🙂
I have a problem with the intersection of a View plane and a Face. I am in a section and I wish to receive the intersectioncurve between my viewplane and my ceilings.

 

Here I receive the plane of my Section View

View activeView = doc.ActiveView;
            var origin = activeView.Origin;
            var direction = activeView.ViewDirection;
            Plane plane = Plane.CreateByNormalAndOrigin(direction, origin);

Here is my code to receive the upper faces of my ceilings.

var floors = new FilteredElementCollector(doc, activeView.Id).WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_Floors)).WhereElementIsNotElementType().Cast<Element>().ToList();
            foreach(Element f in floors)
            {

                var opt = new Options();
                var e = f.get_Geometry(opt);
                List<PlanarFace> faces = new List<PlanarFace>();
                foreach (GeometryObject obj in e)
                {
                    Solid solid = obj as Solid;
                    if (null != solid)
                    {
                        foreach (Face face in solid.Faces)
                        {
                            PlanarFace pf = face as PlanarFace;
                            XYZ normal = pf.FaceNormal;
                            

                            if (normal.X == 0 && normal.Y == 0 && normal.Z == 1)
                            {
                               

                                faces.Add(pf);

                                // TODO: Intersection between pf and plane
                            }
                        }
                    }
                }
            }

 

PlanarFace has no Method to intersect with a Plane and the other way round. Can anyone please help me with this one? I´m a little stuck right now 😞

0 Likes
1,201 Views
10 Replies
Replies (10)
Message 2 of 11

jeremy_tammik
Alumni
Alumni

You can easily extract the plane properties from the two given planes and calculate your own intersection:

  

https://duckduckgo.com/?q=plane-plane+intersection 

  

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

jeremy_tammik
Alumni
Alumni

If you prefer to stick with the Revit API, I just noticed something useful was added just for you back in 2013:

  

https://thebuildingcoder.typepad.com/blog/2013/04/whats-new-in-the-revit-2014-api.html

  

Face/Face Intersection

  
The method

  

  • Face.Intersect()

  

calculates the intersection of the input face with this face and returns the intersection results. The method can output the intersection geometry if the intersection consists of a single curve.

  

Oh no, I see you have a plane and a face, not two faces... Sorry about that.

  

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

jeremy_tammik
Alumni
Alumni

Looking further into the DIY approach, this discussion looks very promising:

  

https://stackoverflow.com/questions/6408670/line-of-intersection-between-two-planes

  

If you write a neat generic solution for this, I'll gladly add it to The Building Coder samples for future reference. Thank you!

  

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

architect.bim
Collaborator
Collaborator

Hi @bixilix and @jeremy_tammik! This may not be the cleanest solution, but you can write a method that creates a Solid in a specified plane, consisting of a single rectangular planar Face of given dimensions. Later you can use this object for "Face/Face Intersection".

# Python sample

def create_rectangular_face(plane, width, height=None):
    if height is None:
        height = width
    origin = plane.Origin
    right_direction = plane.XVec * width
    up_direction = plane.YVec * height

    pt1 = origin + (up_direction / 2) + (right_direction / 2)
    pt2 = pt1 - right_direction
    pt3 = pt2 - up_direction
    pt4 = pt3 + right_direction

    builder = DB.BRepBuilder(DB.BRepType.OpenShell)

    face_id = builder.AddFace(
        DB.BRepBuilderSurfaceGeometry.Create(
            plane,
            None
        ),
        False
    )

    loop_id = builder.AddLoop(face_id)

    edge_1_id = builder.AddEdge(DB.BRepBuilderEdgeGeometry.Create(pt1, pt2))
    edge_2_id = builder.AddEdge(DB.BRepBuilderEdgeGeometry.Create(pt2, pt3))
    edge_3_id = builder.AddEdge(DB.BRepBuilderEdgeGeometry.Create(pt3, pt4))
    edge_4_id = builder.AddEdge(DB.BRepBuilderEdgeGeometry.Create(pt4, pt1))

    builder.AddCoEdge(loop_id, edge_1_id, False)
    builder.AddCoEdge(loop_id, edge_2_id, False)
    builder.AddCoEdge(loop_id, edge_3_id, False)
    builder.AddCoEdge(loop_id, edge_4_id, False)
    builder.FinishLoop(loop_id)
    builder.FinishFace(face_id)
    builder.Finish()

    return builder.GetResult().Faces[0]


view = doc.ActiveView
plane = DB.Plane.CreateByOriginAndBasis(
    view.Origin,
    view.RightDirection,
    view.UpDirection,
)

face = create_rectangular_face(plane, 100)

You can additionally analyze the dimensions of the floor face to know exactly what size of the second face should be.


Maxim Stepannikov | Architect, BIM Manager, Instructor
Message 6 of 11

jeremy_tammik
Alumni
Alumni

Yup, that is another possibility, indeed. Don't you think the DIY direct intersection of two planes will be faster, though? By an order of magnitude, maybe, or two, or three?

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 7 of 11

architect.bim
Collaborator
Collaborator

Yes, I think in case of planes your way should be really much faster.


Maxim Stepannikov | Architect, BIM Manager, Instructor
Message 8 of 11

bixilix
Contributor
Contributor

Hi Jeremy, hi Maxim,

thanks for your answers. I created a plane from my view with your code and it seems to work great.

public static Face CreateRectangularFaceFromPlane(Plane plane, double width, double height = -1)
        {
            if (height == -1)
            {
                height = width;
            }

            XYZ origin = plane.Origin;
            XYZ rightDirection = plane.XVec * width;
            XYZ upDirection = plane.YVec * height;

            XYZ pt1 = origin + (upDirection / 2) + (rightDirection / 2);
            XYZ pt2 = pt1 - rightDirection;
            XYZ pt3 = pt2 - upDirection;
            XYZ pt4 = pt3 + rightDirection;

            BRepBuilder builder = new BRepBuilder(BRepType.OpenShell);

            BRepBuilderSurfaceGeometry surface = BRepBuilderSurfaceGeometry.Create(plane, null);
            BRepBuilderGeometryId faceId = builder.AddFace(surface, false);

            BRepBuilderGeometryId loopId = builder.AddLoop(faceId);

            BRepBuilderEdgeGeometry edge1 = BRepBuilderEdgeGeometry.Create(pt1, pt2);
            BRepBuilderEdgeGeometry edge2 = BRepBuilderEdgeGeometry.Create(pt2, pt3);
            BRepBuilderEdgeGeometry edge3 = BRepBuilderEdgeGeometry.Create(pt3, pt4);
            BRepBuilderEdgeGeometry edge4 = BRepBuilderEdgeGeometry.Create(pt4, pt1);

            BRepBuilderGeometryId edge1Id = builder.AddEdge(edge1);
            BRepBuilderGeometryId edge2Id = builder.AddEdge(edge2);
            BRepBuilderGeometryId edge3Id = builder.AddEdge(edge3);
            BRepBuilderGeometryId edge4Id = builder.AddEdge(edge4);

            builder.AddCoEdge(loopId, edge1Id, false);
            builder.AddCoEdge(loopId, edge2Id, false);
            builder.AddCoEdge(loopId, edge3Id, false);
            builder.AddCoEdge(loopId, edge4Id, false);
            builder.FinishLoop(loopId);
            builder.FinishFace(faceId);
            builder.Finish();

            var faces = builder.GetResult().Faces;
            return faces.get_Item(0);
            
        }

Actually my problem is, that there are multiple intersections between the topface of my floor and the viewface. As Jeremy said, the Face / Face Intersection is only capable of creating one line instead of multiple lines. My goal is to reach something like this:

bixilix_1-1676459664530.png

With the Face / Face I get something like this:

bixilix_2-1676459717515.png

 

Is there any option to use the Geometry.Intersect() from Dynamo somehow? This works perfectly for my case. I know, its not really performant, but for my case that would be ok. And I know that Dynamo is open source, but I am not able to find the C# Method for this node, even though it is an OOTB-Node 😅

bixilix_0-1676459572975.png

 

0 Likes
Message 9 of 11

RPTHOMAS108
Mentor
Mentor

A common question regarding what Dynamo does and the API can't, not easy.

 

Dynamo uses a different geometry library for this I believe those within:

C:\Program Files\Autodesk\Revit 2023\AddIns\DynamoForRevit\libg_228_0_0

 

It conducts a number of geometry conversions to utilise the objects of these libraries namely those at:

https://github.com/DynamoDS/DynamoRevit/tree/master/src/Libraries/RevitNodes/GeometryConversion

 

This is all deeply imbedded into Dynamo so you have two options.

1) Reference all the Dynamo libraries to get those Dynamo parts to do the work (would probably not work because of a myriad of dependencies not initialised).

2) Try to understand what you need to do with the Geometry from Revit API to use the libraries above directly.

 

For example:

There is a static method in the LibG.Managed.dll called Autodesk.LibG.Solid.by_joined_surfaces

 

Then in the github source below there is the call

DynamoRevit/RevitToProtoSolid.cs at master · DynamoDS/DynamoRevit · GitHub

 

Solid converted = null;
try
   {
      converted = Solid.ByJoinedSurfaces(srfs);
   }

 

So is this an indirect call to this library? There are a lot of other pieces to work out for example you first have to extract all the faces and convert them to the types of object used in this library function.

 

I can't comment on the licensing aspect of all of that either.

 

If anyone has more information regarding the above I think it would be of interest here i.e. is there a way to use the geometry libraries that Dynamo uses (without Dynamo) and what are the considerations for it?

0 Likes
Message 10 of 11

jeremy_tammik
Alumni
Alumni

Thank you for the details and for digging in. The licensing aspect should be OK, it all being open source and intended for public use. I still think it would be a lot easier to go to the StackOverflow thread I mentioned above and just roll your own plane-plane intersection algorithm. After all, an infinite plane is a very simple object, and defined by just four real numbers. Actually, in regards of complexity, an infinite plane is simpler than an infinite line (ray). The plane definition requires four real numbers, the normal vector and distance from origin. The line needs the direction vector and two distances from the origin, both perpendicular to the direction vector. So, the line is more complex than the plane. Surprise.

  

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

RPTHOMAS108
Mentor
Mentor

Thanks Jeremy. I have seen similar plane/plane intersection also code in the past but that one on StackOverflow seems the most straightforward.

 

As I read the thread I think the main issue in most recent post was regarding finding the bounds of the intersections between two faces rather than an unbound line between two infinite planes. I think the library that Dynamo uses behaves slightly differently in that respect (compared to Face.Intersect). Dynamo was the first narrow image in @bixilix last post where the red dashed line stops and starts at the extents of the slab whilst the second narrow image shows a red dashed line through the entire width of the image.

 

Regardless I think @bixilix will have larger issues when it comes to shaped slabs or even those with a slope perpendicular to the view direction.

 

However more broadly speaking there are often threads about how the boolean operations between solids are more forgiving in Dynamo regarding small dimensional imperfections (I don't know that to be true but a couple of threads have pointed to it). So that was my general motivation for understanding how to use this external geometry library that is part of Dynamo.

 

0 Likes