// // (C) Copyright 2003-2013 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.CodeChecking; using Autodesk.Revit.DB.CodeChecking.Documentation; using Autodesk.Revit.DB.CodeChecking.Engineering; using Autodesk.Revit.DB; using Autodesk.Revit.DB.ExtensibleStorage.Framework; using Autodesk.Revit.DB.CodeChecking.Storage; using CodeCheckingConcreteExample.Server; using CodeCheckingConcreteExample.Properties; using System.Threading; using System.Threading.Tasks; namespace CodeCheckingConcreteExample.Engine { /// /// Represents the main calculation loop. /// public class Engine { private IEngineData EngineData; private Engine() { } /// /// Initializes a new instance of the Engine class. /// /// The interface cref="IEngineData" needed to parametrize Engine. public Engine(IEngineData engineData) { EngineData = engineData; } /// /// Runs calculation for elements served in user implementation of cref="IEngineData". /// /// Acces to cref="Server". /// Acces to cref="ServiceData". public void Calculate(Server.Server server, Autodesk.Revit.DB.CodeChecking.ServiceData data) { List> listElementStatus = ReadListElementIdWithStatus(server, data); if (listElementStatus.Count > 0) CalculateSetOfElements(listElementStatus, server, data); } /// /// Reads from Revit information about selected elements, next Calculates the list of elements, at the end saves calculation results in Revit Data Base. /// /// List identyficators of elements with result status. /// Acces to cref="Server". /// Acces to cref="ServiceData". protected void CalculateSetOfElements(List> listElementStatus, Server.Server server, Autodesk.Revit.DB.CodeChecking.ServiceData data) { // reading from Revit Api CommonParametersBase parameters = ReadCommonParameters(listElementStatus, server, data); List listElementData = ReadListElementData(data, listElementStatus, parameters); if (NotificationService.ProgressBreakInvoked() == false) EngineData.ReadFromRevitDB(listElementData, parameters, data); int maxNumberOfThreads = EngineData.GetNumberOfThreads(data); if (maxNumberOfThreads < 1) maxNumberOfThreads = 1; // pure calculation (without any connection with Revit api) List listElementFiltered = EngineData.FilterElementForCalculation(listElementData); if (NotificationService.ProgressBreakInvoked() == false) /// CalculateElementList(listElementFiltered, parameters, maxNumberOfThreads, server); /// // writing to Revit Api if (NotificationService.ProgressBreakInvoked() == false) { SaveListElementData(data, listElementData); EngineData.SaveToRevitDB(listElementData, parameters, data); } } /// /// /// Gets list of elements with the given category. /// /// Category of the element. /// Material of the element. /// List of elements objects List GetListElementForCategory(BuiltInCategory category, StructuralAssetClass material, List listElementData) { List list = new List(); foreach (ObjectDataBase obj in listElementData) if (obj.Category == category && obj.Material == material) list.Add(obj); return list; } /// /// /// /// Calculates list of elements according to calculation scenario returned by cref="CreateCalculationScenario". /// /// List of elements objects /// Common parameters /// Maximal namber of threads. /// Acces to cref="Server". protected void CalculateElementList(List listElementData, CommonParametersBase parameters, int maxNumberOfThreads, Server.Server server) { ICalculationScenario scenario = EngineData.CreateCalculationScenario(parameters); int stepsCount = 0; foreach(Autodesk.Revit.DB.StructuralAssetClass material in server.GetSupportedMaterials()) foreach (BuiltInCategory category in server.GetSupportedCategories(material)) { List scenarioList = scenario.CalculationScenarioList(category, material); foreach (ICalculationObject calcObj in scenarioList) { foreach (ElementDataBase elemData in listElementData) { if (elemData.Category == category && elemData.Material == material && calcObj.Categories.Contains(elemData.Category)) { if (calcObj.Type == CalculationObjectType.Element) stepsCount++; else stepsCount += elemData.ListSectionData.Count; } } } } Autodesk.Revit.DB.CodeChecking.NotificationService.ProgressStart(Resources.ResourceManager.GetString("Calculation"), 100); int stepNbr = 0; if (maxNumberOfThreads < 2) { foreach(Autodesk.Revit.DB.StructuralAssetClass material in server.GetSupportedMaterials()) foreach (BuiltInCategory category in server.GetSupportedCategories(material)) { List listElement = GetListElementForCategory(category, material, listElementData); List scenarioList = scenario.CalculationScenarioList(category,material); foreach (ICalculationObject calcObj in scenarioList) calcObj.Parameters = parameters; foreach (ObjectDataBase element in listElement) { bool errorOccured = false; foreach (ICalculationObject calcObj in scenarioList) { if (calcObj.Categories.Contains(element.Category)) { if (calcObj.Type == CalculationObjectType.Element) { if (NotificationService.ProgressBreakInvoked()) break; stepNbr++; if ((int)((stepNbr - 1) * 100 / stepsCount) != (int)(stepNbr * 100 / stepsCount)) NotificationService.ProgressStep(string.Format("{0:d}%", stepNbr * 100 / stepsCount)); if (!errorOccured || calcObj.ErrorResponse == ErrorResponse.RunOnError) if (!calcObj.Run(element)) errorOccured = true; } else { List listSections = (element as ElementDataBase).ListSectionData; int sectionSteps = listSections.Count; if (!errorOccured || calcObj.ErrorResponse == ErrorResponse.RunOnError) { foreach (SectionDataBase section in listSections) { if (NotificationService.ProgressBreakInvoked()) break; stepNbr++; sectionSteps--; if ((int)((stepNbr - 1) * 100 / stepsCount) != (int)(stepNbr * 100 / stepsCount)) NotificationService.ProgressStep(string.Format("{0:d}%", stepNbr * 100 / stepsCount)); if (!calcObj.Run(section)) { errorOccured = true; if (calcObj.ErrorResponse == ErrorResponse.SkipOnError) break; } } } while (sectionSteps > 0) { stepNbr++; sectionSteps--; if ((int)((stepNbr - 1) * 100 / stepsCount) != (int)(stepNbr * 100 / stepsCount)) NotificationService.ProgressStep(string.Format("{0:d}%", stepNbr * 100 / stepsCount)); } } } } if (NotificationService.ProgressBreakInvoked()) break; } } } else { foreach(Autodesk.Revit.DB.StructuralAssetClass material in server.GetSupportedMaterials()) foreach (BuiltInCategory category in server.GetSupportedCategories(material)) { List listElement = GetListElementForCategory(category, material, listElementData); List scenarioList = scenario.CalculationScenarioList(category,material); foreach (ICalculationObject calcObj in scenarioList) calcObj.Parameters = parameters; object oStepNbr = (object)stepNbr; Parallel.ForEach(listElement, new ParallelOptions() { MaxDegreeOfParallelism = maxNumberOfThreads }, (element, elLoopState) => { bool errorOccured = false; foreach (ICalculationObject calcObj in scenarioList) { if (calcObj.Categories.Contains(element.Category)) { if (calcObj.Type == CalculationObjectType.Element) { if (NotificationService.ProgressBreakInvoked()) elLoopState.Break(); lock (oStepNbr) { stepNbr++; if ((int)((stepNbr - 1) * 100 / stepsCount) != (int)(stepNbr * 100 / stepsCount)) NotificationService.ProgressStep(string.Format("{0:d}%", stepNbr * 100 / stepsCount)); } if (!errorOccured || calcObj.ErrorResponse == ErrorResponse.RunOnError) if (!calcObj.Run(element)) errorOccured = true; } else { List listSections = (element as ElementDataBase).ListSectionData; int sectionSteps = listSections.Count; if (!errorOccured || calcObj.ErrorResponse == ErrorResponse.RunOnError) { Parallel.ForEach(listSections, new ParallelOptions() { MaxDegreeOfParallelism = maxNumberOfThreads }, (section, secLoopState) => { if (NotificationService.ProgressBreakInvoked()) secLoopState.Break(); lock (oStepNbr) { stepNbr++; sectionSteps--; if ((int)((stepNbr - 1) * 100 / stepsCount) != (int)(stepNbr * 100 / stepsCount)) NotificationService.ProgressStep(string.Format("{0:d}%", stepNbr * 100 / stepsCount)); } if (!calcObj.Run(section)) { errorOccured = true; if (calcObj.ErrorResponse == ErrorResponse.SkipOnError) secLoopState.Break(); } }); } while (sectionSteps > 0) { stepNbr++; sectionSteps--; if ((int)((stepNbr - 1) * 100 / stepsCount) != (int)(stepNbr * 100 / stepsCount)) NotificationService.ProgressStep(string.Format("{0:d}%", stepNbr * 100 / stepsCount)); } } } } if (NotificationService.ProgressBreakInvoked()) elLoopState.Break(); }); } } } /// /// /// Read from Revit parameters common for all selected elements and stores them in cref="CommonParametersBase". /// /// List identyficators of elements with result status. /// Acces to cref="Server". /// Acces to cref="ServiceData". /// Common parameters. protected CommonParametersBase ReadCommonParameters(List> listElementStatus, Server.Server server, Autodesk.Revit.DB.CodeChecking.ServiceData data) { Autodesk.Revit.DB.CodeChecking.Storage.StorageService service = Autodesk.Revit.DB.CodeChecking.Storage.StorageService.GetStorageService(); Autodesk.Revit.DB.CodeChecking.Storage.StorageDocument storageDocument = service.GetStorageDocument(data.Document); Guid activePackageId = storageDocument.CalculationParamsManager.CalculationParams.GetInputResultPackageId(server.GetServerId()); Autodesk.Revit.DB.ExtensibleStorage.Framework.SchemaClass calcParams = EngineData.ReadCalculationParameter(data); List listCombinationId = new List(); if (server.LoadCasesAndCombinationsSupport()) listCombinationId = storageDocument.CalculationParamsManager.CalculationParams.GetLoadCasesAndCombinations(Server.Server.ID); CommonParametersBase parameBase = new CommonParametersBase(listElementStatus, listCombinationId, activePackageId, calcParams); CommonParametersBase parameters = EngineData.CreateCommonParameters(data, parameBase); return parameters; } /// /// Reads from Revit selected elements identificators and collect in the list only that which has apprppriate label, material and category. /// /// Acces to cref="Server". /// Acces to cref="ServiceData". /// List identyficators of elements with result status. protected List> ReadListElementIdWithStatus(Server.Server server, Autodesk.Revit.DB.CodeChecking.ServiceData data) { Autodesk.Revit.DB.CodeChecking.Storage.StorageService service = Autodesk.Revit.DB.CodeChecking.Storage.StorageService.GetStorageService(); Autodesk.Revit.DB.CodeChecking.Storage.StorageDocument storageDocument = service.GetStorageDocument(data.Document); Guid activePackageId = storageDocument.CalculationParamsManager.CalculationParams.GetInputResultPackageId(server.GetServerId()); List> listElementId = new List>(); foreach (Element element in data.Selection) { Autodesk.Revit.DB.CodeChecking.Storage.Label ccLabel = storageDocument.LabelsManager.GetLabel(element); if (ccLabel != null) { Autodesk.Revit.DB.BuiltInCategory category = (Autodesk.Revit.DB.BuiltInCategory)element.Category.Id.IntegerValue; StructuralAssetClass material = ccLabel.Material; if (server.GetSupportedMaterials().Contains(material) && server.GetSupportedCategories(material).Contains(category)) { ElementId id = new ElementId(element.Id.IntegerValue); SchemaClass label = EngineData.ReadElementLabel(category, material, ccLabel, data); ResultStatus status = new Autodesk.Revit.DB.CodeChecking.Storage.ResultStatus(Server.Server.ID, activePackageId); EngineData.VerifyElementLabel(category, material, label, ref status); listElementId.Add(new Tuple(id, status)); } } } return listElementId; } /// /// Reads from Revit information about selected elements and store it in the list with elements data. /// /// Acces to cref="ServiceData". /// List identyficators of elements with result status. /// Common parameters. /// List of elements data. protected List ReadListElementData(Autodesk.Revit.DB.CodeChecking.ServiceData data, List> listElementStatus, CommonParametersBase parameters) { Autodesk.Revit.DB.CodeChecking.Storage.StorageService service = Autodesk.Revit.DB.CodeChecking.Storage.StorageService.GetStorageService(); Autodesk.Revit.DB.CodeChecking.Storage.StorageDocument storageDocument = service.GetStorageDocument(data.Document); List listElementData = new List(); foreach (Tuple elemStatus in listElementStatus) { Element element = data.Document.GetElement(elemStatus.Item1); if (element != null) { Autodesk.Revit.DB.CodeChecking.Storage.Label ccLabel = storageDocument.LabelsManager.GetLabel(element); if (ccLabel != null) { Autodesk.Revit.DB.BuiltInCategory category = (Autodesk.Revit.DB.BuiltInCategory)element.Category.Id.IntegerValue; StructuralAssetClass material = ccLabel.Material; Autodesk.Revit.DB.ExtensibleStorage.Framework.SchemaClass label = EngineData.ReadElementLabel(category, material, ccLabel, data); Autodesk.Revit.DB.ExtensibleStorage.Framework.SchemaClass result = EngineData.CreateElementResult(category, material); ObjectDataBase objectData = new ObjectDataBase(elemStatus.Item1, category, material, label); List listSectionsData = new List(); List listCalcPoints = EngineData.CreateCalcPointsForElement(data, parameters, elemStatus.Item1); foreach (CalcPoint p in listCalcPoints) { SectionDataBase sectBase = new SectionDataBase(p, objectData); SectionDataBase sectData = EngineData.CreateSectionData(sectBase); listSectionsData.Add(sectData); } ElementDataBase elemBase = new ElementDataBase(result, listCalcPoints, listSectionsData, elemStatus.Item2, data.Document, objectData); ElementDataBase elemData = EngineData.CreateElementData(elemBase); listElementData.Add(elemData); } } } return listElementData; } /// /// Saves in Revit data base information collected in the list elements data. /// /// Acces to cref="ServiceData". /// List of elements data. protected void SaveListElementData(Autodesk.Revit.DB.CodeChecking.ServiceData data, List listElementData) { Autodesk.Revit.DB.CodeChecking.NotificationService.ProgressStart(Resources.ResourceManager.GetString("DataSaving"), listElementData.Count); int step = 0; foreach (ElementDataBase elemData in listElementData) { SaveElementResult(elemData.ElementId, elemData.Result, elemData.Status, data); step++; Autodesk.Revit.DB.CodeChecking.NotificationService.ProgressStep(string.Format("{0:d}%", step * 100 / listElementData.Count)); } } /// /// Saves in Revit the result object of an element. /// /// Identificator of an element. /// Result object. /// Status of element's results. /// Acces to cref="ServiceData". protected void SaveElementResult(ElementId elementId, Autodesk.Revit.DB.ExtensibleStorage.Framework.SchemaClass resultSchema, Autodesk.Revit.DB.CodeChecking.Storage.ResultStatus status, Autodesk.Revit.DB.CodeChecking.ServiceData data) { Autodesk.Revit.DB.CodeChecking.Storage.StorageService service = Autodesk.Revit.DB.CodeChecking.Storage.StorageService.GetStorageService(); Autodesk.Revit.DB.CodeChecking.Storage.StorageDocument storageDocument = service.GetStorageDocument(data.Document); Element element = data.Document.GetElement(elementId); if (resultSchema != null) storageDocument.ResultsManager.SetResult(resultSchema.GetEntity(), element, status, true); } } }