From ff311bc436fdd4e8cff8dd867105c0e34aba60c6 Mon Sep 17 00:00:00 2001 From: connorivy <43247197+connorivy@users.noreply.github.com> Date: Sun, 16 Jul 2023 08:51:17 -0500 Subject: [PATCH] Feat(Tekla) : receive instances in Tekla (#2774) receive instances in Tekla Co-authored-by: Connor Ivy --- ...onnectorBindingsTeklaStructures.Receive.cs | 64 +++-------- .../Models/GraphTraversal/DefaultTraversal.cs | 4 +- .../ConverterTeklaStructures2022.csproj | 4 + .../ConverterTeklaStructures.cs | 43 +++---- Objects/Objects/Other/Instance.cs | 105 ++++++++++-------- 5 files changed, 95 insertions(+), 125 deletions(-) diff --git a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs index 87e7ff7397..fa20e4d68e 100644 --- a/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs +++ b/ConnectorTeklaStructures/ConnectorTeklaStructuresShared/UI/ConnectorBindingsTeklaStructures.Receive.cs @@ -1,4 +1,4 @@ -using DesktopUI2; +using DesktopUI2; using DesktopUI2.Models; using DesktopUI2.Models.Settings; using DesktopUI2.ViewModels; @@ -14,6 +14,7 @@ using System.Linq; using System.Threading.Tasks; using Serilog; +using Speckle.Core.Models.GraphTraversal; namespace Speckle.ConnectorTeklaStructures.UI { @@ -59,9 +60,7 @@ public override async Task ReceiveStream(StreamState state, Progres progress.Update(conversionProgressDict); }; - - var commitObjs = FlattenCommitObject(commitObject, converter); - foreach (var commitObj in commitObjs) + foreach (var commitObj in FlattenCommitObject(commitObject, converter)) { BakeObject(commitObj, state, converter); updateProgressAction?.Invoke(); @@ -94,53 +93,20 @@ private void BakeObject(Base obj, StreamState state, ISpeckleConverter converter } /// - /// Recurses through the commit object and flattens it. + /// Traverses the object graph, returning objects to be converted. /// - /// - /// - /// - private List FlattenCommitObject(object obj, ISpeckleConverter converter) + /// The root object to traverse + /// The converter instance, used to define what objects are convertable + /// A flattened list of objects to be converted ToNative + private IEnumerable FlattenCommitObject(Base obj, ISpeckleConverter converter) { - List objects = new List(); - - - if (obj is Base @base) - { - if (converter.CanConvertToNative(@base)) - { - objects.Add(@base); - - return objects; - } - else - { - foreach (var prop in @base.GetDynamicMembers()) - { - objects.AddRange(FlattenCommitObject(@base[prop], converter)); - } - return objects; - } - } - - if (obj is List list) - { - foreach (var listObj in list) - { - objects.AddRange(FlattenCommitObject(listObj, converter)); - } - return objects; - } - - if (obj is IDictionary dict) - { - foreach (DictionaryEntry kvp in dict) - { - objects.AddRange(FlattenCommitObject(kvp.Value, converter)); - } - return objects; - } - - return objects; + var traverseFunction = DefaultTraversal.CreateTraverseFunc(converter); + + return traverseFunction.Traverse(obj) + .Select(tc => tc.current) + .Where(b => b != null) + .Where(converter.CanConvertToNative) + .Reverse(); } #endregion diff --git a/Core/Core/Models/GraphTraversal/DefaultTraversal.cs b/Core/Core/Models/GraphTraversal/DefaultTraversal.cs index 1bab2a9351..40f5cc0352 100644 --- a/Core/Core/Models/GraphTraversal/DefaultTraversal.cs +++ b/Core/Core/Models/GraphTraversal/DefaultTraversal.cs @@ -74,7 +74,7 @@ public static GraphTraversal CreateBIMTraverseFunc(ISpeckleConverter converter) .When(o => o.speckle_type.Contains("Objects.Structural.Results")) .ContinueTraversing(None); - private static readonly ITraversalRule DefaultRule = TraversalRule + public static readonly ITraversalRule DefaultRule = TraversalRule .NewTraversalRule() .When(_ => true) .ContinueTraversing(Members()); @@ -132,7 +132,7 @@ public static bool HasGeometry(Base x) } [Pure] - internal static IEnumerable None(Base _) + public static IEnumerable None(Base _) { return Enumerable.Empty(); } diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructures2022/ConverterTeklaStructures2022.csproj b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructures2022/ConverterTeklaStructures2022.csproj index 31e254d8fa..300367260d 100644 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructures2022/ConverterTeklaStructures2022.csproj +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructures2022/ConverterTeklaStructures2022.csproj @@ -29,4 +29,8 @@ + + + + diff --git a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs index 581def3f5a..0243f4d28e 100644 --- a/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs +++ b/Objects/Converters/ConverterTeklaStructures/ConverterTeklaStructuresShared/ConverterTeklaStructures.cs @@ -1,15 +1,12 @@ -using Speckle.Core.Kits; +using Objects.Geometry; +using Objects.Other; using Speckle.Core.Kits; -using Speckle.Core.Logging; -using Speckle.Core.Models; using Speckle.Core.Models; using Speckle.Core.Models.Extensions; -using System; +using Speckle.Core.Models.GraphTraversal; using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using Tekla.Structures; using Tekla.Structures.Model; using BE = Objects.BuiltElements; using GE = Objects.Geometry; @@ -67,9 +64,13 @@ public void SetContextDocument(object doc) public bool CanConvertToNative(Base @object) { Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); - if (bool.Parse(recieveModelMesh) == true) + if (bool.TryParse(recieveModelMesh, out var receiveAsMesh) && receiveAsMesh) { - return true; + if (DefaultTraversal.HasDefinition(@object) || DefaultTraversal.HasDisplayValue(@object)) + { + return true; + } + return false; } switch (@object) @@ -128,33 +129,25 @@ public bool CanConvertToSpeckle(object @object) public object ConvertToNative(Base @object) { - Settings.TryGetValue("recieve-objects-mesh", out string recieveModelMesh); - if (bool.Parse(recieveModelMesh) == true) + if (bool.TryParse(recieveModelMesh, out var receiveAsMesh) && receiveAsMesh) { - try + if (@object is Instance instance) + { + MeshToNative(instance, instance.GetTransformedGeometry().Where(t => t is Mesh).Cast().ToList()); + } + else { var bases = BaseExtensions.Flatten(@object); foreach (var @base in bases) { - try - { - List displayValues = new List { }; - var meshes = @base.GetType().GetProperty("displayValue").GetValue(@base) as List; - //dynamic property = propInfo; - //List meshes = (List)property; - MeshToNative(@base, meshes); - } - catch + foreach (var displayAlias in DefaultTraversal.displayValuePropAliases) { + if (@base[displayAlias] is not List meshes) continue; + MeshToNative(@base, meshes); } } - return true; - } - catch - { - } } diff --git a/Objects/Objects/Other/Instance.cs b/Objects/Objects/Other/Instance.cs index 7e8ff4f693..4022a9131a 100644 --- a/Objects/Objects/Other/Instance.cs +++ b/Objects/Objects/Other/Instance.cs @@ -6,6 +6,7 @@ using Objects.Geometry; using Speckle.Core.Kits; using Speckle.Core.Models; +using Speckle.Core.Models.GraphTraversal; using Speckle.Newtonsoft.Json; namespace Objects.Other @@ -33,6 +34,52 @@ protected Instance() { } /// The units of this Instance, should be the same as the instance transform units /// public string units { get; set; } + + // helper method that scans an Instance for all transformable geometry and nested instances + protected virtual IEnumerable GetTransformableGeometry() + { + var displayValueRule = TraversalRule + .NewTraversalRule() + .When(DefaultTraversal.HasDisplayValue) + .ContinueTraversing(_ => DefaultTraversal.displayValueAndElementsPropAliases); + + var instanceRule = TraversalRule.NewTraversalRule() + .When(b => b is Instance instance && instance != null) + .ContinueTraversing(DefaultTraversal.None); + + var traversal = new GraphTraversal(instanceRule, displayValueRule, DefaultTraversal.DefaultRule); + + return traversal + .Traverse(definition) + .Select(tc => tc.current) + .Where(b => b is ITransformable || b is Instance) + .Where(b => b != null); + } + + [SchemaComputed("transformedGeometry")] + public virtual IEnumerable GetTransformedGeometry() + { + return GetTransformableGeometry() + .SelectMany(b => + { + switch (b) + { + case Instance i: + return i.GetTransformedGeometry() + .Select(b => + { + b.TransformTo(transform, out var tranformed); + return tranformed; + }); + case ITransformable bt: + var res = bt.TransformTo(transform, out var transformed); + return res ? new List { transformed } : new(); + default: + return new List(); + } + }) + .Where(b => b != null); + } } /// @@ -89,31 +136,9 @@ public BlockDefinition blockDefinition set => typedDefinition = value; } - [SchemaComputed("transformedGeometry")] - public List GetTransformedGeometry() + protected override IEnumerable GetTransformableGeometry() { - return typedDefinition.geometry - .SelectMany(b => - { - switch (b) - { - case BlockInstance bi: - return bi.GetTransformedGeometry() - ?.Select(b => - { - ITransformable childTransformed = null; - b?.TransformTo(transform, out childTransformed); - return childTransformed; - }); - case ITransformable bt: - var res = bt.TransformTo(transform, out var transformed); - return new List { res ? transformed : null }; - default: - return new List(); - } - }) - .Where(b => b != null) - .ToList(); + return typedDefinition.geometry; } /// @@ -149,36 +174,18 @@ public class RevitInstance : Instance public Base parameters { get; set; } public string elementId { get; set; } - [SchemaComputed("transformedGeometry")] - public List GetTransformedGeometry() + protected override IEnumerable GetTransformableGeometry() { var allChildren = typedDefinition.elements ?? new List(); if (typedDefinition.displayValue.Any()) allChildren.AddRange(typedDefinition.displayValue); + return allChildren; + } - // get transformed definition objs - var transformed = allChildren - .SelectMany(b => - { - switch (b) - { - case RevitInstance ri: - return ri.GetTransformedGeometry() - ?.Select(b => - { - ITransformable childTransformed = null; - b?.TransformTo(transform, out childTransformed); - return childTransformed; - }); - case ITransformable bt: - var res = bt.TransformTo(transform, out var transformed); - return new List { res ? transformed : null }; - default: - return new List(); - } - }) - .Where(b => b != null) - .ToList(); + [SchemaComputed("transformedGeometry")] + public override IEnumerable GetTransformedGeometry() + { + var transformed = base.GetTransformedGeometry().ToList(); // add any dynamically attached elements on this instance var elements = (this["elements"] ?? this["@elements"]) as List;