Auto Join Beam and Wall without warnings

Auto Join Beam and Wall without warnings

Arciviz
Advocate Advocate
623 Views
8 Replies
Message 1 of 9

Auto Join Beam and Wall without warnings

Arciviz
Advocate
Advocate

I am getting very very slow in performance. I feel I made a mistake. How to optimize the code to active the performance. 

 

https://prnt.sc/DJuYEfg8Pq5w

https://prnt.sc/SfgVcbUU_zsa

 

 

 

#region Namespaces
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
#endregion

namespace Auto_Join_V3
{
  [Transaction(TransactionMode.Manual)]
  public class Command : IExternalCommand
  {
    public static int transactionCount = 0;
    public static bool accept;
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
      try
      {
        UIApplication uiapp = commandData.Application;
        UIDocument uidoc = uiapp.ActiveUIDocument;
        // Application app = uiapp.Application;
        Document doc = uidoc.Document;
        accept = false;
        Autojoin_form form = new Autojoin_form();
        form.ShowDialog();
        if (accept)
        {
          SelectElementsToJoin(uidoc, doc);
        }
        return Result.Succeeded;
      }
      catch (Exception ex)
      {
        message = ex.ToString();
        return Result.Failed;
      }
    }
    static void SelectElementsToJoin(UIDocument uidoc, Document doc)
    {
      // FilteredElementCollector - First Beam Element
      if (Autojoin_form.CurrentElementSelection == ElementSelection.Beam_Wall)
      {
        var collFirstBeamElement = GetElementCollect(doc).OfClass(typeof(FamilyInstance))
             .OfCategory(BuiltInCategory.OST_StructuralFraming);
        // Join With Beam
        foreach (var beam in collFirstBeamElement)
        {
          BoundingBoxXYZ beamBoundingBox = beam.get_BoundingBox(doc.ActiveView);
          Outline beamOutline = new Outline(beamBoundingBox.Min, beamBoundingBox.Max);
          BoundingBoxIntersectsFilter beamBBFilter = new BoundingBoxIntersectsFilter(beamOutline);
          //  Wall Selection and Join With Beams
          if (Autojoin_form.CurrentElementSelection == ElementSelection.Beam_Floor_Wall ||
                Autojoin_form.CurrentElementSelection == ElementSelection.Beam_Wall)
          {
            FilteredElementCollector collWalls = GetElementCollect(doc).OfClass(typeof(Wall));
            collWalls.WherePasses(beamBBFilter);
            //CollWalls.WherePasses(new ElementIntersectsElementFilter(beam));
            if (collWalls.GetElementCount() > 0)
            {
              Elementjoin(uidoc, doc, beam, collWalls, "Beam + Wall");
            }
          }
        }
      }
    }

    static void Elementjoin(UIDocument uidoc, Document doc,
      Element FirstElem,
      FilteredElementCollector Coll_of_Elems,
      string transactionText)
    {
      if (transactionText == null || transactionText == "")
      {
        transactionText = "AutoJoin V3";
      }

      foreach (Element elem in Coll_of_Elems)
      {
        if (JoinGeometryUtils.AreElementsJoined(doc, FirstElem, elem))
        {
          if (JoinGeometryUtils.IsCuttingElementInJoin(doc, elem, FirstElem))
          {
            JoinGeometryUtils.SwitchJoinOrder(doc, FirstElem, elem);
          }
        }
        else
        {
          transactionCount++;
          transactionText = transactionCount + ".  " + transactionText;
          using (Transaction t = new Transaction(doc, transactionText))
          {
            t.Start();
            FailureHandlingOptions options = t.GetFailureHandlingOptions();
            WarningDiscard preproccessor = new WarningDiscard();
            options.SetFailuresPreprocessor(preproccessor);
            options.SetClearAfterRollback(true);
            t.SetFailureHandlingOptions(options);
            try
            {
              bool check = JoinGeometryUtils.AreElementsJoined(doc, FirstElem, elem);

              if (check == false)
              {
                JoinGeometryUtils.JoinGeometry(doc, FirstElem, elem);
              }

              if (JoinGeometryUtils.IsCuttingElementInJoin(doc, elem, FirstElem))
              {
                JoinGeometryUtils.SwitchJoinOrder(doc, elem, FirstElem);
              }
            }
            catch { }
            t.Commit();
          }
        }
      }
    }
    static FilteredElementCollector GetElementCollect(Document doc)
    {
      if (Autojoin_form.CurrentViewSeclection == ViewSelection.Entire_Project)
      {
        return new FilteredElementCollector(doc);
      }
      else
      {
        return new FilteredElementCollector(doc, doc.ActiveView.Id);
      }
    }
  }

  public class WarningDiscard : IFailuresPreprocessor
  {
    FailureProcessingResult IFailuresPreprocessor.PreprocessFailures(FailuresAccessor failuresAccessor)
    {
      String transactionName = failuresAccessor.GetTransactionName();

      IList<FailureMessageAccessor> fmas = failuresAccessor.GetFailureMessages();

      if (fmas.Count == 0)
      {
        return FailureProcessingResult.Continue;
      }

      bool HasErrors = false;

      foreach (FailureMessageAccessor fma in fmas)
      {
        if (fma.GetFailureDefinitionId() == BuiltInFailures.ColumnInsideWallFailures.ColumnInsideWall
          || fma.GetFailureDefinitionId() == BuiltInFailures.JoinElementsFailures.JoiningDisjointWarn
          )
        {
          if (fma.HasResolutions())
          {
            failuresAccessor.DeleteWarning(fma);
            HasErrors = true;
          }
        }

      }
      if (HasErrors)
      {
        return FailureProcessingResult.ProceedWithRollBack;
      }

      return FailureProcessingResult.Continue;
    }
  }
}

 

 

 

regards,

Sudhan. 

0 Likes
Accepted solutions (2)
624 Views
8 Replies
Replies (8)
Message 2 of 9

jeremy_tammik
Alumni
Alumni

Afaict from your code, your are:

  

  for every single family instance
    creating a collection of all walls in the model
      and doing something

  

Assuming that you model contains 1000 family instances and 1000 walls, that will do something one million times. That might indeed take a while. I would suggest thinking through what you are doing in more depth and optimising your approach.

  

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

Arciviz
Advocate
Advocate

Dear Mr.Jeremy Tammik,

Yes, You are correct. I made a mistake. I have tried lot methods to get the proper solution, but no use. Can you hint the solution?

Regards,

Sudhan.

0 Likes
Message 4 of 9

jeremy_tammik
Alumni
Alumni
Accepted solution

Well, there are many possible improvements. The first that come to mind are:

   

  • Create one single filtered element collector for walls up front and use that single collection forever
  • Ditto for beams
  • Instead of checking whether elements are joined for each wall against each beam, N x M operations, perform a very quick test whether their bounding boxes intersect

   

If the two elements' bounding boxes are disjunct, the elements cannot be joined, so there is no need for further processing of that pair. 

  

Further optimisation is still possible and would make sense for large models, e.g., sorting the elements by X, Y and Z to significantly further reduce the number of pairs to process.

   

I hope this helps. We can happily continue discussing and optimising your code, if you like.

    

For serious optimisation tasks, it is important to measure performance. To do so, you can add some simple timers to your code to determine which operations are most costly. Nowadays, actually, the built-in profiling tools provided by the IDE are very powerful and may provide all the performance measurement functionality that you need just by activating them and looking at the results.

  

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

Arciviz
Advocate
Advocate

Dear Mr.Jeremy Tammik,

Thank you very much.

Regards,

Sudhan.

0 Likes
Message 6 of 9

Arciviz
Advocate
Advocate

Hello,

I have coded like below. But shows error 

Autodesk.Revit.Exceptions.InvalidOperationException: The iterator cannot proceed due to changes made to the Element table in Revit's database (typically, This can be the result of an Element deletion). at Autodesk.Revit.DB.FilteredElementIterator.MoveNext() at Auto_Join_V3.Command.SelectElementsToJoin(UIDocument uidoc, Document doc) at Auto_Join_V3.Command.Execute(ExternalCommandData commandData, String& message, ElementSet elements)

 

 

#region Namespaces
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System;
using System.Collections.Generic;
#endregion

namespace Auto_Join_V3
{
  [Transaction(TransactionMode.Manual)]
  public class Command : IExternalCommand
  {
    public static int transactionCount = 0;
    public static bool accept;
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
      try
      {
        UIApplication uiApp = commandData.Application;
        UIDocument uiDoc = uiApp.ActiveUIDocument;
        // Application app = uiapp.Application;
        Document doc = uiDoc.Document;
        accept = false;
        Autojoin_form form = new Autojoin_form();
        form.ShowDialog();
        if (accept)
        {
          SelectElementsToJoin(uiDoc, doc);
        }
        return Result.Succeeded;
      }
      catch (Exception ex)
      {
        message = ex.ToString();
        return Result.Failed;
      }
    }
    static void SelectElementsToJoin(UIDocument uidoc, Document doc)
    {
      // FilteredElementCollector - First Beam Element
      if (Autojoin_form.CurrentElementSelection == ElementSelection.Beam_Wall)
      {
        // Collect all walls
        FilteredElementCollector walls = new FilteredElementCollector(doc)
            .OfCategory(BuiltInCategory.OST_Walls)
            .WhereElementIsNotElementType();
        // Collect all structural framing elements (beams)
        FilteredElementCollector beams = new FilteredElementCollector(doc)
            .OfCategory(BuiltInCategory.OST_StructuralFraming)
            .WhereElementIsNotElementType();

        List<ElementId> intersectingBeamIds = new List<ElementId>();

        Reference r = uidoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element);
        Element wall = doc.GetElement(r);
        BoundingBoxXYZ wallBox = wall.get_BoundingBox(doc.ActiveView);
        Outline outline = new Outline(wallBox.Min, wallBox.Max);
        BoundingBoxIntersectsFilter filter = new BoundingBoxIntersectsFilter(outline);
        FilteredElementCollector intersectingBeams = beams.WherePasses(filter);

        foreach (Element beam in intersectingBeams)
        {
          if (!intersectingBeamIds.Contains(beam.Id))
          {
            intersectingBeamIds.Add(beam.Id);
            Elementjoin(uidoc, doc, beam,
              wall, "BEAM & WALL");
          }
        }

        TaskDialog.Show("Results", $"Found {intersectingBeamIds.Count} beams intersecting with walls.");

      }
    }
     static void Elementjoin(UIDocument uidoc, Document doc,
      Element firstElem,
      Element secondElem,
      string transactionText)
    {
      if (transactionText == null || transactionText == "")
      {
        transactionText = "AutoJoin V3";
      }
      if (JoinGeometryUtils.AreElementsJoined(doc, firstElem, secondElem))
      {
        if (JoinGeometryUtils.IsCuttingElementInJoin(doc, secondElem, firstElem))
        {
          JoinGeometryUtils.SwitchJoinOrder(doc, firstElem, secondElem);
        }
      }
      else
      {
        transactionCount++;
        transactionText = transactionCount + ".  " + transactionText;
        using (Transaction t = new Transaction(doc, transactionText))
        {
          t.Start();
          FailureHandlingOptions options = t.GetFailureHandlingOptions();
          WarningDiscard preproccessor = new WarningDiscard();
          options.SetFailuresPreprocessor(preproccessor);
          options.SetClearAfterRollback(true);
          t.SetFailureHandlingOptions(options);
          try
          {
            bool check = JoinGeometryUtils.AreElementsJoined(doc, firstElem, secondElem);

            if (check == false)
            {
              JoinGeometryUtils.JoinGeometry(doc, firstElem, secondElem);
            }

            if (JoinGeometryUtils.IsCuttingElementInJoin(doc, secondElem, firstElem))
            {
              JoinGeometryUtils.SwitchJoinOrder(doc, secondElem, firstElem);
            }
          }
          catch { }
          t.Commit();
        }
      }
    }
    static FilteredElementCollector GetElementCollect(Document doc)
    {
      if (Autojoin_form.CurrentViewSeclection == ViewSelection.Entire_Project)
      {
        return new FilteredElementCollector(doc);
      }
      else
      {
        return new FilteredElementCollector(doc, doc.ActiveView.Id);
      }
    }
  }

  public class WarningDiscard : IFailuresPreprocessor
  {
    FailureProcessingResult IFailuresPreprocessor.PreprocessFailures(FailuresAccessor failuresAccessor)
    {
      String transactionName = failuresAccessor.GetTransactionName();

      IList<FailureMessageAccessor> fmas = failuresAccessor.GetFailureMessages();

      if (fmas.Count == 0)
      {
        return FailureProcessingResult.Continue;
      }

      bool HasErrors = false;

      foreach (FailureMessageAccessor fma in fmas)
      {
        if (fma.GetFailureDefinitionId() == BuiltInFailures.ColumnInsideWallFailures.ColumnInsideWall
          || fma.GetFailureDefinitionId() == BuiltInFailures.JoinElementsFailures.JoiningDisjointWarn
          )
        {
          if (fma.HasResolutions())
          {
            failuresAccessor.DeleteWarning(fma);
            HasErrors = true;
          }
        }

      }
      if (HasErrors)
      {
        return FailureProcessingResult.ProceedWithRollBack;
      }

      return FailureProcessingResult.Continue;
    }
  }
}

Please help me to fix it.

Regards,

Sudhan.

0 Likes
Message 7 of 9

mhannonQ65N2
Collaborator
Collaborator
Accepted solution

That error message occurs because you are modifying the document while the FilteredElementCollector is still "running". To fix it, retrieve the results of the FilteredElementCollector before iterating over them. To do so, you can just replace this line: 

foreach (Element beam in intersectingBeams)

 with:

foreach (Element beam in intersectingBeams.ToElements())
Message 8 of 9

Arciviz
Advocate
Advocate

Thanks. Working. I found few errors in the program. beam is not joining in few cases.

0 Likes
Message 9 of 9

jeremy_tammik
Alumni
Alumni

Bravo! Fantastic. I am impressed how quickly and thoroughly you were able to enhance your code and put all the recommendations into practice! Exceptionally well done. 

   

Cheers and happy weekend,

  

Jeremy

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open