Wall Solid Intersection with Revit API

Hi All,

I’m trying to check if walls are intersecting by checking the volume of the intersecting solids

I was trying to use this method:

I only get the right result if I intersect each wall with itself. What am I doing wrong? is there another way?

this is the code:

import clr
# Import RevitAPI
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

# Import DocumentManager and TransactionManager

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

from System.Collections.Generic import *

import itertools

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

elements=[UnwrapElement(i) for i in IN[0]]

opt = Options()

Geom=[i.get_Geometry(opt) for i in elements]


Solids = list(itertools.chain(*Geom))

OUT=(BooleanOperationsUtils.ExecuteBooleanOperation(Solids[IN[1]], Solids[IN[2]], BooleanOperationsType.Intersect).Volume)*0.0283168

I suspect because the wall join mechanics in Revit results in segmented wall elements which subsequently never intersect:

Thanks Thomas. Any suggestions?

I can definitely check if the location lines are intersecting but I was wondering if there is another way.

Your options are limited it seems. You could extract the curves from the walls then perform an intersection using the Geometry.Intersect method from the ProtoGeometry library, although to implement this completely will result in a heavy process that will very quickly become inefficient and probably fail on big projects with lots of walls.

One idea that you might find a bit more efficient, but unfortunately seems to be buggy as hell (if you test this you’ll notice the apparent intersection yeilds inconsistent results), is the RevitAPI ReferenceIntersector filter class. In the example below, swap out the model curve with the wall location curve and only evaluate wall elements other than the one being tested (get pop()ing) to prevent duplicate results:

#Copyright 2017. All rights reserved. Bimorph Consultancy LTD, 5 St Johns Lane, London EC1M 4BH www.bimorph.co.uk
#Written by Thomas Mahon @Thomas__Mahon info@bimorph.co.uk Package: bimorphNodes
#GitHub: https://github.com/ThomasMahon/bimorphNodes/
#Follow: facebook.com/bimorphBIM | linkedin.com/company/bimorph-bim | @bimorphBIM

import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
from System.Collections.Generic import *

clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

doc = DocumentManager.Instance.CurrentDBDocument

view3d = UnwrapElement(IN[0])
modelLine = UnwrapElement(IN[1])
elements = UnwrapElement(IN[2])

TransactionManager.Instance.EnsureInTransaction(doc)

crv = modelLine.GeometryCurve 
targetElementIds = List[ElementId]([e.Id for e in elements])
refIntersect = ReferenceIntersector(targetElementIds, Autodesk.Revit.DB.FindReferenceTarget.Element, view3d)

intersectResult = refIntersect.Find(crv.GetEndPoint(0), crv.GetEndPoint(1))

out  = []
for i in intersectResult:
	ref = i.GetReference()
	represent = ref.ConvertToStableRepresentation(doc)
	e = doc.GetElement(represent)
	out.append(e)
	
TransactionManager.Instance.TransactionTaskDone()
OUT = out

Hi Thomas,

Thank you for your reply. As you said it’s a bit buggy it doesn’t detect all intersections and it depends on drawing a model line.

I was looking more for an automatic method which groups all intersecting walls,similar to the post below post but just using the Revit API.

Are you aware of any methods to manipulate the solid (from revit wall) to fill the gap:

It could be rebuilt without the gap in dynamo with a variety of methods, but all of the light ones will fail under one circumstance or another (how was the wall built? Is the profile edited? Is the height inconsistent? etc…)

Might be simpler to unjoin the elements, build the geometry, and rejoin the elements. That said, how big is your dataset? Joining and unjoining isn’t a fast operation on large sets, and wall joins are inconsistent at best.

Better to keep it simple and avoid that mess too.

Try to use the element.location node to query the line for each wall, then build a solid geometry from that - offset them by a small number (say 0.01), start point and end point, some list management, polycuvre through points and then extrude. You can then run the Python test you had before but with a simplified geometry that mimics the wall geometry you had before.

The only issue I see with that is multi story walls - that element location node will place the line (and therefore your extrusion) at the level the wall is hosted to, so set the z values for all of them to a consistent point. Assuming you are doing this one level at a time, you can either use the level you are testing or the origin plane. If you are attempting all walls in a job at once then the list management gets dicey. Try the sample set first and lists setup can be reviewed from there.

Hi @jacob.small,

Thank you for your reply. Please see below.

I’d like to re-build the wall using just Revit API methods only (Python). I will try to solve the general case first and the look at what could make the workflow fail later. What Revit API methods would you use to re-build the solids?

I think I’ll try that as last resort.

I tried that. I can get the wall location lines, create lines and intersect them (just using Revit API). That works. But my goal is to sort them by finding out the intersecting volume.

In which case offset twice - once by Wall Thickness * 0.5 and once by Wall thickness * -0.5.
Build the polycurve and extrude by the wall height. Then intersect your geometries and go from there. Only issue will be if your walls have profile edits or shapes.

Out of curiosity, what is the need for the intersecting volumes?

None that I’m aware of. You could un-join, but it will be destructive, even if you perform the action in a sub-transaction and rollback to avoid the myriad of problems that can (will?) arise when attempting to re-join, I can still see this process failing. There’s also another issue with accessing the wall joins via the LocationCurve class: it only provides access to the ends of the curve meaning any junctions in-between the walls location curve cant be accessed!

If you need the volumes for the intersections, then it would be easiest to calculate this mathematically in my view. If the method of using the location curve intersections tells you which walls are intersecting, get both walls height and width, you could then calculate the total area of the intersection using trigonometry, then yield the intersecting volume from this information. Sounds complicated, and it is, however the alternatives are beset by pitfalls that would hinder the solution.

I’ve not tested the above so even that has no guarantee of working, however there is one other option you could try:

  1. Extract the location curve of the target wall, including its width and height
  2. Use this data to create a new solid
  3. Get the bounding box of the solid and use the BoundingBoxIntersectsFilter to select any surrounding wall elements. This is a quick filter which will reduce the number of brute-force intersections on the solid object that will need to be performed
  4. Extract the location curves of any walls selected from the quick filter
  5. Use the SolidCurveIntersection filter to test which location curve intersect the solid. This will also solve any problems caused by multi-storey target walls intersecting smaller walls on single floors
  6. Calculate the intersection volumes using your preferred method (i.e. new solid or mathematics)
1 Like

A better way to search for intersections between Revit elements is provided by the ReferenceIntersector class:

http://www.revitapidocs.com/2017/36f82b40-1065-2305-e260-18fc618e756f.htm

Here is a deeper explanation of this class:

To find intersecting walls, you could shoot a ray along the given wall’s location line, maybe raised above floor level by a foot or so, and ask it for intersections with other wall elements.

Here is a full-fledged example using the ReferenceIntersector to determine a point on a neighbouring, parallel wall to create dimensioning:

It uses the ReferenceIntersector class to determine points and geometry references to create dimensioning between the walls.

At that time, the method was called FindReferencesByDirection. It was later wrapped in the ReferenceIntersector class. The external command CmdDimensionWallsFindRefs demonstrating its use has been updated to use the new class and is available in The Building Coder samples on GitHub:

I hope this helps.

Cheers,

Jeremy

4 Likes

Hi @Jeremy_Tammik this is a sound approach and was my suggested solution in the early part of this thread, however I noticed it output inconsistent results and seemed buggy which lead to the more cumbersome ‘solid intersection’ approach. Are there limitations with the ReferenceIntersector class? For example, if walls are very obtuse to the ray, they seemed to be ignored. Only walls (or any other element) that were perpendicular or slightly rotated were picked up?

@salvatoredragotta also observed this when he used this class.

Have you observed these problems?

Thank for your reply. I’ll try the second option :grin:

No, never. If you run into such a situation, please produce a simple, minimal, reproducible case for it and submit it to the development team for analysis.

1 Like