Compare commits

...

1 Commits

Author SHA1 Message Date
Dimitrie Stefanescu 22c6303167 wip pipe implementation 2026-01-21 14:23:27 +00:00
6 changed files with 68 additions and 19 deletions
@@ -42,7 +42,11 @@ public class RevitRootObjectBuilder(
() => Task.FromResult(BuildSync(documentElementContexts, projectId, onOperationProgressed, ct)) () => Task.FromResult(BuildSync(documentElementContexts, projectId, onOperationProgressed, ct))
); );
#pragma warning disable CA1506
#pragma warning disable CA1502
private RootObjectBuilderResult BuildSync( private RootObjectBuilderResult BuildSync(
#pragma warning restore CA1506
#pragma warning restore CA1502
IReadOnlyList<DocumentToConvert> documentElementContexts, IReadOnlyList<DocumentToConvert> documentElementContexts,
string projectId, string projectId,
IProgress<CardProgress> onOperationProgressed, IProgress<CardProgress> onOperationProgressed,
@@ -56,6 +60,9 @@ public class RevitRootObjectBuilder(
throw new SpeckleException("Family Environment documents are not supported."); throw new SpeckleException("Family Environment documents are not supported.");
} }
// create a new send pipeline
using var sendPipeline = new Speckle.Sdk.Pipeline.Send();
// init the root // init the root
Collection rootObject = Collection rootObject =
new() { name = converterSettings.Current.Document.PathName.Split('\\').Last().Split('.').First() }; new() { name = converterSettings.Current.Document.PathName.Split('\\').Last().Split('.').First() };
@@ -184,10 +191,12 @@ public class RevitRootObjectBuilder(
// non-transformed elements can safely rely on cache // non-transformed elements can safely rely on cache
// TODO: Potential here to transform cached objects and NOT reconvert, // TODO: Potential here to transform cached objects and NOT reconvert,
// TODO: we wont do !hasTransform here, and re-set application id before this // TODO: we wont do !hasTransform here, and re-set application id before this
bool wasCached = false;
if (!hasTransform && sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value)) if (!hasTransform && sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value))
{ {
// TODO: cahce hit
converted = value; converted = value;
wasCached = true;
cacheHitCount++; cacheHitCount++;
} }
// not in cache means we convert // not in cache means we convert
@@ -206,6 +215,12 @@ public class RevitRootObjectBuilder(
converted.applicationId = applicationId; converted.applicationId = applicationId;
} }
var reference = sendPipeline.Process(converted).Result; // .Wait(cancellationToken);//.ConfigureAwait(false);
if (!wasCached)
{
sendConversionCache.AppendSendResult(projectId, applicationId, reference);
}
var collection = sendCollectionManager.GetAndCreateObjectHostCollection( var collection = sendCollectionManager.GetAndCreateObjectHostCollection(
revitElement, revitElement,
rootObject, rootObject,
@@ -213,7 +228,7 @@ public class RevitRootObjectBuilder(
modelDisplayName modelDisplayName
); );
collection.elements.Add(converted); collection.elements.Add(reference);
results.Add(new(Status.SUCCESS, applicationId, sourceType, converted)); results.Add(new(Status.SUCCESS, applicationId, sourceType, converted));
} }
catch (Exception ex) when (!ex.IsFatal()) catch (Exception ex) when (!ex.IsFatal())
@@ -254,13 +269,20 @@ public class RevitRootObjectBuilder(
rootObject[ProxyKeys.INSTANCE_DEFINITION] = revitToSpeckleCacheSingleton.GetInstanceDefinitionProxiesForObjects( rootObject[ProxyKeys.INSTANCE_DEFINITION] = revitToSpeckleCacheSingleton.GetInstanceDefinitionProxiesForObjects(
idsAndSubElementIds idsAndSubElementIds
); );
rootObject.elements.Add( // NOTE: i might be overdoing things in here, but tldr:
new Collection() // - all instance objects (meshes) are processed individually
{ // - process their collection individually, and then attach it to the root collection
elements = revitToSpeckleCacheSingleton.GetBaseObjectsForObjects(idsAndSubElementIds), // we could, theoretically, just process the collection as a whole (but it can be big?)
name = "revitInstancedObjects" // note/ask: do these need to go in the conversion cache? or not?
} var instanceObjects = revitToSpeckleCacheSingleton.GetBaseObjectsForObjects(idsAndSubElementIds);
); var instanceReferences = new Collection("revitInstancedObjects");
foreach (var instanceObject in instanceObjects)
{
var referenceInstanceObject = sendPipeline.Process(instanceObject).Result;
instanceReferences.elements.Add(referenceInstanceObject);
}
var instanceReferenceCollection = sendPipeline.Process(instanceReferences).Result;
rootObject.elements.Add(instanceReferenceCollection);
// STEP 6: Unpack all other objects to attach to root collection // STEP 6: Unpack all other objects to attach to root collection
List<Objects.Other.Camera> views = viewUnpacker.Unpack(converterSettings.Current.Document); List<Objects.Other.Camera> views = viewUnpacker.Unpack(converterSettings.Current.Document);
@@ -279,6 +301,10 @@ public class RevitRootObjectBuilder(
rootObject[RootKeys.REFERENCE_POINT_TRANSFORM] = transformMatrix; rootObject[RootKeys.REFERENCE_POINT_TRANSFORM] = transformMatrix;
} }
return new RootObjectBuilderResult(rootObject, results); // NOTE: could be
sendPipeline.Process(rootObject).Wait(cancellationToken);
sendPipeline.WaitForUpload().Wait(cancellationToken);
return new RootObjectBuilderResult(new Collection() { name = "ignore" }, results);
} }
} }
@@ -75,6 +75,8 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
) )
{ {
using var activity = _activityFactory.Start("Build"); using var activity = _activityFactory.Start("Build");
using var sendPipeline = new Speckle.Sdk.Pipeline.Send();
// 0 - Init the root // 0 - Init the root
Collection rootObjectCollection = new() { name = _converterSettings.Current.Document.Name ?? "Unnamed document" }; Collection rootObjectCollection = new() { name = _converterSettings.Current.Document.Name ?? "Unnamed document" };
rootObjectCollection["units"] = _converterSettings.Current.SpeckleUnits; rootObjectCollection["units"] = _converterSettings.Current.SpeckleUnits;
@@ -97,6 +99,7 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
// 3 - Convert atomic objects // 3 - Convert atomic objects
List<SendConversionResult> results = new(atomicObjects.Count); List<SendConversionResult> results = new(atomicObjects.Count);
int count = 0; int count = 0;
using (var _ = _activityFactory.Start("Convert all")) using (var _ = _activityFactory.Start("Convert all"))
{ {
foreach (RhinoObject rhinoObject in atomicObjects) foreach (RhinoObject rhinoObject in atomicObjects)
@@ -108,9 +111,8 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
Layer layer = _converterSettings.Current.Document.Layers[rhinoObject.Attributes.LayerIndex]; Layer layer = _converterSettings.Current.Document.Layers[rhinoObject.Attributes.LayerIndex];
Collection collectionHost = _layerUnpacker.GetHostObjectCollection(layer, rootObjectCollection); Collection collectionHost = _layerUnpacker.GetHostObjectCollection(layer, rootObjectCollection);
var result = ConvertRhinoObject(rhinoObject, collectionHost, instanceProxies, projectId); var result = await ConvertRhinoObject(rhinoObject, collectionHost, instanceProxies, projectId, sendPipeline);
results.Add(result); results.Add(result);
++count; ++count;
onOperationProgressed.Report(new("Converting", (double)count / atomicObjects.Count)); onOperationProgressed.Report(new("Converting", (double)count / atomicObjects.Count));
await Task.Yield(); await Task.Yield();
@@ -149,18 +151,23 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
} }
} }
return new RootObjectBuilderResult(rootObjectCollection, results); await sendPipeline.Process(rootObjectCollection);
await sendPipeline.WaitForUpload();
return new RootObjectBuilderResult(new Collection() { name = "ignore" }, results);
} }
private SendConversionResult ConvertRhinoObject( private async Task<SendConversionResult> ConvertRhinoObject(
RhinoObject rhinoObject, RhinoObject rhinoObject,
Collection collectionHost, Collection collectionHost,
IReadOnlyDictionary<string, InstanceProxy> instanceProxies, IReadOnlyDictionary<string, InstanceProxy> instanceProxies,
string projectId string projectId,
Sdk.Pipeline.Send sendPipeline
) )
{ {
string applicationId = rhinoObject.Id.ToString(); string applicationId = rhinoObject.Id.ToString();
string sourceType = rhinoObject.ObjectType.ToString(); string sourceType = rhinoObject.ObjectType.ToString();
bool wasCached = false;
try try
{ {
// get from cache or convert: // get from cache or convert:
@@ -174,6 +181,7 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
else if (_sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value)) else if (_sendConversionCache.TryGetValue(projectId, applicationId, out ObjectReference? value))
{ {
converted = value; converted = value;
wasCached = true;
} }
else else
{ {
@@ -194,10 +202,17 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder<RhinoObject>
converted["properties"] = properties; converted["properties"] = properties;
} }
// add to host // process in pipeline
collectionHost.elements.Add(converted); var reference = await sendPipeline.Process(converted).ConfigureAwait(false);
if (!wasCached)
{
_sendConversionCache.AppendSendResult(projectId, applicationId, reference);
}
return new(Status.SUCCESS, applicationId, sourceType, converted); // add to host
collectionHost.elements.Add(reference);
return new(Status.SUCCESS, applicationId, sourceType, reference);
} }
catch (Exception ex) when (!ex.IsFatal()) catch (Exception ex) when (!ex.IsFatal())
{ {
@@ -6,7 +6,7 @@ using Speckle.Connectors.Rhino.DependencyInjection;
using Speckle.Converters.Rhino; using Speckle.Converters.Rhino;
using Speckle.Sdk; using Speckle.Sdk;
using Speckle.Sdk.Models.Extensions; using Speckle.Sdk.Models.Extensions;
namespace Speckle.Connectors.Rhino.Plugin; namespace Speckle.Connectors.Rhino.Plugin;
///<summary> ///<summary>
@@ -14,6 +14,7 @@ namespace Speckle.Connectors.Common.Caching;
public interface ISendConversionCache public interface ISendConversionCache
{ {
void StoreSendResult(string projectId, IReadOnlyDictionary<Id, ObjectReference> convertedReferences); void StoreSendResult(string projectId, IReadOnlyDictionary<Id, ObjectReference> convertedReferences);
void AppendSendResult(string projectId, string applicationId, ObjectReference convertedReference);
/// <summary> /// <summary>
/// <para>Call this method whenever you need to invalidate a set of objects that have changed in the host app.</para> /// <para>Call this method whenever you need to invalidate a set of objects that have changed in the host app.</para>
@@ -11,6 +11,8 @@ public class NullSendConversionCache : ISendConversionCache
{ {
public void StoreSendResult(string projectId, IReadOnlyDictionary<Id, ObjectReference> convertedReferences) { } public void StoreSendResult(string projectId, IReadOnlyDictionary<Id, ObjectReference> convertedReferences) { }
public void AppendSendResult(string projectId, string applicationId, ObjectReference convertedReference) { }
public void EvictObjects(IEnumerable<string> objectIds) { } public void EvictObjects(IEnumerable<string> objectIds) { }
public void ClearCache() { } public void ClearCache() { }
@@ -17,6 +17,11 @@ public class SendConversionCache : ISendConversionCache
} }
} }
public void AppendSendResult(string projectId, string applicationId, ObjectReference convertedReference)
{
Cache[(applicationId, projectId)] = convertedReference;
}
/// <inheritdoc/> /// <inheritdoc/>
public void EvictObjects(IEnumerable<string> objectIds) => public void EvictObjects(IEnumerable<string> objectIds) =>
Cache = Cache Cache = Cache