Share
 
 

The Contextual Analytical Model in the Revit API

Explore the newly developed API in the context of analytical modeling.

This project is part of a broader Analytical Driven Modeling initiative for Revit that introduces an innovative approach to analytical modeling, enhancing its overall structural modeling capabilities. The analytical model is an essential part of BIM data and is subject to collaborative workflows within engineering teams and across project teams, therefore Revit, with the new set of features and behaviors will enable engineers to:
  • Have freedom of analytical modeling to reflect their individual design decisions with respect to structural elements and buildings/structures seen as whole systems.
  • Analytically represent any types of structures.
  • Create consistent analytical models enabling structural analysis jobs from Revit models.
  • Perform full bi-directional workflow with analysis software and capture model modifications made there.
  • Preserve the analytical model from unexpected changes if needed.
  • Create multiple analytical models reflecting diverse analysis types and configurations.
  • Replicate the ease of analytical modeling like in dedicated structural analysis software, combined with the power of parametric and collaboration enabling BIM platform.

Revit Elements with a New API

New API Classes

AnalyticalElement - represents the base class for all analytical objects. It replaced AnaltyicalModel.

  •  Transform GetTransform () - Returns the transform which reflects Analytical Element orientation.
  •  AnalyzeAs AnalyzeAs - This represents the Analyze As parameter assigned to Analytical Element.
  •  Reference GetReference (AnalyticalModelSelector selector) - Returns a reference to a given curve within the Analytical Element.
  • ElementId MaterialId - Defines the Material Id for the Analytical Element.

AnalyticalMember - represents a linear element in the structural analytical model. It replaced AnalyticalModelStick and AnalyticalModelColumn.

  • AnalyticalMember Create(Document aDoc,Curve curve) - Method which creates a new instance of an Analytical Member within the project.
  • AnalyticalStructuralRole StructuralRole - The structural role assigned to the Analytical Member.
  • Curve GetCurve () - Returns the curve of the Analytical Member.
  • void SetCurve(Curve curve) - Sets the curve for the Analytical Member. This method disconnects elements from other analytical elements (if the end nodes are in the same position).


    If the user wants to move the corner, and keep the connection, there are other ways for achieving that such as ElementTransformUtils.moveElements.
  •  bool IsValidCurve(Curve curve) - Verifies if the curve is valid for an Analytical Member.
  •  void FlipCurve() - Flips the ends of the Analytical Member.
  • StructuralSectionShape StructuralSectionShape - The structural section shape of the Analytical Member (read only).
  •  ElementId SectionType - The id of the type from the structural family assigned to the Analytical Member.
  •  double CrossSectionRotation - Cross-section rotation of the Analytical Member.
AnalyticalPanel - represents a surface in the structural analytical model. It replaced AnalyticalModelSurface.
  • AnalyticalPanel Create(Document aDoc, CurveLoop curveLoop) - Method which creates a new instance of an Analytical Panel within the project.
  • CurveLoop GetOuterContour() - Returns the Curve Loop that defines the geometry of the Analytical Surface element.
  • bool IsCurveLoopValid(CurveLoop profile) - Checks if curve loop is valid for Analytical Panel.
    • To modify Analytical Panel geometry, users should use SketchEditScope framework. This was enhanced with a new method:
      •  void StartWithNewSketch(ElementId elementId) - Starts a sketch edit mode for an element which, at this moment, doesn't have a sketch.
    • Another way of editing geometry is:
      • void SetOuterContour(CurveLoop outerContour) - Sets the Curve Loop that defines the geometry of the Analytical Surface element.


      • Like for AnalyticalMember, setting the contour for analytical panel will break the connection with other analytical elements. If the user wants to move the corner, and keep the connection, there are other ways for achieving that like ElementTransformUtils.moveElements.

  •  ISet<ElementId> GetAnalyticalOpeningsIds() - Returns the Analytical Openings Ids of the Analytical Panel.
  • ElementId SketchId - Sketch associated to this Revit element.
    
  • AnalyticalStructuralRole StructuralRole - Structural role assigned to the Analytical Panel.
AnalyticalOpening - an element which represents an opening in an Analytical Panel. This is a new object in the Revit API (prior to this version, there was no separate element for analytical openings).
  • AnalyticalOpening Create(Document doc, CurveLoop curveLoop, ElementId panelId) - Method which creates a new instance of an Analytical Opening within the project.
  • CurveLoop GetOuterContour () - Returns the Curve Loop that defines the geometry of the Analytical Surface element.
    
  •  bool IsCurveLoopValidForAnalyticalOpening(CurveLoop loop, Document aDoc, ElementId panelId) - Checks if curve loop is valid for Analytical Opening.
    • To modify Analytical Opening geometry, use SketchEditScope framework.
    • Another way to modify Analytical Opening geometry is:
      •  void SetOuterContour(CurveLoop outerContour) - Sets the Curve Loop that defines the geometry of the Analytical Surface element.
  • ElementId PanelId - ElementId of the host Analytical Panel.
    
  •  ElementId SketchId - Sketch associated to this Revit element.

AnalyticalToPhysicalAssociationManager - manages the associations between analytical and physical elements. Previously, the elements themselves knew about one another and the user had no control over them(the association could not be modified). With this new approach, the association can be edited. 1-1 association is supported and elements cannot be part of multiple associations at the same time.

  •  AnalyticalToPhysicalAssociationManager GetAnalyticalToPhysicalAssociationManager(Document doc) Returns the AnalyticalToPhysicalAssociationManager for this
    document.
  • void AddAssociation(ElementId analyticalElementId, ElementId physicalElementId) - Adds a new association between an analytical element and a physical element.
  •  void RemoveAssociation(ElementId elementId) - This method will remove the association for the element with the given ElementId.
  •  ElementId GetAssociatedElementId (ElementId elementId) - Returns id of the element which is associated with the given ElementId.
  •  bool HasAssociation(ElementId id) - Verifies if the element has already defined an association.
AnalyticalNodeData - holds information about connection status of analytical nodes.
  • AnalyticalNodeData GetAnalyticalNodeData ( Element element) - Returns AnalyticalNodeData associated with this element, if it exists.
    
  • AnalyticalNodeConnectionStatus GetConnectionStatus () - Returns the Connections Status for an
    Analytical Node.

AnalyticalLinks, BoundaryConditions and Loads were migrated to work with the new elements. The API related to them remains in most cases the same. Some enhancements were made for Loads.

Loads
  •  LineLoad.Create(Document aDoc,ElementId hostElemId, XYZ forceVector1, XYZmomentVector1, LineLoadType symbol).
  •  LineLoad.Create(Document aDoc,ElementId hostElemId, int curveIndex, XYZ forceVector1, XYZ momentVector1, Structure.LineLoadType symbol).
  •  LineLoad.IsValidHostId(Document doc, ElementId hostElemId).
  •  AreaLoad.IsValidHostId(Document doc, ElementId hostElemId).
  •  AreaLoad.Create(Document doc, ElementId hostElemId, XYZ forceVector1, AreaLoadType symbol).
  •  PointLoad.Create(Document doc, ElementId hostElemId, AnalyticalElementSelector selector, XYZ forceVector, XYZ momentVector, AreaLoadTyp 
    symbol).
  • PointLoad.IsValidHostId(Document doc, ElementId hostElemId).

Samples

Creation of an AnalyticalMember

      using (Transaction transaction = new Transaction(document, "Create Analytical Member"))
               {
                  transaction.Start();
                  //create curve which will be assigned to the analytical member
                  Line line = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(5, 0, 0));
                  //create the AnalyticalMember
                  AnalyticalMember analyticalMember = AnalyticalMember.Create(document, line);
                  analyticalMember.StructuralRole = AnalyticalStructuralRole.StructuralRoleBeam;
                  transaction.Commit();
                }

Creation of an Analytical Panel

 using (Transaction transaction = new Transaction(revitDoc, "Create Analytical Panel"))
         {
            transaction.Start();
            //create the curveLoop for the AnalyticalPanel element
            CurveLoop profileloop = new CurveLoop();
            profileloop.Append(Line.CreateBound(new XYZ(1, 1, 0), new XYZ(2, 1, 0)));
            profileloop.Append(Line.CreateBound(new XYZ(2, 1, 0), new XYZ(2, 2, 0)));
            profileloop.Append(Line.CreateBound(new XYZ(2, 2, 0), new XYZ(1, 2, 0)));
            profileloop.Append(Line.CreateBound(new XYZ(1, 2, 0), new XYZ(1, 1, 0)));
            //create the AnalyticalPanel 
            analyticalPanel = AnalyticalPanel .Create(revitDoc, profileloop);
            transaction.Commit();
          }

Add new association between a physical and an analytical element

using (Transaction trans = new Transaction(doc, "AddAssociationBetweenPhysicalAndAnalyticalElements"))
 {
            trans.Start();
            ElementId analyticalElementId = ContextualAnalyticalModel.Utilities.GetSelectedObject(activeDoc, "Please select analytical element");
            ElementId physicalElementId = ContextualAnalyticalModel.Utilities.GetSelectedObject(activeDoc, "Please select physical element");
            //gets the AnalyticalToPhysicalAssociationManager for the current document
            AnalyticalToPhysicalAssociationManager analyticalToPhysicalManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager(doc);
            if (analyticalToPhysicalManager == null)
               return Result.Failed;
            //creates a new association between physical and analytical elements
            analyticalToPhysicalManager.AddAssociation(analyticalElementId, physicalElementId);
            trans.Commit();
  }

Edit boundary for an analytical panel using SketchEditScope framework



             // Start a sketch edit scope
             SketchEditScope sketchEditScope = new SketchEditScope(document, "Replace line with an arc");
               sketchEditScope.StartWithNewSketch(analyticalPanel.Id);
               using (Transaction transaction = new Transaction(document, "Modify sketch"))
               {
                  transaction.Start();
                  //replace a boundary line with an arc
                  Line line = null;
                  Sketch sketch = document.GetElement(analyticalPanel.SketchId) as Sketch;
                  if (sketch != null)
                  {
                     //find first line in the sketch profile
                    …..
                  }
  	              // Create arc
                  XYZ normal = line.Direction.CrossProduct(XYZ.BasisZ).Normalize().Negate();
                  XYZ middle = line.GetEndPoint(0).Add(line.Direction.Multiply(line.Length / 2));
                  Curve arc = Arc.Create(line.GetEndPoint(0), line.GetEndPoint(1), middle.Add(normal.Multiply(20)));
                  // Remove element referenced by the found line. 
                  document.Delete(line.Reference.ElementId);
                  // Model curve creation automatically puts the curve into the sketch, if sketch edit scope is running.
                  document.Create.NewModelCurve(arc, sketch.SketchPlane);
                  transaction.Commit();
               }
               sketchEditScope.Commit(new FailurePreproccessor());

Move an analytical node and keep connection



            // Create Analytical Panel
            AnalyticalPanel analyticalPanel = CreateAnalyticalPanel.CreateAMPanel(document);
            // Create the connected Analytical Member
            AnalyticalMember analyticalMember = CreateAnalyticalMember.CreateMember(document);
            // Select the node
            Reference eRef = activeDoc.Selection.PickObject(ObjectType.PointOnElement , "Select an Analytical Node");
          
            // Move the Analytical Node using ElementTransformUtils
            using (Transaction transaction = new Transaction(document, "Move node with ElementTransformUtils"))
            {
               transaction.Start();
               ElementTransformUtils.MoveElement(document, eRef.ElementId, new XYZ(-5, -5, 0));
               transaction.Commit();
            }

Get analytical surface contour points

With the previous solution:
    
      private List<XYZ> GetSurfaceContourPoints( Document doc, ElementId elementId )
      {
         	// Create point list, get list of curves from analytical model
         	List<XYZ> contourPoints = new List<XYZ>();
         	AnalyticalModel analyticalModel = (doc.GetElement(elementId) as AnalyticalModel);
         	IList<Curve> curves = analyticalModel.GetCurves(AnalyticalCurveType.RawCurves);
         
         	// Iterate over curves and make the desired processing   
         …...	
        	return contourPoints;
      }
With the new solution:
     
      private List<XYZ> GetSurfaceContourPoints( Document doc, ElementId elementId )
      {
         	// Create point list, get list of curves from analytical model
         	List<XYZ> contourPoints = new List<XYZ>();
         	AnalyticalPanel analyticalPanel = (doc.GetElement(elementId) as AnalyticalPanel);
          CurveLoop outerContour = analyticalPanel.GetOuterContour();
         
         	// Iterate over curves and make the desired processing 
          …...	
        	return contourPoints;
      }

Gets the associated analytical element for a physical one

     
      AnalyticalElement GetAnalyticalElement(Element physicalElement)
      {
         AnalyticalElement analyticalElement = null;
         Document document = element.Document;
         AnalyticalToPhysicalAssociationManager assocManager = AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager(document);
         if (assocManager != null)
         {
            ElementId associatedElementId = assocManager.GetAssociatedElementId(physicalElement.Id);
            if (associatedElementId != ElementId.InvalidElementId)
            {
               Element associatedElement = document.GetElement(associatedElementId);
               if (associatedElement != null && associatedElement is AnalyticalElement)
               {
                  analyticalElement = associatedElement as AnalyticalElement;
               }
            }
         }
         return analyticalElement;
      }

Create line boundary conditions

With the previous solution:

       
        private BoundaryConditions CreateLineBC(Element hostElement)
        {
										    Document createDoc = hostElement.Document.Create;
 
             	// use Document.NewLineBoundaryConditions Method
              BoundaryConditions createdBC = 
                    createDoc.NewLineBoundaryConditions(hostElement.GetAnalyticalModel(), 0, 0, 0, 0, 0, 0, 0, 0);
 
            return createdBC;
        }

With the new solution:

      private BoundaryConditions CreateLineBC(Element hostElement)
      {
         Document createDoc = hostElement.Document.Create;

         // use Document.NewLineBoundaryConditions Method
         AnalyticalElement analyticalElement = GetAnalyticalElement(hostElement);
         BoundaryConditions createdBC =
                    createDoc.NewLineBoundaryConditions(analyticalElement, 0, 0, 0, 0, 0, 0, 0, 0);
         return createdBC;
      }

Was this information helpful?