Skip to content

Commit 286a1c0

Browse files
authored
Merge branch 'dev' into dimitrie/cnx-1086-stuck-at-publish-when-trying-to-publish-not-supported-array
2 parents a23f9c1 + 4af9095 commit 286a1c0

File tree

4 files changed

+157
-108
lines changed

4 files changed

+157
-108
lines changed

Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoColorUnpacker.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.Extensions.Logging;
1+
using Microsoft.Extensions.Logging;
22
using Rhino;
33
using Rhino.DocObjects;
44
using Speckle.Connectors.Rhino.Extensions;
@@ -99,7 +99,7 @@ private ColorProxy ConvertColorToColorProxy(Color color, ObjectColorSource sourc
9999
/// Iterates through a given set of rhino objects and layers to collect colors.
100100
/// </summary>
101101
/// <param name="atomicObjects">atomic root objects, including instance objects</param>
102-
/// <param name="layers">layers used by atomic objects</param>
102+
/// <param name="layers">the layers corresponding to collections on the root collection</param>
103103
/// <returns></returns>
104104
public List<ColorProxy> UnpackColors(List<RhinoObject> atomicObjects, List<Layer> layers)
105105
{

Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoLayerUnpacker.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Rhino;
2+
using Speckle.Sdk;
23
using Speckle.Sdk.Models.Collections;
34
using Layer = Rhino.DocObjects.Layer;
45
using SpeckleLayer = Speckle.Sdk.Models.Collections.Layer;
@@ -23,6 +24,35 @@ public class RhinoLayerUnpacker
2324
#endif
2425
private static readonly string[] s_pathSeparatorSplit = [s_pathSeparator];
2526

27+
/// <summary>
28+
/// Use this method to get all of the layers that correspond to collection created in the root collection.
29+
/// </summary>
30+
/// <returns></returns>
31+
/// <exception cref="SpeckleException">Throws when a layer could not be retrieved from a stored collection application id</exception>
32+
public IEnumerable<Layer> GetUsedLayers()
33+
{
34+
var currentDoc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around
35+
36+
foreach (string layerId in _layerCollectionCache.Values.Select(o => o.applicationId ?? string.Empty).ToList())
37+
{
38+
if (Guid.TryParse(layerId, out Guid layerGuid))
39+
{
40+
if (currentDoc.Layers.FindId(layerGuid) is Layer layer)
41+
{
42+
yield return layer;
43+
}
44+
else
45+
{
46+
throw new SpeckleException($"Could not retrieve layer with guid: {layerId}.");
47+
}
48+
}
49+
else
50+
{
51+
throw new SpeckleException($"Invalid Collection Layer id: {layerId}. Should be convertible to a Guid.");
52+
}
53+
}
54+
}
55+
2656
/// <summary>
2757
/// <para>Use this method to construct the root commit object while converting objects.</para>
2858
/// <para>Returns the host collection corresponding to the provided layer. If it's the first time that it is being asked for, it will be created and stored in the root object collection.</para>

Connectors/Rhino/Speckle.Connectors.RhinoShared/HostApp/RhinoMaterialUnpacker.cs

Lines changed: 118 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -15,137 +15,154 @@ public class RhinoMaterialUnpacker
1515
{
1616
private readonly ILogger<RhinoMaterialUnpacker> _logger;
1717

18+
/// <summary>
19+
/// For send operations
20+
/// </summary>
21+
private Dictionary<string, RenderMaterialProxy> RenderMaterialProxies { get; } = new();
22+
1823
public RhinoMaterialUnpacker(ILogger<RhinoMaterialUnpacker> logger)
1924
{
2025
_logger = logger;
2126
}
2227

23-
public List<RenderMaterialProxy> UnpackRenderMaterial(List<RhinoObject> atomicObjects)
28+
/// <summary>
29+
/// Processes an object's material and adds the object id to a material proxy in <see cref="RenderMaterialProxies"/> if object color is set ByObject or ByParent.
30+
/// </summary>
31+
/// <param name="objId"></param>
32+
private void ProcessObjectMaterial(
33+
string objId,
34+
RenderMaterial? renderMaterial,
35+
Material? material,
36+
ObjectMaterialSource source
37+
)
38+
{
39+
switch (source)
40+
{
41+
case ObjectMaterialSource.MaterialFromObject:
42+
AddObjectIdToRenderMaterialProxy(objId, renderMaterial, material);
43+
break;
44+
45+
// POC: skip if object material source is *not* by object. we don't support render material inheritance atm bc alex disagrees with the concept
46+
default:
47+
break;
48+
}
49+
}
50+
51+
private void AddObjectIdToRenderMaterialProxy(string objectId, RenderMaterial? renderMaterial, Material? material)
2452
{
25-
Dictionary<string, RenderMaterialProxy> renderMaterialProxies = new();
26-
Dictionary<string, Layer> usedLayerMap = new();
53+
string? renderMaterialId = renderMaterial?.Id.ToString() ?? material?.Id.ToString();
2754

28-
// Stage 1: unpack materials from objects, and collect their uniqe layers in the process
29-
foreach (RhinoObject rhinoObject in atomicObjects)
55+
if (renderMaterialId is not null)
3056
{
31-
try
57+
if (RenderMaterialProxies.TryGetValue(renderMaterialId, out RenderMaterialProxy? proxy))
3258
{
33-
var layer = RhinoDoc.ActiveDoc.Layers[rhinoObject.Attributes.LayerIndex];
34-
usedLayerMap[layer.Id.ToString()] = layer;
35-
36-
if (rhinoObject.Attributes.MaterialSource != ObjectMaterialSource.MaterialFromObject)
59+
proxy.objects.Add(objectId);
60+
}
61+
else
62+
{
63+
if (
64+
ConvertMaterialToRenderMaterialProxy(renderMaterialId, renderMaterial, material)
65+
is RenderMaterialProxy newRenderMaterial
66+
)
3767
{
38-
continue; // TODO: will not catch layer materials
68+
newRenderMaterial.objects.Add(objectId);
69+
RenderMaterialProxies[renderMaterialId] = newRenderMaterial;
3970
}
71+
}
72+
}
73+
}
4074

41-
var rhinoRenderMaterial = rhinoObject.GetRenderMaterial(true);
42-
var rhinoMaterial = rhinoObject.GetMaterial(true);
43-
var rhinoMaterialId = rhinoRenderMaterial?.Id.ToString() ?? rhinoMaterial?.Id.ToString();
75+
private RenderMaterialProxy? ConvertMaterialToRenderMaterialProxy(
76+
string materialId,
77+
RenderMaterial? renderMaterial,
78+
Material? material
79+
)
80+
{
81+
// TY Rhino api for being a bit confused about materials 💖
82+
SpeckleRenderMaterial? myMaterial = null;
83+
if (renderMaterial is not null)
84+
{
85+
myMaterial = ConvertRenderMaterialToSpeckle(renderMaterial);
86+
}
87+
else if (material is not null)
88+
{
89+
RenderMaterial convertedRender = ConvertMaterialToRenderMaterial(material);
90+
myMaterial = ConvertRenderMaterialToSpeckle(convertedRender);
91+
}
4492

45-
if (rhinoMaterialId == null)
46-
{
47-
continue;
48-
}
93+
if (myMaterial is null)
94+
{
95+
return null;
96+
}
4997

50-
if (renderMaterialProxies.TryGetValue(rhinoMaterialId, out RenderMaterialProxy? value))
51-
{
52-
value.objects.Add(rhinoObject.Id.ToString());
53-
}
54-
else
55-
{
56-
// TY Rhino api for being a bit confused about materials 💖
57-
SpeckleRenderMaterial? myMaterial = null;
58-
if (rhinoRenderMaterial is not null)
59-
{
60-
myMaterial = ConvertRenderMaterialToSpeckle(rhinoRenderMaterial);
61-
}
62-
else if (rhinoMaterial is not null)
63-
{
64-
RenderMaterial convertedRender = ConvertMaterialToRenderMaterial(rhinoMaterial);
65-
myMaterial = ConvertRenderMaterialToSpeckle(convertedRender);
66-
}
67-
68-
if (myMaterial is not null)
69-
{
70-
renderMaterialProxies[rhinoMaterialId] = new RenderMaterialProxy()
71-
{
72-
value = myMaterial,
73-
objects = [rhinoObject.Id.ToString()]
74-
};
75-
}
76-
}
98+
RenderMaterialProxy renderMaterialProxy =
99+
new()
100+
{
101+
value = myMaterial,
102+
applicationId = materialId,
103+
objects = new()
104+
};
105+
106+
// POC: we are not attaching source information here, since we do not support material inheritance
107+
return renderMaterialProxy;
108+
}
109+
110+
/// <summary>
111+
/// Iterates through a given set of rhino objects and layers to collect render materials.
112+
/// </summary>
113+
/// <param name="atomicObjects">atomic root objects, including instance objects</param>
114+
/// <param name="layers">the layers corresponding to collections on the root collection</param>
115+
/// <returns></returns>
116+
public List<RenderMaterialProxy> UnpackRenderMaterials(List<RhinoObject> atomicObjects, List<Layer> layers)
117+
{
118+
var currentDoc = RhinoDoc.ActiveDoc; // POC: too much right now to interface around
119+
120+
// Stage 1: unpack materials from objects
121+
foreach (RhinoObject rootObj in atomicObjects)
122+
{
123+
// materials are confusing in rhino. we need both render material and material because objects can have either assigned
124+
RenderMaterial? rhinoRenderMaterial = rootObj.GetRenderMaterial(true);
125+
Material? rhinoMaterial = rootObj.GetMaterial(true);
126+
127+
try
128+
{
129+
ProcessObjectMaterial(
130+
rootObj.Id.ToString(),
131+
rhinoRenderMaterial,
132+
rhinoMaterial,
133+
rootObj.Attributes.MaterialSource
134+
);
77135
}
78136
catch (Exception ex) when (!ex.IsFatal())
79137
{
80-
_logger.LogError(ex, "Failed to unpack render material from RhinoObject");
138+
_logger.LogError(ex, "Failed to unpack material from Rhino Object");
81139
}
82140
}
83141

84142
// Stage 2: make sure we collect layer materials as well
85-
foreach (var layer in usedLayerMap.Values)
143+
foreach (Layer layer in layers)
86144
{
145+
// materials are confusing in rhino. we will first try to get layer render material and then material by index if null
146+
RenderMaterial? rhinoRenderMaterial = layer.RenderMaterial;
147+
Material? rhinoMaterial =
148+
layer.RenderMaterialIndex == -1 ? null : currentDoc.Materials[layer.RenderMaterialIndex];
149+
87150
try
88151
{
89-
// 1. Try to create from RenderMaterial
90-
var renderMaterial = layer.RenderMaterial;
91-
if (renderMaterial is not null)
92-
{
93-
if (renderMaterialProxies.TryGetValue(renderMaterial.Id.ToString(), out RenderMaterialProxy? value))
94-
{
95-
value.objects.Add(layer.Id.ToString());
96-
}
97-
else
98-
{
99-
renderMaterialProxies[renderMaterial.Id.ToString()] = new RenderMaterialProxy()
100-
{
101-
value = ConvertRenderMaterialToSpeckle(renderMaterial),
102-
objects = [layer.Id.ToString()]
103-
};
104-
}
105-
106-
continue;
107-
}
108-
109-
// 2. As fallback, try to create from index
110-
// ON RECEIVE: when creating a layer on receive we cannot set RenderMaterial to layer. (RhinoCommon API limitation, it tested)
111-
// We can only set render material index of layer. So for the second send, we also need to check its index!
112-
var renderMaterialIndex = layer.RenderMaterialIndex;
113-
if (renderMaterialIndex == -1)
114-
{
115-
continue;
116-
}
117-
118-
var renderMaterialFromIndex = RhinoDoc.ActiveDoc.Materials[renderMaterialIndex];
119-
if (renderMaterialFromIndex is null)
120-
{
121-
continue;
122-
}
123-
124-
if (
125-
renderMaterialProxies.TryGetValue(
126-
renderMaterialFromIndex.Id.ToString(),
127-
out RenderMaterialProxy? renderMaterialProxy
128-
)
129-
)
130-
{
131-
renderMaterialProxy.objects.Add(layer.Id.ToString());
132-
}
133-
else
134-
{
135-
renderMaterialProxies[renderMaterialFromIndex.Id.ToString()] = new RenderMaterialProxy()
136-
{
137-
value = ConvertRenderMaterialToSpeckle(ConvertMaterialToRenderMaterial(renderMaterialFromIndex)),
138-
objects = [layer.Id.ToString()]
139-
};
140-
}
152+
ProcessObjectMaterial(
153+
layer.Id.ToString(),
154+
rhinoRenderMaterial,
155+
rhinoMaterial,
156+
ObjectMaterialSource.MaterialFromObject
157+
);
141158
}
142159
catch (Exception ex) when (!ex.IsFatal())
143160
{
144-
_logger.LogError(ex, "Failed to unpack render material from Rhino Layer");
161+
_logger.LogError(ex, "Failed to unpack materials from Rhino Layer");
145162
}
146163
}
147164

148-
return renderMaterialProxies.Values.ToList();
165+
return RenderMaterialProxies.Values.ToList();
149166
}
150167

151168
// converts a rhino material to a rhino render material

Connectors/Rhino/Speckle.Connectors.RhinoShared/Operations/Send/RhinoRootObjectBuilder.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ CancellationToken cancellationToken
8989

9090
// 3 - Convert atomic objects
9191
List<SendConversionResult> results = new(atomicObjects.Count);
92-
HashSet<Layer> versionLayers = new();
9392
int count = 0;
9493
using (var _ = _activityFactory.Start("Convert all"))
9594
{
@@ -98,9 +97,9 @@ CancellationToken cancellationToken
9897
cancellationToken.ThrowIfCancellationRequested();
9998
using var _2 = _activityFactory.Start("Convert");
10099

101-
// handle layer
100+
// handle layer and store object layer *and all layer parents* to the version layers
101+
// this is important because we need to unpack colors and materials on intermediate layers that do not have objects as well.
102102
Layer layer = _converterSettings.Current.Document.Layers[rhinoObject.Attributes.LayerIndex];
103-
versionLayers.Add(layer);
104103
Collection collectionHost = _layerUnpacker.GetHostObjectCollection(layer, rootObjectCollection);
105104

106105
var result = ConvertRhinoObject(rhinoObject, collectionHost, instanceProxies, sendInfo.ProjectId);
@@ -120,15 +119,18 @@ CancellationToken cancellationToken
120119
throw new SpeckleException("Failed to convert all objects."); // fail fast instead creating empty commit! It will appear as model card error with red color.
121120
}
122121

122+
// Get all layers from the created collections on the root object commit for proxy processing
123+
List<Layer> layers = _layerUnpacker.GetUsedLayers().ToList();
124+
123125
using (var _ = _activityFactory.Start("UnpackRenderMaterials"))
124126
{
125127
// 4 - Unpack the render material proxies
126-
rootObjectCollection[ProxyKeys.RENDER_MATERIAL] = _materialUnpacker.UnpackRenderMaterial(atomicObjects);
128+
rootObjectCollection[ProxyKeys.RENDER_MATERIAL] = _materialUnpacker.UnpackRenderMaterials(atomicObjects, layers);
127129
}
128130
using (var _ = _activityFactory.Start("UnpackColors"))
129131
{
130132
// 5 - Unpack the color proxies
131-
rootObjectCollection[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, versionLayers.ToList());
133+
rootObjectCollection[ProxyKeys.COLOR] = _colorUnpacker.UnpackColors(atomicObjects, layers);
132134
}
133135

134136
return new RootObjectBuilderResult(rootObjectCollection, results);

0 commit comments

Comments
 (0)