Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Problem with Constraining Stirrups to the Cover of the Host Element

17 REPLIES 17
SOLVED
Reply
Message 1 of 18
kevin.anggrek
1892 Views, 17 Replies

Problem with Constraining Stirrups to the Cover of the Host Element

Hi all,

 

I have been working on an add-in to automatically place stirrups inside a host element (Structural Column in this case). I use the Rebar.CreateFromRebarShape() Method in order to create the stirrup inside the column. However, the RebarShape came with its own dimensions and thus didn't fit inside the concrete's cover.

 

Through the Revit user interface, every time the stirrup is placed manually inside a host element in the plan view, Revit can automatically constrains the stirrup edges to be inside the cover, How to do the same thing through the Revit API? I have tried getting the RebarConstraintManager of the newly created stirrup, iterating through all of its handles and then changing the preferred RebarConstraint to ToCover as illustrated in the code snippet shown below:

 

Rebar stirrup = Rebar.CreateFromRebarShape(doc, rebarShape, barType, column, bottomLeftXYZ1, XYZ.BasisX, XYZ.BasisY);

// Modify the RebarConstraint
RebarConstraintsManager rebarConstraintsManager = stirrup.GetRebarConstraintsManager();
IList<RebarConstrainedHandle> rebarConstrainedHandles = rebarConstraintsManager.GetAllConstrainedHandles();
foreach (RebarConstrainedHandle handle in rebarConstrainedHandles)
{
    List<RebarConstraint> constraintCandidates = rebarConstraintsManager.GetConstraintCandidatesForHandle(handle).ToList();
    RebarConstraint toCoverConstraint = constraintCandidates.Find(c => c.IsToCover() == true);

    RebarConstraint constraint = rebarConstraintsManager.GetCurrentConstraintOnHandle(handle);
    if (!constraint.IsToCover())
    {
        rebarConstraintsManager.SetPreferredConstraintForHandle(handle, toCoverConstraint);
    }
}

 

After running the program, nothing changed at all to the stirrup (still didn't fit inside the concrete cover of the column host). After doing some debugging, I discovered that the GetAllConstrainedHandles() method returned 0 handles, that is why the rest of the program didn't work. Why did the method return zero handles even though the handles are visible in the user interface (both the dot and triangle handles)? Are there other methods to snap the stirrup inside the concrete cover?

 

Thanks in advance

Labels (2)
17 REPLIES 17
Message 2 of 18

Tricky question, at least for me.

 

I have passed it on to the development team for you and hope that they can advise.

 

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 3 of 18
RPTHOMAS108
in reply to: kevin.anggrek

Rebar is quite a complex area of the API due to the various objects involved:

 

RebarShapeDrivenAccessor.ScaleToBox:

This purportedly uses the same algorithm as when you place shape in section view for example.

From this you probably have to work out the size of the rectangle by looking at cross section deducting covers, not sure there is a faster method. You probably have to size tto get it somewhere near and then constrain (historically I've noticed similar in UI).

 

There is a related method:
RebarShapeDrivenAccessor.ScaleToBoxFor3D

 

RebarShapeDrivenAccessor comes from Rebar.GetShapeDrivenAccessor and is specific to shape driven rebar.

 

I'm not sure this algorithm always gets it right (from UI experience with it) and there is an element of rationalisation of free end dimensions that need to be applied afterwards. Perhaps sometimes it can't be placed at all and perhaps sometimes when you increse bar diameter the shape can't be made (after placing a smaller bar diameter size) i.e. due to incresing bending diameter reducing distance between straights.

 

 

Message 4 of 18

The development team replied:

  

You should use:

 

  •  public IList<RebarConstrainedHandle> GetAllHandles();

  

which gets all RebarConstrainedHandles of this bar. All RebarConstrainedHandle objects will be returned, regardless of whether there are constraints associated to them.

  
The GetAllConstrainedHandles() function returns all handles that are already constrained to external references.

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 5 of 18

Dear Mr. @jeremy_tammik ,

 

Thank you for taking your time to contact the development team. I have tried the method that the development team has suggested and indeed it works! I can now get the handles in the rebar. However, after setting a new RebarConstraint to each handle in order to snap them to the concrete cover of the host element, the stirrup didn't change to be inside the cover.

 

Let me provide more details to my case. In the beginning, I tried to create a stirrup inside the column by using CreateFromRebarShape() Method as shown below:

Rebar stirrup = Rebar.CreateFromRebarShape(doc, rebarShape, barType, column, bottomLeftXYZ1, XYZ.BasisX, XYZ.BasisY);

I used the default RebarShape called T1 which is provided as a template by Revit, and the result of the above code is a stirrup. However the sizes of the stirrup doesn't match my current column (each rebar shape should have their own default dimensions) as shown below:

1.png

 

That is why I am trying to fit the stirrup inside my column as what the Revit can do through the user interface as shown below:

Placing a stirrup through the user interface (the selected rebar shape T1 automatically got constrained inside the cover)Placing a stirrup through the user interface (the selected rebar shape T1 automatically got constrained inside the cover)

I fixed my C# code to the following based on your suggestion in order to change the RebarConstraints to be inside the cover:

Rebar stirrup = Rebar.CreateFromRebarShape(doc, rebarShape, barType, column, bottomLeftXYZ1, XYZ.BasisX, XYZ.BasisY);

#region // Modify the RebarConstraint (Trying to snap the stirrup to the rebar)
RebarConstraintsManager rebarConstraintsManager = stirrup.GetRebarConstraintsManager();
IList<RebarConstrainedHandle> rebarConstrainedHandles = rebarConstraintsManager.GetAllHandles();
foreach (RebarConstrainedHandle handle in rebarConstrainedHandles)
{
    List<RebarConstraint> constraintCandidates = rebarConstraintsManager.GetConstraintCandidatesForHandle(handle).ToList();
    RebarConstraint toCoverConstraint = constraintCandidates.Find(c => c.IsToCover() == true);
    RebarConstraint constraint = rebarConstraintsManager.GetCurrentConstraintOnHandle(handle);
    if (constraint == null || !constraint.IsToCover())
    {
        rebarConstraintsManager.SetPreferredConstraintForHandle(handle, toCoverConstraint);
    }
}

and indeed, the RebarConstraint did change to be constrained to the cover as shown in the images below:

 

Before implementing the code (the handles are constrained to the Host face as shown by the orange line at the host face)

Before Implementing the Code (The Handles are constrained to the Host Face)Before Implementing the Code (The Handles are constrained to the Host Face)

 

After Implementing the code (the handles are now constrained to the cover as shown by the blue logo under the triangle handles)

After implementing the Code snippet (The handles are indeed constrained to the cover as shown by the blue Toggle Rebar Cover Constraint logo)After implementing the Code snippet (The handles are indeed constrained to the cover as shown by the blue Toggle Rebar Cover Constraint logo)

Even though the stirrup indeed got constrained to the cover, but it didn't automatically resize just like in the user interface. Any suggestion on how I can achieve similar result as through the user interface?

 

Thank you

Message 6 of 18

Thank you for the appreciation, and very glad to hear it helped one step further.

 

Now, your question is getting harder and harder.

 

I passed it on to the development team again and hope that they have further good suggestions lined up for you.

 

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 7 of 18

Dear Mr. @RPTHOMAS108 

 

Thank you for taking your time to answer my question,

I tried the ScaleToBox() method that you suggested as shown in the code snippet below:

 

 

Rebar stirrup = Rebar.CreateFromRebarShape(doc, rebarShape, barType, column, bottomLeftXYZ1, XYZ.BasisX, XYZ.BasisY);

stirrup.GetShapeDrivenAccessor().ScaleToBox(bottomLeftXYZ1, new XYZ(horDist, 0, 0), new XYZ(0, vertDist, 0));

 

 

 

It seems to work well, the stirrup indeed got resized according to the rectangle that is specified by the ScaleToBox() method, I will double check whether all the parameters are correct after the scaling. I will mark your answer as the solution after I did the checking and there's no other issues left! Thanks!

Message 8 of 18

Devteam reply:

  

You should set the distance between bar segment and the cover to zero, i.e., `constraint.SetDistanceToTargetCover(0.0)`.

 

Another thing I observe in the last picture: the highlighted segment is constrained to the bottom cover; however, it should be constrained to the upper one.

 

In this case, for each segment, there are two constraint candidates that are to cover. You should choose the one that is closer to the segment. `constraint.GetDistanceToTargetCover` can be used to obtain the distance between bar segment and the cover candidate.

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 9 of 18

Dear Mr. @jeremy_tammik ,

 

Thank you for the quick responses. I believe I am pretty close in cracking the case down. I implemented both the development team's and your suggestion into the following code snippet:

 

 

 

Rebar stirrup = Rebar.CreateFromRebarShape(doc, rebarShape, barType, column, bottomLeftXYZ1, XYZ.BasisX, XYZ.BasisY);

RebarConstraintsManager rebarConstraintsManager = stirrup.GetRebarConstraintsManager();
IList<RebarConstrainedHandle> rebarConstrainedHandles = rebarConstraintsManager.GetAllHandles();
foreach (RebarConstrainedHandle handle in rebarConstrainedHandles)
{
    List<RebarConstraint> constraintCandidates = rebarConstraintsManager.GetConstraintCandidatesForHandle(handle).ToList();
    List<RebarConstraint> toCoverConstraints = constraintCandidates.FindAll(c => c.IsToCover() == true);

    // Find the nearest cover constraint to the handle
    RebarConstraint nearestToCoverConstraint = toCoverConstraints[0]; // Temporarily set the variable to the first RebarConstraint element
    foreach (RebarConstraint constraint in toCoverConstraints) // Loop through the RebarConstraint list to find the nearest cover constraint
    {
        if (constraint.GetDistanceToTargetCover() < nearestToCoverConstraint.GetDistanceToTargetCover())
        {
            nearestToCoverConstraint = constraint;
        }
    }

    // Setting distance of the handle to the Host cover
    nearestToCoverConstraint.SetDistanceToTargetCover(0.0);

    // Setting the RebarConstraint as the preferred constraint to the handle
    RebarConstraint currentConstraint = rebarConstraintsManager.GetCurrentConstraintOnHandle(handle);
    if (currentConstraint == null || !currentConstraint.IsToCover())
    {
        rebarConstraintsManager.SetPreferredConstraintForHandle(handle, nearestToCoverConstraint);
    }
    RebarConstraint constraintTest = rebarConstraintsManager.GetPreferredConstraintOnHandle(handle);
}

 

 

 

 

Compared to the previous code snippet, I now store all of the possible ToCover constraints inside the toCoverConstraints List, and precisely as you have mentioned, there are 2 possible ToCover constraints detected and I need to find the closest one to the handle. I then implemented the GetDistanceToTargetCover() Method as you have suggested in order to find the constraint that is closest to the handle. Afterwards, I set the distance to 0 and then I set the modified constraint to the handle. However, an error occurred (Rebar Shape Failure) inside Revit when running the add-in:

7.png

First thing that I did trying to solve this issue was checking the Handle Types of each of the Rebar handles obtained from the RebarConstraintsManager.GetAllHandles(). There are 7 Handles in total, 1 handle has the RebarHandleType of RebarPlane, 4 handles have the RebarHandleType of Edge, the last two Handles are of the type StartOfBar and EndOfBar respectively. I tried setting the ToCover constraint only to specific handle types (to Edge type only, to StartOfBar and EndOfBar handles only, etc) but the same Rebar Shape Failure still appear.

 

If I try to model the stirrups manually using the Revit User Interface (using the same Rebar Shape that I used in the Add-in) and then checking each of the Rebar Constraint, I got the following set up in the User Interface:

One of the Edge Handle, Constrained to Cover at Zero Distance)One of the Edge Handle, Constrained to Cover at Zero Distance)StartOfBar Handle, Constrained to Cover at Zero Distance)StartOfBar Handle, Constrained to Cover at Zero Distance)EndOfBar Handle, Constrained to Cover at Zero Distance)EndOfBar Handle, Constrained to Cover at Zero Distance)

Looking at these handle constraints of the manually created stirrups in the User Interface, they are all constrained to Cover, and have their distance set at zero. The suggestions that you have provided to me should have lead to the correct approach (The code snippet already implemented approaches to find the correct cover and then setting the distance to zero). However, I couldn't get the same result as the stirrup created through the User Interface even though the approaches in the code snippet seems to lead to the correct result already. Instead, I am getting the Rebar Shape Failure Error that forces me to delete the rebar. Is there something that I am missing here that I am still unaware of?

 

Thanks in advance and sorry for my lengthy reply

 

Message 10 of 18

Thank you for your update and sorry to hear about the new challenge. I passed it on to the development team and hope they can pick it up with you directly.

 

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 11 of 18

The devteam replied:

 

It looks like the constraints that were set were not good. There should be done some debugging to understand what is happening. This can also be done on customer's side. For example, from API there can be set the constraints but without  setting the distance zero to cover. Then look in Edit Constraints and check if each handle is constrained to the expected cover. Here I'm expecting to see that the constraints were not set to the correct cover and should be investigated.


There can be done something else. Create the bar without setting any constraints from API, from Revit UI - Edit Constraints go and set constrains manually for each segment, then, with an API command, for each constraint set the distance to 0. There should be no error. I'm expecting this to work without any problems.


To debug it, you need the sample model and the entire code, not just the part with constraints, but also the code that calculates the rebar curves.

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 12 of 18

Dear Mr. @jeremy_tammik 

 

Once again, thank you so much for taking your time in answering my queries.

 

You are right! after debugging in the same manner as suggested by the devteam, I found out that the handles are constrained to the wrong side of the Rebar Cover, thus setting the distance to zero will result in an error. After checking my code again, I figured out that the RebarConstraint.GetDistanceToTargetCover() will return distance with the plus/minus sign and thus in order to find the nearest constraint to the cover, I need to compare the absolute value of the RebarConstraint.GetDistanceToTargetCover().

 

Thus in the end, I can successfully get the correct result!

Thank you

 

Message 13 of 18

Wow, fantastic! Congratulations on getting this to work. Thank you very much for letting us know and your kind appreciation.

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 14 of 18

Thank you for the fruitful conversation and congratulations again on the successful conclusion.

 

I shared it here on the blog for posterity:

 

https://thebuildingcoder.typepad.com/blog/2021/03/boundary-elements-and-stirrup-constraints.html#2

  

Jeremy Tammik, Developer Advocacy and Support, The Building Coder, Autodesk Developer Network, ADN Open
Message 15 of 18
arshad.k
in reply to: kevin.anggrek

Dear @kevin.anggrek 

 

I too stuck at constraining Stirrups, how you compare the RebarConstraint.GetDistanceToTargetCover().

can you explain me in detail. I also attached my forum post below.

jeremy also answered for my post, He told me to see this conversation.

 

My Forum Post link

https://forums.autodesk.com/t5/revit-api-forum/rebar-location-controlling/m-p/10903636/highlight/tru... 

 

Message 16 of 18
kevin.anggrek
in reply to: arshad.k

Hi @arshad.k ,

 

First of all, I would like to apologize for not reaching back to you as soon as your comment was up. Two weeks ago, I was busy at work and then Chinese New Year came, so we all had a week of holiday here in Taiwan, I ended up travelling with my peers so I didn't have any chance to reach back to you.

 

Anyway, I will try to explain how I constrain the stirrups to the concrete cover.

 

First, I use the CreateFromRebarShape method to create an initial stirrup by using a template rebar shape that is provided by Revit. As you probably have noticed, the initial stirrup follows the size of the template rebar shape and we need to constrain it down to the appropriate size that matches the size of our concrete element.

 

So the next thing that we need to do is to call the RebarConstraintManager of the particular initial stirrup in order to access and modify the rebar constraints of the initial stirrup.

 

By using the RebarConstraintManager, I would first collect all of the handles of the stirrup by using the GetAllHandles() Method and stores them inside a list or array. Handles are those interaction points located on the rebar element that one normally uses when trying to modify the shape or size of the rebar through the user interface of Revit.

 

The logic here is that I would like to move the handles of the stirrup, especially the handles at the legs of the stirrup, so that they can be moved or constrained to the correct concrete cover of our current beam/column element, thus we can obtain the correct stirrup size.

 

So, the next thing we should do is to iterate through all of the handle in the list of handles that we obtained previously. For each handle, Find all of the constraint candidates that are of the type ToCover using the GetConstraintCandidatesForHandle() Method. Rebar handles can be constrained to a lot of things, but what we want here are the ToCover constraints because we want to constraint a particular handle to the concrete cover. You can imagine each ToCover constraint as a representation of the handles' constraint to a concrete cover. By following this method, a single handle will detect several ToCover constraints. Now, Imagine that you are editing a rebar handle of one stirrup leg, notice that a rectangular column would have eight concrete cover that the leg handle can be constrained to. However, the leg handle shall only be constrained to the correct concrete cover, which in this case is the cover that is closest to the particular leg handle. This is where the GetDistanceToTargetCover plays a role.

 

But before we get into that, there is something that you need to be careful of, when trying to find all of the ToCover constraint of a particular handle, Revit API will also detect not only the concrete cover of a particular concrete element, but also all of the ToCover constraints of other concrete element in the periphery of the stirrup. Therefore, it is necessary that you first make sure that the ToCover constraint that you are targeting is the same as the concrete element that you will use as the host of your stirrup. In my case, I first checked for the ElementId of the target element of the ToCover constraint and compared it with the ElementId of my host concrete element. If you are not careful, your handle will end up getting constrained to the cover of other adjacent concrete element instead of the intended concrete element.

 

After you have cleared that, we can safely move on to find the nearest ToCover constraint that we are going to constrain our handle to. I used the GetDistanceToTargetCover() method, this method finds the distance between the current ToCover constraint of the handle to the target cover. Then find the one with absolute minimum distance. When I said absolute, I mean that you first need to find the absolute value of the distance before comparing it to the other distance to find the actual minimum distance. This was actually my issue before, where the handle won't be constrained to the nearest cover. Turns out, my code previously compared non-absolute values. After I debugged the code, I noticed something like: the distance to the nearest cover was 10 but distance to the farthest cover was -400, if we compare non-absolute values, -400 is less than 10 but the absolute value is the true indicator of the distance to the cover. So if we compare the absolute values, it is obvious that 400 is greater than 10.

 

After we find the nearest cover constraint to the handle, we can go ahead and move the constraint of the handle to the cover itself by using the SetDistanceToTargetCover() method and setting the distance as 0. After the constraint of the handle has been moved to its cover, we can then go ahead and set the constraint as the preferred constraint for the handle by using the SetPreferredConstraintForHandle() method, this will set the constraint that we just moved to the cover as the preferred constraint that the handle will use. At the end, this will move the handle to the cover.

 

I hope my explanations are clear. If you have further questions, don't hesitate to continue this discussion, I am willing to help.

 

 

Message 17 of 18

 Hi @kevin.anggrek 

 I have same problem with you but i can't solve.

 My post here, can you help me ?

 Many thanks !

https://forums.autodesk.com/t5/revit-api-forum/edit-start-end-of-constraint-rebar-stirrupt/td-p/1095...

Message 18 of 18
arshad.k
in reply to: kevin.anggrek

 Hi @kevin.anggrek 

Thank you for your detailed explanation, I will go through this and fix my issue....

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Rail Community