Auto-Dimension from Walls

Hi All,

Just a WIP incase anyone has a free Sunday and fancies a play with it! Otherwise I’ll get back on it on Monday…

Following the amazing work here:


I want a graph which will create individual dimensions (so I can check them against brick dimensions) and automatically create the dimension location lines.

So far I’ve got here… It’s nearly there, but rather than create a dim per ‘reference’ it’s creating a dim per line… It’s also doing something weird with the view… The created dims are in Revit but not appearing until I change their type.

Any assistance appreciated!

Cheers,

Mark

auto dim walls-14.dyn (38.9 KB)

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

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)

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

doc = DocumentManager.Instance.CurrentDBDocument

#create a for loop to go through every index
b = IN[0]
elements = IN[1]
dim = 0
a = []

for x in range (0, len(b)):

	line = UnwrapElement(b[x]).GeometryCurve
	elementsRef = ReferenceArray()
	opt = Options()
	opt.ComputeReferences = True
	opt.IncludeNonVisibleObjects = True
	opt.View = doc.ActiveView
	for element in elements:
		elementsRef.Append(element)
	TransactionManager.Instance.EnsureInTransaction(doc)

	dim = doc.Create.NewDimension(doc.ActiveView, line, elementsRef).ToDSType(True)

	TransactionManager.Instance.TransactionTaskDone()
	d = dim
	a.extend ([d])

	OUT = a

Minor update, the springs.list.subpairs node is awesome!

So this is where I’m leaving it for the moment… putting the python in a custom node let me work at level 2, so if I Pick a wall I get all the dimensions along it offset automatically.

If I get more time I’ll keep working on it…

Any assistance welcome!

Mark

DimWallsAuto-Chop.dyn (46.8 KB)
Dim.FromReference.dyf (5.1 KB)

2 Likes

Just an update, I’ve got it working for multiple walls in active view and removed the need for a custom node by updating my python.

Thanks to all who’s work I have built upon,

Mark

It struggles with angled corners as you’d need a reference ‘point’ rather than plane, any suggestions welcome :slight_smile:
EDIT: It’s also using the angle of the wall to work out which should be dim’d, so I’d need to get only the wall faces which are vertical and not aligned to the location line, then pick the point closest to the location line which intersected the external face… simples… Getting the ‘point’ might be the easy bit!

DimWallsAuto-All.dyn (64.7 KB)

4 Likes

It is just an Idea that I haven’t tested. Can’t you take start and end of the wall as references?

Hi :slight_smile:

Thanks for the response!

So… My dimension wouldn’t want to be from the End Point of the location line… Otherwise it would be too short…
image
Unfortunately the relationship between references and geometry seems very easily broken, I would need an actual point on the wall corner somehow…

I could make a dimension to a reference plane, but it wouldn’t be dynamic, or I could extract a corner point from the geometry of the wall, but it then loses it’s association.

Thanks again,

Mark

What packages are needed to make this work?

Hi,
Maybe it’s much easier to be done in Python itself.
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI.Selection import ObjectType

def isParallel(v1, v2):
#it needs two vector
return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0, 0, 0))

ref = uidoc.Selection.PickObject(ObjectType.Element)
wall = doc.GetElement(ref)
ln = wall.Location.Curve

wallRefArray = ReferenceArray()

opts = Options()
opts.ComputeReferences = True
opts.IncludeNonVisibleObjects = True
opts.View = doc.ActiveView

for obj in wall.get_Geometry(opts):
if isinstance(obj, Solid):
for face in obj.Faces:
if isParallel(face.FaceNormal, ln.GetEndPoint(1) - ln.GetEndPoint(0)):
wallRefArray.Append(face.Reference)

t = Transaction(doc)
t.Start(“Create Dimensioning”)
doc.Create.NewDimension(doc.ActiveView, ln, wallRefArray)
t.Commit()
the above code works in PRS, however with minor changes can run in Dynamo

1 Like

Hi @Dave_Vaughn just the usual I think… Clockwork? Since this was done, Genius Loci has added quite a view nodes for references…

Hi @Sam_Dehghani, thanks for your code, it’s very interesting :slight_smile:

Here’s my version to run in Dynamo… You need to add more libraries & I would recommend using the transaction manager. I had updated mine in the first post to give the working version. If you use the </> button when you paste it will be formatted.

import clr

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

# Import Element wrapper extension methods
clr.AddReference("RevitNodes")
import Revit
from Autodesk.Revit.DB import *

clr.AddReference("RevitAPIUI")
from Autodesk.Revit.UI.Selection import ObjectType

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

def isParallel(v1, v2):
    #it needs two vector
    return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0, 0, 0))
    
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
ref = uidoc.Selection.PickObject(ObjectType.Element)
wall = doc.GetElement(ref)
ln = wall.Location.Curve

wallRefArray = ReferenceArray()

opts = Options()
opts.ComputeReferences = True
opts.IncludeNonVisibleObjects = True
opts.View = doc.ActiveView

for obj in wall.get_Geometry(opts):
    if isinstance(obj, Solid):
        for face in obj.Faces:
            if isParallel(face.FaceNormal, ln.GetEndPoint(1) - ln.GetEndPoint(0)):
                wallRefArray.Append(face.Reference)

TransactionManager.Instance.EnsureInTransaction(doc)

OUT = doc.Create.NewDimension(doc.ActiveView, ln, wallRefArray)

TransactionManager.Instance.TransactionTaskDone()

My graph is doing quite a few more things than your code, when all that’s in, your code will be a bit more complex.

It would also be great to find a solution to the walls which are not perpendicular :slight_smile:

It requires isolating edges of the External face which are vertical, then finding those which intersect surfaces which are not perpendicular or aligned to the external face… My python isn’t that good yet :slight_smile:

I updated my graph to run off the external face, otherwise, as you see on the below image, you don’t dimension the intersecting walls.

image
Cheers,

Mark

2 Likes

Hi Mark,
I’m glad that the Python code helped. It’s not that difficult to prepare a code to make dimension between interior walls, however combining the exterior and interior is a bit complex

Hey, it’s not too bad if you isolate the exterior face (the surface with the same vector as the wall.Orientation) then you can run intersection checks against it and the surfaces which are perpendicular to it… At least if you’re just getting 1 dimension, you’re not bothered what order the references are in :slight_smile: It’s a bit more fiddly if you want to pair them up and make individual dimensions, though quite doable.

1 Like

So, some success… I’ve tried running it off Edge references rather than Face references, it occured to me that the ‘Point’ you get in Revit is actually a vertical edge…

It works at least, though you have to make sure your wall joins are mitred.

Also, on the other side, Revit thinks of the external ‘edge’ as stopping before the joint of the wall… So I need to get the adjacent wall face as well.

Also I need to find a way to prune duplicate references from my list.

i mport clr

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

# Import Element wrapper extension methods
clr.AddReference("RevitNodes")
import Revit
from Autodesk.Revit.DB import *

clr.AddReference("RevitAPIUI")
from Autodesk.Revit.UI.Selection import ObjectType

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

def isParallel(v1, v2):
    #it needs two vector
    return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0, 0, 0))

def isAlmostEqualTo(v1, v2):
    return v1.IsAlmostEqualTo(v2)
    
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
ref = uidoc.Selection.PickObject(ObjectType.Element)
wall = doc.GetElement(ref)
ln = wall.Location.Curve

opts = Options()
opts.ComputeReferences = True
opts.IncludeNonVisibleObjects = True
opts.View = doc.ActiveView

frontFaceEdges = []
edgesObj = []
for obj in wall.get_Geometry(opts):
    if isinstance(obj, Solid):
        for face in obj.Faces:
             #if face is normal is equal to wall normal it is the external face
            if isAlmostEqualTo(wall.Orientation, face.ComputeNormal(UV(0.5,0.5))):
                frontFace = face                
                for edgeL in face.EdgeLoops:
                    frontFaceEdges.append(edgeL)
        #we want edges which intersect the external face
        for edgeO in obj.Edges:
            if frontFace.Intersect(edgeO.AsCurve()):
                edgesObj.append(edgeO)

vertEdges = ReferenceArray()
#get edges in faceEdges which are vertical up
for edgeF in edgesObj:
    #if edge is up, get it
    if edgeF.AsCurve().Direction.Normalize().IsAlmostEqualTo(XYZ(0,0,1)):
        vertEdges.Append(edgeF.Reference)

#vertFaceEdges = ReferenceArray()
#get edges in front faces which are vertical up 
#there are multiple loops if we have hosted objects, we want the first
for edgeFFE in frontFaceEdges[0]:
    #if edge is down, get it
    if edgeFFE.AsCurve().Direction.Normalize().IsAlmostEqualTo(XYZ(0,0,-1)):
        vertEdges.Append(edgeFFE.Reference)
             

TransactionManager.Instance.EnsureInTransaction(doc)

OUT = doc.Create.NewDimension(doc.ActiveView, ln, vertEdges)

TransactionManager.Instance.TransactionTaskDone()

Hope that’s of interest, any comments welcome :slight_smile:

Mark

Hi Mark,
The following code may somehow do what you asked for.
Please give me a shout out if it was the one.

#@Suncobim.ir, Email:info@suncobim.ir
#Author: Sam Dehghani

from Autodesk.Revit.DB import *
from Autodesk.Revit.UI.Selection import ObjectType

def isParallel(v1, v2):
return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0, 0, 0))
def isPerpendicular(v1, v2):
if v1.DotProduct(v2)== 0:
return True
else:
return False

intersectedWalls =
wallRefArray = ReferenceArray()

ref = uidoc.Selection.PickObject(ObjectType.Element, “Select a Wall”)
wall = doc.GetElement(ref)
ln = wall.Location.Curve

ref = uidoc.Selection.PickObject(ObjectType.Element)
dimLn = doc.GetElement(ref).GeometryCurve

collectedWalls = FilteredElementCollector(doc, doc.ActiveView.Id).OfClass(Wall).ToElements()
for collectedWall in collectedWalls:
if dimLn.Intersect(collectedWall.Location.Curve) == SetComparisonResult.Overlap
and isParallel(dimLn.Direction, collectedWall.Orientation):
intersectedWalls.append(collectedWall)

opts = Options()
opts.ComputeReferences = True
opts.IncludeNonVisibleObjects = True

for obj in wall.get_Geometry(opts):
if isinstance(obj, Solid):
for face in obj.Faces:
if isParallel(face.FaceNormal, ln.GetEndPoint(1) - ln.GetEndPoint(0)):
wallRefArray.Append(face.Reference)

for intersectedWall in intersectedWalls:
wallRefArray.Append((HostObjectUtils.GetSideFaces(intersectedWall, ShellLayerType.Exterior))[0])
wallRefArray.Append((HostObjectUtils.GetSideFaces(intersectedWall, ShellLayerType.Interior))[0])

t = Transaction(doc)
t.Start(“Dimension”)
doc.Create.NewDimension(doc.ActiveView, dimLn, wallRefArray)
t.Commit()

1 Like

Very cute, I didn’t know about the HostObjectUtils :slight_smile:
Here’s my version, still needs some tidying…

import clr

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

# Import Element wrapper extension methods
clr.AddReference("RevitNodes")
import Revit
from Autodesk.Revit.DB import *

# Import ToProtoType, ToRevitType geometry conversion extension methods
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitAPIUI")
from Autodesk.Revit.UI.Selection import ObjectType

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript import Geometry as geom

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

def isParallel(v1, v2):
    #it needs two vector
    return v1.CrossProduct(v2).IsAlmostEqualTo(XYZ(0, 0, 0))

def isAlmostEqualTo(v1, v2):
    return v1.IsAlmostEqualTo(v2)

def isPerpendicular(v1, v2):
    if v1.DotProduct(v2)== 0:
        return True
    else:
        return False
    
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
ref = uidoc.Selection.PickObject(ObjectType.Element, 'Select A Wall')
wall = doc.GetElement(ref)
ln = wall.Location.Curve
wallCrv = ln.ToProtoType()
wallNormalExterior = wall.Orientation.ToVector()

offDist = IN[0]
offCrv = geom.Line.Translate(wallCrv, wallNormalExterior, offDist)

intersectedWalls = []
collectedWalls = FilteredElementCollector(doc, doc.ActiveView.Id).OfClass(Wall).ToElements()
for collectedWall in collectedWalls:
    if ln.Intersect(collectedWall.Location.Curve) == SetComparisonResult.Overlap and isParallel(ln.Direction, collectedWall.Orientation):
        intersectedWalls.append(collectedWall)

opts = Options()
opts.ComputeReferences = True
opts.IncludeNonVisibleObjects = True
opts.View = doc.ActiveView

frontFaceEdges = []
edgesObj = []
for obj in wall.get_Geometry(opts):
    if isinstance(obj, Solid):
        for face in obj.Faces:
             #if face is normal is equal to wall normal it is the external face
            if isAlmostEqualTo(wall.Orientation, face.ComputeNormal(UV(0.5,0.5))):
                frontFace = face                
                for edgeL in face.EdgeLoops:
                    frontFaceEdges.append(edgeL)
        #we want edges which intersect the external face
        for edgeO in obj.Edges:
            if frontFace.Intersect(edgeO.AsCurve()):
                edgesObj.append(edgeO)

vertEdges = ReferenceArray()
#get edges in faceEdges which are vertical up
for edgeF in edgesObj:
    #if edge is down, get it
    if edgeF.AsCurve().Direction.Normalize().IsAlmostEqualTo(XYZ(0,0,1)):
        vertEdges.Append(edgeF.Reference)
        
#get edges in front faces which are vertical up 
#there are multiple loops if we have hosted objects, we want the first
for edgeFFE in frontFaceEdges[0]:
    #if edge is up, get it
    if edgeFFE.AsCurve().Direction.Normalize().IsAlmostEqualTo(XYZ(0,0,-1)):
        vertEdges.Append(edgeFFE.Reference)

for intersectedWall in intersectedWalls:
    #get external side faces of intersecting walls
    vertEdges.Append((HostObjectUtils.GetSideFaces(intersectedWall, ShellLayerType.Exterior))[0])
    #thanks Sam!
    #get internal side faces of intersecting walls
#    vertEdges.Append((HostObjectUtils.GetSideFaces(intersectedWall, ShellLayerType.Interior))[0])

TransactionManager.Instance.EnsureInTransaction(doc)

OUT = doc.Create.NewDimension(doc.ActiveView, offCrv.ToRevitType(), vertEdges)

TransactionManager.Instance.TransactionTaskDone()
2 Likes

HostObjectUtils helps a lot

1 Like

I downloaded the Clockwork package, but I still get the error: Custom node definition is not loaded!
I installed the latest clockwork that matches my dynamo, or should I have an earlier version?

Hey,

Maybe, which node/s? there is a depreciated page on Andreas’ github?

These are the nodes I get the error on:

  • Get Revit ActiveView
  • Elements in view by category
  • Wall.GetWallType
  • WallLocationLine.FinishFaceExterior
  • Surface.FilterByOrientation-Clockwork
  • Wall.ByFace
  • DanEDU.List.Clean
  • Element.Delete

I’m using dynamo 2.0.3 and I’m using the clockwork 2.x

I installed all older versions for Clockwork, now I only get the error for:

  • Get Revit ActiveView
  • Elements in view by category
  • Wall.GetWallType
  • Surface.FilterByOrientation-Clockwork
  • DanEDU.List.Clean
  • Element.Delete
    (2 lesser then previously)

Hey,

So maybe try just typing in the name and seeing if it’s an update issue? I think Wall.ByFace is a Revit one…

DanEDU was replaced by Orchid, if you have that package? I think Element delete might be in there? But there are equivalents in Archilab and others…