Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c719cfd66f | |||
| 76ea67af54 | |||
| 12c80e2d40 | |||
| c013953368 | |||
| 92435ce1a1 | |||
| 34457ead0a | |||
| 5e92889825 |
+7
-1
@@ -41,7 +41,13 @@ public static class Consts
|
||||
new("Connectors/Autocad/Speckle.Connectors.Civil3d2025", "net8.0-windows")
|
||||
]
|
||||
),
|
||||
new("tekla-structures", [new("Connectors/Tekla/Speckle.Connector.Tekla2024", "net48")])
|
||||
new(
|
||||
"tekla-structures",
|
||||
[
|
||||
new("Connectors/Tekla/Speckle.Connector.Tekla2023", "net48"),
|
||||
new("Connectors/Tekla/Speckle.Connector.Tekla2024", "net48")
|
||||
]
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ internal sealed class BasicConnectorBindingRevit : IBasicConnectorBinding
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedObjects = senderModelCard.SendFilter.NotNull().IdMap.NotNull().Values;
|
||||
var selectedObjects = senderModelCard.SendFilter.NotNull().SelectedObjectIds;
|
||||
|
||||
elementIds = selectedObjects
|
||||
.Select(uid => ElementIdHelper.GetElementIdFromUniqueId(activeUIDoc.Document, uid))
|
||||
|
||||
@@ -133,18 +133,6 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
|
||||
);
|
||||
|
||||
List<Element> elements = await RefreshElementsOnSender(modelCard.NotNull()).ConfigureAwait(false);
|
||||
|
||||
if (modelCard is SenderModelCard senderModel)
|
||||
{
|
||||
foreach (Element element in elements)
|
||||
{
|
||||
senderModel.SendFilter.NotNull().IdMap.NotNull()[element.Id.ToString()] = element.UniqueId;
|
||||
}
|
||||
await Commands
|
||||
.SetFilterObjectIds(modelCardId, senderModel.SendFilter.NotNull().IdMap.NotNull())
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
List<ElementId> elementIds = elements.Select(el => el.Id).ToList();
|
||||
|
||||
if (elementIds.Count == 0)
|
||||
@@ -202,14 +190,16 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
|
||||
|
||||
if (modelCard.SendFilter is not null && modelCard.SendFilter.IdMap is not null)
|
||||
{
|
||||
var newSelectedObjectIds = new List<string>();
|
||||
foreach (Element element in elements)
|
||||
{
|
||||
modelCard.SendFilter.IdMap[element.Id.ToString()] = element.UniqueId;
|
||||
newSelectedObjectIds.Add(element.UniqueId);
|
||||
}
|
||||
|
||||
// We update the state on the UI SenderModelCard to prevent potential inconsistencies between hostApp IdMap in sendfilters.
|
||||
await Commands
|
||||
.SetFilterObjectIds(modelCard.ModelCardId.NotNull(), modelCard.SendFilter.IdMap)
|
||||
.SetFilterObjectIds(modelCard.ModelCardId.NotNull(), modelCard.SendFilter.IdMap, newSelectedObjectIds)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,10 +118,7 @@ public class RhinoInstanceBaker : IInstanceBaker<List<string>>
|
||||
)
|
||||
{
|
||||
var transform = MatrixToTransform(instanceProxy.transform, instanceProxy.units);
|
||||
|
||||
// POC: having layer creation during instance bake means no render materials!!
|
||||
int layerIndex = _layerBaker.GetAndCreateLayerFromPath(layerCollection, baseLayerName);
|
||||
|
||||
int layerIndex = _layerBaker.GetLayerIndex(layerCollection, baseLayerName);
|
||||
string instanceProxyId = instanceProxy.applicationId ?? instanceProxy.id;
|
||||
|
||||
ObjectAttributes atts = new() { LayerIndex = layerIndex };
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Rhino;
|
||||
using Rhino.DocObjects;
|
||||
using Speckle.Connectors.Common.Operations.Receive;
|
||||
using Speckle.Sdk;
|
||||
using Speckle.Sdk.Models.Collections;
|
||||
using Layer = Rhino.DocObjects.Layer;
|
||||
|
||||
@@ -25,18 +26,48 @@ public class RhinoLayerBaker : TraversalContextUnpacker
|
||||
/// Creates the base layer and adds it to the cache.
|
||||
/// </summary>
|
||||
/// <param name="baseLayerName"></param>
|
||||
public void CreateBaseLayer(string baseLayerName)
|
||||
private void CreateBaseLayer(string baseLayerName)
|
||||
{
|
||||
var index = RhinoDoc.ActiveDoc.Layers.Add(new Layer { Name = baseLayerName }); // POC: too much effort right now to wrap around the interfaced layers and doc
|
||||
_hostLayerCache.Add(baseLayerName, index);
|
||||
_hostLayerCache[baseLayerName] = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>For receive: Use this method to construct layers in the host app when receiving. It progressively caches layers while creating them, so a second call to get the same layer will be fast.</para>
|
||||
/// Creates all layers needed for receiving data.
|
||||
/// </summary>
|
||||
public int GetAndCreateLayerFromPath(Collection[] collectionPath, string baseLayerName)
|
||||
/// <param name="paths">Collections of paths</param>
|
||||
/// <param name="baseLayerName">Name of the base layer</param>
|
||||
/// <remarks>Make sure this is executing on the main thread, using e.g RhinoApp.InvokeAndWait.</remarks>
|
||||
public void CreateAllLayersForReceive(IEnumerable<Collection[]> paths, string baseLayerName)
|
||||
{
|
||||
var layerPath = collectionPath.Select(o => string.IsNullOrWhiteSpace(o.name) ? "unnamed" : o.name);
|
||||
CreateBaseLayer(baseLayerName);
|
||||
var uniquePaths = new Dictionary<string, Collection[]>();
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var names = path.Select(o => string.IsNullOrWhiteSpace(o.name) ? "unnamed" : o.name);
|
||||
var key = string.Join(",", names!);
|
||||
uniquePaths[key] = path;
|
||||
}
|
||||
|
||||
foreach (var uniquePath in uniquePaths)
|
||||
{
|
||||
var layerIndex = CreateLayerFromPath(uniquePath.Value, baseLayerName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the index of a layer based on the given collection path and base layer name.
|
||||
/// </summary>
|
||||
/// <param name="collectionPath">The array containing the collection path to the layer.</param>
|
||||
/// <param name="baseLayerName">The name of the base layer.</param>
|
||||
/// <returns>The index of the layer in the cache.</returns>
|
||||
/// <exception cref="SpeckleException">Thrown when the layer is not found in the cache. This can happen if you didn't call previously <see cref="CreateAllLayersForReceive"/></exception>
|
||||
public int GetLayerIndex(Collection[] collectionPath, string baseLayerName)
|
||||
{
|
||||
var layerPath = collectionPath
|
||||
.Select(o => string.IsNullOrWhiteSpace(o.name) ? "unnamed" : o.name)
|
||||
.Prepend(baseLayerName);
|
||||
|
||||
var layerFullName = string.Join(Layer.PathSeparator, layerPath);
|
||||
|
||||
if (_hostLayerCache.TryGetValue(layerFullName, out int existingLayerIndex))
|
||||
@@ -44,6 +75,17 @@ public class RhinoLayerBaker : TraversalContextUnpacker
|
||||
return existingLayerIndex;
|
||||
}
|
||||
|
||||
throw new SpeckleException("Did not find a layer in the cache.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a layer based on the given collection path and adds it to the Rhino document.
|
||||
/// </summary>
|
||||
/// <param name="collectionPath">An array of Collection objects representing the path to create the layer.</param>
|
||||
/// <param name="baseLayerName">The base layer name to start creating the new layer.</param>
|
||||
/// <returns>The index of the last created layer.</returns>
|
||||
private int CreateLayerFromPath(Collection[] collectionPath, string baseLayerName)
|
||||
{
|
||||
var currentLayerName = baseLayerName;
|
||||
var currentDocument = RhinoDoc.ActiveDoc; // POC: too much effort right now to wrap around the interfaced layers
|
||||
Layer? previousLayer = currentDocument.Layers.FindName(currentLayerName);
|
||||
|
||||
+1
@@ -21,5 +21,6 @@ public sealed class DisableRedrawScope : IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
_viewTable.RedrawEnabled = _returnToStatus;
|
||||
_viewTable.Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
+29
-24
@@ -54,7 +54,9 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
|
||||
_activityFactory = activityFactory;
|
||||
}
|
||||
|
||||
#pragma warning disable CA1506
|
||||
public async Task<HostObjectBuilderResult> Build(
|
||||
#pragma warning restore CA1506
|
||||
Base rootObject,
|
||||
string projectName,
|
||||
string modelName,
|
||||
@@ -68,9 +70,9 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
|
||||
|
||||
// 0 - Clean then Rock n Roll!
|
||||
PreReceiveDeepClean(baseLayerName);
|
||||
_layerBaker.CreateBaseLayer(baseLayerName);
|
||||
|
||||
// 1 - Unpack objects and proxies from root commit object
|
||||
|
||||
var unpackedRoot = _rootObjectUnpacker.Unpack(rootObject);
|
||||
|
||||
// 2 - Split atomic objects and instance components with their path
|
||||
@@ -107,11 +109,11 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
|
||||
onOperationProgressed.Report(new("Baking layers (redraw disabled)", null));
|
||||
using (var _ = _activityFactory.Start("Pre baking layers"))
|
||||
{
|
||||
using var layerNoDraw = new DisableRedrawScope(_converterSettings.Current.Document.Views);
|
||||
foreach (var (path, _) in atomicObjectsWithPath)
|
||||
RhinoApp.InvokeAndWait(() =>
|
||||
{
|
||||
_layerBaker.GetAndCreateLayerFromPath(path, baseLayerName);
|
||||
}
|
||||
using var layerNoDraw = new DisableRedrawScope(_converterSettings.Current.Document.Views);
|
||||
_layerBaker.CreateAllLayersForReceive(atomicObjectsWithPath.Select(t => t.path), baseLayerName);
|
||||
});
|
||||
}
|
||||
|
||||
// 5 - Convert atomic objects
|
||||
@@ -130,7 +132,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
|
||||
try
|
||||
{
|
||||
// 0: get pre-created layer from cache in layer baker
|
||||
int layerIndex = _layerBaker.GetAndCreateLayerFromPath(path, baseLayerName);
|
||||
int layerIndex = _layerBaker.GetLayerIndex(path, baseLayerName);
|
||||
|
||||
// 1: create object attributes for baking
|
||||
string name = obj["name"] as string ?? "";
|
||||
@@ -217,7 +219,6 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
|
||||
}
|
||||
|
||||
_converterSettings.Current.Document.Views.Redraw();
|
||||
|
||||
return new HostObjectBuilderResult(bakedObjectIds, conversionResults);
|
||||
}
|
||||
|
||||
@@ -230,31 +231,35 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
|
||||
RhinoMath.UnsetIntIndex
|
||||
);
|
||||
|
||||
_instanceBaker.PurgeInstances(baseLayerName);
|
||||
_materialBaker.PurgeMaterials(baseLayerName);
|
||||
|
||||
var doc = _converterSettings.Current.Document;
|
||||
// Cleans up any previously received objects
|
||||
if (rootLayerIndex != RhinoMath.UnsetIntIndex)
|
||||
RhinoApp.InvokeAndWait(() =>
|
||||
{
|
||||
var documentLayer = doc.Layers[rootLayerIndex];
|
||||
var childLayers = documentLayer.GetChildren();
|
||||
if (childLayers != null)
|
||||
_instanceBaker.PurgeInstances(baseLayerName);
|
||||
_materialBaker.PurgeMaterials(baseLayerName);
|
||||
|
||||
var doc = _converterSettings.Current.Document;
|
||||
// Cleans up any previously received objects
|
||||
if (rootLayerIndex != RhinoMath.UnsetIntIndex)
|
||||
{
|
||||
using var layerNoDraw = new DisableRedrawScope(doc.Views);
|
||||
foreach (var layer in childLayers)
|
||||
var documentLayer = doc.Layers[rootLayerIndex];
|
||||
var childLayers = documentLayer.GetChildren();
|
||||
if (childLayers != null)
|
||||
{
|
||||
var purgeSuccess = doc.Layers.Purge(layer.Index, true);
|
||||
if (!purgeSuccess)
|
||||
using var layerNoDraw = new DisableRedrawScope(doc.Views);
|
||||
foreach (var layer in childLayers)
|
||||
{
|
||||
Console.WriteLine($"Failed to purge layer: {layer}");
|
||||
var purgeSuccess = doc.Layers.Purge(layer.Index, true);
|
||||
if (!purgeSuccess)
|
||||
{
|
||||
Console.WriteLine($"Failed to purge layer: {layer}");
|
||||
}
|
||||
}
|
||||
}
|
||||
doc.Layers.Purge(documentLayer.Index, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleans up any previously received group
|
||||
_groupBaker.PurgeGroups(baseLayerName);
|
||||
// Cleans up any previously received group
|
||||
_groupBaker.PurgeGroups(baseLayerName);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -48,12 +48,6 @@
|
||||
<Reference Include="WindowsFormsIntegration" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\et_element_Speckle.bmp">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\Speckle.Connector.TeklaShared\Speckle.Connectors.TeklaShared.projitems" Label="Shared" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -47,12 +47,6 @@
|
||||
<Reference Include="WindowsFormsIntegration" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Assets\et_element_Speckle.bmp">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="..\Speckle.Connector.TeklaShared\Speckle.Connectors.TeklaShared.projitems" Label="Shared" />
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -2,9 +2,9 @@ using Tekla.Structures.Plugins;
|
||||
|
||||
namespace Speckle.Connector.Tekla2024.Plugin;
|
||||
|
||||
[Plugin("Speckle (Beta)")]
|
||||
[Plugin("Speckle")]
|
||||
[PluginUserInterface("Speckle.Connector.Tekla2024.SpeckleTeklaPanelHost")]
|
||||
[InputObjectDependency(InputObjectDependency.NOT_DEPENDENT)] // See DevDocs/InputObjectDependency.NOT_DEPENDENT.png
|
||||
[InputObjectDependency(InputObjectDependency.NOT_DEPENDENT)]
|
||||
public class TeklaPlugin : PluginBase
|
||||
{
|
||||
#pragma warning disable IDE1006
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.Integration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -15,17 +16,38 @@ public class SpeckleTeklaPanelHost : PluginFormBase
|
||||
{
|
||||
private ElementHost Host { get; }
|
||||
public Model Model { get; private set; }
|
||||
|
||||
public static new ServiceProvider? Container { get; private set; }
|
||||
|
||||
// TODO: private IDisposable? _disposableLogger;
|
||||
private static readonly List<SpeckleTeklaPanelHost> s_instances = new();
|
||||
|
||||
public SpeckleTeklaPanelHost()
|
||||
{
|
||||
this.Text = "Speckle (Beta)";
|
||||
this.Name = "Speckle (Beta)";
|
||||
//TODO: Add Speckle icon
|
||||
// TODO: Add thumbnail to connector
|
||||
|
||||
// CNX-790: Needs to be solved
|
||||
string version = GetVersion().ToString()[1..]; // removes the 'v' from version
|
||||
string resourcePath = $"Speckle.Connector.Tekla{version}.Resources.et_element_Speckle.bmp";
|
||||
using (
|
||||
Bitmap bmp = new Bitmap(
|
||||
GetType().Assembly.GetManifestResourceStream(resourcePath)
|
||||
?? throw new InvalidOperationException($"Could not find resource: {resourcePath}")
|
||||
)
|
||||
)
|
||||
{
|
||||
this.Icon = Icon.FromHandle(bmp.GetHicon());
|
||||
}
|
||||
|
||||
// adds instances to tracking list
|
||||
s_instances.Add(this);
|
||||
|
||||
if (s_instances.Count > 1)
|
||||
{
|
||||
var firstInstance = s_instances[0];
|
||||
s_instances.RemoveAt(0);
|
||||
// hides the first instance if there is more than one
|
||||
firstInstance.Hide();
|
||||
}
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.Initialize(HostApplications.TeklaStructures, GetVersion());
|
||||
services.AddTekla();
|
||||
|
||||
+5
-1
@@ -55,7 +55,11 @@ public class PolylineToHostConverter
|
||||
RG.PolylineCurve ITypedConverter<SOG.Polyline, RG.PolylineCurve>.Convert(SOG.Polyline target)
|
||||
{
|
||||
var poly = Convert(target).ToPolylineCurve();
|
||||
poly.Domain = _intervalConverter.Convert(target.domain);
|
||||
if (target.domain is not null) // note it can be null
|
||||
{
|
||||
poly.Domain = _intervalConverter.Convert(target.domain);
|
||||
}
|
||||
|
||||
return poly;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,22 @@ public class SendBindingUICommands(IBrowserBridge bridge) : BasicConnectorBindin
|
||||
public async Task SetModelsExpired(IEnumerable<string> expiredModelIds) =>
|
||||
await Bridge.Send(SET_MODELS_EXPIRED_UI_COMMAND_NAME, expiredModelIds).ConfigureAwait(false);
|
||||
|
||||
public async Task SetFilterObjectIds(string modelCardId, Dictionary<string, string> idMap) =>
|
||||
await Bridge.Send(SET_ID_MAP_COMMAND_NAME, new { modelCardId, idMap }).ConfigureAwait(false);
|
||||
public async Task SetFilterObjectIds(
|
||||
string modelCardId,
|
||||
Dictionary<string, string> idMap,
|
||||
List<string> newSelectedObjectIds
|
||||
) =>
|
||||
await Bridge
|
||||
.Send(
|
||||
SET_ID_MAP_COMMAND_NAME,
|
||||
new
|
||||
{
|
||||
modelCardId,
|
||||
idMap,
|
||||
newSelectedObjectIds
|
||||
}
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
public async Task SetModelSendResult(
|
||||
string modelCardId,
|
||||
|
||||
Reference in New Issue
Block a user