BIM World
A Professional BIM Learning Platform


Revit Custom Development: Designing a Continuous Rigid Frame Bridge with Horizontal and Vertical Curves

The previous method works well for straight, continuous rigid frame bridges. However, it falls short when applied to continuous rigid frame bridges with both horizontal and vertical curves. This limitation arises because each segment of such a bridge can be considered an irregular structure. Attempting to manually create a separate family for each segment is both time-consuming and inefficient. To address this, secondary development techniques are required.

First, it is essential to clarify the modeling goals and identify the necessary mathematical principles.

The desired outcomes are as follows:

1) The beam segment’s cross-section must be perpendicular to the horizontal curve of the route. This is crucial because many users model the bridge using spatial curves and adaptive component families, which often results in the cross-section being perpendicular to the spatial curve rather than strictly the horizontal curve.

2) To accommodate vertical curves, the cross-section must be adjusted vertically along the z-axis to the correct elevation.

3) To achieve these effects, the process begins by generating lines through the adaptive component family’s reference points, where each point represents the center of a beam section. The section family is then placed at each corresponding point and rotated so that it is perpendicular to the tangent vector at that point. Finally, the section is moved to the correct 3D position, and a Form structure is generated.

The following class demonstrates the specific implementation:

class CreatJM
{
    /// <summary>
    /// Creates the beam section family.
    /// </summary>
    /// <param name="familyDoc">The family document.</param>
    /// <param name="revitDoc">The Revit project document.</param>
    /// <param name="revitApp">The Revit application.</param>
    /// <param name="i">Index of the segment.</param>
    /// <param name="filePath1">File path for outer section family.</param>
    /// <param name="filePath2">File path for inner section family.</param>
    /// <returns>The loaded family instance.</returns>
    public Family CreatFamiliesItem(Document familyDoc, Document revitDoc, Application revitApp, int i, string filePath1, string filePath2)
    {
        FamilyInstance famIns1;
        FamilyInstance famIns2;
        FamilyInstance famIns3;
        FamilyInstance famIns4;

        Plane plane1 = new Plane();
        Plane plane2 = new Plane();

        using (Transaction transaction1 = new Transaction(familyDoc))
        {
            transaction1.Start("Create Reference Curves");

            #region Horizontal Curve
            ReferencePointArray refPointArray = new ReferencePointArray();
            for (int j = 0; j < ListData.ListXYZ_X.Count; j++)
            {
                ReferencePoint referencePoint = familyDoc.FamilyCreate.NewReferencePoint(new XYZ(ListData.ListXYZ_X[j], ListData.ListXYZ_Y[j], 0));
                refPointArray.Append(referencePoint);
            }
            CurveByPoints curve = familyDoc.FamilyCreate.NewCurveByPoints(refPointArray);
            #endregion

            #region Vertical Curve
            ReferencePointArray refPointArray2 = new ReferencePointArray();
            for (int j = 0; j < ListData.ListXYZ_X.Count; j++)
            {
                ReferencePoint referencePoint2 = familyDoc.FamilyCreate.NewReferencePoint(new XYZ(ListData.ListXYZ_X[j], ListData.ListXYZ_Y[j], ListData.ListXYZ_Z[j]));
                refPointArray2.Append(referencePoint2);
            }
            CurveByPoints curve2 = familyDoc.FamilyCreate.NewCurveByPoints(refPointArray2);
            #endregion

            famIns1 = LocationFamilyInstance(familyDoc, filePath1, curve2.GetPoints().get_Item(i).Position, (curve.GeometryCurve as HermiteSpline).Tangents[i], i);
            famIns2 = LocationFamilyInstance(familyDoc, filePath1, curve2.GetPoints().get_Item(i + 1).Position, (curve.GeometryCurve as HermiteSpline).Tangents[i + 1], i + 1);
            famIns3 = LocationFamilyInstance2(familyDoc, filePath2, curve2.GetPoints().get_Item(i).Position, (curve.GeometryCurve as HermiteSpline).Tangents[i], i);
            famIns4 = LocationFamilyInstance2(familyDoc, filePath2, curve2.GetPoints().get_Item(i + 1).Position, (curve.GeometryCurve as HermiteSpline).Tangents[i + 1], i + 1);

            plane1 = new Plane((curve.GeometryCurve as HermiteSpline).Tangents[i], curve.GetPoints().get_Item(i).Position);
            plane2 = new Plane((curve.GeometryCurve as HermiteSpline).Tangents[i + 1], curve.GetPoints().get_Item(i + 1).Position);

            familyDoc.Delete(curve.Id);
            familyDoc.Delete(curve2.Id);
            refPointArray.Clear();
            refPointArray2.Clear();

            transaction1.Commit();
        }

        using (Transaction transaction2 = new Transaction(familyDoc))
        {
            transaction2.Start("Generate Beam Form");

            ReferenceArray profiles0 = GetReferenceArrayFromFamilyInstance(familyDoc, famIns1, plane1);
            ReferenceArray profiles1 = GetReferenceArrayFromFamilyInstance(familyDoc, famIns2, plane2);

            ReferenceArray profiles2 = GetReferenceArrayFromFamilyInstance(familyDoc, famIns3, plane1);
            ReferenceArray profiles3 = GetReferenceArrayFromFamilyInstance(familyDoc, famIns4, plane2);

            ReferenceArrayArray profilesArray = new ReferenceArrayArray();
            profilesArray.Append(profiles0);
            profilesArray.Append(profiles1);
            Form form = familyDoc.FamilyCreate.NewLoftForm(true, profilesArray);

            ReferenceArrayArray profilesArray2 = new ReferenceArrayArray();
            profilesArray2.Append(profiles2);
            profilesArray2.Append(profiles3);
            Form form2 = familyDoc.FamilyCreate.NewLoftForm(false, profilesArray2);

            string paramName = "Material";
            familyDoc.FamilyManager.AddParameter(paramName, BuiltInParameterGroup.PG_MATERIALS, ParameterType.Material, true);

            transaction2.Commit();

            Family loadedFamily = familyDoc.LoadFamily(revitDoc, new ProjiectFamLoadOption());
            return loadedFamily;
        }
    }

    /// <summary>
    /// Retrieves the reference array for the beam section.
    /// </summary>
    /// <param name="familyDoc">Family document.</param>
    /// <param name="famIns">Family instance.</param>
    /// <param name="plane">Reference plane.</param>
    /// <returns>Reference array of the section curves.</returns>
    private ReferenceArray GetReferenceArrayFromFamilyInstance(Document familyDoc, FamilyInstance famIns, Plane plane)
    {
        ReferenceArray profilesArray = new ReferenceArray();
        Options opt = new Options();

        IList<Curve> curves1 = new List<Curve>();
        GeometryElement e = famIns.get_Geometry(opt);

        foreach (GeometryObject obj in e)
        {
            GeometryInstance geoInstance = obj as GeometryInstance;
            GeometryElement geoElement = geoInstance.GetInstanceGeometry();

            foreach (GeometryObject obj2 in geoElement)
            {
                if (obj2 is Line || obj2 is Arc)
                {
                    Curve curve = obj2 as Curve;
                    ModelCurve modelcurve = familyDoc.FamilyCreate.NewModelCurve(curve, SketchPlane.Create(familyDoc, plane));
                    profilesArray.Append(modelcurve.GeometryCurve.Reference);
                }
            }
        }
        return profilesArray;
    }

    /// <summary>
    /// Places the outer section family at the specified location with correct orientation.
    /// </summary>
    /// <param name="familyDoc">Family document.</param>
    /// <param name="filePath">File path of the family.</param>
    /// <param name="location">Location point in 3D space.</param>
    /// <param name="normal">Normal vector for orientation.</param>
    /// <param name="i">Segment index.</param>
    /// <returns>Placed family instance.</returns>
    private FamilyInstance LocationFamilyInstance(Document familyDoc, string filePath, XYZ location, XYZ normal, int i)
    {
        FamilySymbol familySymbol = null;
        bool loaded = familyDoc.LoadFamilySymbol(filePath, System.IO.Path.GetFileNameWithoutExtension(filePath), out familySymbol);
        familySymbol.Activate();

        List<Autodesk.Revit.Creation.FamilyInstanceCreationData> list = new List<Autodesk.Revit.Creation.FamilyInstanceCreationData>();
        list.Add(new Autodesk.Revit.Creation.FamilyInstanceCreationData(location, familySymbol, StructuralType.NonStructural));
        var familyInstancesIds = familyDoc.FamilyCreate.NewFamilyInstances2(list);
        FamilyInstance familyInstance = familyDoc.GetElement(familyInstancesIds.ElementAt(0)) as FamilyInstance;

        LocationPoint point = familyInstance.Location as LocationPoint;
        Line axis = Line.CreateBound(location, new XYZ(location.X, location.Y, location.Z + 1));
        double angle = normal.AngleTo(new XYZ(1, 0, 0));

        if (normal.CrossProduct(new XYZ(1, 0, 0)).Z < 0)
        {
            point.Rotate(axis, angle);
        }
        else
        {
            point.Rotate(axis, -angle);
        }

        IList<Parameter> heightParams = familyInstance.GetParameters("H");
        heightParams[0].Set(ListData.List_height[i]);

        return familyInstance;
    }

    /// <summary>
    /// Places the inner section family at the specified location with correct orientation.
    /// </summary>
    /// <param name="familyDoc">Family document.</param>
    /// <param name="filePath">File path of the family.</param>
    /// <param name="location">Location point in 3D space.</param>
    /// <param name="normal">Normal vector for orientation.</param>
    /// <param name="i">Segment index.</param>
    /// <returns>Placed family instance.</returns>
    private FamilyInstance LocationFamilyInstance2(Document familyDoc, string filePath, XYZ location, XYZ normal, int i)
    {
        FamilySymbol familySymbol = null;
        bool loaded = familyDoc.LoadFamilySymbol(filePath, System.IO.Path.GetFileNameWithoutExtension(filePath), out familySymbol);
        familySymbol.Activate();

        List<Autodesk.Revit.Creation.FamilyInstanceCreationData> list = new List<Autodesk.Revit.Creation.FamilyInstanceCreationData>();
        list.Add(new Autodesk.Revit.Creation.FamilyInstanceCreationData(location, familySymbol, StructuralType.NonStructural));
        var familyInstancesIds = familyDoc.FamilyCreate.NewFamilyInstances2(list);
        FamilyInstance familyInstance = familyDoc.GetElement(familyInstancesIds.ElementAt(0)) as FamilyInstance;

        LocationPoint point = familyInstance.Location as LocationPoint;
        Line axis = Line.CreateBound(location, new XYZ(location.X, location.Y, location.Z + 1));
        double angle = normal.AngleTo(new XYZ(1, 0, 0));

        if (normal.CrossProduct(new XYZ(1, 0, 0)).Z < 0)
        {
            point.Rotate(axis, angle);
        }
        else
        {
            point.Rotate(axis, -angle);
        }

        IList<Parameter> paramHi1 = familyInstance.GetParameters("Hi1");
        paramHi1[0].Set(ListData.List_Hi1[i]);
        IList<Parameter> paramHi5 = familyInstance.GetParameters("Hi5");
        paramHi5[0].Set(ListData.List_Hi5[i]);
        IList<Parameter> paramT = familyInstance.GetParameters("T");
        paramT[0].Set(ListData.List_t[i]);
        IList<Parameter> paramH = familyInstance.GetParameters("H");
        paramH[0].Set(ListData.List_height[i]);

        return familyInstance;
    }
}

You can see the specific result in the following video:
http://v.youku.com/v_show/id_XMjgwMjcwMjY3Ng==.html

xuebim
Follow the latest BIM developments in the architecture industry, explore innovative building technologies, and discover cutting-edge industry insights.
← Scan with WeChat
Like(0) 打赏
BIM WORLD » Revit Custom Development: Designing a Continuous Rigid Frame Bridge with Horizontal and Vertical Curves

Comment Get first!

Must log in before commenting!

 

BIM World, A Professional BIM Learning Platform

Stay updated on the latest architecture trends and share new building technologies.

Contact UsAbout Us

觉得文章有用就打赏一下小编吧

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

Account Login

By signing in, you agree toUser Agreement

Sign Up