Create Beams from level

Create Beams from level

emaguilera
Contributor Contributor
688 Views
1 Reply
Message 1 of 2

Create Beams from level

emaguilera
Contributor
Contributor

Hi everyone!

I'm working with this plugin and I have a problem: when I want to set the "Level 2" for some reason, this is not set in the beam.

If there is any solution I would appreciate it.
Regards.

        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            Document doc = commandData.Application.ActiveUIDocument.Document;

            var cadLinkInstances = new FilteredElementCollector(doc)
                .OfClass(typeof(ImportInstance))
                .Cast<ImportInstance>()
                .ToList();

            if (!cadLinkInstances.Any())
            {
                message = "No se encontró ningún archivo CAD cargado.";
                return Result.Failed;
            }

            ImportInstance cadInstance = cadLinkInstances.First();

            Options geometryOptions = new Options { DetailLevel = ViewDetailLevel.Fine };
            GeometryElement geometryElement = cadInstance.get_Geometry(geometryOptions);

            List<Line> cadLines = new List<Line>();

            foreach (GeometryObject geometryObject in geometryElement)
            {
                if (geometryObject is GeometryInstance geometryInstance)
                {
                    GeometryElement symbolGeometry = geometryInstance.GetInstanceGeometry();
                    foreach (GeometryObject geomObj in symbolGeometry)
                    {
                        if (geomObj is Line line) 
                        {
                            cadLines.Add(line);
                        }
                        else if (geomObj is PolyLine polyline) 
                        {
                            IList<XYZ> points = polyline.GetCoordinates();
                            for (int i = 0; i < points.Count - 1; i++)
                            {
                                Line segment = Line.CreateBound(points[i], points[i + 1]);
                                cadLines.Add(segment);
                            }
                        }
                    }
                }
            }

            if (!cadLines.Any())
            {
                message = "No se encontraron líneas o polilíneas en el archivo CAD.";
                return Result.Failed;
            }

            Level level = new FilteredElementCollector(doc)
                .OfClass(typeof(Level))
                .Cast<Level>()
                .FirstOrDefault(l => l.Name == "Level 2");

            if (level == null)
            {
                message = "No se encontró el nivel 'Level 2'.";
                return Result.Failed;
            }

            using (Transaction trans = new Transaction(doc, "Crear vigas desde CAD"))
            {
                trans.Start();

                FamilySymbol beamType = new FilteredElementCollector(doc)
                    .OfClass(typeof(FamilySymbol))
                    .OfCategory(BuiltInCategory.OST_StructuralFraming)
                    .Cast<FamilySymbol>()
                    .FirstOrDefault(fs => fs.FamilyName == "VIGA Hº Aº");

                if (beamType == null)
                {
                    message = "No se encontró la familia 'VIGA Hº Aº'.";
                    return Result.Failed;
                }

                if (!beamType.IsActive)
                {
                    beamType.Activate();
                    doc.Regenerate();
                }

                foreach (Line line in cadLines)
                {
                    FamilyInstance beam = doc.Create.NewFamilyInstance(
                        line,
                        beamType,
                        level,
                        StructuralType.Beam);

                    LocationCurve locationCurve = beam.Location as LocationCurve;
                    if (locationCurve != null)
                    {
                        locationCurve.Curve = line; 
                    }
                }

                trans.Commit();
            }

            return Result.Succeeded;
        }
    }

 

0 Likes
689 Views
1 Reply
  • Beam
Reply (1)
Message 2 of 2

jeremy_tammik
Alumni
Alumni

It looks as if you are using an inappropriate overload of NewFamilyInstance:

 

https://www.revitapidocs.com/2024/451ee414-cea0-e9bd-227b-c73bc93507dd.htm

 

The only overload that I see taking a line as first argument only expects three arguments. 

 

I asked Gemini for a solution for you, and it replied:

Inserting a Beam Between Two Points in Revit using the API

This is a common task in Revit add-in development. Here's a comprehensive guide on how to insert a beam between two points using the Revit API, drawing on best practices and insights from The Building Coder and other resources.

Understanding the Process

Inserting a beam involves these key steps:

  1. Define the Beam's Geometry: This is done by creating a Line object representing the beam's centerline.
  2. Select a Beam Family Symbol: You need a valid FamilySymbol representing the beam type to be inserted.
  3. Create the Beam Instance: Use the Document.Create.NewFamilyInstance method to create the beam in the Revit model.

Code Example (C#)

C#
 
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;

namespace RevitAddin
{
    [Transaction(TransactionMode.Manual)]
    public class InsertBeam : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Document doc = uidoc.Document;

            try
            {
                // 1. Get two points for the beam's centerline
                XYZ pt1 = uidoc.Selection.PickPoint("Select start point of beam");
                XYZ pt2 = uidoc.Selection.PickPoint("Select end point of beam");

                // 2. Create the line representing the beam's centerline
                Line beamLine = Line.CreateBound(pt1, pt2);

                // 3. Get a beam family symbol (you might want to add more robust symbol selection)
                FilteredElementCollector collector = new FilteredElementCollector(doc);
                collector.OfClass(typeof(FamilySymbol));
                collector.OfCategory(BuiltInCategory.OST_StructuralFraming); // Beams are in this category

                FamilySymbol beamSymbol = collector.FirstElement() as FamilySymbol;
                if (beamSymbol == null)
                {
                    message = "No beam family symbol found in the project.";
                    return Result.Failed;
                }

                                // Activate the symbol if it is not already active
                                if (!beamSymbol.IsActive)
                                {
                                        beamSymbol.Activate();
                                        doc.Regenerate();
                                }

                using (Transaction tx = new Transaction(doc))
                {
                    tx.Start("Insert Beam");

                                        // 4. Create the beam instance. Use the overload with StructuralType.Beam
                    FamilyInstance beamInstance = doc.Create.NewFamilyInstance(beamLine, beamSymbol, StructuralType.Beam);

                    tx.Commit();
                }

                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return Result.Failed;
            }
        }
    }
}

Key Improvements and Explanations:

  • Error Handling: The code includes a try-catch block to handle potential exceptions and provide more informative error messages.
  • Beam Family Symbol Selection: The code now uses a FilteredElementCollector to find a beam family symbol. This is more robust than hardcoding a specific symbol name. It also checks if the symbol is active and activates it if not. This prevents errors if the symbol is loaded but not active in the project.
  • Structural Type: The NewFamilyInstance overload with the StructuralType.Beam parameter is used. This is crucial for creating actual structural beams, not just generic family instances.
  • Transaction: The beam creation is wrapped in a transaction, which is essential for proper Revit API usage.
  • Clearer Comments: The code is well-commented to explain each step.
  • User Interaction: Uses uidoc.Selection.PickPoint to allow the user to graphically select the start and end points of the beam.

Further Considerations:

  • More Robust Symbol Selection: You might want to provide a more sophisticated way for the user to select the beam type, such as a dialog box listing available beam families and types.
  • Level and Host Element: Consider specifying the level and host element for the beam if needed.
  • Beam Orientation: For more complex scenarios, you might need to control the beam's orientation using a XYZvector for the beam's up direction.
  • Handling Sloped Beams: For sloped beams, you'll need to create a 3D line and potentially use work planes.
  • The Building Coder: Refer to Jeremy Tammik's The Building Coder blog (thebuildingcoder.typepad.com) for more advanced examples and discussions on creating structural elements. Search for keywords like "NewFamilyInstance," "beam," and "structural."

This improved example provides a more complete and robust solution for inserting beams between two points in Revit using the API. Remember to adapt the code to your specific needs and always test thoroughly.

  

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