1.设计思路
其中,在运行前设置的时候需要创建ui界面,其他处理包含将楼板标记信息同步为楼板所在房间编号和将楼板面层信息同步为楼板面层名称。
2.后台处理
通过过滤器获得所有的房间
public List<Element> getRoomList(Document doc) //获取所有房间
{
FilteredElementCollector RoomCollector = new FilteredElementCollector(doc);
RoomCollector.OfCategory(BuiltInCategory.OST_Rooms).OfClass(typeof(SpatialElement));//SpatialElement空间元素
List<Element> RoomList = RoomCollector.ToList();
return RoomList;
}
通过过滤器获得所有楼板的集合
private List<Element> getFloorList(Document doc) //获取楼板集合
{
FilteredElementCollector FloorCollector = new FilteredElementCollector(doc);
FloorCollector.OfCategory(BuiltInCategory.OST_Floors).OfClass(typeof(FloorType));//SpatialElement空间元素
List<Element> FloorList = FloorCollector.ToList();
return FloorList;
}
通过比较房间中所有轮廓的拉伸体的体积,获取房间的最大轮廓
private List<CurveArray> RoomBoundaryList(List<Element> roomList) //获取房间轮廓
{
List<CurveArray> CurveArrayList = new List<CurveArray>();
foreach(Element element in roomList)
{
Room room = element as Room;
SpatialElementBoundaryOptions seBoundaryOption = new SpatialElementBoundaryOptions();
CurveArray ca = new CurveArray();
IList<IList<BoundarySegment>> roomBoundaryListList = room.GetBoundarySegments(seBoundaryOption);
List<CurveLoop> curveLoopList = new List<CurveLoop>();
//获取房间的所有边界
if(roomBoundaryListList!=null)
{
foreach(IList<BoundarySegment> roomBoundaryList in roomBoundaryListList)
{
CurveLoop curveLoop = new CurveLoop();
foreach(BoundarySegment roomBoundary in roomBoundaryList)
{
curveLoop.Append(roomBoundary.GetCurve());
}
curveLoopList.Add(curveLoop);
}
}
//获取房间边界拉伸体的体积
List<double> volumn = new List<double>();
try
{
foreach(CurveLoop curveLoop in curveLoopList)
{
IList<CurveLoop> cList = new List<CurveLoop>();
cList.Add(curveLoop);
Solid solid = GeometryCreationUtilities.CreateExtrusionGeometry(cList, XYZ.BasisZ, 1);
volumn.Add(solid.Volume);
}
}
catch
{
continue;
}
//通过房间边界拉伸体的体积找出最大轮廓
CurveLoop LargeLoop = curveLoopList.ElementAt(volumn.IndexOf(volumn.Max()));
foreach(Curve curve in LargeLoop)
{
ca.Append(curve);
}
CurveArrayList.Add(ca);
}
return CurveArrayList;
}
绘制楼层面板
private bool CreateSurface(Document doc,FloorType floorType,List<CurveArray> roomBoundaryList)
{
using (Transaction Trans = new Transaction(doc, "生成楼层面板"))
{
Trans.Start();
foreach(CurveArray ca in roomBoundaryList)
{
Floor floor = doc.Create.NewFloor(ca, false);
}
Trans.Commit();
}
return true;
}
其中,过滤房间和过滤楼板的函数可以合并为一个,根据传入函数的不同来过滤。
3.界面设计
采用winform设计,工具箱直接拖控件,很神奇的是在vs里面看不到标题,于是手动在代码里面添加了this.Text = "创建楼板面层",然后发现vs还是看不到,但是revit里面却显示有,而且生平第一次用中文来当变量名,震惊了。
界面代码:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Autodesk.Revit.DB;
namespace 创建楼板面层
{
public partial class setUi : System.Windows.Forms.Form
{
//声明一个List对象rooms,通过rooms来找出属性值
List<Element> rooms = null;
//构造函数,传入房间集合,房间集合拥有的所有属性名称以及楼板类型
public setUi(List<Element> room, List<string> roomParametersNames, List<string> floorTypeNames)
{
InitializeComponent();
roomParametersNames.Add("无");
属性名称.DataSource = roomParametersNames;
类型名称.DataSource = floorTypeNames;
rooms = room;
}
private void setUi_Load(object sender, EventArgs e)
{
this.Text = "创建楼板面层"; //设置窗口标题
//禁用放大和缩小按钮
this.MaximizeBox = false;
this.MinimizeBox = false;
//设置combox的默认值
属性名称.SelectedIndex = 1;
属性值.SelectedIndex = 0;
类型名称.SelectedIndex = 0;
}
//找出属性值的集合,传入combox
private void 属性名称_SelectedIndexChanged(object sender, EventArgs e)
{
if (属性名称.SelectedItem != null)
{
string parameterName = 属性名称.SelectedItem.ToString();
List<string> parameterValuelist = new List<string>();
parameterValuelist.Add("无");
foreach (Element el in rooms)
{
属性值.DataSource = null;
IList<Parameter> roomsPa = el.GetParameters(parameterName);
foreach (Parameter pa in roomsPa)
{
if (pa.HasValue)
{
if (pa.StorageType != StorageType.String)
{
if (!parameterValuelist.Contains(pa.AsValueString()))
{
parameterValuelist.Add(pa.AsValueString());
}
}
else
{
if (!parameterValuelist.Contains(pa.AsString()))
{
parameterValuelist.Add(pa.AsString());
}
}
}
}
}
属性值.DataSource = parameterValuelist;
}
}
private void commitButton_Click(object sender, EventArgs e)
{
if (属性名称.SelectedItem != null &&属性值.SelectedItem != null && 类型名称.SelectedItem != null)
{
this.DialogResult = DialogResult.OK;
this.Close();
}
}
}
}
;
4.后台代码的再处理
对后台代码再处理,将ui返回的值传到后台,并根据条件创建楼板。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB.Architecture;
using System.Windows.Forms;
namespace 创建楼板面层
{
[Transaction(TransactionMode.Manual)]
public class CreateFloorSurface : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIDocument uidoc = commandData.Application.ActiveUIDocument;
Document doc = uidoc.Document;
//过滤房间
List<Element> roomList = getRoomList(doc);
if(!(roomList.Count>0))
{
message = "模型中没有绘制房间!";
return Result.Failed;
}
//过滤所有楼板
List<Element> floorList = getFloorList(doc);
if (!(floorList.Count > 0))
{
message = "模型中没有绘制楼板!";
return Result.Failed;
}
//弹出对话框,选择过滤条件和楼板类型
List<string> createSetting = ShowDialog(roomList, floorList);
if(!(createSetting.Count>0))
{
return Result.Cancelled;
}
//获取房间轮廓
List<Element> roomsList = new List<Element>();
List<CurveArray> CuveArrayList = RoomBoundaryList(roomList,createSetting,out roomsList);
if (!(CuveArrayList.Count > 0))
{
message = "模型中的房间没有轮廓!";
return Result.Failed;
}
//绘制楼层面板
FloorType ft = floorList.Where(x => x.Name == createSetting[2]).First() as FloorType;
bool result = CreateSurface(doc, ft, CuveArrayList,roomsList);
if (!result)
{
message = "楼层绘制失败!";
return Result.Failed;
}
return Result.Succeeded;
}
public List<Element> getRoomList(Document doc) //获取所有房间
{
FilteredElementCollector RoomCollector = new FilteredElementCollector(doc);
RoomCollector.OfCategory(BuiltInCategory.OST_Rooms).OfClass(typeof(SpatialElement));//SpatialElement空间元素
List<Element> RoomList = RoomCollector.ToList();
return RoomList;
}
private List<Element> getFloorList(Document doc) //获取楼板集合
{
FilteredElementCollector FloorCollector = new FilteredElementCollector(doc);
FloorCollector.OfCategory(BuiltInCategory.OST_Floors).OfClass(typeof(FloorType));
List<Element> FloorList = FloorCollector.ToList();
return FloorList;
}
private List<CurveArray> RoomBoundaryList(List<Element> roomList,List<string> createSetting,out List<Element> roomToCreate) //获取房间轮廓
{
//通过传入的creatSetting获取指定房间
List<Element> roomsList = new List<Element>();
string paraName = createSetting[0];
string paraValue = createSetting[1];
foreach(Element ele in roomList)
{
ParameterMap paraMap = ele.ParametersMap;
foreach(Parameter para in paraMap)
{
if(para.Definition.Name==paraName)
{
if(para.HasValue)
{
string value;
if (para.StorageType == StorageType.String)
value = para.AsString();
else
value = para.AsString();
if (value == paraValue)
roomsList.Add(ele);
}
}
}
}
List<CurveArray> CurveArrayList = new List<CurveArray>();
roomToCreate = new List<Element>();
foreach(Element element in roomsList)
{
Room room = element as Room;
SpatialElementBoundaryOptions seBoundaryOption = new SpatialElementBoundaryOptions();
CurveArray ca = new CurveArray();
IList<IList<BoundarySegment>> roomBoundaryListList = room.GetBoundarySegments(seBoundaryOption);
List<CurveLoop> curveLoopList = new List<CurveLoop>();
//获取房间的所有边界
if(roomBoundaryListList!=null)
{
foreach(IList<BoundarySegment> roomBoundaryList in roomBoundaryListList)
{
CurveLoop curveLoop = new CurveLoop();
foreach(BoundarySegment roomBoundary in roomBoundaryList)
{
curveLoop.Append(roomBoundary.GetCurve());
}
curveLoopList.Add(curveLoop);
}
}
if (curveLoopList.Count == 0)
continue;
//获取房间边界拉伸体的体积
List<double> volumn = new List<double>();
try
{
foreach(CurveLoop curveLoop in curveLoopList)
{
IList<CurveLoop> cList = new List<CurveLoop>();
cList.Add(curveLoop);
Solid solid = GeometryCreationUtilities.CreateExtrusionGeometry(cList, XYZ.BasisZ, 1);
volumn.Add(solid.Volume);
}
}
catch
{
continue;
}
//通过房间边界拉伸体的体积找出最大轮廓
CurveLoop LargeLoop = curveLoopList.ElementAt(volumn.IndexOf(volumn.Max()));
foreach(Curve curve in LargeLoop)
{
ca.Append(curve);
}
CurveArrayList.Add(ca);
roomToCreate.Add(element);
}
return CurveArrayList;
}
//创建楼板并同步房间和楼板类型
private bool CreateSurface(Document doc,FloorType floorType,List<CurveArray> roomBoundaryList,List<Element> roomsList)
{
double thick = floorType.get_Parameter(BuiltInParameter.FLOOR_ATTR_DEFAULT_THICKNESS_PARAM).AsDouble();
using (Transaction Trans = new Transaction(doc, "生成楼层面板"))
{
Trans.Start();
for(int i=0;i<roomBoundaryList.Count;i++)
{
Floor floor = doc.Create.NewFloor(roomBoundaryList[i],floorType,doc.GetElement(roomsList[i].LevelId)as Level , false);
floor.get_Parameter(BuiltInParameter.FLOOR_HEIGHTABOVELEVEL_PARAM).Set(thick); //更改偏移量
floor.get_Parameter(BuiltInParameter.ALL_MODEL_MARK).Set(roomsList[i].get_Parameter(BuiltInParameter.ROOM_NUMBER).AsString()); //同步房间信息
roomsList[i].get_Parameter(BuiltInParameter.ROOM_FINISH_FLOOR).Set(floorType.Name);
}
Trans.Commit();
}
return true;
}
//创建界面对象,并返回value,其中value包含combox选中的三个值
private List<string> ShowDialog(List<Element> roomList,List<Element> floorList)
{
//获取房间编号,房间属性名称以及楼板类型
List<string> value = new List<string>(); //保存ui返还的值
List<Element> room = new List<Element>();
List<string> roomParametersNames = new List<string>();
List<string> floorTypeNames = new List<string>();
//找出属性名称,属性值,以及楼板类型,并传入给setUi的构造函数
foreach (Element rm in roomList)
{
room.Add(rm);
}
ParameterMap pm = room[0].ParametersMap;
foreach (Parameter pa in pm)
{
if (!roomParametersNames.Contains(pa.Definition.Name))
{
roomParametersNames.Add(pa.Definition.Name);
}
}
foreach (Element el in floorList)
{
floorTypeNames.Add(el.Name);
}
setUi ui = new setUi(room, roomParametersNames, floorTypeNames);
if(ui.ShowDialog() == DialogResult.OK)
{
value.Add(ui.属性名称.SelectedItem.ToString());
value.Add(ui.属性值.SelectedItem.ToString());
value.Add(ui.类型名称.SelectedItem.ToString());
return value;
}
return null;
}
}
}
5.前方高能
神奇的是,ui设计器会出问题???不是很懂问题出在哪里,但是点击“忽略并继续”后,可以成功生成,而且运行也没问题,哪位大佬路过看到了望告知。