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

CNX-9228 : minimal working revit receive operation that receives levels #3286

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.Revit.HostApp;
using Speckle.Connectors.Utils.Cancellation;
using Speckle.Connectors.Utils.Operations;
using Speckle.Converters.RevitShared.Helpers;
using Speckle.Core.Logging;

Expand All @@ -10,38 +16,46 @@ namespace Speckle.Connectors.Revit.Bindings;
internal class ReceiveBinding : RevitBaseBinding, ICancelable
{
public CancellationManager CancellationManager { get; } = new();

public ReceiveBinding(RevitContext revitContext, RevitDocumentStore store, IBridge bridge)
: base("receiveBinding", store, bridge, revitContext) { }
private readonly ReceiveOperation _receiveOperation;

public ReceiveBinding(
RevitContext revitContext,
RevitDocumentStore store,
IBridge bridge,
ReceiveOperation receiveOperation
connorivy marked this conversation as resolved.
Show resolved Hide resolved
)
: base("receiveBinding", store, bridge, revitContext)
{
_receiveOperation = receiveOperation;
}

public void CancelReceive(string modelCardId) => CancellationManager.CancelOperation(modelCardId);

public async void Receive(string modelCardId, string versionId)
public async Task Receive(string modelCardId)
{
try
{
//// 0 - Init cancellation token source -> Manager also cancel it if exist before
//CancellationTokenSource cts = CancellationManager.InitCancellationTokenSource(modelCardId);

//// 1 - Get receiver card
//ReceiverModelCard model = _store.GetModelById(modelCardId) as ReceiverModelCard;

//// 2 - Get commit object from server
//Base commitObject = await Operations.GetCommitBase(Parent, model, versionId, cts.Token).ConfigureAwait(true);

//if (cts.IsCancellationRequested)
//{
// return;
//}

//// 3 - Get converter
//ISpeckleConverter converter = Converters.GetConverter(Doc, RevitAppProvider.Version());

//// 4 - Traverse commit object
//List<Base> objectsToConvert = Traversal.GetObjectsToConvert(commitObject, converter);

//// 5 - Bake objects
//BakeObjects(objectsToConvert, converter, modelCardId, cts);
// 0 - Init cancellation token source -> Manager also cancel it if exist before
connorivy marked this conversation as resolved.
Show resolved Hide resolved
CancellationTokenSource cts = CancellationManager.InitCancellationTokenSource(modelCardId);

if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
{
throw new InvalidOperationException("No publish model card was found.");
}

List<string> receivedObjectIds = (
await _receiveOperation
.Execute(
modelCard.AccountId,
modelCard.ProjectId,
modelCard.ProjectName,
modelCard.ModelName,
modelCard.SelectedVersionId,
cts.Token,
null
)
.ConfigureAwait(false)
).ToList();
}
catch (Exception e) when (!e.IsFatal())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
using Speckle.Connectors.DUI.Utils;
using Speckle.Connectors.Revit.Bindings;
using Speckle.Connectors.Revit.HostApp;
using Speckle.Connectors.Revit.Operations.Receive;
using Speckle.Connectors.Revit.Operations.Send;
using Speckle.Connectors.Revit.Plugin;
using Speckle.Connectors.Utils.Builders;
using Speckle.Connectors.Utils.Operations;
using Speckle.Converters.RevitShared.Helpers;
using Speckle.Core.Transports;
using Speckle.Newtonsoft.Json;
Expand Down Expand Up @@ -72,6 +75,9 @@ protected override void Load(ContainerBuilder builder)
builder.RegisterType<ServerTransport>().As<ITransport>().InstancePerDependency();
builder.RegisterType<RootObjectSender>().As<IRootObjectSender>().SingleInstance();

builder.RegisterType<ReceiveOperation>().AsSelf().SingleInstance();
connorivy marked this conversation as resolved.
Show resolved Hide resolved
builder.RegisterType<RevitHostObjectBuilder>().As<IHostObjectBuilder>().InstancePerLifetimeScope();

// register
builder.RegisterType<RevitDocumentStore>().SingleInstance();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Autodesk.Revit.DB;
using Revit.Async;
using Speckle.Connectors.Utils.Builders;
using Speckle.Converters.Common;
using Speckle.Converters.RevitShared.Services;
using Speckle.Core.Models;
using Speckle.Core.Models.Extensions;

namespace Speckle.Connectors.Revit.Operations.Receive;

public class RevitHostObjectBuilder : IHostObjectBuilder
{
private readonly ISpeckleConverterToHost _toHostConverter;
private readonly ITransactionManagementService _transactionManagementService;

public RevitHostObjectBuilder(
ISpeckleConverterToHost toHostConverter,
ITransactionManagementService transactionManagementService
)
{
_toHostConverter = toHostConverter;
_transactionManagementService = transactionManagementService;
}

public IEnumerable<string> Build(
Base rootObject,
string projectName,
string modelName,
Action<string, double?>? onOperationProgressed,
CancellationToken cancellationToken
)
{
// POC : asyncify
return RevitTask
.RunAsync(() =>
{
_transactionManagementService.StartTransactionManagement($"Loaded data from {projectName}");
List<string> elementIds = new();
// POC : obviously not the traversal we want.
// I'm waiting for jedd to magically make all my traversal issues go away again
connorivy marked this conversation as resolved.
Show resolved Hide resolved
foreach (var obj in rootObject.Traverse(b => false))
{
object? conversionResult = null;
try
{
conversionResult = _toHostConverter.Convert(obj);
}
catch (SpeckleConversionException ex)
{
// POC : logging
}
if (conversionResult is Element element)
{
elementIds.Add(element.UniqueId);
}
YieldToUiThread();
}

_transactionManagementService.FinishTransactionManagement();
return elementIds;
})
.GetAwaiter()
.GetResult();
}

private DateTime _timerStarted = DateTime.MinValue;

private void YieldToUiThread()
{
var currentTime = DateTime.UtcNow;

if (currentTime.Subtract(_timerStarted) < TimeSpan.FromSeconds(.15))
{
return;
}

System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(
() => { },
System.Windows.Threading.DispatcherPriority.Background
);

_timerStarted = currentTime;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ private void _container_PreBuildEvent(object sender, ContainerBuilder containerB
// tbe event can probably go
// IRawConversions should be separately injectable (and not Require an IHostObject... or NameAndRank attribute)
// Name and Rank can become ConversionRank or something and be optional (otherwise it is rank 0)
containerBuilder.RegisterRawConversions().InjectNamedTypes<IHostObjectToSpeckleConversion>();
containerBuilder.RegisterRawConversions();
containerBuilder.InjectNamedTypes<IHostObjectToSpeckleConversion>();
containerBuilder.InjectNamedTypes<ISpeckleObjectToHostConversion>();
}

public Result OnShutdown(UIControlledApplication application)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Elements.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\RevitDocumentStore.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DependencyInjection\AutofacUIModule.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Receive\RevitHostObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\IRootObjectSender.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\RootObjectBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\RootObjectSender.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ protected override void Load(ContainerBuilder builder)
{
// most things should be InstancePerLifetimeScope so we get one per operation
builder.RegisterType<RevitConverterToSpeckle>().As<ISpeckleConverterToSpeckle>();
connorivy marked this conversation as resolved.
Show resolved Hide resolved
builder.RegisterType<RevitConverterToHost>().As<ISpeckleConverterToHost>();

// factory for conversions
builder
.RegisterType<Factory<string, IHostObjectToSpeckleConversion>>()
.As<IFactory<string, IHostObjectToSpeckleConversion>>();
builder
.RegisterType<Factory<string, ISpeckleObjectToHostConversion>>()
.As<IFactory<string, ISpeckleObjectToHostConversion>>();

// POC: do we need ToSpeckleScalingService as is, do we need to interface it out?
builder.RegisterType<ToSpeckleScalingService>().AsSelf().InstancePerLifetimeScope();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should all be interfaced out

Expand All @@ -35,5 +39,12 @@ protected override void Load(ContainerBuilder builder)
builder.RegisterType<MeshDataTriangulator>().AsSelf().InstancePerLifetimeScope();
builder.RegisterType<HostedElementConversionToSpeckle>().AsSelf().InstancePerLifetimeScope();
builder.RegisterType<ParameterObjectAssigner>().AsSelf().InstancePerLifetimeScope();

// Register receive operation dependencies
builder
.RegisterType<TransactionManagementService>()
.As<ITransactionManagementService>()
.InstancePerLifetimeScope();
builder.RegisterType<ErrorPreprocessingService>().AsSelf().InstancePerLifetimeScope();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
global using DB = Autodesk.Revit.DB;
global using UI = Autodesk.Revit.UI;
global using SOG = Objects.Geometry;
global using SOB = Objects.BuiltElements;
global using SOBR = Objects.BuiltElements.Revit;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Speckle.Autofac.DependencyInjection;
using Speckle.Converters.Common;
using Speckle.Converters.Common.Objects;
using Speckle.Core.Models;

namespace Speckle.Converters.RevitShared;

public class RevitConverterToHost : ISpeckleConverterToHost
{
private readonly IFactory<string, ISpeckleObjectToHostConversion> _toHostConversions;

public RevitConverterToHost(IFactory<string, ISpeckleObjectToHostConversion> toHostConversions)
{
_toHostConversions = toHostConversions;
}

public object Convert(Base target)
{
ISpeckleObjectToHostConversion conversion =
GetToHostConversion(target.GetType())
?? throw new SpeckleConversionException($"No conversion found for {target.GetType().Name}");

object result =
conversion.Convert(target)
?? throw new SpeckleConversionException($"Conversion of object with type {target.GetType()} returned null");

return result;
}

private ISpeckleObjectToHostConversion? GetToHostConversion(Type? targetType)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would Type be null?

{
if (targetType is null || targetType == typeof(object))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think either of these can be true can they?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh right you're walking back until you hit object. So we are looking at the super type.

{
return null;
}

if (_toHostConversions.ResolveInstance(targetType.Name) is ISpeckleObjectToHostConversion conversion)
{
return conversion;
}

return GetToHostConversion(targetType.BaseType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,9 @@ ParameterValueExtractor parameterValueExtractor
// if it cannot be converted then we should throw
public Base Convert(object target)
{
var objectConverter = _toSpeckle.ResolveInstance(target.GetType().Name);

if (objectConverter == null)
{
throw new NotSupportedException($"No conversion found for {target.GetType().Name}");
}
var objectConverter =
_toSpeckle.ResolveInstance(target.GetType().Name)
?? throw new SpeckleConversionException($"No conversion found for {target.GetType().Name}");

Base result =
objectConverter.Convert(target)
Expand Down
Loading