Building Coder(Revit 二次开发) - 设置标签类型

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 中运行的结果是:一面墙、一扇门以及指定标签类型的门标签。


Revit二次开发中,Jeremy Tammik 提供的项目模板是许多开发者的首选工具。这些模板不仅简化了开发流程,还提供了最佳实践和标准结构,使开发者能够更高效地创建Revit插件。 Jeremy Tammik 是Autodesk的开发专家,长期致力于推动Revit API的使用和发展。他提供的项目模板通常包括用于创建外部命令、外部应用、事件处理程序等的标准类结构,并集成了必要的引用和配置文件,以减少开发者在项目初始化阶段的工作量。 ### 项目模板的主要特性 - **标准类结构**:模板通常包含`IExternalCommand`或`IExternalApplication`的实现类,开发者可以直接在这些类中编写核心逻辑。 - **调试支持**:集成调试器启动设置,允许开发者在Visual Studio中直接启动Revit并附加调试器,提高调试效率。 - **资源管理**:模板通常包含图标、资源文件以及本地化支持的示例代码。 - **日志记录**:部分模板集成了日志记录功能,便于调试和错误追踪。 - **兼容性支持**:针对不同版本的Revit(如2020至2024),模板通常提供多个分支,以确保与不同API版本的兼容性[^1]。 ### 如何获取 Jeremy 的项目模板 Jeremy Tammik 的项目模板可以在其官方GitHub仓库中找到。访问地址为: [The Building Coder GitHub Repository](https://github.com/jeremytammik/the_building_coder_samples) 在该仓库中,模板通常以`C:\...\The Building Coder Samples\`的形式组织,开发者可以下载整个项目并从中提取所需的模板部分。 此外,部分开发者社区和论坛也提供了基于Jeremy模板的改进版本,例如: - GitHub上的衍生项目 - Revit API论坛(如Revit API中文论坛) - Autodesk官方论坛中的相关讨论帖 ### 使用指南 1. **克隆仓库**:使用Git将整个仓库克隆到本地,或直接下载ZIP文件。 2. **提取模板**:找到`Source`目录下的项目结构,通常包含多个示例和模板。 3. **创建新项目**:复制模板文件夹,重命名项目,并在Visual Studio中打开进行开发。 4. **配置属性**:确保`post-build`事件中的路径与本地Revit安装路径一致,以便调试器可以正确启动Revit。 5. **编写逻辑**:在`Execute`方法中实现业务逻辑,并利用模板中已有的辅助类(如`App`和`Cmd`)进行注册和调用[^1]。 ### 示例代码 以下是一个简单的外部命令模板示例: ```csharp using System; using Autodesk.Revit.Attributes; using Autodesk.Revit.DB; using Autodesk.Revit.UI; [Transaction(TransactionMode.Manual)] public class MyExternalCommand : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { // 获取当前文档 Document doc = commandData.Application.ActiveUIDocument.Document; // 显示一个信息框 TaskDialog.Show("Revit二次开发", "Hello, Revit API!"); return Result.Succeeded; } } ``` ### 常见问题 - **如何调试插件?**:在Visual Studio中设置启动程序为Revit.exe,并确保DLL输出路径正确。调试时Revit会自动加载插件。 - **如何处理版本差异?**:模板通常会标注支持的Revit版本,开发者应根据目标版本选择合适的模板分支。 - **如何部署插件?**:生成的DLL文件可以通过`.addin`配置文件注册到Revit中,通常位于`%APPDATA%\Autodesk\Revit\Addins\`目录下。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值