Intersect PlanarFace with Solid (Python)

Hello Dynamo Friends,

I want to intersect a Wall Face (got that as PlanarFace) and a Solid with the DoesIntersect method.
But this method doesn´t work with the planarface. Can I convert that to a face/surface somehow?
Tried to GetSurface but that gives me a Plane :smiley:

z= x.DoesIntersect(y)

Thankful for any advice!

You’ll need to convert the Revit face to a DesignScript (Dynamo) surface first, which you should be able to do with the ToProtoType() method. Something along the lines of this:

dynamoFace = x.ToProtoType()
dynamoSolid = y.ToProtoType()
z = dynamoFace.DoesIntersect(DynamoSolid)

Note that it’s likely there is a better way to do what you’re after by staying in the Revit API enitrely, but we don’t have enough context to help just yet.

2 Likes

Hello Jacob :slight_smile:
Yes i would like to avoid the dynamo geometry, so how about that:

I can use the Face.Intersect(Face) method by breaking the solid down.

Good solution or will this be much slower then intersecting with a solid?

I just want to know if this specific wall face is intersecting with a solid (floor.)

This method does not work, it alway gives intersections where are none :confused:

The Building Coder: Face Intersect Face is Unbounded (typepad.com)

w = UnwrapElement(IN[0])
f = UnwrapElement(IN[1])
outlist=[]

for f in face:
	z= w.Intersect(f)
	outlist.append(z)

OUT = outlist

What are you getting the PlanarFaces and solids from? What is the larger workflow?

I found a method and now have wonderful 5mm solids from the faces :smiley:

lines = UnwrapElement(IN[0])
normal = UnwrapElement(IN[1])

loop = CurveLoop.Create(lines)

z= GeometryCreationUtilities.CreateExtrusionGeometry(List[CurveLoop]([loop]),normal,0.005)

OUT = z

Now i just have to find out if i can also get the area/volume of inbtersection when workin with Revit.DB.

Purpose is still that one:

Getting Faces and Solids gives errors for Walls and Floors - Dynamo (dynamobim.com)

Want to try to go the full Revit.DB route.

Aaaaand this method is not reliable :grimacing:

lineslist = UnwrapElement(IN[0])
normalslist = UnwrapElement(IN[1])

for lines, normals in zip(lineslist,normalslist):
	for line, normal in zip(lines, normals):
		loop = CurveLoop.Create(line)

		z= GeometryCreationUtilities.CreateExtrusionGeometry(List[CurveLoop]([loop]),normal,0.005)

OUT = z

Next idea is to use UV method to get min and max points and build a whole face on my own.
But I have no luck again, here is what i get for UV 0,0 and UV 1,1:

w = UnwrapElement(IN[0])
uv=UV(0,0)
x=w.Evaluate(uv)

OUT = x

Maybe time now to give up that Revit geometry thing…

So a different approach:

Using solids for intersection and then getting the right wall face by checking which wall face is the nearest to the floor:

for floor, wall in zip(floors,walls):
	outlist=[]
	for w in wall:
			x=BooleanOperationsUtils.ExecuteBooleanOperation(floor, w, BooleanOperationsType.Intersect).Volume
			outlist.append(x)
	outlist2.append(outlist)

	
OUT = outlist2
for walls,floor in zip(wallslist,floors):
	outlist2=[]
	for wall in walls:
		outlist=[]
		for w in wall:
			x= w.Project(floor).Distance
			outlist.append(x)
		outlist2.append(outlist)
	outlist3.append(outlist2)
OUT = outlist3

SO you’re gathering a bunch of floors, and a bunch of walls, and testing to see which floors intersect which walls?

Why not use an element.intersects filter instead?

Hello Jacob, thats in fact the method I´m starting with, but there is so much else to do :smiley:
At this moment i got nearly everything working with Revit.DB, had a hard time and would be very interrested in your thoughts about my methods. Questionable workarounds with question marks.

  • Get floor solid with f.get_Geometry(opt)
  • Scale Floor Solid with SolidUtils.CreateTransformed(scaledSolid, transform)
  • Get Walls with ElementIntersectsSolidFilter(s)
  • Get wall solid with w.get_Geometry(opt)
  • Intersect with BooleanOperationsUtils.ExecuteBooleanOperation(floor, w, * BooleanOperationsType.Intersect).Volume to drop walls that are intersecting too little
  • Get floor centroid with s.ComputeCentroid()
  • Get 2 largest wall faces by s.Faces and sort by area
  • Get nearest wall face for every wall by w.Project(floor).Distance
  • Get vertical floor faces with s.FaceNormal.Z ==0
  • Filter floor faces by edges that have length=floor hight

Now it gets interresting at finding the wall face for every floor face.

  • Get all Face normal vectors by x=f.FaceNormal
  • Match parallel wall and floor faces
  • Get floor faces center by x=face.GetEdgesAsCurveLoops(), y=z.GetPlane(), center= y.Origin ???
  • Pull floor face centerpoints on wall faces by wall.Project(point).Distance and use distance to match a floor face to every wall face
  • Get lines from floor faces by w.GetEdgesAsCurveLoops() and y=u.ToProtoType()
  • Switch to Dynamo geometry, lines to Polycurve, surface by patch, use U/V parameter 0/0.5 and 1/0.5 to get centerline on floor face.??? , thats where the family will be placed
  • Back to Revit Geometry, pull start/endpoint of line on wall face by w.Project(p).XYZPoint
  • finally place family by doc.Create.NewFamilyInstance(f,p,v,family)

There is for sure potential to make some things better, for example, can i get the distance between 2 faces?

After testing on about 30 floors/90 walls, it works great!

There is only one single method failing from time to time, in about 3% of my tests.

It is getting the distance from floor centroid to the wall faces to check which face is the nearest one:

so i have to find another way for that.

But if it works, pretty much fun :smiley:

[video-to-gif output image]

1 Like

This seems pretty close to spot on. it may be that the 3% of conditions returning an error could be resolved by modifying the call methods, but it’d require you post the full python to confirm.

1 Like

Hey Jacob, thanks for your reply,

As this Project method fails 3 times in the graph, i looked for another method and found this:

The Building Coder: Planes, Projections and Picking Points (typepad.com)

So I´m now using the Signed distance and the dotproduct, it works now for all the walls that didnt work befor, but now the others don´t work anymore :smiley: Hope to find the mistake tomorrow. And then i also will post the code you mentioned, maybe you will find out why my project method fails.

current status:

	for w,p in zip(wall,point):
		a = w.GetEdgesAsCurveLoops()
		for i in a:
			k=i.GetPlane()
			v=p-k.Origin
			x=k.Normal.DotProduct(v)
			o=p-x*k.Normal
			p=o.ToPoint()

EDIT: Here is the failing project method code:

wallslist = UnwrapElement(IN[0])
floors = UnwrapElement(IN[1])
outlist3=[]
for walls,floor in zip(wallslist,floors):
	outlist2=[]
	for wall in walls:
		outlist=[]
		for w in wall:
			x= w.Project(floor)#.Distance
			outlist.append(x)
		outlist2.append(outlist)
	outlist3.append(outlist2)
OUT = outlist3

1 Like

I had just some mistake with my variables, the graph works now on 100% of the floors i tested :smiley:

faces = UnwrapElement(IN[0])
points = UnwrapElement(IN[1])
outlist2=[]
for face, point in zip(faces, points):
	outlist=[]
	for f,p in zip(face,point):
		loops = f.GetEdgesAsCurveLoops()
		for loop in loops:
			plane = loop.GetPlane()
			diff = p-plane.Origin
			normal = plane.Normal
			skalar = normal.DotProduct(diff)
			pointOnPlane=p-skalar*normal
			dynPoint=pointOnPlane.ToPoint()
		outlist.append(dynPoint)
	outlist2.append(outlist)

OUT = outlist2

Still interrested in finding out why the Project-Method doesn´t work, going to isolate a failing element…

1 Like

Haha, any idea why this point cant be projected on this wall face? :smiley:

So this planar faces are so strange, they always behave as they would have no boundaries, as if they were planes. So they can not be used for face intersection etc…

BUT if you want them to behave one single time like a plane, they don´t and won´t let you project if there is a hole.

So the method with the curveloops/plane seems to be the better option for my purposes.

Not sure why it won’t project in this case; the profile shape being convex in two spots might be causing an issue, but it’d take awhile to confirm.

It is definitely the cutout, i now remember that i had the exact same problem with the dynamo geometry version, thats why I also there used pull onto plane instead of pull onto face.