From f2f832a183986d840a7941e34d76f460f7efd6ff Mon Sep 17 00:00:00 2001 From: Pawel Baran Date: Wed, 12 Jun 2024 09:41:30 +0200 Subject: [PATCH 1/6] WIP semi-working solution --- Revit_Core_Adapter/CRUD/Read.cs | 110 +++++++++++++----- .../Compute/SplitRequestTreeByLinks.cs | 54 ++++++--- 2 files changed, 119 insertions(+), 45 deletions(-) diff --git a/Revit_Core_Adapter/CRUD/Read.cs b/Revit_Core_Adapter/CRUD/Read.cs index 52ee6d3fb..b21f3bfcb 100644 --- a/Revit_Core_Adapter/CRUD/Read.cs +++ b/Revit_Core_Adapter/CRUD/Read.cs @@ -87,7 +87,7 @@ protected override IEnumerable Read(IRequest request, ActionConfig } } - Dictionary requestsByLinks = request.SplitRequestTreeByLinks(this.Document); + Dictionary requestsByLinks = request.SplitRequestTreeByLinks(this.Document); if (requestsByLinks == null) { BH.Engine.Base.Compute.RecordError($"Pull failed due to issues with the request containing {nameof(FilterByLink)}. Please try to restructure the used Request and try again."); @@ -96,12 +96,42 @@ protected override IEnumerable Read(IRequest request, ActionConfig RevitSettings settings = RevitSettings.DefaultIfNull(); + Dictionary<(Document, Transform), List> requestsByDocumentAndTransform = new Dictionary<(Document, Transform), List>(); + foreach (KeyValuePair requestByLink in requestsByLinks) + { + Document doc; + Transform transform = null; + if (requestByLink.Key.IntegerValue == -1) + doc = this.Document; + else + { + var rli = this.Document.GetElement(requestByLink.Key) as RevitLinkInstance; + doc = rli.GetLinkDocument(); + + Transform t = rli.GetTotalTransform(); + if (!t.IsIdentity) + transform = t; + } + + var tuple = (doc, transform); + if (!requestsByDocumentAndTransform.ContainsKey(tuple)) + requestsByDocumentAndTransform.Add(tuple, new List()); + + requestsByDocumentAndTransform[tuple].Add(requestByLink.Value); + } + + Dictionary>> globalRefObjects = new Dictionary>>(); List result = new List(); - foreach (KeyValuePair requestByLink in requestsByLinks) + foreach (var kvp in requestsByDocumentAndTransform) { - result.AddRange(Read(requestByLink.Key, requestByLink.Value, pullConfig, settings)); + result.AddRange(Read(kvp.Key.Item1, kvp.Key.Item2, kvp.Value, pullConfig, settings, globalRefObjects)); } + //foreach (KeyValuePair requestByLink in requestsByLinks) + //{ + // result.AddRange(Read(requestByLink.Key, requestByLink.Value, pullConfig, settings)); + //} + this.UIDocument.Selection.SetElementIds(selected); return result; @@ -112,7 +142,7 @@ protected override IEnumerable Read(IRequest request, ActionConfig /**** Public Methods ****/ /***************************************************/ - public static List Read(Document document, IRequest request, RevitPullConfig pullConfig = null, RevitSettings settings = null) + public static List Read(Document document, Transform transform, List requests, RevitPullConfig pullConfig = null, RevitSettings settings = null, Dictionary>> globalRefObjects = null) { if (document == null) { @@ -120,11 +150,13 @@ public static List Read(Document document, IRequest request, RevitP return new List(); } - if (request == null) - { - BH.Engine.Base.Compute.RecordError("BHoM objects could not be read because provided IRequest is null."); - return new List(); - } + //TODO: union requests and if any duplicates then warning!! + + //if (request == null) + //{ + // BH.Engine.Base.Compute.RecordError("BHoM objects could not be read because provided IRequest is null."); + // return new List(); + //} pullConfig = pullConfig.DefaultIfNull(); settings = settings.DefaultIfNull(); @@ -133,9 +165,11 @@ public static List Read(Document document, IRequest request, RevitP if (!pullConfig.IncludeClosedWorksets) worksetPrefilter = document.OpenWorksetsPrefilter(); - List elementIds = request.IElementIds(document, pullConfig.Discipline, settings, worksetPrefilter).RemoveGridSegmentIds(document)?.ToList(); - if (elementIds == null) - return new List(); + HashSet elementIds = new HashSet(); + foreach (IRequest request in requests) + { + elementIds.UnionWith(request.IElementIds(document, pullConfig.Discipline, settings, worksetPrefilter)?.RemoveGridSegmentIds(document) ?? new List()); + } if (pullConfig.IncludeNestedElements) { @@ -150,15 +184,15 @@ public static List Read(Document document, IRequest request, RevitP elemIds.AddRange(nestedElemIds); } } - elementIds.AddRange(elemIds); + elementIds.UnionWith(elemIds); } - return Read(document, elementIds, pullConfig, settings); + return Read(document, transform, elementIds.ToList(), pullConfig, settings, globalRefObjects); } /***************************************************/ - public static List Read(Document document, List elementIds, RevitPullConfig pullConfig = null, RevitSettings settings = null) + public static List Read(Document document, Transform transform, List elementIds, RevitPullConfig pullConfig = null, RevitSettings settings = null, Dictionary>> globalRefObjects = null) { if (document == null) { @@ -194,29 +228,51 @@ public static List Read(Document document, List elementI Options meshOptions = BH.Revit.Engine.Core.Create.Options(geometryConfig.MeshDetailLevel.ViewDetailLevel(), geometryConfig.IncludeNonVisible, false); Options renderMeshOptions = BH.Revit.Engine.Core.Create.Options(representationConfig.DetailLevel.ViewDetailLevel(), representationConfig.IncludeNonVisible, false); - Transform linkTransform = null; - TransformMatrix bHoMTransform = null; - if (document.IsLinked) + //TODO: that does not work for multiple links! + // would rather get LinkTransforms(), find unique ones and work with these? + // NOT GOING TO WORK FOR LINKS FILTERED BY ID + //Transform linkTransform = null; + //TransformMatrix bHoMTransform = null; + //if (document.IsLinked) + //{ + // linkTransform = document.LinkTransform(); + // if (linkTransform?.IsIdentity == false) + // bHoMTransform = linkTransform.FromRevit(); + //} + + var bHoMTransform = transform.FromRevit(); + if (globalRefObjects == null) + globalRefObjects = new Dictionary>>(); + + if (!globalRefObjects.ContainsKey(document.Title)) + globalRefObjects.Add(document.Title, new Dictionary>()); + + Dictionary> refObjects = globalRefObjects[document.Title]; + + List result = new List(); + List remainingElementIds = elementIds.ToList(); + for (int i = 0; i < remainingElementIds.Count; i++) { - linkTransform = document.LinkTransform(); - if (linkTransform?.IsIdentity == false) - bHoMTransform = linkTransform.FromRevit(); + ElementId id = remainingElementIds[i]; + var existing = refObjects.GetValues(id); + if (existing != null) + { + result.AddRange(existing.Select(x => x.IPostprocess(transform, settings))); + remainingElementIds.RemoveAt(i); + } } - Dictionary> refObjects = new Dictionary>(); - // Extract panel geometry of walls, floors, slabs and roofs prior to running the converts (this is an optimisation aimed to reduce the number of view regenerations) if (!document.IsLinked) - document.CachePanelGeometry(elementIds, discipline, settings, refObjects); + document.CachePanelGeometry(remainingElementIds, discipline, settings, refObjects); - List result = new List(); - foreach (ElementId id in elementIds) + foreach (ElementId id in remainingElementIds) { Element element = document.GetElement(id); if (element == null) continue; - IEnumerable iBHoMObjects = Read(element, discipline, linkTransform, settings, refObjects); + IEnumerable iBHoMObjects = Read(element, discipline, transform, settings, refObjects); if (iBHoMObjects != null && iBHoMObjects.Any()) { diff --git a/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs b/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs index 205357c7f..ce68fa2bc 100644 --- a/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs +++ b/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs @@ -43,10 +43,10 @@ public static partial class Compute [Input("request", "An IRequest to be split into a dictionary of Revit documents and the IRequests relevant to them.")] [Input("document", "Host document to be used as the basis of the splitting routine.")] [Output("splitRequests", "A dictionary of Revit documents (both host and linked) and the IRequests relevant to them, which in total represents the same request as the input IRequest.")] - public static Dictionary SplitRequestTreeByLinks(this IRequest request, Document document) + public static Dictionary SplitRequestTreeByLinks(this IRequest request, Document document) { - Dictionary requestsByLinks = new Dictionary(); + Dictionary requestsByLinks = new Dictionary(); List splitPerDoc = request.SplitRequestTreeByType(typeof(FilterByLink)); foreach (IRequest splitRequest in splitPerDoc) { @@ -62,7 +62,7 @@ public static Dictionary SplitRequestTreeByLinks(this IReque /**** Private Methods ****/ /***************************************************/ - private static bool TryOrganizeByLink(this IRequest request, Document document, Dictionary requestsByLinks) + private static bool TryOrganizeByLink(this IRequest request, Document document, Dictionary requestsByLinks) { if (request == null) return false; @@ -78,7 +78,7 @@ private static bool TryOrganizeByLink(this IRequest request, Document document, List linkRequests = request.AllRequestsOfType(typeof(FilterByLink)); if (linkRequests.Count == 0) { - requestsByLinks.AddRequestByLink(request, document); + requestsByLinks.AddRequestByLink(request, new ElementId(-1)); return true; } else if (linkRequests.Count == 1) @@ -86,29 +86,47 @@ private static bool TryOrganizeByLink(this IRequest request, Document document, FilterByLink linkRequest = (FilterByLink)linkRequests[0]; List linkInstanceIds = document.ElementIdsOfLinkInstances(linkRequest.LinkName, linkRequest.CaseSensitive); - if (linkInstanceIds.Count == 1) + if (linkInstanceIds.Count == 0) + { + BH.Engine.Base.Compute.RecordError($"Active Revit document does not contain links with neither name nor path nor ElementId equal to {linkRequest.LinkName}."); + return false; + } + else if (linkInstanceIds.Count > 1) + BH.Engine.Base.Compute.RecordWarning($"There is more than one link document named {linkRequest.LinkName} - elements will be pulled from all unique instances of the links." + + $"\nPlease use full link path or its ElementId instead of link name to pull specifically from a chosen instance."); + + foreach (ElementId linkInstanceId in linkInstanceIds) { request.RemoveSubRequest(linkRequest); request = request.SimplifyRequestTree(); - requestsByLinks.AddRequestByLink(request, ((RevitLinkInstance)document.GetElement(linkInstanceIds[0])).GetLinkDocument()); - return true; + requestsByLinks.AddRequestByLink(request, linkInstanceId); } - else if (linkInstanceIds.Count == 0) - BH.Engine.Base.Compute.RecordError($"Active Revit document does not contain links with neither name nor path nor ElementId equal to {linkRequest.LinkName}."); - else - BH.Engine.Base.Compute.RecordError($"There is more than one link document named {linkRequest.LinkName} - please use full link path or its ElementId instead of link name to pull."); - } - return false; + return true; + + //if (linkInstanceIds.Count == 1) + //{ + // request.RemoveSubRequest(linkRequest); + // request = request.SimplifyRequestTree(); + // requestsByLinks.AddRequestByLink(request, ((RevitLinkInstance)document.GetElement(linkInstanceIds[0])).Id); + // return true; + //} + //else if (linkInstanceIds.Count == 0) + // BH.Engine.Base.Compute.RecordError($"Active Revit document does not contain links with neither name nor path nor ElementId equal to {linkRequest.LinkName}."); + //else + // BH.Engine.Base.Compute.RecordError($"There is more than one link document named {linkRequest.LinkName} - please use full link path or its ElementId instead of link name to pull."); + } + else + return false; } /***************************************************/ - private static void AddRequestByLink(this Dictionary requestsByLinks, IRequest request, Document document) + private static void AddRequestByLink(this Dictionary requestsByLinks, IRequest request, ElementId linkId) { - if (requestsByLinks.ContainsKey(document)) + if (requestsByLinks.ContainsKey(linkId)) { - IRequest requestByLink = requestsByLinks[document]; + IRequest requestByLink = requestsByLinks[linkId]; if (requestByLink is LogicalOrFilter) ((LogicalOrRequest)requestByLink).Requests.Add(request); else @@ -116,11 +134,11 @@ private static void AddRequestByLink(this Dictionary request LogicalOrRequest newHead = new LogicalOrRequest(); newHead.Requests.Add(requestByLink); newHead.Requests.Add(request); - requestsByLinks[document] = newHead; + requestsByLinks[linkId] = newHead; } } else - requestsByLinks[document] = request; + requestsByLinks[linkId] = request; } /***************************************************/ From 198c2f6b5e39dcfaebd884733cf794d907766b0a Mon Sep 17 00:00:00 2001 From: Pawel Baran Date: Wed, 12 Jun 2024 13:05:03 +0200 Subject: [PATCH 2/6] #1477 finally fixed --- Revit_Core_Adapter/CRUD/Read.cs | 75 ++++++++----------------- Revit_Core_Engine/Convert/FromRevit.cs | 21 +++---- Revit_Core_Engine/Modify/Postprocess.cs | 72 +++++++++++++++++++++--- 3 files changed, 93 insertions(+), 75 deletions(-) diff --git a/Revit_Core_Adapter/CRUD/Read.cs b/Revit_Core_Adapter/CRUD/Read.cs index b21f3bfcb..9239c8289 100644 --- a/Revit_Core_Adapter/CRUD/Read.cs +++ b/Revit_Core_Adapter/CRUD/Read.cs @@ -224,23 +224,6 @@ public static List Read(Document document, Transform transform, Lis discipline = Discipline.Physical; } - Options geometryOptions = BH.Revit.Engine.Core.Create.Options(ViewDetailLevel.Fine, geometryConfig.IncludeNonVisible, false); - Options meshOptions = BH.Revit.Engine.Core.Create.Options(geometryConfig.MeshDetailLevel.ViewDetailLevel(), geometryConfig.IncludeNonVisible, false); - Options renderMeshOptions = BH.Revit.Engine.Core.Create.Options(representationConfig.DetailLevel.ViewDetailLevel(), representationConfig.IncludeNonVisible, false); - - //TODO: that does not work for multiple links! - // would rather get LinkTransforms(), find unique ones and work with these? - // NOT GOING TO WORK FOR LINKS FILTERED BY ID - //Transform linkTransform = null; - //TransformMatrix bHoMTransform = null; - //if (document.IsLinked) - //{ - // linkTransform = document.LinkTransform(); - // if (linkTransform?.IsIdentity == false) - // bHoMTransform = linkTransform.FromRevit(); - //} - - var bHoMTransform = transform.FromRevit(); if (globalRefObjects == null) globalRefObjects = new Dictionary>>(); @@ -250,89 +233,75 @@ public static List Read(Document document, Transform transform, Lis Dictionary> refObjects = globalRefObjects[document.Title]; List result = new List(); - List remainingElementIds = elementIds.ToList(); - for (int i = 0; i < remainingElementIds.Count; i++) + List remainingElementIds = new List(); + foreach (ElementId id in elementIds) { - ElementId id = remainingElementIds[i]; var existing = refObjects.GetValues(id); if (existing != null) - { - result.AddRange(existing.Select(x => x.IPostprocess(transform, settings))); - remainingElementIds.RemoveAt(i); - } + result.AddRange(existing); + else + remainingElementIds.Add(id); } // Extract panel geometry of walls, floors, slabs and roofs prior to running the converts (this is an optimisation aimed to reduce the number of view regenerations) if (!document.IsLinked) document.CachePanelGeometry(remainingElementIds, discipline, settings, refObjects); - + + Options geometryOptions = BH.Revit.Engine.Core.Create.Options(ViewDetailLevel.Fine, geometryConfig.IncludeNonVisible, false); + Options meshOptions = BH.Revit.Engine.Core.Create.Options(geometryConfig.MeshDetailLevel.ViewDetailLevel(), geometryConfig.IncludeNonVisible, false); + Options renderMeshOptions = BH.Revit.Engine.Core.Create.Options(representationConfig.DetailLevel.ViewDetailLevel(), representationConfig.IncludeNonVisible, false); + foreach (ElementId id in remainingElementIds) { Element element = document.GetElement(id); if (element == null) continue; - IEnumerable iBHoMObjects = Read(element, discipline, transform, settings, refObjects); - - if (iBHoMObjects != null && iBHoMObjects.Any()) + IEnumerable converted = Read(element, discipline, settings, refObjects); + if (converted != null) { if (pullConfig.PullMaterialTakeOff) { - foreach (IBHoMObject iBHoMObject in iBHoMObjects) + foreach (IBHoMObject obj in converted) { oM.Physical.Materials.VolumetricMaterialTakeoff takeoff = element.VolumetricMaterialTakeoff(settings, refObjects); if (takeoff != null) - iBHoMObject.Fragments.AddOrReplace(takeoff); + obj.Fragments.AddOrReplace(takeoff); } } List edges = null; if (geometryConfig.PullEdges) - { edges = element.Curves(geometryOptions, settings, true).FromRevit(); - if (bHoMTransform != null) - edges = edges.Select(x => x?.ITransform(bHoMTransform)).ToList(); - } List surfaces = null; if (geometryConfig.PullSurfaces) - { surfaces = element.Faces(geometryOptions, settings).Select(x => x.IFromRevit()).ToList(); - if (bHoMTransform != null) - surfaces = surfaces.Select(x => x?.ITransform(bHoMTransform)).ToList(); - } List meshes = null; if (geometryConfig.PullMeshes) - { meshes = element.MeshedGeometry(meshOptions, settings); - if (bHoMTransform != null) - meshes = meshes.Select(x => x?.Transform(bHoMTransform)).ToList(); - } if (geometryConfig.PullEdges || geometryConfig.PullSurfaces || geometryConfig.PullMeshes) { RevitGeometry geometry = new RevitGeometry(edges, surfaces, meshes); - foreach (IBHoMObject iBHoMObject in iBHoMObjects) + foreach (IBHoMObject obj in converted) { - iBHoMObject.Fragments.AddOrReplace(geometry); + obj.Fragments.AddOrReplace(geometry); } } if (representationConfig.PullRenderMesh) { List renderMeshes = element.RenderMeshes(renderMeshOptions, settings); - if (bHoMTransform != null) - renderMeshes = renderMeshes.Select(x => x?.Transform(bHoMTransform)).ToList(); - RevitRepresentation representation = new RevitRepresentation(renderMeshes); - foreach (IBHoMObject iBHoMObject in iBHoMObjects) + foreach (IBHoMObject obj in converted) { - iBHoMObject.Fragments.AddOrReplace(representation); + obj.Fragments.AddOrReplace(representation); } } - result.AddRange(iBHoMObjects); + result.AddRange(converted); } } @@ -340,12 +309,12 @@ public static List Read(Document document, Transform transform, Lis if (activePulls.Count(x => x) > 1) BH.Engine.Base.Compute.RecordWarning("Pull of more than one geometry/representation type has been specified in RevitPullConfig. Please consider this can be time consuming due to the amount of conversions."); - return result; + return result.Select(x => x.IPostprocess(transform, settings)).Where(x => x != null).ToList(); } /***************************************************/ - public static List Read(Element element, Discipline discipline, Transform transform, RevitSettings settings = null, Dictionary> refObjects = null) + public static List Read(Element element, Discipline discipline, RevitSettings settings = null, Dictionary> refObjects = null) { if (element == null || !element.IsValidObject) return new List(); @@ -353,7 +322,7 @@ public static List Read(Element element, Discipline discipline, Tra List result = null; try { - result = element.IFromRevit(discipline, transform, settings, refObjects); + result = element.IFromRevit(discipline, settings, refObjects); } catch (Exception exception) { diff --git a/Revit_Core_Engine/Convert/FromRevit.cs b/Revit_Core_Engine/Convert/FromRevit.cs index a33531928..66f80fe35 100644 --- a/Revit_Core_Engine/Convert/FromRevit.cs +++ b/Revit_Core_Engine/Convert/FromRevit.cs @@ -44,13 +44,12 @@ public static partial class Convert [Description("Interface method that tries to find a suitable FromRevit convert for any Revit Element.")] [Input("element", "Revit Element to be converted.")] [Input("discipline", "Engineering discipline based on the BHoM discipline classification.")] - [Input("transform", "Optional, a transform to apply to the converted object.")] [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 Element.")] - public static List IFromRevit(this Element element, Discipline discipline, Transform transform = null, RevitSettings settings = null, Dictionary> refObjects = null) + public static List IFromRevit(this Element element, Discipline discipline, RevitSettings settings = null, Dictionary> refObjects = null) { - return FromRevit(element as dynamic, discipline, transform, settings, refObjects); + return FromRevit(element as dynamic, discipline, settings, refObjects); } /***************************************************/ @@ -74,11 +73,10 @@ public static IGeometry IFromRevit(this Location location) [Description("Converts a Revit EnergyAnalysisDetailModel to a BHoM object based on the requested engineering discipline.")] [Input("energyAnalysisModel", "Revit EnergyAnalysisDetailModel to be converted.")] [Input("discipline", "Engineering discipline based on the BHoM discipline classification.")] - [Input("transform", "Optional, a transform to apply to the converted object.")] [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 EnergyAnalysisDetailModel.")] - public static List FromRevit(this EnergyAnalysisDetailModel energyAnalysisModel, Discipline discipline, Transform transform = null, RevitSettings settings = null, Dictionary> refObjects = null) + public static List FromRevit(this EnergyAnalysisDetailModel energyAnalysisModel, Discipline discipline, RevitSettings settings = null, Dictionary> refObjects = null) { if (energyAnalysisModel == null) { @@ -100,11 +98,10 @@ public static List 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 FromRevit(this AssemblyInstance assemblyInstance, Discipline discipline, Transform transform = null, RevitSettings settings = null, Dictionary> refObjects = null) + public static List FromRevit(this AssemblyInstance assemblyInstance, Discipline discipline, RevitSettings settings = null, Dictionary> refObjects = null) { if (assemblyInstance == null) { @@ -114,7 +111,7 @@ public static List FromRevit(this AssemblyInstance assemblyInstance foreach (ElementId memberId in assemblyInstance.GetMemberIds()) { - assemblyInstance.Document.GetElement(memberId).IFromRevit(discipline, transform, settings, refObjects); + assemblyInstance.Document.GetElement(memberId).IFromRevit(discipline, settings, refObjects); } return new List { assemblyInstance.AssemblyFromRevit(settings, refObjects) }; @@ -125,11 +122,10 @@ public static List FromRevit(this AssemblyInstance assemblyInstance [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.")] - [Input("transform", "Optional, a transform to apply to the converted object.")] [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 Element.")] - public static List FromRevit(this Element element, Discipline discipline, Transform transform = null, RevitSettings settings = null, Dictionary> refObjects = null) + public static List FromRevit(this Element element, Discipline discipline, RevitSettings settings = null, Dictionary> refObjects = null) { if (element == null) { @@ -159,12 +155,11 @@ public static List FromRevit(this Element element, Discipline disci List result = null; if (converted is IBHoMObject) - result = new List { ((IBHoMObject)converted).IPostprocess(transform, settings) }; + result = new List { ((IBHoMObject)converted) }; else if (converted is IEnumerable) { result = new List(((IEnumerable)converted) - .Where(x => x != null) - .Select(x => x.IPostprocess(transform, settings))); + .Where(x => x != null)); } return result; diff --git a/Revit_Core_Engine/Modify/Postprocess.cs b/Revit_Core_Engine/Modify/Postprocess.cs index 651c6753c..c71b2f12e 100644 --- a/Revit_Core_Engine/Modify/Postprocess.cs +++ b/Revit_Core_Engine/Modify/Postprocess.cs @@ -23,14 +23,19 @@ using Autodesk.Revit.DB; using BH.Engine.Adapters.Revit; using BH.Engine.Base; -using BH.Engine.Spatial; +using BH.Engine.Geometry; +using BH.Engine.Graphics; +using BH.oM.Adapters.Revit; using BH.oM.Adapters.Revit.Elements; using BH.oM.Adapters.Revit.Settings; using BH.oM.Base; +using BH.oM.Base.Attributes; using BH.oM.Dimensional; using BH.oM.Geometry; -using BH.oM.Base.Attributes; +using BH.oM.MEP.Fragments; +using BH.oM.Spatial.SettingOut; using System.ComponentModel; +using System.Linq; namespace BH.Revit.Engine.Core { @@ -71,7 +76,17 @@ public static IElement Postprocess(this IElement element, Transform transform, R settings = settings.DefaultIfNull(); if (transform?.IsIdentity == false) - element = element.ITransform(transform.FromRevit(), settings.DistanceTolerance); + { + TransformMatrix bhomTransform = transform.FromRevit(); + element = BH.Engine.Spatial.Modify.ITransform(element, bhomTransform, settings.DistanceTolerance); + + if (element is IBHoMObject) + { + IBHoMObject obj = (IBHoMObject)element; + obj.TransformGeometry(bhomTransform); + obj.TransformRepresentation(bhomTransform); + } + } return element; } @@ -94,7 +109,12 @@ public static IInstance Postprocess(this ModelInstance instance, Transform trans settings = settings.DefaultIfNull(); if (transform?.IsIdentity == false) - instance = instance.Transform(transform.FromRevit(), settings.DistanceTolerance) as ModelInstance; + { + TransformMatrix bhomTransform = transform.FromRevit(); + instance = instance.Transform(bhomTransform, settings.DistanceTolerance) as ModelInstance; + instance.TransformGeometry(bhomTransform); + instance.TransformRepresentation(bhomTransform); + } return instance; } @@ -118,16 +138,54 @@ public static BH.oM.Spatial.SettingOut.Level Postprocess(this BH.oM.Spatial.Sett { level = level.ShallowClone(); level.Elevation += transform.Origin.Z.ToSI(SpecTypeId.Length); + TransformMatrix bhomTransform = transform.FromRevit(); + level.TransformGeometry(bhomTransform); + level.TransformRepresentation(bhomTransform); } return level; } + /***************************************************/ + /**** Private methods ****/ + /***************************************************/ + + private static void TransformGeometry(this IBHoMObject obj, TransformMatrix transform) + { + RevitGeometry geometryFragment = obj.FindFragment(); + if (geometryFragment != null) + { + obj.Fragments.Remove(geometryFragment); + obj.Fragments.Add(new RevitGeometry + ( + geometryFragment.Edges?.Select(x => x.ITransform(transform)).ToList(), + geometryFragment.Surfaces?.Select(x => x.ITransform(transform)).ToList(), + geometryFragment.Meshes?.Select(x => x.Transform(transform)).ToList() + )); + } + } + + /***************************************************/ + + private static void TransformRepresentation(this IBHoMObject obj, TransformMatrix transform) + { + RevitRepresentation representationFragment = obj.FindFragment(); + if (representationFragment != null) + { + obj.Fragments.Remove(representationFragment); + obj.Fragments.Add(new RevitRepresentation + ( + representationFragment.RenderMeshes?.Select(x => x.Transform(transform)) + )); + } + } + + /***************************************************/ /**** Fallback methods ****/ /***************************************************/ - + private static IObject Postprocess(this IObject obj, Transform transform, RevitSettings settings) { return obj; @@ -136,7 +194,3 @@ private static IObject Postprocess(this IObject obj, Transform transform, RevitS /***************************************************/ } } - - - - From 9ba961a963e4fbf5fd13e63f8cb119fc4e0201c2 Mon Sep 17 00:00:00 2001 From: Pawel Baran Date: Wed, 12 Jun 2024 13:35:23 +0200 Subject: [PATCH 3/6] comments added, code cleaned up --- Revit_Core_Adapter/CRUD/Read.cs | 79 ++++++++++--------- .../Compute/SplitRequestTreeByLinks.cs | 18 +---- 2 files changed, 42 insertions(+), 55 deletions(-) diff --git a/Revit_Core_Adapter/CRUD/Read.cs b/Revit_Core_Adapter/CRUD/Read.cs index 9239c8289..f0d6ade6c 100644 --- a/Revit_Core_Adapter/CRUD/Read.cs +++ b/Revit_Core_Adapter/CRUD/Read.cs @@ -24,7 +24,6 @@ using BH.Engine.Adapters.Revit; using BH.Engine.Base; using BH.Engine.Geometry; -using BH.Engine.Graphics; using BH.oM.Adapter; using BH.oM.Adapters.Revit; using BH.oM.Adapters.Revit.Enums; @@ -87,6 +86,7 @@ protected override IEnumerable Read(IRequest request, ActionConfig } } + // Split the request into separate requests per each link model Dictionary requestsByLinks = request.SplitRequestTreeByLinks(this.Document); if (requestsByLinks == null) { @@ -96,6 +96,10 @@ protected override IEnumerable Read(IRequest request, ActionConfig RevitSettings settings = RevitSettings.DefaultIfNull(); + // Group links that hold the same document and have same transform + // Addresses the case when there is a nested link being loaded via more than one parent link + // Same document linked in multiple locations is being pulled per each location + // Performance is not affected by multiple converts of same elements thanks to refObjects Dictionary<(Document, Transform), List> requestsByDocumentAndTransform = new Dictionary<(Document, Transform), List>(); foreach (KeyValuePair requestByLink in requestsByLinks) { @@ -105,21 +109,28 @@ protected override IEnumerable Read(IRequest request, ActionConfig doc = this.Document; else { - var rli = this.Document.GetElement(requestByLink.Key) as RevitLinkInstance; - doc = rli.GetLinkDocument(); + var linkInstance = this.Document.GetElement(requestByLink.Key) as RevitLinkInstance; + doc = linkInstance.GetLinkDocument(); - Transform t = rli.GetTotalTransform(); - if (!t.IsIdentity) - transform = t; + Transform linkTransform = linkInstance.GetTotalTransform(); + if (!linkTransform.IsIdentity) + transform = linkTransform; } - var tuple = (doc, transform); - if (!requestsByDocumentAndTransform.ContainsKey(tuple)) + (Document doc, Transform transform) tuple; + if (requestsByDocumentAndTransform.Keys.All(x => x.Item1.Title != doc.Title || !x.Item2.AlmostEqual(transform))) + { + tuple = (doc, transform); requestsByDocumentAndTransform.Add(tuple, new List()); + } + else + tuple = requestsByDocumentAndTransform.Keys.First(x => x.Item1.Title == doc.Title && x.Item2.AlmostEqual(transform)); requestsByDocumentAndTransform[tuple].Add(requestByLink.Value); } + // Global refObjects help sharing the refObjects when pulling from same document linked in a few different locations (e.g. copy-pasted link) + // Thanks to sharing refObjects, an element is processed only once even if FromRevit is called against it multiple times Dictionary>> globalRefObjects = new Dictionary>>(); List result = new List(); foreach (var kvp in requestsByDocumentAndTransform) @@ -127,11 +138,7 @@ protected override IEnumerable Read(IRequest request, ActionConfig result.AddRange(Read(kvp.Key.Item1, kvp.Key.Item2, kvp.Value, pullConfig, settings, globalRefObjects)); } - //foreach (KeyValuePair requestByLink in requestsByLinks) - //{ - // result.AddRange(Read(requestByLink.Key, requestByLink.Value, pullConfig, settings)); - //} - + // Restore selection this.UIDocument.Selection.SetElementIds(selected); return result; @@ -150,27 +157,18 @@ public static List Read(Document document, Transform transform, Lis return new List(); } - //TODO: union requests and if any duplicates then warning!! - - //if (request == null) - //{ - // BH.Engine.Base.Compute.RecordError("BHoM objects could not be read because provided IRequest is null."); - // return new List(); - //} - pullConfig = pullConfig.DefaultIfNull(); settings = settings.DefaultIfNull(); + // Prefilter only elements from open worksets if requested IEnumerable worksetPrefilter = null; if (!pullConfig.IncludeClosedWorksets) worksetPrefilter = document.OpenWorksetsPrefilter(); - HashSet elementIds = new HashSet(); - foreach (IRequest request in requests) - { - elementIds.UnionWith(request.IElementIds(document, pullConfig.Discipline, settings, worksetPrefilter)?.RemoveGridSegmentIds(document) ?? new List()); - } + // Get elementIds from all requests + List elementIds = new LogicalOrRequest { Requests = requests }.ElementIds(document, pullConfig.Discipline, settings, worksetPrefilter).ToList(); + // Get elementIds of nested elements if requested if (pullConfig.IncludeNestedElements) { List elemIds = new List(); @@ -184,7 +182,7 @@ public static List Read(Document document, Transform transform, Lis elemIds.AddRange(nestedElemIds); } } - elementIds.UnionWith(elemIds); + elementIds.AddRange(elemIds); } return Read(document, transform, elementIds.ToList(), pullConfig, settings, globalRefObjects); @@ -209,14 +207,6 @@ public static List Read(Document document, Transform transform, Lis pullConfig = pullConfig.DefaultIfNull(); settings = settings.DefaultIfNull(); - PullGeometryConfig geometryConfig = pullConfig.GeometryConfig; - if (geometryConfig == null) - geometryConfig = new PullGeometryConfig(); - - PullRepresentationConfig representationConfig = pullConfig.RepresentationConfig; - if (representationConfig == null) - representationConfig = new PullRepresentationConfig(); - Discipline discipline = pullConfig.Discipline; if (discipline == Discipline.Undefined) { @@ -224,6 +214,7 @@ public static List Read(Document document, Transform transform, Lis discipline = Discipline.Physical; } + // Set up refObjects if (globalRefObjects == null) globalRefObjects = new Dictionary>>(); @@ -232,6 +223,9 @@ public static List Read(Document document, Transform transform, Lis Dictionary> refObjects = globalRefObjects[document.Title]; + // Get the elements already processed for a given document + // Only relevant in case of same document linked in multiple locations + // Helps avoid getting same element processed multiple times List result = new List(); List remainingElementIds = new List(); foreach (ElementId id in elementIds) @@ -247,10 +241,21 @@ public static List Read(Document document, Transform transform, Lis if (!document.IsLinked) document.CachePanelGeometry(remainingElementIds, discipline, settings, refObjects); + // Set up all geometry/representation configs + PullGeometryConfig geometryConfig = pullConfig.GeometryConfig; + if (geometryConfig == null) + geometryConfig = new PullGeometryConfig(); + + PullRepresentationConfig representationConfig = pullConfig.RepresentationConfig; + if (representationConfig == null) + representationConfig = new PullRepresentationConfig(); + Options geometryOptions = BH.Revit.Engine.Core.Create.Options(ViewDetailLevel.Fine, geometryConfig.IncludeNonVisible, false); Options meshOptions = BH.Revit.Engine.Core.Create.Options(geometryConfig.MeshDetailLevel.ViewDetailLevel(), geometryConfig.IncludeNonVisible, false); Options renderMeshOptions = BH.Revit.Engine.Core.Create.Options(representationConfig.DetailLevel.ViewDetailLevel(), representationConfig.IncludeNonVisible, false); + // Convert each element in coordinate system of the document that owns it + // Transformation from that document's coordinate system to the coordinate system of host document done further downstream foreach (ElementId id in remainingElementIds) { Element element = document.GetElement(id); @@ -309,6 +314,7 @@ public static List Read(Document document, Transform transform, Lis if (activePulls.Count(x => x) > 1) BH.Engine.Base.Compute.RecordWarning("Pull of more than one geometry/representation type has been specified in RevitPullConfig. Please consider this can be time consuming due to the amount of conversions."); + // Postprocess clones the output and transforms it to the coordinate system of the host model return result.Select(x => x.IPostprocess(transform, settings)).Where(x => x != null).ToList(); } @@ -348,6 +354,3 @@ public static List Read(Element element, Discipline discipline, Rev /***************************************************/ } } - - - diff --git a/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs b/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs index ce68fa2bc..d025a8c96 100644 --- a/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs +++ b/Revit_Core_Engine/Compute/SplitRequestTreeByLinks.cs @@ -42,10 +42,9 @@ public static partial class Compute [Description("Decomposes a tree created by a set of nested ILogicalRequests into a dictionary of Revit documents (both host and linked) and the IRequests relevant to them, which in total represents the same request as the original IRequest.")] [Input("request", "An IRequest to be split into a dictionary of Revit documents and the IRequests relevant to them.")] [Input("document", "Host document to be used as the basis of the splitting routine.")] - [Output("splitRequests", "A dictionary of Revit documents (both host and linked) and the IRequests relevant to them, which in total represents the same request as the input IRequest.")] + [Output("splitRequests", "A dictionary of elementIds representing Revit documents (both host as -1 and linked as link Id) and the IRequests relevant to them, which in total represents the same request as the input IRequest.")] public static Dictionary SplitRequestTreeByLinks(this IRequest request, Document document) { - Dictionary requestsByLinks = new Dictionary(); List splitPerDoc = request.SplitRequestTreeByType(typeof(FilterByLink)); foreach (IRequest splitRequest in splitPerDoc) @@ -103,18 +102,6 @@ private static bool TryOrganizeByLink(this IRequest request, Document document, } return true; - - //if (linkInstanceIds.Count == 1) - //{ - // request.RemoveSubRequest(linkRequest); - // request = request.SimplifyRequestTree(); - // requestsByLinks.AddRequestByLink(request, ((RevitLinkInstance)document.GetElement(linkInstanceIds[0])).Id); - // return true; - //} - //else if (linkInstanceIds.Count == 0) - // BH.Engine.Base.Compute.RecordError($"Active Revit document does not contain links with neither name nor path nor ElementId equal to {linkRequest.LinkName}."); - //else - // BH.Engine.Base.Compute.RecordError($"There is more than one link document named {linkRequest.LinkName} - please use full link path or its ElementId instead of link name to pull."); } else return false; @@ -226,6 +213,3 @@ private static bool IsValidToOrganize(this IRequest request) /***************************************************/ } } - - - From 94bed577bf689a10a1dbc26c8f19b918020a6316 Mon Sep 17 00:00:00 2001 From: Pawel Baran Date: Wed, 12 Jun 2024 13:44:06 +0200 Subject: [PATCH 4/6] null reference bugfix --- Revit_Core_Adapter/CRUD/Read.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Revit_Core_Adapter/CRUD/Read.cs b/Revit_Core_Adapter/CRUD/Read.cs index f0d6ade6c..b3598afe9 100644 --- a/Revit_Core_Adapter/CRUD/Read.cs +++ b/Revit_Core_Adapter/CRUD/Read.cs @@ -104,7 +104,7 @@ protected override IEnumerable Read(IRequest request, ActionConfig foreach (KeyValuePair requestByLink in requestsByLinks) { Document doc; - Transform transform = null; + Transform transform = Transform.Identity; if (requestByLink.Key.IntegerValue == -1) doc = this.Document; else From 9c554b9069a77be9ad4d6f0a2572c9c34ca55cf7 Mon Sep 17 00:00:00 2001 From: Pawel Baran Date: Wed, 12 Jun 2024 17:51:07 +0200 Subject: [PATCH 5/6] removal of grid segments brought back --- Revit_Core_Adapter/CRUD/Read.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Revit_Core_Adapter/CRUD/Read.cs b/Revit_Core_Adapter/CRUD/Read.cs index b3598afe9..36cd14797 100644 --- a/Revit_Core_Adapter/CRUD/Read.cs +++ b/Revit_Core_Adapter/CRUD/Read.cs @@ -166,7 +166,7 @@ public static List Read(Document document, Transform transform, Lis worksetPrefilter = document.OpenWorksetsPrefilter(); // Get elementIds from all requests - List elementIds = new LogicalOrRequest { Requests = requests }.ElementIds(document, pullConfig.Discipline, settings, worksetPrefilter).ToList(); + List elementIds = new LogicalOrRequest { Requests = requests }.ElementIds(document, pullConfig.Discipline, settings, worksetPrefilter).RemoveGridSegmentIds(document).ToList(); // Get elementIds of nested elements if requested if (pullConfig.IncludeNestedElements) From 11760a23a1d818c54234bd8404c0281f0cc1e9a7 Mon Sep 17 00:00:00 2001 From: Pawel Baran Date: Thu, 13 Jun 2024 10:28:40 +0200 Subject: [PATCH 6/6] versioning fixed --- Revit_Core_Engine/Convert/FromRevit.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Revit_Core_Engine/Convert/FromRevit.cs b/Revit_Core_Engine/Convert/FromRevit.cs index 66f80fe35..048187f62 100644 --- a/Revit_Core_Engine/Convert/FromRevit.cs +++ b/Revit_Core_Engine/Convert/FromRevit.cs @@ -41,6 +41,7 @@ public static partial class Convert /**** Interface Methods ****/ /***************************************************/ + [PreviousVersion("7.2", "BH.Revit.Engine.Core.Convert.IFromRevit(Autodesk.Revit.DB.Element, BH.oM.Adapters.Revit.Enums.Discipline, Autodesk.Revit.DB.Transform, BH.oM.Adapters.Revit.Settings.RevitSettings, System.Collections.Generic.Dictionary>)")] [Description("Interface method that tries to find a suitable FromRevit convert for any Revit Element.")] [Input("element", "Revit Element to be converted.")] [Input("discipline", "Engineering discipline based on the BHoM discipline classification.")] @@ -70,6 +71,7 @@ public static IGeometry IFromRevit(this Location location) /**** Convert Revit elements to BHoM ****/ /***************************************************/ + [PreviousVersion("7.2", "BH.Revit.Engine.Core.Convert.FromRevit(Autodesk.Revit.DB.Analysis.EnergyAnalysisDetailModel, BH.oM.Adapters.Revit.Enums.Discipline, Autodesk.Revit.DB.Transform, BH.oM.Adapters.Revit.Settings.RevitSettings, System.Collections.Generic.Dictionary>)")] [Description("Converts a Revit EnergyAnalysisDetailModel to a BHoM object based on the requested engineering discipline.")] [Input("energyAnalysisModel", "Revit EnergyAnalysisDetailModel to be converted.")] [Input("discipline", "Engineering discipline based on the BHoM discipline classification.")] @@ -95,6 +97,7 @@ public static List FromRevit(this EnergyAnalysisDetailModel energyA /***************************************************/ + [PreviousVersion("7.2", "BH.Revit.Engine.Core.Convert.FromRevit(Autodesk.Revit.DB.AssemblyInstance, BH.oM.Adapters.Revit.Enums.Discipline, Autodesk.Revit.DB.Transform, BH.oM.Adapters.Revit.Settings.RevitSettings, System.Collections.Generic.Dictionary>)")] [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.")] @@ -119,6 +122,7 @@ public static List FromRevit(this AssemblyInstance assemblyInstance /***************************************************/ + [PreviousVersion("7.2", "BH.Revit.Engine.Core.Convert.FromRevit(Autodesk.Revit.DB.Element, BH.oM.Adapters.Revit.Enums.Discipline, Autodesk.Revit.DB.Transform, BH.oM.Adapters.Revit.Settings.RevitSettings, System.Collections.Generic.Dictionary>)")] [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.")]