diff --git a/Core/Core/Models/Instances/IInstanceComponent.cs b/Core/Core/Models/Instances/IInstanceComponent.cs new file mode 100644 index 0000000000..9a6478607d --- /dev/null +++ b/Core/Core/Models/Instances/IInstanceComponent.cs @@ -0,0 +1,12 @@ +namespace Speckle.Core.Models.Instances; + +/// +/// Abstracts over and for sorting and grouping in receive operations. +/// +public interface IInstanceComponent +{ + /// + /// The maximum "depth" at which this or was found. On receive, as instances can be composed of other instances, we need to start from the deepest instance elements first when reconstructing them, starting with definitions first. + /// + public int MaxDepth { get; set; } +} diff --git a/Core/Core/Models/Instances/InstanceDefinitionProxy.cs b/Core/Core/Models/Instances/InstanceDefinitionProxy.cs new file mode 100644 index 0000000000..0fde842faa --- /dev/null +++ b/Core/Core/Models/Instances/InstanceDefinitionProxy.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Speckle.Core.Models.Instances; + +/// +/// A proxy class for an instance definition. +/// +public class InstanceDefinitionProxy : Base, IInstanceComponent +{ + /// + /// The original ids of the objects that are part of this definition, as present in the source host app. On receive, they will be mapped to corresponding newly created definition ids. + /// + public List Objects { get; set; } // source app application ids for the objects + + public int MaxDepth { get; set; } +} diff --git a/Core/Core/Models/Instances/InstanceProxy.cs b/Core/Core/Models/Instances/InstanceProxy.cs new file mode 100644 index 0000000000..5fa18496e9 --- /dev/null +++ b/Core/Core/Models/Instances/InstanceProxy.cs @@ -0,0 +1,26 @@ +using System.DoubleNumerics; + +namespace Speckle.Core.Models.Instances; + +/// +/// A proxy class for an instance (e.g, a rhino block, or an autocad block reference). +/// +public class InstanceProxy : Base, IInstanceComponent +{ + /// + /// The definition id as present in the original host app. On receive, it will be mapped to the newly created definition id. + /// + public string DefinitionId { get; set; } + + /// + /// The transform of the instance reference. + /// + public Matrix4x4 Transform { get; set; } + + /// + /// The units of the host application file. + /// + public string Units { get; set; } = Kits.Units.Meters; + + public int MaxDepth { get; set; } +} diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json index e890a9f47a..b975016a9b 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/packages.lock.json @@ -383,7 +383,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Connectors.Utils": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )", + "Speckle.Core": "[3.0.1-alpha.14, )", "System.Threading.Tasks.Dataflow": "[6.0.0, )" } }, @@ -399,7 +399,7 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "speckle.converters.arcgis3": { @@ -421,7 +421,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -455,9 +455,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -479,11 +479,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } }, "System.Threading.Tasks.Dataflow": { diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json index 68bcf35809..0fff9ad56a 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Autocad2023/packages.lock.json @@ -436,7 +436,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Connectors.Utils": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )", + "Speckle.Core": "[3.0.1-alpha.14, )", "System.Threading.Tasks.Dataflow": "[6.0.0, )" } }, @@ -452,7 +452,7 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "speckle.converters.autocad2023": { @@ -474,7 +474,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -511,9 +511,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -535,11 +535,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } }, "System.Threading.Tasks.Dataflow": { diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index a87ea7f70d..a30179a2cb 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -8,6 +8,7 @@ using Speckle.Core.Credentials; using Speckle.Connectors.Autocad.HostApp.Extensions; using Speckle.Connectors.Utils; +using Speckle.Core.Logging; namespace Speckle.Connectors.Autocad.Bindings; @@ -108,34 +109,50 @@ public void HighlightModel(string modelCardId) return; } - HighlightObjectsOnView(objectIds); + HighlightObjectsOnView(objectIds, modelCardId); } - private void HighlightObjectsOnView(ObjectId[] objectIds) + private void HighlightObjectsOnView(ObjectId[] objectIds, string? modelCardId = null) { var doc = Application.DocumentManager.MdiActiveDocument; Parent.RunOnMainThread(() => { - doc.Editor.SetImpliedSelection(Array.Empty()); // Deselects - doc.Editor.SetImpliedSelection(objectIds); // Selects - doc.Editor.UpdateScreen(); + try + { + doc.Editor.SetImpliedSelection(Array.Empty()); // Deselects + doc.Editor.SetImpliedSelection(objectIds); // Selects + doc.Editor.UpdateScreen(); + + Extents3d selectedExtents = new(); - Extents3d selectedExtents = new(); + var tr = doc.TransactionManager.StartTransaction(); + foreach (ObjectId objectId in objectIds) + { + var entity = (Entity)tr.GetObject(objectId, OpenMode.ForRead); + if (entity != null) + { + selectedExtents.AddExtents(entity.GeometricExtents); + } + } - var tr = doc.TransactionManager.StartTransaction(); - foreach (ObjectId objectId in objectIds) + doc.Editor.Zoom(selectedExtents); + tr.Commit(); + Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); + } + catch (Exception ex) when (!ex.IsFatal()) { - var entity = (Entity)tr.GetObject(objectId, OpenMode.ForRead); - if (entity != null) + if (modelCardId != null) + { + Commands.SetModelError(modelCardId, new OperationCanceledException("Failed to highlight objects.")); + } + else { - selectedExtents.AddExtents(entity.GeometricExtents); + // This will happen, in some cases, where we highlight individual objects. Should be caught by the top level handler and not + // crash the host app. + throw; } } - - doc.Editor.Zoom(selectedExtents); - tr.Commit(); - Autodesk.AutoCAD.Internal.Utils.FlushGraphics(); }); } } diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/AutocadConnectorModule.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/AutocadConnectorModule.cs index 731098b249..52da8c7d75 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/AutocadConnectorModule.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/DependencyInjection/AutocadConnectorModule.cs @@ -1,13 +1,23 @@ #if AUTOCAD +using Autodesk.AutoCAD.DatabaseServices; +using Speckle.Autofac; using Speckle.Autofac.DependencyInjection; using Speckle.Connectors.Autocad.Bindings; using Speckle.Connectors.Autocad.Filters; +using Speckle.Connectors.Autocad.HostApp; +using Speckle.Connectors.Autocad.Interfaces; using Speckle.Connectors.Autocad.Operations.Receive; using Speckle.Connectors.Autocad.Operations.Send; +using Speckle.Connectors.Autocad.Plugin; +using Speckle.Connectors.DUI; using Speckle.Connectors.DUI.Bindings; +using Speckle.Connectors.DUI.Models; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.DUI.WebView; +using Speckle.Connectors.Utils; using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Caching; +using Speckle.Connectors.Utils.Instances; using Speckle.Connectors.Utils.Operations; using Speckle.Core.Models.GraphTraversal; @@ -17,8 +27,24 @@ public class AutocadConnectorModule : ISpeckleModule { public void Load(SpeckleContainerBuilder builder) { + builder.AddAutofac(); + builder.AddConnectorUtils(); + builder.AddDUI(); + builder.AddDUIView(); + + // Register other connector specific types + builder.AddSingleton(); + builder.AddTransient(); + builder.AddSingleton(new AutocadDocumentManager()); // TODO: Dependent to TransactionContext, can be moved to AutocadContext + builder.AddSingleton(); + builder.AddSingleton(); + builder.AddSingleton(); + SharedConnectorModule.LoadShared(builder); + + builder.AddScoped(); + // Operations builder.AddScoped>(); builder.AddSingleton(DefaultTraversal.CreateTraversalFunc()); @@ -37,6 +63,7 @@ public void Load(SpeckleContainerBuilder builder) // register send conversion cache builder.AddSingleton(); + builder.AddScoped>, AutocadInstanceObjectManager>(); } } #endif diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceObjectManager.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceObjectManager.cs new file mode 100644 index 0000000000..11067f52ba --- /dev/null +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceObjectManager.cs @@ -0,0 +1,368 @@ +using System.DoubleNumerics; +using Autodesk.AutoCAD.DatabaseServices; +using Autodesk.AutoCAD.Geometry; +using Speckle.Connectors.Autocad.HostApp.Extensions; +using Speckle.Connectors.Autocad.Operations.Send; +using Speckle.Connectors.Utils.Conversion; +using Speckle.Connectors.Utils.Instances; +using Speckle.Core.Kits; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using Speckle.Core.Models.Instances; + +namespace Speckle.Connectors.Autocad.HostApp; + +/// +/// +/// Expects to be a scoped dependency per send or receive operation. +/// +public class AutocadInstanceObjectManager : IInstanceObjectsManager> +{ + private readonly AutocadLayerManager _autocadLayerManager; + private Dictionary InstanceProxies { get; set; } = new(); + private Dictionary> InstanceProxiesByDefinitionId { get; set; } = new(); + private Dictionary DefinitionProxies { get; set; } = new(); + private Dictionary FlatAtomicObjects { get; set; } = new(); + + public AutocadInstanceObjectManager(AutocadLayerManager autocadLayerManager) + { + _autocadLayerManager = autocadLayerManager; + } + + public UnpackResult UnpackSelection(IEnumerable objects) + { + using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction(); + + foreach (var obj in objects) + { + if (obj.Root is BlockReference blockReference && !blockReference.IsDynamicBlock) + { + UnpackInstance(blockReference, 0, transaction); + } + + FlatAtomicObjects[obj.ApplicationId] = obj; + } + return new(FlatAtomicObjects.Values.ToList(), InstanceProxies, DefinitionProxies.Values.ToList()); + } + + private void UnpackInstance(BlockReference instance, int depth, Transaction transaction) + { + var instanceIdString = instance.Handle.Value.ToString(); + var definitionId = instance.BlockTableRecord; + + InstanceProxies[instanceIdString] = new InstanceProxy() + { + applicationId = instanceIdString, + DefinitionId = definitionId.ToString(), + MaxDepth = depth, + Transform = GetMatrix(instance.BlockTransform.ToArray()), + Units = Application.DocumentManager.CurrentDocument.Database.Insunits.ToSpeckleString() + }; + + // For each block instance that has the same definition, we need to keep track of the "maximum depth" at which is found. + // This will enable on receive to create them in the correct order (descending by max depth, interleaved definitions and instances). + // We need to interleave the creation of definitions and instances, as some definitions may depend on instances. + if ( + !InstanceProxiesByDefinitionId.TryGetValue( + definitionId.ToString(), + out List instanceProxiesWithSameDefinition + ) + ) + { + instanceProxiesWithSameDefinition = new List(); + InstanceProxiesByDefinitionId[definitionId.ToString()] = instanceProxiesWithSameDefinition; + } + + // We ensure that all previous instance proxies that have the same definition are at this max depth. I kind of have a feeling this can be done more elegantly, but YOLO + foreach (var instanceProxy in instanceProxiesWithSameDefinition) + { + instanceProxy.MaxDepth = depth; + } + + instanceProxiesWithSameDefinition.Add(InstanceProxies[instanceIdString]); + + if (DefinitionProxies.TryGetValue(definitionId.ToString(), out InstanceDefinitionProxy value)) + { + value.MaxDepth = depth; + return; // exit fast - we've parsed this one so no need to go further + } + + var definition = (BlockTableRecord)transaction.GetObject(definitionId, OpenMode.ForRead); + // definition.Origin + var definitionProxy = new InstanceDefinitionProxy() + { + applicationId = definitionId.ToString(), + Objects = new(), + MaxDepth = depth, + ["name"] = definition.Name, + ["comments"] = definition.Comments, + ["units"] = definition.Units // ? not sure needed? + }; + + // Go through each definition object + foreach (ObjectId id in definition) + { + var obj = transaction.GetObject(id, OpenMode.ForRead); + var handleIdString = obj.Handle.Value.ToString(); + definitionProxy.Objects.Add(handleIdString); + + if (obj is BlockReference blockReference && !blockReference.IsDynamicBlock) + { + UnpackInstance(blockReference, depth + 1, transaction); + } + FlatAtomicObjects[handleIdString] = new(obj, handleIdString); + } + + DefinitionProxies[definitionId.ToString()] = definitionProxy; + } + + public BakeResult BakeInstances( + List<(string[] layerPath, IInstanceComponent obj)> instanceComponents, + Dictionary> applicationIdMap, + string baseLayerName, + Action? onOperationProgressed + ) + { + var sortedInstanceComponents = instanceComponents + .OrderByDescending(x => x.obj.MaxDepth) // Sort by max depth, so we start baking from the deepest element first + .ThenBy(x => x.obj is InstanceDefinitionProxy ? 0 : 1) // Ensure we bake the deepest definition first, then any instances that depend on it + .ToList(); + + var definitionIdAndApplicationIdMap = new Dictionary(); + + using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction(); + var conversionResults = new List(); + var createdObjectIds = new List(); + var consumedObjectIds = new List(); + var count = 0; + + foreach (var (path, instanceOrDefinition) in sortedInstanceComponents) + { + try + { + onOperationProgressed?.Invoke("Converting blocks", (double)++count / sortedInstanceComponents.Count); + if (instanceOrDefinition is InstanceDefinitionProxy { applicationId: not null } definitionProxy) + { + // TODO: create definition (block table record) + var constituentEntities = definitionProxy.Objects + .Select(id => applicationIdMap.TryGetValue(id, out List value) ? value : null) + .Where(x => x is not null) + .SelectMany(ent => ent) + .ToList(); + + var record = new BlockTableRecord(); + var objectIds = new ObjectIdCollection(); + record.Name = baseLayerName; + if (definitionProxy["name"] is string name) + { + record.Name += name; + } + else + { + record.Name += definitionProxy.applicationId; + } + + foreach (var entity in constituentEntities) + { + // record.AppendEntity(entity); + objectIds.Add(entity.ObjectId); + } + + using var blockTable = (BlockTable) + transaction.GetObject(Application.DocumentManager.CurrentDocument.Database.BlockTableId, OpenMode.ForWrite); + var id = blockTable.Add(record); + record.AssumeOwnershipOf(objectIds); + + definitionIdAndApplicationIdMap[definitionProxy.applicationId] = id; + transaction.AddNewlyCreatedDBObject(record, true); + var consumedEntitiesHandleValues = constituentEntities.Select(ent => ent.Handle.Value.ToString()).ToArray(); + consumedObjectIds.AddRange(consumedEntitiesHandleValues); + createdObjectIds.RemoveAll(newId => consumedEntitiesHandleValues.Contains(newId)); + } + else if ( + instanceOrDefinition is InstanceProxy instanceProxy + && definitionIdAndApplicationIdMap.TryGetValue(instanceProxy.DefinitionId, out ObjectId definitionId) + ) + { + var matrix3d = GetMatrix3d(instanceProxy.Transform, instanceProxy.Units); + var insertionPoint = Point3d.Origin.TransformBy(matrix3d); + + var modelSpaceBlockTableRecord = Application.DocumentManager.CurrentDocument.Database.GetModelSpace( + OpenMode.ForWrite + ); + _autocadLayerManager.CreateLayerForReceive(path[0]); + var blockRef = new BlockReference(insertionPoint, definitionId) + { + BlockTransform = matrix3d, + Layer = path[0], + }; + + modelSpaceBlockTableRecord.AppendEntity(blockRef); + + if (instanceProxy.applicationId != null) + { + applicationIdMap[instanceProxy.applicationId] = new List { blockRef }; + } + + transaction.AddNewlyCreatedDBObject(blockRef, true); + conversionResults.Add( + new(Status.SUCCESS, instanceProxy, blockRef.Handle.Value.ToString(), "Instance (Block)") + ); + createdObjectIds.Add(blockRef.Handle.Value.ToString()); + } + } + catch (Exception ex) when (!ex.IsFatal()) + { + conversionResults.Add(new(Status.ERROR, instanceOrDefinition as Base ?? new Base(), null, null, ex)); + } + } + transaction.Commit(); + return new(createdObjectIds, consumedObjectIds, conversionResults); + } + + /// + /// Cleans up any previously created instances. + /// POC: This function will not be able to delete block definitions if the user creates a new one composed out of received definitions. + /// + /// + public void PurgeInstances(string namePrefix) + { + using var transaction = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction(); + var instanceDefinitionsToDelete = new Dictionary(); + + // Helper function that recurses through a given block table record's constituent objects and purges inner instances as required. + void TraverseAndClean(BlockTableRecord btr) + { + foreach (var objectId in btr) + { + var obj = transaction.GetObject(objectId, OpenMode.ForRead) as BlockReference; + if (obj == null) + { + continue; + } + var definition = (BlockTableRecord)transaction.GetObject(obj.BlockTableRecord, OpenMode.ForRead); + if (obj.IsErased) + { + TraverseAndClean(definition); + continue; + } + + obj.UpgradeOpen(); + obj.Erase(); + TraverseAndClean(definition); + instanceDefinitionsToDelete[obj.BlockTableRecord.ToString()] = definition; + } + } + + using var blockTable = (BlockTable) + transaction.GetObject(Application.DocumentManager.CurrentDocument.Database.BlockTableId, OpenMode.ForRead); + + // deep clean definitions + foreach (var btrId in blockTable) + { + var btr = (BlockTableRecord)transaction.GetObject(btrId, OpenMode.ForRead); + if (btr.Name.Contains(namePrefix)) // POC: this is tightly coupled with a naming convention for definitions in the instance object manager + { + TraverseAndClean(btr); + instanceDefinitionsToDelete[btr.Name] = btr; + } + } + + foreach (var def in instanceDefinitionsToDelete.Values) + { + def.UpgradeOpen(); + def.Erase(); + } + + transaction.Commit(); + } + + private Matrix4x4 GetMatrix(double[] t) + { + return new Matrix4x4( + t[0], + t[1], + t[2], + t[3], + t[4], + t[5], + t[6], + t[7], + t[8], + t[9], + t[10], + t[11], + t[12], + t[13], + t[14], + t[15] + ); + } + + private Matrix3d GetMatrix3d(Matrix4x4 matrix, string units) + { + var sf = Units.GetConversionFactor( + units, + Application.DocumentManager.CurrentDocument.Database.Insunits.ToSpeckleString() + ); + + var scaledTransform = new[] + { + matrix.M11, + matrix.M12, + matrix.M13, + matrix.M14 * sf, + matrix.M21, + matrix.M22, + matrix.M23, + matrix.M24 * sf, + matrix.M31, + matrix.M32, + matrix.M33, + matrix.M34 * sf, + matrix.M41, + matrix.M42, + matrix.M43, + matrix.M44 + }; + + var m3d = new Matrix3d(scaledTransform); + if (!m3d.IsScaledOrtho()) + { + m3d = new Matrix3d(MakePerpendicular(m3d)); + } + + return m3d; + } + + // https://forums.autodesk.com/t5/net/set-blocktransform-values/m-p/6452121#M49479 + private static double[] MakePerpendicular(Matrix3d matrix) + { + // Get the basis vectors of the matrix + Vector3d right = new(matrix[0, 0], matrix[1, 0], matrix[2, 0]); + Vector3d up = new(matrix[0, 1], matrix[1, 1], matrix[2, 1]); + + Vector3d newForward = right.CrossProduct(up).GetNormal(); + Vector3d newUp = newForward.CrossProduct(right).GetNormal(); + + return new[] + { + right.X, + newUp.X, + newForward.X, + matrix[0, 3], + right.Y, + newUp.Y, + newForward.Y, + matrix[1, 3], + right.Z, + newUp.Z, + newForward.Z, + matrix[2, 3], + 0.0, + 0.0, + 0.0, + matrix[3, 3], + }; + } +} diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerManager.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerManager.cs index 87b1f00ca7..d172bea860 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerManager.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadLayerManager.cs @@ -1,9 +1,14 @@ using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.LayerManager; +using Speckle.Core.Models; +using Speckle.Core.Models.GraphTraversal; namespace Speckle.Connectors.Autocad.HostApp; +/// +/// Expects to be a scoped dependency for a given operation and helps with layer creation and cleanup. +/// public class AutocadLayerManager { private readonly AutocadContext _autocadContext; @@ -11,38 +16,30 @@ public class AutocadLayerManager // POC: Will be addressed to move it into AutocadContext! private Document Doc => Application.DocumentManager.MdiActiveDocument; + private readonly HashSet _uniqueLayerNames = new(); public AutocadLayerManager(AutocadContext autocadContext) { _autocadContext = autocadContext; } - /// - /// Constructs layer name with prefix and valid characters. - /// - /// Prefix to add layer name. - /// list of entries to concat with hyphen. - /// Full layer name with provided prefix and path. - public string LayerFullName(string baseLayerPrefix, string path) - { - var layerFullName = baseLayerPrefix + string.Join("-", path); - return _autocadContext.RemoveInvalidChars(layerFullName); - } - /// /// Will create a layer with the provided name, or, if it finds an existing one, will "purge" all objects from it. /// This ensures we're creating the new objects we've just received rather than overlaying them. /// /// Name to search layer for purge and create. - public void CreateLayerOrPurge(string layerName) + public void CreateLayerForReceive(string layerName) { - // POC: Will be addressed to move it into AutocadContext! - Document doc = Application.DocumentManager.MdiActiveDocument; - doc.LockDocument(); - using Transaction transaction = doc.TransactionManager.StartTransaction(); + if (!_uniqueLayerNames.Add(layerName)) + { + return; + } + + Doc.LockDocument(); + using Transaction transaction = Doc.TransactionManager.StartTransaction(); LayerTable? layerTable = - transaction.TransactionManager.GetObject(doc.Database.LayerTableId, OpenMode.ForRead) as LayerTable; + transaction.TransactionManager.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead) as LayerTable; LayerTableRecord layerTableRecord = new() { Name = layerName }; bool hasLayer = layerTable != null && layerTable.Has(layerName); @@ -50,7 +47,7 @@ public void CreateLayerOrPurge(string layerName) { TypedValue[] tvs = { new((int)DxfCode.LayerName, layerName) }; SelectionFilter selectionFilter = new(tvs); - SelectionSet selectionResult = doc.Editor.SelectAll(selectionFilter).Value; + SelectionSet selectionResult = Doc.Editor.SelectAll(selectionFilter).Value; if (selectionResult == null) { return; @@ -69,7 +66,38 @@ public void CreateLayerOrPurge(string layerName) transaction.Commit(); } - // POC: Consider to extract somehow in factory or service! + public void DeleteAllLayersByPrefix(string prefix) + { + Doc.LockDocument(); + using Transaction transaction = Doc.TransactionManager.StartTransaction(); + + var layerTable = (LayerTable)transaction.TransactionManager.GetObject(Doc.Database.LayerTableId, OpenMode.ForRead); + foreach (var layerId in layerTable) + { + var layer = (LayerTableRecord)transaction.GetObject(layerId, OpenMode.ForRead); + var layerName = layer.Name; + if (layer.Name.Contains(prefix)) + { + // Delete objects from this layer + TypedValue[] tvs = { new((int)DxfCode.LayerName, layerName) }; + SelectionFilter selectionFilter = new(tvs); + SelectionSet selectionResult = Doc.Editor.SelectAll(selectionFilter).Value; + if (selectionResult == null) + { + return; + } + foreach (SelectedObject selectedObject in selectionResult) + { + transaction.GetObject(selectedObject.ObjectId, OpenMode.ForWrite).Erase(); + } + // Delete layer + layer.UpgradeOpen(); + layer.Erase(); + } + } + transaction.Commit(); + } + /// /// Creates a layer filter for the just received model, grouped under a top level filter "Speckle". Note: manual close and open of the layer properties panel required (it's an acad thing). /// This comes in handy to quickly access the layers created for this specific model. @@ -114,4 +142,19 @@ public void CreateLayerFilter(string projectName, string modelName) groupFilter.NestedFilters.Add(layerFilter); Doc.Database.LayerFilters = layerFilterTree; } + + /// + /// Gets a valid layer name for a given context. + /// + /// + /// + /// + public string GetLayerPath(TraversalContext context, string baseLayerPrefix) + { + string[] collectionBasedPath = context.GetAscendantOfType().Select(c => c.name).Reverse().ToArray(); + string[] path = collectionBasedPath.Length != 0 ? collectionBasedPath : context.GetPropertyPath().ToArray(); + + var name = baseLayerPrefix + string.Join("-", path); + return _autocadContext.RemoveInvalidChars(name); + } } diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/AcadUnitsExtension.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/AcadUnitsExtension.cs new file mode 100644 index 0000000000..f4ee8e3a66 --- /dev/null +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/AcadUnitsExtension.cs @@ -0,0 +1,39 @@ +using Autodesk.AutoCAD.DatabaseServices; +using Speckle.Core.Kits; +using Speckle.Core.Logging; + +namespace Speckle.Connectors.Autocad.HostApp.Extensions; + +public static class AcadUnitsExtension +{ + public static string ToSpeckleString(this UnitsValue units) + { + switch (units) + { + case UnitsValue.Millimeters: + return Units.Millimeters; + case UnitsValue.Centimeters: + return Units.Centimeters; + case UnitsValue.Meters: + return Units.Meters; + case UnitsValue.Kilometers: + return Units.Kilometers; + case UnitsValue.Inches: + case UnitsValue.USSurveyInch: + return Units.Inches; + case UnitsValue.Feet: + case UnitsValue.USSurveyFeet: + return Units.Feet; + case UnitsValue.Yards: + case UnitsValue.USSurveyYard: + return Units.Yards; + case UnitsValue.Miles: + case UnitsValue.USSurveyMile: + return Units.Miles; + case UnitsValue.Undefined: + return Units.None; + default: + throw new SpeckleException($"The Unit System \"{units}\" is unsupported."); + } + } +} diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index e5b720aad7..3e2e44c0fe 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -1,30 +1,41 @@ using Autodesk.AutoCAD.DatabaseServices; using Speckle.Connectors.Autocad.HostApp; using Speckle.Connectors.Autocad.HostApp.Extensions; +using Speckle.Connectors.Autocad.Operations.Send; using Speckle.Core.Models; using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Conversion; +using Speckle.Connectors.Utils.Instances; using Speckle.Converters.Common; using Speckle.Core.Logging; using Speckle.Core.Models.GraphTraversal; +using Speckle.Core.Models.Instances; namespace Speckle.Connectors.Autocad.Operations.Receive; +/// +/// Expects to be a scoped dependency per receive operation. +/// public class AutocadHostObjectBuilder : IHostObjectBuilder { private readonly AutocadLayerManager _autocadLayerManager; private readonly IRootToHostConverter _converter; private readonly GraphTraversal _traversalFunction; + // private readonly HashSet _uniqueLayerNames = new(); + private readonly IInstanceObjectsManager> _instanceObjectsManager; + public AutocadHostObjectBuilder( IRootToHostConverter converter, GraphTraversal traversalFunction, - AutocadLayerManager autocadLayerManager + AutocadLayerManager autocadLayerManager, + IInstanceObjectsManager> instanceObjectsManager ) { _converter = converter; _traversalFunction = traversalFunction; _autocadLayerManager = autocadLayerManager; + _instanceObjectsManager = instanceObjectsManager; } public HostObjectBuilderResult Build( @@ -43,20 +54,68 @@ CancellationToken cancellationToken //TODO: make the layerManager handle \/ ? string baseLayerPrefix = $"SPK-{projectName}-{modelName}-"; - HashSet uniqueLayerNames = new(); + + PreReceiveDeepClean(baseLayerPrefix); List results = new(); List bakedObjectIds = new(); - foreach (var tc in _traversalFunction.TraverseWithProgress(rootObject, onOperationProgressed, cancellationToken)) + + // return new(bakedObjectIds, results); + + var objectGraph = _traversalFunction.Traverse(rootObject).Where(obj => obj.Current is not Collection); + + // POC: these are not captured by traversal, so we need to re-add them here + var instanceDefinitionProxies = (rootObject["instanceDefinitionProxies"] as List) + ?.Cast() + .ToList(); + + var instanceComponents = new List<(string[] path, IInstanceComponent obj)>(); + // POC: these are not captured by traversal, so we need to re-add them here + if (instanceDefinitionProxies != null && instanceDefinitionProxies.Count > 0) + { + var transformed = instanceDefinitionProxies.Select(proxy => (Array.Empty(), proxy as IInstanceComponent)); + instanceComponents.AddRange(transformed); + } + + var atomicObjects = new List<(string layerName, Base obj)>(); + + foreach (TraversalContext tc in objectGraph) + { + var layerName = _autocadLayerManager.GetLayerPath(tc, baseLayerPrefix); + if (tc.Current is IInstanceComponent instanceComponent) + { + instanceComponents.Add((new string[] { layerName }, instanceComponent)); + } + else + { + atomicObjects.Add((layerName, tc.Current)); + } + } + + // Stage 1: Convert atomic objects + Dictionary> applicationIdMap = new(); + var count = 0; + foreach (var (layerName, atomicObject) in atomicObjects) { + onOperationProgressed?.Invoke("Converting objects", (double)++count / atomicObjects.Count); try { - var convertedObjects = ConvertObject(tc, baseLayerPrefix, uniqueLayerNames).ToList(); + var convertedObjects = ConvertObject(atomicObject, layerName).ToList(); + + if (atomicObject.applicationId != null) + { + applicationIdMap[atomicObject.applicationId] = convertedObjects; + } results.AddRange( convertedObjects.Select( e => - new ReceiveConversionResult(Status.SUCCESS, tc.Current, e.Handle.Value.ToString(), e.GetType().ToString()) + new ReceiveConversionResult( + Status.SUCCESS, + atomicObject, + e.Handle.Value.ToString(), + e.GetType().ToString() + ) ) ); @@ -64,32 +123,44 @@ CancellationToken cancellationToken } catch (Exception ex) when (!ex.IsFatal()) { - results.Add(new(Status.ERROR, tc.Current, null, null, ex)); + results.Add(new(Status.ERROR, atomicObject, null, null, ex)); } } + // Stage 2: Convert instances + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceObjectsManager.BakeInstances( + instanceComponents, + applicationIdMap, + baseLayerPrefix, + onOperationProgressed + ); + + bakedObjectIds.RemoveAll(id => consumedObjectIds.Contains(id)); + bakedObjectIds.AddRange(createdInstanceIds); + results.RemoveAll(result => result.ResultId != null && consumedObjectIds.Contains(result.ResultId)); + results.AddRange(instanceConversionResults); + return new(bakedObjectIds, results); } - private IEnumerable ConvertObject(TraversalContext tc, string baseLayerPrefix, ISet uniqueLayerNames) + private void PreReceiveDeepClean(string baseLayerPrefix) + { + _autocadLayerManager.DeleteAllLayersByPrefix(baseLayerPrefix); + _instanceObjectsManager.PurgeInstances(baseLayerPrefix); + } + + private IEnumerable ConvertObject(Base obj, string layerName) { using TransactionContext transactionContext = TransactionContext.StartTransaction( Application.DocumentManager.MdiActiveDocument ); - string layerFullName = GetLayerPath(tc, baseLayerPrefix); + _autocadLayerManager.CreateLayerForReceive(layerName); - if (uniqueLayerNames.Add(layerFullName)) - { - _autocadLayerManager.CreateLayerOrPurge(layerFullName); - } - - //POC: this transaction used to be called in the converter, We've moved it here to unify converter implementation - //POC: Is this transaction 100% needed? we are already inside a transaction? object converted; using (var tr = Application.DocumentManager.CurrentDocument.Database.TransactionManager.StartTransaction()) { - converted = _converter.Convert(tc.Current); + converted = _converter.Convert(obj); tr.Commit(); } @@ -103,17 +174,8 @@ private IEnumerable ConvertObject(TraversalContext tc, string baseLayerP continue; } - conversionResult.AppendToDb(layerFullName); - + conversionResult.AppendToDb(layerName); yield return conversionResult; } } - - private string GetLayerPath(TraversalContext context, string baseLayerPrefix) - { - string[] collectionBasedPath = context.GetAscendantOfType().Select(c => c.name).ToArray(); - string[] path = collectionBasedPath.Length != 0 ? collectionBasedPath : context.GetPropertyPath().ToArray(); - - return _autocadLayerManager.LayerFullName(baseLayerPrefix, string.Join("-", path)); //TODO: reverse path? - } } diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs index 3073a07b25..5c09948f3b 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs @@ -3,10 +3,12 @@ using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Caching; using Speckle.Connectors.Utils.Conversion; +using Speckle.Connectors.Utils.Instances; using Speckle.Connectors.Utils.Operations; using Speckle.Converters.Common; using Speckle.Core.Logging; using Speckle.Core.Models; +using Speckle.Core.Models.Instances; namespace Speckle.Connectors.Autocad.Operations.Send; @@ -15,11 +17,17 @@ public class AutocadRootObjectBuilder : IRootObjectBuilder private readonly IRootToSpeckleConverter _converter; private readonly string[] _documentPathSeparator = { "\\" }; private readonly ISendConversionCache _sendConversionCache; + private readonly IInstanceObjectsManager> _instanceObjectsManager; - public AutocadRootObjectBuilder(IRootToSpeckleConverter converter, ISendConversionCache sendConversionCache) + public AutocadRootObjectBuilder( + IRootToSpeckleConverter converter, + ISendConversionCache sendConversionCache, + IInstanceObjectsManager> instanceObjectManager + ) { _converter = converter; _sendConversionCache = sendConversionCache; + _instanceObjectsManager = instanceObjectManager; } public RootObjectBuilderResult Build( @@ -43,16 +51,24 @@ public RootObjectBuilderResult Build( Dictionary collectionCache = new(); int count = 0; - List results = new(objects.Count); + var (atomicObjects, instanceProxies, instanceDefinitionProxies) = _instanceObjectsManager.UnpackSelection(objects); + // POC: until we formalise a bit more the root object + modelWithLayers["instanceDefinitionProxies"] = instanceDefinitionProxies; + + List results = new(); var cacheHitCount = 0; - foreach (var (dbObject, applicationId) in objects) + + foreach (var (dbObject, applicationId) in atomicObjects) { ct.ThrowIfCancellationRequested(); - try { Base converted; - if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value)) + if (dbObject is BlockReference && instanceProxies.TryGetValue(applicationId, out InstanceProxy instanceProxy)) + { + converted = instanceProxy; + } + else if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value)) { converted = value; cacheHitCount++; @@ -84,7 +100,7 @@ public RootObjectBuilderResult Build( // POC: add logging } - onOperationProgressed?.Invoke("Converting", (double)++count / objects.Count); + onOperationProgressed?.Invoke("Converting", (double)++count / atomicObjects.Count); } // POC: Log would be nice, or can be removed. diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems index dd0f8afa29..b95639804d 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems @@ -17,12 +17,14 @@ + + diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json index b6c4d13a4c..71a6fee082 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.Civil3d2024/packages.lock.json @@ -439,7 +439,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Connectors.Utils": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )", + "Speckle.Core": "[3.0.1-alpha.14, )", "System.Threading.Tasks.Dataflow": "[6.0.0, )" } }, @@ -455,7 +455,7 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "speckle.converters.autocad2024": { @@ -477,7 +477,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -520,9 +520,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -544,11 +544,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } }, "System.Threading.Tasks.Dataflow": { diff --git a/DUI3-DX/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json b/DUI3-DX/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json index 0a002c7391..503e92ef50 100644 --- a/DUI3-DX/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json +++ b/DUI3-DX/Connectors/Revit/Speckle.Connectors.Revit2023/packages.lock.json @@ -454,7 +454,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Connectors.Utils": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )", + "Speckle.Core": "[3.0.1-alpha.14, )", "System.Threading.Tasks.Dataflow": "[6.0.0, )" } }, @@ -463,14 +463,14 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "speckle.converters.common": { "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -517,9 +517,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -541,11 +541,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } }, "Speckle.Revit.API": { diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs index f0fd3a63d3..7e4e6be8a3 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs @@ -1,4 +1,5 @@ using Rhino; +using Rhino.Commands; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; using Speckle.Connectors.DUI.Models; @@ -64,6 +65,20 @@ ITopLevelExceptionHandler topLevelExceptionHandler private void SubscribeToRhinoEvents() { + RhinoDoc.LayerTableEvent += (_, _) => + { + Commands.RefreshSendFilters(); + }; + + Command.BeginCommand += (_, e) => + { + if (e.CommandEnglishName == "BlockEdit") + { + var selectedObject = RhinoDoc.ActiveDoc.Objects.GetSelectedObjects(false, false).First(); + ChangedObjectIds.Add(selectedObject.Id.ToString()); + } + }; + RhinoDoc.AddRhinoObject += (_, e) => _topLevelExceptionHandler.CatchUnhandled(() => { diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/DependencyInjection/RhinoConnectorModule.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/DependencyInjection/RhinoConnectorModule.cs index 7be48aa2b6..a21fee9903 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/DependencyInjection/RhinoConnectorModule.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/DependencyInjection/RhinoConnectorModule.cs @@ -19,6 +19,7 @@ using Speckle.Connectors.Utils; using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Caching; +using Speckle.Connectors.Utils.Instances; using Speckle.Connectors.Utils.Operations; using Speckle.Core.Models.GraphTraversal; @@ -70,5 +71,7 @@ public void Load(SpeckleContainerBuilder builder) builder.AddSingleton(DefaultTraversal.CreateTraversalFunc()); builder.AddScoped, RhinoRootObjectBuilder>(); + builder.AddScoped>, RhinoInstanceObjectsManager>(); + builder.AddScoped(); } } diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Extensions/RhinoUnitsExtension.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Extensions/RhinoUnitsExtension.cs new file mode 100644 index 0000000000..2d431afadc --- /dev/null +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Extensions/RhinoUnitsExtension.cs @@ -0,0 +1,37 @@ +using Rhino; +using Speckle.Core.Kits; +using Speckle.Core.Logging; + +namespace Speckle.Connectors.Rhino7.Extensions; + +public static class RhinoUnitsExtension +{ + public static string ToSpeckleString(this UnitSystem unitSystem) + { + switch (unitSystem) + { + case UnitSystem.None: + return Units.Meters; + case UnitSystem.Millimeters: + return Units.Millimeters; + case UnitSystem.Centimeters: + return Units.Centimeters; + case UnitSystem.Meters: + return Units.Meters; + case UnitSystem.Kilometers: + return Units.Kilometers; + case UnitSystem.Inches: + return Units.Inches; + case UnitSystem.Feet: + return Units.Feet; + case UnitSystem.Yards: + return Units.Yards; + case UnitSystem.Miles: + return Units.Miles; + case UnitSystem.Unset: + return Units.Meters; + default: + throw new SpeckleException($"The Unit System \"{unitSystem}\" is unsupported."); + } + } +} diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/HostApp/RhinoInstanceObjectsManager.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/HostApp/RhinoInstanceObjectsManager.cs new file mode 100644 index 0000000000..e79073bddf --- /dev/null +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/HostApp/RhinoInstanceObjectsManager.cs @@ -0,0 +1,254 @@ +using System.DoubleNumerics; +using Rhino; +using Rhino.DocObjects; +using Rhino.Geometry; +using Speckle.Connectors.Rhino7.Extensions; +using Speckle.Connectors.Utils.Conversion; +using Speckle.Connectors.Utils.Instances; +using Speckle.Core.Kits; +using Speckle.Core.Logging; +using Speckle.Core.Models; +using Speckle.Core.Models.Instances; + +namespace Speckle.Connectors.Rhino7.HostApp; + +/// +/// +/// Expects to be a scoped dependency per send or receive operation. +/// +public class RhinoInstanceObjectsManager : IInstanceObjectsManager> +{ + private readonly Dictionary _instanceProxies = new(); + private readonly Dictionary> _instanceProxiesByDefinitionId = new(); + private readonly Dictionary _definitionProxies = new(); + private readonly Dictionary _flatAtomicObjects = new(); + private readonly RhinoLayerManager _layerManager; + + public RhinoInstanceObjectsManager(RhinoLayerManager layerManager) + { + _layerManager = layerManager; + } + + public UnpackResult UnpackSelection(IEnumerable objects) + { + foreach (var obj in objects) + { + if (obj is InstanceObject instanceObject) + { + UnpackInstance(instanceObject); + } + _flatAtomicObjects[obj.Id.ToString()] = obj; + } + return new(_flatAtomicObjects.Values.ToList(), _instanceProxies, _definitionProxies.Values.ToList()); + } + + private void UnpackInstance(InstanceObject instance, int depth = 0) + { + var instanceId = instance.Id.ToString(); + var instanceDefinitionId = instance.InstanceDefinition.Id.ToString(); + var currentDoc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around + + _instanceProxies[instanceId] = new InstanceProxy() + { + applicationId = instanceId, + DefinitionId = instance.InstanceDefinition.Id.ToString(), + Transform = XFormToMatrix(instance.InstanceXform), + MaxDepth = depth, + Units = currentDoc.ModelUnitSystem.ToSpeckleString() + }; + + // For each block instance that has the same definition, we need to keep track of the "maximum depth" at which is found. + // This will enable on receive to create them in the correct order (descending by max depth, interleaved definitions and instances). + // We need to interleave the creation of definitions and instances, as some definitions may depend on instances. + if ( + !_instanceProxiesByDefinitionId.TryGetValue( + instanceDefinitionId, + out List instanceProxiesWithSameDefinition + ) + ) + { + instanceProxiesWithSameDefinition = new List(); + _instanceProxiesByDefinitionId[instanceDefinitionId] = instanceProxiesWithSameDefinition; + } + + // We ensure that all previous instance proxies that have the same definition are at this max depth. I kind of have a feeling this can be done more elegantly, but YOLO + foreach (var instanceProxy in instanceProxiesWithSameDefinition) + { + instanceProxy.MaxDepth = depth; + } + + instanceProxiesWithSameDefinition.Add(_instanceProxies[instanceId]); + + if (_definitionProxies.TryGetValue(instanceDefinitionId, out InstanceDefinitionProxy value)) + { + value.MaxDepth = depth; + return; + } + + var definition = new InstanceDefinitionProxy + { + applicationId = instanceDefinitionId, + Objects = new List(), + MaxDepth = depth, + ["name"] = instance.InstanceDefinition.Name, + ["description"] = instance.InstanceDefinition.Description + }; + + _definitionProxies[instance.InstanceDefinition.Id.ToString()] = definition; + + foreach (var obj in instance.InstanceDefinition.GetObjects()) + { + definition.Objects.Add(obj.Id.ToString()); + if (obj is InstanceObject localInstance) + { + UnpackInstance(localInstance, depth + 1); + } + _flatAtomicObjects[obj.Id.ToString()] = obj; + } + } + + /// + /// Bakes in the host app doc instances. Assumes constituent atomic objects already present in the host app. + /// + /// Instance definitions and instances that need creating. + /// A dict mapping { original application id -> [resulting application ids post conversion] } + /// + public BakeResult BakeInstances( + List<(string[] layerPath, IInstanceComponent obj)> instanceComponents, + Dictionary> applicationIdMap, + string baseLayerName, + Action? onOperationProgressed + ) + { + // var doc = _contextStack.Current.Document; + var doc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around + + var sortedInstanceComponents = instanceComponents + .OrderByDescending(x => x.obj.MaxDepth) // Sort by max depth, so we start baking from the deepest element first + .ThenBy(x => x.obj is InstanceDefinitionProxy ? 0 : 1) // Ensure we bake the deepest definition first, then any instances that depend on it + .ToList(); + var definitionIdAndApplicationIdMap = new Dictionary(); + + var count = 0; + var conversionResults = new List(); + var createdObjectIds = new List(); + var consumedObjectIds = new List(); + foreach (var (path, instanceOrDefinition) in sortedInstanceComponents) + { + onOperationProgressed?.Invoke("Converting blocks", (double)++count / sortedInstanceComponents.Count); + try + { + if (instanceOrDefinition is InstanceDefinitionProxy definitionProxy) + { + var currentApplicationObjectsIds = definitionProxy.Objects + .Select(x => applicationIdMap.TryGetValue(x, out List value) ? value : null) + .Where(x => x is not null) + .SelectMany(id => id) + .ToList(); + + var definitionGeometryList = new List(); + var attributes = new List(); + + foreach (var id in currentApplicationObjectsIds) + { + var docObject = doc.Objects.FindId(new Guid(id)); + definitionGeometryList.Add(docObject.Geometry); + attributes.Add(docObject.Attributes); + } + + // POC: Currently we're relying on the definition name for identification if it's coming from speckle and from which model; could we do something else? + var defName = $"{baseLayerName} ({definitionProxy.applicationId})"; + var defIndex = doc.InstanceDefinitions.Add( + defName, + "No description", // POC: perhaps bring it along from source? We'd need to look at ACAD first + Point3d.Origin, + definitionGeometryList, + attributes + ); + + // POC: check on defIndex -1, means we haven't created anything - this is most likely an recoverable error at this stage + if (defIndex == -1) + { + throw new ConversionException("Failed to create an instance defintion object."); + } + + if (definitionProxy.applicationId != null) + { + definitionIdAndApplicationIdMap[definitionProxy.applicationId] = defIndex; + } + + // Rhino deletes original objects on block creation - we should do the same. + doc.Objects.Delete(currentApplicationObjectsIds.Select(stringId => new Guid(stringId)), false); + consumedObjectIds.AddRange(currentApplicationObjectsIds); + createdObjectIds.RemoveAll(id => consumedObjectIds.Contains(id)); // in case we've consumed some existing instances + } + + if ( + instanceOrDefinition is InstanceProxy instanceProxy + && definitionIdAndApplicationIdMap.TryGetValue(instanceProxy.DefinitionId, out int index) + ) + { + var transform = MatrixToTransform(instanceProxy.Transform, instanceProxy.Units); + var layerIndex = _layerManager.GetAndCreateLayerFromPath(path, baseLayerName); + var id = doc.Objects.AddInstanceObject(index, transform, new ObjectAttributes() { LayerIndex = layerIndex }); + if (instanceProxy.applicationId != null) + { + applicationIdMap[instanceProxy.applicationId] = new List() { id.ToString() }; + } + + createdObjectIds.Add(id.ToString()); + conversionResults.Add(new(Status.SUCCESS, instanceProxy, id.ToString(), "Instance (Block)")); + } + } + catch (Exception ex) when (!ex.IsFatal()) + { + conversionResults.Add(new(Status.ERROR, instanceOrDefinition as Base ?? new Base(), null, null, ex)); + } + } + + return new(createdObjectIds, consumedObjectIds, conversionResults); + } + + public void PurgeInstances(string namePrefix) + { + var currentDoc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around + foreach (var definition in currentDoc.InstanceDefinitions) + { + if (!definition.IsDeleted && definition.Name.Contains(namePrefix)) + { + currentDoc.InstanceDefinitions.Delete(definition.Index, true, false); + } + } + } + + private Matrix4x4 XFormToMatrix(Transform t) => + new(t.M00, t.M01, t.M02, t.M03, t.M10, t.M11, t.M12, t.M13, t.M20, t.M21, t.M22, t.M23, t.M30, t.M31, t.M32, t.M33); + + private Transform MatrixToTransform(Matrix4x4 matrix, string units) + { + var currentDoc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around + var conversionFactor = Units.GetConversionFactor(units, currentDoc.ModelUnitSystem.ToSpeckleString()); + + var t = Transform.Identity; + t.M00 = matrix.M11; + t.M01 = matrix.M12; + t.M02 = matrix.M13; + t.M03 = matrix.M14 * conversionFactor; + + t.M10 = matrix.M21; + t.M11 = matrix.M22; + t.M12 = matrix.M23; + t.M13 = matrix.M24 * conversionFactor; + + t.M20 = matrix.M31; + t.M21 = matrix.M32; + t.M22 = matrix.M33; + t.M23 = matrix.M34 * conversionFactor; + + t.M30 = matrix.M41; + t.M31 = matrix.M42; + t.M32 = matrix.M43; + t.M33 = matrix.M44; + return t; + } +} diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/HostApp/RhinoLayerManager.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/HostApp/RhinoLayerManager.cs new file mode 100644 index 0000000000..55323bf099 --- /dev/null +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/HostApp/RhinoLayerManager.cs @@ -0,0 +1,122 @@ +using System.Diagnostics.Contracts; +using Rhino; +using Rhino.DocObjects; +using Speckle.Core.Models; +using Speckle.Core.Models.GraphTraversal; + +namespace Speckle.Connectors.Rhino7.HostApp; + +/// +/// Utility class managing layer creation and/or extraction from rhino. Expects to be a scoped dependency per send or receive operation. +/// +public class RhinoLayerManager +{ + private readonly Dictionary _hostLayerCache = new(); + private readonly Dictionary _layerCollectionCache = new(); + + /// + /// Creates the base layer and adds it to the cache. + /// + /// + public void CreateBaseLayer(string baseLayerName) + { + var index = RhinoDoc.ActiveDoc.Layers.Add(new Layer { Name = baseLayerName }); // POC: too much effort right now to wrap around the interfaced layers and doc + // var index = _contextStack.Current.Document.Layers.Add(new Layer { Name = baseLayerName }); + _hostLayerCache.Add(baseLayerName, index); + } + + /// + /// For receive: Use this method to construct layers in the host app when receiving.. + /// + /// + /// + /// + public int GetAndCreateLayerFromPath(string[] path, string baseLayerName) + { + var fullLayerName = string.Join(Layer.PathSeparator, path); + if (_hostLayerCache.TryGetValue(fullLayerName, out int existingLayerIndex)) + { + return existingLayerIndex; + } + + var currentLayerName = baseLayerName; + var currentDocument = RhinoDoc.ActiveDoc; // POC: too much effort right now to wrap around the interfaced layers + + var previousLayer = currentDocument.Layers.FindName(currentLayerName); + foreach (var layerName in path) + { + currentLayerName = baseLayerName + Layer.PathSeparator + layerName; + currentLayerName = currentLayerName.Replace("{", "").Replace("}", ""); // Rhino specific cleanup for gh (see RemoveInvalidRhinoChars) + if (_hostLayerCache.TryGetValue(currentLayerName, out int value)) + { + previousLayer = currentDocument.Layers.FindIndex(value); + continue; + } + + var cleanNewLayerName = layerName.Replace("{", "").Replace("}", ""); + var newLayer = new Layer { Name = cleanNewLayerName, ParentLayerId = previousLayer.Id }; + var index = currentDocument.Layers.Add(newLayer); + _hostLayerCache.Add(currentLayerName, index); + previousLayer = currentDocument.Layers.FindIndex(index); // note we need to get the correct id out, hence why we're double calling this + } + return previousLayer.Index; + } + + /// + /// For send: Use this method to construct the root commit object while converting objects. + /// Returns the host collection corresponding to the provided layer. If it's the first time that it is being asked for, it will be created and stored in the root object collection. + /// + /// The layer you want the equivalent collection for. + /// The root object that will be sent to Speckle, and will host all collections. + /// + public Collection GetHostObjectCollection(Layer layer, Collection rootObjectCollection) + { + if (_layerCollectionCache.TryGetValue(layer.Index, out Collection value)) + { + return value; + } + + var names = layer.FullPath.Split(new[] { Layer.PathSeparator }, StringSplitOptions.None); + var path = names[0]; + var index = 0; + var previousCollection = rootObjectCollection; + foreach (var layerName in names) + { + var existingLayerIndex = RhinoDoc.ActiveDoc.Layers.FindByFullPath(path, -1); + Collection? childCollection = null; + if (_layerCollectionCache.TryGetValue(existingLayerIndex, out Collection? collection)) + { + childCollection = collection; + } + else + { + childCollection = new Collection(layerName, "layer") + { + applicationId = RhinoDoc.ActiveDoc.Layers[existingLayerIndex].Id.ToString() + }; + previousCollection.elements.Add(childCollection); + _layerCollectionCache[existingLayerIndex] = childCollection; + } + + previousCollection = childCollection; + + if (index < names.Length - 1) + { + path += Layer.PathSeparator + names[index + 1]; + } + index++; + } + + _layerCollectionCache[layer.Index] = previousCollection; + return previousCollection; + } + + [Pure] + public string[] GetLayerPath(TraversalContext context) + { + string[] collectionBasedPath = context.GetAscendantOfType().Select(c => c.name).ToArray(); + string[] reverseOrderPath = + collectionBasedPath.Length != 0 ? collectionBasedPath : context.GetPropertyPath().ToArray(); + return reverseOrderPath.Reverse().ToArray(); + } +} diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Receive/RhinoHostObjectBuilder.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Receive/RhinoHostObjectBuilder.cs index 02f653f08a..1967f3a2bf 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Receive/RhinoHostObjectBuilder.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Receive/RhinoHostObjectBuilder.cs @@ -1,31 +1,43 @@ -using System.Diagnostics.Contracts; using Rhino; using Rhino.DocObjects; using Rhino.Geometry; +using Speckle.Connectors.Rhino7.HostApp; using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Conversion; +using Speckle.Connectors.Utils.Instances; using Speckle.Converters.Common; using Speckle.Core.Logging; using Speckle.Core.Models; using Speckle.Core.Models.GraphTraversal; +using Speckle.Core.Models.Instances; namespace Speckle.Connectors.Rhino7.Operations.Receive; +/// +/// Expects to be a scoped dependency per receive operation. +/// public class RhinoHostObjectBuilder : IHostObjectBuilder { private readonly IRootToHostConverter _converter; private readonly IConversionContextStack _contextStack; private readonly GraphTraversal _traverseFunction; + private readonly IInstanceObjectsManager> _instanceObjectsManager; + private readonly RhinoLayerManager _layerManager; + public RhinoHostObjectBuilder( IRootToHostConverter converter, IConversionContextStack contextStack, - GraphTraversal traverseFunction + GraphTraversal traverseFunction, + RhinoLayerManager layerManager, + IInstanceObjectsManager> instanceObjectsManager ) { _converter = converter; _contextStack = contextStack; _traverseFunction = traverseFunction; + _layerManager = layerManager; + _instanceObjectsManager = instanceObjectsManager; } public HostObjectBuilderResult Build( @@ -43,77 +55,136 @@ CancellationToken cancellationToken .TraverseWithProgress(rootObject, onOperationProgressed, cancellationToken) .Where(obj => obj.Current is not Collection); - var conversionResults = BakeObjects(objectsToConvert, baseLayerName); + var instanceDefinitionProxies = (rootObject["instanceDefinitionProxies"] as List) + ?.Cast() + .ToList(); + + var conversionResults = BakeObjects( + objectsToConvert, + instanceDefinitionProxies, + baseLayerName, + onOperationProgressed + ); _contextStack.Current.Document.Views.Redraw(); return conversionResults; } - // POC: Potentially refactor out into an IObjectBaker. - private HostObjectBuilderResult BakeObjects(IEnumerable objectsGraph, string baseLayerName) + private HostObjectBuilderResult BakeObjects( + IEnumerable objectsGraph, + List? instanceDefinitionProxies, + string baseLayerName, + Action? onOperationProgressed + ) { RhinoDoc doc = _contextStack.Current.Document; var rootLayerIndex = _contextStack.Current.Document.Layers.Find(Guid.Empty, baseLayerName, RhinoMath.UnsetIntIndex); - // POC: We could move this out into a separate service for testing and re-use. - // Cleans up any previously received objects - if (rootLayerIndex != RhinoMath.UnsetIntIndex) - { - Layer documentLayer = doc.Layers[rootLayerIndex]; - Layer[]? childLayers = documentLayer.GetChildren(); - if (childLayers != null) - { - using var layerNoDraw = new DisableRedrawScope(doc.Views); - foreach (var layer in childLayers) - { - var purgeSuccess = doc.Layers.Purge(layer.Index, true); - if (!purgeSuccess) - { - Console.WriteLine($"Failed to purge layer: {layer}"); - } - } - } - } - - var cache = new Dictionary(); - rootLayerIndex = doc.Layers.Add(new Layer { Name = baseLayerName }); - cache.Add(baseLayerName, rootLayerIndex); + PreReceiveDeepClean(baseLayerName, rootLayerIndex); + _layerManager.CreateBaseLayer(baseLayerName); using var noDraw = new DisableRedrawScope(doc.Views); var conversionResults = new List(); var bakedObjectIds = new List(); - foreach (TraversalContext tc in objectsGraph) + var instanceComponents = new List<(string[] layerPath, IInstanceComponent obj)>(); + + // POC: these are not captured by traversal, so we need to re-add them here + if (instanceDefinitionProxies != null && instanceDefinitionProxies.Count > 0) { - try - { - var path = GetLayerPath(tc); + var transformed = instanceDefinitionProxies.Select(proxy => (Array.Empty(), proxy as IInstanceComponent)); + instanceComponents.AddRange(transformed); + } - var fullLayerName = string.Join(Layer.PathSeparator, path); - var layerIndex = cache.TryGetValue(fullLayerName, out int value) - ? value - : GetAndCreateLayerFromPath(path, baseLayerName, cache); + var atomicObjects = new List<(string[] layerPath, Base obj)>(); - var result = _converter.Convert(tc.Current); + // Split up the instances from the non-instances + foreach (TraversalContext tc in objectsGraph) + { + var path = _layerManager.GetLayerPath(tc); + if (tc.Current is IInstanceComponent instanceComponent) + { + instanceComponents.Add((path, instanceComponent)); + } + else + { + atomicObjects.Add((path, tc.Current)); + } + } - var conversionIds = HandleConversionResult(result, tc.Current, layerIndex); + // Stage 1: Convert atomic objects + // Note: this can become encapsulated later in an "atomic object baker" of sorts, if needed. + var applicationIdMap = new Dictionary>(); // used in converting blocks in stage 2. keeps track of original app id => resulting new app ids post baking + var count = 0; + foreach (var (path, obj) in atomicObjects) + { + onOperationProgressed?.Invoke("Converting objects", (double)++count / atomicObjects.Count); + try + { + var layerIndex = _layerManager.GetAndCreateLayerFromPath(path, baseLayerName); + var result = _converter.Convert(obj); + var conversionIds = HandleConversionResult(result, obj, layerIndex).ToList(); foreach (var r in conversionIds) { - conversionResults.Add(new(Status.SUCCESS, tc.Current, r, result.GetType().ToString())); + conversionResults.Add(new(Status.SUCCESS, obj, r, result.GetType().ToString())); bakedObjectIds.Add(r); } + + if (obj.applicationId != null) + { + applicationIdMap[obj.applicationId] = conversionIds; + } } catch (Exception ex) when (!ex.IsFatal()) { - conversionResults.Add(new(Status.ERROR, tc.Current, null, null, ex)); + conversionResults.Add(new(Status.ERROR, obj, null, null, ex)); } } + // Stage 2: Convert instances + var (createdInstanceIds, consumedObjectIds, instanceConversionResults) = _instanceObjectsManager.BakeInstances( + instanceComponents, + applicationIdMap, + baseLayerName, + onOperationProgressed + ); + + bakedObjectIds.RemoveAll(id => consumedObjectIds.Contains(id)); // remove all objects that have been "consumed" + bakedObjectIds.AddRange(createdInstanceIds); // add instance ids + conversionResults.RemoveAll(result => result.ResultId != null && consumedObjectIds.Contains(result.ResultId)); // remove all conversion results for atomic objects that have been consumed (POC: not that cool, but prevents problems on object highlighting) + conversionResults.AddRange(instanceConversionResults); // add instance conversion results to our list + + // Stage 3: Return return new(bakedObjectIds, conversionResults); } + private void PreReceiveDeepClean(string baseLayerName, int rootLayerIndex) + { + _instanceObjectsManager.PurgeInstances(baseLayerName); + + var doc = _contextStack.Current.Document; + // Cleans up any previously received objects + if (rootLayerIndex != RhinoMath.UnsetIntIndex) + { + var documentLayer = doc.Layers[rootLayerIndex]; + var childLayers = documentLayer.GetChildren(); + if (childLayers != null) + { + using var layerNoDraw = new DisableRedrawScope(doc.Views); + foreach (var layer in childLayers) + { + var purgeSuccess = doc.Layers.Purge(layer.Index, true); + if (!purgeSuccess) + { + Console.WriteLine($"Failed to purge layer: {layer}"); + } + } + } + } + } + private IReadOnlyList HandleConversionResult(object conversionResult, Base originalObject, int layerIndex) { var doc = _contextStack.Current.Document; @@ -149,39 +220,4 @@ private Group BakeObjectsAsGroup(string groupName, IEnumerable lis var group = _contextStack.Current.Document.Groups.FindIndex(groupIndex); return group; } - - // POC: This is the original DUI3 function, this will grow over time as we add more conversions that are missing, so it should be refactored out into an ILayerManager or some sort of service. - private int GetAndCreateLayerFromPath(string[] path, string baseLayerName, Dictionary cache) - { - var currentLayerName = baseLayerName; - RhinoDoc currentDocument = _contextStack.Current.Document; - - var previousLayer = currentDocument.Layers.FindName(currentLayerName); - foreach (var layerName in path) - { - currentLayerName = baseLayerName + Layer.PathSeparator + layerName; - currentLayerName = currentLayerName.Replace("{", "").Replace("}", ""); // Rhino specific cleanup for gh (see RemoveInvalidRhinoChars) - if (cache.TryGetValue(currentLayerName, out int value)) - { - previousLayer = currentDocument.Layers.FindIndex(value); - continue; - } - - var cleanNewLayerName = layerName.Replace("{", "").Replace("}", ""); - var newLayer = new Layer { Name = cleanNewLayerName, ParentLayerId = previousLayer.Id }; - var index = currentDocument.Layers.Add(newLayer); - cache.Add(currentLayerName, index); - previousLayer = currentDocument.Layers.FindIndex(index); // note we need to get the correct id out, hence why we're double calling this - } - return previousLayer.Index; - } - - [Pure] - private static string[] GetLayerPath(TraversalContext context) - { - string[] collectionBasedPath = context.GetAscendantOfType().Select(c => c.name).ToArray(); - string[] reverseOrderPath = - collectionBasedPath.Length != 0 ? collectionBasedPath : context.GetPropertyPath().ToArray(); - return reverseOrderPath.Reverse().ToArray(); - } } diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs index 2d5996c97a..03d01c8568 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Operations/Send/RhinoRootObjectBuilder.cs @@ -1,13 +1,15 @@ using System.Diagnostics; -using Rhino.DocObjects; using Rhino; +using Rhino.DocObjects; using Speckle.Core.Models; using Speckle.Autofac.DependencyInjection; using Speckle.Converters.Common; using Speckle.Connectors.DUI.Models.Card.SendFilter; +using Speckle.Connectors.Rhino7.HostApp; using Speckle.Connectors.Utils.Builders; using Speckle.Connectors.Utils.Caching; using Speckle.Connectors.Utils.Conversion; +using Speckle.Connectors.Utils.Instances; using Speckle.Connectors.Utils.Operations; using Speckle.Core.Logging; @@ -20,11 +22,23 @@ public class RhinoRootObjectBuilder : IRootObjectBuilder { private readonly IUnitOfWorkFactory _unitOfWorkFactory; private readonly ISendConversionCache _sendConversionCache; - - public RhinoRootObjectBuilder(IUnitOfWorkFactory unitOfWorkFactory, ISendConversionCache sendConversionCache) + private readonly IInstanceObjectsManager> _instanceObjectsManager; + private readonly IConversionContextStack _contextStack; + private readonly RhinoLayerManager _layerManager; + + public RhinoRootObjectBuilder( + IUnitOfWorkFactory unitOfWorkFactory, + ISendConversionCache sendConversionCache, + IConversionContextStack contextStack, + RhinoLayerManager layerManager, + IInstanceObjectsManager> instanceObjectsManager + ) { _unitOfWorkFactory = unitOfWorkFactory; _sendConversionCache = sendConversionCache; + _contextStack = contextStack; + _layerManager = layerManager; + _instanceObjectsManager = instanceObjectsManager; } public RootObjectBuilderResult Build( @@ -46,22 +60,28 @@ private RootObjectBuilderResult ConvertObjects( using var uow = _unitOfWorkFactory.Resolve(); var converter = uow.Service; - var rootObjectCollection = new Collection { name = RhinoDoc.ActiveDoc.Name ?? "Unnamed document" }; + var rootObjectCollection = new Collection { name = _contextStack.Current.Document.Name ?? "Unnamed document" }; int count = 0; Dictionary layerCollectionCache = new(); + var (atomicObjects, instanceProxies, instanceDefinitionProxies) = _instanceObjectsManager.UnpackSelection( + rhinoObjects + ); + + // POC: we should formalise this, sooner or later - or somehow fix it a bit more + rootObjectCollection["instanceDefinitionProxies"] = instanceDefinitionProxies; // this won't work re traversal on receive + // POC: Handle blocks. List results = new(rhinoObjects.Count); var cacheHitCount = 0; - foreach (RhinoObject rhinoObject in rhinoObjects) + foreach (RhinoObject rhinoObject in atomicObjects) { cancellationToken.ThrowIfCancellationRequested(); + // RhinoDoc.ActiveDoc.Layers + var layer = _contextStack.Current.Document.Layers[rhinoObject.Attributes.LayerIndex]; - // POC: This uses the ActiveDoc but it is bad practice to do so. A context object should be injected that would contain the Doc. - var layer = RhinoDoc.ActiveDoc.Layers[rhinoObject.Attributes.LayerIndex]; - - var collectionHost = GetHostObjectCollection(layerCollectionCache, layer, rootObjectCollection); + var collectionHost = _layerManager.GetHostObjectCollection(layer, rootObjectCollection); var applicationId = rhinoObject.Id.ToString(); try @@ -70,8 +90,11 @@ private RootObjectBuilderResult ConvertObjects( // What we actually do here is check if the object has been previously converted AND has not changed. // If that's the case, we insert in the host collection just its object reference which has been saved from the prior conversion. Base converted; - - if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value)) + if (rhinoObject is InstanceObject) + { + converted = instanceProxies[applicationId]; + } + else if (_sendConversionCache.TryGetValue(sendInfo.ProjectId, applicationId, out ObjectReference value)) { converted = value; cacheHitCount++; @@ -106,58 +129,4 @@ private RootObjectBuilderResult ConvertObjects( // 5. profit return new(rootObjectCollection, results); } - - /// - /// Returns the host collection based on the provided layer. If it's not found, it will be created and hosted within the the rootObjectCollection. - /// - /// - /// - /// - /// - private Collection GetHostObjectCollection( - Dictionary layerCollectionCache, - Layer layer, - Collection rootObjectCollection - ) - { - // POC: This entire implementation should be broken down and potentially injected in. - if (layerCollectionCache.TryGetValue(layer.Index, out Collection value)) - { - return value; - } - - var names = layer.FullPath.Split(new[] { Layer.PathSeparator }, StringSplitOptions.None); - var path = names[0]; - var index = 0; - var previousCollection = rootObjectCollection; - foreach (var layerName in names) - { - var existingLayerIndex = RhinoDoc.ActiveDoc.Layers.FindByFullPath(path, -1); - Collection? childCollection = null; - if (layerCollectionCache.TryGetValue(existingLayerIndex, out Collection? collection)) - { - childCollection = collection; - } - else - { - childCollection = new Collection(layerName, "layer") - { - applicationId = RhinoDoc.ActiveDoc.Layers[existingLayerIndex].Id.ToString() - }; - previousCollection.elements.Add(childCollection); - layerCollectionCache[existingLayerIndex] = childCollection; - } - - previousCollection = childCollection; - - if (index < names.Length - 1) - { - path += Layer.PathSeparator + names[index + 1]; - } - index++; - } - - layerCollectionCache[layer.Index] = previousCollection; - return previousCollection; - } } diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json index 42b0399f3e..53de68cb60 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/packages.lock.json @@ -285,11 +285,6 @@ "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" }, - "Speckle.Revit2023.Interfaces": { - "type": "Transitive", - "resolved": "0.1.1-preview.0.24", - "contentHash": "BSVpOUJc9g6ISrw8GxvtkglTlITpHEDYNOhxv1ZPbckBsI0yO36JiphhQV4q57ERqD9PpCozUJkVhlCaxWeS6A==" - }, "SQLitePCLRaw.bundle_e_sqlite3": { "type": "Transitive", "resolved": "2.1.4", @@ -449,7 +444,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Connectors.Utils": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )", + "Speckle.Core": "[3.0.1-alpha.14, )", "System.Threading.Tasks.Dataflow": "[6.0.0, )" } }, @@ -465,14 +460,14 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "speckle.converters.common": { "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -516,9 +511,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -540,11 +535,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } }, "System.Threading.Tasks.Dataflow": { diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/packages.lock.json b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/packages.lock.json index 383e499052..9f83e4c13d 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/packages.lock.json +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/packages.lock.json @@ -370,7 +370,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -394,9 +394,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -418,11 +418,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/packages.lock.json b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/packages.lock.json index 18027e4d25..b77f27c0be 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/packages.lock.json +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3/packages.lock.json @@ -363,7 +363,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -374,9 +374,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -398,11 +398,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023.DependencyInjection/packages.lock.json b/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023.DependencyInjection/packages.lock.json index e9931ee09e..e51635ea86 100644 --- a/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023.DependencyInjection/packages.lock.json +++ b/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023.DependencyInjection/packages.lock.json @@ -374,7 +374,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -402,9 +402,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -426,11 +426,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023/packages.lock.json b/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023/packages.lock.json index b114e8a7c5..3c281f9dcf 100644 --- a/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023/packages.lock.json +++ b/DUI3-DX/Converters/Autocad/2023/Speckle.Converters.Autocad2023/packages.lock.json @@ -364,7 +364,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -379,9 +379,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -403,11 +403,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024.DependencyInjection/packages.lock.json b/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024.DependencyInjection/packages.lock.json index 8eee516ff1..fe9923d926 100644 --- a/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024.DependencyInjection/packages.lock.json +++ b/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024.DependencyInjection/packages.lock.json @@ -374,7 +374,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -402,9 +402,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -426,11 +426,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024/packages.lock.json b/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024/packages.lock.json index 5ef4059ca1..0a1d936cee 100644 --- a/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024/packages.lock.json +++ b/DUI3-DX/Converters/Autocad/2024/Speckle.Converters.Autocad2024/packages.lock.json @@ -364,7 +364,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -379,9 +379,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -403,11 +403,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/packages.lock.json b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/packages.lock.json index a1186a3a61..254754bd42 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/packages.lock.json +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/packages.lock.json @@ -358,7 +358,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -387,9 +387,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -411,11 +411,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } }, "Speckle.Revit.API": { diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/XyzConversionToPointTests.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/XyzConversionToPointTests.cs deleted file mode 100644 index 471ca0be47..0000000000 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/XyzConversionToPointTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using FluentAssertions; -using Moq; -using NUnit.Framework; -using Speckle.Converters.Common; -using Speckle.Converters.RevitShared.Services; -using Speckle.Converters.RevitShared.ToSpeckle; -using Speckle.Revit.Interfaces; - -namespace Speckle.Converters.Revit2023.Tests; - -public class XyzConversionToPointTests -{ - private readonly MockRepository _repository = new(MockBehavior.Strict); - - private readonly Mock> _revitConversionContextStack; - private readonly Mock _scalingServiceToSpeckle; - - public XyzConversionToPointTests() - { - _revitConversionContextStack = _repository.Create>(); - _scalingServiceToSpeckle = _repository.Create(); - } - - [TearDown] - public void Verify() => _repository.VerifyAll(); - - [Test] - public void Convert_Point() - { - var x = 3.1; - var y = 3.2; - var z = 3.3; - var xScaled = 4.1; - var yScaled = 4.2; - var zScaled = 4.3; - var xyz = _repository.Create(); - xyz.Setup(x => x.X).Returns(x); - xyz.Setup(x => x.Y).Returns(y); - xyz.Setup(x => x.Z).Returns(z); - - var units = "units"; - var conversionContext = _repository.Create>(); - conversionContext.Setup(x => x.SpeckleUnits).Returns(units); - - _scalingServiceToSpeckle.Setup(a => a.ScaleLength(x)).Returns(xScaled); - _scalingServiceToSpeckle.Setup(a => a.ScaleLength(y)).Returns(yScaled); - _scalingServiceToSpeckle.Setup(a => a.ScaleLength(z)).Returns(zScaled); - - _revitConversionContextStack.Setup(x => x.Current).Returns(conversionContext.Object); - - var converter = new XyzConversionToPoint(_scalingServiceToSpeckle.Object, _revitConversionContextStack.Object); - var point = converter.Convert(xyz.Object); - - point.x.Should().Be(xScaled); - point.y.Should().Be(yScaled); - point.z.Should().Be(zScaled); - point.units.Should().Be(units); - } -} diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/packages.lock.json b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/packages.lock.json index 0fbae10307..742efddba5 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/packages.lock.json +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/packages.lock.json @@ -364,7 +364,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -379,9 +379,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -403,11 +403,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/packages.lock.json b/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/packages.lock.json index a897641f42..8094f14468 100644 --- a/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/packages.lock.json +++ b/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/packages.lock.json @@ -216,11 +216,6 @@ "resolved": "13.0.2", "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" }, - "Speckle.Revit2023.Interfaces": { - "type": "Transitive", - "resolved": "0.1.1-preview.0.24", - "contentHash": "BSVpOUJc9g6ISrw8GxvtkglTlITpHEDYNOhxv1ZPbckBsI0yO36JiphhQV4q57ERqD9PpCozUJkVhlCaxWeS6A==" - }, "SQLitePCLRaw.bundle_e_sqlite3": { "type": "Transitive", "resolved": "2.1.4", @@ -369,7 +364,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "speckle.converters.common.dependencyinjection": { @@ -398,9 +393,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -422,11 +417,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7/packages.lock.json b/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7/packages.lock.json index 57b03cf40e..98fcfe0158 100644 --- a/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7/packages.lock.json +++ b/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7/packages.lock.json @@ -364,7 +364,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -379,9 +379,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -403,11 +403,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json b/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json index 9529e2c9c7..ff084cdbee 100644 --- a/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json +++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI.WebView/packages.lock.json @@ -426,7 +426,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Connectors.Utils": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )", + "Speckle.Core": "[3.0.1-alpha.14, )", "System.Threading.Tasks.Dataflow": "[6.0.0, )" } }, @@ -435,7 +435,7 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -460,9 +460,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -865,7 +865,7 @@ "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Connectors.Utils": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )", + "Speckle.Core": "[3.0.1-alpha.14, )", "System.Threading.Tasks.Dataflow": "[6.0.0, )" } }, @@ -874,7 +874,7 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -895,9 +895,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI/packages.lock.json b/DUI3-DX/DUI3/Speckle.Connectors.DUI/packages.lock.json index d1e30f591b..9f44602e71 100644 --- a/DUI3-DX/DUI3/Speckle.Connectors.DUI/packages.lock.json +++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI/packages.lock.json @@ -39,9 +39,9 @@ }, "Speckle.Core": { "type": "Direct", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -538,7 +538,7 @@ "dependencies": { "Serilog.Extensions.Logging": "[7.0.0, )", "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Core": "[3.0.1-alpha.11, )" + "Speckle.Core": "[3.0.1-alpha.14, )" } }, "Serilog.Extensions.Logging": { diff --git a/DUI3-DX/Directory.Packages.props b/DUI3-DX/Directory.Packages.props index ece50df9a0..f8e92452ff 100644 --- a/DUI3-DX/Directory.Packages.props +++ b/DUI3-DX/Directory.Packages.props @@ -16,8 +16,8 @@ - - + + diff --git a/DUI3-DX/Sdk/Speckle.Connectors.Utils/Instances/IInstanceObjectsManager.cs b/DUI3-DX/Sdk/Speckle.Connectors.Utils/Instances/IInstanceObjectsManager.cs new file mode 100644 index 0000000000..532e42ed0e --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Connectors.Utils/Instances/IInstanceObjectsManager.cs @@ -0,0 +1,53 @@ +using Speckle.Connectors.Utils.Conversion; +using Speckle.Core.Models.Instances; + +namespace Speckle.Connectors.Utils.Instances; + +/// +/// A utility class that helps manage host application blocks in send/receive operations. This expects to be a scoped dependendency per send/receive operation. +/// POC: could be split into two - instance unpacker and instance baker. +/// +/// Host application object type, e.g. RhinoObject +/// The type of the applicationIdMap values. +public interface IInstanceObjectsManager +{ + /// + /// Given a list of host application objects, it will unpack them into atomic objects, instance proxies and instance proxy definitions. + /// + /// Raw selection from the host application. + UnpackResult UnpackSelection(IEnumerable objects); + + /// + /// Will bake a set of instance components (instances and instance definitions) in the host app. + /// + /// + /// + /// + /// + /// + BakeResult BakeInstances( + List<(string[] layerPath, IInstanceComponent obj)> instanceComponents, + Dictionary applicationIdMap, + string baseLayerName, + Action? onOperationProgressed + ); + + /// + /// Cleans up previously baked instances and associated definitions containing the `namePrefix` in their name. + /// Note: this is based on the convention that all defintions have their name set to a model based prefix. + /// + /// The name prefix to search and delete by. + void PurgeInstances(string namePrefix); +} + +public record UnpackResult( + List AtomicObjects, + Dictionary InstanceProxies, + List InstanceDefinitionProxies +); + +public record BakeResult( + List CreatedInstanceIds, + List ConsumedObjectIds, + List InstanceConversionResults +); diff --git a/DUI3-DX/Sdk/Speckle.Connectors.Utils/packages.lock.json b/DUI3-DX/Sdk/Speckle.Connectors.Utils/packages.lock.json index 2b72b82db0..990763d412 100644 --- a/DUI3-DX/Sdk/Speckle.Connectors.Utils/packages.lock.json +++ b/DUI3-DX/Sdk/Speckle.Connectors.Utils/packages.lock.json @@ -48,9 +48,9 @@ }, "Speckle.Core": { "type": "Direct", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/packages.lock.json b/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/packages.lock.json index 19523196d8..cb39bea478 100644 --- a/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/packages.lock.json +++ b/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/packages.lock.json @@ -464,7 +464,7 @@ "type": "Project", "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", - "Speckle.Objects": "[3.0.1-alpha.11, )" + "Speckle.Objects": "[3.0.1-alpha.14, )" } }, "Microsoft.Extensions.Logging.Abstractions": { @@ -479,9 +479,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0", @@ -503,11 +503,11 @@ }, "Speckle.Objects": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } } } diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common/packages.lock.json b/DUI3-DX/Sdk/Speckle.Converters.Common/packages.lock.json index 0bd34a6305..23035de679 100644 --- a/DUI3-DX/Sdk/Speckle.Converters.Common/packages.lock.json +++ b/DUI3-DX/Sdk/Speckle.Converters.Common/packages.lock.json @@ -35,11 +35,11 @@ }, "Speckle.Objects": { "type": "Direct", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "YR7sei3OQBAi8R/kIu8bEmg5ELDIJK6l5fhOgdnqA9ZvD/fvmRb+09z8lIUTDsgdAdvYU/A/x9VxH9OGPbp9Kw==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "z38LGryMvh7iU1uBW+4uo5DwsB3CwRgLt2uFexWFx3mPSid+A0l5XcJzOgLwgFhNl6B42Ryz4ezBsddTp1Uc/g==", "dependencies": { - "Speckle.Core": "3.0.1-alpha.11" + "Speckle.Core": "3.0.1-alpha.14" } }, "GraphQL.Client": { @@ -472,9 +472,9 @@ }, "Speckle.Core": { "type": "CentralTransitive", - "requested": "[3.0.1-alpha.11, )", - "resolved": "3.0.1-alpha.11", - "contentHash": "Zt2dBJLlfziEACYCHThbhKypSjhoA01rTw9BzNI72c/BDyftXIz70Tetq/8ZMEqQnKqfmRyYADsAdWKxpdV0Hg==", + "requested": "[3.0.1-alpha.14, )", + "resolved": "3.0.1-alpha.14", + "contentHash": "RzQPVIGFFkKvG56YLr8ACtiwdWJE6IJ9vCQ4qHa0PIsUEpfzAIAi59jnzqtByOFC0FiFrFPow9bkfzylaZorAA==", "dependencies": { "GraphQL.Client": "6.0.0", "Microsoft.CSharp": "4.7.0",