应一位粉丝的要求,让我写一篇异形柱翻模的文章,今天来写一下,捋一捋思路和方法,当我们拿到CAD图纸,上边有很多异形柱或者约束边缘构件,手动翻模很费劲的,确实需要API来解决。目前有很多插件都有这个功能,但我在网上搜罗了一圈就一篇这类型的文章(我是歌手写的),源代码量还很少,我就顺手写了一篇,但功能不是特别完备,还需要完善一下,看一下成果:
五边形的图纸是我自己用CAD画的,使用链接到revit中,点击拾取图层自动根据图层线绘制一个异形柱的族,并加载到项目里,下面看一下全过程:
1.获取图纸对象:
Reference reff = uiDoc.Selection.PickObject(ObjectType.PointOnElement, "请选择闭合轮廓");//获取对象
Element el = doc.GetElement(reff);
2.获取到图纸的图层,并对该图层隐藏(这样在图纸比较乱的情况下容易分辨是否全部选中创建了)最后要不要显示,看你自己,小编这里只隐藏了。
GeometryObject geoObj = el.GetGeometryObjectFromReference(reff);
GeometryElement geoEl = el.get_Geometry(new Options());
Category ca = null;
ElementId elid = null;
if (geoObj.GraphicsStyleId != ElementId.InvalidElementId)
{
elid = geoObj.GraphicsStyleId;
// MessageBox.Show(elid.ToString());
GraphicsStyle gs = doc.GetElement(geoObj.GraphicsStyleId) as GraphicsStyle;
if (gs != null)
{
ca = gs.GraphicsStyleCategory;
var name = gs.GraphicsStyleCategory.Name;
// MessageBox.Show(name);
}
}
3.获取该图层的线
这里只是提供了一下PolyLine的获得方法,实际上还是有bug的,小编这里只测试一组图案就把Line一股脑的全放在CurveArray里了,实际上还要去区分,还要自己写算法,小编就先不测试了。
/// <summary>
/// 获得图纸的线集合
/// </summary>
/// <returns></returns>
private CurveArrArray GetCurveArrArray(GeometryElement geoEl)
{
//获得线
IList<XYZ> points = null;
List<Line> lineLists = new List<Line>();
CurveArray curveAr = new CurveArray();
CurveArrArray curveArray = new CurveArrArray();
foreach (var gobj in geoEl)
{
GeometryInstance geoInstance = gobj as GeometryInstance;
Transform transform = geoInstance.Transform;
if (geoInstance != null)
{
foreach (var insObj in geoInstance.SymbolGeometry)
{
if (insObj.GetType().ToString() == "Autodesk.Revit.DB.PolyLine")
{
PolyLine polyLine = insObj as PolyLine;
points = polyLine.GetCoordinates();//获取坐标点
// MessageBox.Show(points.Count.ToString());
for (int i = 0; i < points.Count - 1; i++)
{
Line line = Line.CreateBound(points[i], points[i + 1]);
line = TransformLine(transform, line);
Line newLine = line;
// MessageBox.Show(points[i].ToString() + "||||||" + points[i + 1].ToString());
curveAr.Append(newLine);
lineLists.Add(newLine);
}
}
}
}
}
curveArray.Append(curveAr);
return curveArray;
}
4.确定要创建的样板
//确定族样板
string path = @"C:\ProgramData\Autodesk\RVT 2016\Family Templates\Chinese\公制结构柱.rft";
if (path == null)
{
MessageBox.Show("族样板路径错误");
return Result.Cancelled;
}
Document faDoc = app.NewFamilyDocument(path);
5.打开族样板后添加一个族类型
FamilyManager manager = faDoc.FamilyManager;
manager.NewType("异形");
6.添加材质
//添加材质参数
FamilyParameter mfp = manager.AddParameter("材质", BuiltInParameterGroup.PG_MATERIALS, ParameterType.Material, false);
7.利用拉伸来创建一个异形柱
//创建拉伸
SketchPlane skplane = GetSketchPlane(faDoc);
Extrusion extrusion = faDoc.FamilyCreate.NewExtrusion(true, curveArrArray, skplane, 4000 / 304.8);
faDoc.Regenerate();
8.创建约束
//创建约束
Reference topFaceRef = null;
Options opt = new Options();
opt.ComputeReferences = true;
opt.DetailLevel = ViewDetailLevel.Fine;
GeometryElement gelm = extrusion.get_Geometry(opt);
foreach (GeometryObject gobj in gelm)
{
if (gobj is Solid)
{
Solid s = gobj as Solid;
foreach (Face face in s.Faces)
{
if (face.ComputeNormal(new UV()).IsAlmostEqualTo(new XYZ(0, 0, 1)))
{
topFaceRef = face.Reference;
}
}
}
}
Autodesk.Revit.DB.View v = GetView(faDoc);
Reference r = GetTopLevel(faDoc);
Dimension d = faDoc.FamilyCreate.NewAlignment(v, r, topFaceRef);
d.IsLocked = true;
faDoc.Regenerate();
9.关联材质
//关联材质参数
Parameter p = extrusion.get_Parameter(BuiltInParameter.MATERIAL_ID_PARAM);
manager.AssociateElementParameterToFamilyParameter(p, mfp);
10.载入族
Family fa = faDoc.LoadFamily(doc);
faDoc.Close(false);
11.给族重命名
因为打开族样板,族的名称默认是族1,没办法在族文件里修改,小编没找到方法,所以只能在项目里修改族名称,要是知道的小伙伴请在文章末尾留言哦。
fa.Name = "异形柱";
12.创建柱
/// <summary>
/// 生成柱子
/// </summary>
/// <param name="doc"></param>
/// <param name="faSy"></param>
/// <param name="point"></param>
private void CreatColu(Document doc,FamilySymbol faSy, XYZ point)
{
FilteredElementCollector filleve = new FilteredElementCollector(doc);
filleve.OfClass(typeof(Level));
Level le = null;
foreach (Level ll in filleve)//找标高
{
if (ll.Name.Contains("FL1"))
{
le = ll;
}
}
doc.Create.NewFamilyInstance(point, faSy, le, Autodesk.Revit.DB.Structure.StructuralType.Column);
}
这里有一点非常值得注意,因为Revit 2016不会自动激活没有用到的族类型,因此如果没激活的话会抛出异常The symbol is not active.,解决这个问题的办法是将族类型激活即可。
if (!fasy.IsActive)
{
fasy.Activate();//如果不激活会抛出族类型未激活的错误
}
整个思路就是这样子的,下面是全部代码内容:
//开始事务
Transaction ts = new Transaction(doc, "异形柱,约束边缘构件,翻模");
//获取CAD图纸的数据
Reference reff = uiDoc.Selection.PickObject(ObjectType.PointOnElement, "请选择闭合轮廓");//获取对象
Element el = doc.GetElement(reff);
GeometryObject geoObj = el.GetGeometryObjectFromReference(reff);
GeometryElement geoEl = el.get_Geometry(new Options());
Category ca = null;
ElementId elid = null;
if (geoObj.GraphicsStyleId != ElementId.InvalidElementId)
{
elid = geoObj.GraphicsStyleId;
// MessageBox.Show(elid.ToString());
GraphicsStyle gs = doc.GetElement(geoObj.GraphicsStyleId) as GraphicsStyle;
if (gs != null)
{
ca = gs.GraphicsStyleCategory;
var name = gs.GraphicsStyleCategory.Name;
// MessageBox.Show(name);
}
}
ts.Start();
//隐藏图层
if (ca != null)
{
doc.ActiveView.SetVisibility(ca, false);
}
ts.Commit();
CurveArrArray curveArrArray = GetCurveArrArray(geoEl);
//确定族样板
string path = @"C:\ProgramData\Autodesk\RVT 2016\Family Templates\Chinese\公制结构柱.rft";
if (path == null)
{
MessageBox.Show("族样板路径错误");
return Result.Cancelled;
}
Document faDoc = app.NewFamilyDocument(path);
CreatColum(faDoc, curveArrArray);
Family fa = faDoc.LoadFamily(doc);
// MessageBox.Show(fa.Name);
faDoc.Close(false);
//给族重命名
ts.Start();
fa.Name = "异形柱";
FamilySymbol fasy = null;
foreach(ElementId fas in fa.GetFamilySymbolIds())
{
// MessageBox.Show(doc.GetElement(fas).Name);
fasy = doc.GetElement(fas) as FamilySymbol;
}
if (!fasy.IsActive)
{
fasy.Activate();//如果不激活会抛出族类型未激活的错误
}
CreatColu(doc, fasy, new XYZ(0, 0, 0));
ts.Commit();
return Result.Succeeded;
}
/// <summary>
/// 创建族
/// </summary>
/// <param name="faDoc"></param>
/// <param name="curveArrArray"></param>
private void CreatColum(Document faDoc, CurveArrArray curveArrArray)
{
Transaction tss = new Transaction(faDoc, "异形柱, 约束边缘构件,翻模");
tss.Start();
FamilyManager manager = faDoc.FamilyManager;
manager.NewType("异形");
//添加材质参数
FamilyParameter mfp = manager.AddParameter("材质", BuiltInParameterGroup.PG_MATERIALS, ParameterType.Material, false);
//创建拉伸
SketchPlane skplane = GetSketchPlane(faDoc);
Extrusion extrusion = faDoc.FamilyCreate.NewExtrusion(true, curveArrArray, skplane, 4000 / 304.8);
faDoc.Regenerate();
//创建约束
Reference topFaceRef = null;
Options opt = new Options();
opt.ComputeReferences = true;
opt.DetailLevel = ViewDetailLevel.Fine;
GeometryElement gelm = extrusion.get_Geometry(opt);
foreach (GeometryObject gobj in gelm)
{
if (gobj is Solid)
{
Solid s = gobj as Solid;
foreach (Face face in s.Faces)
{
if (face.ComputeNormal(new UV()).IsAlmostEqualTo(new XYZ(0, 0, 1)))
{
topFaceRef = face.Reference;
}
}
}
}
Autodesk.Revit.DB.View v = GetView(faDoc);
Reference r = GetTopLevel(faDoc);
Dimension d = faDoc.FamilyCreate.NewAlignment(v, r, topFaceRef);
d.IsLocked = true;
faDoc.Regenerate();
//关联材质参数
Parameter p = extrusion.get_Parameter(BuiltInParameter.MATERIAL_ID_PARAM);
manager.AssociateElementParameterToFamilyParameter(p, mfp);
// MessageBox.Show(fa.Name);
tss.Commit();
}
/// <summary>
/// 获得图纸的线集合
/// </summary>
/// <returns></returns>
private CurveArrArray GetCurveArrArray(GeometryElement geoEl)
{
//获得线
IList<XYZ> points = null;
List<Line> lineLists = new List<Line>();
CurveArray curveAr = new CurveArray();
CurveArrArray curveArray = new CurveArrArray();
foreach (var gobj in geoEl)
{
GeometryInstance geoInstance = gobj as GeometryInstance;
Transform transform = geoInstance.Transform;
if (geoInstance != null)
{
foreach (var insObj in geoInstance.SymbolGeometry)
{
if (insObj.GetType().ToString() == "Autodesk.Revit.DB.PolyLine")
{
PolyLine polyLine = insObj as PolyLine;
points = polyLine.GetCoordinates();//获取坐标点
// MessageBox.Show(points.Count.ToString());
for (int i = 0; i < points.Count - 1; i++)
{
Line line = Line.CreateBound(points[i], points[i + 1]);
line = TransformLine(transform, line);
Line newLine = line;
// MessageBox.Show(points[i].ToString() + "||||||" + points[i + 1].ToString());
curveAr.Append(newLine);
lineLists.Add(newLine);
}
}
}
}
}
curveArray.Append(curveAr);
return curveArray;
}
/// <summary>
/// 翻转指定线
/// </summary>
/// <param name="transform">矩阵</param>
/// <param name="line">被翻转的线</param>
/// <returns></returns>
private Line TransformLine(Transform transform, Line line)
{
XYZ startPoint = transform.OfPoint(line.GetEndPoint(0));
XYZ endPoint = transform.OfPoint(line.GetEndPoint(1));
Line newLine = Line.CreateBound(startPoint, endPoint);
return newLine;
}
/// <summary>
/// 参照平面
/// </summary>
/// <param name="doc"></param>
/// <returns></returns>
private SketchPlane GetSketchPlane(Document doc)
{
FilteredElementCollector temc = new FilteredElementCollector(doc);
temc.OfClass(typeof(SketchPlane));
SketchPlane sketchPlane = temc.First(m => m.Name == "低于参照标高") as SketchPlane;
return sketchPlane;
}
/// <summary>
/// 获得shitu
/// </summary>
/// <param name="doc"></param>
/// <returns></returns>
private Autodesk.Revit.DB.View GetView(Document doc)
{
FilteredElementCollector viewFilter = new FilteredElementCollector(doc);
viewFilter.OfClass(typeof(Autodesk.Revit.DB.View));
Autodesk.Revit.DB.View v = viewFilter.First(m => m.Name == "前") as Autodesk.Revit.DB.View;
return v;
}
/// <summary>
/// 约束平面
/// </summary>
/// <param name="doc"></param>
/// <returns></returns>
private Reference GetTopLevel(Document doc)
{
FilteredElementCollector temc = new FilteredElementCollector(doc);
temc.OfClass(typeof(Level));
Level lvl = temc.First(m => m.Name == "高于参照标高") as Level;
return new Reference(lvl);
}
//
/// <summary>
/// 生成柱子
/// </summary>
/// <param name="doc"></param>
/// <param name="faSy"></param>
/// <param name="point"></param>
private void CreatColu(Document doc,FamilySymbol faSy, XYZ point)
{
FilteredElementCollector filleve = new FilteredElementCollector(doc);
filleve.OfClass(typeof(Level));
Level le = null;
foreach (Level ll in filleve)//找标高
{
if (ll.Name.Contains("FL1"))
{
le = ll;
}
}
doc.Create.NewFamilyInstance(point, faSy, le, Autodesk.Revit.DB.Structure.StructuralType.Column);
}
}
}