最近写了一个revit二次开发的异形柱翻模的功能,柱子翻模网上有很多插件可以用,我用的比较多的是红瓦,其中异形柱的翻模对于图纸的要求较高,有很多不准确的地方。很多异形柱,整体翻模出来是错误的,翻出来之后还要逐一核对是否正确,在进行删除和修整,增加了很多修改的时间。本功能主要想通过拾取图层来进行单个异性柱子的翻模,来替代整体柱子翻模的功能。
写本功能时,在网上搜索资料,基本思路与代码来自于我是歌手写得异形柱翻模文章并附加了自己的实际需求做成的此功能。
由于本人并非专业程序员,代码会有很多不规范的地方,但是功能可以正常运行,希望能给大家提供帮助,欢迎大家指导沟通。
运行演示
异形柱翻模
功能实现思路
1.确定族样板(使用公制结构柱就可以)
string zhufamilypath = @"D:\二开码\族\公制结构柱.rft";
if (zhufamilypath == null)
{
TaskDialog.Show("r", "请检查族样板路径是否正确");
}
else
{
}
2.选择异形柱轮廓。
Selection sel = uidoc.Selection;
Reference reference = sel.PickObject(Autodesk.Revit.UI.Selection.ObjectType.PointOnElement, "请选择柱轮廓");
Element element = doc.GetElement(reference);
GeometryObject geometryObject = element.GetGeometryObjectFromReference(reference);
ImportInstance importInstance = element as ImportInstance;
3根据选择的图纸链接拿到图纸的transform坐标
Transform transform = null;//图纸的
GeometryElement geomElem = importInstance.get_Geometry(new Options());
foreach (GeometryObject geomObj in geomElem)
{
GeometryInstance geomInstance = geomObj as GeometryInstance;
transform = geomInstance.Transform;
}
4.根据柱轮廓信息PolyLine创建一个CurveArrArray。
//根据柱轮廓信息创建一个CurveArrArray
PolyLine polyLine = geometryObject as PolyLine;
CurveArray curveArray = new CurveArray();
CurveArrArray Arr = new CurveArrArray();
IList<XYZ> listPoint = polyLine.GetCoordinates();
XYZ zhuLocation = listPoint[0];//
double x = listPoint[0].X;
double y = listPoint[0].Y;
double z = listPoint[0].Z;
listPoint[0] = new XYZ(0, 0, 0);
for (int i = 0; i < listPoint.Count - 1; i++)//因为循环里面用的是i和i+1所以设定的条件为i < listPoint.Count - 1。
{
Curve temp = Line.CreateBound(new XYZ(listPoint[i].X - x, listPoint[i].Y - y, listPoint[i].Z - z)
, new XYZ(listPoint[i + 1].X - x, listPoint[i + 1].Y - y, listPoint[i + 1].Z - z));
if (i == 0)
{
temp = Line.CreateBound(listPoint[i], new XYZ(listPoint[i + 1].X - x, listPoint[i + 1].Y - y, listPoint[i + 1].Z - z));
}
curveArray.Append(temp);
}
Arr.Append(curveArray);
此处需要划重点!!
因为参照线的中心为族的放置点,按照原本CAD的坐标会把族的轮廓距放置点很远,所以吧轮廓的第一个点记录下来(x,y,z)。然后在把第一个点做成0,0,0。用其余的点减去第一个点的xyz就能得到其余的点与远点形成轮廓需要的点。这个地方有些绕,有些朋友和初学者可能会绕不过来,没关系,大家可以按照自己的想法写,如果自己的写法有问题可以按照我的方法来,有更好的方法的欢迎指导。
5.检索窗体传来的名字,如果在文件夹里有重名的进行提示并退出程序。
//检索文件
DirectoryInfo directoryInfo = new DirectoryInfo(@"D:\二开码\族\");
FileInfo[] fileInfos = directoryInfo.GetFiles("*.rfa");
if (fileInfos!=null&&fileInfos.Count()>0)
{
foreach (FileInfo item in fileInfos)
{
if (item.Name== famNameNorfa + ".rfa")
{
TaskDialog.Show("阿灿提示","此异形状结构柱已存在,请重新命名");
return Result.Succeeded;
}
}
}
此处应该放到最前面,减少用户的等待时间。大家可以根据需求来排列这一步的顺序,不写这一项不影响功能的实现。
6.用族样板来创建新的异形柱,并对异形柱创建了标高约束。
//创建异形柱
UIApplication uIApplication = commandData.Application;
Application app = uIApplication.Application;
Document fadoc = app.NewFamilyDocument(zhufamilypath);
string famName = famNameNorfa+".rfa";//异形柱族名称
using (Transaction tran = new Transaction(fadoc, "create family"))
{
tran.Start("create family");
//创建拉伸
#if RVT2018
Extrusion extrusion = fadoc.FamilyCreate.NewExtrusion(true, Arr, SketchPlane.Create(fadoc, Plane.CreateByNormalAndOrigin(new XYZ(0, 0, 1), new XYZ(0, 0, 0))), 100);
#elif RVT2016
Extrusion extrusion = fadoc.FamilyCreate.NewExtrusion(true, Arr, SketchPlane.Create(fadoc, app.Create.NewPlane(new XYZ(0, 0, 1), new XYZ(0, 0, 0))), 4000/304.8);
#endif
//创建约束
Reference topFaceRef = null;
Reference LowFaceRef = 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;
}
}
}
}
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)))
{
LowFaceRef = face.Reference;
}
}
}
}
View v = new FilteredElementCollector(fadoc).OfClass(typeof(View)).
Where(a => (a as View).Name == "前").FirstOrDefault() as View;
Level toplevel = new FilteredElementCollector(fadoc).OfClass(typeof(Level)).Cast<Level>()
.Where(a => a.Name == "高于参照标高").FirstOrDefault();
Level lowlevel = new FilteredElementCollector(fadoc).OfClass(typeof(Level)).Cast<Level>()
.Where(a => a.Name == "低于参照标高").FirstOrDefault();
Reference r = toplevel.GetPlaneReference();
Reference rlow = lowlevel.GetPlaneReference();
//对齐锁定
Dimension d = fadoc.FamilyCreate.NewAlignment(v, r, topFaceRef);
Dimension e = fadoc.FamilyCreate.NewAlignment(v, rlow, LowFaceRef);
d.IsLocked = true;
e.IsLocked = true;
//更新revit元素
fadoc.Regenerate();
//创建异形柱类型
fadoc.FamilyManager.NewType(famNameNorfa);
tran.Commit();
//族另存为
fadoc.SaveAs(@"D:\二开码\族\" + famName);
}
using (Transaction tran = new Transaction(doc, "loadFamily"))
{
tran.Start();
this.doc.LoadFamily(@"D:\二开码\族\" + famName);
tran.Commit();
}
再次划重点!!
新创建的异形柱需要创建约束,代码创建约束要求必须长度正好对其到参照线上。所以提前按照样板设定了长度。所以在前立面图中锁定了两个标高。并创建了新类型,然后进行保存。
族和族类型的名字是用的窗体传进来的名字,其实可以用识别CAD文字的方式来做名字,但是涉及其他引用并且代码量太大,而且是单个翻模,没有涉及CAD识别文字的相关功能。以后上传别的功能时在进行描述。
7.载入族。
using (Transaction tran = new Transaction(doc, "loadFamily"))
{
tran.Start();
this.doc.LoadFamily(@"D:\二开码\族\" + famName);
tran.Commit();
}
8.放置族。并设置底部标高与顶部标高。
using (Transaction tran = new Transaction(doc, "placeFamily"))
{
tran.Start();
FamilySymbol symbol = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralColumns)
.OfClass(typeof(FamilySymbol)).Cast<FamilySymbol>()
.Where(a => a.FamilyName.Contains(famNameNorfa)).ToList().FirstOrDefault();
if (!symbol.IsActive)
{
symbol.Activate();
}
Level zhulevel = doc.ActiveView.GenLevel;
XYZ location = transform.OfPoint(zhuLocation);
//XYZ location = new XYZ((location2.X)+zhuLocation.X, ( location2.Y) + zhuLocation.Y,
// (location2.Z) + zhuLocation.Z);
FamilyInstance jgZhu = doc.Create.NewFamilyInstance(location, symbol, zhulevel, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);
jgZhu.GetParameters("底部标高").FirstOrDefault().Set(zhulevel.Id);
List<Level> allLevel=new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels)
.OfClass(typeof(Level)).Cast<Level>().Where(a=>int.Parse(a.GetParameters("立面").FirstOrDefault().AsValueString())>
int.Parse(zhulevel.GetParameters("立面").FirstOrDefault().AsValueString())).ToList();
//柱子顶部偏移标高
Level zhuTopLevel = allLevel[0];
if (allLevel.Count>0)
{
foreach (Level item in allLevel)
{
if (int.Parse(item.GetParameters("立面").FirstOrDefault().AsValueString())
- int.Parse(zhulevel.GetParameters("立面").FirstOrDefault().AsValueString())<
int.Parse(zhuTopLevel.GetParameters("立面").FirstOrDefault().AsValueString())
- int.Parse(zhulevel.GetParameters("立面").FirstOrDefault().AsValueString()))
{
zhuTopLevel = item;
}
}
jgZhu.GetParameters("顶部标高").FirstOrDefault().Set(zhuTopLevel.Id);
}
tran.Commit();
}
最后一个重点!!!
1.使用族之前需要做一个isactive的命令,固定写法,记住就好。
2.族的放置点是通过第四步location记录的点,然后通过第三部的transform坐标进行转换得到放置点。
3.此功能需要在平面来做,因为画柱一般是用平面来画,然后用当前所在的视图,来确定底部标高,然后在自动锁定底部标高上面最近的标高来做顶部标高,因为不是批量翻模在窗体里设置底部顶部标高和用revit原生命令做时间上差不多,所以此功能没有设置,写太多反而比较绕。不易做记录与教程。
总结:
本功能的思路和代码就讲到这里了。基本我把我在做此功能遇到的坑和想的思路都告诉了大家。源码基本复制粘贴就可以使用,需要把窗体传来的string更换成其他名称即可。可能大家在做时会遇到别的坑。