元素与族
Revit 的核心是"族"(Family)。族定义了对象的几何形状和元数据,实例化后成为项目中的元素。理解元素和族的创建、修改是关键技能。
Revit 元素体系
Element (所有内容的基类)
├── 模型元素(Model Elements)
│ ├── 系统族(System Family)
│ │ └── Wall, Floor, Roof, Ceiling, Duct, Pipe...
│ ├── 可载入族(Loadable Family)
│ │ └── FamilyInstance → Door, Window, Furniture, Column...
│ └── 内建族(In-Place Family)
│ └── 项目中直接建模的独特构件
├── 基准元素(Datum Elements)
│ ├── Level (标高)
│ └── Grid (轴网)
└── 视图元素(View Elements)
├── ViewPlan (平面图)
├── ViewSection (剖面)
├── View3D (三维视图)
└── ViewSchedule (明细表)🔬 系统族(如基本墙)在 Revit 内部预定义,不能从外部文件载入也不能保存为 .rfa。可载入族可以通过 .rfa 文件交换。
创建元素
创建墙
public Wall CreateWall(Document doc, Curve curve, Level level, WallType wallType)
{
// 计算墙高度
double height = 4000.0 / 304.8; // 4000mm → 英尺
// 创建墙
Wall wall = Wall.Create(
doc,
curve,
wallType.Id,
level.Id,
height,
0.0, // 底部偏移
false, // 是否翻转
false // 是否结构
);
return wall;
}创建楼板
public Floor CreateFloor(Document doc, List<CurveLoop> profile, FloorType floorType, Level level)
{
Floor floor = Floor.Create(
doc,
profile,
floorType.Id,
level.Id
);
return floor;
}
// 构建 CurveLoop(楼板轮廓)
CurveLoop profile = new CurveLoop();
profile.Append(Line.CreateBound(new XYZ(0, 0, 0), new XYZ(10, 0, 0)));
profile.Append(Line.CreateBound(new XYZ(10, 0, 0), new XYZ(10, 10, 0)));
profile.Append(Line.CreateBound(new XYZ(10, 10, 0), new XYZ(0, 10, 0)));
profile.Append(Line.CreateBound(new XYZ(0, 10, 0), new XYZ(0, 0, 0)));放置族实例(门、窗、家具)
public FamilyInstance PlaceFamilyInstance(
Document doc,
FamilySymbol symbol, // 族类型(如 "0915 × 2100mm" 门)
XYZ location, // 插入点
Level level)
{
// 激活族类型
if (!symbol.IsActive)
symbol.Activate();
// 创建实例
FamilyInstance instance = doc.Create.NewFamilyInstance(
location,
symbol,
level,
StructuralType.NonStructural
);
return instance;
}基于线的族(如梁、管线)
public FamilyInstance PlaceBeam(
Document doc,
FamilySymbol beamType,
XYZ startPoint,
XYZ endPoint,
Level level)
{
if (!beamType.IsActive)
beamType.Activate();
FamilyInstance beam = doc.Create.NewFamilyInstance(
Line.CreateBound(startPoint, endPoint),
beamType,
level,
StructuralType.Beam
);
return beam;
}获取族类型
// 获取特定族名称的所有类型
public List<FamilySymbol> GetFamilySymbols(Document doc, string familyName)
{
return new FilteredElementCollector(doc)
.OfClass(typeof(FamilySymbol))
.Cast<FamilySymbol>()
.Where(s => s.FamilyName == familyName)
.ToList();
}
// 根据类别和名称获取族类型
public FamilySymbol? GetFamilySymbol(
Document doc,
BuiltInCategory category,
string familyName,
string typeName)
{
return new FilteredElementCollector(doc)
.OfClass(typeof(FamilySymbol))
.OfCategory(category)
.Cast<FamilySymbol>()
.FirstOrDefault(s => s.FamilyName == familyName && s.Name == typeName);
}
// 获取项目中可用的门类型
var doorTypes = GetFamilySymbols(doc, "单扇门");
foreach (FamilySymbol doorType in doorTypes)
{
Debug.Print($"{doorType.FamilyName} - {doorType.Name}");
}修改元素位置
// 移动元素
public void MoveElement(Document doc, Element element, XYZ translation)
{
ElementTransformUtils.MoveElement(doc, element.Id, translation);
}
// 旋转元素
public void RotateElement(Document doc, Element element, XYZ center, XYZ axis, double angle)
{
Line axisLine = Line.CreateBound(center, center + axis);
ElementTransformUtils.RotateElement(doc, element.Id, axisLine, angle);
}
// 镜像元素
public void MirrorElement(Document doc, Element element, Plane plane)
{
ElementTransformUtils.MirrorElement(doc, element.Id, plane);
}
// 复制元素
public ICollection<ElementId> CopyElements(
Document doc,
ICollection<ElementId> elementIds,
XYZ translation)
{
return ElementTransformUtils.CopyElements(
doc,
elementIds,
translation
);
}删除元素
// 删除单个元素
public void DeleteElement(Document doc, ElementId id)
{
doc.Delete(id);
}
// 批量删除
public void DeleteElements(Document doc, ICollection<ElementId> ids)
{
doc.Delete(ids);
}
// 检查元素是否可以被删除
// (有些系统族类型、当前活动的 Level 等不可删除)🚨 删除操作必须在事务中进行。删除后元素 ID 立即失效,后续引用会导致异常。
标高与轴网
// 创建标高
public Level CreateLevel(Document doc, double elevationMeters)
{
double elevationFeet = elevationMeters / 0.3048;
Level level = Level.Create(
doc,
elevationFeet
);
// 设置名称
level.Name = $"Level {elevationMeters:F1}m";
return level;
}
// 获取所有标高(从低到高排序)
public List<Level> GetAllLevels(Document doc)
{
return new FilteredElementCollector(doc)
.OfClass(typeof(Level))
.Cast<Level>()
.OrderBy(l => l.Elevation)
.ToList();
}
// 获取最近的标高
public Level? GetNearestLevel(Document doc, double elevationFeet)
{
return GetAllLevels(doc)
.OrderBy(l => Math.Abs(l.Elevation - elevationFeet))
.FirstOrDefault();
}
// 创建轴网
public Grid CreateGrid(Document doc, XYZ start, XYZ end, string name)
{
Line line = Line.CreateBound(start, end);
Grid grid = Grid.Create(doc, line);
grid.Name = name;
return grid;
}获取元素的几何数据
public void ExtractGeometry(Element element)
{
Options geomOptions = new Options
{
ComputeReferences = true,
IncludeNonVisibleObjects = false,
DetailLevel = ViewDetailLevel.Medium
};
GeometryElement geomElem = element.get_Geometry(geomOptions);
foreach (GeometryObject geomObj in geomElem)
{
// 实体(Solid)—— 具有体积
if (geomObj is Solid solid && solid.Volume > 0)
{
double volume = solid.Volume;
double surfaceArea = solid.SurfaceArea;
foreach (Face face in solid.Faces)
{
double faceArea = face.Area;
}
}
// 线(Line)—— 基于线的元素
if (geomObj is Line line)
{
XYZ start = line.GetEndPoint(0);
XYZ end = line.GetEndPoint(1);
double length = line.Length;
}
// 几何实例(GeometryInstance)—— 嵌套族
if (geomObj is GeometryInstance instance)
{
GeometryElement instanceGeom = instance.GetInstanceGeometry();
// 递归处理
}
}
}BoundingBox —— 包围盒
// 获取当前视图中的包围盒
BoundingBoxXYZ bbox = element.get_BoundingBox(doc.ActiveView);
if (bbox != null)
{
XYZ min = bbox.Min; // 左下前角
XYZ max = bbox.Max; // 右上后角
XYZ center = (min + max) / 2;
}
// 获取元素的包围盒(需要传入视图 null 获取模型坐标)
BoundingBoxXYZ bbox2 = element.get_BoundingBox(null);元素 ID 核心概念
Revit 中有多种标识符,每次打开项目可能变化:
| 类型 | 属性 | 说明 |
|---|---|---|
ElementId |
element.Id |
会话内唯一,关闭文档后失效 |
UniqueId |
element.UniqueId |
永久唯一,跨会话稳定(推荐持久化引用时使用) |
IntegerValue |
element.Id.IntegerValue |
32 位整数值 |
// 通过 UniqueId 获取元素(跨文档持久化引用)
string uid = "6a7b8c9d-1234-5678-...";
Element element = doc.GetElement(uid); // 通常返回 null,需用其他方式
// UniqueId 格式包含 EpisodeId,通常用于 IFC 导出
// 跨会话持久化推荐存储 (CategoryId, TypeName, Level, Location) 组合信息重组💡 如果要跨 Revit 会话持久化引用某个元素,不要存储
ElementId。存储元素的位置信息、类型和 UniqueId,在重新打开文档时通过这些信息重组查找。