这段时间有一些开发同仁问了一些关于房间放置踢脚或一些相关的问题,所以今天趁着有点时间,觉得还是写一点心得体会和大家分享一下,其实我们得到了房间后,还是可以做很多事情,不仅能能获得房间的边界线,还可以获得组成房间闭合区域的图元,如墙,建筑柱,门,窗等,最近公司的设计四院要求做一个算量的插件,就是根据每一个房间的属性做地面和墙体的排砖,然后做对应的算量工作,当然算量可以使用很多软件,这里只是举一个例子。那么,言归正传,我们还是来看看怎么利用"墙饰条"功能制作墙踢脚吧!
思路如下:我们假设组成这个房间的图元都是墙(如果还有柱子的话,需要多一些考虑了),
1,大家都知道"墙饰条"有两个重要的属性, 那就是轮廓和材质,材质好说随便过滤一个,这里使用"涂料-黄色"。
Material mate = new FilteredElementCollector(doc).OfClass(typeof(Material)).Where(o => o.Name == "涂料 - 黄色").First() as Material;
2,那么轮廓该怎么办,这里使用"公制轮廓"样板,编程实现创建一个矩形轮廓作为墙饰条的轮廓,截面高,宽分别为150mm和25mm,示意图和载入到项目中的情况如下:
创建轮廓族后 进行了保存 为了是可以给这个轮廓族命名,而不是软件自定义的“族1”......“族n!,关键代码如下:
private Family CreateProfileFamily(UIApplication uiapp)
{
//这里为了不干扰软件族样板的路径,把公制轮廓样板单独复制出来了
Document familyDoc = uiapp.Application.NewFamilyDocument(@"C:\ProgramData\Autodesk\Revit\Addins\2016\BIM建筑工具\BIM\AEfamily\公制轮廓.rft");
Family family = null;
using (Transaction transFamily = new Transaction(familyDoc))
{ //找到默认的平面,为详图线服务
View view = new FilteredElementCollector(familyDoc).OfClass(typeof(View)).Where(o => o.Name == "参照标高").First() as View;
transFamily.Start("familyCreation");
//创建四条首尾相连的曲线,为详图线服务
Curve curve1 = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(0, 150 / 304.8, 0));
Curve curve2 = Line.CreateBound(new XYZ(0, 150 / 304.8, 0), new XYZ(25 / 304.8, 150 / 304.8, 0));
Curve curve3 = Line.CreateBound(new XYZ(25 / 304.8, 150 / 304.8, 0), new XYZ(25 / 304.8, 0, 0));
Curve curve4 = Line.CreateBound(new XYZ(25 / 304.8, 0, 0), new XYZ(0, 0, 0));
//创建四条首尾相连的详图线也就是真正的墙饰条轮廓
DetailCurve dc1 = familyDoc.FamilyCreate.NewDetailCurve(view, curve1);
DetailCurve dc2 = familyDoc.FamilyCreate.NewDetailCurve(view, curve2);
DetailCurve dc3 = familyDoc.FamilyCreate.NewDetailCurve(view, curve3);
DetailCurve dc4 = familyDoc.FamilyCreate.NewDetailCurve(view, curve4);
transFamily.Commit();
//族另存选项
SaveAsOptions option = new SaveAsOptions();
//覆盖已有同名文件
option.OverwriteExistingFile = true;
//保存在本地桌面上,可以删除也可以保留为其他项目使用
familyDoc.SaveAs(Environment.GetFolderPath(Environment.SpecialFolder.Desktop, Environment.SpecialFolderOption.None) + @"\踢脚线.rfa", option);
//保存后族就有名字了可以直接使用familyDoc导入到目标项目中了
family = familyDoc.LoadFamily(uiapp.ActiveUIDocument.Document,new LoadOptions());
//记得关闭 要不然在桌面上临时生成的族文件无法顺利删除也就是要资源释放
familyDoc.Close();
}
return family;
}
3,那么我们有了材质和轮廓 那么我们就剩下创建这一步了,创建函数是WallSweep.Create(Wall wall,ElementId wallSweepType,WallSweepInfo wallSweepInfo)是一个静态函数,第一个参数是墙,第二个参数是墙饰条类型,一般我们会过滤到默认的然后复制一个新的类型:
ElementType wallSweepType = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Cornices).WhereElementIsElementType().Cast().First();
复制一个墙饰条类型
ElementType type = wallSweepType.Duplicate("踢脚线");
然后我们剩下最后一个参数 WallSweepInfo,创建如下(记得选择Sweep选项,false代表水平布置,true为垂直布置);
WallSweepInfo wallSweepInfo = new WallSweepInfo(WallSweepType.Sweep, false);
那么wallsweepInfo下有几个重要的选项需要设置 ,这里就不一 一说明了,读者自行查看吧 也不难!
//墙的正反或里外面
wallSweepInfo.WallSide = WallSide.Interior;
//距墙底高度
wallSweepInfo.Distance = 0;
//偏离墙水平距离
wallSweepInfo.WallOffset = 0;
foreach (Parameter o in type.Parameters)
{
if (o.Definition.Name == "轮廓")
{
o.Set(family.Id);
}
if (o.Definition.Name == "材质")
{
o.Set(mate.Id);
}
}
//然后就是创建这个墙饰条
WallSweep ws = WallSweep.Create(wall, type.Id, wallSweepInfo);
本来轮廓和材质的属性在wallSweepInfo下是可以设置的分别是 MaterialId,ProfileId但是在测试过程中并未成功,最后在类型参数里进行了更改,这里注意的是 所需的轮廓是族不是族类型!
我们这里直接使用的是Family.Id,并没有进行项目轮廓族的过滤,如果使用项目中已有的轮廓族有两种方法去查找
一种就是普通的快速过滤,类型设为Family,然后根据FamilyCategory.Name和Family.Name属性限定到目标轮廓族,第二种就是使用FamilyUtils下的方法FamilyUtils.GetProfileSymbols(doc, ProfileFamilyUsage.WallSweep, false)去过滤, ProfileFamilyUsage下有很多轮廓类型,如墙饰条,楼板边,栏杆,扶手等,自己查看吧!
最后生成的图如下:
本测试项目全部代码如下:
public class Test : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Document doc = uidoc.Document;
Reference refer = uidoc.Selection.PickObject(ObjectType.Element, new roomFilter(), "");
Family family = CreateProfileFamily(uiapp);
Material mate = new FilteredElementCollector(doc).OfClass(typeof(Material)).Where(o => o.Name == "涂料 - 黄色").First() as Material;
ElementType wallSweepType = new FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Cornices).WhereElementIsElementType().Cast().First();
using (Transaction transaction = new Transaction(doc, "BIM"))
{
transaction.Start();
ElementType type = wallSweepType.Duplicate("踢脚线");
Room room = doc.GetElement(refer) as Room;
SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
options.SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish;
IList list = new List();
IList> boundList = room.GetBoundarySegments(options);
foreach (IList loop in boundList)
{
foreach (BoundarySegment seg in loop)
{
Element elem = doc.GetElement(seg.ElementId);
if (elem is Wall)
{
Wall wall = elem as Wall;
WallSweepInfo wallSweepInfo = new WallSweepInfo(WallSweepType.Sweep, false);
//墙的正反或里外面
wallSweepInfo.WallSide = WallSide.Interior;
//距墙底高度
wallSweepInfo.Distance = 0;
//偏离墙距离
wallSweepInfo.WallOffset = 0;
foreach (Parameter o in type.Parameters)
{
if (o.Definition.Name == "轮廓")
{
// o.Set(FamilyUtils.GetProfileSymbols(doc, ProfileFamilyUsage.WallSweep, false).ElementAt(0));
o.Set(family.Id);
}
if (o.Definition.Name == "材质")
{
o.Set(mate.Id);
}
}
WallSweep ws = WallSweep.Create(wall, type.Id, wallSweepInfo);
}
}
}
transaction.Commit();
}
return Result.Succeeded;
}
private Family CreateProfileFamily(UIApplication uiapp)
{
Document familyDoc = uiapp.Application.NewFamilyDocument(@"C:\ProgramData\Autodesk\Revit\Addins\2016\BIM建筑工具\BIM\AEfamily\公制轮廓.rft");
Family family = null;
using (Transaction transFamily = new Transaction(familyDoc))
{
View view = new FilteredElementCollector(familyDoc).OfClass(typeof(View)).Where(o => o.Name == "参照标高").First() as View;
transFamily.Start("familyCreation");
Curve curve1 = Line.CreateBound(new XYZ(0, 0, 0), new XYZ(0, 150 / 304.8, 0));
Curve curve2 = Line.CreateBound(new XYZ(0, 150 / 304.8, 0), new XYZ(25 / 304.8, 150 / 304.8, 0));
Curve curve3 = Line.CreateBound(new XYZ(25 / 304.8, 150 / 304.8, 0), new XYZ(25 / 304.8, 0, 0));
Curve curve4 = Line.CreateBound(new XYZ(25 / 304.8, 0, 0), new XYZ(0, 0, 0));
DetailCurve dc1 = familyDoc.FamilyCreate.NewDetailCurve(view, curve1);
DetailCurve dc2 = familyDoc.FamilyCreate.NewDetailCurve(view, curve2);
DetailCurve dc3 = familyDoc.FamilyCreate.NewDetailCurve(view, curve3);
DetailCurve dc4 = familyDoc.FamilyCreate.NewDetailCurve(view, curve4);
transFamily.Commit();
SaveAsOptions option = new SaveAsOptions();
option.OverwriteExistingFile = true;
familyDoc.SaveAs(Environment.GetFolderPath(Environment.SpecialFolder.Desktop, Environment.SpecialFolderOption.None) + @"\踢脚线.rfa", option);
family = familyDoc.LoadFamily(uiapp.ActiveUIDocument.Document,new LoadOptions());
familyDoc.Close();
}
return family;
}
}
public class roomFilter : ISelectionFilter
{
public bool AllowElement(Element elem)
{
return elem is Room;
}
public bool AllowReference(Reference reference, XYZ position)
{
return false;
}
}
public class LoadOptions : IFamilyLoadOptions
{
public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
{
overwriteParameterValues = true;
return true;
}
public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues)
{
source = FamilySource.Project;
overwriteParameterValues = true;
return true;
}
}