|
许多时候,开发者希望Revit有这样的功能。当用户对模型进行修改后,二次开发的程序能够相应用户的修改,对模型作出一些相应的修改操作。例如,一些墙上的窗户要求永远居中显示。当用户对这个墙做了长度修改,这个窗户还要自动的在墙的中心处。这就是一个比较容易理解的应用。
这要求Revit具有感知用户所做的操作,并且能随后对模型作出修改。对于感知用户的操作或动作,Revit有两个办法,一个是用反应器,也就是事件。另一个是模型动态更新机制DMU(Dynamic Model Update)。
Revit提供了一些事件,比如捕获文档的打开,保存,关闭,打印,视图切换等等。也提供了构建级别的事件(DocumentChanged)来捕获有新的对象加入,或有些对象发生修改,或一些对象的参数发生变化。但是在DocumentChanged事件处理函数里,无法对模型进行修改。禁止在这里进行模型的修改是为了防止循环调用DocumentChanged事件处理函数,形成死循环。基于这个原因,Revit 提供了DMU机制,模型动态更新。
DMU具有感知用户对模型进行了构建级别的修改,并且可以进行作出相应。而且在这里可以对模型进行修改。它之所以无法触发循环调用,是因为它对模型所做的修改和用户模型所做的修改共享同一个事务。在代码中对模型进行修改后,程序员无法掌控什么时候提交修改事务,Revit系统自动来提交事务的修改。
下面代码是DMU的一个例子,让窗户永居中的代码。
用法:
首先加载和注册DMU:
- [csharp] view plaincopy
- [Transaction(TransactionMode.Automatic)]
- public class UIEventApp : IExternalApplication
- {
- // Flag to indicate if we want to show a message at each object modified events.
- public static bool m_showEvent = false;
-
- /// <summary>
- /// OnShutdown() - called when Revit ends.
- /// </summary>
- public Result OnShutdown(UIControlledApplication app)
- {
- // (1) unregister our document changed event hander
- app.ControlledApplication.DocumentChanged -= UILabs_DocumentChanged;
-
- return Result.Succeeded;
- }
-
- /// <summary>
- /// OnStartup() - called when Revit starts.
- /// </summary>
- public Result OnStartup(UIControlledApplication app)
- {
-
- // (2) register our dynamic model updater (WindowDoorUpdater class definition below.)
- // We are going to keep doors and windows at the center of the wall.
- //
- // Construct our updater.
- WindowDoorUpdater winDoorUpdater = new WindowDoorUpdater(app.ActiveAddInId);
- // ActiveAddInId is from addin menifest.
- // Register it
- UpdaterRegistry.RegisterUpdater(winDoorUpdater);
-
- // Tell which elements we are interested in being notified about.
- // We want to know when wall changes its length.
-
- ElementClassFilter wallFilter = new ElementClassFilter(typeof(Wall));
- UpdaterRegistry.AddTrigger(winDoorUpdater.GetUpdaterId(), wallFilter, Element.GetChangeTypeGeometry());
-
- return Result.Succeeded;
- }
- [csharp] view plaincopy
- //。。。
- [csharp] view plaincopy
- }
复制代码
模型动态更新的实现类。在这里实现了如何更新模型。
[csharp] view plaincopy//======================================================== // dynamic model update - derive from IUpdater class //======================================================== public class WindowDoorUpdater : IUpdater { // Unique id for this updater = addin GUID + GUID for this specific updater. UpdaterId m_updaterId = null; // Flag to indicate if we want to perform public static bool m_updateActive = false; /// <summary> /// Constructor /// </summary> public WindowDoorUpdater(AddInId id) { m_updaterId = new UpdaterId(id, new Guid("EF43510F-38CB-4980-844C-72174A674D56")); } /// <summary> /// This is the main function to do the actual job. /// For this exercise, we assume that we want to keep the door and window always at the center. /// </summary> public void Execute(UpdaterData data) { if (!m_updateActive) return; Document rvtDoc = data.GetDocument(); ICollection<ElementId> idsModified = data.GetModifiedElementIds(); foreach (ElementId id in idsModified) { // Wall aWall = rvtDoc.get_Element(id) as Wall; // For 2012 Wall aWall = rvtDoc.GetElement(id) as Wall; // For 2013 CenterWindowDoor(rvtDoc, aWall); //Get the wall solid. Options opt = new Options(); opt.ComputeReferences = false; Solid wallSolid = null; GeometryElement geoElem = aWall.get_Geometry(opt); foreach (GeometryObject geoObj in geoElem.Objects) { wallSolid = geoObj as Solid; if (wallSolid != null) { if (wallSolid.Faces.Size > 0) { break; } } } //XYZ ptCenter = wallSolid.ComputeCentroid(); } }
下面这个函数是窗居中操作。- [csharp] view plaincopy
- /// <summary>
- /// Helper function for Execute.
- /// Checks if there is a door or a window on the given wall.
- /// If it does, adjust the location to the center of the wall.
- /// For simplicity, we assume there is only one door or window.
- /// (TBD: or evenly if there are more than one.)
- /// </summary>
- public void CenterWindowDoor(Document rvtDoc, Wall aWall)
- {
- // Find a winow or a door on the wall.
- FamilyInstance e = FindWindowDoorOnWall(rvtDoc, aWall);
- if (e == null) return;
-
- // Move the element (door or window) to the center of the wall.
-
- // Center of the wall
- LocationCurve wallLocationCurve = aWall.Location as LocationCurve;
- XYZ pt1 = wallLocationCurve.Curve.get_EndPoint(0);
- XYZ pt2 = wallLocationCurve.Curve.get_EndPoint(1);
- XYZ midPt = (pt1 + pt2) * 0.5;
-
- LocationPoint loc = e.Location as LocationPoint;
- loc.Point = new XYZ(midPt.X, midPt.Y, loc.Point.Z);
- }
-
- /// <summary>
- /// Helper function
- /// Find a door or window on the given wall.
- /// If it does, return it.
- /// </summary>
- public FamilyInstance FindWindowDoorOnWall(Document rvtDoc, Wall aWall)
- {
- // Collect the list of windows and doors
- // No object relation graph. So going hard way.
- // List all the door instances
- var windowDoorCollector = new FilteredElementCollector(rvtDoc);
- windowDoorCollector.OfClass(typeof(FamilyInstance));
-
- ElementCategoryFilter windowFilter = new ElementCategoryFilter(BuiltInCategory.OST_Windows);
- ElementCategoryFilter doorFilter = new ElementCategoryFilter(BuiltInCategory.OST_Doors);
- LogicalOrFilter windowDoorFilter = new LogicalOrFilter(windowFilter, doorFilter);
-
- windowDoorCollector.WherePasses(windowDoorFilter);
- IList<Element> windowDoorList = windowDoorCollector.ToElements();
-
- // This is really bad in a large model!
- // You might have ten thousand doors and windows.
- // It would make sense to add a bounding box containment or intersection filter as well.
-
- // Check to see if the door or window is on the wall we got.
- foreach (FamilyInstance e in windowDoorList)
- {
- if (e.Host.Id.Equals(aWall.Id))
- {
- return e;
- }
- }
-
- // If you come here, you did not find window or door on the given wall.
-
- return null;
- }
复制代码
在Revit有三个例子演示了DMU的使用机制。请搜索UpdaterRegistry.RegisterUpdater 找到这几个例子更多了解模型动态更新的用法。转载请复制以下信息:原文链接: http://blog.csdn.net/joexiongjin/article/details/84855681作者: 叶雄进 , Autodesk ADN
|
|