// // (C) Copyright 2003-2019 by Autodesk, Inc. All rights reserved. // // 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 ITS 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.Text; using System.IO; using Autodesk; using Autodesk.Revit; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.UI.Events; using Autodesk.Revit.DB.Events; using Autodesk.Revit.DB.Analysis; namespace Revit.SDK.Samples.WorkThread.CS { /// /// Implements the Revit add-in interface IExternalApplication /// public class Application : IExternalApplication { // instance of class Application internal static Application thisApp = null; // instance of class FaceAnalyzer private FaceAnalyzer m_analyzer = null; // event handler of idling private EventHandler m_hIdling = null; // event handler of document changed private EventHandler m_hDocChanged = null; #region IExternalApplication Members /// /// Implements the OnShutdown event /// /// /// public Result OnShutdown(UIControlledApplication application) { if (m_analyzer != null) { m_analyzer.StopCalculation(); } if (m_hIdling != null) { application.Idling -= m_hIdling; } if (m_hDocChanged != null) { application.ControlledApplication.DocumentChanged -= m_hDocChanged; } return Result.Succeeded; } /// /// Implements the OnStartup event /// /// /// public Result OnStartup(UIControlledApplication application) { thisApp = this; return Result.Succeeded; } /// /// Kicking off an analysis of a wall face. /// /// /// After successfully starting a new application /// the method subscribe to the Idling event in order to /// periodically fetch data from the analyzer to Revit. /// It also subscribes to DocumentChange to monitor /// eventual changes to the element being analyzed. /// /// public void RunAnalyzer(UIApplication uiapp, String sref) { if (uiapp.ActiveUIDocument != null) { // we could have our document ready with a display style // but here we create our display style pro grammatically View view = uiapp.ActiveUIDocument.ActiveView; SetupDisplayStyle(view); // setting up a new analyzer, // then initializing it and starting it m_analyzer = new FaceAnalyzer(view, sref); m_analyzer.Initialize(); // if we the calculating when off successfully // we know we need to subscribe to Idling // to get the results as they'll keep pouring in if (m_analyzer.StartCalculation()) { SubscribeToIdling(uiapp); SubscribeToChanges(uiapp); } } } /// /// Subscription to Idling /// /// /// We hold the delegate to remember we we have subscribed. /// /// private void SubscribeToIdling(UIApplication uiapp) { if (m_hIdling == null) { m_hIdling = new EventHandler(IdlingHandler); uiapp.Idling += m_hIdling; } } /// /// Unsubscribing from Idling event /// /// private void UnsubscribeFromIdling(UIApplication uiapp) { if (m_hIdling != null) { uiapp.Idling -= m_hIdling; m_hIdling = null; } } /// /// Subscription to DocumentChanged /// /// /// We hold the delegate to remember we we have subscribed. /// /// private void SubscribeToChanges(UIApplication uiapp) { if (m_hDocChanged == null) { m_hDocChanged = new EventHandler(DocChangedHandler); uiapp.Application.DocumentChanged += m_hDocChanged; } } /// /// Unsubscribing from DocumentChanged event /// /// private void UnsubscribeFromChanges(UIApplication uiapp) { if (m_hDocChanged != null) { uiapp.Application.DocumentChanged -= m_hDocChanged; m_hDocChanged = null; } } /// /// Idling Handler /// /// /// It reaches out to the analyzer and ask it to update /// the results in Revit if more data has been calculated /// since the last time we asked. /// /// If there is no more data available, we unsubscribe /// from the Idling event, for we do not need it anymore. /// /// /// public void IdlingHandler(object sender, IdlingEventArgs args) { bool processing = false; if (m_analyzer != null) { UIApplication uiapp = sender as UIApplication; if (uiapp.ActiveUIDocument != null) { // In order for the analysis to appear correctly in the view // we seem to need the mechanism of a transaction to be run // even though the results are not really parts of the document. using (Transaction trans = new Transaction(uiapp.ActiveUIDocument.Document)) { trans.Start("bogus transaction"); processing = m_analyzer.UpdateResults(); trans.Commit(); } // In our case, we want Revit to get back to as as soon as possible args.SetRaiseWithoutDelay(); } } // We do not need the event once the analysis is over if (!processing) { UnsubscribeFromIdling(sender as UIApplication); m_analyzer = null; } } /// /// DocumentChanged Handler /// /// /// It monitors changes to the element that is being analyzed. /// If the element was changed, we ask it to restart the analysis. /// If the element was deleted, we ask the analyzer to stop. /// /// public void DocChangedHandler(object sender, DocumentChangedEventArgs args) { if (m_analyzer != null) { // first we check if the element was deleted ICollection elems = args.GetDeletedElementIds(); if (elems.Contains(m_analyzer.AnalyzedElementId)) { m_analyzer.StopCalculation(); m_analyzer = null; // if we've stopped, we do not need events anymore UnsubscribeFromIdling(sender as UIApplication); UnsubscribeFromChanges(sender as UIApplication); } else // not deleted? what about changed? { elems = args.GetModifiedElementIds(); if (elems.Contains(m_analyzer.AnalyzedElementId)) { m_analyzer.RestartCalculation(); } } } else // no analyzer => no need for the events anymore { UnsubscribeFromIdling(sender as UIApplication); UnsubscribeFromChanges(sender as UIApplication); } } /// /// We setup our preferred style for displaying the results /// /// /// This is to make it easier to run this sample on any document. /// We create a gradient-like style (unless it already exists) /// and register it with the given view. Then we set it as the /// default analysis stile in that view. /// /// private void SetupDisplayStyle(Autodesk.Revit.DB.View view) { const string styleName = "SDK2014-AL Style"; AnalysisDisplayStyle ourStyle = null; // check if we are already using our preferred display style if (ElementId.InvalidElementId != view.AnalysisDisplayStyleId) { ourStyle = view.Document.GetElement(view.AnalysisDisplayStyleId) as AnalysisDisplayStyle; if (ourStyle.Name == styleName) { return; } } // Look if the style exist at all in the document FilteredElementCollector collector = new FilteredElementCollector(view.Document); ICollection allStyles = collector.OfClass(typeof(AnalysisDisplayStyle)).ToElements(); foreach (Element elem in allStyles) { if (elem.Name == styleName) { using (Transaction trans = new Transaction(view.Document)) { trans.Start("Change Analysis Display Style"); view.AnalysisDisplayStyleId = elem.Id; trans.Commit(); return; } } } // we do not have out style yet - let's create it // a) grid lines AnalysisDisplayColoredSurfaceSettings surface = new AnalysisDisplayColoredSurfaceSettings(); surface.ShowGridLines = true; // b) colors AnalysisDisplayColorSettings colors = new AnalysisDisplayColorSettings(); Color orange = new Color(255, 205, 0); Color green = new Color(0, 255, 0); colors.MinColor = orange; colors.MaxColor = green; // c) the legend AnalysisDisplayLegendSettings legend = new AnalysisDisplayLegendSettings(); legend.NumberOfSteps = 10; legend.Rounding = 0.1; legend.ShowDataDescription = false; legend.ShowLegend = false; // creation of a style needs to be in a transaction using (Transaction trans = new Transaction(view.Document)) { trans.Start("Set Analysis Display Style"); ourStyle = AnalysisDisplayStyle.CreateAnalysisDisplayStyle(view.Document, styleName, surface, colors, legend); view.AnalysisDisplayStyleId = ourStyle.Id; trans.Commit(); } } #endregion } }