Create rebar shape from wall face

Hi All, @c.poupin

In the code below, I am trying to create a ‘U’ shape (as a model line for now) from a selected wall face, which I intend to use later for creating shape-driven rebar using the CreateFromCurves method. Is there a better approach or code logic for this, or can you suggest an alternative?

rebar Shape U
import clr
import sys
import System
import math

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#import specify namespace
from Autodesk.Revit.DB.Structure import *


#import net library
from System import Array
from System.Collections.Generic import List, IList, Dictionary

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

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

# select all walls within the project
Walls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElementType().ToElements()

# get walls faces 
Faces = []
for w in Walls:
    face_Ref = list(HostObjectUtils.GetSideFaces(w, ShellLayerType.Interior))[0]
    wall_face = w.GetGeometryObjectFromReference(face_Ref)
    Faces.append(wall_face)
    
# choose one face end get its edges serving as the base of creating the searched rebar shape

face = Faces[0]

boundary = face.EdgeLoops[0]

edges = []

for edge in boundary:
    edges.append(edge.AsCurve())

# iterate over the edges list and choose the first vertical edge as a begening curve for the rebar shape
for idx, edge in enumerate(edges):
    if idx == 3:
        edges = edges[idx:] + edges[:idx]

# obtaining the searched rebar shape " U "
edges = edges[:-1]

curves = []

#Creating a temporary 2D plane to visualize the rebar shape

Points = [i.GetEndPoint(0) for i in edges]

plan = Plane.CreateByThreePoints(Points[0], Points[1], Points[2])

# get the Normal of the plane for calculation purposes
Ref_vect = plan.Normal.Normalize()

# Differentiate the horizontal curve from the two vertical ones for calculation purposes.
horiz_vect = [e.Direction for e in edges if e.GetEndPoint(0).Z == e.GetEndPoint(1).Z][0]

# Create a transformation function to obtain the final rebar shape from the offset face edges  
def trans(vector, cover):
    t = Transform.CreateTranslation(vector.Normalize().Multiply(cover))
    return(t)

curves = []

# offset distance c1 for the vertical edge 
c1 = 0.1/0.3048

# offset distance c2 for the horizontal edge 
c2 = 0.1/0.3048

# create the final rebar shape " U " 
for e in edges:
    st_pt = e.GetEndPoint(0)
    End_pt = e.GetEndPoint(1)
    direct = e.Direction
    vect = direct.CrossProduct(Ref_vect)
    # select the horizontal edge and offset it with the desired parameters
    if direct.IsAlmostEqualTo(horiz_vect):
        e = e.CreateTransformed(trans(vect, c2))
        param1 = c1/e.Length
        param2 = 1 - param1
        st_pt = e.Evaluate(param1, True)
        End_pt = e.Evaluate(param2, True)
        e = Line.CreateBound(st_pt, End_pt)
        curves.append(e)
    # select the vertical edges and offset them with the desired parameters    
    else:
        # check if the two vertical edge have the same orientation 
        if direct.IsAlmostEqualTo(XYZ.BasisZ) :
            if vect.IsAlmostEqualTo(horiz_vect):
                vect = vect.Negate()
                e = e.CreateTransformed(trans(vect, c1))
                # new start point for the offseted curve
                p = XYZ(e.GetEndPoint(0).X, e.GetEndPoint(0).Y, e.GetEndPoint(0).Z - c2)
                e = Line.CreateBound(p, e.GetEndPoint(1)) 
                curves.append(e)
        else: 
            e= Line.CreateBound(End_pt, st_pt)
            vect = vect.Negate()
            e = e.CreateTransformed(trans(vect, c1))
            # new start point for the offseted curve
            p = XYZ(e.GetEndPoint(0).X, e.GetEndPoint(0).Y, e.GetEndPoint(0).Z - c2)
            e = Line.CreateBound(p, e.GetEndPoint(1)) 
            curves.append(e)
            
# create a sketch plan to temporary visualize the rebar shape         
with Transaction(doc, 'create Sketch plan') as t:
    t.Start()
    skp = SketchPlane.Create(doc, plan)
    t.Commit()
print(skp)

# create a tomporary model lines to visualize the rebar shape
Lines = []
with Transaction(doc, 'create Model Lines') as t:
    t.Start()
    for l in curves:
        Ml = doc.Create.NewModelCurve(l, skp)
        Lines.append(Ml)
    t.Commit()
    
OUT = Lines

Please check the Revit Model below

regard.rvt (5.2 MB)

Thanks for All.

@REDO10

i found this old topic here

3 Likes

You could simplify the code by using the available methods in the API

Using the CurveLoop class can save a lot of fiddling - edges and new_edges are both curve loops. Using CreateViaOffset and CreateTranslation methods do all the geometry work for you.

# Your code up to face = Faces[0]

units = doc.GetUnits().GetFormatOptions(SpecTypeId.Length).GetUnitTypeId()
cover = UnitUtils.ConvertToInternalUnits(0.1, units)

edges = face.GetEdgesAsCurveLoops()
plane = edges.GetPlane()

new_edges = edges.CreateViaOffset([cover, cover, cover, cover], plane.Normal.Negate())

trans = Transform.CreateTranslation(plane.Normal.Negate().Multiply(cover))
new_edges.Transform(trans)

# Inside Transaction
sketch_plane = SketchPlane.Create(doc, new_edges.GetPlane())

# Remove unwanted lines from new_edges

curves = [doc.Create.NewModelCurve(e, sketch_plane) for e in new_edges]

# Close Transaction
OUT = curves
1 Like

@Mike.Buttery

As usual, your solutions are helpful and concise

I tried your code, and it works perfectly.

Is there another correct way, besides the one I used in my code, to remove the top curve and obtain the desired ‘U’ shape relative to the selected wall?

Thanks.

@c.poupin

Have you any idea how to solve this?

Thanks.

Please note the spirit of this forum is for people to try, or at least think something through before asking

Your code ‘rolls’ the lines in the CurveLoop to the last Curve (index 3) - this may be true for a rectangular wall, and if that is the intent of you code then that may work - but it is not guaranteed, then you remove the last item - the Curve originally at index 2.

So it is not the way I would remove the top horizontal line to create the U shape because I have not checked if it is the top horizontal.

Checking if a line is horizontal is straight forward - the dot product with the Z axis will be zero i.e. perpendicular. Python evaluates 0 as False

def is_horizontal(line):
    return not XYZ.BasisZ.DotProduct(line.Direction)

I think one of the ways to efficiently find the highest line element is to evaluate the Z coordinate of the mid point which is an average of the two end points. We can also use python list methods to remove it and the key argument of the max() function with a lambda function

curves = list(curve_loop)
curves.remove(max(curves, key=lambda line: line.Evaluate(0.5, True).Z))  # In place
OUT = curves
2 Likes

@Mike.Buttery

I completely agree with you, and I regret not having tried something new. My problem is that I don’t have enough time to dedicate to development due to my work, and I haven’t documented myself enough on the Revit API, where everything is well explained. Sometimes, I tend to complicate things instead of simplifying them, as you are doing so well.

I tried your approach to remove the top line by evaluating the Z coordinate in each line, tested the code for each wall, and it worked perfectly, which definitively solved my issue.

Here the final code:

import Autodesk.Revit.DB as DB
#import specify namespace
from Autodesk.Revit.DB.Structure import *


#import net library
from System import Array
from System.Collections.Generic import List, IList, Dictionary

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

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

# select all walls within the project
Walls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).WhereElementIsNotElementType().ToElements()

units = doc.GetUnits().GetFormatOptions(SpecTypeId.Length).GetUnitTypeId()

 
# get walls faces 
Faces = []
for w in Walls:
    face_Ref = list(HostObjectUtils.GetSideFaces(w, ShellLayerType.Interior))[0]
    wall_face = w.GetGeometryObjectFromReference(face_Ref)
    Faces.append(wall_face)
    Thick_wall = w.Width
# cover parameters    
c1 = UnitUtils.ConvertToInternalUnits(0.03, units)
c2 = UnitUtils.ConvertToInternalUnits(0.05, units)
c3 = UnitUtils.ConvertToInternalUnits(0.05, units) + Thick_wall

# choose one face end get its edges serving as the base of creating the searched rebar shape

face = Faces[0]

edges = face.GetEdgesAsCurveLoops()[0]

plane = edges.GetPlane()

# new offseted edges in their plane
new_edges = edges.CreateViaOffset([c2, c1, c2, c1], plane.Normal.Negate())

# Translate the edges in their final position
trans = Transform.CreateTranslation(plane.Normal.Negate().Multiply(c3))

new_edges.Transform(trans)

u_plane = new_edges.GetPlane()

# remove the top horizontal edge to get the desired shape " U "
new_edges = list(new_edges)
new_edges.remove(max(new_edges, key=lambda line: line.Evaluate(0.5, True).Z))    

# create a sketch plan to temporary visualize the rebar shape         
with Transaction(doc, 'create Sketch plan') as t:
    t.Start()
    skp = SketchPlane.Create(doc, u_plane)
    t.Commit()


# create a tomporary model lines to visualize the rebar shape

with Transaction(doc, 'create Model Lines') as t:
    t.Start()
    curves = [doc.Create.NewModelCurve(e, skp) for e in new_edges]
    t.Commit()


OUT = curves

Thanks again Mike.

1 Like