From 6f03aa8678d1b16d3a6294b398c71048ad6ae70b Mon Sep 17 00:00:00 2001 From: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com> Date: Mon, 17 Feb 2025 16:35:26 +0000 Subject: [PATCH] Jedd's IFC improvements (#510) * ifc safe * reverted LibraryImport as it would need more testing * IFC app ids --- .../Speckle.Importers.Ifc.Tester2/Program.cs | 33 ++ .../Speckle.Importers.Ifc.Tester2/Sender.cs | 48 +++ .../Speckle.Importers.Ifc.Tester2.csproj | 11 + .../packages.lock.json | 308 ++++++++++++++++++ .../Converters/GeometryConverter.cs | 10 +- .../Converters/GraphConverter.cs | 8 +- .../Converters/MeshConverter.cs | 63 ++-- .../Converters/NodeConverter.cs | 4 +- Importers/Ifc/Speckle.Importers.Ifc/Import.cs | 7 +- .../Speckle.Importers.Ifc/Native/WebIfc.cs | 5 +- .../ServiceRegistration.cs | 2 + .../Services/RenderMaterialProxyManager.cs | 27 ++ .../Speckle.Importers.Ifc/Types/IfcColor.cs | 4 +- .../Speckle.Importers.Ifc/Types/IfcFactory.cs | 2 +- .../Types/IfcGeometry.cs | 2 +- .../Speckle.Importers.Ifc/Types/IfcLine.cs | 2 +- .../Speckle.Importers.Ifc/Types/IfcMesh.cs | 39 ++- .../Speckle.Importers.Ifc/Types/IfcModel.cs | 2 +- .../Speckle.Importers.Ifc/Types/IfcVertex.cs | 6 +- Local.sln | 8 + Speckle.Connectors.sln | 8 + Speckle.Connectors.sln.DotSettings | 1 + 22 files changed, 553 insertions(+), 47 deletions(-) create mode 100644 Importers/Ifc/Speckle.Importers.Ifc.Tester2/Program.cs create mode 100644 Importers/Ifc/Speckle.Importers.Ifc.Tester2/Sender.cs create mode 100644 Importers/Ifc/Speckle.Importers.Ifc.Tester2/Speckle.Importers.Ifc.Tester2.csproj create mode 100644 Importers/Ifc/Speckle.Importers.Ifc.Tester2/packages.lock.json create mode 100644 Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs diff --git a/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Program.cs b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Program.cs new file mode 100644 index 000000000..74cc8541d --- /dev/null +++ b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Program.cs @@ -0,0 +1,33 @@ +using Ara3D.Utils; +using Microsoft.Extensions.DependencyInjection; +using Speckle.Importers.Ifc; +using Speckle.Importers.Ifc.Ara3D.IfcParser; +using Speckle.Importers.Ifc.Converters; +using Speckle.Importers.Ifc.Tester2; +using Speckle.Importers.Ifc.Types; +using Speckle.Objects.Geometry; +using Speckle.Sdk.Host; +using Speckle.Sdk.Models; + +// Settings +var filePath = new FilePath(@"C:\Users\Jedd\Desktop\231110AC11-Institute-Var-2-IFC.ifc"); +const string PROJECT_ID = "f3a42bdf24"; + +// Setup +TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); + +var serviceCollection = new ServiceCollection(); +serviceCollection.AddIFCImporter(); +serviceCollection.AddSingleton(); +var serviceProvider = serviceCollection.BuildServiceProvider(); + +// Convert IFC to Speckle Objects +var ifcFactory = serviceProvider.GetRequiredService(); +var model = ifcFactory.Open(filePath); +var graph = IfcGraph.Load(new FilePath(filePath)); +var converter = serviceProvider.GetRequiredService(); +var b = converter.Convert(model, graph); + +//Send Speckle Objects to server +var sender = serviceProvider.GetRequiredService(); +await sender.Send(b, PROJECT_ID); diff --git a/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Sender.cs b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Sender.cs new file mode 100644 index 000000000..62f83d600 --- /dev/null +++ b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Sender.cs @@ -0,0 +1,48 @@ +using Speckle.Sdk.Api; +using Speckle.Sdk.Api.GraphQL.Inputs; +using Speckle.Sdk.Api.GraphQL.Models; +using Speckle.Sdk.Common; +using Speckle.Sdk.Credentials; +using Speckle.Sdk.Models; +using Version = Speckle.Sdk.Api.GraphQL.Models.Version; + +namespace Speckle.Importers.Ifc.Tester2; + +public class Sender(IClientFactory clientFactory, IAccountManager accountManager, IOperations operations) +{ + public const string MODEL_NAME = "IFC Import"; + + public async Task Send(Base rootObject, string projectId, CancellationToken cancellationToken = default) + { + var account = accountManager.GetDefaultAccount().NotNull(); + using var client = clientFactory.Create(account); + + var res = await operations.Send2( + new(account.serverInfo.url), + projectId, + account.token, + rootObject, + null, + cancellationToken + ); + + var t = await GetOrCreateIfcModel(client, projectId); + + CreateVersionInput input = new(res.RootId, t.id, projectId); + return await client.Version.Create(input, cancellationToken); + } + + public async Task GetOrCreateIfcModel(Client client, string projectId) + { + ProjectModelsFilter filter = new(null, null, null, null, MODEL_NAME, null); + + var existing = await client.Model.GetModels(projectId, 1, modelsFilter: filter); + if (existing.items.Count != 0) + { + return existing.items[0]; + } + + CreateModelInput input = new(MODEL_NAME, null, projectId); + return await client.Model.Create(input); + } +} diff --git a/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Speckle.Importers.Ifc.Tester2.csproj b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Speckle.Importers.Ifc.Tester2.csproj new file mode 100644 index 000000000..1cf67660b --- /dev/null +++ b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/Speckle.Importers.Ifc.Tester2.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + + + + + + diff --git a/Importers/Ifc/Speckle.Importers.Ifc.Tester2/packages.lock.json b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/packages.lock.json new file mode 100644 index 000000000..db24bd368 --- /dev/null +++ b/Importers/Ifc/Speckle.Importers.Ifc.Tester2/packages.lock.json @@ -0,0 +1,308 @@ +{ + "version": 2, + "dependencies": { + "net8.0": { + "Microsoft.NETFramework.ReferenceAssemblies": { + "type": "Direct", + "requested": "[1.0.3, )", + "resolved": "1.0.3", + "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", + "dependencies": { + "Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3" + } + }, + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "8.0.0", + "Microsoft.SourceLink.Common": "8.0.0" + } + }, + "PolySharp": { + "type": "Direct", + "requested": "[1.14.1, )", + "resolved": "1.14.1", + "contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ==" + }, + "Speckle.InterfaceGenerator": { + "type": "Direct", + "requested": "[0.9.6, )", + "resolved": "0.9.6", + "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" + }, + "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.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.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" + }, + "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.Configuration": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "2.2.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.2.0" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "2.2.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw==" + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.Primitives": "2.2.0", + "System.ComponentModel.Annotations": "4.5.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==", + "dependencies": { + "System.Memory": "4.5.1", + "System.Runtime.CompilerServices.Unsafe": "4.5.1" + } + }, + "Microsoft.NETFramework.ReferenceAssemblies.net461": { + "type": "Transitive", + "resolved": "1.0.3", + "contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA==" + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" + }, + "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.e_sqlite3": "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.e_sqlite3": { + "type": "Transitive", + "resolved": "2.1.4", + "contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.4" + } + }, + "System.ComponentModel.Annotations": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" + }, + "System.Reactive": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" + }, + "speckle.importers.ifc": { + "type": "Project", + "dependencies": { + "Ara3D.Buffers": "[1.4.5, )", + "Ara3D.Logging": "[1.4.5, )", + "Ara3D.Utils": "[1.4.5, )", + "Microsoft.Extensions.DependencyInjection": "[2.2.0, )", + "Speckle.Objects": "[3.1.0-dev.255, )", + "Speckle.Sdk": "[3.1.0-dev.255, )" + } + }, + "Ara3D.Buffers": { + "type": "CentralTransitive", + "requested": "[1.4.5, )", + "resolved": "1.4.5", + "contentHash": "SKcQqgtXukyHTlTKFPCaUW4spSkue3XfBU/GmoA7KhH6H995v6TbJxtqjs0EfSgnXEkajL8U7X1NqktScRozXw==", + "dependencies": { + "System.Memory": "4.5.5" + } + }, + "Ara3D.Logging": { + "type": "CentralTransitive", + "requested": "[1.4.5, )", + "resolved": "1.4.5", + "contentHash": "7HPCe5Dq21JoOBF1iclk9H37XFCoB2ZzCPqTMNgdg4PWFvuRsofNbiuMdiE/HKgMHCVhy1C5opB2KwDKcO7Axw==", + "dependencies": { + "Ara3D.Utils": "1.4.5" + } + }, + "Ara3D.Utils": { + "type": "CentralTransitive", + "requested": "[1.4.5, )", + "resolved": "1.4.5", + "contentHash": "yba/E7PpbWP0+RDp+KbKw/vBXnXBSIheScdpVKuDnr8ytRg8pZ2Jd6nwKES+G0FcVEB9PeOVmEW7SGrFvAwRCg==" + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "CentralTransitive", + "requested": "[2.2.0, )", + "resolved": "2.2.0", + "contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0" + } + }, + "Microsoft.Extensions.Logging": { + "type": "CentralTransitive", + "requested": "[2.2.0, )", + "resolved": "2.2.0", + "contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==", + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "2.2.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0", + "Microsoft.Extensions.Logging.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "CentralTransitive", + "requested": "[2.2.0, )", + "resolved": "2.2.0", + "contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A==" + }, + "Speckle.DoubleNumerics": { + "type": "CentralTransitive", + "requested": "[4.1.0, )", + "resolved": "4.0.1", + "contentHash": "MzEQ1Im0zTja+tEsdRIk/WlPiKqb22NmTOJcR1ZKm/mz46pezyyID3/wRz6vJUELMpSLnG7LhsxBL+nxbr7V0w==" + }, + "Speckle.Objects": { + "type": "CentralTransitive", + "requested": "[3.1.0-dev.255, )", + "resolved": "3.1.0-dev.255", + "contentHash": "0S9YVdu5nx7SYS0y5Gq1nwCbxfYB2UxsUUCskaGmzRAm+QzHGqCLYHgadz7Sw5mNAF3bOTLVrOYMzyLAWFWxJA==", + "dependencies": { + "Speckle.Sdk": "3.1.0-dev.255" + } + }, + "Speckle.Sdk": { + "type": "CentralTransitive", + "requested": "[3.1.0-dev.255, )", + "resolved": "3.1.0-dev.255", + "contentHash": "TsFpIv8ipvOD/r0se1XmcNPo7t5dWVadwV32Z6vUqoW3s94VIE54/ZTHNkRCEYHFhfOyTcFfbLegiei+0D13bQ==", + "dependencies": { + "GraphQL.Client": "6.0.0", + "Microsoft.CSharp": "4.7.0", + "Microsoft.Data.Sqlite": "[7.0.5]", + "Microsoft.Extensions.DependencyInjection.Abstractions": "[2.2.0]", + "Microsoft.Extensions.Logging": "[2.2.0]", + "Speckle.DoubleNumerics": "4.0.1", + "Speckle.Newtonsoft.Json": "13.0.2", + "Speckle.Sdk.Dependencies": "3.1.0-dev.255" + } + }, + "Speckle.Sdk.Dependencies": { + "type": "CentralTransitive", + "requested": "[3.1.0-dev.255, )", + "resolved": "3.1.0-dev.255", + "contentHash": "koFeWc/EB2XrMH2aKl2Hqwrqk/fAGYEVKgxFlFpnEAsbZf7Kk57gBQ3ViV5l6X9vqMHGWFc4dWUp24diq/XPtQ==" + } + } + } +} \ No newline at end of file diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Converters/GeometryConverter.cs b/Importers/Ifc/Speckle.Importers.Ifc/Converters/GeometryConverter.cs index c59ad90b9..e4215e3e1 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Converters/GeometryConverter.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Converters/GeometryConverter.cs @@ -1,20 +1,20 @@ using Speckle.Importers.Ifc.Types; using Speckle.InterfaceGenerator; -using Speckle.Sdk.Models.Collections; +using Speckle.Sdk.Models; namespace Speckle.Importers.Ifc.Converters; [GenerateAutoInterface] public class GeometryConverter(IMeshConverter meshConverter) : IGeometryConverter { - public Collection Convert(IfcGeometry geometry) + public IList Convert(IfcGeometry geometry) { - var c = new Collection(); + List ret = new(); foreach (var mesh in geometry.GetMeshes()) { - c.elements.Add(meshConverter.Convert(mesh)); + ret.Add(meshConverter.Convert(mesh)); } - return c; + return ret; } } diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs b/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs index 3c6c3f88d..fe5b4d910 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Converters/GraphConverter.cs @@ -1,4 +1,5 @@ using Speckle.Importers.Ifc.Ara3D.IfcParser; +using Speckle.Importers.Ifc.Services; using Speckle.Importers.Ifc.Types; using Speckle.InterfaceGenerator; using Speckle.Sdk.Models; @@ -7,13 +8,18 @@ using Speckle.Sdk.Models.Collections; namespace Speckle.Importers.Ifc.Converters; [GenerateAutoInterface] -public class GraphConverter(INodeConverter nodeConverter) : IGraphConverter +public class GraphConverter(INodeConverter nodeConverter, IRenderMaterialProxyManager proxyManager) : IGraphConverter { public Base Convert(IfcModel model, IfcGraph graph) { var collection = new Collection(); + var children = graph.GetSources().Select(x => nodeConverter.Convert(model, x)).ToList(); collection.elements = children; + + //Grabing materials from ProxyManager + collection["renderMaterialProxies"] = proxyManager.RenderMaterialProxies.Values.ToList(); + return collection; } } diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Converters/MeshConverter.cs b/Importers/Ifc/Speckle.Importers.Ifc/Converters/MeshConverter.cs index 961bc3297..79a5f6bc6 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Converters/MeshConverter.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Converters/MeshConverter.cs @@ -1,31 +1,35 @@ +using System.Drawing; +using Speckle.Importers.Ifc.Services; using Speckle.Importers.Ifc.Types; using Speckle.InterfaceGenerator; using Speckle.Objects.Geometry; +using Speckle.Objects.Other; namespace Speckle.Importers.Ifc.Converters; [GenerateAutoInterface] -public class MeshConverter : IMeshConverter +public class MeshConverter(IRenderMaterialProxyManager renderMaterialManager) : IMeshConverter { - public unsafe Mesh Convert(IfcMesh mesh) + public Mesh Convert(IfcMesh mesh) { - var m = (double*)mesh.Transform; - var vp = mesh.GetVertices(); - var ip = mesh.GetIndexes(); + var m = mesh.Transform; + var vp = mesh.Vertices; + var ip = mesh.Indices; - var vertices = new List(mesh.VertexCount * 3); - for (var i = 0; i < mesh.VertexCount; i++) + var vertices = new List(vp.Length * 3); + foreach (var vertex in vp) { - var x = vp[i].PX; - var y = vp[i].PY; - var z = vp[i].PZ; + var x = vertex.PX; + var y = vertex.PY; + var z = vertex.PZ; + vertices.Add(m[0] * x + m[4] * y + m[8] * z + m[12]); vertices.Add(-(m[2] * x + m[6] * y + m[10] * z + m[14])); vertices.Add(m[1] * x + m[5] * y + m[9] * z + m[13]); } - var faces = new List(mesh.IndexCount * 4); - for (var i = 0; i < mesh.IndexCount; i += 3) + var faces = new List(ip.Length * 4); + for (var i = 0; i < ip.Length; i += 3) { var a = ip[i]; var b = ip[i + 1]; @@ -36,14 +40,35 @@ public class MeshConverter : IMeshConverter faces.Add(c); } - var color = mesh.GetColor(); - List colors = [(int)(color->A * 255), (int)(color->R * 255), (int)(color->G * 255), (int)(color->B * 255),]; - return new Mesh() + RenderMaterial renderMaterial = ConvertRenderMaterial(mesh); + Mesh converted = + new() + { + applicationId = Guid.NewGuid().ToString(), + vertices = vertices, + faces = faces, + units = "m", + }; + + renderMaterialManager.AddMeshMapping(renderMaterial, converted); + + return converted; + } + + private static RenderMaterial ConvertRenderMaterial(IfcMesh mesh) + { + var color = mesh.Color; + var diffuse = Color.FromArgb(1, To8BitValue(color.R), To8BitValue(color.G), To8BitValue(color.B)); + + var name = $"IFC_MATERIAL:{(color.A, color.R, color.G, color.B).GetHashCode()}"; + + return new RenderMaterial() { - colors = colors, - vertices = vertices, - faces = faces, - units = "m", + applicationId = name, + name = name, + diffuse = diffuse.ToArgb(), + opacity = color.A }; + static int To8BitValue(double value) => (int)(value * 255); } } diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Converters/NodeConverter.cs b/Importers/Ifc/Speckle.Importers.Ifc/Converters/NodeConverter.cs index f9b246d27..b7307a9be 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Converters/NodeConverter.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Converters/NodeConverter.cs @@ -37,8 +37,8 @@ public class NodeConverter(IGeometryConverter geometryConverter) : INodeConverte if (geo != null) { var c = geometryConverter.Convert(geo); - if (c.elements.Count > 0) - b["@displayValue"] = c.elements; + if (c.Count > 0) + b["@displayValue"] = c; } // Create the children diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Import.cs b/Importers/Ifc/Speckle.Importers.Ifc/Import.cs index 1f5e6a5ce..6a96a7923 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Import.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Import.cs @@ -39,10 +39,15 @@ public static class Import { TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); var serviceCollection = new ServiceCollection(); + serviceCollection.AddIFCImporter(); + return serviceCollection.BuildServiceProvider(); + } + + public static void AddIFCImporter(this ServiceCollection serviceCollection) + { serviceCollection.AddSpeckleSdk(HostApplications.Other, HostAppVersion.v2024, "IFC-Importer"); serviceCollection.AddSpeckleWebIfc(); serviceCollection.AddMatchingInterfacesAsTransient(Assembly.GetExecutingAssembly()); - return serviceCollection.BuildServiceProvider(); } public static async Task Ifc( diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Native/WebIfc.cs b/Importers/Ifc/Speckle.Importers.Ifc/Native/WebIfc.cs index 52f182185..0775d7605 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Native/WebIfc.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Native/WebIfc.cs @@ -4,12 +4,11 @@ using System.Runtime.InteropServices; namespace Speckle.Importers.Ifc.Native; [SuppressMessage("Globalization", "CA2101:Specify marshaling for P/Invoke string arguments")] -[SuppressMessage("Interoperability", "CA1401:P/Invokes should not be visible")] [SuppressMessage("Security", "CA5393:Do not use unsafe DllImportSearchPath value")] -public static class WebIfc +internal static class WebIfc { #if WINDOWS - private const string DllName = "web-ifc.dll"; + private const string DllName = "Native/web-ifc.dll"; private const CharSet Set = CharSet.Ansi; #else private const string DllName = "libweb-ifc.so"; diff --git a/Importers/Ifc/Speckle.Importers.Ifc/ServiceRegistration.cs b/Importers/Ifc/Speckle.Importers.Ifc/ServiceRegistration.cs index 129d398d6..9b8c9b4a0 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/ServiceRegistration.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/ServiceRegistration.cs @@ -1,6 +1,7 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Speckle.Importers.Ifc.Services; using Speckle.Importers.Ifc.Types; using Speckle.Sdk; @@ -11,6 +12,7 @@ public static class ServiceRegistration public static void AddSpeckleWebIfc(this IServiceCollection services) { services.AddSingleton(); + services.AddSingleton(); } public static IServiceCollection AddMatchingInterfacesAsTransient( diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs b/Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs new file mode 100644 index 000000000..643401f43 --- /dev/null +++ b/Importers/Ifc/Speckle.Importers.Ifc/Services/RenderMaterialProxyManager.cs @@ -0,0 +1,27 @@ +using Speckle.InterfaceGenerator; +using Speckle.Objects.Geometry; +using Speckle.Objects.Other; +using Speckle.Sdk.Common; + +namespace Speckle.Importers.Ifc.Services; + +[GenerateAutoInterface] +public sealed class RenderMaterialProxyManager : IRenderMaterialProxyManager +{ + public Dictionary RenderMaterialProxies { get; } = new(); + + public void AddMeshMapping(RenderMaterial renderMaterial, Mesh mesh) + { + string materialId = renderMaterial.applicationId.NotNull(); + string meshId = mesh.applicationId.NotNull(); + + if (RenderMaterialProxies.TryGetValue(materialId, out RenderMaterialProxy? proxy)) + { + proxy.objects.Add(meshId); + } + else + { + RenderMaterialProxies.Add(materialId, new() { objects = [meshId], value = renderMaterial, }); + } + } +} diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcColor.cs b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcColor.cs index 508a57d48..9a99790b2 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcColor.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcColor.cs @@ -3,9 +3,9 @@ using System.Runtime.InteropServices; namespace Speckle.Importers.Ifc.Types; [StructLayout(LayoutKind.Sequential, Pack = 1)] -public struct IfcColor +public readonly struct IfcColor { - public double R, + public readonly double R, G, B, A; diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcFactory.cs b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcFactory.cs index 567453924..3689ff4ed 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcFactory.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcFactory.cs @@ -3,7 +3,7 @@ using Speckle.InterfaceGenerator; namespace Speckle.Importers.Ifc.Types; [GenerateAutoInterface] -public class IfcFactory : IIfcFactory +public sealed class IfcFactory : IIfcFactory { //probably never disposing this private static readonly IntPtr _ptr = Importers.Ifc.Native.WebIfc.InitializeApi(); diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcGeometry.cs b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcGeometry.cs index 099d94618..8cc5b48dd 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcGeometry.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcGeometry.cs @@ -1,6 +1,6 @@ namespace Speckle.Importers.Ifc.Types; -public class IfcGeometry(IntPtr geometry) +public sealed class IfcGeometry(IntPtr geometry) { public IfcMesh GetMesh(int i) => new(Importers.Ifc.Native.WebIfc.GetMesh(geometry, i)); diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcLine.cs b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcLine.cs index a3c2306f1..12ddb010c 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcLine.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcLine.cs @@ -1,6 +1,6 @@ namespace Speckle.Importers.Ifc.Types; -public class IfcLine(IntPtr line) +public sealed class IfcLine(IntPtr line) { public uint Id => Importers.Ifc.Native.WebIfc.GetLineId(line); public IfcSchemaType Type => (IfcSchemaType)Importers.Ifc.Native.WebIfc.GetLineType(line); diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcMesh.cs b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcMesh.cs index e0b34e73c..00543cc0f 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcMesh.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcMesh.cs @@ -1,15 +1,40 @@ +using System.Runtime.InteropServices; +using Speckle.Importers.Ifc.Native; + namespace Speckle.Importers.Ifc.Types; -public class IfcMesh(IntPtr mesh) +public sealed class IfcMesh(IntPtr mesh) { - public int VertexCount => Importers.Ifc.Native.WebIfc.GetNumVertices(mesh); + public int VerticesCount => WebIfc.GetNumVertices(mesh); - public unsafe IfcVertex* GetVertices() => (IfcVertex*)Importers.Ifc.Native.WebIfc.GetVertices(mesh); + public unsafe ReadOnlySpan Vertices + { + get + { + IfcVertex* ptr = (IfcVertex*)WebIfc.GetVertices(mesh); + return new ReadOnlySpan(ptr, VerticesCount); + } + } - public IntPtr Transform => Importers.Ifc.Native.WebIfc.GetTransform(mesh); - public int IndexCount => Importers.Ifc.Native.WebIfc.GetNumIndices(mesh); + public unsafe ReadOnlySpan Transform + { + get + { + double* ptr = (double*)WebIfc.GetTransform(mesh); + return new ReadOnlySpan(ptr, 16); + } + } - public unsafe int* GetIndexes() => (int*)Importers.Ifc.Native.WebIfc.GetIndices(mesh); + public int IndicesCount => WebIfc.GetNumIndices(mesh); - public unsafe IfcColor* GetColor() => (IfcColor*)Importers.Ifc.Native.WebIfc.GetColor(mesh); + public unsafe ReadOnlySpan Indices + { + get + { + var ptr = (int*)WebIfc.GetIndices(mesh); + return new ReadOnlySpan(ptr, IndicesCount); + } + } + + public IfcColor Color => Marshal.PtrToStructure(WebIfc.GetColor(mesh)); } diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcModel.cs b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcModel.cs index 6da106e9b..06184a04d 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcModel.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcModel.cs @@ -1,6 +1,6 @@ namespace Speckle.Importers.Ifc.Types; -public class IfcModel(IntPtr model) +public sealed class IfcModel(IntPtr model) { public int GetNumGeometries() => Importers.Ifc.Native.WebIfc.GetNumGeometries(model); diff --git a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcVertex.cs b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcVertex.cs index c4b28722e..b227f1f52 100644 --- a/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcVertex.cs +++ b/Importers/Ifc/Speckle.Importers.Ifc/Types/IfcVertex.cs @@ -3,12 +3,12 @@ using System.Runtime.InteropServices; namespace Speckle.Importers.Ifc.Types; [StructLayout(LayoutKind.Sequential, Pack = 1)] -public struct IfcVertex +public readonly struct IfcVertex { - public double PX, + public readonly double PX, PY, PZ; - public double NX, + public readonly double NX, NY, NZ; } diff --git a/Local.sln b/Local.sln index ba46e6228..a1f667bf8 100644 --- a/Local.sln +++ b/Local.sln @@ -269,6 +269,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Importers.Ifc", "Im EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Importers.Ifc.Tester", "Importers\Ifc\Speckle.Importers.Ifc.Tester\Speckle.Importers.Ifc.Tester.csproj", "{B3B126CA-A419-48D1-B117-6DEE1DE1AFAD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Importers.Ifc.Tester2", "Importers\Ifc\Speckle.Importers.Ifc.Tester2\Speckle.Importers.Ifc.Tester2.csproj", "{867DC1A5-A886-4F49-8665-793EB9832F9E}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Connectors.Common.Tests", "Sdk\Speckle.Connectors.Common.Tests\Speckle.Connectors.Common.Tests.csproj", "{C19C3EDF-D95D-4D22-9949-D99F91447AE7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Common.MeshTriangulation", "Sdk\Speckle.Common.MeshTriangulation\Speckle.Common.MeshTriangulation.csproj", "{20BB9687-2C92-44E9-9E2F-9D2F45641354}" @@ -694,6 +695,12 @@ Global {B3B126CA-A419-48D1-B117-6DEE1DE1AFAD}.Local|Any CPU.Build.0 = Local|Any CPU {B3B126CA-A419-48D1-B117-6DEE1DE1AFAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {B3B126CA-A419-48D1-B117-6DEE1DE1AFAD}.Release|Any CPU.Build.0 = Release|Any CPU + {867DC1A5-A886-4F49-8665-793EB9832F9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {867DC1A5-A886-4F49-8665-793EB9832F9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {867DC1A5-A886-4F49-8665-793EB9832F9E}.Local|Any CPU.ActiveCfg = Debug|Any CPU + {867DC1A5-A886-4F49-8665-793EB9832F9E}.Local|Any CPU.Build.0 = Debug|Any CPU + {867DC1A5-A886-4F49-8665-793EB9832F9E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {867DC1A5-A886-4F49-8665-793EB9832F9E}.Release|Any CPU.Build.0 = Release|Any CPU {C19C3EDF-D95D-4D22-9949-D99F91447AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C19C3EDF-D95D-4D22-9949-D99F91447AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU {C19C3EDF-D95D-4D22-9949-D99F91447AE7}.Local|Any CPU.ActiveCfg = Local|Any CPU @@ -829,6 +836,7 @@ Global {0EF6C4D6-AC76-408F-8D32-2F9DA8006077} = {24750B06-C90D-43B1-B2E4-088D531D6748} {9FD99F9B-8D50-4C7A-B3A6-22E28AB5F26B} = {0EF6C4D6-AC76-408F-8D32-2F9DA8006077} {B3B126CA-A419-48D1-B117-6DEE1DE1AFAD} = {0EF6C4D6-AC76-408F-8D32-2F9DA8006077} + {867DC1A5-A886-4F49-8665-793EB9832F9E} = {0EF6C4D6-AC76-408F-8D32-2F9DA8006077} {C19C3EDF-D95D-4D22-9949-D99F91447AE7} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} {20BB9687-2C92-44E9-9E2F-9D2F45641354} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} EndGlobalSection diff --git a/Speckle.Connectors.sln b/Speckle.Connectors.sln index cc65052a7..17526d835 100644 --- a/Speckle.Connectors.sln +++ b/Speckle.Connectors.sln @@ -277,6 +277,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Importers", "Importers", "{ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Importers.Ifc.Tester", "Importers\Ifc\Speckle.Importers.Ifc.Tester\Speckle.Importers.Ifc.Tester.csproj", "{FCD6CB79-6B41-4448-99E1-787408AD24B0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Importers.Ifc.Tester2", "Importers\Ifc\Speckle.Importers.Ifc.Tester2\Speckle.Importers.Ifc.Tester2.csproj", "{17FB6920-DF63-4D94-86A4-F1619D501C6D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Connectors.Common.Tests", "Sdk\Speckle.Connectors.Common.Tests\Speckle.Connectors.Common.Tests.csproj", "{F86DFA8A-E2E0-4EBE-9BAF-72AE2698EDC6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Common.MeshTriangulation", "Sdk\Speckle.Common.MeshTriangulation\Speckle.Common.MeshTriangulation.csproj", "{B740A025-1035-4A75-865B-7825857D610C}" @@ -684,6 +685,12 @@ Global {FCD6CB79-6B41-4448-99E1-787408AD24B0}.Local|Any CPU.Build.0 = Debug|Any CPU {FCD6CB79-6B41-4448-99E1-787408AD24B0}.Release|Any CPU.ActiveCfg = Release|Any CPU {FCD6CB79-6B41-4448-99E1-787408AD24B0}.Release|Any CPU.Build.0 = Release|Any CPU + {17FB6920-DF63-4D94-86A4-F1619D501C6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17FB6920-DF63-4D94-86A4-F1619D501C6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17FB6920-DF63-4D94-86A4-F1619D501C6D}.Local|Any CPU.ActiveCfg = Debug|Any CPU + {17FB6920-DF63-4D94-86A4-F1619D501C6D}.Local|Any CPU.Build.0 = Debug|Any CPU + {17FB6920-DF63-4D94-86A4-F1619D501C6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17FB6920-DF63-4D94-86A4-F1619D501C6D}.Release|Any CPU.Build.0 = Release|Any CPU {F86DFA8A-E2E0-4EBE-9BAF-72AE2698EDC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F86DFA8A-E2E0-4EBE-9BAF-72AE2698EDC6}.Debug|Any CPU.Build.0 = Debug|Any CPU {F86DFA8A-E2E0-4EBE-9BAF-72AE2698EDC6}.Local|Any CPU.ActiveCfg = Debug|Any CPU @@ -819,6 +826,7 @@ Global {E6B7A640-F85C-41C9-8226-B5310A98822D} = {F93052A6-6937-443F-8F1F-4A967A8A2BEF} {F93052A6-6937-443F-8F1F-4A967A8A2BEF} = {336F0341-5C39-40F7-9377-122FED4E4549} {FCD6CB79-6B41-4448-99E1-787408AD24B0} = {F93052A6-6937-443F-8F1F-4A967A8A2BEF} + {17FB6920-DF63-4D94-86A4-F1619D501C6D} = {F93052A6-6937-443F-8F1F-4A967A8A2BEF} {F86DFA8A-E2E0-4EBE-9BAF-72AE2698EDC6} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} {B740A025-1035-4A75-865B-7825857D610C} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA} EndGlobalSection diff --git a/Speckle.Connectors.sln.DotSettings b/Speckle.Connectors.sln.DotSettings index 3af02c0f3..71bf7f852 100644 --- a/Speckle.Connectors.sln.DotSettings +++ b/Speckle.Connectors.sln.DotSettings @@ -1,4 +1,5 @@  DUI + IFC UI URI \ No newline at end of file