rebar wrong hook orientation

rebar wrong hook orientation

REDO10
Collaborator Collaborator
1,024 Views
16 Replies
Message 1 of 17

rebar wrong hook orientation

REDO10
Collaborator
Collaborator

Hi everyone, @longt61 

 

I'm using Dynamo inside Revit and IronPython 2.7 , and I'm attempting to create longitudinal rebars (Bottom and Top rebar) for a stright beam which is oriented in +X direction as you can see in the image below, and this by using CreateFromCurves Method.

As you can see in the image below, in my code I grabed the South beam face where its FaceNormal is XYZ(0,-1,0), then to create rebars I set normal vector to be the opposite of FaceNormal and equal to XYZ(0,1,0)...however I'm conused and unable to set correct RebarHookOrientation for both ends in Top rebar, which are always oriented toward UP (+Z) instead of Down (-Z), even though I tried  to set all possible orientation combinations in my code (Left/Right, Left/Left, Right/Right, Right/Left)!!

Please check my code below and guide me to well understand RebarHookOrientation priciple to be able to solve my issue

rebar.png

Here my code:

import clr
import sys
import System
from System.Collections.Generic import IList, List

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

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

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

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

doc = DocumentManager.Instance.CurrentDBDocument

top_bar_type = UnwrapElement(IN[0])
btm_bar_type = UnwrapElement(IN[1])
hook_type = UnwrapElement(IN[2])

def get_solid(beam):
    options = Options()
    options.IncludeNonVisibleObjects = False
    options.DetailLevel = ViewDetailLevel.Fine
    geoElement = beam.get_Geometry(options)

    for geoObj in geoElement:
        if isinstance(geoObj, Solid) and geoObj.Volume > 0:
            return geoObj
        elif isinstance(geoObj, GeometryInstance):
            inst_geo = geoObj.GetInstanceGeometry()
            for g in inst_geo:
                if isinstance(g, Solid) and g.Volume > 0:
                    return g
    return None

def get_side_face_edges_and_normal(solid, direction, vector):
    for face in solid.Faces:
        normal = face.FaceNormal
        if not normal.IsAlmostEqualTo(XYZ.BasisZ) \
            and not normal.IsAlmostEqualTo(XYZ.BasisZ.Negate()) \
            and not normal.IsAlmostEqualTo(direction) \
            and not normal.IsAlmostEqualTo(direction.Negate()) \
            and normal.IsAlmostEqualTo(vector):

            edges = [e for loop in face.EdgeLoops for e in loop]
            curvesorted = sorted(edges, key=lambda x: x.AsCurve().Length)
            btmLine, topLine = sorted(curvesorted[2:], key=lambda x: x.AsCurve().GetEndPoint(0).Z)
            return [[btmLine, topLine]], normal  # Wrap in nested list for consistency
    return None, None

def get_opposite_beam_faces(beam):
    beam_curve = beam.Location.Curve
    direction = beam_curve.Direction
    vector = XYZ(0, -1, 0)  # Target face normal (North)
    solid = get_solid(beam)
    if not solid:
        return None, None
    return get_side_face_edges_and_normal(solid, direction, vector)

# Collect beams
all_beams = FilteredElementCollector(doc)\
    .OfCategory(BuiltInCategory.OST_StructuralFraming)\
    .WhereElementIsNotElementType()\
    .ToElements()



rebars = []
rebar_curves = []

with Transaction(doc, "create rebars") as t:
    t.Start()
    beam = all_beams[0]
    beam_loc = beam.Location.Curve
    beam_direction = beam_loc.Direction
    max_edges, face_normal = get_opposite_beam_faces(beam)
    normal = face_normal.Negate()
    
    
    for btm_edge, top_edge in max_edges:
        # Create fresh curve lists for each bar
        btm_crv = btm_edge.AsCurve()
        top_crv = top_edge.AsCurve()
        btm_rebar_curv = List[Curve]()
        top_rebar_curv = List[Curve]()
         
        btm_rebar_curv.Add(btm_crv)
        top_rebar_curv.Add(top_crv)
        
        btm_rebar = Rebar.CreateFromCurves(
            doc, RebarStyle.Standard,
            btm_bar_type, hook_type, hook_type,
            beam, normal, btm_rebar_curv,
            RebarHookOrientation.Left, RebarHookOrientation.Right,
            True, True
        )
        rebars.append(btm_rebar)
        rebar_curves.append(btm_crv.ToProtoType())

        top_rebar = Rebar.CreateFromCurves(
            doc, RebarStyle.Standard,
            top_bar_type, hook_type, hook_type,
            beam, normal, top_rebar_curv,
            RebarHookOrientation.Left, RebarHookOrientation.Right,
            True, True
        )
        rebars.append(top_rebar)
        rebar_curves.append(top_crv.ToProtoType())

    t.Commit()

OUT = rebars, rebar_curves

 

Any help would be appreciated.

 

Thanks.

0 Likes
Accepted solutions (1)
1,025 Views
16 Replies
Replies (16)
Message 2 of 17

longt61
Advocate
Advocate

Hi @REDO10 , thanks for the direct message.

I only have a few experience with Revit rebar in older versions, newer ones such as 2025 and 2026 might be a bit different, so take my opinions with caution :)) .

The thing I would point out from your code is that when you trying to get top edge and bottom edge from the "South" face, their direction would conform to a complete loop. Which means, the 4 edges will be clockwise or counter clockwise, a.k.a the direction of top edge and bottom edge is opposite. Therefore, applying the same input for rebar hook for both of them might not work. Furthermore, Revit rebars have some quirks (in the older version, at least), so you need to do some extra work sometimes .

 

To directly solve your issue, I would suggest these following:
1. Try check if the direction of top line and bottom line are opposite. If so, try to use different inputs for them.

2. If it does not work, you might want to try the overload method for "CreteRebarFromCurves" where you can specify the rotation for rebar hook. I not sure about python, but it should wrap the original C# Revit API here and here . Please read the remarks carefully to find the one that suits your need. 

 

Bonus: here are a few things to keep in mind:

1. Revit has some quirks, where some of the parameters are affected by or become visible/ invisible by other parameters

2. Some settings or geometry are not available for modification until you have regen the document or ui document

3. Your rebar might be affected by the rebar constraints, which will "snap" rebar to some special points such as: the framing 's rebar cover (the distance from the outer most face to where you can validly placed a rebar to ensure that the concrete will cover the rebar in real life), the other rebar 's bend point / mid point / start-end points, etc.. Therefore, even if you calculate everything correctly, your rebar still "snap" to those points and change location/ rotation/ normal vector unexpectedly. I would suggest you create some model lines to visualize your rebar locations, normal vector, etc.. to see if your input is correct, then try to analyze the Rebar constraints manually and programmatically via RebarConstraintManager.

 

Hope this helps.

Message 3 of 17

REDO10
Collaborator
Collaborator

Hi @longt61 

First of all, I’m sorry for the very late reply. I was traveling and didn’t have access to my computer or the forum to check your message.

Secondly, I’ve taken note of your suggestions. However, I’m still quite confused about hook orientations and can’t figure out how Revit determines them.

As you can see in the two images below and as you suggested, I tested two cases where the bottom and top lines are first in opposite directions, then in the same direction as the beam. I tried all possible hook orientations, but still got unexpected results—except for one case, as shown in the image.

Could you please explain why I’m getting these incorrect orientations and guide me toward a better understanding of RebarHookOrientation so I can resolve this issue?

 

rebars.png

rebars_same_direction.png

Thanks.

0 Likes
Message 4 of 17

longt61
Advocate
Advocate

sorry for the late reply, I was quite busy for the past few day.

Firstly, make sure you understand the normal vector, the direction of the rebar. Any 3D coordinate consists of 3 axes: X, Y and Z. You can consider rebar direction is X axis, rebar normal is Z axis. These 3 axes conform to the right hand rule (you can look it up online for visualization):

  • Rebar direction / X axis is the index finger
  • Y axis is the middle finger
  • Rebar normal / Z axis is the thumb, which is the cross product of X and Y axes.
  • In your case, the rebar hooks:
    - Left hook should be the same direction as Y axis
    - Right hook should be the opposite direction to Y axis.

Therefore, you can calculate the hook direction to see if it suits your need, otherwise, negate the normal. I will try to use the left case in your first picture to demonstrate. All of the vector will normalize to unit vector (vector with length = 1):

Consider the top bar

  • rebar direction (X axis of rebar) = (-10, 0,0). Normalize() = (-1, 0,0)
  • rebar normal (Z axis of rebar) = (0,1,0)

=> Y axis of rebar = X.CrossProduct(Z).Negate() = ( -1, 0, 0).CrossProduct(0, 1, 0).Negate() = (0,0, 1) (pointing upward direction)

if you set it to left hook, the hook should point upward. If you set it to right hook, the hook should point downward.

Then, you can consider changing the normal vector or the left/right settings of the hook to create rebar.

longt61_0-1752137883739.png

 

Message 5 of 17

REDO10
Collaborator
Collaborator

@longt61

First of all, I’m sorry if I bothered you with my questions...it seems there's something that keeps tricking me and prevents me from fully understand the logic behind RebarHookOrientation

I carefully read your explanation, and I thought I had finally understood everything. However, I still find myself confused...something always escapes me!

Considering the same example as above which is illustrated in the image below where:

  • rebar direction (X axis of rebar) = (-10, 0,0) (normalized direction: (-1, 0,0))
  • rebar normal (Z axis of rebar) = (0,1,0) (Note: this normal is considered fixed to avoid placing the rebar outside the beam)

According to the right-hand rule, the cross product between the rebar direction and the normal gives (0,0,-1), so the Y-axis of the rebar might point downward, as shown in the image.

I tried assigning the appropriate hook orientations for the three cases in the image, but I always end up getting "Right"... even when I explicitly set it to "Left" That’s what confuses me again!

hooks_orientation.png

 

Here my used code for the expected 3rd case (start hook  "Downward", end hook "Upward")

import clr
import sys
import System
from System.Collections.Generic import IList, List

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

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

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

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

doc = DocumentManager.Instance.CurrentDBDocument

top_bar_type = UnwrapElement(IN[0])
btm_bar_type = UnwrapElement(IN[1])
hook_type = UnwrapElement(IN[2])

cover = 0.05/0.3048

# Collect beams
all_beams = FilteredElementCollector(doc)\
    .OfCategory(BuiltInCategory.OST_StructuralFraming)\
    .WhereElementIsNotElementType()\
    .ToElements()

beam = all_beams[0]

curve = beam.Location.Curve
top_curve = Line.CreateBound(curve.GetEndPoint(1), curve.GetEndPoint(0))
width = beam.Symbol.LookupParameter("b").AsDouble()
top_curve = top_curve.CreateTransformed(Transform.CreateTranslation(XYZ.BasisY.Negate().Multiply(width/2 - cover)))


with Transaction(doc, "create rebars") as t:
    t.Start()
    top_rebar_curv = List[Curve]()
         
    top_rebar_curv.Add(top_curve)
    top_rebar = Rebar.CreateFromCurves(
        doc, RebarStyle.Standard,
        top_bar_type, hook_type, hook_type,
        beam, XYZ(0,1,0), top_rebar_curv,
        RebarHookOrientation.Right, RebarHookOrientation.Left,
        True, True
    )
    top_rebar.GetShapeDrivenAccessor().SetLayoutAsFixedNumber(3, width-2*cover, True, True, True)
        
    t.Commit()

OUT = top_rebar, top_curve.ToProtoType()

Any further details or explanations that could help solidify my understanding would be greatly appreciated.

Thanks.

 

 

0 Likes
Message 6 of 17

REDO10
Collaborator
Collaborator

@jeremy_tammik , @Mohamed_Arshad 

 

Can you please guide me to better understand the hook orientation rules so I can solve my issue?

 

Thanks.

0 Likes
Message 7 of 17

longt61
Advocate
Advocate

the only thing that I  would point out is


According to the right-hand rule, the cross product between the rebar direction and the normal gives (0,0,-1), so the Y-axis of the rebar might point downward, as shown in the image.

The right hand rule applies to X_axis.CrossProduct(Y_axis) = Z_axis, you can not switch the order of the vectors so that "it seems fit". What you thought and demonstrate in the image is the left hand rule.  Therefore, if X_axis = (-1,0,0) and Z_axis (0,1,0), Y_axis = (0,0,1) so that X_axis.CrossProduct(Y_axis) = Z_axis, not that X_axis.CrossProduct(Z_axis) = Y_axis.

Other than this, I see nothing wrong with your code. I tried to recreate you case with Revit 2022 and Revit API C#, and it worked as expected. Even though the code is written in C#, I believe it should be easy enough for you to understand and compare with yours.

 

using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
using RevitUtilsShared.Extensions;
using RevitUtilsShared.SelectionFilters;

namespace RevitUtilsShared.Entry.Commands.RnD
{
    [Transaction(TransactionMode.Manual)]
    public class CmdCreateRebar : IExternalCommand
    {
        private UIDocument _uidoc;
        private Document _doc;
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            _uidoc = commandData.Application.ActiveUIDocument;
            _doc = _uidoc.Document;
            CreateRebar();
            return Result.Succeeded;
        }

        private void CreateRebar()
        {
            var elem = RevitCommon.PickElement(_uidoc, new FamilyInstanceSelectionFilter(), "pick beam");
            if (elem != null && elem is FamilyInstance beam)
            {
                var solid = beam.GetSolid();
                var topFace = GetTopFace(solid);
                var barType = GetBarType();
                var hookType = GetHookType(barType);

                if (topFace != null && barType != null)
                {
                    using (Transaction trans = new Transaction(_doc, "create rebar"))
                    {
                        trans.Start();
                        var rebarLine = GetRebarLine(topFace, beam);
                        var rebar = Rebar.CreateFromCurves(_doc, RebarStyle.Standard, barType, hookType, hookType, beam,
                            beam.FacingOrientation, rebarLine, RebarHookOrientation.Right, RebarHookOrientation.Left, true, true);
                        trans.Commit();
                    }
                }
            }
        }

        private PlanarFace GetTopFace(Solid solid)
        {
            if (solid != null)
            {
                return solid.Faces
                      .Cast<PlanarFace>()
                      .Where(x => x != null
                               && x.FaceNormal.IsParallel(XYZ.BasisZ))
                      .OrderBy(x => x.Origin.Z)
                      .LastOrDefault();
            }
            return null;
        }

        private List<Curve> GetRebarLine(PlanarFace topFace, FamilyInstance beam)
        {
            var lines = new List<Curve>();
            var beamCurve = (beam.Location as LocationCurve).Curve;
            var beamDir = (beamCurve as Line).Direction;
            var rebarLine = topFace.GetEdgesAsCurveLoops()
                                    .SelectMany(x => x)
                                    .Cast<Line>()
                                    .FirstOrDefault(x => x != null && x.Direction.IsAlmostEqualTo(beamDir));

            if (rebarLine != null)
            {
                var topCover = GetRebarCover(beam, BuiltInParameter.CLEAR_COVER_TOP);
                var sideCover = GetRebarCover(beam, BuiltInParameter.CLEAR_COVER_OTHER);
                var width = (double)beam.Symbol.GetParameterValue("b");

                var vector = beam.FacingOrientation * sideCover + XYZ.BasisZ.Negate() * topCover;
                var translate = Transform.CreateTranslation(vector);
                rebarLine = rebarLine.CreateTransformed(translate) as Line;
            }

            if (rebarLine != null)
                lines.Add(rebarLine);
            return lines;
        }

        private double GetRebarCover(FamilyInstance beam, BuiltInParameter param)
        {
            var coverId = (ElementId)beam.GetParameterValue(param);
            var cover = _doc.GetElement(coverId) as RebarCoverType;
            if (cover != null)
                return cover.CoverDistance;
            return 0;
        }

        private RebarBarType GetBarType()
        {
            return new FilteredElementCollector(_doc)
                    .WhereElementIsElementType()
                    .OfCategory(BuiltInCategory.OST_Rebar)
                    .OfClass(typeof(RebarBarType))
                    .Cast<RebarBarType>()
                    .FirstOrDefault();
        }

        private RebarHookType GetHookType(RebarBarType barType)
        {
            return new FilteredElementCollector(_doc)
                    .WhereElementIsElementType()
                    .OfCategory(BuiltInCategory.OST_Rebar)
                    .OfClass(typeof(RebarHookType))
                    .Cast<RebarHookType>()
                    .FirstOrDefault(x => x.Style == RebarStyle.Standard
                                      && barType.GetHookPermission(x.Id));
        }
    }
}

longt61_0-1752485252457.png

 

Message 8 of 17

longt61
Advocate
Advocate

@REDO10 like I have proposed before, could you check the rebar constraint to make sure it was properly constrained as shown in the images below? Besides, you can check it in the code using the RebarConstraintsManager

longt61_1-1752485351074.png

 

longt61_2-1752485409319.png

 

Message 9 of 17

REDO10
Collaborator
Collaborator

Hi @longt61


@longt61  a écrit :

The right hand rule applies to X_axis.CrossProduct(Y_axis) = Z_axis, you can not switch the order of the vectors so that "it seems fit". What you thought and demonstrate in the image is the left hand rule.  Therefore, if X_axis = (-1,0,0) and Z_axis (0,1,0), Y_axis = (0,0,1) so that X_axis.CrossProduct(Y_axis) = Z_axis, not that X_axis.CrossProduct(Z_axis) = Y_axis.


Maybe I wasn’t very clear, but I think we can agree on this:

When applying the right-hand rule, the result of the cross product points in the direction of the thumb. In my case, the direction of the bar is (-1, 0, 0). The normal vector of the plane where the rebar is placed can be determined by changing the rebar distribution from "Single" to another rule.

Here, the normal vector is (0, 1, 0), which points north (+Y), because I selected the south face of the beam as the placement constraint (to prevent distributed rebars from going outside the beam). Based on this:

(-1, 0, 0).CrossProduct(0, 1, 0) = (0, 0, -1)

This result gives us the vector that defines the Left/Right hook orientation.

Could you please confirm if my understanding is correct: since the cross product result is (0, 0, -1), does that mean "Left" orientation points downward in this case?

 

I'll test your code and compare it with mine to see if I get the expected result.

 

Thanks.

0 Likes
Message 10 of 17

longt61
Advocate
Advocate

hi @REDO10 , I hope my code works for you, otherwise, please try to research the rebar constraints to see if it affects your rebar locations.

As for the vectors issue, let us break it down into 2 parts:
1. The idea of cross product of the right hand rule:

    yes, you absolutely correct.

2. Its application: 
    I think what you confuse is that the right hand rule only apply in one way: X_axis.CrossProduct(Y_axis) = Z_axis. Z_axis is always the direction of your thumb. You cannot change the order of the equation. What you are using is X_axis.CrossProduct(Z_axis) = Y_axis. You have switch the place of Y_axis and Z_axis. You can try to place your index finger to the direction of X_axis (rebar direction) and your thumb to the direction of Z_axis (normal). Then, the middle finger is the direction of Y_axis according to the right hand rule. 
    In other words, the issue is "given X and Z known, find Y that satisfies X.CrossProduct(Y) = Z" while you are trying to solve "find Y that satisfies X.CrossProduct(Z) = Y".
I hope this is clear enough.

 

 

Message 11 of 17

REDO10
Collaborator
Collaborator

Hi @longt61 

I'm sorry to ask again, but I'm still confused, so let me explain:

 


@longt61  a écrit :

2. Its application: 
    I think what you confuse is that the right hand rule only apply in one way: X_axis.CrossProduct(Y_axis) = Z_axis. Z_axis is always the direction of your thumb. You cannot change the order of the equation. What you are using is X_axis.CrossProduct(Z_axis) = Y_axis. You have switch the place of Y_axis and Z_axis. You can try to place your index finger to the direction of X_axis (rebar direction) and your thumb to the direction of Z_axis (normal). Then, the middle finger is the direction of Y_axis according to the right hand rule. 
    In other words, the issue is "given X and Z known, find Y that satisfies X.CrossProduct(Y) = Z" while you are trying to solve "find Y that satisfies X.CrossProduct(Z) = Y".
I hope this is clear enough.


I admit that I was initially confused about the order of the Y and Z vectors in the cross product equation. I now understand how to correctly orient the X and Z vectors (which are given), and how to determine the Y orientation by following the direction of my middle finger representing the Left orientation for the hook at the start or End(0) of the bar (whether it's facing upward or downward.)

However, in my code below (where I reproduced the exact same logic as in your code, with slight modifications to get the desired BarType and HookType), you can see in the image that I still get the hook reversed compared to your result...even though I made sure to replicate your case by taking these key points into account:

  • As you suggested (and as shown in the image), I ensured the rebar is properly constrained, just like in your case.
  • I printed out the normal vector and the rebar direction to confirm they match your setup, where:

       - The normal vector Z is (0, 1, 0)

       - the bar direction X is: Vector(X = 10.000, Y = 0.000, Z = 0.000, Length = 10.000)

 

Furthermore, I’d like to point out the following:

  • Even when I reverse the bar direction to Vector(X = -10.000, Y = 0.000, Z = 0.000, Length = 10.000) while keeping the normal vector unchanged (0, 1, 0), the hooks still appear unchanged and behave opposite to your case!?
  • The hook orientations read from Revit Lookup are always the opposite of those set in the code. (as you can see in the code I've set the start hook to Right but Revit Lookup reports it as Left, and vice versa.
  • How does Revit determine which rebar shape family to use from the Rebar Shape Browser that matches the hook criteria I've set ? (as shown in the image, the chosen rebar shape is "23") Should I load all shapes from the Rebar Shape Browser and let Revit automatically select the correct one that matches the hook criteria? Or should I delete all shapes except the standard one "00" to ensure Revit creates the desired shape?

shape_23.png

Please check my code below:

 

import clr
import sys
import System
from System.Collections.Generic import IList, List

# Add Revit and Dynamo references
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

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

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

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

# Document reference
doc = DocumentManager.Instance.CurrentDBDocument


def get_solid(beam):
    options = Options()
    options.ComputeReferences = True
    options.IncludeNonVisibleObjects = True  # important for nested geometry
    options.DetailLevel = ViewDetailLevel.Fine

    geo_element = beam.get_Geometry(options)
    if not geo_element:
        return None

    for geom_obj in geo_element:
        if isinstance(geom_obj, Solid) and geom_obj.Volume > 0:
            return geom_obj
        elif isinstance(geom_obj, GeometryInstance):
            symbol_geo = geom_obj.GetInstanceGeometry()
            for g in symbol_geo:
                if isinstance(g, Solid) and g.Volume > 0:
                    return g
    return None

def get_top_face(solid):
    if not solid:
        return None
    for face in solid.Faces:
        if isinstance(face, PlanarFace) and face.FaceNormal.IsAlmostEqualTo(XYZ.BasisZ):
            return face
    return None

def get_rebar_cover(beam, param_enum):
    param = beam.get_Parameter(param_enum)
    if param and param.AsElementId() != ElementId.InvalidElementId:
        cover_elem = doc.GetElement(param.AsElementId())
        if isinstance(cover_elem, RebarCoverType):
            return cover_elem.CoverDistance
    return 0

def get_rebar_line(top_face, beam):
    if not top_face:
        return None
    lines = List[Curve]()
    loc_curve = beam.Location.Curve
    beam_dir = loc_curve.Direction

    edge_loops = top_face.GetEdgesAsCurveLoops()
    curves = [c for loop in edge_loops for c in loop]

    rebar_line = None
    for c in curves:
        if c.Direction.IsAlmostEqualTo(beam_dir):
            rebar_line = c
            break
    
    if rebar_line:
        top_cover = get_rebar_cover(beam, BuiltInParameter.CLEAR_COVER_TOP)
        side_cover = get_rebar_cover(beam, BuiltInParameter.CLEAR_COVER_OTHER)

        offset = beam.FacingOrientation.Multiply(side_cover).Add(XYZ.BasisZ.Negate().Multiply(top_cover))
        translate = Transform.CreateTranslation(offset)
        rebar_line = rebar_line.CreateTransformed(translate)
        print(rebar_line.ToProtoType())
        lines.Add(rebar_line)

    return lines if lines.Count > 0 else None


# Main logic
all_beams = FilteredElementCollector(doc)\
    .OfCategory(BuiltInCategory.OST_StructuralFraming)\
    .WhereElementIsNotElementType()\
    .ToElements()

hook_types = FilteredElementCollector(doc) \
    .OfCategory(BuiltInCategory.OST_Rebar) \
    .WhereElementIsElementType() \
    .WherePasses(ElementClassFilter(RebarHookType)) \
    .ToElements()

rebar_types = (FilteredElementCollector(doc)
        .OfCategory(BuiltInCategory.OST_Rebar)
        .WhereElementIsElementType()
        .WherePasses(ElementClassFilter(RebarBarType))
        .ToElements())
        
hook_90 = next((h for h in hook_types if Element.Name.GetValue(h) == "Standard - 90 deg"), None)

HA_12mm = next((r for r in rebar_types if Element.Name.GetValue(r) == "HA12 (Fe400)"), None)
rebar = None

if all_beams:
    beam = all_beams[0]
    print(beam.FacingOrientation)
    solid = get_solid(beam)
    top_face = get_top_face(solid)
    rebar_lines = get_rebar_line(top_face, beam)

    if rebar_lines:
        with Transaction(doc, "Create Rebar") as t:
            t.Start()
            rebar = Rebar.CreateFromCurves(
                doc,
                RebarStyle.Standard,
                HA_12mm,
                hook_90,
                hook_90,
                beam,
                XYZ(0,1,0),
                rebar_lines,
                RebarHookOrientation.Right,
                RebarHookOrientation.Left,
                True,
                True
            )
            t.Commit()


OUT = beam.FacingOrientation, rebar_lines[0].Direction, rebar

 

Thanks.

0 Likes
Message 12 of 17

longt61
Advocate
Advocate

Hi @REDO10 , could you share the revit file where you had created rebar with all the settings? I am not sure if I can identify and solve your problem, but investigate the current state of the revit file might shed some light into the matter. Please remove all sensitive information as you seem fits. Thanks.

Message 13 of 17

REDO10
Collaborator
Collaborator

Hi @longt61 

Please check below my attached model

 

Thanks.

 

0 Likes
Message 14 of 17

REDO10
Collaborator
Collaborator

Can anyone help me clear up my confusion about hook orientation?

 

Thanks.

0 Likes
Message 15 of 17

longt61
Advocate
Advocate
Accepted solution

@REDO10 sorry for taking too long to reply, I have been scratching my head when my code produce the same result as yours with your shared file, but it works fine with default Revit project file. The causes of the issue are:
1. You have tried many versions of your code, both correct and incorrect ones, in the shared project, and it creates many rebar shapes. You can see that there are multiple rebar shape with "23" name as shown in the image below.

longt61_0-1756894359388.png

2. Due to there are many shapes in the shared project and you did not tick on the Reinforcement settings as shown in this image, Revit does not take the hooks into account when trying to resolve the shape of Rebar. Furthermore, I set the "useExistingShapeIfPossible" parameter to "true" in the code, therefore, Revit will try to use the first custom shape that satisfies the main rebar segment excluding the hooks.

longt61_1-1756894509466.png

You just need to tick the checkbox for the mentioned Reinforcement settings, then run the code again to produce the result you want. As you can see in these images, I can create 2 different results using the same code just by changing the Reinforcement setting:

longt61_2-1756894845772.png                     

longt61_3-1756894866698.png

Hope this is not too late for your work. 

P/S:
1. I got the result with Revit 2024, so I am not sure about earlier version. You might want to check the settings and API again since your shared file is of Revit 2023.
2. If Revit API does not expose any way to change this setting then I guess this is how it is.

3. You might want to change back to original settings so that it does not affect future manual rebar creation.

Message 16 of 17

REDO10
Collaborator
Collaborator

Hi @longt61 


@longt61  a écrit :

@REDO10 sorry for taking too long to reply, I have been scratching my head when my code produce the same result as yours with your shared file


No problem at all ... I’m the one who’s grateful to you for your patience in helping me track down the source of my issue. So once again, thank you!

 


@longt61  a écrit :

 

2. Due to there are many shapes in the shared project and you did not tick on the Reinforcement settings as shown in this image, Revit does not take the hooks into account when trying to resolve the shape of Rebar. Furthermore, I set the "useExistingShapeIfPossible" parameter to "true" in the code, therefore, Revit will try to use the first custom shape that satisfies the main rebar segment excluding the hooks.


Like you, this issue was driving me crazy!!...I tried editing the original shape "23" and created two new shapes, hoping that the generated rebar shape would match one of them, where:

  • first I reversed the bar direction to create a "23_reversed" shape,
  • then I flipped the hooks to create a "23_hooks_reversed" shape.

It never crossed my mind that the problem was actually related to the reinforcement settings. As you suggested, I should have checked the “Include hooks in Rebar Shape definition” option from the start. Now the issue is solved, and I’ve tested my code in multiple cases with different hook orientations. I’m getting the expected shapes with the correct hook orientations exactly as defined in my code.

 

In conclusion, if we want hooks to be included in the generated shape “Include hooks in Rebar Shape definition” option must be checked?...for that and using Revit API, is there a code that ensure this option is enabled by default when starting new project?

 

Thanks.

0 Likes
Message 17 of 17

longt61
Advocate
Advocate

Glad that I could be helpful. And I also learn something new along the way.
As for the Include hooks in Rebar Shape definition”, I have not found any API related to this settings yet. I guess we have to take as it is, and trying to find out more as we work with Revit. When I first start working with Revit and rebar back in 2019, rebar does even have geometry or solid, which is frustrating for checking interference of automate created rebars and existing one. Now, to my surprise when trying to analyze your issue, I find out that rebar have solid, which is great. So, maybe I was looking hard enough, or we can hope for a better future. :))
Cheers, happy coding. 

Update: I looked it up and you can use the "ReinforcementSettings" class to modify the “Include hooks in Rebar Shape definition”. Even though this is a project wise settings, it can not be retrieved directly from the "Document" class, which is a Revit quirk and that is why it slips my mind. Furthermore, according to the remarks, you can only change the settings when the project contains no rebars in general. Quite limited compared to the Revit user interface, but there hope in the future. I hope that you can find the similar function in your Python code.

var settings = ReinforcementSettings.GetReinforcementSettings(_doc);
settings.RebarShapeDefinesHooks = true;

longt61_0-1757043861151.png

 



0 Likes