Building Coder 链接:http://thebuildingcoder.typepad.com/blog/2010/06/set-tag-type.html
Revit 二次开发论坛链接:http://revit.5d6d.com/viewthread.php?tid=1292&page=1&extra=#pid1814
对设置标签类型这个问题的研究让我有机会重新回顾了之前分别讨论过的几个主题。我觉得有必要将它们在这个新问题中整理一下呈现给大家。
1. 在创建墙体时决定墙体的顶层(Top Level)和底层(Bottom Level);
2. 创建一个新墙体时设置它的顶层边缘;
3. 获取墙体厚度(用于之后计算标签放置位置);
4. 获取门类型(用户在墙体中插入一个门实例);
5. 在墙体中部插入一个门实例;
6. 创建一个和门实例关联的门标签;
7. 获取一个现有的门标签类型(用于复制);
8. 通过复制创建一个新的门标签类型;
9. 将现有门标签的类型设置为新创建的标签类型。
实现 1~6 步的代码我们在 Lab2_0_CreateLittleHouse 外部命令中已经讨论过了。关于 Duplicate() 方法,我们在讨论创建墙体、柱子等元素的时候也都涉及过。
为了讨论本主题,我的代码中还是有些新东西的:几个简洁实用的辅助函数。鉴于此,我觉得有必要将这些新老代码整合到一个独立的外部命令中。
不过还是先让我们看看本主题的来龙去脉吧。
问题:
我正在编写一些代码来自动为元素创建标签。下面是我的代码片段:
doc.Create.NewTag(
doc.ActiveView,
elem,
False,
TagMode.TM_ADDBY_CATEGORY,
TagOrientation.TAG_HORIZONTAL,
panelCenter );
NewTag()方法允许我选择标签模式,但是无法设定标签类型。我想知道如何为新创建的标签设定类型。在用户界面中,我可以在 Tag 对话框中做到这一点。
回答:
你可以通过对 NewTag() 方法返回的标签对象调用 ChangeTypeId() 方法,并传入期望的标签类型对应的 element id 来实现这一点。我实现了一个新的外部命令“CmdSetTypeTage”作为例程。
该例程实现了上面提到的所有步骤。其中最后四步(6~9)就能回答你的问题。该例程同时包含多个常量和辅助函数。
1. 英寸和毫米的转换函数
译者注:估计地球人都已经实现了;
2. 求两点连线的中点
译者注:看样子传说是真的:老外的数学基础教育不咋地。这个我们初中就教过了哦;
3. 一组过滤元素收集器
译者注:实用!!!
GetElementsOfType:返回指定类型(class)的所有元素;
static FilteredElementCollector
GetElementsOfType(
Document doc,
Type type,
BuiltInCategory bic )
{
FilteredElementCollector collector
= new FilteredElementCollector( doc );
collector.OfCategory( bic );
collector.OfClass( type );
return collector;
}
GetFamilySymbols:返回指定内置类别(built-in category)的所有族类型;
static FilteredElementCollector
GetFamilySymbols(
Document doc,
BuiltInCategory bic )
{
return GetElementsOfType( doc,
typeof( FamilySymbol ), bic );
}
GetFirstFamilySymbol:返回指定内置类别(built-in category)的第一个族类型;
static FamilySymbol GetFirstFamilySymbol(
Document doc,
BuiltInCategory bic )
{
FamilySymbol s = GetFamilySymbols( doc, bic )
.FirstElement() as FamilySymbol;
Debug.Assert( null != s, string.Format(
"expected at least one {0} symbol in project",
bic.ToString() ) );
return s;
}
GetBottomAndTopLevels:判定创建墙体的顶层和底层。对一个 empty project 中,顶层和底层分别为 Level 1 和 Level 2;
static bool GetBottomAndTopLevels(
Document doc,
ref Level levelBottom,
ref Level levelTop )
{
FilteredElementCollector levels
= GetElementsOfType( doc, typeof( Level ),
BuiltInCategory.OST_Levels );
foreach( Element e in levels )
{
if( null == levelBottom )
{
levelBottom = e as Level;
}
else if( null == levelTop )
{
levelTop = e as Level;
}
else
{
break;
}
}
if( levelTop.Elevation < levelBottom.Elevation )
{
Level tmp = levelTop;
levelTop = levelBottom;
levelBottom = tmp;
}
return null != levelBottom && null != levelTop;
}
有了所有上述的准备工作,下面我就可以 CmdSetTypeTage 命令主体了:
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements )
{
UIApplication app = commandData.Application;
Document doc = app.ActiveUIDocument.Document;
Autodesk.Revit.Creation.Application createApp
= app.Application.Create;
Autodesk.Revit.Creation.Document createDoc
= doc.Create;
// determine the wall endpoints:
double length = 5 * MeterToFeet;
XYZ [] pts = new XYZ[2];
pts[0] = XYZ.Zero;
pts[1] = new XYZ( length, 0, 0 );
// determine the levels where
// the wall will be located:
Level levelBottom = null;
Level levelTop = null;
if( !GetBottomAndTopLevels( doc,
ref levelBottom, ref levelTop ) )
{
message = "Unable to determine "
+ "wall bottom and top levels";
return Result.Failed;
}
// create a wall:
BuiltInParameter topLevelParam
= BuiltInParameter.WALL_HEIGHT_TYPE;
ElementId topLevelId = levelTop.Id;
Line line = createApp.NewLineBound(
pts[0], pts[1] );
Wall wall = createDoc.NewWall(
line, levelBottom, false );
Parameter param = wall.get_Parameter(
topLevelParam );
param.Set( topLevelId );
// determine wall thickness for tag
// offset and profile growth:
double wallThickness = wall.WallType
.CompoundStructure.Layers.get_Item( 0 )
.Thickness;
// add door to wall;
// note that the NewFamilyInstance method
// does not automatically add a door tag,
// like the ui command does:
FamilySymbol doorSymbol = GetFirstFamilySymbol(
doc, BuiltInCategory.OST_Doors );
if( null == doorSymbol )
{
message = "No door symbol found.";
return Result.Failed;
}
XYZ midpoint = Midpoint( pts[0], pts[1] );
FamilyInstance door = createDoc
.NewFamilyInstance( midpoint, doorSymbol,
wall, levelBottom,
StructuralType.NonStructural );
// create door tag:
View view = doc.ActiveView;
double tagOffset = 3 * wallThickness;
midpoint += tagOffset * XYZ.BasisY;
IndependentTag tag = createDoc.NewTag(
view, door, false, TagMode.TM_ADDBY_CATEGORY,
TagOrientation.TAG_HORIZONTAL, midpoint );
// create and assign new door tag type:
FamilySymbol doorTagType
= GetFirstFamilySymbol(
doc, BuiltInCategory.OST_DoorTags );
doorTagType = doorTagType.Duplicate(
"New door tag type" ) as FamilySymbol;
tag.ChangeTypeId( doorTagType.Id );
return Result.Succeeded;
}
该命令在一个 empty project 中运行的结果是:一面墙、一扇门以及指定标签类型的门标签。