族文档

本节讨论族以及如何:

  • 创建和修改族文档
  • 访问族类型和参数

本节中的页面

  • 关于族文档
  • 在族中创建图元
  • 族元素的可见性
  • 管理族类型和参数

关于族文档

族对象表示整个Revit族。族文档是表示族的文档(rfa)而不是Revit项目。

使用Revit API的族创建功能,可以创建和编辑族及其类型。当您有来自外部系统的现有数据并希望将其转换为Revit族库时,此功能特别有用。

对系统族编辑的API访问不可用。

类别

如前一节所述,Family.FamilyCategory属性指示族的类别,如柱、家具、结构框架或窗。

以下代码可用于确定打开的Revit族文档中族的类别。

1
string categoryName = familyDoc.OwnerFamily.FamilyCategory.Name;

还可以设置FamilyCategory,以允许更改正在编辑的族的类别。

参数设置 可以从族文档的OwnerFamily属性访问族参数,如下例所示。

代码区域13-2:打开的Revit族文档的类别

1
2
3
4
5
6
7
// get the owner family of the family document.
Family family = familyDoc.OwnerFamily;
Parameter param = family.get_Parameter(BuiltInParameter.FAMILY_WORK_PLANE_BASED);
// this param is a Yes/No parameter in UI, but an integer value in API
// 1 for true and 0 for false
int isTrue = param.AsInteger();
// param.Set(1); // set value to true.

创建族文档

如果文档是族文档(由IsFamilyDocument属性确定),则可以通过Document类修改Revit族文档并访问族类型和参数。若要在处理Project文档时编辑现有族,请使用Document类中提供的EditFamily()函数,然后在编辑完成后使用LoadFamily()将族重新加载回所有者文档。要创建新的族文档,请使用Application.NewFamilyDocument():

代码区域13-3:创建新的族文档

1
2
3
4
5
6
7
8
// create a new family document using Generic Model.rft template
string templateFileName = @"C:\Documents and Settings\All Users\Application Data\Autodesk\RST 2011\Imperial Templates\Generic Model.rft";

Document familyDocument = application.NewFamilyDocument(templateFileName);
if (null == familyDocument)
{
throw new Exception("Cannot open family document");
}

嵌套族符号

可以过滤FamilySymbols的族文档,以将所有FamilySymbols加载到族中。在此代码示例中,列出了给定FamilyInstance的族中的所有嵌套FamilySymbol。

代码区域13-4:在族中获取嵌套的族符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public void GetLoadedSymbols(Autodesk.Revit.DB.Document document, FamilyInstance familyInstance)
{
if (null != familyInstance.Symbol)
{
// Get family associated with this
Family family = familyInstance.Symbol.Family;

// Get Family document for family
Document familyDoc = document.EditFamily(family);
if (null != familyDoc && familyDoc.IsFamilyDocument == true)
{
String loadedFamilies = "FamilySymbols in " + family.Name + ":\n";
FilteredElementCollector collector = new FilteredElementCollector(document);
ICollection collection =
collector.OfClass(typeof(FamilySymbol)).ToElements();
foreach (Element e in collection)
{
FamilySymbol fs = e as FamilySymbol;
loadedFamilies += "\t" + fs.Name + "\n";
}

TaskDialog.Show("Revit",loadedFamilies);
}
}
}

在族中创建元素

FamilyItemFactory类提供了在族文档中创建图元的功能。可以通过Document.FamilyCreate属性访问它。FamilyItemFactory派生自ItemFactoryBase类,该类是一个实用的用于在Revit项目文档和族文档中创建元素。

本节中的页面

  • 创建表单元素
  • 创建注释

创建形状元素

FamilyItemFactory类提供了在族中创建形状图元的功能,例如拉伸、旋转、放样和融合。有关这些3D草图表格的更多信息,请参见3D草图部分。

下面的示例演示如何创建新的Extrusion元素。它将创建一个简单的矩形截面轮廓,然后将新创建的“拉伸”移动到新位置。

代码区域:创建新拉伸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
private Extrusion CreateExtrusion(Autodesk.Revit.DB.Document document, SketchPlane sketchPlane)
{
Extrusion rectExtrusion = null;

// make sure we have a family document
if (true == document.IsFamilyDocument)
{
// define the profile for the extrusion
CurveArrArray curveArrArray = new CurveArrArray();
CurveArray curveArray1 = new CurveArray();
CurveArray curveArray2 = new CurveArray();
CurveArray curveArray3 = new CurveArray();

// create a rectangular profile
XYZ p0 = XYZ.Zero;
XYZ p1 = new XYZ(10, 0, 0);
XYZ p2 = new XYZ(10, 10, 0);
XYZ p3 = new XYZ(0, 10, 0);
Line line1 = Line.CreateBound(p0, p1);
Line line2 = Line.CreateBound(p1, p2);
Line line3 = Line.CreateBound(p2, p3);
Line line4 = Line.CreateBound(p3, p0);
curveArray1.Append(line1);
curveArray1.Append(line2);
curveArray1.Append(line3);
curveArray1.Append(line4);

curveArrArray.Append(curveArray1);

// create solid rectangular extrusion
rectExtrusion = document.FamilyCreate.NewExtrusion(true, curveArrArray, sketchPlane, 10);

if (null != rectExtrusion)
{
// move extrusion to proper place
XYZ transPoint1 = new XYZ(-16, 0, 0);
ElementTransformUtils.MoveElement(document, rectExtrusion.Id, transPoint1);
}
else
{
throw new Exception("Create new Extrusion failed.");
}
}
else
{
throw new Exception("Please open a Family document before invoking this command.");
}

return rectExtrusion;
}

以下示例显示了如何从族文档中的实心卵形轮廓创建新放样。

代码区域:创建新放样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
private Sweep CreateSweep(Autodesk.Revit.DB.Document document, SketchPlane sketchPlane)
{
Sweep sweep = null;

// make sure we have a family document
if (true == document.IsFamilyDocument)
{
// Define a profile for the sweep
CurveArrArray arrarr = new CurveArrArray();
CurveArray arr = new CurveArray();

// Create an ovoid profile
XYZ pnt1 = new XYZ(0, 0, 0);
XYZ pnt2 = new XYZ(2, 0, 0);
XYZ pnt3 = new XYZ(1, 1, 0);
arr.Append(Arc.Create(pnt2, 1.0d, 0.0d, 180.0d, XYZ.BasisX, XYZ.BasisY));
arr.Append(Arc.Create(pnt1, pnt3, pnt2));
arrarr.Append(arr);
SweepProfile profile = document.Application.Create.NewCurveLoopsProfile(arrarr);

// Create a path for the sweep
XYZ pnt4 = new XYZ(10, 0, 0);
XYZ pnt5 = new XYZ(0, 10, 0);
Curve curve = Line.CreateBound(pnt4, pnt5);

CurveArray curves = new CurveArray();
curves.Append(curve);

// create a solid ovoid sweep
sweep = document.FamilyCreate.NewSweep(true, curves, sketchPlane, profile, 0, ProfilePlaneLocation.Start);

if (null != sweep)
{
// move to proper place
XYZ transPoint1 = new XYZ(11, 0, 0);
ElementTransformUtils.MoveElement(document, sweep.Id, transPoint1);
}
else
{
throw new Exception("Failed to create a new Sweep.");
}
}
else
{
throw new Exception("Please open a Family document before invoking this command.");
}

return sweep;
}

图50:由上一个示例创建的卵形扫描

FreeFormElement类允许创建从输入实体轮廓创建的非参数化几何体。FreeFormElement可以与其他可组合元素一起参与连接和空切割。元素的平面可以在面法线方向上以交互方式和编程方式偏移。

将子类别转换为形状 在族中创建新形状后,可能需要修改形状的子类别。例如,您可能有一个门族,并且希望创建多个门的子类别,并将不同的子类别指定给族中的不同门类型。 下面的示例演示如何创建新的子类别,为其指定材质,然后将该子类别指定给窗体。

代码区域:指定子类别

1
2
3
4
5
6
7
8
9
10
11
12
13
public void AssignSubCategory(Document document, GenericForm extrusion)
{
// create a new subcategory
Category cat = document.OwnerFamily.FamilyCategory;
Category subCat = document.Settings.Categories.NewSubcategory(cat, "NewSubCat");

// create a new material and assign it to the subcategory
ElementId materialId = Material.Create(document, "Wood Material");
subCat.Material = document.GetElement(materialId) as Material;

// assign the subcategory to the element
extrusion.Subcategory = subCat;
}

创建注释

还可以在族中创建新注释(例如尺寸标注和ModelText和TextNote对象)以及曲线注释元素(例如SymbolicCurve、ModelCurve和DetailCurve)。有关注释元素的详细信息,请参见注释元素。

此外,还可以添加新路线,并参照确定路线方向的视图和两个几何图形参照。

以下示例演示如何创建新的弧长标注。

代码区域:创建标注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Dimension CreateArcDimension(Document document, SketchPlane sketchPlane)
{
Autodesk.Revit.Creation.Application appCreate = document.Application.Create;
Line gLine1 = Line.CreateBound(new XYZ(0, 2, 0), new XYZ(2, 2, 0));
Line gLine2 = Line.CreateBound(new XYZ(0, 2, 0), new XYZ(2, 4, 0));
Arc arctoDim = Arc.Create(new XYZ(1, 2, 0), new XYZ(-1, 2, 0), new XYZ(0, 3, 0));
Arc arcofDim = Arc.Create(new XYZ(0, 3, 0), new XYZ(1, 2, 0), new XYZ(0.8, 2.8, 0));

Autodesk.Revit.Creation.FamilyItemFactory creationFamily = document.FamilyCreate;
ModelCurve modelCurve1 = creationFamily.NewModelCurve(gLine1, sketchPlane);
ModelCurve modelCurve2 = creationFamily.NewModelCurve(gLine2, sketchPlane);
ModelCurve modelCurve3 = creationFamily.NewModelCurve(arctoDim, sketchPlane);
//get their reference
Reference ref1 = modelCurve1.GeometryCurve.Reference;
Reference ref2 = modelCurve2.GeometryCurve.Reference;
Reference arcRef = modelCurve3.GeometryCurve.Reference;

Dimension newArcDim = creationFamily.NewArcLengthDimension(document.ActiveView, arcofDim, arcRef, ref1, ref2);
if (newArcDim == null)
{
throw new Exception("Failed to create new arc length dimension.");
}

return newArcDim;
}

图51:产生的弧长尺寸

某些类型的尺寸标注可以使用FamilyParameter进行标记。如果尝试获取或设置Label属性,则无法标记的尺寸标注将引发Autodesk.Revit. Revit.InvalidOperationException。在下面的示例中,在两条线之间创建了一个新的线性尺寸标注,并将其标记为“width”。

代码区域:标注尺寸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public Dimension CreateLinearDimension(Document document)
{
// first create two lines
XYZ pt1 = new XYZ(5, 5, 0);
XYZ pt2 = new XYZ(5, 10, 0);
Line line = Line.CreateBound(pt1, pt2);
Plane plane = Plane.CreateByNormalAndOrigin(pt1.CrossProduct(pt2), pt2);
SketchPlane skplane = SketchPlane.Create (document, plane);
ModelCurve modelcurve1 = document.FamilyCreate.NewModelCurve(line, skplane);

pt1 = new XYZ(10, 5, 0);
pt2 = new XYZ(10, 10, 0);
line = Line.CreateBound(pt1, pt2);
plane = Plane.CreateByNormalAndOrigin(pt1.CrossProduct(pt2), pt2);
skplane = SketchPlane.Create (document, plane);
ModelCurve modelcurve2 = document.FamilyCreate.NewModelCurve(line, skplane);

// now create a linear dimension between them
ReferenceArray ra = new ReferenceArray();
ra.Append(modelcurve1.GeometryCurve.Reference);
ra.Append(modelcurve2.GeometryCurve.Reference);

pt1 = new XYZ(5, 10, 0);
pt2 = new XYZ(10, 10, 0);
line = Line.CreateBound(pt1, pt2);

Dimension dim = document.FamilyCreate.NewLinearDimension(document.ActiveView, line, ra);

// create a label for the dimension called "width"
FamilyParameter param = document.FamilyManager.AddParameter("width",
BuiltInParameterGroup.PG_CONSTRAINTS,
ParameterType.Length, false);

dim.FamilyLabel = param;

return dim;
}

图52:标记的线性尺寸

族元素的可见性

FamilyElementVisibility类可用于控制族图元在项目文档中的可见性。例如,如果有门族,则可能只希望门开启方向在放置门的项目文档的平面视图中可见,而在三维视图中不可见。通过设置门开启方向的可见性,您可以控制其可见性。FamilyElementVisibility适用于以下具有SetVisibility()函数的族图元类:

  • GenericForm
  • SymbolicCurve
  • ModelText
  • CurveByPoints
  • ModelCurve
  • ReferencePoint
  • ImportInstance

在下面的示例中,生成的族文档将显示文本“Hello World”,其下有一条线。当族载入到Revit项目文档中并放置实例时,在平面视图中,只有该线可见。在3D视图中,将同时显示线条和文本,除非将“详细程度”设置为“粗”,在这种情况下,线条将消失。

代码区域13-10:设置族图元可见性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public void CreateAndSetVisibility(Autodesk.Revit.DB.Document familyDocument, SketchPlane sketchPlane)
{
// create a new ModelCurve in the family document
XYZ p0 = new XYZ(1, 1, 0);
XYZ p1 = new XYZ(5, 1, 0);
Line line1 = Line.CreateBound(p0, p1);

ModelCurve modelCurve1 = familyDocument.FamilyCreate.NewModelCurve(line1, sketchPlane);

// create a new ModelText along ModelCurve line
ModelText text = familyDocument.FamilyCreate.NewModelText("Hello World", null, sketchPlane, p0, HorizontalAlign.Center, 0.1);

// set visibility for text
FamilyElementVisibility textVisibility = new FamilyElementVisibility(FamilyElementVisibilityType.Model);
textVisibility.IsShownInTopBottom = false;
text.SetVisibility(textVisibility);

// set visibility for line
FamilyElementVisibility curveVisibility = new FamilyElementVisibility(FamilyElementVisibilityType.Model);
curveVisibility.IsShownInCoarse = false;
modelCurve1.SetVisibility(curveVisibility);

}

管理族类型和参数

族文档提供对FamilyManager属性的访问。FamilyManager类提供对族类型和参数的访问。使用此类,可以添加和删除类型、添加和删除族参数和共享参数、设置不同族类型中的参数值以及定义公式来驱动参数值。

在族中获取种类

FamilyManager可用于遍历族中的种类,如下例所示。

代码区域13-11:获取族中的种类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void GetFamilyTypesInFamily(Document familyDoc)
{
if (familyDoc.IsFamilyDocument)
{
FamilyManager familyManager = familyDoc.FamilyManager;

// get types in family
string types = "Family Types: ";
FamilyTypeSet familyTypes = familyManager.Types;
FamilyTypeSetIterator familyTypesItor = familyTypes.ForwardIterator();
familyTypesItor.Reset();
while (familyTypesItor.MoveNext())
{
FamilyType familyType = familyTypesItor.Current as FamilyType;
types += "\n" + familyType.Name;
}
TaskDialog.Show("Revit",types);
}
}

图53:混凝土矩形柱族中的族种类

编辑族种类

FamilyManager提供了遍历族中现有种类以及添加和修改种类及其参数的功能。

下面的示例演示如何添加新种类(familysymbol),设置其参数,然后将新种类分配给FamilyInstance。种类编辑是通过使用Set()函数在当前种类上完成的。当前种类可从CurrentType属性获得。CurrentType属性可用于在编辑之前设置当前种类,或使用NewType()函数创建新种类并将其设置为当前种类以进行编辑。

请注意,一旦创建并修改了新种类,就会使用Document.LoadFamily()将族重新载入到Revit项目中,以使新种类可用。

代码区域13-12:编辑族类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
public void EditFamilyTypes(Document document, FamilyInstance familyInstance)
{
// example works best when familyInstance is a rectangular concrete element

if ((null == document) || (null == familyInstance.Symbol))
{
return; // invalid arguments
}

// Get family associated with this
Family family = familyInstance.Symbol.Family;
if (null == family)
{
return; // could not get the family
}

// Get Family document for family
Document familyDoc = document.EditFamily(family);
if (null == familyDoc)
{
return; // could not open a family for edit
}

FamilyManager familyManager = familyDoc.FamilyManager;
if (null == familyManager)
{
return; // cuould not get a family manager
}

// Start transaction for the family document
using (Transaction newFamilyTypeTransaction = new Transaction(familyDoc, "Add Type to Family"))
{
int changesMade = 0;
newFamilyTypeTransaction.Start();

// add a new type and edit its parameters
FamilyType newFamilyType = familyManager.NewType("2X2");

if (newFamilyType != null)
{
// look for 'b' and 'h' parameters and set them to 2 feet
FamilyParameter familyParam = familyManager.get_Parameter("宽度");
if (null != familyParam)
{
familyManager.Set(familyParam, 2.0);
changesMade += 1;
}

familyParam = familyManager.get_Parameter("高度");
if (null != familyParam)
{
familyManager.Set(familyParam, 2.0);
changesMade += 1;
}
}

if (2 == changesMade) // set both paramaters?
{
newFamilyTypeTransaction.Commit();
}
else // could not make the change -> should roll back
{
newFamilyTypeTransaction.RollBack();
}

// if could not make the change or could not commit it, we return
if (newFamilyTypeTransaction.GetStatus() != TransactionStatus.Committed)
{
return;
}
}

// now update the Revit project with Family which has a new type
LoadOpts loadOptions = new LoadOpts();

// This overload is necessary for reloading an edited family
// back into the source document from which it was extracted
family = familyDoc.LoadFamily(document, loadOptions);
if (null != family)
{
// find the new type and assign it to FamilyInstance
ISet familySymbolIds = family.GetFamilySymbolIds();
foreach (ElementId id in familySymbolIds)
{
FamilySymbol familySymbol = family.Document.GetElement(id) as FamilySymbol;
if ((null != familySymbol) && familySymbol.Name == "2X2")
{
using (Transaction changeSymbol = new Transaction(document, "Change Symbol Assignment"))
{
changeSymbol.Start();
familyInstance.Symbol = familySymbol;
changeSymbol.Commit();
}
break;
}
}
}
}

class LoadOpts : 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.Family;
overwriteParameterValues = true;
return true;
}
}

FamilyManager类提供对所有族参数的访问。这包括族内置参数、类别内置参数和与族类型关联的共享参数。有两种方法可以获取族参数:

  • Parameters property - 获取族中的所有参数
  • GetParameters()-按族中所有参数在Revit UI中出现的顺序获取这些参数使用GetParameters()方法时,Revit UI顺序首先按组确定,然后按各个参数的顺序确定。

可以从给定族的API(不支持重新排序参数的钢筋形状族除外)重新排序(在其组内)族参数。这允许参数以最符合逻辑的顺序呈现给用户。排序仅影响同一参数组中的可见参数。属于不同组的参数将保持分离,并且组的顺序不会受到影响。

对参数重新排序的最简单方法是使用FamilyManager.SortParameters()方法,该方法接受一个指示所需排序顺序的参数。下面的示例按升序对参数进行排序。

代码区域:对族参数排序

1
2
3
4
5
private void DisplayParametersInAscendingOrder(Document familyDoc)
{
FamilyManager familyManager = familyDoc.FamilyManager;
familyManager.SortParameters(ParametersOrder.Ascending);
}

注意:排序是一次性操作。当添加新参数时,它们不会自动排序。若要对参数的排序方式进行更多控制,请使用FamilyManager.ReorderParameters()方法,该方法以新顺序接受族参数列表。此列表必须包含GetParameters()方法返回的所有参数,包括任何不可见的参数,否则将引发异常。

注:翻译自Revit API Developers Guide