Files
speckle-sharp-connectors/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs
T
Dimitrie Stefanescu dbc359f0e4 Dim/revit materials (#149)
* chore: cleans up display value extractor

removes transform references and checks for groups, as objects are ungrouped by that point

* feat: generates render material proxy maps in revit send

* chore: removes unused code

* feat(revit): material proxies wip

* wip

* removes unused converted cache

* wip

* chore: cleanup part 1

* chore: finished cleanup (moved revit render material proxy cache out)

* fix(revit): invalid progress reporting on send

* feat(rhino): adds rhino support for revit proxy materials

* fix(acad): checks group names for invalid chars

* fix(acad): checks material name for invalid chars

* feat(acad): adds support for baking fallback objects properly

including materials!

* wip: arcgis support for multiple fallback values

* Fix build errors (#166)

* fix: arcgis

---------

Co-authored-by: Oğuzhan Koral <45078678+oguzhankoral@users.noreply.github.com>
2024-08-19 16:14:09 +01:00

132 lines
4.5 KiB
C#

using System.Diagnostics;
using Autodesk.Revit.DB;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.Revit.HostApp;
using Speckle.Connectors.Utils.Builders;
using Speckle.Connectors.Utils.Caching;
using Speckle.Connectors.Utils.Conversion;
using Speckle.Connectors.Utils.Operations;
using Speckle.Converters.Common;
using Speckle.Converters.RevitShared.Helpers;
using Speckle.Sdk;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.Revit.Operations.Send;
public class RevitRootObjectBuilder : IRootObjectBuilder<ElementId>
{
// POC: SendSelection and RevitConversionContextStack should be interfaces, former needs interfaces
private readonly IRootToSpeckleConverter _converter;
private readonly IRevitConversionContextStack _conversionContextStack;
private readonly Collection _rootObject;
private readonly ISendConversionCache _sendConversionCache;
private readonly ISyncToThread _syncToThread;
private readonly ElementUnpacker _elementUnpacker;
private readonly SendCollectionManager _sendCollectionManager;
public RevitRootObjectBuilder(
IRootToSpeckleConverter converter,
IRevitConversionContextStack conversionContextStack,
ISendConversionCache sendConversionCache,
ISyncToThread syncToThread,
ElementUnpacker elementUnpacker,
SendCollectionManager sendCollectionManager
)
{
_converter = converter;
_conversionContextStack = conversionContextStack;
_sendConversionCache = sendConversionCache;
_syncToThread = syncToThread;
_elementUnpacker = elementUnpacker;
_sendCollectionManager = sendCollectionManager;
_rootObject = new Collection()
{
name = _conversionContextStack.Current.Document.PathName.Split('\\').Last().Split('.').First()
};
}
public Task<RootObjectBuilderResult> Build(
IReadOnlyList<ElementId> objects,
SendInfo sendInfo,
Action<string, double?>? onOperationProgressed = null,
CancellationToken ct = default
) =>
_syncToThread.RunOnThread(() =>
{
var doc = _conversionContextStack.Current.Document;
if (doc.IsFamilyDocument)
{
throw new SpeckleException("Family Environment documents are not supported.");
}
var revitElements = new List<Element>();
// Convert ids to actual revit elements
foreach (var id in objects)
{
var el = _conversionContextStack.Current.Document.GetElement(id);
if (el != null)
{
revitElements.Add(el);
}
}
if (revitElements.Count == 0)
{
throw new SpeckleSendFilterException("No objects were found. Please update your send filter!");
}
// Unpack groups (& other complex data structures)
var atomicObjects = _elementUnpacker.UnpackSelectionForConversion(revitElements).ToList();
var countProgress = 0;
var cacheHitCount = 0;
List<SendConversionResult> results = new(revitElements.Count);
foreach (Element revitElement in atomicObjects)
{
ct.ThrowIfCancellationRequested();
var applicationId = revitElement.Id.ToString();
try
{
Base converted;
if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value))
{
converted = value;
cacheHitCount++;
}
else
{
converted = _converter.Convert(revitElement);
converted.applicationId = applicationId;
}
var collection = _sendCollectionManager.GetAndCreateObjectHostCollection(revitElement, _rootObject);
collection.elements.Add(converted);
results.Add(new(Status.SUCCESS, applicationId, revitElement.GetType().Name, converted));
}
catch (Exception ex) when (!ex.IsFatal())
{
results.Add(new(Status.ERROR, applicationId, revitElement.GetType().Name, null, ex));
}
onOperationProgressed?.Invoke("Converting", (double)++countProgress / atomicObjects.Count);
}
var idsAndSubElementIds = _elementUnpacker.GetElementsAndSubelementIdsFromAtomicObjects(atomicObjects);
var materialProxies = _conversionContextStack.RenderMaterialProxyCache.GetRenderMaterialProxyListForObjects(
idsAndSubElementIds
);
_rootObject["renderMaterialProxies"] = materialProxies;
Debug.WriteLine(
$"Cache hit count {cacheHitCount} out of {objects.Count} ({(double)cacheHitCount / objects.Count})"
);
return new RootObjectBuilderResult(_rootObject, results);
});
}