API Constraint management

API Constraint management

jose_prieto
Participant Participant
3,362 Views
12 Replies
Message 1 of 13

API Constraint management

jose_prieto
Participant
Participant

Hello all,

 

I am trying to create a simple family with some defined constraints, however I don't get the same results like doing the process manually in Revit interface.

 

Here is the code:

 

  private void CreateContents()
  {
   var view = m_context.GetView();
   var width = 1000.0;
   // step 0, create parameters
   var parameterWidth = m_context.Document.FamilyManager.AddParameter("Width", BuiltInParameterGroup.INVALID, ParameterType.Length, true);
   var parameterAlpha = m_context.Document.FamilyManager.AddParameter("Alpha", BuiltInParameterGroup.INVALID, ParameterType.Angle, true);
 
   Trace.TraceInformation("Parameter Width " + parameterWidth.Id);
   Trace.TraceInformation("Parameter Alpha " + parameterAlpha.Id);
 
   // step 1, create reference plane
   var bubbleEnd = new XYZ(width, width, 0);
   var freeEnd = new XYZ(-width/2, width, 0);
   var widthReferencePlane = m_context.Factory.NewReferencePlane(Conversion.ToImperial(bubbleEnd), Conversion.ToImperial(freeEnd), XYZ.BasisZ, view);
   widthReferencePlane.Name = "OuterAxis";
 
   // step 2, create cut line
   var cutA = XYZ.Zero;
   var cutB = new XYZ(width, width, 0);
   var cutLine = Line.CreateBound(Conversion.ToImperial(cutA), Conversion.ToImperial(cutB));
   var cutReferenceLine = m_context.Factory.NewModelCurve(cutLine, m_context.SketchPlane) as ModelLine;
   if (cutReferenceLine == null)
    return;
   cutReferenceLine.ChangeToReferenceLine();
 
   m_context.Document.Regenerate();
 
   // paso 3, get generic family Reference Planes
   var horzReferencePlane = m_context.GetElement<ReferencePlane>(@"Center (Front/Back)");
   var vertReferencePlane = m_context.GetElement<ReferencePlane>(@"Center (Left/Right)");
 
   if (horzReferencePlane == null || vertReferencePlane == null)
    return;
 
   // step 4: get references
 
   var axis = horzReferencePlane.GetReference();
   var side = vertReferencePlane.GetReference();
   var thickness = widthReferencePlane.GetReference();
 
   var cut = cutReferenceLine.GeometryCurve.Reference;
   var start = cutReferenceLine.GeometryCurve.GetEndPointReference(0);
   var end = cutReferenceLine.GeometryCurve.GetEndPointReference(1);
 
   // step 7, create constraints
   var constraint1 = m_context.Factory.NewAlignment(view, axis, start);
   var constraint2 = m_context.Factory.NewAlignment(view, side, start);
   var constraint3 = m_context.Factory.NewAlignment(view, thickness, end);
 
   Trace.TraceInformation("Contraint axis_start " + constraint1.Id);
   Trace.TraceInformation("Contraint side_start " + constraint2.Id);
   Trace.TraceInformation("Contraint thickness_end " + constraint3.Id);
 
   // step 8, create thickness dimension
   var thicknessA = new XYZ(-width/2.0,0,0);
   var thicknessB = new XYZ(-width/2.0, width, 0);
   var thicknessLine = Line.CreateBound(Conversion.ToImperial(thicknessA), Conversion.ToImperial(thicknessB));
   var references = new ReferenceArray();
   references.Append(axis);
   references.Append(thickness);
 
   var thicknessDimension = m_context.Factory.NewLinearDimension(view, thicknessLine, references);
   if (thicknessDimension == null)
    return;
   thicknessDimension.FamilyLabel = parameterWidth;
 
   Trace.TraceInformation("Thickness Dimension " + thicknessDimension.Id);
 

   // step 8, create angular dimension
   var plane = new Plane(XYZ.BasisZ, XYZ.Zero);
   var arc = Arc.Create(plane, Conversion.ToImperial(width), 0, Math.PI/4.0);
 
   m_context.Document.Regenerate();
 
   var angularDimension = m_context.Factory.NewAngularDimension(view, arc, cut, axis);
   Trace.TraceInformation("Angular Dimension " + angularDimension.Id);
 
   m_context.Document.Regenerate();
 
   angularDimension.FamilyLabel = parameterAlpha;
  }
 
When I edit the family created by this code and remove the angular dimenions then recreate it, it works fine, but with the dimension created through the API I get a "Constraint not satisfied" message.
 
Somehow I suspect about some interaction between the undefined parameter value and the arc creation process, but I am stuck after trying several combinations.
 
 
In the attachment I place the full source code, the created family, and the created family, once fixed manually from the Revit interface.
 
José.
 
 
3,363 Views
12 Replies
Replies (12)
Message 2 of 13

jeremytammik
Autodesk
Autodesk

Dear José,

 

Thank you for your query and sample code.

 

I would love to dive in and try to help you debug this, but I am sorry to say I do not have the time.

 

You will have to continue exloring it yourself.

 

All I can suggest is to keep at it.

 

One approach to debugging a problem like this is:

 

  1. Simplify it down to something absolutly trivial and stupid that is guaranteed to work -- dumb it down.
  2. Once that is working, add the required complications one by one until it either works completely or fails.

 

Once you have determined the exact point of failure, you can narrow that down further and create a minimal reproducible case:

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b

 

With the minimal reproducible case in hand, I can either take a look myself of pass it on to the Revit development team for furhter analysis.

 

I hope this helps.

 

Best regards,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Message 3 of 13

jose_prieto
Participant
Participant

Dear Jeremy,

 

Thanks for your nice reaction.

 

My current target is to model profile extrusions with start and end cut angles. The test case is only defining the geometry scenario for one end, having as parameters profile thickess and cut angle (alpha).

 

In my original scenario I am dealing with the full problem, considering initial and end cut angle and producing sweeps and void sweeps. Everything works fine but flexing it!

 

I have already removed all the code creating the solid, and restricted the problem to one of both ends, in my opinion, to the minumum primitives. I have proven all kind of combinations and for a couple of times refactored completely the approach, no success.

 

I start from a generic model template, then add a reference plane for profile thickness and a model line for cut direction. the aim is to be able to flex this family changing the thickness and the cut angle. I need to add a linear dimension to be linked to the thickness parameter and an angular dimension to be associated to the cut angle paramenter (alpha).

 

I have created a solution after your guidelines, I attach it now. I only use a couple of helper classes, one for unit conversion and one for holding the "revit context" objects, it makes the code more readable in my opinion but if you'd like so I can get rid off them. The context class has a helper method to find Reference Planes by name.

 

in the attached screencast I show how to change the family which has been produced by my code in order to fix it, still I need the "API way" to do the same.

 

in the solution .rar file there is a folder called "families", revit_constraints.rfa is the file created by the command whereas revit_contraints_aim.rfa is the same file modified from Revit so it flexes correctly. This edition process is shown in the screencast.

 

My current diagnostic:

 

Mostly for some reason the angular dimension is incorrectly created and do not allows flexing through the "alpha" parameter. To make it work it has to be destroyed from Revit, then re-created and re-associated to the alpha parameter.

 

I suppose that the critical code is in this last step (sorry for the two regenerates, is a result of my growing paranoia)

 

   // step 8, create angular dimension
   var plane = new Plane(XYZ.BasisZ, XYZ.Zero);
   var arc = Arc.Create(plane, Conversion.ToImperial(width), 0, Math.PI / 4.0);
 
   m_context.Document.Regenerate();
 
   var angularDimension = m_context.Factory.NewAngularDimension(view, arc, cut, axis);
   Trace.TraceInformation("Angular Dimension " + angularDimension.Id);
 
   m_context.Document.Regenerate();
 
   angularDimension.FamilyLabel = parameterAlpha;

 

In fact it is already strange that the arc dimension is not following the given arch (in fact you can try to disable the last line above.

 

Please let me know if I can help further somehow.

 

José.

 

 

 

 

0 Likes
Message 4 of 13

jose_prieto
Participant
Participant

Finally I have managed to reduce the problem, I hope somebody can help me further now.

 

The code created a reference line from (0,0) to (1,1), then creates an angular dimension from the X axis to the reference line (45 degrees), and associates it to a previously created "alpha" parameter.

 

Below is the final code in a typical command.cs

 

The usage procedure is creating a family based on "Generic Model.rft" template, then invoking the command.

 

Changing the alpha parameter will not flex the family, causing a "constraint not satisfied" error.

 

Deleting the angular dimension, recreating it, and re-associating the alpha parameter to it will fix the model, allowing it to flex as expected.

 

#region Namespaces
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
#endregion
 
namespace RevitConstraints2
{
 

 [Transaction(TransactionMode.Manual)]
 public class Command : IExternalCommand
 {
  static public T GetElement<T>(string sName, Document doc) where T : Autodesk.Revit.DB.Element
  {
   var collector1 = new FilteredElementCollector(doc);
   var classFilter = new ElementClassFilter(typeof(T));
   var elements = collector1.WherePasses(classFilter).ToElements();
   return (from elt in elements let t = elt as T where t != null where elt.Name == sName select t).FirstOrDefault();
  }
 
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements)
  {
   UIApplication uiapp = commandData.Application;
   UIDocument uidoc = uiapp.ActiveUIDocument;
   Application app = uiapp.Application;
   Document doc = uidoc.Document;
 
   var view = doc.ActiveView;
   var familyCreate = doc.FamilyCreate;
 
   using (Transaction tx = new Transaction(doc))
   {
    tx.Start("Transaction Name");
    // step 1, create parameters
    var parameterAlpha = doc.FamilyManager.AddParameter("Alpha", BuiltInParameterGroup.INVALID, ParameterType.Angle, true);
 
    // step 2, create cut line
    var plane = new Plane(new XYZ(1, 0, 0), new XYZ(0, 1, 0), new XYZ(0, 0, 0));
    SketchPlane SketchPlane;
    SketchPlane = SketchPlane.Create(doc, plane);
    var cutA = XYZ.Zero;
    var cutB = new XYZ(1, 1, 0);
    var cutLine = Line.CreateBound(cutA, cutB);
    var cutReferenceLine = familyCreate.NewModelCurve(cutLine, SketchPlane) as ModelLine;
    cutReferenceLine.ChangeToReferenceLine();
    doc.Regenerate();
 
    // step 3, get generic family relevant default reference plane
    var horzReferencePlane = GetElement<ReferencePlane>(@"Center (Front/Back)", doc);
 
    // step 4 get references
    var axis = horzReferencePlane.GetReference();
    var cut = cutReferenceLine.GeometryCurve.Reference;
 
    // step 5, create angular dimension
    var arc = Arc.Create(plane, 1, 0, Math.PI / 4.0);
 
    doc.Regenerate();
    var angularDimension = familyCreate.NewAngularDimension(view, arc, cut, axis);
    Trace.TraceInformation("Angular Dimension " + angularDimension.Id);
    angularDimension.FamilyLabel = parameterAlpha;
 
    // Modify document within a transaction
    tx.Commit();
   }
 
   return Result.Succeeded;
  }
 }
}
 
 
 
0 Likes
Message 5 of 13

jose_prieto
Participant
Participant

I attach the solution corresponding to the minimal reproduction scenario.

0 Likes
Message 6 of 13

jeremytammik
Autodesk
Autodesk

Dear José,

 

Thank you for your updates, clean-up, new sample code, duplicate ADN case and private email to me.

 

I am now ready to raise an issue for the development team to explore this further.

 

Before doing so, however, I think there is one more part that we can clarify up front.

 

You say, "although I am an experienced programmer and CAD user/programmer, I miss fundamental concepts in the way to build Revit families for windows, especially how to build these families from our 3D models through the API."

 

I can fully understand that and am in exactly the same position as you.

 

In fact, so are probably many of the internal Revit developers as well.

 

Programming for Revit is really easy.

 

Using it in the proper manner, understanding the optimal workflows and honouring all the best practices is a completely different matter.

 

In order to achieve that, you either need to take some heavy-duty end user training yourself, or consult with expert users and application engineers.

 

I cannot help you with that at all.

 

The Building Coder does provide a teeny weeny little bit of guidance in that area.

 

Please take a look at the topic group on the Family API for Creating Family Definitions:

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#5.25.1

 

It includes a post on the Key Concepts of the Family Editor.

 

That provides the absolute minimum that you need to know to get started defining your won families, but there is infinitely more as you get into advanced and complex content creation areas.

 

Can you please confirm that you have read and understood those discussions?

 

Have you consulted with users and application engineers on your family structures from an end user point of view before starting to even think about automating the family creation?

 

If so, then we can move on to the next step, which I would suggest to be:

 

Please clean up the various posts above into one single minimal reproducible case again, since I am not sure which of the initial descriptions still apply and which do not.

 

I need something short and succinct to present to the development team for deeper analysis:

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b

 

I am very sorry to continue pestering you for this minimal reproducible case, and I understand that you have already invested a lot of effort in describing the issue and reducing it to something simple.

 

Still I hope that you understand the importance of making the problem description short, simple and sweet for potentially quite a number of people on the development team to understand quickly, easily and unequivocally what is going on.

 

And of course it should be clear and they should be convinced that your really are doing the right thing in the first place, i.e. that your family definitions really make sense. 🙂

 

I also hope that the final clean-up should be very easy. If all is already good, you just need to summarise everything you said before into one single text and tell me to ignore everything above.

 

Thank you very much for your understanding and perseverance!

 

I hope this helps.

 

Best regards,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 7 of 13

jose_prieto
Participant
Participant

Thanks Jeremy,

 

Just to report that based on this thread you have created a case for Revit API Team, REVIT-86315 [API versus manual difference defining angular dimension constraint in family -- 11486046]

 

I just guess if there is a time range for geting a reaction, in order to decide next steps in my project.

 

José

0 Likes
Message 8 of 13

jeremytammik
Autodesk
Autodesk

Dear José,

 

Thank you for your update.

 

Yes, indeed, I do have a reaction from the development team.

 

They took a look at the issue I raised for you, REVIT-86315 [API versus manual difference defining angular dimension constraint in family -- 11486046].

 

They conclude that a code fix is needed.

 

Since development for the upcoming next major release of Revit is already complete, they raised a new code fix issue REVIT-87238 [API versus manual difference defining angular dimension constraint in family -- 11486046] for the future development.

 

Please make a note of this new number as well for future reference.

 

Unfortunately, as you can imagine, it will be a while before that fix makes it into a released product.

 

I will ask them whether the code fix can also be retrofitted into an update release of the next major release of Revit so that you can enjoy its benefits somewhat sooner.

 

Let's keep our fingers crossed that that is possible.

 

Providing a good business case for this request will help underline its importance:

 

This issue is important to me. What can I do to help?

 

This issue needs to be assessed by our engineering team, and prioritised against all of the other outstanding change requests. Any information that you can provide to influence this assessment will help. Please provide the following where possible:

 

  • Impact on your application and/or your development.
  • The number of users affected.
  • The potential revenue impact to you.
  • The potential revenue impact to Autodesk.
  • Realistic timescale over which a fix would help you.
  • In the case of a request for a new feature or a feature enhancement, please also provide detailed Use cases for the workflows that this change would address.

 

This information is extremely important. Our engineering team have limited resources, and so must focus their efforts on the highest impact items. We do understand that this will cause you delays and affect your development planning, and we appreciate your cooperation and patience.

 

I hope this helps.

 

Best regards,

 

Jeremy



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 9 of 13

Anonymous
Not applicable

Jeremy,

 

is there any update on this issue. I have the same problem. Creating the angular dimension through the API the dimension shows up, but I get the constraint error message when changing the angle. Creating it in the UI allows to change the angle without any issues.

 

Working in 2018.2 - is this fixed?

 

Thanks

Christian

0 Likes
Message 10 of 13

mehdi.blanchard
Enthusiast
Enthusiast

This problem still occurs in Revit 2019.1

 

Very annoying as there is no workaround. The only solution I can think of now is to manually create a separate family with the angle rotation built in,  then build my additional geometry with the API in this separate family and then nest it into the original family. Very inconvenient.

0 Likes
Message 11 of 13

mehdi.blanchard
Enthusiast
Enthusiast

Hi Jeremy,

 

This problem still occurs in Revit 2019.1

 

Very annoying as there is no workaround. The only solution I can think of now is to manually create a separate family with the angle rotation built in,  then build my additional geometry with the API in this separate family and then nest it into the original family. 

0 Likes
Message 12 of 13

jeremy_tammik
Alumni
Alumni

Thank you Christian and Mehdi for your additional comments and thanks to all for your patience and endurance.

 

Very sorry that this issue still persists, now reported again in a new thread:

 

https://forums.autodesk.com/t5/revit-api-forum/angular-dimensions-in-family-document/m-p/9938047

 

I added all your comments to the development ticket REVIT-87238 [[API] [AngularDim] Versus manual difference defining angular dimension constraint in family -- 11486046] and hope that the developers will take a fresh look and address this asap.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 13 of 13

fernando.pavonC234G
Explorer
Explorer

Hi Jose,

Thanks for your useful contribution!

0 Likes