应用程序:DynamicModelUpdate

Revit 平台:所有版本

Revit 版本:2012.0

首次发布时间:2011.0

编程语言:C#

技能要求:高阶

类别:几何

类型:外部应用程序

主题:Dynamic Model Update 用于维护元素之间的相对位置

摘要:移动一个截面标记以便保持与窗户的相对位置

相关类:

Autodesk.Revit.DB.UpdaterRegistry

Autodesk.Revit.DB.ElementClassFilter

Autodesk.Revit.DB.ElementCategoryFilter

Autodesk.Revit.DB.LogicalAndFilter

Autodesk.Revit.DB.LocationPoint

项目文件:

Application.cs

SectionUpdater.cs

描述:

1. 执行“关联截面更新程序”命令时:

a. 注册 SectionUpdater。

b. 选择视图截面元素和窗户,将它们关联起来。

c. 添加触发器,使 SectionUpdater 类会在窗户的任何几何变化时被调用。

2. 当窗户几何变化时:

a. 根据窗户的定位点移动截面到新位置,并使其旋转并垂直于窗户的朝向。

b. 在 RejustSectionView 函数中进行计算。

说明:

1. 打开 AssociativeSection.rvt 文件。

2. 选择一个视图截面和一个窗户。

3. 移动窗户或旋转墙体。

4. Revit 会移动截面,使得窗户和截面保持垂直位置。

5. 可以更改截面和窗户之间的关联,并重新添加更新器触发器。

完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码

Application.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;

namespace Revit.SDK.Samples.DynamicModelUpdate.CS
{

    ///////////////////////////////////////////////////////////////////////////////////////////////
    //
    // Command to setup the updater, register the triggers (on execute), and unregister it (on close the document)
    //

    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    public class AssociativeSectionUpdater : Autodesk.Revit.UI.IExternalCommand
    {
        Document m_document;
        UIDocument m_documentUI;

        // application's private data
        private static SectionUpdater m_sectionUpdater = null;
        private AddInId m_thisAppId;

        private static List<ElementId> idsToWatch = new List<ElementId>();
        private static ElementId m_oldSectionId = ElementId.InvalidElementId;

        Result IExternalCommand.Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                m_document = commandData.Application.ActiveUIDocument.Document;
                m_documentUI = commandData.Application.ActiveUIDocument;
                m_thisAppId = commandData.Application.ActiveAddInId;


                // creating and registering the updater for the document.
                if (m_sectionUpdater == null)
                {
                    using (Transaction tran = new Transaction(m_document, "Register Section Updater"))
                    {
                        tran.Start();

                        m_sectionUpdater = new SectionUpdater(m_thisAppId);
                        m_sectionUpdater.Register(m_document);

                        tran.Commit();
                    }
                }

                TaskDialog.Show("Message", "Please select a section view, then select a window.");

                ElementId modelId = null;
                Element sectionElement = null;
                ElementId sectionId = null;
                try
                {
                    Reference referSection = m_documentUI.Selection.PickObject(ObjectType.Element, "Please select a section view.");
                    if (referSection != null)
                    {
                        Element sectionElem = m_document.GetElement(referSection);
                        if (sectionElem != null)
                        {
                            sectionElement = sectionElem;
                        }
                    }
                    Reference referModel = m_documentUI.Selection.PickObject(ObjectType.Element, "Please select a window to associated with the section view.");
                    if (referModel != null)
                    {
                        Element model = m_document.GetElement(referModel);
                        if (model != null)
                        {
                            if (model is FamilyInstance)
                                modelId = model.Id;
                        }
                    }
                }
                catch (OperationCanceledException)
                {
                    TaskDialog.Show("Message", "The selection has been canceled.");
                    return Result.Cancelled;
                }

                if (modelId == null)
                {
                    TaskDialog.Show("Error", "The model is supposed to be a window.\n The operation will be canceled.");
                    return Result.Cancelled;
                }

                // Find the real ViewSection for the selected section element.
                string name = sectionElement.Name;
                FilteredElementCollector collector = new FilteredElementCollector(m_document);
                collector.WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_Views));
                var viewElements = from element in collector
                                   where element.Name == name
                                   select element;

                List<Autodesk.Revit.DB.Element> sectionViews = viewElements.ToList<Autodesk.Revit.DB.Element>();
                if (sectionViews.Count == 0)
                {
                    TaskDialog.Show("Message", "Cannot find the view name " + name + "\n The operation will be canceled.");
                    return Result.Failed;
                }
                sectionId = sectionViews[0].Id;

                // Associated the section view to the window, and add a trigger for it.
                if (!idsToWatch.Contains(modelId) || m_oldSectionId != sectionId)
                {
                    idsToWatch.Clear();
                    idsToWatch.Add(modelId);
                    m_oldSectionId = sectionId;
                    UpdaterRegistry.RemoveAllTriggers(m_sectionUpdater.GetUpdaterId());
                    m_sectionUpdater.AddTriggerForUpdater(m_document, idsToWatch, sectionId, sectionElement);
                    TaskDialog.Show("Message", "The ViewSection id: " + sectionId + " has been associated to the window id: " + modelId + "\n You can try to move or modify the window to see how the updater works.");
                }
                else
                {
                    TaskDialog.Show("Message", "The model has been already associated to the ViewSection.");
                }

                m_document.DocumentClosing += UnregisterSectionUpdaterOnClose;

                return Result.Succeeded;
            }
            catch (System.Exception ex)
            {
                message = ex.ToString();
                return Result.Failed;
            }
        }

        /// <summary>
        /// Unregister the updater on Revit document close.
        /// </summary>
        /// <param name="source">The source object.</param>
        /// <param name="args">The DocumentClosing event args.</param>
        private void UnregisterSectionUpdaterOnClose(object source, DocumentClosingEventArgs args)
        {
            idsToWatch.Clear();
            m_oldSectionId = ElementId.InvalidElementId;

            if (m_sectionUpdater != null)
            {
                UpdaterRegistry.UnregisterUpdater(m_sectionUpdater.GetUpdaterId());
                m_sectionUpdater = null;
            }
        }

    }

}

SectionUpdater.cs

//
// (C) Copyright 2003-2015 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using Autodesk.Revit.UI;

namespace Revit.SDK.Samples.DynamicModelUpdate.CS
{

    /// <summary>
    /// Updater to automatically move a section in conjunction with the location of a window
    /// </summary>
    public class SectionUpdater : IUpdater
    {
        internal SectionUpdater(AddInId addinID)
        {
            m_updaterId = new UpdaterId(addinID, new Guid("FBF3F6B2-4C06-42d4-97C1-D1B4EB593EFF"));
        }

        // Registers itself with Revit
        internal void Register(Document doc)
        {
            // Register the section updater if the updater is not registered.
            if (!UpdaterRegistry.IsUpdaterRegistered(m_updaterId))
                UpdaterRegistry.RegisterUpdater(this, doc);
        }

        internal void AddTriggerForUpdater(Document doc, List<ElementId> idsToWatch, ElementId sectionId, Element sectionElement)
        {
            if (idsToWatch.Count == 0)
                return;

            m_windowId = idsToWatch[0];
            m_sectionId = sectionId;
            m_sectionElement = sectionElement;
            UpdaterRegistry.AddTrigger(m_updaterId, doc, idsToWatch, Element.GetChangeTypeGeometry());
        }

        #region IUpdater members

        // The Execute method for the updater
        public void Execute(UpdaterData data)
        {
            try
            {
                Document doc = data.GetDocument();
                // iterate through modified elements to find the one we want the section to follow
                foreach (ElementId id in data.GetModifiedElementIds())
                {
                    if (id == m_windowId)
                    {
                        FamilyInstance window = doc.GetElement(m_windowId) as FamilyInstance;
                        ViewSection section = doc.GetElement(m_sectionId) as ViewSection;

                        RejustSectionView(doc, window, section);
                    }
                }

            }
            catch (System.Exception ex)
            {
                TaskDialog.Show("Exception", ex.ToString());
            }
            return;
        }

        public UpdaterId GetUpdaterId()
        {
            return m_updaterId;
        }

        public string GetUpdaterName()
        {
            return "Associative Section Updater";
        }

        public string GetAdditionalInformation()
        {
            return "Automatically moves a section to maintain its position relative to a window";
        }

        public ChangePriority GetChangePriority()
        {
            return ChangePriority.Views;
        }

        #endregion

        internal void RejustSectionView(Document doc, Element elem, ViewSection section)
        {
            XYZ position = XYZ.Zero;
            XYZ fOrientation = XYZ.Zero;
            if (elem is FamilyInstance)
            {
                FamilyInstance familyInstance = elem as FamilyInstance;
                if (familyInstance.Location != null && familyInstance.Location is LocationPoint)
                {
                    LocationPoint locationPoint = familyInstance.Location as LocationPoint;
                    position = locationPoint.Point;
                }
                fOrientation = familyInstance.FacingOrientation;
            }

            XYZ sOrigin = section.Origin;
            XYZ sDirection = section.ViewDirection;

            XYZ fRectOrientation = fOrientation.CrossProduct(XYZ.BasisZ);

            // Rotate the section element
            double angle = fOrientation.AngleTo(sDirection);
            // Need to adjust the rotation angle based on the direction of rotation (not covered by AngleTo)
            XYZ cross = fRectOrientation.CrossProduct(sDirection).Normalize();
            double sign = 1.0;
            if (!cross.IsAlmostEqualTo(XYZ.BasisZ))
            {
                sign = -1.0;
            }

            double rotateAngle = 0;
            if (Math.Abs(angle) > 0 && Math.Abs(angle) <= Math.PI / 2.0)
            {
                if (angle < 0)
                {
                    rotateAngle = Math.PI / 2.0 + angle;
                }
                else
                {
                    rotateAngle = Math.PI / 2.0 - angle;
                }

            }
            else if (Math.Abs(angle) > Math.PI / 2.0)
            {
                if (angle < 0)
                {
                    rotateAngle = angle + Math.PI / 2.0;
                }
                else
                {
                    rotateAngle = angle - Math.PI / 2.0;
                }
            }

            rotateAngle *= sign;

            if (Math.Abs(rotateAngle) > 0)
            {
                Line axis = Line.CreateBound(sOrigin, sOrigin + XYZ.BasisZ);
                ElementTransformUtils.RotateElement(doc, m_sectionElement.Id, axis, rotateAngle);
            }

            // Regenerate the document
            doc.Regenerate();

            // Move the section element
            double dotF = position.DotProduct(fRectOrientation);
            double dotS = sOrigin.DotProduct(fRectOrientation);
            double moveDot = dotF - dotS;
            XYZ sNewDirection = section.ViewDirection;    // Get the new direction after rotation.
            double correction = fRectOrientation.DotProduct(sNewDirection);
            XYZ translationVec = sNewDirection * correction * moveDot;

            if (!translationVec.IsZeroLength())
            {
                ElementTransformUtils.MoveElement(doc, m_sectionElement.Id, translationVec);
            }
        }

        // private data:

        private UpdaterId m_updaterId = null;
        private ElementId m_windowId = null;
        private ElementId m_sectionId = null;   // The real ViewSection that contains the Origin and ViewDirection
        private Element m_sectionElement = null;    // The view section element to move and rotate
    }

}