Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for assemblies added #1235

Merged
merged 8 commits into from
Aug 15, 2022
83 changes: 68 additions & 15 deletions Revit_Core_Adapter/AdapterActions/Push.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using Autodesk.Revit.UI;
using BH.oM.Adapter;
using BH.oM.Adapters.Revit;
using BH.oM.Adapters.Revit.Elements;
using BH.oM.Base;
using BH.Revit.Engine.Core;
using System.Collections.Generic;
Expand Down Expand Up @@ -62,7 +63,7 @@ public override List<object> Push(IEnumerable<object> objects, string tag = "",

// If unset, set the pushType to AdapterSettings' value (base AdapterSettings default is FullCRUD). Disallow the unsupported PushTypes.
if (pushType == PushType.AdapterDefault)
pushType = PushType.DeleteThenCreate;
pushType = PushType.UpdateOrCreateOnly;
else if (pushType == PushType.FullPush)
{
BH.Engine.Base.Compute.RecordError("Full Push is currently not supported by Revit_Toolkit, please use Create, UpdateOnly or DeleteThenCreate instead.");
Expand Down Expand Up @@ -102,24 +103,68 @@ public override List<object> Push(IEnumerable<object> objects, string tag = "",
}
}

// Push the objects
string transactionName = "BHoM Push " + pushType;
// First push everything that is not a Revit assembly
List<IBHoMObject> nonAssemblies = objectsToPush.Where(x => !(x is Assembly)).ToList();
List<IBHoMObject> pushed = PushToRevit(document, nonAssemblies, pushType, pushConfig, "BHoM Push " + pushType);

// Assemblies are being pushed separately in a few steps due to Revit API limitations in this field
List<IBHoMObject> revitAssemblies = objectsToPush.Where(x => x is Assembly).ToList();
if (revitAssemblies.Count != 0)
{
// Push assembly members first
List<IBHoMObject> pushedMembers = PushToRevit(document, revitAssemblies.SelectMany(x => ((Assembly)x).AssemblyMembers()), pushType, pushConfig, "BHoM Push " + pushType);

// Create the assemblies - no changes applied to the newly created assemblies here due to Revit API limitations
// Warnings are being suppressed to avoid all assembly-related warnings
UIControlledApplication.ControlledApplication.FailuresProcessing += ControlledApplication_FailuresProcessing;
List<IBHoMObject> createdAssemblies = new List<IBHoMObject>();
if (pushType == PushType.CreateOnly || pushType == PushType.CreateNonExisting || pushType == PushType.DeleteThenCreate || pushType == PushType.UpdateOrCreateOnly)
createdAssemblies.AddRange(PushToRevit(document, revitAssemblies, pushType, pushConfig, "BHoM Push Create Assemblies"));
vietle-bh marked this conversation as resolved.
Show resolved Hide resolved

// Update the assemblies in a separate transaction
List<IBHoMObject> assembliesToUpdate = pushType == PushType.UpdateOnly || pushType == PushType.UpdateOrCreateOnly ? revitAssemblies : createdAssemblies;
List<IBHoMObject> pushedAssemblies = PushToRevit(document, assembliesToUpdate, PushType.UpdateOnly, pushConfig, "BHoM Push Update Assemblies");
pushed.AddRange(pushedAssemblies);

// Warn the user if he/she self-overwrites the assembly name
foreach (var group in pushedAssemblies.GroupBy(x => new { (document.GetElement(x.ElementId()) as AssemblyInstance).NamingCategoryId, (document.GetElement(x.ElementId()) as AssemblyInstance).AssemblyTypeName }))
{
List<string> distinctNames = group.Select(x => x.Name).Distinct().ToList();
if (distinctNames.Count > 1)
BH.Engine.Base.Compute.RecordWarning($"BHoM objects with names {string.Join(", ", distinctNames)} correspond to the same Revit assembly that has finally been named {group.Key.AssemblyTypeName}.");
}
}

// Switch of warning suppression
if (UIControlledApplication != null)
UIControlledApplication.ControlledApplication.FailuresProcessing -= ControlledApplication_FailuresProcessing;

return pushed.Cast<object>().ToList();
}


/***************************************************/
/**** Private Methods ****/
/***************************************************/

private List<IBHoMObject> PushToRevit(Document document, IEnumerable<IBHoMObject> objects, PushType pushType, RevitPushConfig pushConfig, string transactionName)
{
List<IBHoMObject> pushed = new List<IBHoMObject>();
using (Transaction transaction = new Transaction(document, transactionName))
{
transaction.Start();

if (pushType == PushType.CreateOnly)
pushed = Create(objectsToPush, pushConfig);
pushed = Create(objects, pushConfig);
else if (pushType == PushType.CreateNonExisting)
{
IEnumerable<IBHoMObject> toCreate = objectsToPush.Where(x => x.Element(document) == null);
IEnumerable<IBHoMObject> toCreate = objects.Where(x => x.Element(document) == null);
pushed = Create(toCreate, pushConfig);
}
else if (pushType == PushType.DeleteThenCreate)
{
List<IBHoMObject> toCreate = new List<IBHoMObject>();
foreach (IBHoMObject obj in objectsToPush)
foreach (IBHoMObject obj in objects)
{
Element element = obj.Element(document);
if (element == null || Delete(element.Id, document, false).Count() != 0)
Expand All @@ -130,26 +175,34 @@ public override List<object> Push(IEnumerable<object> objects, string tag = "",
}
else if (pushType == PushType.UpdateOnly)
{
foreach (IBHoMObject obj in objectsToPush)
foreach (IBHoMObject obj in objects)
{
Element element = obj.Element(document);
if (element != null && Update(element, obj, pushConfig))
pushed.Add(obj);
}
}
else if (pushType == PushType.UpdateOrCreateOnly)
{
List<IBHoMObject> toCreate = new List<IBHoMObject>();
foreach (IBHoMObject obj in objects)
{
Element element = obj.Element(document);
if (element != null && Update(element, obj, pushConfig))
pushed.Add(obj);
else if (element == null || Delete(element.Id, document, false).Count() != 0)
toCreate.Add(obj);
}

pushed.AddRange(Create(toCreate, pushConfig));
}

transaction.Commit();
}

// Switch of warning suppression
if (UIControlledApplication != null)
UIControlledApplication.ControlledApplication.FailuresProcessing -= ControlledApplication_FailuresProcessing;

return pushed.Cast<object>().ToList();
return pushed;
}

/***************************************************/
}
}


}
4 changes: 0 additions & 4 deletions Revit_Core_Adapter/FailuresProcessing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ private static void ControlledApplication_FailuresProcessing(object sender, Auto
bool hasFailure = false;
FailuresAccessor failuresAccessor = e.GetFailuresAccessor();
List<FailureMessageAccessor> failureMessageAccessorsList = failuresAccessor.GetFailureMessages().ToList();
List<ElementId> elementsToDelete = new List<ElementId>();
foreach (FailureMessageAccessor failureMessageAccessor in failureMessageAccessorsList)
{
try
Expand All @@ -60,9 +59,6 @@ private static void ControlledApplication_FailuresProcessing(object sender, Auto
}
}

if (elementsToDelete.Count != 0)
failuresAccessor.DeleteElements(elementsToDelete);

if (hasFailure)
e.SetProcessingResult(FailureProcessingResult.ProceedWithCommit);

Expand Down
27 changes: 26 additions & 1 deletion Revit_Core_Engine/Convert/FromRevit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public static IGeometry IFromRevit(this Location location)
return FromRevit(location as dynamic);
}


/***************************************************/
/**** Convert Revit elements to BHoM ****/
/***************************************************/
Expand Down Expand Up @@ -97,6 +97,31 @@ public static List<IBHoMObject> FromRevit(this EnergyAnalysisDetailModel energyA

/***************************************************/

[Description("Converts a Revit AssemblyInstance to a BHoM object based on the requested engineering discipline.")]
[Input("assemblyInstance", "Revit AssemblyInstance to be converted.")]
[Input("discipline", "Engineering discipline based on the BHoM discipline classification.")]
[Input("transform", "Optional, a transform to apply to the converted object. Irrelevant in case of assembly instances.")]
[Input("settings", "Revit adapter settings to be used while performing the convert.")]
[Input("refObjects", "Optional, a collection of objects already processed in the current adapter action, stored to avoid processing the same object more than once.")]
[Output("fromRevit", "Resulted BHoM object converted from a Revit AssemblyInstance.")]
public static List<IBHoMObject> FromRevit(this AssemblyInstance assemblyInstance, Discipline discipline, Transform transform = null, RevitSettings settings = null, Dictionary<string, List<IBHoMObject>> refObjects = null)
{
if (assemblyInstance == null)
{
BH.Engine.Base.Compute.RecordWarning("BHoM object could not be read because Revit assembly instance is null.");
return null;
}

foreach (ElementId memberId in assemblyInstance.GetMemberIds())
{
assemblyInstance.Document.GetElement(memberId).IFromRevit(discipline, transform, settings, refObjects);
}

return new List<IBHoMObject> { assemblyInstance.AssemblyFromRevit(settings, refObjects) };
}

/***************************************************/

[Description("Converts a Revit Element to a BHoM object based on the requested engineering discipline.")]
[Input("element", "Revit EnergyAnalysisDetailModel to be converted.")]
[Input("discipline", "Engineering discipline based on the BHoM discipline classification.")]
Expand Down
78 changes: 78 additions & 0 deletions Revit_Core_Engine/Convert/Revit/FromRevit/Assembly.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* This file is part of the Buildings and Habitats object Model (BHoM)
* Copyright (c) 2015 - 2022, the respective contributors. All rights reserved.
*
* Each contributor holds copyright over their respective contributions.
* The project versioning (Git) records all such contribution source information.
*
*
* The BHoM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* The BHoM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
*/

using Autodesk.Revit.DB;
using BH.Engine.Adapters.Revit;
using BH.oM.Adapters.Revit.Elements;
using BH.oM.Adapters.Revit.Settings;
using BH.oM.Base;
using BH.oM.Base.Attributes;
using System.Collections.Generic;
using System.ComponentModel;

namespace BH.Revit.Engine.Core
{
public static partial class Convert
{
/***************************************************/
/**** Public Methods ****/
/***************************************************/

[Description("Converts a Revit AssemblyInstance to BH.oM.Adapters.Revit.Elements.Assembly.")]
[Input("assemblyInstance", "Revit AssemblyInstance to be converted.")]
[Input("settings", "Revit adapter settings to be used while performing the convert.")]
[Input("refObjects", "Optional, a collection of objects already processed in the current adapter action, stored to avoid processing the same object more than once.")]
[Output("assembly", "BH.oM.Adapters.Revit.Elements.Assembly resulting from converting the input Revit AssemblyInstance.")]
public static Assembly AssemblyFromRevit(this AssemblyInstance assemblyInstance, RevitSettings settings = null, Dictionary<string, List<IBHoMObject>> refObjects = null)
{
settings = settings.DefaultIfNull();

Assembly assembly = refObjects.GetValue<Assembly>(assemblyInstance.Id);
if (assembly != null)
return assembly;

assembly = new Assembly { Name = assemblyInstance.AssemblyTypeName };
foreach (ElementId memberId in assemblyInstance.GetMemberIds())
{
List<IBHoMObject> members;
if (refObjects == null || !refObjects.TryGetValue(memberId.ToString(), out members))
{
BH.Engine.Base.Compute.RecordError("Assembly instance could not be converted from Revit because not all of its members were converted prior to it." +
"\nPlease make sure all member elements of an assembly instance get converted to BHoM and cached in refObjects before conversion of the instance itself.");
return null;
}

assembly.MemberElements.AddRange(members);
}

//Set identifiers, parameters & custom data
assembly.SetIdentifiers(assemblyInstance);
assembly.CopyParameters(assemblyInstance, settings.MappingSettings);
assembly.SetProperties(assemblyInstance, settings.MappingSettings);

refObjects.AddOrReplace(assemblyInstance.Id, assembly);
return assembly;
}

/***************************************************/
}
}
74 changes: 74 additions & 0 deletions Revit_Core_Engine/Convert/Revit/ToRevit/AssemblyInstance.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* This file is part of the Buildings and Habitats object Model (BHoM)
* Copyright (c) 2015 - 2022, the respective contributors. All rights reserved.
*
* Each contributor holds copyright over their respective contributions.
* The project versioning (Git) records all such contribution source information.
*
*
* The BHoM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* The BHoM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
*/

using Autodesk.Revit.DB;
using BH.oM.Adapters.Revit.Settings;
using BH.oM.Base;
using BH.oM.Base.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace BH.Revit.Engine.Core
{
public static partial class Convert
{
/***************************************************/
/**** Public Methods ****/
/***************************************************/

[Description("Converts BH.oM.Adapters.Revit.Elements.Assembly to a Revit AssemblyInstance." +
"\nOnly the assembly instance itself is created, while any updates of name or parameters need to happen in a separate transaction, which is caused by Revit API limitations.")]
[Input("assembly", "BH.oM.Adapters.Revit.Elements.Assembly to be converted.")]
[Input("document", "Revit document, in which the output of the convert will be created.")]
[Input("settings", "Revit adapter settings to be used while performing the convert.")]
[Input("refObjects", "Optional, a collection of objects already processed in the current adapter action, stored to avoid processing the same object more than once.")]
[Output("assemblyInstance", "Revit AssemblyInstance resulting from converting the input BH.oM.Adapters.Revit.Elements.Assembly.")]
public static AssemblyInstance ToRevitAssembly(this oM.Adapters.Revit.Elements.Assembly assembly, Document document, RevitSettings settings = null, Dictionary<Guid, List<int>> refObjects = null)
{
if (assembly?.MemberElements == null)
return null;

AssemblyInstance revitAssembly = refObjects.GetValue<AssemblyInstance>(document, assembly.BHoM_Guid);
if (revitAssembly != null)
return revitAssembly;

List<IBHoMObject> assemblyMembers = assembly.AssemblyMembers();
List<ElementId> memberElementIds = assemblyMembers.Select(x => x.ElementId()).Where(x => x != null).ToList();
if (memberElementIds.Count == 0)
{
BH.Engine.Base.Compute.RecordError($"Creation of the assembly failed because it does not have any valid member elements. BHoM_Guid: {assembly.BHoM_Guid}");
return null;
}
else if (memberElementIds.Count != assemblyMembers.Count)
BH.Engine.Base.Compute.RecordWarning($"The assembly is missing some member elements. BHoM_Guid: {assembly.BHoM_Guid}");

revitAssembly = AssemblyInstance.Create(document, memberElementIds, document.GetElement(memberElementIds[0]).Category.Id);

refObjects.AddOrReplace(assembly, revitAssembly);
return revitAssembly;
}

/***************************************************/
}
}
1 change: 0 additions & 1 deletion Revit_Core_Engine/Convert/Revit/ToRevit/ViewPlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ public static ViewPlan ToRevitViewPlan(this oM.Adapters.Revit.Elements.ViewPlan

revitViewPlan = Create.ViewPlan(document, level, viewPlan.ViewName, null, viewTemplateId) as ViewPlan;


// Copy parameters from BHoM object to Revit element
revitViewPlan.CopyParameters(viewPlan, settings);

Expand Down
Loading