diff --git a/All.sln b/All.sln index ff3a26c713..1365d9e652 100644 --- a/All.sln +++ b/All.sln @@ -557,6 +557,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B1324D25 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Converters.Revit2023.Tests", "DUI3-DX\Converters\Revit\Speckle.Converters.Revit2023.Tests\Speckle.Converters.Revit2023.Tests.csproj", "{AEC26A0B-25F3-4544-A9D6-A427BFF79250}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Converters.Common.Tests", "DUI3-DX\Sdk\Speckle.Converters.Common.Tests\Speckle.Converters.Common.Tests.csproj", "{95E23A97-E5EA-4506-A52C-D3DA9012DA02}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug Mac|Any CPU = Debug Mac|Any CPU @@ -2807,6 +2809,22 @@ Global {AEC26A0B-25F3-4544-A9D6-A427BFF79250}.Release|Any CPU.Build.0 = Release|Any CPU {AEC26A0B-25F3-4544-A9D6-A427BFF79250}.Release|x64.ActiveCfg = Release|Any CPU {AEC26A0B-25F3-4544-A9D6-A427BFF79250}.Release|x64.Build.0 = Release|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug Mac|Any CPU.ActiveCfg = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug Mac|Any CPU.Build.0 = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug Mac|x64.ActiveCfg = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug Mac|x64.Build.0 = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug|Any CPU.Build.0 = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug|x64.ActiveCfg = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Debug|x64.Build.0 = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release Mac|Any CPU.ActiveCfg = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release Mac|Any CPU.Build.0 = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release Mac|x64.ActiveCfg = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release Mac|x64.Build.0 = Debug|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release|Any CPU.ActiveCfg = Release|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release|Any CPU.Build.0 = Release|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release|x64.ActiveCfg = Release|Any CPU + {95E23A97-E5EA-4506-A52C-D3DA9012DA02}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3019,6 +3037,7 @@ Global {F06E4C37-4076-4272-9CA6-FB505E02CD31} = {BE521908-7944-46F3-98BF-B47D34509934} {E1C43415-3200-45F4-8BF9-A4DD7D7F2ED6} = {D92751C8-1039-4005-90B2-913E55E0B8BD} {AEC26A0B-25F3-4544-A9D6-A427BFF79250} = {D92751C8-1039-4005-90B2-913E55E0B8BD} + {95E23A97-E5EA-4506-A52C-D3DA9012DA02} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1D43D91B-4F01-4A78-8250-CC6F9BD93A14} diff --git a/Core/Core/Core.csproj b/Core/Core/Core.csproj index 275dcc12cc..caaa2ab93a 100644 --- a/Core/Core/Core.csproj +++ b/Core/Core/Core.csproj @@ -51,7 +51,6 @@ - diff --git a/DUI3-DX.slnf b/DUI3-DX.slnf index 80e74b0b65..483d0c9d43 100644 --- a/DUI3-DX.slnf +++ b/DUI3-DX.slnf @@ -30,6 +30,7 @@ "DUI3-DX\\Sdk\\Speckle.Autofac\\Speckle.Autofac.csproj", "DUI3-DX\\Sdk\\Speckle.Connectors.Utils\\Speckle.Connectors.Utils.csproj", "DUI3-DX\\Sdk\\Speckle.Converters.Common.DependencyInjection\\Speckle.Converters.Common.DependencyInjection.csproj", + "DUI3-DX\\Sdk\\Speckle.Converters.Common.Tests\\Speckle.Converters.Common.Tests.csproj", "DUI3-DX\\Sdk\\Speckle.Converters.Common\\Speckle.Converters.Common.csproj", "Objects\\Objects\\Objects.csproj", "Objects\\Tests\\Objects.Tests.Unit\\Objects.Tests.Unit.csproj" diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs index ddc096b629..157bad2797 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/ArcGISSelectionBinding.cs @@ -7,8 +7,8 @@ namespace Speckle.Connectors.ArcGIS.Bindings; public class ArcGISSelectionBinding : ISelectionBinding { - public string Name { get; } = "selectionBinding"; - public IBridge Parent { get; set; } + public string Name => "selectionBinding"; + public IBridge Parent { get; } public ArcGISSelectionBinding(IBridge parent) { @@ -22,7 +22,7 @@ public ArcGISSelectionBinding(IBridge parent) private void OnSelectionChanged(MapViewEventArgs args) { SelectionInfo selInfo = GetSelection(); - Parent?.Send(SelectionBindingEvents.SET_SELECTION, selInfo); + Parent.Send(SelectionBindingEvents.SET_SELECTION, selInfo); } public SelectionInfo GetSelection() diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs index dd2fa19efa..649691a526 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Bindings/BasicConnectorBinding.cs @@ -163,7 +163,10 @@ private void SelectMapMembersInTOC(List mapMembers) { if (member is Layer layer) { - layers.Add(layer); + if (member is not GroupLayer) // group layer selection clears other layers selection + { + layers.Add(layer); + } } else if (member is StandaloneTable table) { diff --git a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs index a681f5317a..e3a3b6300e 100644 --- a/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs +++ b/DUI3-DX/Connectors/ArcGIS/Speckle.Connectors.ArcGIS3/Operations/Receive/HostObjectBuilder.cs @@ -70,7 +70,7 @@ CancellationToken cancellationToken { if (IsGISType(obj)) { - string nestedLayerPath = $"{string.Join("\\", path)}\\{((Collection)obj).name}"; + string nestedLayerPath = $"{string.Join("\\", path)}"; string datasetId = (string)_converter.Convert(obj); conversionTracker[ctx] = new ObjectConversionTracker(obj, nestedLayerPath, datasetId); } @@ -92,10 +92,17 @@ CancellationToken cancellationToken onOperationProgressed?.Invoke("Writing to Database", null); _nonGisFeaturesUtils.WriteGeometriesToDatasets(conversionTracker); + // Create main group layer + Dictionary createdLayerGroups = new(); + Map map = _contextStack.Current.Document.Map; + GroupLayer groupLayer = LayerFactory.Instance.CreateGroupLayer(map, 0, $"{projectName}: {modelName}"); + createdLayerGroups["Basic Speckle Group"] = groupLayer; // key doesn't really matter here + // 3. add layer and tables to the Table Of Content int bakeCount = 0; Dictionary bakedMapMembers = new(); onOperationProgressed?.Invoke("Adding to Map", bakeCount); + foreach (var item in conversionTracker) { cancellationToken.ThrowIfCancellationRequested(); @@ -120,7 +127,7 @@ CancellationToken cancellationToken else { // add layer and layer URI to tracker - MapMember mapMember = AddDatasetsToMap(trackerItem); + MapMember mapMember = AddDatasetsToMap(trackerItem, createdLayerGroups); trackerItem.AddConvertedMapMember(mapMember); trackerItem.AddLayerURI(mapMember.URI); conversionTracker[item.Key] = trackerItem; @@ -133,6 +140,7 @@ CancellationToken cancellationToken } onOperationProgressed?.Invoke("Adding to Map", (double)++bakeCount / conversionTracker.Count); } + bakedObjectIds.AddRange(createdLayerGroups.Values.Select(x => x.URI)); // TODO: validated a correct set regarding bakedobject ids return new(bakedObjectIds, results); @@ -160,13 +168,21 @@ private void AddResultsFromTracker(ObjectConversionTracker trackerItem, List createdLayerGroups + ) { + // get layer details string? datasetId = trackerItem.DatasetId; // should not ne null here + Uri uri = new($"{_contextStack.Current.Document.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{datasetId}"); string nestedLayerName = trackerItem.NestedLayerName; - Uri uri = new($"{_contextStack.Current.Document.SpeckleDatabasePath.AbsolutePath.Replace('/', '\\')}\\{datasetId}"); - Map map = _contextStack.Current.Document.Map; + // add group for the current layer + string shortName = nestedLayerName.Split("\\")[^1]; + string nestedLayerPath = string.Join("\\", nestedLayerName.Split("\\").SkipLast(1)); + + GroupLayer groupLayer = CreateNestedGroupLayer(nestedLayerPath, createdLayerGroups); // Most of the Speckle-written datasets will be containing geometry and added as Layers // although, some datasets might be just tables (e.g. native GIS Tables, in the future maybe Revit schedules etc. @@ -174,23 +190,55 @@ private MapMember AddDatasetsToMap(ObjectConversionTracker trackerItem) // expensive, than assuming by default that it's a layer with geometry (which in most cases it's expected to be) try { - var layer = LayerFactory.Instance.CreateLayer(uri, map, layerName: nestedLayerName); + var layer = LayerFactory.Instance.CreateLayer(uri, groupLayer, layerName: shortName); + layer.SetExpanded(true); return layer; } catch (ArgumentException) { - var table = StandaloneTableFactory.Instance.CreateStandaloneTable(uri, map, tableName: nestedLayerName); + var table = StandaloneTableFactory.Instance.CreateStandaloneTable(uri, groupLayer, tableName: shortName); return table; } } + private GroupLayer CreateNestedGroupLayer(string nestedLayerPath, Dictionary createdLayerGroups) + { + GroupLayer lastGroup = createdLayerGroups.FirstOrDefault().Value; + if (lastGroup == null) // if layer not found + { + throw new InvalidOperationException("Speckle Layer Group not found"); + } + + // iterate through each nested level + string createdGroupPath = ""; + var allPathElements = nestedLayerPath.Split("\\").Where(x => !string.IsNullOrEmpty(x)); + foreach (string pathElement in allPathElements) + { + createdGroupPath += "\\" + pathElement; + if (createdLayerGroups.TryGetValue(createdGroupPath, out var existingGroupLayer)) + { + lastGroup = existingGroupLayer; + } + else + { + // create new GroupLayer under last found Group, named with last pathElement + lastGroup = LayerFactory.Instance.CreateGroupLayer(lastGroup, 0, pathElement); + lastGroup.SetExpanded(true); + } + createdLayerGroups[createdGroupPath] = lastGroup; + } + return lastGroup; + } + [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(); + + var originalPath = reverseOrderPath.Reverse().ToArray(); + return originalPath.Where(x => !string.IsNullOrEmpty(x)).ToArray(); } [Pure] diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index b52fcba337..1da7250ceb 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -9,10 +9,8 @@ public class AutocadSelectionBinding : ISelectionBinding { private const string SELECTION_EVENT = "setSelection"; - private readonly List _visitedDocuments = new(); - - public string Name { get; set; } = "selectionBinding"; - + private readonly HashSet _visitedDocuments = new(); + public string Name => "selectionBinding"; public IBridge Parent { get; } public AutocadSelectionBinding(IBridge parent) @@ -26,9 +24,9 @@ public AutocadSelectionBinding(IBridge parent) Application.DocumentManager.DocumentActivated += (sender, e) => OnDocumentChanged(e.Document); } - private void OnDocumentChanged(Document document) => TryRegisterDocumentForSelection(document); + private void OnDocumentChanged(Document? document) => TryRegisterDocumentForSelection(document); - private void TryRegisterDocumentForSelection(Document document) + private void TryRegisterDocumentForSelection(Document? document) { if (document == null) { @@ -49,13 +47,13 @@ private void TryRegisterDocumentForSelection(Document document) private void OnSelectionChanged() { SelectionInfo selInfo = GetSelection(); - Parent?.Send(SELECTION_EVENT, selInfo); + Parent.Send(SELECTION_EVENT, selInfo); } public SelectionInfo GetSelection() { // POC: Will be addressed to move it into AutocadContext! https://spockle.atlassian.net/browse/CNX-9319 - Document doc = Application.DocumentManager.MdiActiveDocument; + Document? doc = Application.DocumentManager.MdiActiveDocument; List objs = new(); List objectTypes = new(); if (doc != null) diff --git a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index 296dd64359..8ebb187279 100644 --- a/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/DUI3-DX/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -18,7 +18,7 @@ namespace Speckle.Connectors.Autocad.Bindings; public sealed class AutocadSendBinding : ISendBinding { - public string Name { get; } = "sendBinding"; + public string Name => "sendBinding"; public SendBindingUICommands Commands { get; } public IBridge Parent { get; } diff --git a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitBaseBinding.cs b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitBaseBinding.cs index 7e1e0afdec..566cc9c41a 100644 --- a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitBaseBinding.cs +++ b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Bindings/RevitBaseBinding.cs @@ -8,13 +8,13 @@ namespace Speckle.Connectors.Revit.Bindings; internal abstract class RevitBaseBinding : IBinding { // POC: name and bridge might be better for them to be protected props? - public string Name { get; protected set; } - public IBridge Parent { get; protected set; } + public string Name { get; } + public IBridge Parent { get; } protected readonly DocumentModelStore Store; protected readonly RevitContext RevitContext; - public RevitBaseBinding(string name, DocumentModelStore store, IBridge bridge, RevitContext revitContext) + protected RevitBaseBinding(string name, DocumentModelStore store, IBridge bridge, RevitContext revitContext) { Name = name; Parent = bridge; diff --git a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs index 6652aad320..417478e952 100644 --- a/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs +++ b/DUI3-DX/Connectors/Revit/Speckle.Connectors.RevitShared/Operations/Send/RevitRootObjectBuilder.cs @@ -72,12 +72,14 @@ public RootObjectBuilderResult Build( var countProgress = 0; // because for(int i = 0; ...) loops are so last year var cacheHitCount = 0; List results = new(revitElements.Count); + var path = new string[2]; foreach (Element revitElement in revitElements) { ct.ThrowIfCancellationRequested(); var cat = revitElement.Category.Name; - var path = new[] { doc.GetElement(revitElement.LevelId) is not Level level ? "No level" : level.Name, cat }; + path[0] = doc.GetElement(revitElement.LevelId) is not Level level ? "No level" : level.Name; + path[1] = cat; var collection = GetAndCreateObjectHostCollection(path); var applicationId = revitElement.Id.ToString(); diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoBasicConnectorBinding.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoBasicConnectorBinding.cs index 4154665c7b..1ceb31b69a 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoBasicConnectorBinding.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoBasicConnectorBinding.cs @@ -14,8 +14,8 @@ namespace Speckle.Connectors.Rhino7.Bindings; public class RhinoBasicConnectorBinding : IBasicConnectorBinding { - public string Name { get; set; } = "baseBinding"; - public IBridge Parent { get; set; } + public string Name => "baseBinding"; + public IBridge Parent { get; } public BasicConnectorBindingCommands Commands { get; } private readonly DocumentModelStore _store; diff --git a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs index 0314a0f78f..951ff40f6f 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoReceiveBinding.cs @@ -12,8 +12,8 @@ namespace Speckle.Connectors.Rhino7.Bindings; public class RhinoReceiveBinding : IReceiveBinding { - public string Name { get; set; } = "receiveBinding"; - public IBridge Parent { get; set; } + public string Name => "receiveBinding"; + public IBridge Parent { get; } private readonly CancellationManager _cancellationManager; private readonly DocumentModelStore _store; 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 8f8594f193..b2c2ab1a20 100644 --- a/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs +++ b/DUI3-DX/Connectors/Rhino/Speckle.Connectors.Rhino7/Bindings/RhinoSendBinding.cs @@ -18,9 +18,9 @@ namespace Speckle.Connectors.Rhino7.Bindings; public sealed class RhinoSendBinding : ISendBinding { - public string Name { get; } = "sendBinding"; + public string Name => "sendBinding"; public SendBindingUICommands Commands { get; } - public IBridge Parent { get; set; } + public IBridge Parent { get; } private readonly DocumentModelStore _store; private readonly RhinoIdleManager _idleManager; diff --git a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/ArcGISConverterModule.cs b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/ArcGISConverterModule.cs index 30a739310b..88d26d8166 100644 --- a/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/ArcGISConverterModule.cs +++ b/DUI3-DX/Converters/ArcGIS/Speckle.Converters.ArcGIS3.DependencyInjection/ArcGISConverterModule.cs @@ -11,7 +11,7 @@ public class ArcGISConverterModule : ISpeckleModule public void Load(SpeckleContainerBuilder builder) { //don't need a host specific RootToSpeckleConverter - builder.AddConverterCommon(); + builder.AddConverterCommon(); // most things should be InstancePerLifetimeScope so we get one per operation builder.AddScoped(); builder.AddScoped(); diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/RevitConverterModule.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/RevitConverterModule.cs index 533baf679e..1c7eae1e2f 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/RevitConverterModule.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/RevitConverterModule.cs @@ -14,6 +14,7 @@ public class RevitConverterModule : ISpeckleModule public void Load(SpeckleContainerBuilder builder) { builder.AddConverterCommon(); + builder.ScanAssemblyOfType(); // POC: do we need ToSpeckleScalingService as is, do we need to interface it out? builder.AddScoped(); @@ -28,5 +29,6 @@ public void Load(SpeckleContainerBuilder builder) builder.AddScoped(); builder.AddScoped(); builder.AddScoped(); + builder.AddScoped(); } } diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/Speckle.Converters.Revit2023.DependencyInjection.csproj b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/Speckle.Converters.Revit2023.DependencyInjection.csproj index 8458d1fdaa..ae4703a46f 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/Speckle.Converters.Revit2023.DependencyInjection.csproj +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.DependencyInjection/Speckle.Converters.Revit2023.DependencyInjection.csproj @@ -6,7 +6,7 @@ - + diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/Speckle.Converters.Revit2023.Tests.csproj b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/Speckle.Converters.Revit2023.Tests.csproj index 23e43c993c..296350ca71 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/Speckle.Converters.Revit2023.Tests.csproj +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/Speckle.Converters.Revit2023.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/XyzConversionToPointTests.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/XyzConversionToPointTests.cs new file mode 100644 index 0000000000..dee5979761 --- /dev/null +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/XyzConversionToPointTests.cs @@ -0,0 +1,61 @@ +using FluentAssertions; +using Moq; +using NUnit.Framework; +using Objects; +using Speckle.Converters.Common; +using Speckle.Converters.Common.Objects; +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.Tests/packages.lock.json b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/packages.lock.json index 6fdd69eb66..256510d436 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/packages.lock.json +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023.Tests/packages.lock.json @@ -65,9 +65,9 @@ }, "Speckle.Revit2023.Interfaces": { "type": "Direct", - "requested": "[0.1.1-preview.0.23, )", - "resolved": "0.1.1-preview.0.23", - "contentHash": "H66I9JRUGt1l1YS8aOdniRPDOixRPqua9puGrhGnTEKJ26kVlgkM3FpKfdAMFea4hf03hdqhnFVmNEwgA6mPHA==" + "requested": "[0.1.1-preview.0.24, )", + "resolved": "0.1.1-preview.0.24", + "contentHash": "BSVpOUJc9g6ISrw8GxvtkglTlITpHEDYNOhxv1ZPbckBsI0yO36JiphhQV4q57ERqD9PpCozUJkVhlCaxWeS6A==" }, "Castle.Core": { "type": "Transitive", @@ -251,14 +251,6 @@ "Serilog": "2.4.0" } }, - "Serilog.Enrichers.GlobalLogContext": { - "type": "Transitive", - "resolved": "3.0.0", - "contentHash": "IIZcj5mAUVhIl/NTA+YI2KC+sPDzcwvs0ZMHH42jsPfl1a4LVX7ohVpw5UK+e3GxuV3Nv239Il5oM2peUIl44g==", - "dependencies": { - "Serilog": "2.12.0" - } - }, "Serilog.Exceptions": { "type": "Transitive", "resolved": "8.4.0", @@ -499,7 +491,7 @@ "dependencies": { "Speckle.Autofac": "[2.0.999-local, )", "Speckle.Objects": "[2.0.999-local, )", - "Speckle.Revit2023.Interfaces": "[0.1.1-preview.0.23, )" + "Speckle.Revit2023.Interfaces": "[0.1.1-preview.0.24, )" } }, "speckle.converters.common.dependencyinjection": { @@ -513,7 +505,7 @@ "type": "Project", "dependencies": { "Speckle.Converters.Common": "[2.0.999-local, )", - "Speckle.Revit2023.Interfaces": "[0.1.1-preview.0.23, )" + "Speckle.Revit2023.Interfaces": "[0.1.1-preview.0.24, )" } }, "Speckle.Core": { @@ -529,7 +521,6 @@ "Sentry.Serilog": "[3.33.0, )", "Serilog": "[2.12.0, )", "Serilog.Enrichers.ClientInfo": "[1.3.0, )", - "Serilog.Enrichers.GlobalLogContext": "[3.0.0, )", "Serilog.Exceptions": "[8.4.0, )", "Serilog.Sinks.Console": "[4.1.0, )", "Serilog.Sinks.Seq": "[5.2.2, )", diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/Speckle.Converters.Revit2023.csproj b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/Speckle.Converters.Revit2023.csproj index f2fe665f57..01dc874c3f 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/Speckle.Converters.Revit2023.csproj +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.Revit2023/Speckle.Converters.Revit2023.csproj @@ -9,7 +9,7 @@ - + diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/DisplayValueExtractor.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/DisplayValueExtractor.cs index 83cd6a4dd6..9dd899678a 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/DisplayValueExtractor.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/DisplayValueExtractor.cs @@ -103,7 +103,7 @@ List solids //options = ViewSpecificOptions ?? options ?? new Options() { DetailLevel = DetailLevelSetting }; options ??= _revitOptionsFactory.Create(RevitViewDetailLevel.Fine); - IRevitGeometryElement geom; + IRevitGeometryElement? geom; try { geom = element.GetGeometry(options); diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/IParameterValueExtractor.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/IParameterValueExtractor.cs new file mode 100644 index 0000000000..7366b0d055 --- /dev/null +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/IParameterValueExtractor.cs @@ -0,0 +1,34 @@ +using System.Diagnostics.CodeAnalysis; +using Speckle.Revit.Interfaces; + +namespace Speckle.Converters.RevitShared.Helpers; + +//not auto because of NotNullWhen +public interface IParameterValueExtractor +{ + object? GetValue(IRevitParameter parameter); + double GetValueAsDouble(IRevitElement element, RevitBuiltInParameter builtInParameter); + bool TryGetValueAsDouble( + IRevitElement element, + RevitBuiltInParameter builtInParameter, + [NotNullWhen(true)] out double? value + ); + int GetValueAsInt(IRevitElement element, RevitBuiltInParameter builtInParameter); + bool? GetValueAsBool(IRevitElement element, RevitBuiltInParameter builtInParameter); + string? GetValueAsString(IRevitElement element, RevitBuiltInParameter builtInParameter); + IRevitElementId GetValueAsElementId(IRevitElement element, RevitBuiltInParameter builtInParameter); + bool TryGetValueAsElementId( + IRevitElement element, + RevitBuiltInParameter builtInParameter, + out IRevitElementId? elementId + ); + IRevitElementId? GetValueAsElementId(IRevitParameter parameter); + IRevitLevel GetValueAsRevitLevel(IRevitElement element, RevitBuiltInParameter builtInParameter); + bool TryGetValueAsRevitLevel( + IRevitElement element, + RevitBuiltInParameter builtInParameter, + [NotNullWhen(true)] out IRevitLevel? revitLevel + ); + Dictionary GetAllRemainingParams(IRevitElement revitElement); + void RemoveUniqueId(string uniqueId); +} diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/ParameterValueExtractor.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/ParameterValueExtractor.cs index b5218980fd..2f5a71a853 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/ParameterValueExtractor.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Helpers/ParameterValueExtractor.cs @@ -2,7 +2,6 @@ using Speckle.Converters.Common; using Speckle.Converters.RevitShared.Extensions; using Speckle.Converters.RevitShared.Services; -using Speckle.InterfaceGenerator; using Speckle.Revit.Interfaces; namespace Speckle.Converters.RevitShared.Helpers; @@ -11,7 +10,7 @@ namespace Speckle.Converters.RevitShared.Helpers; // really if we have to edit a switch statement... // maybe also better as an extension method, but maybe is fine? // POC: there are a lot of public methods here. Maybe consider consolodating -[GenerateAutoInterface] + public class ParameterValueExtractor : IParameterValueExtractor { private readonly IScalingServiceToSpeckle _scalingService; @@ -160,7 +159,7 @@ public bool TryGetValueAsElementId( return GetValueGeneric(parameter, RevitStorageType.ElementId, (p) => p.AsElementId()); } - public IRevitLevel? GetValueAsRevitLevel(IRevitElement element, RevitBuiltInParameter builtInParameter) + public IRevitLevel GetValueAsRevitLevel(IRevitElement element, RevitBuiltInParameter builtInParameter) { if (!TryGetValueAsElementId(element, builtInParameter, out var elementId)) { @@ -168,7 +167,24 @@ public bool TryGetValueAsElementId( } var paramElement = element.Document.GetElement(elementId); - return paramElement?.ToLevel(); + return (paramElement?.ToLevel()).NotNull(); + } + + public bool TryGetValueAsRevitLevel( + IRevitElement element, + RevitBuiltInParameter builtInParameter, + [NotNullWhen(true)] out IRevitLevel? revitLevel + ) + { + if (!TryGetValueAsElementId(element, builtInParameter, out var elementId)) + { + revitLevel = null; + return false; + } + + var paramElement = element.Document.GetElement(elementId); + revitLevel = paramElement?.ToLevel(); + return revitLevel is not null; } private TResult? GetValueGeneric( diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/BeamConversionToSpeckle.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/BeamConversionToSpeckle.cs index 8c7d36aea1..59f790664f 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/BeamConversionToSpeckle.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/BeamConversionToSpeckle.cs @@ -1,4 +1,4 @@ -using Objects; +using Objects; using Speckle.Converters.Common; using Speckle.Converters.Common.Objects; using Speckle.Converters.RevitShared.Helpers; @@ -58,7 +58,7 @@ public SOBR.RevitBeam Convert(IRevitFamilyInstance target) target, RevitBuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM ); - speckleBeam.level = _levelConverter.Convert(level.NotNull()); + speckleBeam.level = _levelConverter.Convert(level); speckleBeam.displayValue = _displayValueExtractor.GetDisplayValue(target); diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/ColumnConversionToSpeckle.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/ColumnConversionToSpeckle.cs index dc12c29082..afcf6f27eb 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/ColumnConversionToSpeckle.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/ColumnConversionToSpeckle.cs @@ -42,22 +42,52 @@ public SOBR.RevitColumn Convert(IRevitFamilyInstance target) SOBR.RevitColumn speckleColumn = new() { family = symbol.FamilyName, type = target.Document.GetElement(target.GetTypeId()).NotNull().Name }; - var level = _parameterValueExtractor.GetValueAsRevitLevel(target, RevitBuiltInParameter.FAMILY_BASE_LEVEL_PARAM); - speckleColumn.level = _levelConverter.Convert(level.NotNull()); - - var topLevel = _parameterValueExtractor.GetValueAsRevitLevel(target, RevitBuiltInParameter.FAMILY_TOP_LEVEL_PARAM); - - speckleColumn.topLevel = _levelConverter.Convert(topLevel.NotNull()); - speckleColumn.baseOffset = _parameterValueExtractor.GetValueAsDouble( - target, - RevitBuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM - ); + //should these all be try? + if ( + _parameterValueExtractor.TryGetValueAsRevitLevel( + target, + RevitBuiltInParameter.FAMILY_BASE_LEVEL_PARAM, + out var level + ) + ) + { + speckleColumn.level = _levelConverter.Convert(level); + } + //should these all be try? + if ( + _parameterValueExtractor.TryGetValueAsRevitLevel( + target, + RevitBuiltInParameter.FAMILY_TOP_LEVEL_PARAM, + out var topLevel + ) + ) + { + speckleColumn.topLevel = _levelConverter.Convert(topLevel); + } - speckleColumn.topOffset = _parameterValueExtractor.GetValueAsDouble( - target, - RevitBuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM - ); + //should these all be try? + if ( + _parameterValueExtractor.TryGetValueAsDouble( + target, + RevitBuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM, + out var baseOffset + ) + ) + { + speckleColumn.baseOffset = baseOffset.Value; + } + //should these all be try? + if ( + _parameterValueExtractor.TryGetValueAsDouble( + target, + RevitBuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM, + out var topOffset + ) + ) + { + speckleColumn.topOffset = topOffset.Value; + } speckleColumn.facingFlipped = target.FacingFlipped; speckleColumn.handFlipped = target.HandFlipped; speckleColumn.isSlanted = target.IsSlantedColumn; @@ -69,7 +99,7 @@ public SOBR.RevitColumn Convert(IRevitFamilyInstance target) } speckleColumn.baseLine = - GetBaseCurve(target, speckleColumn.topLevel.elevation, speckleColumn.topOffset) + GetBaseCurve(target, speckleColumn.topLevel?.elevation, speckleColumn.topOffset) ?? throw new SpeckleConversionException("Unable to find a valid baseCurve for column"); speckleColumn.displayValue = _displayValueExtractor.GetDisplayValue(target); @@ -79,7 +109,7 @@ public SOBR.RevitColumn Convert(IRevitFamilyInstance target) return speckleColumn; } - private ICurve? GetBaseCurve(IRevitFamilyInstance target, double topLevelElevation, double topLevelOffset) + private ICurve? GetBaseCurve(IRevitFamilyInstance target, double? topLevelElevation, double topLevelOffset) { Base baseGeometry = _locationConverter.Convert(target.Location); ICurve? baseCurve = baseGeometry as ICurve; @@ -102,7 +132,12 @@ public SOBR.RevitColumn Convert(IRevitFamilyInstance target) return new SOG.Line( basePoint, - new SOG.Point(basePoint.x, basePoint.y, topLevelElevation + topLevelOffset, _contextStack.Current.SpeckleUnits), + new SOG.Point( + basePoint.x, + basePoint.y, + topLevelElevation ?? 0 + topLevelOffset, + _contextStack.Current.SpeckleUnits + ), _contextStack.Current.SpeckleUnits ); } diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/Geometry/PointCloudToSpeckleConverter.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/Geometry/PointCloudToSpeckleConverter.cs index ee5b81e95d..c552e7dbdf 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/Geometry/PointCloudToSpeckleConverter.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/Raw/Geometry/PointCloudToSpeckleConverter.cs @@ -37,7 +37,7 @@ public SOG.Pointcloud Convert(IRevitPointCloudInstance target) { var minPlane = _revitPlaneUtils.CreateByNormalAndOrigin( _revitxyzUtils.BasisZ, - transform.OfPoint(boundingBox.Min) + transform.OfPoint(boundingBox.NotNull().Min) ); var filter = _revitFilterFactory.CreateMultiPlaneFilter(minPlane); var points = target.GetPoints(filter, 0.0001, 999999); // max limit is 1 mil but 1000000 throws error diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/RevitRootElementProvider.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/RevitRootElementProvider.cs new file mode 100644 index 0000000000..65aeca21da --- /dev/null +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/RevitRootElementProvider.cs @@ -0,0 +1,11 @@ +using Speckle.Converters.Common; +using Speckle.Revit.Interfaces; + +namespace Speckle.Converters.RevitShared; + +public class RevitRootElementProvider : IRootElementProvider +{ + private static readonly Type s_wrappedElementType = typeof(IRevitElement); + + public Type GetRootType() => s_wrappedElementType; +} diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/CeilingTopLevelConverterToSpeckle.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/CeilingTopLevelConverterToSpeckle.cs index b757b03215..3dd7ed8cb6 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/CeilingTopLevelConverterToSpeckle.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/CeilingTopLevelConverterToSpeckle.cs @@ -1,4 +1,4 @@ -using Objects; +using Objects; using Objects.BuiltElements.Revit; using Objects.Geometry; using Speckle.Converters.Common; @@ -60,7 +60,7 @@ public override RevitCeiling Convert(IRevitCeiling target) // but it is never being set. We should be setting it var level = _parameterValueExtractor.GetValueAsRevitLevel(target, RevitBuiltInParameter.LEVEL_PARAM); - speckleCeiling.level = _levelConverter.Convert(level.NotNull()); + speckleCeiling.level = _levelConverter.Convert(level); _parameterObjectAssigner.AssignParametersToBase(target, speckleCeiling); speckleCeiling.displayValue = _displayValueExtractor.GetDisplayValue(target); diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/ExtrusionRoofToSpeckleTopLevelConverter.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/ExtrusionRoofToSpeckleTopLevelConverter.cs index b02390e933..8dfeb7907a 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/ExtrusionRoofToSpeckleTopLevelConverter.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/ExtrusionRoofToSpeckleTopLevelConverter.cs @@ -1,4 +1,4 @@ -using Objects.BuiltElements.Revit.RevitRoof; +using Objects.BuiltElements.Revit.RevitRoof; using Speckle.Converters.Common; using Speckle.Converters.Common.Objects; using Speckle.Converters.RevitShared.Extensions; @@ -57,7 +57,7 @@ public override RevitExtrusionRoof Convert(IRevitExtrusionRoof target) target, RevitBuiltInParameter.ROOF_CONSTRAINT_LEVEL_PARAM ); - speckleExtrusionRoof.level = _levelConverter.Convert(level.NotNull()); + speckleExtrusionRoof.level = _levelConverter.Convert(level); speckleExtrusionRoof.outline = _modelCurveArrayConverter.Convert(target.GetProfile()); var elementType = target.Document.GetElement(target.GetTypeId()).NotNull().ToType().NotNull(); diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FloorTopLevelConverterToSpeckle.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FloorTopLevelConverterToSpeckle.cs index b6c8ade775..eb292cae5b 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FloorTopLevelConverterToSpeckle.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FloorTopLevelConverterToSpeckle.cs @@ -1,4 +1,4 @@ -using Objects; +using Objects; using Speckle.Converters.Common; using Speckle.Converters.Common.Objects; using Speckle.Converters.RevitShared.Helpers; diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FootPrintRoofToSpeckleTopLevelConverter.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FootPrintRoofToSpeckleTopLevelConverter.cs index 5a51d40f28..78600db3ff 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FootPrintRoofToSpeckleTopLevelConverter.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/FootPrintRoofToSpeckleTopLevelConverter.cs @@ -44,7 +44,8 @@ public override RevitFootprintRoof Convert(IRevitFootPrintRoof target) var baseLevel = _parameterValueExtractor.GetValueAsRevitLevel(target, RevitBuiltInParameter.ROOF_BASE_LEVEL_PARAM); // We don't currently validate the success of this TryGet, it is assumed some Roofs don't have a top-level. - var topLevel = _parameterValueExtractor.GetValueAsRevitLevel(target, RevitBuiltInParameter.ROOF_UPTO_LEVEL_PARAM); + IRevitLevel? topLevel; + _parameterValueExtractor.TryGetValueAsRevitLevel(target, RevitBuiltInParameter.ROOF_UPTO_LEVEL_PARAM, out topLevel); //POC: CNX-9403 can be null if the sides have different slopes. //We currently don't validate the success or failure of this TryGet as it's not necessary, but will be once we start the above ticket. @@ -53,7 +54,7 @@ public override RevitFootprintRoof Convert(IRevitFootPrintRoof target) RevitFootprintRoof speckleFootprintRoof = new() { - level = _levelConverter.Convert(baseLevel.NotNull()), + level = _levelConverter.Convert(baseLevel), cutOffLevel = topLevel is not null ? _levelConverter.Convert(topLevel) : null, slope = slope }; diff --git a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/WallTopLevelConverterToSpeckle.cs b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/WallTopLevelConverterToSpeckle.cs index 3d48ca2ede..e9a0dbafc1 100644 --- a/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/WallTopLevelConverterToSpeckle.cs +++ b/DUI3-DX/Converters/Revit/Speckle.Converters.RevitShared/ToSpeckle/WallTopLevelConverterToSpeckle.cs @@ -1,4 +1,4 @@ -using Speckle.Converters.Common.Objects; +using Speckle.Converters.Common.Objects; using Speckle.Converters.Common; using Objects; using Speckle.Converters.RevitShared.Helpers; @@ -74,10 +74,10 @@ private void AssignSpecificParameters(IRevitWall target, RevitWall speckleWall) speckleWall.baseLine = _curveConverter.Convert(locationCurve.Curve); var level = _parameterValueExtractor.GetValueAsRevitLevel(target, RevitBuiltInParameter.WALL_BASE_CONSTRAINT); - speckleWall.level = _levelConverter.Convert(level.NotNull()); + speckleWall.level = _levelConverter.Convert(level); var topLevel = _parameterValueExtractor.GetValueAsRevitLevel(target, RevitBuiltInParameter.WALL_BASE_CONSTRAINT); - speckleWall.topLevel = _levelConverter.Convert(topLevel.NotNull()); + speckleWall.topLevel = _levelConverter.Convert(topLevel); // POC : what to do if these parameters are unset (instead of assigning default) _ = _parameterValueExtractor.TryGetValueAsDouble( diff --git a/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/RhinoConverterModule.cs b/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/RhinoConverterModule.cs index 9117848c90..088b93cc10 100644 --- a/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/RhinoConverterModule.cs +++ b/DUI3-DX/Converters/Rhino/Speckle.Converters.Rhino7.DependencyInjection/RhinoConverterModule.cs @@ -9,7 +9,7 @@ public class RhinoConverterModule : ISpeckleModule { public void Load(SpeckleContainerBuilder builder) { - builder.AddConverterCommon(); + builder.AddConverterCommon(); // single stack per conversion builder.AddScoped, RhinoConversionContextStack>(); } diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/AccountBinding.cs b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/AccountBinding.cs index ffd61239c1..6357195a43 100644 --- a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/AccountBinding.cs +++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/AccountBinding.cs @@ -5,8 +5,8 @@ namespace Speckle.Connectors.DUI.Bindings; public class AccountBinding : IBinding { - public string Name { get; set; } = "accountsBinding"; - public IBridge Parent { get; private set; } + public string Name => "accountsBinding"; + public IBridge Parent { get; } public AccountBinding(IBridge bridge) { diff --git a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs index e4676053e0..f0523db541 100644 --- a/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs +++ b/DUI3-DX/DUI3/Speckle.Connectors.DUI/Bindings/TestBinding.cs @@ -9,8 +9,8 @@ namespace Speckle.Connectors.DUI.Bindings; /// public class TestBinding : IBinding { - public string Name { get; set; } = "testBinding"; - public IBridge Parent { get; private set; } + public string Name => "testBinding"; + public IBridge Parent { get; } public TestBinding(IBridge bridge) { diff --git a/DUI3-DX/Sdk/Speckle.Connectors.Utils/NotNullExtensions.cs b/DUI3-DX/Sdk/Speckle.Connectors.Utils/NotNullExtensions.cs index a34d6dd671..59d9f2b3c0 100644 --- a/DUI3-DX/Sdk/Speckle.Connectors.Utils/NotNullExtensions.cs +++ b/DUI3-DX/Sdk/Speckle.Connectors.Utils/NotNullExtensions.cs @@ -5,6 +5,7 @@ namespace Speckle.Connectors.Utils; public static class NotNullExtensions { + /// public static async Task NotNull( this Task task, [CallerArgumentExpression(nameof(task))] string? message = null @@ -19,6 +20,7 @@ public static async Task NotNull( return x; } + /// public static async Task NotNull( this Task task, [CallerArgumentExpression(nameof(task))] string? message = null @@ -33,6 +35,11 @@ public static async Task NotNull( return x.Value; } + /// the object to check for null + /// see + /// type + /// A non null value + /// was null public static T NotNull([NotNull] this T? obj, [CallerArgumentExpression(nameof(obj))] string? paramName = null) where T : class { @@ -43,6 +50,7 @@ public static T NotNull([NotNull] this T? obj, [CallerArgumentExpression(name return obj; } + /// public static T NotNull([NotNull] this T? obj, [CallerArgumentExpression(nameof(obj))] string? paramName = null) where T : struct { diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/ToHost/ConverterWithFallback.cs b/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/ToHost/ConverterWithFallback.cs index 9d972cdd99..1d143ef8f9 100644 --- a/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/ToHost/ConverterWithFallback.cs +++ b/DUI3-DX/Sdk/Speckle.Converters.Common.DependencyInjection/ToHost/ConverterWithFallback.cs @@ -1,4 +1,5 @@ -using Speckle.Converters.Common.Objects; +using System.Collections; +using Speckle.Converters.Common.Objects; using Speckle.Core.Models; using Speckle.Core.Models.Extensions; @@ -49,6 +50,10 @@ public object Convert(Base target) var displayValue = target.TryGetDisplayValue(); if (displayValue != null) { + if (displayValue is IList && !displayValue.Any()) + { + throw new NotSupportedException($"No display value found for {type}"); + } return FallbackToDisplayValue(displayValue); } diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/FakeType.cs b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/FakeType.cs new file mode 100644 index 0000000000..517313bd4b --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/FakeType.cs @@ -0,0 +1,109 @@ +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; + +namespace Speckle.Converters.Common.Tests; + +public class FakeType : Type +{ + public FakeType(string name) + { + Name = name; + } + + public override object[] GetCustomAttributes(bool inherit) => throw new NotImplementedException(); + + public override bool IsDefined(Type attributeType, bool inherit) => throw new NotImplementedException(); + + public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override Type GetInterface(string name, bool ignoreCase) => throw new NotImplementedException(); + + public override Type[] GetInterfaces() => throw new NotImplementedException(); + + public override EventInfo GetEvent(string name, BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override EventInfo[] GetEvents(BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override Type[] GetNestedTypes(BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override Type GetNestedType(string name, BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override Type GetElementType() => throw new NotImplementedException(); + + protected override bool HasElementTypeImpl() => throw new NotImplementedException(); + + protected override PropertyInfo GetPropertyImpl( + string name, + BindingFlags bindingAttr, + Binder binder, + Type returnType, + Type[] types, + ParameterModifier[] modifiers + ) => throw new NotImplementedException(); + + public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => throw new NotImplementedException(); + + protected override MethodInfo GetMethodImpl( + string name, + BindingFlags bindingAttr, + Binder binder, + CallingConventions callConvention, + Type[] types, + ParameterModifier[] modifiers + ) => throw new NotImplementedException(); + + public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override FieldInfo GetField(string name, BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override FieldInfo[] GetFields(BindingFlags bindingAttr) => throw new NotImplementedException(); + + public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => throw new NotImplementedException(); + + protected override TypeAttributes GetAttributeFlagsImpl() => throw new NotImplementedException(); + + protected override bool IsArrayImpl() => throw new NotImplementedException(); + + protected override bool IsByRefImpl() => throw new NotImplementedException(); + + protected override bool IsPointerImpl() => throw new NotImplementedException(); + + protected override bool IsPrimitiveImpl() => throw new NotImplementedException(); + + protected override bool IsCOMObjectImpl() => throw new NotImplementedException(); + + public override object InvokeMember( + string name, + BindingFlags invokeAttr, + Binder binder, + object target, + object[] args, + ParameterModifier[] modifiers, + CultureInfo culture, + string[] namedParameters + ) => throw new NotImplementedException(); + + public override Type UnderlyingSystemType { get; } + + protected override ConstructorInfo GetConstructorImpl( + BindingFlags bindingAttr, + Binder binder, + CallingConventions callConvention, + Type[] types, + ParameterModifier[] modifiers + ) => throw new NotImplementedException(); + + public override string Name { get; } + + [SuppressMessage("Naming", "CA1720:Identifier contains type name")] + public override Guid GUID { get; } = Guid.Empty; + public override Module Module { get; } + public override Assembly Assembly { get; } + public override string FullName { get; } + public override string Namespace { get; } + public override string AssemblyQualifiedName { get; } + public override Type BaseType { get; } + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotImplementedException(); +} diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/RootToSpeckleConverterTests.cs b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/RootToSpeckleConverterTests.cs new file mode 100644 index 0000000000..a94bf874e4 --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/RootToSpeckleConverterTests.cs @@ -0,0 +1,67 @@ +using FluentAssertions; +using Moq; +using NUnit.Framework; +using Speckle.Core.Models; +using Speckle.Revit.Interfaces; + +namespace Speckle.Converters.Common.Tests; + +public class RootToSpeckleConverterTests +{ + private readonly MockRepository _repository = new(MockBehavior.Strict); + + private readonly Mock _rootConvertManager; + private readonly Mock _proxyMapper; + private readonly Mock _rootElementProvider; + + public RootToSpeckleConverterTests() + { + _rootConvertManager = _repository.Create(); + _proxyMapper = _repository.Create(); + _rootElementProvider = _repository.Create(); + } + + [TearDown] + public void Verify() => _repository.VerifyAll(); + + [Test] + public void Convert_BaseType() + { + try + { + Type baseType = new FakeType("baseType"); + Type hostType = new FakeType("hostType"); + + object target = new(); + Type targetType = new FakeType("targetType"); + + object wrappedTarget = new(); + Base converted = new(); + + _rootConvertManager.Setup(x => x.GetTargetType(target)).Returns(targetType); + _rootElementProvider.Setup(x => x.GetRootType()).Returns(baseType); + _proxyMapper.Setup(x => x.GetHostTypeFromMappedType(baseType)).Returns(hostType); + + _proxyMapper.Setup(x => x.GetMappedTypeFromHostType(targetType)).Returns((Type?)null); + _proxyMapper.Setup(x => x.GetMappedTypeFromProxyType(targetType)).Returns((Type?)null); + + _rootConvertManager.Setup(x => x.IsSubClass(baseType, targetType)).Returns(true); + _proxyMapper.Setup(x => x.CreateProxy(baseType, target)).Returns(wrappedTarget); + _rootConvertManager.Setup(x => x.Convert(baseType, wrappedTarget)).Returns(converted); + + var rootToSpeckleConverter = new RootToSpeckleConverter( + _proxyMapper.Object, + _rootConvertManager.Object, + _rootElementProvider.Object + ); + var testConverted = rootToSpeckleConverter.Convert(target); + + testConverted.Should().BeSameAs(converted); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } +} diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/Speckle.Converters.Common.Tests.csproj b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/Speckle.Converters.Common.Tests.csproj new file mode 100644 index 0000000000..e687d74095 --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/Speckle.Converters.Common.Tests.csproj @@ -0,0 +1,25 @@ + + + + net48 + x64 + false + true + + + + + + + + + + + + + + + + + + diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/packages.lock.json b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/packages.lock.json new file mode 100644 index 0000000000..745cd3ba1e --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Converters.Common.Tests/packages.lock.json @@ -0,0 +1,458 @@ +{ + "version": 1, + "dependencies": { + ".NETFramework,Version=v4.8": { + "coverlet.collector": { + "type": "Direct", + "requested": "[6.0.2, )", + "resolved": "6.0.2", + "contentHash": "bJShQ6uWRTQ100ZeyiMqcFlhP7WJ+bCuabUs885dJiBEzMsJMSFr7BOyeCw4rgvQokteGi5rKQTlkhfQPUXg2A==" + }, + "FluentAssertions": { + "type": "Direct", + "requested": "[6.12.0, )", + "resolved": "6.12.0", + "contentHash": "ZXhHT2YwP9lajrwSKbLlFqsmCCvFJMoRSK9t7sImfnCyd0OB3MhgxdoMcVqxbq1iyxD6mD2fiackWmBb7ayiXQ==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.0" + } + }, + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[17.10.0, )", + "resolved": "17.10.0", + "contentHash": "0/2HeACkaHEYU3wc83YlcD2Fi4LMtECJjqrtvw0lPi9DCEa35zSPt1j4fuvM8NagjDqJuh1Ja35WcRtn1Um6/A==", + "dependencies": { + "Microsoft.CodeCoverage": "17.10.0" + } + }, + "Moq": { + "type": "Direct", + "requested": "[4.20.70, )", + "resolved": "4.20.70", + "contentHash": "4rNnAwdpXJBuxqrOCzCyICXHSImOTRktCgCWXWykuF1qwoIsVvEnR7PjbMk/eLOxWvhmj5Kwt+kDV3RGUYcNwg==", + "dependencies": { + "Castle.Core": "5.1.1", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "NUnit": { + "type": "Direct", + "requested": "[4.1.0, )", + "resolved": "4.1.0", + "contentHash": "MT/DpAhjtiytzhTgTqIhBuWx4y26PKfDepYUHUM+5uv4TsryHC2jwFo5e6NhWkApCm/G6kZ80dRjdJFuAxq3rg==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "NUnit.Analyzers": { + "type": "Direct", + "requested": "[4.2.0, )", + "resolved": "4.2.0", + "contentHash": "4fJojPkzdoa4nB2+p6U+fITvPnVvwWSnsmiJ/Dl30xqiL3oxNbYvfeSLVd91hOmEjoUqSwN3Z7j1aFedjqWbUA==" + }, + "PolySharp": { + "type": "Direct", + "requested": "[1.14.1, )", + "resolved": "1.14.1", + "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" + }, + "Speckle.InterfaceGenerator": { + "type": "Direct", + "requested": "[0.9.5, )", + "resolved": "0.9.5", + "contentHash": "oU/L7pN1R7q8KkbrpQ3WJnHirPHqn+9DEA7asOcUiggV5dzVg1A/VYs7GOSusD24njxXh03tE3a2oTLOjt3cVg==" + }, + "Speckle.Revit2023.Interfaces": { + "type": "Direct", + "requested": "[0.1.1-preview.0.24, )", + "resolved": "0.1.1-preview.0.24", + "contentHash": "BSVpOUJc9g6ISrw8GxvtkglTlITpHEDYNOhxv1ZPbckBsI0yO36JiphhQV4q57ERqD9PpCozUJkVhlCaxWeS6A==" + }, + "Castle.Core": { + "type": "Transitive", + "resolved": "5.1.1", + "contentHash": "rpYtIczkzGpf+EkZgDr9CClTdemhsrwA/W5hMoPjLkRFnXzH44zDLoovXeKtmxb1ykXK9aJVODSpiJml8CTw2g==" + }, + "GraphQL.Client": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==", + "dependencies": { + "GraphQL.Client.Abstractions": "6.0.0", + "GraphQL.Client.Abstractions.Websocket": "6.0.0", + "System.Net.WebSockets.Client.Managed": "1.0.22", + "System.Reactive": "5.0.0" + } + }, + "GraphQL.Client.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==", + "dependencies": { + "GraphQL.Primitives": "6.0.0" + } + }, + "GraphQL.Client.Abstractions.Websocket": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==", + "dependencies": { + "GraphQL.Client.Abstractions": "6.0.0" + } + }, + "GraphQL.Primitives": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA==" + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "17.10.0", + "contentHash": "yC7oSlnR54XO5kOuHlVOKtxomNNN1BWXX8lK1G2jaPXT9sUok7kCOoA4Pgs0qyFaCtMrNsprztYMeoEGqCm4uA==" + }, + "Microsoft.CSharp": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" + }, + "Microsoft.Data.Sqlite": { + "type": "Transitive", + "resolved": "7.0.5", + "contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==", + "dependencies": { + "Microsoft.Data.Sqlite.Core": "7.0.5", + "SQLitePCLRaw.bundle_e_sqlite3": "2.1.4" + } + }, + "Microsoft.Data.Sqlite.Core": { + "type": "Transitive", + "resolved": "7.0.5", + "contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.4" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5" + } + }, + "Polly": { + "type": "Transitive", + "resolved": "7.2.3", + "contentHash": "DeCY0OFbNdNxsjntr1gTXHJ5pKUwYzp04Er2LLeN3g6pWhffsGuKVfMBLe1lw7x76HrPkLxKEFxBlpRxS2nDEQ==" + }, + "Polly.Contrib.WaitAndRetry": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "1MUQLiSo4KDkQe6nzQRhIU05lm9jlexX5BVsbuw0SL82ynZ+GzAHQxJVDPVBboxV37Po3SG077aX8DuSy8TkaA==" + }, + "Polly.Extensions.Http": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "drrG+hB3pYFY7w1c3BD+lSGYvH2oIclH8GRSehgfyP5kjnFnHKQuuBhuHLv+PWyFuaTDyk/vfRpnxOzd11+J8g==", + "dependencies": { + "Polly": "7.1.0" + } + }, + "Sentry": { + "type": "Transitive", + "resolved": "3.33.0", + "contentHash": "8vbD2o6IR2wrRrkSiRbnodWGWUOqIlwYtzpjvPNOb5raJdOf+zxMwfS8f6nx9bmrTTfDj7KrCB8C/5OuicAc8A==", + "dependencies": { + "System.Reflection.Metadata": "5.0.0", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", + "System.Text.Json": "5.0.2" + } + }, + "Sentry.Serilog": { + "type": "Transitive", + "resolved": "3.33.0", + "contentHash": "V8BU7QGWg2qLYfNPqtuTBhC1opysny5l+Ifp6J6PhOeAxU0FssR7nYfbJVetrnLIoh2rd3DlJ6hHYYQosQYcUQ==", + "dependencies": { + "Sentry": "3.33.0", + "Serilog": "2.7.1" + } + }, + "Serilog": { + "type": "Transitive", + "resolved": "2.12.0", + "contentHash": "xaiJLIdu6rYMKfQMYUZgTy8YK7SMZjB4Yk50C/u//Z4OsvxkUfSPJy4nknfvwAC34yr13q7kcyh4grbwhSxyZg==" + }, + "Serilog.Enrichers.ClientInfo": { + "type": "Transitive", + "resolved": "1.3.0", + "contentHash": "mTc7PM+wC9Hr7LWSwqt5mmnlAr7RJs+eTb3PGPRhwdOackk95MkhUZognuxXEdlW19HAFNmEBTSBY5DfLwM8jQ==", + "dependencies": { + "Serilog": "2.4.0" + } + }, + "Serilog.Enrichers.GlobalLogContext": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "IIZcj5mAUVhIl/NTA+YI2KC+sPDzcwvs0ZMHH42jsPfl1a4LVX7ohVpw5UK+e3GxuV3Nv239Il5oM2peUIl44g==", + "dependencies": { + "Serilog": "2.12.0" + } + }, + "Serilog.Exceptions": { + "type": "Transitive", + "resolved": "8.4.0", + "contentHash": "nc/+hUw3lsdo0zCj0KMIybAu7perMx79vu72w0za9Nsi6mWyNkGXxYxakAjWB7nEmYL6zdmhEQRB4oJ2ALUeug==", + "dependencies": { + "Serilog": "2.8.0" + } + }, + "Serilog.Formatting.Compact": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==", + "dependencies": { + "Serilog": "2.8.0" + } + }, + "Serilog.Sinks.Console": { + "type": "Transitive", + "resolved": "4.1.0", + "contentHash": "K6N5q+5fetjnJPvCmkWOpJ/V8IEIoMIB1s86OzBrbxwTyHxdx3pmz4H+8+O/Dc/ftUX12DM1aynx/dDowkwzqg==", + "dependencies": { + "Serilog": "2.10.0" + } + }, + "Serilog.Sinks.File": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==", + "dependencies": { + "Serilog": "2.10.0" + } + }, + "Serilog.Sinks.PeriodicBatching": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "NDWR7m3PalVlGEq3rzoktrXikjFMLmpwF0HI4sowo8YDdU+gqPlTHlDQiOGxHfB0sTfjPA9JjA7ctKG9zqjGkw==", + "dependencies": { + "Serilog": "2.0.0" + } + }, + "Serilog.Sinks.Seq": { + "type": "Transitive", + "resolved": "5.2.2", + "contentHash": "1Csmo5ua7NKUe0yXUx+zsRefjAniPWcXFhUXxXG8pwo0iMiw2gjn9SOkgYnnxbgWqmlGv236w0N/dHc2v5XwMg==", + "dependencies": { + "Serilog": "2.12.0", + "Serilog.Formatting.Compact": "1.1.0", + "Serilog.Sinks.File": "5.0.0", + "Serilog.Sinks.PeriodicBatching": "3.1.0" + } + }, + "SerilogTimings": { + "type": "Transitive", + "resolved": "3.0.1", + "contentHash": "Zs28eTgszAMwpIrbBnWHBI50yuxL50p/dmAUWmy75+axdZYK/Sjm5/5m1N/CisR8acJUhTVcjPZrsB1P5iv0Uw==", + "dependencies": { + "Serilog": "2.10.0" + } + }, + "Speckle.Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.2", + "contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA==" + }, + "SQLitePCLRaw.bundle_e_sqlite3": { + "type": "Transitive", + "resolved": "2.1.4", + "contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==", + "dependencies": { + "SQLitePCLRaw.lib.e_sqlite3": "2.1.4", + "SQLitePCLRaw.provider.dynamic_cdecl": "2.1.4" + } + }, + "SQLitePCLRaw.core": { + "type": "Transitive", + "resolved": "2.1.4", + "contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==", + "dependencies": { + "System.Memory": "4.5.3" + } + }, + "SQLitePCLRaw.lib.e_sqlite3": { + "type": "Transitive", + "resolved": "2.1.4", + "contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg==" + }, + "SQLitePCLRaw.provider.dynamic_cdecl": { + "type": "Transitive", + "resolved": "2.1.4", + "contentHash": "ZsaKKhgYF9B1fvcnOGKl3EycNAwd9CRWX7v0rEfuPWhQQ5Jjpvf2VEHahiLIGHio3hxi3EIKFJw9KvyowWOUAw==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.4" + } + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Collections.Immutable": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "FXkLXiK0sVVewcso0imKQoOxjoPAj42R8HtjjbSjVPAzwDfzoyoznWxgA3c38LDbN9SJux1xXoXYAhz98j7r2g==", + "dependencies": { + "System.Memory": "4.5.4" + } + }, + "System.DoubleNumerics": { + "type": "Transitive", + "resolved": "3.1.3", + "contentHash": "KRKEM/L3KBodjA9VOg3EifFVWUY6EOqaMB05UvPEDm7Zeby/kZW+4kdWUEPzW6xtkwf46p661L9NrbeeQhtLzw==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.Net.WebSockets.Client.Managed": { + "type": "Transitive", + "resolved": "1.0.22", + "contentHash": "WqEOxPlXjuZrIjUtXNE9NxEfU/n5E35iV2PtoZdJSUC4tlrqwHnTee+wvMIM4OUaJWmwrymeqcgYrE0IkGAgLA==", + "dependencies": { + "System.Buffers": "4.4.0", + "System.Numerics.Vectors": "4.4.0" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Reactive": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==", + "dependencies": { + "System.Collections.Immutable": "5.0.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==" + }, + "System.Runtime.InteropServices.RuntimeInformation": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==" + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "5.0.1", + "contentHash": "KmJ+CJXizDofbq6mpqDoRRLcxgOd2z9X3XoFNULSbvbqVRZkFX3istvr+MUjL6Zw1RT+RNdoI4GYidIINtgvqQ==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.4" + } + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "I47dVIGiV6SfAyppphxqupertT/5oZkYLDCX6vC3HpOI4ZLjyoKAreUoem2ie6G0RbRuFrlqz/PcTQjfb2DOfQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "5.0.0", + "System.Buffers": "4.5.1", + "System.Memory": "4.5.4", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "5.0.0", + "System.Text.Encodings.Web": "5.0.1", + "System.Threading.Tasks.Extensions": "4.5.4", + "System.ValueTuple": "4.5.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.ValueTuple": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==" + }, + "speckle.autofac": { + "type": "Project", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "[7.0.0, )", + "Speckle.Core": "[2.0.999-local, )" + } + }, + "speckle.converters.common": { + "type": "Project", + "dependencies": { + "Speckle.Autofac": "[2.0.999-local, )", + "Speckle.Objects": "[2.0.999-local, )", + "Speckle.Revit2023.Interfaces": "[0.1.1-preview.0.24, )" + } + }, + "Speckle.Core": { + "type": "Project", + "dependencies": { + "GraphQL.Client": "[6.0.0, )", + "Microsoft.CSharp": "[4.7.0, )", + "Microsoft.Data.Sqlite": "[7.0.5, )", + "Polly": "[7.2.3, )", + "Polly.Contrib.WaitAndRetry": "[1.1.1, )", + "Polly.Extensions.Http": "[3.0.0, )", + "Sentry": "[3.33.0, )", + "Sentry.Serilog": "[3.33.0, )", + "Serilog": "[2.12.0, )", + "Serilog.Enrichers.ClientInfo": "[1.3.0, )", + "Serilog.Enrichers.GlobalLogContext": "[3.0.0, )", + "Serilog.Exceptions": "[8.4.0, )", + "Serilog.Sinks.Console": "[4.1.0, )", + "Serilog.Sinks.Seq": "[5.2.2, )", + "SerilogTimings": "[3.0.1, )", + "Speckle.Newtonsoft.Json": "[13.0.2, )", + "System.DoubleNumerics": "[3.1.3, )" + } + }, + "Speckle.Objects": { + "type": "Project", + "dependencies": { + "Speckle.Core": "[2.0.999-local, )" + } + } + } + } +} \ No newline at end of file diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common/IRootElementProvider.cs b/DUI3-DX/Sdk/Speckle.Converters.Common/IRootElementProvider.cs new file mode 100644 index 0000000000..e183c154af --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Converters.Common/IRootElementProvider.cs @@ -0,0 +1,6 @@ +namespace Speckle.Converters.Common; + +public interface IRootElementProvider +{ + Type GetRootType(); +} diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common/LegacyRootToSpeckleConverter.cs b/DUI3-DX/Sdk/Speckle.Converters.Common/LegacyRootToSpeckleConverter.cs new file mode 100644 index 0000000000..34cd5576a2 --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Converters.Common/LegacyRootToSpeckleConverter.cs @@ -0,0 +1,37 @@ +using Speckle.Autofac.DependencyInjection; +using Speckle.Converters.Common.Objects; +using Speckle.Core.Models; + +namespace Speckle.Converters.Common; + +public class LegacyRootToSpeckleConverter : IRootToSpeckleConverter +{ + private readonly IFactory _toSpeckle; + + public LegacyRootToSpeckleConverter(IFactory toSpeckle) + { + _toSpeckle = toSpeckle; + } + + public Base Convert(object target) + { + Type type = target.GetType(); + try + { + var objectConverter = _toSpeckle.ResolveInstance(type.Name); //poc: would be nice to have supertypes resolve + + if (objectConverter == null) + { + throw new NotSupportedException($"No conversion found for {type.Name}"); + } + var convertedObject = objectConverter.Convert(target); + + return convertedObject; + } + catch (SpeckleConversionException e) + { + Console.WriteLine(e); + throw; // Just rethrowing for now, Logs may be needed here. + } + } +} diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common/RootConvertManager.cs b/DUI3-DX/Sdk/Speckle.Converters.Common/RootConvertManager.cs new file mode 100644 index 0000000000..4ae930fa1c --- /dev/null +++ b/DUI3-DX/Sdk/Speckle.Converters.Common/RootConvertManager.cs @@ -0,0 +1,42 @@ +using Speckle.Autofac.DependencyInjection; +using Speckle.Converters.Common.Objects; +using Speckle.Core.Models; +using Speckle.InterfaceGenerator; + +namespace Speckle.Converters.Common; + +[GenerateAutoInterface] +public class RootConvertManager : IRootConvertManager +{ + private readonly IFactory _toSpeckle; + + public RootConvertManager(IFactory toSpeckle) + { + _toSpeckle = toSpeckle; + } + + public Type GetTargetType(object target) => target.GetType(); + + public bool IsSubClass(Type baseType, Type childType) => baseType.IsAssignableFrom(childType); + + public Base Convert(Type type, object obj) + { + try + { + var objectConverter = _toSpeckle.ResolveInstance(type.Name); //poc: would be nice to have supertypes resolve + + if (objectConverter == null) + { + throw new NotSupportedException($"No conversion found for {type.Name}"); + } + var convertedObject = objectConverter.Convert(obj); + + return convertedObject; + } + catch (SpeckleConversionException e) + { + Console.WriteLine(e); + throw; // Just rethrowing for now, Logs may be needed here. + } + } +} diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common/RootToSpeckleConverter.cs b/DUI3-DX/Sdk/Speckle.Converters.Common/RootToSpeckleConverter.cs index 04d87e8349..fac0af321d 100644 --- a/DUI3-DX/Sdk/Speckle.Converters.Common/RootToSpeckleConverter.cs +++ b/DUI3-DX/Sdk/Speckle.Converters.Common/RootToSpeckleConverter.cs @@ -1,5 +1,3 @@ -using Speckle.Autofac.DependencyInjection; -using Speckle.Converters.Common.Objects; using Speckle.Core.Models; using Speckle.InterfaceGenerator; using Speckle.Revit.Interfaces; @@ -9,40 +7,41 @@ namespace Speckle.Converters.Common; [GenerateAutoInterface] public class RootToSpeckleConverter : IRootToSpeckleConverter { - private readonly IFactory _toSpeckle; + private readonly IRootConvertManager _rootConvertManager; private readonly IProxyMapper _proxyMapper; + private readonly IRootElementProvider _rootElementProvider; - public RootToSpeckleConverter(IFactory toSpeckle, IProxyMapper proxyMapper) + private readonly Type _revitElementType; + + public RootToSpeckleConverter( + IProxyMapper proxyMapper, + IRootConvertManager rootConvertManager, + IRootElementProvider rootElementProvider + ) { - _toSpeckle = toSpeckle; _proxyMapper = proxyMapper; + _rootConvertManager = rootConvertManager; + _rootElementProvider = rootElementProvider; + _revitElementType = _proxyMapper.GetHostTypeFromMappedType(_rootElementProvider.GetRootType()).NotNull(); } public Base Convert(object target) { - Type revitType = target.GetType(); + Type revitType = _rootConvertManager.GetTargetType(target); var wrapper = _proxyMapper.WrapIfExists(revitType, target); if (wrapper == null) { - throw new NotSupportedException($"No wrapper found for Revit type: {revitType.Name}"); - } - var (wrappedType, wrappedObject) = wrapper.Value; - try - { - var objectConverter = _toSpeckle.ResolveInstance(wrappedType.Name); //poc: would be nice to have supertypes resolve - - if (objectConverter == null) + //try to fallback to element type + if (_rootConvertManager.IsSubClass(_revitElementType, revitType)) { - throw new NotSupportedException($"No conversion found for {wrappedType.Name}"); + return _rootConvertManager.Convert( + _rootElementProvider.GetRootType(), + _proxyMapper.CreateProxy(_rootElementProvider.GetRootType(), target) + ); } - var convertedObject = objectConverter.Convert(wrappedObject); - - return convertedObject; - } - catch (SpeckleConversionException e) - { - Console.WriteLine(e); - throw; // Just rethrowing for now, Logs may be needed here. + throw new NotSupportedException($"No wrapper found for Revit type: {revitType.Name}"); } + var (wrappedType, wrappedObject) = wrapper; + return _rootConvertManager.Convert(wrappedType, wrappedObject); } } diff --git a/DUI3-DX/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj b/DUI3-DX/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj index 761f021575..07793ee159 100644 --- a/DUI3-DX/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj +++ b/DUI3-DX/Sdk/Speckle.Converters.Common/Speckle.Converters.Common.csproj @@ -3,12 +3,13 @@ netstandard2.0 - - - + + + +