材质

在Revit Platform API中,材质数据作为图元进行存储和管理。就像在Revit UI中一样,材质可以有多个与之关联的资源,但只能使用API指定热学和结构(在Revit UI中称为物理)资源。

某些材质特征由材质类本身的属性(例如FillPattern、Color或Render)表示,而其他材质特征则可用作与材质关联的结构资源或热资源的属性。

在本章中,您将学习如何访问Material元素以及如何管理文档中的Material对象。“元素材质”提供了一个演练,演示如何获取窗材质。

本节中的页面

  • 一般材质信息
  • 材质管理
  • 元素材质
  • 材质数量
  • 绘制元素的表面

一般材质信息

在开始演练之前,请通读以下部分以更好地理解Material类。

所有材质对象都可以使用材质类过滤器进行检索。材质对象也可在文档、类别、元素、面等中使用,并在本章的相关部分中进行讨论。无论你在哪里得到一个材质对象,它都被表示为Material类。

属性

材质将具有与渲染外观、结构或其他主要材质类别相关的一个或多个方面。每个方面都由Material类本身的属性或通过其结构或热资产之一表示。StructuralAsset类表示与结构分析相关的材料属性。ThermalAsset类表示与能量分析相关的材料属性。

代码区域19-3:获取材料属性

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
private void ReadMaterialProps(Document document, Material material)
{
ElementId strucAssetId = material.StructuralAssetId;
if (strucAssetId != ElementId.InvalidElementId)
{
PropertySetElement pse = document.GetElement(strucAssetId) asPropertySetElement;
if (pse != null)
{
StructuralAsset asset = pse.GetStructuralAsset();

// Check the material behavior and only read if Isotropic
if (asset.Behavior == StructuralBehavior.Isotropic)
{
// Get the class of material
StructuralAssetClass assetClass = asset.StructuralAssetClass; // Get other material properties

// Get other material properties
double poisson = asset.PoissonRatio.X;
double youngMod = asset.YoungModulus.X;
double thermCoeff = asset.ThermalExpansionCoefficient.X;
double unitweight = asset.Density;
double shearMod = asset.ShearModulus.X;
double dampingRatio = asset.DampingRatio;
if (assetClass == StructuralAssetClass.Metal)
{
double dMinStress = asset.MinimumYieldStress;
}
elseif (assetClass == StructuralAssetClass.Concrete)
{
double dConcComp = asset.ConcreteCompression;
}
}
}
}
}

Classification

与结构分析相关的材料分类(即钢、混凝土、木材)可以从与材料关联的StructuralAsset的StructuralAssetClass属性中获得。

注意:API不提供对混凝土材料的混凝土类型值的访问。

与能量分析相关的材料分类(即固体、液体、气体)可以从与材料关联的ThermalAsset的ThermalMaterialType属性中获得。

其它性质

材质对象属性标识特定类型的材质,包括颜色、填充图案等。

属性和参数

某些“材质”属性只能作为“参数”使用。有一些,如颜色,可作为属性或作为参数使用内置参数MATERIAL_PARAM_COLOR。

渲染信息

渲染数据的集合被组织到称为资源的对象中,这些对象是只读的。您可以从Application.Assets属性获取所有可用的与外观相关的资产。可以通过Material.AppearanceAssetId属性从材质访问外观资源。

下图显示了“资源浏览器”对话框的“外观库”部分,其中显示了某些渲染资源在UI中的显示方式。

图106:外观库

SDK附带的Materials示例应用程序显示了如何将RenderApperance属性设置为对话框中选定的材质。该对话框将填充Application.Assets中的所有Asset对象。

填充模式

文档中的所有FillPatterns都可以使用FilteredElementCollector过滤类FillPatternElement。FillPatternElement是包含FillPattern的元素,而FillPattern类提供对模式名称和组成模式的FillGrid集的访问。

FillPatterns有两种:Drafting和Model。在UI中,只能将“绘图”填充样式设置为Material.CutPatternId。填充图案类型通过FillPattern.Target属性公开。下面的示例显示如何更改材质FillPattern。

代码区域19-4:设置填充图案

1
2
3
4
5
6
7
8
9
10
11
public void SetFillPattern(Document document, Material material)
{
FilteredElementCollector collector = new FilteredElementCollector(document);
ICollection fillPatternElements = collector.OfClass(typeof(FillPatternElement)).ToElementIds();
foreach (ElementId fillPatternId in fillPatternElements)
{
// always set successfully
material.CutPatternId = fillPatternId;
material.SurfacePatternId = fillPatternId;
}
}

材质管理

您可以使用过滤来检索文档中的所有材料。文档中的每个Material对象都由唯一的名称标识。

以下示例说明如何使用材质名称获取材质。

代码区域19-5:按名称获取材质

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FilteredElementCollector elementCollector = new FilteredElementCollector(document);
elementCollector.WherePasses(new ElementClassFilter(typeof(Material)));
IList materials = elementCollector.ToElements();

Material floorMaterial = null;
string floorMaterialName = "Default Floor";

foreach (Element materialElement in materials)
{
Material material = materialElement as Material;
if (floorMaterialName == material.Name)
{
floorMaterial = material;
break;
}
}
if (null != floorMaterial)
{
TaskDialog.Show("Revit","Material found.");
}

注意:要运行示例代码,请确保文档中存在材质名称。当前文档的所有材质名称都位于“管理”选项卡(“项目设置”面板 Materials)下。

创建材质

有两种方法可以在API中创建新的Material对象。

  • 复制现有材质
  • 添加新材质。

使用Duplicate()方法时,返回的Material对象与原始对象的类型相同。

代码区域19-6:复制材料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private bool DuplicateMaterial(Material material)
{
bool duplicated = false;
//try to duplicate a new instance of Material class using duplicate method
//make sure the name of new material is unique in MaterailSet
string newName = "new" + material.Name;
Material myMaterial = material.Duplicate(newName);
if (null == myMaterial)
{
TaskDialog.Show("Revit", "Failed to duplicate a material!");
}
else
{
duplicated = true;
}

return duplicated;
}

使用静态方法Material.Create()直接添加新Material。无论如何应用,都必须为材质和属于该材质的任何资产指定唯一的名称。唯一名称是“材质”对象键。

代码区域19-7:添加新材质

1
2
3
4
5
6
7
8
9
10
11
12
//Create the material
ElementId materialId = Material.Create(document, "My Material");
Material material = document.GetElement(materialId) as Material;

//Create a new property set that can be used by this material
StructuralAsset strucAsset = new StructuralAsset("My Property Set", StructuralAssetClass.Concrete);
strucAsset.Behavior = StructuralBehavior.Isotropic;
strucAsset.Density = 232.0;

//Assign the property set to the material.
PropertySetElement pse = PropertySetElement.Create(document, strucAsset);
material.SetMaterialAspectByPropertySet(MaterialAspect.Structural, pse.Id);

删除材质

要删除材料,用:

  • Document.Delete()

Document.Delete() 是一个泛型方法。有关详细信息,请参见编辑元素。

元素材质

一个元素可以有多个元素和组件。例如,FamilyInstance具有SubComponents,Wall具有CompoundStructure,其中包含多个CompoundStructureLayers。(有关“子构件”的详细信息,请参阅“族”部分,有关“复合结构”的详细信息,请参阅“墙、楼板、屋顶和洞口”。)

在Revit Platform API中,使用以下准则获取图元的材质:

  • 如果元素包含元素,则单独获取材料。
  • 如果图元包含构件,请从参数或以特定方式获取每个构件的材质(请参见墙、楼板、屋顶和洞口中的“材质”部分)。
  • 如果构件的材质返回null,则从相应的Element.Category子类别中获取物料。

参数中的材质

如果Element对象有一个参数,其中的参数类型是参数类型.材料,您可以从参数中获取元素材料。例如,结构柱FamilySymbol(类别为BuiltInCategory.OST_StructuralColumns的FamilyInstance)具有“结构材质”参数。使用ElementId获取材质。下面的代码示例阐释如何获取具有一个构件的结构柱Material。

代码区域:从参数获取元素材质

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
public void GetMaterial(Document document, FamilyInstance familyInstance)
{
foreach (Parameter parameter in familyInstance.Parameters)
{
Definition definition = parameter.Definition;
// material is stored as element id
if (parameter.StorageType == StorageType.ElementId)
{
if (definition.ParameterGroup == BuiltInParameterGroup.PG_MATERIALS &&
definition.ParameterType == ParameterType.Material)
{
Autodesk.Revit.DB.Material material = null;
Autodesk.Revit.DB.ElementId materialId = parameter.AsElementId();
if (-1 == materialId.IntegerValue)
{
//Invalid ElementId, assume the material is "By Category"
if (null != familyInstance.Category)
{
material = familyInstance.Category.Material;
}
}
else
{
material = document.GetElement(materialId) as Material;
}

TaskDialog.Show("Revit","Element material: " + material.Name);
break;
}
}
}
}

注意:如果在UI中将材质属性设置为“按类别”,则材质的ElementId为ElementId.InvalidElementId,并且不能用于检索Material对象,如示例代码中所示。尝试从类别中检索材质,如下一节所述。 其他化合物参数中包含的某些材质特性无法从API访问。例如,在下图中,对于“系统族:栏杆扶手”,“栏杆结构”参数的“栏杆类型”为“栏杆类型.无”。因此,在这种情况下,您无法获得实质性信息。

图107:扶手结构属性

Material和FamilyInstance 梁族、柱族和基础族有另一种使用其StructuralMaterialId属性获取其材质的方法。此属性返回一个ElementId,用于标识定义实例的结构分析属性的材质。

代码区域:从族实例获取图元材质

1
2
3
4
5
6
public Material GetFamilyInstanceMaterial(Document document, FamilyInstance beam)
{
Material material = document.GetElement(beam.StructuralMaterialId) as Material;

return material;
}

材质和类别

只有模型图元可以具有材质。

从Revit的“管理”选项卡中,单击“设置” img “对象样式”以显示“对象样式”对话框。类别列在“模型对象”(Model Objects)选项卡中的图元具有材质信息。

img

图108:材质分类

只有模型元素可以指定“材质”属性。因此,查询与Model元素(例如,Annotations或Imported)以外的元素相对应的类别的Material将始终导致null。有关元素和类别分类的更多详细信息,请参阅元素要素。

如果一个元素有多个组件,则某些类别.子类别对应于这些组件。

在上一个“对象样式”对话框中,“窗类别”和“框架/竖梃”子类别以及“玻璃”子类别将映射到windows元素中的构件。在下图中,似乎窗符号Glass材质参数是获取窗玻璃材质的唯一方法。但是,该值为“按类别”,相应的参数返回ElementId. InvalidElementId。

在这种情况下,窗户的Material不为null,它取决于Category OST_WindowsFrameMullionProjection的Material属性,该属性是窗口类别OST_Windows的子类别。如果它也返回null,则窗格的Material由父类别OST_Windows确定。有关更多详细信息,请参阅元素材质。

图109:窗户材料

复合结构层材料

可以从HostObjAttributes获取CompoundStructureLayer对象。有关详细信息,请参阅墙、地板、天花板、屋顶和洞口。

电子元件材料

下图显示了检索元素材质的工作流:

图110:获取元素材质工作流

此工作流说明了以下过程:

  • 该工作流显示了如何获取属于图元的Material对象(而不是Autodesk.Revit.DB.Structure.StructuralMaterialType枚举类型)。
  • 检索材质时有两种要素分类:
    • HostObject with CompoundStructure -从CompoundStructureLayer类MaterialId属性获取Material对象。
    • 其他-从参数中获取材质。
  • 当您获得空Material对象或值为ElementId.InvalidElementId的无效ElementId时,请尝试相应类别中的Material。请注意,FamilyInstance及其FamilySymbol通常具有相同的类别。
  • 对Element对象了解得越多,获取材质就越容易。举例来说:
    • 如果知道元素是梁,则可以获取实例参数Structural Material
    • 如果知道该元素是一个窗口,则可以将其强制转换为FamilyInstance并获取FamilySymbol。
  • 之后,您可以获得参数,如框架外部材料或框架内部材料,以获得材料对象。如果你得到null,尝试从FamilySymbol类别中获取Material对象。
  • API中并非所有元素材质都可用。

演练:获取窗户材质

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
public void GetMaterial(Document document, FamilyInstance window)
{
FamilySymbol windowSymbol = window.Symbol;
Category category = windowSymbol.Category;
Autodesk.Revit.DB.Material frameExteriorMaterial = null;
Autodesk.Revit.DB.Material frameInteriorMaterial = null;
Autodesk.Revit.DB.Material sashMaterial = null;
// Check the parameters first
foreach (Parameter parameter in windowSymbol.Parameters)
{
switch (parameter.Definition.Name)
{
case "Frame Exterior Material":
frameExteriorMaterial = document.GetElement(parameter.AsElementId()) as Material;
break;
case "Frame Interior Material":
frameInteriorMaterial = document.GetElement(parameter.AsElementId()) as Material;
break;
case "Sash":
sashMaterial = document.GetElement(parameter.AsElementId()) as Material;
break;
default:
break;
}
}
// Try category if the material is set by category
if (null == frameExteriorMaterial)
frameExteriorMaterial = category.Material;
if (null == frameInteriorMaterial)
frameInteriorMaterial = category.Material;
if (null == sashMaterial)
sashMaterial = category.Material;
// Show the result because the category may have a null Material,
// the Material objects need to be checked.
string materialsInfo = "Frame Exterior Material: " + (null != frameExteriorMaterial ? frameExteriorMaterial.Name : "null") + "\n";
materialsInfo += "Frame Interior Material: " + (null != frameInteriorMaterial ? frameInteriorMaterial.Name : "null") + "\n";
materialsInfo += "Sash: " + (null != sashMaterial ? sashMaterial.Name : "null") + "\n";
TaskDialog.Show("Revit",materialsInfo);
}

材质数量

有一些方法可以直接获取Revit为材质提取明细表计算的材质体积和面积:

  • Element.GetMaterialIds() –获取元素中的材料列表
  • Element.GetMaterialVolume() – 获取元素中特定材料的体积
  • Element.GetMaterialArea() – 获取元素中特定材质的面积

这些方法适用于其中Category. HasMaterialList属性为true的元素类别。实际上,这仅限于使用复合结构的图元(如墙、屋顶、楼板、天花板)、其他一些基本三维图元(如楼梯)以及可以将材质指定给族几何图形的三维族(如窗、门、柱、MEP设备和装置以及常规模型族)。请注意,在这些类别中,对于如何提取材料数量有进一步的限制。例如,幕墙和幕墙屋顶本身不会报告任何材质数量;这些构件使用的材质可以从组成幕墙系统的各个嵌板图元中提取。

请注意,在某些情况下,Revit计算的体积和面积可能是近似值。例如,对于墙内的各个层,模型中可见的体积与材质提取明细表中显示的体积之间可能会出现微小的差异。使用墙饰条工具向墙添加饰条或分隔缝时,或在某些连接条件下,往往会出现这些差异。

SDK示例“MaterialTools”结合了材质数量提取工具和剪切元素(洞口、窗和门)的临时抑制,以提取总材质数量和净材质数量。

绘制元素的表面

绘制工具功能可通过Revit API使用。可以使用材质绘制墙、楼板和屋顶等图元的面以更改其外观。它不会改变元素的结构。

与绘制元素相关的方法是Document类的一部分。Paint()将材质应用于元素的指定面。Document.RemovePaint()将移除应用的材质。此外,IsPainted()和GetPaintedMaterial()方法返回有关元素表面的信息。

代码区域:绘制墙面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Paint any unpainted faces of a given wall
public void PaintWallFaces(Wall wall, ElementId matId)
{
Document doc = wall.Document;
GeometryElement geometryElement = wall.get_Geometry(new Options());
foreach (GeometryObject geometryObject in geometryElement)
{
if (geometryObject is Solid)
{
Solid solid = geometryObject as Solid;
foreach (Face face in solid.Faces)
{
if (doc.IsPainted(wall.Id, face) == false)
{
doc.Paint(wall.Id, face, matId);
}
}
}
}
}

注:翻译自Revit API Developers Guide