应用程序:钢筋

Revit平台:结构

Revit版本:2011.0

首次发布于:9.1

编程语言:C#

技能水平:高级

类别:结构

类型:ExternalCommand

主题:创建钢筋

摘要:展示如何在没有任何钢筋的混凝土构件(梁或柱)中创建钢筋。

相关类:

Autodesk.Revit.UI.IExternalCommand

Autodesk.Revit.Creation.Document

Autodesk.Revit.DB.Structure.Rebar

Autodesk.Revit.DB.Structure.StructuralType

项目文件:

Command.cs

该文件定义了类Command,该类继承自IExternalCommand接口并实现Execute方法。Execute方法的功能是显示一个模型对话框,以创建所选元素的钢筋。

FramReinMaker.cs

该文件定义了FramReinMaker类,该类是由BeamFramReinMakerColumnFramReinMaker派生的。这些类的功能是为选定的主机元素创建钢筋。如果选定的元素是一根梁,则制造者是BeamFramReinMaker。如果选定的元素是一根柱,则制造者是ColumnFramReinMaker

BeamFramReinMaker.cs

该文件定义了BeamFramReinMaker类,该类继承自FramReinMaker。它用于为梁创建钢筋。

ColumnFramReinMaker.cs

该文件定义了ColumnFramReinMaker类,该类继承自FramReinMaker。它用于为柱创建钢筋。

BeamFramReinMakerForm.cs

该文件定义了BeamFramReinMakerForm类,该类继承自Form。此类的功能是为梁创建准备参数。

ColumnFramReinMakerForm.cs

该文件定义了ColumnFramReinMakerForm类,该类继承自Form。此类的功能是为柱创建准备参数。 

GeomData.cs

该文件定义了BeamRebarDataColumnRebarData类。它们可存储有关支持梁和柱钢筋的信息。 

GeometrySupport.cs

作为基类,它可以支持BeamGeometrySupportColumnGeometrySupport,该类还可以存储一些常见的几何信息。并提供一些辅助函数。

BeamGeometrySupport.cs

作为梁上钢筋创建的几何支持,它可以为顶部钢筋、底部和横向钢筋创建准备几何信息。

ColumnGeometrySupport.cs

作为柱上钢筋创建的几何支持,它可以为横向和垂直钢筋创建准备几何信息。

GeomUtil.cs

该文件定义了GeomUtil类,该类提供基本几何操作,是一个静态类。

ParameterUtil.cs

该文件定义了ParameterUtil类,该类包含用于查找或设置特定参数的实用程序方法,是一个静态类。

描述:

这个示例使用Autodesk.Revit.Creation.Document.NewRebar方法为所选主机创建钢筋。NewRebar方法需要两个参数RebarBarTypeRebarHookType。可以通过迭代活动文档元素来获取这两个参数

说明:

1. 打开或新建一个Revit项目,确保已放置一些没有任何加固的混凝土梁或柱。该示例的文件夹中有一个示例项目文件Reinforcement.rvt

2. 选择混凝土梁或柱,运行命令。

3. 在弹出的对话框中设置钢筋的参数。

4. 单击“确定”,所选元素(梁或柱)的钢筋将被创建。

源代码:

完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码

BeamFramReinMaker.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Structure;

namespace Revit.SDK.Samples.Reinforcement.CS
{

/// <summary>
/// The class derived from FramReinMaker shows how to create the rebars for a beam
/// </summary>
public class BeamFramReinMaker : FramReinMaker
{
#region Private Members

BeamGeometrySupport m_geometry; // The geometry support for beam rebar creation

// The rebar type, hook type and spacing information
RebarBarType m_topEndType = null; //type of the end rebar in the top of beam
RebarBarType m_topCenterType = null; //type of the center rebar in the center of beam
RebarBarType m_bottomType = null; //type of the rebar on bottom of the beam
RebarBarType m_transverseType = null; //type of the transverse rebar

RebarHookType m_topHookType = null; //type of the hook in the top end rebar
RebarHookType m_transverseHookType = null; // type of the hook in the transverse rebar

double m_transverseEndSpacing = 0; //the spacing value of end transverse rebar
double m_transverseCenterSpacing = 0; //the spacing value of center transverse rebar

#endregion

#region Properties
/// <summary>
/// get and set the type of the end rebar in the top of beam
/// </summary>
public RebarBarType TopEndRebarType
{
get
{
return m_topEndType;
}
set
{
m_topEndType = value;
}
}

/// <summary>
/// get and set the type of the center rebar in the top of beam
/// </summary>
public RebarBarType TopCenterRebarType
{
get
{
return m_topCenterType;
}
set
{
m_topCenterType = value;
}
}

/// <summary>
/// get and set the type of the rebar in the bottom of beam
/// </summary>
public RebarBarType BottomRebarType
{
get
{
return m_bottomType;
}
set
{
m_bottomType = value;
}
}

/// <summary>
/// get and set the type of the transverse rebar
/// </summary>
public RebarBarType TransverseRebarType
{
get
{
return m_transverseType;
}
set
{
m_transverseType = value;
}
}

/// <summary>
/// get and set the spacing value of end transverse rebar
/// </summary>
public double TransverseEndSpacing
{
get
{
return m_transverseEndSpacing;
}
set
{
if (0 > value)
{
throw new Exception("Transverse end spacing should be above zero");
}
m_transverseEndSpacing = value;
}
}

/// <summary>
/// get and set the spacing value of center transverse rebar
/// </summary>
public double TransverseCenterSpacing
{
get
{
return m_transverseCenterSpacing;
}
set
{
if (0 > value)
{
throw new Exception("Transverse center spacing should be above zero");
}
m_transverseCenterSpacing = value;
}
}

/// <summary>
/// get and set the hook type of top end rebar
/// </summary>
public RebarHookType TopHookType
{
get
{
return m_topHookType;
}
set
{
m_topHookType = value;
}
}

/// <summary>
/// get and set the hook type of transverse rebar
/// </summary>
public RebarHookType TransverseHookType
{
get
{
return m_transverseHookType;
}
set
{
m_transverseHookType = value;
}
}

#endregion

#region Constructor
/// <summary>
/// Constructor of the BeamFramReinMaker
/// </summary>
/// <param name="commandData">the ExternalCommandData reference</param>
/// <param name="hostObject">the host beam</param>
public BeamFramReinMaker(ExternalCommandData commandData, FamilyInstance hostObject)
: base(commandData, hostObject)
{
//create new options for current project
Options geoOptions = commandData.Application.Application.Create.NewGeometryOptions();
geoOptions.ComputeReferences = true;

//create a BeamGeometrySupport instance.
m_geometry = new BeamGeometrySupport(hostObject, geoOptions);
}
#endregion

#region Override Methods
/// <summary>
/// Override method to do some further checks
/// </summary>
/// <returns>true if the the data is right and enough, otherwise false.</returns>
protected override bool AssertData()
{
return base.AssertData();
}

/// <summary>
/// Display a form to collect the information for beam reinforcement creation
/// </summary>
/// <returns>true if the information collection is successful, otherwise false</returns>
protected override bool DisplayForm()
{
// Display BeamFramReinMakerForm for the user to input information
using (BeamFramReinMakerForm displayForm = new BeamFramReinMakerForm(this))
{
if (DialogResult.OK != displayForm.ShowDialog())
{
return false;
}
}
return base.DisplayForm();
}

/// <summary>
/// Override method to create rebar on the selected beam
/// </summary>
/// <returns>true if the creation is successful, otherwise false</returns>
protected override bool FillWithBars()
{
// create the top rebars
bool flag = FillTopBars();

// create the bottom rebars
flag = flag && FillBottomBars();

// create the transverse rebars
flag = flag && FillTransverseBars();

return base.FillWithBars();
}

#endregion

/// <summary>
/// Create the rebar at the bottom of beam
/// </summary>
/// <returns>true if the creation is successful, otherwise false</returns>
public bool FillBottomBars()
{
// get the geometry information of the bottom rebar
RebarGeometry geomInfo = m_geometry.GetBottomRebar();

// create the rebar
Rebar rebar = PlaceRebars(m_bottomType, null, null, geomInfo,
RebarHookOrientation.Left, RebarHookOrientation.Left);
return (null != rebar);
}

/// <summary>
/// Create the transverse rebars
/// </summary>
/// <returns>true if the creation is successful, otherwise false</returns>
public bool FillTransverseBars()
{
// create all kinds of transverse rebars according to the TransverseRebarLocation
foreach (TransverseRebarLocation location in Enum.GetValues(
typeof(TransverseRebarLocation)))
{
Rebar createdRebar = FillTransverseBar(location);
//judge whether the transverse rebar creation is successful
if (null == createdRebar)
{
return false;
}
}

return true;
}

/// <summary>
/// Create the transverse rebars, according to the location of transverse rebars
/// </summary>
/// <param name="location">location of rebar which need to be created</param>
/// <returns>the created rebar, return null if the creation is unsuccessful</returns>
public Rebar FillTransverseBar(TransverseRebarLocation location)
{
// Get the geometry information which support rebar creation
RebarGeometry geomInfo = new RebarGeometry();
switch (location)
{
case TransverseRebarLocation.Start: // start transverse rebar
case TransverseRebarLocation.End: // end transverse rebar
geomInfo = m_geometry.GetTransverseRebar(location, m_transverseEndSpacing);
break;
case TransverseRebarLocation.Center:// center transverse rebar
geomInfo = m_geometry.GetTransverseRebar(location, m_transverseCenterSpacing);
break;
}

RebarHookOrientation startHook = RebarHookOrientation.Right;
RebarHookOrientation endHook = RebarHookOrientation.Left;
if (!GeomUtil.IsInRightDir(geomInfo.Normal))
{
startHook = RebarHookOrientation.Left;
endHook = RebarHookOrientation.Right;
}

// create the rebar
return PlaceRebars(m_transverseType, m_transverseHookType, m_transverseHookType,
geomInfo, startHook, endHook);
}

/// <summary>
/// Get the hook orient of the top rebar
/// </summary>
/// <param name="geomInfo">the rebar geometry support information</param>
/// <param name="location">the location of top rebar</param>
/// <returns>the hook orient of the top hook</returns>
private RebarHookOrientation GetTopHookOrient(RebarGeometry geomInfo, TopRebarLocation location)
{
// Top center rebar doesn't need hook.
if (TopRebarLocation.Center == location)
{
throw new Exception("Center top rebar doesn't have any hook.");
}

// Get the hook direction, rebar normal and rebar line
Autodesk.Revit.DB.XYZ hookVec = m_geometry.GetDownDirection();
Autodesk.Revit.DB.XYZ normal = geomInfo.Normal;
Line rebarLine = geomInfo.Curves[0] as Line;

// get the top start hook orient
if (TopRebarLocation.Start == location)
{
Autodesk.Revit.DB.XYZ curveVec = GeomUtil.SubXYZ(rebarLine.GetEndPoint(1), rebarLine.GetEndPoint(0));
return GeomUtil.GetHookOrient(curveVec, normal, hookVec);
}
else // get the top end hook orient
{
Autodesk.Revit.DB.XYZ curveVec = GeomUtil.SubXYZ(rebarLine.GetEndPoint(0), rebarLine.GetEndPoint(1));
return GeomUtil.GetHookOrient(curveVec, normal, hookVec);
}
}

/// <summary>
/// Create the rebar at the top of beam
/// </summary>
/// <returns>true if the creation is successful, otherwise false</returns>
private bool FillTopBars()
{
// create all kinds of top rebars according to the TopRebarLocation
foreach (TopRebarLocation location in Enum.GetValues(typeof(TopRebarLocation)))
{
Rebar createdRebar = FillTopBar(location);
//judge whether the top rebar creation is successful
if (null == createdRebar)
{
return false;
}
}

return true;
}

/// <summary>
/// Create the rebar at the top of beam, according to the top rebar location
/// </summary>
/// <param name="location">location of rebar which need to be created</param>
/// <returns>the created rebar, return null if the creation is unsuccessful</returns>
private Rebar FillTopBar(TopRebarLocation location)
{
//get the geometry information of the rebar
RebarGeometry geomInfo = m_geometry.GetTopRebar(location);

RebarHookType startHookType = null; //the start hook type of the rebar
RebarHookType endHookType = null; // the end hook type of the rebar
RebarBarType rebarType = null; // the rebar type
RebarHookOrientation startOrient = RebarHookOrientation.Right;// the start hook orient
RebarHookOrientation endOrient = RebarHookOrientation.Left; // the end hook orient

// decide the rebar type, hook type and hook orient according to location
switch (location)
{
case TopRebarLocation.Start:
startHookType = m_topHookType; // start hook type
rebarType = m_topEndType; // rebar type
startOrient = GetTopHookOrient(geomInfo, location); // start hook orient
break;
case TopRebarLocation.Center:
rebarType = m_topCenterType; // rebar type
break;
case TopRebarLocation.End:
endHookType = m_topHookType; // end hook type
rebarType = m_topEndType; // rebar type
endOrient = GetTopHookOrient(geomInfo, location); // end hook orient
break;
}

// create the rebar
return PlaceRebars(rebarType, startHookType, endHookType,
geomInfo, startOrient, endOrient);
}

}
}

BeamGeometrySupport.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Text;

using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;

namespace Revit.SDK.Samples.Reinforcement.CS
{
/// <summary>
/// The geometry support for reinforcement creation on beam.
/// It can prepare the geometry information for top rebar, bottom and transverse rebar creation
/// </summary>
public class BeamGeometrySupport : GeometrySupport
{
// Private members
double m_beamLength; //the length of the beam
double m_beamWidth; //the width of the beam
double m_beamHeight; //the height of the beam

/// <summary>
/// constructor
/// </summary>
/// <param name="element">the beam which the rebars are placed on</param>
/// <param name="geoOptions">the geometry option</param>
public BeamGeometrySupport(FamilyInstance element, Options geoOptions)
: base(element, geoOptions)
{
// assert the host element is a beam
if (!element.StructuralType.Equals(StructuralType.Beam))
{
throw new Exception("BeamGeometrySupport can only work for beam instance.");
}

// Get the length, width and height of the beam.
m_beamLength = GetDrivingLineLength();
m_beamWidth = GetBeamWidth();
m_beamHeight = GetBeamHeight();
}

/// <summary>
/// Get the geometry information for top rebar
/// </summary>
/// <param name="location">indicate where top rebar is placed</param>
/// <returns>the gotten geometry information</returns>
public RebarGeometry GetTopRebar(TopRebarLocation location)
{
// sort the points of the swept profile
XYZHeightComparer comparer = new XYZHeightComparer();
m_points.Sort(comparer);

// Get the normal parameter for rebar creation
List<Autodesk.Revit.DB.XYZ > directions = GetRelatedVectors(m_points[3]);
directions.Sort(comparer);
Autodesk.Revit.DB.XYZ normal = directions[1];

double offset = 0; //the offset from the beam surface to the rebar
double startPointOffset = 0; // the offset of start point from swept profile
double rebarLength = m_beamLength / 3; //the length of the rebar
int rebarNumber = BeamRebarData.TopRebarNumber; //the number of the rebar

// set offset and startPointOffset according to the location of rebar
switch (location)
{
case TopRebarLocation.Start: // top start rebar
offset = BeamRebarData.TopEndOffset;
break;
case TopRebarLocation.Center: // top center rebar
offset = BeamRebarData.TopCenterOffset;
startPointOffset = m_beamLength / 3 - 0.5;
rebarLength = m_beamLength / 3 + 1;
break;
case TopRebarLocation.End: // top end rebar
offset = BeamRebarData.TopEndOffset;
startPointOffset = m_beamLength * 2 / 3;
break;
default:
throw new Exception("The program should never go here.");
}

// Get the curve which define the shape of the top rebar curve
List<Autodesk.Revit.DB.XYZ > movedPoints = OffsetPoints(offset);
Autodesk.Revit.DB.XYZ startPoint = movedPoints[movedPoints.Count - 1];

// offset the start point according startPointOffset
startPoint = GeomUtil.OffsetPoint(startPoint, m_drivingVector, startPointOffset);
// get the coordinate of endpoint
Autodesk.Revit.DB.XYZ endPoint = GeomUtil.OffsetPoint(startPoint, m_drivingVector, rebarLength);
IList<Curve> curves = new List<Curve>(); //the profile of the top rebar
curves.Add(Line.CreateBound(startPoint, endPoint));

// the spacing of the rebar
double spacing = spacing = (m_beamWidth - 2 * offset) / (rebarNumber - 1);

// return the rebar geometry information
return new RebarGeometry(normal, curves, rebarNumber, spacing);
}

/// <summary>
/// Get the geometry information of bottom rebar
/// </summary>
/// <returns>the gotten geometry information</returns>
public RebarGeometry GetBottomRebar()
{
// sort the points of the swept profile
XYZHeightComparer comparer = new XYZHeightComparer();
m_points.Sort(comparer);

// Get the normal parameter for bottom rebar creation
List<Autodesk.Revit.DB.XYZ > directions = GetRelatedVectors(m_points[0]);
directions.Sort(comparer);
Autodesk.Revit.DB.XYZ normal = directions[0];

double offset = BeamRebarData.BottomOffset; //offset value of the rebar
int rebarNumber = BeamRebarData.BottomRebarNumber; //the number of the rebar
// the spacing of the rebar
double spacing = (m_beamWidth - 2 * offset) / (rebarNumber - 1);

// Get the curve which define the shape of the bottom rebar curve
List<Autodesk.Revit.DB.XYZ > movedPoints = OffsetPoints(offset);
Autodesk.Revit.DB.XYZ startPoint = movedPoints[0]; //get the coordinate of startpoint
//get the coordinate of endpoint
Autodesk.Revit.DB.XYZ endPoint = GeomUtil.OffsetPoint(startPoint, m_drivingVector, m_beamLength);

IList<Curve> curves = new List<Curve>(); //the profile of the bottom rebar
curves.Add(Line.CreateBound(startPoint, endPoint));

// return the rebar geometry information
return new RebarGeometry(normal, curves, rebarNumber, spacing);
}

/// <summary>
/// Get the geometry information of transverse rebar
/// </summary>
/// <param name="location">indicate which part of transverse rebar</param>
/// <param name="spacing">the spacing of the rebar</param>
/// <returns>the gotten geometry information</returns>
public RebarGeometry GetTransverseRebar(TransverseRebarLocation location, double spacing)
{
// sort the points of the swept profile
XYZHeightComparer comparer = new XYZHeightComparer();
m_points.Sort(comparer);

// the offset from the beam surface to the rebar
double offset = BeamRebarData.TransverseOffset;
// the offset from the beam end to the transverse end
double endOffset = BeamRebarData.TransverseEndOffset;
// the offset between two transverses
double betweenOffset = BeamRebarData.TransverseSpaceBetween;
// the length of the transverse rebar
double rebarLength = (m_beamLength - 2 * endOffset - 2 * betweenOffset) / 3;
// the number of the transverse rebar
int rebarNumber = (int)(rebarLength / spacing) + 1;

// get the origin and normal parameter for rebar creation
Autodesk.Revit.DB.XYZ normal = m_drivingVector;
double curveOffset = 0;

//judge the coordinate of transverse rebar according to the location
switch (location)
{
case TransverseRebarLocation.Start: // start transverse rebar
curveOffset = endOffset;
break;
case TransverseRebarLocation.Center: // center transverse rebar
curveOffset = endOffset + rebarLength + betweenOffset;
curveOffset = curveOffset + (rebarLength % spacing) / 2;
break;
case TransverseRebarLocation.End: // end transverse rebar
curveOffset = m_beamLength - endOffset - rebarLength + (rebarLength % spacing);
break;
default:
throw new Exception("The program should never go here.");
}

// get the profile of the transverse rebar
List<Autodesk.Revit.DB.XYZ > movedPoints = OffsetPoints(offset);

// Translate curves points
List<Autodesk.Revit.DB.XYZ > translatedPoints = new List<Autodesk.Revit.DB.XYZ >();
foreach (Autodesk.Revit.DB.XYZ point in movedPoints)
{
translatedPoints.Add(GeomUtil.OffsetPoint(point, m_drivingVector, curveOffset));
}

IList<Curve> curves = new List<Curve>();
Autodesk.Revit.DB.XYZ first = translatedPoints[0];
Autodesk.Revit.DB.XYZ second = translatedPoints[1];
Autodesk.Revit.DB.XYZ third = translatedPoints[2];
Autodesk.Revit.DB.XYZ fourth = translatedPoints[3];

curves.Add(Line.CreateBound(first, second));
curves.Add(Line.CreateBound(second, fourth));
curves.Add(Line.CreateBound(fourth, third));
curves.Add(Line.CreateBound(third, first));

// return the rebar geometry information
return new RebarGeometry(normal, curves, rebarNumber, spacing);
}

/// <summary>
/// Get the down direction, which stand for the top hook direction
/// </summary>
/// <returns>the down direction</returns>
public Autodesk.Revit.DB.XYZ GetDownDirection()
{
XYZHeightComparer comparer = new XYZHeightComparer();
m_points.Sort(comparer);

Autodesk.Revit.DB.XYZ refPoint = m_points[3];
List<Autodesk.Revit.DB.XYZ > directions = GetRelatedVectors(refPoint);
directions.Sort(comparer);

return directions[0];
}

/// <summary>
/// Get the width of the beam
/// </summary>
/// <returns>the width data</returns>
private double GetBeamWidth()
{
XYZHeightComparer comparer = new XYZHeightComparer();
m_points.Sort(comparer);

Autodesk.Revit.DB.XYZ refPoint = m_points[0];
List<Autodesk.Revit.DB.XYZ > directions = GetRelatedVectors(refPoint);
directions.Sort(comparer);

return GeomUtil.GetLength(directions[0]);
}

/// <summary>
/// Get the height of the beam
/// </summary>
/// <returns>the height data</returns>
private double GetBeamHeight()
{
XYZHeightComparer comparer = new XYZHeightComparer();
m_points.Sort(comparer);

Autodesk.Revit.DB.XYZ refPoint = m_points[0];
List<Autodesk.Revit.DB.XYZ > directions = GetRelatedVectors(refPoint);
directions.Sort(comparer);

return GeomUtil.GetLength(directions[1]);
}
}
}

ColumnFramReinMaker.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Structure;

namespace Revit.SDK.Samples.Reinforcement.CS
{
/// <summary>
/// The class derived form FramReinMaker showes how to create the rebars for a column
/// </summary>
public class ColumnFramReinMaker : FramReinMaker
{
#region Private Members

ColumnGeometrySupport m_geometry; // The geometry support for column rebar creation

RebarBarType m_transverseEndType = null; //type of the end transverse rebar
RebarBarType m_transverseCenterType = null; //type of the center transverse rebar
RebarBarType m_verticalType = null; //type of the vertical rebar
RebarHookType m_transverseHookType = null; //type of the hook

double m_transverseEndSpacing = 0; //the space value of end transverse rebar
double m_transverseCenterSpacing = 0; //the space value of center transverse rebar
int m_verticalRebarNumber = 0; //the number of the vertical rebar

#endregion

#region Properties

/// <summary>
/// get and set the type of the end transverse rebar
/// </summary>
public RebarBarType TransverseEndType
{
get
{
return m_transverseEndType;
}
set
{
m_transverseEndType = value;
}
}

/// <summary>
/// get and set the type of the center transverse rebar
/// </summary>
public RebarBarType TransverseCenterType
{
get
{
return m_transverseCenterType;
}
set
{
m_transverseCenterType = value;
}
}

/// <summary>
/// get and set the type of the vertical rebar
/// </summary>
public RebarBarType VerticalRebarType
{
get
{
return m_verticalType;
}
set
{
m_verticalType = value;
}
}

/// <summary>
/// get and set the space value of end transverse rebar
/// </summary>
public double TransverseEndSpacing
{
get
{
return m_transverseEndSpacing;
}
set
{
if (0 > value) // spacing data must be above 0
{
throw new Exception("Transverse end spacing should be above zero");
}
m_transverseEndSpacing = value;
}
}

/// <summary>
/// get and set the space value of center transverse rebar
/// </summary>
public double TransverseCenterSpacing
{
get
{
return m_transverseCenterSpacing;
}
set
{
if (0 > value) // spacing data must be above 0
{
throw new Exception("Transverse center spacing should be above zero");
}
m_transverseCenterSpacing = value;
}
}

/// <summary>
/// get and set the number of vertical rebar
/// </summary>
public int VerticalRebarNumber
{
get
{
return m_verticalRebarNumber;
}
set
{
if (4 > value) // vertical rebar number must be above 3
{
throw new Exception("The minimum of vertical rebar number shouble be four.");
}
m_verticalRebarNumber = value;
}
}

/// <summary>
/// get and set the hook type of transverse rebar
/// </summary>
public RebarHookType TransverseHookType
{
get
{
return m_transverseHookType;
}
set
{
m_transverseHookType = value;
}
}

#endregion

#region Constructor
/// <summary>
/// Constructor of the ColumnFramReinMaker
/// </summary>
/// <param name="commandData">the ExternalCommandData reference</param>
/// <param name="hostObject">the host column</param>
public ColumnFramReinMaker(ExternalCommandData commandData, FamilyInstance hostObject)
: base(commandData, hostObject)
{
//create a new options for current project
Options geoOptions = commandData.Application.Application.Create.NewGeometryOptions();
geoOptions.ComputeReferences = true;

//create a ColumnGeometrySupport instance
m_geometry = new ColumnGeometrySupport(hostObject, geoOptions);
}
#endregion

#region Override Methods

/// <summary>
/// Override method to do some further checks
/// </summary>
/// <returns>true if the the data is right and enough, otherwise false.</returns>
protected override bool AssertData()
{
return base.AssertData();
}

/// <summary>
/// Display a form to collect the information for column reinforcement creation
/// </summary>
/// <returns>true if the informatin collection is successful, otherwise false</returns>
protected override bool DisplayForm()
{
// Display ColumnFramReinMakerForm for the user input information
using (ColumnFramReinMakerForm displayForm = new ColumnFramReinMakerForm(this))
{
if (DialogResult.OK != displayForm.ShowDialog())
{
return false;
}
}
return base.DisplayForm();
}

/// <summary>
/// Override method to create rebars on the selected column
/// </summary>
/// <returns>true if the creation is successful, otherwise false.</returns>
protected override bool FillWithBars()
{
// create the transverse rebars
bool flag = FillTransverseBars();

// create the vertical rebars
flag = flag && FillVerticalBars();

return base.FillWithBars();
}

#endregion

/// <summary>
/// create the transverse rebars for the column
/// </summary>
/// <returns>true if the creation is successful, otherwise false</returns>
public bool FillTransverseBars()
{
// create all kinds of transverse rebars according to the TransverseRebarLocation
foreach (TransverseRebarLocation location in Enum.GetValues(
typeof(TransverseRebarLocation)))
{
Rebar createdRebar = FillTransverseBar(location);
//judge whether the transverse rebar creation is successful
if (null == createdRebar)
{
return false;
}
}

return true;
}

/// <summary>
/// Create the transverse rebars, according to the transverse rebar location
/// </summary>
/// <param name="location">location of rebar which need to be created</param>
/// <returns>the created rebar, return null if the creation is unsuccessful</returns>
public Rebar FillTransverseBar(TransverseRebarLocation location)
{
// Get the geometry information which support rebar creation
RebarGeometry geomInfo = new RebarGeometry();
RebarBarType barType = null;
switch (location)
{
case TransverseRebarLocation.Start: // start transverse rebar
case TransverseRebarLocation.End: // end transverse rebar
geomInfo = m_geometry.GetTransverseRebar(location, m_transverseEndSpacing);
barType = m_transverseEndType;
break;
case TransverseRebarLocation.Center:// center transverse rebar
geomInfo = m_geometry.GetTransverseRebar(location, m_transverseCenterSpacing);
barType = m_transverseCenterType;
break;
default:
break;
}

// create the rebar
return PlaceRebars(barType, m_transverseHookType, m_transverseHookType,
geomInfo, RebarHookOrientation.Right, RebarHookOrientation.Left);
}

/// <summary>
/// Create the vertical rebar according the location
/// </summary>
/// <param name="location">location of rebar which need to be created</param>
/// <returns>the created rebar, return null if the creation is unsuccessful</returns>
public Rebar FillVerticalBar(VerticalRebarLocation location)
{
//calculate the rebar number in different location
int rebarNubmer = m_verticalRebarNumber / 4;
switch (location)
{
case VerticalRebarLocation.East: // the east vertical rebar
if (0 < m_verticalRebarNumber % 4)
{
rebarNubmer++;
}
break;
case VerticalRebarLocation.North: // the north vertical rebar
if (2 < m_verticalRebarNumber % 4)
{
rebarNubmer++;
}
break;
case VerticalRebarLocation.West: // the west vertical rebar
if (1 < m_verticalRebarNumber % 4)
{
rebarNubmer++;
}
break;
case VerticalRebarLocation.South: // the south vertical rebar
break;
}

// get the geometry information for rebar creation
RebarGeometry geomInfo = m_geometry.GetVerticalRebar(location, rebarNubmer);

// create the rebar
return PlaceRebars(m_verticalType, null, null, geomInfo,
RebarHookOrientation.Left, RebarHookOrientation.Left);
}

/// <summary>
/// create the all the vertial rebar
/// </summary>
/// <returns>true if the creation is successful, otherwise false</returns>
private bool FillVerticalBars()
{
// create all kinds of vertical rebars according to the VerticalRebarLocation
foreach (VerticalRebarLocation location in Enum.GetValues(
typeof(VerticalRebarLocation)))
{
Rebar createdRebar = FillVerticalBar(location);
//judge whether the vertical rebar creation is successful
if (null == createdRebar)
{
return false;
}
}

return true;
}
}
}

ColumnGeometrySupport.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
namespace Revit.SDK.Samples.Reinforcement.CS
{
   /// <summary>
   /// The geometry support for reinforcement creation on conlumn.
   /// It can prepare the geometry information for transverse and vertical rebar creation
   /// </summary>
   class ColumnGeometrySupport : GeometrySupport
   {
      // Private members
      double m_columnLength; //the length of the column
      double m_columnWidth;  //the width of the column
      double m_columnHeight; //the height of the column
      /// <summary>
      /// constructor for the ColumnGeometrySupport
      /// </summary>
      /// <param name="element">the column which the rebars are placed on</param>
      /// <param name="geoOptions">the geometry option</param>
      public ColumnGeometrySupport(FamilyInstance element, Options geoOptions)
         : base(element, geoOptions)
      {
         // assert the host element is a column
         if (!element.StructuralType.Equals(StructuralType.Column))
         {
            throw new Exception("ColumnGeometrySupport can only work for column instance.");
         }
         // Get the length, width and height of the column.
         m_columnHeight = GetDrivingLineLength();
         m_columnLength = GetColumnLength();
         m_columnWidth = GetColumnWidth();
      }
      /// <summary>
      /// Get the geometry information of the transverse rebar
      /// </summary>
      /// <param name="location">the location of transverse rebar</param>
      /// <param name="spacing">the spacing value of the rebar</param>
      /// <returns>the gotted geometry information</returns>
      public RebarGeometry GetTransverseRebar(TransverseRebarLocation location, double spacing)
      {
         // sort the points of the swept profile
         XYZHeightComparer comparer = new XYZHeightComparer();
         m_points.Sort(comparer);
         // the offset from the column surface to the rebar
         double offset = ColumnRebarData.TransverseOffset;
         //the length of the transverse rebar
         double rebarLength = 0;
         // get the origin and normal parameter for rebar creation
         Autodesk.Revit.DB.XYZ normal = m_drivingVector;
         double curveOffset = 0;
         //set rebar length and origin according to the location of rebar
         switch (location)
         {
            case TransverseRebarLocation.Start:     // start transverse rebar
               rebarLength = m_columnHeight / 4;
               break;
            case TransverseRebarLocation.Center:    // center transverse rebar
               rebarLength = m_columnHeight / 2;
               curveOffset = m_columnHeight / 4 + (rebarLength % spacing) / 2;
               break;
            case TransverseRebarLocation.End:       // end transverse rebar
               rebarLength = m_columnHeight / 4;
               curveOffset = m_columnHeight - rebarLength + (rebarLength % spacing);
               break;
            default:
               throw new Exception("The program should never go here.");
         }
         // the number of the transverse rebar
         int rebarNumber = (int)(rebarLength / spacing) + 1;
         // get the profile of the transverse rebar
         List<Autodesk.Revit.DB.XYZ> movedPoints = OffsetPoints(offset);
         List<Autodesk.Revit.DB.XYZ> translatedPoints = new List<Autodesk.Revit.DB.XYZ>();
         foreach (Autodesk.Revit.DB.XYZ point in movedPoints)
         {
            translatedPoints.Add(GeomUtil.OffsetPoint(point, m_drivingVector, curveOffset));
         }
         IList<Curve> curves = new List<Curve>(); //the profile of the transverse rebar
         Autodesk.Revit.DB.XYZ first = translatedPoints[0];
         Autodesk.Revit.DB.XYZ second = translatedPoints[1];
         Autodesk.Revit.DB.XYZ third = translatedPoints[2];
         Autodesk.Revit.DB.XYZ fourth = translatedPoints[3];
         curves.Add(Line.CreateBound(first, second));
         curves.Add(Line.CreateBound(second, fourth));
         curves.Add(Line.CreateBound(fourth, third));
         curves.Add(Line.CreateBound(third, first));
         // return the rebar geometry information
         return new RebarGeometry(normal, curves, rebarNumber, spacing);
      }
      /// <summary>
      /// Get the geometry information of vertical rebar
      /// </summary>
      /// <param name="location">the location of vertical rebar</param>
      /// <param name="rebarNumber">the spacing value of the rebar</param>
      /// <returns>the gotted geometry information</returns>
      public RebarGeometry GetVerticalRebar(VerticalRebarLocation location, int rebarNumber)
      {
         // sort the points of the swept profile
         XYZHeightComparer comparer = new XYZHeightComparer();
         m_points.Sort(comparer);
         // Get the offset and rebar length of rebar
         double offset = ColumnRebarData.VerticalOffset;
         double rebarLength = m_columnHeight + 3; //the length of rebar
         // Get the start point of the vertical rebar curve
         Autodesk.Revit.DB.XYZ startPoint = m_drivingLine.GetEndPoint(0);
         List<Autodesk.Revit.DB.XYZ> movedPoints = OffsetPoints(offset);
         movedPoints.Sort(comparer);
         Autodesk.Revit.DB.XYZ normal = new Autodesk.Revit.DB.XYZ(); // the normal parameter
         double rebarOffset = 0; // rebar offset, equal to rebarNumber* spacing 
         // get the normal, start point and rebar offset of vertical rebar
         switch (location)
         {
            case VerticalRebarLocation.East:   //vertical rebar in east 
               normal = new Autodesk.Revit.DB.XYZ(0, 1, 0);
               rebarOffset = m_columnWidth - 2 * offset;
               startPoint = movedPoints[1];
               break;
            case VerticalRebarLocation.North: //vertical rebar in north
               normal = new Autodesk.Revit.DB.XYZ(-1, 0, 0);
               rebarOffset = m_columnLength - 2 * offset;
               startPoint = movedPoints[3];
               break;
            case VerticalRebarLocation.West: //vertical rebar in west
               normal = new Autodesk.Revit.DB.XYZ(0, -1, 0);
               rebarOffset = m_columnWidth - 2 * offset;
               startPoint = movedPoints[2];
               break;
            case VerticalRebarLocation.South: //vertical rebar in south
               normal = new Autodesk.Revit.DB.XYZ(1, 0, 0);
               rebarOffset = m_columnLength - 2 * offset;
               startPoint = movedPoints[0];
               break;
            default:
               break;
         }
         double spacing = rebarOffset / rebarNumber; //spacing value of the rebar
         Autodesk.Revit.DB.XYZ endPoint = GeomUtil.OffsetPoint(startPoint, m_drivingVector, rebarLength);
         IList<Curve> curves = new List<Curve>();       //profile of the rebar
         curves.Add(Line.CreateBound(startPoint, endPoint));
         // return the rebar geometry information
         return new RebarGeometry(normal, curves, rebarNumber, spacing);
      }
      /// <summary>
      /// Get the length of the column
      /// </summary>
      /// <returns>the length data</returns>
      private double GetColumnLength()
      {
         XYZHeightComparer comparer = new XYZHeightComparer();
         m_points.Sort(comparer);
         Autodesk.Revit.DB.XYZ refPoint = m_points[0];
         List<Autodesk.Revit.DB.XYZ> directions = GetRelatedVectors(refPoint);
         directions.Sort(comparer);
         return GeomUtil.GetLength(directions[0]);
      }
      /// <summary>
      /// Get the width of the column
      /// </summary>
      /// <returns>the width data</returns>
      private double GetColumnWidth()
      {
         XYZHeightComparer comparer = new XYZHeightComparer();
         m_points.Sort(comparer);
         Autodesk.Revit.DB.XYZ refPoint = m_points[0];
         List<Autodesk.Revit.DB.XYZ> directions = GetRelatedVectors(refPoint);
         directions.Sort(comparer);
         return GeomUtil.GetLength(directions[1]);
      }
   }
}

FrameReinMakerFactory.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Structure;
namespace Revit.SDK.Samples.Reinforcement.CS
{
    /// <summary>
    /// The factory to create the corresponding FrameReinMaker, such as BeamFramReinMaker.
    /// </summary>
    class FrameReinMakerFactory
    {
        // Private members
        ExternalCommandData m_commandData;  // the ExternalCommandData reference
        FamilyInstance m_hostObject;        // the host object
        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="commandData">the ExternalCommandData reference</param>
        public FrameReinMakerFactory(ExternalCommandData commandData)
        {
            m_commandData = commandData;
            if (!GetHostObject())
            {
                throw new Exception("Please select a beam or column.");
            }
        }
        /// <summary>
        /// check the condition of host object and see whether the rebars can be placed on
        /// </summary>
        /// <returns></returns>
        public bool AssertData()
        {
            // judge whether is any rebar exist in the beam or column
            if (new FilteredElementCollector(m_commandData.Application.ActiveUIDocument.Document)
                .OfClass(typeof(Rebar))
                .Cast<Rebar>()
                .Where(x => x.GetHostId().IntegerValue == m_hostObject.Id.IntegerValue).Count() > 0)
                return false;
            
            return true;
        }
        /// <summary>
        /// The main method which create the corresponding FrameReinMaker according to 
        /// the host object type, and invoke Run() method to create reinforcement rebars
        /// </summary>
        /// <returns>true if the creation is successful, otherwise false</returns>
        public bool work()
        {
            // define an IFrameReinMaker interface to create reinforcement rebars
            IFrameReinMaker maker = null;
            // create FrameReinMaker instance according to host object type
            switch (m_hostObject.StructuralType)
            {
                case StructuralType.Beam:   // if host object is a beam
                    maker = new BeamFramReinMaker(m_commandData, m_hostObject);
                    break;
                case StructuralType.Column: // if host object is a column
                    maker = new ColumnFramReinMaker(m_commandData, m_hostObject);
                    break;
                default:
                    break;
            }
            // invoke Run() method to do the reinforcement creation
            maker.Run();
            return true;
        }
        /// <summary>
        /// Get the selected element as the host object, also check if the selected element is expected host object
        /// </summary>
        /// <returns>true if get the selected element, otherwise false.</returns>
        private bool GetHostObject()
        {
            List<ElementId> selectedIds = new List<ElementId>();
            foreach (Autodesk.Revit.DB.ElementId elemId in m_commandData.Application.ActiveUIDocument.Selection.GetElementIds())
            {
               Autodesk.Revit.DB.Element elem = m_commandData.Application.ActiveUIDocument.Document.GetElement(elemId);
                selectedIds.Add(elem.Id);
            }
            if (selectedIds.Count != 1)
                return false;
            //
            // Construct filters to find expected host object: 
            // . Host should be Beam/Column structural type.
            // . and it's material type should be Concrete
            // . and it should be FamilyInstance
            //
            // Structural type filters firstly
            LogicalOrFilter stFilter = new LogicalOrFilter(
                new ElementStructuralTypeFilter(StructuralType.Beam),
                new ElementStructuralTypeFilter(StructuralType.Column));
            // StructuralMaterialType should be Concrete
            LogicalAndFilter hostFilter = new LogicalAndFilter(stFilter,
                new StructuralMaterialTypeFilter(StructuralMaterialType.Concrete));
            //
            // Expected host object
            FilteredElementCollector collector = new FilteredElementCollector(m_commandData.Application.ActiveUIDocument.Document, selectedIds);
            m_hostObject = collector
                .OfClass(typeof(FamilyInstance)) // FamilyInstance
                .WherePasses(hostFilter) // Filters
                .FirstElement() as FamilyInstance;
            return (null != m_hostObject);
        }
    }
}