Skip to content

Commit

Permalink
Issues with pulling from links fixed (#1486)
Browse files Browse the repository at this point in the history
  • Loading branch information
pawelbaran authored Jun 13, 2024
2 parents 3bb620d + 11760a2 commit 4f273f5
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 115 deletions.
168 changes: 98 additions & 70 deletions Revit_Core_Adapter/CRUD/Read.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -87,7 +86,8 @@ protected override IEnumerable<IBHoMObject> Read(IRequest request, ActionConfig
}
}

Dictionary<Document, IRequest> requestsByLinks = request.SplitRequestTreeByLinks(this.Document);
// Split the request into separate requests per each link model
Dictionary<ElementId, IRequest> 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.");
Expand All @@ -96,12 +96,49 @@ protected override IEnumerable<IBHoMObject> 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<IRequest>> requestsByDocumentAndTransform = new Dictionary<(Document, Transform), List<IRequest>>();
foreach (KeyValuePair<ElementId, IRequest> requestByLink in requestsByLinks)
{
Document doc;
Transform transform = Transform.Identity;
if (requestByLink.Key.IntegerValue == -1)
doc = this.Document;
else
{
var linkInstance = this.Document.GetElement(requestByLink.Key) as RevitLinkInstance;
doc = linkInstance.GetLinkDocument();

Transform linkTransform = linkInstance.GetTotalTransform();
if (!linkTransform.IsIdentity)
transform = linkTransform;
}

(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<IRequest>());
}
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<string, Dictionary<string, List<IBHoMObject>>> globalRefObjects = new Dictionary<string, Dictionary<string, List<IBHoMObject>>>();
List<IBHoMObject> result = new List<IBHoMObject>();
foreach (KeyValuePair<Document, IRequest> 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));
}

// Restore selection
this.UIDocument.Selection.SetElementIds(selected);

return result;
Expand All @@ -112,31 +149,26 @@ protected override IEnumerable<IBHoMObject> Read(IRequest request, ActionConfig
/**** Public Methods ****/
/***************************************************/

public static List<IBHoMObject> Read(Document document, IRequest request, RevitPullConfig pullConfig = null, RevitSettings settings = null)
public static List<IBHoMObject> Read(Document document, Transform transform, List<IRequest> requests, RevitPullConfig pullConfig = null, RevitSettings settings = null, Dictionary<string, Dictionary<string, List<IBHoMObject>>> globalRefObjects = null)
{
if (document == null)
{
BH.Engine.Base.Compute.RecordError("BHoM objects could not be read because provided Revit document is null.");
return new List<IBHoMObject>();
}

if (request == null)
{
BH.Engine.Base.Compute.RecordError("BHoM objects could not be read because provided IRequest is null.");
return new List<IBHoMObject>();
}

pullConfig = pullConfig.DefaultIfNull();
settings = settings.DefaultIfNull();

// Prefilter only elements from open worksets if requested
IEnumerable<ElementId> worksetPrefilter = null;
if (!pullConfig.IncludeClosedWorksets)
worksetPrefilter = document.OpenWorksetsPrefilter();

List<ElementId> elementIds = request.IElementIds(document, pullConfig.Discipline, settings, worksetPrefilter).RemoveGridSegmentIds(document)?.ToList();
if (elementIds == null)
return new List<IBHoMObject>();
// Get elementIds from all requests
List<ElementId> elementIds = new LogicalOrRequest { Requests = requests }.ElementIds(document, pullConfig.Discipline, settings, worksetPrefilter).RemoveGridSegmentIds(document).ToList();

// Get elementIds of nested elements if requested
if (pullConfig.IncludeNestedElements)
{
List<ElementId> elemIds = new List<ElementId>();
Expand All @@ -153,12 +185,12 @@ public static List<IBHoMObject> Read(Document document, IRequest request, RevitP
elementIds.AddRange(elemIds);
}

return Read(document, elementIds, pullConfig, settings);
return Read(document, transform, elementIds.ToList(), pullConfig, settings, globalRefObjects);
}

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

public static List<IBHoMObject> Read(Document document, List<ElementId> elementIds, RevitPullConfig pullConfig = null, RevitSettings settings = null)
public static List<IBHoMObject> Read(Document document, Transform transform, List<ElementId> elementIds, RevitPullConfig pullConfig = null, RevitSettings settings = null, Dictionary<string, Dictionary<string, List<IBHoMObject>>> globalRefObjects = null)
{
if (document == null)
{
Expand All @@ -175,129 +207,128 @@ public static List<IBHoMObject> Read(Document document, List<ElementId> elementI
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)
{
BH.Engine.Base.Compute.RecordNote($"Conversion discipline has not been specified, default {Discipline.Physical} will be used.");
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);
// Set up refObjects
if (globalRefObjects == null)
globalRefObjects = new Dictionary<string, Dictionary<string, List<IBHoMObject>>>();

if (!globalRefObjects.ContainsKey(document.Title))
globalRefObjects.Add(document.Title, new Dictionary<string, List<IBHoMObject>>());

Dictionary<string, List<IBHoMObject>> refObjects = globalRefObjects[document.Title];

Transform linkTransform = null;
TransformMatrix bHoMTransform = null;
if (document.IsLinked)
// 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<IBHoMObject> result = new List<IBHoMObject>();
List<ElementId> remainingElementIds = new List<ElementId>();
foreach (ElementId id in elementIds)
{
linkTransform = document.LinkTransform();
if (linkTransform?.IsIdentity == false)
bHoMTransform = linkTransform.FromRevit();
var existing = refObjects.GetValues<IBHoMObject>(id);
if (existing != null)
result.AddRange(existing);
else
remainingElementIds.Add(id);
}

Dictionary<string, List<IBHoMObject>> refObjects = new Dictionary<string, List<IBHoMObject>>();

// 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);

List<IBHoMObject> result = new List<IBHoMObject>();
foreach (ElementId id in elementIds)
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);
if (element == null)
continue;

IEnumerable<IBHoMObject> iBHoMObjects = Read(element, discipline, linkTransform, settings, refObjects);

if (iBHoMObjects != null && iBHoMObjects.Any())
IEnumerable<IBHoMObject> 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<ICurve> edges = null;
if (geometryConfig.PullEdges)
{
edges = element.Curves(geometryOptions, settings, true).FromRevit();
if (bHoMTransform != null)
edges = edges.Select(x => x?.ITransform(bHoMTransform)).ToList();
}

List<ISurface> 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<oM.Geometry.Mesh> 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<RenderMesh> 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);
}
}

bool[] activePulls = new bool[] { geometryConfig.PullEdges, geometryConfig.PullSurfaces, geometryConfig.PullMeshes, representationConfig.PullRenderMesh };
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;
// 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();
}

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

public static List<IBHoMObject> Read(Element element, Discipline discipline, Transform transform, RevitSettings settings = null, Dictionary<string, List<IBHoMObject>> refObjects = null)
public static List<IBHoMObject> Read(Element element, Discipline discipline, RevitSettings settings = null, Dictionary<string, List<IBHoMObject>> refObjects = null)
{
if (element == null || !element.IsValidObject)
return new List<IBHoMObject>();

List<IBHoMObject> result = null;
try
{
result = element.IFromRevit(discipline, transform, settings, refObjects);
result = element.IFromRevit(discipline, settings, refObjects);
}
catch (Exception exception)
{
Expand All @@ -323,6 +354,3 @@ public static List<IBHoMObject> Read(Element element, Discipline discipline, Tra
/***************************************************/
}
}



Loading

0 comments on commit 4f273f5

Please sign in to comment.