From 8a0dfca20473cee19119e26bec274e5152cf71cb Mon Sep 17 00:00:00 2001 From: Claire Kuang Date: Tue, 20 Aug 2024 13:39:21 +0200 Subject: [PATCH] fix(autocad): CNX-318 better color inheritance for blocks (#167) * updates definition object colors and refactors speckle application id retrieval * adds definition object color inehritance and speckle app id extensions * minor build fixes * adds source to color proxy and color proxy id * Update AutocadColorManager.cs * Update AutocadColorManager.cs --- .../Bindings/AutocadBasicConnectorBinding.cs | 4 +- .../Bindings/AutocadSelectionBinding.cs | 4 +- .../Bindings/AutocadSendBinding.cs | 2 +- .../HostApp/AutocadColorManager.cs | 180 +++++++++++++----- .../HostApp/AutocadGroupManager.cs | 3 +- .../HostApp/AutocadInstanceObjectManager.cs | 31 +-- .../HostApp/AutocadMaterialManager.cs | 4 +- .../HostApp/Extensions/AcadUnitsExtension.cs | 39 ---- .../Extensions/LayerTableRecordExtensions.cs | 14 -- .../SpeckleApplicationIdExtensions.cs | 44 +++++ .../Receive/AutocadHostObjectBuilder.cs | 4 +- .../Send/AutocadRootObjectBuilder.cs | 6 +- ...Speckle.Connectors.AutocadShared.projitems | 3 +- 13 files changed, 210 insertions(+), 128 deletions(-) delete mode 100644 Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/AcadUnitsExtension.cs delete mode 100644 Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/LayerTableRecordExtensions.cs create mode 100644 Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/SpeckleApplicationIdExtensions.cs diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs index 03ce9e0b7..a4dab3f4b 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadBasicConnectorBinding.cs @@ -33,9 +33,9 @@ public class AutocadBasicConnectorBinding : IBasicConnectorBinding public string GetConnectorVersion() => typeof(AutocadBasicConnectorBinding).Assembly.GetVersion(); - public string GetSourceApplicationName() => Speckle.Connectors.Utils.Connector.Slug; + public string GetSourceApplicationName() => Utils.Connector.Slug; - public string GetSourceApplicationVersion() => Speckle.Connectors.Utils.Connector.VersionString; + public string GetSourceApplicationVersion() => Utils.Connector.VersionString; public Account[] GetAccounts() => AccountManager.GetAccounts().ToArray(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs index a968e9fee..310f98a4a 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSelectionBinding.cs @@ -1,5 +1,6 @@ using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; +using Speckle.Connectors.Autocad.HostApp.Extensions; using Speckle.Connectors.DUI.Bindings; using Speckle.Connectors.DUI.Bridge; @@ -79,9 +80,8 @@ public class AutocadSelectionBinding : ISelectionBinding continue; } - var handleString = dbObject.Handle.Value.ToString(); objectTypes.Add(dbObject.GetType().Name); - objs.Add(handleString); + objs.Add(dbObject.GetSpeckleApplicationId()); } tr.Commit(); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs index da2dfcd29..574646015 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Bindings/AutocadSendBinding.cs @@ -107,7 +107,7 @@ public sealed class AutocadSendBinding : ISendBinding private void OnChangeChangedObjectIds(DBObject dBObject) { - ChangedObjectIds[dBObject.Handle.Value.ToString()] = 1; + ChangedObjectIds[dBObject.GetSpeckleApplicationId()] = 1; _idleManager.SubscribeToIdle(nameof(AutocadSendBinding), RunExpirationChecks); } diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorManager.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorManager.cs index 8748511bf..bf2678b61 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorManager.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadColorManager.cs @@ -2,6 +2,7 @@ using Autodesk.AutoCAD.Colors; using Autodesk.AutoCAD.DatabaseServices; using Speckle.Connectors.Autocad.HostApp.Extensions; using Speckle.Connectors.Autocad.Operations.Send; +using Speckle.Sdk.Models.Instances; using Speckle.Sdk.Models.Proxies; using AutocadColor = Autodesk.AutoCAD.Colors.Color; @@ -15,93 +16,171 @@ public class AutocadColorManager // POC: Will be addressed to move it into AutocadContext! private Document Doc => Application.DocumentManager.MdiActiveDocument; + /// + /// For receive operations + /// public Dictionary ObjectColorsIdMap { get; } = new(); - private ColorProxy ConvertColorToColorProxy(AutocadColor color, string id) + /// + /// For send operations + /// + private Dictionary ColorProxies { get; } = new(); + private readonly Dictionary _layerColorDict = new(); // keeps track of layer colors for object inheritance + private readonly Dictionary _objectsByLayerDict = new(); // keeps track of ids for all objects that inherited their color by layer + + /// + /// Processes an object's color and adds the object id to a color proxy in if object color is set ByAci, ByColor, or ByBlock. + /// Otherwise, stores the object id and color in a corresponding ByLayer dictionary for further processing block definitions after all objects are converted. + /// From testing, a definition object will inherit its layer's color if by layer, otherwise it will inherit the instance color settings (which we are sending with the instance). + /// Skips processing ByPen for now, because I don't understand what this means. + /// + /// + /// + private void ProcessObjectColor(string objectId, AutocadColor color, string? layerId = null) + { + switch (color.ColorMethod) + { + case ColorMethod.ByAci: + case ColorMethod.ByColor: + case ColorMethod.ByBlock: + AddObjectIdToColorProxy(objectId, color); + break; + case ColorMethod.ByLayer: + if (layerId != null) + { +#if NET8_0 + _objectsByLayerDict.TryAdd(objectId, layerId); +#else + if (!_objectsByLayerDict.ContainsKey(objectId)) + { + _objectsByLayerDict.Add(objectId, layerId); + } +#endif + } + break; + case ColorMethod.ByPen: // POC: no idea what this means + break; + } + } + + private void AddObjectIdToColorProxy(string objectId, AutocadColor color) + { + string colorId = color.GetSpeckleApplicationId(); + if (ColorProxies.TryGetValue(colorId, out ColorProxy? proxy)) + { + proxy.objects.Add(objectId); + } + else + { + ColorProxy newColor = ConvertColorToColorProxy(color); + newColor.objects.Add(objectId); + ColorProxies[colorId] = newColor; + } + } + + private ColorProxy ConvertColorToColorProxy(AutocadColor color) { int argb = color.ColorValue.ToArgb(); string name = color.ColorNameForDisplay; + string id = color.GetSpeckleApplicationId(); ColorProxy colorProxy = new(argb, id, name) { objects = new() }; - // INFO: this index is an Autocad internal index for set rgb values - // https://gohtx.com/acadcolors.php + // add the color source as well for receiving in other apps + // POC: in order to support full fidelity color support across autocad and rhino, we need to keep track of the color source property. Not sure if this is the best place to keep track of the source, vs on a ColorSourceProxy or as a property on the atomic object. + colorProxy["source"] = color.IsByBlock + ? "block" + : color.IsByLayer + ? "layer" + : "object"; + + // set additional properties if by aci or by block + // ByBlock colors for some reason do not have their color value set to the correct color (white): instead it's a near-black + // ByACI is an Autocad internal index for set rgb values, which effects name presentation, see: https://gohtx.com/acadcolors.php if (color.IsByAci) { colorProxy["autocadColorIndex"] = (int)color.ColorIndex; } + else if (color.IsByBlock) + { + colorProxy.value = -1; + } return colorProxy; } /// - /// Iterates through a given set of autocad objects and collects their colors. Note: expects objects to be "atomic", and extracted out of their instances already. + /// Processes colors for definition objects that had their colors inherited. This method is in place primarily to process complex color inheritance in blocks. /// - /// - /// /// + /// + /// We are **always setting the color** (treating it as ColorMethod.ByColor) for definition objects with color "ByLayer" because this overrides instance color, to guarantee they look correct in the viewer and when receiving. + /// + public void ProcessDefinitionObjects(List definitions) + { + // process all definition objects, while removing process objects from the by block color dict as necessary + foreach (InstanceDefinitionProxy definition in definitions) + { + foreach (string objectId in definition.objects) + { + if (_objectsByLayerDict.TryGetValue(objectId, out string? layerId)) + { + if (_layerColorDict.TryGetValue(layerId, out AutocadColor? layerColor)) + { + AddObjectIdToColorProxy(objectId, layerColor); + } + } + } + } + } + + /// + /// Iterates through a given set of autocad objects, layers, and definitions to collect atomic object colors. + /// + /// atomic root objects, including definition objects + /// layers used by atomic objects + /// definitions used by instances in atomic objects + /// + /// + /// Due to complications in color inheritance for blocks, we are processing block definition object colors last. + /// public List UnpackColors( List unpackedAutocadRootObjects, - List layers + List layers, + List definitions ) { - Dictionary colorProxies = new(); - // Stage 1: unpack colors from objects foreach (AutocadRootObject rootObj in unpackedAutocadRootObjects) { Entity entity = rootObj.Root; - - // skip any objects that inherit their colors - if (!entity.Color.IsByAci && !entity.Color.IsByColor) - { - continue; - } - - // assumes color names are unique - string colorId = entity.Color.ColorNameForDisplay; - - if (colorProxies.TryGetValue(colorId, out ColorProxy? value)) - { - value.objects.Add(rootObj.ApplicationId); - } - else - { - ColorProxy newColor = ConvertColorToColorProxy(entity.Color, colorId); - newColor.objects.Add(rootObj.ApplicationId); - colorProxies[colorId] = newColor; - } + ProcessObjectColor(rootObj.ApplicationId, entity.Color, entity.LayerId.ToString()); } // Stage 2: make sure we collect layer colors as well foreach (LayerTableRecord layer in layers) { - // assumes color names are unique - string colorId = layer.Color.ColorNameForDisplay; - string layerId = layer.GetSpeckleApplicationId(); // Do not use handle directly, see note in the 'GetSpeckleApplicationId' method - - if (colorProxies.TryGetValue(colorId, out ColorProxy? value)) - { - value.objects.Add(layerId); - } - else - { - ColorProxy newColor = ConvertColorToColorProxy(layer.Color, colorId); - newColor.objects.Add(layerId); - colorProxies[colorId] = newColor; - } + ProcessObjectColor(layer.GetSpeckleApplicationId(), layer.Color); + _layerColorDict.Add(layer.Id.ToString(), layer.Color); } - return colorProxies.Values.ToList(); + // Stage 3: process definition objects that inherited their colors + ProcessDefinitionObjects(definitions); + + return ColorProxies.Values.ToList(); } public AutocadColor ConvertColorProxyToColor(ColorProxy colorProxy) { - AutocadColor color = colorProxy["autocadColorIndex"] is long index + // if source = block, return a default ByBlock color + if (colorProxy["source"] is string source && source == "block") + { + return AutocadColor.FromColorIndex(ColorMethod.ByBlock, 0); + } + + return colorProxy["autocadColorIndex"] is long index ? AutocadColor.FromColorIndex(ColorMethod.ByAci, (short)index) : AutocadColor.FromColor(System.Drawing.Color.FromArgb(colorProxy.value)); - - return color; } /// @@ -115,6 +194,13 @@ public class AutocadColorManager foreach (ColorProxy colorProxy in colorProxies) { onOperationProgressed?.Invoke("Converting colors", (double)++count / colorProxies.Count); + + // skip any colors with source = layer, since object color default source is by layer + if (colorProxy["source"] is string source && source == "layer") + { + continue; + } + foreach (string objectId in colorProxy.objects) { AutocadColor convertedColor = ConvertColorProxyToColor(colorProxy); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadGroupManager.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadGroupManager.cs index 4148fcdc1..38937dda2 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadGroupManager.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadGroupManager.cs @@ -1,4 +1,5 @@ using Autodesk.AutoCAD.DatabaseServices; +using Speckle.Connectors.Autocad.HostApp.Extensions; using Speckle.Connectors.Autocad.Operations.Send; using Speckle.Connectors.Utils.Conversion; using Speckle.Sdk; @@ -39,7 +40,7 @@ public class AutocadGroupManager { continue; } - var groupAppId = group.Handle.ToString(); + var groupAppId = group.GetSpeckleApplicationId(); if (groupProxies.TryGetValue(groupAppId, out GroupProxy? groupProxy)) { groupProxy.objects.Add(applicationId); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceObjectManager.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceObjectManager.cs index b29b6ed42..f4d2dafa0 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceObjectManager.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadInstanceObjectManager.cs @@ -65,27 +65,27 @@ public class AutocadInstanceObjectManager : IInstanceUnpacker private void UnpackInstance(BlockReference instance, int depth, Transaction transaction) { - var instanceIdString = instance.Handle.Value.ToString(); + string instanceId = instance.GetSpeckleApplicationId(); + // If this instance has a reference to an anonymous block, it means it's spawned from a dynamic block. Anonymous blocks are // used to represent specific "instances" of dynamic ones. // We do not want to send the full dynamic block definition, but its current "instance", as such here we're making sure we // take up the anon block table reference definition (if it exists). If it's not an instance of a dynamic block, we're // using the normal def reference. - var hasAnonymousBlockTableRecordDefinition = instance.AnonymousBlockTableRecord != ObjectId.Null; - var definitionId = hasAnonymousBlockTableRecordDefinition + ObjectId definitionId = !instance.AnonymousBlockTableRecord.IsNull ? instance.AnonymousBlockTableRecord : instance.BlockTableRecord; InstanceProxy instanceProxy = new() { - applicationId = instanceIdString, + applicationId = instanceId, definitionId = definitionId.ToString(), maxDepth = depth, transform = GetMatrix(instance.BlockTransform.ToArray()), units = _unitsConverter.ConvertOrThrow(Application.DocumentManager.CurrentDocument.Database.Insunits) }; - _instanceObjectsManager.AddInstanceProxy(instanceIdString, instanceProxy); + _instanceObjectsManager.AddInstanceProxy(instanceId, instanceProxy); // For each block instance that has the same definition, we need to keep track of the "maximum depth" at which is found. // This will enable on receive to create them in the correct order (descending by max depth, interleaved definitions and instances). @@ -113,7 +113,7 @@ public class AutocadInstanceObjectManager : IInstanceUnpacker } } - instanceProxiesWithSameDefinition.Add(_instanceObjectsManager.GetInstanceProxy(instanceIdString)); + instanceProxiesWithSameDefinition.Add(_instanceObjectsManager.GetInstanceProxy(instanceId)); if ( _instanceObjectsManager.TryGetInstanceDefinitionProxy(definitionId.ToString(), out InstanceDefinitionProxy value) @@ -134,29 +134,30 @@ public class AutocadInstanceObjectManager : IInstanceUnpacker applicationId = definitionId.ToString(), objects = new(), maxDepth = depth, - name = hasAnonymousBlockTableRecordDefinition ? "Dynamic instance " + definitionId : definition.Name, + name = !instance.AnonymousBlockTableRecord.IsNull ? "Dynamic instance " + definitionId : definition.Name, ["comments"] = definition.Comments }; // Go through each definition object foreach (ObjectId id in definition) { - var obj = transaction.GetObject(id, OpenMode.ForRead); + Entity obj = (Entity)transaction.GetObject(id, OpenMode.ForRead); + // In the case of dynamic blocks, this prevents sending objects that are not visibile in its current state. - if (obj is Entity { Visible: false }) + if (!obj.Visible) { continue; } - var handleIdString = obj.Handle.Value.ToString(); - definitionProxy.objects.Add(handleIdString); + string appId = obj.GetSpeckleApplicationId(); + definitionProxy.objects.Add(appId); if (obj is BlockReference blockReference) { UnpackInstance(blockReference, depth + 1, transaction); } - _instanceObjectsManager.AddAtomicObject(handleIdString, new((Entity)obj, handleIdString)); + _instanceObjectsManager.AddAtomicObject(appId, new(obj, appId)); } _instanceObjectsManager.AddDefinitionProxy(definitionId.ToString(), definitionProxy); @@ -220,7 +221,7 @@ public class AutocadInstanceObjectManager : IInstanceUnpacker definitionIdAndApplicationIdMap[definitionProxy.applicationId] = id; transaction.AddNewlyCreatedDBObject(record, true); - var consumedEntitiesHandleValues = constituentEntities.Select(ent => ent.Handle.Value.ToString()).ToArray(); + var consumedEntitiesHandleValues = constituentEntities.Select(ent => ent.GetSpeckleApplicationId()).ToArray(); consumedObjectIds.AddRange(consumedEntitiesHandleValues); createdObjectIds.RemoveAll(newId => consumedEntitiesHandleValues.Contains(newId)); } @@ -272,9 +273,9 @@ public class AutocadInstanceObjectManager : IInstanceUnpacker transaction.AddNewlyCreatedDBObject(blockRef, true); conversionResults.Add( - new(Status.SUCCESS, instanceProxy, blockRef.Handle.Value.ToString(), "Instance (Block)") + new(Status.SUCCESS, instanceProxy, blockRef.GetSpeckleApplicationId(), "Instance (Block)") ); - createdObjectIds.Add(blockRef.Handle.Value.ToString()); + createdObjectIds.Add(blockRef.GetSpeckleApplicationId()); } } catch (Exception ex) when (!ex.IsFatal()) diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialManager.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialManager.cs index b66611389..129b053b1 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialManager.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/AutocadMaterialManager.cs @@ -76,7 +76,7 @@ public class AutocadMaterialManager if (transaction.GetObject(entity.MaterialId, OpenMode.ForRead) is Material material) { - string materialId = material.Handle.ToString(); + string materialId = material.GetSpeckleApplicationId(); if (materialProxies.TryGetValue(materialId, out RenderMaterialProxy? value)) { value.objects.Add(rootObj.ApplicationId); @@ -95,7 +95,7 @@ public class AutocadMaterialManager { if (transaction.GetObject(layer.MaterialId, OpenMode.ForRead) is Material material) { - string materialId = material.Handle.ToString(); + string materialId = material.GetSpeckleApplicationId(); string layerId = layer.GetSpeckleApplicationId(); // Do not use handle directly, see note in the 'GetSpeckleApplicationId' method if (materialProxies.TryGetValue(materialId, out RenderMaterialProxy? value)) { diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/AcadUnitsExtension.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/AcadUnitsExtension.cs deleted file mode 100644 index 1e3c66e33..000000000 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/AcadUnitsExtension.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Autodesk.AutoCAD.DatabaseServices; -using Speckle.Sdk; -using Speckle.Sdk.Common; - -namespace Speckle.Connectors.Autocad.HostApp.Extensions; - -public static class AcadUnitsExtension -{ - public static string ToSpeckleString(this UnitsValue units) - { - switch (units) - { - case UnitsValue.Millimeters: - return Units.Millimeters; - case UnitsValue.Centimeters: - return Units.Centimeters; - case UnitsValue.Meters: - return Units.Meters; - case UnitsValue.Kilometers: - return Units.Kilometers; - case UnitsValue.Inches: - case UnitsValue.USSurveyInch: - return Units.Inches; - case UnitsValue.Feet: - case UnitsValue.USSurveyFeet: - return Units.Feet; - case UnitsValue.Yards: - case UnitsValue.USSurveyYard: - return Units.Yards; - case UnitsValue.Miles: - case UnitsValue.USSurveyMile: - return Units.Miles; - case UnitsValue.Undefined: - return Units.None; - default: - throw new SpeckleException($"The Unit System \"{units}\" is unsupported."); - } - } -} diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/LayerTableRecordExtensions.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/LayerTableRecordExtensions.cs deleted file mode 100644 index e64189ec5..000000000 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/LayerTableRecordExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Autodesk.AutoCAD.DatabaseServices; - -namespace Speckle.Connectors.Autocad.HostApp.Extensions; - -public static class LayerTableRecordExtensions -{ - /// - /// Layers and geometries can have same application ids..... - /// We should prevent it for sketchup converter. Because when it happens "objects_to_bake" definition - /// is changing on the way if it happens. - /// - public static string GetSpeckleApplicationId(this LayerTableRecord layerTableRecord) => - $"layer_{layerTableRecord.Handle}"; -} diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/SpeckleApplicationIdExtensions.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/SpeckleApplicationIdExtensions.cs new file mode 100644 index 000000000..136f7bc55 --- /dev/null +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/HostApp/Extensions/SpeckleApplicationIdExtensions.cs @@ -0,0 +1,44 @@ +using Autodesk.AutoCAD.DatabaseServices; +using AutocadColor = Autodesk.AutoCAD.Colors.Color; + +namespace Speckle.Connectors.Autocad.HostApp.Extensions; + +public static class SpeckleApplicationIdExtensions +{ + /// + /// Retrieves the Speckle object application id + /// + public static string GetSpeckleApplicationId(this Entity entity) => entity.Handle.Value.ToString(); + + /// + /// Retrieves the Speckle object application id + /// + public static string GetSpeckleApplicationId(this DBObject dbObj) => dbObj.Handle.Value.ToString(); + + /// + /// Layers and geometries can have same application ids..... + /// We should prevent it for sketchup converter. Because when it happens "objects_to_bake" definition + /// is changing on the way if it happens. + /// + public static string GetSpeckleApplicationId(this LayerTableRecord layerTableRecord) => + $"layer_{layerTableRecord.Handle.Value}"; + + /// + /// Retrieves a unique material Speckle object application id. + /// + /// Unconfirmed, but materials and geometries may have same application ids. + public static string GetSpeckleApplicationId(this Material material) => $"material_{material.Handle.Value}"; + + /// + /// Retrieves a unique color Speckle object application id from the rgb value and color source. + /// + /// Uses the rgb value since color names are not unique + public static string GetSpeckleApplicationId(this AutocadColor color) => + $"color_{color.ColorValue}_{(color.IsByBlock ? "block" : color.IsByLayer ? "layer" : "object")}"; + + /// + /// Retrieves a unique group Speckle object application id. + /// + /// Unconfirmed, but groups and geometries may have same application ids. + public static string GetSpeckleApplicationId(this Group group) => $"group_{group.Handle.Value}"; +} diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs index 77003946f..87812f241 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Receive/AutocadHostObjectBuilder.cs @@ -156,12 +156,12 @@ public class AutocadHostObjectBuilder : IHostObjectBuilder convertedObjects.Select(e => new ReceiveConversionResult( Status.SUCCESS, atomicObject, - e.Handle.Value.ToString(), + e.GetSpeckleApplicationId(), e.GetType().ToString() )) ); - bakedObjectIds.AddRange(convertedObjects.Select(e => e.Handle.Value.ToString())); + bakedObjectIds.AddRange(convertedObjects.Select(e => e.GetSpeckleApplicationId())); } catch (Exception ex) when (!ex.IsFatal()) { diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs index 5b589f905..dc22562f8 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Operations/Send/AutocadRootObjectBuilder.cs @@ -149,7 +149,11 @@ public class AutocadRootObjectBuilder : IRootObjectBuilder modelWithLayers["renderMaterialProxies"] = materialProxies; // set colors - List colorProxies = _colorManager.UnpackColors(atomicObjects, usedAcadLayers); + List colorProxies = _colorManager.UnpackColors( + atomicObjects, + usedAcadLayers, + instanceDefinitionProxies + ); modelWithLayers["colorProxies"] = colorProxies; return new RootObjectBuilderResult(modelWithLayers, results); diff --git a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems index 2e3fb4abf..8656167b2 100644 --- a/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems +++ b/Connectors/Autocad/Speckle.Connectors.AutocadShared/Speckle.Connectors.AutocadShared.projitems @@ -26,12 +26,11 @@ - - +